[
  {
    "name": "FCRotateViewAbsolute",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "",
    "code": "__Name__ = 'FCRotateViewAbsolute'\n__Comment__ = ''\n__License__ = ''\n__Web__ = ''\n__Wiki__ = ''\n__Icon__ = ''\n__Help__ = ''\n__Author__ = ''\n__Version__ = ''\n__Status__ = ''\n__Requires__ = ''\n__Files__ = ''\n\nfrom FreeCAD import Base\nimport FreeCADGui as Gui\n\n\nfrom math import cos,sin,pi\n\nimport sys\nfrom PySide.QtCore import *\nfrom PySide.QtGui import *\n\nfrom pivy import coin\n\nclass Form(QDialog):\n\n\tdef __init__(self, parent=None):\n\t\tsuper(Form, self).__init__(parent)\n\t\tself.alpha=00\n\t\tself.beta=180\n\t\tself.setWindowFlags(Qt.WindowStaysOnTopHint)\n\n\t\tdial = QDial()\n\t\tdial.setNotchesVisible(True)\n\t\tself.dial=dial\n\t\tdial.setMaximum(360)\n\t\tdial.setValue(self.alpha)\n\n\n\n\t\tdial2 = QDial()\n\t\tdial2.setNotchesVisible(True)\n\t\tself.dial2=dial2\n\t\tdial2.setMaximum(360)\n\t\tdial2.setValue(self.beta)\n\n\t\tspinbox = QSpinBox()\n\t\tspinbox.setMaximum(360)\n\n\t\tlayout = QHBoxLayout()\n\n\n\t\tself.pushButton00 = QPushButton(QIcon('icons:freecad.svg'),\"Dimetric\")\n\t\tself.pushButton01 = QPushButton(QIcon('icons:freecad.svg'),\"Trimetric\")\n\t\tself.pushButton02 = QPushButton(QIcon('icons:freecad.svg'),\"Isometric\")\n\t\tself.pushButton03 = QPushButton(QIcon('icons:freecad.svg'),\"Front\")\n\t\tself.pushButton00.clicked.connect(self.dimetric)\n\t\tself.pushButton01.clicked.connect(self.trimetric)\n\t\tself.pushButton02.clicked.connect(self.isometric)\n\t\tself.pushButton03.clicked.connect(self.front)\n\t\tlayout.addWidget(self.pushButton03)\n\t\tlayout.addWidget(self.pushButton00)\n\t\tlayout.addWidget(self.pushButton01)\n\t\tlayout.addWidget(self.pushButton02)\n\n\n\t\tlayout.addWidget(dial)\n\t\tlayout.addWidget(dial2)\n# \t\tlayout.addWidget(spinbox)\n\t\tself.setLayout(layout)\n\n\t\t#self.connect(dial, SIGNAL(\"valueChanged(int)\"),                    spinbox.setValue)\n\t\t#self.connect(spinbox, SIGNAL(\"valueChanged(int)\"),                    dial.setValue)\n\t\tdial.valueChanged.connect(spinbox.setValue);\n\n\t\tdial.valueChanged.connect(self.dreher);\n\t\tdial2.valueChanged.connect(self.heber);\n\n\n\t\tself.cami()\n\t\tself.setWindowTitle(\"Camera position\")\n\t\tGui.SendMsgToActiveView(\"ViewFit\")\n\n\n\n\tdef dreher(self):\n\t\tself.alpha=self.dial.value()\n\t\tself.cami()\n\n\tdef heber(self):\n\t\tself.beta=self.dial2.value()\n\t\tself.cami()\n\n\tdef rotY(self,delta=10):\n\t\tif self.beta==1:\n\t\t\tself.beta=0\n\n\t\tself.beta += delta\n\t\tif self.beta >360:\n\t\t\tself.beta -= 360\n\t\tif self.beta <0:\n\t\t\tself.beta += 360\n\t\tif self.beta==0:\n\t\t\tself.beta=1\n\t\tFreeCAD.Console.PrintMessage(str(self.beta)+\"  # \");\n\t\tself.dial2.setValue(self.beta)\n\n\n\tdef rotZ(self,delta=10):\n\t\tself.alpha += delta\n\t\tif self.alpha >360:\n\t\t\tself.alpha -= 360\n\t\tif self.alpha <0:\n\t\t\tself.alpha += 360\n\t\tself.dial.setValue(self.alpha)\n\n\tdef cami(self):\n\n\t\tfrom pivy import coin\n\t\talpha=self.alpha\n\t\tbeta=self.beta\n\n\t\tcamera = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()\n\n\t\tGui=FreeCADGui\n\t\tif False:\n\t\t\ttypeCamera=\"Orthographic\"\n\t\t\tif typeCamera==\"Orthographic\":\n\t\t\t\tGui.activeDocument().activeView().setCameraType(\"Orthographic\")\n\t\t\telse:\n\t\t\t\tGui.activeDocument().activeView().setCameraType(\"Perspective\")\n\n\t\tcampos=Base.Vector( 1000 * cos (pi*alpha/360*2)*sin(pi*beta/360*1), 1000*sin(pi*alpha/360*2)*sin(pi*beta/360*1), 1000*cos(pi*beta/360*1))\n\t\tcamera.position.setValue( campos)\n\n\t\tpos3=FreeCAD.Vector(0,0,0)\n\t\tpos3.sub(campos)\n\n\t\t#if False:\n\t\tcamera.pointAt(coin.SbVec3f(pos3),coin.SbVec3f(0,0,1))\n\n\t\tApp.ActiveDocument.recompute()\n\t\tFreeCADGui.updateGui()\n\n\tdef front(self):\n\t\tfrom pivy import coin\n\t\tpos3=FreeCAD.Vector(0,0,0)\n\t\tcampos=FreeCAD.Vector(0,-10,0)\n\t\tcamera = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()\n\t\tcamera.position.setValue( campos)\n\t\tcamera.pointAt(coin.SbVec3f(pos3),coin.SbVec3f(0,0,1))\n\n\tdef isometric(self):\n\n\t\tpos3=FreeCAD.Vector(0,0,0)\n\t\tcampos=FreeCAD.Vector(100,-100,100)\n\t\tcamera = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()\n\t\tcamera.position.setValue( campos)\n\t\tpos3.sub(campos)\n\t\tcamera.pointAt(coin.SbVec3f(pos3),coin.SbVec3f(0,0,1))\n\n\tdef dimetric(self):\n\t\tpos3=FreeCAD.Vector(0,0,0)\n\t\tcampos=FreeCAD.Vector(68,-68,27)\n\t\tcamera = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()\n\t\tcamera.position.setValue( campos)\n\t\tpos3.sub(campos)\n\t\tcamera.pointAt(coin.SbVec3f(pos3),coin.SbVec3f(0,0,1))\n\t\tApp.ActiveDocument.recompute()\n\t\tFreeCADGui.updateGui()\n\n\n\tdef trimetric(self):\n\t\tpos3=FreeCAD.Vector(0,0,0)\n\t\tcampos=FreeCAD.Vector(210,-790,580)\n\t\tcamera = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()\n\t\tcamera.position.setValue( campos)\n\t\tpos3.sub(campos)\n\t\tcamera.pointAt(coin.SbVec3f(pos3),coin.SbVec3f(0,0,1))\n\n\nif hasattr(FreeCAD,\"ViewMgr\")and FreeCAD.ViewMgr:\n\tFreeCAD.ViewMgr.show()\n\tFreeCAD.Console.PrintMessage(\"neu gestrte\")\nelse:\n\tFreeCAD.ViewMgr=Form()\n\tFreeCAD.ViewMgr.show()\n\tFreeCAD.Console.PrintMessage(\" war schon da\")\n\n\nt=FreeCADGui.getMainWindow()\nt.activateWindow()\n",
    "url": "",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\FCRotateViewAbsolute.FCMacro",
    "filename_from_url": "",
    "author": "",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Foto",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Creates a real sized 300-dpi foto of the selected part from top view",
    "code": "# -*- coding: utf-8 -*-\n# (c) microelly 2015\n\n__Name__ = 'Foto'\n__Comment__ = 'Creates a real sized 300-dpi foto of the selected part from top view'\n__Author__ = 'microelly'\n__Version__ = '0.1.0'\n__Date__ = ''\n__License__ = ''\n__Web__ = ''\n__Wiki__ = ''\n__Icon__ = ''\n__Help__ = 'Select an object'\n__Status__ = 'alpha'\n__Requires__ = ''\n__Contact__ = 'https://forum.freecadweb.org/memberlist.php?mode=viewprofile&u=2364'\n__Communication__ = ''\n__Files__ = ''\n\nimport os\n\nimport FreeCADGui\n\n\ndef foto(fn='/tmp/fc_camera_out.jpg', width=150, height=100, x=0, y=0, res=300):\n    if res <= 0:\n        # TODO: add a warning about wrong res value.\n        res = 300\n    dpmm = 11.8110 * res / 300\n    ppy = int(dpmm * height)\n    ppx = int(dpmm * width)\n    y -= 1\n    cam = '''#Inventor V2.1 ascii\n    OrthographicCamera {{\n      viewportMapping ADJUST_CAMERA\n      orientation 1 0 0  0.001\n      nearDistance 0\n      farDistance 1000\n      aspectRatio 100\n      focalDistance 1\n      position {x} {y} 999\n      height {height}\n    }}\n\n    '''.format(x=x, y=y, height=height)\n\n    FreeCADGui.activeDocument().activeView().setCamera(cam)\n\n    FreeCADGui.ActiveDocument.update()\n    FreeCADGui.activeDocument().activeView().saveImage(fn, ppx, ppy, '#ffffff')\n\nfn = \"/tmp/fc_photo.jpg\"\nres = 300\n\nsel = FreeCADGui.Selection.getSelection()\nsel0 = sel[0]\nsel0.ViewObject.LineWidth = 1\nbbox = sel0.Shape.BoundBox\npx = 0.5 * (bbox.XMin + bbox.XMax)\npy = 0.5 * (bbox.YMin + bbox.YMax)\nwidth = bbox.XMax - bbox.XMin\nheight = bbox.YMax - bbox.YMin\n\nfoto(fn, width, height, px, py, res)\nos.system('xdg-open {}'.format(fn))\n",
    "url": "",
    "raw_code_url": "",
    "wiki": "",
    "version": "0.1.0",
    "license": "",
    "date": "",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Foto.FCMacro",
    "filename_from_url": "",
    "author": "microelly",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "SolidSweep",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "",
    "code": "import Part, FreeCAD, math, PartGui, FreeCADGui\nfrom FreeCAD import Base\n\n# get the selected objects, with first selection for the trajectory and second for the section\ns = FreeCADGui.Selection.getSelection()\ntry:\n     shape1=s[0].Shape\n     shape2=s[1].Shape\nexcept:\n     print \"Wrong selection\"\n\ntraj = Part.Wire([shape1])\nsection = Part.Wire([shape2])\n\n# create Part object in the current document\nmyObject=App.ActiveDocument.addObject(\"Part::Feature\",\"Sweep\")\n\n# variable makeSolid = 1 to create solid, 0 to create surfaces\nmakeSolid = True #1\nisFrenet = True #1\n\n# create a 3D shape and assigh it to the current document\nSweep = Part.Wire(traj).makePipeShell([section],makeSolid,isFrenet)\nmyObject.Shape = Sweep\n",
    "url": "",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\SolidSweep.FCMacro",
    "filename_from_url": "",
    "author": "",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "DeepCopy",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Takes a part and makes a compound out of it",
    "code": "# Make a copy of the shape of all children of a part and make a compound\n# from them.\n\nfrom __future__ import annotations\n\n__Name__ = 'Deep Copy'\n__Comment__ = 'Takes a part and makes a compound out of it'\n__License__ = 'Apache-2.0'\n__Web__ = 'https://www.freecadweb.org/wiki/Macro_DeepCopy'\n__Wiki__ = 'https://www.freecadweb.org/wiki/Macro_DeepCopy'\n__Icon__ = 'DeepCopy.svg'\n__Help__ = 'Select a part and launch'\n__Author__ = 'galou_breizh'\n__Version__ = '1.1.0'\n__Date__ = '2023-03-22'\n__Status__ = 'Stable'\n__Requires__ = 'FreeCAD >= v0.17'\n__Files__ = 'DeepCopy.svg'\n\nfrom typing import Iterable, Optional\n\nfrom Arch import pruneIncluded\n\nimport FreeCAD as app\nimport FreeCADGui as gui\n\n\n# Typing hints.\nDO: app.DocumentObject\nAppPart: DO  # TypeId == 'App::Part'.\nDOList: Iterable[DO]\n\n\ndef deep_copy(doc: Optional[app.Document] = None):\n    \"\"\"Copy the shape of the selected objects.\n\n    Parameters\n    ----------\n    - doc: document to copy the shape to. Defaults to the document of the\n      selected objects.\n\n    \"\"\"\n    sel = gui.Selection.getSelectionEx()\n    if not sel:\n        app.Console.PrintWarning('No objects selected')\n        return\n    # Check that all selected objects are in the same document.\n    if doc is None:\n        doc = sel[0].Object.Document\n        for sel_object in sel:\n            if sel_object.Object.Document is not doc:\n                app.Console.PrintError('Selected objects belong to'\n                                       ' different documents\\n')\n                return\n\n    for sel_object in sel:\n        deep_copy_part(sel_object.Object, doc)\n\n\ndef deep_copy_part(part: AppPart, doc: Optional[app.Document] = None):\n    \"\"\"Copy the shape of a \"App::Part\" object.\n\n    Parameters\n    ----------\n    - doc: document to copy the shape to. Defaults to the document of the\n      given object.\n\n    \"\"\"\n    if (not hasattr(part, 'TypeId')) or part.TypeId != 'App::Part':\n        # Part is not a part, return.\n        try:\n            app.Console.PrintWarning(f'\"{part.Label}\" ({part.Name})'\n                                     ' is not a part, ignoring\\n')\n        except AttributeError:\n            app.Console.PrintWarning('Object is not a part, ignoring\\n')\n        return\n\n    if doc is None:\n        doc = part.Document\n\n    copied_subobjects = []\n    for o in get_all_subobjects(part):\n        copied_subobjects += copy_subobject(doc, o)\n\n    compound = doc.addObject('Part::Compound', 'Copy of ' + part.Label)\n    compound.Links = copied_subobjects\n    compound.Placement = part.Placement\n    doc.recompute()\n\n\ndef get_all_subobjects(obj: DO) -> DOList:\n    \"\"\"Recursively get all subobjects\n\n    Subobjects of objects having a Shape attribute are not included otherwise\n    each single feature of the object would be copied. The result is that\n    bodies, compounds, and the result of boolean operations will be converted\n    into a simple copy of their shape.\n\n    \"\"\"\n    # Depth-first search algorithm.\n    discovered = []\n    # We do not need an extra copy for stack because OutList is already a copy.\n    stack = obj.OutList\n    while stack:\n        v = stack.pop(0)\n        if v not in discovered:\n            discovered.append(v)\n            if not hasattr(v, 'Shape'):\n                stack += v.OutList\n    return pruneIncluded(discovered)\n\n\ndef copy_subobject(doc: app.DocumentObject, obj: DO) -> DOList:\n    \"\"\"Copy the shape of an object\n\n    Some GUI attributes are also copied\n\n    \"\"\"\n    copied_object = []\n    if not hasattr(obj, 'Shape') or obj.Shape.isNull():\n        return copied_object\n    vobj = obj.ViewObject\n    try:\n        copy = doc.addObject('Part::Feature', obj.Name + '_Shape')\n        copy.Shape = obj.Shape\n        copy.Label = 'Copy of ' + obj.Label\n    except AttributeError as e:\n        app.Console.PrintLog(e)\n        pass\n    else:\n        copied_object = [copy]\n    vo_copy = copy.ViewObject\n    # Implementation note: cannot use __setattr__ and __getattribute__.\n    try:\n        vo_copy.ShapeColor = vobj.ShapeColor\n    except AttributeError:\n        pass\n    try:\n        vo_copy.LineColor = vobj.LineColor\n    except AttributeError:\n        pass\n    try:\n        vo_copy.PointColor = vobj.PointColor\n    except AttributeError:\n        pass\n    try:\n        vo_copy.DiffuseColor = vobj.DiffuseColor\n    except AttributeError:\n        pass\n    try:\n        vo_copy.Transparency = vobj.Transparency\n    except AttributeError:\n        pass\n    return copied_object\n\n\nif __name__ == '__main__':\n    deep_copy()\n",
    "url": "https://www.freecadweb.org/wiki/Macro_DeepCopy",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_DeepCopy",
    "version": "1.1.0",
    "license": "",
    "date": "2023-03-22",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Conversion\\DeepCopy.FCMacro",
    "filename_from_url": "",
    "author": "galou_breizh",
    "icon": "DeepCopy.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "DeepCopy.svg"
    ],
    "parsed": true
  },
  {
    "name": "DxfToSketchLayers",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "DXF loader to a sketch for each layer or color",
    "code": "# -*- coding: utf-8 -*-\n\n__Name__ = 'DXF to Sketch Layers'\n__Comment__ = 'DXF loader to a sketch for each layer or color'\n__Author__ = 'Julian Todd'\n__Version__ = '1.0.2'\n__Date__ = '2019-04-30'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'https://github.com/goatchurchprime/transition-CAM/blob/master/dxfimporting/Macro_DXF_to_Sketch_layers.FCMacro'\n__Wiki__ = ''\n__Icon__ = ''\n__Help__ = ''\n__Status__ = 'stable'\n__Requires__ = 'FreeCAD >= 0.17'\n__Communication__ = ''\n__Files__ = ''\n\n# This should be a general function available to all macros\n# (Taken from https://stackoverflow.com/questions/12332975/installing-python-module-within-code )\nfrom PySide import QtGui\ndef import_and_install(packagename):\n    try:\n        _encoding = QtGui.QApplication.UnicodeUTF8\n        def tr(context, text):\n            return QtGui.QApplication.translate(context, text, None, _encoding)\n    except AttributeError:\n        def tr(context, text):\n            return QtGui.QApplication.translate(context, text, None)\n\n    import importlib\n    try:\n        importlib.import_module(packagename)\n    except ImportError:\n        cmdlist = [\"pip\", \"install\", packagename, \"--user\"]\n        answer = QtGui.QMessageBox.question(None,\n                    tr(__Name__, 'Install %s?' % packagename),\n        \t    tr(__Name__, 'Install %s by executing \"%s\"?' % (packagename, \" \".join(cmdlist))))\n        if answer == QtGui.QMessageBox.StandardButton.Yes:\n            import subprocess\n            proc = subprocess.Popen(cmdlist, stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n            out, err = proc.communicate()\n            print(out.decode())\n            print(err.decode())\n        else:\n            raise\n    globals()[packagename] = importlib.import_module(packagename)\n\n\n#\n# Imports and start of code\n#\nimport_and_install(\"ezdxf\")\nfrom PySide import QtGui\nimport math\nimport Draft, Part\nfrom FreeCAD import Vector\nimport FreeCAD\nimport FreeCADGui\n\n\n#\n# DXF unwrapping and colour converting.\n# TODO: Would like this in a separate file.)\ndxfcolors = ['#000000', '#FF0000', '#FFFF00', '#00FF00',\n             '#00FFFF', '#0000FF', '#FF00FF', '#000000',\n             '#808080', '#C0C0C0', '#FF0000', '#FF7F7F',\n             '#CC0000', '#CC6666', '#990000', '#994C4C',\n             '#7F0000', '#7F3F3F', '#4C0000', '#4C2626',\n             '#FF3F00', '#FF9F7F', '#CC3300', '#CC7F66',\n             '#992600', '#995F4C', '#7F1F00', '#7F4F3F',\n             '#4C1300', '#4C2F26', '#FF7F00', '#FFBF7F',\n             '#CC6600', '#CC9966', '#994C00', '#99724C',\n             '#7F3F00', '#7F5F3F', '#4C2600', '#4C3926',\n             '#FFBF00', '#FFDF7F', '#CC9900', '#CCB266',\n             '#997200', '#99854C', '#7F5F00', '#7F6F3F',\n             '#4C3900', '#4C4226', '#FFFF00', '#FFFF7F',\n             '#CCCC00', '#CCCC66', '#999900', '#99994C',\n             '#7F7F00', '#7F7F3F', '#4C4C00', '#4C4C26',\n             '#BFFF00', '#DFFF7F', '#99CC00', '#B2CC66',\n             '#729900', '#85994C', '#5F7F00', '#6F7F3F',\n             '#394C00', '#424C26', '#7FFF00', '#BFFF7F',\n             '#66CC00', '#99CC66', '#4C9900', '#72994C',\n             '#3F7F00', '#5F7F3F', '#264C00', '#394C26',\n             '#3FFF00', '#9FFF7F', '#33CC00', '#7FCC66',\n             '#269900', '#5F994C', '#1F7F00', '#4F7F3F',\n             '#134C00', '#2F4C26', '#00FF00', '#7FFF7F',\n             '#00CC00', '#66CC66', '#009900', '#4C994C',\n             '#007F00', '#3F7F3F', '#004C00', '#264C26',\n             '#00FF3F', '#7FFF9F', '#00CC33', '#66CC7F',\n             '#009926', '#4C995F', '#007F1F', '#3F7F4F',\n             '#004C13', '#264C2F', '#00FF7F', '#7FFFBF',\n             '#00CC66', '#66CC99', '#00994C', '#4C9972',\n             '#007F3F', '#3F7F5F', '#004C26', '#264C39',\n             '#00FFBF', '#7FFFDF', '#00CC99', '#66CCB2',\n             '#009972', '#4C9985', '#007F5F', '#3F7F6F',\n             '#004C39', '#264C42', '#00FFFF', '#7FFFFF',\n             '#00CCCC', '#66CCCC', '#009999', '#4C9999',\n             '#007F7F', '#3F7F7F', '#004C4C', '#264C4C',\n             '#00BFFF', '#7FDFFF', '#0099CC', '#66B2CC',\n             '#007299', '#4C8599', '#005F7F', '#3F6F7F',\n             '#00394C', '#26424C', '#007FFF', '#7FBFFF',\n             '#0066CC', '#6699CC', '#004C99', '#4C7299',\n             '#003F7F', '#3F5F7F', '#00264C', '#26394C',\n             '#0042FF', '#7F9FFF', '#0033CC', '#667FCC',\n             '#002699', '#4C5F99', '#001F7F', '#3F4F7F',\n             '#00134C', '#262F4C', '#0000FF', '#7F7FFF',\n             '#0000CC', '#6666CC', '#000099', '#4C4C99',\n             '#00007F', '#3F3F7F', '#00004C', '#26264C',\n             '#3F00FF', '#9F7FFF', '#3200CC', '#7F66CC',\n             '#260099', '#5F4C99', '#1F007F', '#4F3F7F',\n             '#13004C', '#2F264C', '#7F00FF', '#BF7FFF',\n             '#6600CC', '#9966CC', '#4C0099', '#724C99',\n             '#3F007F', '#5F3F7F', '#26004C', '#39264C',\n             '#BF00FF', '#DF7FFF', '#9900CC', '#B266CC',\n             '#720099', '#854C99', '#5F007F', '#6F3F7F',\n             '#39004C', '#42264C', '#FF00FF', '#FF7FFF',\n             '#CC00CC', '#CC66CC', '#990099', '#994C99',\n             '#7F007F', '#7F3F7F', '#4C004C', '#4C264C',\n             '#FF00BF', '#FF7FDF', '#CC0099', '#CC66B2',\n             '#990072', '#994C85', '#7F005F', '#7F3F0B',\n             '#4C0039', '#4C2642', '#FF007F', '#FF7FBF',\n             '#CC0066', '#CC6699', '#99004C', '#994C72',\n             '#7F003F', '#7F3F5F', '#4C0026', '#4C2639',\n             '#FF003F', '#FF7F9F', '#CC0033', '#CC667F',\n             '#990026', '#994C5F', '#7F001F', '#7F3F4F',\n             '#4C0013', '#4C262F', '#333333', '#5B5B5B',\n             '#848484', '#ADADAD', '#D6D6D6', '#FFFFFF']\n\n\ndef getlayercol(e, dfile, blockcolnum):\n    if e.dxf.color == 256:\n        layer = dfile.layers.get(e.dxf.layer)\n        colnum = layer.get_dxf_attrib(\"color\", 0)\n    elif e.dxf.color == 0:\n        colnum = blockcolnum\n    else:\n        colnum = e.dxf.color\n    return (e.dxf.layer, dxfcolors[colnum])\n\ndef makeentitygroupsrecurse(entitygroupdict, dfile, entities, blockcolnum):\n    for e in entities:\n        if e.dxftype() == 'INSERT':\n            print(\"INSERT translate\", e.dxf.insert, \"rotate\", e.dxf.rotation, \"scale\", e.dxf.xscale, e.dxf.yscale)\n            lblockcolnum = dfile.layers.get(e.dxf.layer).get_color()\n            makeentitygroupsrecurse(entitygroupdict, dfile, list(dfile.blocks[e.dxf.name]), lblockcolnum)\n        elif e.dxftype() == 'MTEXT':\n            pass\n        elif e.dxftype() == 'TEXT':\n            pass\n        else:\n            layercol = getlayercol(e, dfile, blockcolnum)\n            entitygroupdict.setdefault(layercol, []).append(e)\n    return entitygroupdict\n\ndef makeentitygroups(dfile):\n    entitygroupdict = { }\n    makeentitygroupsrecurse(entitygroupdict, dfile, dfile.entities, 1)\n    entitygroups = list(entitygroupdict.items())\n    layernameorder = dict((n, i)  for i, n in enumerate(l.dxf.name  for l in dfile.layers))\n    entitygroups.sort(key=lambda X:layernameorder[X[0][0]])\n    return entitygroups\n\n\n# See also arbitrary axis algorithm in http://paulbourke.net/dataformats/dxf/dxf10.html\n# Seems to flip rotation around Y-axis, so only invert the X\ndef arcextrusionfac(e):\n    if max(abs(e.dxf.extrusion[0]), abs(e.dxf.extrusion[1]), abs(abs(e.dxf.extrusion[2]) - 1)) > 1e-5:\n        print(\"Unknown arc extrusion\", e.dxf.extrusion)\n    return 1 if e.dxf.extrusion[2] >= 0 else -1\n\n\n#\n# Function to create sketches and inject dxf geometry directly into it\n#\n\ndef MakeSketches(addObjectFunc, entitygroups):\n    cnorm = Vector(0, 0, 1)\n    sketches = [ ]\n    for (layer, col), entities in entitygroups:\n        slayer = str(layer)\n        if len(slayer) <= 1:\n            slayer = \"layer_\"+slayer  # Sketcher name is '_' if it's a 1 character number\n        sketch = addObjectFunc(\"Sketcher::SketchObject\", slayer)\n        if sketch.ViewObject is not None:\n            sketch.ViewObject.Visibility = True\n            sketch.ViewObject.LineColor = (int(col[1:3],16)/255.0, int(col[3:5],16)/255.0, int(col[5:7],16)/255.0)\n        print(\"Making sketch\", layer, col)\n        sketches.append(sketch)\n        for e in entities:\n            try:\n                if e.dxftype() == \"LINE\":\n                    if e.dxf.start != e.dxf.end:\n                        p0 = Vector(e.dxf.start[0], e.dxf.start[1])\n                        p1 = Vector(e.dxf.end[0], e.dxf.end[1])\n                        sketch.addGeometry(Part.LineSegment(p0, p1))\n\n                elif e.dxftype() == \"CIRCLE\":\n                    exfac = arcextrusionfac(e)\n                    cen = Vector(e.dxf.center[0]*exfac, e.dxf.center[1])\n                    sketch.addGeometry(Part.Circle(cen, cnorm, e.dxf.radius))\n\n                elif e.dxftype() == \"ARC\":\n                    exfac = arcextrusionfac(e)\n                    cen = Vector(e.dxf.center[0]*exfac, e.dxf.center[1])\n                    circ = Part.Circle(cen, cnorm, e.dxf.radius)\n                    a0, a1 = e.dxf.start_angle, e.dxf.end_angle\n                    if exfac == -1:\n                        a0, a1 = 180-a1, 180-a0\n                    sketch.addGeometry(Part.ArcOfCircle(circ, math.radians(a0), math.radians(a1)))\n\n                elif e.dxftype() == \"SPLINE\":\n                    cps = [Vector(x[0], x[1])  for x in list(e.control_points)]\n                    bspl = Part.BSplineCurve(cps,None,None,False,e.dxf.degree,None,e.closed)\n                    sketch.addGeometry(bspl)\n\n                elif e.dxftype() == \"LWPOLYLINE\":\n                    def lwpgeo(p0, p1, bulge):\n                        if bulge != 0:\n                            lv = p1 - p0\n                            b = abs(bulge)\n                            d = lv.Length/2\n                            bd = b*d\n                            r = (bd + d/b)/2\n                            sb = (1 if bulge >= 0 else -1)\n                            pf = (r - bd)/(d*2)\n                            cnorm = Vector(0, 0, 1)\n                            lvperp = lv.cross(cnorm)*sb\n                            cen = p0 + lv*0.5 - lvperp*pf\n                            circ = Part.Circle(cen, cnorm, r)\n                            mang = math.atan2(lvperp.y, lvperp.x)\n                            th2 = math.asin(d/r)\n                            return(Part.ArcOfCircle(circ, mang-th2, mang+th2))\n                        else:\n                            return Part.LineSegment(p0, p1)\n\n                    p0 = Vector(e[0][0], e[0][1])\n                    for i in range(1, len(e)):\n                        p1 = Vector(e[i][0], e[i][1])\n                        sketch.addGeometry(lwpgeo(p0, p1, e[i-1][4]))\n                        p0 = p1\n                    if e.closed:\n                        sketch.addGeometry(lwpgeo(p0, Vector(e[0][0], e[0][1]), e[-1][4]))\n\n                elif e.dxftype() == \"POLYLINE\":\n                    p0s = Vector(e[0].dxf.location[0], e[0].dxf.location[1])\n                    p0 = p0s\n                    for i in range(1, len(e)):\n                        p1 = Vector(e[i].dxf.location[0], e[i].dxf.location[1])\n                        if p0 != p1:\n                            sketch.addGeometry(Part.LineSegment(p0, p1))\n                        p0 = p1\n                    if e.is_closed and p0s != p0:\n                        sketch.addGeometry(Part.LineSegment(p0, p0s))\n\n                else:\n                    print(\"unknown\", e.dxftype())\n\n            except Part.OCCError as err:\n                print(e, err)\n    return sketches\n\n\n\n#\n# Main entry which finds or creates the document and body\n#\ndef main():\n    \"\"\"Main entry which finds or creates the document and body\"\"\"\n    fname, fnamefilter = QtGui.QFileDialog.getOpenFileName(parent=FreeCADGui.getMainWindow(), caption='Read a DXF file', filter='*.dxf')\n    if fname:\n        FreeCAD.Console.PrintMessage('Parsing file {}'.format(fname))\n        dfile = ezdxf.readfile(fname)\n\n        unitfacmap = {4:1.0} # 4->mm\n        unitfac = unitfacmap[dfile.header['$INSUNITS']]\n        fac = dfile.header['$DIMALTF']\n        print(\"Factor multiply requested (not implemented)\", fac, unitfac)\n\n        entitygroups = makeentitygroups(dfile)\n        doc = FreeCAD.activeDocument()\n        if doc is None:\n            doc = FreeCAD.newDocument()\n        # Get the active body, if any.\n        obj = FreeCADGui.activeDocument().ActiveView.getActiveObject('pdbody')\n        try:\n            addObjectFunc = obj.newObject\n        except AttributeError:\n            addObjectFunc = doc.addObject\n\n        sketches = MakeSketches(addObjectFunc, entitygroups)\n        doc.recompute()\n\nif __name__ == '__main__':\n    main()\n\n",
    "url": "https://github.com/goatchurchprime/transition-CAM/blob/master/dxfimporting/Macro_DXF_to_Sketch_layers.FCMacro",
    "raw_code_url": "",
    "wiki": "",
    "version": "1.0.2",
    "license": "",
    "date": "2019-04-30",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Conversion\\DxfToSketchLayers.FCMacro",
    "filename_from_url": "",
    "author": "Julian Todd",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "MultiCopy",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "MultiCopy allows the duplication (copy and paste) of multiple FreeCAD objects that can be labelled sequentially and in a custom manner.",
    "code": "\n\n##########################################################################################\n#####\t\t\t\tL I C E N S E\t\t\t\t\t     #####\n##########################################################################################\n#\n#  GNU LESSER GENERAL PUBLIC LICENSE\n#  Version 2.1, February 1999\n#\n#  Copyright (C) 1991, 1999 Free Software Foundation, Inc.\n#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n#  Everyone is permitted to copy and distribute verbatim copies\n#  of this license document, but changing it is not allowed.\n#\n#  [This is the first released version of the Lesser GPL. It also counts\n#  as the successor of the GNU Library Public License, version 2, hence\n#  the version number 2.1.]\n#\n#  'MultiCopy' is a FreeCAD macro package. MultiCopy allows the duplication\n#  (copy and paste) of multiple FreeCAD objects that can be labelled\n#  sequentially and in a custom manner.\n#\n#  Copyright (C) 2021  Melwyn Francis Carlo\n#\n#  This library is free software; you can redistribute it and/or\n#  modify it under the terms of the GNU Lesser General Public\n#  License as published by the Free Software Foundation; either\n#  version 2.1 of the License, or (at your option) any later version.\n#\n#  This library is distributed in the hope that it will be useful,\n#  but WITHOUT ANY WARRANTY; without even the implied warranty of\n#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n#  Lesser General Public License for more details.\n#\n#  You should have received a copy of the GNU Lesser General Public License\n#  along with this library; if not, write to the Free Software Foundation, Inc.,\n#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n#\n#  Contact Information :-\n#  Email :  carlo.melwyn@outlook.com\n#  FreeCAD UserTalk :  http://www.freecadweb.org/wiki/index.php?title=User:Melwyncarlo\n#\n##########################################################################################\n#####\t\t\t\tL I C E N S E\t\t\t\t\t     #####\n##########################################################################################\n#\n#\n#\n#  The MultiCopy macro was developed and tested on a platform containing the\n#  following system and FreeCAD software specifications :\n#\n#  - OS\t\t\t: Ubuntu 18.04.5 LTS (LXDE/Lubuntu)\n#  - Word size of OS\t: 64-bit\n#  - Word size of FreeCAD: 64-bit\n#  - Version\t\t: 0.19\n#  - Build type\t\t: Release\n#  - Branch\t\t: unknown\n#  - Hash\t\t: 32200b604d421c4dad527fe587a7d047cf953b4f\n#  - Python version\t: 3.6.9\n#  - Qt version\t\t: 5.9.5\n#  - Coin version\t: 4.0.0a\n#  - OCC version\t: 7.3.0\n#  - Locale\t\t: English/UnitedKingdom (en_GB)\n\n\n\n\"\"\"\n  To use this macro, the steps to be followed are simple and straightforward :\n  select one or more FreeCAD objects from the Tree view, and then select 'MultiCopy'.\n  In the dialog box that pops up, choose the copy method, select and input the relevant\n  paste parameters and commands, and then click on 'Paste'.\n\n  Note (1)\tThe single underscore prefix (e.g. _name) denotes a private\n\t\tfunction or a private variable.\n  Note (2)\tSome of the short forms used in this script are as follows:\n\t\t  'mc' stands for MultiCopy\n  \t\t  'pcc' stands for Paste Code Commands\n  \t\t  'd' stands for Dialog (e.g. _d_, etc.)\n\"\"\"\n\n\n\n__Title__='MultiCopy'\n__Author__='Melwyncarlo'\n__Version__='2.0.0'\n__Date__='2021-03-23'\n__Comment__='MultiCopy allows the duplication (copy and paste) of multiple FreeCAD objects that can be labelled sequentially and in a custom manner.'\n__Web__='https://github.com/melwyncarlo/MultiCopy'\n__Wiki__='http://www.freecadweb.org/wiki/index.php?title=Macro_MultiCopy'\n__Icon__='MultiCopy.svg'\n__Help__='Select one or more FreeCAD objects, then click on the MultiCopy button/macro, and follow the instructions in the dialog box.'\n__Status__='stable'\n__Requires__='Freecad >= v0.17'\n__Communication__='https://github.com/melwyncarlo/MultiCopy/issues'\n__Files__='MultiCopyGui.py, MultiCopyCore.py, MultiCopyAuxFunc.py, MultiCopy/resources/MultiCopy_Main_Dialog.ui, MultiCopy/resources/MultiCopy_Commands_Dialog.ui, MultiCopy/resources/MultiCopy.svg'\n\n\n\n\n# Library Imports\n#------------------------------------------------------------------------------------------------\n\nimport MultiCopy\n\n\n\n###################################################################\n###-------------------------------------------------------------###\n### \t\t\tMULTICOPY MACRO CALLS\t\t\t###\n###-------------------------------------------------------------###\n###\t\t\t\t\t\t\t\t###\n###\tThis is the main macro call. The code below commences \t###\n###\tthe MultiCopy GUI interface. This script cannot be \t###\n###\tcalled externally.\t\t\t\t\t###\n\t\t\t\t\t\t\t\t###\n\t\t\t\t\t\t\t\t###\nif __name__ == '__main__':\t\t\t\t\t###\n\tMultiCopy.Gui.Launch()\t\t\t\t\t###\n\t\t\t\t\t\t\t\t###\n###-------------------------------------------------------------###\n### \t\t\tMULTICOPY MACRO CALLS\t   \t\t###\n###-------------------------------------------------------------###\n###################################################################\n\n\n\n",
    "url": "https://github.com/melwyncarlo/MultiCopy",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_MultiCopy",
    "version": "2.0.0",
    "license": "",
    "date": "2021-03-23",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Conversion\\MultiCopy.FCMacro",
    "filename_from_url": "",
    "author": "Melwyncarlo",
    "icon": "MultiCopy.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "MultiCopyGui.py",
      "MultiCopyCore.py",
      "MultiCopyAuxFunc.py",
      "MultiCopy/resources/MultiCopy_Main_Dialog.ui",
      "MultiCopy/resources/MultiCopy_Commands_Dialog.ui",
      "MultiCopy/resources/MultiCopy.svg"
    ],
    "parsed": true
  },
  {
    "name": "ExportFem",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "This macro exports FEM Data",
    "code": "# -*- coding: utf-8 -*-\n# Export FreeCAD FEM Data\n# Author: Gomez Lucio\n# License: LGPL v 2.1\n\n\n__Name__ = \"Export Fem\"\n__Comment__ = \"This macro exports FEM Data\"\n__License__ = \"LGPL v 2.1\"\n__Web__ = \"http://forum.freecadweb.org/viewtopic.php?f=18&t=11455\"\n__Wiki__ = \"\"\n__Icon__  = \"\"\n__Help__ = \"Select an object and start the macro\"\n__Author__ =\"Gomez Lucio\"\n__Version__= \"\"\n__Status__ = \"\"\n__Requires__ = \"\"\n__Files__ = \"\"\n\n\n\n\nimport os\nimport FreeCADGui\nimport FreeCAD\nimport shutil\nfrom PySide import QtGui\n\n### START OF MACRO ###\n\n# Mehcanical Analysis Select\nsel = FreeCADGui.Selection.getSelection() # Selection\nsel1=sel[0]\n\n# Save folder select\ndialog = QtGui.QFileDialog.getExistingDirectory()\ndestiny_folder = str(dialog)\n\n# Proceed\nif sel1.TypeId == 'Fem::FemAnalysisPython':\n  try:\n     dir1 = sel1.Document.TransientDir  # Temporary Directory\n     nam_fold = sel1.Uid[32:]           # Analysis temporary folder name\n     # Analysis Final Directory\n     direc = str(dir1 + '/FemAnl_' + nam_fold + '/')\n     calculix_files = os.listdir(direc)\n     for files in calculix_files:\n          shutil.copy(direc + files,destiny_folder)\n     FreeCAD.Console.PrintMessage('Mechanical Analysis files save in' + destiny_folder)\n  except:\n     FreeCAD.Console.PrintError('Sorry but no temporary file exists')\nelse:\n  FreeCAD.Console.PrintError('Error in Selection: Select a correct Mechanical Analysis')\n\n### END OF MACRO ###\n",
    "url": "http://forum.freecadweb.org/viewtopic.php?f=18&t=11455",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\FEM\\ExportFem.FCMacro",
    "filename_from_url": "",
    "author": "Gomez Lucio",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FemAnimateModeShapes",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Animate mode shapes after running CalculiX",
    "code": "\"\"\"FreeCAD macro to animate mode shapes.\n\nThese are the steps used to generate the data to be animated, these are the\nusual steps:\n- click on \"CalculiXccxTools\"\n- select \"Frequency\"\n- select \"Write .inp file\"\n- select \"Run CalculiX\"\n\nThese are the steps to prepare for and perform the animation:\n- open \"Macro\" in the ToolBar.\n- select \"Macros...\" and choose \"FemAnimateModeShapes.py\" and \"execute\". A\n  widget \"Animate\" will be generated in a separate window.\n- Double-click on a set of results \"CalculiX_frequency_mode_7\", for example.\n  This panel must be visible for the animation to work, Note (1).\n- select \"Abs displacement\", for example.\n- click the radio button \"Displacement/Show\"\n- click on \"Start Animation\" in the widget.\n\nThe entries in the widget are:\n- \"scale\" - scale for the displacements, 1 to 999, this may be a problem if the\n  displacements are very large/small before scaling.\n- \"factor\" - enter the value for the scale, this is linked to \"scale\"\n- \"number of steps...\" - the number of steps in 1 vibratory cycle, if this\n  value is increased the apparent speed of the animation will slow down.\n- \"steps/second\" - the number of steps displayed per second, if this value is\n  increased the animation will speed up.\n- \"number of cycles\" - the number of cycles in the animation.\n- \"Start Animation\" - starts the animation, this changes to \"Stop Animation\"\n  during the animation.\n\nNote(1) - if you click on \"Results_mesh001\", and start animation you may\n  possibly be animating the wrong mode shape.\n\"\"\"\n\nimport math\nimport os\nimport time\n\nimport FreeCAD as app\n\nimport FreeCADGui as gui\n\nfrom PySide import QtGui  # FreeCAD's PySide!\n\n__Name__ = 'Animate Mode Shapes for FEM'\n__Comment__ = 'Animate mode shapes after running CalculiX'\n__Author__ = 'mac_the_bike,galou'\n__Version__ = '1.0.1'\n__Date__ = '2022-02-04'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'https://forum.freecadweb.org/viewtopic.php?t=39081'\n__Wiki__ = ''\n__Icon__ = ''\n__Help__ = ''\n__Status__ = ''\n__Requires__ = ''\n__Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'\n__Files__ = 'fem_animate_mode_shapes.ui'\n\n# Items in the widget window:\n# - startEndButton\n# - amplitude\n# - factor\n# - steps\n# - steps/second is coded as frames/second\n# - loops\n\n\nclass FemAnimateModeShapes():\n    def __init__(self):\n        self.do_animation = False\n        self.ui_file = os.path.join(app.getUserMacroDir(True),\n                                    'fem_animate_mode_shapes.ui')\n        self.inc = 1  # TODO: find a better name and use.\n\n        self.form = gui.PySideUic.loadUi(self.ui_file)\n        self._connect_widgets()\n        self.form.show()\n        self.box = self._message_box()\n\n    def _connect_widgets(self):\n        self.form.startEndButton.clicked.connect(self.start_stop)\n        self.form.amplitude.valueChanged.connect(self._on_amplitude_changed)\n        self.form.factor.valueChanged.connect(self._on_factor_changed)\n\n    def start(self):\n        self.do_animation = True\n        self._do_animate()\n\n    def start_stop(self):\n        if self.do_animation:\n            self.do_animation = False\n        else:\n            self.do_animation = True\n            self._do_animate()\n\n    def _on_amplitude_changed(self):\n        if self.inc == 0:\n            self.form.factor.setValue(self.form.amplitude.value())\n        self.inc = 1 - self.inc\n\n    def _on_factor_changed(self):\n        if self.inc == 0:\n            self.form.amplitude.setValue(int(self.form.factor.value()))\n        self.inc = 1 - self.inc\n\n    def _message_box(self):\n        box = QtGui.QMessageBox()\n        box.setWindowTitle('No Results')\n        box.setText('Select a case and select a displacement type, e.g. Abs')\n        box.setInformativeText('Tick the displacement radio button')\n        box.setStandardButtons(QtGui.QMessageBox.Ok)\n        box.setDefaultButton(QtGui.QMessageBox.Save)\n        return box\n\n    def _do_animate(self):\n        if not self.do_animation:\n            return\n        try:\n            mesh_obj = app.FEM_dialog['result_obj']\n            mesh_obj.Mesh.ViewObject.applyDisplacement(0)\n        except:\n            self.box.exec_()\n            self.do_animation = False\n            return\n\n        self.form.startEndButton.setText('Stop Animation')\n\n        frame_count = self.form.frames.value()\n        steps = self.form.steps.value()\n        loops = self.form.loops.value()\n        inc = 2 * math.pi / steps\n\n        done = False\n        for lo in range(loops):\n            for st in range(steps):\n                mesh_obj.Mesh.ViewObject.applyDisplacement(\n                    math.sin(inc * st) * self.form.factor.value())\n                gui.updateGui()\n                if not self.do_animation:\n                    done = True\n                    break\n                time.sleep(1. / frame_count)\n            if done:\n                break\n        self.form.startEndButton.setText('Start Animation')\n        self.do_animation = False\n\n\nif __name__ == '__main__':\n    FemAnimateModeShapes()\n",
    "url": "https://forum.freecadweb.org/viewtopic.php?t=39081",
    "raw_code_url": "",
    "wiki": "",
    "version": "1.0.1",
    "license": "",
    "date": "2022-02-04",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\FEM\\FemAnimateModeShapes.FCMacro",
    "filename_from_url": "",
    "author": "mac_the_bike,galou",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "fem_animate_mode_shapes.ui"
    ],
    "parsed": true
  },
  {
    "name": "Export2Slicer",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Export selected objects to amf/stl files and open them in slicing program",
    "code": "# -*- coding: utf-8 -*-\n# Opens current visible objects in Slic3r. One can use different slicing software\n\n__Title__ = '3D Print / Slice'\n__Author__ = 'Damian \u0141ozi\u0144ski'\n__Version__ = '0.4.1'\n__Date__ = '2024-08-28'\n__Comment__ = 'Export selected objects to amf/stl files and open them in slicing program'\n__Web__ = 'https://github.com/dlozinski/FreeCAD-macros/blob/doc/ImportExport/ExportToSlicer.md'\n__Wiki__ = ''\n__Icon__ = 'Export2Slicer.png'\n__Help__ = 'You may need to change slicer path. To do so open Tools > Edit parameters > BaseApp/Preferences/Macros/Export2Slicer'\n__Status__ = 'Stable'\n__Requires__ = 'freecad 0.17+'\n__Communication__ = 'lozinski dot d at gmail dot com'\n__Files__ = 'Export2Slicer.png'\n\nimport os\nimport re\nfrom subprocess import Popen\nimport shlex\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nimport Mesh\nimport MeshPart\n\n\nMACRO_PARAMS = app.ParamGet('User parameter:BaseApp/Preferences/Macros/Export2Slicer')\nDEFAULT_SLICER_CMD = '\"/Applications/Original Prusa Drivers/PrusaSlicer.app/Contents/MacOS/PrusaSlicer\" --single-instance \"{file}\"'\nDEFAULT_OUTPUT_FORMAT = 'amf'\nDEFAULT_ANGULAR_DEFLECTION = 0.07\n\n\ndef get_string_param(name, default):\n    value = MACRO_PARAMS.GetString(name)\n    if not value:\n        MACRO_PARAMS.SetString(name, default)\n        value = default\n    return value\n\n\ndef get_float_param(name, default):\n    value = MACRO_PARAMS.GetFloat(name)\n    if not value:\n        MACRO_PARAMS.SetFloat(name, default)\n        value = default\n    return value\n\n\nslicer_cmd = get_string_param('SlicerCommand', DEFAULT_SLICER_CMD)\noutput_format = get_string_param('OutputFormat', DEFAULT_OUTPUT_FORMAT)\nangular_deflection = get_float_param('AngularDeflection', DEFAULT_ANGULAR_DEFLECTION)\n\n\ndef escape(text):\n    return re.sub(r'\\W', '_', text)\n\n\ndef get_mesh_filename(doc_filename, mesh_names):\n    \"\"\"Returns valid filename for temporary mesh file.\"\"\"\n    if doc_filename:\n        dirname = os.path.dirname(doc_filename)\n        filename = (\n            os.path.basename(doc_filename).partition('.')[0]\n            + '-'\n            + escape('_'.join(mesh_names))\n            + '.'\n            + output_format)\n        file_path = os.path.join(dirname, filename)\n    else:\n        file_path = 'meshes-export.' + output_format\n    return file_path\n\n\ndef main():\n    doc = app.activeDocument()\n    if not doc:\n        raise RuntimeError('Export2Slicer: No active document')\n\n    selection = gui.Selection.getSelectionEx()\n    objects_to_export = [x.Object for x in selection] or [doc.ActiveObject]\n    try:\n        # Create temporary doc to store meshes so that we don't affect current doc history\n        tmp_doc = app.newDocument('meshes_to_export', temp=True)\n        meshes = []\n        mesh_names = []\n        for o in objects_to_export:\n            if o.TypeId == 'Mesh::Feature':\n                meshes.append(o)\n            else:\n                mesh = tmp_doc.addObject('Mesh::Feature', f'{doc.Label}_{o.Label}')\n                mesh.Mesh = MeshPart.meshFromShape(o.Shape, LinearDeflection=0.1, AngularDeflection=angular_deflection, Relative=False)\n                meshes.append(mesh)\n                mesh_names.append(o.Label)\n        if meshes:\n            mesh_path = get_mesh_filename(doc.FileName, mesh_names)\n            Mesh.export(meshes, mesh_path)\n        else:\n            raise RuntimeError('Export2Slicer: No objects to export')\n    finally:\n        app.closeDocument('meshes_to_export')\n        for x in selection:\n            gui.Selection.addSelection(doc.Name, x.ObjectName)\n\n    # Launch Slicer with meshes\n    Popen(shlex.split(slicer_cmd.format(file=mesh_path)))\n    app.Console.PrintMessage(f'Export2Slicer: Objects exported into: {mesh_path}\\n')\n\n\ntry:\n    main()\nexcept Exception as e:\n    app.Console.PrintError('Export2Slicer: ERROR: {}\\n'.format(e))\n",
    "url": "https://github.com/dlozinski/FreeCAD-macros/blob/doc/ImportExport/ExportToSlicer.md",
    "raw_code_url": "",
    "wiki": "",
    "version": "0.4.1",
    "license": "",
    "date": "2024-08-28",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ImportExport\\Export2Slicer.FCMacro",
    "filename_from_url": "",
    "author": "Damian \u0141ozi\u0144ski",
    "icon": "Export2Slicer.png",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "Export2Slicer.png"
    ],
    "parsed": true
  },
  {
    "name": "FabricationCutlist",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "For designs made of Part WB Box and Cylinder primitives, creates a CSV cutlist.",
    "code": "# This macro aims to make it easy to create an accurate cutlist when you are going to fabricate something made out of rectangles and round bar.\n# For example, if you're welding together a gate from commercial mild steel, you are probably using square tubing, round bar and / or angle iron.\n# For all of these you can use Part WB's *Box* and *Cylinder* types.\n# Having done so, this macro will create a comma-separated set of values that make up your cutlist. The collumns are as follows:\n#   Timestamp: Just throw this away\n#   Label: The label you gave the part. Perhaps use this to indicate the role of the part in your design.\n#   Label2: The secondary label you gave the part. Perhaps use this to indicate the profile (\"roundbar\", \"squaretube\" etc)\n#   Dim1: For round bar, this is the diameter. For box shapes, this is one dimension of the profile size.\n#   Dim2: For round bar, this is blank. For box shapes this is the other dimension of the profile size.\n#   Length: How long this piece is.\n\n__Name__ = 'Fabrication Cutlist Maker'\n__Comment__ = 'For designs made of Part WB Box and Cylinder primitives, creates a CSV cutlist.'\n__Author__ = 'Johan Pretorius'\n__Date__ = '2024-08-28'\n__Version__ = '2024.8.10'\n__License__ = 'AAL'\n__Web__ = 'https://github.com/FreeCAD/FreeCAD-macros'\n__Wiki__ = ''\n__Icon__ = 'FabricationCutlist.png'\n__Xpm__ = ''\n__Help__ = 'Make your design out of \"Box\" and \"Cylinder\" primitives in Part WB. Then run the macro to get a cutlist in the Report View.'\n__Status__ = 'Stable'\n__Requires__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'\n__Communication__ = ''\n__Files__ = ''\n\nimport FreeCAD as app\n\ndoc = app.activeDocument()\nif doc:\n    objects = doc.Objects\n    warnings = []\n\n    app.Console.PrintMessage('------- CSV Cutlist Begins -------\\n')\n\n    for obj in objects:\n        label = obj.Label\n        label2 = obj.Label2\n\n        if (obj.TypeId == 'Part::Cylinder') and label2:\n            diameter = obj.Radius.Value * 2\n            length = obj.Height.Value\n            app.Console.PrintMessage(\n                    f', {label}, {label2}, {diameter}, , {length}\\n')\n        elif obj.TypeId == 'Part::Cylinder':\n            warnings.append(\n                    f'\"{label}\" not used, it is a Part::Cylinder object but has no Label2\\n')\n        elif (obj.TypeId == 'Part::Box') and label2:\n            size = [obj.Length.Value, obj.Width.Value, obj.Height.Value]\n            size.sort()\n            app.Console.PrintMessage(\n                    f', {label}, {label2}, {size[0]}, {size[1]}, {size[2]}\\n')\n        elif obj.TypeId == 'Part::Box':\n            warnings.append(\n                    f'\"{label}\" not used, it is a Part::Box object but has no Label2\\n')\n        else:\n            warnings.append(\n                    f'\"{label}\" not used, only considering Box and Cylinder objects\\n')\n\n    app.Console.PrintMessage('======= CSV Cutlist Completed =======\\n')\n\n    for w in warnings:\n        app.Console.PrintWarning(w)\n",
    "url": "https://github.com/FreeCAD/FreeCAD-macros",
    "raw_code_url": "",
    "wiki": "",
    "version": "2024.8.10",
    "license": "",
    "date": "2024-08-28",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ImportExport\\FabricationCutlist.FCMacro",
    "filename_from_url": "",
    "author": "Johan Pretorius",
    "icon": "FabricationCutlist.png",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "ObjectsToPython",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Exports objects from a FreeCAD project to a python script",
    "code": "# -*- coding: utf-8 -*-\n\n__Version__ = '0.7.6'\n__Date__ = '2025-01-09'\n__License__ = 'LGPL-3.0-or-later'\n__Web__ = ''\n__Wiki__ = 'README.md'\n__Name__ = 'Objects To Python'\n__Comment__ = 'Exports objects from a FreeCAD project to a python script'\n__Author__ = 'Christi'\n__Icon__ = 'ObjectsToPython.svg'\n__Help__ = 'ObjectsToPython/README.md'\n__Status__ = 'Alpha'\n__Requires__ = 'FreeCAD >= 0.19'\n__Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=22&t=34612'\n__Files__ = 'ObjectsToPython/README.md,ObjectsToPython/ObjectsToPython.ui,ObjectsToPython.svg'\n\nimport os\nimport re\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nimport Part\nfrom FreeCAD import Vector, Placement\n\n\ndef exportObjectsToPython(doc=None):\n    if doc is None:\n        doc = app.activeDocument()\n\n    add_script_line('from FreeCAD import Vector, Placement, Rotation')\n    add_script_line('import Sketcher')\n    add_script_line('import Part')\n    add_script_line('import FreeCAD as app')\n    objectlist = []\n    skip_objects = [\n        ('App::Line', 'X_Axis'),\n        ('App::Line', 'Y_Axis'),\n        ('App::Line', 'Z_Axis'),\n        ('App::Plane', 'XY_Plane'),\n        ('App::Plane', 'XZ_Plane'),\n        ('App::Plane', 'YZ_Plane'),\n        ('App::Origin', 'Origin'),\n    ]\n\n    selection = gui.Selection.getSelection()\n    if not selection:\n        selection = doc.Objects\n    else:\n        expandSelection(selection)\n\n    for obj in doc.Objects:\n        objectlist.append(doc.getObject(obj.Name))\n\n    for obj in selection:\n        if obj.TypeId == 'Sketcher::SketchObject':\n            add_script_line('')\n            add_script_line(f'def createSketch_{varname(obj)}(doc):')\n            addObject(doc, obj, objectlist)\n            add_body_line('return ' + varname(obj))\n\n    add_script_line('')\n    add_script_line('')\n    add_script_line(f'def make_{doc.Name}():')\n    if not selection:\n        add_body_line(f\"doc = app.newDocument('{doc.Name}')\")\n    else:\n        add_body_line('doc = app.activeDocument()')\n\n    for obj in selection:\n        if (obj.TypeId, obj.Label) not in skip_objects:\n            add_script_line('')\n            if obj.TypeId == 'Sketcher::SketchObject':\n                add_body_line(f'{varname(obj)} = createSketch_{varname(obj)}(doc)')\n            else:\n                addObject(doc, obj, objectlist)\n\n    for obj in selection:\n        if obj.TypeId == 'PartDesign::Body':\n            add_script_line('')\n            add_body_line(f'{varname(obj)}.Group = {varname(obj)}_Group')\n            if obj.Tip:\n                add_body_line(f'{varname(obj)}.Tip = {varname(obj.Tip)}')\n\n    add_body_line('')\n    add_body_line('doc.recompute()')\n    add_script_line('')\n    add_script_line('')\n    add_script_line(f'make_{doc.Name}()')\n\n\ndef varname(obj):\n    forbidden = [' ', '.', ',', '%', '+', '-', '*',\n                 '/', '(', ')', '[', ']', '=', '\"', \"'\"]\n    l = obj.Label\n    for f in forbidden:\n        l = l.replace(f, '_')\n\n    if l[0].isdigit():\n        l = '_' + l\n    return l\n\n\ndef add_script_line(line, indent=0):\n    spaces = ' ' * 4 * indent\n    dialog.form.textEdit.append(spaces + line)\n\n\ndef add_body_line(line, indent=1):\n    add_script_line(line, indent)\n\n\ndef expandSelection(selection):\n    addthis = []\n    for obj in selection:\n        if hasattr(obj, 'Group'):\n            addthis += obj.Group\n        if hasattr(obj, 'Source'):\n            addthis.append(obj.Source)\n        if hasattr(obj, 'Links'):\n            addthis += obj.Links\n\n    addcount = 0\n    for a in addthis:\n        if ((a not in selection)\n                and hasattr(obj, 'Name')\n                and hasattr(obj, 'TypeId')):\n            selection.insert(0, a)\n            addcount = addcount + 1\n\n    if addcount > 0:\n        expandSelection(selection)\n\n\ndef addObject(doc, obj, objectlist):\n    objname = varname(obj)\n    add_body_line(f\"{objname} = doc.addObject('{obj.TypeId}', '{objname}')\")\n    defaultobj = doc.addObject(obj.TypeId, obj.Name + 'Default')\n    addProperties(obj, objname, defaultobj, objectlist)\n    addProperties(obj.ViewObject, objname + '.ViewObject',\n                  defaultobj.ViewObject, [])\n    doc.removeObject(obj.Name + 'Default')\n\ndef addProperties(obj, objname, refobj, objectlist):\n    skipProperties = ['Label', 'Shape', 'Proxy',\n                      'AddSubShape', 'FullyConstrained', 'VisualLayerList',\n                     'InternalShape', 'ShapeMaterial', 'ShapeAppearance', 'MaterialName',\n                     'SuppressedShape']\n\n    skipObjProp = [\n        ('Sketcher::SketchObject', 'Geometry'),\n        ('Sketcher::SketchObject', 'Constraints'),\n        ('PartDesign::Body', 'Origin'),\n        ('PartDesign::Body', 'Tip'),\n    ]\n\n    # Cf. https://github.com/FreeCAD/FreeCAD/blob/278ce803907ef72548d7ac761613038ac435c481/src/App/Property.h#L60\n    statuslist = [\n            'Immutable', 1,\n            'ReadOnly', 2,\n            'PropReadOnly', 24,\n            'PropOutput', 27,\n    ]\n\n    def propIsReadonly(obj, propname):\n        statusnums = obj.getPropertyStatus(propname)\n        for status in statuslist:\n            if status in statusnums:\n                return True\n        return False\n\n    if obj.TypeId == 'Spreadsheet::Sheet':\n        addSpreadsheet(obj, objname)\n        return\n\n    if obj.TypeId == 'Sketcher::SketchObject':\n        addSketch(obj, objname)\n\n    for propname in obj.PropertiesList:\n        if (propname not in skipProperties)\\\n            and ((obj.TypeId, propname) not in skipObjProp)\\\n            and not propIsReadonly(obj, propname):\n            prop = obj.getPropertyByName(propname)\n            val = objectToText(prop, objectlist)\n\n            try:\n                refprop = refobj.getPropertyByName(propname)\n                defaultval = objectToText(refprop, objectlist)\n            except:\n                defaultval = None\n\n            if propname == 'Support':\n                val = val.replace('XY_Plane', 'doc.XY_Plane')\n                val = val.replace('XZ_Plane', 'doc.XZ_Plane')\n                val = val.replace('YZ_Plane', 'doc.YZ_Plane')\n\n            if propname == 'ExpressionEngine':\n                for expression in prop:\n                    add_body_line(objname + '.setExpression' +\n                                  str(expression).replace('<', '').replace('>', ''))\n\n            elif propname == '_Body':\n                add_body_line(f'{val}_Group.append({objname})')\n\n            elif (obj.TypeId, propname) == ('PartDesign::Body', 'Group'):\n                add_body_line(f'{objname}_Group = []')\n\n            elif (obj.TypeId, propname) == ('App::Part', 'Group'):\n                proplist = []\n                for pn in prop:\n                    proplist.append(varname(pn))\n\n                add_body_line(objname + '.Group = ' + str(proplist))\n\n            elif objectToText(prop, objectlist) is not None:\n                if val != defaultval:\n                    add_body_line(f'{objname}.{propname} = {val}')\n\n\ndef objectToText(obj, objectlist=None):\n    if objectlist is None:\n        objectlist = []\n    if obj in objectlist:\n        return obj.Label\n\n    # how can I test if type(obj) is Base.Quantity ?\n    if hasattr(obj, 'Value') and hasattr(obj, 'Unit'):\n        return str(obj.Value)\n\n    if isinstance(obj, str):\n        return f\"'{obj}'\"\n\n    if isinstance(obj, bool):\n        return 'True' if obj else 'False'\n\n    if isinstance(obj, int):\n        return str(obj)\n\n    if isinstance(obj, float):\n        return floatstr(obj)\n\n    if isinstance(obj, Placement):\n        return f'Placement({objectToText(obj.Base)}, {objectToText(obj.Rotation)})'\n\n    if isinstance(obj, Part.Point):\n        return f'Part.Point(Vector({floatstr(obj.X)}, {floatstr(obj.Y)}, {floatstr(obj.Z)}))'\n\n    if isinstance(obj, Part.LineSegment):\n        return f'Part.LineSegment({obj.StartPoint}, {obj.EndPoint})'\n\n    if isinstance(obj, Part.Circle):\n        return f'Part.Circle({vecstr(obj.Center)}, {obj.Axis}, {floatstr(obj.Radius)})'\n\n    if isinstance(obj, Part.ArcOfCircle):\n        return f'Part.ArcOfCircle({objectToText(obj.Circle)}, {obj.FirstParameter}, {obj.LastParameter})'\n\n    if isinstance(obj, Part.Ellipse):\n        return f'Part.Ellipse({vecstr(obj.Center)}, {obj.MajorRadius}, {obj.MinorRadius})'\n\n    if isinstance(obj, Part.BSplineCurve):\n        poles = ''\n        komma = False\n        for p in obj.getPoles():\n            if komma:\n                poles += ', '\n            poles += vecstr(p)\n            komma = True\n\n        return f'Part.BSplineCurve([{poles}])'\n\n    if isinstance(obj, Part.Parabola):\n        return f'Part.Parabola({vecstr(obj.Focus)}, {vecstr(obj.Location)}, {vecstr(obj.Axis)})'\n\n    if isinstance(obj, Part.Hyperbola):\n        return f'Part.Hyperbola({vecstr(obj.Center)}, {obj.MajorRadius}, {obj.MinorRadius})'\n\n    if isinstance(obj, Part.ArcOfEllipse):\n        return f'Part.ArcOfEllipse({objectToText(obj.Ellipse)}, {obj.FirstParameter}, {obj.LastParameter})'\n\n    if isinstance(obj, Part.ArcOfParabola):\n        return f'Part.ArcOfParabola({objectToText(obj.Parabola)}, {obj.FirstParameter}, {obj.LastParameter})'\n\n    if isinstance(obj, Part.ArcOfHyperbola):\n        return f'Part.ArcOfHyperbola({objectToText(obj.Hyperbola)}, {obj.FirstParameter}, {obj.LastParameter})'\n\n    if isinstance(obj, Vector):\n        return vecstr(obj)\n\n    liststart = ''\n    if isinstance(obj, list):\n        liststart = '['\n        listend = ']'\n\n    if isinstance(obj, tuple):\n        liststart = '('\n        listend = ')'\n\n    if liststart != '':\n        sline = liststart\n        comma = False\n        for listele in obj:\n            if comma:\n                sline = sline + ', '\n            else:\n                comma = True\n\n            val = objectToText(listele, objectlist)\n            if val is not None:\n                sline = sline + val\n\n        sline += listend\n        return sline\n\n    stringobj = str(obj)\n    return stringobj\n\n\ndef addSketch(obj, objname):\n    prop = obj.getPropertyByName('Geometry')\n    gflist = obj.GeometryFacadeList\n\n    n = 0\n    exposing = 0\n    exposed = []\n    for geo in prop:\n        objstr = objectToText(geo)\n\n        if exposing > 0:\n            exposed.append(n)\n            exposing = exposing - 1\n        else:\n            add_body_line(f'geo{n} = {objname}.addGeometry({objstr})')\n            if gflist[n].Construction:\n                add_body_line(f'{objname}.toggleConstruction(geo{n})')\n\n            if isinstance(geo, Part.BSplineCurve):\n                poles = len(geo.getPoles())\n                exposing = poles - 2\n                if exposing < 2:\n                    exposing = 2\n\n            if isinstance(geo, Part.ArcOfParabola):\n                exposing = 2\n\n            if isinstance(geo, Part.ArcOfHyperbola):\n                exposing = 3\n\n            if isinstance(geo, Part.ArcOfEllipse):\n                exposing = 4\n\n        n = n + 1\n\n    splinecount = 0\n    concount = 0\n    prop = obj.getPropertyByName('Constraints')\n    for con in obj.Constraints:\n        conargs = con.Value\n        contype = con.Type\n        if con.First < 0:\n            first = str(con.First)\n        else:\n            first = f'geo{con.First}'\n\n        if con.Second < 0:\n            sec = str(con.Second)\n        else:\n            sec = f'geo{con.Second}'\n\n        if con.Third < 0:\n            third = str(con.Third)\n        else:\n            third = f'geo{con.Third}'\n\n        if con.Type == 'Coincident':\n            conargs = f'{first}, {con.FirstPos}, {sec}, {con.SecondPos}'\n        elif con.Type == 'PointOnObject':\n            conargs = f'{first}, {con.FirstPos}, {sec}'\n\n        elif con.Type == 'Vertical':\n            if sec[:3] == 'geo':\n                # Two points.\n                conargs = f'{first}, {con.FirstPos}, {sec}, {con.SecondPos}'\n            else:\n                # Line.\n                conargs = str(first)\n\n        elif con.Type == 'Horizontal':\n            if sec[:3] == 'geo':\n                # Two points.\n                conargs = f'{first}, {con.FirstPos}, {sec}, {con.SecondPos}'\n            else:\n                # Line.\n                conargs = str(first)\n        elif con.Type == 'Parallel':\n            conargs = f'{first}, {sec}'\n\n        elif con.Type == 'PerpendicularViaPoint':\n            conargs = f'{first}, {sec}, {third}, {con.ThirdPos}'\n        elif con.Type == 'Perpendicular':\n            if con.FirstPos == 0:\n                conargs = f'{first}, {sec}'\n            elif third[:3] == 'geo':\n                contype = 'PerpendicularViaPoint'  # compatiblity to FreeCAD 2.20\n                conargs = f'{first}, {sec}, {third}, {con.ThirdPos}'\n            elif con.SecondPos == 0:\n                conargs = f'{first}, {con.FirstPos}, {sec}'\n            else:\n                conargs = f'{first}, {con.FirstPos}, {sec}, {con.SecondPos}'\n\n        elif con.Type == 'TangentViaPoint':\n            conargs = f'{first}, {sec}, {third}, {con.ThirdPos}'\n        elif con.Type == 'Tangent':\n            if con.Second < 0:\n                conargs = f'{first}, {con.FirstPos}'\n            elif third[:3] == 'geo':\n                contype = 'TangentViaPoint'  # compatiblity to FreeCAD 2.20\n                conargs = f'{first}, {sec}, {third}, {con.ThirdPos}'\n            elif con.SecondPos == 0:\n                conargs = f'{first}, {con.FirstPos}, {sec}'\n            else:\n                conargs = f'{first}, {con.FirstPos}, {sec}, {con.SecondPos}'\n\n        elif con.Type == 'Equal':\n            conargs = f'{first}, {sec}'\n\n        elif con.Type == 'Symmetric':\n            conargs = f'{first}, {con.FirstPos}, {sec}, {con.SecondPos}, {third}, {con.ThirdPos}'\n        elif con.Type == 'Block':\n            conargs = str(first)\n\n        elif con.Type == 'Distance':\n            if sec[:3] != 'geo':\n                conargs = f'{first}, {floatstr(con.Value)}'\n            elif con.FirstPos == 0:\n                conargs = f'{first}, {sec}, {floatstr(con.Value)}'\n            elif con.SecondPos == 0:\n                conargs = f'{first}, {con.FirstPos}, {sec}, {floatstr(con.Value)}'\n            else:\n                conargs = f'{first}, {con.FirstPos}, {sec}, {con.SecondPos}, {floatstr(con.Value)}'\n        elif con.Type == 'DistanceX' or con.Type == 'DistanceY':\n            if sec[:3] != 'geo':\n                conargs = f'{first}, {con.FirstPos}, {floatstr(con.Value)}'\n            else:\n                conargs = f'{first}, {con.FirstPos}, {sec}, {con.SecondPos}, {floatstr(con.Value)}'\n\n        elif con.Type == 'AngleViaPoint':\n            conargs = f'{first}, {sec}, {third}, {floatstr(con.Value)}'\n        elif con.Type == 'Angle':\n            if con.FirstPos == 0:\n                conargs = f'{first}, {sec}, {floatstr(con.Value)}'\n            elif third[:3] == 'geo':\n                contype = 'AngleViaPoint'  # compatiblity to FreeCAD 2.20\n                conargs = f'{first}, {sec}, {third}, {floatstr(con.Value)}'\n            else:\n                conargs = f'{first}, {con.FirstPos}, {sec}, {con.SecondPos}, {floatstr(con.Value)}'\n\n        elif con.Type == 'Weight' or con.Type == 'Radius' or con.Type == 'Diameter':\n            conargs = f'{first}, {floatstr(con.Value)}'\n            splinecount = 0\n\n        elif con.Type == 'InternalAlignment':\n            if con.Second > con.First:\n                contype = 'InternalAlignment:Sketcher::BSplineControlPoint'\n                conargs = f'{first}, {con.FirstPos}, {sec}, {splinecount}'\n                splineindex = con.Second\n                splinecount = splinecount + 1\n            else:\n                conargs = None\n\n        if conargs is not None:\n            add_body_line(\n                f\"{objname}.addConstraint(Sketcher.Constraint('{contype}', {conargs}))\")\n\n        if con.Name != \"\":\n            add_body_line(f\"{objname}.renameConstraint({concount}, '{con.Name}')\")\n\n        concount = concount + 1\n\n\ndef addSpreadsheet(obj, objname):\n    for propname in obj.PropertiesList:\n        match = re.search('[A-Z]+[0-9]+', propname)\n        if match:\n            prop = obj.getPropertyByName(propname)\n            val = objectToText(prop)\n            add_body_line(\"{}.set('{}', {})\".format(\n                objname, propname, val.replace(\"'\", '')))\n            alias = obj.getAlias(propname)\n            if alias is not None:\n                add_body_line(f\"{objname}.setAlias('{propname}', '{alias}')\")\n\n    add_body_line('doc.recompute()')\n\n\ndef floatstr(f):\n    # return '{:.2f}'.format(f)\n    return str(f)\n\n\ndef vecstr(v):\n    return f'Vector({floatstr(v.x)}, {floatstr(v.y)}, {floatstr(v.z)})'\n\n\nclass O2PDialog:\n    \"\"\"Show a dialog for ObjectsToPython\"\"\"\n\n    def __init__(self):\n        macro_dir = app.getUserMacroDir(True)\n        self.ui_file = os.path.join(\n            macro_dir, 'ObjectsToPython/ObjectsToPython.ui')\n        self.form = gui.PySideUic.loadUi(self.ui_file)\n        self.form.pushButtonClose.pressed.connect(self.close_callback)\n        self.form.show()\n\n    def close_callback(self):\n        self.form.close()\n\n\ndialog = O2PDialog()\nexportObjectsToPython()\n",
    "url": "",
    "raw_code_url": "",
    "wiki": "README.md",
    "version": "0.7.6",
    "license": "",
    "date": "2025-01-09",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ImportExport\\ObjectsToPython.FCMacro",
    "filename_from_url": "",
    "author": "Christi",
    "icon": "ObjectsToPython.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "ObjectsToPython/README.md",
      "ObjectsToPython/ObjectsToPython.ui",
      "ObjectsToPython.svg"
    ],
    "parsed": true
  },
  {
    "name": "CenterOfMass",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Compute and show the center of mass for multiple solids",
    "code": "#!/usr/bin/env python\n# coding: utf-8\n#\n# Compute and show the center of mass for multiple solids\n#\n# Usage:\n# 1. Select one or multiple solids.\n# 2. Launch the macro.\n# 3. You'll have a window listing the solids. You can put the density of your\n#    material in different unit systems or choose from predefined materials.\n#\n# Options:\n# * Color the solids according to density.\n# * Display where is the center of mass.\n# * Export and import masses, materials and densities (even if it's not a .csv\n#  file from the macro, as soon as there is a column named accordingly).\n# * Save densities in the document (remove them again when setting material\n#  to \"default\")\n#\n# Credits:\n# 2018 - 2022: schupin\n# 2022 - 2024: SyProLei project (Saarland University)\n# 2025: farahats9, s-quirin (former SyProLei project)\n#\n\n__Name__ = 'CenterOfMass'\n__Comment__ = 'Compute and show the center of mass for multiple solids'\n__Author__ = 'chupins, s-quirin, farahats9'\n__Version__ = '0.8.3'\n__Date__ = '2025-01-21'\n__License__ = 'LGPL-3.0-or-later'\n__Web__ = 'https://forum.freecad.org/viewtopic.php?f=24&t=31883'\n__Wiki__ = 'https://wiki.freecad.org/Macro_CenterOfMass'\n__Icon__ = 'https://wiki.freecad.org/images/a/a6/Macro_CenterOfMass.svg'\n__Help__ = 'Select one or more bodies and launch'\n__Status__ = 'Alpha'\n__Requires__ = 'FreeCAD >= 0.20'\n__Communication__ = 'https://forum.freecad.org/viewtopic.php?f=24&t=31883'\n__Files__ = ''\n\n# Todo:\n# - error with draft array of meshes (relevant?)\n# Ideas:\n# - moments of inertia with arrows that allow the user to see the relative magnitudes\n\nimport copy\nimport csv\nimport math\nimport os\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nimport numpy as np\nfrom FreeCAD import Units\nfrom PySide import QtCore, QtGui  # FreeCAD's PySide!\n\n# Preferences\nMAXIMUM_DENSITY = '25000 kg/m^3'    # maximum physically meaningful value\nVALUE_DELIMITER = '\\t'              # delimiter-separated values format: Tab\n\n# FreeCAD: Tools -> Edit Parameters, 2nd parameter of .GetX sets the default\nMACRO_SETTINGS = 'User parameter:BaseApp/Preferences/Macros/' + __Name__\nDEFAULT_DENSITY = app.ParamGet(MACRO_SETTINGS).GetString('Default density', '2500 kg/m^3')\nDOCKED_WINDOW = app.ParamGet(MACRO_SETTINGS).GetBool('Docked window', True)    # False: floating\nSORT_SELECTION = app.ParamGet(MACRO_SETTINGS).GetBool('Sort selection', False)\nCOLOR_SPHERES = app.ParamGet(MACRO_SETTINGS).GetBool('Color spheres', False)\nCOLOR_SATURAT = app.ParamGet(MACRO_SETTINGS).GetUnsigned('Color saturation', 80)\nCOLORMAP_USER = app.ParamGet(MACRO_SETTINGS).GetString('Matplotlib colormap', 'Spectral_r')\nGUI_FONT_SIZE = app.ParamGet('User parameter:BaseApp/Preferences/Editor').GetInt('FontSize', 10)\nGUI_ICON_SIZE = app.ParamGet('User parameter:BaseApp/Preferences/General').GetInt('ToolbarIconSize', 24)\nGUI_THEME = app.ParamGet('User parameter:BaseApp/Preferences/MainWindow').GetString('Theme', '')\n\nMATERIAL_SETTINGS = app.ParamGet('User parameter:BaseApp/Preferences/Mod/Material/Resources')\nUSE_BUILT_IN_MATERIALS = MATERIAL_SETTINGS.GetBool('UseBuiltInMaterials', True)\nUSE_MAT_FROM_CONFIG_DIR = MATERIAL_SETTINGS.GetBool('UseMaterialsFromConfigDir', True)\nUSE_MAT_FROM_CUSTOM_DIR = MATERIAL_SETTINGS.GetBool('UseMaterialsFromCustomDir', True)\nCUSTOM_MAT_DIR = MATERIAL_SETTINGS.GetString('CustomMaterialsDir', '')\n\n# Floating window size preferences: fraction of primary screen's size\nWINDOW_WIDTH = int(0.2 * QtGui.QGuiApplication.screens()[0].geometry().width())\nWINDOW_HEIGHT = int(0.5 * QtGui.QGuiApplication.screens()[0].geometry().height())\n\nFREECAD_VERSION = float(f'{app.Version()[0]}.{app.Version()[1]}')\n\nif FREECAD_VERSION < 0.21:\n    # FreeCAD 0.20 is able to run with Qt 5.9.5 but Qt 5.12 was adopted here\n    if QtCore.QLibraryInfo.version() < QtCore.QVersionNumber(5, 12):\n        app.Console.PrintWarning('Qt 5.12 or higher is needed to run\\n')\n\napp.ParamGet(MACRO_SETTINGS).SetString('Default density', DEFAULT_DENSITY)\napp.ParamGet(MACRO_SETTINGS).SetBool('Docked window', DOCKED_WINDOW)\napp.ParamGet(MACRO_SETTINGS).SetBool('Sort selection', SORT_SELECTION)\napp.ParamGet(MACRO_SETTINGS).SetBool('Color spheres', COLOR_SPHERES)\napp.ParamGet(MACRO_SETTINGS).SetUnsigned('Color saturation', COLOR_SATURAT)\napp.ParamGet(MACRO_SETTINGS).SetString('Matplotlib colormap', COLORMAP_USER)\ng_main_window = gui.getMainWindow()\ng_font = g_main_window.font()\ng_font.setPointSize(GUI_FONT_SIZE)\ng_font_metrics = QtGui.QFontMetrics(g_font)\ng_str_width = g_font_metrics.horizontalAdvance('_0_000e+00_')\ng_icon_size = QtCore.QSize(GUI_ICON_SIZE, GUI_ICON_SIZE)\ng_sel_user = []    # the user list of selected objects\ng_sel = []    # the valid list of selected objects\n\n\nclass CenterofmassDock(QtGui.QDockWidget):\n    \"\"\"if DOCKED_WINDOW = True\"\"\"\n\n    def __init__(self):\n        super().__init__()\n        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)    # free memory\n        self.setLocale(QtCore.QLocale.English)\n        self.child = CenterofmassWidget(self)\n        self.setWidget(self.child)\n        g_main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, self)\n\n\nclass CenterofmassWindow(QtGui.QMainWindow):\n    \"\"\"if DOCKED_WINDOW = False\"\"\"\n\n    def __init__(self, parent=g_main_window):\n        super().__init__(parent)    # parent: Window stays on top\n        self.setLocale(QtCore.QLocale.English)\n        self.child = CenterofmassWidget(self)\n        self.setCentralWidget(self.child)\n        self.set_position()\n        self.show()\n\n    def set_position(self):\n        \"\"\"Set a sensible default position for the window.\n        With FreeCAD's default layout, this will be over the Combo View.\n        \"\"\"\n        geom = g_main_window.geometry()\n        xpos = geom.left() + 50\n        ypos = geom.center().y() - WINDOW_HEIGHT // 2\n        self.setGeometry(xpos, ypos, WINDOW_WIDTH, WINDOW_HEIGHT)\n\n\nclass SolidsWidget():\n    \"\"\"Rows in scroll area\"\"\"\n\n    def __init__(self, parent, solid, sol):\n        self.parent = parent\n        self.sol = sol\n        if hasattr(solid.ViewObject, 'ShapeColor'):\n            color = solid.ViewObject.ShapeColor\n        elif hasattr(solid.ViewObject, 'ShapeAppearance'):\n            # App::Link in FreeCAD 0.22\n            color = solid.ViewObject.ShapeAppearance[0].DiffuseColor\n        self.orgColorFC = color\n        self.orgColorQT = QtGui.QColor.fromRgbF(*color)\n        self.orgTransparency = solid.ViewObject.Transparency\n        self.labelC = QtGui.QLabel(' ', parent)\n        self.label = QtGui.QLabel(solid.Label, parent)\n        self.combo = QtGui.QComboBox(parent)\n        self.spinDens = QtGui.QDoubleSpinBox(parent)\n        self.spinMass = QtGui.QLineEdit(parent)\n\n        # init properties\n        self.labelC.setStyleSheet(\n            'QLabel {background-color: %s}' % self.orgColorQT.name())\n        self.labelC.setMaximumWidth(GUI_ICON_SIZE)\n        self.combo.addItem('custom')\n        self.combo.setMinimumContentsLength(14)    # auto size adjustment and truncation\n        d_min, d_max = parent.material_base_range\n        if d_min == d_max:\n            self.combo.addItems(parent.material_base)\n        else:\n            # icons filled according to density relation\n            qs = len(parent.pieIcon) - 1\n            for m in parent.material_base:\n                q = math.ceil((parent.material_base[m] - d_min) / (d_max - d_min) * qs)\n                self.combo.addItem(QtGui.QIcon(parent.pieIcon[q]), m)\n            self.combo.setItemIcon(1, QtGui.QIcon())    # no icon for 'default'\n        self.combo.insertSeparator(2)    # after custom+default\n        mat_name = getattr(g_sel[sol], 'Mat_Name', 'default')\n        mat_density = getattr(g_sel[sol], 'Mat_Density', parent.material_base['default'])\n        # class 'Base.Quantity' for saves with FreeCAD > 0.21, before: class 'str'\n        if hasattr(g_sel[sol], 'Material'):\n            if hasattr(g_sel[sol].Material, 'Material'):\n                # overwrite if Arch Material set\n                mat_name = g_sel[sol].Material.Material['CardName']\n                mat_density = g_sel[sol].Material.Material['Density']    # class 'str'\n        self.combo.setCurrentText(mat_name)    # not found: stays 0=custom\n        self.combo.currentIndexChanged.connect(self.on_comboMaterial_changed)\n        self.init_spinDensity(self.spinDens, Units.Quantity(mat_density), parent.unitForD)\n        self.spinDens.setToolTip(\n            'density of ' + solid.Label + ' (in ' + parent.unitForD_text + ')')\n        self.spinDens.valueChanged.connect(self.on_spinDensity_changed)\n        self.spinMass.setAlignment(QtCore.Qt.AlignCenter)\n        self.spinMass.setMinimumWidth(g_str_width)\n        self.spinMass.setMaximumWidth(g_str_width + GUI_FONT_SIZE)\n        self.spinMass.editingFinished.connect(self.on_spinMass_edited)\n\n        # layout grid\n        if sol == 0:\n            searchL = QtGui.QLineEdit(parent, placeholderText='Search...')\n            searchL.setClearButtonEnabled(True)\n            searchL.textEdited.connect(parent.on_searchL_edited)\n            label02 = QtGui.QLabel('Material', parent)\n            label03 = QtGui.QLabel('Density', parent)\n            label04 = QtGui.QLabel('Mass', parent)\n            parent.solidLayout.addWidget(searchL, sol, 1)\n            parent.solidLayout.addWidget(label02, sol, 2)\n            parent.solidLayout.addWidget(label03, sol, 3)\n            parent.solidLayout.addWidget(label04, sol, 4)\n        parent.solidLayout.addWidget(self.labelC, sol+1, 0)\n        parent.solidLayout.addWidget(self.label, sol+1, 1)\n        parent.solidLayout.addWidget(self.combo, sol+1, 2)\n        parent.solidLayout.addWidget(self.spinDens, sol+1, 3)\n        parent.solidLayout.addWidget(self.spinMass, sol+1, 4)\n        material = self.get_object_material(solid)\n        if material:\n            for i in range(self.combo.count()):\n                if material.Name == self.combo.itemText(i):\n                    self.combo.setCurrentIndex(i)\n                    break\n\n    def init_spinDensity(self, spin, qty, unitForD):\n        spinBoxDigits = 6\n        # don't trigger on_spinDensity_changed (e.g. when on_comboUnitDensity_changed)\n        spin.blockSignals(True)\n        spin.setRange(0., Units.Quantity(MAXIMUM_DENSITY).getValueAs(unitForD))\n        decimals = spinBoxDigits - math.floor(math.fabs(math.log10(spin.maximum())))\n        spin.setDecimals(decimals)\n        spin.setStepType(QtGui.QAbstractSpinBox.StepType.AdaptiveDecimalStepType)\n        spin.setValue(qty.getValueAs(unitForD))\n        spin.blockSignals(False)\n\n    def on_spinDensity_changed(self):\n        self.combo.setCurrentIndex(0)    # set to custom\n        self.parent.compute_centerOfMass()\n\n    def on_spinMass_edited(self):\n        parent = self.parent\n        if self.spinMass.text() == format(parent.masses[self.sol], '.3e'):\n            return    # there was no editing\n        v_ = QtGui.QDoubleValidator(0., 9.999e99, 3)\n        if v_.validate(self.spinMass.text(), 0)[0] == QtGui.QValidator.State.Invalid:\n            self.spinMass.undo()\n            if v_.validate(self.spinMass.text(), 0)[0] == QtGui.QValidator.State.Invalid:\n                self.spinMass.setText('0.000e00')\n            return    # input not in scientific notation\n        volumeInUnit = parent.convert_volume(parent.volumes[self.sol])\n        dens = float(self.spinMass.text()) / volumeInUnit\n        self.spinDens.setValue(dens)    # trigger on_spinDensity_changed\n\n    def on_comboMaterial_changed(self, newIndex):\n        materialName = self.combo.currentText()\n        qty = self.parent.material_base.get(materialName, 0)\n        if qty:\n            materialDensity = Units.Quantity(qty).getValueAs(self.parent.unitForD)\n            self.spinDens.blockSignals(True)\n            # don't trigger on_spinDensity_changed\n            self.spinDens.setValue(materialDensity)\n            self.spinDens.blockSignals(False)\n            self.parent.compute_centerOfMass()\n\n    @staticmethod\n    def get_object_material(solid):\n        \"\"\"Retrieves material properties, handling PartDesign features correctly.\"\"\"\n        material = None\n        if FREECAD_VERSION < 0.22:\n            return material\n        if hasattr(solid, \"ShapeMaterial\"):\n            material = solid.ShapeMaterial\n        elif hasattr(solid, \"getParentGroup\") and solid.getParentGroup():\n            for feature in solid.getParentGroup().Objects:\n                if hasattr(feature, \"ShapeMaterial\") and feature.ShapeMaterial:\n                    material = feature.ShapeMaterial\n                    break\n        return material\n\n\nclass CenterofmassWidget(QtGui.QWidget):\n    \"\"\"This is the widget which does almost all of the work.\n    Widgets don't have close boxes, so closing is dealt with in\n    CenterofmassWindow.\n    \"\"\"\n\n    def __init__(self, parent):\n        super().__init__(parent)\n        self.compute_enabled = None\n        self.setObjectName(__Name__)\n        parent.setWindowTitle(__Name__ + ' ' + __Version__)\n        parent.setFont(g_font)\n        self.doc = app.activeDocument()\n        self.material_base = {}\n        self.solid_count = 0\n        objs = self.valid_selection(gui.Selection.getSelection())\n        self.init_UI()\n        if self.solid_count <= 0:\n            self.setDisabled(True)\n            self.startup_dialog()\n        else:\n            self.init_solids(objs)\n\n    def startup_dialog(self):\n        \"\"\"Error dialog allowing a new selection\"\"\"\n        msg = 'Select a valid object (a solid or a mesh) first.'\n        app.Console.PrintError(msg + '\\n')\n        diag = QtGui.QMessageBox(QtGui.QMessageBox.Critical, 'Error', msg, parent=g_main_window)\n        diag.setModal(False)\n        diag.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)\n        diag.finished.connect(self.on_startup_dialog_finished)\n        diag.show()\n\n    def on_startup_dialog_finished(self, result):\n        if result == QtGui.QMessageBox.Ok:\n            objs = self.valid_selection(gui.Selection.getSelection())\n            if self.solid_count <= 0:\n                self.startup_dialog()\n            else:\n                self.init_solids(objs)\n                self.setDisabled(False)\n        else:\n            self.parentWidget().close()\n\n    def init_UI(self):\n        \"\"\"Lay out the interactive elements\"\"\"\n        # main layout\n        layout = QtGui.QVBoxLayout(self)\n\n        # titleLayout\n        toPreferences = QtGui.QPushButton(QtGui.QIcon(':/icons/Std_DlgParameter.svg'), '')\n        toPreferences.setToolTip('Preferences -> Macros')\n        toPreferences.clicked.connect(self.on_pushButton_toPreferences)\n\n        editMaterial = QtGui.QPushButton(QtGui.QIcon(':/icons/Arch_Material_Group.svg'), '')\n        editMaterial.setToolTip('Edit Material list')\n        editMaterial.clicked.connect(self.on_pushButton_editMaterial)\n\n        label_comboUnit = QtGui.QLabel('Density:')\n        label_comboUnit.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)\n\n        comboUnitDensity = QtGui.QComboBox(toolTip='Unit of density')\n        comboUnitDensity.addItems(['kg/m\u00b3',\n                                   'g/dm\u00b3', 'g/cm\u00b3',\n                                   'mg/mm\u00b3',\n                                   'oz/in\u00b3',\n                                   'lb/in\u00b3', 'lb/ft\u00b3', 'lb/yd\u00b3'])\n        comboUnitDensity.currentTextChanged.connect(self.on_comboUnitDensity_changed)\n        # Get units set as preference\n        self.store_prefered_units(comboUnitDensity.currentText())\n\n        label_defaultDensity = QtGui.QLabel('Default value:')\n        label_defaultDensity.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)\n\n        self.defaultDensitySpin = QtGui.QDoubleSpinBox(self)\n        SolidsWidget.init_spinDensity(self,\n                                      self.defaultDensitySpin,\n                                      Units.Quantity(DEFAULT_DENSITY),\n                                      self.unitForD)\n        self.defaultDensitySpin.setMinimum(math.pow(10, -self.defaultDensitySpin.decimals()))\n        self.defaultDensitySpin.setToolTip(\n            'set default density (in ' + self.unitForD_text + ')')\n        self.defaultDensitySpin.valueChanged.connect(self.on_spinDefaultDensity_changed)\n        self.material_base['default'] = Units.Quantity(DEFAULT_DENSITY)\n\n        allToDefaultDensity = QtGui.QPushButton(QtGui.QIcon(':/icons/Std_Revert.svg'), ' to all')\n        allToDefaultDensity.setToolTip('Set all solids to default density')\n        allToDefaultDensity.clicked.connect(self.on_pushButton_allToDefaultDensity)\n\n        titleLayoutBox = QtGui.QGroupBox('Preferences')\n        titleLayout = QtGui.QHBoxLayout()\n        titleLayout.addWidget(toPreferences)\n        titleLayout.addWidget(editMaterial)\n        titleLayout.addWidget(label_comboUnit)\n        titleLayout.addWidget(comboUnitDensity)\n        titleLayout.addSpacing(GUI_FONT_SIZE)\n        titleLayout.addWidget(label_defaultDensity)\n        titleLayout.addWidget(self.defaultDensitySpin)\n        titleLayout.addWidget(allToDefaultDensity)\n        titleLayoutBox.setLayout(titleLayout)\n        layout.addWidget(titleLayoutBox)\n\n        # solidGroupBox\n        self.load_materials()    # load material cards\n        solidGroupBox = QtGui.QWidget()\n        self.solidLayout = QtGui.QGridLayout(solidGroupBox)\n        margin = self.solidLayout.contentsMargins()\n        self.solidLayout.setContentsMargins(0, 0, margin.right(), margin.bottom()/2)\n        self.scroll = QtGui.QScrollArea()\n        self.scroll.setFrameShape(QtGui.QFrame.NoFrame)    # remove frame shadow in old themes\n        self.scroll.setWidget(solidGroupBox)\n        self.scroll.setWidgetResizable(True)\n        self.found_labels = []    # for search\n\n        # custom icon set of pies for SolidsWidget().combo\n        self.pieIcon = []\n        drawSize = g_font_metrics.height() * 2\n        drawArea = QtCore.QRect(0, 0, drawSize-8, drawSize)\n        drawArea.adjust(2, 6, -2, -6)    # padding\n        for q in range(5):\n            pixmap = QtGui.QPixmap(drawSize-8, drawSize)\n            pixmap.fill(QtCore.Qt.transparent)\n            painter = QtGui.QPainter(pixmap)\n            painter.drawEllipse(drawArea)\n            if q in range(1, 5):\n                painter.setBrush(QtGui.QBrush(QtCore.Qt.black))\n                painter.drawPie(drawArea, (1-q)*90*16, q*90*16)\n                # 1/16th of a degree counterclockwise, zero degrees at the 3 o'clock position\n            painter.end()    # needed in Python\n            self.pieIcon.append(pixmap)\n\n        # buttonGroupBox\n        newSelection = QtGui.QPushButton('New')\n        newSelection.setToolTip('Get solids from selection')\n        newSelection.setIcon(QtGui.QIcon(':/icons/LinkSelect.svg'))\n        newSelection.clicked.connect(self.on_pushButton_newSelection)\n\n        update = QtGui.QPushButton('Update')\n        update.setToolTip('Update solids from document')\n        update.setIcon(QtGui.QIcon(':/icons/view-refresh.svg'))\n        update.clicked.connect(self.on_pushButton_update)\n\n        save = QtGui.QPushButton('Save')\n        save.setToolTip('Copy material property to your document model data')\n        save.setIcon(QtGui.QIcon(':/icons/Std_MergeProjects.svg'))\n        save.clicked.connect(self.on_pushButton_Save)\n\n        export = QtGui.QPushButton('Export')\n        export.setToolTip('Export values to a .csv file')\n        export.setIcon(QtGui.QIcon(':/icons/Std_Export.svg'))\n        export.clicked.connect(self.on_pushButton_Export)\n\n        readDensities = QtGui.QPushButton('Import')\n        readDensities.setToolTip('Import masses, materials or densities from a file')\n        readDensities.setIcon(QtGui.QIcon(':/icons/Std_Import.svg'))\n        readDensities.clicked.connect(self.on_pushButton_Import)\n\n        buttonGroupBox = QtGui.QWidget()\n        buttonLayout = QtGui.QHBoxLayout(buttonGroupBox)\n        buttonLayout.addWidget(newSelection)\n        buttonLayout.addWidget(update)\n        buttonLayout.addWidget(save)\n        buttonLayout.addWidget(export)\n        buttonLayout.addWidget(readDensities)\n        margin = buttonLayout.contentsMargins()\n        buttonLayout.setContentsMargins(0, margin.top()/2, 0, 0)\n\n        self.mainGroupBox = QtGui.QGroupBox('Selected solids: 0')\n        mainGroupLayout = QtGui.QVBoxLayout()\n        mainGroupLayout.addWidget(self.scroll)\n        mainGroupLayout.addWidget(buttonGroupBox)\n        self.mainGroupBox.setLayout(mainGroupLayout)\n        layout.addWidget(self.mainGroupBox)\n\n        # viewGroupBox\n        showCoM = QtGui.QCheckBox(toolTip='Show center of mass')\n        if self.doc.getObject('CenterOfMass'):\n            if self.doc.getObject('CenterOfMass').TypeId == 'App::DocumentObjectGroup':\n                showCoM.setChecked(True)\n        showCoM.setIcon(QtGui.QIcon(':/icons/Std_ToggleVisibility.svg'))\n        showCoM.setIconSize(g_icon_size)\n        showCoM.stateChanged.connect(self.on_stateChanged_showCoM)\n\n        self.changeRadius = QtGui.QSlider(QtGui.Qt.Horizontal)\n        self.changeRadius.setToolTip('Change radius of spheres')\n        self.changeRadius.setEnabled(showCoM.isChecked())\n        self.changeRadius.setMaximum(49)\n        self.changeRadius.valueChanged.connect(self.on_slideButton_changeRadius)\n\n        self.checkColorify = QtGui.QCheckBox(toolTip='Color shapes depending on density')\n        self.checkColorify.setIcon(QtGui.QIcon(':/icons/Std_RandomColor.svg'))\n        self.checkColorify.setIconSize(g_icon_size)\n        self.checkColorify.stateChanged.connect(self.on_stateChanged_Coloring)\n\n        self.comboColormap = QtGui.QComboBox(toolTip='Colormap to color shapes depending on density')\n        self.comboColormap.addItem('Traffic')    # built-in default\n        # See https://matplotlib.org/3.3.3/tutorials/colors/colormaps.html\n        self.comboColormap.addItems(['RdYlGn_r', 'autumn_r', 'cividis', 'coolwarm',\n                                     'Greys', 'Greys_r', 'summer', 'Wistia'])\n        self.comboColormap.addItem(COLORMAP_USER)\n        self.comboColormap.currentTextChanged.connect(self.on_comboColormap_changed)\n\n        viewLayout = QtGui.QHBoxLayout()\n        viewLayout.addWidget(showCoM)\n        viewLayout.addWidget(self.changeRadius)\n        viewLayout.addSpacing(GUI_FONT_SIZE)\n        viewLayout.addWidget(self.checkColorify)\n        viewLayout.addWidget(self.comboColormap)\n        viewGroupBox = QtGui.QGroupBox('View')\n        viewGroupBox.setLayout(viewLayout)\n        layout.addWidget(viewGroupBox)\n\n        self.resultCdG = []\n        for axis in range(3):\n            self.resultCdG.append(QtGui.QLineEdit(self))\n            self.resultCdG[axis].setObjectName('center of mass')\n            self.resultCdG[axis].setReadOnly(True)\n\n        self.com_clipboard = QtGui.QPushButton(QtGui.QIcon(':/icons/edit-copy.svg'), '')\n        self.com_clipboard.setToolTip(f'Copy to clipboard ({self.unitForL})')\n        self.com_clipboard.setFlat(True)\n        self.com_clipboard.clicked.connect(self.on_pushButton_copyToClipboardCdG)\n\n        axis_labels = [{'label': 'X', 'style': 'color:rgb(255, 0, 0)'},\n                       {'label': 'Y', 'style': 'color:rgb(0, 255, 0)'},\n                       {'label': 'Z', 'style': 'color:rgb(0, 0, 255)'}]\n        cdgLayout = QtGui.QHBoxLayout()\n        for index, axis in enumerate(axis_labels):\n            label_CdG = QtGui.QLabel(axis['label'])\n            label_CdG.setStyleSheet(axis['style'])\n            cdgLayout.addWidget(label_CdG)\n            cdgLayout.addWidget(self.resultCdG[index])\n        cdgLayout.addWidget(self.com_clipboard)\n        cdgGroupBox = QtGui.QGroupBox('Center of Mass')\n        cdgGroupBox.setLayout(cdgLayout)\n        layout.addWidget(cdgGroupBox)\n\n        # totalGroupBox\n        label_Mass = QtGui.QLabel('Mass')\n\n        self.resultMass = QtGui.QLineEdit(self)\n        self.resultMass.setObjectName('total weight')\n        self.resultMass.setReadOnly(True)\n\n        label_Density = QtGui.QLabel('Density')\n\n        self.resultDensity = QtGui.QLineEdit(self)\n        self.resultDensity.setReadOnly(True)\n\n        self.total_clipboard = QtGui.QPushButton(QtGui.QIcon(':/icons/edit-copy.svg'), '')\n        self.total_clipboard.setToolTip(f'Copy to clipboard ({self.unitForM} and {self.unitForD})')\n        self.total_clipboard.setFlat(True)\n        self.total_clipboard.clicked.connect(self.on_pushButton_copyToClipboardTotal)\n\n        totalLayout = QtGui.QGridLayout()\n        totalLayout.addWidget(label_Mass, 0, 0)\n        totalLayout.addWidget(self.resultMass, 0, 1)\n        totalLayout.addWidget(label_Density, 0, 2)\n        totalLayout.addWidget(self.resultDensity, 0, 3)\n        totalLayout.addWidget(self.total_clipboard, 0, 4)\n\n        self.volume_clipboard = QtGui.QPushButton(QtGui.QIcon(':/icons/edit-copy.svg'), '')\n        self.volume_clipboard.setToolTip(f'Copy to clipboard ({self.unitForV} and {self.unitForA})')\n        self.volume_clipboard.setFlat(True)\n        self.volume_clipboard.clicked.connect(self.on_pushButton_copyToClipboardVolume)\n\n        label_Volume = QtGui.QLabel('Volume')\n\n        self.resultVolume = QtGui.QLineEdit(self)\n        self.resultVolume.setObjectName('total volume')\n        self.resultVolume.setReadOnly(True)\n\n        label_Area = QtGui.QLabel('Area')\n\n        self.resultArea = QtGui.QLineEdit(self)\n        self.resultArea.setReadOnly(True)\n        self.resultArea.setObjectName('total surface area')\n        totalLayout.addWidget(label_Volume, 1, 0)\n        totalLayout.addWidget(self.resultVolume, 1, 1)\n        totalLayout.addWidget(label_Area, 1, 2)\n        totalLayout.addWidget(self.resultArea, 1, 3)\n        totalLayout.addWidget(self.volume_clipboard, 1, 4)\n        totalGroupBox = QtGui.QGroupBox('Total')\n        totalGroupBox.setLayout(totalLayout)\n        layout.addWidget(totalGroupBox)\n\n        self.resultMoI = []\n        inertiaLayout = QtGui.QGridLayout()\n        inertiaLayout.setVerticalSpacing(0)    # reduce vertical window size\n        for i, axis in enumerate(axis_labels):\n            label_row = QtGui.QLabel(axis['label'])\n            label_row.setStyleSheet(axis['style'])\n            inertiaLayout.addWidget(label_row, 0, i+1)\n            label_row.setAlignment(QtCore.Qt.AlignCenter)\n\n        for j, axis in enumerate(axis_labels):\n            label_col = QtGui.QLabel(axis['label'])\n            label_col.setStyleSheet(axis['style'])\n            inertiaLayout.addWidget(label_col, j+1, 0)\n            label_col.setAlignment(QtCore.Qt.AlignCenter)\n\n        for i in range(3):\n            self.resultMoI.append([])\n            for j in range(3):\n                line_edit = QtGui.QLineEdit(self)\n                self.resultMoI[i].append(line_edit)\n                line_edit.setAlignment(QtCore.Qt.AlignCenter)\n                inertiaLayout.addWidget(line_edit, j+1, i+1)\n        inertiaGroupBox = QtGui.QGroupBox('Moments of Inertia')\n        inertiaGroupBox.setToolTip('Taken at the center of mass and aligned with global coordinates')\n        inertiaGroupBox.setLayout(inertiaLayout)\n        layout.addWidget(inertiaGroupBox)\n        layout.addStretch()    # minimize all groupboxes to their necessary vertical size\n\n        self.inertia_clipboard = QtGui.QPushButton(QtGui.QIcon(':/icons/edit-copy.svg'), '')\n        self.inertia_clipboard.setToolTip(f'Copy to clipboard ({self.unitForI})')\n        self.inertia_clipboard.setFlat(True)\n        self.inertia_clipboard.clicked.connect(self.on_pushButton_copyToClipboardInertia)\n        inertiaLayout.addWidget(self.inertia_clipboard, 2, 4)\n\n        qApp = QtGui.QApplication.instance()\n        qApp.focusChanged.connect(self.on_focusChanged)    # emits on each focus change in FreeCAD\n\n    def init_solids(self, objs):\n        \"\"\"Construct new items and compute\"\"\"\n        self.find_all_centerOfMass(objs)\n        for sol in range(self.solid_count):\n            self.solids[sol] = SolidsWidget(\n                parent=self,\n                solid=g_sel[sol],\n                sol=sol\n            )\n\n        self.mainGroupBox.setTitle('Selected solids: ' + str(self.solid_count))\n        self.compute_centerOfMass(True)\n\n    def on_searchL_edited(self, text):\n        \"\"\"Highlight all findings and scroll to first or reset\"\"\"\n        if self.found_labels:\n            # Reset label highlighting\n            for label in self.found_labels:\n                label.setFrameStyle(QtGui.QFrame.NoFrame)\n                if FREECAD_VERSION > 0.22 and GUI_THEME in ['FreeCAD Light', 'FreeCAD Dark']:\n                    # BUG if theme non Classic\n                    label.setStyleSheet('')\n            self.found_labels = []\n        if text == '':\n            self.scroll.ensureWidgetVisible(self.solids[0].label)\n            return\n        for selfsol in self.solids:\n            if text.lower() in selfsol.label.text().lower():\n                self.found_labels.append(selfsol.label)\n                selfsol.label.setFrameShape(QtGui.QFrame.StyledPanel)\n                if FREECAD_VERSION > 0.22 and GUI_THEME in ['FreeCAD Light', 'FreeCAD Dark']:\n                    # BUG if theme non Classic\n                    selfsol.label.setStyleSheet('QFrame {border: 1px solid #B477FF}')\n        if self.found_labels:\n            self.scroll.ensureWidgetVisible(self.found_labels[0])\n\n    def on_focusChanged(self, oldWidget, nowWidget):\n        \"\"\"Toggle appearance of solid being edited\"\"\"\n        if 'QListView' in (type(oldWidget).__name__, type(nowWidget).__name__):\n            # skip if focus changes between combo box and its dropdown list\n            return\n        for w in (oldWidget, nowWidget):\n            macroWidgetFocus = False\n            if w is not None:\n                try:\n                    macroWidgetFocus = w.parent() == self.solidLayout.parentWidget()\n                except RuntimeError:\n                    pass    # deleted (None) objects can be passed\n            if macroWidgetFocus:\n                idx = self.solidLayout.indexOf(w)\n                if idx > 0:\n                    row = self.solidLayout.getItemPosition(idx)[0] - 1    # minus header\n                    if gui.Selection.isSelected(g_sel[row]):\n                        gui.Selection.removeSelection(g_sel[row])\n                    else:\n                        gui.Selection.addSelection(g_sel[row])\n\n    def valid_selection(self, _sel):\n        \"\"\"Get valid objects (Shape, Mesh) from selection\"\"\"\n        def sort_selection_by_label(s_):\n            return s_.Label\n\n        def sort_selection_by_tree(s_):\n            return self.tree_list.index(s_.Label)\n\n        global g_sel_user\n        g_sel_user = copy.copy(_sel)\n\n        # Add contents of group objects 'groupObjs' (breadth-first search).\n        # For PartDesign objects a Group contains recursive features treated separately.\n        groupObjs = ('App::DocumentObjectGroup', 'App::GeometryPython', 'Assembly::AssemblyObject')\n        i_ = 0\n        while i_ < len(_sel):\n            if hasattr(_sel[i_], 'Group') and _sel[i_].TypeId in groupObjs:\n                _sel.extend(_sel[i_].Group)\n                del _sel[i_]\n            elif hasattr(_sel[i_], 'Group') and _sel[i_].TypeId == 'App::Part':\n                for gp in _sel[i_].Group:\n                    # Nested App:Part are considered at this place:\n                    if gp.TypeId == 'App::Part':\n                        _sel.append(gp)\n                    # App:Part can be shapeless container of meshes (e.g. .stl's):\n                    elif gp.TypeId == 'Mesh::Feature':\n                        _sel.append(gp)\n                i_ += 1    # where to look at the next run\n            else:\n                i_ += 1\n\n        # create valid selection list\n        vsel = []\n        for s_ in _sel:\n            p_ = s_.getParent() if callable(getattr(s_, 'getParent', None)) else False\n            # no getParent() in FreeCAD 0.20\n            if p_ and p_.Name == 'CenterOfMass' and p_.TypeId == 'App::DocumentObjectGroup':\n                # Skip objects created for the macro to avoid error or crash\n                continue\n            elif hasattr(s_, 'Shape') and s_.Shape.Volume:\n                if s_.TypeId == 'App::Part':\n                    # because contains bodies\n                    for cs in s_.Shape.childShapes(False, False):\n                        # childShapes(False,False): ignore placement of parent\n                        # get first match from OutList (contains different object types)\n                        for ot in s_.OutList:\n                            if hasattr(ot, 'Shape') and ot.Shape.isEqual(cs):\n                                # nested App:Part and App:Link in App:Part not match here\n                                vsel.append(ot)\n                                break\n                    # App:Link in App:Part\n                    for ot in s_.OutList:\n                        if ot.TypeId == 'App::Link':\n                            vsel.append(ot)\n                elif s_.TypeId == 'Part::FeaturePython' and hasattr(s_, 'IfcType'):\n                    # e.g. Arch Wall/Structure, because can contain childs\n                    vsel.append(s_)\n                    for it in s_.InList[1:]:\n                        # include childs (Windows etc.), parent is first InList\n                        if it.TypeId == 'Part::FeaturePython' and it.Shape.Volume:\n                            vsel.append(it)\n                else:\n                    vsel.append(s_)\n            elif hasattr(s_, 'Mesh') and s_.Mesh.Volume:\n                vsel.append(s_)\n\n        # remove double items (when groupObjs and containing item selected)\n        vsel = list(dict.fromkeys(vsel))\n\n        # sort valid selection list or match up with tree view\n        if SORT_SELECTION:\n            vsel.sort(key=sort_selection_by_label)\n        else:\n            tree = g_main_window.findChild(QtGui.QTreeWidget)\n            if tree.topLevelItem(0) is None:    # FreeCAD > 0.22\n                for t_ in g_main_window.findChildren(QtGui.QTreeWidget):\n                    if t_.topLevelItem(0) is not None:\n                        tree = t_\n            iterator = QtGui.QTreeWidgetItemIterator(tree, QtGui.QTreeWidgetItemIterator.Editable)\n            self.tree_list = [i_.value().text(0) for i_ in iterator]\n            if self.tree_list:\n                vsel.sort(key=sort_selection_by_tree)\n            else:\n                # e.g. some FreeCAD 0.21 weekly builds\n                app.Console.PrintWarning('Could not take over the sorting of the tree view\\n')\n                vsel.sort(key=sort_selection_by_label)\n\n        # create valid objects list (e.g. shapes)\n        import Part\n        if 0.22 <= FREECAD_VERSION < 1.0:\n            import UtilsAssembly\n        objs = []\n        for i_, s_ in enumerate(vsel):\n            if hasattr(s_, 'Shape'):\n                # local placement correction (transform to global coordinate system)\n                o_ = Part.getShape(s_)    # copy shape for transformation\n                if callable(getattr(s_, 'getGlobalPlacement', None)):\n                    o_.Placement = s_.getGlobalPlacement()\n                    # e.g. App::Link has no method getGlobalPlacement\n                elif FREECAD_VERSION < 0.22:\n                    if s_.InList:\n                        for it in s_.InListRecursive:\n                            o_.Placement = o_.Placement.multiply(it.Placement)\n                elif 0.22 <= FREECAD_VERSION < 1.0:\n                    o_.Placement = UtilsAssembly.getGlobalPlacement(s_)\n                elif s_.TypeId != 'Assembly::JointGroup' or s_.TypeId == 'App::Link':\n                    if s_.InList:\n                        for it in s_.InListRecursive:\n                            if it.TypeId != 'Assembly::JointGroup':\n                                o_.Placement = o_.Placement.multiply(it.Placement)\n                elif s_.TypeId == 'Assembly::JointGroup':\n                    continue\n                objs.append(o_)\n            elif hasattr(s_, 'Mesh'):\n                objs.append(s_.Mesh)\n            # change vsel entry for special object cases\n            if s_.TypeId == 'Part::FeaturePython' and hasattr(s_, 'ArrayType'):\n                # e.g. Draft Arrays, because no ShapeColor etc. in ViewObject\n                vsel[i_] = s_.OutList[0]\n\n        if len(_sel) > len(vsel):\n            app.Console.PrintWarning('Ignored invalid object from selection\\n')\n        if objs:\n            global g_sel\n            g_sel = vsel\n            self.solid_count = len(objs)\n        return objs\n\n    def on_pushButton_newSelection(self):\n        initial = self.checkColorify.checkState()\n        self.checkColorify.setCheckState(QtCore.Qt.Unchecked)    # preserve SolidsWidget.orgColor\n        self.doc = app.activeDocument()\n        self.update_selection(gui.Selection.getSelection())\n        self.checkColorify.setCheckState(initial)\n\n    def on_pushButton_update(self):\n        initial = self.checkColorify.checkState()\n        self.checkColorify.setCheckState(QtCore.Qt.Unchecked)    # preserve SolidsWidget.orgColor\n        self.update_selection(g_sel_user)\n        self.checkColorify.setCheckState(initial)\n\n    def update_selection(self, _sel):\n        try:\n            self.set_objects_transparent(False)\n        except:\n            pass\n        objs = self.valid_selection(_sel)\n        if not objs:\n            return\n        # safe way to remove all items from layout\n        while self.solidLayout.count():\n            child = self.solidLayout.takeAt(0)\n            if child.widget():\n                child.widget().deleteLater()\n        self.init_solids(objs)\n        if self.changeRadius.isEnabled():\n            self.draw_centerOfMass()\n\n    def load_materials(self):\n        \"\"\"Load density from material cards, get resource paths from preferences\"\"\"\n        from pathlib import Path\n\n        import importFCMat\n        resources: list[Path] = []\n        if USE_BUILT_IN_MATERIALS:\n            if FREECAD_VERSION < 0.22:\n                resources.append(Path(app.getResourceDir(), \"Mod\", \"Material\", \"StandardMaterial\"))\n            else:\n                resources.append(Path(\n                    app.getResourceDir(), \"Mod\", \"Material\", \"Resources\", \"Materials\", \"Standard\")\n                )\n        if USE_MAT_FROM_CONFIG_DIR:\n            resources.append(Path(app.ConfigGet(\"UserAppData\"), \"Material\"))\n        if USE_MAT_FROM_CUSTOM_DIR and CUSTOM_MAT_DIR:\n            resources.append(Path(CUSTOM_MAT_DIR))\n        app.Console.PrintMessage('Looking for material cards according to ' +\n            'User parameter:BaseApp/Preferences/Mod/Material/Resources' + '\\n')\n\n        # Read material cards\n        for p in resources:\n            app.Console.PrintMessage(f'  {p}' + '\\n')\n            # cards found later with same name will override previous ones\n            dir_gen = p.rglob('*.FCMat')   # is generator -> use only once\n            for f in dir_gen:\n                if f.stem == 'Default':\n                    continue\n                try:\n                    d = importFCMat.read(str(f)).get('Density')\n                except LookupError:\n                    pass\n                else:\n                    if d and Units.Quantity(d).Value > 0:\n                        self.material_base[f.stem] = Units.Quantity(d)\n        qtys = self.material_base.values()\n        self.material_base_range = (min(qtys), max(qtys))\n\n    def on_pushButton_editMaterial(self):\n        import MaterialEditor\n        material_base_old = copy.copy(self.material_base)\n        MaterialEditor.openEditor()\n        self.load_materials()\n        # add combo items for newly created materials\n        new_materials = [m for m in self.material_base if m not in material_base_old]\n        for selfsol in self.solids:\n            selfsol.combo.addItems(new_materials)\n\n    def store_prefered_units(self, txt):\n        \"\"\"Get units set as preference\"\"\"\n        self.unitForD_text = txt\n        self.unitForD = self.unitForD_text.replace('\u00b3', '^3')         # density\n        self.unitForL = self.unitForD_text.split('/')[1].rstrip('\u00b3')  # length\n        self.unitForM = self.unitForD_text.split('/')[0]              # mass\n        self.unitForV = self.unitForD.split('/')[1]                   # volume\n        self.unitForA = self.unitForV.replace('^3', '^2')             # area\n        self.unitForI = self.unitForM + '*' + self.unitForA           # inertia\n\n    def convert_length(self, length):\n        \"\"\"Convert length from internal FreeCAD to preference unit\"\"\"\n        pq = Units.parseQuantity\n        return float(pq(f'{length} mm') / pq(self.unitForL))\n\n    def convert_volume(self, volume):\n        \"\"\"Convert volume from internal FreeCAD to preference unit\"\"\"\n        pq = Units.parseQuantity\n        return float(pq(f'{volume} mm^3') / pq(self.unitForV))\n\n    def convert_area(self, area):\n        \"\"\"Convert area from internal FreeCAD to preference unit\"\"\"\n        pq = Units.parseQuantity\n        return float(pq(f'{area} mm^2') / pq(self.unitForA))\n\n    def convert_inertia(self, inertia):\n        \"\"\"Convert length from internal FreeCAD to preference unit\"\"\"\n        pq = Units.parseQuantity\n        return float(pq(f'{inertia} kg*mm^2') / pq(self.unitForI))\n\n    def on_comboUnitDensity_changed(self, newText):\n        unitForD_prev = self.unitForD\n        self.store_prefered_units(newText)\n        for selfsol in self.solids:\n            qty = str(selfsol.spinDens.value()) + ' ' + unitForD_prev\n            selfsol.init_spinDensity(selfsol.spinDens, Units.Quantity(qty), self.unitForD)\n            selfsol.spinDens.setToolTip(\n                'density of ' + selfsol.label.text() + ' (in ' + self.unitForD_text + ')')\n        qty = self.material_base.get('default', 0)\n        SolidsWidget.init_spinDensity(self, self.defaultDensitySpin,\n                                      Units.Quantity(qty),\n                                      self.unitForD)\n        self.defaultDensitySpin.setToolTip('set default density (in ' + self.unitForD_text + ')')\n        self.com_clipboard.setToolTip(f'Copy to clipboard ({self.unitForL})')\n        self.total_clipboard.setToolTip(f'Copy to clipboard ({self.unitForM} and {self.unitForD})')\n        self.volume_clipboard.setToolTip(f'Copy to clipboard ({self.unitForV} and {self.unitForA})')\n        self.inertia_clipboard.setToolTip(f'Copy to clipboard ({self.unitForI})')\n        self.compute_centerOfMass()\n\n    def on_spinDefaultDensity_changed(self, newValue):\n        qty = str(newValue) + ' ' + self.unitForD\n        self.material_base['default'] = Units.Quantity(qty)\n        self.compute_centerOfMass(False)\n        for selfsol in self.solids:\n            if selfsol.combo.currentText() == 'default':\n                selfsol.on_comboMaterial_changed(1)    # trigger update of \"default\"\n        self.compute_centerOfMass(True)\n\n    def on_pushButton_allToDefaultDensity(self):\n        self.compute_centerOfMass(False)\n        for selfsol in self.solids:\n            selfsol.combo.setCurrentText('default')\n        self.compute_centerOfMass(True)\n\n    def find_all_centerOfMass(self, objs):\n        \"\"\"Find all center of mass (CoMs) depending on the type of object.\"\"\"\n        import DraftVecUtils\n        self.solids = [0] * self.solid_count\n        self.volumes = [0] * self.solid_count\n        self.areas = [0] * self.solid_count\n        self.masses = [0] * self.solid_count\n        self.CoMs = [app.Vector(0, 0, 0)] * self.solid_count\n        self.MoIs = [np.zeros((3, 3))] * self.solid_count\n\n        # function is slower than valid_selection and compute_centerOfMass\n        # because of .Volume and .CenterOfMass\n        progress_bar = app.Base.ProgressIndicator()\n        progress_bar.start('Finding center of mass ...', self.solid_count)\n        for sol in range(self.solid_count):\n            self.volumes[sol] = objs[sol].Volume\n            self.areas[sol] = objs[sol].Area\n            if hasattr(objs[sol], 'CenterOfGravity'):\n                # FreeCAD >= 0.20\n                self.CoMs[sol] = objs[sol].CenterOfGravity\n            elif hasattr(objs[sol], 'CenterOfMass'):\n                # FreeCAD 0.19\n                self.CoMs[sol] = objs[sol].CenterOfMass\n            elif hasattr(objs[sol], 'Solids'):\n                for array_sol in objs[sol].Solids:\n                    if hasattr(array_sol, 'CenterOfGravity'):\n                        self.CoMs[sol] += array_sol.CenterOfGravity\n                    else:\n                        self.CoMs[sol] += array_sol.CenterOfMass\n                self.CoMs[sol] /= objs[sol].Solids.__len__()\n            # estimate CoM of a mesh\n            elif hasattr(objs[sol], 'Points'):\n                _CoM = [0, 0, 0]\n                for f in objs[sol].Facets:\n                    currentVolume = (f.Points[0][0]*f.Points[1][1]*f.Points[2][2]\n                                     - f.Points[0][0]*f.Points[2][1]*f.Points[1][2]\n                                     - f.Points[1][0]*f.Points[0][1]*f.Points[2][2]\n                                     + f.Points[1][0]*f.Points[2][1]*f.Points[0][2]\n                                     + f.Points[2][0]*f.Points[0][1]*f.Points[1][2]\n                                     - f.Points[2][0]*f.Points[1][1]*f.Points[0][2]) / 6.\n                    for ax in range(3):\n                        _CoM[ax] += ((f.Points[0][ax] + f.Points[1][ax] + f.Points[2][ax]) / 4.\n                                     ) * currentVolume\n                for ax in range(3):\n                    _CoM[ax] /= self.volumes[sol]\n                self.CoMs[sol] = app.Vector(*_CoM)\n            # Calculate BoundBox of all objects\n            if sol == 0:\n                self.boundBox = objs[sol].BoundBox\n            else:\n                self.boundBox = self.boundBox.united(objs[sol].BoundBox)\n            progress_bar.next()\n        progress_bar.stop()\n\n    def get_MoI(self, matrix, density):\n        # Body's inertia matrix in mm^5\n        inertia_body = np.array(matrix.A).reshape(4, 4)[:3, :3]  # Inertia matrix in mm\u2075\n        qty = str(density) + ' ' + self.unitForD\n        density_kg_mm3 = Units.Quantity(qty).getValueAs('kg/mm^3').Value\n        inertia_body_kg_mm2 = inertia_body * density_kg_mm3  # Convert to kg\u00b7mm\u00b2\n        return inertia_body_kg_mm2\n\n    def compute_momentOfInertia(self, icm, mass, CoM):\n        com_body_mm = np.array(CoM)  # COM in mm\n        com_assembly_mm = np.array(self.TotalCoM)  # Assembly COM in mm\n        # Distance vector from assembly COM to body's COM\n        r_mm = com_body_mm - com_assembly_mm  # mm\n        # Apply the Parallel Axis Theorem\n        parallel_axis_term_kg_mm2 = mass * (np.dot(r_mm, r_mm) * np.eye(3) - np.outer(r_mm, r_mm))\n        I = icm + parallel_axis_term_kg_mm2\n        return I\n\n    def compute_centerOfMass(self, enabled=None):\n        \"\"\"Compute joint center of mass from all objects if enabled. Block by setting to False.\"\"\"\n        if enabled is not None:\n            self.compute_enabled = enabled\n        if not self.compute_enabled:\n            return\n        self.massTot = 0.\n        self.volTot = 0.\n        self.areaTot = 0.\n        self.TotalCoM = app.Vector(0, 0, 0)\n        self.TotalMoI = np.zeros((3, 3))\n        for sol in range(self.solid_count):\n            if not isinstance(self.solids[sol], SolidsWidget):\n                return\n            volumeInUnit = self.convert_volume(self.volumes[sol])\n            areaInUnit = self.convert_area(self.areas[sol])\n            self.masses[sol] = volumeInUnit * self.solids[sol].spinDens.value()\n            if self.masses[sol] == 0:\n                continue\n            self.massTot += self.masses[sol]\n            self.volTot += volumeInUnit\n            self.areaTot += areaInUnit\n\n        if self.massTot == 0:\n            error_message('All masses were set to zero. Last one reset to default.')\n            self.solids[-1].combo.setCurrentText('default')\n            return\n        for sol in range(self.solid_count):\n            self.TotalCoM += 1 / self.massTot * self.masses[sol] * self.CoMs[sol]\n            if hasattr(g_sel[sol], 'MatrixOfInertia'):\n                self.MoIs[sol] = self.get_MoI(g_sel[sol].MatrixOfInertia, self.solids[sol].spinDens.value())\n            elif hasattr(g_sel[sol],'Shape') and hasattr(g_sel[sol].Shape, 'MatrixOfInertia'):\n                self.MoIs[sol] = self.get_MoI(g_sel[sol].Shape.MatrixOfInertia, self.solids[sol].spinDens.value())\n            else:\n                app.Console.PrintWarning(f'Solid {self.solids[sol].label.text()} has no \"MatrixOfInertia\" \\n')\n        for sol in range(self.solid_count):\n            self.TotalMoI += self.compute_momentOfInertia(self.MoIs[sol], self.masses[sol], self.CoMs[sol])\n\n        # output\n        for sol, selfsol in enumerate(self.solids):\n            selfsol.spinMass.setText(f'{self.masses[sol]:.4f}')\n            selfsol.spinMass.setToolTip(f'mass of {selfsol.label.text()} (in {self.unitForM})')\n        for axis in range(3):\n            self.resultCdG[axis].setText(f'{self.convert_length(self.TotalCoM[axis]):.6}')\n        self.resultCdG[0].setToolTip(f'center of mass X (in {self.unitForL})')\n        self.resultCdG[1].setToolTip(f'center of mass Y (in {self.unitForL})')\n        self.resultCdG[2].setToolTip(f'center of mass Z (in {self.unitForL})')\n        self.resultVolume.setText(f'{self.volTot:.6f}')\n        self.resultVolume.setToolTip(f'total volume (in {self.unitForV})')\n        self.resultArea.setText(f'{self.areaTot:.6f}')\n        self.resultArea.setToolTip(f'total surface area (in {self.unitForA})')\n        self.resultMass.setText(f'{self.massTot:.6f}')\n        self.resultMass.setToolTip(f'total weight (in {self.unitForM})')\n        self.resultDensity.setText(f'{self.massTot/self.volTot:.6}')\n        self.resultDensity.setToolTip(f'total density (in {self.unitForD_text})')\n        axis = ['x', 'y', 'z']\n        for i in range(3):\n            for j in range(3):\n                self.resultMoI[i][j].setText(f'{self.convert_inertia(self.TotalMoI[i, j]):.6}')\n                self.resultMoI[i][j].setToolTip(f'L{axis[i]}{axis[j]} (in {self.unitForI})')\n        if self.changeRadius.isEnabled():\n            self.draw_centerOfMass()\n        if self.checkColorify.isChecked():\n            self.coloring()\n\n    def draw_centerOfMass(self):\n        boundBoxL = (self.boundBox.XLength, self.boundBox.YLength, self.boundBox.ZLength)\n        self.doc = app.activeDocument()    # it is possible to draw in a different document\n        CoMObjs = self.doc.getObject('CenterOfMass')    # none if no object\n        if CoMObjs:\n            CoMObjs.removeObjectsFromDocument()    # remove childs\n        else:\n            CoMObjs = self.doc.addObject('App::DocumentObjectGroup', 'CenterOfMass')\n\n        # These objects will be created by the macro and should not exist anymore in the document\n        for s_ in ('CoMBBoxOfSel', 'CoMLCS', 'CoMTotal', 'CoMPlaneYZ', 'CoMPlaneXZ', 'CoMPlaneXY'):\n            if self.doc.getObject(s_):\n                self.doc.removeObject(s_)\n\n        # Bounding box of valid selection\n        BBoxSolid = self.doc.addObject('Part::Box', 'CoMBBoxOfSel')\n        BBoxSolid.Placement.Base = self.boundBox.Center.sub(app.Vector(boundBoxL).multiply(0.5))\n        BBoxSolid.Length = boundBoxL[0]\n        BBoxSolid.Width = boundBoxL[1]\n        BBoxSolid.Height = boundBoxL[2]\n        BBoxSolid.ViewObject.BoundingBox = True\n        BBoxSolid.ViewObject.Transparency = 90\n        BBoxSolid.ViewObject.ShapeColor = (0.5, 0.5, 0.5)\n        BBoxSolid.ViewObject.Visibility = False\n        CoMObjs.addObject(BBoxSolid)\n\n        # Local coordinate system at center of masses\n        lcs = self.doc.addObject('PartDesign::CoordinateSystem', 'CoMLCS')\n        lcs.Placement = app.Placement(self.TotalCoM, app.Rotation(0, 0, 0))\n        CoMObjs.addObject(lcs)\n\n        # Sphere to represent the center of masses\n        sphere = self.doc.addObject('Part::Sphere', 'CoMTotal')\n        sphere.Placement.Base = self.TotalCoM\n        sphere.ViewObject.ShapeColor = (0.6, 0.0, 0.0)\n        sphere.ViewObject.LineWidth = 1.0\n        CoMObjs.addObject(sphere)\n\n        # Spheres for all center of mass\n        if self.solid_count > 1:\n            for sol in range(self.solid_count):\n                if self.masses[sol] == 0:\n                    continue\n                sphere = self.doc.addObject('Part::Sphere', 'CoM_' + g_sel[sol].Name)\n                sphere.Label = 'CoM_' + g_sel[sol].Label\n                sphere.Placement.Base = self.CoMs[sol]\n                if COLOR_SPHERES:\n                    sphere.ViewObject.ShapeColor = self.solids[sol].orgColorFC\n                else:\n                    sphere.ViewObject.ShapeColor = (1.0, 1.0, 1.0)\n                sphere.ViewObject.LineWidth = 1.0\n                CoMObjs.addObject(sphere)\n\n        # Planes with center of mass and size of boundBox\n        cplane_name = ('CoMPlaneYZ', 'CoMPlaneXZ', 'CoMPlaneXY')\n        cplane_norm = (app.Vector(1., 0., 0.),\n                       app.Vector(0., 1., 0.),\n                       app.Vector(0., 0., 1.))\n        cplane_rot = (app.Rotation(0, -90,  0),\n                      app.Rotation(0,  0, 90),\n                      app.Rotation(0,  0,  0))\n        cplane_lewi = ((boundBoxL[2], boundBoxL[1]),\n                       (boundBoxL[0], boundBoxL[2]),\n                       (boundBoxL[0], boundBoxL[1]))\n        for axis in range(3):\n            plane = self.doc.addObject('Part::Plane', cplane_name[axis])\n            plane.Length = cplane_lewi[axis][0]\n            plane.Width = cplane_lewi[axis][1]\n            plane.Placement = app.Placement(self.TotalCoM, cplane_rot[axis])\n            for axi2 in range(3):\n                plane.Placement.move(cplane_norm[axi2] * boundBoxL[axi2] / -2.)\n            plane.Placement.move(cplane_norm[axis] * boundBoxL[axis] / 2.)\n            color = list(cplane_norm[axis])\n            plane.ViewObject.LineColor = (*color, 0.)    # rgba\n            plane.ViewObject.LineWidth = 1.0\n            plane.ViewObject.Transparency = 100\n            CoMObjs.addObject(plane)\n\n        self.draw_update_sphere_radius()\n        self.set_objects_transparent(True)\n        self.doc.recompute()\n\n    def draw_update_sphere_radius(self):\n        boundBoxL = (self.boundBox.XLength, self.boundBox.YLength, self.boundBox.ZLength)\n        radiusCOM = (1+self.changeRadius.value())/100.\n\n        # Sphere to represent the center of masses\n        sphere = self.doc.getObject('CoMTotal')\n        if hasattr(sphere, 'Radius'):\n            sphere.Radius = radiusCOM * max(boundBoxL)\n\n        # Spheres for all center of mass\n        # Radius of the sphere is linked to the mass of the solid: R = (m_sol/m_tot)^1/3\n        for sol in range(self.solid_count):\n            sphere = self.doc.getObject('CoM_' + g_sel[sol].Name)\n            if hasattr(sphere, 'Radius'):\n                sphere.Radius = radiusCOM * max(boundBoxL) * math.pow(self.masses[sol]/self.massTot, 1./3.)\n        self.doc.recompute()\n\n    def set_objects_transparent(self, transparent):\n        if transparent:\n            for sol in range(self.solid_count):\n                g_sel[sol].ViewObject.Transparency = 25\n        else:\n            for sol in range(self.solid_count):\n                g_sel[sol].ViewObject.Transparency = self.solids[sol].orgTransparency\n\n    def on_stateChanged_showCoM(self, state):\n        CoMObjs = self.doc.getObject('CenterOfMass')    # none if no object\n        if state == QtCore.Qt.Checked:\n            if CoMObjs and CoMObjs.TypeId != 'App::DocumentObjectGroup':\n                error_message(f'Please delete the object that occupies the name \"CenterOfMass\".')\n                return\n            self.draw_centerOfMass()\n            self.changeRadius.setEnabled(True)\n        else:\n            self.changeRadius.setEnabled(False)\n            try:\n                self.set_objects_transparent(False)\n                CoMObjs.removeObjectsFromDocument()\n                self.doc.removeObject('CenterOfMass')\n            except:\n                pass\n\n    def on_slideButton_changeRadius(self):\n        self.draw_update_sphere_radius()\n\n    def on_stateChanged_Coloring(self, state):\n        if state == QtCore.Qt.Checked:\n            self.coloring()\n        else:\n            for sol, selfsol in enumerate(self.solids):\n                self.set_object_color(g_sel[sol].Name, selfsol.orgColorFC)\n                if COLOR_SPHERES and self.changeRadius.isEnabled():\n                    self.set_object_color('CoM_' + g_sel[sol].Name, selfsol.orgColorFC)\n                selfsol.spinDens.setPalette(QtGui.QPalette())    # reset to normal\n                if FREECAD_VERSION > 0.22 and GUI_THEME in ['FreeCAD Light', 'FreeCAD Dark']:\n                    # BUG if theme non Classic\n                    selfsol.spinDens.setStyleSheet('')\n\n    def on_comboColormap_changed(self, newText):\n        if self.checkColorify.isChecked():\n            self.coloring()\n\n    def set_object_color(self, name, color):\n        obj = self.doc.getObject(name)\n        if hasattr(obj.ViewObject, 'ShapeColor'):\n            obj.ViewObject.ShapeColor = color\n        elif hasattr(obj.ViewObject, 'ShapeAppearance'):\n            # App::Link in FreeCAD 0.22\n            material = obj.ViewObject.ShapeAppearance[0]\n            material.DiffuseColor = color\n            obj.ViewObject.ShapeAppearance = (material, )    # overwrite tuple\n\n    def coloring(self):\n        cmName = self.comboColormap.currentText()\n        if cmName != 'Traffic':\n            if FREECAD_VERSION < 0.22:\n                import matplotlib.cm\n                cm = matplotlib.cm.get_cmap(cmName)\n            else:\n                import matplotlib\n                cm = matplotlib.colormaps[cmName]\n        densities = [selfsol.spinDens.value() for selfsol in self.solids]\n        maxD = max(densities)\n        minD = min([i_ for i_ in densities if i_ != 0])    # min without zeros\n        for sol, selfsol in enumerate(self.solids):\n            if self.masses[sol] == 0:\n                self.set_object_color(g_sel[sol].Name, selfsol.orgColorFC)\n                selfsol.spinDens.setPalette(QtGui.QPalette())    # reset to normal\n                if FREECAD_VERSION > 0.22 and GUI_THEME in ['FreeCAD Light', 'FreeCAD Dark']:\n                    # BUG if theme non Classic\n                    selfsol.spinDens.setStyleSheet('')\n                continue\n            if maxD == minD:\n                drel = 0    # default to low color\n            else:\n                drel = (densities[sol]-minD) / (maxD-minD)\n            if cmName == 'Traffic':\n                # density value to hsv color range green to red\n                drel = math.acos(1-2*drel) / math.pi    # stretch yellow (sigmoid-like)\n                h = 120 * (1-drel) / 360\n                color = QtGui.QColor.fromHsvF(h, 1, 1)\n            else:\n                color = QtGui.QColor.fromRgbF(*cm(drel))\n            color.setHsvF(color.hueF(), COLOR_SATURAT/100, color.valueF())    # skips if s > 1\n            self.set_object_color(g_sel[sol].Name, color.getRgbF())\n            if COLOR_SPHERES and self.changeRadius.isEnabled():\n                self.set_object_color('CoM_' + g_sel[sol].Name, color.getRgbF())\n            pal = QtGui.QPalette()\n            pal.setColor(QtGui.QPalette.Base, color)\n            lum = color.getRgbF()\n            # https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum#dfn-relative-luminance\n            for c in lum:\n                c = c/12.92 if c <= 0.04045 else math.pow((c+0.055)/1.055, 2.4)\n            if 0.2126*lum[0] + 0.7152*lum[1] + 0.0722*lum[2] < 0.5:\n                pal.setColor(QtGui.QPalette.Text, QtCore.Qt.white)\n                textColor = 'white'\n            else:\n                textColor = 'black'\n            selfsol.spinDens.setPalette(pal)\n            if FREECAD_VERSION > 0.22 and GUI_THEME in ['FreeCAD Light', 'FreeCAD Dark']:\n                # BUG if theme non Classic\n                selfsol.spinDens.setStyleSheet(\n                    'QDoubleSpinBox {background-color: %s; color: %s}' % (color.name(), textColor))\n\n    def on_pushButton_toPreferences(self):\n        gui.runCommand('Std_DlgParameter', 0)\n\n    def on_pushButton_copyToClipboardCdG(self):\n        \"\"\"Copy Vector to clipboard (in FreeCAD Standard unit system)\"\"\"\n        string = VALUE_DELIMITER.join(str(self.convert_length(self.TotalCoM[axis])) for axis in range(3))\n        QtGui.QGuiApplication.clipboard().setText(string)\n\n    def on_pushButton_copyToClipboardTotal(self):\n        \"\"\"Copy total mass and density to clipboard (in FreeCAD Standard unit system)\"\"\"\n        string = VALUE_DELIMITER.join((str(self.massTot), str(self.massTot/self.volTot)))\n        QtGui.QGuiApplication.clipboard().setText(string)\n\n    def on_pushButton_copyToClipboardVolume(self):\n        \"\"\"Copy total volume and area to clipboard (in FreeCAD Standard unit system)\"\"\"\n        string = VALUE_DELIMITER.join((str(self.volTot), str(self.areaTot)))\n        QtGui.QGuiApplication.clipboard().setText(string)\n\n    def on_pushButton_copyToClipboardInertia(self):\n        \"\"\"Copy total mass and density to clipboard (in FreeCAD Standard unit system)\"\"\"\n        string = ''\n        for i in range(3):\n            string += VALUE_DELIMITER.join(str(self.convert_inertia(self.TotalMoI[i][axis])) for axis in range(3))\n            string += '\\n'\n        QtGui.QGuiApplication.clipboard().setText(string)\n\n    def on_pushButton_Save(self):\n        for sol in range(self.solid_count):\n            mat_selected = self.solids[sol].combo.currentText()\n            if mat_selected == 'default':\n                # remove properties set by this macro\n                g_sel[sol].removeProperty('Mat_Name')\n                g_sel[sol].removeProperty('Mat_Density')\n            else:\n                # Material Name\n                tip = ('Custom', 'set by CenterOfMass Macro')\n                if not hasattr(g_sel[sol], 'Mat_Name'):\n                    g_sel[sol].addProperty('App::PropertyString', 'Mat_Name', *tip)\n                g_sel[sol].Mat_Name = mat_selected\n                # Density\n                if not hasattr(g_sel[sol], 'Mat_Density'):\n                    if FREECAD_VERSION < 0.22:\n                        g_sel[sol].addProperty('App::PropertyString', 'Mat_Density', *tip)\n                    else:\n                        # 'App::PropertyDensity' available since FreeCAD 0.21\n                        # -> cannot be opened in FreeCAD < 0.21 so start using with the next version\n                        g_sel[sol].addProperty('App::PropertyDensity', 'Mat_Density', *tip)\n                g_sel[sol].Mat_Density = str(self.solids[sol].spinDens.value()) + ' ' + self.unitForD\n\n    def on_pushButton_Export(self):\n        \"\"\"Export values in a delimiter-separated table (default: Tab)\"\"\"\n        encoding, delimiter = 'utf-8', VALUE_DELIMITER\n        dstr = 'Tab' if VALUE_DELIMITER == '\\t' else 'User-delimiter'\n        fileFilter = (f'{dstr}-separated CSV (*.csv)', f'{dstr}-separated Text (*.txt)')\n        fileName, selectedFilter = QtGui.QFileDialog.getSaveFileName(self,\n                                                                     'Export values', os.path.expanduser('~'), ';;'.join(fileFilter))\n        if fileName == '':\n            app.Console.PrintWarning('No file saved \\n')\n            return\n        app.Console.PrintMessage('Saving ' + fileName + '\\n')\n        densTot = self.massTot/self.volTot if self.volTot != 0 else 0.\n        head = ['Number', 'Label', 'Material',\n                f'Volume ({self.unitForV})',\n                f'Area ({self.unitForA})',\n                f'Density ({self.unitForD})',\n                f'Mass ({self.unitForM})',\n                *(f'Center of mass {axis} ({self.unitForL})' for axis in ['X', 'Y', 'Z']),\n                *(f'L{axis1}{axis2} ({self.unitForI})' for axis1 in ['x', 'y', 'z'] for axis2 in ['x', 'y', 'z'])]\n        foot = ['Total', '', '',\n                f'{self.volTot:.6e}',\n                f'{self.areaTot:.6e}',\n                f'{densTot:.6e}',\n                f'{self.massTot:.6e}',\n                *(f'{self.convert_length(self.TotalCoM[axis]):.6e}' for axis in range(3)),\n                *(f'{self.convert_inertia(self.TotalMoI[axis1, axis2]):.6e}' for axis1 in range(3) for axis2 in range(3))]\n        try:\n            f = open(fileName, 'w', encoding=encoding)\n            f.write(delimiter.join(head) + '\\n')\n            for selfsol in self.solids:\n                sol = selfsol.sol\n                row = [f'{sol + 1}', g_sel[sol].Label, selfsol.combo.currentText(),\n                       f'{self.convert_volume(self.volumes[sol]):.6e}',\n                       f'{self.convert_area(self.areas[sol]):.6e}',\n                       f'{selfsol.spinDens.value():.6e}',\n                       f'{self.masses[sol]:.6e}',\n                       *(f'{self.convert_length(self.CoMs[sol][axis]):.6e}' for axis in range(3)),\n                       *(f'{self.convert_inertia(self.MoIs[sol][axis1, axis2]):.6e}' for axis1 in range(3) for axis2 in range(3))]\n                f.write(delimiter.join(row) + '\\n')\n            f.write(delimiter.join(foot))\n            f.close()\n            app.Console.PrintMessage(fileName + ' saved \\n')\n        except:\n            error_message('Error writing file ' + fileName)\n\n    def on_pushButton_Import(self):\n        \"\"\"Load a previously exported or an external bill of materials (BOM)\"\"\"\n        encoding, delimiter = 'utf-8', VALUE_DELIMITER\n        dstr = 'Tab' if VALUE_DELIMITER == '\\t' else 'User-delimiter'\n        fileFilter = (f'{dstr}-separated CSV or Text (*.csv *.txt)',\n                      'Semicolon-CSV from Excel (*.csv)')\n        fileName, selectedFilter = QtGui.QFileDialog.getOpenFileName(self,\n                                                                     'Open file', os.path.expanduser('~'), ';;'.join(fileFilter))\n        if fileName == '':\n            return\n        if selectedFilter == fileFilter[-1]:\n            import locale\n            encoding = locale.getpreferredencoding()\n            delimiter = ';'\n        with open(fileName, 'r', encoding=encoding) as csvfile:\n            app.Console.PrintMessage(f'Reading from {fileName}\\n')\n            reader = csv.DictReader(csvfile, delimiter=delimiter, skipinitialspace=True)\n            col = {}\n            # find first column titled label(s), densit(y/ies), mass(es), material(s) respectively\n            for name in ['label', 'densit', 'mass', 'material']:\n                col[name] = next((s for s in reader.fieldnames if name in s.lower()), None)\n            if col['mass'] and 'cent' in col['mass'].lower():\n                # the column was titled something like \"Center of mass\" which is not mass\n                col['mass'] = None\n            col_values_w_o_label = list(col.values())[1:]\n            reader_list = list(reader)    # make whole file accessible\n        if not col['label']:\n            error_message('Unable to find a \"Label\" column in the file.')\n            return\n        if not any(col_values_w_o_label):\n            error_message('Unable to find a \"Density\", \"Mass\" or \"Material\" column in the file.')\n            return\n        if sum(bool(x) for x in col_values_w_o_label) > 1:\n            app.Console.PrintWarning('  Material card takes precedence over mass over density\\n')\n\n        # Extract unit between round brackets\n        try:\n            unitForD = col['densit'].split('(')[1].split(')')[0]\n        except:\n            unitForD = self.unitForD\n        try:\n            unitForM = col['mass'].split('(')[1].split(')')[0]\n        except:\n            unitForM = self.unitForM\n\n        self.compute_centerOfMass(False)\n        loaded = [False] * self.solid_count    # bool list whether solids have been updated\n        reader_labels = [row[col['label']] for row in reader_list]\n\n        # Get material if not 'custom' from combobox items (0=custom) else get mass then density\n        items = [self.solids[0].combo.itemText(i) for i in range(1, self.solids[0].combo.count())]\n        items.remove('')    # remove empty item e.g. line separator\n        for sol, selfsol in enumerate(self.solids):\n            selLabel = g_sel[sol].Label\n            if selLabel in reader_labels:\n                row = reader_list[reader_labels.index(selLabel)]\n            elif selLabel[-3:].isnumeric() and selLabel[:-3] in reader_labels:\n                # admit FreeCAD's sequential numbering (001 etc.) for same objects\n                row = reader_list[reader_labels.index(selLabel[:-3])]\n            else:\n                continue\n\n            if col['material'] and row[col['material']] in items:\n                selfsol.combo.setCurrentText(row[col['material']])\n                loaded[sol] = True\n            elif col['mass'] and row[col['mass']]:\n                qty = row[col['mass']] + ' ' + unitForM\n                qty_qty = Units.Quantity(qty).getValueAs(self.unitForM)\n                selfsol.spinMass.setText(str(qty_qty))\n                selfsol.on_spinMass_edited()    # trigger update\n                loaded[sol] = True\n            elif col['densit'] and row[col['densit']]:\n                qty = row[col['densit']] + ' ' + unitForD\n                selfsol.spinDens.setValue(Units.Quantity(qty).getValueAs(self.unitForD))\n                loaded[sol] = True\n        self.compute_centerOfMass(True)\n\n        msg = str(sum(loaded)) + ' solids loaded'\n        if 0 < sum(loaded) <= self.solid_count/2:\n            msg += ': '\n            msg += str([g_sel[sol].Label for sol in range(self.solid_count) if loaded[sol]])\n        if self.solid_count/2 < sum(loaded) < self.solid_count:\n            msg += '.\\nNot loaded: '\n            msg += str([g_sel[sol].Label for sol in range(self.solid_count) if not loaded[sol]])\n        app.Console.PrintMessage(msg + '\\n')\n\n\ndef valid_density_string(string):\n    valid = False\n    try:\n        if Units.Quantity(string).Unit.Type == 'Density':\n            valid = True\n    except:\n        pass\n    return valid\n\n\ndef error_message(msg):\n    app.Console.PrintError(msg + '\\n')\n    QtGui.QMessageBox.critical(g_main_window, 'Error', msg)\n\n\nif __name__ == '__main__':\n    if not valid_density_string(DEFAULT_DENSITY):\n        app.ParamGet(MACRO_SETTINGS).RemString('Default density')\n        error_message('Default density user parameter was set wrong. Try again.')\n    elif not app.activeDocument():\n        error_message('Open a document first.')\n    else:\n        app.Console.PrintMessage(f'Loading {__Name__} {__Version__} ...' + '\\n')\n        gui.updateGui()\n        if DOCKED_WINDOW:\n            myWidget = CenterofmassDock()\n        else:\n            myWidget = CenterofmassWindow()\n",
    "url": "https://forum.freecad.org/viewtopic.php?f=24&t=31883",
    "raw_code_url": "",
    "wiki": "https://wiki.freecad.org/Macro_CenterOfMass",
    "version": "0.8.3",
    "license": "",
    "date": "2025-01-21",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Information\\CenterOfMass.FCMacro",
    "filename_from_url": "",
    "author": "chupins, s-quirin, farahats9",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_CenterOfMass.svg",
    "icon_source": "https://wiki.freecad.org/images/a/a6/Macro_CenterOfMass.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "DatumPlaneLocalAxis",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Select a datum plane in the 3D view then run, this macro will shows local axes for all selected planes or delete all created local axes if nothing is selected",
    "code": "# -*- coding: utf-8 -*-\n# view loacal axis of selected datum plane macro\n# Author: Avinash Pudale\n# License: LGPL v 2.1\n\nfrom __future__ import annotations\n\n__Name__ = 'Datum-Plane Local Axis'\n__Comment__ = 'Select a datum plane in the 3D view then run, this macro will shows local axes for all selected planes or delete all created local axes if nothing is selected'\n__Author__ = 'Avinash Pudale'\n__Date__ = '2023-08-11'\n__Version__ = '0.3.0'\n__License__ = 'LGPL-2.1'\n__Web__ = 'https://forum.freecad.org/viewtopic.php?t=79562'\n__Wiki__ = ''\n__Icon__ = 'DatumPlaneLocalAxis.svg'\n__Xpm__ = ''\n__Help__ = 'The macro will add small X-, Y-, and Z-axis representations on the selected datum planes in the 3D view. The X-axis is represented in red, the Y-axis in green, and the Z-axis in blue. To clear the axis representations, simply run the macro again without selecting anything.'\n__Status__ = 'Stable'\n__Requires__ = 'FreeCAD >=0.20'\n__Communication__ = 'https://github.com/FabLabBaramati/freecadDatumLoacalAxisMacro/issues'\n__Files__ = 'DatumPlaneLocalAxis.svg'\n\n\nimport FreeCAD as app\nimport FreeCADGui as gui\n\nimport Draft\n\n# Typing hints.\nDO = app.DocumentObject\nPL = DO  # A `PartDesign::Plane` or a `Part::Link` to a `PartDesign::Plane`.\n\n# The 3 axes representing a plane will be inside a group that\n# starts with this label.\nGROUP_LABEL = 'Datum_Plane_Axis'\n\n\ndef strip_subelement(sub_fullpath: str) -> str:\n    \"\"\"Return sub_fullpath without the last sub-element.\n\n    A sub-element is a face, edge or vertex.\n    Parameters\n    ----------\n    - subobject_fullpath: SelectionObject.SubElementNames[i], where\n        SelectionObject is obtained with gui.Selection.getSelectionEx('', 0)\n        (i.e. not gui.Selection.getSelectionEx()).\n        Examples:\n        - 'Face6' if you select the top face of a cube solid made in Part.\n        - 'Body.Box001.' if you select the tip of a Part->Body->\"additive\n            primitve\" in PartDesign.\n        - 'Body.Box001.Face6' if you select the top face of a Part->Body->\n            \"additive primitve\" in PartDesign.\n\n    \"\"\"\n    if (not sub_fullpath) or ('.' not in sub_fullpath):\n        return ''\n    return sub_fullpath.rsplit('.', maxsplit=1)[0]\n\n\ndef get_subobject_by_name(object_: app.DocumentObject,\n                          subobject_name: str,\n                          ) -> app.DocumentObject:\n    \"\"\"Return the appropriate object from object_.OutListRecursive.\"\"\"\n    for o in object_.OutListRecursive:\n        if o.Name == subobject_name:\n            return o\n\n\ndef get_subobjects_by_full_name(\n        root_object: app.DocumentObject,\n        subobject_fullpath: str,\n        ) -> list[app.DocumentObject]:\n    \"\"\"Return the list of objects from root_object excluded to the named object.\n\n    The last part of ``subobject_fullpath`` is then a specific vertex, edge or\n    face and is ignored.\n    So, subobject_fullpath has the form 'name0.name1.Edge001', for example; in\n    this case, the returned objects are\n    [object_named_name0, object_named_name1].\n\n    Parameters\n    ----------\n    - root_object: SelectionObject.Object, where SelectionObject is obtained\n        with gui.Selection.getSelectionEx('', 0)\n        (i.e. not gui.Selection.getSelectionEx()).\n    - subobject_fullpath: SelectionObject.SubElementNames[i].\n        Examples:\n        - 'Face6' if you select the top face of a cube solid made in Part.\n        - 'Body.Box001.' if you select the tip of a Part->Body->\"additive\n            primitve\" in PartDesign.\n        - 'Body.Box001.Face6' if you select the top face of a Part->Body->\n            \"additive primitve\" in PartDesign.\n\n    \"\"\"\n    objects = []\n    names = strip_subelement(subobject_fullpath).split('.')\n    subobject = root_object\n    for name in names:\n        subobject = get_subobject_by_name(subobject, name)\n        if subobject is None:\n            # This should not append.\n            return []\n        objects.append(subobject)\n    return objects\n\n\ndef get_global_placement_expression(\n        root_object: app.DocumentObject,\n        subobject_fullpath: str,\n        ) -> str:\n    \"\"\"Return the global placement by recursively going through parents.\n\n    Return the expression to compute the global placement of `root_object`.\n\n    Parameters\n    ----------\n    - root_object: SelectionObject.Object, where SelectionObject is obtained\n        with gui.Selection.getSelectionEx('', 0)\n        (i.e. not gui.Selection.getSelectionEx()).\n    - subobject_fullpath: SelectionObject.SubElementNames[i].\n        Examples:\n        - 'Face6' if you select the top face of a cube solid made in Part.\n        - 'Body.Box001.' if you select the tip of a Part->Body->\"additive\n            primitve\" in PartDesign.\n        - 'Body.Box001.Face6' if you select the top face of a Part->Body->\n            \"additive primitve\" in PartDesign.\n\n    \"\"\"\n    objects = get_subobjects_by_full_name(root_object, subobject_fullpath)\n    expr = f'{root_object.Name}.Placement'\n    for o in objects:\n        expr += f' * {o.Name}.Placement'\n    return expr\n\n\ndef _add_local_axis_to_plane(\n        plane_or_link: app.DocumentObject,\n        placement_expression: str,\n        ) -> None:\n    \"\"\"Add the local axis to the plane or link.\"\"\"\n    doc = plane_or_link.Document\n    # Implementation note: returns self for non-links.\n    plane = plane_or_link.getLinkedObject()\n\n    # Create a group to contain the axis representations.\n    group = doc.addObject('App::DocumentObjectGroup',\n                          f'{GROUP_LABEL}_{plane_or_link.Name}')\n\n    # Size of the line representing an axis.\n    size = 0.95 * min(plane.Length, plane.Width) / 2.0\n\n    labels_points_colors = (\n        ('x', app.Vector(size, 0.0, 0.0), (1.0, 0.0, 0.0)),  # Red.\n        ('y', app.Vector(0.0, size, 0.0), (0.0, 1.0, 0.0)),  # Green.\n        ('z', app.Vector(0.0, 0.0, size), (0.0, 0.0, 1.0)),  # Blue.\n        )\n\n    for label, point, color in labels_points_colors:\n        # Create Draft objects for the axis.\n        axis = Draft.makeLine(app.Vector(0.0, 0.0, 0.0), point)\n        axis.Label = label\n\n        # Set the placements for the axis representations\n        axis.setExpression('Placement', placement_expression)\n        axis.setPropertyStatus('Placement', ['ReadOnly'])\n\n        axis.ViewObject.DisplayMode = 'Wireframe'\n\n        axis.ViewObject.LineColor = color\n        axis.ViewObject.PointColor = color\n\n        # Add the axis representations as child objects to the group\n        group.addObject(axis)\n\n\ndef add_local_axis():\n    doc = app.activeDocument()\n\n    if not doc:\n        return\n\n    # Check if a datum plane is selected in the tree view.\n    selection = gui.Selection.getSelectionEx('', 0)\n\n    if not selection:\n        # Delete all axis representations if no object is selected.\n        objs_to_delete: list[DO] = []\n        for obj in doc.Objects:\n            if (obj.isDerivedFrom('App::DocumentObjectGroup')\n                    and obj.Label.startswith(GROUP_LABEL)):\n                for child_obj in obj.Group:\n                    objs_to_delete.append(child_obj)\n                objs_to_delete.append(obj)\n        # Delete the groups and lines.\n        for obj in objs_to_delete:\n            doc.removeObject(obj.Name)\n        doc.recompute()\n        return\n\n    # The list of selected planes (or links to a plane).\n    planes_or_links: set[PL] = set()\n    # For each plane, the expressions to place the axis representations.\n    placement_expression: dict[PL] = {}\n    for sel_obj in selection:\n        obj = sel_obj.Object\n        sub_fullpaths = sel_obj.SubElementNames\n        if not sub_fullpaths:\n            # Cannot be a datum plane because the plane itself must be\n            # the last element of `sub_fullpaths`.\n            continue\n        sub_fullpath = sub_fullpaths[0]\n        objects = get_subobjects_by_full_name(obj, sub_fullpath)\n        if ((not objects)\n                or (not hasattr(objects[-1], 'isDerivedFrom'))\n                or (not hasattr(objects[-1], 'getLinkedObject'))):\n            # Cannot be a datum plane.\n            continue\n        plane_or_link = objects[-1]\n        # Implementation note: returns self for non-links.\n        plane = plane_or_link.getLinkedObject()\n        if not plane.isDerivedFrom('PartDesign::Plane'):\n            continue\n        planes_or_links.add(plane_or_link)\n        placement_expression[plane_or_link] = get_global_placement_expression(\n                obj, sub_fullpath)\n\n    for plane_or_link in planes_or_links:\n        _add_local_axis_to_plane(plane_or_link,\n                                 placement_expression[plane_or_link])\n\n    doc.recompute()\n\n\nif __name__ == '__main__':\n    add_local_axis()\n",
    "url": "https://forum.freecad.org/viewtopic.php?t=79562",
    "raw_code_url": "",
    "wiki": "",
    "version": "0.3.0",
    "license": "",
    "date": "2023-08-11",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Information\\DatumPlaneLocalAxis.FCMacro",
    "filename_from_url": "",
    "author": "Avinash Pudale",
    "icon": "DatumPlaneLocalAxis.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "DatumPlaneLocalAxis.svg"
    ],
    "parsed": true
  },
  {
    "name": "GetGlobalPlacement",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Get the global placement, respecting links, link arrays and link scale",
    "code": "\"\"\"Get the global placement of selected objects, respecting links.\"\"\"\n# Usage: select some objects or some subelements, run and get the result in the\n# Report View.\n\n__Name__ = 'Get Global Placement'\n__Comment__ = 'Get the global placement, respecting links, link arrays and link scale'\n__Author__ = 'galou_breizh, Jolbas'\n__Version__ = '1.1.2'\n__Date__ = '2023-02-27'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = '' #'http://forum.freecadweb.org/viewtopic.php?f=?&t=????'\n__Wiki__ = '' #'http://www.freecadweb.org/wiki/Macro_Title_Of_macro'\n__Icon__ = ''\n__Help__ = 'Select some objects or some subelements and run'\n__Status__ = ''\n__Requires__ = 'FreeCAD >=0.21'\n__Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'\n__Files__ = 'GetGlobalPlacement.svg'\n\nfrom math import copysign, hypot\nfrom typing import Set, Tuple\n\nimport FreeCAD as app\nimport FreeCADGui as gui\n\n\ndef strip_subelement(sub_fullpath: str) -> str:\n    \"\"\"Return sub_fullpath without the last sub-element.\n\n    A sub-element is a face, edge or vertex.\n\n    Parameters\n    ----------\n    - subobject_fullpath: SelectionObject.SubElementNames[i], where\n        SelectionObject is obtained with gui.Selection.getSelectionEx('', 0)\n        (i.e. not gui.Selection.getSelectionEx()).\n        Examples:\n        - 'Face6' if you select the top face of a cube solid made in Part.\n        - 'Body.Box001.' if you select the tip of a Part->Body->\"additive\n            primitve\" in PartDesign.\n        - 'Body.Box001.Face6' if you select the top face of a Part->Body->\n            \"additive primitve\" in PartDesign.\n\n    \"\"\"\n    return sub_fullpath.rpartition('.')[0]\n\n\ndef get_global_placement_and_scale(\n        object: app.DocumentObject,\n        subobject_fullpath: str,\n        ) -> Tuple[app.Placement, app.Vector]:\n    \"\"\"Return the global placement and the total scale, respecting links.\n    Returns the placement and scale the objects content is related to,\n    which means the properties LinkTransform and Scale is respected if\n    path points to a link.\n\n    This is in contrast with ``object.getGlobalPlacement()`` that returns\n    the placement of the original object, not the linked one.\n\n    Parameters\n    ----------\n    - root_object: SelectionObject.Object, where SelectionObject is obtained\n        with gui.Selection.getSelectionEx('', 0)\n        (i.e. not gui.Selection.getSelectionEx()).\n    - subobject_fullpath: SelectionObject.SubElementNames[i].\n        Examples:\n        - 'Face6' if you select the top face of a cube solid made in Part.\n        - 'Body.Box001.' if you select the tip of a Part->Body->\"additive\n            primitve\" in PartDesign.\n        - 'Body.Box001.Face6' if you select the top face of a Part->Body->\n            \"additive primitve\" in PartDesign.\n    \"\"\"\n    return_type_link_matrix = 6  # Cf. DocumentObjectPyImp.cpp::getSubObject (l.417).\n    matrix = object.getSubObject(subobject_fullpath, return_type_link_matrix,\n                                 transform=True)\n    if matrix is None:\n        return\n    scale_type = matrix.hasScale(1e-5)\n    if scale_type == app.ScaleType.NoScaling:\n        return app.Placement(matrix), app.Vector(1.0, 1.0, 1.0)\n    if scale_type != app.ScaleType.Uniform:\n        app.Console.PrintWarning('Non-uniform scaling not supported\\n')\n        return\n    app.Console.PrintWarning('Uniform scaling may give wrong results, use with care\\n')\n    # Find scale.\n    # Works only if uniform?\n    s_gen = (copysign(hypot(*matrix.col(i)), matrix.col(i)[i])\n             for i in range(3))\n    scale_vec = app.Vector(*s_gen)\n    # Workaround for scale affecting rotation\n    # see https://forum.freecad.org/viewtopic.php?t=75448\n    # Remove the scale from the rotation.\n    position = matrix.col(3)\n    matrix.setCol(3, app.Vector())\n    matrix.scale(*(1/s for s in scale_vec))\n    matrix.setCol(3, position)\n    return app.Placement(matrix), scale_vec\n\n\ndef get_global_placement(\n        object: app.DocumentObject,\n        subobject_fullpath: str,\n        ) -> app.Placement:\n    \"\"\"Return the global placement respecting links.\n    Returns the placement the objects content is related to, which means\n    the properties LinkTransform is respected if path points to a link.\n\n    This is in contrast with ``object.getGlobalPlacement()`` that returns\n    the placement of the original object, not the linked one.\n\n    Parameters\n    ----------\n    - root_object: SelectionObject.Object, where SelectionObject is obtained\n        with gui.Selection.getSelectionEx('', 0)\n        (i.e. not gui.Selection.getSelectionEx()).\n    - subobject_fullpath: SelectionObject.SubElementNames[i].\n        Examples:\n        - 'Face6' if you select the top face of a cube solid made in Part.\n        - 'Body.Box001.' if you select the tip of a Part->Body->\"additive\n            primitve\" in PartDesign.\n        - 'Body.Box001.Face6' if you select the top face of a Part->Body->\n            \"additive primitve\" in PartDesign.\n    \"\"\"\n    p_and_s = get_global_placement_and_scale(object, subobject_fullpath)\n    if p_and_s is None:\n        return\n    return p_and_s[0]\n\n\ndef print_placement(object_name: str,\n                    sub_fullpath: str,\n                    placement: app.Placement,\n                    ) -> None:\n    \"\"\"Pretty-print a placement in the console.\"\"\"\n    dot = '.' if sub_fullpath else ''\n    if placement:\n        app.Console.PrintMessage(\n            f'{object_name}{dot}{sub_fullpath}:'\n            + (' {b.x:.3f}, {b.y:.3f}, {b.z:.3f};'\n               ' {q[0]:.4f}, {q[1]:.4f}, {q[2]:.4f}, {q[3]:.4f};'\n               ' App.Placement(App.Vector({b.x:.3f}, {b.y:.3f}, {b.z:.3f}),'\n               ' App.Rotation({q[0]:.5f}, {q[1]:.5f}, {q[2]:.5f}, {q[3]:.5f}));'\n              ).format(\n                   b=placement.Base,\n                   q=placement.Rotation.Q)\n            + ' (rpy: {r[2]:.2f}, {r[1]:.2f}, {r[0]:.2f}) deg'.format(\n                r=placement.Rotation.getYawPitchRoll())\n            + '\\n')\n    else:\n        app.Console.PrintMessage(\n            f'{object_name}{dot}{sub_fullpath}:'\n            + 'Couldn\\'t find the placement\\n')\n\n\ndef get_and_print_selected_placements():\n    \"\"\"Get selected objects and print their placement.\"\"\"\n    doc = app.activeDocument()\n    if doc is None:\n        return\n\n    selection = gui.Selection.getSelectionEx('', 0)\n    if not selection:\n        app.Console.PrintWarning('Nothing selected, nothing to do\\n')\n        return\n\n    shown_paths: Set[str] = set()\n    for selection_object in selection:\n        object_ = selection_object.Object\n        sub_fullpaths = selection_object.SubElementNames\n        if not sub_fullpaths:\n            # An object is selected, not a face, edge, vertex.\n            placement = get_global_placement(object_, '')\n            print_placement(object_.Name, '', placement)\n            continue\n        for sub_fullpath in sub_fullpaths:\n            # One or more subelements are selected.\n            wo_subelement = strip_subelement(sub_fullpath)\n            path = object_.Name + wo_subelement\n            if not path in shown_paths:\n                shown_paths.add(path)\n                placement = get_global_placement(object_, sub_fullpath)\n                print_placement(object_.Name, wo_subelement, placement)\n\n\nif __name__ == '__main__':\n    get_and_print_selected_placements()\n",
    "url": "",
    "raw_code_url": "",
    "wiki": "",
    "version": "1.1.2",
    "license": "",
    "date": "2023-02-27",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Information\\GetGlobalPlacement.FCMacro",
    "filename_from_url": "",
    "author": "galou_breizh, Jolbas",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "GetGlobalPlacement.svg"
    ],
    "parsed": true
  },
  {
    "name": "InfoPlus",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Shows detailed information",
    "code": "# -*- coding: utf-8 -*-\n# (c) 18Turbo, 2022\n\n__Name__ = 'InfoPlus'\n__Comment__ = 'Shows detailed information'\n__Author__ = '18Turbo'\n__Version__ = '0.1.0'\n__Date__ = '2022-10-03'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'https://github.com/18turbo/infoPlusFreeCAD'\n__Wiki__ = 'https://github.com/18turbo/infoPlusFreeCAD/wiki'\n__Icon__ = 'InfoPlus.svg'\n__Help__ = ''\n__Status__ = 'beta'\n__Requires__ = 'FreeCAD >= v0.20'\n__Contact__ = 'https://github.com/18turbo'\n__Communication__ = 'https://github.com/18turbo/infoPlusFreeCAD/issues'\n__Files__ = 'InfoPlus.svg,InfoPlus/ui/InfoPlus.ui'\n\n\n# (En espa\u00f1ol:)\n\n# Autor:            18Turbo\n# Fecha inicial:  22-08-2022\n# Versi\u00f3n:          0.1.0 BETA\n#\n# Funcionalidad:    Muestra datos detallados del objeto seleccionado\n#\n# Notas de versiones:\n# v.0.1.0:        Adaptaci\u00f3n al Addon Manager\n#                Traducci\u00f3n al ingl\u00e9s\n#                Deshabilitaci\u00f3n la informaci\u00f3n que no se muestra\n# v.0.0.6:        Mejora visual de la interfaz\n# v.0.0.5:        Mejora de la presentaci\u00f3n de algunos datos\n#                Implementaci\u00f3n de la masa\n#                Todos los textos seleccionables\n#                Presentaci\u00f3n de todos los v\u00e9rtices del objeto\n#                Presentaci\u00f3n de todas las aristas del objeto\n# v.0.0.4:        Nuevos objetos para mostrar informaci\u00f3n, y m\u00e1s informaci\u00f3n\n# v.0.0.3:        Otra pesta\u00f1a de informaci\u00f3n, mejora de los datos\n# v.0.0.2:        Mejora presentaci\u00f3n de los datos\n# v.0.0.1:      Informaci\u00f3n del Bounding Box, \u00e1rea, volumen, ubicaci\u00f3n, longitud.\n#\n#\n# --------------------------------------------------------------------------------------------------------\n# Agradecimiento especial a Rocco Vicedomini, por la traducci\u00f3n al ingl\u00e9s e italiano.\n# ----------------------------------------------------------------------------------------------------------\n#\n#\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nfrom PySide import QtCore, QtGui, QtUiTools\n\npathMacro = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")\npathUI = pathMacro.GetString(\"MacroPath\",\"\") + \"/InfoPlus/ui/InfoPlus.ui\"\n\nprincipio = \" (\"\nfin = \")\"\niniRichText = '<html><head/><body><p>'\nred = '<span style=\" color:#cc0000;\">'\nblue = '<span style=\" color:#0000cc;\">'\ngreen = '<span style=\" color:#4e9a06;\">'\nfColor = '</span>'\nbold = '<strong>'\nfBold = '</strong>'\nfinRichText = '</p></body></html>'\n\nstrLang = [\n    [ # Espa\u00f1ol\n\n        \"InfoPlus\",                 # DON'T CHANGE\n        \"Versi\u00f3n:\",\n        \"B\u00e1sico\",\n        \"\u00c1REA:\",\n        \"VOLUMEN:\",\n        \"MASA:\",\n        \"Ubicaci\u00f3n Base:\",\n        \"X:\",\n        \"Y:\",\n        \"Z:\",\n        \"Long. Origen:\",            # Longitud al Origen\n        \"Longitud:\",\n        \"Centro de Masas:\",\n        \"X:\",\n        \"Y:\",\n        \"Z:\",\n        \"Centro de Gravedad:\",\n        \"X:\",\n        \"Y:\",\n        \"Z:\",\n        \"BBox\",                    # DON'T CHANGE\n        \"Cuadro Delimitador\",      #21\n        \"M\u00ednimo en X:\",\n        \"M\u00e1ximo en X:\",\n        \"Longitud en X:\",\n        \"M\u00ednimo en Y:\",\n        \"M\u00e1ximo en Y:\",\n        \"Longitud en Y:\",\n        \"M\u00ednimo en Z:\",\n        \"M\u00e1ximo en Z:\",\n        \"Longitud en Z:\",\n        \"Coordenadas del Centro:\",\n        \"X:\",\n        \"Y:\",\n        \"Z:\",\n        \"Longitud de la diagonal del cuadro delimitador:\",\n        \"Comp\",                                                # ABBREVIATION FOR: Composici\u00f3n\n        \"COMPOSICI\u00d3N DEL OBJETO\",\n        \"V\u00e9rtices (Vertexes):\",\n        \"Ejes/Aristas (Edges):\",\n        \"Alambres (Wires):\",\n        \"Caras (Faces):\",\n        \"V\u00e9rtices\",\n        \"Coordenadas de los v\u00e9rtices:\",\n        \"Ejes/Aristas\",\n        \"V\u00e9rtices de las Aristas:\",\n        \"Longitudes de las Aristas:\",\n        \"Masas de las Aristas:\",\n        \"Subformas (Subshapes):\",\n        \"Compuestos (Compounds):\",\n        \"Fundas (Shells):\",\n        \"S\u00f3lidos (Solids):\",\n        \"Img\",                                                  # ABBREVIATION FOR: Imagen\n        \"IMAGEN\",\n        \"Tama\u00f1o de X:\",\n        \"Tama\u00f1o de Y:\",\n        \"Ruta de la imagen (puede mostrar la ruta de cach\u00e9 de FreeCAD)\",\n        \"Datos\",\n        \"Nombre del Objeto\",\n        \"Nombre INTERNO del Objeto\",\n        \"Nombre completo del Objeto\",\n        \"Nombre del Objeto\",\n        \"Identificador\",\n        \"Visibilidad:\",\n        \"V\u00e9rtice\",\n        \"Ejes/Aristas\",\n        \"Visible\",\n        \"Oculto\",\n        \"Debe seleccionar un solo objeto adecuado\",\n        \"Coordenadas de los v\u00e9rtices:\",\n        \"V\u00e9rtices de las Aristas:\",\n        \"Longitudes de las Aristas:\",\n        \"Masas de las Aristas:\",\n        \"\u00a1Es un s\u00f3lido!\",\n        \"Arista\"\n\n    ],\n    [ # English\n        ## Strings for translation into any language (English Strings)\n        \"InfoPlus\",                 # DON'T CHANGE\n        \"Version:\",\n        \"Basic:\",\n        \"AREA:\",\n        \"VOLUME:\",\n        \"MASS:\",\n        \"Base placement:\",\n        \"X:\",\n        \"Y:\",\n        \"Z:\",\n        \"Dist. to Origin:\",            # Longitud al Origen\n        \"Lenght:\",\n        \"Centre of mass:\",\n        \"X:\",\n        \"Y:\",\n        \"Z:\",\n        \"Centre of gravity:\",\n        \"X:\",\n        \"Y:\",\n        \"Z:\",\n        \"BBox\",                    # DON'T CHANGE\n        \"Bounding box\",      #21\n        \"Minimum X value:\",\n        \"Maximum X value:\",\n        \"Lenght X:\",\n        \"Minimum Y value:\",\n        \"Maximum Y value:\",\n        \"Lenght Y:\",\n        \"Mimimum Z value:\",\n        \"Maximum Z value:\",\n        \"Lenght Z:\",\n        \"Coordinates of centre:\",\n        \"X:\",\n        \"Y:\",\n        \"Z:\",\n        \"Lenght of the bounding box diagonal:\",\n        \"Comp\",                                                # ABBREVIATION FOR: Composition\n        \"OBJECT COMPOSITION\",\n        \"Vertices:\",\n        \"Edges:\",\n        \"Wires:\",\n        \"Faces:\",\n        \"Vertices\",\n        \"Vertex coordinates:\",\n        \"Axis/Edges\",\n        \"Vertices of edge:\",\n        \"Edge lenght:\",\n        \"Edge mass:\",\n        \"Subshapes:\",\n        \"Compounds:\",\n        \"Shells:\",\n        \"Solids:\",\n        \"Img\",                                                  # ABBREVIATION FOR: Image\n        \"IMAGE\",\n        \"X size:\",\n        \"Y size:\",\n        \"Image path: (it could display the path of FreeCAD cache)\",\n        \"Data\",\n        \"Object name\",\n        \"Object internal name\",\n        \"Object full name\",\n        \"Object name\",\n        \"Identifier\",\n        \"Visibility:\",\n        \"Vertex\",\n        \"Axis/Edges\",\n        \"Visible\",\n        \"Hidden\",\n        \"Select only one suitable object\",\n        \"Vertex coordinates:\",\n        \"Vertices of edge:\",\n        \"Edge lenght:\",\n        \"Edge mass:\",\n        \"\u00a1It is a solid!\",\n        \"Edge\"\n    ],\n    [    # Italian\n        \"InfoPlus\",                 # DON'T CHANGE\n        \"Versione:\",\n        \"Principale\",\n        \"AREA:\",\n        \"VOLUME:\",\n        \"MASSA:\",\n        \"Posizione base:\",\n        \"X:\",\n        \"Y:\",\n        \"Z:\",\n        \"Dist. dall'Origine:\",            # Longitud al Origen\n        \"Distanza:\",\n        \"Centro di massa:\",\n        \"X:\",\n        \"Y:\",\n        \"Z:\",\n        \"Centro di gravit\u00e0:\",\n        \"X:\",\n        \"Y:\",\n        \"Z:\",\n        \"BBox\",                    # DON'T CHANGE\n        \"Quadro contenitore\",      #21\n        \"Minimo in X:\",\n        \"Massimo in X:\",\n        \"Lunghezza in X:\",\n        \"Minimo in Y :\",\n        \"Massimo in Y:\",\n        \"Lunghezza in Y:\",\n        \"Mimimo in Z:\",\n        \"Massimo in Z:\",\n        \"Lunghezza in Z:\",\n        \"Coordinate del centro:\",\n        \"X:\",\n        \"Y:\",\n        \"Z:\",\n        \"Lunghezza della diagonale del quadro contenitore:\",\n        \"Comp\",                                                # ABBREVIATION FOR: Composizione\n        \"COMPOSIZIONE DELL'OGGETTO\",\n        \"Vertici (Vertices):\",\n        \"Contorni (Edges):\",\n        \"Fili (Wires):\",\n        \"Facce (Faces):\",\n        \"Vertici\",\n        \"Coordinates dei vertici:\",\n        \"Assi/Contorni\",\n        \"Vertici dei contorni:\",\n        \"Lunghezza dei contorni:\",\n        \"Massa dei contorni:\",\n        \"Forme inferiori (Subshapes):\",\n        \"Composti (Compounds):\",\n        \"Gusci (Shells):\",\n        \"Solidi (Solids):\",\n        \"Img\",                                                  # ABBREVIATION FOR: Image\n        \"IMMAGINE\",\n        \"Dimensione in X:\",\n        \"Dimensione in Y:\",\n        \"Percorso dell'immagine: (pu\u00f2 visualizzare il percorso della cache di FreeCAD)\",\n        \"Dati\",\n        \"Nome dell'Oggetto\",\n        \"Nome INTERNO dell'oggetto\",\n        \"Nome completo dell'Oggetto\",\n        \"NNome delel'Oggetto\",\n        \"Identificatore\",\n        \"Visibilit\u00e0:\",\n        \"Verticec\",\n        \"Assi/Contorni\",\n        \"Visibile\",\n        \"Nascosto\",\n        \"Seleziona un solo oggetto idoneo\",\n        \"Coordinates dei vertici:\",\n        \"Vertici dei contorni:\",\n        \"Lunghezza dei contorni:\",\n        \"Massa dei contorni:\",\n        \"\u00a1E' un solido!\",\n        \"Contorni\"\n    ]\n        ]\n\nclass InfoPlus:\n\n    def __init__(self):\n        self.form = FreeCADGui.PySideUic.loadUi(pathUI)\n        self.initStrings()\n\n        tipo = seleccion[0].TypeId\n        #Ubicaci\u00f3n\n        if ((tipo.find('Sketcher::')>-1) or (tipo.find('PartDesign')>-1) or (tipo.find('Part::')>-1) or (tipo.find('Image::ImagePlane') >-1)\n                or (tipo.find('App::Part')>-1) ):\n            self.form.tab.setEnabled(True)\n            self.ubicacion()\n            # Ubicaci\u00f3n (Longitud)\n            if (tipo.find('PartDesign::Plane')>-1):\n                self.longitud()\n        #Bounding Box\n        if (tipo.find('Sketcher::')>-1) or (tipo.find('PartDesign')>-1) or (tipo.find('Part::')>-1):\n            self.form.tab.setEnabled(True)\n            self.boundbox()\n        #Composici\u00f3n\n        if (tipo.find('Sketcher::')>-1) or (tipo.find('PartDesign')>-1) or (tipo.find('Part::')>-1):\n            self.form.tab.setEnabled(True)\n            self.composicion()\n        #\u00c1rea y Volumen\n        if (tipo.find('Sketcher::')>-1) or (tipo.find('PartDesign')>-1) or (tipo.find('Part::')>-1):\n            self.form.tab.setEnabled(True)\n            self.areaVolumen()\n        #Masa\n        if (tipo.find('PartDesign')>-1):\n            self.form.tab.setEnabled(True)\n            self.masa()\n        #Centro de Masas\n        if (tipo.find('Sketcher::')>-1) or (tipo.find('PartDesign')>-1):\n            self.form.tab.setEnabled(True)\n            self.centroMasas()\n        #Centro de Gravedad\n        if (tipo.find('Sketcher::')>-1) or (tipo.find('PartDesign')>-1):\n            self.form.tab.setEnabled(True)\n            self.centroGravedad()\n        #Imagen\n        if (tipo.find('Image::ImagePlane') >-1):\n            self.form.tab.setEnabled(True)\n            self.dimImagenes()\n        #Datos\n        if ((tipo.find('Sketcher::')>-1) or (tipo.find('PartDesign')>-1) or (tipo.find('Part::')>-1) or (tipo.find('Image::ImagePlane') >-1)\n                or (tipo.find('App::Part')>-1) ):\n            self.form.tab.setEnabled(True)\n            self.datos()\n\n    def initStrings(self):\n        tr = self.translate\n        self.form.setWindowTitle(objetoSeleccion.Label)\n        self.form.etInfoPlus.setText(__Name__)\n        self.form.etVersion.setText(tr(\"Versi\u00f3n:\"))\n        self.form.version.setText(__Version__)\n        self.form.tipoVersion.setText(__Status__)\n        self.form.tab.addTab(self.form.basicos, tr(\"B\u00e1sico\"))\n        self.form.tab.addTab(self.form.boundingbox, tr(\"BBox\"))\n        self.form.tab.addTab(self.form.composicion, tr(\"Comp.\"))\n        self.form.tab.addTab(self.form.imagen, tr(\"Img\"))\n        self.form.tab.addTab(self.form.tabDatos, tr(\"Datos\"))\n\n        #B\u00e1sicos\n        self.form.etArea.setText(tr(\"\u00c1REA:\"))\n        self.form.etArea.setEnabled(False)\n        self.form.area.setEnabled(False)\n        self.form.etVolumen.setText(tr(\"VOLUMEN:\"))\n        self.form.etVolumen.setEnabled(False)\n        self.form.volumen.setEnabled(False)\n        self.form.etMasa.setText(tr(\"MASA:\"))\n        self.form.etMasa.setEnabled(False)\n        self.form.masa.setEnabled(False)\n        self.form.etUbicacion.setText(iniRichText + bold + tr(\"Ubicaci\u00f3n Base:\") + fBold + finRichText)\n        self.form.etUbicacion.setEnabled(False)\n        self.form.etUbx.setText(iniRichText + bold + red + tr(\"X:\") + fColor + fBold + finRichText)\n        self.form.etUbx.setEnabled(False)\n        self.form.ubx.setEnabled(False)\n        self.form.etUby.setText(iniRichText + bold + green + tr(\"Y:\") + fColor + fBold + finRichText)\n        self.form.etUby.setEnabled(False)\n        self.form.uby.setEnabled(False)\n        self.form.etUbz.setText(iniRichText + bold + blue + tr(\"Z:\") + fColor + fBold + finRichText)\n        self.form.etUbz.setEnabled(False)\n        self.form.ubz.setEnabled(False)\n        self.form.etUblon.setText(tr(\"Long. Origen:\"))\n        self.form.etUblon.setEnabled(False)\n        self.form.lonBase.setEnabled(False)\n        self.form.etLon.setText(iniRichText + bold + tr(\"Longitud:\") + fBold + finRichText)\n        self.form.etLon.setEnabled(False)\n        self.form.longitud.setEnabled(False)\n        self.form.etCMasas.setText(iniRichText + bold + tr(\"Centro de Masas:\") + fBold + finRichText)\n        self.form.etCMasas.setEnabled(False)\n        self.form.etCmx.setText(iniRichText + bold + red + tr(\"X:\") + fColor + fBold + finRichText)\n        self.form.etCmx.setEnabled(False)\n        self.form.cmx.setEnabled(False)\n        self.form.etCmy.setText(iniRichText + bold + green + tr(\"Y:\") + fColor + fBold + finRichText)\n        self.form.etCmy.setEnabled(False)\n        self.form.cmy.setEnabled(False)\n        self.form.etCmz.setText(iniRichText + bold + blue + tr(\"Z:\") + fColor + fBold + finRichText)\n        self.form.etCmz.setEnabled(False)\n        self.form.cmz.setEnabled(False)\n        self.form.etCg.setText(iniRichText + bold + tr(\"Centro de Gravedad:\") + fBold + finRichText)\n        self.form.etCg.setEnabled(False)\n        self.form.etCgx.setText(iniRichText + bold + red + tr(\"X:\") + fColor + fBold + finRichText)\n        self.form.etCgx.setEnabled(False)\n        self.form.cgx.setEnabled(False)\n        self.form.etCgy.setText(iniRichText + bold + green + tr(\"Y:\") + fColor + fBold + finRichText)\n        self.form.etCgy.setEnabled(False)\n        self.form.cgy.setEnabled(False)\n        self.form.etCgz.setText(iniRichText + bold + blue + tr(\"Z:\") + fColor + fBold + finRichText)\n        self.form.etCgz.setEnabled(False)\n        self.form.cgz.setEnabled(False)\n\n        # Bounding Box\n        if g_num_lang != 1:\n            titleBb = \"(\" + strLang[g_num_lang][21] + \")\"\n        else:\n            titleBb = \"\"\n        self.form.etBb.setText(iniRichText + bold + \"BOUNDING BOX\" + titleBb + fBold + finRichText)\n        self.form.etMinx.setText(iniRichText + bold + tr(\"M\u00ednimo en X:\") + fBold + finRichText)\n        self.form.etMinx.setEnabled(False)\n        self.form.minx.setEnabled(False)\n        self.form.etMaxx.setText(iniRichText + bold + tr(\"M\u00e1ximo en X:\") + fBold + finRichText)\n        self.form.etMaxx.setEnabled(False)\n        self.form.maxx.setEnabled(False)\n        self.form.etLonx.setText(iniRichText + bold + tr(\"Longitud en X:\") + fBold + finRichText)\n        self.form.etLonx.setEnabled(False)\n        self.form.lonx.setEnabled(False)\n        self.form.etMiny.setText(iniRichText + bold + tr(\"M\u00ednimo en Y:\") + fBold + finRichText)\n        self.form.etMiny.setEnabled(False)\n        self.form.miny.setEnabled(False)\n        self.form.etMaxy.setText(iniRichText + bold + tr(\"M\u00e1ximo en Y:\") + fBold + finRichText)\n        self.form.etMaxy.setEnabled(False)\n        self.form.maxy.setEnabled(False)\n        self.form.etLony.setText(iniRichText + bold + tr(\"Longitud en Y:\") + fBold + finRichText)\n        self.form.etLony.setEnabled(False)\n        self.form.lony.setEnabled(False)\n        self.form.etMinz.setText(iniRichText + bold + tr(\"M\u00ednimo en Z:\") + fBold + finRichText)\n        self.form.etMinz.setEnabled(False)\n        self.form.minz.setEnabled(False)\n        self.form.etMaxz.setText(iniRichText + bold + tr(\"M\u00e1ximo en Z:\") + fBold + finRichText)\n        self.form.etMaxz.setEnabled(False)\n        self.form.maxz.setEnabled(False)\n        self.form.etLonz.setText(iniRichText + bold + tr(\"Longitud en Z:\") + fBold + finRichText)\n        self.form.etLonz.setEnabled(False)\n        self.form.lonz.setEnabled(False)\n        self.form.etCentro.setText(iniRichText + bold + tr(\"Coordenadas del Centro:\") + fBold + finRichText)\n        self.form.etCentrox.setText(iniRichText + bold + red + tr(\"X:\") + fColor + fBold + finRichText)\n        self.form.etCentrox.setEnabled(False)\n        self.form.centrox.setEnabled(False)\n        self.form.etCentroy.setText(iniRichText + bold + green + tr(\"Y:\") + fColor + fBold + finRichText)\n        self.form.etCentroy.setEnabled(False)\n        self.form.centroy.setEnabled(False)\n        self.form.etCentroz.setText(iniRichText + bold + blue + tr(\"Z:\") + fColor + fBold + finRichText)\n        self.form.etCentroz.setEnabled(False)\n        self.form.centroz.setEnabled(False)\n        self.form.etDiabb.setText(iniRichText + bold + tr(\"Longitud de la diagonal del cuadro delimitador:\") + fBold + finRichText)\n        self.form.etDiabb.setEnabled(False)\n        self.form.diabb.setEnabled(False)\n\n        #Composici\u00f3n\n        self.form.etComposicion.setText(iniRichText + bold + tr(\"COMPOSICI\u00d3N DEL OBJETO\") + fBold + finRichText)\n        self.form.etVertices.setText(iniRichText + bold + tr(\"V\u00e9rtices (Vertexes):\") + fBold + finRichText)\n        self.form.etVertices.setEnabled(False)\n        self.form.vertices.setEnabled(False)\n        self.form.etEjes.setText(iniRichText + bold + tr(\"Ejes/Aristas (Edges):\") + fBold + finRichText)\n        self.form.etEjes.setEnabled(False)\n        self.form.ejes.setEnabled(False)\n        self.form.etAlambres.setText(iniRichText + bold + tr(\"Alambres (Wires):\") + fBold + finRichText)\n        self.form.etAlambres.setEnabled(False)\n        self.form.alambres.setEnabled(False)\n        self.form.etCaras.setText(iniRichText + bold + tr(\"Caras (Faces):\") + fBold + finRichText)\n        self.form.etCaras.setEnabled(False)\n        self.form.caras.setEnabled(False)\n\n        self.form.tabComp.addTab(self.form.tabVertices, tr(\"V\u00e9rtices\"))\n        self.form.etComboVertices.setText(tr(\"Coordenadas de los v\u00e9rtices:\"))\n        self.form.etComboVertices.setEnabled(False)\n        self.form.comboVertices.setEnabled(False)\n        self.form.tabComp.addTab(self.form.tabEjes, tr(\"Ejes/Aristas\"))\n        self.form.etComboEjes.setText(tr(\"V\u00e9rtices de las Aristas:\"))\n        self.form.etComboEjes.setEnabled(False)\n        self.form.comboEjes.setEnabled(False)\n        self.form.etComboEjesLongitudes.setText(tr(\"Longitudes de las Aristas:\"))\n        self.form.etComboEjesLongitudes.setEnabled(False)\n        self.form.comboEjesLongitudes.setEnabled(False)\n        self.form.etComboEjesMasas.setText(tr(\"Masas de las Aristas:\"))\n        self.form.etComboEjesMasas.setEnabled(False)\n        self.form.comboEjesMasas.setEnabled(False)\n\n        self.form.etSubformas.setText(iniRichText + bold + tr(\"Subformas (Subshapes):\") + fBold + finRichText)\n        self.form.etSubformas.setEnabled(False)\n        self.form.subformas.setEnabled(False)\n        self.form.etCompuestos.setText(iniRichText + bold + tr(\"Compuestos (Compounds):\") + fBold + finRichText)\n        self.form.etCompuestos.setEnabled(False)\n        self.form.compuestos.setEnabled(False)\n        self.form.etFundas.setText(iniRichText + bold + tr(\"Fundas (Shells):\") + fBold + finRichText)\n        self.form.etFundas.setEnabled(False)\n        self.form.fundas.setEnabled(False)\n        self.form.etSolidos.setText(iniRichText + bold + tr(\"S\u00f3lidos (Solids):\") + fBold + finRichText)\n        self.form.etSolidos.setEnabled(False)\n        self.form.solidos.setEnabled(False)\n\n        # Imagen\n        self.form.etImagen.setText(iniRichText + bold + tr(\"IMAGEN\") + fBold + finRichText)\n        self.form.etImgx.setText(iniRichText + bold + tr(\"Tama\u00f1o de X:\") + fBold + finRichText)\n        self.form.etImgx.setEnabled(False)\n        self.form.imgx.setEnabled(False)\n        self.form.etImgy.setText(iniRichText + bold + tr(\"Tama\u00f1o de Y:\") + fBold + finRichText)\n        self.form.etImgy.setEnabled(False)\n        self.form.imgy.setEnabled(False)\n        self.form.etRutaImagen.setText(iniRichText + bold + tr(\"Ruta de la imagen (puede mostrar la ruta de cach\u00e9 de FreeCAD)\") + fBold + finRichText)\n        self.form.etRutaImagen.setEnabled(False)\n        self.form.rutaImagen.setEnabled(False)\n\n        # Datos\n        self.form.etDatoLabel.setText(iniRichText + tr(\"Nombre del Objeto\") + bold + \" (Label):\" + fBold + finRichText)\n        self.form.etDatoLabel.setEnabled(False)\n        self.form.datoLabel.setEnabled(False)\n        self.form.etDatoName.setText(iniRichText + tr(\"Nombre INTERNO del Objeto\") + bold + \" (Name):\" + fBold + finRichText)\n        self.form.etDatoName.setEnabled(False)\n        self.form.datoName.setEnabled(False)\n        self.form.etDatoFullName.setText(iniRichText + tr(\"Nombre completo del Objeto\") + bold + \" (FullName):\" + fBold + finRichText)\n        self.form.etDatoFullName.setEnabled(False)\n        self.form.datoFullName.setEnabled(False)\n        self.form.etDatoLabel2.setText(iniRichText + tr(\"Nombre del Objeto\") + bold + \" (Label2):\" + fBold + finRichText)\n        self.form.etDatoLabel2.setEnabled(False)\n        self.form.datoLabel2.setEnabled(False)\n        self.form.etDatoId.setText(iniRichText + tr(\"Identificador\") + bold + \" (ID):\" + fBold + finRichText)\n        self.form.etDatoId.setEnabled(False)\n        self.form.datoId.setEnabled(False)\n        self.form.etDatoVisibilidad.setText(tr(\"Visibilidad:\"))\n        self.form.etDatoVisibilidad.setEnabled(False)\n        self.form.datoVisibilidad.setEnabled(False)\n\n    def translate(self, text):\n        if (text not in strLang[0]) or (g_num_lang < 0) or (g_num_lang >= len(strLang)):\n            return text\n        primerIdioma = strLang[0]\n        indice = primerIdioma.index(text)\n        if (indice == -1) or (indice >= len(strLang[g_num_lang])):\n            return text\n        return strLang[g_num_lang][indice]\n\n    def areaVolumen(self):\n        self.form.basicos.setEnabled(True)\n        areaBas = objetoSeleccion.Shape.Area\n        volumenBas = objetoSeleccion.Shape.Volume\n        self.form.area.setText(str(round(areaBas,2)) + principio + str(areaBas) + fin)\n        self.form.area.setEnabled(True)\n        self.form.etArea.setEnabled(True)\n        self.form.volumen.setText(str(round(volumenBas,2)) + principio + str(volumenBas) + fin)\n        self.form.volumen.setEnabled(True)\n        self.form.etVolumen.setEnabled(True)\n\n    def masa(self):\n        self.form.basicos.setEnabled(True)\n        mass = objetoSeleccion.Shape.Mass\n        self.form.masa.setText(str(round(mass,2)) + principio + str(mass) + fin)\n        self.form.masa.setEnabled(True)\n\n    def ubicacion(self):\n        self.form.basicos.setEnabled(True)\n        ubicacionX = objetoSeleccion.Placement.Base[0]\n        ubicacionY = objetoSeleccion.Placement.Base[1]\n        ubicacionZ = objetoSeleccion.Placement.Base[2]\n        self.form.ubx.setText(str(round(ubicacionX, 2)) + principio + str(ubicacionX) + fin)\n        self.form.ubx.setEnabled(True)\n        self.form.uby.setText(str(round(ubicacionY, 2)) + principio + str(ubicacionY) + fin)\n        self.form.uby.setEnabled(True)\n        self.form.ubz.setText(str(round(ubicacionZ, 2)) + principio + str(ubicacionZ) + fin)\n        self.form.ubz.setEnabled(True)\n        self.form.lonBase.setText(str(round(objetoSeleccion.Placement.Base.Length, 2)) + principio + str(objetoSeleccion.Placement.Base.Length) + fin)\n        self.form.lonBase.setEnabled(True)\n        self.form.etUbicacion.setEnabled(True)\n        self.form.etUblon.setEnabled(True)\n\n    def longitud(self):\n        # Length\n        self.form.basicos.setEnabled(True)\n        self.form.longitud.setText(str(objetoSeleccion.Length, 2) + principio + str(objetoSeleccion.Length) + fin)\n        self.form.longitud.setEnabled(True)\n        self.form.etLon.setEnabled(True)\n\n    def centroMasas(self):\n        # Center of Mass\n        self.form.basicos.setEnabled(True)\n        cmX = objetoSeleccion.Shape.CenterOfMass[0]\n        cmY = objetoSeleccion.Shape.CenterOfMass[1]\n        cmZ = objetoSeleccion.Shape.CenterOfMass[2]\n        self.form.cmx.setText(str(round(cmX, 2)) + principio + str(cmX) + fin)\n        self.form.cmx.setEnabled(True)\n        self.form.cmy.setText(str(round(cmY, 2)) + principio + str(cmY) + fin)\n        self.form.cmy.setEnabled(True)\n        self.form.cmz.setText(str(round(cmZ, 2)) + principio + str(cmZ) + fin)\n        self.form.cmz.setEnabled(True)\n        self.form.etCMasas.setEnabled(True)\n\n    def centroGravedad(self):\n        # Center of Gravity\n        self.form.basicos.setEnabled(True)\n        cgX = objetoSeleccion.Shape.CenterOfGravity[0]\n        cgY = objetoSeleccion.Shape.CenterOfGravity[1]\n        cgZ = objetoSeleccion.Shape.CenterOfGravity[2]\n        self.form.cgx.setText(str(round(cgX, 2)) + principio + str(cgX) + fin)\n        self.form.cgx.setEnabled(True)\n        self.form.cgy.setText(str(round(cgY, 2)) + principio + str(cgY) + fin)\n        self.form.cgx.setEnabled(True)\n        self.form.cgz.setText(str(round(cgZ, 2)) + principio + str(cgZ) + fin)\n        self.form.cgx.setEnabled(True)\n        self.form.etCg.setEnabled(True)\n\n    def boundbox(self):\n        # Bounding Box\n        self.form.boundingbox.setEnabled(True)\n        xmin = objetoSeleccion.Shape.BoundBox.XMin\n        xmax = objetoSeleccion.Shape.BoundBox.XMax\n        xlen = objetoSeleccion.Shape.BoundBox.XLength\n        self.form.minx.setText(str(round(xmin,2)) + principio + str(xmin) + fin)\n        self.form.maxx.setText(str(round(xmax,2)) + principio + str(xmax) + fin)\n        self.form.lonx.setText(str(round(xlen,2)) + principio + str(xlen) +fin)\n        self.form.etMinx.setEnabled(True)\n        self.form.minx.setEnabled(True)\n        self.form.etMaxx.setEnabled(True)\n        self.form.maxx.setEnabled(True)\n        self.form.etLonx.setEnabled(True)\n        self.form.lonx.setEnabled(True)\n\n        ymin = objetoSeleccion.Shape.BoundBox.YMin\n        ymax = objetoSeleccion.Shape.BoundBox.YMax\n        ylen = objetoSeleccion.Shape.BoundBox.YLength\n        self.form.miny.setText(str(round(ymin,2)) + principio + str(ymin) + fin)\n        self.form.maxy.setText(str(round(ymax,2)) + principio + str(ymax) + fin)\n        self.form.lony.setText(str(round(ylen,2)) + principio + str(ylen) + fin)\n        self.form.etMiny.setEnabled(True)\n        self.form.miny.setEnabled(True)\n        self.form.etMaxy.setEnabled(True)\n        self.form.maxy.setEnabled(True)\n        self.form.etLony.setEnabled(True)\n        self.form.lony.setEnabled(True)\n\n        zmin = objetoSeleccion.Shape.BoundBox.ZMin\n        zmax = objetoSeleccion.Shape.BoundBox.ZMax\n        zlen = objetoSeleccion.Shape.BoundBox.ZLength\n        self.form.minz.setText(str(round(zmin,2)) + principio + str(zmin) + fin)\n        self.form.maxz.setText(str(round(zmax,2)) + principio + str(zmax) + fin)\n        self.form.lonz.setText(str(round(zlen,2)) + principio + str(zlen) + fin)\n        self.form.etMinz.setEnabled(True)\n        self.form.minz.setEnabled(True)\n        self.form.etMaxz.setEnabled(True)\n        self.form.maxz.setEnabled(True)\n        self.form.etLonz.setEnabled(True)\n        self.form.lonz.setEnabled(True)\n\n        centroBBx = objetoSeleccion.Shape.BoundBox.Center[0]\n        centroBBy = objetoSeleccion.Shape.BoundBox.Center[1]\n        centroBBz = objetoSeleccion.Shape.BoundBox.Center[2]\n        self.form.centrox.setText(str(round(centroBBx,2)) + principio + str(centroBBx) + fin)\n        self.form.centroy.setText(str(round(centroBBy,2)) + principio + str(centroBBy) + fin)\n        self.form.centroz.setText(str(round(centroBBz,2)) + principio + str(centroBBz) + fin)\n        self.form.etCentrox.setEnabled(True)\n        self.form.centrox.setEnabled(True)\n        self.form.etCentroy.setEnabled(True)\n        self.form.centroy.setEnabled(True)\n        self.form.etCentroz.setEnabled(True)\n        self.form.centroz.setEnabled(True)\n\n        lonDiagonalBB = objetoSeleccion.Shape.BoundBox.DiagonalLength\n        self.form.diabb.setText(str(round(lonDiagonalBB,2)) + principio + str(lonDiagonalBB) + fin)\n        self.form.etDiabb.setEnabled(True)\n        self.form.diabb.setEnabled(True)\n\n    def composicion(self):\n        # Shapes\n        self.form.composicion.setEnabled(True)\n        self.form.etComposicion.setEnabled(True)\n        listaVertices = objetoSeleccion.Shape.Vertexes\n        self.form.vertices.setText(str(len(listaVertices)))\n        self.form.vertices.setEnabled(True)\n        self.form.etVertices.setEnabled(True)\n        listaEjes = objetoSeleccion.Shape.Edges\n        self.form.ejes.setText(str(len(listaEjes)))\n        self.form.ejes.setEnabled(True)\n        self.form.etEjes.setEnabled(True)\n        listaAlambres = objetoSeleccion.Shape.Wires\n        self.form.alambres.setText(str(len(listaAlambres)))\n        self.form.alambres.setEnabled(True)\n        self.form.etAlambres.setEnabled(True)\n        listaCaras = objetoSeleccion.Shape.Faces\n        self.form.caras.setText(str(len(listaCaras)))\n        self.form.caras.setEnabled(True)\n        self.form.etCaras.setEnabled(True)\n\n        #if (len(listaCaras)>0):            --> Next Version\n        #    self.form.tabCaras.setEnabled(False)\n\n        if (len(listaVertices)>0):\n            self.form.tabComp.setEnabled(True)\n            self.form.tabVertices.setEnabled(True)\n            contador = 0\n            for vert in listaVertices:\n                self.form.comboVertices.addItem(self.translate(\"V\u00e9rtice\") + \" \" + str(contador + 1) + \": (\" +\n                    str(round(listaVertices[contador].X,2)) + \", \" +\n                    str(round(listaVertices[contador].Y,2)) + \", \" +\n                    str(round(listaVertices[contador].Z,2)) + \")\" )\n                contador += 1\n            self.form.comboVertices.setEnabled(True)\n            self.form.etComboVertices.setEnabled(True)\n\n        if (len(listaEjes)>0):\n            self.form.tabComp.setEnabled(True)\n            self.form.tabEjes.setEnabled(True)\n            contador = 0\n            for eje in listaEjes:\n                vertice1 = eje.Vertexes[0].Point\n                vertice2 = eje.Vertexes[-1].Point\n                texto = self.translate(\"Arista\") + \" \" + str(contador + 1) + \": v1 (\"\n                texto += str(round(vertice1[0],2)) + \", \"\n                texto += str(round(vertice1[1],2)) + \", \"\n                texto += str(round(vertice1[2],2)) + \")\"\n                texto += \" | v2 (\"\n                texto += str(round(vertice2[0],2)) + \", \"\n                texto += str(round(vertice2[1],2)) + \", \"\n                texto += str(round(vertice2[2],2)) + \")\"\n                self.form.comboEjes.addItem(texto)\n                texto2 = self.translate(\"Arista\") + \" \" + str(contador + 1) + \": \" + str(eje.Length)\n                self.form.comboEjesLongitudes.addItem(texto2)\n                texto3 = self.translate(\"Arista\") + \" \" + str(contador + 1) + \": \" + str(eje.Mass)\n                self.form.comboEjesMasas.addItem(texto3)\n                contador += 1\n            self.form.comboEjes.setEnabled(True)\n            self.form.etComboEjes.setEnabled(True)\n            self.form.comboEjesLongitudes.setEnabled(True)\n            self.form.etComboEjesLongitudes.setEnabled(True)\n            self.form.comboEjesMasas.setEnabled(True)\n            self.form.etComboEjesMasas.setEnabled(True)\n\n        listaSubformas = objetoSeleccion.Shape.SubShapes\n        self.form.subformas.setText(str(len(listaSubformas)))\n        self.form.subformas.setEnabled(True)\n        self.form.etSubformas.setEnabled(True)\n        listaCompuestos = objetoSeleccion.Shape.Compounds\n        self.form.compuestos.setText(str(len(listaCompuestos)))\n        self.form.compuestos.setEnabled(True)\n        self.form.etCompuestos.setEnabled(True)\n        listaFundas = objetoSeleccion.Shape.Shells\n        self.form.fundas.setText(str(len(listaFundas)))\n        self.form.fundas.setEnabled(True)\n        self.form.etFundas.setEnabled(True)\n        listaSolidos = objetoSeleccion.Shape.Solids\n        self.form.solidos.setText(str(len(listaSolidos)))\n        self.form.solidos.setEnabled(True)\n        self.form.etSolidos.setEnabled(True)\n        if len(listaSolidos)>0:\n            self.form.textoSolido.setText(iniRichText + bold + red + self.translate(\"\u00a1Es un s\u00f3lido!\") + fColor + fBold + finRichText)\n\n    def dimImagenes(self):\n        # Image\n        self.form.imagen.setEnabled(True)\n        self.form.imagen.setFocusPolicy(QtCore.Qt.TabFocus)\n        self.form.imagen.setFocus()\n        imgX = objetoSeleccion.XSize\n        imgY = objetoSeleccion.YSize\n        self.form.imgx.setText(str(imgX))\n        self.form.imgx.setEnabled(True)\n        self.form.etImgx.setEnabled(True)\n        self.form.imgy.setText(str(imgY))\n        self.form.imgy.setEnabled(True)\n        self.form.etImgy.setEnabled(True)\n        self.form.rutaImagen.setText(objetoSeleccion.ImageFile)\n        self.form.rutaImagen.setEnabled(True)\n        self.form.etRutaImagen.setEnabled(True)\n\n    def datos(self):\n        # Data\n        self.form.tabDatos.setEnabled(True)\n        self.form.datoLabel.setText(iniRichText + bold + red + objetoSeleccion.Label + fColor + fBold + finRichText)\n        self.form.etDatoLabel.setEnabled(True)\n        self.form.datoLabel.setEnabled(True)\n        self.form.datoName.setText(objetoSeleccion.Name)\n        self.form.etDatoName.setEnabled(True)\n        self.form.datoName.setEnabled(True)\n        self.form.datoFullName.setText(objetoSeleccion.FullName)\n        self.form.etDatoFullName.setEnabled(True)\n        self.form.datoFullName.setEnabled(True)\n        label2 = objetoSeleccion.Label2\n        if (label2 != \"\"):\n            self.form.datoLabel2.setText(label2)\n            self.form.etDatoLabel2.setEnabled(True)\n            self.form.datoLabel2.setEnabled(True)\n        self.form.datoId.setText(iniRichText + bold + blue + str(objetoSeleccion.ID) + fColor + fBold + finRichText)\n        self.form.etDatoId.setEnabled(True)\n        self.form.datoId.setEnabled(True)\n        visib = objetoSeleccion.Visibility\n        if (visib):\n            self.form.datoVisibilidad.setText(self.translate(\"Visible\"))\n        else:\n            self.form.datoVisibilidad.setText(self.translate(\"Oculto\"))\n        self.form.etDatoVisibilidad.setEnabled(True)\n        self.form.datoVisibilidad.setEnabled(True)\n\n\nseleccion = Gui.Selection.getSelection()\n# Se define el g_num_lang con variable global\nlang = gui.getLocale()\n# Default to English.\ng_num_lang = 1\nif 'Spanish' in lang:\n    g_num_lang = 0\nelif 'Italian' in lang:\n    g_num_lang = 2\nif (len(seleccion) == 1):\n    objetoSeleccion = App.ActiveDocument.getObject(seleccion[0].Name)\n    InfoPlus().form.show()\nelse:\n    App.Console.PrintWarning(\"You must select an only object.\")\n",
    "url": "https://github.com/18turbo/infoPlusFreeCAD",
    "raw_code_url": "",
    "wiki": "https://github.com/18turbo/infoPlusFreeCAD/wiki",
    "version": "0.1.0",
    "license": "",
    "date": "2022-10-03",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Information\\InfoPlus.FCMacro",
    "filename_from_url": "",
    "author": "18Turbo",
    "icon": "InfoPlus.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "InfoPlus.svg",
      "InfoPlus/ui/InfoPlus.ui"
    ],
    "parsed": true
  },
  {
    "name": "MeasureCircle",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Compute the radius of a circle by 3 points or a circular edge",
    "code": "__Name__ = 'Measure Circle'\n__Comment__ = 'Compute the radius of a circle by 3 points or a circular edge'\n__Author__ = 'peepsalot, galou_breizh'\n__Version__ = '0.10.1'\n__Date__ = '2023-03-11'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'http://www.freecadweb.org/wiki/Macro_MeasureCircle'\n__Wiki__ = 'http://www.freecadweb.org/wiki/Macro_MeasureCircle'\n__Icon__ = 'MeasureCircle.png'\n__Help__ = 'Make a selection of 3 points or an edge and launch, or launch first'\n__Status__ = 'Beta'\n__Requires__ = 'FreeCAD >= 0.18'\n__Communication__ = ''\n__Files__ = 'MeasureCircle.png'\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nimport Part\n\n\ndef get_global_placement(obj):\n    try:\n        # If obj is part of a Part or Body.\n        return obj.getParentGeoFeatureGroup().getGlobalPlacement()\n    except AttributeError:\n        return app.Placement()\n\n\nclass MeasureCircle:\n    \"\"\"Report the radius and center of a circle\n\n    This class will report the computed radius and center of a circle given 3\n    vertices or a circular edge.\n\n    Just select the vertices and the result will be shown in the Report View.\n    Edges may also be selected and count as two vertices.\n    A circular edge can also be selected.\n    If two edges are selected the end vertex of the second edge is not\n    used in the calculation.\n    \"\"\"\n    def __init__(self):\n        self.points = []\n        self.curve = None\n        self.observer_needed = False\n        self.get_elements_from_selection_ex()\n        # We add the observer only if necessary.\n        self.observer_needed = (self.curve is None)\n        if self.observer_needed:\n            gui.Selection.addObserver(self)\n            app.Console.PrintMessage(\n                'Select {} vertices on a circle\\n'.format(\n                    3 - len(self.points)))\n\n    def addSelection(self, doc, obj, sub, pos):\n        \"\"\"Callback of the selection observer\n\n        Do not rename.\n        \"\"\"\n        o = app.getDocument(doc).getObject(obj)\n        # Get the shape of selected object, if any.\n        try:\n            shape = o.Shape\n        except AttributeError:\n            app.Console.PrintMessage('Object is not a shape\\n')\n            return\n        # Get the selected subshape.\n        try:\n            subshape = getattr(shape, sub)\n        except:\n            app.Console.PrintMessage(\n                '\"{}\" is not a subshape of \"{}\"\\n'.format(sub, shape))\n            return\n        if subshape.ShapeType == 'Vertex':\n            self.add_point(o, subshape)\n        elif subshape.ShapeType == 'Edge':\n            self.on_edge(o, subshape)\n        # Exit if we have enough points.\n        if len(self.points) >= 3:\n            self.on_three_points()\n\n    def get_elements_from_selection_ex(self):\n        for sel_object in gui.Selection.getSelectionEx():\n            obj = sel_object.Object\n            for subobject in sel_object.SubObjects:\n                if type(subobject) == Part.Vertex:\n                    self.add_point(obj, subobject)\n                elif type(subobject) == Part.Edge:\n                    self.on_edge(obj, subobject)\n                # Exit if we have enough points.\n                if len(self.points) >= 3:\n                    self.on_three_points()\n                    return\n\n    def add_point(self, obj, v):\n        \"\"\"Add a point at the location of the selected vertex\n\n        obj is the object the vertex belongs to. If obj belongs to a body, the\n        body placement must be taken into account.\n        \"\"\"\n        placement = get_global_placement(obj)\n        point = placement.multVec(v.Point)\n        if point in self.points:\n            # Don't allow duplicate points.\n            app.Console.PrintWarning('Point already chosen, ignoring\\n')\n            return\n        self.points.append(point)\n\n    def on_edge(self, obj, edge):\n        \"\"\"Add either two points or a circle\n\n        obj is the object the edge belongs to. If obj belongs to a body, the\n        body placement must be taken into account.\n        \"\"\"\n        curve_type = type(edge.Curve)\n        if curve_type == Part.Circle:\n            self.on_circle(obj, edge)\n        elif curve_type == Part.LineSegment:\n            self.add_point(obj, edge.Vertexes[0])\n            self.add_point(obj, edge.Vertexes[1])\n\n    def finish(self):\n        if self.curve:\n            c = self.curve\n            # line = Part.makeLine(c.Center, c.Center + c.XAxis * c.Radius)\n            # obj = app.ActiveDocument.addObject('Part::Feature', 'Radius')\n            # obj.Shape = line\n            app.Console.PrintMessage('Diameter: {} mm\\n'.format(2 * c.Radius))\n            app.Console.PrintMessage('Radius: {} mm\\n'.format(c.Radius))\n            app.Console.PrintMessage(\n                'Center: (X, Y, Z) = ({}, {}, {})\\n'.format(\n                    *list(c.Location)))\n        if self.observer_needed:\n            gui.Selection.removeObserver(self)\n\n    def on_circle(self, obj, edge):\n        \"\"\"Add a circle and finish\n\n        obj is the object the curve belongs to. If obj belongs to a body, the\n        body placement must be taken into account.\n        \"\"\"\n        placement = get_global_placement(obj)\n        edge = edge.copy()\n        edge.Placement = edge.Placement.multiply(placement)\n        self.curve = edge.Curve\n        self.finish()\n\n    def on_three_points(self):\n        v1 = self.points[0]\n        v2 = self.points[1]\n        v3 = self.points[2]\n        self.curve = Part.Arc(v1, v2, v3).toShape().Curve\n        self.finish()\n\nif __name__ == '__main__':\n    MeasureCircle()\n",
    "url": "http://www.freecadweb.org/wiki/Macro_MeasureCircle",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/Macro_MeasureCircle",
    "version": "0.10.1",
    "license": "",
    "date": "2023-03-11",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Information\\MeasureCircle.FCMacro",
    "filename_from_url": "",
    "author": "peepsalot, galou_breizh",
    "icon": "MeasureCircle.png",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "MeasureCircle.png"
    ],
    "parsed": true
  },
  {
    "name": "SimpleProperties",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Gives basic properties of object (volume, boundbox, ...)",
    "code": "#!/usr/bin/python\n#####################################\n# Copyright (c) openBrain 2019\n# Licensed under LGPL v2\n#\n# This FreeCAD macro will give basic properties of the selected object (volume, boundbox, ...)\n#\n#\n# Version history :\n# *0.7 : some typo improvement + commenting\n# *0.6 : check if selected object has a valid shape\n# *0.5 : beta release\n#\n#####################################\n\n__Name__ = 'Simple Properties'\n__Comment__ = 'Gives basic properties of object (volume, boundbox, ...)'\n__Author__ = 'openBrain'\n__Version__ = '0.7.1'\n__Date__ = '2019-07-10'\n__License__ = 'LGPL v2'\n__Web__ = 'https://www.freecadweb.org/wiki/Macro_SimpleProperties'\n__Wiki__ = 'https://www.freecadweb.org/wiki/Macro_SimpleProperties'\n__Icon__ = ''\n__Help__ = 'Select an object and run the macro'\n__Status__ = 'Beta'\n__Requires__ = 'FreeCAD >= 0.17'\n\n__dbg__ = False  # True for debugging.\ng_disp_width = 3  # Set the display format of numbers.\n\nfrom PySide import QtGui\n\nimport FreeCAD as app\nimport FreeCADGui as gui\n\ndef cslM(msg): #Print message in console\n    app.Console.PrintMessage('\\n')\n    app.Console.PrintMessage(msg)\n\n\ndef cslW(msg): #Print warning in console\n    app.Console.PrintMessage('\\n')\n    app.Console.PrintWarning(msg)\n\n\ndef cslE(msg): #Print error in console\n    app.Console.PrintMessage('\\n')\n    app.Console.PrintError(msg)\n\n\ndef cslD(msg): #Print debug message in console\n    if __dbg__:\n        app.Console.PrintMessage('\\n')\n        app.Console.PrintMessage('Debug: ' + str(msg))\n\nif __dbg__:  ##Clear report view in debug mode\n    gui.getMainWindow().findChild(QtGui.QTextEdit, 'Report view').clear()\n\ncslM('Starting Simple Properties macro')\n\nif len(gui.Selection.getSelection()) != 1:\n    # If not exactly one object selected, warn user & quit.\n    cslE('One and only one object shall be selected ... Exiting')\nelif not ('Shape' in gui.Selection.getSelection()[0].PropertiesList):\n    # If selected object has no shape, warn user & exit.\n    cslE('Selected object has no valid shape ... Exiting')\nelse:\n    obj = gui.Selection.getSelection()[0]\n    # Get selected object.\n    retStr = ''\n    if len(gui.Selection.getSelectionEx()[0].SubObjects) != 1:\n        # If several object subobjects have been selected, ignore & warn user.\n        cslW('None or several subobject(s) selected, will be ignored')\n    else:\n        # If one subobject selected.\n        objEx = gui.Selection.getSelectionEx()[0].SubObjects[0]\n        if isinstance(objEx, Part.Edge):\n            # If it's an edge, print its length.\n            retStr += 'Edge length: {:.{w}g} mm\\n'.format(objEx.Length, w=g_disp_width)\n        elif isinstance(objEx, Part.Face):\n            # If it's a face, print its area.\n            retStr += 'Face area: {:.{w}g} m\u00b2\\n'.format(objEx.Area / 1000000, w=g_disp_width)\n        else:\n            # If other (unsupported) type, warn user.\n            cslD('Subobject type: ' + str(objEx.ShapeType))\n            cslW('Unsupported type of subobject')\n    retStr += 'Object volume: {:.{w}g}  l\\n'.format(obj.Shape.Volume / 1000000, w=g_disp_width)\n    bb = obj.Shape.BoundBox  # Get object's bounding box.\n    retStr += 'Object boundbox : {:.{w}g} x {:.{w}g} x {:.{w}g} mm\u00b3\\n'.format(\n        bb.XLength, bb.YLength, bb.ZLength, w=g_disp_width)\n\n    # Display information in a message box.\n    QtGui.QMessageBox(QtGui.QMessageBox.Information, 'Object Simple Props', retStr).exec_()\n",
    "url": "https://www.freecadweb.org/wiki/Macro_SimpleProperties",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_SimpleProperties",
    "version": "0.7.1",
    "license": "",
    "date": "2019-07-10",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Information\\SimpleProperties.FCMacro",
    "filename_from_url": "",
    "author": "openBrain",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "TreeToAscii",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Prints the Tree of selected object(s) as ASCII art",
    "code": "#####################################\n# Copyright (c) openBrain 2020\n# Licensed under LGPL v2\n#\n# This FreeCAD macro prints the Tree of selected object(s) as ASCII art.\n# Several styles are available. Tree branch pattern is customizable.\n# It can export to clipboard, file or embedded text document.\n# This mainly aims at documenting the model.\n#\n# Version history:\n# *0.7: add option to exclude origin objects\n# *0.6: introduce last fork string definition, add new style\n# *0.5: beta release\n#\n#####################################\n\nfrom __future__ import annotations\n\n\n__Name__ = 'TreeToAscii'\n__Comment__ = 'Prints the Tree of selected object(s) as ASCII art'\n__Author__ = 'openBrain'\n__Version__ = '0.7.1'\n__Date__ = '2020-03-23'\n__License__ = 'LGPL v2'\n__Web__ = 'https://www.freecadweb.org/wiki/Macro_TreeToAscii'\n__Wiki__ = 'https://www.freecadweb.org/wiki/Macro_TreeToAscii'\n__Icon__ = ''\n__Help__ = 'Select object(s) you want to print the tree then run'\n__Status__ = 'Beta'\n__Requires__ = 'FreeCAD >= 0.17'\n__Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=22&t=43504'\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nfrom PySide import QtGui, QtCore  # Special FreeCAD's PySide, which may be PySide2!\n\nPREF_PATH = 'User parameter:BaseApp/Preferences/Mod/TreeToAscii'\nPREF_PATTERN = 'TreePattern'\nPREF_STYLE = 'TreeStyle'\n# Define styles as NAME: [branch str, fork str, opt:last fork str].\nSTYLES = {\n    'Modern': [' \u2502 ', ' \u251c ', ' \u2514 '],  # U+2502, U+251C, U+2502\n    'Baroque': [' \u2502  ', ' \u251c\u2500 ',  ' \u2514\u2500 '],  # U+2502, U+251C + U+2500, U+2514 + U+2500\n    'ASCII': [' | ', ' \\\\_']\n    }\nDEF_PATTERN = '{LBL} ({SNAM})'\nDEF_STYLE = list(STYLES.keys())[0]\n\ng_ascii_tree = ''\n\n\ndef print_children(objs: list, top_level=True, baseline='', excluded=None):\n    \"\"\"Build ASCII tree by recursive call.\n\n    Parameters\n    ==========\n    objs: List objects to print and start the recursion from.\n    baseline: String to print before the object name.\n    excluded: List of objects to exclude from the tree.\n              As of v0.7.0, optionaly exclude part origins and origin's children.\n\n    \"\"\"\n    global g_ascii_tree\n    if excluded is None:\n        excluded = []\n    for i, obj in enumerate(objs, start=1):\n        data = {\n            'LBL': obj.Label,\n            'NAM': obj.Name,\n            'SNAM': ''.join(filter(str.isalpha, obj.Name)),\n            'TYP': obj.TypeId,\n            'BTYP': obj.TypeId.partition('::')[0],\n            'STYP': obj.TypeId.rpartition('::')[-1]\n        }\n        if (\n                getattr(obj, 'TypeId', '') == 'App::Part'\n                and not gen_include_origins.isChecked()\n        ):\n            excluded.append(obj.Origin)\n            excluded += obj.Origin.OriginFeatures\n\n        if obj in excluded:\n            continue\n        branch_str = STYLES[gen_style.currentText()][0]\n        fork_str = STYLES[gen_style.currentText()][1]\n        last_fork_str = STYLES[gen_style.currentText()][-1]\n        if i == len(objs):\n            # The last object.\n            if not top_level:\n                g_ascii_tree += baseline + last_fork_str\n        else:\n            if not top_level:\n                g_ascii_tree += baseline + fork_str\n        try:\n            g_ascii_tree += gen_pattern.text().format(**data)\n        except (ValueError, IndexError, KeyError):\n            g_ascii_tree = 'Error in generating pattern'\n            return\n        g_ascii_tree += '\\n'\n        if i == len(objs):\n            # The last object.\n            if top_level:\n                baseline_children = ''\n            else:\n                baseline_children = baseline + ' ' * len(branch_str)\n        else:\n            if top_level:\n                baseline_children = ''\n            else:\n                baseline_children = baseline + branch_str\n        print_children(\n                obj.ViewObject.claimChildren(),\n                False,\n                baseline_children,\n                excluded,\n        )\n\n\ndef copy_to_clipboard():\n    \"\"\"Copy the global ASCII tree to clipboard.\"\"\"\n    tree_view.selectAll()\n    tree_view.copy()\n    tree_view.setPlainText('Copied to clipboard')\n    QtCore.QTimer.singleShot(3000, lambda:tree_view.setPlainText(g_ascii_tree))\n\n\ndef save_to_file():\n    \"\"\"Save the global ASCII tree to file system.\"\"\"\n    path = QtGui.QFileDialog.getSaveFileName()\n    if path[0]:\n        filename = path[0]\n        try:\n            with open(filename, 'w') as f:\n                f.write(g_ascii_tree)\n        except OSError:\n            tree_view.setPlainText(f'ERROR: Can not open file: \"{filename}\"')\n        else:\n            tree_view.setPlainText(f'Saved to file: \"{filename}\"')\n        QtCore.QTimer.singleShot(3000, lambda:tree_view.setPlainText(g_ascii_tree))\n\n\ndef embed_in_doc():\n    \"\"\"Store the global ASCII tree as `App::TextDocument` object.\"\"\"\n    try:\n        text_obj = app.ActiveDocument.addObject('App::TextDocument', 'ModelTree')\n    except TypeError:\n        tree_view.setPlainText('ERROR: can not create a Text object. Maybe your FreeCAD version is too old')\n        return\n    text_obj.Text = g_ascii_tree\n    tree_view.setPlainText(f'Embedded as text object \"{text_obj.Label}\"')\n    QtCore.QTimer.singleShot(3000, lambda: tree_view.setPlainText(g_ascii_tree))\n\n\ndef update_text():\n    \"\"\"Update the global ASCII tree.\"\"\"\n    global g_ascii_tree\n    g_ascii_tree = ''\n    print_children(gui.Selection.getSelection())\n    tree_view.setPlainText(g_ascii_tree)\n\n\ndef on_generate():\n    \"\"\"Called when the 'Generate' button is clicked.\"\"\"\n    p.SetString(PREF_PATTERN, gen_pattern.text())\n    p.SetString(PREF_STYLE, gen_style.currentText())\n    update_text()\n\n\n# Get saved parameters or use defaults.\np = app.ParamGet(PREF_PATH)\ng_name_pattern = p.GetString(PREF_PATTERN, DEF_PATTERN)\ng_tree_style = p.GetString(PREF_STYLE, DEF_STYLE)\nif g_tree_style not in STYLES:\n    g_tree_style = DEF_STYLE\n\n\n# Build UI and show\ndlg = QtGui.QDialog(gui.getMainWindow(), QtCore.Qt.Tool)\ndlg_layout = QtGui.QVBoxLayout(dlg)\ngen_layout = QtGui.QHBoxLayout()\ngen_pattern = QtGui.QLineEdit(g_name_pattern, dlg)\ngen_pattern.setToolTip('''Defined variables are:\n    {LBL}: object Label\n    {NAM}: object Name\n    {SNAM}: object ShortName (without digits)\n    {TYP}: object Type\n    {BTYP}: object BaseType\n    {STYP}: object ShortType (without base)\nIf you need to print curly braces, they have to be doubled''')\ngen_run = QtGui.QPushButton('Generate', dlg)\ngen_run.clicked.connect(on_generate)\ngen_style = QtGui.QComboBox(dlg)\ngen_style.addItems(list(STYLES.keys()))\ngen_style.setCurrentIndex(list(STYLES.keys()).index(g_tree_style))\ngen_include_origins = QtGui.QCheckBox('Include origins', dlg)\ngen_include_origins.setChecked(True)\ngen_include_origins.stateChanged.connect(on_generate)\ngen_layout.addWidget(QtGui.QLabel('Generating pattern: '))\ngen_layout.addWidget(gen_pattern)\ngen_layout.addWidget(QtGui.QLabel('Style: '))\ngen_layout.addWidget(gen_style)\ngen_layout.addWidget(gen_include_origins)\ngen_layout.addWidget(gen_run)\ntree_view = QtGui.QPlainTextEdit(g_ascii_tree)\ntree_view.setReadOnly(True)\ntree_view.setMinimumWidth(gui.getMainWindow().width() // 2)\ntree_view.setMinimumHeight(gui.getMainWindow().height() // 2)\ntree_view.setLineWrapMode(QtGui.QPlainTextEdit.NoWrap)\nbutton_box = QtGui.QDialogButtonBox()\ncopy_clip_but = QtGui.QPushButton('Copy to clipboard', button_box)\nbutton_box.addButton(copy_clip_but, QtGui.QDialogButtonBox.ActionRole)\ncopy_clip_but.clicked.connect(copy_to_clipboard)\n_but = QtGui.QPushButton('Save to file', button_box)\nbutton_box.addButton(_but, QtGui.QDialogButtonBox.ActionRole)\n_but.clicked.connect(save_to_file)\nstore_embed_but = QtGui.QPushButton('Embed in document', button_box)\nbutton_box.addButton(store_embed_but, QtGui.QDialogButtonBox.ActionRole)\nstore_embed_but.clicked.connect(embed_in_doc)\nclose_dlg_but = QtGui.QPushButton('Close', button_box)\nbutton_box.addButton(close_dlg_but, QtGui.QDialogButtonBox.RejectRole)\nbutton_box.rejected.connect(dlg.reject)\ndlg_layout.insertLayout(0, gen_layout)\ndlg_layout.addWidget(tree_view)\ndlg_layout.addWidget(button_box)\nupdate_text()\ndlg.exec_()\n",
    "url": "https://www.freecadweb.org/wiki/Macro_TreeToAscii",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_TreeToAscii",
    "version": "0.7.1",
    "license": "",
    "date": "2020-03-23",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Information\\TreeToAscii.FCMacro",
    "filename_from_url": "",
    "author": "openBrain",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "AeroFoil",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "AeroFoil creates airfoil curves and faces using pre-defined models, algebraic functions, and DAT or CSV Files",
    "code": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n##########################################################################################\n#####\t\t\t\tL I C E N S E\t\t\t\t\t     #####\n##########################################################################################\n#\n#  GNU LESSER GENERAL PUBLIC LICENSE\n#  Version 2.1, February 1999\n#\n#  Copyright (C) 1991, 1999 Free Software Foundation, Inc.\n#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n#  Everyone is permitted to copy and distribute verbatim copies\n#  of this license document, but changing it is not allowed.\n#\n#  [This is the first released version of the Lesser GPL. It also counts\n#  as the successor of the GNU Library Public License, version 2, hence\n#  the version number 2.1.]\n#\n#  'AeroFoil' is a FreeCAD macro. AeroFoil creates airfoil curves and faces\n#  using pre-defined models, algebraic functions, and DAT or CSV Files.\n#\n#  Copyright (C) 2021  Melwyn Francis Carlo\n#\n#  This library is free software; you can redistribute it and/or\n#  modify it under the terms of the GNU Lesser General Public\n#  License as published by the Free Software Foundation; either\n#  version 2.1 of the License, or (at your option) any later version.\n#\n#  This library is distributed in the hope that it will be useful,\n#  but WITHOUT ANY WARRANTY; without even the implied warranty of\n#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n#  Lesser General Public License for more details.\n#\n#  You should have received a copy of the GNU Lesser General Public License\n#  along with this library; if not, write to the Free Software Foundation, Inc.,\n#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n#\n#  Contact Information :-\n#  Email :  carlo.melwyn@outlook.com\n#  FreeCAD UserTalk :  http://www.freecadweb.org/wiki/index.php?title=User:Melwyncarlo\n#\n##########################################################################################\n#####\t\t\t\tL I C E N S E\t\t\t\t\t     #####\n##########################################################################################\n#\n#\n#\n#  The AeroFoil macro was developed and tested on a platform containing the\n#  following system and FreeCAD software specifications :\n#\n#  - OS\t\t\t: Ubuntu 18.04.5 LTS (LXDE/Lubuntu)\n#  - Word size of OS\t: 64-bit\n#  - Word size of FreeCAD: 64-bit\n#  - Version\t\t: 0.19\n#  - Build type\t\t: Release\n#  - Branch\t\t: unknown\n#  - Hash\t\t: 32200b604d421c4dad527fe587a7d047cf953b4f\n#  - Python version\t: 3.6.9\n#  - Qt version\t\t: 5.9.5\n#  - Coin version\t: 4.0.0a\n#  - OCC version\t: 7.3.0\n#  - Locale\t\t: English/UnitedKingdom (en_GB)\n\n\n\"\"\"\n  To use this macro, the steps to be followed are simple and straightforward :\n  follow the instructions in the respective dialog boxes, fill in the relevant inputs,\n  and navigate accordingly. In case of error or warning, you will automatically be\n  notified the same. In case you are notified to report an unexpected error,\n  communicate the error by mentioning the FreeCAD version, tracing the steps\n  taken, and mentioning whether (and how much) or not any ouput was generated.\n\n  Note (1)\tPerforming the macro operation with custom points and refinement\n\t\tproduces no visible changes.\n  Note (2)\tThe AeroFoil object properties are only visible on the FreeCAD\n\t\tsoftware version 0.19. On older versions, you will be shown\n\t\ta warning on the console.\n  Note (3)\tThe single underscore prefix (e.g. _name) denotes a private\n\t\tfunction or a private variable.\n  Note (4)\tSome of the short forms used in this script are as follows:\n\t\t  'af' stands for AeroFoil\n  \t\t  'mfb' stands for Math Functions Box\n  \t\t  'd' stands for Dialog (e.g. d2c, d3, etc.)\n  Note (5)\tThe dialog boxes and their corresponding UI elements may be\n\t\tlabelled differently. Here is a map:\n\t\t  d1\t= AeroFoil_Initial_Dialog\n\t\t  d2a\t= AeroFoil_NACA4Digit_Dialog\n\t\t  d2b\t= AeroFoil_NACA5Digit_Dialog\n\t\t  d2c\t= AeroFoil_CurvesInput_Dialog\n\t\t  d2d\t= AeroFoil_PointsInput_Dialog\n\t\t  d2d1a\t= AeroFoil_DATInput_Dialog\n\t\t  d2d1b\t= AeroFoil_CSVInput_Dialog\n\t\t  dcd2\t= AeroFoil_FileLoad_Dialog\n\t\t  d3\t= AeroFoil_Final_Dialog\n\t\t  mfb\t= AeroFoil_Math_Functions_Box\n\t\tRead the DocString of the '_setDialogIndex' method in the\n\t\t'AeroFoilDialog' class to know more about its implementation.\n  Note (6)\tThe global variable 'dialogIndex' is listed in the exact order\n\t\tas the above list of dialog boxes.\n\"\"\"\n\n__Title__         = \"AeroFoil\"\n__Author__        = \"Melwyncarlo\"\n__Version__       = \"2.0.3\"\n__Date__          = \"2021-03-10\"\n__Comment__       = \"AeroFoil creates airfoil curves and faces using pre-defined models, algebraic functions, and DAT or CSV Files\"\n__Web__           = \"https://github.com/melwyncarlo/AeroFoil\"\n__Wiki__          = \"http://www.freecadweb.org/wiki/index.php?title=Macro_AeroFoil\"\n__Icon__          = \"AeroFoil.svg\"\n__Help__          = \"Click on the AeroFoil button/macro, and follow the instructions in the subsequent dialog boxes.\"\n__Status__        = \"stable\"\n__Requires__      = \"Freecad >= v0.17\"\n__License__       = \"LGPL-2.1-or-later\"\n__Communication__ = \"https://github.com/melwyncarlo/AeroFoil/issues\"\n__Files__         = \"AeroFoil_UI_Files/AeroFoil_Initial_Dialog.ui,AeroFoil_UI_Files/AeroFoil_NACA4Digit_Dialog.ui,AeroFoil_UI_Files/AeroFoil_NACA5Digit_Dialog.ui,AeroFoil_UI_Files/AeroFoil_CurvesInput_Dialog.ui,AeroFoil_UI_Files/AeroFoil_PointsInput_Dialog.ui,AeroFoil_UI_Files/AeroFoil_DATInput_Dialog.ui,AeroFoil_UI_Files/AeroFoil_CSVInput_Dialog.ui,AeroFoil_UI_Files/AeroFoil_FileLoad_Dialog.ui,AeroFoil_UI_Files/AeroFoil_Final_Dialog.ui,AeroFoil_UI_Files/AeroFoil_Math_Functions_Box.ui,AeroFoil_UI_Files/AeroFoil_mfb_img.gif,AeroFoil.svg\"\n\n# Library Imports\n# ------------------------------------------------------------------------------------------------\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nimport Sketcher, Part, Draft\nfrom pathlib import Path\nimport PySide\nfrom PySide import QtGui, QtCore\nfrom PySide.QtGui import *\nfrom PySide.QtCore import *\nimport time, math, csv, re\n\n###########################################################################\n###---------------------------------------------------------------------###\n### \t\tAEROFOIL MACRO CALLS - Top (check Bottom)\t\t###\n###---------------------------------------------------------------------###\n                                                                        ###\ndef AeroFoil_generate(obj):\t\t\t\t\t\t###\n    \"\"\"\n    The 'AeroFoil_generate' function generates the 2D curves\n    and shapes, assigns them properties, and creates\n    multiples of created curves and shapes.\n\n    Arguments\n    ----------\n    obj: An instance of the 'AeroFoilDialog' object.\n\n    Return\n    ----------\n    True:   The airfoil curves/shapes were generated\n            successfully.\n    False:  The airfoil curves/shapes were NOT generated\n            successfully.\n    \"\"\"\t\t\t\t\t\t\t\t\t###\n    n_ = (obj.multi * (obj.multiParam - 1)) + 1\t\t\t\t###\n    AeroFoil_object = AeroFoil(obj)\t\t\t\t\t###\n    if AeroFoil_object.create():\t\t\t\t\t###\n        AeroFoil_object.characterize()\t\t\t\t\t###\n    else:\t\t\t\t\t\t\t\t###\n        return False\t\t\t\t\t\t\t###\n    AeroFoil_object.copy(n_)\t\t\t\t\t\t###\n    return True\t\t\t\t\t\t\t\t###\n                                                                        ###\n###---------------------------------------------------------------------###\n### \t\tAEROFOIL MACRO CALLS - Top (check Bottom)\t\t###\n###---------------------------------------------------------------------###\n###########################################################################\n\n\n\n# Constant Variables\n# ------------------------------------------------------------------------------------------------\n\nMAX_REFINE_PARAM = 2\n# Pertaining to the 'Refine Parameter' input from AeroFoil_Final_Dialog\n# It is the maximum airfoil points refinement coefficient above which\n# a warning is diplayed notifying the user of increased computation.\nMAX_QUANTITY_PARAM = 5\n# Pertaining to the 'Quantity Parameter' input from AeroFoil_Final_Dialog\n# It is the maximum number of Airfoil curves to be generated above which\n# a warning is diplayed notifying the user of increased computation.\nMIN_DATA_POINTS = 10\n# Pertaining to the 'Quantity Parameter' input from AeroFoil_FileLoad_Dialog\n# It is the minimum pair of airfoil data points to be present in the file\n# below which an error is shown.\nNACA_NUMBER_OF_POINTS = 50\n# It is the number of airfoil data points pair used while generating the curves\n# It is the value set at REFINE_PARAM = 1\nNACA_5_2ND_3RD_DIGITS = [\"10\", \"20\", \"30\", \"40\", \"50\", \"21\", \"31\", \"41\", \"51\"]\n# The NACA 5 Digit airfoils are limited. These are the 2nd and 3rd digit combinations\n# of the available NACA 5 Digit airfoils\nFUNCTIONSARRAY = [\n    \"+\",\n    \"-\",\n    \"*\",\n    \"/\",\n    \"^\",\n    \"e\",\n    \"pi\",\n    \"ln(\",\n    \"log(\",\n    \"sqrt(\",\n    \"sin(\",\n    \"cos(\",\n    \"tan(\",\n    \"asin(\",\n    \"acos(\",\n    \"atan(\",\n    \"x\",\n    \"(\",\n    \")\",\n    \".\",\n]\n# A list of functions and mathematics-based characters that are allowed for input.\nUNITSCONVERSION = [0, 1, 10, 1000, 25.4, 304.8, 914.4]\n# This is the conversion coefficients list to convert different units into millimetres (mm).\n# From element 2 to 7 :  millimetre (mm), centimetre (cm), metre (m), inch (in), feet (ft),\n# and yards.\n# Ignore the 1st element; it's superfluous.\nMIN_CHORD_LENGTH_MM = 1\n# It is the minimum airfoil chord length input below which a warning is displayed.\nMACRO_DIR = app.getUserMacroDir(True) + \"/AeroFoil_UI_Files/AeroFoil_\"\n# It is the user's macro directory\n\n\n\n# Global Variables\n# ------------------------------------------------------------------------------------------------\n\ndialogIndex = [1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n# These are the code numbers pertaining to the entire program's dialogs\n# Each dialog box is assigned an initial code number.\n# Each of the numbers given in the list from element 2 t0 11\n# correspond to a dialog box as mentioned in the macro's\n# main DocString above.\n# The 1st element contains the current dialog box's index number\n# Read the DocString of the '_setDialogIndex' method in the\n# 'AeroFoilDialog' class to know more about its implementation.\ndoc = app.activeDocument()\n\n\n\n# Main Function Class\n# ------------------------------------------------------------------------------------------------\n\nclass AeroFoil:\n\n    \"\"\"\n    The 'AeroFoil' class is the AeroFoil object itself. It is a non-interactive\n    console-based class that is responsible for physical creation of the custom\n    2D airfoil curves/shapes. The gathered user input data is used for the process.\n\n    Functions include:\n    __init__\n    copy\n    characterize\n    create\n    _create_tempX_var\n    _createSketcherPolyLine\n    _createSketcherBSpline\n    \"\"\"\n\n    def __init__(self, obj):\n        \"\"\"\n        This function initializes of the 'AeroFoil' class.\n        This function transfers the user input data through the 'obj' variable.\n\n        Arguments\n        ----------\n        obj: An instance of the 'AeroFoilDialog' object.\n        \"\"\"\n        global UNITSCONVERSION\n        self.profileName = generateName(\"AeroFoil\")\n        self.chord = obj.chordLength * UNITSCONVERSION[obj.chordUnits]\n        # 'designtype' is used as a container for a set of relevant variables\n        self.designtype = [obj.workbench, obj.curveType]\n        self.designclosed = obj.closed_\n        self.designsplit = obj.splitCurve\n        self.designsplitmode = obj.splitCurveMode\n        self.defaultEndPoints = obj.defaultEndPoints\n        # 'midIndices' is used as a container for a set of relevant variables\n        self.midIndices = [obj.midIndex1, obj.midIndex2]\n        self.points = []\n        self.points.append(obj.pointsX)\n        self.points.append(obj.pointsY)\n        self.n_units = len(self.points[0])\n        self.designprogressbar = obj.progressBar_\n        # 'objRefData' is used as a container for a set of relevant variables\n        self.objRefData = [\n            obj.airfoilType,\n            obj.airfoil4DNumber,\n            obj.airfoil5DNumber,\n            obj.airfoilProfileType,\n            obj.importFrom,\n        ]\n\n    def copy(self, quantity_):\n        \"\"\"\n        This function creates multiple copies of the created airfoil curves/shapes.\n\n        Arguments\n        ----------\n        quantity_: (Integer) Number of copies required.\n        \"\"\"\n        if quantity_ != 1:\n            refNum = int(re.findall(r\"\\d+\", self.profileName)[0])\n            gui.Selection.clearSelection()\n            if self.designsplit:\n                gui.Selection.addSelection(\n                    doc.getObjectsByLabel(self.profileName + \"_Upper\")[0]\n                )\n                gui.Selection.addSelection(\n                    doc.getObjectsByLabel(self.profileName + \"_Lower\")[0]\n                )\n            else:\n                gui.Selection.addSelection(doc.getObjectsByLabel(self.profileName)[0])\n            gui.runCommand(\"Std_Copy\")\n            for i in range(quantity_ - 1):\n                gui.runCommand(\"Std_Paste\")\n                if self.designsplit:\n                    doc.getObjectsByLabel(\n                        \"AeroFoil_\" + str(refNum) + \"_Upper\" + str(i + 1).zfill(3)\n                    )[0].Label = (\"AeroFoil_\" + str(refNum + i + 1) + \"_Upper\")\n                    doc.getObjectsByLabel(\n                        \"AeroFoil_\" + str(refNum) + \"_Lower\" + str(i + 1).zfill(3)\n                    )[0].Label = (\"AeroFoil_\" + str(refNum + i + 1) + \"_Lower\")\n                else:\n                    doc.getObjectsByLabel(\"AeroFoil_\" + str(refNum + i + 1).zfill(3))[\n                        0\n                    ].Label = \"AeroFoil_\" + str(refNum + i + 1)\n                if self.designprogressbar.value() < 99:\n                    self.designprogressbar.setValue(\n                        round(75 + (((i + 1) / (4 * quantity_)) * 100))\n                    )\n        self.designprogressbar.setValue(100)\n        time.sleep(1)\n\n    def characterize(self):\n        \"\"\"\n        This function adds external (read-only) properties to an instance of the AeroFoil object.\n        The user input data has been obtained from the '__init__' module of this class.\n\n        Properties\n        ---------------\n        Airfoil Type:         Options - NACA 4 Digit, NACA 5 Digit, Custom Curves (Symmetric or\n                              Asymmetric), or Custom Points (DAT or CSV)\n        Design Curve Type:    Options - Unsplit or Open Split or Open Split (End Points Fixed) or\n                              Closed Split or Closed Split (End Points Fixed) |\n                              Polygon or BSpline | Draft or Sketch or Surface\n        Airfoil Chord Length: Length in millimetres (mm)\n        Number of Points :    Number of airfoil points\n        \"\"\"\n        try:\n            objRef = doc.getObjectsByLabel(self.profileName)[0]\n            objRef.addProperty(\"App::PropertyString\", \"AirfoilType\", \"\", \"\", 1)\n            objRef.addProperty(\"App::PropertyLength\", \"AirfoilChordLength\", \"\", \"\", 1)\n            objRef.addProperty(\"App::PropertyString\", \"DesignCurveType\", \"\", \"\", 1)\n            objRef.addProperty(\"App::PropertyInteger\", \"NumberOfPoints\", \"\", \"\", 1)\n            tempStr = \"\"\n            # Refer to the '__init__' method of this class for more info. on 'objRefData'\n            if self.objRefData[0] == 1:\n                tempStr = \"NACA - \" + self.objRefData[1]\n            elif self.objRefData[0] == 2:\n                tempStr = \"NACA - \" + self.objRefData[2]\n            elif self.objRefData[0] == 3 and self.objRefData[3] == 1:\n                tempStr = \"Custom Curves (Symmetric)\"\n            elif self.objRefData[0] == 3 and self.objRefData[3] == 2:\n                tempStr = \"Custom Curves (Asymmetric)\"\n            elif self.objRefData[0] == 4 and self.objRefData[4] == 1:\n                tempStr = \"Custom Points (DAT)\"\n            elif self.objRefData[0] == 4 and self.objRefData[4] == 2:\n                tempStr = \"Custom Points (CSV)\"\n            objRef.AirfoilType = tempStr\n            objRef.AirfoilChordLength = str(self.chord) + \"mm\"\n            tempStr = \"\"\n            if self.designsplit:\n                if self.designsplitmode == 1:\n                    tempStr += \"Open Split \"\n                else:\n                    tempStr += \"Closed Split \"\n                tempStr += \"(End Points Fixed) \" if self.defaultEndPoints else \"\"\n            else:\n                tempStr += \"Unsplit \"\n            tempStr += \"Polygon \" if self.designtype[1] == 1 else \"BSpline \"\n            if self.designclosed:\n                tempStr += \"Surface\"\n            elif self.designtype[0] == 1:\n                tempStr += \"Sketch\"\n            elif self.designtype[0] == 2:\n                tempStr += \"Draft\"\n            objRef.DesignCurveType = tempStr\n            objRef.NumberOfPoints = self.n_units - 1\n        except Exception:\n            print(\n                \"\\nCannot generate AeroFoil properties in FreeCAD version &#60;0.19 !\\n\"\n            )\n            app.Console.PrintWarning(\n                \"\\nCannot generate AeroFoil properties in FreeCAD version &#60;0.19 !\\n\"\n            )\n\n    def create(self):\n        \"\"\"\n        This function is responsible for physical creation of the custom 2D airfoil curves/shapes.\n        The user input data has been obtained from the '__init__' module of this class.\n        This function utilizes the 'try ... except' method to avoid any complications\n        on the user's end. A simple error message is displayed instead.\n        \"\"\"\n        # Generating Polygons and BSplines\n        try:\n            if self.designtype[0] == 2:\n                if self.designtype[1] == 1:\n                    if self.designsplit:\n                        self._createSketcherPolyLine(\n                            self.profileName + \"_Upper\", 0, self.midIndices[0]\n                        )\n                        self._createSketcherPolyLine(\n                            self.profileName + \"_Lower\",\n                            self.midIndices[1],\n                            len(self.points[0]) - 1,\n                        )\n                    else:\n                        self._createSketcherPolyLine(\n                            self.profileName, 0, len(self.points[0]) - 1\n                        )\n                elif self.designtype[1] == 2:\n                    if self.designsplit:\n                        self._createSketcherBSpline(\n                            self.profileName + \"_Upper\", 0, self.midIndices[0]\n                        )\n                        self._createSketcherBSpline(\n                            self.profileName + \"_Lower\",\n                            self.midIndices[1],\n                            len(self.points[0]) - 1,\n                        )\n                    else:\n                        self._createSketcherBSpline(\n                            self.profileName, 0, len(self.points[0]) - 1\n                        )\n            elif self.designtype[0] == 1:\n                tempXif, tempXm = 0, 0\n                i_count, iteration = 0, 1\n                if self.designsplit:\n                    iteration = 2\n                while i_count < iteration:\n                    DWireOrBSpline_, pointsVector, draftCurveClosed = 0, [], True\n                    startIndex, endIndex = 0, len(self.points[0]) - 1\n                    draftOutputName = self.profileName\n                    n_ = len(self.points[0])\n                    if self.designsplit:\n                        draftCurveClosed = False\n                        startIndex, endIndex = (\n                            (0, self.midIndices[0])\n                            if i_count == 0\n                            else (self.midIndices[1], len(self.points[0]) - 1)\n                        )\n                        tempXif, tempXm, startIndex, endIndex = self._create_tempX_var(startIndex, endIndex)\n                        draftOutputName = (\n                            self.profileName + \"_Upper\"\n                            if i_count == 0\n                            else self.profileName + \"_Lower\"\n                        )\n                        n_ = endIndex - startIndex + 1\n                    if self.designsplit and (\n                        tempXif != self.points[0][startIndex]\n                        or self.points[1][startIndex] != 0\n                    ):\n                        pointsVector.append(app.Vector(tempXif, 0, 0))\n                    for i in range(startIndex, endIndex + 1):\n                        pointsVector.append(\n                            app.Vector(self.points[0][i], 0, self.points[1][i])\n                        )\n                        if not self.designsplit:\n                            if self.designprogressbar.value() < 75:\n                                self.designprogressbar.setValue(\n                                    round(50 + ((i / (4 * n_)) * 100))\n                                )\n                        elif self.designsplit and i_count == 0:\n                            if self.designprogressbar.value() < 62.5:\n                                self.designprogressbar.setValue(\n                                    round(50 + ((i / (8 * n_)) * 100))\n                                )\n                        else:\n                            if self.designprogressbar.value() < 75:\n                                self.designprogressbar.setValue(\n                                    round(62.5 + ((i / (8 * n_)) * 100))\n                                )\n                    if self.designsplit and (\n                        tempXm != self.points[0][endIndex]\n                        or self.points[1][endIndex] != 0\n                    ):\n                        pointsVector.append(app.Vector(tempXm, 0, 0))\n                    if self.designtype[1] == 1:\n                        # if self.designclosed is determined by face=self.designclosed\n                        DWireOrBSpline_ = Draft.makeWire(\n                            pointsVector,\n                            closed=draftCurveClosed,\n                            placement=None,\n                            face=self.designclosed,\n                            support=None,\n                        )\n                    elif self.designtype[1] == 2:\n                        # if self.designclosed is determined by face=self.designclosed\n                        DWireOrBSpline_ = Draft.makeBSpline(\n                            pointsVector,\n                            closed=draftCurveClosed,\n                            placement=None,\n                            face=self.designclosed,\n                            support=None,\n                        )\n                        if self.designsplit and self.designsplitmode == 2:\n                            pointsVector_aux = [pointsVector[0], pointsVector[-1]]\n                            DWire_aux = Draft.makeWire(\n                                pointsVector_aux,\n                                closed=False,\n                                placement=None,\n                                face=False,\n                                support=None,\n                            )\n                            addList, deleteList = Draft.upgrade(\n                                [DWireOrBSpline_, DWire_aux], delete=True, force=None\n                            )\n                    doc.recompute()\n                    if self.designsplit and self.designsplitmode == 2:\n                        doc.getObject(addList[0].Name).Label = draftOutputName\n                    else:\n                        shape_ = doc.addObject(\"Part::Feature\", draftOutputName)\n                        shape_.Shape = DWireOrBSpline_.Shape\n                        doc.removeObject(DWireOrBSpline_.Label)\n                    i_count += 1\n        except Exception:\n            # Unexpected Error Occurred while Processing\n            try:\n                doc.removeObject(self.profileName)\n                doc.removeObject(self.profileName + \"_Upper\")\n                doc.removeObject(self.profileName + \"_Lower\")\n            except Exception:\n                pass\n            doc.recompute()\n            return False\n        doc.recompute()\n        gui.activeDocument().activeView().viewFront()\n        gui.SendMsgToActiveView(\"ViewFit\")\n        return True\n\n    def _create_tempX_var(self, startIndex, endIndex):\n        \"\"\"\n        This function determines the start and end points of a 'split' curve.\n        This function generates additional start and end points if\n        their existing counterparts do not have a Y-axis value of zero (0).\n        This function calls the linear interpolation method to achieve the same.\n\n        Arguments\n        ----------\n        startIndex: (Integer) Zero-based index of the data points list to begin from.\n        endIndex:   (Integer) Zero-based index of the data points list to end to.\n        \"\"\"\n        posVar, negVar, startIndex_new, endIndex_new = 0, 0, startIndex, endIndex\n        for i1 in range(startIndex, startIndex + int(0.1 * (endIndex - startIndex))):\n            if self.points[1][i1] >= 0:\n                posVar += 1\n            else:\n                negVar += 1\n        for j1 in range(startIndex, startIndex + int(0.1 * (endIndex - startIndex))):\n            if posVar >= negVar:\n                if self.points[1][j1] >= 0:\n                    startIndex_new = j1\n                    break\n            else:\n                if self.points[1][j1] < 0:\n                    startIndex_new = j1\n                    break\n        for i2 in range(endIndex, endIndex - int(0.1 * (endIndex - startIndex)), -1):\n            if self.points[1][i2] >= 0:\n                posVar += 1\n            else:\n                negVar += 1\n        for j2 in range(endIndex, endIndex - int(0.1 * (endIndex - startIndex)), -1):\n            if posVar >= negVar:\n                if self.points[1][j2] >= 0:\n                    endIndex_new = j2\n                    break\n            else:\n                if self.points[1][j2] < 0:\n                    endIndex_new = j2\n                    break\n        if self.defaultEndPoints:\n            tempXif = round(self.points[0][startIndex_new], 2)\n            tempXm = round(self.points[0][endIndex_new], 2)\n            self.points[0][startIndex_new] = round(self.points[0][startIndex_new], 2)\n            self.points[0][endIndex_new] = round(self.points[0][endIndex_new], 2)\n        else:\n            if startIndex_new == 0:\n                xi_, yi_ = self.points[0][0], self.points[1][0]\n                xf_, yf_ = (\n                    (self.points[0][-1], self.points[1][-1])\n                    if (\n                        self.points[0][0] != self.points[0][-1]\n                        or self.points[1][0] != self.points[1][-1]\n                    )\n                    else (self.points[0][-2], self.points[1][-2])\n                )\n                x1m_, y1m_ = self.points[0][endIndex_new], self.points[1][endIndex_new]\n                x2m_, y2m_ = (\n                    (self.points[0][endIndex_new + 1], self.points[1][endIndex_new + 1])\n                    if self.points[0][endIndex_new] != self.points[0][endIndex_new + 1]\n                    or self.points[1][endIndex_new] != self.points[1][endIndex_new + 1]\n                    else (self.points[0][endIndex_new + 2], self.points[1][endIndex_new + 2])\n                )\n            else:\n                xi_, yi_ = self.points[0][startIndex_new], self.points[1][startIndex_new]\n                xf_, yf_ = (\n                    (self.points[0][startIndex_new - 1], self.points[1][startIndex_new - 1])\n                    if (\n                        self.points[0][startIndex_new] != self.points[0][startIndex_new - 1]\n                        or self.points[1][startIndex_new] != self.points[1][startIndex_new - 1]\n                    )\n                    else (\n                        self.points[0][startIndex_new - 2],\n                        self.points[1][startIndex_new - 2],\n                    )\n                )\n                x1m_, y1m_ = self.points[0][-1], self.points[1][-1]\n                x2m_, y2m_ = (\n                    (self.points[0][0], self.points[1][0])\n                    if self.points[0][-1] != self.points[0][0]\n                    or self.points[1][-1] != self.points[1][0]\n                    else (self.points[0][1], self.points[1][1])\n                )\n            tempXif = interpolateNum(yi_, xi_, yf_, xf_, 0)\n            tempXm = interpolateNum(y1m_, x1m_, y2m_, x2m_, 0)\n        return tempXif, tempXm, startIndex_new, endIndex_new\n\n    def _createSketcherPolyLine(self, sketchName, startIndex, endIndex):\n        \"\"\"\n        This function creates the Sketcher Workbench based PolyLine curve.\n\n        Arguments\n        ----------\n        sketchName: (String)  The name/label of the generated sketch.\n        startIndex: (Integer) Zero-based index of the data points list to begin from.\n        endIndex:   (Integer) Zero-based index of the data points list to end to.\n        \"\"\"\n        # Sketch Preparation and Naming\n        sketchObj = doc.addObject(\"Sketcher::SketchObject\", sketchName)\n        sketchObj.Placement = app.Placement(\n            app.Vector(0.000000, 0.000000, 0.000000),\n            app.Rotation(-0.707107, 0.000000, 0.000000, -0.707107),\n        )\n        sketchObj.MapMode = \"Deactivated\"\n        # Sketch PolyLine Procedure\n        count, tempBool = 0, False\n        tempXif, tempXm = 0, 0\n        if self.designsplit:\n            tempXif, tempXm, startIndex, endIndex = self._create_tempX_var(startIndex, endIndex)\n            if (\n                tempXif == self.points[0][startIndex]\n                and self.points[1][startIndex] == 0\n            ):\n                tempBool = False\n            else:\n                tempBool = True\n                sketchObj.addGeometry(\n                    Part.LineSegment(\n                        app.Vector(tempXif, 0, 0),\n                        app.Vector(\n                            self.points[0][startIndex], self.points[1][startIndex], 0\n                        ),\n                    ),\n                    False,\n                )\n                constraintIndex = sketchObj.addConstraint(\n                    Sketcher.Constraint(\"DistanceX\", 0, 1, tempXif)\n                )\n                sketchObj.setDatum(\n                    constraintIndex, app.Units.Quantity(str(tempXif) + \"mm\")\n                )\n                constraintIndex = sketchObj.addConstraint(\n                    Sketcher.Constraint(\"DistanceY\", 0, 1, 0)\n                )\n                sketchObj.setDatum(constraintIndex, app.Units.Quantity(str(0) + \"mm\"))\n                constraintIndex = sketchObj.addConstraint(\n                    Sketcher.Constraint(\"DistanceX\", 0, 2, self.points[0][startIndex])\n                )\n                sketchObj.setDatum(\n                    constraintIndex,\n                    app.Units.Quantity(str(self.points[0][startIndex]) + \"mm\"),\n                )\n                constraintIndex = sketchObj.addConstraint(\n                    Sketcher.Constraint(\"DistanceY\", 0, 2, self.points[1][startIndex])\n                )\n                sketchObj.setDatum(\n                    constraintIndex,\n                    app.Units.Quantity(str(self.points[1][startIndex]) + \"mm\"),\n                )\n        sketchObj.addGeometry(\n            Part.LineSegment(\n                app.Vector(self.points[0][startIndex], self.points[1][startIndex], 0),\n                app.Vector(\n                    self.points[0][startIndex + 1], self.points[1][startIndex + 1], 0\n                ),\n            ),\n            False,\n        )\n        if tempBool:\n            sketchObj.addConstraint(Sketcher.Constraint(\"Coincident\", 0, 2, 1, 1))\n            count = 2\n        else:\n            count = 1\n        n_ = endIndex - startIndex + 1\n        for i in range(startIndex + 1, endIndex):\n            sketchObj.addGeometry(\n                Part.LineSegment(\n                    app.Vector(self.points[0][i], self.points[1][i], 0),\n                    app.Vector(self.points[0][i + 1], self.points[1][i + 1], 0),\n                ),\n                False,\n            )\n            sketchObj.addConstraint(\n                Sketcher.Constraint(\"Coincident\", count - 1, 2, count, 1)\n            )\n            if self.designprogressbar.value() < 62.5:\n                self.designprogressbar.setValue(round(50 + ((count / (8 * n_)) * 100)))\n            count += 1\n        tempVar1, tempVar2 = self.points[0][endIndex], self.points[1][endIndex]\n        if self.designsplit and (\n            tempXm != self.points[0][endIndex] or self.points[1][endIndex] != 0\n        ):\n            sketchObj.addGeometry(\n                Part.LineSegment(\n                    app.Vector(self.points[0][endIndex], self.points[1][endIndex], 0),\n                    app.Vector(tempXm, 0, 0),\n                ),\n                False,\n            )\n            sketchObj.addConstraint(\n                Sketcher.Constraint(\"Coincident\", count - 1, 2, count, 1)\n            )\n            tempVar1, tempVar2 = tempXm, 0\n            count += 1\n        if self.designsplitmode == 2:\n            sketchObj.addGeometry(\n                Part.LineSegment(\n                    app.Vector(tempVar1, tempVar2, 0),\n                    app.Vector(\n                        self.points[0][startIndex], self.points[1][startIndex], 0\n                    ),\n                ),\n                False,\n            )\n            sketchObj.addConstraint(\n                Sketcher.Constraint(\"Coincident\", count - 1, 2, count, 1)\n            )\n            sketchObj.addConstraint(Sketcher.Constraint(\"Coincident\", count, 2, 0, 1))\n        if self.designsplit:\n            # Here, 'count; denotes the sketcher line number\n            count = 1 if tempBool else 0\n        else:\n            sketchObj.addConstraint(\n                Sketcher.Constraint(\"Coincident\", count - 1, 2, 0, 1)\n            )\n            count = 0\n        for j in range(startIndex, endIndex - 1):\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\"DistanceX\", count, 2, self.points[0][j + 1])\n            )\n            sketchObj.setDatum(\n                constraintIndex, app.Units.Quantity(str(self.points[0][j + 1]) + \"mm\")\n            )\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\"DistanceY\", count, 2, self.points[1][j + 1])\n            )\n            sketchObj.setDatum(\n                constraintIndex, app.Units.Quantity(str(self.points[1][j + 1]) + \"mm\")\n            )\n            if self.designprogressbar.value() < 75:\n                self.designprogressbar.setValue(\n                    round(62.5 + ((count / (8 * n_)) * 100))\n                )\n            count += 1\n        if self.designsplit:\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\"DistanceX\", count, 2, self.points[0][endIndex])\n            )\n            sketchObj.setDatum(\n                constraintIndex,\n                app.Units.Quantity(str(self.points[0][endIndex]) + \"mm\"),\n            )\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\"DistanceY\", count, 2, self.points[1][endIndex])\n            )\n            sketchObj.setDatum(\n                constraintIndex,\n                app.Units.Quantity(str(self.points[1][endIndex]) + \"mm\"),\n            )\n            count += 1\n            if tempXm != self.points[0][endIndex] or self.points[1][endIndex] != 0:\n                constraintIndex = sketchObj.addConstraint(\n                    Sketcher.Constraint(\"DistanceX\", count, 2, tempXm)\n                )\n                sketchObj.setDatum(\n                    constraintIndex, app.Units.Quantity(str(tempXm) + \"mm\")\n                )\n                constraintIndex = sketchObj.addConstraint(\n                    Sketcher.Constraint(\"DistanceY\", count, 2, 0)\n                )\n                sketchObj.setDatum(constraintIndex, app.Units.Quantity(str(0) + \"mm\"))\n                count += 1\n            if not tempBool and self.designsplitmode == 2:\n                constraintIndex = sketchObj.addConstraint(\n                    Sketcher.Constraint(\n                        \"DistanceX\", count, 2, self.points[0][startIndex]\n                    )\n                )\n                sketchObj.setDatum(\n                    constraintIndex,\n                    app.Units.Quantity(str(self.points[0][startIndex]) + \"mm\"),\n                )\n                constraintIndex = sketchObj.addConstraint(\n                    Sketcher.Constraint(\n                        \"DistanceY\", count, 2, self.points[1][startIndex]\n                    )\n                )\n                sketchObj.setDatum(\n                    constraintIndex,\n                    app.Units.Quantity(str(self.points[1][startIndex]) + \"mm\"),\n                )\n                count += 1\n        if not tempBool and self.designsplitmode != 2:\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\"DistanceX\", 0, 1, self.points[0][startIndex])\n            )\n            sketchObj.setDatum(\n                constraintIndex,\n                app.Units.Quantity(str(self.points[0][startIndex]) + \"mm\"),\n            )\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\"DistanceY\", 0, 1, self.points[1][startIndex])\n            )\n            sketchObj.setDatum(\n                constraintIndex,\n                app.Units.Quantity(str(self.points[1][startIndex]) + \"mm\"),\n            )\n\n    def _createSketcherBSpline(self, sketchName, startIndex, endIndex):\n        \"\"\"\n        This function creates the Sketcher Workbench based BSpline curve.\n\n        Arguments\n        ----------\n        sketchName: (String)  The name/label of the generated sketch.\n        startIndex: (Integer) Zero-based index of the data points list to begin from.\n        endIndex:   (Integer) Zero-based index of the data points list to end to.\n        \"\"\"\n        # Sketch Preparation and Naming\n        sketchObj = doc.addObject(\"Sketcher::SketchObject\", sketchName)\n        sketchObj.Placement = app.Placement(\n            app.Vector(0.000000, 0.000000, 0.000000),\n            app.Rotation(-0.707107, 0.000000, 0.000000, -0.707107),\n        )\n        sketchObj.MapMode = \"Deactivated\"\n        # Sketch BSpline Procedure\n        count, points, conList = 0, [], []\n        n_ = endIndex - startIndex + 1\n        isXif, isXm = False, False\n        tempXif, tempXm = 0, 0\n        if self.designsplit:\n            tempXif, tempXm, startIndex, endIndex = self._create_tempX_var(startIndex, endIndex)\n        if self.designsplit and (\n            tempXif != self.points[0][startIndex] or self.points[1][startIndex] != 0\n        ):\n            sketchObj.addGeometry(\n                Part.Circle(app.Vector(tempXif, 0, 0), app.Vector(0, 0, 1), 10), True\n            )\n            sketchObj.addGeometry(\n                Part.Circle(\n                    app.Vector(\n                        self.points[0][startIndex], self.points[1][startIndex], 0\n                    ),\n                    app.Vector(0, 0, 1),\n                    10,\n                ),\n                True,\n            )\n            sketchObj.addConstraint(Sketcher.Constraint(\"Radius\", 0, 1.000000))\n            sketchObj.addConstraint(Sketcher.Constraint(\"Equal\", 0, 1))\n            sketchObj.addGeometry(\n                Part.Circle(\n                    app.Vector(\n                        self.points[0][startIndex + 1],\n                        self.points[1][startIndex + 1],\n                        0,\n                    ),\n                    app.Vector(0, 0, 1),\n                    10,\n                ),\n                True,\n            )\n            sketchObj.addConstraint(Sketcher.Constraint(\"Equal\", 0, 2))\n            isXif = True\n            count = 3\n        else:\n            sketchObj.addGeometry(\n                Part.Circle(\n                    app.Vector(\n                        self.points[0][startIndex], self.points[1][startIndex], 0\n                    ),\n                    app.Vector(0, 0, 1),\n                    10,\n                ),\n                True,\n            )\n            sketchObj.addGeometry(\n                Part.Circle(\n                    app.Vector(\n                        self.points[0][startIndex + 1],\n                        self.points[1][startIndex + 1],\n                        0,\n                    ),\n                    app.Vector(0, 0, 1),\n                    10,\n                ),\n                True,\n            )\n            sketchObj.addConstraint(Sketcher.Constraint(\"Radius\", 0, 1.000000))\n            sketchObj.addConstraint(Sketcher.Constraint(\"Equal\", 0, 1))\n            count = 2\n        for h in range(startIndex + 2, endIndex + 1):\n            sketchObj.addGeometry(\n                Part.Circle(\n                    app.Vector(self.points[0][h], self.points[1][h], 0),\n                    app.Vector(0, 0, 1),\n                    10,\n                ),\n                True,\n            )\n            sketchObj.addConstraint(Sketcher.Constraint(\"Equal\", 0, count))\n            if self.designprogressbar.value() < 60:\n                self.designprogressbar.setValue(round(50 + ((h / (10 * n_)) * 100)))\n            count += 1\n        if self.designsplit and (\n            tempXm != self.points[0][endIndex] or self.points[1][endIndex] != 0\n        ):\n            sketchObj.addGeometry(\n                Part.Circle(app.Vector(tempXm, 0, 0), app.Vector(0, 0, 1), 10), True\n            )\n            sketchObj.addConstraint(Sketcher.Constraint(\"Equal\", 0, count))\n            isXm = True\n            count += 1\n        tempVal = count\n        if isXif:\n            points.append(app.Vector(tempXif, 0))\n            conList.append(\n                Sketcher.Constraint(\n                    \"InternalAlignment:Sketcher::BSplineControlPoint\", 0, 3, tempVal, 0\n                )\n            )\n        count = 0 + isXif\n        for i in range(startIndex, endIndex + 1):\n            points.append(app.Vector(self.points[0][i], self.points[1][i]))\n            conList.append(\n                Sketcher.Constraint(\n                    \"InternalAlignment:Sketcher::BSplineControlPoint\",\n                    count,\n                    3,\n                    tempVal,\n                    count,\n                )\n            )\n            if self.designprogressbar.value() < 70:\n                self.designprogressbar.setValue(round(60 + ((i / (10 * n_)) * 100)))\n            count += 1\n        if isXm:\n            points.append(app.Vector(tempXm, 0))\n            conList.append(\n                Sketcher.Constraint(\n                    \"InternalAlignment:Sketcher::BSplineControlPoint\",\n                    count,\n                    3,\n                    tempVal,\n                    count,\n                )\n            )\n            count += 1\n        if self.designsplit:\n            sketchObj.addGeometry(\n                Part.BSplineCurve(points, None, None, False, 3, None, False), False\n            )\n        else:\n            sketchObj.addGeometry(\n                Part.BSplineCurve(points, None, None, True, 3, None, False), False\n            )\n        sketchObj.addConstraint(conList)\n        sketchObj.exposeInternalGeometry(tempVal)\n        tempVar1x = tempXif if isXif else self.points[0][startIndex]\n        tempVar1y = 0 if isXif else self.points[1][startIndex]\n        tempVar1bx = (\n            self.points[0][startIndex] if isXif else self.points[0][startIndex + 1]\n        )\n        tempVar1by = (\n            self.points[1][startIndex] if isXif else self.points[1][startIndex + 1]\n        )\n        tempVar2x = tempXm if isXm else self.points[0][endIndex]\n        tempVar2y = 0 if isXm else self.points[1][endIndex]\n        count, startFrom = 0, 0\n        if isXif:\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\"DistanceX\", -1, 1, tempVal, 1, tempVar1x)\n            )\n            sketchObj.setDatum(\n                constraintIndex, app.Units.Quantity(str(tempVar1x) + \"mm\")\n            )\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\"DistanceY\", -1, 1, tempVal, 1, tempVar1y)\n            )\n            sketchObj.setDatum(\n                constraintIndex, app.Units.Quantity(str(tempVar1y) + \"mm\")\n            )\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\"DistanceX\", -1, 1, count + 1, 3, tempVar1bx)\n            )\n            sketchObj.setDatum(\n                constraintIndex, app.Units.Quantity(str(tempVar1bx) + \"mm\")\n            )\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\"DistanceY\", -1, 1, count + 1, 3, tempVar1by)\n            )\n            sketchObj.setDatum(\n                constraintIndex, app.Units.Quantity(str(tempVar1by) + \"mm\")\n            )\n            startFrom = startIndex + 1\n            count += 2\n        else:\n            startFrom = startIndex\n        if self.designsplit:\n            endTo = endIndex\n            if not isXif:\n                constraintIndex = sketchObj.addConstraint(\n                    Sketcher.Constraint(\n                        \"DistanceX\", -1, 1, tempVal, 1, self.points[0][startIndex]\n                    )\n                )\n                sketchObj.setDatum(\n                    constraintIndex,\n                    app.Units.Quantity(str(self.points[0][startIndex]) + \"mm\"),\n                )\n                constraintIndex = sketchObj.addConstraint(\n                    Sketcher.Constraint(\n                        \"DistanceY\", -1, 1, tempVal, 1, self.points[1][startIndex]\n                    )\n                )\n                sketchObj.setDatum(\n                    constraintIndex,\n                    app.Units.Quantity(str(self.points[1][startIndex]) + \"mm\"),\n                )\n                startFrom = startIndex + 1\n                count += 1\n        else:\n            endTo = endIndex + 1\n        for j in range(startFrom, endTo):\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\"DistanceX\", -1, 1, count, 3, self.points[0][j])\n            )\n            sketchObj.setDatum(\n                constraintIndex, app.Units.Quantity(str(self.points[0][j]) + \"mm\")\n            )\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\"DistanceY\", -1, 1, count, 3, self.points[1][j])\n            )\n            sketchObj.setDatum(\n                constraintIndex, app.Units.Quantity(str(self.points[1][j]) + \"mm\")\n            )\n            if self.designprogressbar.value() < 75:\n                self.designprogressbar.setValue(round(70 + ((j / (20 * n_)) * 100)))\n            count += 1\n        if self.designsplit:\n            tempVar1, tempVar2 = 0, 0\n            if isXm:\n                tempVar1, tempVar2 = count, 3\n            else:\n                tempVar1, tempVar2 = tempVal, 2\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\n                    \"DistanceX\", -1, 1, tempVar1, tempVar2, self.points[0][endIndex]\n                )\n            )\n            sketchObj.setDatum(\n                constraintIndex,\n                app.Units.Quantity(str(self.points[0][endIndex]) + \"mm\"),\n            )\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\n                    \"DistanceY\", -1, 1, tempVar1, tempVar2, self.points[1][endIndex]\n                )\n            )\n            sketchObj.setDatum(\n                constraintIndex,\n                app.Units.Quantity(str(self.points[1][endIndex]) + \"mm\"),\n            )\n            count += 1\n        if isXm:\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\"DistanceX\", -1, 1, tempVal, 2, tempVar2x)\n            )\n            sketchObj.setDatum(\n                constraintIndex, app.Units.Quantity(str(tempVar2x) + \"mm\")\n            )\n            constraintIndex = sketchObj.addConstraint(\n                Sketcher.Constraint(\"DistanceY\", -1, 1, tempVal, 2, tempVar2y)\n            )\n            sketchObj.setDatum(\n                constraintIndex, app.Units.Quantity(str(tempVar2y) + \"mm\")\n            )\n        if self.designsplitmode == 2:\n            sketchObj.addGeometry(\n                Part.LineSegment(\n                    app.Vector(tempVar1x, tempVar1y, 0),\n                    app.Vector(tempVar2x, tempVar2y, 0),\n                ),\n                False,\n            )\n            sketchObj.addConstraint(\n                Sketcher.Constraint(\"Coincident\", (tempVal * 2) - 1, 2, tempVal, 1)\n            )\n            sketchObj.addConstraint(\n                Sketcher.Constraint(\"Coincident\", (tempVal * 2) - 1, 1, tempVal, 2)\n            )\n\n\n\n# Sub-main Function Class\n# ------------------------------------------------------------------------------------------------\n\nclass AeroFoilDialog:\n\n    \"\"\"\n    The 'AeroFoilDialog' class itself is the AeroFoil GUI interface.\n    It contains dialog boxes that go to and fro, from the initial input dialog box\n    to the final creation dialog box. This class accumulates the user's inputs on\n    how the airfoils are to be created: their dimensions, their design type,\n    their resolution, their multiplicity, etc.\n\n    This class is also responsible for validating the input choices and values,\n    and notifying or warning the user accordingly.\n\n    Functions include:\n    __init__\n    _d\n    _createDialogs\n    _close\n    _next\n    _okay\n    _loadFile\n    _create\n    _af_d2c_radio_toggled\n    _af_d3_spinbox_1_toggled\n    _af_d3_spinbox_2_toggled\n    _af_d3_checkbox_1_toggled\n    _af_d3_checkbox_2_toggled\n    _af_d3_checkbox_5_toggled\n    _af_d3_checkbox_3_toggled\n    _af_d3_checkbox_4_toggled\n    _af_d3_radio_toggled\n    _functionsList\n    \"\"\"\n\n    def __init__(self):\n        \"\"\"\n        This function initializes of the 'AeroFoilDialog' class.\n        \"\"\"\n        # Variables Pertaining to the Entire Program\n        (\n            self.canMirror,\n            self.functionElements,\n            self.functionElements_Pos,\n            self.pointsX,\n            self.pointsY,\n        ) = (True, [], [], [], [])\n        self.tempStart, self.tempEnd = 0, 0\n        self.midIndex1, self.midIndex2 = 0, 0\n        # Variables Pertaining to AeroFoil_Initial_Dialog\n        self.airfoilType = 1\n        # Variables Pertaining to AeroFoil_NACA4Digit_Dialog\n        self.airfoil4DNumber = \"\"\n        # Variables Pertaining to AeroFoil_NACA5Digit_Dialog\n        self.airfoil5DNumber = \"\"\n        # Variables Pertaining to AeroFoil_CurvesInput_Dialog\n        self.airfoilProfileType, self.topCurveFunction, self.bottomCurveFunction = (\n            1,\n            \"\",\n            \"\",\n        )\n        # Variables Pertaining to AeroFoil_PointsInput_Dialog\n        self.importFrom, self.mirroring = 1, False\n        # Variables Pertaining to AeroFoil_DATInput_Dialog\n        self.lineStart, self.lineEnd, self.decimalType = 0, 0, 1\n        # Variables Pertaining to AeroFoil_CSVInput_Dialog\n        self.col1, self.col2, self.row1, self.row2 = 1, 2, 0, 0\n        # Variables Pertaining to AeroFoil_FileLoad_Dialog\n        (\n            self.loadSuccess,\n            self.loadedFilePath,\n            self.loadedFile,\n            self.loadedFileContents,\n        ) = (False, [\"\"], \"\", [])\n        # Variables Pertaining to AeroFoil_Final_Dialog\n        (\n            self.refine,\n            self.refineParam,\n            self.multi,\n            self.multiParam,\n            self.closed_,\n            self.workbench,\n            self.curveType,\n            self.maxRefineParamWarned,\n            self.maxQuantityParamWarned,\n            self.chordLength,\n            self.chordUnits,\n            self.progressBar_,\n            self.splitCurve,\n            self.splitCurveMode,\n            self.defaultEndPoints,\n        ) = (False, 2, False, 2, False, 1, 1, False, False, 0, 1, 0, False, 1, False)\n        # Actual Functions begin here\n        dialogIndex[0] = 1\n        self._createDialogs()\n\n    def _d(self, qcode, objStr):\n        \"\"\"\n        This function is a shortcut for obtaining a dialog's UI element.\n\n        Arguments\n        ----------\n        qcode: A distinct code for each UI element as listed below.\n        objStr: The UI element's name/label.\n        \"\"\"\n        qkey = [\n            0,\n            QPushButton,\n            QLineEdit,\n            QComboBox,\n            QRadioButton,\n            QCheckBox,\n            QSpinBox,\n            QDoubleSpinBox,\n            QLabel,\n            QProgressBar,\n        ]\n        # Elements 2 to 10 are the various UI elements employed in this macro.\n        # Ignore the 1st element; it's superfluous.\n        return self.dialog.findChild(qkey[qcode], objStr)\n\n    def _createDialogs(self):\n        \"\"\"\n        This function generates and displays the AeroFoil GUI interface, that is,\n        it creates all the dialog boxes for user interaction and input.\n        \"\"\"\n        global MACRO_DIR\n        global dialogIndex\n        if dialogIndex[0] == 1:\n            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + \"Initial_Dialog.ui\")\n            self._d(1, \"af_d1_close_button\").clicked.connect(lambda: self._close())\n            self._d(1, \"af_d1_next_button\").clicked.connect(lambda: self._next(1))\n            self._d(3, \"af_d1_combo\").setCurrentIndex(self.airfoilType - 1)\n        elif dialogIndex[0] == 2:\n            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + \"NACA4Digit_Dialog.ui\")\n            self._d(1, \"af_d2a_next_button\").clicked.connect(lambda: self._next(1))\n            self._d(1, \"af_d2a_back_button\").clicked.connect(lambda: self._next(-1))\n            self._d(2, \"af_d2a_textbox\").setText(self.airfoil4DNumber)\n        elif dialogIndex[0] == 3:\n            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + \"NACA5Digit_Dialog.ui\")\n            self._d(1, \"af_d2b_next_button\").clicked.connect(lambda: self._next(1))\n            self._d(1, \"af_d2b_back_button\").clicked.connect(lambda: self._next(-1))\n            self._d(2, \"af_d2b_textbox\").setText(self.airfoil5DNumber)\n        elif dialogIndex[0] == 4:\n            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + \"CurvesInput_Dialog.ui\")\n            self._d(2, \"af_d2c_textbox_1\").setText(self.topCurveFunction)\n            self._d(2, \"af_d2c_textbox_2\").setText(self.bottomCurveFunction)\n            self._d(4, \"af_d2c_radio_1\").toggled.connect(\n                lambda: self._af_d2c_radio_toggled()\n            )\n            if self.airfoilProfileType == 1:\n                self._d(4, \"af_d2c_radio_1\").setChecked(True)\n            else:\n                self._d(4, \"af_d2c_radio_2\").setChecked(True)\n            self._d(1, \"af_d2c_list_button\").clicked.connect(\n                lambda: self._functionsList()\n            )\n            self._d(1, \"af_d2c_next_button\").clicked.connect(lambda: self._next(1))\n            self._d(1, \"af_d2c_back_button\").clicked.connect(lambda: self._next(-1))\n        elif dialogIndex[0] == 5:\n            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + \"PointsInput_Dialog.ui\")\n            if self.importFrom == 1:\n                self._d(4, \"af_d2d_radio_1\").setChecked(True)\n            else:\n                self._d(4, \"af_d2d_radio_2\").setChecked(True)\n            if self.mirroring:\n                self._d(5, \"af_d2d_checkbox\").setChecked(True)\n            else:\n                self._d(5, \"af_d2d_checkbox\").setChecked(False)\n            self._d(1, \"af_d2d_next_button\").clicked.connect(lambda: self._next(1))\n            self._d(1, \"af_d2d_back_button\").clicked.connect(lambda: self._next(-1))\n        elif dialogIndex[0] == 6:\n            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + \"DATInput_Dialog.ui\")\n            self._d(6, \"af_d2d1a_spinBox_1\").setValue(self.tempStart)\n            self._d(6, \"af_d2d1a_spinBox_2\").setValue(self.tempEnd)\n            if self.decimalType == 1:\n                self._d(4, \"af_d2d1a_radio_1\").setChecked(True)\n            else:\n                self._d(4, \"af_d2d1a_radio_2\").setChecked(True)\n            self._d(1, \"af_d2d1a_next_button\").clicked.connect(lambda: self._next(1))\n            self._d(1, \"af_d2d1a_back_button\").clicked.connect(lambda: self._next(-1))\n        elif dialogIndex[0] == 7:\n            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + \"CSVInput_Dialog.ui\")\n            self._d(6, \"af_d2d1b_spinBox_1\").setValue(self.col1)\n            self._d(6, \"af_d2d1b_spinBox_2\").setValue(self.col2)\n            self._d(6, \"af_d2d1b_spinBox_3\").setValue(self.tempStart)\n            self._d(6, \"af_d2d1b_spinBox_4\").setValue(self.tempEnd)\n            if self.decimalType == 1:\n                self._d(4, \"af_d2d1b_radio_1\").setChecked(True)\n            else:\n                self._d(4, \"af_d2d1b_radio_2\").setChecked(True)\n            self._d(1, \"af_d2d1b_next_button\").clicked.connect(lambda: self._next(1))\n            self._d(1, \"af_d2d1b_back_button\").clicked.connect(lambda: self._next(-1))\n        elif dialogIndex[0] == 8:\n            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + \"FileLoad_Dialog.ui\")\n            self._d(2, \"af_d2cd2_textbox\").setText(self.loadedFilePath[0])\n            if self.loadedFilePath[0] == \"\":\n                self.loadSuccess = False\n                self._d(8, \"af_d2cd2_label_2\").setText(\"File Not Loaded\")\n                self._d(8, \"af_d2cd2_label_2\").setStyleSheet(\"color: black;\")\n            else:\n                if self.loadSuccess:\n                    self._d(8, \"af_d2cd2_label_2\").setText(\"File Loaded Successfully\")\n                    self._d(8, \"af_d2cd2_label_2\").setStyleSheet(\"color: darkgreen;\")\n                else:\n                    self._d(8, \"af_d2cd2_label_2\").setText(\n                        \"File Loaded Un-successfully\"\n                    )\n                    self._d(8, \"af_d2cd2_label_2\").setStyleSheet(\"color: crimson;\")\n            self._d(1, \"af_d2cd2_load_button\").clicked.connect(lambda: self._loadFile())\n            self._d(1, \"af_d2cd2_next_button\").clicked.connect(lambda: self._next(1))\n            self._d(1, \"af_d2cd2_back_button\").clicked.connect(lambda: self._next(-1))\n        elif dialogIndex[0] == 9:\n            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + \"Final_Dialog.ui\")\n            if self.refine:\n                self._d(6, \"af_d3_spinbox_1\").setValue(self.refineParam)\n                self._d(6, \"af_d3_spinbox_1\").setEnabled(True)\n                self._d(5, \"af_d3_checkbox_1\").setChecked(True)\n            else:\n                self.refineParam = 2\n                self._d(6, \"af_d3_spinbox_1\").setValue(2)\n                self._d(6, \"af_d3_spinbox_1\").setEnabled(False)\n                self._d(5, \"af_d3_checkbox_1\").setChecked(False)\n            if self.multi:\n                self._d(6, \"af_d3_spinbox_2\").setValue(self.multiParam)\n                self._d(6, \"af_d3_spinbox_2\").setEnabled(True)\n                self._d(5, \"af_d3_checkbox_2\").setChecked(True)\n            else:\n                self.multiParam = 2\n                self._d(6, \"af_d3_spinbox_2\").setValue(2)\n                self._d(6, \"af_d3_spinbox_2\").setEnabled(False)\n                self._d(5, \"af_d3_checkbox_2\").setChecked(False)\n            if self.splitCurve:\n                self._d(5, \"af_d3_checkbox_5\").setChecked(False)\n                self._d(5, \"af_d3_checkbox_5\").setEnabled(False)\n                self._d(5, \"af_d3_checkbox_6\").setChecked(False)\n                self._d(5, \"af_d3_checkbox_6\").setEnabled(True)\n                if self.splitCurveMode == 1:\n                    self._d(5, \"af_d3_checkbox_3\").setChecked(True)\n                    self._d(5, \"af_d3_checkbox_4\").setChecked(False)\n                else:\n                    self._d(5, \"af_d3_checkbox_3\").setChecked(False)\n                    self._d(5, \"af_d3_checkbox_4\").setChecked(True)\n                self._af_d3_checkbox_5_toggled()\n            else:\n                self._d(5, \"af_d3_checkbox_3\").setChecked(False)\n                self._d(5, \"af_d3_checkbox_4\").setChecked(False)\n                self._d(5, \"af_d3_checkbox_6\").setChecked(False)\n                self._d(5, \"af_d3_checkbox_6\").setEnabled(False)\n                self._d(5, \"af_d3_checkbox_5\").setChecked(False)\n                self._d(5, \"af_d3_checkbox_5\").setEnabled(True)\n                if self.closed_:\n                    self._d(5, \"af_d3_checkbox_3\").setEnabled(False)\n                    self._d(5, \"af_d3_checkbox_4\").setEnabled(False)\n                    self._d(5, \"af_d3_checkbox_5\").setChecked(True)\n                    self._af_d3_checkbox_5_toggled()\n                else:\n                    self._d(5, \"af_d3_checkbox_5\").setChecked(False)\n                    self._d(4, \"af_d3_radio_1\").setEnabled(True)\n                    self._d(4, \"af_d3_radio_2\").setEnabled(True)\n                    if self.workbench == 1:\n                        self._d(4, \"af_d3_radio_1\").setChecked(True)\n                        self._d(4, \"af_d3_radio_1a\").setEnabled(True)\n                        self._d(4, \"af_d3_radio_1b\").setEnabled(True)\n                        self._d(4, \"af_d3_radio_2a\").setEnabled(False)\n                        self._d(4, \"af_d3_radio_2b\").setEnabled(False)\n                        if self.curveType == 1:\n                            self._d(4, \"af_d3_radio_1a\").setChecked(True)\n                        else:\n                            self._d(4, \"af_d3_radio_1b\").setChecked(True)\n                    else:\n                        self._d(4, \"af_d3_radio_2\").setChecked(True)\n                        self._d(4, \"af_d3_radio_1a\").setEnabled(False)\n                        self._d(4, \"af_d3_radio_1b\").setEnabled(False)\n                        self._d(4, \"af_d3_radio_2a\").setEnabled(True)\n                        self._d(4, \"af_d3_radio_2b\").setEnabled(True)\n                        if self.curveType == 1:\n                            self._d(4, \"af_d3_radio_2a\").setChecked(True)\n                        else:\n                            self._d(4, \"af_d3_radio_2b\").setChecked(True)\n            self.progressBar_ = self._d(9, \"af_d3_progressbar\")\n            self.progressBar_.setEnabled(False)\n            self.progressBar_.setValue(0)\n            self._d(7, \"af_d3_spinbox_3\").setValue(self.chordLength)\n            self._d(3, \"af_d3_combobox\").setCurrentIndex(self.chordUnits - 1)\n            self._d(4, \"af_d3_radio_1\").toggled.connect(\n                lambda: self._af_d3_radio_toggled()\n            )\n            self._d(5, \"af_d3_checkbox_1\").toggled.connect(\n                lambda: self._af_d3_checkbox_1_toggled()\n            )\n            self._d(5, \"af_d3_checkbox_2\").toggled.connect(\n                lambda: self._af_d3_checkbox_2_toggled()\n            )\n            self._d(5, \"af_d3_checkbox_5\").toggled.connect(\n                lambda: self._af_d3_checkbox_5_toggled()\n            )\n            self._d(5, \"af_d3_checkbox_3\").clicked.connect(\n                lambda: self._af_d3_checkbox_3_toggled()\n            )\n            self._d(5, \"af_d3_checkbox_4\").clicked.connect(\n                lambda: self._af_d3_checkbox_4_toggled()\n            )\n            self._d(6, \"af_d3_spinbox_1\").valueChanged.connect(\n                lambda: self._af_d3_spinbox_1_toggled()\n            )\n            self._d(6, \"af_d3_spinbox_2\").valueChanged.connect(\n                lambda: self._af_d3_spinbox_2_toggled()\n            )\n            self._d(1, \"af_d3_create_button\").clicked.connect(\n                lambda: self._startCreating()\n            )\n            self._d(1, \"af_d3_close_button\").clicked.connect(lambda: self._close())\n            self._d(1, \"af_d3_back_button\").clicked.connect(lambda: self._next(-1))\n        elif dialogIndex[0] == 10:\n            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + \"Math_Functions_Box.ui\")\n            self._d(8, \"af_mfb_label_6\").setText(\n                \"<img src=\" + MACRO_DIR + \"mfb_img.gif>\"\n            )\n            self._d(1, \"af_mfb_okay_button\").clicked.connect(lambda: self._okay())\n        self.dialog.setWindowIcon(\n            QtGui.QIcon(app.getUserMacroDir(True) + \"/AeroFoil_UI_Files/AeroFoil.svg\")\n        )\n        self.dialog.exec_()\n\n# Button Functions\n# ----------------------------------------------------------------\n\n    def _close(self):\n        \"\"\"\n        This function closes an open dialog box.\n        This function is called when the 'Close' button is clicked.\n        \"\"\"\n        self.dialog.done(1)\n\n    def _next(self, direction):\n        \"\"\"\n        This function takes the user from one dialog box to another.\n        This function is called when the 'Next' or 'Back' buttons are clicked.\n\n        Arguments\n        ----------\n        direction: '1' denotes a 'Go Next'; and '-1' denotes a 'Go Back'\n        \"\"\"\n        global dialogIndex\n        global MIN_DATA_POINTS\n        if direction == -1:\n            if dialogIndex[0] == 2:\n                self.airfoil4DNumber = \"\"\n            elif dialogIndex[0] == 3:\n                self.airfoil5DNumber = \"\"\n            elif dialogIndex[0] == 4:\n                (\n                    self.airfoilProfileType,\n                    self.topCurveFunction,\n                    self.bottomCurveFunction,\n                ) = (1, \"\", \"\")\n            elif dialogIndex[0] == 5:\n                self.importFrom, self.mirroring = 1, False\n            elif dialogIndex[0] == 6:\n                self.lineStart, self.lineEnd, self.decimalType = 0, 0, 1\n                self.tempStart, self.tempEnd, = (\n                    0,\n                    0,\n                )\n                self.midIndex1, self.midIndex2 = 0, 0\n            elif dialogIndex[0] == 7:\n                self.col1, self.col2, self.row1, self.row2 = 1, 2, 0, 0\n                self.tempStart, self.tempEnd, = (\n                    0,\n                    0,\n                )\n                self.midIndex1, self.midIndex2 = 0, 0\n            elif dialogIndex[0] == 8:\n                (\n                    self.loadedFilePath,\n                    self.loadSuccess,\n                    self.loadedFile,\n                    self.loadedFileContents,\n                ) = ([\"\"], False, \"\", [])\n            elif dialogIndex[0] == 9:\n                (\n                    self.refine,\n                    self.refineParam,\n                    self.multi,\n                    self.multiParam,\n                    self.closed_,\n                    self.workbench,\n                    self.curveType,\n                    self.maxRefineParamWarned,\n                    self.maxQuantityParamWarned,\n                    self.chordLength,\n                    self.chordUnits,\n                    self.splitCurve,\n                    self.splitCurveMode,\n                    self.defaultEndPoints,\n                ) = (\n                    False,\n                    2,\n                    False,\n                    2,\n                    False,\n                    1,\n                    1,\n                    False,\n                    False,\n                    0,\n                    1,\n                    False,\n                    1,\n                    False,\n                )\n            dialogIndex[0] = dialogIndex[dialogIndex[0]]\n        else:\n            if dialogIndex[0] == 1:\n                self.airfoilType = self._d(3, \"af_d1_combo\").currentIndex() + 1\n                if self.airfoilType == 1:\n                    _setDialogIndex(2)\n                elif self.airfoilType == 2:\n                    _setDialogIndex(3)\n                elif self.airfoilType == 3:\n                    _setDialogIndex(4)\n                elif self.airfoilType == 4:\n                    _setDialogIndex(5)\n            elif dialogIndex[0] == 2:\n                self.airfoil4DNumber = self._d(2, \"af_d2a_textbox\").text()\n                if _validateAirfoilNumber(self, 4):\n                    _setDialogIndex(9)\n                else:\n                    return\n            elif dialogIndex[0] == 3:\n                self.airfoil5DNumber = self._d(2, \"af_d2b_textbox\").text()\n                if _validateAirfoilNumber(self, 5):\n                    _setDialogIndex(9)\n                else:\n                    return\n            elif dialogIndex[0] == 4:\n                self.topCurveFunction = self._d(2, \"af_d2c_textbox_1\").text()\n                self.bottomCurveFunction = self._d(2, \"af_d2c_textbox_2\").text()\n                if not self._d(4, \"af_d2c_radio_2\").isChecked():\n                    self.airfoilProfileType = 1\n                    if _validateFunction(self, 1):\n                        _setDialogIndex(9)\n                    else:\n                        return\n                else:\n                    self.airfoilProfileType = 2\n                    if _validateFunction(self, 2):\n                        _setDialogIndex(9)\n                    else:\n                        return\n            elif dialogIndex[0] == 5:\n                if self._d(4, \"af_d2d_radio_1\").isChecked():\n                    self.importFrom = 1\n                    _setDialogIndex(6)\n                else:\n                    self.importFrom = 2\n                    _setDialogIndex(7)\n                if self._d(5, \"af_d2d_checkbox\").isChecked():\n                    self.mirroring = True\n                else:\n                    self.mirroring = False\n            elif dialogIndex[0] == 6:\n                tempVar1 = self._d(6, \"af_d2d1a_spinBox_1\").value()\n                tempVar2 = self._d(6, \"af_d2d1a_spinBox_2\").value()\n                tempVar3 = (\n                    0 if tempVar1 == 0 or tempVar2 == 0 else tempVar2 - tempVar1 + 1\n                )\n                if tempVar3 == 0 or tempVar3 >= MIN_DATA_POINTS:\n                    self.tempStart = self.lineStart = self._d(\n                        6, \"af_d2d1a_spinBox_1\"\n                    ).value()\n                    self.tempEnd = self.lineEnd = self._d(\n                        6, \"af_d2d1a_spinBox_2\"\n                    ).value()\n                    if self._d(4, \"af_d2d1a_radio_1\").isChecked():\n                        self.decimalType = 1\n                    else:\n                        self.decimalType = 2\n                    _setDialogIndex(8)\n                else:\n                    setAlertBox(\n                        \"There must be a minimum of \"\n                        + str(MIN_DATA_POINTS)\n                        + \" selected file lines,\\nthat is, pairs of data points !\",\n                        True,\n                    )\n                    return\n            elif dialogIndex[0] == 7:\n                tempVar = (\n                    self._d(6, \"af_d2d1b_spinBox_4\").value()\n                    - self._d(6, \"af_d2d1b_spinBox_3\").value()\n                    + 1\n                )\n                if tempVar >= MIN_DATA_POINTS:\n                    if (\n                        self._d(6, \"af_d2d1b_spinBox_1\").value()\n                        == self._d(6, \"af_d2d1b_spinBox_2\").value()\n                    ):\n                        self.col1 = self._d(6, \"af_d2d1b_spinBox_1\").value()\n                        self.col2 = self._d(6, \"af_d2d1b_spinBox_2\").value()\n                        self.tempStart = self.row1 = self._d(\n                            6, \"af_d2d1b_spinBox_3\"\n                        ).value()\n                        self.tempEnd = self.row2 = self._d(\n                            6, \"af_d2d1b_spinBox_4\"\n                        ).value()\n                        if self._d(4, \"af_d2d1b_radio_1\").isChecked():\n                            self.decimalType = 1\n                        else:\n                            self.decimalType = 2\n                        _setDialogIndex(8)\n                    else:\n                        setAlertBox(\"The two file columns cannot be the same !\", True)\n                        return\n                else:\n                    setAlertBox(\n                        \"There must be a minimum of \"\n                        + str(MIN_DATA_POINTS)\n                        + \" selected file rows,\\nthat is, pairs of data points !\",\n                        True,\n                    )\n                    return\n            elif dialogIndex[0] == 8:\n                if self.loadSuccess:\n                    _setDialogIndex(9)\n                else:\n                    setAlertBox(\n                        \"Cannot proceed further with an invalid/null file !\", True\n                    )\n                    return\n        self._close()\n        self._createDialogs()\n\n    def _okay(self):\n        \"\"\"\n        This function closes an open dialog box, and\n        reverts back to the previous dialog box.\n        This function is called when the 'Okay' button is clicked.\n        \"\"\"\n        global dialogIndex\n        if dialogIndex[0] == 10:\n            dialogIndex[0] = dialogIndex[10]\n        self._close()\n        self._createDialogs()\n\n    def _loadFile(self):\n        \"\"\"\n        This function open up the file loader with custom settings.\n        This function is called when the 'Load File' button from the.\n        'AeroFoil_FileLoad_Dialog' is clicked.\n        This function calls the '_validateFile' function/method\n        post-loading to verify the file's contents, and then\n        notifies the user whether or not the file load was successful.\n        \"\"\"\n        fileType = \"\"\n        homeDirPath = str(Path.home())\n        if self.importFrom == 1:\n            fileType = \"Text Files (*.dat)\"\n        elif self.importFrom == 2:\n            fileType = \"CSV Files (*.dat)\"\n        self.loadedFilePath = PySide.QtGui.QFileDialog.getOpenFileName(\n            None, \"Load 'Airfoil Points' Data File\", homeDirPath, fileType\n        )\n        try:\n            self.loadedFile.close()\n        except Exception:\n            pass\n        try:\n            self.loadedFile = open(self.loadedFilePath[0], \"r\")\n        except Exception:\n            self.loadedFile = \"\"\n        if self.loadedFile == \"\":\n            setAlertBox(\"No file has been selected!\", True)\n        else:\n            if _validateFile(self):\n                self.loadSuccess = True\n                if self.mirroring and not self.canMirror:\n                    setAlertBox(\n                        \"Airfoil profile is complete and cannot be mirrored.\", False\n                    )\n            else:\n                self.loadSuccess = False\n        self._close()\n        self._createDialogs()\n\n    def _startCreating(self):\n        \"\"\"\n        This function begins the airfoil creation process.\n        This function accumulates and stores the final dialog's input data.\n        This function also notifies the user whether or not the entire\n        'AeroFoil' procedure has been successfully completed.\n        This function is called when the 'Create AeroFoil' button from the\n        'AeroFoil_Final_Dialog' is clicked.\n        This function is responsible for launching the second (Top) macro call.\n        \"\"\"\n        global UNITSCONVERSION\n        global MIN_CHORD_LENGTH_MM\n        if self._d(5, \"af_d3_checkbox_1\").isChecked():\n            self.refine = True\n            self.refineParam = self._d(6, \"af_d3_spinbox_1\").value()\n        if self._d(5, \"af_d3_checkbox_2\").isChecked():\n            self.multi = True\n            self.multiParam = self._d(6, \"af_d3_spinbox_2\").value()\n        if self._d(5, \"af_d3_checkbox_5\").isChecked():\n            self.closed_ = True\n        if self._d(5, \"af_d3_checkbox_3\").isChecked():\n            self.splitCurve = True\n            self.splitCurveMode = 1\n        if self._d(5, \"af_d3_checkbox_4\").isChecked():\n            self.splitCurve = True\n            self.splitCurveMode = 2\n        if self._d(5, \"af_d3_checkbox_6\").isChecked():\n            self.defaultEndPoints = True\n        if self._d(4, \"af_d3_radio_1\").isChecked():\n            self.workbench = 1\n            if self._d(4, \"af_d3_radio_1a\").isChecked():\n                self.curveType = 1\n            else:\n                self.curveType = 2\n        else:\n            self.workbench = 2\n            if self._d(4, \"af_d3_radio_2a\").isChecked():\n                self.curveType = 1\n            else:\n                self.curveType = 2\n        self.chordLength = self._d(7, \"af_d3_spinbox_3\").value()\n        self.chordUnits = self._d(3, \"af_d3_combobox\").currentIndex() + 1\n        chordLength_conv = self.chordLength * UNITSCONVERSION[self.chordUnits]\n        if chordLength_conv >= MIN_CHORD_LENGTH_MM:\n            if _prepareAeroFoil(self):\n                if AeroFoil_generate(self):\n                    self._close()\n                    alertBox = QtGui.QMessageBox(\n                        QtGui.QMessageBox.Warning,\n                        \"AeroFoil\",\n                        \"The process has been completed successfully !\",\n                    )\n                    alertBox.setWindowModality(QtCore.Qt.ApplicationModal)\n                    alertBox.exec_()\n                    app.Console.PrintMessage(\n                        \"\\nThe AeroFoil process has been completed successfully !\\n\"\n                    )\n                    return\n            setAlertBox(\n                \"Unexpected error has occurred while processing !\\nPlease report.\", True\n            )\n            self.progressBar_.setEnabled(False)\n            self.progressBar_.setValue(0)\n            app.Console.PrintError(\n                \"\\nUnexpected error has occurred while processing! Please report.\\n\"\n            )\n        else:\n            setAlertBox(\n                \"Airfoil chord length cannot be less than \"\n                + str(MIN_CHORD_LENGTH_MM)\n                + \"mm !\",\n                True,\n            )\n\n# Other Design Functions\n# ------------------------------------------------------------------------------------------\n\n    def _af_d2c_radio_toggled(self):\n        if self._d(4, \"af_d2c_radio_1\").isChecked():\n            self.airfoilProfileType = 1\n            self._d(2, \"af_d2c_textbox_2\").setEnabled(False)\n        else:\n            self.airfoilProfileType = 2\n            self._d(2, \"af_d2c_textbox_2\").setEnabled(True)\n\n    def _af_d3_spinbox_1_toggled(self):\n        global MAX_REFINE_PARAM\n        if not self.maxRefineParamWarned:\n            if self._d(6, \"af_d3_spinbox_1\").value() > MAX_REFINE_PARAM:\n                setAlertBox(\n                    \"Increase in refinement parameter leads to increase\\nin time and memory usage.\",\n                    False,\n                )\n                self.maxRefineParamWarned = True\n\n    def _af_d3_spinbox_2_toggled(self):\n        global MAX_QUANTITY_PARAM\n        if not self.maxQuantityParamWarned:\n            if self._d(6, \"af_d3_spinbox_2\").value() > MAX_QUANTITY_PARAM:\n                setAlertBox(\n                    \"Increase in quantity parameter leads to increase\\nin time and memory usage.\",\n                    False,\n                )\n                self.maxQuantityParamWarned = True\n\n    def _af_d3_checkbox_1_toggled(self):\n        self._d(6, \"af_d3_spinbox_1\").setValue(2)\n        if self._d(5, \"af_d3_checkbox_1\").isChecked():\n            self._d(6, \"af_d3_spinbox_1\").setEnabled(True)\n        else:\n            self._d(6, \"af_d3_spinbox_1\").setEnabled(False)\n\n    def _af_d3_checkbox_2_toggled(self):\n        self._d(6, \"af_d3_spinbox_2\").setValue(2)\n        if self._d(5, \"af_d3_checkbox_2\").isChecked():\n            self._d(6, \"af_d3_spinbox_2\").setEnabled(True)\n        else:\n            self._d(6, \"af_d3_spinbox_2\").setEnabled(False)\n\n    def _af_d3_checkbox_5_toggled(self):\n        self._d(4, \"af_d3_radio_1\").setChecked(True)\n        self._d(4, \"af_d3_radio_1a\").setChecked(True)\n        self._d(4, \"af_d3_radio_2a\").setChecked(True)\n        self._d(4, \"af_d3_radio_1a\").setEnabled(True)\n        self._d(4, \"af_d3_radio_1b\").setEnabled(True)\n        self._d(4, \"af_d3_radio_2a\").setEnabled(False)\n        self._d(4, \"af_d3_radio_2b\").setEnabled(False)\n        if self._d(5, \"af_d3_checkbox_5\").isChecked():\n            self.closed_ = True\n            self._d(4, \"af_d3_radio_1\").setEnabled(False)\n            self._d(4, \"af_d3_radio_2\").setEnabled(False)\n            self._d(5, \"af_d3_checkbox_3\").setEnabled(False)\n            self._d(5, \"af_d3_checkbox_4\").setEnabled(False)\n            self._d(5, \"af_d3_checkbox_6\").setEnabled(False)\n        else:\n            if self.closed_:\n                self._d(5, \"af_d3_checkbox_3\").setEnabled(True)\n                self._d(5, \"af_d3_checkbox_4\").setEnabled(True)\n                self._d(5, \"af_d3_checkbox_6\").setEnabled(True)\n            self.closed_ = False\n            self._d(4, \"af_d3_radio_1\").setEnabled(True)\n            self._d(4, \"af_d3_radio_2\").setEnabled(True)\n\n    def _af_d3_checkbox_3_toggled(self):\n        if self._d(5, \"af_d3_checkbox_3\").isChecked():\n            self._d(5, \"af_d3_checkbox_5\").setEnabled(False)\n            self._d(5, \"af_d3_checkbox_6\").setEnabled(True)\n            self._d(5, \"af_d3_checkbox_4\").setChecked(False)\n        else:\n            self._d(5, \"af_d3_checkbox_5\").setEnabled(True)\n            self._d(5, \"af_d3_checkbox_6\").setEnabled(False)\n            self._d(5, \"af_d3_checkbox_6\").setChecked(False)\n        self._d(5, \"af_d3_checkbox_5\").setChecked(False)\n        self._af_d3_checkbox_5_toggled()\n\n    def _af_d3_checkbox_4_toggled(self):\n        if self._d(5, \"af_d3_checkbox_4\").isChecked():\n            self._d(5, \"af_d3_checkbox_5\").setEnabled(False)\n            self._d(5, \"af_d3_checkbox_6\").setEnabled(True)\n            self._d(5, \"af_d3_checkbox_3\").setChecked(False)\n        else:\n            self._d(5, \"af_d3_checkbox_5\").setEnabled(True)\n            self._d(5, \"af_d3_checkbox_6\").setEnabled(False)\n            self._d(5, \"af_d3_checkbox_6\").setChecked(False)\n        self._d(5, \"af_d3_checkbox_5\").setChecked(False)\n        self._af_d3_checkbox_5_toggled()\n\n    def _af_d3_radio_toggled(self):\n        self._d(4, \"af_d3_radio_1a\").setChecked(True)\n        self._d(4, \"af_d3_radio_2a\").setChecked(True)\n        if self._d(4, \"af_d3_radio_1\").isChecked():\n            self._d(4, \"af_d3_radio_1a\").setEnabled(True)\n            self._d(4, \"af_d3_radio_1b\").setEnabled(True)\n            self._d(4, \"af_d3_radio_2a\").setEnabled(False)\n            self._d(4, \"af_d3_radio_2b\").setEnabled(False)\n        else:\n            self._d(4, \"af_d3_radio_1a\").setEnabled(False)\n            self._d(4, \"af_d3_radio_1b\").setEnabled(False)\n            self._d(4, \"af_d3_radio_2a\").setEnabled(True)\n            self._d(4, \"af_d3_radio_2b\").setEnabled(True)\n\n    def _functionsList(self):\n        self.topCurveFunction = self._d(2, \"af_d2c_textbox_1\").text()\n        self.bottomCurveFunction = self._d(2, \"af_d2c_textbox_2\").text()\n        _setDialogIndex(10)\n        self._close()\n        self._createDialogs()\n\n\n\ndef _setDialogIndex(index):\n    \"\"\"\n    This function sets the appropriate dialog box, when the\n    'Next', 'Back', and 'Okay' buttons are clicked.\n    This function is NOT responsible for loading any dialog boxes.\n\n    The 'index' argument denotes the next or previous dialog box to go to.\n    The 'index' number corresponds to the global variable list 'dialogIndex'\n    as well as the dialog names table mentioned in the macro's main DocString.\n\n    The first element in the global variable 'dialogIndex' is the index number\n    of the currently open dialog box. The other elements too are eventually\n    replaced with the index numbers of the dialog box that was opened prior\n    to the current one. This allows the macro to remember its backward\n    journey through the various dialog boxes.\n\n    Arguments\n    ----------\n    index:  A dialog box code (Integer) as listed in the global variable\n            'dialogIndex'.\n    \"\"\"\n    global dialogIndex\n    dialogIndex[index] = dialogIndex[0]\n    # Here, the first element which contains the current dialog box\n    # index number is assigned to the Nth element, where 'N' is the\n    # index number of the next dialog box.\n    # This ensures that when the 'Back' button is clicked, the macro\n    # can approach the previous dialog box. This way, regardless of 'N',\n    # the macro can approach the 1st dialog box by maximum.\n    dialogIndex[0] = index\n    # Here, the first element is set to the 'index' number argument.\n    # This sets the macro to open up a specific next dialog box.\n    # The macro then opens up the next dialog box when the\n    # '_createDialogs' method from the 'AeroFoilDialog' class is called.\n\ndef setAlertBox(message, error):\n    \"\"\"\n    This function sets the error and warning pop-up messages.\n\n    Arguments\n    ----------\n    message: The string-based message to be displayed.\n    error:   'True' opens up the 'Critical' message box, and\n             'False' opens up the 'Warning' message box.\n    \"\"\"\n    msgbox_ = 0\n    if error:\n        msgbox_ = QtGui.QMessageBox(\n            QtGui.QMessageBox.Critical, \"AeroFoil - Error Message\", message\n        )\n    else:\n        msgbox_ = QtGui.QMessageBox(\n            QtGui.QMessageBox.Warning, \"AeroFoil - Warning Message\", message\n        )\n    msgbox_.setWindowModality(QtCore.Qt.ApplicationModal)\n    msgbox_.exec_()\n\n\n\n# Operating and Math Functions\n# ------------------------------------------------------------------------------------------\n\ndef _prepareAeroFoil(objRef):\n    \"\"\"\n    This function utilizes the various user input data as a basis\n    for creating a list of refined, verified, and finalized\n    airfoil data points to be used later for physical creation.\n    This function is called from the '_startCreating' method\n    of the 'AeroFoilDialog' class.\n\n    Arguments\n    ----------\n    objRef: An instance of the 'AeroFoilDialog' object.\n    \"\"\"\n    global UNITSCONVERSION\n    global NACA_NUMBER_OF_POINTS\n    chordLength_conv = objRef.chordLength * UNITSCONVERSION[objRef.chordUnits]\n    # Enable Progress Bar\n    objRef.progressBar_.setEnabled(True)\n    objRef.progressBar_.setValue(0)\n    # Generating and Furnishing Points\n    if objRef.airfoilType == 1:\n        _naca4digit(objRef)\n    elif objRef.airfoilType == 2:\n        _naca5digit(objRef)\n    elif objRef.airfoilType == 3:\n        xu_, yu_, xl_, yl_ = [], [], [], []\n        n_ = (\n            round(NACA_NUMBER_OF_POINTS / 2)\n            * ((objRef.refine * (objRef.refineParam - 1)) + 1)\n        ) + 1\n        for points_i in range(n_):\n            xu_.append((points_i / (n_ - 1)) * chordLength_conv)\n            xl_.append((points_i / (n_ - 1)) * chordLength_conv)\n            try:\n                yu_.append(solveFx(objRef.topCurveFunction, xu_[-1]) * chordLength_conv)\n                if objRef.airfoilProfileType == 1:\n                    yl_.append(\n                        -1\n                        * solveFx(objRef.topCurveFunction, xu_[-1])\n                        * chordLength_conv\n                    )\n                elif objRef.airfoilProfileType == 2:\n                    yl_.append(\n                        solveFx(objRef.bottomCurveFunction, xu_[-1]) * chordLength_conv\n                    )\n            except Exception:\n                # Unexpected Error Occurred while Processing\n                return False\n            if objRef.progressBar_.value() < 50:\n                objRef.progressBar_.setValue(round((points_i / (2 * n_)) * 100))\n        xl_.reverse()\n        yl_.reverse()\n        objRef.midIndex1, objRef.midIndex2 = len(xu_) - 1, len(xu_)\n        objRef.pointsX, objRef.pointsY = xu_ + xl_, yu_ + yl_\n    elif objRef.airfoilType == 4:\n        count, tempVar, pointsInLine, pointsInLine_prev = (\n            1,\n            \"\",\n            [],\n            [],\n        )\n        n_ = len(objRef.loadedFileContents)\n        for lineOrRow in objRef.loadedFileContents:\n            if objRef.decimalType == 1:\n                tempVar = lineOrRow\n            elif objRef.decimalType == 2:\n                tempVar = (\n                    lineOrRow.replace(\",\", \".\")\n                    if objRef.importFrom == 1\n                    else [element_.replace(\",\", \".\") for element_ in lineOrRow]\n                )\n            tempVar = tempVar.replace(\"-.\", \"-0.\")\n            tempVar = tempVar.replace(\" .\", \"0.\")\n            tempVar = \"0\" + tempVar if tempVar[0] == \".\" else tempVar\n            pointsInLine = (\n                re.findall(r\"[+-]?\\d+(?:\\.\\d+)?\", tempVar)\n                if objRef.importFrom == 1\n                else re.findall(\n                    r\"[+-]?\\d+(?:\\.\\d+)?\", tempVar[col1 - 1] + \" \" + tempVar[col2 - 1]\n                )\n            )\n            if objRef.refine and count > 1:\n                n_ = (\n                    float(pointsInLine[0]) - float(pointsInLine_prev[0])\n                ) / objRef.refineParam\n                for i in range(objRef.refineParam - 1):\n                    tempVar = float(pointsInLine_prev[0]) + n_\n                    objRef.pointsX.append(tempVar * chordLength_conv)\n                    objRef.pointsY.append(\n                        interpolateNum(\n                            float(pointsInLine_prev[0]),\n                            float(pointsInLine_prev[1]),\n                            float(pointsInLine[0]),\n                            float(pointsInLine[1]),\n                            tempVar,\n                        )\n                        * chordLength_conv\n                    )\n            pointsInLine_prev = pointsInLine\n            objRef.pointsX.append(float(pointsInLine[0]) * chordLength_conv)\n            objRef.pointsY.append(float(pointsInLine[1]) * chordLength_conv)\n            if objRef.progressBar_.value() < 50:\n                objRef.progressBar_.setValue(round((count / (2 * n_)) * 100))\n            count += 1\n    if (\n        objRef.pointsX[len(objRef.pointsX) - 1] != objRef.pointsX[0]\n        or objRef.pointsY[len(objRef.pointsY) - 1] != objRef.pointsY[0]\n    ) and not objRef.splitCurve:\n        objRef.pointsX.append(objRef.pointsX[0])\n        objRef.pointsY.append(objRef.pointsY[0])\n    return True\n\n\n\ndef interpolateNum(x1_, y1_, x2_, y2_, x_):\n    \"\"\"\n    This function performs a linear interpolation of any given number.\n\n    Arguments\n    ----------\n    x1_, y1_, x2_, y2_: X and Y-axis values of a pair of data points.\n    x: Input value of one of the axes of the data point sought.\n    \"\"\"\n    return y1_ + (((x_ - x1_) * (y2_ - y1_)) / (x2_ - x1_))\n\n\n\ndef generateName(inputName):\n    \"\"\"\n    This function correctly provides a given name/label with\n    appropriate and non-dulplicate numbering.\n    e.g.  'AeroFoil' results in 'AeroFoil_1' if such a labelled\n          object does not exist; else, it becomes 'AeroFoil_2'.\n\n    Arguments\n    ----------\n    inputName: A non-numbered (simple) name/label\n    \"\"\"\n    nameIndex = 1\n    while True:\n        if (\n            not doc.getObjectsByLabel(inputName + \"_\" + str(nameIndex))\n            and not doc.getObjectsByLabel(inputName + \"_\" + str(nameIndex) + \"_Upper\")\n            and not doc.getObjectsByLabel(inputName + \"_\" + str(nameIndex) + \"_Lower\")\n        ):\n            return inputName + \"_\" + str(nameIndex)\n        nameIndex += 1\n\n\n\ndef _naca4digit(objRef):\n    \"\"\"\n    This function generates a list of airfoil data points\n    for a typical NACA 4 Digit airfoil model.\n    This function is called from the '_startCreating' method\n    of the 'AeroFoilDialog' class.\n\n    Arguments\n    ----------\n    objRef: An instance of the 'AeroFoilDialog' object.\n    \"\"\"\n    global UNITSCONVERSION\n    global NACA_NUMBER_OF_POINTS\n    chordLength_conv = objRef.chordLength * UNITSCONVERSION[objRef.chordUnits]\n    xu_, yu_, xl_, yl_ = [], [], [], []\n    yc_ = yt_ = theta_ = 0\n    a0_, a1_, a2_, a3_, a4_ = 0.2969, -0.126, -0.3516, 0.2843, -0.1015\n    m_, p_, t_ = (\n        int(objRef.airfoil4DNumber[0]) / 100,\n        int(objRef.airfoil4DNumber[1]) / 10,\n        int(objRef.airfoil4DNumber[2] + objRef.airfoil4DNumber[3]) / 100,\n    )\n    n_ = (\n        round(NACA_NUMBER_OF_POINTS / 2)\n        * ((objRef.refine * (objRef.refineParam - 1)) + 1)\n    ) + 1\n    for i in range(n_):\n        x_ = i / (n_ - 1)\n        yt_ = (\n            5\n            * t_\n            * (\n                (a0_ * pow(x_, 0.5))\n                + (a1_ * x_)\n                + (a2_ * pow(x_, 2))\n                + (a3_ * pow(x_, 3))\n                + (a4_ * pow(x_, 4))\n            )\n        )\n        if x_ < p_:\n            yc_ = (m_ * ((2 * p_ * x_) - (x_ * x_))) / (p_ * p_)\n            theta_ = math.degrees(math.atan((2 * m_ * (p_ - x_)) / (p_ * p_)))\n        else:\n            yc_ = (m_ * (1 - (2 * p_) + (2 * p_ * x_) - (x_ * x_))) / pow(1 - p_, 2)\n            theta_ = math.degrees(math.atan((2 * m_ * (p_ - x_)) / pow(1 - p_, 2)))\n        xu_.append((x_ - (yt_ * math.sin(math.radians(theta_)))) * chordLength_conv)\n        yu_.append((yc_ + (yt_ * math.cos(math.radians(theta_)))) * chordLength_conv)\n        xl_.append((x_ + (yt_ * math.sin(math.radians(theta_)))) * chordLength_conv)\n        yl_.append((yc_ - (yt_ * math.cos(math.radians(theta_)))) * chordLength_conv)\n        if objRef.progressBar_.value() < 50:\n            objRef.progressBar_.setValue(round((i / (2 * n_)) * 100))\n    xl_.reverse()\n    yl_.reverse()\n    objRef.midIndex1, objRef.midIndex2 = len(xu_) - 1, len(xu_)\n    objRef.pointsX, objRef.pointsY = xu_ + xl_, yu_ + yl_\n\n\n\ndef _naca5digit(objRef):\n    \"\"\"\n    This function generates a list of airfoil data points\n    for a typical NACA 5 Digit airfoil model.\n    This function is called from the '_startCreating' method\n    of the 'AeroFoilDialog' class.\n\n    Arguments\n    ----------\n    objRef: An instance of the 'AeroFoilDialog' object.\n    \"\"\"\n    global UNITSCONVERSION\n    global NACA_NUMBER_OF_POINTS\n    chordLength_conv = objRef.chordLength * UNITSCONVERSION[objRef.chordUnits]\n    xu_, yu_, xl_, yl_ = [], [], [], []\n    yc_ = yt_ = theta_ = 0\n    a0_, a1_, a2_, a3_, a4_ = 0.2969, -0.126, -0.3516, 0.2843, -0.1015\n    R_ = [0.0580, 0.1260, 0.2025, 0.2900, 0.3910, 0.1300, 0.2170, 0.3180, 0.4410]\n    K1_ = [361.400, 51.640, 15.957, 6.643, 3.230, 51.990, 15.793, 6.520, 3.191]\n    K2K1_ = [0, 0, 0, 0, 0, 0.000764, 0.00677, 0.0303, 0.1355]\n    index = int(objRef.airfoil5DNumber[1]) - 1 + (4 * int(objRef.airfoil5DNumber[2]))\n    r_, k1_, k2k1_, t_ = (\n        R_[index],\n        K1_[index],\n        K2K1_[index],\n        int(objRef.airfoil5DNumber[3] + objRef.airfoil5DNumber[4]) / 100,\n    )\n    n_ = (\n        round(NACA_NUMBER_OF_POINTS / 2)\n        * ((objRef.refine * (objRef.refineParam - 1)) + 1)\n    ) + 1\n    for i in range(n_):\n        x_ = i / (n_ - 1)\n        yt_ = (\n            5\n            * t_\n            * (\n                (a0_ * pow(x_, 0.5))\n                + (a1_ * x_)\n                + (a2_ * pow(x_, 2))\n                + (a3_ * pow(x_, 3))\n                + (a4_ * pow(x_, 4))\n            )\n        )\n        if int(objRef.airfoil5DNumber[2]) == 0:\n            if x_ < r_:\n                yc_ = (\n                    k1_ * (pow(x_, 3) - (3 * r_ * x_ * x_) + (x_ * r_ * r_ * (3 - r_)))\n                ) / 6\n                theta_ = math.degrees(\n                    math.atan(\n                        (k1_ * ((3 * x_ * x_) - (6 * r_ * x_) + (r_ * r_ * (3 - r_))))\n                        / 6\n                    )\n                )\n            else:\n                yc_ = (k1_ * pow(r_, 3) * (1 - x_)) / 6\n                theta_ = math.degrees(math.atan(-(k1_ * pow(r_, 3)) / 6))\n        elif int(objRef.airfoil5DNumber[2]) == 1:\n            if x_ < r_[int(objRef.airfoil5DNumber[1] + objRef.airfoil5DNumber[2])]:\n                yc_ = (\n                    k1_\n                    * (\n                        pow(x_ - r_, 3)\n                        - (k2k1_ * x_ * pow(1 - r_, 3))\n                        - (x_ * pow(r_, 3))\n                        + pow(r_, 3)\n                    )\n                ) / 6\n                theta_ = math.degrees(\n                    math.atan(\n                        (\n                            k1_\n                            * (\n                                (3 * pow(x_ - r_, 2))\n                                - (k2k1_ * pow(1 - r_, 3))\n                                - (pow(r_, 3))\n                            )\n                        )\n                        / 6\n                    )\n                )\n            else:\n                yc_ = (\n                    k1_\n                    * (\n                        (k2k1_ * pow(x_ - r_, 3))\n                        - (k2k1_ * x_ * pow(1 - r_, 3))\n                        - (x_ * pow(r_, 3))\n                        + pow(r_, 3)\n                    )\n                ) / 6\n                theta_ = math.degrees(\n                    math.atan(\n                        (\n                            k1_\n                            * (\n                                (3 * k2k1_ * pow(x_ - r_, 2))\n                                - (k2k1_ * pow(1 - r_, 3))\n                                - (pow(r_, 3))\n                            )\n                        )\n                        / 6\n                    )\n                )\n        xu_.append((x_ - (yt_ * math.sin(math.radians(theta_)))) * chordLength_conv)\n        yu_.append((yc_ + (yt_ * math.cos(math.radians(theta_)))) * chordLength_conv)\n        xl_.append((x_ + (yt_ * math.sin(math.radians(theta_)))) * chordLength_conv)\n        yl_.append((yc_ - (yt_ * math.cos(math.radians(theta_)))) * chordLength_conv)\n        if objRef.progressBar_.value() < 50:\n            objRef.progressBar_.setValue(round((i / (2 * n_)) * 100))\n    xl_.reverse()\n    yl_.reverse()\n    objRef.midIndex1, objRef.midIndex2 = len(xu_) - 1, len(xu_)\n    objRef.pointsX, objRef.pointsY = xu_ + xl_, yu_ + yl_\n\n\n\ndef convTrig(mode, inputVal):\n    \"\"\"\n    This function converts specific, unconventional trigonometric code\n    into a Python-based (Math module) trigonometric code.\n    This function is called from the 'solveFx' method.\n\n    Arguments\n    ----------\n    mode: A code number denoting a specific trignometric function.\n    inputVal: An unconventional trigonometric code string.\n    \"\"\"\n    if mode == 1:\n        return math.sin(math.radians(inputVal))\n    if mode == 2:\n        return math.cos(math.radians(inputVal))\n    if mode == 3:\n        return math.tan(math.radians(inputVal))\n    if mode == 4:\n        return math.degrees(math.asin(inputVal))\n    if mode == 5:\n        return math.degrees(math.acos(inputVal))\n    if mode == 6:\n        return math.degrees(math.atan(inputVal))\n\n\n\ndef solveFx(f_, x_):\n    \"\"\"\n    This function generates a list of airfoil data points\n    for a typical NACA 4 Digit airfoil model.\n    This function is called from the '_validateFunction'\n    and the '_startCreating' methods of the\n    'AeroFoilDialog' class.\n\n    Arguments\n    ----------\n    objRef: An instance of the 'AeroFoilDialog' object.\n    \"\"\"\n    f_ = f_.replace(\"x\", \"x_\")\n    f_ = f_.replace(\"^\", \"**\")\n    f_ = f_.replace(\"e\", \"math.e\")\n    f_ = f_.replace(\"pi\", \"math.pi\")\n    f_ = f_.replace(\"ln\", \"math.log\")\n    f_ = f_.replace(\"log\", \"math.log10\")\n    f_ = f_.replace(\"sqrt\", \"math.sqrt\")\n    f_ = f_.replace(\"sin(\", \"convTrig(1,\")\n    f_ = f_.replace(\"cos(\", \"convTrig(2,\")\n    f_ = f_.replace(\"tan(\", \"convTrig(3,\")\n    f_ = f_.replace(\"asin(\", \"convTrig(4,\")\n    f_ = f_.replace(\"acos(\", \"convTrig(5,\")\n    f_ = f_.replace(\"atan(\", \"convTrig(6,\")\n    try:\n        return eval(f_)\n    except Exception:\n        return\n\n\n\ndef _validateAirfoilNumber(objRef, digit):\n    \"\"\"\n    This function validates whether or not the inputted NACA airfoil model code\n    is valid and existing.\n    This function is called from the '_next' method of the 'AeroFoilDialog' class.\n    This function is called when the 'Next' button from the 'AeroFoil_NACA4Digit_Dialog'\n    or the 'AeroFoil_NACA5Digit_Dialog' is clicked.\n\n    Arguments\n    ----------\n    objRef: An instance of the 'AeroFoilDialog' object.\n    digit:  An integer number denoting the NACA airfoil type.\n            Options: 4 or 5.\n    \"\"\"\n    global NACA_5_2ND_3RD_DIGITS\n    airfoilNumber = \"\"\n    airfoilNumber = objRef.airfoil4DNumber if digit == 4 else objRef.airfoil5DNumber\n    if airfoilNumber.isnumeric():\n        if len(airfoilNumber) == digit:\n            if int(airfoilNumber[-2:]) == 0:\n                setAlertBox(\n                    \"The last two digits of the airfoil code cannot be a\\nzero value !\",\n                    True,\n                )\n            else:\n                if digit == 4:\n                    return True\n                elif digit == 5:\n                    if int(airfoilNumber[0]) == 2:\n                        if int(airfoilNumber[2]) <= 1:\n                            for numRef in NACA_5_2ND_3RD_DIGITS:\n                                if airfoilNumber[1] + airfoilNumber[2] == numRef:\n                                    return True\n                            if airfoilNumber[2] == 0:\n                                setAlertBox(\n                                    \"The second digit of the airfoil code must be\\nbetween one and five, both inclusive !\",\n                                    True,\n                                )\n                            elif airfoilNumber[2] == 1:\n                                setAlertBox(\n                                    \"The second digit of the airfoil code must be\\nbetween two and five, both inclusive !\",\n                                    True,\n                                )\n                        else:\n                            setAlertBox(\n                                \"The third digit of the airfoil code must be either\\na zero or a one !\",\n                                True,\n                            )\n                    else:\n                        setAlertBox(\n                            \"The first digit of the airfoil code must be a two !\", True\n                        )\n        else:\n            setAlertBox(\n                \"Airfoil code must contain exactly \" + str(digit) + \" digits !\", True\n            )\n    else:\n        setAlertBox(\"Airfoil code must be numeric !\", True)\n    objRef.airfoil4DNumber, objRef.airfoil5DNumber = \"\", \"\"\n    return False\n\n\n\ndef _validateFunction(objRef, mode):\n    \"\"\"\n    This function parses the inputted curve functions, and validates them,\n    resulting in whether or not the inputted functions are valid from points\n    0 to 1, both inclusive, in the X-axis of a typical graph.\n    This function is called from the '_next' method of the 'AeroFoilDialog' class.\n    This function is called when the 'Next' button from the 'AeroFoil_CurvesInput_Dialog'\n    is clicked.\n\n    Arguments\n    ----------\n    objRef:   An instance of the 'AeroFoilDialog' object.\n    mode:     An integer number specifying the function input mode.\n    Options:  '1' denotes that one function has been inputted,\n              and the function is to be symmetrically mirrored\n              to produce the lower airfoil points.\n              '2' denotes that two functions have been inputted,\n              one for the upper, and one for the lower airfoil points.\n    \"\"\"\n    global FUNCTIONSARRAY\n    function = [\n        objRef.topCurveFunction.replace(\" \", \"\"),\n        objRef.bottomCurveFunction.replace(\" \", \"\"),\n    ]\n    badFunctionCombinations = [\n        \"()\",\n        \"(+\",\n        \"(-\",\n        \"(*\",\n        \"(/\",\n        \"(^\",\n        \")(\",\n        \"+)\",\n        \"-)\",\n        \"*)\",\n        \"/)\",\n        \"^)\",\n        \".)\",\n        \").\",\n        \".(\",\n        \"(.\",\n        \"++\",\n        \"--\",\n        \"**\",\n        \"//\",\n        \"^^\",\n        \"xx\",\n        \"ee\",\n        \"pipi\",\n        \"xe\",\n        \"ex\",\n        \"xpi\",\n        \"pix\",\n        \"epi\",\n        \"pie\",\n        \"x(\",\n        \"e(\",\n        \"pi(\",\n        \")x\",\n        \")e\",\n        \")pi\",\n        \")ln\",\n        \")log\",\n        \")sqrt\",\n        \")sin\",\n        \")cos\",\n        \")tan\",\n        \")asin\",\n        \")acos\",\n        \")atan\",\n    ]\n    modeName = [\"Top\", \"Bottom\"]\n    for i in range(mode):\n        if len(function[i]) > 0:\n            if function[i].count(\"(\") == function[i].count(\")\"):\n                tempVar = function[i].replace(\",\", \".\")\n                for stringRef in FUNCTIONSARRAY:\n                    tempVar = tempVar.replace(stringRef, \"\")\n                if len(tempVar) == 0 or tempVar.isnumeric():\n                    badFunction, badFunctionFound = \"\", False\n                    for stringRef in badFunctionCombinations:\n                        if function[i].count(stringRef) != 0:\n                            badFunction, badFunctionFound = stringRef, True\n                            break\n                    if not badFunctionFound:\n                        try:\n                            if mode == 1:\n                                if (\n                                    solveFx(function[i], 0) >= 0\n                                    and solveFx(function[i], 1) >= 0\n                                ):\n                                    return True\n                                else:\n                                    setAlertBox(\n                                        \"Top curve function 'range' should not be less than zero !\",\n                                        True,\n                                    )\n                            elif mode == 2 and i == 1:\n                                if solveFx(function[i], 0) <= solveFx(\n                                    function[i - 1], 0\n                                ) and solveFx(function[i], 1) <= solveFx(\n                                    function[i - 1], 1\n                                ):\n                                    return True\n                                else:\n                                    setAlertBox(\n                                        \"Top and Bottom curve function 'ranges' should not intersect!\",\n                                        True,\n                                    )\n                        except Exception:\n                            setAlertBox(\n                                modeName[i]\n                                + \" curve function contains unrecognizable,\\ninvalid components !\",\n                                True,\n                            )\n                    else:\n                        setAlertBox(\n                            modeName[i]\n                            + \" curve function contains this invalidly\\nwritten component ::  \"\n                            + badFunction,\n                            True,\n                        )\n                else:\n                    setAlertBox(\n                        modeName[i]\n                        + \" curve function contains one or more\\ninvalid, extraneous components !\",\n                        True,\n                    )\n            else:\n                setAlertBox(\n                    modeName[i] + \" curve function contains unequal parantheses !\", True\n                )\n        else:\n            setAlertBox(modeName[i] + \" curve function cannot be empty !\", True)\n    objRef.topCurveFunction, objRef.bottomCurveFunction = \"\", \"\"\n    return False\n\n\n\ndef _validateFile(objRef):\n    \"\"\"\n    This function parses the file contents of the inputted file path, and validates them,\n    resulting in whether or not the file is valid (that is, contains minimum number of points,\n    valid data points structure, etc.)\n    This function is called from the '_loadFile' method of the 'AeroFoilDialog' class.\n\n    Arguments\n    ----------\n    objRef: An instance of the 'AeroFoilDialog' object.\n    \"\"\"\n    global MIN_DATA_POINTS\n    objRef.midIndex1, objRef.midIndex2 = 0, 0\n    i_start, i_end, tempVar, tempStr, count, objRef.canMirror, x_prev, dir_ = (\n        0,\n        0,\n        \"\",\n        \"\",\n        1,\n        True,\n        0,\n        [1, 1],\n    )\n    i_start, i_end, fileReader_ = (\n        (objRef.tempStart, objRef.tempEnd, objRef.loadedFile)\n        if objRef.importFrom == 1\n        else (objRef.row1, objRef.row2, csv.reader(objRef.loadedFile))\n    )\n    objRef.loadedFileContents = []\n    objRef.loadedFile.seek(0)\n    if i_start == 0:\n        i_start = i_end = 0\n        for lineOrRow in fileReader_:\n            if objRef.decimalType == 1:\n                tempVar = lineOrRow\n            elif objRef.decimalType == 2:\n                tempVar = (\n                    lineOrRow.replace(\",\", \".\")\n                    if objRef.importFrom == 1\n                    else [element_.replace(\",\", \".\") for element_ in lineOrRow]\n                )\n            pointsInLine = (\n                re.findall(r\"[+-]?\\d+(?:\\.\\d+)?\", tempVar)\n                if objRef.importFrom == 1\n                else re.findall(\n                    r\"[+-]?\\d+(?:\\.\\d+)?\",\n                    tempVar[objRef.col1 - 1] + \" \" + tempVar[objRef.col2 - 1],\n                )\n            )\n            if len(pointsInLine) == 2:\n                i_start = count if i_start == 0 else i_start\n                objRef.loadedFileContents.append(lineOrRow)\n            else:\n                if i_start != 0:\n                    i_end = count - 1\n                    break\n            if i_start != 0:\n                if tempStr == \"\":\n                    tempStr = \"1\"\n                elif tempStr == \"1\":\n                    dir_[0] = dir_[1]\n                    dir_[1] = (float(pointsInLine[0]) - x_prev) / abs(\n                        float(pointsInLine[0]) - x_prev\n                    )\n                    if dir_[0] != dir_[1] and (count - i_start) > 2:\n                        if objRef.canMirror:\n                            objRef.midIndex1, objRef.midIndex2 = (\n                                count - i_start - 1,\n                                count - i_start,\n                            )\n                            swapVar = objRef.loadedFileContents[-1]\n                            objRef.loadedFileContents[-1] = objRef.loadedFileContents[\n                                -2\n                            ]\n                            objRef.loadedFileContents.append(swapVar)\n                        objRef.canMirror = False\n                        tempStr = \"0\"\n                x_prev = float(pointsInLine[0])\n            count += 1\n        if i_start == 0:\n            tempStr = (\n                \"File Line :: \" + str(count)\n                if objRef.importFrom == 1\n                else \"File Row :: \" + str(count)\n            )\n            setAlertBox(\n                \"File is invalid, or file is of incorrect format !\\n\" + tempStr, True\n            )\n            return False\n    else:\n        for lineOrRow in fileReader_:\n            if count >= i_start:\n                if objRef.decimalType == 1:\n                    tempVar = lineOrRow\n                elif objRef.decimalType == 2:\n                    tempVar = (\n                        lineOrRow.replace(\",\", \".\")\n                        if objRef.importFrom == 1\n                        else [element_.replace(\",\", \".\") for element_ in lineOrRow]\n                    )\n                pointsInLine = (\n                    re.findall(r\"[+-]?\\d+(?:\\.\\d+)?\", tempVar)\n                    if objRef.importFrom == 1\n                    else re.findall(\n                        r\"[+-]?\\d+(?:\\.\\d+)?\",\n                        tempVar[objRef.col1 - 1] + \" \" + tempVar[objRef.col2 - 1],\n                    )\n                )\n                if len(pointsInLine) == 2:\n                    objRef.loadedFileContents.append(lineOrRow)\n                else:\n                    if i_end == 0 and count != 1:\n                        count += 1\n                        break\n                    else:\n                        tempStr = (\n                            \"File Line :: \" + str(count)\n                            if objRef.importFrom == 1\n                            else \"File Row :: \" + str(count)\n                        )\n                        setAlertBox(\n                            \"File is invalid, or file is of incorrect format !\\n\"\n                            + tempStr,\n                            True,\n                        )\n                        return False\n                if tempStr == \"\":\n                    tempStr = \"1\"\n                elif tempStr == \"1\":\n                    dir_[0] = dir_[1]\n                    dir_[1] = (float(pointsInLine[0]) - x_prev) / abs(\n                        float(pointsInLine[0]) - x_prev\n                    )\n                    if dir_[0] != dir_[1] and (count - i_start) > 2:\n                        if objRef.canMirror:\n                            objRef.midIndex1, objRef.midIndex2 = (\n                                count - i_start - 1,\n                                count - i_start,\n                            )\n                            swapVar = objRef.loadedFileContents[-1]\n                            objRef.loadedFileContents[-1] = objRef.loadedFileContents[\n                                -2\n                            ]\n                            objRef.loadedFileContents.append(swapVar)\n                        objRef.canMirror = False\n                        tempStr = \"0\"\n                x_prev = float(pointsInLine[0])\n                if i_end != 0 and count == i_end:\n                    count += 1\n                    break\n            count += 1\n    i_end = count - 1\n    # if i_end - i_start + 1 >= MIN_DATA_POINTS:\n    # return True\n    if i_end - i_start + 1 < MIN_DATA_POINTS:\n        setAlertBox(\n            \"There must be a minimum of \"\n            + str(MIN_DATA_POINTS)\n            + \" selected file rows,\\nthat is, pairs of data points !\",\n            True,\n        )\n        return False\n    objRef.lineStart, objRef.row1, objRef.lineEnd, objRef.row2 = (\n        (i_start, i_start, i_end, i_end)\n        if objRef.importFrom == 1\n        else (objRef.lineStart, objRef.row1, objRef.lineEnd, objRef.row2)\n    )\n    objRef.loadedFile.close()\n    return True\n\n\n\n######################################################################\n###----------------------------------------------------------------###\n### \t\tAEROFOIL MACRO CALLS - Bottom (check Top)\t   ###\n###----------------------------------------------------------------###\n###\t\t\t\t\t\t\t\t   ###\n###\t\t\t\t\t\t\t\t   ###\n###\tThis is the main macro call. The code below commences \t   ###\n###\tthe AeroFoil GUI interface. This script cannot be \t   ###\n###\tcalled externally.\t\t\t\t\t   ###\n    \t\t\t\t\t\t\t\t   ###\n                                                                   ###\nif __name__ == \"__main__\":\t\t\t\t\t   ###\n    AeroFoilDialog()\t\t\t\t\t\t   ###\n                                                                   ###\n###----------------------------------------------------------------###\n### \t\tAEROFOIL MACRO CALLS - Bottom (check Top)\t   ###\n###----------------------------------------------------------------###\n######################################################################\n",
    "url": "https://github.com/melwyncarlo/AeroFoil",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_AeroFoil",
    "version": "2.0.3",
    "license": "",
    "date": "2021-03-10",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ObjectCreation\\AeroFoil.FCMacro",
    "filename_from_url": "",
    "author": "Melwyncarlo",
    "icon": "AeroFoil.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "AeroFoil_UI_Files/AeroFoil_Initial_Dialog.ui",
      "AeroFoil_UI_Files/AeroFoil_NACA4Digit_Dialog.ui",
      "AeroFoil_UI_Files/AeroFoil_NACA5Digit_Dialog.ui",
      "AeroFoil_UI_Files/AeroFoil_CurvesInput_Dialog.ui",
      "AeroFoil_UI_Files/AeroFoil_PointsInput_Dialog.ui",
      "AeroFoil_UI_Files/AeroFoil_DATInput_Dialog.ui",
      "AeroFoil_UI_Files/AeroFoil_CSVInput_Dialog.ui",
      "AeroFoil_UI_Files/AeroFoil_FileLoad_Dialog.ui",
      "AeroFoil_UI_Files/AeroFoil_Final_Dialog.ui",
      "AeroFoil_UI_Files/AeroFoil_Math_Functions_Box.ui",
      "AeroFoil_UI_Files/AeroFoil_mfb_img.gif",
      "AeroFoil.svg"
    ],
    "parsed": true
  },
  {
    "name": "AirfoilImportAndScale",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Imports and scales an Airfoil in the form of a Draft Wire (DWire) or Basic Spline (BSpline)",
    "code": "# This Macro, when run, will first provide the user with a file browser to\n# locate and select a .dat airfoil text file. Once selected, a chord length is\n# entered and upon pressing the OK button, a properly scaled airfoil is\n# produced. There are two versions provided here. Version 1.5 should work on\n# FreeCAD versions, 0.13 stable as well as all 0.14 versions. Version 2 should\n# only be used with FreeCAD versions equal to or greater than 0.14 3077 and\n# will work best with versions built with OCE/OCC versions 6.7 or greater (See\n# the Wiki page for all available version).\n#\n# (c) quick61\n\n__Name__ = 'Airfoil Import and Scale'\n__Comment__ = 'Imports and scales an Airfoil in the form of a Draft Wire (DWire) or Basic Spline (BSpline)'\n__Author__ = \"quick61\"\n__Version__ = '2.1.2'\n__Date__ = '2024-01-14'\n__License__ = ''\n__Web__ = 'http://forum.freecadweb.org/viewtopic.php?f=22&t=5554'\n__Wiki__ = 'http://www.freecadweb.org/wiki/Macro_Airfoil_Import_%26_Scale'\n__Icon__ = ''\n__Help__ = ''\n__Status__ = 'stable'\n__Requires__ = 'freecad >= 0.14.3706'\n__Communication__ = ''\n__Files__ = ''\n\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nfrom PySide import QtCore, QtGui  # FreeCAD's PySide!\nimport Draft  # FreeCAD.\nimport importAirfoilDAT  # From the Draft module.\n\n# Select .dat airfoil data file to be imported\n\n# PySide returns a tuple (filename, filter) instead of just a string like in PyQt\nfilename, filefilter = QtGui.QFileDialog.getOpenFileName(\n    gui.getMainWindow(), 'Open An Airfoil File', '*.dat')\n\n\nclass AirfoilImporterAndScaler():\n\n    def __init__(self):\n        self.dialog = None\n\n        # Make dialog box and get the scale size\n        self.dialog = QtGui.QDialog(gui.getMainWindow())\n        self.dialog.resize(350, 100)\n        self.dialog.setWindowTitle('Airfoil Import & Scale')\n        layout = QtGui.QVBoxLayout(self.dialog)\n        label = QtGui.QLabel('Chord Length')\n        layout.addWidget(label)\n        self.line_edit_scale = QtGui.QLineEdit()\n        layout.addWidget(self.line_edit_scale)\n\n        # Add radio buttons to select between DWire and BSpline\n        self.radio_dwire = QtGui.QRadioButton('Make DWire')\n        self.radio_bspline = QtGui.QRadioButton('Make BSpline')\n\n        # set default to DWire & make radio buttons - Change self.radio1.setChecked(True) to\n        # self.radio2.setChecked(True) to set BSpline as default\n\n        self.radio_dwire.setChecked(True)\n        layout.addWidget(self.radio_dwire)\n        layout.addWidget(self.radio_bspline)\n\n        # Add OK / Cancel buttons\n        button_box = QtGui.QDialogButtonBox(self.dialog)\n        button_box.setOrientation(QtCore.Qt.Horizontal)\n        button_box.setStandardButtons(\n                QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok)\n        layout.addWidget(button_box)\n        button_box.accepted.connect(self.proceed)\n        button_box.rejected.connect(self.close)\n        QtCore.QMetaObject.connectSlotsByName(self.dialog)\n        self.dialog.show()\n        self.dialog.exec_()\n\n    def proceed(self):\n        global filename\n        if self.radio_dwire.isChecked():\n            try:\n                # This produces a scaled Airfoil with a DWire\n                scalefactor = float(self.line_edit_scale.text())\n                f1 = str(filename)\n                importAirfoilDAT.insert(f1, 'Unnamed')\n                Draft.scale(\n                        app.ActiveDocument.ActiveObject,\n                        delta=app.Vector(scalefactor, scalefactor, scalefactor),\n                        center=app.Vector(0, 0, 0),\n                        legacy=True)\n            except Exception as e:\n                app.Console.PrintError('Error, not a valid .dat file\\n')\n\n            self.close()\n\n        if self.radio_bspline.isChecked():\n            try:\n                # This produces a scaled Airfoil with a BSpline\n                scalefactor = float(self.line_edit_scale.text())\n                f1 = str(filename)\n                importAirfoilDAT.insert(f1, 'Unnamed')\n                points = app.ActiveDocument.ActiveObject.Points\n                Draft.makeBSpline(points, closed=True)\n                Draft.scale(app.ActiveDocument.ActiveObject,\n                            delta=app.Vector(scalefactor, scalefactor, scalefactor),\n                            center=app.Vector(0, 0, 0),\n                            legacy=True)\n                app.getDocument('Unnamed').removeObject('DWire')\n            except:\n                app.Console.PrintError('Error, not a valid .dat file\\n')\n\n            self.close()\n\n    def close(self):\n        self.dialog.hide()\n\n\nAirfoilImporterAndScaler()\n",
    "url": "http://forum.freecadweb.org/viewtopic.php?f=22&t=5554",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/Macro_Airfoil_Import_%26_Scale",
    "version": "2.1.2",
    "license": "",
    "date": "2024-01-14",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ObjectCreation\\AirfoilImportAndScale.FCMacro",
    "filename_from_url": "",
    "author": "quick61",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "BoxCreator",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Creates a box with interlocked notches",
    "code": "# -*- coding: utf-8 -*-\n\n__Name__ = 'BoxCreator'\n__Comment__ = 'Creates a box with interlocked notches'\n__Author__ = 'christi'\n__Version__ = '1.3.7'\n__Date__ = '2023-01-03'\n__License__ = 'LGPL-3.0-or-later'\n__Web__ = 'https://forum.freecadweb.org/viewtopic.php?t=31795'\n__Wiki__ = ''\n__Icon__ = 'BoxCreator.svg'\n__Help__ = 'Try it out and play with it. It should be self explanatory'\n__Status__ = 'Beta'\n__Requires__ = 'FreeCAD >= v0.17'\n__Communication__ = 'https://forum.freecadweb.org/viewtopic.php?p=264483'\n__Files__ = 'BoxCreator.svg,boxcreator/__init__.py,boxcreator/boxcreator.py,boxcreator/boxcreator.ui'\n\n\nimport os\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nfrom FreeCAD import Vector\n\nfrom boxcreator import boxcreator\n\n\nclass BoxcreatorDialog():\n    \"\"\"Show a dialog for BoxCreator\"\"\"\n    def __init__(self):\n        self.ui_file = os.path.join(app.getUserMacroDir(True),\n                                    'boxcreator/boxcreator.ui')\n        self.form = gui.PySideUic.loadUi(self.ui_file)\n        self._connect_widgets()\n        self.form.show()\n\n    def _connect_widgets(self):\n        self.form.pushButtonCreate.pressed.connect(self.createBox)\n        self.form.pushButton_CompartX.pressed.connect(self.compartmentX)\n        self.form.pushButton_CompartY.pressed.connect(self.compartmentY)\n        self.form.pushButton_CompartZ.pressed.connect(self.compartmentZ)\n\n    def createBox(self):\n        boxWidth = self.form.doubleSpinBoxWidth.value()\n        boxHeight = self.form.doubleSpinBoxHeight.value()\n        boxLength = self.form.doubleSpinBoxLength.value()\n        notchWidth = self.form.doubleSpinBoxNotchWidth.value()\n        materialWidth = self.form.doubleSpinBoxMaterialWidth.value()\n        drawSides = [self.form.checkBoxTop.isChecked(),\n                     self.form.checkBoxBottom.isChecked(),\n                     self.form.checkBoxLeft.isChecked(),\n                     self.form.checkBoxRight.isChecked(),\n                     self.form.checkBoxFront.isChecked(),\n                     self.form.checkBoxBack.isChecked()]\n        overhangTop = [self.form.overhangTopLeft.value(),\n                       self.form.overhangTopRight.value(),\n                       self.form.overhangTopFront.value(),\n                       self.form.overhangTopBack.value()]\n        overhangBottom = [self.form.overhangBotLeft.value(),\n                          self.form.overhangBotRight.value(),\n                          self.form.overhangBotFront.value(),\n                          self.form.overhangBotBack.value()]\n        if (boxWidth == 0) or (boxHeight == 0) or (boxLength == 0):\n            app.Console.PrintError('Error! None of the values can be 0!')\n            # we bail out without doing anything\n            return\n\n        box = boxcreator.create_box(materialWidth, boxWidth, boxHeight, boxLength, notchWidth, drawSides, overhangTop, overhangBottom, app.activeDocument())\n        gui.Selection.clearSelection()\n        gui.Selection.addSelection(box)\n        gui.SendMsgToActiveView('ViewFit')\n\n    def compartmentX(self):\n        self.createCompartment(Vector(1,0,0))\n\n    def compartmentY(self):\n        self.createCompartment(Vector(0,1,0))\n\n    def compartmentZ(self):\n        self.createCompartment(Vector(0,0,1))\n\n    def createCompartment(self, direction):\n        box = gui.Selection.getSelection()\n        notchWidth = self.form.doubleSpinBoxNotchWidth.value()\n        materialWidth = self.form.doubleSpinBoxMaterialWidth.value()\n        drawSides = [self.form.checkBoxTop.isChecked(),\n                     self.form.checkBoxBottom.isChecked(),\n                     self.form.checkBoxLeft.isChecked(),\n                     self.form.checkBoxRight.isChecked(),\n                     self.form.checkBoxFront.isChecked(),\n                     self.form.checkBoxBack.isChecked()]\n        offset = self.form.compartmentOffset.value()\n        boxsize = Vector(self.form.doubleSpinBoxWidth.value(), self.form.doubleSpinBoxLength.value(), self.form.doubleSpinBoxHeight.value())\n        compartment = boxcreator.create_compartment(box, direction, offset, materialWidth, notchWidth, drawSides, boxsize)\n        if compartment:\n            gui.Selection.clearSelection()\n            gui.Selection.addSelection(compartment)\n\n\nif __name__ == '__main__':\n    d = BoxcreatorDialog()\n",
    "url": "https://forum.freecadweb.org/viewtopic.php?t=31795",
    "raw_code_url": "",
    "wiki": "",
    "version": "1.3.7",
    "license": "",
    "date": "2023-01-03",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ObjectCreation\\BoxCreator.FCMacro",
    "filename_from_url": "",
    "author": "christi",
    "icon": "BoxCreator.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "BoxCreator.svg",
      "boxcreator/__init__.py",
      "boxcreator/boxcreator.py",
      "boxcreator/boxcreator.ui"
    ],
    "parsed": true
  },
  {
    "name": "BSpline3D",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Create a parametric BSpline from Vertices selected in 3D view",
    "code": "#!/usr/bin/env python3\n# SPDX-License-Identifier: LGPL-2.1-or-later\n\n#***************************************************************************\n#                          BSpline3D\n#***************************************************************************\n# Create a parametric BSpline from Vertices selected in 3D view\n# Select two or more vertices in the 3D view, then execute the macro.\n#***************************************************************************\n#*   Copyright (c) 2024 Eric Price (CorvusCorax)                           *\n#*                      <eric.price[at]tuebingen.mpg.de>                   *\n#*                                                                         *\n#*   This file is an extension of FreeCAD.                                 *\n#*                                                                         *\n#*   FreeCAD is free software: you can redistribute it and/or modify it    *\n#*   under the terms of the GNU Lesser General Public License as           *\n#*   published by the Free Software Foundation, either version 2.1 of the  *\n#*   License, or (at your option) any later version.                       *\n#*                                                                         *\n#*   FreeCAD is distributed in the hope that it will be useful, but        *\n#*   WITHOUT ANY WARRANTY; without even the implied warranty of            *\n#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *\n#*   Lesser General Public License for more details.                       *\n#*                                                                         *\n#*   You should have received a copy of the GNU Lesser General Public      *\n#*   License along with FreeCAD. If not, see                               *\n#*   <https://www.gnu.org/licenses/>.                                      *\n#*                                                                         *\n#**************************************************************************/\n\n__Name__ = 'BSpline3D'\n__Comment__ = 'Create a parametric BSpline from Vertices selected in 3D view'\n__Author__ = 'CorvusCorax'\n__Version__ = '0.0.2'\n__Date__ = '2024-11-22'\n__License__ = 'LGPL-2.1-or-later'\n__Web__ = 'https://github.com/CorvusCorax/FreeCAD-BSpline3D'\n__Wiki__ = 'https://github.com/CorvusCorax/FreeCAD-BSpline3D/wiki'\n__Help__ = 'Select two or more vertices in the 3D view, then execute the macro.'\n__Status__ = 'beta'\n__Requires__ = 'FreeCAD >= v0.20'\n__Contact__ = 'https://github.com/CorvusCorax'\n__Communication__ = 'https://github.com/CorvusCorax/FreeCAD-BSpline3D/issues'\n__Files__ = ''\n__Xpm__ = \"\"\"\n/* XPM */\nstatic char * XFACE[] = {\n\"32 32 2 1\",\n\"  c #FFFFFF\",\n\". c #000000\",\n\"                                \",\n\"                                \",\n\"                                \",\n\"                                \",\n\"                                \",\n\"              ........         .\",\n\"     ....   ...      ...    . . \",\n\"    ..... ...          .   ...  \",\n\"    .  ....            ..  .... \",\n\"    .  ...              .  ...  \",\n\"    .....               . .     \",\n\"       ..                       \",\n\"       .                        \",\n\"      ..             ....       \",\n\"      .             .....       \",\n\"      ..            .  ..       \",\n\"       .            .  ..       \",\n\"       ..           ....        \",\n\"        .                       \",\n\"        ..                      \",\n\"         ..                     \",\n\"          ..                    \",\n\"           ..                   \",\n\"      .......                   \",\n\"     ........                   \",\n\"     .    ...                   \",\n\"     .    ...                   \",\n\"     .    ..                    \",\n\"     ......                     \",\n\"                                \",\n\"                                \",\n\"                                \"};\n\"\"\"\n\nimport FreeCAD, FreeCADGui\nimport Draft\n\ndef BSpline3D():\n    selection = FreeCADGui.Selection.getCompleteSelection(Gui.Selection.ResolveMode.NoResolve)\n    vertices=[]\n    for obj in selection:\n        for i,feature in enumerate(obj.SubObjects):\n            if (feature.ShapeType!=\"Vertex\"):\n                FreeCAD.Console.PrintWarning(\"Selected object %s is not a Vertex (%s), using CenterOfGravity.\\n\"%(obj.Object.Label+\".\"+ obj.SubElementNames[i], feature.ShapeType)) # dirty little secret: we use CenterOfGravity for vertices as well.\n            subelements=obj.SubElementNames[i].split('.')\n            if len(subelements)==1:\n                # The feature selected is an independent shape and not subject to placements\n                target=\"<<\"+obj.Document.Label+\">>#<<\"+obj.Object.Label+\">>.\"\n                placement=\"\"\n            else:\n                # The feature selected is subelement of a Part, Body, Assembly or similar and subject to a chain of placements\n                placement=\"<<\"+obj.Document.Label+\">>#<<\"+obj.Object.Label+\">>.Placement * \"\n                for i in range(0,len(subelements)-2):\n                    placement+=\"<<\"+obj.Document.Label+\">>#<<\"+obj.Document.getObject(subelements[i]).Label+\">>.Placement * \"\n                target=\"<<\"+obj.Document.Label+\">>#<<\"+obj.Document.getObject(subelements[-2]).Label+\">>.\"\n            if subelements[-1]==\"\":\n                #selected element is the whole shape of a feature\n                target+=\"Shape.CenterOfGravity\"\n            else:\n                #selected element is a subelement of a shape (Vertex, Edge, SubShape, ...)\n                target+=\"Shape.\"+subelements[-1]+\".CenterOfGravity\"\n            vertices.append(\"( \"+placement+target+\" )\")\n    if len(vertices)<2:\n        FreeCAD.Console.PrintError(\"Please select at least 2 Points.\\n\")\n        return False\n    reference=\"list(\" + \"; \".join(vertices) + \")\"\n    FreeCADGui.doCommand(\"import Draft\")\n    FreeCADGui.doCommand(\"Draft.make_bspline([ FreeCAD.Vector(0,0,0), FreeCAD.Vector(1,1,1) ], closed=False, face=False, support=None).setExpression('Points', '%s')\"%(reference))\n    return True\n\nBSpline3D()\n#End\n",
    "url": "https://github.com/CorvusCorax/FreeCAD-BSpline3D",
    "raw_code_url": "",
    "wiki": "https://github.com/CorvusCorax/FreeCAD-BSpline3D/wiki",
    "version": "0.0.2",
    "license": "",
    "date": "2024-11-22",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ObjectCreation\\BSpline3D.FCMacro",
    "filename_from_url": "",
    "author": "CorvusCorax",
    "icon": "",
    "icon_source": null,
    "xpm": "\n/* XPM */\nstatic char * XFACE[] = {\n\"32 32 2 1\",\n\"  c #FFFFFF\",\n\". c #000000\",\n\"                                \",\n\"                                \",\n\"                                \",\n\"                                \",\n\"                                \",\n\"              ........         .\",\n\"     ....   ...      ...    . . \",\n\"    ..... ...          .   ...  \",\n\"    .  ....            ..  .... \",\n\"    .  ...              .  ...  \",\n\"    .....               . .     \",\n\"       ..                       \",\n\"       .                        \",\n\"      ..             ....       \",\n\"      .             .....       \",\n\"      ..            .  ..       \",\n\"       .            .  ..       \",\n\"       ..           ....        \",\n\"        .                       \",\n\"        ..                      \",\n\"         ..                     \",\n\"          ..                    \",\n\"           ..                   \",\n\"      .......                   \",\n\"     ........                   \",\n\"     .    ...                   \",\n\"     .    ...                   \",\n\"     .    ..                    \",\n\"     ......                     \",\n\"                                \",\n\"                                \",\n\"                                \"};\n",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Draft_Circle_3_Points",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Create a circle from three points",
    "code": "# -*- coding: utf-8 -*-\n# cr\u00e9er un cercle \u00e0 partir de 3 points s\u00e9l\u00e9ctionn\u00e9s\n# avec comme options le cercle peut \u00eatre construit sur un plans au choix\n# \u00e0 la coordonn\u00e9e d'une des trois formes s\u00e9lectionn\u00e9es au choix\n# et cr\u00e9ation du point central O/N\n# la formule provient de\n# http://www-obs.univ-lyon1.fr/labo/fc/Ateliers_archives/ateliers_2005-06/cercle_3pts.pdf\n# lire la note dans le pdf, sur l'ordre de s\u00e9lection des points,\n# si la formule renvoie une erreur (exemple les 3 points dans le m\u00eame alignement)\n\n__Name__ = 'Draft Circle 3 Points'\n__Comment__ = 'Create a circle from three points'\n__Author__ = 'Mario52'\n__Version__ = '1.0.1'\n__Date__ = '2019-02-01'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'https://www.freecadweb.org/wiki/Macro_Draft_Circle_3_Points'\n__Wiki__ = 'https://www.freecadweb.org/wiki/Macro_Draft_Circle_3_Points'\n__Icon__ = ''\n__Help__ = 'Select three shapes and run to create a circle passing through the bounding box center of the three shapes'\n__Status__ = ''\n__Requires__ = ''\n__Communication__ = ''\n__Files__ = ''\n\nfrom math import sqrt\n\nfrom PyQt4 import QtCore, QtGui\nimport FreeCAD as app\nimport FreeCADGui as gui\nimport Draft, Part, PartGui, FreeCADGui\nfrom FreeCAD import Base\n\ndef errorDialog(msg):\n    # Create a simple dialog QMessageBox\n    # The first argument indicates the icon used: one of QtGui.QMessageBox.{NoIcon, Information, Warning, Critical, Question}\n    diag = QtGui.QMessageBox(QtGui.QMessageBox.Critical,u\"Error Message\",msg)\n    diag.setWindowModality(QtCore.Qt.ApplicationModal)\n    diag.exec_()\n\ndef affiche(pl, x,y,z,rayon,r,v,b,afficherPoint):\n    pl.Base=app.Vector(x,y,z)\n    Draft.makeCircle((rayon),placement=pl,face=False,support=None)\n    gui.activeDocument().activeObject().LineColor = (r,v,b)\n    if afficherPoint:\n        Draft.makePoint(x,y,z)\n    diag = QtGui.QMessageBox(QtGui.QMessageBox.Information,u\"Coordinates\",u\"Coordinates X : \"+str(x)+\"\\r\\n\"+u\"Coordinates Y : \"+str(y)+\"\\n\"+u\"Coordinates Z : \"+str(z)+\"\\nRayon\\t     : \"+str(rayon))\n    diag.setWindowModality(QtCore.Qt.ApplicationModal)\n    diag.exec_()\n\n# prendre les objets selectionnes\nsel = gui.Selection.getSelection()\n\n# S'il y a 3 points s\u00e9lectionn\u00e9s alors..\nif len(sel)==3:\n    i = 0\n    ta = [0] * 9\n    for obj in sel:\n        x = obj.Shape.BoundBox.Center\n        ta[i + 0] = x.x\n        ta[i + 1] = x.y\n        ta[i + 2] = x.z\n        i += 3\n\n    # mode by default vueChoix = 0 and alignerSur = 0\n    vueChoix=0    # choice of the top view = 1 XY, view Front = 2 ZX, Right view = 3 ZY\n    alignerSur=0    # Aligns the circle shaped the choice (1,2 or 3) or Z = 0\n    afficherPoint = True    # Displays the center point of the circle\n\n    # Affectation des variables\n    if vueChoix==3:\n        # View of right ZY (Red)\n        z_point_1=ta[0]\n        x_point_1=ta[1]\n        y_point_1=ta[2]\n\n        z_point_2=ta[3]\n        x_point_2=ta[4]\n        y_point_2=ta[5]\n\n        z_point_3=ta[6]\n        x_point_3=ta[7]\n        y_point_3=ta[8]\n\n    elif vueChoix==2:\n        # Front view ZX (Green)\n        y_point_1=ta[0]\n        z_point_1=ta[1]\n        x_point_1=ta[2]\n\n        y_point_2=ta[3]\n        z_point_2=ta[4]\n        x_point_2=ta[5]\n\n        y_point_3=ta[6]\n        z_point_3=ta[7]\n        x_point_3=ta[8]\n\n    else:\n        # Top view XY (blue)\n        x_point_1=ta[0]\n        y_point_1=ta[1]\n        z_point_1=ta[2]\n\n        x_point_2=ta[3]\n        y_point_2=ta[4]\n        z_point_2=ta[5]\n\n        x_point_3=ta[6]\n        y_point_3=ta[7]\n        z_point_3=ta[8]\n\n    # Calculation of coordinates of the center of the circle\n    try:\n        centreX =((x_point_3**2-x_point_2**2+y_point_3**2-y_point_2**2)/(2*(y_point_3-y_point_2))-(x_point_2**2-x_point_1**2+y_point_2**2-y_point_1**2)/(2*(y_point_2-y_point_1)))/((x_point_3-x_point_2)/(y_point_3-y_point_2)-(x_point_2-x_point_1)/(y_point_2-y_point_1))\n        centreY =-(x_point_2-x_point_1)/(y_point_2-y_point_1)*centreX+(x_point_2**2-x_point_1**2+y_point_2**2-y_point_1**2)/(2*(y_point_2-y_point_1))\n        rayon =sqrt((x_point_1-centreX)**2+(y_point_1-centreY)**2)\n    except:\n        errorDialog(u\"Impossible calculation too aligned elements\")\n    else:\n       # Definition of the coordinate Z\n        centreZ=0\n        # Cr\u00e9ation du cercle\n        pl=app.Placement()\n        if vueChoix==1:    # Plan XY Dessus\n            pl.Rotation.Q=(0,0,0,1.0)\n            if alignerSur==1:\n                affiche(pl, centreX,centreY,z_point_1,rayon,0.0,0.0,1.0,afficherPoint)\n            elif alignerSur==2:\n                affiche(pl, centreX,centreY,z_point_2,rayon,0.0,0.0,1.0,afficherPoint)\n            elif alignerSur==3:\n                affiche(pl, centreX,centreY,z_point_3,rayon,0.0,0.0,1.0,afficherPoint)\n        elif vueChoix==2: # Plan XZ Face\n            pl.Rotation.Q=(1,0,0,1.0)\n            if alignerSur==1:\n                affiche(pl, centreY,z_point_1,centreX,rayon,0.0,1.0,0.0,afficherPoint)\n            elif alignerSur==2:\n                affiche(pl, centreY,z_point_2,centreX,rayon,0.0,1.0,0.0,afficherPoint)\n            elif alignerSur==3:\n                affiche(pl, centreY,z_point_3,centreX,rayon,0.0,1.0,0.0,afficherPoint)\n        elif vueChoix==3: # Plan YZ Droite\n            pl.Rotation.Q=(0,1,0,1.0)\n            if alignerSur==1:\n                affiche(pl, z_point_1,centreX,centreY,rayon,1.0,0.0,0.0,afficherPoint)\n            elif alignerSur==2:\n                affiche(pl, z_point_2,centreX,centreY,rayon,1.0,0.0,0.0,afficherPoint)\n            elif alignerSur==3:\n                affiche(pl, z_point_3,centreX,centreY,rayon,1.0,0.0,0.0,afficherPoint)\n        else:    # modifier pour avoir XYZ\n            # si les coordonn\u00e9es Z sont \u00e9gales alors le cercle s'aligne \u00e0 Z\n            if z_point_1==z_point_2 and z_point_2==z_point_3:\n                centreZ=z_point_1\n                affiche(pl, centreX,centreY,z_point_1,rayon,0.0,0.0,0.0,afficherPoint)\n            else:\n                # Si une coordonn\u00e9e est diff\u00e9rente alors Z=0\n                affiche(pl, centreX,centreY,0,rayon,0.0,0.0,0.0,afficherPoint)\n\nelse:\n    # We need three points in the selection.\n    errorDialog(u\"Select 3 points and repeat\")\n\n",
    "url": "https://www.freecadweb.org/wiki/Macro_Draft_Circle_3_Points",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_Draft_Circle_3_Points",
    "version": "1.0.1",
    "license": "",
    "date": "2019-02-01",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ObjectCreation\\Draft_Circle_3_Points.FCMacro",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "EllipseCenter2Points",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "",
    "code": "__Name__ = 'Ellipse Center + 2 Points'\n__Comment__ = ''\n__Author__ = 'Eriossoltero'\n__Version__ = ''\n__Date__ = ''\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'http://freecad-tutorial.blogspot.com/2011/12/engine-9-poly-v-belt.html'\n__Wiki__ = ''\n__Icon__ = ''\n__Help__ = ''\n__Status__ = ''\n__Requires__ = ''\n__Communication__ = ''\n__Files__ = ''\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nimport Part, PartGui\nfrom FreeCAD import Base\n\n# get the selected objects, with first selection for the trajectory and second for the section\n# Adapted from:\n# http://freecad-tutorial.blogspot.com/2011/12/engine-9-poly-v-belt.html\ns = gui.Selection.getSelection()\ntry:\n    sel1 = s[0].Shape\n    sel2 = s[1].Shape\n    sel3 = s[2].Shape\nexcept:\n    app.Console.PrintError('Wrong selection')\n\npt_center = sel1.Point\npt_radmay = sel2.Point\npt_radmen = sel3.Point\n\n# create Part object in the current document\nmyObject = app.ActiveDocument.addObject('Part::Feature', 'Ellipse')\n\n# create a shape and assign it to the current document\nellipse = Part.Ellipse(pt_radmay, pt_radmen, pt_center)\nmyObject.Shape = ellipse.toShape()\n",
    "url": "http://freecad-tutorial.blogspot.com/2011/12/engine-9-poly-v-belt.html",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ObjectCreation\\EllipseCenter2Points.FCMacro",
    "filename_from_url": "",
    "author": "Eriossoltero",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "G3d",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Create a solid with 2 or 3 sketches (views)",
    "code": "# -*- coding: utf-8 -*-\n# (c) 18Turbo, 2022\n\n__Name__ = 'Generador3D'\n__Comment__ = 'Create a solid with 2 or 3 sketches (views)'\n__Author__ = '18Turbo'\n__Version__ = '0.1.1'\n__Date__ = '2022-09-20'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'https://github.com/18turbo/Generador3DFreeCAD'\n__Wiki__ = 'https://github.com/18turbo/Generador3DFreeCAD/wiki'\n__Icon__ = 'G3d.svg'\n__Help__ = ''\n__Status__ = 'beta'\n__Requires__ = 'FreeCAD >= v0.20'\n__Contact__ = 'https://github.com/18turbo'\n__Communication__ = 'https://github.com/18turbo/Generador3DFreeCAD/issues'\n__Files__ = 'G3d.svg,g3d/ui/g3d15.ui'\n\n\n# (En espa\u00f1ol:)\n# Funcionalidad:    Genera una pieza 3D a partir de 2 o 3 sketch, cada uno en una vista distinta (planta, frontal o lateral)\n#\n# Descripci\u00f3n:      Una vez ejecutada la macro, habr\u00e1 que asociar cada sketch a cada vista, y pulsar el bot\u00f3n de OK.\n#\n#\n# Notas de versiones:\n# v.0.1.0:      Adaptaci\u00f3n del c\u00f3digo para varios idiomas\n#               Correcci\u00f3n de error en la deselecci\u00f3n de vistas\n#               Cambio de nombres de ficheros\n# v.0.0.16:     Corregido errores en la selecci\u00f3n de vistas\n#               Evita el error de introducir la longitud menor o igual al offset\n# v.0.0.15:     Cambiada la interfaz\n#               A\u00f1adido Offset y Longitud a cada vista\n# v.0.0.14:     Adaptaci\u00f3n al Addon Manager\n# v.0.0.13:     Depuraci\u00f3n de c\u00f3digo\n# v.0.0.12:     Depuraci\u00f3n de c\u00f3digo\n#               Posibilidad de crear una carpeta autom\u00e1ticamente donde meter las vistas y ocultarlas\n# v.0.0.11:     Incluida tolerancia 3D para evitar problemas en los l\u00edmites.\n# v.0.0.10:     Correcci\u00f3n de errores en sketch negativos\n# v.0.0.9:      Cambio de interfaz y correcci\u00f3n de errores. Beta funcional.\n# v.0.0.8:      Correcci\u00f3n de errores\n# v.0.0.7:      Correcci\u00f3n de errores\n# v.0.0.6:      Primera versi\u00f3n BETA\n# v.0.0.5 ALFA: Genera la pieza 3D con 3 vistas\n# v.0.0.4 ALFA: Arregla la selecci\u00f3n en las vistas en la pesta\u00f1a Task (Tarea)\n#\n#\n# BetaTester: Rafael Garc\u00eda Rodr\u00edguez\n# BetaTester: 18Turbo\n\n# Traducci\u00f3n ingl\u00e9s:    Rocco Vicedomini\n\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nimport Part\n\nfrom PySide import QtCore, QtGui\nfrom FreeCAD import Base\n\n\nstrLang = [\n    [ # Espa\u00f1ol\n        \"Generador 3D\",\n        \"Seleccione un sketch (boceto) en 2 o 3 vistas:\",\n        \"Frontal -Alzado- (Front/Rear):\",\n        \"Marque esta casilla si quiere activar la vista frontal y as\u00edgnele un sketch (boceto)\",\n        \"Lateral -Perfil- (Right/Left):\",\n        \"Marque esta casilla si quiere activar la vista lateral y as\u00edgnele un sketch (boceto)\",\n        \"Planta -Sup/Inf- (Top/Bott):\",\n        \"Marque esta casilla si quiere activar la vista en planta y as\u00edgnele un sketch (boceto)\",\n        \"Tol. 3D (mm.):\",\n        \"Es la distancia en mm. que extruir\u00e1 de m\u00e1s. No debe influir en el objeto final. Si no desea tolerancia, ponga este valor a 0\",\n        \"Crear un Grupo (Carpeta) para las vistas (sketches)\",\n        \"Ocultar las vistas al generar el s\u00f3lido\",\n        \"Fusi\u00f3n (interesecci\u00f3n)\",\n        \"Versi\u00f3n:\",\n        \"Informaci\u00f3n Breve de Uso:\",\n        \"Cree un boceto (sketch) para cada vista con la que desee generar un s\u00f3lido 3D. Necesitar\u00e1 al menos 2 bocetos.\",\n        \"Luego pinche en el icono del script y seleccione un boceto para cada vista.\",\n        \"Finalmente, pulse OK para generar el s\u00f3lido.\",\n        \"Documentaci\u00f3n:\",\n        \"Offset\",\n        \"Es la distancia desde la cual empezar\u00e1 la extrusi\u00f3n en el eje Y (desplazamiento en Y)\",\n        \"Longitud\",\n        \"Es la distancia total de extrusi\u00f3n frontal (en el eje Y), que siempre ser\u00e1 mayor que el Offset Frontal\",\n        \"Offset\",\n        \"Es la distancia desde la cual empezar\u00e1 la extrusi\u00f3n en el eje X (desplazamiento en X)\",\n        \"Longitud\",\n        \"Es la distancia total de extrusi\u00f3n lateral (en el eje X), que siempre ser\u00e1 mayor que el Offset Lateral\",\n        \"Offset\",\n        \"Es la distancia desde la cual empezar\u00e1 la extrusi\u00f3n en el eje Z (desplazamiento en Z)\",\n        \"Longitud\",\n        \"Es la distancia total de extrusi\u00f3n en planta (en el eje Z), que siempre ser\u00e1 mayor que el Offset en Planta\",\n        \"Pieza3D\",\n        \"VistasPieza3D\"\n    ],\n    [ # English\n        ## Strings for translation into any language (English Strings)\n\n        \"3D Generator\",\n        \"Select a sketch in 2 or 3 views:\",\n        \"Front view - (Front/Rear):\",\n        \"Check this box if you want to activate the front view and assign it a sketch\",\n        \"Side view - (Right/Left):\",\n        \"Check this box if you want to activate the side view and assign it a sketch\",\n        \"Plan view - (Top/Bott):\",\n        \"Check this box if you want to activate the plan view and assign it a sketch\",\n        \"Tol. 3D (mm):\",\n        \"Length in millimetres. This should not influence the final object. If you do not need this tolerance, set this value to 0\",\n        \"Make a new group (folder) with views (sketches)\",\n        \"Hide views when generating the solid\",\n        \"Fusion (intersection)\",\n        \"Version:\",\n        \"Brief guide to use the script:\",\n        \"Create a sketch for each view required to generate your 3D solid. At least two sketches will be required.\",\n        \"Then click on the script icon and select a sketch for each view.\",\n        \"Finally, press the OK button to generate the solid.\",\n        \"Documentation:\",\n        \"Offset\",\n        \"Offset from the sketch plane from which the extrusion along the Y axis will start\",\n        \"Length\",\n        \"Total length of the frontal extrusion along the Y axis (it must be always larger than the frontal offset)\",\n        \"Offset\",\n        \"Offset from the sketch plane from which the extrusion along the X axis will start\",\n        \"Length\",\n        \"Total length of the lateral extrusion along the X axis (it must be always larger than the lateral offset)\",\n        \"Offset\",\n        \"Offset from the sketch plane from which the extrusion along the Z axis will start\",\n        \"Length\",\n        \"Total length of the vertical extrusion along the Z axis (it must be always larger than the vertical offset)\",\n        \"3D-Part\",\n        \"3D-Part_Views\"\n    ],\n    [ ## Stringhe per la traduzione in qualsiasi lingua (stringhe in italiano)\n\n        \"Generatore 3D\",\n        \"Seleziona uno schizzo in 2 o 3 viste:\",\n        \"Vista frontale - (Fronte/Retro):\",\n        \"Spunta questa casella se desideri utilizzare la vista frontale ed assegnarle uno schizzo\",\n        \"Vista laterale - (Destra/Sinistra):\",\n        \"Spunta questa casella se desideri utilizzare la vista laterale ed assegnarle uno schizzo\",\n        \"Vista in pianta - (Alto/Basso):\",\n        \"Spunta questa casella se desideri utilizzare la vista in pianta ed assegnarle uno schizzo\",\n        \"Tol. 3D (mm):\",\n        \"Lunghezza in mm di sovraestrusione. Non dovrebbe influenzare l'oggetto finale. Se non si necessita questa tolleranza impostare il valore relativo a 0 mm\",\n        \"Crea un nuovo gruppo (cartella) con le viste (sketch)\",\n        \"Nasconde le viste quando viene generato il solido\",\n        \"Fusione (intersezione)\",\n        \"Versione:\",\n        \"Breve guida all'uso dello script:\",\n        \"Crea uno sketch per ogni vista necessaria a generare il solido. Sono necessari almeno due sketch.\",\n        \"Quindi clicca sull'icona dello script e seleziona uno schizzo per ciascuna vista necessaria.\",\n        \"Infine, premi il pulsante OK per generare il solido.\",\n        \"Documentazione:\",\n        \"Offset\",\n        \"Distanza rispetto al piano dello sketch frontale da cui inizier\u00e0 l'estrusione lungo l'asse Y (spostamento in Y)\",\n        \"Lunghezza\",\n        \"Lunghezza totale dell'estrusione frontale lungo l'asse Y (dovr\u00e0 essere sempre pi\u00f9 grande dell'offset frontale)\",\n        \"Offset\",\n        \"Distanza rispetto al piano dello sketch laterale da cui inizier\u00e0 l'estrusione lungo l'asse X (spostamento in X)\",\n        \"Lunghezza\",\n        \"Lunghezza totale dell'estrusione laterale lungo l'asse X (dovr\u00e0 essere sempre pi\u00f9 grande dell'offset laterale)\",\n        \"Offset\",\n        \"Distanza rispetto al piano dello sketch in pianta da cui inizier\u00e0 l'estrusione lungo l'asse Z (spostamento in Z)\",\n        \"Lunghezza\",\n        \"Lunghezza totale dell'estrusione verticale lungo l'asse Z (dovr\u00e0 essere sempre pi\u00f9 grande dell'offset in pianta)\",\n        \"Pezzo3D\",\n        \"Pezzo3D_Viste\"\n    ]\n        ]\n\n\nminimoExtrusion = app.Units.Quantity('0.01 mm')\n\n\nclass Generator3d:\n\n    def __init__(self):\n        self.doc = app.activeDocument()\n        if not self.doc:\n            app.Console.PrintWarning('No active document\\n')\n            return\n\n        ui_path = app.getUserMacroDir(True) + '/g3d/ui/g3d15.ui'\n        self.form = gui.PySideUic.loadUi(ui_path)\n\n        # Whether views are active.\n        self.frontal = False\n        self.lateral = False\n        self.planta = False\n\n        # Find all sketches and add to the widgets.\n        for candidate_sketch in app.activeDocument().Objects:\n            if candidate_sketch.TypeId == 'Sketcher::SketchObject':\n                self.form.listWidgetFrontal.addItem(candidate_sketch.Label)\n                self.form.listWidgetLateral.addItem(candidate_sketch.Label)\n                self.form.listWidgetPlanta.addItem(candidate_sketch.Label)\n\n        self.form.listWidgetFrontal.itemSelectionChanged.connect(self.changeSelectionFront)\n        self.form.listWidgetLateral.itemSelectionChanged.connect(self.changeSelectionLat)\n        self.form.listWidgetPlanta.itemSelectionChanged.connect(self.changeSelectionTop)\n\n        self.form.offsetF.valueChanged.connect(self.changeValueFront)\n        self.form.offsetL.valueChanged.connect(self.changeValueLat)\n        self.form.offsetP.valueChanged.connect(self.changeValueTop)\n\n        self.form.etFrontal.clicked.connect(self.changeCheckedFront)\n        self.form.etLateral.clicked.connect(self.changeCheckedLat)\n        self.form.etPlanta.clicked.connect(self.changeCheckedTop)\n\n        self.initStrings()\n\n    def initStrings(self):\n        tr = self.translate\n        if g_num_lang != 0:\n            title = \"(\" + strLang[g_num_lang][0] + \")\"\n        else:\n            title = \"\"\n        self.form.setWindowTitle(__Name__ + \" \" + title)\n        self.form.etInfo.setText(tr('Seleccione un sketch (boceto) en 2 o 3 vistas:'))\n        self.form.etFrontal.setTitle(tr('Frontal -Alzado- (Front/Rear):'))\n        self.form.etFrontal.setToolTip(tr('Marque esta casilla si quiere activar la vista frontal y as\u00edgnele un sketch (boceto)'))\n        self.form.etLateral.setTitle(tr('Lateral -Perfil- (Right/Left):'))\n        self.form.etLateral.setToolTip(tr('Marque esta casilla si quiere activar la vista lateral y as\u00edgnele un sketch (boceto)'))\n        self.form.etPlanta.setTitle(tr('Planta -Sup/Inf- (Top/Bott):'))\n        self.form.etPlanta.setToolTip(tr('Marque esta casilla si quiere activar la vista en planta y as\u00edgnele un sketch (boceto)'))\n        self.form.etTolerancia.setText(tr('Tol. 3D (mm.):'))\n        self.form.etTolerancia.setToolTip(tr('Es la distancia en mm. que extruir\u00e1 de m\u00e1s. No debe influir en el objeto final. Si no desea tolerancia, ponga este valor a 0'))\n        self.form.meterVistasCarpeta.setText(tr('Crear un Grupo (Carpeta) para las vistas (sketches)'))\n        self.form.ocultarVistas.setText(tr('Ocultar las vistas al generar el s\u00f3lido'))\n        self.form.radioInterseccion.setText(tr('Fusi\u00f3n (interesecci\u00f3n)'))\n        self.form.etVersion.setText(tr('Versi\u00f3n:'))\n        self.form.etNumVersion.setText(__Version__ + \" \" + __Status__)\n        self.form.etInfoUso.setText(tr('Informaci\u00f3n Breve de Uso:'))\n        descripcionInfoUso = (tr('Cree un boceto (sketch) para cada vista con la que desee generar un s\u00f3lido 3D. Necesitar\u00e1 al menos 2 bocetos.')\n                + \" \" + tr('Luego pinche en el icono del script y seleccione un boceto para cada vista.')\n                + \" \" + tr('Finalmente, pulse OK para generar el s\u00f3lido.'))\n        self.form.descInfoUso.setText(descripcionInfoUso)\n        self.form.etDoc.setText(tr('Documentaci\u00f3n:'))\n        self.form.etOffsetF.setText(tr('Offset'))\n        self.form.etOffsetF.setToolTip(tr('Es la distancia desde la cual empezar\u00e1 la extrusi\u00f3n en el eje Y (desplazamiento en Y)'))\n        self.form.offsetF.setToolTip(tr('Es la distancia desde la cual empezar\u00e1 la extrusi\u00f3n en el eje Y (desplazamiento en Y)'))\n        self.form.etOffsetL.setText(tr('Offset'))\n        self.form.etOffsetL.setToolTip(tr('Es la distancia desde la cual empezar\u00e1 la extrusi\u00f3n en el eje X (desplazamiento en X)'))\n        self.form.offsetL.setToolTip(tr('Es la distancia desde la cual empezar\u00e1 la extrusi\u00f3n en el eje X (desplazamiento en X)'))\n        self.form.etOffsetP.setText(tr('Offset'))\n        self.form.etOffsetP.setToolTip(tr('Es la distancia desde la cual empezar\u00e1 la extrusi\u00f3n en el eje Z (desplazamiento en Z)'))\n        self.form.offsetP.setToolTip(tr('Es la distancia desde la cual empezar\u00e1 la extrusi\u00f3n en el eje Z (desplazamiento en Z)'))\n        self.form.etLongitudF.setText(tr('Longitud'))\n        self.form.etLongitudF.setToolTip(tr('Es la distancia total de extrusi\u00f3n frontal (en el eje Y), que siempre ser\u00e1 mayor que el Offset Frontal'))\n        self.form.longF.setToolTip(tr('Es la distancia total de extrusi\u00f3n frontal (en el eje Y), que siempre ser\u00e1 mayor que el Offset Frontal'))\n        self.form.etLongitudL.setText(tr('Longitud'))\n        self.form.etLongitudL.setToolTip(tr('Es la distancia total de extrusi\u00f3n lateral (en el eje X), que siempre ser\u00e1 mayor que el Offset Lateral'))\n        self.form.longL.setToolTip(tr('Es la distancia total de extrusi\u00f3n lateral (en el eje X), que siempre ser\u00e1 mayor que el Offset Lateral'))\n        self.form.etLongitudP.setText(tr('Longitud'))\n        self.form.etLongitudP.setToolTip(tr('Es la distancia total de extrusi\u00f3n en planta (en el eje Z), que siempre ser\u00e1 mayor que el Offset en Planta'))\n        self.form.longP.setToolTip(tr('Es la distancia total de extrusi\u00f3n en planta (en el eje Z), que siempre ser\u00e1 mayor que el Offset en Planta'))\n\n    def translate(self, text):\n        if (text not in strLang[0]) or (g_num_lang < 0) or (g_num_lang >= len(strLang)):\n            return text\n        primerIdioma = strLang[0]\n        indice = primerIdioma.index(text)\n        if (indice == -1) or (indice >= len(strLang[g_num_lang])):\n            return text\n        return strLang[g_num_lang][indice]\n\n    def changeValueFront(self):\n        self.form.longF.setMinimum(self.form.offsetF.value() + minimoExtrusion)\n\n    def changeValueLat(self):\n        self.form.longL.setMinimum(self.form.offsetL.value() + minimoExtrusion)\n\n    def changeValueTop(self):\n        self.form.longP.setMinimum(self.form.offsetP.value() + minimoExtrusion)\n\n    def changeCheckedFront(self):\n        if not self.form.etFrontal.isChecked():\n            self.frontal = False\n        else:\n            self.frontal = True\n\n    def changeCheckedLat(self):\n        if not self.form.etLateral.isChecked():\n            self.lateral = False\n        else:\n            self.lateral = True\n\n    def changeCheckedTop(self):\n        if not self.form.etPlanta.isChecked():\n            self.planta = False\n        else:\n            self.planta = True\n\n    def changeSelectionFront(self):\n        label = str(self.form.listWidgetFrontal.selectedItems()[0].text())\n        self.front_sketch = self.doc.getObjectsByLabel(label)[0]\n\n    def changeSelectionLat(self):\n        label = str(self.form.listWidgetLateral.selectedItems()[0].text())\n        self.lat_sketch = self.doc.getObjectsByLabel(label)[0]\n\n    def changeSelectionTop(self):\n        label = str(self.form.listWidgetPlanta.selectedItems()[0].text())\n        self.top_sketch = self.doc.getObjectsByLabel(label)[0]\n\n    def active_view_count(self):\n        return sum([\n            self.form.etFrontal.isChecked(),\n            self.form.etLateral.isChecked(),\n            self.form.etPlanta.isChecked()])\n\n    def extrusion(self, nombreExtrusion, nombreEnVista, vista):\n        doc = app.activeDocument()\n        doc.addObject('Part::Extrusion', nombreExtrusion)\n        f = doc.getObject(nombreExtrusion)\n        objf = doc.getObjectsByLabel(nombreEnVista)\n        f.Base = doc.getObject(objf[0].Name)\n        f.DirMode = \"Custom\"\n        if vista == \"planta\":\n            offset = self.form.offsetP.value()\n            longitud = self.form.longP.value()\n            f.Dir = app.Vector(0.0, 0.0, 1.0)\n            if self.lateral:\n                maximoLZ = self.lat_sketch.Shape.BoundBox.ZMax\n                minimoLZ = self.lat_sketch.Shape.BoundBox.ZMin\n                if abs(maximoLZ) > abs(minimoLZ):\n                    f.LengthFwd = (abs(maximoLZ) + self.form.tolerancia.value()) * 2\n                else:\n                    f.LengthFwd = (abs(minimoLZ) + self.form.tolerancia.value()) * 2\n            else:\n                maximoFZ = self.front_sketch.Shape.BoundBox.ZMax\n                minimoFZ = self.front_sketch.Shape.BoundBox.ZMin\n                if abs(maximoFZ) > abs(minimoFZ):\n                    f.LengthFwd = (abs(maximoFZ) + self.form.tolerancia.value()) * 2\n                else:\n                    f.LengthFwd = (abs(minimoFZ) + self.form.tolerancia.value()) * 2\n\n        elif vista == \"frontal\":\n            offset = self.form.offsetF.value()\n            longitud = self.form.longF.value()\n            f.Dir = app.Vector(0.0, 1.0, 0.0)\n            if self.lateral:\n                maximoLY = self.lat_sketch.Shape.BoundBox.YMax\n                minimoLY = self.lat_sketch.Shape.BoundBox.YMin\n                if abs(maximoLY) > abs(minimoLY):\n                    f.LengthFwd = (abs(maximoLY) + self.form.tolerancia.value()) *2\n                else:\n                    f.LengthFwd = (abs(minimoLY) + self.form.tolerancia.value()) *2\n            else:\n                maximoPY = self.top_sketch.Shape.BoundBox.YMax\n                minimoPY = self.top_sketch.Shape.BoundBox.YMin\n                if abs(maximoPY) > abs(minimoPY):\n                    f.LengthFwd = (abs(maximoPY) + self.form.tolerancia.value()) *2\n                else:\n                    f.LengthFwd = (abs(minimoPY) + self.form.tolerancia.value()) *2\n\n        elif vista == \"lateral\":\n            offset = self.form.offsetL.value()\n            longitud = self.form.longL.value()\n            f.Dir = app.Vector(1.0, 0.0, 0.0)\n            if self.planta:\n                maximoPX = self.top_sketch.Shape.BoundBox.XMax\n                minimoPX = self.top_sketch.Shape.BoundBox.XMin\n                if abs(maximoPX) > abs(minimoPX):\n                    f.LengthFwd = (abs(maximoPX) + self.form.tolerancia.value()) *2\n                else:\n                    f.LengthFwd = (abs(minimoPX) + self.form.tolerancia.value()) *2\n            else:\n                maximoFX = self.front_sketch.Shape.BoundBox.XMax\n                minimoFX = self.front_sketch.Shape.BoundBox.XMin\n                if abs(maximoFX) > abs(minimoFX):\n                    f.LengthFwd = (abs(maximoFX) + self.form.tolerancia.value()) *2\n                else:\n                    f.LengthFwd = (abs(minimoFX) + self.form.tolerancia.value()) *2\n\n        f.DirLink = None\n        f.Solid = True\n        f.Reversed = False\n        if (offset > 0) or (longitud > 0):\n            f.Symmetric = False\n            f.LengthRev = offset * (-1)\n            if (longitud > 0):\n                f.LengthFwd = longitud\n        else:\n            f.LengthRev = 0.0\n            f.Symmetric = True\n        f.TaperAngle = 0.0\n        f.TaperAngleRev = 0.0\n        doc.recompute()\n        return f\n\n    def accept(self):\n        #Comprobar que no existe ya una extrusi\u00f3n con este nombre\n        numeroCoincidencias = 0\n        encontradoCoincidencia = False\n        cadenaAdicional = \"\"\n        doc = app.activeDocument()\n        for obj in doc.Objects:\n            if (('ExtrPlanta18Turbo' in obj.Name) or\n                    ('ExtrFrontal18Turbo' in obj.Name) or\n                    ('ExtrLateral18Turbo' in obj.Name)):\n                numeroCoincidencias = numeroCoincidencias + 1\n                encontradoCoincidencia = True\n        if encontradoCoincidencia:\n            cadenaAdicional = cadenaAdicional + str(numeroCoincidencias)\n\n        if self.active_view_count() >= 2:\n            if self.planta:\n                # Sketch en Z (Planta XY)\n                planta = self.extrusion(\"ExtrPlanta18Turbo\" + cadenaAdicional,\n                                        self.top_sketch.Label, \"planta\")\n            if self.frontal:\n                # Sketch en Y (Frontal XZ)\n                frontal = self.extrusion(\"ExtrFrontal18Turbo\" + cadenaAdicional,\n                                         self.front_sketch.Label, \"frontal\")\n            if self.lateral:\n                # Sketch en X (Lateral YZ)\n                lateral = self.extrusion(\"ExtrLateral18Turbo\" + cadenaAdicional,\n                                         self.lat_sketch.Label, \"lateral\")\n\n            # Intersecci\u00f3n\n            nombreInterseccion = self.translate('Pieza3D') + cadenaAdicional\n            if self.active_view_count() == 3:\n                common = doc.addObject(\"Part::MultiCommon\", nombreInterseccion)\n                common.Shapes = [planta, frontal, lateral]\n            else:\n                common = doc.addObject(\"Part::MultiCommon\", nombreInterseccion)\n                if (self.planta) and (self.frontal):\n                    common.Shapes = [planta, frontal]\n                if (self.planta) and (self.lateral):\n                    common.Shapes = [planta, lateral]\n                if (self.frontal) and (self.lateral):\n                    common.Shapes = [frontal, lateral]\n            doc.recompute()\n\n            # Meter vistas en Grupo (Carpeta)\n            if self.form.meterVistasCarpeta.checkState():\n                nombreGrupoVistas = self.translate('VistasPieza3D') + cadenaAdicional\n                group = doc.addObject('App::DocumentObjectGroup', nombreGrupoVistas)\n                if self.planta:\n                    group.addObject(self.top_sketch)\n                if self.frontal:\n                    group.addObject(self.front_sketch)\n                if self.lateral:\n                    group.addObject(self.lat_sketch)\n            # Ocultar Vistas\n            if self.form.ocultarVistas.isChecked():\n                if self.planta:\n                    self.top_sketch.Visibility = False\n                if self.frontal:\n                    self.front_sketch.Visibility = False\n                if self.lateral:\n                    self.lat_sketch.Visibility = False\n\n        gui.Control.closeDialog()\n\n\n# Se define el g_num_lang con variable global\nlang = gui.getLocale()\n# Default to English.\ng_num_lang = 1\nif 'Spanish' in lang:\n    g_num_lang = 0\nelif 'Italian' in lang:\n    g_num_lang = 2\n\npanel = Generator3d()\ngui.Control.showDialog(panel)\n",
    "url": "https://github.com/18turbo/Generador3DFreeCAD",
    "raw_code_url": "",
    "wiki": "https://github.com/18turbo/Generador3DFreeCAD/wiki",
    "version": "0.1.1",
    "license": "",
    "date": "2022-09-20",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ObjectCreation\\G3d.FCMacro",
    "filename_from_url": "",
    "author": "18Turbo",
    "icon": "G3d.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "G3d.svg",
      "g3d/ui/g3d15.ui"
    ],
    "parsed": true
  },
  {
    "name": "HalfHull",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "",
    "code": "#\n#\n#\t\t\tHalf Hull\n# (c) piffpoof 2015\n#\n################################\n\nimport FreeCAD\nfrom FreeCAD import Base, Draft\nimport Part, PartGui, sys, math, collections\nfrom collections import OrderedDict\nfrom os.path import expanduser\t\t# default input directory\nfrom PySide import QtGui, QtCore\n\n# UI Class definitions\nglobal ConfigParams\nglobal GetConfigParams\nglobal OrderedDict\n\nclass ConfigParams:\n\t\"\"\"carrier for the user selection parameters\"\"\"\n\tdef __init__(self):\n\t\tself.result\t\t\t\t= None\n\t\tself.cb1a\t\t\t\t= None\n\t\tself.cb1b\t\t\t\t= None\n\t\tself.cb1c\t\t\t\t= None\n\t\tself.cb2a\t\t\t\t= None\n\t\tself.cb2b\t\t\t\t= None\n\t\tself.cb2c\t\t\t\t= None\n\t\tself.cb3a\t\t\t\t= None\n\t\tself.cb3b\t\t\t\t= None\n\t\tself.cb3c\t\t\t\t= None\n\t\tself.cb4a\t\t\t\t= None\n\t\tself.rb4b\t\t\t\t= None\n\t\tself.rb5b\t\t\t\t= None\n\t\tself.skipAtBow\t\t\t= None\n\t\tself.skipAtStern\t\t= None\n\t\tself.deckWidth\t\t\t= None\n\t\tself.deckThrow\t\t\t= None\n\t\tself.coachhouseRise\t\t= None\n\t\tself.coachhouseIncline\t= None\n\t\tself.documentFileName\t= None\n\nclass GetConfigParams(QtGui.QDialog):\n\t\"\"\"\"\"\"\n\tdef __init__(self):\n\t\tsuper(GetConfigParams, self).__init__()\n\t\tself.initUI()\n\tdef initUI(self):\n\t\tself.configParams\t\t\t= ConfigParams()\n\t\t# set default return value\n\t\tself.configParams.result \t= userCancelled\n\t\t# set default values\n\t\tskipAtBowDefault\t\t\t= str(2)\n\t\tskipAtSternDefault\t\t\t= str(2)\n\t\tdeckWidthDefault\t\t\t= str(50)\n\t\tdeckThrowDefault\t\t\t= str(2)\n\t\tcoachhouseRiseDefault\t\t= str(50)\n\t\tcoachhouseInclineDefault\t= str(8)\n\t\t# field descriptors\n\t\tself.promptLbl = QtGui.QLabel(\"Please Choose Options:\", self)\n\t\tself.promptLbl.move(20, 20)\n\t\t# checkboxes - define first so  signals can be set up\n\t\tself.cb1a = QtGui.QCheckBox(\"Starboard half-hull\", self)\n\t\tself.cb1b = QtGui.QCheckBox(\"Mounting plaque\", self)\n\t\tself.cb1c = QtGui.QCheckBox(\"Allow space for keel\", self)\n\t\tself.cb2a = QtGui.QCheckBox(\"Port half-hull\", self)\n\t\tself.cb2b = QtGui.QCheckBox(\"Mounting plaque\", self)\n\t\tself.cb2c = QtGui.QCheckBox(\"Allow space for keel\", self)\n\t\tself.cb3a = QtGui.QCheckBox(\"Complete hull\", self)\n\t\tself.cb3b = QtGui.QCheckBox(\"Bottle for complete hull\", self)\n\t\tself.cb3c = QtGui.QCheckBox(\"Allow space for keel\", self)\n\t\tself.rb4b = QtGui.QRadioButton(\"Bulkheads for flush deck\",self)\n\t\tself.rb5b = QtGui.QRadioButton(\"Bulkheads for coachhouse\",self)\n\t\t#\n\t\tself.cb1a.clicked.connect(self.onCb1a)\n\t\tself.cb1a.toggle() # set default value\n\t\tself.cb1c.setEnabled(False)\n\t\t#self.cb1a.stateChanged.connect(self.onCb1a)\n\t\tself.cb1a.move(20,50)\n\t\t#\n\t\tself.cb1b.clicked.connect(self.onCb1b)\n\t\tself.cb1b.move(250,50)\n\t\t#\n\t\tself.cb1c.clicked.connect(self.onCb1c)\n\t\tself.cb1c.move(450,50)\n\t\t#\n\t\tself.cb2a.clicked.connect(self.onCb2a)\n\t\tself.cb2b.setEnabled(False)\n\t\tself.cb2c.setEnabled(False)\n\t\tself.cb2a.move(20,80)\n\t\t#\n\t\tself.cb2b.clicked.connect(self.onCb2b)\n\t\tself.cb2b.move(250,80)\n\t\t#\n\t\tself.cb2c.clicked.connect(self.onCb2c)\n\t\tself.cb2c.move(450,80)\n\t\t#\n\t\tself.cb3a.clicked.connect(self.onCb3a)\n\t\tself.cb3b.setEnabled(False)\n\t\tself.cb3c.setEnabled(False)\n\t\tself.cb3a.move(20,110)\n\t\t#\n\t\tself.cb3b.clicked.connect(self.onCb3b)\n\t\tself.cb3b.move(250,110)\n\t\t#\n\t\tself.cb3c.clicked.connect(self.onCb3c)\n\t\tself.cb3c.move(450,110)\n\t\t#\n\t\tself.cb4a = QtGui.QCheckBox(\"Bulkheads for complete hull\", self)\n\t\tself.cb4a.clicked.connect(self.onCb4a)\n\t\tself.rb4b.setEnabled(False)\n\t\tself.rb5b.setEnabled(False)\n\t\t#self.hideCoachhouseFields(True) # grey out coachhouse fields\n\t\tself.cb4a.move(20,140)\n\t\t# radio buttons\n\t\tself.rb4b.move(250,140)\n\t\tself.rb4b.clicked.connect(self.onRb4b)\n\t\t#\n\t\tself.rb5b.move(250,170)\n\t\tself.rb5b.clicked.connect(self.onRb5b)\n\t\t#\n\t\tself.skipAtBowLabel = QtGui.QLabel(\"Cross-sections to skip at bow:\", self)\n\t\tself.skipAtBowLabel.move(270, 200)\n\t\tself.skipAtBow = 0\n\t\t#\n\t\tself.skipAtSternLabel = QtGui.QLabel(\"Cross-sections to skip at stern:\", self)\n\t\tself.skipAtSternLabel.move(270, 230)\n\t\tself.skipAtStern = 0\n\t\t#\n\t\tself.deckWidthLabel = QtGui.QLabel(\"Deck Width:\", self)\n\t\tself.deckWidthLabel.move(270, 260)\n\t\tself.deckWidth = QtGui.QLineEdit(self)\n\t\tself.deckWidth.setInputMask(\"999\")\n\t\tself.deckWidth.setText(deckWidthDefault)\n\t\tself.deckWidth.setFixedWidth(35)\n\t\tself.deckWidth.move(493, 260)\n\t\t#\n\t\tself.deckThrowLabel = QtGui.QLabel(\"Deck throw:\", self)\n\t\tself.deckThrowLabel.move(270, 290)\n\t\tself.deckThrow = QtGui.QLineEdit(self)\n\t\tself.deckThrow.setInputMask(\"999\")\n\t\tself.deckThrow.setText(deckThrowDefault)\n\t\tself.deckThrow.setFixedWidth(35)\n\t\tself.deckThrow.move(493, 290)\n\t\t#\n\t\tself.coachhouseRiseLabel = QtGui.QLabel(\"Coachhouse Rise:\", self)\n\t\tself.coachhouseRiseLabel.move(270, 320)\n\t\tself.coachhouseRise = QtGui.QLineEdit(self)\n\t\tself.coachhouseRise.setInputMask(\"999\")\n\t\tself.coachhouseRise.setText(coachhouseRiseDefault)\n\t\tself.coachhouseRise.setFixedWidth(35)\n\t\tself.coachhouseRise.move(493, 320)\n\t\t#\n\t\tself.coachhouseInclineLabel = QtGui.QLabel(\"Coachhouse Incline:\", self)\n\t\tself.coachhouseInclineLabel.move(270, 350)\n\t\tself.coachhouseIncline = QtGui.QLineEdit(self)\n\t\tself.coachhouseIncline.setInputMask(\"999\")\n\t\tself.coachhouseIncline.setText(coachhouseInclineDefault)\n\t\tself.coachhouseIncline.setFixedWidth(35)\n\t\tself.coachhouseIncline.move(493, 350)\n\t\t# set up lists for pop-ups\n\t\tself.popupItemsB = OrderedDict([(\"2\",\"\"),(\"3\",\"\"),(\"4\",\"\"),(\"5\",\"\"),(\"6\",\"\"),(\"7\",\"\"),(\"8\",\"\"),(\"9\",\"\"),(\"10\",\"\")])\n\t\tself.popupItemsS = OrderedDict([(\"1\",\"\"),(\"2\",\"\"),(\"3\",\"\"),(\"4\",\"\"),(\"5\",\"\"),(\"6\",\"\"),(\"7\",\"\"),(\"8\",\"\"),(\"9\",\"\"),(\"10\",\"\")])\n\t\t# set up pop-up menu of bulkheads to skip bulkheads at bow\n\t\tself.skipAtBowPop = QtGui.QComboBox(self)\n\t\tself.skipAtBowPop.addItems(self.popupItemsB.keys())\n\t\tself.skipAtBowPop.setCurrentIndex(self.popupItemsB.keys().index(skipAtBowDefault))\n\t\tself.skipAtBow = skipAtBowDefault\n\t\tself.skipAtBowPop.move(490, 200)\n\t\tself.skipAtBowPop.activated[str].connect(self.onSkipBowActivated)\n\t\t# set up pop-up menu of bulkheads to skip bulkheads at stern\n\t\tself.skipAtSternPop = QtGui.QComboBox(self)\n\t\tself.skipAtSternPop.addItems(self.popupItemsS.keys())\n\t\tself.skipAtSternPop.setCurrentIndex(self.popupItemsS.keys().index(skipAtSternDefault))\n\t\tself.skipAtStern = skipAtSternDefault\n\t\tself.skipAtSternPop.move(490, 230)\n\t\tself.skipAtSternPop.activated[str].connect(self.onSkipSternActivated)\n\t\t# cancel button\n\t\tcancelButton = QtGui.QPushButton('Cancel', self)\n\t\tcancelButton.clicked.connect(self.onCancel)\n\t\tcancelButton.move(260, 390)\n\t\t# last used button\n\t\tlastFileButton = QtGui.QPushButton('Re-use last file', self)\n\t\tlastFileButton.clicked.connect(self.onLastFile)\n\t\tlastFileButton.move(345, 390)\n\t\t# OK button\n\t\tsfButton = QtGui.QPushButton('Select File', self)\n\t\tsfButton.clicked.connect(self.onSf)\n\t\tsfButton.move(480, 390)\n\t\t# define window\t\txLoc,yLoc,xDim,yDim\n\t\tself.setGeometry(\t250, 250, 630, 445)\n\t\tself.setWindowTitle(\"Macro Configuration\")\n\t\tself.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)\n\t\tself.disableCoachhouseFields(True) # grey out coachhouse fields\n\t\tself.show()\n\t\t#\n\tdef onCb1a(self):\n\t\tif self.cb1a.isChecked():\n\t\t\tself.cb1b.setEnabled(True)\n\t\telse:\n\t\t\tself.cb1b.setEnabled(False)\n\t\t\tself.cb1b.setChecked(False)\n\t\t\tself.cb1c.setEnabled(False)\n\t\t\tself.cb1c.setChecked(False)\n\tdef onCb1b(self):\n\t\tif self.cb1b.isChecked():\n\t\t\tself.cb1c.setEnabled(True)\n\t\telse:\n\t\t\tself.cb1c.setEnabled(False)\n\t\t\tself.cb1c.setChecked(False)\n\tdef onCb1c(self):\n\t\tpass\n\tdef onCb2a(self):\n\t\tif self.cb2a.isChecked():\n\t\t\tself.cb2b.setEnabled(True)\n\t\telse:\n\t\t\tself.cb2b.setEnabled(False)\n\t\t\tself.cb2b.setChecked(False)\n\t\t\tself.cb2c.setEnabled(False)\n\t\t\tself.cb2c.setChecked(False)\n\tdef onCb2b(self):\n\t\tif self.cb2b.isChecked():\n\t\t\tself.cb2c.setEnabled(True)\n\t\telse:\n\t\t\tself.cb2c.setEnabled(False)\n\t\t\tself.cb2c.setChecked(False)\n\tdef onCb2c(self):\n\t\tpass\n\tdef onCb3a(self):\n\t\tif self.cb3a.isChecked():\n\t\t\tself.cb3b.setEnabled(True)\n\t\telse:\n\t\t\tself.cb3b.setEnabled(False)\n\t\t\tself.cb3b.setChecked(False)\n\t\t\tself.cb3c.setEnabled(False)\n\t\t\tself.cb3c.setChecked(False)\n\tdef onCb3b(self):\n\t\tif self.cb3b.isChecked():\n\t\t\tself.cb3c.setEnabled(True)\n\t\telse:\n\t\t\tself.cb3c.setEnabled(False)\n\t\t\tself.cb3c.setChecked(False)\n\tdef onCb3c(self):\n\t\tpass\n\tdef onCb4a(self):\n\t\tif self.cb4a.isChecked():\n\t\t\tself.rb4b.setEnabled(True)\n\t\t\tself.rb4b.setChecked(True)\n\t\t\tself.rb5b.setEnabled(True)\n\t\t\tself.rb5b.setChecked(False)\n\t\telse:\n\t\t\tself.rb4b.setChecked(False)\n\t\t\tself.rb4b.setEnabled(False)\n\t\t\tself.rb5b.setChecked(False)\n\t\t\tself.rb5b.setEnabled(False)\n\t\t\tself.disableCoachhouseFields(True)\n\tdef onRb4b(self):\n\t\tif self.rb4b.isChecked():\n\t\t\tself.disableCoachhouseFields(True)\n\t\telse:\n\t\t\tself.disableCoachhouseFields(False)\n\tdef onRb5b(self):\n\t\tif self.rb5b.isChecked():\n\t\t\tself.disableCoachhouseFields(False)\n\t\telse:\n\t\t\tself.disableCoachhouseFields(True)\n\tdef onSkipBowActivated(self, text):\n\t\tself.skipAtBow = text\n\tdef onSkipSternActivated(self, text):\n\t\tself.skipAtStern = text\n\tdef disableCoachhouseFields(self, aFlag):\n\t\t# enable or disable coachhouse parameter fields\n\t\tif aFlag:\n\t\t\tself.skipAtBowLabel.setEnabled(False)\n\t\t\tself.skipAtBowPop.setEnabled(False)\n\t\t\tself.skipAtSternLabel.setEnabled(False)\n\t\t\tself.skipAtSternPop.setEnabled(False)\n\t\t\tself.deckWidthLabel.setEnabled(False)\n\t\t\tself.deckWidth.setEnabled(False)\n\t\t\tself.deckThrowLabel.setEnabled(False)\n\t\t\tself.deckThrow.setEnabled(False)\n\t\t\tself.coachhouseRiseLabel.setEnabled(False)\n\t\t\tself.coachhouseRise.setEnabled(False)\n\t\t\tself.coachhouseInclineLabel.setEnabled(False)\n\t\t\tself.coachhouseIncline.setEnabled(False)\n\t\telse:\n\t\t\tself.skipAtBowLabel.setEnabled(True)\n\t\t\tself.skipAtBowPop.setEnabled(True)\n\t\t\tself.skipAtSternLabel.setEnabled(True)\n\t\t\tself.skipAtSternPop.setEnabled(True)\n\t\t\tself.deckWidthLabel.setEnabled(True)\n\t\t\tself.deckWidth.setEnabled(True)\n\t\t\tself.deckThrowLabel.setEnabled(True)\n\t\t\tself.deckThrow.setEnabled(True)\n\t\t\tself.coachhouseRiseLabel.setEnabled(True)\n\t\t\tself.coachhouseRise.setEnabled(True)\n\t\t\tself.coachhouseInclineLabel.setEnabled(True)\n\t\t\tself.coachhouseIncline.setEnabled(True)\n\tdef onCancel(self):\n\t\tself.configParams.result\t\t\t= userCancelled\n\t\tself.close()\n\tdef transferConfigParams(self):\n\t\tself.configParams.cb1a\t\t\t\t= self.cb1a.isChecked()\n\t\tself.configParams.cb1b\t\t\t\t= self.cb1b.isChecked()\n\t\tself.configParams.cb1c\t\t\t\t= self.cb1c.isChecked()\n\t\tself.configParams.cb2a\t\t\t\t= self.cb2a.isChecked()\n\t\tself.configParams.cb2b\t\t\t\t= self.cb2b.isChecked()\n\t\tself.configParams.cb2c\t\t\t\t= self.cb2c.isChecked()\n\t\tself.configParams.cb3a\t\t\t\t= self.cb3a.isChecked()\n\t\tself.configParams.cb3b\t\t\t\t= self.cb3b.isChecked()\n\t\tself.configParams.cb3c\t\t\t\t= self.cb3c.isChecked()\n\t\tself.configParams.cb4a\t\t\t\t= self.cb4a.isChecked()\n\t\tself.configParams.rb5b\t\t\t\t= self.rb5b.isChecked()\n\t\tself.configParams.skipAtBow\t\t\t= self.skipAtBow\n\t\tself.configParams.skipAtStern\t\t= self.skipAtStern\n\t\tself.configParams.deckWidth\t\t\t= self.deckWidth\n\t\tself.configParams.deckThrow\t\t\t= self.deckThrow\n\t\tself.configParams.coachhouseRise\t= self.coachhouseRise\n\t\tself.configParams.coachhouseIncline\t= self.coachhouseIncline\n\tdef onLastFile(self):\n\t\tself.configParams.result\t\t\t= userLastFile\n\t\tself.transferConfigParams()\n\t\tself.close()\n\tdef onSf(self):\n\t\tself.configParams.result\t\t\t= userOK\n\t\tself.transferConfigParams()\n\t\tself.close()\n\n# Class definitions\n\nclass HullCrossSection:\n\t\"Holder of information pertaining to a cross section profile\"\n\t#persistentInstance = \"\"\n\t#import copy\n\tdef __init__(self,aSketch):\n\t\tself.sketch =\t\taSketch\n\t\tself.geometryCount = aSketch.GeometryCount\n\t\tself.geometryS =\tNone # geometry for starboard side\n\t\tself.geometryP =\tNone # geometry for port side\n\t\tself.geometryC =\tNone # geometry for complete hull (i.e. both halves as one)\n\t\tself.label =\t\taSketch.Label\n\t\t# next 2 lines due to mysterious label morphing routine of FreeCAD\n\t\tself.altLabel =\t\tself.label.replace(\" \", \"_\")\n\t\tself.altLabel =\t\tself.altLabel.replace(\"-\", \"_\")\n\t\t#\n\t\tself.xPos =\t\t\t0.0 # normalise sketch to axis\n\t\tself.yPos =\t\t\taSketch.Placement.Base.y\n\t\tself.zPos =\t\t\taSketch.Placement.Base.z\n\t\tself.xMin =\t\t\tinfinity # will hold min X value in Sketch\n\t\tself.yMin =\t\t\tinfinity # will hold min Y value in Sketch\n\t\tself.xMax =\t\t\tinfinityNegative # will hold max X value in Sketch\n\t\tself.yMax =\t\t\tinfinityNegative # will hold max Y value in Sketch\n\t\tself.endPoint =\t\tNone # will be the 'top' point on the polyline\n\t\tself.key =\t\t\tint(self.yPos)\n\t\tself.rotation =\t\taSketch.Placement.Rotation\n\t\tself.rotAngle =\t\taSketch.Placement.Rotation.Angle\n\t\tself.rotAxis =\t\taSketch.Placement.Rotation.Axis\n\t\tself.rotQ =\t\t\taSketch.Placement.Rotation.Q\n\t\t# following 4 statements seem necessary to pass the Rotation quad-value\n\t\tself.rotQ1 =\t\taSketch.Placement.Rotation.Q[0]\n\t\tself.rotQ2 =\t\taSketch.Placement.Rotation.Q[1]\n\t\tself.rotQ3 =\t\taSketch.Placement.Rotation.Q[2]\n\t\tself.rotQ4 =\t\taSketch.Placement.Rotation.Q[3]\n\t\t# set flags for either stemline or transom or suspected transom cross-section\n\t\tif eqRotation(self.rotation,yzPlane):\n\t\t\t# if we have the stemline then wait to give it the foremost placement\n\t\t\tFreeCAD.Console.PrintMessage(\"Stemline identified '\" + self.label + \"'\\n\")\n\t\t\tself.stemlineFlag = True\n\t\telse:\n\t\t\tself.stemlineFlag = False\n\t\tif eqRotation(self.rotation,xyPlane):\n\t\t\t# if we have the transom then wait to give it the aftmost placement\n\t\t\tFreeCAD.Console.PrintMessage(\"Transom identified '\" + self.label + \"'\\n\")\n\t\t\tself.transomFlag = True\n\t\telse:\n\t\t\tself.transomFlag = False\n\t\tif eqRotation(self.rotation,xzPlane):\n\t\t\t# the most numerous sketches will be the cross-sections, so don't flag it\n\t\t\tself.possibleTransomCS = False\n\t\telse:\n\t\t\t# it's not lying in any of the 3 planes so it's either an error\n\t\t\t# or it could be an inclined cross-section for the transom\n\t\t\t# (although there should only be one or none of these)\n\t\t\t# flag it as such and sort it out later once all the other\n\t\t\t# cross-sections are placed\n\t\t\tif not (self.stemlineFlag or self.transomFlag):\n\t\t\t\tFreeCAD.Console.PrintMessage(\"Possible Transom cross-section identified '\" + self.label + \"'\\n\")\n\t\t\t\tself.possibleTransomCS = True\n\t\tself.defineGeometries() # make S & P & C geometries from the geometry of the supplied Sketch\n\n\tdef defineGeometries(self):\n\t\t# the supplied geometry is for the starboard side and is part of the user supplied Sketch\n\t\t# - make a direct copy for the starboard half-hull\n\t\t# - negate the X coordinates for the Port side\n\t\t# - append a negated reversed copy to each starboard piece for the complete hull\n\t\tself.geometryS =\tlist()\n\t\tself.geometryP =\tlist()\n\t\tself.geometryC =\tlist()\n\t\t#grab the endPoint which will be used for covering the half-hull model\n\t\tepX = max(self.sketch.Geometry[-1].StartPoint.x, self.sketch.Geometry[-1].EndPoint.x)\n\t\tepY = self.yPos\n\t\tepZ = max(self.sketch.Geometry[-1].StartPoint.y, self.sketch.Geometry[-1].EndPoint.y)\n\t\tself.endPoint = Base.Vector(epX,epY,epZ)\n\t\t# first pass through segment of sketch is to determine the min and max X & Y values\n\t\tfor seg in self.sketch.Geometry:\n\t\t\t# determine the minimum X & Y values\n\t\t\tself.xMin = min(self.xMin, seg.StartPoint.x, seg.EndPoint.x)\n\t\t\tself.yMin = min(self.yMin, seg.StartPoint.y, seg.EndPoint.y)\n\t\t\tself.xMax = max(self.xMax, seg.StartPoint.x, seg.EndPoint.x)\n\t\t\tself.yMax = max(self.yMax, seg.StartPoint.y, seg.EndPoint.y)\n\t\t# second pass is to create the S, P and starboard side of the C geometries\n\t\tfor seg in self.sketch.Geometry:\n\t\t\t# extract the X,Y,Z for start and end\n\t\t\tsegStartX = seg.StartPoint.x\n\t\t\tsegStartY = seg.StartPoint.y\n\t\t\tsegStartZ = seg.StartPoint.z\n\t\t\tsegEndX   = seg.EndPoint.x\n\t\t\tsegEndY   = seg.EndPoint.y\n\t\t\tsegEndZ   = seg.EndPoint.z\n\t\t\tabsMinX   = abs(self.xMin)\n\t\t\t# normalise segments within drawing to X axis if not stemline\n\t\t\tif not self.stemlineFlag:\n\t\t\t\tif abs(segStartX) == absMinX:\n\t\t\t\t\tif 0<absMinX<1:\n\t\t\t\t\t\tsegStartX = 0\n\t\t\t\t\telif absMinX >= 1:\n\t\t\t\t\t\tFreeCAD.Console.PrintMessage(\"Move to Y axis of '\" + self.label + \"'\\n\")\n\t\t\t\t\t\tif segStartX<0:\n\t\t\t\t\t\t\tsegStartX = segStartX + absMinX\n\t\t\t\t\t\telif segEndX>0:\n\t\t\t\t\t\t\tsegStartX = segStartX - absMinX\n\t\t\t\tif abs(segEndX) == absMinX:\n\t\t\t\t\tif 0<absMinX<1:\n\t\t\t\t\t\tsegEndX = 0\n\t\t\t\t\telif absMinX >= 1:\n\t\t\t\t\t\tFreeCAD.Console.PrintMessage(\"Move to Y axis of '\" + self.label + \"'\\n\")\n\t\t\t\t\t\tif segEndX<0:\n\t\t\t\t\t\t\tsegEndX = segEndX + absMinX\n\t\t\t\t\t\telif segEndX>0:\n\t\t\t\t\t\t\tsegEndX = segEndX - absMinX\n\t\t\t# now create starboard, port, complete geometries\n\t\t\tself.geometryS.append(Part.Line(\n\t\t\t\tBase.Vector(segStartX, segStartY, segStartZ),\n\t\t\t\tBase.Vector(segEndX, segEndY, segEndZ)))\n\t\t\tif self.stemlineFlag:\n\t\t\t\t# stemline is on the YZ axis and is common to both half-hulls\n\t\t\t\t# so don't flip it's X coordinates\n\t\t\t\tmultiplicand = 1\n\t\t\telse:\n\t\t\t\tmultiplicand = -1\n\t\t\tself.geometryP.append(Part.Line(\n\t\t\t\tBase.Vector(segStartX*multiplicand, segStartY, segStartZ),\n\t\t\t\tBase.Vector(segEndX*multiplicand, segEndY, segEndZ)))\n\t\t\t# starboard geometry is first half of complete hull geometry\n\t\t\tself.geometryC.append(self.geometryS[-1])\n\t\t# third pass is to create the Complete geometry so the segments have\n\t\t# constant direction from starboard to port:\n\t\t# 1) reverse segment order of starboard side\n\t\t# 2 copy port side geometry\n\t\tsegCnt = len(self.sketch.Geometry)\n\t\tcompleteGeometry = list()\n\t\tfor i in range(segCnt):\n\t\t\tcompleteGeometry.append(self.reverseLineDirection(self.geometryS[segCnt-1-i]))\n\t\tfor i in range(segCnt):\n\t\t\tcompleteGeometry.append(self.reverseLineDirection(self.geometryP[i]))\n\t\tself.geometryC = completeGeometry\n\n\tdef reverseLineDirection(self,aLine):\n\t\treturn Part.Line(aLine.EndPoint, aLine.StartPoint)\n\n# Function definitions\n\ndef createBottle(aKeelFlag):\n\t# create a bottle around the hull\n\tbottleRadius = 250\n\tneckRadius = 75\n\tbottleBottom = -1000\n\tbottleTop = 400\n\tneckBottom = 800\n\tneckTop = 1150\n\tcorkHeight = 100\n\t# get some dimensions for the plaque based on the size of the hull or half-hull\n\tminusX = crossSections[-2].yPos * 1.1\n\tplusX = (crossSections[0].yPos + crossSections[0].yMax) * 1.1\n\tminusY = 0; plusY = 0\n\tfor cs in crossSections:\n\t\t#minusY = max(minusY, abs(cs.yMin))\n\t\tplusY = max(plusY, cs.yMax)\n\tminusY = plusY * -0.75\n\tplusY = plusY * 1.1\n\t#print minusX, \" \", plusX, \" \", minusY, \" \", plusY\n\n\tbs0 = FreeCAD.ActiveDocument.addObject(\"Part::Vertex\",\"Ring0\")\n\tbs0.Label='Ring0'\n\tbs0.X=0.00\n\tbs0.Y=bottleBottom*0.97\n\tbs0.Z=0.00\n\tbs0.Placement = Base.Placement(\tBase.Vector(0.00,0.00,0.00),\n\t\t\t\t\t\t\t\t\tBase.Rotation(0.00,0.00,0.00,1.00))\n\tbs0.ViewObject.Visibility=False\n\t#\n\tbs1 = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Ring1')\n\tbs1.addGeometry(Part.Circle(Base.Vector(0,0,0), Base.Vector(0,0,1), bottleRadius))\n\tbs1.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,bottleBottom,0.0),\n\t\t\t\t\t\t\t\t\tFreeCAD.Rotation(-0.707107,0.0,0.0,-0.707107))\n\t#\n\tbs2 = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Ring2')\n\tbs2.addGeometry(Part.Circle(Base.Vector(0,0,0), Base.Vector(0,0,1), bottleRadius))\n\tbs2.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,bottleTop,0.0),\n\t\t\t\t\t\t\t\t\tFreeCAD.Rotation(-0.707107,0.0,0.0,-0.707107))\n\t#\n\tbs3 = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Ring3')\n\tbs3.addGeometry(Part.Circle(Base.Vector(0,0,0), Base.Vector(0,0,1), neckRadius))\n\tbs3.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,neckBottom,0.0),\n\t\t\t\t\t\t\t\t\tFreeCAD.Rotation(-0.707107,0.0,0.0,-0.707107))\n\t#\n\tbs4 = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Ring4')\n\tbs4.addGeometry(Part.Circle(Base.Vector(0,0,0), Base.Vector(0,0,1), neckRadius))\n\tbs4.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,neckTop,0.0),\n\t\t\t\t\t\t\t\t\tFreeCAD.Rotation(-0.707107,0.0,0.0,-0.707107))\n\t#\n\tbot0 = FreeCAD.getDocument('hull_complete').addObject('Part::Loft','Loft0')\n\tbot0.Sections=[bs0, bs1,]\n\tbot0.Solid=False; bot0.Ruled=False; bot0.Closed=False\n\t#\n\tbot1 = FreeCAD.getDocument('hull_complete').addObject('Part::Loft','Loft1')\n\tbot1.Sections=[bs1, bs2,]\n\tbot1.Solid=False; bot1.Ruled=False; bot1.Closed=False\n\t#\n\tbot2 = FreeCAD.getDocument('hull_complete').addObject('Part::Loft','Loft2')\n\tbot2.Sections=[bs2, bs3,]\n\tbot2.Solid=False; bot2.Ruled=False; bot2.Closed=False\n\t#\n\tbot3 = FreeCAD.getDocument('hull_complete').addObject('Part::Loft','Loft3')\n\tbot3.Sections=[bs3,bs4,]\n\tbot3.Solid=False; bot3.Ruled=False; bot3.Closed=False\n\t#\n\tbottle = FreeCAD.activeDocument().addObject(\"Part::MultiFuse\",\"Bottle\")\n\tbottle.Shapes = [bot0,bot1,bot2,bot3,]\n\tbot1.ViewObject.Visibility=False\n\tbot2.ViewObject.Visibility=False\n\tbot3.ViewObject.Visibility=False\n\t#bottle.ViewObject.ShapeColor=Gui.ActiveDocument.Loft1.ShapeColor\n\tbottle.ViewObject.DisplayMode=\"Shaded\"\n\tbottle.ViewObject.Transparency=80\n\tbottle.ViewObject.ShapeColor=(0.4, 0.8, 0.5, 0.0)\n\tFreeCAD.ActiveDocument.recompute()\n\t#\n\tcork = FreeCAD.ActiveDocument.addObject(\"Part::Cylinder\",\"Cylinder\")\n\tcork.Label = \"Cork\"\n\tcork.Radius = neckRadius-1\n\tcork.Height = corkHeight\n\tcork.Placement = FreeCAD.Placement(\tFreeCAD.Vector(0.0,neckTop-(corkHeight/2),0.0),\n\t\t\t\t\t\t\t\t\t\tFreeCAD.Rotation(FreeCAD.Vector(1,0,0),-90))\n\tcork.ViewObject.ShapeColor=(0.78, 0.65, 0.35, 0.0)\n\tcork.ViewObject.DisplayMode = \"Shaded\"\n\t#\n\tFreeCADGui.activeDocument().activeView().viewAxometric()\n\tFreeCADGui.SendMsgToActiveView(\"ViewFit\")\n\tFreeCAD.ActiveDocument.recompute()\n\ndef createBulkheads(aDictionary):\n\tuserAction = None\n\n\tdocKey = findOpenDocumentName(outputWorkspaceB)\n\tprint docKey\n\tif docKey!=None:\n\t\treply = QtGui.QMessageBox.question(None, \"\",\n\t\t\t\"The previous 'Bulkheads' output file is still open, close it\",\n\t\t\tQtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)\n\t\tif reply == QtGui.QMessageBox.Yes:\n\t\t\tFreeCAD.closeDocument(outputWorkspaceB)\n\t\telse:\n\t\t\tuserAction = userCancelled\n\n\tif userAction!=userCancelled:\n\t\t# bring in values from user dialogue\n\t\tcoachhouseFlag\t\t\t= aDictionary[\"coachhouseDeckBulkheadsFlag\"]\n\t\tforwardBulkheadsToSkip\t= aDictionary[\"forwardBulkheadsToSkip\"]\n\t\taftBulkheadsToSkip\t\t= aDictionary[\"aftBulkheadsToSkip\"]\n\t\tdeckWidth\t\t\t\t= aDictionary[\"deckWidth\"]\n\t\tdeckThrow\t\t\t\t= aDictionary[\"deckThrow\"]\n\t\tcoachhouseRise\t\t\t= aDictionary[\"coachhouseRise\"]\n\t\tcoachhouseIncline\t\t= aDictionary[\"coachhouseIncline\"]\n\t\t# set up output workspaces\n\t\tdoc = FreeCAD.newDocument(outputWorkspaceB)\n\t\tFreeCAD.setActiveDocument(outputWorkspaceB)\n\t\tFreeCAD.ActiveDocument = FreeCAD.getDocument(outputWorkspaceB)\n\t\tFreeCADGui.ActiveDocument = FreeCADGui.getDocument(outputWorkspaceB)\n\n\t\tfor i in range(forwardBulkheadsToSkip,len(crossSections)-aftBulkheadsToSkip):\n\t\t\t# add new bulkhead\n\t\t\tcs = crossSections[i]\n\t\t\tnewSketch = FreeCAD.activeDocument().addObject('Sketcher::SketchObject',cs.label)\n\t\t\t#place bulkhead along keel\n\t\t\tnewSketch.Placement = FreeCAD.Placement(\n\t\t\t\tFreeCAD.Vector(cs.xPos,cs.yPos,cs.zPos),\n\t\t\t\tFreeCAD.Rotation(cs.rotQ1,cs.rotQ2,cs.rotQ3,cs.rotQ4))\n\t\t\t# insert geometry segments from both half-hulls plus bulkhead into new Sketch\n\t\t\tfor seg in cs.geometryC:\n\t\t\t\tnewSketch.addGeometry(\n\t\t\t\t\tPart.Line(FreeCAD.Vector(seg.StartPoint.x,\n\t\t\t\t\t\tseg.StartPoint.y,\t0),\n\t\t\t\t\tFreeCAD.Vector(seg.EndPoint.x,\n\t\t\t\t\t\tseg.EndPoint.y,0)))\n\t\t\t\tFreeCAD.ActiveDocument.recompute()\n\t\t\txMin = cs.xMax * -1\n\t\t\tif coachhouseFlag:\n\t\t\t\t# user wants a coachhouse bulkhead\n\t\t\t\tnewSketch.addGeometry(\n\t\t\t\t\tPart.Line(\tFreeCAD.Vector(xMin, cs.yMax, 0),\n\t\t\t\t\t\t\t\tFreeCAD.Vector(xMin+deckWidth, cs.yMax+deckThrow, 0)))\n\t\t\t\tFreeCAD.ActiveDocument.recompute()\n\t\t\t\tnewSketch.addGeometry(\n\t\t\t\t\tPart.Line(\tFreeCAD.Vector(xMin+deckWidth, cs.yMax+deckThrow, 0),\n\t\t\t\t\t\t\t\tFreeCAD.Vector(xMin+deckWidth+coachhouseIncline, cs.yMax+deckThrow+coachhouseRise, 0)))\n\t\t\t\tFreeCAD.ActiveDocument.recompute()\n\t\t\t\t#\n\t\t\t\tnewSketch.addGeometry(\n\t\t\t\t\tPart.Line(\tFreeCAD.Vector(xMin+deckWidth+coachhouseIncline, cs.yMax+deckThrow+coachhouseRise, 0),\n\t\t\t\t\t\t\t\tFreeCAD.Vector(cs.xMax-deckWidth-coachhouseIncline, cs.yMax+deckThrow+coachhouseRise, 0)))\n\t\t\t\tFreeCAD.ActiveDocument.recompute()\n\t\t\t\t# focus at about -800\n\t\t\t\t#newSketch.addGeometry(\n\t\t\t\t#\tPart.ArcOfCircle(Part.Circle(App.Vector(0.0,-190,0),App.Vector(0,0,1),240.0),1.078868,2.064096))\n\t\t\t\tnewSketch.addGeometry(\n\t\t\t\t\tPart.Line(\tFreeCAD.Vector(cs.xMax-deckWidth-coachhouseIncline, cs.yMax+deckThrow+coachhouseRise, 0),\n\t\t\t\t\t\t\t\tFreeCAD.Vector(cs.xMax-deckWidth, cs.yMax+deckThrow, 0)))\n\t\t\t\tFreeCAD.ActiveDocument.recompute()\n\t\t\t\tnewSketch.addGeometry(\n\t\t\t\t\tPart.Line(\tFreeCAD.Vector(cs.xMax-deckWidth, cs.yMax+deckThrow, 0),\n\t\t\t\t\t\t\t\tFreeCAD.Vector(cs.xMax, cs.yMax, 0)))\n\t\t\telse:\n\t\t\t\t# generate bulkheads for flush deck\n\t\t\t\tnewSketch.addGeometry(\n\t\t\t\t\tPart.Line(\tFreeCAD.Vector(xMin, cs.yMax, 0),\n\t\t\t\t\t\t\t\tFreeCAD.Vector(cs.xMax, cs.yMax, 0)))\n\t\t\t\tFreeCAD.ActiveDocument.recompute()\n\n\t\t\tnewPad = App.activeDocument().addObject(\"PartDesign::Pad\",\"Bulkhead\")\n\t\t\tnewPad.Sketch = newSketch\n\t\t\tnewPad.Length = 1.0\n\t\t\tnewPad.Sketch.ViewObject.hide()\n\t\t\tFreeCAD.ActiveDocument.recompute()\n\n\t\tFreeCADGui.SendMsgToActiveView(\"ViewFit\")\n\t\tFreeCADGui.activeDocument().activeView().viewAxometric()\n\ndef createPlaque(aSideFlag, aKeelFlag):\n\t# create plaque to mount half-hull on\n\t# get some dimensions for the plaque based on the size of the hull or half-hull\n\t# note: the X & Y in this routine are to do with the XY of the plaque, not the Sketches\n\twoodColour = (0.53, 0.42, 0.23, 0.0)\n\t# find the overall max & min for X & Y\n\tminusY = crossSections[1].yMin; plusY = crossSections[1].yMin\n\t# get the plaque's Y min & max for the cross-sections (not the stemline or transom)\n\tfor i in range(1,len(crossSections)-1):\n\t\tminusY = min(minusY, crossSections[i].yMin)\n\t\tplusY = max(plusY, crossSections[i].yMax)\n\t# now allow for the extent of the stemline\n\tminusY = min(minusY, crossSections[0].yMin)\n\tplusY = max(plusY, crossSections[0].yMax)\n\t# get extent of aftmost cross-section and add what the transom sticks out\n\tminusX = crossSections[-2].yPos + crossSections[-1].yMin - crossSections[-1].yMax\n\t# get the placement of the stemline and add what the stemline extends forward\n\tplusX = crossSections[0].yPos + crossSections[0].xMax\n\t# some scaling factors to provide margin space around the half-hull\n\tminusX = minusX * 1.1\n\tplusX = plusX * 1.1\n\tminusY = minusY * 1.5\n\tplusY = plusY * 1.25\n\n\tps = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','PlainPlaqueSketch')\n\tps.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,0.0,0.0),\n\t\t\t\t\t\t\t\t\tFreeCAD.Rotation(0.5,0.5,0.5,0.5))\n\tif aSideFlag==starboardSideFlag: ps.Placement.Base.x = -10\n\tps.addGeometry(Part.Line(FreeCAD.Vector(minusX,plusY,0),FreeCAD.Vector(plusX,plusY,0)))\n\tps.addGeometry(Part.Line(FreeCAD.Vector(plusX,plusY,0),FreeCAD.Vector(plusX,minusY,0)))\n\tps.addGeometry(Part.Line(FreeCAD.Vector(plusX,minusY,0),FreeCAD.Vector(minusX,minusY,0)))\n\tps.addGeometry(Part.Line(FreeCAD.Vector(minusX,minusY,0),FreeCAD.Vector(minusX,plusY,0)))\n\t#\n\tps.addConstraint(Sketcher.Constraint('Coincident',0,2,1,1))\n\tps.addConstraint(Sketcher.Constraint('Coincident',1,2,2,1))\n\tps.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1))\n\tps.addConstraint(Sketcher.Constraint('Coincident',3,2,0,1))\n\tps.addConstraint(Sketcher.Constraint('Horizontal',0))\n\tps.addConstraint(Sketcher.Constraint('Horizontal',2))\n\tps.addConstraint(Sketcher.Constraint('Vertical',1))\n\tps.addConstraint(Sketcher.Constraint('Vertical',3))\n\tFreeCAD.ActiveDocument.recompute()\n\t#\n\tpad = FreeCAD.activeDocument().addObject(\"PartDesign::Pad\",\"PlainPlaquePad\")\n\tpad.Sketch = ps\n\tpad.Length = 10.0\n\tpad.Sketch.ViewObject.hide()\n\tpad.ViewObject.ShapeColor = woodColour\n\tFreeCAD.ActiveDocument.recompute()\n\t#\n\tcyl1 = FreeCAD.ActiveDocument.addObject(\"Part::Cylinder\",\"Cylinder1\")\n\tcyl1.Label = \"Cylinder1\"\n\tcyl1.Radius = plusY/5\n\tcyl1.Placement =\tFreeCAD.Placement(FreeCAD.Vector(0,plusX,plusY),\n\t\t\t\t\t\tFreeCAD.Rotation(FreeCAD.Vector(0,1,0),90))\n\tif aSideFlag==starboardSideFlag: cyl1.Placement.Base.x = -10\n\tcut1 = FreeCAD.activeDocument().addObject(\"Part::Cut\",\"Cut1\")\n\tcut1.Base = App.activeDocument().PlainPlaquePad\n\tcut1.Tool = App.activeDocument().Cylinder1\n\tcut1.ViewObject.ShapeColor = woodColour\n\tFreeCAD.ActiveDocument.recompute()\n\t#\n\tcyl2 = FreeCAD.ActiveDocument.addObject(\"Part::Cylinder\",\"Cylinder2\")\n\tcyl2.Label = \"Cylinder2\"\n\tcyl2.Radius = plusY/5\n\tcyl2.Placement =\tFreeCAD.Placement(FreeCAD.Vector(0,plusX,minusY),\n\t\t\t\t\t\tFreeCAD.Rotation(FreeCAD.Vector(0,1,0),90))\n\tif aSideFlag==starboardSideFlag: cyl2.Placement.Base.x = -10\n\tcut2 = FreeCAD.activeDocument().addObject(\"Part::Cut\",\"Cut2\")\n\tcut2.Base = App.activeDocument().Cut1\n\tcut2.Tool = App.activeDocument().Cylinder2\n\tcut2.ViewObject.ShapeColor = woodColour\n\tFreeCAD.ActiveDocument.recompute()\n\t#\n\tcyl3 = FreeCAD.ActiveDocument.addObject(\"Part::Cylinder\",\"Cylinder3\")\n\tcyl3.Label = \"Cylinder3\"\n\tcyl3.Radius = plusY/5\n\tcyl3.Placement =\tFreeCAD.Placement(FreeCAD.Vector(0,minusX,minusY),\n\t\t\t\t\t\tFreeCAD.Rotation(FreeCAD.Vector(0,1,0),90))\n\tif aSideFlag==starboardSideFlag: cyl3.Placement.Base.x = -10\n\tcut3 = FreeCAD.activeDocument().addObject(\"Part::Cut\",\"Cut3\")\n\tcut3.Base = App.activeDocument().Cut2\n\tcut3.Tool = App.activeDocument().Cylinder3\n\tcut3.ViewObject.ShapeColor = woodColour\n\tFreeCAD.ActiveDocument.recompute()\n\t#\n\tcyl4 = FreeCAD.ActiveDocument.addObject(\"Part::Cylinder\",\"Cylinder4\")\n\tcyl4.Label = \"Cylinder4\"\n\tcyl4.Radius = plusY/5\n\tcyl4.Placement =\tFreeCAD.Placement(FreeCAD.Vector(0,minusX,plusY),\n\t\t\t\t\t\tFreeCAD.Rotation(FreeCAD.Vector(0,1,0),90))\n\tif aSideFlag==starboardSideFlag: cyl4.Placement.Base.x = -10\n\tcut4 = FreeCAD.activeDocument().addObject(\"Part::Cut\",\"Cut4\")\n\tcut4.Base = App.activeDocument().Cut3\n\tcut4.Tool = App.activeDocument().Cylinder4\n\tcut4.ViewObject.ShapeColor = woodColour\n\tFreeCAD.ActiveDocument.recompute()\n\t#\n\tcham = FreeCAD.ActiveDocument.addObject(\"Part::Chamfer\",\"Plaque\")\n\tcham.Base = FreeCAD.ActiveDocument.Cut4\n\tedges = []\n\tif aSideFlag == starboardSideFlag:\n\t\tedges.append((3,3.00,3.00)); edges.append((13,3.00,3.00)); edges.append((14,3.00,3.00)); edges.append((15,3.00,3.00))\n\t\tedges.append((16,3.00,3.00)); edges.append((17,3.00,3.00)); edges.append((18,3.00,3.00)); edges.append((19,3.00,3.00))\n\telse:\n\t\tedges.append((1,3.00,3.00)); edges.append((5,3.00,3.00)); edges.append((6,3.00,3.00)); edges.append((7,3.00,3.00))\n\t\tedges.append((8,3.00,3.00)); edges.append((9,3.00,3.00)); edges.append((10,3.00,3.00)); edges.append((11,3.00,3.00))\n\tcham.Edges = edges\n\tcham.Base.ViewObject.Visibility = False\n\tcham.ViewObject.ShapeColor = woodColour\n\n\tcreatePlaqueCover()\n\n\tif aSideFlag == starboardSideFlag:\n\t\tFreeCADGui.activeDocument().activeView().viewRight()\n\telse:\n\t\tFreeCADGui.activeDocument().activeView().viewLeft()\n\tFreeCADGui.SendMsgToActiveView(\"ViewFit\")\n\tFreeCAD.ActiveDocument.recompute()\n\ndef createPlaqueCover():\n\t# get upper bow point UBP\n\t# get upper stern point USP\n\t# get number of sections NS\n\t# divide the line UBP-USP into NS pieces\n\t#---\n\t# for each sketch, get the top point TP\n\t# make segments between each consecutive points\n\t#---\n\t# make RuledSurface between corresponding segments\n\n\tif len(crossSections)<5:\n\t\tFreeCAD.Console.PrintMessage(\"Insufficient cross-sections for plaque cover\")\n\telse:\n\t\t# the number of cross-section and therefore chines determines how many\n\t\t# segments will be in the cover for the half-hull model\n\t\tsegmentCount = len(crossSections)-2\n\t\t# determine endpoints for the line segments along the plaque\n\t\tbowPoint = Base.Vector(0,\n\t\t\tmax(crossSections[0].geometryS[-1].StartPoint.x, crossSections[0].geometryS[-1].EndPoint.x),\n\t\t\tmax(crossSections[0].geometryS[-1].StartPoint.y, crossSections[0].geometryS[-1].EndPoint.y))\n\t\tsternPoint = Base.Vector(0,\n\t\t\tcrossSections[-2].yPos,\n\t\t\tmax(crossSections[-2].geometryS[-1].StartPoint.y, crossSections[-2].geometryS[-1].EndPoint.y))\n\t\tplaquePoints = [bowPoint, sternPoint]\n\t\tlineAlongPlaqueToSplit = Part.Line(bowPoint,sternPoint)\n\t\tlapSection = lineAlongPlaqueToSplit.length()/segmentCount\n\n\t\t# build a list of the points that start/end the segments\n\t\tpointList = []\n\t\tpointList.append(lineAlongPlaqueToSplit.StartPoint)\n\t\tprint lineAlongPlaqueToSplit.StartPoint\n\t\tfor i in range(1, segmentCount):\n\t\t\tpointList.append(lineAlongPlaqueToSplit.value((i)*lapSection))\n\t\t\tprint lineAlongPlaqueToSplit.value((i)*lapSection)\n\t\tpointList.append(lineAlongPlaqueToSplit.EndPoint)\n\t\tprint lineAlongPlaqueToSplit.EndPoint\n\t\tprint\n\t\t# iterate the list of points from the first segment to the last\n\t\t# do stemline first as it is in the YZ plane (cross-sections are in the XZ plane)\n\t\ta=FreeCAD.ActiveDocument.addObject('Part::Line', 'cs1k')\n\t\ta.X1=0; a.Y1=pointList[0].y; a.Z1=pointList[0].z\n\t\ta.X2=0; a.Y2=pointList[1].y; a.Z2=pointList[1].z\n\t\tb=FreeCAD.ActiveDocument.addObject('Part::Line', 'cs1h')\n\t\t# B1 wrong\n\t\tb.X1=0; b.Y1=crossSections[0].endPoint.x; b.Z1=crossSections[0].endPoint.z\n\t\tb.X2=crossSections[1].endPoint.x; b.Y2=crossSections[1].endPoint.y; b.Z2=crossSections[1].endPoint.z\n\t\tFreeCAD.ActiveDocument.addObject('Part::RuledSurface', 'coverSeg1')\n\t\tFreeCAD.ActiveDocument.ActiveObject.Curve1=(a,[''])\n\t\tFreeCAD.ActiveDocument.ActiveObject.Curve2=(b,[''])\n\t\tFreeCAD.ActiveDocument.recompute()\n\t\t# now do cross=sections\n\t\tfor i in range(1, segmentCount):\n\t\t\ta=FreeCAD.ActiveDocument.addObject('Part::Line', 'cs'+str(i+1)+'k')\n\t\t\ta.X1=0; a.Y1=pointList[i].y; a.Z1=pointList[i].z\n\t\t\ta.X2=0; a.Y2=pointList[i+1].y;   a.Z2=pointList[i+1].z\n\t\t\tb=FreeCAD.ActiveDocument.addObject('Part::Line', 'cs'+str(i+1)+'h')\n\t\t\tb.X1=crossSections[i].endPoint.x;   b.Y1=crossSections[i].endPoint.y;   b.Z1=crossSections[i-1].endPoint.z\n\t\t\tb.X2=crossSections[i+1].endPoint.x; b.Y2=crossSections[i+1].endPoint.y; b.Z2=crossSections[i].endPoint.z\n\t\t\tFreeCAD.ActiveDocument.addObject('Part::RuledSurface', 'coverSeg'+str(i+1))\n\t\t\tFreeCAD.ActiveDocument.ActiveObject.Curve1=(a,[''])\n\t\t\tFreeCAD.ActiveDocument.ActiveObject.Curve2=(b,[''])\n\t\t\tFreeCAD.ActiveDocument.recompute()\n\n\t\tFreeCAD.ActiveDocument.recompute()\n\ndef displayChinePanels(crossSectionLabelA, crossSectionLabelB, aSideFlag):\n\t# accept 2 sketch labels and generate a ruled surface between them\n\t#print sketchLabelA\n\tplaceholder = \"_\"\n\tcsA = FreeCAD.ActiveDocument.getObjectsByLabel(crossSectionLabelA)[0]\n\tcsB = FreeCAD.ActiveDocument.getObjectsByLabel(crossSectionLabelB)[0]\n\tlabelA = csA.Label\n\tlabelB = csB.Label\n\tlblA = labelA.split('_', 1)[0]\n\tlblB = labelB.split('_', 1)[0]\n\tif aSideFlag == portSideFlag:\n\t\tsideText = \" Port\"\n\telif aSideFlag == starboardSideFlag:\n\t\tsideText = \" Starboard\"\n\telse:\n\t\tsideText = \"\"\n\t#print str(sketchLabelA) + \" \" + str(sketchLabelB)\n\tFreeCAD.ActiveDocument.addObject('Part::RuledSurface', placeholder+lblA+placeholder+lblB+sideText)\n\tcsObjectA = FreeCAD.ActiveDocument.getObjectsByLabel(crossSectionLabelA)[0]\n\tcsObjectB = FreeCAD.ActiveDocument.getObjectsByLabel(crossSectionLabelB)[0]\n\t#print \"> \" + str(sketchObjectA) + \" \" + str(sketchObjectB)\n\tFreeCAD.ActiveDocument.ActiveObject.Curve1=(csObjectA,[''])\n\tFreeCAD.ActiveDocument.ActiveObject.Curve2=(csObjectB,[''])\n\ndef displayCompleteHull():\n\tuserAction = None\n\n\tdocKey = findOpenDocumentName(outputWorkspaceC)\n\tif docKey!=None:\n\t\treply = QtGui.QMessageBox.question(None, \"\",\n\t\t\t\"The previous 'Complete Hull' output file is still open, close it\",\n\t\t\tQtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)\n\t\tif reply == QtGui.QMessageBox.Yes:\n\t\t\tFreeCAD.closeDocument(outputWorkspaceC)\n\t\telse:\n\t\t\tuserAction = userCancelled\n\n\tif userAction!=userCancelled:\n\t\tdoc = App.newDocument(outputWorkspaceC)\n\t\tApp.setActiveDocument(outputWorkspaceC)\n\t\tApp.ActiveDocument=App.getDocument(outputWorkspaceC)\n\t\tdocComplete = App.ActiveDocument\n\t\tGui.ActiveDocument=Gui.getDocument(outputWorkspaceC)\n\n\t\tfor cs in crossSections:\n\t\t\t# add new Sketch object\n\t\t\tnewSketch = FreeCAD.activeDocument().addObject('Sketcher::SketchObject',cs.label)\n\t\t\tnewSketch.Placement = FreeCAD.Placement(\n\t\t\t\tFreeCAD.Vector(cs.xPos,cs.yPos,cs.zPos),\n\t\t\t\tFreeCAD.Rotation(cs.rotQ1,cs.rotQ2,cs.rotQ3,cs.rotQ4))\n\t\t\tGui.activeDocument().setEdit(cs.altLabel)\n\t\t\t# insert geometry segments from both half-hulls into new Sketch\n\t\t\tfor seg in cs.geometryC:\n\t\t\t\tnewSketch.addGeometry(\n\t\t\t\t\tPart.Line(FreeCAD.Vector(seg.StartPoint.x,\n\t\t\t\t\t\tseg.StartPoint.y,\t0),\n\t\t\t\t\tFreeCAD.Vector(seg.EndPoint.x,\n\t\t\t\t\t\tseg.EndPoint.y,0)))\n\t\t\tGui.getDocument(doc.Label).resetEdit()\n\t\t\t#print obj.Name + \" \" + obj.Label\n\n\t\tFreeCAD.cs = crossSections # debug statement\n\t\tfor i in range(0, len(crossSections)-1):\n\t\t\tdisplayChinePanels(crossSections[i].altLabel,crossSections[i+1].altLabel, \"C\")\n\t\t# now draw the bow sections going to the stemline\n\t\t#displayChinePanels(crossSections[].altLabel,crossSections[i+1].altLabel, \"C\")\n\t\tFreeCAD.activeDocument().recompute()\n\t\tFreeCADGui.SendMsgToActiveView(\"ViewFit\")\n\t\tFreeCADGui.activeDocument().activeView().viewAxometric()\n\ndef displayHalfHull(aSideFlag):\n\tuserAction = None\n\t# create output workspace for one side\n\tif aSideFlag == starboardSideFlag:\n\t\tquery = \"The previous 'Port Half-Hull' output file is still open, close it\"\n\t\tselectedOutputWorkspace = outputWorkspaceS\n\t\toutputWorkspace = outputWorkspaceS\n\t\tsideFlag = starboardSideFlag\n\telse:\n\t\tquery = \"The previous 'Starboard Half-Hull' output file is still open, close it\"\n\t\tselectedOutputWorkspace = outputWorkspaceP\n\t\toutputWorkspace = outputWorkspaceP\n\t\tsideFlag = portSideFlag\n\n\tdocKey = findOpenDocumentName(selectedOutputWorkspace)\n\tif docKey==None:\n\t\tdoc = FreeCAD.newDocument(selectedOutputWorkspace)\n\telse:\n\t\treply = QtGui.QMessageBox.question(None, \"\",\n\t\t\tquery,\n\t\t\tQtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)\n\t\tif reply == QtGui.QMessageBox.Yes:\n\t\t\tFreeCAD.closeDocument(selectedOutputWorkspace)\n\t\t\tdoc = FreeCAD.newDocument(selectedOutputWorkspace)\n\t\telse:\n\t\t\tuserAction = userCancelled\n\n\tif userAction!=userCancelled:\n\t\tFreeCAD.setActiveDocument(outputWorkspace)\n\t\tFreeCAD.ActiveDocument=FreeCAD.getDocument(outputWorkspace)\n\t\tFreeCADGui.ActiveDocument=FreeCADGui.getDocument(outputWorkspace)\n\n\t\t# place the segments in the document\n\t\tfor cs in crossSections:\n\t\t\t# add new Sketch object\n\t\t\tFreeCAD.activeDocument().addObject('Sketcher::SketchObject',cs.label)\n\t\t\tnewSketch = FreeCAD.ActiveDocument.getObject(cs.altLabel)\n\t\t\tnewSketch.Placement = FreeCAD.Placement(\n\t\t\t\tFreeCAD.Vector(cs.xPos,cs.yPos,cs.zPos),\n\t\t\t\tFreeCAD.Rotation(cs.rotQ1,cs.rotQ2,cs.rotQ3,cs.rotQ4))\n\t\t\tGui.activeDocument().setEdit(cs.altLabel)\n\t\t\t# insert geometry segments into new Sketch\n\t\t\tif sideFlag == \"S\":\n\t\t\t\tgeom = cs.geometryS\n\t\t\telse:\n\t\t\t\tgeom = cs.geometryP\n\t\t\tfor seg in geom:\n\t\t\t\tnewSketch.addGeometry(\n\t\t\t\t\tPart.Line(FreeCAD.Vector(seg.StartPoint.x,\n\t\t\t\t\t\tseg.StartPoint.y,\t0),\n\t\t\t\t\tFreeCAD.Vector(seg.EndPoint.x,\n\t\t\t\t\t\tseg.EndPoint.y,0)))\n\t\t\tGui.getDocument(doc.Label).resetEdit()\n\n\t\tfor i in range(0, len(crossSections)-1):\n\t\t\tdisplayChinePanels(crossSections[i].altLabel,crossSections[i+1].altLabel, sideFlag)\n\n\t\tFreeCAD.activeDocument().recompute()\n\t\tFreeCADGui.SendMsgToActiveView(\"ViewFit\")\n\t\tFreeCADGui.activeDocument().activeView().viewAxometric()\n\ndef eqRotation(rotationA, rotationB, eps=0.0001):\n\t\"takes 2 Rotations and compares for equality\"\n\teqFlag = True\n\tfor i in range(0, 4):\n\t\t#print str(rotationA.Q[i]) + \"#\" + str(rotationB.Q[i])\n\t\tif rotationA.Q[i] == 0:\n\t\t\tif rotationB.Q[i] <> 0:\n\t\t\t\teqFlag = False\n\t\telif abs(abs(rotationA.Q[i])-abs(rotationB.Q[i]))/abs(rotationA.Q[i]) > eps:\n\t\t\teqFlag = False\n\treturn eqFlag\n\ndef resetSketchesVisibility():\n\t# set Visibility on all Sketches to False\n\topenWindows = list()\n\tif starboardHHFlag:\n\t\topenWindows.append(outputWorkspaceS)\n\tif portHHFlag:\n\t\topenWindows.append(outputWorkspaceP)\n\tif completeHullFlag:\n\t\topenWindows.append(outputWorkspaceC)\n\t#if fullHullBulkheadsFlag:\n\t\t#openWindows.append(outputWorkspaceB)\n\n\tfor ws in openWindows:\n\t\tFreeCAD.setActiveDocument(ws)\n\t\tFreeCAD.ActiveDocument=FreeCAD.getDocument(ws)\n\t\tFreeCADGui.ActiveDocument=FreeCADGui.getDocument(ws)\n\t\tfor obj in FreeCAD.ActiveDocument.Objects:\n\t\t\tif obj.TypeId == 'Sketcher::SketchObject':\n\t\t\t\tvo = FreeCADGui.ActiveDocument.getObject(obj.Name)\n\t\t\t\tvo.Visibility=False\n\ndef sortOutFilesAndDocuments():\n\tglobal keepSourceOpenFlag\n\t# this routine uses the following variables from the main handler:\n\t# docSrc (returns)\n\t# fileName (reads)\n\t# keepSourceOpenFlag (global, writes)\n\t# it determines if the 'user selected input document' is already open,\n\t# if it is then it is made the ActiveDocument, otherwise it is\n\t# Opened which also sets it to the ActiveDocument\n\tif len(FreeCAD.listDocuments())==0:\n\t\t# no documents open\n\t\treturn FreeCAD.open(fileName)\n\telse:\n\t\t# some document(s) open so check if 'user selected input document' is already open\n\t\t\"\"\"docKey = None\n\t\tfor key in FreeCAD.listDocuments():\n\t\t\tif FreeCAD.listDocuments()[key].FileName==fileName:\n\t\t\t\tdocKey = key\"\"\"\n\t\tdocKey = findOpenDocumentFileSpec(fileName)\n\t\tif docKey==None:\n\t\t\t# 'user selected input document' is not open\n\t\t\treturn FreeCAD.open(fileName)\n\t\telse:\n\t\t\t# 'user selected input document' is among open documents\n\t\t\t# set the 'user selected input document' to the active document (in case it isn't)\n\t\t\tFreeCAD.setActiveDocument(docKey)\n\t\t\t# user started with 'user selected input document' open, so this flag will allow\n\t\t\t# us to leave it open when we finish\n\t\t\tkeepSourceOpenFlag = True\n\t\t\treturn FreeCAD.ActiveDocument\n\ndef findOpenDocumentFileSpec(aDocumentFileSpec):\n\t# check if supplied document is already open\n\t# return document name or None\n\tdocKey = None\n\tfor key in FreeCAD.listDocuments():\n\t\tif FreeCAD.listDocuments()[key].FileName==aDocumentFileSpec:\n\t\t\tdocKey = key\n\treturn docKey\n\ndef findOpenDocumentName(aDocumentName):\n\t# check if supplied document is already open\n\t# return document name or None\n\tdocKey = None\n\tfor key in FreeCAD.listDocuments():\n\t\tif FreeCAD.listDocuments()[key].Name==aDocumentName:\n\t\t\tdocKey = key\n\treturn docKey\n\n# Constant definitions\noutputWorkspaceS\t= \"hull_starboard\"\noutputWorkspaceP\t= \"hull_port\"\noutputWorkspaceC\t= \"hull_complete\"\noutputWorkspaceB\t= \"bulkheads\"\nxyPlane\t\t\t\t= Base.Rotation(0.0, 0.0, 0.0, 1.0) # transom\nxzPlane\t\t\t\t= Base.Rotation(0.7071067811865475, 0.0, 0.0, 0.7071067811865476) # cross section profile\nyzPlane\t\t\t\t= Base.Rotation(0.5,0.5,0.5,0.5) # stemline\ninfinity\t\t\t= +99999999999999.9 # will hold min Y value in Sketch\ninfinityNegative\t= -99999999999999.9 # will hold max X value in Sketch\nglobal starboardSideFlag, portSideFlag, userCancelled, userLastFile, userOK\nstarboardSideFlag\t= \"S\"\nportSideFlag\t\t= \"F\"\ncompleteSidesFlag\t= \"C\"\nuserCancelled\t\t= \"Cancelled\"\nuserLastFile\t\t= \"Last File\"\nuserOK\t\t\t\t= \"OK\"\ndefaultDir = FreeCAD.ConfigGet(\"UserHomePath\")\n\n# code ***********************************************************************************\nallCrossSections\t= {}\ncrossSections\t\t= list()\ndocSrc\t\t\t\t= None\nglobal keepSourceOpenFlag\nkeepSourceOpenFlag\t= False\nstarboardHHFlag\t\t= False; starboardHHPlaqueFlag\t= False; starboardHHPKeelFlag\t\t= False\nportHHFlag\t\t\t= False; portHHPlaqueFlag\t\t= False; portHHPKeelFlag\t\t\t= False\ncompleteHullFlag\t= False; completeHullBottleFlag\t= False; completeHullKeelFlag\t\t= False\nbulkheadsFlag\t\t= False; flushDeckBulkheadsFlag\t= True; coachhouseDeckBulkheadsFlag\t= True\n\nform = GetConfigParams()\nform.exec_()\nconfigParams = form.configParams\n\nif configParams.result==userLastFile:\n\tif hasattr(FreeCAD,\"MacroHalfHullConfigParams\"):\n\t\t# global in FreeCAD exists so use the parameters stored there\n\t\t#if type(FreeCAD.MacroHalfHullConfigParams)=='GetConfigParams':\n\t\tconfigParams = FreeCAD.MacroHalfHullConfigParams\n\t\tconfigParams.result = userLastFile\n\telse:\n\t\t# user requested to re-use last file but there isn't one\n\t\t# so reset the choice to pick a file\n\t\tconfigParams.result = userOK\n\nif configParams.result != userCancelled:\n\t# transfer results to control flags\n\tstarboardHHFlag\t\t\t\t= configParams.cb1a\n\tstarboardHHPlaqueFlag\t\t= configParams.cb1b\n\tstarboardHHPKeelFlag\t\t= configParams.cb1c\n\tportHHFlag\t\t\t\t\t= configParams.cb2a\n\tportHHPlaqueFlag\t\t\t= configParams.cb2b\n\tportHHPKeelFlag\t\t\t\t= configParams.cb2c\n\tcompleteHullFlag\t\t\t= configParams.cb3a\n\tcompleteHullBottleFlag\t\t= configParams.cb3b\n\tcompleteHullKeelFlag\t\t= configParams.cb3c\n\tbulkheadsFlag\t\t\t\t= configParams.cb4a\n\t# transfer bulkhead parameters\n\tbulkheadParams = {}\n\tbulkheadParams[\"coachhouseDeckBulkheadsFlag\"]\t= configParams.rb5b\n\tbulkheadParams[\"forwardBulkheadsToSkip\"]\t\t= int(configParams.skipAtBow)\n\tbulkheadParams[\"aftBulkheadsToSkip\"]\t\t\t= int(configParams.skipAtStern)\n\tbulkheadParams[\"deckWidth\"]\t\t\t\t\t\t= float(configParams.deckWidth.text())\n\tbulkheadParams[\"deckThrow\"]\t\t\t\t\t\t= float(configParams.deckThrow.text())\n\tbulkheadParams[\"coachhouseRise\"]\t\t\t\t= float(configParams.coachhouseRise.text())\n\tbulkheadParams[\"coachhouseIncline\"]\t\t\t\t= float(configParams.coachhouseIncline.text())\n\n\tdefaultDir = expanduser(\"~\")\n\tdefaultDir = \"/Data Pool/Coding/FreeCAD/work items/hull mirroring/half-hull/\"\n\tif configParams.result==userOK:\n\t\t# user wants to select file\n\t\tfileName = QtGui.QFileDialog.getOpenFileName(dir=defaultDir, caption = \"Select a 'Hull Profile' to Load\", filter=\"*.FCStd\")[0]\n\t\tconfigParams.documentFileName = fileName\n\telse:\n\t\t# file is coming out of FreeCAD global\n\t\tfileName = FreeCAD.MacroHalfHullConfigParams.documentFileName\n\n\tif len(fileName) != 0:\n\t\tdocSrc = sortOutFilesAndDocuments()\n\t\t# read all the objects, saving the Sketcher objects\n\t\tfor obj in FreeCAD.ActiveDocument.Objects:\n\t\t\tif obj.TypeId == 'Sketcher::SketchObject':\n\t\t\t\t# ignore anything except Sketches\n\t\t\t\tnewObj = HullCrossSection(obj)\n\t\t\t\tif newObj.transomFlag:\n\t\t\t\t\t# if we have the transom sketch then wait to give\n\t\t\t\t\t# it a placement further aft than anything else\n\t\t\t\t\ttransomObject = newObj\n\t\t\t\telif newObj.stemlineFlag:\n\t\t\t\t\t# if we have the stemline sketch then wait\n\t\t\t\t\t# to give it the first placement\n\t\t\t\t\tstemlineObject = newObj\n\t\t\t\t\tstemlineSegmentCount = stemlineObject.sketch.GeometryCount\n\t\t\t\telse:\n\t\t\t\t\t# must be a regular cross section profile\n\t\t\t\t\t# so add object to our collection\n\t\t\t\t\tallCrossSections[newObj.key] = newObj\n\t\t\t\t\t#maxY = max(maxY, newObj.yPos)\n\n\t\t# discard sketches with wrong number of points\n\t\t# i.e. cross-sections that have a different number\n\t\t# of points than the stemline\n\t\tfor key, cs in allCrossSections.items():\n\t\t\tif cs.geometryCount <> stemlineSegmentCount:\n\t\t\t\tFreeCAD.Console.PrintMessage(\"Discard for wrong number of segments for '\" + str(allCrossSections[key].label) + \"'\\n\")\n\t\t\t\tdel allCrossSections[key]\n\n\t\t# construct a list with cross sections in order from stemline to transom\n\t\tcrossSections.append(stemlineObject)\n\t\tfor sk in sorted(allCrossSections.keys(), reverse=True):\n\t\t\tcrossSections.append(allCrossSections[sk])\n\t\ttransomObject.zPos = crossSections[-1].zPos+crossSections[-1].yMax\n\t\tcrossSections.append(transomObject)\n\n\t\tFreeCAD.cs = crossSections # debug statement\n\n\t\t# now set the transom elevation at the top of the last cross-section\n\t\tcrossSections[-1].zPos = crossSections[-2].zPos + crossSections[-2].yMax\n\n\t\tFreeCAD.cs = crossSections # debug statement\n\n\t\t# depending on user flags, invoke appropriate modules\n\t\tif starboardHHFlag:\t\t\tdisplayHalfHull(starboardSideFlag)\n\t\tif starboardHHPlaqueFlag:\tcreatePlaque(starboardSideFlag, starboardHHPKeelFlag)\n\t\tif portHHFlag:\t\t\t\tdisplayHalfHull(portSideFlag)\n\t\tif portHHPlaqueFlag:\t\tcreatePlaque(portSideFlag, portHHPKeelFlag)\n\t\tif completeHullFlag:\t\tdisplayCompleteHull()\n\t\tif completeHullBottleFlag:\tcreateBottle(completeHullKeelFlag)\n\t\tif bulkheadsFlag:\t\t\tcreateBulkheads(bulkheadParams)\n\n\t\t# save Config Params to FreeCAD global in case user wants to use it next run\n\t\tFreeCAD.MacroHalfHullConfigParams = configParams\n\n\t\tif not keepSourceOpenFlag:\n\t\t\tFreeCAD.closeDocument(docSrc.Name)\n\t\tresetSketchesVisibility()\n#\n#OS: Mac OS X\n#Word size: 64-bit\n#Version: 0.14.3703 (Git)\n#Branch: releases/FreeCAD-0-14\n#Hash: c6edd47334a3e6f209e493773093db2b9b4f0e40\n#Python version: 2.7.5\n#Qt version: 4.8.6\n#Coin version: 3.1.3\n#SoQt version: 1.5.0\n#OCC version: 6.7.0\n#\n#and so the macro ends...\n",
    "url": "",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ObjectCreation\\HalfHull.FCMacro",
    "filename_from_url": "",
    "author": "",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "HilbertCurve",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "This macro creates an Hilbert curve wire in 2 or 3 dimensions with many iterations.",
    "code": "# -*- coding: utf-8 -*-\n\n# Copyright (c) 2020 Simone Bignetti, Gottolengo Italy (simone.b)\n#\n# This file is part of the FreeCAD CAx development system.\n#\n# This library is free software; you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation; either\n# version 2.1 of the License, or (at your option) any later version.\n#\n# This library is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n# Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with this library; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n# USA\n#\n# You can contact me by mail at simone.bignetti@linux.it\n\n__Name__ = 'HilbertCurve'\n__Comment__ = 'This macro creates an Hilbert curve wire in 2 or 3 dimensions with many iterations.'\n__Author__  = 'Simone Bignetti'\n__Version__ = '1.2.0'\n__Date__    = '2020-12-29'\n__License__ = 'LGPL-2.1-or-later'\n__Web__ = 'https://wiki.freecadweb.org/Macro_HilbertCurve'\n__Wiki__ = 'https://wiki.freecadweb.org/Macro_HilbertCurve'\n__Icon__ = 'HilbertCurve.svg'\n__Help__ = 'Choose the dimensions of the wire, the number of the iterations and the length of the wire segment.'\n__Status__ = 'Stable'\n__Requires__ = ''\n__Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=22&t=53781'\n__Files__ = 'HilbertCurve.svg'\n\n\n# For the wire\nimport FreeCAD as app\nimport Draft\n\n# For the gui\nfrom PySide import QtGui, QtCore\n\nclass HilbertCurve:\n    \"\"\"The class of the Hilbert curve.\n\n    By this class it's possible to create a wire\n    of a fractal Hilbert curve with\n    a fixed number of dimensions and iterations.\n    \"\"\"\n\n    def __init__(self, dimensions, iterations):\n        \"\"\"Initialize the Hilbert curve.\n\n        Args:\n            iterations (int): iterations to use in constructing the curve\n            dimensions (int): number of dimensions\n        \"\"\"\n\n        self.dimensions = dimensions\n        self.iterations = iterations\n\n        # minimum and maximum distance along curve\n        self.min_distance = 0\n        self.max_distance = 2 ** (self.iterations * self.dimensions) - 1\n\n        # minimum and maximum coordinate value in any dimension\n        self.min_coordinate = 0\n        self.max_coordinate = 2 ** self.iterations - 1\n\n        # number of points\n        self.number_of_points = 2 ** (self.iterations * self.dimensions)\n\n    def point_from_distance(self, distance):\n        \"\"\"Return a point in n-dimensional space given a distance along a the curve.\n\n        Args:\n            distance (int): integer distance along the curve\n\n        Returns:\n            point (iterable of ints): an n-dimensional vector of length dimensions where\n            each component value is between 0 and 2**iterations-1.\n        \"\"\"\n\n        bit_string = format(distance, 'b').zfill(self.iterations * self.dimensions)  # zero filled binary distance\n        point = [int(bit_string[i::self.dimensions], 2) for i in range(self.dimensions)]  # transpose of distance\n\n        # Gray decode: point = point xor (point / 2)\n        gray = point[self.dimensions-1] >> 1\n        for i in range(self.dimensions-1, 0, -1):\n            point[i] ^= point[i-1]\n        point[0] ^= gray\n\n        # Undo excess work\n        q = 2\n        while q != (2 << (self.iterations-1)):\n            p = q - 1\n            for i in range(self.dimensions-1, -1, -1):\n                if point[i] & q:\n                    # invert\n                    point[0] ^= p\n                else:\n                    # exchange\n                    gray = (point[0] ^ point[i]) & p\n                    point[0] ^= gray\n                    point[i] ^= gray\n            q <<= 1\n\n        return point\n\n    def get_min_distance(self):\n        \"\"\"Return the minimum distance along the curve.\"\"\"\n        return self.min_distance\n\n    def get_max_distance(self):\n        \"\"\"Return the maximum distance along the curve.\"\"\"\n        return self.max_distance\n\n    def get_min_coordinate(self):\n        \"\"\"Return the minimum coordinate value in any dimension.\"\"\"\n        return self.min_coordinate\n\n    def get_max_coordinate(self):\n        \"\"\"Return the maximum coordinate value in any dimension.\"\"\"\n        return self.max_coordinate\n\n    def get_number_of_points(self):\n        \"\"\"Return the number of points in the curve.\"\"\"\n        return self.number_of_points\n\n    def get_points(self):\n        \"\"\"Return the list of points in the curve.\"\"\"\n        points = []\n        for point_number in range(self.number_of_points):\n            points.append(self.point_from_distance(point_number))\n        return points\n\n    def __str__(self):\n        return f\"HilbertCurve(dimensions={self.dimensions}, iterations={self.iterations})\"\n\n    def __repr__(self):\n        return self.__str__()\n\n\nclass Hilbert_Dialog(QtGui.QDialog):\n    \"\"\"The dialog for the Hilbert curve\n\n    This class opens in FreeCAD a dialog to input\n    the number of dimensions and the number of iterations\n    to create the Hilbert curve.\n    OK creates the curve.\n    CANCEL quit the macro.\n    \"\"\"\n\n    def __init__(self):\n        super(Hilbert_Dialog, self).__init__()\n        self.setupUi()\n\n    def setupUi(self):\n        self.dimensions = 2\n        self.iterations = 3\n\n        self.setGeometry(250, 250, 400, 300)  # Window definition\n        self.setWindowTitle(\"Hilbert curve Macro\")\n\n        titleLabel = QtGui.QLabel(\"Create an Hilbert curve in two or three dimensions\")  # Title and subtitle\n        titleFont = QtGui.QFont()\n        titleFont.setBold(True)\n        titleFont.setWeight(75)\n        titleLabel.setFont(titleFont)\n        subtitleLabel = QtGui.QLabel(\"This macro creates a wire in the draft workbench\\nwith the shape of an Hilbert curve in two or three dimensions.\\nFor example, you can use this wire as a sweep path.\\nIt's recommended to apply a radius at the wire,\\nin order to obtain a correct sweep generation.\")\n        titleBox = QtGui.QVBoxLayout()\n        titleBox.addWidget(titleLabel)\n        titleBox.addWidget(subtitleLabel)\n        titleBox.insertStretch(-1)\n\n        dimensionsLabel = QtGui.QLabel(\"Number of dimensions: \")  # Number of dimensions\n        self.twoDradioButton = QtGui.QRadioButton()\n        self.twoDradioButton.setText(\"2D\")\n        self.twoDradioButton.setChecked(True)\n        self.threeDradioButton = QtGui.QRadioButton()\n        self.threeDradioButton.setText(\"3D\")\n        dimensionsBox=QtGui.QHBoxLayout()\n        dimensionsBox.addWidget(dimensionsLabel)\n        dimensionsBox.addWidget(self.twoDradioButton)\n        dimensionsBox.addWidget(self.threeDradioButton)\n\n        iterationsLabel = QtGui.QLabel(\"Iterations:\")  # Iterations  and length spins in a grid\n        self.iterationsSpin = QtGui.QSpinBox()\n        self.iterationsSpin.setMinimum(1)\n        self.iterationsSpin.setMaximum(10)\n        lengthLabel = QtGui.QLabel(\"Length:\")\n        self.lengthSpin = QtGui.QDoubleSpinBox()\n        self.lengthSpin.setMinimum(1.0)\n        self.lengthSpin.setMaximum(999999.000000000000000)\n        self.lengthSpin.setValue(10.000000000000000)\n        grid = QtGui.QGridLayout()\n        grid.setSpacing(10)\n        grid.addWidget(iterationsLabel, 1, 0)\n        grid.addWidget(self.iterationsSpin, 1, 1)\n        grid.addWidget(lengthLabel, 2, 0)\n        grid.addWidget(self.lengthSpin, 2, 1)\n\n        okButton = QtGui.QPushButton(\"OK\")  # Ok and Cancel Buttons at right bottom\n        okButton.clicked.connect(self.onOkButton)\n        cancelButton = QtGui.QPushButton(\"Cancel\")\n        cancelButton.clicked.connect(self.onCancelButton)\n        buttonBox = QtGui.QHBoxLayout()\n        buttonBox.addStretch()\n        buttonBox.addWidget(okButton)\n        buttonBox.addWidget(cancelButton)\n\n        vbox = QtGui.QVBoxLayout()\n        vbox.addLayout(titleBox)\n        vbox.addLayout(dimensionsBox)\n        vbox.addLayout(grid)\n        vbox.addLayout(buttonBox)\n        vbox.setSpacing(30)\n        vbox.insertStretch(1)\n        self.setLayout(vbox)\n\n        self.show()\n\n    def onOkButton(self):\n        if self.twoDradioButton.isChecked():\n            dimensions = 2\n        else:\n            dimensions = 3\n        iterations = self.iterationsSpin.value()\n        length = self.lengthSpin.value()\n        HC=HilbertCurve(dimensions, iterations)\n        points = HC.get_points()\n        pl = app.Placement()\n        pl.Rotation.Q = (0.0, 0.0, 0.0, 1.0)\n        pl.Base = app.Vector(0.0, 0.0, 0.0)\n        vectors = []\n        if dimensions == 2:\n            for point in points:\n                vectors.append(app.Vector(point[0]*length, point[1]*length, 0.0))\n        else:\n            for point in points:\n                vectors.append(app.Vector(point[0]*length, point[1]*length, point[2]*length))\n        wire = Draft.makeWire(vectors, placement=pl, closed=False, face=False, support=None)\n        wire.Label = \"Hilbert\"\n        Draft.autogroup(wire)\n        self.close()\n\n    def onCancelButton(self):\n        self.close()\n\n\nhilbert_dialog = Hilbert_Dialog()\nhilbert_dialog.exec()\n",
    "url": "https://wiki.freecadweb.org/Macro_HilbertCurve",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_HilbertCurve",
    "version": "1.2.0",
    "license": "",
    "date": "2020-12-29",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ObjectCreation\\HilbertCurve.FCMacro",
    "filename_from_url": "",
    "author": "Simone Bignetti",
    "icon": "HilbertCurve.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "HilbertCurve.svg"
    ],
    "parsed": true
  },
  {
    "name": "HyperbolaCreater",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "This macro creates ...",
    "code": "# Hyperbola Creator - Version 0.7\n'''\n***************************************************************************\n*   Copyright (c) 2015 <quick61>                                          *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU  General Public License (GPL)           *\n*   as published by the Free Software Foundation; either version 3 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU General Public License     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n'''\n\n\n_Title__=\"Hyperbola Creator\"\n__Author__ = \"Quick61\"\n__Version__ = \"00.11\"\n__Date__    = \"16/06/2015\"\n\n\n__Comment__ = \"This macro creates ...\"\n\n\n__Web__ = \"http://forum.freecadweb.org/viewtopic.php?f=22&t=11328\"\n__Wiki__ = \"http://www.freecadweb.org\"\n__Icon__  = \"/usr/lib/freecad/Mod/plugins/FreeCAD-macros/icons/HyperbolaIcon.png\"\n__IconW__  = \"C:/Documents and Settings/YourUserName/Application Data/FreeCAD\"\n__Help__ = \"start the macro and follow the instructions\"\n__Status__ = \"\"\n__Requires__ = \"\"\n__License__ = \"GPL-3.0-or-later\"\n__Communication__ = \"https://forum.freecadweb.org/memberlist.php?mode=viewprofile&u=2030\"\n\n\nimport FreeCAD, FreeCADGui, Part, PySide\nfrom FreeCAD import Base\nfrom PySide import QtCore, QtGui\nfrom PySide.QtGui import QLineEdit, QRadioButton\nApp=FreeCAD\n\n#+ hack\nimport sys,traceback\ndef sayexc(mess=''):\n\texc_type, exc_value, exc_traceback = sys.exc_info()\n\tttt=repr(traceback.format_exception(exc_type, exc_value,exc_traceback))\n\tlls=eval(ttt)\n\tl=len(lls)\n\tl2=lls[(l-3):]\n\tFreeCAD.Console.PrintError(mess + \"\\n\" +\"-->  \".join(l2))\n\nclass p():\n\n    def makeHyp(self):\n\n        if self.radio1.isChecked():\n            try:\n\n                Mi = float(self.r1.text())\n                Ma = float(self.r2.text())\n                tS1 = float(self.s1.text())\n                tS2 = float(self.s2.text())\n\n                hyp=Part.Hyperbola()\n                hyp.MinorRadius=Mi\n                hyp.MajorRadius=Ma\n\n                shape=hyp.toShape(tS1,tS2)\n                Part.show(shape)\n\n            except:\n                sayexc()\n                FreeCAD.Console.PrintError(\"Unable to complete task\")\n\n            self.close()\n\n\n        if self.radio2.isChecked():\n            try:\n\n                Mi = float(self.r1.text())\n                Ma = float(self.r2.text())\n                tS1 = float(self.s1.text())\n                tS2 = float(self.s2.text())\n                Dg = float(self.Dg.text())\n\n                hyp=Part.Hyperbola()\n                hyp.MinorRadius=Mi\n                hyp.MajorRadius=Ma\n\n                shape=hyp.toShape(tS1,tS2)\n                rev=shape.revolve(App.Vector(0,0,0),App.Vector(0,1,0),Dg) # revolve around Y axis by number of degrees\n                Part.show(rev)\n            except:\n                sayexc()\n                FreeCAD.Console.PrintError(\"Unable to complete task\")\n\n            self.close()\n\n    def close(self):\n        self.dialog.hide()\n\n\n\n    def __init__(self):\n        self.dialog = None\n\n        self.dialog = QtGui.QDialog()\n        self.dialog.resize(280,110)\n\n        self.dialog.setWindowTitle(\"Hyperbola Creator\")\n        la = QtGui.QVBoxLayout(self.dialog)\n\n        self.radio1 = QRadioButton(\"Make 2D Shape\")\n        self.radio2 = QRadioButton(\"Make 3D Revolution\")\n\n# # # #\n# set default to \"Make 2D Shape\" & make radio buttons - Change self.radio1.setChecked(True) to\n# self.radio2.setChecked(True) to set \"Make 3D Revolution\" as default\n# # # #\n\n        self.radio1.setChecked(True)\n        la.addWidget(self.radio1)\n        la.addWidget(self.radio2)\n\n        iN1 = QtGui.QLabel(\"Minor Radius\")\n        la.addWidget(iN1)\n        self.r1 = QtGui.QLineEdit()\n        la.addWidget(self.r1)\n        self.r1.setText('2')\n\n        iN2 = QtGui.QLabel(\"Major Radius\")\n        la.addWidget(iN2)\n        self.r2 = QtGui.QLineEdit()\n        la.addWidget(self.r2)\n        self.r2.setText('3')\n\n        iN3 = QtGui.QLabel(\"Range Of Curve - Minimum\")\n        la.addWidget(iN3)\n        self.s1 = QtGui.QLineEdit()\n        la.addWidget(self.s1)\n        self.s1.setText('-2')\n\n        iN4 = QtGui.QLabel(\"Range Of Curve - Maximum\")\n        la.addWidget(iN4)\n        self.s2 = QtGui.QLineEdit()\n        la.addWidget(self.s2)\n        self.s2.setText('2')\n\n        iN5 = QtGui.QLabel(\"Degrees of Revolve (Only valid for 3D Revolution)\")\n        la.addWidget(iN5)\n        self.Dg = QtGui.QLineEdit()\n        self.Dg.insert(\"360\")\n        la.addWidget(self.Dg)\n\n        okbox = QtGui.QDialogButtonBox(self.dialog)\n        okbox.setOrientation(QtCore.Qt.Horizontal)\n        okbox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)\n        la.addWidget(okbox)\n        QtCore.QObject.connect(okbox, QtCore.SIGNAL(\"accepted()\"), self.makeHyp)\n        QtCore.QObject.connect(okbox, QtCore.SIGNAL(\"rejected()\"), self.close)\n        QtCore.QMetaObject.connectSlotsByName(self.dialog)\n        self.dialog.show()\n        self.dialog.exec_()\n\np()\n",
    "url": "http://forum.freecadweb.org/viewtopic.php?f=22&t=11328",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org",
    "version": "00.11",
    "license": "",
    "date": "16/06/2015",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ObjectCreation\\HyperbolaCreater.FCMacro",
    "filename_from_url": "",
    "author": "Quick61",
    "icon": "/usr/lib/freecad/Mod/plugins/FreeCAD-macros/icons/HyperbolaIcon.png",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Macro_FCCircularText",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "This macro creates a text around a cylinder",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2014 2015 <mario52>                                     *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*   http://www.freecadweb.org/wiki/Macro_FCCircularText                   *\n*           WARNING! All changes in this file will be lost and            *\n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n# FCCircularText.FCMacro\n# ver 0.10 #\n##################################################################################################\n# OS: Ubuntu 14.04.1 LTS                          # OS: Ubuntu 14.04.2 LTS\n# Platform: 32-bit                                # Word size of OS: 32-bit\n# Version: 0.14.2935 (Git)                        # Word size of FreeCAD: 32-bit\n# Branch: master                                  # Version: 0.16.4928 (Git)\n# Hash: eab159b6ee675012bf79de838c206a311e911d85  # Branch: master\n# Python version: 2.7.6                           # Hash: d8f63bcfd10301f3d1e141cced4370f0782238d0\n# Qt version: 4.8.6                               # Python version: 2.7.6\n# Coin version: 4.0.0a                            # Qt version: 4.8.6\n# SoQt version: 1.6.0a                            # Coin version: 4.0.0a\n# OCC version: 6.7.0                              # OCC version: 6.8.0.oce-0.17\n##################################################################################################\n# OS: Windows Vista                               # OS: Windows Vista\n# Word size of OS: 32-bit                         # Word size of OS: 32-bit\n# Word size of FreeCAD: 32-bit                    # Word size of FreeCAD: 32-bit\n# Version: 0.15.4527 (Git)                        # Version: 0.15.4671 (Git)\n# Branch: master                                  # Branch: releases/FreeCAD-0-15\n# Hash: 0da2e4c45a9a259c26abd54c2a35393e1c15696f  # Hash: 244b3aef360841646cbfe80a1b225c8b39c8380c\n# Python version: 2.7.8                           # Python version: 2.7.8\n# Qt version: 4.8.6                               # Qt version: 4.8.6\n# Coin version: 4.0.0a                            # Coin version: 4.0.0a\n# OCC version: 6.7.1                              # OCC version: 6.8.0.oce-0.17\n##################################################################################################\n\n__Title__=\"FCCircularText\"\n__Author__ = \"Mario52\"\n__Version__ = \"00.11\"\n__Date__    = \"12/06/2015\"\n__License__ = \"LGPL-2.0-or-later\"\n\n__Comment__ = \"This macro creates a text around a cylinder\"\n__Web__ = \"http://forum.freecadweb.org/viewtopic.php?f=3&t=7384\"\n__Wiki__ = \"http://www.freecadweb.org/wiki/Macro_FCCircularText\"\n__Icon__  = \"/usr/lib/freecad/Mod/plugins/icons/FCCircularTextButtom.png\"\n__IconW__  = \"C:/Documents and Settings/YourUserName/Application Data/FreeCAD\"\n__Help__ = \"start the macro and follow the instructions\"\n__Status__ = \"stable\"\n__Requires__ = \"freecad 0.14.3706\"\n__Communication__ = \"http://www.freecadweb.org/wiki/User:Mario52\"\n\n\ntry:\n    import PyQt4\n    from PyQt4 import QtGui ,QtCore\n    from PyQt4.QtGui import *\n    from PyQt4.QtCore import *\nexcept Exception:\n    import PySide\n    from PySide import QtGui ,QtCore\n    from PySide.QtGui import *\n    from PySide.QtCore import *\n\nimport Draft, Part, FreeCAD, math, PartGui, FreeCADGui\nfrom math import sqrt, pi, sin, cos, asin, degrees, radians, tan\nfrom FreeCAD import Base\nimport os, time, sys\n\nApp=FreeCAD\nGui=FreeCADGui\n\nimport sys,traceback\ndef sayexc(mess=''):\n\texc_type, exc_value, exc_traceback = sys.exc_info()\n\tttt=repr(traceback.format_exception(exc_type, exc_value,exc_traceback))\n\tlls=eval(ttt)\n\tl=len(lls)\n\tl2=lls[(l-3):]\n\tFreeCAD.Console.PrintError(mess + \"\\n\" +\"-->  \".join(l2))\n\nimport platform\n\nclass ConfigManager():\n\n\tdef __init__(self,name):\n\t\tself.name=\"Plugins/\"+name\n\n\tdef get(self,param,default,defaultWindows=None,defaultMac=None):\n\t\t\tos=platform.system()\n\t\t\t#os='Linux'\n\t\t\t#os='Windows'\n\t\t\t#os='Darwin'\n\t\t\tv=False\n\t\t\tif not defaultWindows:\n\t\t\t\tdefaultWindows=default\n\t\t\tif not defaultMac:\n\t\t\t\tdefaultMac=default\n\t\t\tif os =='Windows' :\n\t\t\t\tdefault= defaultWindows\n\t\t\tif os =='Darwin' :\n\t\t\t\tdefault= defaultMac\n\t\t\tif default.__class__ == unicode:\n\t\t\t\tdefault=str(default)\n\t\t\tif default.__class__ == int:\n\t\t\t\tv=FreeCAD.ParamGet('User parameter:'+self.name).GetInt(param)\n\t\t\t\tif not v:\n\t\t\t\t\tFreeCAD.ParamGet('User parameter:'+self.name).SetInt(param,default)\n\t\t\tif default.__class__ == float:\n\t\t\t\tv=FreeCAD.ParamGet('User parameter:'+self.name).GetFloat(param)\n\t\t\t\tif not v:\n\t\t\t\t\tFreeCAD.ParamGet('User parameter:'+self.name).SetFloat(param,default)\n\t\t\tif default.__class__ == str:\n\t\t\t\tv=FreeCAD.ParamGet('User parameter:'+self.name).GetString(param)\n\t\t\t\tif not v:\n\t\t\t\t\tFreeCAD.ParamGet('User parameter:'+self.name).SetString(param,default)\n\t\t\tif default.__class__ == bool:\n\t\t\t\tv=FreeCAD.ParamGet('User parameter:'+self.name).GetBool(param)\n\t\t\t\tif not v:\n\t\t\t\t\tFreeCAD.ParamGet('User parameter:'+self.name).SetBool(param,default)\n\t\t\tif not v:\n\t\t\t\tv=default\n\t\t\treturn v\n\nglobal points           ;points   = 0.0\nglobal coor_X           ;coor_X   = 0.0\nglobal coor_Y           ;coor_Y   = 0.0\nglobal coor_Z           ;coor_Z   = 0.0\nglobal vec              ;vec      = 0\n\nglobal PolicePath\n\ncm=ConfigManager(\"circular text\")\nPolicePath=cm.get(\"PolicePath\",\"/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-M.ttf\",\"C:/Windows/Fonts/ARIAL.TTF\",\".../macfontdir/macfont.ttf\")\n\nglobal rayon            ;rayon           = 10.0               # radius\nglobal texte            ;texte           = \"FreeCAD the best\" # FreeCad The Best your text\nglobal debut            ;debut           = 0                  # begin text\nglobal rotation         ;rotation        = 360                # must exceed the number of characters of text\nglobal SizeCaractere    ;SizeCaractere   = 2.0                # size font\n\nglobal precision        ;precision       = 0.0\nglobal correctionAngle  ;correctionAngle = 10.0\nglobal correctionRayon  ;correctionRayon = 0.15\nglobal debout           ;debout          = 1                  # 1=stand   0=flat\nglobal exterieur        ;exterieur       = 1                  # 1=external 0=internal\nglobal baseHelix        ;baseHelix       = 0.0                # base of helix\nglobal endHelix         ;endHelix        = 0.0                # end of helix (height)\nglobal pasHelix         ;pasHelix        = 2.0                # Pas of helix\nglobal nombreCarParTour ;nombreCarParTour= 10                 # number char by Pas\n\nglobal PlacementX       ;PlacementX      = 0.0                # Placement character axis X\nglobal PlacementY       ;PlacementY      = 0.0                # Placement character axis Y\nglobal PlacementZ       ;PlacementZ      = 0.0                # Placement character axis Z\n\nglobal inclinaisonX     ;inclinaisonX    = 0                  # inclination character axis X\nglobal inclinaisonY     ;inclinaisonY    = 0                  # inclination character axis Y\nglobal inclinaisonZ     ;inclinaisonZ    = 0                  # inclination character axis Z + correctionAngle\n\nglobal cercleClock      ;cercleClock     = rayon              # diameter support clock\nglobal nombreFaces      ;nombreFaces     = 0                  # number Faces of support 0=none 1=circle 2=rectangle 3=triangle 4,5 ... polygon\nglobal romain           ;romain          = 0                  # number roman or arabic\nglobal redressement     ;redressement    = 0                  # character V or circular\n\nglobal comP             ;comP            = \"\"                 # container\nglobal nameL            ;nameL           = \"\"                 # container\nglobal epaisseur        ;epaisseur       = 0.0                # epaisseur extrusion character\nglobal epaisSupp        ;epaisSupp       = 0.0                # epaisseur extrusion support\nglobal extrusion        ;extrusion       = 0.0                # epaisseur extrusion\n\nglobal compount1        ;compount1       = 0                  # cree un compose des carachteres\n\n# pointColor\nglobal red              ;red   = 1.0  # 1 = 255 [ color num x = (1/255)*x ]\nglobal green            ;green = 0.0  #\nglobal blue             ;blue  = 0.0  #\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\nclass Ui_MainWindow(object):\n\n    def setupUi(self, MainWindow):\n        self.window = MainWindow\n\n        path = FreeCAD.ConfigGet(\"AppHomePath\")\n        #path = FreeCAD.ConfigGet(\"UserAppData\")\n\n        global PolicePath\n        global rayon\n        global texte\n        global rotation\n        global SizeCaractere\n        global debout\n        global exterieur\n\n        global precision\n        global correctionAngle\n        global correctionRayon\n        global baseHelix\n        global endHelix\n        global nombreCarParTour\n\n        global epaisseur\n        global epaisSupp\n\n        MainWindow.setObjectName(_fromUtf8(\"MainWindow\"))\n        MainWindow.resize(370, 638)\n        MainWindow.setMaximumSize(QtCore.QSize(370, 638))\n        MainWindow.setMinimumSize(QtCore.QSize(370, 638))\n        self.centralWidget = QtGui.QWidget(MainWindow)\n        self.centralWidget.setObjectName(_fromUtf8(\"centralWidget\"))\n        self.groupBox_02 = QtGui.QGroupBox(self.centralWidget)\n        self.groupBox_02.setGeometry(QtCore.QRect(10, 100, 351, 301))\n        self.groupBox_02.setAccessibleDescription(_fromUtf8(\"\"))\n        self.groupBox_02.setObjectName(_fromUtf8(\"groupBox_02\"))\n\n        self.DS_Size_Character = QtGui.QDoubleSpinBox(self.groupBox_02)\n        self.DS_Size_Character.setGeometry(QtCore.QRect(140, 60, 81, 22))\n        self.DS_Size_Character.setAccessibleDescription(_fromUtf8(\"\"))\n        self.DS_Size_Character.setMinimum(0.0)\n        self.DS_Size_Character.setMaximum(99999999.0)\n        self.DS_Size_Character.setSingleStep(1.0)\n        self.DS_Size_Character.setValue(SizeCaractere)\n        self.DS_Size_Character.setObjectName(_fromUtf8(\"DS_Size_Character\"))\n        self.DS_Size_Character.setToolTip(_fromUtf8(\"Size of the font\"))\n        self.DS_Size_Character.valueChanged.connect(self.on_DS_Size_Character) #connection doubleSpinBox\n\n        self.label_4 = QtGui.QLabel(self.groupBox_02)\n        self.label_4.setGeometry(QtCore.QRect(230, 60, 91, 16))\n        self.label_4.setAccessibleDescription(_fromUtf8(\"\"))\n        self.label_4.setText(_fromUtf8(\"Size character\"))\n        self.label_4.setObjectName(_fromUtf8(\"label_4\"))\n\n        self.DS_Extrude = QtGui.QDoubleSpinBox(self.groupBox_02)\n        self.DS_Extrude.setEnabled(False)\n        self.DS_Extrude.setGeometry(QtCore.QRect(140, 210, 81, 22))\n        self.DS_Extrude.setToolTip(_fromUtf8(\"Thickness of the extrude of character. If thickness = 0 then don't extrude\"))\n        self.DS_Extrude.setAccessibleDescription(_fromUtf8(\"\"))\n        self.DS_Extrude.setMinimum(-99999999.0)\n        self.DS_Extrude.setMaximum(99999999.0)\n        self.DS_Extrude.setValue(epaisseur)\n        self.DS_Extrude.setObjectName(_fromUtf8(\"DS_Extrude\"))\n        self.DS_Extrude.valueChanged.connect(self.on_DS_Extrude) #connection doubleSpinBox\n\n        self.label_7 = QtGui.QLabel(self.groupBox_02)\n        self.label_7.setGeometry(QtCore.QRect(230, 150, 101, 20))\n        self.label_7.setAccessibleDescription(_fromUtf8(\"\"))\n        self.label_7.setText(_fromUtf8(\"Correction Angle\"))\n        self.label_7.setObjectName(_fromUtf8(\"label_7\"))\n\n        self.DS_Correction_Angle = QtGui.QDoubleSpinBox(self.groupBox_02)\n        self.DS_Correction_Angle.setGeometry(QtCore.QRect(140, 150, 81, 22))\n        self.DS_Correction_Angle.setToolTip(_fromUtf8(\"Correct angle for tangent the text of the circle or give a tilt angle \"))\n        self.DS_Correction_Angle.setAccessibleDescription(_fromUtf8(\"\"))\n        self.DS_Correction_Angle.setMinimum(-359.00)\n        self.DS_Correction_Angle.setMaximum(359.00)\n        self.DS_Correction_Angle.setValue(correctionAngle)\n        self.DS_Correction_Angle.setObjectName(_fromUtf8(\"DS_Correction_Angle\"))\n        self.DS_Correction_Angle.valueChanged.connect(self.on_DS_Correction_Angle) #connection doubleSpinBox\n\n        self.label_8 = QtGui.QLabel(self.groupBox_02)\n        self.label_8.setGeometry(QtCore.QRect(230, 180, 111, 16))\n        self.label_8.setAccessibleDescription(_fromUtf8(\"\"))\n        self.label_8.setText(_fromUtf8(\"Correction Radius\"))\n        self.label_8.setObjectName(_fromUtf8(\"label_8\"))\n\n        self.DS_Correction_Radius = QtGui.QDoubleSpinBox(self.groupBox_02)\n        self.DS_Correction_Radius.setGeometry(QtCore.QRect(140, 180, 81, 22))\n        self.DS_Correction_Radius.setToolTip(_fromUtf8(\"Correct of the radius (depend of correction angle)\"))\n        self.DS_Correction_Radius.setAccessibleDescription(_fromUtf8(\"\"))\n        self.DS_Correction_Radius.setMinimum(-99999999.0)\n        self.DS_Correction_Radius.setMaximum(99999999.0)\n        self.DS_Correction_Radius.setValue(correctionRayon)\n        self.DS_Correction_Radius.setObjectName(_fromUtf8(\"DS_Correction_Radius\"))\n        self.DS_Correction_Radius.valueChanged.connect(self.on_DS_Correction_Radius) #connection doubleSpinBox\n\n        self.DS_Radius_Circle = QtGui.QDoubleSpinBox(self.groupBox_02)\n        self.DS_Radius_Circle.setGeometry(QtCore.QRect(140, 30, 81, 22))\n        self.DS_Radius_Circle.setToolTip(_fromUtf8(\"Give the radius of circle\"))\n        self.DS_Radius_Circle.setAccessibleDescription(_fromUtf8(\"\"))\n        self.DS_Radius_Circle.setMinimum(-99999999.0)\n        self.DS_Radius_Circle.setMaximum(99999999.0)\n        self.DS_Radius_Circle.setValue(rayon)\n        self.DS_Radius_Circle.setObjectName(_fromUtf8(\"DS_Radius_Circle\"))\n        self.DS_Radius_Circle.valueChanged.connect(self.on_DS_Radius_Circle) #connection doubleSpinBox\n\n        self.label_10 = QtGui.QLabel(self.groupBox_02)\n        self.label_10.setGeometry(QtCore.QRect(230, 30, 101, 16))\n        self.label_10.setAccessibleDescription(_fromUtf8(\"\"))\n        self.label_10.setObjectName(_fromUtf8(\"label_10\"))\n\n        self.groupBox_03 = QtGui.QGroupBox(self.groupBox_02)\n        self.groupBox_03.setGeometry(QtCore.QRect(10, 20, 101, 211))\n        self.groupBox_03.setAccessibleDescription(_fromUtf8(\"\"))\n        self.groupBox_03.setObjectName(_fromUtf8(\"groupBox_03\"))\n\n        self.RA_Choice_Outdoor = QtGui.QRadioButton(self.groupBox_03)\n        self.RA_Choice_Outdoor.setGeometry(QtCore.QRect(10, 20, 71, 20))\n        self.RA_Choice_Outdoor.setAccessibleDescription(_fromUtf8(\"\"))\n        self.RA_Choice_Outdoor.setChecked(True)\n        self.RA_Choice_Outdoor.setObjectName(_fromUtf8(\"RA_Choice_Outdoor\"))\n        self.RA_Choice_Outdoor.clicked.connect(self.on_RA_Choice_Outdoor) #connection radioButton\n\n        self.RA_Choice_Indoor = QtGui.QRadioButton(self.groupBox_03)\n        self.RA_Choice_Indoor.setGeometry(QtCore.QRect(10, 40, 71, 20))\n        self.RA_Choice_Indoor.setAccessibleDescription(_fromUtf8(\"\"))\n        self.RA_Choice_Indoor.setObjectName(_fromUtf8(\"RA_Choice_Indoor\"))\n        self.RA_Choice_Indoor.clicked.connect(self.on_RA_Choice_Indoor) #connection radioButton\n\n        self.RA_Choice_Helix = QtGui.QRadioButton(self.groupBox_03)\n        self.RA_Choice_Helix.setGeometry(QtCore.QRect(10, 60, 61, 20))\n        self.RA_Choice_Helix.setAccessibleDescription(_fromUtf8(\"\"))\n        self.RA_Choice_Helix.setObjectName(_fromUtf8(\"RA_Choice_Helix\"))\n        self.RA_Choice_Helix.clicked.connect(self.on_RA_Choice_Helix) #connection radioButton\n\n        self.RA_Choice_Clock = QtGui.QRadioButton(self.groupBox_03)\n        self.RA_Choice_Clock.setGeometry(QtCore.QRect(10, 80, 61, 20))\n        self.RA_Choice_Clock.setAccessibleDescription(_fromUtf8(\"\"))\n        self.RA_Choice_Clock.setObjectName(_fromUtf8(\"RA_Choice_Clock\"))\n        self.RA_Choice_Clock.clicked.connect(self.on_RA_Choice_Clock) #connection radioButton\n\n        self.PU_Flat = QtGui.QPushButton(self.groupBox_03)\n        self.PU_Flat.setEnabled(True)\n        self.PU_Flat.setGeometry(QtCore.QRect(10, 105, 81, 28))\n        self.PU_Flat.setAccessibleDescription(_fromUtf8(\"\"))\n        self.PU_Flat.setText(_fromUtf8(\"Mode Stand\"))\n        self.PU_Flat.setToolTip(_fromUtf8(\"Click to create the text Flat\"))\n        self.PU_Flat.setObjectName(_fromUtf8(\"PU_Flat\"))\n        self.PU_Flat.clicked.connect(self.on_PU_Flat)\n\n        self.graphicsView = QtGui.QGraphicsView(self.groupBox_03)\n        self.graphicsView.setGeometry(QtCore.QRect(10, 140, 81, 61))\n        self.graphicsView.setObjectName(_fromUtf8(\"graphicsView\"))\n\n        self.label_13 = QtGui.QLabel(self.groupBox_02)\n        self.label_13.setGeometry(QtCore.QRect(230, 90, 71, 16))\n        self.label_13.setAccessibleDescription(_fromUtf8(\"\"))\n        self.label_13.setObjectName(_fromUtf8(\"label_13\"))\n\n        self.label_14 = QtGui.QLabel(self.groupBox_02)\n        self.label_14.setGeometry(QtCore.QRect(230, 120, 71, 16))\n        self.label_14.setAccessibleDescription(_fromUtf8(\"\"))\n        self.label_14.setObjectName(_fromUtf8(\"label_14\"))\n\n        self.CH_Extrude = QtGui.QCheckBox(self.groupBox_02)\n        self.CH_Extrude.setGeometry(QtCore.QRect(230, 210, 105, 20))\n        self.CH_Extrude.setToolTip(_fromUtf8(\"Choice extrude character or not\"))\n        self.CH_Extrude.setAccessibleDescription(_fromUtf8(\"\"))\n        self.CH_Extrude.setObjectName(_fromUtf8(\"CH_Extrude\"))\n        self.CH_Extrude.clicked.connect(self.on_CH_Extrude) #connection checkBox\n\n        self.DS_InclinaisonX = QtGui.QSpinBox(self.groupBox_02)\n        self.DS_InclinaisonX.setEnabled(False)\n        self.DS_InclinaisonX.setGeometry(QtCore.QRect(10, 270, 61, 22))\n        self.DS_InclinaisonX.setToolTip(_fromUtf8(\"Inclination character in axis X\"))\n        self.DS_InclinaisonX.setMinimum(-360)\n        self.DS_InclinaisonX.setMaximum(360)\n        self.DS_InclinaisonX.setValue(inclinaisonX)\n        self.DS_InclinaisonX.setObjectName(_fromUtf8(\"DS_InclinaisonX\"))\n        self.DS_InclinaisonX.valueChanged.connect(self.on_DS_InclinaisonX) #connection doubleSpinBox\n\n        self.DS_InclinaisonY = QtGui.QSpinBox(self.groupBox_02)\n        self.DS_InclinaisonY.setEnabled(False)\n        self.DS_InclinaisonY.setGeometry(QtCore.QRect(85, 270, 61, 22))\n        self.DS_InclinaisonY.setToolTip(_fromUtf8(\"Inclination character axis Y\"))\n        self.DS_InclinaisonY.setMinimum(-360)\n        self.DS_InclinaisonY.setMaximum(360)\n        self.DS_InclinaisonY.setValue(inclinaisonY)\n        self.DS_InclinaisonY.setObjectName(_fromUtf8(\"DS_InclinaisonY\"))\n        self.DS_InclinaisonY.valueChanged.connect(self.on_DS_InclinaisonY) #connection doubleSpinBox\n\n        self.DS_InclinaisonZ = QtGui.QSpinBox(self.groupBox_02)\n        self.DS_InclinaisonZ.setEnabled(False)\n        self.DS_InclinaisonZ.setGeometry(QtCore.QRect(160, 270, 61, 22))\n        self.DS_InclinaisonZ.setToolTip(_fromUtf8(\"Inclination character axis Z\"))\n        self.DS_InclinaisonZ.setMinimum(-360)\n        self.DS_InclinaisonZ.setMaximum(360)\n        self.DS_InclinaisonZ.setValue(inclinaisonZ)\n        self.DS_InclinaisonZ.setObjectName(_fromUtf8(\"DS_InclinaisonZ\"))\n        self.DS_InclinaisonZ.valueChanged.connect(self.on_DS_InclinaisonZ) #connection doubleSpinBox\n\n        self.CH_Sp_Inclination = QtGui.QCheckBox(self.groupBox_02)\n        self.CH_Sp_Inclination.setGeometry(QtCore.QRect(230, 270, 111, 20))\n        self.CH_Sp_Inclination.setToolTip(_fromUtf8(\"Inclination of character in the choice or all plane \"))\n        self.CH_Sp_Inclination.setText(_fromUtf8(\"Sp. inclination\"))\n        self.CH_Sp_Inclination.setObjectName(_fromUtf8(\"CH_Sp_Inclination\"))\n        self.CH_Sp_Inclination.clicked.connect(self.on_CH_Sp_Inclination) #connection checkBox\n\n        self.S_Begin_Angle = QtGui.QSpinBox(self.groupBox_02)\n        self.S_Begin_Angle.setGeometry(QtCore.QRect(140, 90, 81, 22))\n        self.S_Begin_Angle.setMaximum(360)\n        self.S_Begin_Angle.setObjectName(_fromUtf8(\"spinBox\"))\n        self.S_Begin_Angle.setToolTip(_fromUtf8(\"Starting text of the circle \"))\n        self.S_Begin_Angle.setValue(debut)\n        self.S_Begin_Angle.valueChanged.connect(self.on_S_Begin_Angle) #connection SpinBox\n\n        self.S_End_Angle = QtGui.QSpinBox(self.groupBox_02)\n        self.S_End_Angle.setGeometry(QtCore.QRect(140, 120, 81, 22))\n        self.S_End_Angle.setMaximum(360)\n        self.S_End_Angle.setValue(rotation)\n        self.S_End_Angle.setToolTip(_fromUtf8(\"End text of the circle \"))\n        self.S_End_Angle.setObjectName(_fromUtf8(\"S_End_Angle\"))\n        self.S_End_Angle.valueChanged.connect(self.on_S_End_Angle) #connection SpinBox\n\n        self.DS_PlacementX = QtGui.QDoubleSpinBox(self.groupBox_02)\n        self.DS_PlacementX.setEnabled(False)\n        self.DS_PlacementX.setGeometry(QtCore.QRect(10, 240, 62, 22))\n        self.DS_PlacementX.setToolTip(_fromUtf8(\"Placement direction X\"))\n        self.DS_PlacementX.setSpecialValueText(_fromUtf8(\"\"))\n        self.DS_PlacementX.setMinimum(-9999999.0)\n        self.DS_PlacementX.setMaximum(9999999.99)\n        self.DS_PlacementX.setObjectName(_fromUtf8(\"DS_PlacementX\"))\n        self.DS_PlacementX.valueChanged.connect(self.on_DS_PlacementX) #connection doubleSpinBox\n\n        self.DS_PlacementY = QtGui.QDoubleSpinBox(self.groupBox_02)\n        self.DS_PlacementY.setEnabled(False)\n        self.DS_PlacementY.setGeometry(QtCore.QRect(85, 240, 62, 22))\n        self.DS_PlacementY.setToolTip(_fromUtf8(\"Placement direction Y\"))\n        self.DS_PlacementY.setSpecialValueText(_fromUtf8(\"\"))\n        self.DS_PlacementY.setMinimum(-9999999.0)\n        self.DS_PlacementY.setMaximum(9999999.99)\n        self.DS_PlacementY.setObjectName(_fromUtf8(\"DS_PlacementY\"))\n        self.DS_PlacementY.valueChanged.connect(self.on_DS_PlacementY) #connection doubleSpinBox\n\n        self.DS_PlacementZ = QtGui.QDoubleSpinBox(self.groupBox_02)\n        self.DS_PlacementZ.setEnabled(False)\n        self.DS_PlacementZ.setGeometry(QtCore.QRect(160, 240, 62, 22))\n        self.DS_PlacementZ.setToolTip(_fromUtf8(\"Placement direction Z\"))\n        self.DS_PlacementZ.setSpecialValueText(_fromUtf8(\"\"))\n        self.DS_PlacementZ.setMinimum(-9999999.0)\n        self.DS_PlacementZ.setMaximum(9999999.99)\n        self.DS_PlacementZ.setObjectName(_fromUtf8(\"DS_PlacementZ\"))\n        self.DS_PlacementZ.valueChanged.connect(self.on_DS_PlacementZ) #connection doubleSpinBox\n\n        self.CH_Sp_Placement = QtGui.QCheckBox(self.groupBox_02)\n        self.CH_Sp_Placement.setGeometry(QtCore.QRect(230, 240, 111, 20))\n        self.CH_Sp_Placement.setToolTip(_fromUtf8(\"Placement of character in the choice\"))\n        self.CH_Sp_Placement.setObjectName(_fromUtf8(\"CH_Sp_Placement\"))\n        self.CH_Sp_Placement.clicked.connect(self.on_CH_Sp_Placement) #connection checkBox\n\n        self.groupBox_05 = QtGui.QGroupBox(self.centralWidget)\n        self.groupBox_05.setEnabled(False)\n        self.groupBox_05.setGeometry(QtCore.QRect(10, 480, 351, 111))\n        self.groupBox_05.setAccessibleDescription(_fromUtf8(\"\"))\n        self.groupBox_05.setObjectName(_fromUtf8(\"groupBox_05\"))\n\n        self.PU_Roman = QtGui.QPushButton(self.groupBox_05)\n        self.PU_Roman.setGeometry(QtCore.QRect(250, 20, 93, 28))\n        self.PU_Roman.setAccessibleDescription(_fromUtf8(\"\"))\n        self.PU_Roman.setText(_fromUtf8(\"Mode Arabic\"))\n        self.PU_Roman.setObjectName(_fromUtf8(\"PU_Roman\"))\n        self.PU_Roman.clicked.connect(self.on_PU_Roman)\n\n        self.PU_Redress = QtGui.QPushButton(self.groupBox_05)\n        self.PU_Redress.setGeometry(QtCore.QRect(250, 50, 93, 28))\n        self.PU_Redress.setAccessibleDescription(_fromUtf8(\"\"))\n        self.PU_Redress.setText(_fromUtf8(\"Redress\"))\n        self.PU_Redress.setObjectName(_fromUtf8(\"PU_Redress\"))\n        self.PU_Redress.clicked.connect(self.on_PU_Redress)\n\n        self.S_Number_Faces_Support = QtGui.QSpinBox(self.groupBox_05)\n        self.S_Number_Faces_Support.setGeometry(QtCore.QRect(10, 50, 81, 22))\n        self.S_Number_Faces_Support.setToolTip(_fromUtf8(\"Number of side of the support 0=none, 1=circle, 2=rectangle, 3=triangle, 4=square, 5=pentagon . . . . (Thickness egal extrude)\"))\n        self.S_Number_Faces_Support.setAccessibleDescription(_fromUtf8(\"\"))\n        self.S_Number_Faces_Support.setMaximum(999)\n        self.S_Number_Faces_Support.setValue(nombreFaces)\n        self.S_Number_Faces_Support.setObjectName(_fromUtf8(\"S_Number_Faces_Support\"))\n        self.S_Number_Faces_Support.valueChanged.connect(self.on_S_Number_Faces_Support) #connection SpinBox\n\n        self.label_5 = QtGui.QLabel(self.groupBox_05)\n        self.label_5.setGeometry(QtCore.QRect(100, 50, 131, 16))\n        self.label_5.setAccessibleDescription(_fromUtf8(\"\"))\n        self.label_5.setText(_fromUtf8(\"Support number face\"))\n        self.label_5.setObjectName(_fromUtf8(\"label_5\"))\n\n        self.DS_Radius_Support = QtGui.QDoubleSpinBox(self.groupBox_05)\n        self.DS_Radius_Support.setGeometry(QtCore.QRect(10, 20, 81, 22))\n        self.DS_Radius_Support.setToolTip(_fromUtf8(\"Radius of the support the clock (By default : Radius of circle)\"))\n        self.DS_Radius_Support.setAccessibleDescription(_fromUtf8(\"\"))\n        self.DS_Radius_Support.setMaximum(99999999.99)\n        self.DS_Radius_Support.setValue(cercleClock)\n        self.DS_Radius_Support.setObjectName(_fromUtf8(\"DS_Radius_Support\"))\n        self.DS_Radius_Support.valueChanged.connect(self.on_DS_Radius_Support) #connection doubleSpinBox\n\n        self.label_11 = QtGui.QLabel(self.groupBox_05)\n        self.label_11.setGeometry(QtCore.QRect(100, 20, 121, 16))\n        self.label_11.setAccessibleDescription(_fromUtf8(\"\"))\n        self.label_11.setObjectName(_fromUtf8(\"label_11\"))\n\n        self.doubleSpinBox = QtGui.QDoubleSpinBox(self.groupBox_05)\n        self.doubleSpinBox.setGeometry(QtCore.QRect(10, 80, 81, 22))\n        self.doubleSpinBox.setObjectName(_fromUtf8(\"doubleSpinBox\"))\n\n        self.DS_Extrude_Support = QtGui.QDoubleSpinBox(self.groupBox_05)\n        self.DS_Extrude_Support.setGeometry(QtCore.QRect(10, 80, 81, 22))\n        self.DS_Extrude_Support.setToolTip(_fromUtf8(\"Thickness of the extrude the support. If thickness = 0 then don't extrude\"))\n        self.DS_Extrude_Support.setAccessibleDescription(_fromUtf8(\"\"))\n        self.DS_Extrude_Support.setMaximum(99999999.0)\n        self.DS_Extrude_Support.setEnabled(False)\n        self.DS_Extrude_Support.setValue(epaisSupp)\n        self.DS_Extrude_Support.setObjectName(_fromUtf8(\"DS_Extrude_Support\"))\n        self.DS_Extrude_Support.valueChanged.connect(self.on_DS_Extrude_Support) #connection doubleSpinBox\n\n        self.label_6 = QtGui.QLabel(self.groupBox_05)\n        self.label_6.setGeometry(QtCore.QRect(100, 80, 121, 16))\n        self.label_6.setObjectName(_fromUtf8(\"label_6\"))\n\n        self.groupBox_04 = QtGui.QGroupBox(self.centralWidget)\n        self.groupBox_04.setEnabled(False)\n        self.groupBox_04.setGeometry(QtCore.QRect(10, 400, 351, 81))\n        self.groupBox_04.setAccessibleDescription(_fromUtf8(\"\"))\n        self.groupBox_04.setLayoutDirection(QtCore.Qt.LeftToRight)\n        self.groupBox_04.setCheckable(False)\n        self.groupBox_04.setObjectName(_fromUtf8(\"groupBox_04\"))\n\n        self.DS_Base_Helix = QtGui.QDoubleSpinBox(self.groupBox_04)\n        self.DS_Base_Helix.setGeometry(QtCore.QRect(10, 50, 81, 22))\n        self.DS_Base_Helix.setToolTip(_fromUtf8(\"Base (beginning) of helix (to activate Step of Helix must be zero)\"))\n        self.DS_Base_Helix.setEnabled(False)\n        self.DS_Base_Helix.setAccessibleDescription(_fromUtf8(\"\"))\n        self.DS_Base_Helix.setMinimum(-99999999.0)\n        self.DS_Base_Helix.setMaximum(99999999.0)\n        self.DS_Base_Helix.setValue(baseHelix)\n        self.DS_Base_Helix.setObjectName(_fromUtf8(\"DS_Base_Helix\"))\n        self.DS_Base_Helix.valueChanged.connect(self.on_DS_Base_Helix) #connection doubleSpinBox\n\n        self.label = QtGui.QLabel(self.groupBox_04)\n        self.label.setGeometry(QtCore.QRect(270, 20, 91, 16))\n        self.label.setAccessibleDescription(_fromUtf8(\"\"))\n        self.label.setText(_fromUtf8(\"Char. per turn\"))\n        self.label.setObjectName(_fromUtf8(\"label\"))\n\n        self.DS_End_Helix = QtGui.QDoubleSpinBox(self.groupBox_04)\n        self.DS_End_Helix.setGeometry(QtCore.QRect(180, 50, 81, 22))\n        self.DS_End_Helix.setToolTip(_fromUtf8(\"Final height of the helix (to activate Step of Helix must be zero)\"))\n        self.DS_End_Helix.setEnabled(False)\n        self.DS_End_Helix.setAccessibleDescription(_fromUtf8(\"\"))\n        self.DS_End_Helix.setMinimum(-99999999.0)\n        self.DS_End_Helix.setMaximum(99999999.0)\n        self.DS_End_Helix.setValue(endHelix)\n        self.DS_End_Helix.setObjectName(_fromUtf8(\"DS_End_Helix\"))\n        self.DS_End_Helix.valueChanged.connect(self.on_DS_End_Helix) #connection doubleSpinBox\n\n        self.label_2 = QtGui.QLabel(self.groupBox_04)\n        self.label_2.setGeometry(QtCore.QRect(100, 50, 81, 16))\n        self.label_2.setAccessibleDescription(_fromUtf8(\"\"))\n        self.label_2.setText(_fromUtf8(\"Base Helix\"))\n        self.label_2.setObjectName(_fromUtf8(\"label_2\"))\n\n        self.label_3 = QtGui.QLabel(self.groupBox_04)\n        self.label_3.setGeometry(QtCore.QRect(270, 50, 61, 16))\n        self.label_3.setAccessibleDescription(_fromUtf8(\"\"))\n        self.label_3.setText(_fromUtf8(\"End Helix\"))\n        self.label_3.setObjectName(_fromUtf8(\"label_3\"))\n\n        self.DS_Number_Char_Per_Turn = QtGui.QSpinBox(self.groupBox_04)\n        self.DS_Number_Char_Per_Turn.setGeometry(QtCore.QRect(180, 20, 81, 22))\n        self.DS_Number_Char_Per_Turn.setToolTip(_fromUtf8(\"Number of characters for one turn of helix\"))\n        self.DS_Number_Char_Per_Turn.setAccessibleDescription(_fromUtf8(\"\"))\n        self.DS_Number_Char_Per_Turn.setMaximum(99999999)\n        self.DS_Number_Char_Per_Turn.setValue(nombreCarParTour)\n        self.DS_Number_Char_Per_Turn.setObjectName(_fromUtf8(\"DS_Number_Char_Per_Turn\"))\n        self.DS_Number_Char_Per_Turn.valueChanged.connect(self.on_DS_Number_Char_Per_Turn) #connection doubleSpinBox\n\n        self.DS_Step_Of_The_Helix = QtGui.QDoubleSpinBox(self.groupBox_04)\n        self.DS_Step_Of_The_Helix.setGeometry(QtCore.QRect(10, 20, 81, 22))\n        self.DS_Step_Of_The_Helix.setToolTip(_fromUtf8(\"Step of the text along the helix (min Size Character)\"))\n        self.DS_Step_Of_The_Helix.setAccessibleDescription(_fromUtf8(\"\"))\n        self.DS_Step_Of_The_Helix.setMaximum(99999999.99)\n        self.DS_Step_Of_The_Helix.setValue(pasHelix)\n\n        self.DS_Step_Of_The_Helix.setObjectName(_fromUtf8(\"DS_Step_Of_The_Helix\"))\n        self.DS_Step_Of_The_Helix.valueChanged.connect(self.on_DS_Step_Of_The_Helix) #connection doubleSpinBox\n\n        self.label_12 = QtGui.QLabel(self.groupBox_04)\n        self.label_12.setGeometry(QtCore.QRect(100, 20, 81, 16))\n        self.label_12.setAccessibleDescription(_fromUtf8(\"\"))\n        self.label_12.setObjectName(_fromUtf8(\"label_12\"))\n\n        self.PU_Exit = QtGui.QPushButton(self.centralWidget)\n        self.PU_Exit.setGeometry(QtCore.QRect(10, 600, 81, 28))\n        self.PU_Exit.setAccessibleDescription(_fromUtf8(\"\"))\n        self.PU_Exit.setText(_fromUtf8(\"Exit\"))\n        self.PU_Exit.setObjectName(_fromUtf8(\"PU_Exit\"))\n        self.PU_Exit.clicked.connect(self.on_PU_Exit)\n\n        self.PU_Execute = QtGui.QPushButton(self.centralWidget)\n        self.PU_Execute.setGeometry(QtCore.QRect(280, 600, 81, 28))\n        self.PU_Execute.setAccessibleDescription(_fromUtf8(\"\"))\n        self.PU_Execute.setText(_fromUtf8(\"Run\"))\n        self.PU_Execute.setToolTip(\"Execute the process\") # without Compount\n        self.PU_Execute.setObjectName(_fromUtf8(\"PU_Execute\"))\n        self.PU_Execute.clicked.connect(self.on_PU_Execute)\n\n        self.PU_Reset = QtGui.QPushButton(self.centralWidget)\n        self.PU_Reset.setGeometry(QtCore.QRect(100, 600, 81, 28))\n        self.PU_Reset.setToolTip(_fromUtf8(\"Reset the macro and give the number of the characters of windows Textedit\"))\n        self.PU_Reset.setAccessibleDescription(_fromUtf8(\"\"))\n        self.PU_Reset.setEnabled(True)\n        self.PU_Reset.setObjectName(_fromUtf8(\"PU_Reset\"))\n        self.PU_Reset.clicked.connect(self.on_PU_Reset)\n\n        self.groupBox_01 = QtGui.QGroupBox(self.centralWidget)\n        self.groupBox_01.setGeometry(QtCore.QRect(10, 0, 351, 101))\n        self.groupBox_01.setAccessibleDescription(_fromUtf8(\"\"))\n        self.groupBox_01.setObjectName(_fromUtf8(\"groupBox_01\"))\n\n        self.lineEdit = QtGui.QLineEdit(self.groupBox_01)\n        self.lineEdit.setGeometry(QtCore.QRect(10, 70, 211, 22))\n        self.lineEdit.setObjectName(_fromUtf8(\"lineEdit\"))\n        self.lineEdit.setText(PolicePath)\n\n        self.textEdit = QtGui.QTextEdit(self.groupBox_01)\n        self.textEdit.setGeometry(QtCore.QRect(10, 20, 331, 41))\n        self.textEdit.setObjectName(_fromUtf8(\"textEdit\"))\n        self.textEdit.setText(texte)\n\n        self.PU_New_Font = QtGui.QPushButton(self.groupBox_01)\n        self.PU_New_Font.setGeometry(QtCore.QRect(230, 70, 111, 21))\n        self.PU_New_Font.setToolTip(_fromUtf8(\"Search your new font\"))\n        self.PU_New_Font.setAccessibleDescription(_fromUtf8(\"\"))\n        self.PU_New_Font.setText(_fromUtf8(\"New Font\"))\n        self.PU_New_Font.setObjectName(_fromUtf8(\"PU_New_Font\"))\n        self.PU_New_Font.clicked.connect(self.on_PU_New_Font)\n\n        self.PU_Benchmarks = QtGui.QPushButton(self.centralWidget)\n        self.PU_Benchmarks.setGeometry(QtCore.QRect(190, 600, 81, 28))\n        self.PU_Benchmarks.setToolTip(_fromUtf8(\"Execute the process and one Compount of the characters is create\"))\n#        self.PU_Benchmarks.setEnabled(True)\n        self.PU_Benchmarks.setText(\"Run Comp\")\n        self.PU_Benchmarks.setObjectName(_fromUtf8(\"PU_Benchmarks\"))\n        self.PU_Benchmarks.clicked.connect(self.on_PU_Benchmarks)\n\n        MainWindow.setCentralWidget(self.centralWidget)\n\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n        try:\n            MainWindow.setWindowFlags(PyQt4.QtCore.Qt.WindowStaysOnTopHint)        # PyQt4 cette fonction met la fenetre en avant\n        except Exception:\n            MainWindow.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint)       # PySide cette fonction met la fenetre en avant\n        MainWindow.setWindowTitle(\"FCCircularText\")\n        self.groupBox_02.setTitle(\"Configuration FCCircularText Character\")\n        self.label_10.setText(\"Radius of circle\")\n        self.groupBox_03.setTitle(\"Choice\")\n        self.RA_Choice_Outdoor.setToolTip(\"Create the text on the outer face of the cylinder\")\n        self.RA_Choice_Outdoor.setText(\"Outdoor\")\n        self.RA_Choice_Indoor.setToolTip(\"Create the text on the inside of the cylinder\")\n        self.RA_Choice_Indoor.setText(\"Indoor\")\n        self.RA_Choice_Helix.setToolTip(\"Create the text in a helix\")\n        self.RA_Choice_Helix.setText(\"Helix\")\n        self.RA_Choice_Clock.setToolTip(\"Create the text to form a clock\")\n        self.RA_Choice_Clock.setText(\"Clock\")\n        self.label_13.setText(\"Begin angle\")\n        self.label_14.setText(\"End angle\")\n        self.CH_Extrude.setText(\"Extrude Char.\")\n        self.DS_InclinaisonX.setSuffix(unicode(\" \u00c2\u00b0\"))\n        self.DS_InclinaisonY.setSuffix(unicode(\" \u00c2\u00b0\"))\n        self.DS_InclinaisonZ.setSuffix(unicode(\" \u00c2\u00b0\"))\n        self.DS_PlacementX.setSuffix(\" X\")\n        self.DS_PlacementY.setSuffix(\" Y\")\n        self.DS_PlacementZ.setSuffix(\" Z\")\n        self.CH_Sp_Placement.setText(\"Placement\")\n        self.groupBox_05.setTitle(\"Clock\")\n        self.PU_Roman.setToolTip(\"The characters is in Roman or Arabic (default)\")\n        self.PU_Redress.setToolTip(\"The numbers is straight or tangent of the circle\")\n        self.label_11.setText(\"Radius of support\")\n        self.label_6.setText(\"Extrude support\")\n        self.groupBox_04.setTitle(\"Helix\")\n        self.label_12.setText(\"Step of Helix\")\n        self.PU_Exit.setToolTip(\"Exit FCCircularText\")\n        self.PU_Reset.setText(\"Reset\")\n        self.groupBox_01.setTitle(\"Text to be displayed  ( \"+str(len(texte))+\" characters )\")\n        self.lineEdit.setToolTip(\"Font to default\")\n        self.lineEdit.setText(PolicePath)\n        self.textEdit.setToolTip(\"Your text to be displayed\")\n        self.textEdit.setHtml(texte)\n\n##############################################################################\n\n    def on_PU_New_Font(self):         # New Font\n        global PolicePath\n        OpenName = \"\"\n        try:\n            OpenName = QFileDialog.getOpenFileName(None,QString.fromLocal8Bit(\"New Font\"),PolicePath,\"*.ttf\") # PyQt4\n        except Exception:\n            OpenName, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, \"New Font\", PolicePath, \"*.ttf\")#PySide\n        try:\n            if OpenName != \"\":\n                PolicePath = OpenName\n                self.lineEdit.setText(PolicePath)\n        except Exception:\n            None\n        App.Console.PrintMessage(\"New Font \" + (PolicePath)+\"\\n\")\n\n    def on_PU_Reset_Placement(self):           # Reset_Placement\n        global PlacementX\n        global PlacementY\n        global PlacementZ\n        global coor_X\n        global coor_Y\n        global coor_Z\n        coor_X = coor_Y = coor_Z = 0.0\n        PlacementX = PlacementY = PlacementZ = 0.0\n        self.CH_Sp_Placement.setChecked(False)\n        self.DS_PlacementX.setValue(PlacementX)\n        self.DS_PlacementX.setEnabled(False)\n        self.DS_PlacementY.setValue(PlacementY)\n        self.DS_PlacementY.setEnabled(False)\n        self.DS_PlacementZ.setValue(PlacementZ)\n        self.DS_PlacementZ.setEnabled(False)\n#        App.Console.PrintMessage(str(\"on_PU_Reset_Placement \")+\"\\n\")\n\n    def on_PU_Reset_Inclination(self):           # Reset_Inclination\n        global inclinaisonX\n        global inclinaisonY\n        global inclinaisonZ\n        inclinaisonX = inclinaisonY = inclinaisonZ = 0.0\n        self.CH_Sp_Inclination.setChecked(False)\n        self.DS_InclinaisonX.setValue(inclinaisonX)\n        self.DS_InclinaisonX.setEnabled(False)\n        self.DS_InclinaisonY.setValue(inclinaisonY)\n        self.DS_InclinaisonY.setEnabled(False)\n        self.DS_InclinaisonZ.setValue(inclinaisonZ)\n        self.DS_InclinaisonZ.setEnabled(False)\n#        App.Console.PrintMessage(str(\"on_PU_Reset_Inclination \")+\"\\n\")\n\n    def on_RA_Choice_Outdoor(self):           #\n        global exterieur\n        global extrusion\n        global epaisseur\n\n        extrusion = 0\n        epaisseur = 0.0\n        self.DS_Extrude.setValue(epaisseur)\n        self.CH_Extrude.setChecked(False)\n        self.DS_Extrude.setEnabled(False)\n        exterieur = 1\n        self.S_Begin_Angle.setEnabled(True)\n        self.S_End_Angle.setEnabled(True)\n        self.DS_Correction_Radius.setEnabled(True)\n        self.DS_Correction_Angle.setEnabled(True)\n        self.PU_Flat.setEnabled(True)\n        self.groupBox_04.setEnabled(False)\n        self.groupBox_05.setEnabled(False)\n        ff2 = ui\n        ff2.on_PU_Reset_Placement()\n        ff3 = ui\n        ff3.on_PU_Reset_Inclination()\n#        App.Console.PrintMessage(str(\"on_RA_Choice_Outdoor \")+\" \"+str(exterieur)+\"\\n\")\n\n    def on_RA_Choice_Indoor(self):          #\n        global exterieur\n        global extrusion\n        global epaisseur\n\n        extrusion = 0\n        epaisseur = 0.0\n        self.DS_Extrude.setValue(epaisseur)\n        self.CH_Extrude.setChecked(False)\n        self.DS_Extrude.setEnabled(False)\n        exterieur = 0\n        self.S_Begin_Angle.setEnabled(True)\n        self.S_End_Angle.setEnabled(True)\n        self.DS_Correction_Radius.setEnabled(True)\n        self.DS_Correction_Angle.setEnabled(True)\n        self.PU_Flat.setEnabled(True)\n        self.groupBox_04.setEnabled(False)\n        self.groupBox_05.setEnabled(False)\n        ff2 = ui\n        ff2.on_PU_Reset_Placement()\n        ff3 = ui\n        ff3.on_PU_Reset_Inclination()\n#        App.Console.PrintMessage(str(\"on_RA_Choice_Indoor \")+\" \"+str(exterieur)+\"\\n\")\n\n    def on_RA_Choice_Helix(self):              #\n        global exterieur\n        global cercleClock\n        global nombreFaces\n        global debout\n        global extrusion\n        global epaisseur\n\n        extrusion = 0\n        epaisseur = 0.0\n        self.DS_Extrude.setValue(epaisseur)\n        self.CH_Extrude.setChecked(False)\n        self.DS_Extrude.setEnabled(False)\n        exterieur = 2\n        cercleClock = 0\n        nombreFaces = 0\n        debout = 1\n\n        self.RA_Choice_Outdoor.setText(\"Outdoor\")\n        self.RA_Choice_Indoor.setText(\"Indoor\")\n        self.PU_Flat.setText(_fromUtf8(\"Mode Stand\"))\n\n        self.S_Begin_Angle.setEnabled(True)\n        self.S_End_Angle.setEnabled(True)\n        self.DS_Correction_Radius.setEnabled(True)\n        self.DS_Correction_Angle.setEnabled(True)\n        self.PU_Flat.setEnabled(False)##\n        self.groupBox_04.setEnabled(True)\n        self.groupBox_05.setEnabled(False)\n\n        ff2 = ui\n        ff2.on_PU_Reset_Placement()\n        ff3 = ui\n        ff3.on_PU_Reset_Inclination()\n\n    def on_RA_Choice_Clock(self):              #\n        global exterieur\n        global debout\n        global correctionRayon\n        global correctionAngle\n        global extrusion\n        global epaisseur\n\n        extrusion = 0\n        epaisseur = 0.0\n        self.DS_Extrude.setValue(epaisseur)\n        self.CH_Extrude.setChecked(False)\n        self.DS_Extrude.setEnabled(False)\n        exterieur = 3\n        debout = 0\n        self.PU_Flat.setEnabled(False)\n        self.S_Begin_Angle.setEnabled(False)\n        self.S_End_Angle.setEnabled(False)\n#        correctionRayon = 0\n        self.DS_Correction_Radius.setEnabled(False)\n        self.DS_Correction_Radius.setValue(0.0)\n#        correctionAngle = 10.0\n        self.DS_Correction_Angle.setEnabled(False)\n        self.DS_Correction_Angle.setValue(0.0)\n        self.groupBox_04.setEnabled(False)\n        self.groupBox_05.setEnabled(True)\n        ff2 = ui\n        ff2.on_PU_Reset_Placement()\n        ff3 = ui\n        ff3.on_PU_Reset_Inclination()\n#        App.Console.PrintMessage(str(\"on_RA_Choice_Clock \")+str(exterieur)+\"\\n\")\n\n    def on_PU_Flat(self):         # Flat or Stand\n        global debout\n        if debout == 1:\n            debout = 0\n            self.RA_Choice_Outdoor.setText(\"Indoor\")\n            self.RA_Choice_Indoor.setText(\"Outdoor\")\n            self.PU_Flat.setText(_fromUtf8(\"Mode Flat\"))\n            self.PU_Flat.setToolTip(_fromUtf8(\"Click to create the text Stand\"))\n        else:\n            debout = 1\n            self.RA_Choice_Outdoor.setText(\"Outdoor\")\n            self.RA_Choice_Indoor.setText(\"Indoor\")\n            self.PU_Flat.setText(_fromUtf8(\"Mode Stand\"))\n            self.PU_Flat.setToolTip(_fromUtf8(\"Click to create the text Flat\"))\n#        App.Console.PrintMessage(str(\"on_PU_Flat \")+str(debout)+\"\\n\")\n\n    def on_DS_Radius_Circle(self,value):\n        global rayon\n        global cercleClock\n        rayon = value\n        cercleClock = rayon\n#        App.Console.PrintMessage(\"on_DS_Radius_Circle Radius\"+str(rayon)+\"\\n\")\n\n    def on_DS_Size_Character(self,value):\n        global SizeCaractere\n        SizeCaractere = value\n#        App.Console.PrintMessage(\"on_DS_Size_Character Size\"+str(SizeCaractere)+\"\\n\")\n\n    def on_S_Begin_Angle(self,value):          #\n        global debut\n        debut = value\n#        App.Console.PrintMessage(str(\"on_S_Begin_Angle \")+str(debut)+\"\\n\")\n\n    def on_S_End_Angle(self,value):            #\n        global rotation\n        rotation = value\n#        App.Console.PrintMessage(str(\"on_S_End_Angle \")+str(rotation)+\"\\n\")\n\n    def on_DS_PlacementX(self,value):          #\n        global PlacementX\n        PlacementX = value\n#        App.Console.PrintMessage(str(\"on_DS_PlacementX \")+str(PlacementX)+\"\\n\")\n\n    def on_DS_PlacementY(self,value):          #\n        global PlacementY\n        PlacementY = value\n#        App.Console.PrintMessage(str(\"on_DS_PlacementY \")+str(PlacementY)+\"\\n\")\n\n    def on_DS_PlacementZ(self,value):          #\n        global PlacementZ\n        PlacementZ = value\n#        App.Console.PrintMessage(str(\"on_DS_PlacementZ \")+str(PlacementZ)+\"\\n\")\n\n    def on_CH_Sp_Placement(self):              # Placement or not Placement\n        if self.CH_Sp_Placement.isChecked():\n            self.DS_PlacementX.setEnabled(True)\n            self.DS_PlacementY.setEnabled(True)\n            self.DS_PlacementZ.setEnabled(True)\n#            App.Console.PrintMessage(str(\"on_CH_Sp_Placement \")+str(\"True\")+\"\\n\")\n        else:\n            ff2 = ui\n            ff2.on_PU_Reset_Placement()\n        if self.RA_Choice_Clock.isChecked():\n            self.DS_PlacementX.setEnabled(False)\n            self.DS_PlacementY.setEnabled(False)\n#            App.Console.PrintMessage(str(\"on_CH_Sp_Placement \")+str(\"False\")+\"\\n\")\n\n    def on_DS_Correction_Angle(self,value):    #\n        global correctionAngle\n        correctionAngle = value\n#        App.Console.PrintMessage(str(\"on_DS_Correction_Angle \")+str(correctionAngle)+\"\\n\")\n\n    def on_DS_Correction_Radius(self,value):   #\n        global correctionRayon\n        correctionRayon = value\n#        App.Console.PrintMessage(str(\"on_DS_Correction_Radius \")+str(correctionRayon)+\"\\n\")\n\n    def on_DS_Extrude(self,value):             #\n        global epaisseur\n        epaisseur = value\n#        App.Console.PrintMessage(\"on_DS_Extrude \"+str(epaisseur)+\"\\n\")\n\n    def on_CH_Extrude(self):                   #\n        global extrusion\n        global epaisseur\n        if self.CH_Extrude.isChecked():\n            self.DS_Extrude.setEnabled(True)\n            extrusion = 1\n            epaisseur = 1.0\n        else:\n            self.DS_Extrude.setEnabled(False)\n            extrusion = 0\n            epaisseur = 0.0\n        self.DS_Extrude.setValue(epaisseur)\n#        App.Console.PrintMessage(str(\"on_CH_Extrude \")+str(extrusion)+\" \"+str(epaisseur)+\"\\n\")\n\n    def on_DS_InclinaisonX(self,value):        #\n        global inclinaisonX\n        inclinaisonX = value\n#        App.Console.PrintMessage(str(\"on_DS_InclinaisonX \")+str(inclinaisonX)+\"\\n\")\n\n    def on_DS_InclinaisonY(self,value):        #\n        global inclinaisonY\n        inclinaisonY = value\n#        App.Console.PrintMessage(str(\"on_DS_InclinaisonY \")+str(inclinaisonY)+\"\\n\")\n\n    def on_DS_InclinaisonZ(self,value):        #\n        global inclinaisonZ\n        inclinaisonZ = value\n#        App.Console.PrintMessage(str(\"on_DS_InclinaisonZ \")+str(inclinaisonZ)+\"\\n\")\n\n    def on_CH_Sp_Inclination(self):            #\n        if self.CH_Sp_Inclination.isChecked():\n            self.DS_InclinaisonX.setEnabled(True)\n            self.DS_InclinaisonY.setEnabled(True)\n            self.DS_InclinaisonZ.setEnabled(True)\n        else:\n            ff3 = ui\n            ff3.on_PU_Reset_Inclination()\n#        App.Console.PrintMessage(str(\"on_CH_Sp_Inclination \")+str(self.CH_Sp_Inclination.isChecked())+\"\\n\")\n\n    def on_DS_Step_Of_The_Helix(self,value):   #\n        global pasHelix\n        global baseHelix\n        global endHelix\n        pasHelix = value\n        if pasHelix == 0:\n            baseHelix = endHelix = 0.0\n            self.DS_Base_Helix.setValue(baseHelix)\n            self.DS_Base_Helix.setEnabled(True)\n            self.DS_End_Helix.setValue(endHelix)\n            self.DS_End_Helix.setEnabled(True)\n        else:\n            baseHelix = endHelix = 0.0\n            self.DS_Base_Helix.setValue(baseHelix)\n            self.DS_Base_Helix.setEnabled(False)\n            self.DS_End_Helix.setValue(endHelix)\n            self.DS_End_Helix.setEnabled(False)\n#        App.Console.PrintMessage(str(\"on_DS_Step_Of_The_Helix \")+str(SizeCaractere)+\"\\n\")\n\n    def on_DS_Number_Char_Per_Turn(self,value):#\n        global nombreCarParTour\n        nombreCarParTour = value\n#        App.Console.PrintMessage(str(\"on_DS_Number_Char_Per_Turn \")+str(nombreCarParTour)+\"\\n\")\n\n    def on_DS_Base_Helix(self,value):          #\n        global baseHelix\n        baseHelix = value\n#        App.Console.PrintMessage(str(\"on_DS_Base_Helix \")+str(baseHelix)+\"\\n\")\n\n    def on_DS_End_Helix(self,value):           #\n        global endHelix\n        endHelix = value\n#        App.Console.PrintMessage(str(\"on_DS_End_Helix \")+str(endHelix)+\"\\n\")\n\n    def on_DS_Radius_Support(self,value):      #\n        global cercleClock\n        cercleClock = value\n#        App.Console.PrintMessage(str(\"on_DS_Radius_Support \")+str(cercleClock)+\"\\n\")\n\n    def on_S_Number_Faces_Support(self,value): # number Faces of support 0=none 1=circle 2=rectangle 3=triangle 4,5 ... polygon\n        global nombreFaces\n        nombreFaces = value\n        self.DS_Extrude_Support.setEnabled(True)\n        if nombreFaces == 0:\n            self.label_5.setText(_fromUtf8(\"Support number face\"))\n            self.DS_Extrude_Support.setEnabled(False)\n        elif nombreFaces == 1:\n            self.label_5.setText(_fromUtf8(\"Support Circle\"))\n        elif nombreFaces == 2:\n            self.label_5.setText(_fromUtf8(\"Support Rectangle\"))\n        elif nombreFaces == 3:\n            self.label_5.setText(_fromUtf8(\"Support Triangle\"))\n        elif nombreFaces == 4:\n            self.label_5.setText(_fromUtf8(\"Support Square\"))\n        else :\n            self.label_5.setText(_fromUtf8(\"Support Polygone\"))\n#        App.Console.PrintMessage(str(\"on_S_Number_Faces_Support \")+str(nombreFaces)+\"\\n\")\n\n    def on_DS_Extrude_Support(self,value):     #\n        global epaisSupp\n        epaisSupp = value\n        self.DS_PlacementZ.setEnabled(True)\n#        App.Console.PrintMessage(str(\"on_DS_Extrude_Support \")+str(epaisSupp)+\"\\n\")\n\n    def on_PU_Roman(self):                     # Roman or Arabic Clock\n        global romain\n        if romain == 1:\n            romain = 0\n            self.PU_Roman.setText(_fromUtf8(\"Mode Arabic\"))\n            self.PU_Roman.setToolTip(_fromUtf8(\"Click to activate Roman mode\"))\n        else:\n            romain = 1\n            self.PU_Roman.setText(_fromUtf8(\"Mode Roman\"))\n            self.PU_Roman.setToolTip(_fromUtf8(\"Click to activate Arabic mode\"))\n#        App.Console.PrintMessage(str(\"romain \")+str(romain)+\"\\n\")\n\n    def on_PU_Redress(self):                   # Redress or circumferential Clock\n        global redressement\n        if redressement == 1:\n            redressement = 0\n            self.PU_Redress.setText(_fromUtf8(\"Redress\"))\n            self.PU_Redress.setToolTip(_fromUtf8(\"Click to activate Axial mode\"))\n        else:\n            redressement = 1\n            self.PU_Redress.setText(_fromUtf8(\"Axial\"))\n            self.PU_Redress.setToolTip(_fromUtf8(\"Click to activate Redress mode\"))\n#        App.Console.PrintMessage(str(\"redressement \")+str(redressement)+\"\\n\")\n\n    def on_PU_Exit(self):                      # Exit\n        App.Console.PrintMessage(\"Fin FCCircularText\"+\"\\n\")\n        self.window.hide()\n\n    def on_PU_Reset(self):                     #\n        global points\n        global coor_X\n        global coor_Y\n        global coor_Z\n        global vec\n\n        global PolicePath\n\n        global rayon\n        global texte\n        global debut\n        global rotation\n        global SizeCaractere\n\n        global precision\n        global correctionAngle\n        global correctionRayon\n        global debout\n        global exterieur\n        global baseHelix\n        global endHelix\n        global pasHelix\n        global nombreCarParTour\n\n        global PlacementX\n        global PlacementY\n        global PlacementZ\n\n        global inclinaisonX\n        global inclinaisonY\n        global inclinaisonZ\n\n        global cercleClock\n        global nombreFaces\n        global romain\n        global redressement\n\n        global comP\n        global nameL\n        global epaisseur\n        global epaisSupp\n        global extrusion\n        global compount1\n\n        texte = \"\"\n\n        exterieur = 1\n        self.RA_Choice_Outdoor.setText(\"Outdoor\")\n        self.RA_Choice_Indoor.setText(\"Indoor\")\n        self.RA_Choice_Outdoor.setChecked(True)\n\n        debout = 1\n        self.PU_Flat.setText(_fromUtf8(\"Mode Stand\"))\n        self.PU_Flat.setToolTip(_fromUtf8(\"Click to create the Flat text\"))\n\n        SizeCaractere = 2.0\n        self.DS_Size_Character.setValue(SizeCaractere)\n        rayon = 10.0\n        self.DS_Radius_Circle.setValue(rayon)\n\n        debut = 0\n        self.S_Begin_Angle.setValue(debut)\n        self.S_Begin_Angle.setEnabled(True)\n        rotation = 360\n        self.S_End_Angle.setValue(rotation)\n        self.S_End_Angle.setEnabled(True)\n\n        correctionAngle = 10.0\n        self.DS_Correction_Angle.setValue(correctionAngle)\n        self.DS_Correction_Radius.setEnabled(True)\n        correctionRayon = 0.15\n        self.DS_Correction_Radius.setValue(correctionRayon)\n        self.DS_Correction_Angle.setEnabled(True)\n\n        extrusion = 0\n        epaisseur = 0.0\n        self.DS_Extrude.setValue(epaisseur)\n        self.CH_Extrude.setChecked(False)\n        self.DS_Extrude.setEnabled(False)\n\n        ff2 = ui\n        ff2.on_PU_Reset_Placement()\n        ff3 = ui\n        ff3.on_PU_Reset_Inclination()\n\n        self.groupBox_04.setEnabled(False)\n        baseHelix = 0.0\n        self.DS_Base_Helix.setValue(baseHelix)\n        self.DS_Base_Helix.setEnabled(False)\n        endHelix = 0.0\n        self.DS_End_Helix.setValue(endHelix)\n        self.DS_Base_Helix.setEnabled(False)\n        pasHelix = 2.0\n        self.DS_Step_Of_The_Helix.setValue(pasHelix)\n        nombreCarParTour = 10\n        self.DS_Number_Char_Per_Turn.setValue(nombreCarParTour)\n\n        self.groupBox_05.setEnabled(False)\n        cercleClock = rayon\n        self.DS_Radius_Support.setValue(cercleClock)\n        nombreFaces = 0\n        self.S_Number_Faces_Support.setValue(nombreFaces)\n        self.label_5.setText(_fromUtf8(\"Support number face\"))\n        epaisSupp   = 0.0\n        self.DS_Extrude_Support.setEnabled(False)\n        self.DS_Extrude_Support.setValue(epaisSupp)\n\n        romain = 0\n        self.PU_Roman.setText(_fromUtf8(\"Mode Arabic\"))\n        self.PU_Roman.setToolTip(_fromUtf8(\"Click to activate Roman mode\"))\n        redressement = 0\n        self.PU_Redress.setText(_fromUtf8(\"Redress\"))\n        self.PU_Redress.setToolTip(_fromUtf8(\"Click to activate Axial mode\"))\n\n        compount1 = 0\n\n        ##### update the setTitle ########################################\n\n        texte = unicode(self.textEdit.toPlainText())\n        self.groupBox_01.setTitle(\"Text to be displayed  ( \"+str(len(texte))+\" characters )\")\n#        App.Console.PrintMessage(str(\"on_PU_Reset \")+str()+\"\\n\")\n\n    def on_PU_Benchmarks(self):                # Benchmarks\n      try:\n        global compount1\n        compount1 = 1\n        ff = ui\n        ff.on_PU_Execute()\n#        App.Console.PrintMessage(str(\"Benchmarks\")+\"\\n\")\n      except:\n        sayexc(\"Error\")\n\n    ##########################################################################\n\n    def on_PU_Execute(self):         # Execute\n        global PolicePath\n\n        global points\n        global coor_X\n        global coor_Y\n        global coor_Z\n\n        global PlacementX\n        global PlacementY\n        global PlacementZ\n\n        global inclinaisonX\n        global inclinaisonY\n        global inclinaisonZ\n\n        global vec\n        global PolicePath\n        global rayon\n        global texte\n        global debut\n        global rotation\n        global SizeCaractere\n\n        global ii\n        global precision\n        global correctionAngle\n        global correctionRayon\n        global debout\n        global exterieur\n        global baseHelix\n        global endHelix\n        global pasHelix\n        global nombreCarParTour\n\n        global cercleClock\n        global nombreFaces\n        global romain\n        global redressement\n\n        global comP\n        global nameL\n\n        global epaisseur\n        global epaisSupp\n        global extrusion\n        global compount1\n\n        points   = []\n        comP     = []\n        nameL    = []\n\n        del   points[:]\n        del     comP[:]\n        del    nameL[:]\n\n        doc = FreeCAD.ActiveDocument\n        if doc == None:\n            doc = FreeCAD.newDocument()\n\n        texte = unicode(self.textEdit.toPlainText())\n        self.groupBox_01.setTitle(\"Text to be displayed  ( \"+str(len(texte))+\" characters )\")\n\n        if ((exterieur == 0) and (debout == 0)):\n            vecligne=[FreeCAD.Vector(PlacementX,PlacementY,PlacementZ),FreeCAD.Vector(rayon + correctionRayon,0.0,0.0)]      #\n        else:\n            if exterieur == 3:\n                vecligne=[FreeCAD.Vector(PlacementX,PlacementY,PlacementZ),FreeCAD.Vector(rayon - (SizeCaractere/2),0.0,0.0)]      #\n            elif debout == 0:\n                vecligne=[FreeCAD.Vector(PlacementX,PlacementY,PlacementZ),FreeCAD.Vector(rayon + correctionRayon - SizeCaractere,0.0,0.0)]      #\n            else:\n                vecligne=[FreeCAD.Vector(PlacementX,PlacementY,PlacementZ),FreeCAD.Vector(rayon + correctionRayon,0.0,0.0)]      #\n\n        ligne = Draft.makeWire(vecligne,closed=False,face=False,support=None)     # creation de la ligne de base\n        lineName = ligne.Name\n\n        ii  = -1\n        ii2 = -1\n\n        nombre = len(texte)\n        coor_Z = PlacementZ\n\n        if (exterieur == 0) or (debout == 0):\n            texte = texte[::-1]\n            if (exterieur == 0) and (debout == 0):\n                texte = texte[::-1]\n\n        depart = time.clock()     # chrono begin\n\n        if exterieur == 2:        # helix\n            if nombreCarParTour == 0:\n                nombreCarParTour = 1\n                App.Console.PrintError(\"Insufficient number\"+\"\\n\")\n            pas = 0.0\n            nombre = nombreCarParTour\n            if pasHelix != 0:\n                pas = pasHelix / (nombreCarParTour)\n            else:\n                pas = ((((endHelix - SizeCaractere)-baseHelix)/(len(texte) / nombreCarParTour))/(nombreCarParTour)) # pas of helix\n                coor_Z += baseHelix\n        else:\n            nombreCarParTour = 1\n\n        if exterieur == 3:         # Clock\n            FcString = doc.addObject(\"App::DocumentObjectGroup\",\"FcClock\")\n            nombre = 12\n            if romain == 0:\n                texte = [\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"10\",\"11\",\"12\"]\n            else:\n                texte = [\"I\",\"II\",\"III\",\"IIII\",\"V\",\"VI\",\"VII\",\"VIII\",\"IX\",\"X\",\"XI\",\"XII\"]\n            texte = texte[::-1]\n        else:\n            FcString = doc.addObject(\"App::DocumentObjectGroup\",\"FcString\")\n\n        ####Boucle principale############################################################################\n        boucler = len(texte) / nombreCarParTour\n\n        if (len(texte) % nombreCarParTour) != 0: # calcul number spires Helix\n            boucler += 1\n\n        for hel in range(boucler):\n            ii = -1\n            ####Boucle de travail#################################################\n            for angleTr in range(debut,rotation,((rotation-debut)/nombre)):\n                ii  += 1\n                ii2 += 1\n                ligne.Placement = App.Placement(App.Vector(PlacementX,PlacementY,PlacementZ), App.Rotation(App.Vector(0,0,1),angleTr), App.Vector(0,0,0))\n                a = ligne.Shape.Edges[0].Vertexes[1] # fin de ligne\n\n                coor_X = (a.Point.x)\n                coor_Y = (a.Point.y)\n\n                if (ii < nombre) and (ii2 < len(texte)):\n                    if exterieur == 3:                  # clock\n                        ligne.Placement = App.Placement(App.Vector(PlacementX,PlacementY,PlacementZ), App.Rotation(App.Vector(0,0,1),angleTr+90), App.Vector(0,0,0))\n                        a = ligne.Shape.Edges[0].Vertexes[1] # fin\n                        coor_X = (a.Point.x)\n                        coor_Y = (a.Point.y)\n                    ss=Draft.makeShapeString(String=unicode(texte[ii2]),FontFile=PolicePath,Size=SizeCaractere,Tracking=0)\n\n                    FcString.addObject(ss)  # container character\n\n                    centreX = (ss.Shape.BoundBox.Center[0])\n                    centreY = (ss.Shape.BoundBox.Center[1])\n                    centreZ = (ss.Shape.BoundBox.Center[2])\n                    lengthX = (ss.Shape.BoundBox.XLength)\n                    lengthY = (ss.Shape.BoundBox.YLength)\n                    lengthZ = (ss.Shape.BoundBox.ZLength)\n\n                    coor_X = coor_X + PlacementX\n                    coor_Y = coor_Y + PlacementY\n\n                    plm=\"\"\n                    plm=FreeCAD.Placement()\n                    plm.Base=FreeCAD.Vector(coor_X,coor_Y,coor_Z)\n\n                    if debout == 1:           # debout\n                        if exterieur == 0:    # circumferential internal\n                            plm = App.Placement(App.Vector(coor_X,coor_Y,coor_Z), App.Rotation(angleTr-90-correctionAngle+inclinaisonX,inclinaisonY,90+inclinaisonZ), App.Vector(0,0,0)) # pitch,roll...1\n                        elif exterieur == 1:  # circumferential external\n                            plm = App.Placement(App.Vector(coor_X,coor_Y,coor_Z), App.Rotation(angleTr+90+correctionAngle+inclinaisonX,inclinaisonY,90+inclinaisonZ), App.Vector(0,0,0)) # pitch,roll...1\n                        elif exterieur == 2:  # circumferential helix\n                            plm = App.Placement(App.Vector(coor_X,coor_Y,coor_Z), App.Rotation(angleTr+90+correctionAngle+inclinaisonX,inclinaisonY,90+inclinaisonZ), App.Vector(0,0,0)) # pitch,roll...1\n                            coor_Z = coor_Z + pas\n                    else:                     # a plat\n                        if exterieur == 1:    # exterieur (superieur)\n                            plm = App.Placement(App.Vector(coor_X,coor_Y,coor_Z), App.Rotation(angleTr-90-correctionAngle+inclinaisonX,inclinaisonY,inclinaisonZ), App.Vector(0,0,0)) # pitch,roll...1\n                        elif exterieur == 3:  # circumferential plat (clock)\n                            if redressement == 1:\n                                plm = App.Placement(App.Vector(coor_X-centreX,coor_Y-centreY,coor_Z), App.Rotation(inclinaisonX,inclinaisonY,inclinaisonZ), App.Vector(0,0,0)) # pitch,roll...1\n                            else:\n                                plm = App.Placement(App.Vector(coor_X-centreX,coor_Y-centreY,coor_Z), App.Rotation(angleTr+inclinaisonX,inclinaisonY,inclinaisonZ), App.Vector(centreX,centreY,centreZ)) # pitch,roll...1\n                        else:                 # interieur  (inferieur)\n                            plm = App.Placement(App.Vector(-coor_X,-coor_Y,-coor_Z), App.Rotation(angleTr+90+correctionAngle+inclinaisonX,180+inclinaisonY,180+inclinaisonZ), App.Vector(0,0,0)) # pitch,roll...1\n\n                    if epaisseur > 0:         # extrusion characrters\n                        CharExtrude = Draft.extrude(ss,Base.Vector(0,0,epaisseur))\n                        CharExtrude.Placement=plm\n                        comP.append(CharExtrude.Shape)\n#                        nameL.append(CharExtrude.Name)\n                        FcString.addObject(CharExtrude)  # container extrude\n                    else:                 #\n                        ss.Placement=plm\n                        ss.Support=None\n                        comP.append(ss.Shape)\n#                        nameL.append(ss.Name)\n\n#                        points += [FreeCAD.Vector(coor_X,coor_Y,coor_Z)]  # coordinates makeBSpline\n#        BSpline = Draft.makeBSpline(points,closed=False)                  # makeBSpline repere\n        App.ActiveDocument.removeObject(lineName)     # remove ligne de base directrice\n        if compount1 == 1:                            # create compount\n            comp = Part.makeCompound(comP)\n            Part.show(comp)\n        ####Boucle de travail fin########################################################################\n\n        ####Extrude support clock#############################################\n        if nombreFaces > 0:                           # support clock\n            pl = FreeCAD.Placement()\n            if nombreFaces == 1:                      # circle\n                pl.Base = FreeCAD.Vector(0.0,0.0,0.0)\n                supp = Draft.makeCircle(cercleClock,placement=pl,face=True,support=None)\n            if nombreFaces == 2:                      # rectangle\n                cercleClock = cercleClock * 2\n                pl.Base = FreeCAD.Vector(-cercleClock, (-cercleClock / 2), 0.0)\n                supp = Draft.makeRectangle((cercleClock * 2), cercleClock, placement=pl, face = True)\n            if nombreFaces > 2:                       # polygon with number faces\n                if nombreFaces == 4:\n                    rotateSupport = 45\n                else:\n                    rotateSupport = 90\n                pl = App.Placement(App.Vector(0.0,0.0,0.0), App.Rotation(rotateSupport,0,0), App.Vector(0,0,0))\n                supp = Draft.makePolygon(nombreFaces,cercleClock,inscribed = False,placement = pl,face = True,support=None)\n\n            supp.MakeFace = True\n            App.activeDocument().recompute()\n            FcString.addObject(supp)                  # container support\n\n            if epaisSupp != 0:                        # extrude support clock\n                suppExtrude = Draft.extrude(supp,Base.Vector(0,0,epaisSupp))\n                FcString.addObject(suppExtrude)       # container support extrude\n\n        ####Info################################################\n        App.Console.PrintMessage((PolicePath)+\"\\n\")\n        App.Console.PrintMessage(u\"texte        \" + unicode(texte)+\"\\n\")\n        App.Console.PrintMessage(\"rayon         \" + str(rayon)+\"\\n\")\n        App.Console.PrintMessage(\"rotation      \" + str(rotation)+\"\\n\")\n        App.Console.PrintMessage(\"SizeCaractere \" + str(SizeCaractere)+\"\\n\")\n        App.Console.PrintMessage(\"debout        \" + str(debout)+\"\\n\")\n\n        ####Reset################################################\n        ff = ui\n        ff.on_PU_Reset()\n\n        #### Chrono end ####################################\n        arrive = time.clock()                                                                    # chrono end\n        App.Console.PrintMessage(\"Time : \"+str(\"%.2f\" % ((arrive - depart)/60))+\" min\"+\"\\n\\n\")   # chrono end\n        ####################################################\n\nMainWindow = QtGui.QMainWindow()\nui = Ui_MainWindow()\nui.setupUi(MainWindow)\nMainWindow.show()\n",
    "url": "http://forum.freecadweb.org/viewtopic.php?f=3&t=7384",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/Macro_FCCircularText",
    "version": "00.11",
    "license": "",
    "date": "12/06/2015",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ObjectCreation\\Macro_FCCircularText.FCMacro",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "/usr/lib/freecad/Mod/plugins/icons/FCCircularTextButtom.png",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "ParabolaCreater",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Parabola Creater",
    "code": "__Name__ = 'Parabola Creater'\n__Comment__ = 'Parabola Creater'\n__Author__ = 'unknown'\n__Version__ = '1.0.1'\n__Date__ = '2019-02-02'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = ''\n__Wiki__ = ''\n__Icon__ = ''\n__Help__ = ''\n__Status__ = ''\n__Requires__ = ''\n__Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'\n__Files__ = ''\n\nimport FreeCAD as app\nimport Part, PySide\nfrom PySide import QtCore, QtGui\nfrom PySide.QtGui import QLineEdit, QRadioButton\n\n\nclass ParabolaCreater():\n    def __init__(self):\n        self.dialog = None\n\n        self.dialog = QtGui.QDialog()\n        #self.dialog.resize(450,110)\n\n        self.dialog.setWindowTitle(\"Parabola Creator\")\n        la = QtGui.QVBoxLayout(self.dialog)\n\n        self.radio1 = QRadioButton(\"Make 2D Shape\")\n        self.radio2 = QRadioButton(\"Make 3D Revolution\")\n\n        # set default to \"Make 2D Shape\" & make radio buttons - Change self.radio1.setChecked(True) to\n        # self.radio2.setChecked(True) to set \"Make 3D Revolution\" as default\n\n        self.radio1.setChecked(True)\n        la.addWidget(self.radio1)\n        la.addWidget(self.radio2)\n\n        iN1 = QtGui.QLabel(\"Range Of Curve - Minimum\")\n        la.addWidget(iN1)\n        self.r1 = QtGui.QLineEdit()\n        la.addWidget(self.r1)\n        self.r1.setText('-3')\n\n        iN2 = QtGui.QLabel(\"Range Of Curve - Maximum\")\n        la.addWidget(iN2)\n        self.r2 = QtGui.QLineEdit()\n        la.addWidget(self.r2)\n        self.r2.setText('3')\n\n        iN3 = QtGui.QLabel(\"Focus\")\n        la.addWidget(iN3)\n        self.f1 = QtGui.QLineEdit()\n        la.addWidget(self.f1)\n        self.f1.setText('2')\n\n        iN4 = QtGui.QLabel(\"Degrees of Revolve (Only valid for 3D Revolution)\")\n        la.addWidget(iN4)\n        self.Dg = QtGui.QLineEdit()\n        la.addWidget(self.Dg)\n        self.Dg.setText('360')\n\n        okbox = QtGui.QDialogButtonBox(self.dialog)\n        okbox.setOrientation(QtCore.Qt.Horizontal)\n        okbox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)\n        la.addWidget(okbox)\n        QtCore.QObject.connect(okbox, QtCore.SIGNAL(\"accepted()\"), self.makeHyp)\n        QtCore.QObject.connect(okbox, QtCore.SIGNAL(\"rejected()\"), self.close)\n        QtCore.QMetaObject.connectSlotsByName(self.dialog)\n        self.dialog.show()\n        self.dialog.exec_()\n\n    def makeHyp(self):\n        if self.radio1.isChecked():\n            try:\n                tS1 = float(self.r1.text())\n                tS2 = float(self.r2.text())\n                fc = float(self.f1.text())\n\n                para=Part.Parabola()\n                para.Focal = fc\n\n                shape=para.toShape(tS1,tS2)\n                Part.show(shape)\n            except:\n                sayexc()\n                app.Console.PrintError(\"Unable to complete task\")\n\n            self.close()\n\n        if self.radio2.isChecked():\n            try:\n                tS1 = float(self.r1.text())\n                tS2 = float(self.r2.text())\n                fc = float(self.f1.text())\n                Dg = float(self.Dg.text())\n\n                para=Part.Parabola()\n                para.Focal = fc\n\n                shape=para.toShape(tS1,tS2)\n                rev=shape.revolve(app.Vector(1,0,0),app.Vector(1,0,0),Dg) # revolve around X axis by number of degrees\n                Part.show(rev)\n            except:\n                sayexc()\n                app.Console.PrintError(\"Unable to complete task\")\n\n            self.close()\n\n    def close(self):\n        self.dialog.hide()\n\nif __name__ == '__main__':\n    ParabolaCreater()\n",
    "url": "",
    "raw_code_url": "",
    "wiki": "",
    "version": "1.0.1",
    "license": "",
    "date": "2019-02-02",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ObjectCreation\\ParabolaCreater.FCMacro",
    "filename_from_url": "",
    "author": "unknown",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "ScrewMaker",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Generate a screw",
    "code": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\nMacro to generate screws with FreeCAD.\nVersion 1.4 from 1st of September 2013\nVersion 1.5 from 23rd of December 2013\nCorrected hex-heads above M12 not done.\nVersion 1.6 from 15th of March 2014\nAdded PySide support\n\nVersion 1.7 from April 2014\nfixed bool type error. (int is not anymore accepted at linux)\nfixed starting point of real thread at some screw types.\n\nVersion 1.8 from July 2014\nfirst approach for a faster real thread\n\nVersion 1.9 / 2.0 July 2015\nnew calculation of starting point of thread\nshell-based approach for screw generation\nadded:\nISO 14582 Hexalobular socket countersunk head screws, high head\nISO 14584 Hexalobular socket raised countersunk head screws\nISO 7380-2 Hexagon socket button head screws with collar\nDIN 967 Cross recessed pan head screws with collar\nISO 4032 Hexagon nuts, Style 1\nISO 4033 Hexagon nuts, Style 2\nISO 4035 Hexagon thin nuts, chamfered\nEN 1661 Hexagon nuts with flange\nISO 7094 definitions  Plain washers - Extra large series\nISO 7092 definitions  Plain washers - Small series\nISO 7093-1 Plain washer - Large series\nScrew-tap to drill inner threads in parts with user defined length\n\nScrewMaker can now also used as a python module.\nThe following shows how to generate a screw from a python script:\n  import screw_maker2_0\n\n  threadDef = 'M3.5'\n  o = screw_maker2_0.Screw()\n  t = screw_maker2_0.Screw.setThreadType(o,'real')\n  # Creates a Document-Object with label describing the screw\n  d = screw_maker2_0.Screw.createScrew(o, 'ISO1207', threadDef, '20', 'real')\n\n  # creates a shape in memory\n  t = screw_maker2_0.Screw.setThreadType(o,'real')\n  s = screw_maker1_9d.Screw.makeIso7046(o, 'ISO14582', threadDef, 40.0)\n  Part.show(s)\n\nVersion 2.1 August 2015\nadded:\nISO 8676 Hexagon head screw with metric fine pitch thread\n\nVersion 2.2 May 2018\n- Extend function \"moveScrew\" to check for Body and Part.\n- Add Screw to Part if Body is in Part.\n- Search for plane support face to get correct orientation\n- fix failed hex-head\n\nVersion 2.3 Oct 2018\n- fix missing function equal_vertex\n\nto do: check ISO7380 usage of rs and rt, actual only rs is used\ncheck chamfer angle on hexogon heads and nuts\n***************************************************************************\n*   Copyright (c) 2013, 2014, 2015 2018                                   *\n*   Ulrich Brammer <ulrich1a[at]users.sourceforge.net>                    *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n*                                                                         *\n***************************************************************************\n\"\"\"\nfrom __future__ import division\n\n__Name__ = 'Screw Maker'\n__Comment__ = 'Generate a screw'\n__Author__ = \"Ulrich Brammer <ulrich1a@users.sourceforge.net>\"\n__Version__ = '2.3.1'\n__Date__ = '2018-10-22'\n__License__ = 'LGPL2+'\n__Web__ = 'http://freecadweb.org/wiki/Macro_screw_maker1_2'\n__Wiki__ = 'http://freecadweb.org/wiki/Macro_screw_maker1_2'\n__Icon__ = ''\n__Help__ = 'Select the characteristics of the screw and click on the create button'\n__Status__ = ''\n__Requires__ = ''\n__Communication__ = ''\n__Files__ = ''\n\nimport math\n\nimport FreeCAD\nimport FreeCADGui\nimport Part\nfrom FreeCAD import Base\nimport DraftVecUtils\n\ntry:\n  from PySide import QtCore, QtGui\n  #FreeCAD.Console.PrintMessage(\"PySide is used\" + \"\\n\")\nexcept ImportError:\n  #FreeCAD.Console.PrintMessage(\"PyQt4 is needed\" + \"\\n\")\n  from PyQt4 import QtCore, QtGui\n\ntry:\n  _encoding = QtGui.QApplication.UnicodeUTF8\n  def tr(context, text):\n    return QtGui.QApplication.translate(context, text, None, _encoding)\nexcept AttributeError:\n  def tr(context, text):\n    return QtGui.QApplication.translate(context, text, None)\n\nDEBUG = False # set to True to show debug messages; does not work, still todo.\n\ndebObject = None\n\n# Diameters included in this library/macro.\n# Some ISO-standards may include more diameters!\n# Dictionary used for user messages\nstandard_diameters = {\n  'ISO4017': ('M1.6', 'M64'), # ISO 4017 Hex-head-screw\n  'ISO4014': ('M1.6', 'M64'), # ISO 4014 Hex-head-bolt\n  'EN1662':  ('M5',   'M16'), # EN 1662 Hexagon bolts with flange, small series\n  'EN1665':  ('M5',   'M20'), # EN 1665 Hexagon bolts with flange, heavy series\n  'ISO8676': ('M8x1', 'M64x4'), # ISO 8676 Hexagon head screw with metric fine pitch thread\n  'ISO4762': ('M1.6', 'M64'), # ISO 4762 Hexagon socket head cap screws\n  'ISO2009': ('M1.6', 'M10'), # ISO 2009 Slotted countersunk flat head screws\n  'ISO2010': ('M1.6', 'M10'), # ISO 2010 Slotted raised countersunk head screws\n  'ISO1580': ('M1.6', 'M10'), # ISO 1580 Slotted pan head screws\n  'ISO7045': ('M1.6', 'M10'), # ISO 7045 Pan head screws type H cross recess\n  'ISO7046': ('M1.6', 'M10'),\n  'ISO7047': ('M1.6', 'M10'),\n  'ISO1207': ('M3',   'M10'), # ISO 1207 Slotted cheese head screws\n  'ISO7048': ('M2.5', 'M8'),  # ISO 7048 Cross-recessed cheese head screws with type H cross recess\n  'ISO7380-1':('M3',  'M16'), # ISO 7380 Hexagon socket button head screws\n  'ISO7380-2':('M3',  'M16'), # ISO 7380 Hexagon socket button head screws with collar\n  'DIN967'  :('M3',   'M8'),  # DIN 967 Cross recessed pan head screws with collar\n  'ISO10642':('M3',   'M20'), # ISO 10642 Hexagon socket countersunk head screws\n  'ISO14579':('M2',   'M20'), # ISO 14579 Hexalobular socket head cap screws\n  'ISO14580':('M2',   'M10'), # ISO 14580 Hexalobular socket cheese head screws\n  'ISO14581':('M2',   'M10'), # ISO 14581 Hexalobular socket countersunk flat head screws (to do!!)\n  'ISO14582':('M3',   'M10'), # ISO 14582 Hexalobular socket countersunk head screws, high head\n  'ISO14583':('M2',   'M10'), # ISO 14583 Hexalobular socket pan head screws\n  'ISO14584':('M2',   'M10'), # ISO 14584 Hexalobular socket raised countersunk head screws\n  'ISO7089': ('M1.6', 'M64'), # Washer\n  'ISO7090': ('M5',   'M64'), # ISO 7090 definitions Plain washers, chamfered - Normal series\n  'ISO7091': ('M1.6', 'M64'), # ISO 7091 definitions  Plain washer - Normal series Product Grade C\n  'ISO7092': ('M1.6', 'M36'), # ISO 7092 definitions  Plain washers - Small series\n  'ISO7093-1': ('M3', 'M36'), # ISO 7093-1 Plain washer - Large series\n  'ISO7094': ('M5',   'M36'), # ISO 7094 definitions  Plain washers - Extra large series\n  'ISO4032': ('M1.6', 'M64'), # ISO 4032 Hexagon nuts, Style 1\n  'ISO4033': ('M5',   'M36'), # ISO 4033 Hexagon nuts, Style 2\n  'ISO4035': ('M1.6', 'M64'), # ISO 4035 Hexagon thin nuts, chamfered\n  'ISO4036': ('M1.6', 'M10'), # ISO 4035 Hexagon thin nuts, unchamfered, todo no function coded\n  'EN1661':  ('M5',   'M20')} # EN 1661 Hexagon nuts with flange\n\n# ISO 4017 Hex-head-screw\n#           P,    c,  dw,    e,     k,   r,   s\niso4017head={\n  'M1.6':  (0.35, 0.2, 2.9,  3.4,   1.1, 0.1,  3.2),\n  'M2':    (0.40, 0.2, 3.7,  4.4,   1.4, 0.1,  4.0),\n  'M2.5':  (0.45, 0.2, 4.6,  5.5,   1.7, 0.1,  5.0),\n  'M3':    (0.5,  0.2, 5.2,  6.1,   2.0, 0.1,  5.5),\n  '(M3.5)':(0.6,  0.2, 5.2,  6.6,   2.4, 0.1,  5.5),\n  'M4':    (0.7,  0.2, 6.6,  7.7,   2.8, 0.2,  7.0),\n  'M5':    (0.8,  0.2, 7.5,  8.9,   3.5, 0.2,  8.0),\n  'M6':    (1.0,  0.2, 9.5,  11.05, 4.0, 0.25, 10.0),\n  'M8':    (1.25, 0.3, 11.7, 14.5,  5.3, 0.25, 13.0),\n  'M10':   (1.50, 0.3, 14.7, 17.9,  6.4, 0.4,  16.0),\n  'M12':   (1.75, 0.3, 16.7, 20.1,  7.5, 0.6,  18.0),\n  '(M14)': (2.00, 0.3, 20.5, 24.5,  8.8, 0.6,  22.0),\n  'M16':   (2.00, 0.4, 22.4, 26.9, 10.0, 0.6,  24.0),\n  '(M18)': (2.50, 0.4, 25.4, 30.2, 11.5, 0.6,  27.0),\n  'M20':   (2.50, 0.4, 28.2, 33.7, 12.5, 0.8,  30.0),\n  '(M22)': (2.50, 0.4, 31.8, 37.7, 14.0, 0.8,  34.0),\n  'M24':   (3.00, 0.4, 33.7, 40.1, 15.0, 0.8,  36.0),\n  '(M27)': (3.00, 0.4, 38.0, 45.2, 17.0, 1.0,  41.0),\n  'M30':   (3.50, 0.4, 42.8, 50.9, 18.7, 1.0,  46.0), #dw not in class A, e not in class A\n  '(M33)': (3.50, 0.4, 46.6, 55.4, 21.0, 1.0,  50.0),\n  'M36':   (4.00, 0.4, 51.2, 61.0, 22.5, 1.0,  55.0), #dw not in class A, e not in class A\n  '(M39)': (4.00, 0.5, 55.9, 66.5, 25.0, 1.0,  60.0),\n  'M42':   (4.50, 0.7, 60.0, 71.3, 26.0, 1.2,  65.0),\n  '(M45)': (4.50, 0.7, 64.7, 77.0, 28.0, 1.2,  70.0),\n  'M48':   (5.00, 0.7, 69.5, 82.6, 30.0, 1.6,  75.0),\n  '(M52)': (5.00, 0.7, 74.5, 88.3, 33.0, 1.6,  80.0),\n  'M56':   (5.50, 0.7, 78.7, 93.6, 35.0, 2.0,  85.0),\n  '(M60)': (5.50, 0.7, 82.7, 99.2, 38.0, 2.0,  90.0),\n  'M64':   (6.00, 0.7, 88.2,104.9, 40.0, 2.0,  95.0)\n  }\n\niso4017length = {\n  '2': ( 1.8,  2.2),\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '100':(99.3, 100.7),\n  '110':(109.3, 110.7),\n  '120':(119.3, 120.7),\n  '130':(129.2, 130.8),\n  '140':(139.2, 130.8),\n  '150':(149.2, 150.8),\n  '160':(159.2, 160.8),\n  '180':(179.2, 180.8),\n  '200':(199.1, 200.9)\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso4017range = {\n  'M1.6':  ('2', '16'),\n  'M2':    ('4', '20'),\n  'M2.5':  ('5', '25'),\n  'M3':    ('5', '30'),\n  '(M3.5)':('8', '35'),\n  'M4':    ('6', '40'),\n  'M5':    ('8', '50'),\n  'M6':   ('12', '60'),\n  'M8':   ('16', '80'),\n  'M10':  ('20','100'),\n  'M12':  ('25','120'),\n  '(M14)':('25','140'),\n  'M16':  ('30','150'),\n  '(M18)':('35','200'),\n  'M20':  ('40','160'),\n  '(M22)':('45','200'),\n  'M24':  ('50','180'),\n  '(M27)':('50','100'),\n  'M30':  ('60','200'),\n  '(M33)':('65','200'),\n  'M36':  ('70','200'),\n  '(M39)':('80','200'),\n  'M42':  ('70','200'),\n  '(M45)':('90','200'),\n  'M48': ('100','200'),\n  '(M52)':('100','200'),\n  'M56':  ('110','200'),\n  '(M60)':('120','200'),\n  'M64':  ('120','200')\n  }\n\n# ISO 8676 Hexagon head screw with metric fine pitch thread\n#                P,    c,  dw,    e,     k,   r,   s\niso8676def={\n  'M8x1':      (1.00, 0.3, 11.7, 14.5,  5.3, 0.25, 13.0),\n  'M10x1':     (1.00, 0.3, 14.7, 17.9,  6.4, 0.4,  16.0),\n  '(M10x1.25)':(1.25, 0.3, 14.7, 17.9,  6.4, 0.4,  16.0),\n  'M12x1.5':   (1.50, 0.3, 16.7, 20.1,  7.5, 0.6,  18.0),\n  '(M12x1.25)':(1.75, 0.3, 16.7, 20.1,  7.5, 0.6,  18.0),\n  '(M14x1.5)': (1.50, 0.3, 20.5, 24.5,  8.8, 0.6,  22.0),\n  'M16x1.5':   (1.50, 0.4, 22.4, 26.9, 10.0, 0.6,  24.0),\n  '(M18x1.5)': (1.50, 0.4, 25.4, 30.2, 11.5, 0.6,  27.0),\n  'M20x1.5':   (1.50, 0.4, 28.2, 33.7, 12.5, 0.8,  30.0),\n  '(M20x2)':   (2.00, 0.4, 28.2, 33.7, 12.5, 0.8,  30.0),\n  '(M22x1.5)': (1.50, 0.4, 31.8, 37.7, 14.0, 0.8,  34.0),\n  'M24x2':     (2.00, 0.4, 33.7, 40.1, 15.0, 0.8,  36.0),\n  '(M27x2)':   (2.00, 0.4, 38.0, 45.2, 17.0, 1.0,  41.0),\n  'M30x2':     (2.00, 0.4, 42.8, 50.9, 18.7, 1.0,  46.0), #dw not in class A, e not in class A\n  '(M33x2)':   (2.00, 0.4, 46.6, 55.4, 21.0, 1.0,  50.0),\n  'M36x3':     (3.00, 0.4, 51.2, 61.0, 22.5, 1.0,  55.0), #dw not in class A, e not in class A\n  '(M39x3)':   (3.00, 0.5, 55.9, 66.5, 25.0, 1.0,  60.0),\n  'M42x3':     (3.00, 0.7, 60.0, 71.3, 26.0, 1.2,  65.0),\n  '(M45x3)':   (3.00, 0.7, 64.7, 77.0, 28.0, 1.2,  70.0),\n  'M48x3':     (3.00, 0.7, 69.5, 82.6, 30.0, 1.6,  75.0),\n  '(M52x4)':   (4.00, 0.7, 74.5, 88.3, 33.0, 1.6,  80.0),\n  'M56x4':     (4.00, 0.7, 78.7, 93.6, 35.0, 2.0,  85.0),\n  '(M60x4)':   (4.00, 0.7, 82.7, 99.2, 38.0, 2.0,  90.0),\n  'M64x4':     (4.00, 0.7, 88.2,104.9, 40.0, 2.0,  95.0)\n  }\n\niso8676length = {\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '100':(99.3, 100.7),\n  '110':(109.3, 110.7),\n  '120':(119.3, 120.7),\n  '130':(129.2, 130.8),\n  '140':(139.2, 130.8),\n  '150':(149.2, 150.8),\n  '160':(159.2, 160.8),\n  '180':(179.2, 180.8),\n  '200':(199.1, 200.9),\n  '220':(217.7, 222.3),\n  '240':(237.7, 242.3),\n  '260':(219.1, 220.9),\n  '280':(219.1, 220.9),\n  '300':(219.1, 220.9),\n  '320':(219.1, 220.9),\n  '340':(219.1, 220.9),\n  '360':(219.1, 220.9),\n  '380':(219.1, 220.9),\n  '400':(219.1, 220.9),\n  '420':(219.1, 220.9),\n  '440':(219.1, 220.9),\n  '460':(219.1, 220.9),\n  '480':(219.1, 220.9),\n  '500':(496.85, 503.15)\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso8676range = {\n  'M8x1':      ('16', '80'),\n  'M10x1':     ('20','100'),\n  '(M10x1.25)':('20','100'),\n  'M12x1.5':   ('25','120'),\n  '(M12x1.25)':('25','120'),\n  '(M14x1.5)': ('30','140'),\n  'M16x1.5':   ('35','160'),\n  '(M18x1.5)': ('35','180'),\n  'M20x1.5':   ('40','200'),\n  '(M20x2)':   ('40','200'),\n  '(M22x1.5)': ('45','220'),\n  'M24x2':     ('40','200'),\n  '(M27x2)':   ('55','260'),\n  'M30x2':     ('40','200'),\n  '(M33x2)':   ('65','360'),\n  'M36x3':     ('40','200'),\n  '(M39x3)':   ('80','380'),\n  'M42x3':     ('90','420'),\n  '(M45x3)':   ('90','440'),\n  'M48x3':     ('100','480'),\n  '(M52x4)':   ('100','500'),\n  'M56x4':     ('120','500'),\n  '(M60x4)':   ('120','500'),\n  'M64x4':     ('130','500')\n  }\n\n# ISO 4014 Hex-head-bolt\n#          P,      b1,    b2,    b3,  c,   dw,    e,    k,   r,   s\niso4014head={\n  'M1.6':  (0.35,   9.0,  15.0,  28.0, 0.2,  2.3,  3.4,  1.1, 0.1,  3.2),\n  'M2':    (0.40,  10.0,  16.0,  29.0, 0.2,  3.0,  4.4,  1.4, 0.1,  4.0),\n  'M2.5':  (0.45,  11.0,  17.0,  30.0, 0.2,  4.0,  5.5,  1.7, 0.1,  5.0),\n  'M3':    (0.50,  12.0,  18.0,  31.0, 0.2,  4.6,  6.1,  2.0, 0.1,  5.5),\n  '(M3.5)':(0.60,  13.0,  19.0,  32.0, 0.2,  5.1,  6.6,  2.4, 0.1,  6.0),\n  'M4':    (0.70,  14.0,  20.0,  33.0, 0.2,  5.9,  7.7,  2.8, 0.2,  7.0),\n  'M5':    (0.80,  16.0,  22.0,  35.0, 0.2,  6.9,  8.9,  3.5, 0.2,  8.0),\n  'M6':    (1.00,  18.0,  24.0,  37.0, 0.2,  8.9, 11.05, 4.0, 0.25,10.0),\n  'M8':    (1.25,  22.0,  28.0,  41.0, 0.3, 11.7, 14.5,  5.3, 0.4, 13.0),\n  'M10':   (1.50,  26.0,  32.0,  45.0, 0.3, 14.7, 17.9,  6.4, 0.4, 16.0),\n  'M12':   (1.75,  30.0,  36.0,  49.0, 0.3, 16.7, 20.1,  7.5, 0.6, 18.0),\n  '(M14)': (2.00,  34.0,  40.0,  53.0, 0.3, 20.5, 24.5,  8.8, 0.6, 22.0),\n  'M16':   (2.00,  38.0,  44.0,  57.0, 0.4, 22.4, 26.9, 10.0, 0.6, 24.0),\n  '(M18)': (2.50,  42.0,  48.0,  61.0, 0.4, 25.4, 30.2, 11.5, 0.6, 27.0),\n  'M20':   (2.50,  46.0,  52.0,  65.0, 0.4, 28.2, 33.7, 12.5, 0.8, 30.0),\n  '(M22)': (2.50,  50.0,  56.0,  69.0, 0.4, 31.8, 37.7, 14.0, 0.8, 34.0),\n  'M24':   (3.00,  54.0,  60.0,  73.0, 0.4, 33.7, 40.1, 15.0, 0.8, 36.0),\n  '(M27)': (3.00,  60.0,  66.0,  79.0, 0.4, 38.0, 45.2, 17.0, 1.0, 41.0),\n  'M30':   (3.50,  66.0,  72.0,  85.0, 0.4, 42.8, 50.9, 18.7, 1.0, 46.0), #dw not in class A, e not in class A\n  '(M33)': (3.50,  78.0,  78.0,  91.0, 0.4, 46.6, 55.4, 21.0, 1.0, 50.0),\n  'M36':   (4.00,  84.0,  84.0,  97.0, 0.4, 51.2, 60.8, 22.5, 1.0, 55.0),\n  '(M39)': (4.00,  90.0,  90.0, 103.0, 0.5, 55.9, 66.5, 25.0, 1.0, 60.0),\n  'M42':   (4.50,  96.0,  96.0, 109.0, 0.6, 60.0, 71.3, 26.0, 1.2, 65.0),\n  '(M45)': (4.50, 102.0, 102.0, 115.0, 0.7, 64.7, 77.0, 28.0, 1.2, 70.0),\n  'M48':   (5.00, 108.0, 108.0, 121.0, 0.6, 69.5, 82.6, 30.0, 1.6, 75.0),\n  '(M52)': (5.00, 116.0, 116.0, 129.0, 0.7, 74.5, 88.3, 33.0, 1.6, 80.0),\n  'M56':   (5.50, 137.0, 137.0, 137.0, 0.6, 78.7, 93.6, 35.0, 2.0, 85.0),\n  '(M60)': (5.50, 145.0, 145.0, 145.0, 0.7, 82.7, 99.2, 38.0, 2.0, 90.0),\n  'M64':   (6.00, 153.0, 153.0, 153.0, 0.6, 88.2,104.9, 40.0, 2.0, 55.0)\n  }\n\niso4014length = {\n  '12':(11.65, 12.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '100':(99.3, 100.7),\n  '110':(109.3, 110.7),\n  '120':(119.3, 120.7),\n  '130':(129.2, 130.8),\n  '140':(139.2, 130.8),\n  '150':(149.2, 150.8),\n  '160':(159.2, 160.8),\n  '180':(179.2, 180.8),\n  '200':(199.1, 200.9),\n  '220':(219.1, 220.9),\n  '240':(237.7, 242.3),\n  '260':(219.1, 220.9),\n  '280':(219.1, 220.9),\n  '300':(219.1, 220.9),\n  '320':(219.1, 220.9),\n  '340':(219.1, 220.9),\n  '360':(219.1, 220.9),\n  '380':(219.1, 220.9),\n  '400':(219.1, 220.9),\n  '420':(219.1, 220.9),\n  '440':(219.1, 220.9),\n  '460':(219.1, 220.9),\n  '480':(219.1, 220.9),\n  '500':(496.85, 503.15),\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso4014range = {\n  'M1.6':('12', '16'),\n  'M2':  ('16', '20'),\n  'M2.5':('16', '25'),\n  'M3':  ('20', '30'),\n  '(M3.5)':('20', '35'),\n  'M4':  ('25', '50'),\n  'M5':  ('25', '50'),\n  'M6':  ('30', '130'),\n  'M8':  ('30', '180'),\n  'M10': ('35', '150'),\n  'M12': ('50', '150'),\n  '(M14)': ('50', '160'),\n  'M16': ('55', '200'),\n  '(M18)':('70','180'),\n  'M20': ('60', '300'),\n  '(M22)':('70','220'),\n  'M24': ('80', '220'),\n  '(M27)':('90', '220'),\n  'M30': ('110','300'),\n  '(M33)':('130','320'),\n  'M36': ('140','360'),\n  '(M39)':('150','380'),\n  'M42': ('160','440'),\n  '(M45)':('180','440'),\n  'M48': ('180','480'),\n  '(M52)':('200','480'),\n  'M56': ('220','500'),\n  '(M60)':('220','500'),\n  'M64': ('260','500')\n  }\n\n# EN 1662 Hexagon bolts with flange, small series\n#          P,   b0,    b1,   b2,   b3,   c,  dc,    dw,    e,     k,   kw,  lf,  r1,   s\nen1662def={\n  'M5': (0.80, 25.0, 16.0,  0.0,  0.0, 1.0, 11.4,  9.4,  7.59,  5.6, 2.3, 1.4, 0.2, 7.0),\n  'M6': (1.00, 30.0, 18.0,  0.0,  0.0, 1.1, 13.6, 11.6,  8.71,  6.9, 2.9, 1.6, 0.25, 8.0),\n  'M8': (1.25, 35.0, 22.0, 28.0,  0.0, 1.2, 17.0, 14.9, 10.95,  8.5, 3.8, 2.1, 0.4, 10.0),\n  'M10':(1.50, 40.0, 26.0, 32.0,  0.0, 1.5, 20.8, 18.7, 14.26,  9.7, 4.3, 2.1, 0.4, 13.0),\n  'M12':(1.75, 45.0, 30.0, 36.0,  0.0, 1.8, 24.7, 22.5, 17.62, 12.1, 5.4, 2.1, 0.6, 16.0),\n  '(M14)':(2.00, 50.0, 34.0, 40.0,  0.0, 2.1, 28.6, 26.4, 19.86, 12.9, 5.6, 2.1, 0.6, 18.0),\n  'M16':(2.00, 55.0, 38.0, 44.0, 57.0, 2.4, 32.8, 30.6, 23.15, 15.2, 6.8, 3.2, 0.6, 21.0)}\n\n# range of typical screw lengths\n#    min_length,  max_length\nen1662range = {\n  'M5': ('10', '50'),\n  'M6': ('12', '60'),\n  'M8': ('16', '80'),\n  'M10':('20','100'),\n  'M12':('25','120'),\n  '(M14)':('30','140'),\n  'M16':('35','160')\n  }\n\nen1662length = {\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '90':(89.3, 90.7),\n  '100':(99.3, 100.7),\n  '110':(109.3, 110.7),\n  '120':(119.3, 120.7),\n  '130':(129.2, 130.8),\n  '140':(139.2, 130.8),\n  '150':(149.2, 150.8),\n  '160':(159.2, 160.8)\n  }\n\n# EN 1665 Hexagon bolts with flange, heavy series\n#          P,    b0,  b1,   b2,   b3,   c,  dc,    dw,    e,     k,   kw,  lf,  r1,   s\nen1665def={\n  'M5': (0.80, 25.0, 16.0,  0.0,  0.0, 1.0, 11.8,  9.8,  8.71,  5.8, 2.6, 1.4, 0.2,  8.0),\n  'M6': (1.00, 30.0, 18.0,  0.0,  0.0, 1.1, 14.2, 12.2, 10.95,  6.6, 3.0, 1.6, 0.25,10.0),\n  'M8': (1.25, 35.0, 22.0, 28.0,  0.0, 1.2, 18.0, 15.8, 14.26,  8.1, 3.9, 2.1, 0.4, 13.0),\n  'M10':(1.50, 40.0, 26.0, 32.0,  0.0, 1.5, 22.3, 19.6, 17.62, 10.4, 4.1, 2.1, 0.4, 16.0),\n  'M12':(1.75, 45.0, 30.0, 36.0,  0.0, 1.8, 26.6, 23.8, 19.86, 11.8, 5.6, 2.1, 0.6, 18.0),\n  '(M14)':(2.00, 50.0, 34.0, 40.0,  0.0, 2.1, 30.5, 27.6, 23.15, 13.7, 6.5, 2.1, 0.6, 21.0),\n  'M16':(2.00, 55.0, 38.0, 44.0, 57.0, 2.4, 35.0, 31.9, 26.51, 15.4, 7.3, 3.2, 0.6, 24.0),\n  'M20':(2.50, 65.0, 46.0, 52.0, 65.0, 3.0, 43.0, 39.9, 33.23, 18.9, 8.9, 4.2, 0.8, 30.0)}\n\n# range of typical screw lengths\n#    min_length,  max_length\nen1665range = {\n  'M5': ('10', '50'),\n  'M6': ('12', '60'),\n  'M8': ('16', '80'),\n  'M10':('20','100'),\n  'M12':('25','120'),\n  '(M14)':('30','140'),\n  'M16':('35','160'),\n  'M20':('65','200')\n  }\n\nen1665length = {\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '90':(89.3, 90.7),\n  '100':(99.3, 100.7),\n  '110':(109.3, 110.7),\n  '120':(119.3, 120.7),\n  '130':(129.2, 130.8),\n  '140':(139.2, 130.8),\n  '150':(149.2, 150.8),\n  '160':(159.2, 160.8),\n  '180':(179.2, 180.8),\n  '200':(199.1, 200.9)\n  }\n\n# ISO 1207 definitions Class A, Slotted cheese head screws\n#          P,     a,   b,   dk,  dk_mean, da,  k,  n_min, r, t_min, x\niso1207def={\n  'M1.6':(0.35, 0.7, 25.0,  3.0,  2.9,  2.0, 1.1, 0.46, 0.1, 0.45, 0.9),\n  'M2':  (0.40, 0.8, 25.0,  3.8,  3.7,  2.6, 1.4, 0.56, 0.1, 0.6, 1.0),\n  'M2.5':(0.45, 0.9, 25.0,  4.5,  4.4,  3.1, 1.8, 0.66, 0.1, 0.7, 1.1),\n  'M3':  (0.50, 1.0, 25.0,  5.5,  5.4,  3.6, 2.0, 0.86, 0.1, 0.85, 1.25),\n  '(M3.5)':(0.60, 1.2, 38.0,  6.0,  5.9,  4.1, 2.4, 1.06, 0.1, 1.0, 1.5),\n  'M4':  (0.70, 1.4, 38.0,  7.0,  6.9,  4.7, 2.6, 1.26, 0.2, 1.1, 1.75),\n  'M5':  (0.80, 1.6, 38.0,  8.5,  8.4,  5.7, 3.3, 1.26, 0.2, 1.3, 2.0),\n  'M6':  (1.00, 2.0, 38.0, 10.0,  9.9,  6.8, 3.9, 1.66, 0.25,1.6, 2.5),\n  'M8':  (1.25, 2.5, 38.0, 13.0, 12.85, 9.2, 5.0, 2.06, 0.4, 2.0, 3.2),\n  'M10': (1.50, 3.0, 38.0, 16.0, 15.85, 11.2,6.0, 2.56, 0.4, 2.4, 3.8)}\n\n# range of typical screw lengths\n#    min_length,  max_length\niso1207range = {\n  'M1.6':('2', '16'),\n  'M2':  ('3', '20'),\n  'M2.5':('3', '25'),\n  'M3':  ('4', '30'),\n  '(M3.5)':('5', '35'),\n  'M4':  ('5', '40'),\n  'M5':  ('6', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '80'),\n  'M10':('12', '80')}\n\n# slotted cheese head screws\n# nom length: l_min, l_max\niso1207length = {\n  '2': (1.8,  2.2),\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.05, 55.95),\n  '60':(59.05, 60.95),\n  '65':(64.05, 65.95),\n  '70':(69.05, 70.95),\n  '75':(74.05, 75.95),\n  '80':(79.05, 80.95)\n  }\n\n# ISO 14580 definitions , Hexalobular socket cheese head screws\n#          P,     a,   b,   dk,  dk_mean, da,  k,  n_min, r, t_min, x\n#           tt,    k,    A,  t_mean\niso14580def={\n  'M2':  ('T6',  1.55, 1.75, 0.8),\n  'M2.5':('T8',  1.85, 2.40, 0.9),\n  'M3':  ('T10', 2.40, 2.80, 1.2),\n  '(M3.5)':('T15', 2.60, 3.35, 1.3),\n  'M4':  ('T20', 3.10, 3.95, 1.5),\n  'M5':  ('T25', 3.65, 4.50, 1.7),\n  'M6':  ('T30', 4.40, 5.60, 2.1),\n  'M8':  ('T45', 5.80, 7.95, 2.9),\n  'M10': ('T50', 6.90, 8.95, 3.3)}\n\n# range of typical screw lengths\n#    min_length,  max_length\n# iso14580range = iso1207range\n\n# nom length: l_min, l_max\niso14580length = {\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.05, 55.95),\n  '60':(59.05, 60.95),\n  '65':(64.05, 65.95),\n  '70':(69.05, 70.95),\n  '75':(74.05, 75.95),\n  '80':(79.05, 80.95)\n  }\n\n\n\n# ISO 7048 definitions Class A,\n# Cross-recessed cheese head screws with type H or Z cross recess\n#          P,     a,   b,   dk,  dk_mean, da,  k,   r,   x, cT,   mH,   mZ\niso7048def={\n  'M2.5':(0.45, 0.9, 25.0,  4.5,  4.4,  3.1, 1.8, 0.1, 1.1, '1', 2.7, 2.4),\n  'M3':  (0.50, 1.0, 25.0,  5.5,  5.4,  3.6, 2.0, 0.1, 1.25,'2', 3.5, 3.5),\n  '(M3.5)':(0.60, 1.2, 38.0,  6.0,  5.9,  4.1, 2.4, 0.1, 1.5, '2', 3.8, 3.7),\n  'M4':  (0.70, 1.4, 38.0,  7.0,  6.9,  4.7, 2.6, 0.2, 1.75,'2', 4.1, 4.0),\n  'M5':  (0.80, 1.6, 38.0,  8.5,  8.4,  5.7, 3.3, 0.2, 2.0, '2', 4.8, 4.6),\n  'M6':  (1.00, 2.0, 38.0, 10.0,  9.9,  6.8, 3.9, 0.25,2.5, '3', 6.2, 6.1),\n  'M8':  (1.25, 2.5, 38.0, 13.0, 12.85, 9.2, 5.0, 0.4, 3.2, '3', 7.7, 7.5)\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso7048range = {\n  'M2.5':('3', '25'),\n  'M3':  ('4', '30'),\n  '(M3.5)':('5', '35'),\n  'M4':  ('5', '40'),\n  'M5':  ('6', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '80')}\n\n# nom length: l_min, l_max\niso7048length = {\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '60':(59.05, 60.95),\n  '70':(69.05, 70.95),\n  '80':(79.05, 80.95)\n  }\n\n\n# Button Head Screw\n# nom length: l_min, l_max\niso7380length = {\n  #'2.5':(2.3,  2.7),\n  #'3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.05, 55.95),\n  '60':(59.05, 60.95),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '90':(89.3, 90.7)\n  }\n\n# ISO 7380-1 definitions Class A\n# http://www.agrati.com/it/unificati/it/gamma/unificati/home02.htm\n#          P,   b,     a,   da, dk,  dk_mean,s_mean,t_min, r, k,   e,    w,\niso7380def={\n  'M3':  (0.50, 18.0, 1.0,  3.6,  5.7,  5.5, 2.03, 1.04, 0.1, 1.65, 2.3,  0.2),\n  'M4':  (0.70, 20.0, 1.4,  4.7,  7.6,  7.4, 2.54, 1.30, 0.2, 2.20, 2.87, 0.3),\n  'M5':  (0.80, 22.0, 1.6,  5.7,  9.5,  9.3, 3.05, 1.56, 0.2, 2.75, 3.44, 0.38),\n  'M6':  (1.00, 24.0, 2.0,  6.8, 10.5, 10.3, 4.05, 2.08, 0.25,3.3,  4.58, 0.74),\n  'M8':  (1.25, 28.0, 2.5,  9.2, 14.0, 13.8, 5.05, 2.60, 0.4, 4.4,  5.72, 1.05),\n  'M10': (1.50, 32.0, 3.0, 11.2, 17.5, 17.3, 6.05, 3.12, 0.4, 5.5,  6.86, 1.45),\n  'M12': (1.75, 36.0, 3.5, 13.7, 21.0, 20.7, 8.06, 4.16, 0.6, 6.6,  9.15, 1.63),\n  'M16': (2.00, 44.0, 3.5, 17.7, 28.0, 27.8, 10.06,5.20, 0.6, 8.8, 11.43, 2.25)\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso7380range = {\n  'M3':  ('6', '30'),\n  'M4':  ('6', '40'),\n  'M5':  ('8', '50'),\n  'M6':  ('10', '60'),\n  'M8': ('12', '80'),\n  'M10':('16', '90'),\n  'M12':('20', '90'),\n  'M16':('25', '90')}\n\n# ISO 7380-2 definitions\n#          P,   b,     c,   da, dk,    dk_c,s_mean,t_min, r,  k,   e,    w,\niso7380_2def={\n  'M3':  (0.50, 18.0, 0.7,  3.6,  5.2,  6.9, 2.03, 1.04, 0.1, 1.65, 2.3,  0.2),\n  'M4':  (0.70, 20.0, 0.8,  4.7,  7.2,  9.4, 2.54, 1.30, 0.2, 2.20, 2.87, 0.3),\n  'M5':  (0.80, 22.0, 1.0,  5.7,  8.8, 11.8, 3.05, 1.56, 0.2, 2.75, 3.44, 0.38),\n  'M6':  (1.00, 24.0, 1.2,  6.8, 10.0, 13.6, 4.05, 2.08, 0.25,3.3,  4.58, 0.74),\n  'M8':  (1.25, 28.0, 1.5,  9.2, 13.2, 17.8, 5.05, 2.60, 0.4, 4.4,  5.72, 1.05),\n  'M10': (1.50, 32.0, 2.0, 11.2, 16.5, 21.9, 6.05, 3.12, 0.4, 5.5,  6.86, 1.45),\n  'M12': (1.75, 36.0, 2.4, 13.7, 19.4, 26.0, 8.06, 4.16, 0.6, 6.6,  9.15, 1.63),\n  'M16': (2.00, 44.0, 2.8, 17.7, 26.0, 34.0, 10.06,5.20, 0.6, 8.8, 11.43, 2.25)\n  }\n\n\n# DIN 967 definitions: Cross recessed pan head screw with collar\n#          P,   b,     c,   da,   dk,   r,  k,    rf,  x,    cT,  mH,   mZ\ndin967def={\n  'M3':  (0.50, 25.0, 0.7,  3.6,  7.5, 0.1, 2.35,  3.8, 1.25, '1', 3.0, 2.9),\n  '(M3.5)':(0.60, 38.0, 0.8,  4.1,  9.0, 0.1, 2.60,  4.6, 1.5,  '2', 4.2, 3.9),\n  'M4':  (0.70, 38.0, 1.0,  4.7, 10.0, 0.2, 3.05,  5.8, 1.75, '2', 4.6, 4.3),\n  'M5':  (0.80, 38.0, 1.2,  5.7, 11.5, 0.2, 3.55,  6.6, 2.0,  '2', 5.0, 4.7),\n  'M6':  (1.00, 38.0, 1.6,  6.8, 14.5, 0.25,4.55,  8.2, 2.5,  '3', 7.1, 6.7),\n  'M8':  (1.25, 38.0, 2.0,  9.2, 19.0, 0.4, 5.90, 11.0, 3.2,  '4', 9.0, 8.8)\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\ndin967range = {\n  'M3':  ('4', '30'),\n  '(M3.5)':  ('5', '35'),\n  'M4':  ('5', '40'),\n  'M5':  ('6', '45'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '60')\n}\n# Button Head Screw\n# nom length: l_min, l_max\ndin967length = {\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.05, 55.95),\n  '60':(59.05, 60.95)\n  }\n\n\nL_iso2009length =['2.5','3','4','5','6','8','10','12','14','16','20', \\\n   '25','30','35','40','45','50','55','60','65','70','75','80']\n# nom length: l_min, l_max\niso2009length = {\n  '2.5':(2.3,  2.7),\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.05, 55.95),\n  '60':(59.05, 60.95),\n  '65':(64.05, 65.95),\n  '70':(69.05, 70.95),\n  '75':(74.05, 75.95),\n  '80':(79.05, 80.95)\n  }\n\n\n# ISO 2009 definitions Class A\n#          P, a, b, dk_theo, dk_mean, k, n_min, r, t_mean, x\niso2009def={\n   'M1.6':(0.35, 0.7, 25, 3.6, 2.8,  1.0,  0.46, 0.2, 0.4, 0.9),\n   'M2':  (0.40, 0.8, 25, 4.4, 3.6,  1.2,  0.56, 0.3, 0.5, 1.0),\n   'M2.5':(0.45, 0.9, 25, 5.5, 4.5,  1.5,  0.66, 0.3, 0.6, 1.1),\n   'M3':  (0.50, 1.0, 25, 6.3, 5.3,  1.65, 0.86, 0.4, 0.7, 1.25),\n   '(M3.5)':(0.60, 1.2, 38, 8.2, 7.1,  2.35, 1.06, 0.4, 1.0, 1.5),\n   'M4':  (0.70, 1.4, 38, 9.4, 8.2,  2.7,  1.26, 0.5, 1.1, 1.75),\n   'M5':  (0.80, 1.6, 38,10.4, 9.2,  2.7,  1.26, 0.6, 1.2, 2.0),\n   'M6':  (1.00, 2.0, 38,12.6, 11.2, 3.3,  1.66, 0.7, 1.4, 2.5),\n   'M8':  (1.25, 2.5, 38,17.3, 15.6, 4.65, 2.06, 1.0, 2.0, 3.2),\n   'M10': (1.50, 3.0, 38,20.0, 18.1, 5.0,  2.56, 1.2, 2.3, 3.8)}\n\n# range of typical screw lengths\n#    min_length,  max_length\niso2009range = {\n  'M1.6':('2.5', '16'),\n  'M2':  ('3', '20'),\n  'M2.5':('4', '25'),\n  'M3':  ('5', '30'),\n  '(M3.5)':('6', '35'),\n  'M4':  ('6', '40'),\n  'M5':  ('8', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '80'),\n  'M10':('12', '80')}\n\n\n# ISO 7046 definitions Class A\n# ISO 7046 Countersunk flat head screws (common head style)\n# with type H or type Z cross recess\n# Parameters P, a, b, dk_theo, dk_mean, k, r, x to be read from iso2009def\n# Length = iso7045length\n#          cT,   mH,   mZ\niso7046def={\n  'M1.6':('0', 1.6, 1.6),\n  'M2':  ('0', 1.9, 1.9),\n  'M2.5':('1', 2.9, 2.8),\n  'M3':  ('1', 3.2, 3.0),\n  '(M3.5)':('2', 4.4, 4.1),\n  'M4':  ('2', 4.6, 4.4),\n  'M5':  ('2', 5.2, 4.0),\n  'M6':  ('3', 6.8, 6.6),\n  'M8':  ('4', 8.9, 8.8),\n  'M10': ('4', 10.0,9.8)}\n\n# range of typical screw lengths\n#    min_length,  max_length\niso7046range = {\n  'M1.6':('3', '16'),\n  'M2':  ('3', '20'),\n  'M2.5':('3', '25'),\n  'M3':  ('4', '30'),\n  '(M3.5)':('5', '35'),\n  'M4':  ('5', '40'),\n  'M5':  ('6', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '60'),\n  'M10':('12', '60')}\n\n# ISO 2010, ISO 7047 definitions Class A: Raised Countersunk head screws\n# ISO 2010 slotted screws (common head style)   range = iso2009range\n# ISO 7047  with type H or type Z cross recess  range = iso7046range\n# Parameters P, a, b, dk_theo, dk_mean, k, r, x to be read from iso2009def\n# Length = iso7045length\n#          rf, t_mean, cT,   mH,   mZ\nRaised_countersunk_def={\n  'M1.6':(3.0,  0.7, '0', 1.9,  1.9),\n  'M2':  (4.0,  0.9, '0', 2.0,  2.2),\n  'M2.5':(5.0,  1.1, '1', 3.0,  2.8),\n  'M3':  (6.0,  1.3, '1', 3.4,  3.1),\n  '(M3.5)':(8.5,  1.5, '2', 4.8,  4.6),\n  'M4':  (9.5,  1.8, '2', 5.2,  5.0),\n  'M5':  (9.5,  2.2, '2', 5.4,  5.3),\n  'M6':  (12.0, 2.6, '3', 7.3,  7.1),\n  'M8':  (16.5, 3.5, '4', 9.6,  9.5),\n  'M10': (19.5, 4.1, '4', 10.4,10.3)}\n\n\n\n# ISO 14582 definitions\n#          P,    a,    b, dk_theo, dk_mean,k,   r,  tt, A, t_mean\niso14582def={\n  'M3':  (0.50, 1.0, 18.0,  7.40,  6.5, 2.20, 0.10, 'T10', 2.80, 1.1),\n  'M4':  (0.70, 1.4, 20.0, 10.02,  9.0, 3.01, 0.20, 'T20', 3.95, 1.6),\n  'M5':  (0.80, 1.6, 22.0, 12.00, 10.8, 3.50, 0.20, 'T25', 4.50, 1.8),\n  'M6':  (1.00, 2.0, 24.0, 14.44, 13.1, 4.22, 0.25, 'T30', 5.60, 2.2),\n  'M8':  (1.25, 2.5, 28.0, 19.38, 17.8, 5.69, 0.40, 'T45', 7.93, 2.8),\n  'M10': (1.50, 3.0, 32.0, 23.00, 21.1, 6.50, 0.40, 'T50', 8.95, 3.3)}\n\n# range of typical screw lengths\n#    min_length,  max_length\niso14582range = {\n  'M3':  ('8', '30'),\n  'M4':  ('8', '40'),\n  'M5':  ('8', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '80'),\n  'M10':('12', '100')}\n\n# nom length: l_min, l_max\niso14582length = {\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '90':(89.3, 90.7),\n  '100':(99.3, 100.7)\n  }\n\n\n\n# ISO 1580 definitions Class A, Slotted pan head screws\n#           P,    a,   b, dk_max,da,  k, n_min,  r,  rf, t_mean, x\niso1580def={\n  'M1.6':(0.35, 0.7, 25,  3.2, 2.0, 1.0, 0.46, 0.1, 0.5, 0.4, 0.9),\n  'M2':  (0.4,  0.8, 25,  4.0, 2.6, 1.3, 0.56, 0.1, 0.6, 0.5, 1.0),\n  'M2.5':(0.45, 0.9, 25,  5.0, 3.1, 1.5, 0.66, 0.1, 0.8, 0.6, 1.1),\n  'M3':  (0.5,  1.0, 25,  5.6, 3.6, 1.8, 0.86, 0.1, 0.9, 0.7, 1.25),\n  '(M3.5)':(0.6,  1.2, 38,  7.0, 4.1, 2.1, 1.06, 0.1, 1.0, 0.8, 1.5),\n  'M4':  (0.7,  1.4, 38,  8.0, 4.7, 2.4, 1.26, 0.2, 1.2, 1.0, 1.75),\n  'M5':  (0.8,  1.6, 38,  9.5, 5.7, 3.0, 1.26, 0.2, 1.5, 1.2, 2.0),\n  'M6':  (1.0,  2.0, 38, 12.0, 6.8, 3.6, 1.66, 0.25,1.8, 1.4, 2.5),\n  'M8':  (1.25, 2.5, 38, 16.0, 9.2, 4.8, 2.06, 0.4, 2.4, 1.9, 3.2),\n  'M10': (1.50, 3.0, 38, 20.0,11.2, 6.0, 2.56, 0.4, 3.0, 2.4, 3.8)}\n\n\n\n# ISO 7045 definitions Class A, Pan head screws with type H or type Z\n# partly used also for ISO 14583 Hexalobular socket pan head screws\n#   cross recess; cT = size of cross recess\n#           P,    a,   b, dk_max,da,  k,   r,   rf,  x,  cT,   mH,   mZ\niso7045def={\n  'M1.6':(0.35, 0.7, 25,  3.2, 2.0, 1.3, 0.1, 2.5, 0.9, '0', 1.7, 1.6),\n  'M2':  (0.4,  0.8, 25,  4.0, 2.6, 1.6, 0.1, 3.2, 1.0, '0', 1.9, 2.1),\n  'M2.5':(0.45, 0.9, 25,  5.0, 3.1, 2.1, 0.1, 4.0, 1.1, '1', 2.7, 2.6),\n  'M3':  (0.5,  1.0, 25,  5.6, 3.6, 2.4, 0.1, 5.0, 1.25,'1', 3.0, 2.8),\n  '(M3.5)':(0.6,  1.2, 38,  7.0, 4.1, 2.6, 0.1, 6.0, 1.5, '2', 3.9, 3.9),\n  'M4':  (0.7,  1.4, 38,  8.0, 4.7, 3.1, 0.2, 6.5, 1.75,'2', 4.4, 4.3),\n  'M5':  (0.8,  1.6, 38,  9.5, 5.7, 3.7, 0.2, 8.0, 2.0, '2', 4.9, 4.7),\n  'M6':  (1.0,  2.0, 38, 12.0, 6.8, 4.6, 0.25,10., 2.5, '3', 6.9, 6.7),\n  'M8':  (1.25, 2.5, 38, 16.0, 9.2, 6.0, 0.4, 13., 3.2, '4', 9.0, 8.8),\n  'M10': (1.50, 3.0, 38, 20.0,11.2, 7.5, 0.4, 16., 3.8, '4', 10.1,9.9)}\n\n# nom length: l_min, l_max\niso7045length = {\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.05, 55.95),\n  '60':(59.05, 60.95)\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso7045range = {\n  'M1.6':('3', '16'),\n  'M2':  ('3', '20'),\n  'M2.5':('3', '25'),\n  'M3':  ('4', '30'),\n  '(M3.5)':('5', '35'),\n  'M4':  ('5', '40'),\n  'M5':  ('6', '45'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '60'),\n  'M10':('12', '60')}\n\n\n# ISO 14583 Hexalobular socket pan head screws\n#   hexalobular recess;    tt = size of hexalobular recess\n\n#           tt,    A,  t_mean\niso14583def={\n  'M2':  ('T6',  1.75, 0.7),\n  'M2.5':('T8',  2.40, 1.0),\n  'M3':  ('T10', 2.80, 1.2),\n  '(M3.5)':('T15', 3.35, 1.3),\n  'M4':  ('T20', 3.95, 1.5),\n  'M5':  ('T25', 4.50, 1.7),\n  'M6':  ('T30', 5.60, 2.2),\n  'M8':  ('T45', 7.95, 3.0),\n  'M10': ('T50', 8.95, 3.8)}\n\n\n#iso14583range = iso7046range\n#iso14583length = iso7045length\n\n# ISO 14584 Hexalobular socket raised countersunk head screws\n#           P,   b, dk_theo, dk_mean, f,  k,   r,   rf,    x,    tt,    A,  t_mean\niso14584def={\n  'M2':  (0.40, 25.0,  4.4,  3.8,  0.5, 1.20, 0.2,  4.0, 1.00, 'T6',  1.75, 0.7),\n  'M2.5':(0.45, 25.0,  5.5,  4.7,  0.6, 1.50, 0.3,  5.0, 1.10, 'T8',  2.40, 1.0),\n  'M3':  (0.50, 25.0,  6.3,  5.5,  0.7, 1.65, 0.4,  6.0, 1.25, 'T10', 2.80, 1.2),\n  '(M3.5)':(0.60, 38.0,  8.2,  7.3,  0.8, 2.35, 0.4,  8.5, 1.50, 'T15', 3.35, 1.3),\n  'M4':  (0.70, 38.0,  9.4,  8.4,  1.0, 2.70, 0.5,  9.5, 1.75, 'T20', 3.95, 1.5),\n  'M5':  (0.80, 38.0, 10.4,  9.3,  1.2, 2.70, 0.6,  9.5, 2.00, 'T25', 4.50, 1.7),\n  'M6':  (1.00, 38.0, 12.6, 11.3,  1.4, 3.30, 0.7, 12.0, 2.50, 'T30', 5.60, 2.2),\n  'M8':  (1.25, 38.0, 17.3, 15.8,  2.0, 4.65, 1.0, 16.5, 3.20, 'T45', 7.95, 3.0),\n  'M10': (1.50, 38.0, 20.0, 18.3,  2.3, 5.00, 1.2, 19.5, 3.80, 'T50', 8.95, 3.8)}\n\n\n# range of typical screw lengths\n#    min_length,  max_length\niso14584range = {\n  'M2':  ('3', '20'),\n  'M2.5':('3', '25'),\n  'M3':  ('4', '30'),\n  '(M3.5)':('5', '35'),\n  'M4':  ('5', '40'),\n  'M5':  ('6', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '60'),\n  'M10':('12', '60')}\n\n#iso14584length = iso7045length\n\n\n# ISO 4762 Hexagon socket head cap screws (Allen screw)\n# ISO 4762 definitions\n#           P,   b,  dk_max,  da,  ds_min,   e,    lf,   k,   r,   s_mean, t,    v,   dw,   w\niso4762def={\n  'M1.6':(0.35,  15.0,  3.0,  2.0,  1.46,  1.73, 0.34,  1.6, 0.1,  1.56,  0.7, 0.16, 2.72, 0.55),\n  'M2':  (0.40,  16.0,  3.8,  2.6,  1.86,  1.73, 0.51,  2.0, 0.1,  1.56,  1.0, 0.2,  3.48, 0.55),\n  'M2.5':(0.45,  17.0,  4.5,  3.1,  2.36,  2.30, 0.51,  2.5, 0.1,  2.06,  1.1, 0.25, 4.18, 0.85),\n  'M3':  (0.50,  18.0,  5.5,  3.6,  2.86,  2.87, 0.51,  3.0, 0.1,  2.56,  1.3, 0.3,  5.07, 1.15),\n  'M4':  (0.70,  20.0,  7.0,  4.7,  3.82,  3.44, 0.60,  4.0, 0.2,  3.06,  2.0, 0.4,  6.53, 1.40),\n  'M5':  (0.80,  22.0,  8.5,  5.7,  4.82,  4.58, 0.60,  5.0, 0.2,  4.06,  2.5, 0.5,  8.03, 1.9),\n  'M6':  (1.00,  24.0, 10.0,  6.8,  5.82,  5.72, 0.68,  6.0, 0.25, 5.06,  3.0, 0.6,  9.38, 2.3),\n  'M8':  (1.25,  28.0, 13.0,  9.2,  7.78,  6.86, 1.02,  8.0, 0.4,  6.06,  4.0, 0.8, 12.33, 3.3),\n  'M10': (1.50,  32.0, 16.0, 11.2,  9.78,  9.15, 1.02, 10.0, 0.4,  8.07,  5.0, 1.0, 15.33, 4.0),\n  'M12': (1.75,  36.0, 18.0, 13.7, 11.73, 11.43, 1.45, 12.0, 0.6, 10.07,  6.0, 1.2, 17.23, 4.8),\n  '(M14)':(2.00,  40.0, 21.0, 15.7, 13.73, 13.72, 1.45, 14.0, 0.6, 12.07,  7.0, 1.4, 20.17, 5.8),\n  'M16': (2.00,  44.0, 24.0, 17.7, 15.73, 16.00, 1.45, 16.0, 0.6, 14.08,  8.0, 1.6, 23.17, 6.8),\n  'M20': (2.50,  52.0, 30.0, 22.4, 19.67, 19.44, 2.04, 20.0, 0.8, 17.10, 10.0, 2.0, 28.87, 8.6),\n  'M24': (3.00,  60.0, 36.0, 26.4, 23.67, 21.73, 2.04, 24.0, 0.8, 19.15, 12.0, 2.0, 34.81, 10.4),\n  'M30': (3.50,  72.0, 45.0, 33.4, 29.67, 25.15, 2.89, 30.0, 1.0, 22.15, 15.5, 2.4, 43.61, 13.1),\n  'M36': (4.00,  84.0, 54.0, 39.4, 35.61, 30.85, 2.89, 36.0, 1.0, 27.15, 19.0, 3.0, 52.54, 15.3),\n  'M42': (4.50,  96.0, 63.0, 45.6, 41.61, 36.58, 3.06, 42.0, 1.2, 32.15, 24.0, 4.2, 61.34, 16.3),\n  'M48': (5.00, 108.0, 72.0, 52.6, 47.61, 41.14, 3.91, 48.0, 1.6, 36.15, 28.0, 4.8, 70.34, 17.5),\n  'M56': (5.50, 124.0, 84.0, 63.0, 55.54, 46.84, 5.95, 56.0, 2.0, 41.15, 34.0, 5.6, 82.26, 19.0),\n  'M64': (6.00, 140.0, 96.0, 71.0, 63.54, 52.54, 5.95, 64.0, 2.0, 46.15, 38.0, 6.4, 94.26, 22.0)\n  }\n\n# nom length: l_min, l_max\niso4762length = {\n  '2.5':(2.3,  2.7),\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '75':(74.4, 75.6),\n  '80':(79.4, 80.6),\n  '100':(99.3, 100.7),\n  '110':(109.3, 110.7),\n  '120':(119.3, 120.7),\n  '130':(129.2, 130.8),\n  '140':(139.2, 130.8),\n  '150':(149.2, 150.8),\n  '160':(159.2, 160.8),\n  '180':(179.2, 180.8),\n  '200':(199.1, 200.9),\n  '220':(219.1, 220.9),\n  '240':(237.7, 242.3),\n  '260':(219.1, 220.9),\n  '280':(219.1, 220.9),\n  '300':(219.1, 220.9)\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso4762range = {\n  'M1.6':('2.5', '16'),\n  'M2':  ('3', '20'),\n  'M2.5':('4', '25'),\n  'M3':  ('5', '30'),\n  '(M3.5)':('6', '35'),\n  'M4':  ('6', '40'),\n  'M5':  ('8', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '80'),\n  'M10':('16', '100'),\n  'M12':('20', '120'),\n  '(M14)':('25', '140'),\n  'M16':('25', '160'),\n  'M20':('16', '100'),\n  'M24':('40', '200'),\n  'M30':('45', '200'),\n  'M36':('55', '200'),\n  'M42':('60', '300'),\n  'M48':('100','300'),\n  'M56':('110','300'),\n  'M64':('120','300')\n  }\n\n\n# ISO 14579 Hexalobular socket head cap screws\n#   hexalobular recess;    tt = size of hexalobular recess\n\n#           tt,    A,  t_mean\niso14579def={\n  'M2':  ( 'T6',  1.75, 0.8),\n  'M2.5':( 'T8',  2.40, 1.0),\n  'M3':  ('T10',  2.80, 1.2),\n  'M4':  ('T20',  3.95, 1.7),\n  'M5':  ('T25',  4.50, 1.9),\n  'M6':  ('T30',  5.60, 2.3),\n  'M8':  ('T45',  7.95, 3.2),\n  'M10': ('T50',  8.95, 3.8),\n  'M12': ('T55', 11.35, 5.0),\n  '(M14)': ('T60', 13.45, 5.8),\n  'M16': ('T70', 15.70, 6.8),\n  '(M18)': ('T80', 17.75, 7.8),\n  'M20': ('T90', 20.20, 9.0),\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso14579range = {\n  'M2':  ('3', '20'),\n  'M2.5':('4', '25'),\n  'M3':  ('5', '30'),\n  'M4':  ('6', '40'),\n  'M5':  ('8', '50'),\n  'M6': ('10', '60'),\n  'M8': ('12', '80'),\n  'M10':('16','100'),\n  'M12':('20','120'),\n  '(M14)':('25','140'),\n  'M16':('25','160'),\n  '(M18)':('30','180'),\n  'M20':('30','200'),\n  }\n\niso14579length = {\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '90':(89.3, 90.7),\n  '100':(99.3, 100.7),\n  '110':(109.3, 110.7),\n  '120':(119.3, 120.7),\n  '130':(129.2, 130.8),\n  '140':(139.2, 130.8),\n  '150':(149.2, 150.8),\n  '160':(159.2, 160.8),\n  '180':(179.2, 180.8),\n  '200':(199.1, 200.9)\n  }\n\n\n# ISO 10642 Hexagon socket countersunk head screws (Allen screw)\n# ISO 10642 definitions\n#           P,   b,  dk_theo, dk_mean,da,  ds_min,   e,  k,   r,   s_mean, t,    w\niso10642def={\n  'M3':  (0.50, 18.0,  6.72,  6.0,  3.3,  2.86,  2.31, 1.86, 0.1,  2.06,  1.1, 0.25),\n  'M4':  (0.70, 20.0,  8.96,  8.0,  4.4,  3.82,  2.88, 2.48, 0.2,  2.56,  1.5, 0.45),\n  'M5':  (0.80, 22.0, 11.20, 10.0,  5.5,  4.82,  3.45, 3.10, 0.2,  3.06,  1.9, 0.66),\n  'M6':  (1.00, 24.0, 13.44, 12.0,  6.6,  5.82,  4.59, 3.72, 0.25, 4.06,  2.2, 0.70),\n  'M8':  (1.25, 28.0, 17.92, 16.0,  8.54, 7.78,  5.73, 4.96, 0.4,  5.06,  3.0, 1.16),\n  'M10': (1.50, 32.0, 22.40, 20.5, 10.62, 9.78,  6.87, 6.20, 0.4,  6.06,  3.6, 1.62),\n  'M12': (1.75, 36.0, 26.88, 25.0, 13.5, 11.73,  9.15, 7.44, 0.6,  8.07,  4.3, 1.80),\n  '(M14)': (2.00, 40.0, 30.80, 28.4, 15.5, 13.73, 11.43, 8.40, 0.6, 10.07,  4.5, 1.62),\n  'M16': (2.00, 44.0, 33.60, 31.0, 17.5, 15.73, 11.43, 8.80, 0.6, 10.07,  4.8, 2.20),\n  'M20': (2.50, 52.0, 40.32, 38.0, 22.0, 19.67, 13.72, 10.16, 0.8, 12.10,  5.6, 2.20)}\n\n# range of typical screw lengths\n#    min_length,  max_length\niso10642range = {\n  'M3':  ('8', '30'),\n  'M4':  ('8', '40'),\n  'M5':  ('8', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '80'),\n  'M10':('12','100'),\n  'M12':('20','100'),\n  '(M14)':('25','100'),\n  'M16':('30','100'),\n  'M20':('35','100'),\n  }\n\niso10642length = {\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '90':(89.3, 90.7),\n  '100':(99.3, 100.7),\n  }\n\n\n# ISO 7089 definitions Washer\n#           d1_min, d2_max, h, h_max\niso7089def={\n  'M1.6':( 1.7,  4.0, 0.3, 0.35),\n  'M2':  ( 2.2,  5.0, 0.3, 0.35),\n  'M2.5':( 2.7,  6.0, 0.5, 0.55),\n  'M3':  ( 3.2,  7.0, 0.5, 0.55),\n  'M4':  ( 4.3,  9.0, 0.8, 0.90),\n  'M5':  ( 5.3, 10.0, 1.0, 1.10),\n  'M6':  ( 6.4, 12.0, 1.6, 1.80),\n  'M8':  ( 8.4, 16.0, 1.6, 1.80),\n  'M10': (10.5, 20.0, 2.0, 2.20),\n  'M12': (13.0, 24.0, 2.5, 2.70),\n  'M16': (17.0, 30.0, 3.0, 3.30),\n  'M20': (21.0, 37.0, 3.0, 3.30),\n  'M24': (25.0, 44.0, 4.0, 4.30),\n  'M30': (31.0, 56.0, 4.0, 4.30),\n  'M36': (37.0, 66.0, 5.0, 5.60),\n  'M42': (45.0, 78.0, 8.0, 9.0),\n  'M48': (52.0, 92.0, 8.0, 9.0),\n  'M56': (62.0,105.0,10.0, 11.0),\n  'M64': (70.0,115.0,10.0, 11.0)\n  }\n\n\n# ISO 7090 definitions Plain washers, chamfered - Normal series\n# chamfer angle 30\u00b0 / 45\u00b0\n# chamfer      h/4 / h/2\n#           d1_min, d2_max, h, h_max\niso7090def={\n  'M5':  ( 5.3, 10.0, 1.0, 1.10),\n  'M6':  ( 6.4, 12.0, 1.6, 1.80),\n  'M8':  ( 8.4, 16.0, 1.6, 1.80),\n  'M10': (10.5, 20.0, 2.0, 2.20),\n  'M12': (13.0, 24.0, 2.5, 2.70),\n  'M16': (17.0, 30.0, 3.0, 3.30),\n  'M20': (21.0, 37.0, 3.0, 3.30),\n  'M24': (25.0, 44.0, 4.0, 4.30),\n  'M30': (31.0, 56.0, 4.0, 4.30),\n  'M36': (37.0, 66.0, 5.0, 5.60),\n  'M42': (45.0, 78.0, 8.0, 9.0),\n  'M48': (52.0, 92.0, 8.0, 9.0),\n  'M56': (62.0,105.0,10.0, 11.0),\n  'M64': (70.0,115.0,10.0, 11.0)\n  }\n\n\n# ISO 7091 definitions  Plain washer - Normal series Product Grade C\n#           d1_min, d2_max, h, h_max\niso7091def={\n  'M1.6':( 1.8,  4.0, 0.3, 0.35),\n  'M2':  ( 2.4,  5.0, 0.3, 0.35),\n  'M2.5':( 2.9,  6.0, 0.5, 0.55),\n  'M3':  ( 3.4,  7.0, 0.5, 0.55),\n  'M4':  ( 4.5,  9.0, 0.8, 0.90),\n  'M5':  ( 5.5, 10.0, 1.0, 1.10),\n  'M6':  ( 6.6, 12.0, 1.6, 1.80),\n  'M8':  ( 9.0, 16.0, 1.6, 1.80),\n  'M10': (11.0, 20.0, 2.0, 2.20),\n  'M12': (13.5, 24.0, 2.5, 2.70),\n  'M16': (17.5, 30.0, 3.0, 3.30),\n  'M20': (22.0, 37.0, 3.0, 3.30),\n  'M24': (26.0, 44.0, 4.0, 4.30),\n  'M30': (33.0, 56.0, 4.0, 4.30),\n  'M36': (39.0, 66.0, 5.0, 5.60),\n  'M42': (45.0, 78.0, 8.0, 9.0),\n  'M48': (52.0, 92.0, 8.0, 9.0),\n  'M56': (62.0,105.0,10.0, 11.0),\n  'M64': (70.0,115.0,10.0, 11.0)\n  }\n\n\n# ISO 7092 definitions  Plain washers - Small series\n#           d1_min, d2_max, h, h_max\niso7092def={\n  'M1.6':( 1.7,  3.5, 0.3, 0.35),\n  'M2':  ( 2.2,  4.5, 0.3, 0.35),\n  'M2.5':( 2.7,  5.0, 0.5, 0.55),\n  'M3':  ( 3.2,  6.0, 0.5, 0.55),\n  'M4':  ( 4.3,  8.0, 0.5, 0.55),\n  'M5':  ( 5.3,  9.0, 1.0, 1.10),\n  'M6':  ( 6.4, 11.0, 1.6, 1.80),\n  'M8':  ( 8.4, 15.0, 1.6, 1.80),\n  'M10': (10.5, 18.0, 1.6, 1.80),\n  'M12': (13.0, 20.0, 2.0, 2.20),\n  'M16': (17.0, 28.0, 2.5, 2.70),\n  'M20': (21.0, 34.0, 3.0, 3.30),\n  'M24': (25.0, 39.0, 4.0, 4.30),\n  'M30': (31.0, 50.0, 4.0, 4.30),\n  'M36': (37.0, 60.0, 5.0, 5.60)\n  }\n\n\n\n# ISO 7093-1 definitions  Plain washers - Large series\n#           d1_min, d2_max, h, h_max\niso7093def={\n  'M3':    ( 3.2,  9.0, 0.8, 0.90),\n  '(M3.5)':( 3.7, 11.0, 0.8, 0.90),\n  'M4':    ( 4.3, 12.0, 1.0, 1.10),\n  'M5':    ( 5.3, 15.0, 1.0, 1.10),\n  'M6':    ( 6.4, 18.0, 1.6, 1.80),\n  'M8':    ( 8.4, 24.0, 2.0, 2.20),\n  'M10':   (10.5, 30.0, 2.5, 2.70),\n  'M12':   (13.0, 37.0, 3.0, 3.30),\n  '(M14)': (15.0, 44.0, 3.0, 3.30),\n  'M16':   (17.0, 50.0, 3.0, 3.30),\n  '(M18)': (19.0, 56.0, 4.0, 4.30),\n  'M20':   (21.0, 60.0, 4.0, 4.30),\n  '(M22)': (23.0, 66.0, 5.0, 5.60),\n  'M24':   (25.0, 72.0, 5.0, 5.60),\n  '(M27)': (30.0, 85.0, 6.0, 6.60),\n  'M30':   (33.0, 92.0, 6.0, 6.60),\n  '(M33)': (36.0,105.0, 6.0, 6.60),\n  'M36':   (39.0,110.0, 8.0, 9.00)\n  }\n\n\n# ISO 7094 definitions  Plain washers - Extra large series\n#           d1_min, d2_max, h, h_max\niso7094def={\n  'M5':    ( 5.5, 18.0, 2.0, 2.3),\n  'M6':    ( 6.6, 22.0, 2.0, 2.3),\n  'M8':    ( 9.0, 28.0, 3.0, 3.6),\n  'M10':   (11.0, 34.0, 3.0, 3.6),\n  'M12':   (13.5, 44.0, 4.0, 4.6),\n  '(M14)': (15.5, 50.0, 4.0, 4.6),\n  'M16':   (17.5, 56.0, 5.0, 6.0),\n  '(M18)': (20.0, 60.0, 5.0, 6.0),\n  'M20':   (22.0, 72.0, 6.0, 7.0),\n  '(M22)': (24.0, 80.0, 6.0, 7.0),\n  'M24':   (26.0, 85.0, 6.0, 7.0),\n  '(M27)': (30.0, 98.0, 6.0, 7.0),\n  'M30':   (33.0,105.0, 6.0, 7.0),\n  '(M33)': (36.0,115.0, 8.0, 9.2),\n  'M36':   (39.0,125.0, 8.0, 9.2)\n  }\n\n\n\n\n# ISO 4757:1983 Definition of cross recess type H\n#          b, e_min, g, f_mean, r, t1, alpha, beta\niso4757def = {\n  '0': (0.61, 0.26, 0.81, 0.34, 0.3, 0.22, 138.0, 7.0 ),\n  '1': (0.97, 0.41, 1.27, 0.54, 0.5, 0.34, 138.0, 7.0 ),\n  '2': (1.47, 0.79, 2.29, 0.70, 0.6, 0.61, 140.0, 5.75),\n  '3': (2.41, 1.98, 3.81, 0.83, 0.8, 1.01, 146.0, 5.75),\n  '4': (3.48, 2.39, 5.08, 1.23, 1.0, 1.35, 153.0, 7.0 )\n  }\n\n# ISO 10664 Hexalobular internal driving feature for bolts and screws\n#           A,     B,   Re\niso10664def = {\n  'T6': ( 1.75,  1.205, 0.14),\n  'T8': ( 2.40,  1.67, 0.20),\n  'T10':( 2.80,  1.98, 0.24),\n  'T15':( 3.35,  2.35, 0.28),\n  'T20':( 3.95,  2.75, 0.32),\n  'T25':( 4.50,  3.16, 0.39),\n  'T30':( 5.60,  3.95, 0.46),\n  'T40':( 6.75,  4.76, 0.56),\n  'T45':( 7.93,  5.55, 0.59),\n  'T50':( 8.95,  6.36, 0.78),\n  'T55':(11.35,  7.92, 0.77),\n  'T60':(13.45,  9.48, 1.07),\n  'T70':(15.70, 11.08, 1.20),\n  'T80':(17.75, 12.64, 1.53),\n  'T90':(20.20, 14.22, 1.54),\n  'T100':(22.40,15.81, 1.73)\n  }\n\n\n\n# ISO 4032 Hex-head-nut\n#           P,   c,  damax, dw,    e,     m,  mw,  s_nom\niso4032def={\n  'M1.6':  (0.35, 0.2, 1.84, 2.9,  3.4,   1.3, 0.8,  3.2),\n  'M2':    (0.40, 0.2, 2.3,  3.7,  4.4,   1.6, 1.1,  4.0),\n  'M2.5':  (0.45, 0.2, 2.9,  4.6,  5.5,   2.0, 1.4,  5.0),\n  'M3':    (0.5,  0.2, 3.45, 5.2,  6.1,   2.4, 1.7,  5.5),\n  '(M3.5)':(0.6,  0.2, 4.00, 5.7,  6.6,   2.8, 2.0,  6.0),\n  'M4':    (0.7,  0.2, 4.6,  6.6,  7.7,   3.2, 2.3,  7.0),\n  'M5':    (0.8,  0.2, 5.75, 7.5,  8.9,   3.5, 3.5,  8.0),\n  'M6':    (1.0,  0.2, 6.75, 9.5,  11.05, 4.7, 3.9, 10.0),\n  'M8':    (1.25, 0.3, 8.75, 11.7, 14.5,  6.8, 5.2, 13.0),\n  'M10':   (1.50, 0.3, 10.8, 14.7, 17.9,  8.4, 6.4,  16.0),\n  'M12':   (1.75, 0.3, 13.0, 16.7, 20.1, 10.8, 8.3,  18.0),\n  '(M14)': (2.00, 0.3, 15.1, 20.5, 24.5, 12.8, 9.7,  22.0),\n  'M16':   (2.00, 0.4, 17.3, 22.4, 26.9, 14.8, 11.3,  24.0),\n  '(M18)': (2.50, 0.4, 19.5, 24.9, 29.6, 15.8, 12.3,  27.0),\n  'M20':   (2.50, 0.4, 21.6, 28.2, 33.7, 18.0, 13.5,  30.0),\n  '(M22)': (2.50, 0.4, 23.7, 31.4, 37.3, 19.4, 15.0,  34.0),\n  'M24':   (3.00, 0.4, 25.9, 33.7, 40.1, 21.5, 16.2,  36.0),\n  '(M27)': (3.00, 0.4, 29.1, 38.0, 45.2, 23.8, 18.0,  41.0),\n  'M30':   (3.50, 0.4, 32.4, 42.8, 50.9, 25.6, 19.4,  46.0),\n  '(M33)': (3.50, 0.4, 35.6, 46.6, 55.4, 28.7, 21.4,  50.0),\n  'M36':   (4.00, 0.4, 38.9, 51.2, 61.0, 31.0, 23.5,  55.0),\n  '(M39)': (4.00, 0.5, 42.1, 55.9, 66.5, 33.4, 24.5,  60.0),\n  'M42':   (4.50, 0.7, 45.4, 60.0, 71.3, 34.0, 25.9,  65.0),\n  '(M45)': (4.50, 0.7, 48.6, 64.7, 77.0, 36.0, 27.9,  70.0),\n  'M48':   (5.00, 0.7, 51.8, 69.5, 82.6, 38.0, 29.1,  75.0),\n  '(M52)': (5.00, 0.7, 56.2, 74.5, 88.3, 42.0, 32.1,  80.0),\n  'M56':   (5.50, 0.7, 60.5, 78.7, 93.6, 45.0, 34.7,  85.0),\n  '(M60)': (5.50, 0.7, 64.8, 82.7, 99.2, 48.0, 38.7,  90.0),\n  'M64':   (6.00, 0.7, 69.1, 88.2,104.9, 51.0, 39.3,  95.0)\n  }\n\n\n\n# ISO 4033 Hexagon nuts style 2\n#           P,   c,  damax, dw,    e,     m,  mw,  s_nom\niso4033def={\n  'M5':    (0.8,  0.2, 5.75, 7.5,  8.9,   5.1, 3.5,  8.0),\n  'M6':    (1.0,  0.2, 6.75, 9.5,  11.05, 5.7, 3.9, 10.0),\n  'M8':    (1.25, 0.3, 8.75, 11.7, 14.5,  7.5, 5.2, 13.0),\n  'M10':   (1.50, 0.3, 10.8, 14.7, 17.9,  9.3, 6.4,  16.0),\n  'M12':   (1.75, 0.3, 13.0, 16.7, 20.1, 12.0, 8.3,  18.0),\n  '(M14)': (2.00, 0.3, 15.1, 20.5, 24.5, 14.1, 9.7,  22.0),\n  'M16':   (2.00, 0.4, 17.3, 22.4, 26.9, 16.4, 11.3,  24.0),\n  'M20':   (2.50, 0.4, 21.6, 28.2, 33.7, 20.3, 13.5,  30.0),\n  'M24':   (3.00, 0.4, 25.9, 33.7, 40.1, 23.9, 16.2,  36.0),\n  'M30':   (3.50, 0.4, 32.4, 42.8, 50.9, 28.6, 19.4,  46.0),\n  'M36':   (4.00, 0.4, 38.9, 51.2, 61.0, 33.1, 23.5,  55.0)\n  }\n\n# ISO 4035 Hexagon thin nuts, chamfered\n#           P,   c,  damax, dw,    e,     m,  mw,  s_nom\niso4035def={\n  'M1.6':  (0.35, 0.2, 1.84, 2.9,  3.4,   1.0,  0.8,  3.2),\n  'M2':    (0.40, 0.2, 2.3,  3.7,  4.4,   1.2,  1.1,  4.0),\n  'M2.5':  (0.45, 0.2, 2.9,  4.6,  5.5,   1.6,  1.4,  5.0),\n  'M3':    (0.5,  0.2, 3.45, 5.2,  6.1,   1.8,  1.7,  5.5),\n  '(M3.5)':(0.6,  0.2, 4.00, 5.7,  6.6,   2.0,  2.0,  6.0),\n  'M4':    (0.7,  0.2, 4.6,  6.6,  7.7,   2.2,  2.3,  7.0),\n  'M5':    (0.8,  0.2, 5.75, 7.5,  8.9,   2.7,  3.5,  8.0),\n  'M6':    (1.0,  0.2, 6.75, 9.5,  11.05, 3.2,  3.9, 10.0),\n  'M8':    (1.25, 0.3, 8.75, 11.7, 14.5,  4.0,  5.2, 13.0),\n  'M10':   (1.50, 0.3, 10.8, 14.7, 17.9,  5.0,  6.4, 16.0),\n  'M12':   (1.75, 0.3, 13.0, 16.7, 20.1,  6.0,  8.3, 18.0),\n  '(M14)': (2.00, 0.3, 15.1, 20.5, 24.5,  7.0,  9.7, 22.0),\n  'M16':   (2.00, 0.4, 17.3, 22.4, 26.9,  8.0, 11.3, 24.0),\n  '(M18)': (2.50, 0.4, 19.5, 24.9, 29.6,  9.0, 12.3, 27.0),\n  'M20':   (2.50, 0.4, 21.6, 28.2, 33.7, 10.0, 13.5, 30.0),\n  '(M22)': (2.50, 0.4, 23.7, 31.4, 37.3, 11.0, 15.0, 34.0),\n  'M24':   (3.00, 0.4, 25.9, 33.7, 40.1, 12.0, 16.2, 36.0),\n  '(M27)': (3.00, 0.4, 29.1, 38.0, 45.2, 13.5, 18.0, 41.0),\n  'M30':   (3.50, 0.4, 32.4, 42.8, 50.9, 15.0, 19.4, 46.0),\n  '(M33)': (3.50, 0.4, 35.6, 46.6, 55.4, 16.5, 21.4, 50.0),\n  'M36':   (4.00, 0.4, 38.9, 51.2, 61.0, 18.0, 23.5, 55.0),\n  '(M39)': (4.00, 0.5, 42.1, 55.9, 66.5, 19.5, 24.5, 60.0),\n  'M42':   (4.50, 0.7, 45.4, 60.0, 71.3, 21.0, 25.9, 65.0),\n  '(M45)': (4.50, 0.7, 48.6, 64.7, 77.0, 22.5, 27.9, 70.0),\n  'M48':   (5.00, 0.7, 51.8, 69.5, 82.6, 24.0, 29.1, 75.0),\n  '(M52)': (5.00, 0.7, 56.2, 74.5, 88.3, 26.0, 32.1, 80.0),\n  'M56':   (5.50, 0.7, 60.5, 78.7, 93.6, 28.0, 34.7, 85.0),\n  '(M60)': (5.50, 0.7, 64.8, 82.7, 99.2, 30.0, 38.7, 90.0),\n  'M64':   (6.00, 0.7, 69.1, 88.2,104.9, 32.0, 39.3, 95.0)\n  }\n\n# ISO 4036 Hexagon thin nuts, unchamfered\n#           P,      e,   m,  s_nom\niso4036def={\n  'M1.6':  (0.35,  3.4, 1.0,  3.2),\n  'M2':    (0.40,  4.4, 1.2,  4.0),\n  'M2.5':  (0.45,  5.5, 1.6,  5.0),\n  'M3':    (0.5,   6.1, 1.8,  5.5),\n  '(M3.5)':(0.6,   6.6, 2.0,  6.0),\n  'M4':    (0.7,   7.7, 2.2,  7.0),\n  'M5':    (0.8,   8.9, 2.7,  8.0),\n  'M6':    (1.0,  10.9, 3.2, 10.0),\n  'M8':    (1.25, 14.5, 4.0, 13.0),\n  'M10':   (1.50, 17.9, 5.0, 16.0)}\n\n# EN 1661 Hexagon nuts with flange\n#          P,    damax,  c,  dc,    dw,    e,     m,   mw,   r,   s\nen1661def={\n  'M5'   :(0.80,  5.75, 1.0, 11.8,  9.8,  8.79,  5.0, 2.5,  0.30,  8.0),\n  'M6'   :(1.00,  6.75, 1.1, 14.2, 12.2, 11.05,  6.0, 3.1,  0.36, 10.0),\n  'M8'   :(1.25,  8.75, 1.2, 17.9, 15.8, 14.38,  8.0, 4.6,  0.48, 13.0),\n  'M10'  :(1.50, 10.80, 1.5, 21.8, 19.6, 17.77, 10.0, 5.9,  0.60, 16.0),\n  'M12'  :(1.75, 13.00, 1.8, 26.0, 23.8, 20.03, 12.0, 6.8,  0.72, 18.0),\n  '(M14)':(2.00, 15.10, 2.1, 29.9, 27.6, 23.36, 14.0, 7.7,  0.88, 21.0),\n  'M16'  :(2.00, 17.30, 2.4, 34.5, 31.9, 26.75, 16.0, 8.9,  0.96, 24.0),\n  'M20'  :(2.50, 21.60, 3.0, 42.8, 39.9, 33.23, 20.0,10.7,  1.20, 30.0)}\n\n# Tuning table to get valid shapes\n#         P, tunIn, tunEx\ntuningTable={\n  'M1.6':(0.35, 516, 516),\n  'M2':  (0.40, 515, 516),\n  'M2.5':(0.45, 515, 515),\n  'M3':  (0.5,  480, 502),\n  '(M3.5)':(0.6,  480, 502),\n  'M4':  (0.7,  510, 519), #last value needed for ISO7380\n  'M5':  (0.8,  510, 510),\n  'M6':  (1.0,  515, 515),\n  'M8':  (1.25, 516, 516),\n  'M10': (1.50, 515, 515),\n  'M12': (1.75, 513, 513),\n  '(M14)': (2.00, 513, 513),\n  'M16': (2.00, 513, 513),\n  'M20': (2.50, 513, 513),\n  'M24': (3.00, 513, 513),\n  '(M27)': (3.00, 513, 513),\n  'M30': (3.50, 513, 513),\n  '(M33)': (3.50, 513, 513),\n  'M36': (4.00, 513, 513),\n  'M42': (4.50, 515, 515),\n  '(M45)': (4.50, 515, 515),\n  'M48': (5.00, 515, 505), # ISO4014: 505, 502 or 488; ISO4017: above 505\n  '(M52)': (5.00, 508, 508),\n  'M56': (5.50, 508, 508),\n  '(M60)': (5.50, 508, 508),\n  'M64': (6.00, 489, 489) # Nut ISO4032: 489\n  }\n\n\ndef equal_vertex(vert1, vert2, p=5):\n  # compares two vertices\n  return (round(vert1.X - vert2.X,p)==0 and round(vert1.Y - vert2.Y,p)==0 and round(vert1.Z - vert2.Z,p)==0)\n\ntry:\n  _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n  _fromUtf8 = lambda s: s\n\nclass Ui_ScrewMaker(object):\n  def setupUi(self, ScrewMaker):\n    FCUi = FreeCADGui.UiLoader()\n\n    ScrewMaker.setObjectName(_fromUtf8(\"ScrewMaker\"))\n    ScrewMaker.resize(450, 362)\n    ScrewMaker.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedKingdom))\n    self.layoutWidget = QtGui.QWidget(ScrewMaker)\n    self.layoutWidget.setGeometry(QtCore.QRect(348, 35, 102, 161))\n    self.layoutWidget.setObjectName(_fromUtf8(\"layoutWidget\"))\n    self.verticalLayout_2 = QtGui.QVBoxLayout(self.layoutWidget)\n    #self.verticalLayout_2.setMargin(0)\n    self.verticalLayout_2.setObjectName(_fromUtf8(\"verticalLayout_2\"))\n    self.ScrewTypeLabel = QtGui.QLabel(self.layoutWidget)\n    self.ScrewTypeLabel.setObjectName(_fromUtf8(\"ScrewTypeLabel\"))\n    self.verticalLayout_2.addWidget(self.ScrewTypeLabel)\n    self.NomDiaLabel = QtGui.QLabel(self.layoutWidget)\n    self.NomDiaLabel.setObjectName(_fromUtf8(\"NomDiaLabel\"))\n    self.verticalLayout_2.addWidget(self.NomDiaLabel)\n    self.NomLenLabel = QtGui.QLabel(self.layoutWidget)\n    self.NomLenLabel.setObjectName(_fromUtf8(\"NomLenLabel\"))\n    self.verticalLayout_2.addWidget(self.NomLenLabel)\n    self.UserLenLabel = QtGui.QLabel(self.layoutWidget)\n    self.UserLenLabel.setObjectName(_fromUtf8(\"UserLenLabel\"))\n    self.verticalLayout_2.addWidget(self.UserLenLabel)\n\n    self.layoutWidget1 = QtGui.QWidget(ScrewMaker)\n    self.layoutWidget1.setGeometry(QtCore.QRect(3, 35, 350, 166))\n    #self.layoutWidget1.setGeometry(QtCore.QRect(10, 5, 315, 200))\n    self.layoutWidget1.setObjectName(_fromUtf8(\"layoutWidget1\"))\n    self.verticalLayout = QtGui.QVBoxLayout(self.layoutWidget1)\n    #self.verticalLayout.setMargin(0)\n    self.verticalLayout.setObjectName(_fromUtf8(\"verticalLayout\"))\n    self.ScrewType = QtGui.QComboBox(self.layoutWidget1)\n    self.ScrewType.setObjectName(_fromUtf8(\"ScrewType\"))\n    for i in range(33):\n      self.ScrewType.addItem(_fromUtf8(\"\"))  # 0\n\n    self.verticalLayout.addWidget(self.ScrewType)\n    self.NominalDiameter = QtGui.QComboBox(self.layoutWidget1)\n    self.NominalDiameter.setObjectName(_fromUtf8(\"NominalDiameter\"))\n    for i in range(52):\n      self.NominalDiameter.addItem(_fromUtf8(\"\")) # 0\n\n    self.verticalLayout.addWidget(self.NominalDiameter)\n    self.NominalLength = QtGui.QComboBox(self.layoutWidget1)\n    self.NominalLength.setObjectName(_fromUtf8(\"NominalLength\"))\n    for i in range(48):\n      self.NominalLength.addItem(_fromUtf8(\"\")) #0\n\n    self.verticalLayout.addWidget(self.NominalLength)\n    #self.UserLen = QtGui.QComboBox(self.layoutWidget1)\n    self.UserLen = FCUi.createWidget(\"Gui::InputField\")\n    self.UserLen.setObjectName(_fromUtf8(\"UserLen\"))\n    #self.UserLen.addItem(_fromUtf8(\"\"))\n    self.UserLen.setProperty(\"text\", \"0 mm\")\n    self.verticalLayout.addWidget(self.UserLen)\n\n    #self.CommentLabel = QtGui.QLabel(self.layoutWidget)\n    self.CommentLabel = QtGui.QLabel(ScrewMaker)\n    self.CommentLabel.setObjectName(_fromUtf8(\"CommentLabel\"))\n    self.CommentLabel.setGeometry(QtCore.QRect(10, 184, 411, 21))\n    #self.verticalLayout.addWidget(self.CommentLabel)\n\n    self.layoutWidget2 = QtGui.QWidget(ScrewMaker)\n    #self.layoutWidget2.setGeometry(QtCore.QRect(10, 200, 321, 83))\n    self.layoutWidget2.setGeometry(QtCore.QRect(3, 200, 321, 120))\n    self.layoutWidget2.setObjectName(_fromUtf8(\"layoutWidget2\"))\n    self.verticalLayout_3 = QtGui.QVBoxLayout(self.layoutWidget2)\n    #self.verticalLayout_3.setMargin(0)\n    self.verticalLayout_3.setObjectName(_fromUtf8(\"verticalLayout_3\"))\n    self.SimpleScrew = QtGui.QRadioButton(self.layoutWidget2)\n    self.SimpleScrew.setChecked(True)\n    self.SimpleScrew.setObjectName(_fromUtf8(\"SimpleScrew\"))\n    self.verticalLayout_3.addWidget(self.SimpleScrew)\n    self.SymbolThread = QtGui.QRadioButton(self.layoutWidget2)\n    self.SymbolThread.setObjectName(_fromUtf8(\"SymbolThread\"))\n    self.verticalLayout_3.addWidget(self.SymbolThread)\n    self.RealThread = QtGui.QRadioButton(self.layoutWidget2)\n    self.RealThread.setObjectName(_fromUtf8(\"RealThread\"))\n    self.verticalLayout_3.addWidget(self.RealThread)\n    self.MessageLabel = QtGui.QLabel(ScrewMaker)\n    self.MessageLabel.setGeometry(QtCore.QRect(10, 10, 411, 21))\n    self.MessageLabel.setProperty(\"Empty_text\", _fromUtf8(\"\"))\n    self.MessageLabel.setObjectName(_fromUtf8(\"MessageLabel\"))\n    self.CreateButton = QtGui.QToolButton(ScrewMaker)\n    self.CreateButton.setGeometry(QtCore.QRect(180, 320, 111, 26))\n    self.CreateButton.setObjectName(_fromUtf8(\"CreateButton\"))\n    self.ScrewAvailable = True\n\n    self.simpThread = self.SimpleScrew.isChecked()\n    self.symThread = self.SymbolThread.isChecked()\n    self.rThread = self.RealThread.isChecked()\n\n    self.theScrew = Screw()\n\n    self.retranslateUi(ScrewMaker)\n    self.NominalDiameter.setCurrentIndex(5)\n    self.NominalLength.setCurrentIndex(9)\n    QtCore.QObject.connect(self.ScrewType, QtCore.SIGNAL(_fromUtf8(\"currentIndexChanged(int)\")), self.guiCheck_Data)\n    QtCore.QObject.connect(self.CreateButton, QtCore.SIGNAL(_fromUtf8(\"pressed()\")), self.guiCreateScrew)\n    QtCore.QObject.connect(self.NominalDiameter, QtCore.SIGNAL(_fromUtf8(\"currentIndexChanged(int)\")), self.guiCheck_Data)\n    QtCore.QObject.connect(self.NominalLength, QtCore.SIGNAL(_fromUtf8(\"currentIndexChanged(int)\")), self.guiCheck_Data)\n    QtCore.QMetaObject.connectSlotsByName(ScrewMaker)\n\n  def retranslateUi(self, ScrewMaker):\n    ScrewMaker.setWindowTitle(tr('ScrewMaker', 'Screw-Maker 2.2'))\n    self.ScrewTypeLabel.setText(tr('ScrewMaker', 'Type of Screw'))\n    self.NomDiaLabel.setText(tr('ScrewMaker', 'Nomimal\\nDiameter'))\n    self.NomLenLabel.setText(tr('ScrewMaker', 'Nominal\\nLength'))\n    self.UserLenLabel.setText(tr('ScrewMaker', 'User length \\nfor screw-tap'))\n    self.CommentLabel.setText(tr('ScrewMaker', 'Values in brackets are not recommended!'))\n    self.ScrewType.setItemText(0, tr('ScrewMaker', 'ISO4017: Hexagon head screws'))\n    self.ScrewType.setItemText(1, tr('ScrewMaker', 'ISO4014: Hexagon head bolts'))\n    self.ScrewType.setItemText(2, tr('ScrewMaker', 'EN1662: Hexagon bolts with flange, small\\n    series'))\n    self.ScrewType.setItemText(3, tr('ScrewMaker', 'EN1665: Hexagon bolts with flange, heavy\\n    series'))\n    self.ScrewType.setItemText(4, tr('ScrewMaker', 'ISO8676: Hexagon head screw with\\n    metric fine pitch thread'))\n    self.ScrewType.setItemText(5, tr('ScrewMaker', 'ISO4762: Hexagon socket head cap screws'))\n    self.ScrewType.setItemText(6, tr('ScrewMaker', 'ISO7380-1: Hexagon socket button head\\n    screws'))\n    self.ScrewType.setItemText(7, tr('ScrewMaker', 'ISO7380-2: Hexagon socket button head\\n    screws with collar'))\n    self.ScrewType.setItemText(8, tr('ScrewMaker', 'DIN967: Cross recessed pan head screws\\n    with collar'))\n    self.ScrewType.setItemText(9, tr('ScrewMaker', 'ISO10642: Hexagon socket countersunk \\n    head screws'))\n    self.ScrewType.setItemText(10, tr('ScrewMaker', 'ISO2009: Slotted countersunk flat head\\n    screws'))\n    self.ScrewType.setItemText(11, tr('ScrewMaker', 'ISO2010: Slotted raised countersunk head\\n    screws'))\n    self.ScrewType.setItemText(12, tr('ScrewMaker', 'ISO1207: Slotted cheese head screws'))\n    self.ScrewType.setItemText(13, tr('ScrewMaker', 'ISO1580: Slotted pan head screws'))\n    self.ScrewType.setItemText(14, tr('ScrewMaker', 'ISO7045: Pan head screws, type H cross recess'))\n    self.ScrewType.setItemText(15, tr('ScrewMaker', 'ISO7046: Countersunk flat head screws\\n    H cross recess'))\n    self.ScrewType.setItemText(16, tr('ScrewMaker', 'ISO7047: Raised countersunk head screws\\n    H cross recess'))\n    self.ScrewType.setItemText(17, tr('ScrewMaker', 'ISO7048: Cheese head screws type H cross recess'))\n    self.ScrewType.setItemText(18, tr('ScrewMaker', 'ISO14579: Hexalobular socket head cap screws'))\n    self.ScrewType.setItemText(19, tr('ScrewMaker', 'ISO14580: Hexalobular socket cheese head\\n    screws'))\n    self.ScrewType.setItemText(20, tr('ScrewMaker', 'ISO14583: Hexalobular socket pan head screws'))\n    self.ScrewType.setItemText(21, tr('ScrewMaker', 'ISO14582: Hexalobular socket countersunk\\n    head screws, high head'))\n    self.ScrewType.setItemText(22, tr('ScrewMaker', 'ISO14584: Hexalobular socket raised\\n    countersunk head screws'))\n    self.ScrewType.setItemText(23, tr('ScrewMaker', 'ISO7089: Plain washers - Normal series'))\n    self.ScrewType.setItemText(24, tr('ScrewMaker', 'ISO7090: Plain washers, chamfered - Normal series'))\n    self.ScrewType.setItemText(25, tr('ScrewMaker', 'ISO7092: Plain washers - Small series'))\n    self.ScrewType.setItemText(26, tr('ScrewMaker', 'ISO7093-1: Plain washer - Large series'))\n    self.ScrewType.setItemText(27, tr('ScrewMaker', 'ISO7094: Plain washers - Extra large series'))\n    self.ScrewType.setItemText(28, tr('ScrewMaker', 'ISO4032: Hexagon nuts, Style 1'))\n    self.ScrewType.setItemText(29, tr('ScrewMaker', 'ISO4033: Hexagon nuts, Style 2'))\n    self.ScrewType.setItemText(30, tr('ScrewMaker', 'ISO4035: Hexagon thin nuts, chamfered'))\n    self.ScrewType.setItemText(31, tr('ScrewMaker', 'EN1661: Hexagon nuts with flange'))\n    self.ScrewType.setItemText(32, tr('ScrewMaker', 'ScrewTap: ISO Screw-Tap'))\n\n    self.NominalDiameter.setItemText(0, tr('ScrewMaker', 'M1.6'))\n    self.NominalDiameter.setItemText(1, tr('ScrewMaker', 'M2'))\n    self.NominalDiameter.setItemText(2, tr('ScrewMaker', 'M2.5'))\n    self.NominalDiameter.setItemText(3, tr('ScrewMaker', 'M3'))\n    self.NominalDiameter.setItemText(4, tr('ScrewMaker', '(M3.5)'))\n    self.NominalDiameter.setItemText(5, tr('ScrewMaker', 'M4'))\n    self.NominalDiameter.setItemText(6, tr('ScrewMaker', 'M5'))\n    self.NominalDiameter.setItemText(7, tr('ScrewMaker', 'M6'))\n    self.NominalDiameter.setItemText(8, tr('ScrewMaker', 'M8'))\n    self.NominalDiameter.setItemText(9, tr('ScrewMaker', 'M10'))\n    self.NominalDiameter.setItemText(10, tr('ScrewMaker', 'M12'))\n    self.NominalDiameter.setItemText(11, tr('ScrewMaker', '(M14)'))\n    self.NominalDiameter.setItemText(12, tr('ScrewMaker', 'M16'))\n    self.NominalDiameter.setItemText(13, tr('ScrewMaker', '(M18)'))\n    self.NominalDiameter.setItemText(14, tr('ScrewMaker', 'M20'))\n    self.NominalDiameter.setItemText(15, tr('ScrewMaker', '(M22)'))\n    self.NominalDiameter.setItemText(16, tr('ScrewMaker', 'M24'))\n    self.NominalDiameter.setItemText(17, tr('ScrewMaker', '(M27)'))\n    self.NominalDiameter.setItemText(18, tr('ScrewMaker', 'M30'))\n    self.NominalDiameter.setItemText(19, tr('ScrewMaker', 'M36'))\n    self.NominalDiameter.setItemText(20, tr('ScrewMaker', '(M33)'))\n    self.NominalDiameter.setItemText(21, tr('ScrewMaker', 'M42'))\n    self.NominalDiameter.setItemText(22, tr('ScrewMaker', '(M45)'))\n    self.NominalDiameter.setItemText(23, tr('ScrewMaker', 'M48'))\n    self.NominalDiameter.setItemText(24, tr('ScrewMaker', '(M52)'))\n    self.NominalDiameter.setItemText(25, tr('ScrewMaker', 'M54'))\n    self.NominalDiameter.setItemText(26, tr('ScrewMaker', '(M60)'))\n    self.NominalDiameter.setItemText(27, tr('ScrewMaker', 'M64'))\n\n    self.NominalDiameter.setItemText(28, tr('ScrewMaker', 'M8x1'))\n    self.NominalDiameter.setItemText(29, tr('ScrewMaker', 'M10x1'))\n    self.NominalDiameter.setItemText(30, tr('ScrewMaker', '(M10x1.25)'))\n    self.NominalDiameter.setItemText(31, tr('ScrewMaker', 'M12x1.5'))\n    self.NominalDiameter.setItemText(32, tr('ScrewMaker', '(M12x1.25)'))\n    self.NominalDiameter.setItemText(33, tr('ScrewMaker', '(M14x1.5)'))\n    self.NominalDiameter.setItemText(34, tr('ScrewMaker', 'M16x1.5'))\n    self.NominalDiameter.setItemText(35, tr('ScrewMaker', '(M18x1.5)'))\n    self.NominalDiameter.setItemText(36, tr('ScrewMaker', 'M20x1.5'))\n    self.NominalDiameter.setItemText(37, tr('ScrewMaker', '(M20x2)'))\n    self.NominalDiameter.setItemText(38, tr('ScrewMaker', '(M22x1.5)'))\n    self.NominalDiameter.setItemText(39, tr('ScrewMaker', 'M24x2'))\n    self.NominalDiameter.setItemText(40, tr('ScrewMaker', '(M27x2)'))\n    self.NominalDiameter.setItemText(41, tr('ScrewMaker', 'M30x2'))\n    self.NominalDiameter.setItemText(42, tr('ScrewMaker', '(M33x2)'))\n    self.NominalDiameter.setItemText(43, tr('ScrewMaker', 'M36x3'))\n    self.NominalDiameter.setItemText(44, tr('ScrewMaker', '(M39x3)'))\n    self.NominalDiameter.setItemText(45, tr('ScrewMaker', 'M42x3'))\n    self.NominalDiameter.setItemText(46, tr('ScrewMaker', '(M45x3)'))\n    self.NominalDiameter.setItemText(47, tr('ScrewMaker', 'M48x3'))\n    self.NominalDiameter.setItemText(48, tr('ScrewMaker', '(M52x4)'))\n    self.NominalDiameter.setItemText(49, tr('ScrewMaker', 'M56x4'))\n    self.NominalDiameter.setItemText(50, tr('ScrewMaker', '(M60x4)'))\n    self.NominalDiameter.setItemText(51, tr('ScrewMaker', 'M64x4'))\n\n    self.NominalLength.setItemText(0, tr('ScrewMaker', '2'))\n    self.NominalLength.setItemText(1, tr('ScrewMaker', '2.5'))\n    self.NominalLength.setItemText(2, tr('ScrewMaker', '3'))\n    self.NominalLength.setItemText(3, tr('ScrewMaker', '4'))\n    self.NominalLength.setItemText(4, tr('ScrewMaker', '5'))\n    self.NominalLength.setItemText(5, tr('ScrewMaker', '6'))\n    self.NominalLength.setItemText(6, tr('ScrewMaker', '8'))\n    self.NominalLength.setItemText(7, tr('ScrewMaker', '10'))\n    self.NominalLength.setItemText(8, tr('ScrewMaker', '12'))\n    self.NominalLength.setItemText(9, tr('ScrewMaker', '16'))\n    self.NominalLength.setItemText(10, tr('ScrewMaker', '20'))\n    self.NominalLength.setItemText(11, tr('ScrewMaker', '25'))\n    self.NominalLength.setItemText(12, tr('ScrewMaker', '30'))\n    self.NominalLength.setItemText(13, tr('ScrewMaker', '35'))\n    self.NominalLength.setItemText(14, tr('ScrewMaker', '40'))\n    self.NominalLength.setItemText(15, tr('ScrewMaker', '45'))\n    self.NominalLength.setItemText(16, tr('ScrewMaker', '50'))\n    self.NominalLength.setItemText(17, tr('ScrewMaker', '55'))\n    self.NominalLength.setItemText(18, tr('ScrewMaker', '60'))\n    self.NominalLength.setItemText(19, tr('ScrewMaker', '65'))\n    self.NominalLength.setItemText(20, tr('ScrewMaker', '70'))\n    self.NominalLength.setItemText(21, tr('ScrewMaker', '80'))\n    self.NominalLength.setItemText(22, tr('ScrewMaker', '90'))\n    self.NominalLength.setItemText(23, tr('ScrewMaker', '100'))\n    self.NominalLength.setItemText(24, tr('ScrewMaker', '110'))\n    self.NominalLength.setItemText(25, tr('ScrewMaker', '120'))\n    self.NominalLength.setItemText(26, tr('ScrewMaker', '130'))\n    self.NominalLength.setItemText(27, tr('ScrewMaker', '140'))\n    self.NominalLength.setItemText(28, tr('ScrewMaker', '150'))\n    self.NominalLength.setItemText(29, tr('ScrewMaker', '160'))\n    self.NominalLength.setItemText(30, tr('ScrewMaker', '180'))\n    self.NominalLength.setItemText(31, tr('ScrewMaker', '200'))\n    self.NominalLength.setItemText(32, tr('ScrewMaker', '220'))\n    self.NominalLength.setItemText(33, tr('ScrewMaker', '240'))\n    self.NominalLength.setItemText(34, tr('ScrewMaker', '260'))\n    self.NominalLength.setItemText(35, tr('ScrewMaker', '280'))\n    self.NominalLength.setItemText(36, tr('ScrewMaker', '300'))\n    self.NominalLength.setItemText(37, tr('ScrewMaker', '320'))\n    self.NominalLength.setItemText(38, tr('ScrewMaker', '340'))\n    self.NominalLength.setItemText(39, tr('ScrewMaker', '360'))\n    self.NominalLength.setItemText(40, tr('ScrewMaker', '380'))\n    self.NominalLength.setItemText(41, tr('ScrewMaker', '400'))\n    self.NominalLength.setItemText(42, tr('ScrewMaker', '420'))\n    self.NominalLength.setItemText(43, tr('ScrewMaker', '440'))\n    self.NominalLength.setItemText(44, tr('ScrewMaker', '460'))\n    self.NominalLength.setItemText(45, tr('ScrewMaker', '480'))\n    self.NominalLength.setItemText(46, tr('ScrewMaker', '500'))\n    self.NominalLength.setItemText(47, tr('ScrewMaker', 'User'))\n    #self.UserLen.setItemText(0, tr('ScrewMaker', 'regular pitch'))\n    self.SimpleScrew.setText(tr('ScrewMaker', 'Simple Screw (no thread at all!)'))\n    self.SymbolThread.setText(tr('ScrewMaker', 'Symbol Thread (not implemented yet)'))\n    self.RealThread.setText(tr('ScrewMaker', 'Real Thread (takes time, memory intensive)\\nMay not work for all screws!'))\n    self.MessageLabel.setText(tr('ScrewMaker', 'Select your screw type'))\n    self.MessageLabel.setProperty('Errortext', tr('ScrewMaker', 'Combination not implemented'))\n    self.MessageLabel.setProperty('OK_text', tr('ScrewMaker', 'Screw is made'))\n    self.CreateButton.setText(tr('ScrewMaker', 'create'))\n\n  def guiCheck_Data(self):\n    ST_text = str(self.ScrewType.currentText())\n    ST_text = ST_text.split(':')[0]\n    ND_text = str(self.NominalDiameter.currentText())\n    NL_text = str(self.NominalLength.currentText())\n    M_text, self.ScrewAvailable  = self.theScrew.check_Data(ST_text, ND_text, NL_text)\n    self.MessageLabel.setText(tr('ScrewMaker', M_text))\n\n  def guiCreateScrew(self):\n    #self.simpThread = self.SimpleScrew.isChecked()\n    #self.symThread = self.SymbolThread.isChecked()\n    #self.rThread = self.RealThread.isChecked()\n    if self.SimpleScrew.isChecked():\n      threadType = 'simple'\n    if self.SymbolThread.isChecked():\n      threadType = 'symbol'\n    if self.RealThread.isChecked():\n      threadType = 'real'\n\n    ND_text = str(self.NominalDiameter.currentText())\n    NL_text = str(self.NominalLength.currentText())\n    ST_text = str(self.ScrewType.currentText())\n    ST_text = ST_text.split(':')[0]\n\n    if (ST_text == 'ScrewTap') or (ST_text == 'ISO8676'):\n      if NL_text == 'User':\n        textValue = self.UserLen.property(\"text\")\n        stLength = FreeCAD.Units.parseQuantity(textValue).Value\n        NL_text = str(stLength)\n\n    myObj = self.theScrew.createScrew(ST_text, ND_text, NL_text, threadType)\n\n\ndef get_diameter(thread_type):\n  \"\"\"Return the screw diameter as float\n\n  Accepted input format are e.g. 'M5', 'M8x1', '(M3.5)', '(M10x1.25)'.\n  \"\"\"\n  thread_string = thread_type.lstrip('(M').rstrip(')')\n  dia = float(thread_string.split('x')[0])\n  return dia\n\n\nclass Screw(object):\n  def __init__(self):\n    self.objAvailable = True\n    self.Tuner = 510\n    testCirc=Part.makeCircle(2.0,Base.Vector(0.0,0.0,-0.0),Base.Vector(0.0,0.0,-1.0))\n    testDisk = Part.Face(Part.Wire(testCirc))\n    z = testDisk.Surface.Axis.z\n    if z > 0:\n      self.circleAxis = Base.Vector(0.0,0.0,1.0)\n    else:\n      self.circleAxis = Base.Vector(0.0,0.0,-1.0)\n\n  def check_Data(self, ST_text, ND_text, NL_text):\n    #FreeCAD.Console.PrintMessage(\"Data checking\" + NL_text + \"\\n\")\n    #set screw not ok\n    self.objAvailable = False\n    M_text = \"Select your screw type\"\n    Type_text = ''\n    if ST_text == 'ISO4017':\n      table = iso4017head\n      tab_len = iso4017length\n      tab_range = iso4017range\n      Type_text = 'Screw'\n\n    if ST_text == 'EN1662':\n      table = en1662def\n      tab_len = en1662length\n      tab_range = en1662range\n      Type_text = 'Screw'\n\n    if ST_text == 'EN1665':\n      table = en1665def\n      tab_len = en1665length\n      tab_range = en1665range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO8676':\n      table = iso8676def\n      tab_len = iso8676length\n      tab_range = iso8676range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO2009':\n      table = iso2009def\n      tab_len = iso2009length\n      tab_range = iso2009range\n      Type_text = 'Screw'\n    if ST_text == 'ISO2010':\n      table = iso2009def\n      tab_len = iso2009length\n      tab_range = iso2009range\n      Type_text = 'Screw'\n    if ST_text == 'ISO4762':\n      table = iso4762def\n      tab_len = iso4762length\n      tab_range = iso4762range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO10642':\n      table = iso10642def\n      tab_len = iso10642length\n      tab_range = iso10642range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO4014':\n      table = iso4014head\n      tab_len = iso4014length\n      tab_range = iso4014range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO1207':\n      table = iso1207def\n      tab_len = iso1207length\n      tab_range = iso1207range\n      Type_text = 'Screw'\n    if ST_text == 'ISO1580':\n      table = iso1580def\n      tab_len = iso2009length\n      tab_range = iso2009range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO7045':\n      table = iso7045def\n      tab_len = iso7045length\n      tab_range = iso7045range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO7046':\n      table = iso7046def  # contains only cross recess data\n      tab_len = iso7045length\n      tab_range = iso7046range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO7047':\n      table = iso2009def\n      tab_len = iso7045length\n      tab_range = iso7046range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO7048':\n      table = iso7048def\n      tab_len = iso7048length\n      tab_range = iso7048range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO7380-1':\n      table = iso7380def\n      tab_len = iso7380length\n      tab_range = iso7380range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO7380-2':\n      table = iso7380_2def\n      tab_len = iso7380length\n      tab_range = iso7380range\n      Type_text = 'Screw'\n\n    if ST_text == 'DIN967':\n      table = din967def\n      tab_len = din967length\n      tab_range = din967range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO14579':\n      table = iso14579def\n      tab_len = iso14579length\n      tab_range = iso14579range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO14580':\n      table = iso14580def\n      tab_len = iso14580length\n      tab_range = iso1207range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO14583':\n      table = iso14583def\n      tab_len = iso7045length\n      tab_range = iso7046range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO14584':\n      table = iso14584def\n      tab_len = iso7045length\n      tab_range = iso14584range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO14582':\n      table = iso14582def\n      tab_len = iso14582length\n      tab_range = iso14582range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO7089':\n      table = iso7089def\n      Type_text = 'Washer'\n\n    if ST_text == 'ISO7090':\n      table = iso7090def\n      Type_text = 'Washer'\n\n    if ST_text == 'ISO7091':\n      table = iso7091def\n      Type_text = 'Washer'\n\n    if ST_text == 'ISO7092':\n      table = iso7092def\n      Type_text = 'Washer'\n\n    if ST_text == 'ISO7093-1':\n      table = iso7093def\n      Type_text = 'Washer'\n\n    if ST_text == 'ISO7094':\n      table = iso7094def\n      Type_text = 'Washer'\n\n    if ST_text == 'ISO4032':\n      table = iso4032def\n      Type_text = 'Nut'\n\n    if ST_text == 'ISO4033':\n      table = iso4033def\n      Type_text = 'Nut'\n\n    if ST_text == 'ISO4035':\n      table = iso4035def\n      Type_text = 'Nut'\n\n    if ST_text == 'ISO4036':\n      table = iso4036def\n      Type_text = 'Nut'\n\n    if ST_text == 'EN1661':\n      table = en1661def\n      Type_text = 'Nut'\n\n    if ST_text == 'ScrewTap':\n      table = tuningTable\n      Type_text = 'Screw-Tap'\n\n    if ND_text not in table:\n       ND_min, ND_max = standard_diameters[ST_text]\n       M_text = ST_text+' has diameters from '+ ND_min +' to ' + ND_max + ' and not ' + ND_text +'!'\n       self.objAvailable = False\n       # set scew not ok\n    else:\n      if Type_text == 'Screw':\n        #NL_text = str(self.NominalLength.currentText())\n        NL_min, NL_max = tab_range[ND_text]\n        NL_min_float = float(NL_min)\n        NL_max_float = float(NL_max)\n        if (NL_text == 'User') and (ST_text != 'ISO8676'):\n          M_text = 'User length is only available for the screw-tab and ISO 8676!'\n          self.objAvailable = False\n        else:\n          if NL_text == 'User':\n            M_text = 'ISO 8676 with user length is ok!'\n            self.objAvailable = True\n          else:\n            NL_text_float = float(NL_text)\n            if (NL_text_float<NL_min_float)or(NL_text_float>NL_max_float)or(NL_text not in tab_len):\n              if '(' in ND_text:\n                ND_text = ND_text.lstrip('(').rstrip(')')\n              M_text = ST_text+'-'+ ND_text +' has lengths from '+ NL_min +' to ' + NL_max + ' and not ' + NL_text +'!'\n              self.objAvailable = False\n              # set screw not ok\n            else:\n              if '(' in ND_text:\n                ND_text = ND_text.lstrip('(').rstrip(')')\n              M_text = ST_text+'-'+ ND_text +'x'+ NL_text +' is in library available! '\n              self.objAvailable = True\n              #set screw ok\n      else: # Washers and Nuts\n        if Type_text != 'Screw-Tap':\n          if '(' in ND_text:\n            ND_text = ND_text.lstrip('(').rstrip(')')\n          M_text = ST_text+'-'+ ND_text +' is available in library!'\n          self.objAvailable = True\n          #set washer/nut ok\n        else:\n          if NL_text == 'User':\n            M_text = 'Screw-tab with user length is ok!'\n            self.objAvailable = True\n          else:\n            #NL_text = str(self.NominalLength.currentText())\n            if '(' in ND_text:\n              ND_text = ND_text.lstrip('(').rstrip(')')\n            M_text = ST_text+'-'+ ND_text +' with '+ NL_text +'mm length is available in library!'\n            self.objAvailable = True\n            #set screwTap ok\n\n    #print \"Data checking: \", self.NominalLength.currentText(), \"\\n\"\n    #FreeCAD.Console.PrintMessage(\"Set Check_result into text \" + str(self.objAvailable) + M_text + \"\\n\")\n    return M_text, self.objAvailable\n\n\n  def createScrew(self, ST_text, ND_text, NL_text, threadType):\n    #self.simpThread = self.SimpleScrew.isChecked()\n    #self.symThread = self.SymbolThread.isChecked()\n    #self.rThread = self.RealThread.isChecked()\n    if threadType == 'real':\n      self.rThread = True\n    else:\n      self.rThread = False\n\n    if self.objAvailable:\n      try:\n        # first we check if valid numbers have been entered\n        #FreeCAD.Console.PrintMessage(\"NominalLength: \" + self.NominalLength.currentText() + \"\\n\")\n        #FreeCAD.Console.PrintMessage(\"NominalDiameter: \" + self.NominalDiameter.currentText() + \"\\n\")\n        #FreeCAD.Console.PrintMessage(\"SimpleThread: \" + str(self.SimpleScrew.isChecked()) + \"\\n\")\n        #FreeCAD.Console.PrintMessage(\"SymbolThread: \" + str(self.SymbolThread.isChecked()) + \"\\n\")\n        #FreeCAD.Console.PrintMessage(\"RealThread: \" + str(self.RealThread.isChecked()) + \"\\n\")\n\n        #ND_text = str(self.NominalDiameter.currentText())\n        #NL_text = str(self.NominalLength.currentText())\n        #ST_text = str(self.ScrewType.currentText())\n        #ST_text = ST_text.split(':')[0]\n        #dia = float(ND_text.lstrip('M'))\n        l = float(NL_text)\n        if ST_text == 'ISO4017':\n           table = iso4017head\n        if ST_text == 'ISO4014':\n           table = iso4014head\n        if ST_text == 'EN1662':\n           table = en1662def\n        if ST_text == 'EN1665':\n           table = en1665def\n        if ST_text == 'ISO8676':\n           table = iso8676def\n        if ST_text == 'ISO2009':\n           table = iso2009def\n        if ST_text == 'ISO2010':\n           table = iso2009def\n        if ST_text == 'ISO4762':\n           table = iso4762def\n        if ST_text == 'ISO10642':\n           table = iso10642def\n        if ST_text == 'ISO1207':\n           table = iso1207def\n        if ST_text == 'ISO1580':\n           table = iso1580def\n        if ST_text == 'ISO7045':\n           table = iso7045def\n        if ST_text == 'ISO7046':\n           table = iso7045def\n        if ST_text == 'ISO7047':\n           table = iso7045def\n        if ST_text == 'ISO7048':\n           table = iso7048def\n        if ST_text == 'ISO7380-1':\n           table = iso7380def\n        if ST_text == 'ISO7380-2':\n           table = iso7380_2def\n        if ST_text == 'DIN967':\n           table = din967def\n        if ST_text == 'ISO14579':\n           table = iso14579def\n        if ST_text == 'ISO14580':\n           table = iso14580def\n        if ST_text == 'ISO14582':\n           table = iso14582def\n        if ST_text == 'ISO14583':\n           table = iso14583def\n        if ST_text == 'ISO14584':\n           table = iso14584def\n        if ST_text == 'ISO7089':\n           table = iso7089def\n        if ST_text == 'ISO7090':\n           table = iso7090def\n        if ST_text == 'ISO7091':\n           table = iso7091def\n        if ST_text == 'ISO7092':\n           table = iso7092def\n        if ST_text == 'ISO7093-1':\n           table = iso7093def\n        if ST_text == 'ISO7094':\n           table = iso7094def\n        if ST_text == 'ISO4032':\n           table = iso4032def\n        if ST_text == 'ISO4033':\n           table = iso4033def\n        if ST_text == 'ISO4035':\n           table = iso4035def\n        if ST_text == 'ISO4036':\n           table = iso4036def\n        if ST_text == 'EN1661':\n           table = en1661def\n        if ST_text == 'ScrewTap':\n           table = tuningTable\n        if ND_text not in table:\n           FreeCAD.Console.PrintMessage(\"Combination of type \"+ST_text \\\n              + \" and diameter \" + ND_text +\" not available!\" + \"\\n\")\n        #self.MessageLabel.setText(tr('ScrewMaker', 'not implemented'))\n\n      except ValueError:\n        #print \"Error! nom_dia and length values must be valid numbers!\"\n        FreeCAD.Console.PrintMessage(\"Error! nom_dia and length values must be valid numbers!\\n\")\n      else:\n        doc=FreeCAD.activeDocument()\n        done = False\n        if (ST_text == 'ISO4014') or (ST_text == 'ISO4017') or (ST_text == 'ISO8676'):\n          screw = self.makeIso4017_2(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'EN1662') or (ST_text == 'EN1665'):\n          screw = self.makeEN1662_2(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'ISO2009') or (ST_text == 'ISO2010') or (ST_text == 'ISO1580'):\n          screw = self.makeSlottedScrew(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'ISO4762') or (ST_text == 'ISO14579'):\n          screw = self.makeIso4762(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'ISO1207') or (ST_text == 'ISO14580') or (ST_text == 'ISO7048'):\n          screw = self.makeIso1207(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'ISO7045') or (ST_text == 'ISO14583'):\n          screw = self.makeIso7045(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'ISO7046') or (ST_text == 'ISO7047') or \\\n          (ST_text == 'ISO14582') or (ST_text == 'ISO14584') or (ST_text == 'ISO10642'):\n          screw = self.makeIso7046(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'ISO7380-1') or (ST_text == 'ISO7380-2') or (ST_text == 'DIN967'):\n          screw = self.makeIso7380(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'ISO7089') or (ST_text == 'ISO7090') or (ST_text == 'ISO7093-1') or \\\n          (ST_text == 'ISO7091') or (ST_text == 'ISO7092') or (ST_text == 'ISO7094'):\n          screw = self.makeIso7089(ST_text, ND_text)\n          Type_text = 'Washer'\n          done = True\n        if (ST_text == 'ISO4032') or (ST_text == 'ISO4033') or (ST_text == 'ISO4035'):\n          screw = self.makeIso4032(ST_text, ND_text)\n          Type_text = 'Nut'\n          done = True\n        if ST_text == 'EN1661':\n          screw = self.makeEN1661(ND_text)\n          Type_text = 'Nut'\n          done = True\n        if ST_text == 'ScrewTap':\n          screw = self.makeScrewTap(ND_text,l)\n          Type_text = 'Screw-Tap'\n          done = True\n        if not done:\n          FreeCAD.Console.PrintMessage(\"No valid Screw Type!\" +  \"\\n\")\n        if '(' in ND_text:\n          ND_text = ND_text.lstrip('(').rstrip(')')\n\n        if Type_text == 'Screw':\n          label = ST_text + \"-\" + ND_text +\"x\"+ NL_text +\"_\"\n        else:\n          if (Type_text == 'Nut'):\n            label = ST_text + '-' + ND_text +'_'\n          else:\n            if Type_text == 'Screw-Tap':\n              label = ST_text + '-' + ND_text +'x'+ NL_text +'_'\n            else: # washer\n              label = ST_text + '-' + ND_text.lstrip('M') +'_'\n        ScrewObj = doc.addObject(\"Part::Feature\")\n        ScrewObj.Label=label\n        ScrewObj.Shape=screw\n        #FreeCAD.Console.PrintMessage(\"Placement: \"+ str(ScrewObj.Placement) +\"\\n\")\n        #FreeCAD.Console.PrintMessage(\"The label: \"+ label +\"\\n\")\n        self.moveScrew(ScrewObj)\n        #ScrewObj.Label = label\n        if self.gotPart:\n          self.thePart.addObject(ScrewObj)\n        doc.recompute()\n        # Part.show(screw)\n        return ScrewObj\n\n  def getFaceAxis(self, sp, c):\n    fList = []\n    fAxis = None\n    if len(c.Vertexes) ==1:\n      theVert = c.Vertexes[0]\n      # search for faces which have a vertex equal to theVert.\n      for f in sp.Faces:\n        for v in f.Vertexes:\n          if equal_vertex(v, theVert):\n            fList.append(f)\n    print (str(fList))\n    # search for a plane face\n    for f in fList:\n      if hasattr(f,'Surface'):\n        FreeCAD.Console.PrintMessage('type of surface: ', str(f.Surface))\n        if f.Surface.isPlanar():\n          fAxis = f.Surface.normal(0,0)\n          print ('got planar Face with normal: ', str(f.Surface.normal(0,0)))\n          print ('Orientation: ', str(f.Orientation))\n          if f.Orientation == 'Reversed':\n            fAxis = fAxis.multiply(-1.0)\n    return fAxis\n\n  def moveScrew(self, ScrewObj_m):\n    #FreeCAD.Console.PrintMessage(\"In Move Screw: \" + str(ScrewObj_m) + \"\\n\")\n    self.gotBody = False\n    self.gotPart = False\n\n    mylist = FreeCAD.Gui.Selection.getSelectionEx()\n    if (mylist.__len__() == 1):\n       # check selection\n       #FreeCAD.Console.PrintMessage(\"Selektionen: \" + str(mylist.__len__()) + \"\\n\")\n       Pnt1 = None\n       Axis1 = None\n       Axis2 = None\n       theSelection = mylist[0]\n       #FreeCAD.Console.PrintMessage( \"ObjectName: \" + str(theSelection.ObjectName) + \"\\n\")\n       if hasattr(theSelection, 'Object'):\n         if hasattr(theSelection.Object, 'InList'):\n           inLength = len(theSelection.Object.InList)\n           #FreeCAD.Console.PrintMessage( \"InList: \" + str(theSelection.Object.InList) + \"\\n\")\n           for b in theSelection.Object.InList:\n             #FreeCAD.Console.PrintMessage( \"OType: \" + str(b.TypeId) + \"\\n\")\n             if b.TypeId == 'PartDesign::Body':\n               self.gotBody = True\n               self.bPlacement = b.Placement\n               for par in b.InList:\n                 if par.TypeId == 'App::Part':\n                   self.gotPart = True\n                   self.thePart = par\n\n                   break\n\n       for o in FreeCADGui.Selection.getSelectionEx():\n          #FreeCAD.Console.PrintMessage( \"name: \" + str(o) + \"\\n\")\n          #FreeCAD.Console.PrintMessage( \"Properties: \" + str(o.PropertiesList) + \"\\n\")\n\n          #for s in o.SubElementNames:\n             #FreeCAD.Console.PrintMessage( \"name: \" + str(s) + \"\\n\")\n          for s in o.SubObjects:\n             #FreeCAD.Console.PrintMessage( \"object: \"+ str(s) + \"\\n\")\n             #FreeCAD.Console.PrintMessage( \"Properties: \" + str(s.PropertiesList) + \"\\n\")\n             if hasattr(s,\"Curve\"):\n                #FreeCAD.Console.PrintMessage( \"The Object is a Curve!\\n\")\n                if hasattr(s.Curve,\"Center\"):\n                   \"\"\"\n                   FreeCAD.Console.PrintMessage( \"The object has a Center!\\n\")\n                   FreeCAD.Console.PrintMessage( \"Curve attribute. \"+ str(s.__getattribute__('Curve')) + \"\\n\")\n                   FreeCAD.Console.PrintMessage( \"Center: \"+ str(s.Curve.Center) + \"\\n\")\n                   FreeCAD.Console.PrintMessage( \"Axis: \"+ str(s.Curve.Axis) + \"\\n\")\n                   \"\"\"\n                   Pnt1 = s.Curve.Center\n                   Axis1 = s.Curve.Axis\n                   fAxis = self.getFaceAxis(o.Object.Shape, s)\n                   if fAxis:\n                     Axis1 = fAxis\n             if hasattr(s,'Surface'):\n                #print 'the object is a face!'\n                if hasattr(s.Surface,'Axis'):\n                   Axis1 = s.Surface.Axis\n\n             if hasattr(s,'Point'):\n                #FreeCAD.Console.PrintMessage( \"the object seems to be a vertex! \"+ str(s.Point) + \"\\n\")\n                Pnt1 = s.Point\n\n       if (Axis1 != None):\n          #FreeCAD.Console.PrintMessage( \"Got Axis1: \" + str(Axis1) + \"\\n\")\n          Axis2 = Base.Vector(0.0,0.0,1.0)\n          Axis2_minus = Base.Vector(0.0,0.0,-1.0)\n\n          # Calculate angle\n          if Axis1 == Axis2:\n             normvec = Base.Vector(1.0,0.0,0.0)\n             result = 0.0\n          else:\n             if Axis1 == Axis2_minus:\n                normvec = Base.Vector(1.0,0.0,0.0)\n                result = math.pi\n             else:\n                normvec = Axis1.cross(Axis2) # Berechne Achse der Drehung = normvec\n                normvec.normalize() # Normalisieren fuer Quaternionenrechnung\n                #normvec_rot = normvec\n                result = DraftVecUtils.angle(Axis1, Axis2, normvec) # Winkelberechnung\n          sin_res = math.sin(result/2.0)\n          cos_res = math.cos(result/2.0)\n          normvec.multiply(-sin_res) # Berechnung der Quaternionen-Elemente\n          #FreeCAD.Console.PrintMessage( \"Winkel = \"+ str(math.degrees(result)) + \"\\n\")\n          #FreeCAD.Console.PrintMessage(\"Normalvektor: \"+ str(normvec) + \"\\n\")\n\n          pl = FreeCAD.Placement()\n          pl.Rotation = (normvec.x,normvec.y,normvec.z,cos_res) #Drehungs-Quaternion\n\n          #FreeCAD.Console.PrintMessage(\"pl mit Rot: \"+ str(pl) + \"\\n\")\n          #neuPlatz = Part2.Object.Placement.multiply(pl)\n          neuPlatz = ScrewObj_m.Placement\n          FreeCAD.Console.PrintMessage(\"The Position     \"+ str(neuPlatz) + \"\\n\")\n          neuPlatz.Rotation = pl.Rotation.multiply(ScrewObj_m.Placement.Rotation)\n          # neuPlatz.move(Pnt1)\n          FreeCAD.Console.PrintMessage(\"The Position in Body    \"+ str(neuPlatz) + \"\\n\")\n          if self.gotBody:\n            FreeCAD.Console.PrintMessage(\"got Placement: \"+ str(self.bPlacement) + \"\\n\")\n            #neuPlatz.Rotation = neuPlatz.Rotation.multiply(self.bPlacement.Rotation)\n            neuPlatz.Rotation = neuPlatz.Rotation.multiply(self.bPlacement.Rotation)\n            Pnt1 = self.bPlacement.multVec(Pnt1)\n          neuPlatz.move(Pnt1)\n          #if self.gotBody:\n            #neuPlatz.move(self.bPlacement.Base)\n\n          # Python is not phytonic in FreeCAD 0.17, need to add allocation.\n          ScrewObj_m.Placement = neuPlatz\n          #FreeCAD.Console.PrintMessage(\"die rot. Position: \"+ str(neuPlatz) + \"\\n\")\n\n\n\n  # make Washer\n  def makeIso7089(self,SType ='ISO7089', ThreadType ='M6'):\n    dia = get_diameter(ThreadType)\n    #FreeCAD.Console.PrintMessage(\"die Scheibe mit dia: \" + str(dia) + \"\\n\")\n    if SType == 'ISO7089':\n      d1_min, d2_max, h, h_max = iso7089def[ThreadType]\n    if SType == 'ISO7090':\n      d1_min, d2_max, h, h_max = iso7090def[ThreadType]\n    if SType == 'ISO7091':\n      d1_min, d2_max, h, h_max = iso7091def[ThreadType]\n    if SType == 'ISO7092':\n      d1_min, d2_max, h, h_max = iso7092def[ThreadType]\n    if SType == 'ISO7093-1':\n      d1_min, d2_max, h, h_max = iso7093def[ThreadType]\n    if SType == 'ISO7094':\n      d1_min, d2_max, h, h_max = iso7094def[ThreadType]\n      #FreeCAD.Console.PrintMessage(\"got: \" + SType + \"\\n\")\n\n    #FreeCAD.Console.PrintMessage(\"die Scheibe mit d1_min: \" + str(d1_min) + \"\\n\")\n\n    #Washer Points\n    Pnt0 = Base.Vector(d1_min/2.0,0.0,h_max)\n    Pnt2 = Base.Vector(d2_max/2.0,0.0,h_max)\n    Pnt3 = Base.Vector(d2_max/2.0,0.0,0.0)\n    Pnt4 = Base.Vector(d1_min/2.0,0.0,0.0)\n    if SType == 'ISO7090':\n      Pnt1 = Base.Vector(d2_max/2.0-h_max/4.0,0.0,h_max)\n      Pnt2 = Base.Vector(d2_max/2.0,0.0,h_max*0.75)\n      edge1 = Part.makeLine(Pnt0,Pnt1)\n      edgeCham = Part.makeLine(Pnt1,Pnt2)\n      edge1 = Part.Wire([edge1, edgeCham])\n    else:\n      edge1 = Part.makeLine(Pnt0,Pnt2)\n\n    edge2 = Part.makeLine(Pnt2,Pnt3)\n    edge3 = Part.makeLine(Pnt3,Pnt4)\n    edge4 = Part.makeLine(Pnt4,Pnt0)\n    #FreeCAD.Console.PrintMessage(\"Edges made Pnt2: \" + str(Pnt2) + \"\\n\")\n\n    aWire=Part.Wire([edge1,edge2,edge3,edge4])\n    #Part.show(aWire)\n    aFace =Part.Face(aWire)\n    head = aFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #FreeCAD.Console.PrintMessage(\"Washer revolved: \" + str(dia) + \"\\n\")\n\n    return head\n\n\n  # make ISO 2009 Slotted countersunk flat head screws\n  # make ISO 2010 Slotted raised countersunk head screws\n  # make ISO 1580 Pan head slotted screw (Code is nearly identical to iso1207)\n  def makeSlottedScrew(self,SType ='ISO1580', ThreadType ='M6',l=25.0):\n    dia = get_diameter(ThreadType)\n    if SType == 'ISO1580':\n      #FreeCAD.Console.PrintMessage(\"der Kopf mit l: \" + str(l) + \"\\n\")\n      #P, a, b, dk, dk_mean, da, k, n_min, r, t_min, x = iso1580def[ThreadType]\n      P, a, b, dk_max, da, k, n_min, r, rf, t_min, x = iso1580def[ThreadType]\n      #FreeCAD.Console.PrintMessage(\"der Kopf mit iso: \" + str(dk_max) + \"\\n\")\n      ht = k\n      headEnd = r\n\n      #Length for calculation of head fillet\n      sqrt2_ = 1.0/math.sqrt(2.0)\n      r_fil = rf\n      beta = math.radians(5.0)   # angle of pan head edge\n      alpha = math.radians(90.0 - (90.0+5.0)/2.0)\n      tan_beta = math.tan(beta)\n      # top head diameter without fillet\n      rK_top = dk_max/2.0 - k * tan_beta\n      fillet_center_x = rK_top - r_fil + r_fil * tan_beta\n      fillet_center_z = k - r_fil\n      fillet_arc_x = fillet_center_x + r_fil * math.sin(alpha)\n      fillet_arc_z = fillet_center_z + r_fil * math.cos(alpha)\n      #FreeCAD.Console.PrintMessage(\"rK_top: \" + str(rK_top) + \"\\n\")\n      if (b > (l - 1.0*P)):\n        bmax = l- 1.0*P\n      else:\n        bmax = b\n\n      #Head Points\n      Pnt0 = Base.Vector(0.0,0.0,k)\n      Pnt2 = Base.Vector(fillet_center_x,0.0,k)\n      Pnt3 = Base.Vector(fillet_arc_x,0.0,fillet_arc_z)\n      Pnt4 = Base.Vector(fillet_center_x + r_fil*math.cos(beta),0.0,fillet_center_z+ r_fil * math.sin(beta))\n      Pnt5 = Base.Vector(dk_max/2.0,0.0,0.0)\n      Pnt6 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n      Pnt7 = Base.Vector(dia/2.0+r-r*sqrt2_,0.0,-r+r*sqrt2_) #arc-point of fillet\n      #Pnt8 = Base.Vector(dia/2.0,0.0,-r)        # end of fillet\n      PntR = Base.Vector(dia/2.0,0.0,-r)        # end of fillet\n      PntT0 = Base.Vector(0.0,0.0,-r)        # helper point for real thread\n\n      edge1 = Part.makeLine(Pnt0,Pnt2)\n      edge2 = Part.Arc(Pnt2,Pnt3,Pnt4).toShape()\n      edge3 = Part.makeLine(Pnt4,Pnt5)\n      edge4 = Part.makeLine(Pnt5,Pnt6)\n      edge5 = Part.Arc(Pnt6,Pnt7,PntR).toShape()\n      headWire=Part.Wire([edge1,edge2,edge3,edge4,edge5])\n\n    if (SType == 'ISO2009') or (SType == 'ISO2010'):\n      P, a, b, dk_theo, dk_mean, k, n_min, r, t_mean, x = iso2009def[ThreadType]\n      dk_max = dk_theo\n      t_min = t_mean\n      ht = 0.0 # Head height of flat head\n      if (SType == 'ISO2010'):\n        rf, t_mean, cT, mH, mZ = Raised_countersunk_def[ThreadType]\n        #Lengths and angles for calculation of head rounding\n        beta = math.asin(dk_mean /2.0 / rf)   # angle of head edge\n        tan_beta = math.tan(beta)\n        alpha = beta/2.0 # half angle\n        # height of raised head top\n        ht = rf - (dk_mean/2.0) / tan_beta\n        h_arc_x = rf * math.sin(alpha)\n        h_arc_z = ht - rf + rf * math.cos(alpha)\n\n      cham = (dk_theo - dk_mean)/2.0\n      rad225 = math.radians(22.5)\n      rad45 = math.radians(45.0)\n      rtan = r*math.tan(rad225)\n      headEnd = k + rtan\n\n      if (b > l - k - rtan/2.0 - 1.0*P):\n        bmax = l-k-rtan/2.0 - 1.0*P\n      else:\n        bmax = b\n\n      #Head Points\n      Pnt0 = Base.Vector(0.0,0.0,ht)\n      Pnt1 = Base.Vector(dk_mean/2.0,0.0,0.0)\n      Pnt2 = Base.Vector(dk_mean/2.0,0.0,-cham)\n      Pnt3 = Base.Vector(dia/2.0+r-r*math.cos(rad45),0.0,-k-rtan+r*math.sin(rad45))\n      # Arc-points\n      Pnt4 = Base.Vector(dia/2.0+r-r*(math.cos(rad225)),0.0,-k-rtan+r*math.sin(rad225))\n      PntR = Base.Vector(dia/2.0,0.0,-k-rtan)\n      #PntA = Base.Vector(dia/2.0,0.0,-a_point)\n      PntT0 = Base.Vector(0.0,0.0,-k-rtan)        # helper point for real thread\n\n      if (SType == 'ISO2010'): # make raised head rounding\n        Pnt0arc = Base.Vector(h_arc_x,0.0,h_arc_z)\n        edge1 = Part.Arc(Pnt0,Pnt0arc,Pnt1).toShape()\n      else:\n        edge1 = Part.makeLine(Pnt0,Pnt1)  # make flat head\n\n      edge2 = Part.makeLine(Pnt1,Pnt2)\n      edge3 = Part.makeLine(Pnt2,Pnt3)\n      edgeArc = Part.Arc(Pnt3,Pnt4,PntR).toShape()\n      headWire=Part.Wire([edge1,edge2,edge3,edgeArc])\n\n\n    ### make the new code with math.modf(l)\n    residue, turns = math.modf((bmax)/P)\n    halfturns = 2*int(turns)\n    if residue < 0.5:\n      a_point = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a_point = l - (turns+2.0) * P\n    #halfturns = halfturns + 2\n    offSet = headEnd - a_point\n    PntA = Base.Vector(dia/2.0,0.0,-a_point)        # Start of thread\n\n\n    if self.rThread:\n      edgeZ1 = Part.makeLine(PntR,PntT0)\n      edgeZ0 = Part.makeLine(PntT0,Pnt0)\n      aWire=Part.Wire([headWire, edgeZ1, edgeZ0])\n\n    else:\n      # bolt points\n      PntB1 = Base.Vector(dia/2.0,0.0,-l)\n      PntB2 = Base.Vector(0.0,0.0,-l)\n\n      edgeB2 = Part.makeLine(PntB1,PntB2)\n      edgeZ0 = Part.makeLine(PntB2,Pnt0)\n\n      if a_point <= r:\n        edgeB1 = Part.makeLine(PntR,PntB1)\n        aWire=Part.Wire([headWire, edgeB1, edgeB2, edgeZ0])\n      else:\n        edgeRA = Part.makeLine(PntR,PntA)\n        edgeB1 = Part.makeLine(PntA,PntB1)\n        aWire=Part.Wire([headWire, edgeRA, edgeB1, edgeB2, edgeZ0])\n\n    aFace =Part.Face(aWire)\n    head = aFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n\n    #Parameter for slot-recess: dk_max, n_min, k, t_min\n    slot = Part.makePlane(dk_max, n_min, \\\n        Base.Vector(dk_max/2.0,-n_min/2.0,ht+1.0),Base.Vector(0.0,0.0,-1.0))\n    slot = slot.extrude(Base.Vector(0.0,0.0,-t_min-1.0))\n    #Part.show(slot)\n    head = head.cut(slot)\n    #FreeCAD.Console.PrintMessage(\"der Kopf geschnitten: \" + str(dia) + \"\\n\")\n    #Part.show(head)\n\n    if self.rThread:\n      rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n      rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n      #Part.show(rthread)\n      headFaces = []\n      if (SType == 'ISO2009'):\n        for i in range(0,len(head.Faces)-2):\n          headFaces.append(head.Faces[i])\n        headFaces.append(head.Faces[len(head.Faces)-1])\n\n      if (SType == 'ISO1580') or (SType == 'ISO2010'):\n        for i in range(0,len(head.Faces)-1):\n          headFaces.append(head.Faces[i])\n\n      for threadFace in rthread.Faces:\n        headFaces.append(threadFace)\n\n      newHeadShell = Part.Shell(headFaces)\n      #Part.show(newHeadShell)\n      head = Part.Solid(newHeadShell)\n\n    return head\n\n\n\n\n\n\n  # ISO 7045 Pan head screws with type H or type Z cross recess\n  # ISO 14583 Hexalobular socket pan head screws\n  def makeIso7045(self, SType ='ISO7045', ThreadType ='M6',l=25.0):\n    dia = get_diameter(ThreadType)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit l: \" + str(l) + \"\\n\")\n    P, a, b, dk_max,da, k, r, rf, x, cT, mH, mZ  = iso7045def[ThreadType]\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit iso: \" + str(dk_max) + \"\\n\")\n\n    #Lengths and angles for calculation of head rounding\n    beta = math.asin(dk_max /2.0 / rf)   # angle of head edge\n    #print 'beta: ', math.degrees(beta)\n    tan_beta = math.tan(beta)\n\n\n    if SType == 'ISO14583':\n       tt, A, t_mean = iso14583def[ThreadType]\n       beta_A = math.asin(A/2.0 / rf)   # angle of recess edge\n       tan_beta_A = math.tan(beta_A)\n\n       alpha = (beta_A + beta)/2.0 # half angle\n       #print 'alpha: ', math.degrees(alpha)\n       # height of head edge\n       he = k - A/2.0/tan_beta_A + (dk_max/2.0) / tan_beta\n       #print 'he: ', he\n       h_arc_x = rf * math.sin(alpha)\n       h_arc_z = k - A/2.0/tan_beta_A + rf * math.cos(alpha)\n       #FreeCAD.Console.PrintMessage(\"h_arc_z: \" + str(h_arc_z) + \"\\n\")\n    else:\n       alpha = beta/2.0 # half angle\n       #print 'alpha: ', math.degrees(alpha)\n       # height of head edge\n       he = k - rf + (dk_max/2.0) / tan_beta\n       #print 'he: ', he\n       h_arc_x = rf * math.sin(alpha)\n       h_arc_z = k - rf + rf * math.cos(alpha)\n       #FreeCAD.Console.PrintMessage(\"h_arc_z: \" + str(h_arc_z) + \"\\n\")\n\n    if (b > (l - 1.0*P)):\n       bmax = l- 1.0*P\n    else:\n       bmax = b\n\n    ### make the new code with math.modf(l)\n    residue, turns = math.modf((bmax)/P)\n    halfturns = 2*int(turns)\n    if residue < 0.5:\n      a_point = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a_point = l - (turns+2.0) * P\n    #halfturns = halfturns + 2\n    offSet = r - a_point\n    #FreeCAD.Console.PrintMessage(\"The transition at a: \" + str(a) + \" turns \" + str(turns) + \"\\n\")\n\n    sqrt2_ = 1.0/math.sqrt(2.0)\n\n    #Head Points\n    Pnt1 = Base.Vector(h_arc_x,0.0,h_arc_z)\n    Pnt2 = Base.Vector(dk_max/2.0,0.0,he)\n    Pnt3 = Base.Vector(dk_max/2.0,0.0,0.0)\n    Pnt4 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n    Pnt5 = Base.Vector(dia/2.0+r-r*sqrt2_,0.0,-r+r*sqrt2_) #arc-point of fillet\n    Pnt6 = Base.Vector(dia/2.0,0.0,-r)        # end of fillet\n    Pnt7 = Base.Vector(dia/2.0,0.0,-a_point)        # Start of thread\n    #FreeCAD.Console.PrintMessage(\"Points defined a_point: \" + str(a_point) + \"\\n\")\n\n\n    if (SType == 'ISO14583'):\n      #Pnt0 = Base.Vector(0.0,0.0,k-A/4.0)\n      Pnt0 = Base.Vector(0.0,0.0,k-A/8.0)\n      PntFlat = Base.Vector(A/8.0,0.0,k-A/8.0)\n      PntCham = Base.Vector(A/1.99,0.0,k)\n      edgeCham0 = Part.makeLine(Pnt0,PntFlat)\n      edgeCham1 = Part.makeLine(PntFlat,PntCham)\n      edgeCham2 = Part.Arc(PntCham,Pnt1,Pnt2).toShape()\n      #edge1 = Part.Wire([edgeCham0,edgeCham1,edgeCham2])\n      edge1 = Part.Wire([edgeCham0,edgeCham1])\n      edge2 = Part.makeLine(Pnt2,Pnt3)\n      edge2 = Part.Wire([edgeCham2, edge2])\n      # Part.show(edge2)\n\n      # Here is the next approach to shorten the head building time\n      # Make two helper points to create a cutting tool for the\n      # recess and recess shell.\n      PntH1 = Base.Vector(A/1.99,0.0, 2.0*k)\n      PntH2 = Base.Vector(0.0,0.0, 2.0*k)\n      edgeH1 = Part.makeLine(PntCham,PntH1)\n      edgeH2 = Part.makeLine(PntH1,PntH2)\n      edgeH3 = Part.makeLine(PntH2,Pnt0)\n\n    else:\n      Pnt0 = Base.Vector(0.0,0.0,k)\n      edge1 = Part.Arc(Pnt0,Pnt1,Pnt2).toShape()  # make round head\n      edge2 = Part.makeLine(Pnt2,Pnt3)\n\n      # Here is the next approach to shorten the head building time\n      # Make two helper points to create a cutting tool for the\n      # recess and recess shell.\n      PntH1 = Base.Vector(dk_max/2.0,0.0, 2.0*k)\n      PntH2 = Base.Vector(0.0,0.0, 2.0*k)\n      edgeH1 = Part.makeLine(Pnt2,PntH1)\n      edgeH2 = Part.makeLine(PntH1,PntH2)\n      edgeH3 = Part.makeLine(PntH2,Pnt0)\n\n    edge3 = Part.makeLine(Pnt3,Pnt4)\n    edge4 = Part.Arc(Pnt4,Pnt5,Pnt6).toShape()\n    #FreeCAD.Console.PrintMessage(\"Edges made h_arc_z: \" + str(h_arc_z) + \"\\n\")\n\n    #if self.RealThread.isChecked():\n    if self.rThread:\n      aWire=Part.Wire([edge2,edge3,edge4])\n    else:\n      # bolt points\n      PntB1 = Base.Vector(dia/2.0,0.0,-l)\n      PntB2 = Base.Vector(0.0,0.0,-l)\n      edgeB2 = Part.makeLine(PntB1,PntB2)\n      if a_point <= r:\n        edgeB1 = Part.makeLine(Pnt6,PntB1)\n        aWire=Part.Wire([edge2, edge3, edge4, edgeB1, edgeB2])\n      else:\n        edge5 = Part.makeLine(Pnt6,Pnt7)\n        edgeB1 = Part.makeLine(Pnt7,PntB1)\n        aWire=Part.Wire([edge2, edge3, edge4, edge5, edgeB1, edgeB2])\n\n\n\n    hWire = Part.Wire([edge1,edgeH1,edgeH2,edgeH3]) # Cutter for recess-Shell\n    hFace = Part.Face(hWire)\n    hCut = hFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(hWire)\n\n    headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #head = Part.Solid(headShell)\n    #Part.show(aWire)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n    headFaces = headShell.Faces\n\n    if (SType == 'ISO14583'):\n      recess, recessShell = self.makeIso10664_3(tt, t_mean, k)\n      recessShell = recessShell.cut(hCut)\n      topFace = hCut.Faces[1]\n      topFace = topFace.cut(recess)\n      #Part.show(topFace)\n      #Part.show(recessShell)\n      #Part.show(headShell)\n      headFaces.append(topFace.Faces[0])\n      #headFaces.append(hCut.Faces[2])\n\n    else:\n      #Lengths and angles for calculation of recess positioning\n      beta_cr = math.asin(mH /2.0 / rf)   # angle of recess edge\n      tan_beta_cr = math.tan(beta_cr)\n      # height of cross recess cutting\n      hcr = k - rf + (mH/2.0) / tan_beta_cr\n      #print 'hcr: ', hcr\n\n      #Parameter for cross-recess type H: cT, mH\n      recess, recessShell = self.makeCross_H3(cT, mH, hcr)\n      recessShell = recessShell.cut(hCut)\n      topFace = hCut.Faces[0]\n      topFace = topFace.cut(recess)\n      #Part.show(topFace)\n      #Part.show(recessShell)\n      #Part.show(headShell)\n      headFaces.append(topFace.Faces[0])\n\n    #Part.show(hCut)\n    headFaces.extend(recessShell.Faces)\n\n\n    #if self.RealThread.isChecked():\n    if self.rThread:\n      #head = self.cutIsoThread(head, dia, P, turns, l)\n      rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n      rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n      #head = head.fuse(rthread)\n      #Part.show(rthread)\n      for threadFace in rthread.Faces:\n        headFaces.append(threadFace)\n\n    newHeadShell = Part.Shell(headFaces)\n    #Part.show(newHeadShell)\n    head = Part.Solid(newHeadShell)\n\n    return head\n\n\n  # make Cheese head screw\n  # ISO 1207 slotted screw\n  # ISO 7048 cross recessed screw\n  # ISO 14580 Hexalobular socket cheese head screws\n  def makeIso1207(self,SType ='ISO1207', ThreadType ='M6',l=25.0):\n    dia = get_diameter(ThreadType)\n    '''\n    if '(' in TreadType:\n      threadString = ThreadType.lstrip('(M')\n      dia = float(ThreadType.rstrip(')'))\n    else:\n      dia=float(ThreadType.lstrip('M'))\n    '''\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit l: \" + str(l) + \"\\n\")\n    if (SType == 'ISO1207') or (SType == 'ISO14580'):\n       P, a, b, dk, dk_mean, da, k, n_min, r, t_min, x = iso1207def[ThreadType]\n    if SType == 'ISO7048':\n       P, a, b, dk, dk_mean, da, k, r, x, cT, mH, mZ  = iso7048def[ThreadType]\n    if (SType == 'ISO14580'):\n       tt, k, A, t_min = iso14580def[ThreadType]\n\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit iso: \" + str(dk) + \"\\n\")\n\n    #Length for calculation of head fillet\n    r_fil = r*2.0\n    beta = math.radians(5.0)   # angle of cheese head edge\n    alpha = math.radians(90.0 - (90.0+5.0)/2.0)\n    tan_beta = math.tan(beta)\n    # top head diameter without fillet\n    rK_top = dk/2.0 - k * tan_beta\n    fillet_center_x = rK_top - r_fil + r_fil * tan_beta\n    fillet_center_z = k - r_fil\n    fillet_arc_x = fillet_center_x + r_fil * math.sin(alpha)\n    fillet_arc_z = fillet_center_z + r_fil * math.cos(alpha)\n    #FreeCAD.Console.PrintMessage(\"rK_top: \" + str(rK_top) + \"\\n\")\n\n    if (b > (l - 1.0*P)):\n       bmax = l- 1.0*P\n    else:\n       bmax = b\n\n    ### make the new code with math.modf(l)\n    residue, turns = math.modf((bmax)/P)\n    halfturns = 2*int(turns)\n    if residue < 0.5:\n      a_point = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a_point = l - (turns+2.0) * P\n    #halfturns = halfturns + 2\n    offSet = r - a_point\n\n    sqrt2_ = 1.0/math.sqrt(2.0)\n\n    #Head Points\n    Pnt2 = Base.Vector(fillet_center_x,0.0,k)\n    Pnt3 = Base.Vector(fillet_arc_x,0.0,fillet_arc_z)\n    Pnt4 = Base.Vector(fillet_center_x + r_fil*math.cos(beta),0.0,fillet_center_z+ r_fil * math.sin(beta))\n    Pnt5 = Base.Vector(dk/2.0,0.0,0.0)\n    Pnt6 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n    Pnt7 = Base.Vector(dia/2.0+r-r*sqrt2_,0.0,-r+r*sqrt2_) #arc-point of fillet\n    Pnt8 = Base.Vector(dia/2.0,0.0,-r)        # end of fillet\n    Pnt9 = Base.Vector(dia/2.0,0.0,-a_point)        # Start of thread\n    #FreeCAD.Console.PrintMessage(\"Points defined fillet_center_x: \" + str(fillet_center_x) + \"\\n\")\n\n    if (SType == 'ISO14580'):\n      # Pnt0 = Base.Vector(0.0,0.0,k-A/4.0) #Center Point for countersunk\n      Pnt0 = Base.Vector(0.0,0.0,k-A/8.0) #Center Point for flat countersunk\n      PntFlat = Base.Vector(A/8.0,0.0,k-A/8.0) # End of flat part\n      Pnt1 = Base.Vector(A/1.99,0.0,k)     #countersunk edge at head\n      edgeCham0 = Part.makeLine(Pnt0,PntFlat)\n      edgeCham1 = Part.makeLine(PntFlat,Pnt1)\n      edgeCham2 = Part.makeLine(Pnt1,Pnt2)\n      edge1 = Part.Wire([edgeCham1,edgeCham2]) # make head with countersunk\n      PntH1 = Base.Vector(A/1.99,0.0, 2.0*k)\n\n    else:\n      Pnt0 = Base.Vector(0.0,0.0,k)\n      edge1 = Part.makeLine(Pnt0,Pnt2)  # make flat head\n\n\n    edge2 = Part.Arc(Pnt2,Pnt3,Pnt4).toShape()\n    edge3 = Part.makeLine(Pnt4,Pnt5)\n    edge4 = Part.makeLine(Pnt5,Pnt6)\n    edge5 = Part.Arc(Pnt6,Pnt7,Pnt8).toShape()\n    #FreeCAD.Console.PrintMessage(\"Edges made fillet_center_z: \" + str(fillet_center_z) + \"\\n\")\n\n    if SType == 'ISO1207':\n      #Parameter for slot-recess: dk, n_min, k, t_min\n      recess = Part.makePlane(dk, n_min, \\\n        Base.Vector(dk/2.0,-n_min/2.0,k+1.0),Base.Vector(0.0,0.0,-1.0))\n      recess = recess.extrude(Base.Vector(0.0,0.0,-t_min-1.0))\n\n      if self.rThread:\n        Pnt11 = Base.Vector(0.0,0.0,-r)        # helper point for real thread\n        edgeZ1 = Part.makeLine(Pnt8,Pnt11)\n        edgeZ0 = Part.makeLine(Pnt11,Pnt0)\n        aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5, \\\n            edgeZ1, edgeZ0])\n      else:\n        # bolt points\n        PntB1 = Base.Vector(dia/2.0,0.0,-l)\n        PntB2 = Base.Vector(0.0,0.0,-l)\n\n        edgeB2 = Part.makeLine(PntB1,PntB2)\n\n        if a_point <= r:\n          edgeB1 = Part.makeLine(Pnt8,PntB1)\n          aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5, \\\n              edgeB1, edgeB2])\n        else:\n          edge6 = Part.makeLine(Pnt8,Pnt9)\n          edgeB1 = Part.makeLine(Pnt9,PntB1)\n          aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5,edge6, \\\n              edgeB1, edgeB2])\n\n      aFace =Part.Face(aWire)\n      head = aFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360.0)\n      head = head.cut(recess)\n      # FreeCAD.Console.PrintMessage(\"der Kopf geschnitten: \" + str(dia) + \"\\n\")\n      #Part.show(head)\n      if self.rThread:\n        screwFaces = []\n        for i in range(0, len(head.Faces)-1):\n          screwFaces.append(head.Faces[i])\n        rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n        for threadFace in rthread.Faces:\n          screwFaces.append(threadFace)\n\n        screwShell = Part.Shell(screwFaces)\n        head = Part.Solid(screwShell)\n\n\n\n    else:\n      if self.rThread:\n        aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5 ])\n      else:\n        # bolt points\n        PntB1 = Base.Vector(dia/2.0,0.0,-l)\n        PntB2 = Base.Vector(0.0,0.0,-l)\n\n        edgeB2 = Part.makeLine(PntB1,PntB2)\n\n        if a_point <= r:\n          edgeB1 = Part.makeLine(Pnt8,PntB1)\n          aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5, \\\n              edgeB1, edgeB2])\n        else:\n          edge6 = Part.makeLine(Pnt8,Pnt9)\n          edgeB1 = Part.makeLine(Pnt9,PntB1)\n          aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5,edge6, \\\n              edgeB1, edgeB2])\n\n      #aFace =Part.Face(aWire)\n      headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360.0)\n      #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n\n      if SType == 'ISO7048':\n        # hCut should be just a cylinder\n        hCut = Part.makeCylinder(fillet_center_x,k,Pnt0)\n        recess, recessShell = self.makeCross_H3(cT, mH, k)\n        recessShell = recessShell.cut(hCut)\n        topFace = headShell.Faces[0].cut(recess)\n        screwFaces = [topFace.Faces[0]]\n        screwFaces.extend(recessShell.Faces)\n      if (SType == 'ISO14580'):\n        # Ring-cutter for recess shell\n        PntH2 = Base.Vector(A/8.0,0.0, 2.0*k)\n        edgeH1 = Part.makeLine(Pnt1,PntH1)\n        edgeH2 = Part.makeLine(PntH1,PntH2)\n        edgeH3 = Part.makeLine(PntH2,PntFlat)\n        hWire = Part.Wire([edgeCham1,edgeH1,edgeH2,edgeH3]) # Cutter for recess-Shell\n        hFace = Part.Face(hWire)\n        hCut = hFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n        #Part.show(hWire)\n\n        recess, recessShell = self.makeIso10664_3(tt, t_min, k)\n        recessShell = recessShell.cut(hCut)\n        topFace = headShell.Faces[0].cut(recess)\n        screwFaces = [topFace.Faces[0]]\n        screwFaces.extend(recessShell.Faces)\n\n      for i in range(1, len(headShell.Faces)):\n        screwFaces.append(headShell.Faces[i])\n\n      if self.rThread:\n        #head = self.cutIsoThread(head, dia, P, turns, l)\n        rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n        #head = head.fuse(rthread)\n        #Part.show(rthread)\n        for threadFace in rthread.Faces:\n          screwFaces.append(threadFace)\n\n      screwShell = Part.Shell(screwFaces)\n      head = Part.Solid(screwShell)\n\n    return head\n\n\n\n  # make the ISO 4017 Hex-head-screw\n  # make the ISO 4014 Hex-head-bolt\n  def makeIso4017_2(self,SType ='ISO4017', ThreadType ='M6',l=40.0):\n    dia = get_diameter(ThreadType)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit l: \" + str(l) + \"\\n\")\n    if SType == 'ISO4017':\n      P, c, dw, e,k,r,s = iso4017head[ThreadType]\n      residue, turns = math.modf((l-1*P)/P)\n      halfturns = 2*int(turns)\n\n    if SType == 'ISO8676':\n      P, c, dw, e,k,r,s = iso8676def[ThreadType]\n      residue, turns = math.modf((l-r-1*P)/P)\n      halfturns = 2*int(turns)\n\n    if SType == 'ISO4014':\n      P, b1, b2, b3, c, dw, e, k, r, s = iso4014head[ThreadType]\n      if l<= 125.0:\n         b = b1\n      else:\n         if l<= 200.0:\n            b = b2\n         else:\n            b = b3\n      residue, turns = math.modf((b)/P)\n      halfturns = 2*int(turns)\n\n    if residue < 0.5:\n      a = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a = l - (turns+2.0) * P\n    #halfturns = halfturns + 2\n    offSet = r - a\n\n    sqrt2_ = 1.0/math.sqrt(2.0)\n    cham = (e-s)*math.sin(math.radians(15)) # needed for chamfer at head top\n\n    #Head Points  Usage of k, s, cham, c, dw, dia, r, a\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit halfturns: \" + str(halfturns) + \"\\n\")\n    Pnt0 = Base.Vector(0.0,0.0,k)\n    Pnt2 = Base.Vector(s/2.0,0.0,k)\n    Pnt3 = Base.Vector(s/math.sqrt(3.0),0.0,k-cham)\n    Pnt4 = Base.Vector(s/math.sqrt(3.0),0.0,c)\n    Pnt5 = Base.Vector(dw/2.0,0.0,c)\n    Pnt6 = Base.Vector(dw/2.0,0.0,0.0)\n    Pnt7 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n    Pnt8 = Base.Vector(dia/2.0+r-r*sqrt2_,0.0,-r+r*sqrt2_) #arc-point of fillet\n    Pnt9 = Base.Vector(dia/2.0,0.0,-r)        # end of fillet\n    Pnt10 = Base.Vector(dia/2.0,0.0,-a)        # Start of thread\n\n    edge1 = Part.makeLine(Pnt0,Pnt2)\n    edge2 = Part.makeLine(Pnt2,Pnt3)\n    edge3 = Part.makeLine(Pnt3,Pnt4)\n    edge4 = Part.makeLine(Pnt4,Pnt5)\n    edge5 = Part.makeLine(Pnt5,Pnt6)\n    edge6 = Part.makeLine(Pnt6,Pnt7)\n    edge7 = Part.Arc(Pnt7,Pnt8,Pnt9).toShape()\n\n    # create cutting tool for hexagon head\n    # Parameters s, k, outer circle diameter =  e/2.0+10.0\n    extrude = self.makeHextool(s, k, s*2.0)\n\n    #if self.RealThread.isChecked():\n    if self.rThread:\n      Pnt11 = Base.Vector(0.0,0.0,-r)        # helper point for real thread\n      edgeZ1 = Part.makeLine(Pnt9,Pnt11)\n      edgeZ0 = Part.makeLine(Pnt11,Pnt0)\n      aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5,edge6,edge7, \\\n          edgeZ1, edgeZ0])\n\n      aFace =Part.Face(aWire)\n      head = aFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360.0)\n      #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n\n      # Part.show(extrude)\n      head = head.cut(extrude)\n      #FreeCAD.Console.PrintMessage(\"der Kopf geschnitten: \" + str(dia) + \"\\n\")\n      #Part.show(head)\n\n      headFaces = []\n      for i in range(18):\n        headFaces.append(head.Faces[i])\n\n      if (dia < 3.0) or (dia > 5.0):\n        rthread = self.makeShellthread(dia, P, halfturns, True, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a-2.0*P))\n        #rthread.translate(Base.Vector(0.0, 0.0,-2.0*P))\n        #Part.show(rthread)\n        for tFace in rthread.Faces:\n          headFaces.append(tFace)\n        headShell = Part.Shell(headFaces)\n        head = Part.Solid(headShell)\n      else:\n        rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a-2.0*P))\n        #rthread.translate(Base.Vector(0.0, 0.0,-2.0*P))\n        #Part.show(rthread)\n        for tFace in rthread.Faces:\n          headFaces.append(tFace)\n        headShell = Part.Shell(headFaces)\n        head = Part.Solid(headShell)\n        cyl = self.cutChamfer(dia, P, l)\n        #FreeCAD.Console.PrintMessage(\"vor Schnitt Ende: \" + str(dia) + \"\\n\")\n        head = head.cut(cyl)\n\n    else:\n      # bolt points\n      cham_t = P*math.sqrt(3.0)/2.0*17.0/24.0\n\n      PntB0 = Base.Vector(0.0,0.0,-a)\n      PntB1 = Base.Vector(dia/2.0,0.0,-l+cham_t)\n      PntB2 = Base.Vector(dia/2.0-cham_t,0.0,-l)\n      PntB3 = Base.Vector(0.0,0.0,-l)\n\n      edgeB1 = Part.makeLine(Pnt10,PntB1)\n      edgeB2 = Part.makeLine(PntB1,PntB2)\n      edgeB3 = Part.makeLine(PntB2,PntB3)\n\n      edgeZ0 = Part.makeLine(PntB3,Pnt0)\n      if a <= r:\n        edgeB1 = Part.makeLine(Pnt9,PntB1)\n        aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5,edge6,edge7, \\\n            edgeB1, edgeB2, edgeB3, edgeZ0])\n\n      else:\n        edge8 = Part.makeLine(Pnt9,Pnt10)\n        edgeB1 = Part.makeLine(Pnt10,PntB1)\n        aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5,edge6,edge7,edge8, \\\n            edgeB1, edgeB2, edgeB3, edgeZ0])\n\n      aFace =Part.Face(aWire)\n      head = aFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360.0)\n      #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n\n      # Part.show(extrude)\n      head = head.cut(extrude)\n      #FreeCAD.Console.PrintMessage(\"der Kopf geschnitten: \" + str(dia) + \"\\n\")\n\n    return head\n\n\n  # EN 1662 Hex-head-bolt with flange - small series\n  # EN 1665 Hexagon bolts with flange, heavy series\n  def makeEN1662_2(self,SType ='EN1662', ThreadType ='M8',l=25.0):\n    dia = get_diameter(ThreadType)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit l: \" + str(l) + \"\\n\")\n    if SType == 'EN1662':\n       P, b0, b1, b2, b3, c, dc, dw, e, k, kw,f, r1, s = en1662def[ThreadType]\n    else:\n       P, b0, b1, b2, b3, c, dc, dw, e, k, kw,f, r1, s = en1665def[ThreadType]\n    if l< b0:\n       b = l - 2*P\n    else:\n       if l<= 125.0:\n          b = b1\n       else:\n          if l<= 200.0:\n             b = b2\n          else:\n             b = b3\n\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit isoEN1662: \" + str(c) + \"\\n\")\n    cham = s*(2.0/math.sqrt(3.0)-1.0)*math.sin(math.radians(25)) # needed for chamfer at head top\n\n    ### make the new code with math.modf(l)\n    residue, turns = math.modf((b)/P)\n    halfturns = 2*int(turns)\n    if residue < 0.5:\n      a_point = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a_point = l - (turns+2.0) * P\n    #halfturns = halfturns + 2\n    offSet = r1 - a_point\n\n    sqrt2_ = 1.0/math.sqrt(2.0)\n\n    # Flange is made with a radius of c\n    beta = math.radians(25.0)\n    tan_beta = math.tan(beta)\n\n    # Calculation of Arc points of flange edge using dc and c\n    arc1_x = dc/2.0 - c/2.0 + (c/2.0)*math.sin(beta)\n    arc1_z = c/2.0 + (c/2.0)*math.cos(beta)\n\n    hF = arc1_z + (arc1_x -s/2.0) * tan_beta  # height of flange at center\n\n    kmean = arc1_z + (arc1_x - s/math.sqrt(3.0)) * tan_beta + kw * 1.1 + cham\n    #kmean = k * 0.95\n\n\n    #Hex-Head Points\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit math a: \" + str(a_point) + \"\\n\")\n    PntH0 = Base.Vector(0.0,0.0,kmean*0.9)\n    PntH1 = Base.Vector(s/2.0*0.8 - r1/2.0,0.0,kmean*0.9)\n    PntH1a = Base.Vector(s/2.0*0.8-r1/2.0+r1/2.0*sqrt2_,0.0,kmean*0.9 +r1/2.0 -r1/2.0*sqrt2_)\n    PntH1b = Base.Vector(s/2.0*0.8,0.0,kmean*0.9 +r1/2.0)\n    PntH2 = Base.Vector(s/2.0*0.8,0.0,kmean -r1)\n    PntH2a = Base.Vector(s/2.0*0.8+r1-r1*sqrt2_,0.0,kmean -r1 +r1*sqrt2_)\n    PntH2b = Base.Vector(s/2.0*0.8 + r1 ,0.0,kmean)\n    PntH3 = Base.Vector(s/2.0,0.0,kmean)\n    #PntH4 = Base.Vector(s/math.sqrt(3.0),0.0,kmean-cham)   #s/math.sqrt(3.0)\n    #PntH5 = Base.Vector(s/math.sqrt(3.0),0.0,c)\n    #PntH6 = Base.Vector(0.0,0.0,c)\n\n    edgeH1 = Part.makeLine(PntH0,PntH1)\n    edgeH2 = Part.Arc(PntH1,PntH1a,PntH1b).toShape()\n    edgeH3 = Part.makeLine(PntH1b,PntH2)\n    edgeH3a = Part.Arc(PntH2,PntH2a,PntH2b).toShape()\n    edgeH3b = Part.makeLine(PntH2b,PntH3)\n\n    hWire=Part.Wire([edgeH1,edgeH2,edgeH3,edgeH3a,edgeH3b])\n    topShell = hWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(hWire)\n    #Part.show(topShell)\n\n    # create a cutter ring to generate the chamfer at the top of the hex\n    chamHori = s/math.sqrt(3.0) - s/2.0\n    PntC1 = Base.Vector(s/2.0-chamHori,0.0,kmean+kmean)\n    PntC2 = Base.Vector(s/math.sqrt(3.0)+chamHori,0.0,kmean+kmean)\n    PntC3 = Base.Vector(s/2.0-chamHori,0.0,kmean+cham)\n    PntC4 = Base.Vector(s/math.sqrt(3.0)+chamHori,0.0,kmean-cham-cham)   #s/math.sqrt(3.0)\n    edgeC1 = Part.makeLine(PntC3, PntC1)\n    edgeC2 = Part.makeLine(PntC1, PntC2)\n    edgeC3 = Part.makeLine(PntC2, PntC4)\n    edgeC4 = Part.makeLine(PntC4, PntC3)\n    cWire = Part.Wire([edgeC4, edgeC1, edgeC2, edgeC3])\n    cFace = Part.Face(cWire)\n    chamCut = cFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(cWire)\n    #Part.show(chamCut)\n\n\n    # create hexagon\n    mhex=Base.Matrix()\n    mhex.rotateZ(math.radians(60.0))\n    polygon = []\n    vhex=Base.Vector(s/math.sqrt(3.0),0.0,kmean)\n    for i in range(6):\n       polygon.append(vhex)\n       vhex = mhex.multiply(vhex)\n    polygon.append(vhex)\n    hexagon = Part.makePolygon(polygon)\n    hexFace = Part.Face(hexagon)\n    solidHex = hexFace.extrude(Base.Vector(0.0,0.0,c-kmean))\n    #Part.show(solidHex)\n    hexCham = solidHex.cut(chamCut)\n    #Part.show(hexCham)\n\n    topFaces = topShell.Faces\n\n    topFaces.append(hexCham.Faces[6])\n    topFaces.append(hexCham.Faces[12])\n    topFaces.append(hexCham.Faces[14])\n    topFaces.append(hexCham.Faces[13])\n    topFaces.append(hexCham.Faces[8])\n    topFaces.append(hexCham.Faces[2])\n    topFaces.append(hexCham.Faces[1])\n\n    hexFaces = [hexCham.Faces[5], hexCham.Faces[11], hexCham.Faces[10]]\n    hexFaces.extend([hexCham.Faces[9], hexCham.Faces[3], hexCham.Faces[0]])\n    hexShell = Part.Shell(hexFaces)\n\n    # Center of flange:\n    Pnt0 = Base.Vector(0.0,0.0,hF)\n    Pnt1 = Base.Vector(s/2.0,0.0,hF)\n\n    # arc edge of flange:\n    Pnt2 = Base.Vector(arc1_x,0.0,arc1_z)\n    Pnt3 = Base.Vector(dc/2.0,0.0,c/2.0)\n    Pnt4 = Base.Vector((dc-c)/2.0,0.0,0.0)\n\n    Pnt5 = Base.Vector(dia/2.0+r1,0.0,0.0)     #start of fillet between head and shank\n    Pnt6 = Base.Vector(dia/2.0+r1-r1*sqrt2_,0.0,-r1+r1*sqrt2_) #arc-point of fillet\n    Pnt7 = Base.Vector(dia/2.0,0.0,-r1)        # end of fillet\n    Pnt8 = Base.Vector(dia/2.0,0.0,-a_point)        # Start of thread\n\n    edge1 = Part.makeLine(Pnt0,Pnt1)\n    edge2 = Part.makeLine(Pnt1,Pnt2)\n    edge3 = Part.Arc(Pnt2,Pnt3,Pnt4).toShape()\n    edge4 = Part.makeLine(Pnt4,Pnt5)\n    edge5 = Part.Arc(Pnt5,Pnt6,Pnt7).toShape()\n\n    # make a cutter for the hexShell\n    PntHC1 = Base.Vector(0.0,0.0,arc1_z)\n    PntHC2 = Base.Vector(0.0,0.0,0.0)\n\n    edgeHC1 = Part.makeLine(Pnt2,PntHC1)\n    edgeHC2 = Part.makeLine(PntHC1,PntHC2)\n    edgeHC3 = Part.makeLine(PntHC2,Pnt0)\n\n    HCWire = Part.Wire([edge2, edgeHC1, edgeHC2, edgeHC3, edge1])\n    HCFace = Part.Face(HCWire)\n    hex2Cut = HCFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n\n    hexShell = hexShell.cut(hex2Cut)\n    #Part.show(hexShell)\n\n    topFaces.extend(hexShell.Faces)\n\n    # bolt points\n    cham_t = P*math.sqrt(3.0)/2.0*17.0/24.0\n\n    PntB0 = Base.Vector(0.0,0.0,-a_point)\n    PntB1 = Base.Vector(dia/2.0,0.0,-l+cham_t)\n    PntB2 = Base.Vector(dia/2.0-cham_t,0.0,-l)\n    PntB3 = Base.Vector(0.0,0.0,-l)\n\n    edgeB2 = Part.makeLine(PntB1,PntB2)\n    edgeB3 = Part.makeLine(PntB2,PntB3)\n\n    #if self.RealThread.isChecked():\n    if self.rThread:\n      aWire=Part.Wire([edge2,edge3,edge4,edge5])\n      boltIndex = 4\n\n    else:\n      if a_point <=r1:\n        edgeB1 = Part.makeLine(Pnt7,PntB1)\n        aWire=Part.Wire([edge2,edge3,edge4,edge5, edgeB1, edgeB2, edgeB3])\n        boltIndex = 7\n      else:\n        edgeB1 = Part.makeLine(Pnt8,PntB1)\n        edge6 = Part.makeLine(Pnt7,Pnt8)\n        aWire=Part.Wire([edge2,edge3,edge4,edge5,edge6, \\\n            edgeB1, edgeB2, edgeB3])\n        boltIndex = 8\n\n\n    #aFace =Part.Face(aWire)\n    #Part.show(aWire)\n    headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n    #Part.show(headShell)\n    chamFace = headShell.Faces[0].cut(solidHex)\n    #Part.show(chamFace)\n\n    topFaces.append(chamFace.Faces[0])\n    for i in range(1,boltIndex):\n      topFaces.append(headShell.Faces[i])\n\n\n    if self.rThread:\n      if (dia < 3.0) or (dia > 5.0):\n        rthread = self.makeShellthread(dia, P, halfturns, True, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point-2.0*P))\n        for tFace in rthread.Faces:\n          topFaces.append(tFace)\n        headShell = Part.Shell(topFaces)\n        screw = Part.Solid(headShell)\n      else:\n        rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point-2.0*P))\n        for tFace in rthread.Faces:\n          topFaces.append(tFace)\n        headShell = Part.Shell(topFaces)\n        head = Part.Solid(headShell)\n        cyl = self.cutChamfer(dia, P, l)\n        #FreeCAD.Console.PrintMessage(\"vor Schnitt Ende: \" + str(dia) + \"\\n\")\n        screw = head.cut(cyl)\n    else:\n      screwShell = Part.Shell(topFaces)\n      screw = Part.Solid(screwShell)\n\n    return screw\n\n  def makeIso7046(self, SType ='ISO7046', ThreadType ='M6', l=25.0):\n    \"\"\"ISO 7046, ISO 7047, ISO 10642, ISO 14582, ISO 14584\n\n    Used for ISO 7046 countersunk flat head screws with H cross recess\n    Used for ISO 7047 raised countersunk head screws with H cross recess\n    Used for ISO 10642 Hexagon socket countersunk head screws\n    Used for ISO 14582 Hexalobular socket countersunk head screws, high head\n    Used for ISO 14584 Hexalobular socket raised countersunk head screws\n    \"\"\"\n    dia = get_diameter(ThreadType)\n    #FreeCAD.Console.PrintMessage(\"The 2009 head with l: \" + str(l) + \"\\n\")\n    if (SType == 'ISO10642'):\n      P,b,dk_theo,dk_mean,da, ds_min, e, k, r, s_mean, t, w =iso10642def[ThreadType]\n      ePrax = s_mean / math.sqrt(3.0) / 0.99\n      ht = 0.0\n      a = 2*P\n      t_mean = t\n    else: #still need the data from iso2009def, but this screw can not created here\n      P, a, b, dk_theo, dk_mean, k, n_min, r, t_mean, x = iso2009def[ThreadType]\n      ht = 0.0 # Head height of flat head\n    if SType == 'ISO7046':\n      cT, mH, mZ  = iso7046def[ThreadType]\n    if (SType == 'ISO7047'):\n      rf, t_mean, cT, mH, mZ = Raised_countersunk_def[ThreadType]\n      #Lengths and angles for calculation of head rounding\n      beta = math.asin(dk_mean /2.0 / rf)   # angle of head edge\n      tan_beta = math.tan(beta)\n      alpha = beta/2.0 # half angle\n      # height of raised head top\n      ht = rf - (dk_mean/2.0) / tan_beta\n      #print 'he: ', he\n      h_arc_x = rf * math.sin(alpha)\n      h_arc_z = ht - rf + rf * math.cos(alpha)\n      #FreeCAD.Console.PrintMessage(\"h_arc_z: \" + str(h_arc_z) + \"\\n\")\n\n    if (SType == 'ISO14582'):\n      P, a, b, dk_theo, dk_mean, k, r, tt, A, t_mean = iso14582def[ThreadType]\n      ePrax = A / 2.0 / 0.99\n\n    if (SType == 'ISO14584'):\n      P, b, dk_theo, dk_mean, f, k, r, rf, x, tt, A, t_mean = iso14584def[ThreadType]\n      ePrax = A / 2.0 / 0.99\n      #Lengths and angles for calculation of head rounding\n      beta = math.asin(dk_mean /2.0 / rf)   # angle of head edge\n      tan_beta = math.tan(beta)\n      ctp = - (dk_mean/2.0) / tan_beta # Center Top Edge = center for rf\n      betaA = math.asin(ePrax / rf)   # angle of head edge at start of recess\n      ht = ctp + ePrax / math.tan(betaA)\n      alpha = betaA + (beta - betaA)/2.0 # half angle of top Arc\n      h_arc_x = rf * math.sin(alpha)\n      h_arc_z = ctp + rf * math.cos(alpha)\n\n\n    FreeCAD.Console.PrintMessage(\"The head with iso r: \" + str(r) + \"\\n\")\n    cham = (dk_theo - dk_mean)/2.0\n    rad225 = math.radians(22.5)\n    rad45 = math.radians(45.0)\n    rtan = r*math.tan(rad225)\n    #FreeCAD.Console.PrintMessage(\"Checking rtan: \" + str(rtan) + \"\\n\")\n\n    if (b > (l - k - rtan/2.0 - 1.0*P)):\n      bmax = l - k - rtan/2.0 - 1.0*P\n    else:\n      bmax = b\n\n    ### make the new code with math.modf(l)\n    residue, turns = math.modf((bmax)/P)\n    halfturns = 2*int(turns)\n    if residue < 0.5:\n      a_point = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a_point = l - (turns+2.0) * P\n    #halfturns = halfturns + 2\n    offSet = k + rtan - a_point\n\n    #Head Points\n    Pnt1 = Base.Vector(dk_mean/2.0,0.0,0.0)\n    Pnt2 = Base.Vector(dk_mean/2.0,0.0,-cham)\n    Pnt3 = Base.Vector(dia/2.0+r-r*math.cos(rad45),0.0,-k-rtan+r*math.sin(rad45))\n\n    # Arc-points\n    Pnt4 = Base.Vector(dia/2.0+r-r*(math.cos(rad225)),0.0,-k-rtan+r*math.sin(rad225))\n    Pnt5 = Base.Vector(dia/2.0,0.0,-k-rtan)\n    Pnt6 = Base.Vector(dia/2.0,0.0,-a_point)\n\n    if (SType == 'ISO10642') or (SType == 'ISO14582'):\n      if (SType == 'ISO10642'):\n        recess, recessShell = self.makeAllen2(s_mean, t_mean, 0.0 )\n        Pnt0 = Base.Vector(ePrax/2.0,0.0,-ePrax/2.0)\n        PntCham = Base.Vector(ePrax,0.0,0.0)\n        edge1 = Part.makeLine(Pnt0,PntCham)\n        edgeCham2 = Part.makeLine(PntCham,Pnt1)\n        edge2 = Part.makeLine(Pnt1,Pnt2)\n        edge2 = Part.Wire([edgeCham2,edge2])\n        PntH0 = Base.Vector(ePrax/2.0,0.0, ht + k)\n        PntH1 = Base.Vector(ePrax,0.0, ht + k)\n      if (SType == 'ISO14582'):\n        recess, recessShell = self.makeIso10664_3(tt, t_mean, 0.0) # hexalobular recess\n        Pnt0 = Base.Vector(0.0,0.0,0.0)\n        edge1 = Part.makeLine(Pnt0,Pnt1)\n        edge2 = Part.makeLine(Pnt1,Pnt2)\n\n\n      # bolt points with bolt chamfer\n      cham_b = P*math.sqrt(3.0)/2.0*17.0/24.0\n\n      PntB1 = Base.Vector(dia/2.0,0.0,-l+cham_b)\n      PntB2 = Base.Vector(dia/2.0-cham_b,0.0,-l)\n      PntB3 = Base.Vector(0.0,0.0,-l)\n      if a_point <= (k + rtan):\n        edgeB0 = Part.makeLine(Pnt5,PntB1)\n      else:\n        edgeB0 = Part.makeLine(Pnt6,PntB1)\n      edgeB2 = Part.makeLine(PntB1,PntB2)\n      edgeB3 = Part.makeLine(PntB2,PntB3)\n      edgeB1 = Part.Wire([edgeB2,edgeB3])\n\n    else:\n      # bolt points\n      PntB1 = Base.Vector(dia/2.0,0.0,-l)\n      PntB2 = Base.Vector(0.0,0.0,-l)\n      if a_point <= (k + rtan):\n        edgeB0 = Part.makeLine(Pnt5,PntB1)\n      else:\n        edgeB0 = Part.makeLine(Pnt6,PntB1)\n      edgeB1 = Part.makeLine(PntB1,PntB2)\n\n      if (SType == 'ISO7047'): # make raised head rounding\n        Pnt0 = Base.Vector(0.0,0.0,ht)\n        Pnt0arc = Base.Vector(h_arc_x,0.0,h_arc_z)\n        edge1 = Part.Arc(Pnt0,Pnt0arc,Pnt1).toShape()\n        edge2 = Part.makeLine(Pnt1,Pnt2)\n        PntH0 = Base.Vector(0.0,0.0, ht + k)\n        PntH1 = Base.Vector(dk_mean/2.0,0.0, ht + k)\n        recess, recessShell = self.makeCross_H3(cT, mH, ht)\n      if (SType == 'ISO7046'):\n        # ISO7046\n        FreeCAD.Console.PrintMessage(\"ISO7046: \" + str(ht) + \"\\n\")\n        Pnt0 = Base.Vector(0.0,0.0,ht)\n        edge1 = Part.makeLine(Pnt0,Pnt1)  # make flat head\n        edge2 = Part.makeLine(Pnt1,Pnt2)\n        recess, recessShell = self.makeCross_H3(cT, mH, ht)\n\n      if (SType == 'ISO14584'): # make raised head rounding with chamfer\n        Pnt0 = Base.Vector(ePrax/2.0,0.0,ht-ePrax/4.0)\n        PntCham = Base.Vector(ePrax,0.0,ht)\n        PntArc = Base.Vector(h_arc_x,0.0,h_arc_z)\n        edge1 = Part.makeLine(Pnt0,PntCham)\n        edgeArc = Part.Arc(PntCham,PntArc,Pnt1).toShape()\n        edge2 = Part.makeLine(Pnt1,Pnt2)\n        edge2 = Part.Wire([edgeArc,edge2])\n        PntH0 = Base.Vector(ePrax/2.0,0.0, ht + k)\n        PntH1 = Base.Vector(ePrax,0.0, ht + k)\n        recess, recessShell = self.makeIso10664_3(tt, t_mean, ht) # hexalobular recess\n\n    edge3 = Part.makeLine(Pnt2,Pnt3)\n    edgeArc = Part.Arc(Pnt3,Pnt4,Pnt5).toShape()\n    edgeArc1 = Part.makeLine(Pnt3,Pnt4)\n    edgeArc2 = Part.makeLine(Pnt4,Pnt5)\n    edge6 = Part.makeLine(Pnt5,Pnt6)\n\n    if self.rThread:\n      #aWire=Part.Wire([edge1,edge2,edge3,edgeArc])\n      aWire=Part.Wire([edge2,edge3,edgeArc])\n    else:\n      if a_point <= (k + rtan):\n        aWire=Part.Wire([edge2,edge3,edgeArc, edgeB0, edgeB1])\n      else:\n        aWire=Part.Wire([edge2,edge3,edgeArc,edge6, edgeB0, edgeB1])\n\n    #Part.show(aWire)\n    headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    headFaces = headShell.Faces\n    #Part.show(headShell)\n\n    if (SType == 'ISO7046') or (SType == 'ISO14582'):\n      # hCut is just a cylinder for ISO7046\n      hCut = Part.makeCylinder(dk_mean/2.0,k,Pnt0)\n      #Part.show(hCut)\n      topFace = hCut.Faces[2]\n    else:\n      if (SType == 'ISO7047'):\n        edgeH1 = Part.makeLine(Pnt1,PntH1)\n      else:\n        edgeH1 = Part.makeLine(PntCham,PntH1)\n      edgeH2 = Part.makeLine(PntH1,PntH0)\n      edgeH3 = Part.makeLine(PntH0,Pnt0)\n      hWire = Part.Wire([edge1,edgeH1,edgeH2,edgeH3]) # Cutter for recess-Shell\n      hFace = Part.Face(hWire)\n      hCut = hFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n      Part.show(hWire)\n      #Part.show(hCut)\n      topFace = hCut.Faces[0]\n\n    recessShell = recessShell.cut(hCut)\n    topFace = topFace.cut(recess)\n    #Part.show(topFace)\n    #Part.show(recessShell)\n    #Part.show(headShell)\n    headFaces.append(topFace.Faces[0])\n    headFaces.extend(recessShell.Faces)\n\n\n    if (SType == 'ISO10642') or (SType == 'ISO14582'):\n      if self.rThread:\n        if (dia < 3.0) or (dia > 5.0):\n          #if True:\n          rthread = self.makeShellthread(dia, P, halfturns, True, offSet)\n          rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n          #head = head.fuse(rthread)\n          #Part.show(rthread)\n          for threadFace in rthread.Faces:\n            headFaces.append(threadFace)\n\n          screwShell = Part.Shell(headFaces)\n          screw = Part.Solid(screwShell)\n        else:\n          '''\n          # head = self.cutIsoThread(head, dia, P, turns, l)\n          rthread = self.makeShellthread(dia, P, halfturns, False)\n          rthread.translate(Base.Vector(0.0, 0.0,-a_point-2.0*P))\n          head = head.fuse(rthread)\n          head = head.removeSplitter()\n          cyl = self.cutChamfer(dia, P, l)\n          #FreeCAD.Console.PrintMessage(\"vor Schnitt Ende: \" + str(dia) + \"\\n\")\n          head = head.cut(cyl)\n          '''\n\n          rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n          rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n          #head = head.fuse(rthread)\n          #Part.show(rthread)\n          for threadFace in rthread.Faces:\n            headFaces.append(threadFace)\n\n          screwShell = Part.Shell(headFaces)\n          screw = Part.Solid(screwShell)\n          cyl = self.cutChamfer(dia, P, l)\n          screw = screw.cut(cyl)\n      else:\n        screwShell = Part.Shell(headFaces)\n        screw = Part.Solid(screwShell)\n\n    else:\n      if self.rThread:\n        rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n        #head = head.fuse(rthread)\n        #Part.show(rthread)\n        for threadFace in rthread.Faces:\n          headFaces.append(threadFace)\n\n      screwShell = Part.Shell(headFaces)\n      screw = Part.Solid(screwShell)\n\n    return screw\n\n  def makeIso4762(self, SType ='ISO4762', ThreadType ='M6',l=25.0):\n    \"\"\"ISO 4762 Allen Screw head and ISO 14579 Hexalobular socket head cap\n    \"\"\"\n    dia = get_diameter(ThreadType)\n    #FreeCAD.Console.PrintMessage(\"der 4762Kopf mit l: \" + str(l) + \"\\n\")\n    P, b, dk_max, da, ds_mean, e, lf, k, r, s_mean, t, v, dw, w = iso4762def[ThreadType]\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit iso r: \" + str(r) + \"\\n\")\n    if SType == 'ISO14579':\n      tt, A, t = iso14579def[ThreadType]\n      #Head Points 30\u00b0 countersunk\n      # Pnt0 = Base.Vector(0.0,0.0,k-A/4.0) #Center Point for countersunk\n      Pnt0 = Base.Vector(0.0,0.0,k-A/8.0) #Center Point for flat countersunk\n      PntFlat = Base.Vector(A/8.0,0.0,k-A/8.0) # End of flat part\n      Pnt1 = Base.Vector(A/1.99,0.0,k)     #countersunk edge at head\n      edgeCham0 = Part.makeLine(Pnt0,PntFlat)\n      edgeCham1 = Part.makeLine(PntFlat,Pnt1)\n      edge1 = Part.Wire([edgeCham0,edgeCham1])\n\n      # Here is the next approach to shorten the head building time\n      # Make two helper points to create a cutting tool for the\n      # recess and recess shell.\n      PntH1 = Base.Vector(A/1.99,0.0, 2.0*k)\n\n    else:\n      e_cham = 2.0 * s_mean / math.sqrt(3.0)\n      #Head Points 45\u00b0 countersunk\n      Pnt0 = Base.Vector(0.0,0.0,k-e_cham/1.99/2.0) #Center Point for countersunk\n      PntFlat = Base.Vector(e_cham/1.99/2.0,0.0,k-e_cham/1.99/2.0) # End of flat part\n      Pnt1 = Base.Vector(e_cham/1.99,0.0,k)     #countersunk edge at head\n      edgeCham0 = Part.makeLine(Pnt0,PntFlat)\n      edgeCham1 = Part.makeLine(PntFlat,Pnt1)\n      edge1 = Part.Wire([edgeCham0,edgeCham1])\n      PntH1 = Base.Vector(e_cham/1.99,0.0, 2.0*k)\n\n\n    PntH2 = Base.Vector(0.0,0.0, 2.0*k)\n    edgeH1 = Part.makeLine(Pnt1,PntH1)\n    edgeH2 = Part.makeLine(PntH1,PntH2)\n    edgeH3 = Part.makeLine(PntH2,Pnt0)\n    hWire = Part.Wire([edge1,edgeH1,edgeH2,edgeH3]) # Cutter for recess-Shell\n    hFace = Part.Face(hWire)\n    hCut = hFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(hWire)\n    '''\n\n\n    PntH2 = Base.Vector(A/8.0,0.0, 2.0*k)\n    edgeH1 = Part.makeLine(Pnt1,PntH1)\n    edgeH2 = Part.makeLine(PntH1,PntH2)\n    edgeH3 = Part.makeLine(PntH2,PntFlat)\n    hWire = Part.Wire([edgeCham1,edgeH1,edgeH2,edgeH3]) # Cutter for recess-Shell\n    hFace = Part.Face(hWire)\n    hCut = hFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(hWire)\n    '''\n\n\n    sqrt2_ = 1.0/math.sqrt(2.0)\n    #depth = s_mean / 3.0\n\n    '''\n    if (b > l - 2*P):\n       bmax = l-2*P\n    else:\n       bmax = b\n    halfturns = round(2.0*(bmax+P)/P) # number of thread turns\n    if self.RealThread.isChecked():\n      a_real = l-(halfturns+2)*P/2.0  # point to fuse real thread\n    else:\n      a_real = l-halfturns*P/2.0  # starting point of thread\n    if a_real < r:\n      a_point = r*1.3\n    else:\n      a_point = a_real\n    '''\n\n\n    if (b > (l - 1.0*P)):\n       bmax = l- 1.0*P\n    else:\n       bmax = b\n\n    ### make the new code with math.modf(l)\n    residue, turns = math.modf((bmax)/P)\n    halfturns = 2*int(turns)\n    if residue < 0.5:\n      a_point = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a_point = l - (turns+2.0) * P\n    #halfturns = halfturns + 2\n    offSet = r - a_point\n    #FreeCAD.Console.PrintMessage(\"The transition at a: \" + str(a) + \" turns \" + str(turns) + \"\\n\")\n\n\n\n\n    #rad30 = math.radians(30.0)\n    #Head Points\n    Pnt2 = Base.Vector(dk_max/2.0-v,0.0,k)   #start of fillet\n    Pnt3 = Base.Vector(dk_max/2.0-v+v*sqrt2_,0.0,k-v+v*sqrt2_) #arc-point of fillet\n    Pnt4 = Base.Vector(dk_max/2.0,0.0,k-v)   #end of fillet\n    Pnt5 = Base.Vector(dk_max/2.0,0.0,(dk_max-dw)/2.0) #we have a chamfer here\n    Pnt6 = Base.Vector(dw/2.0,0.0,0.0)           #end of chamfer\n    Pnt7 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n    Pnt8 = Base.Vector(dia/2.0+r-r*sqrt2_,0.0,-r+r*sqrt2_) #arc-point of fillet\n    Pnt9 = Base.Vector(dia/2.0,0.0,-r)        # end of fillet\n    Pnt10 = Base.Vector(dia/2.0,0.0,-a_point)        # start of thread\n\n    edge1 = Part.makeLine(Pnt0,Pnt1)\n    edge2 = Part.makeLine(Pnt1,Pnt2)\n    edge3 = Part.Arc(Pnt2,Pnt3,Pnt4).toShape()\n    edge4 = Part.makeLine(Pnt4,Pnt5)\n    edge5 = Part.makeLine(Pnt5,Pnt6)\n    edge6 = Part.makeLine(Pnt6,Pnt7)\n    edge7 = Part.Arc(Pnt7,Pnt8,Pnt9).toShape()\n\n    '''\n    # bolt points\n    PntB1 = Base.Vector(dia/2.0,0.0,-l-P)  # Chamfer is made with a cut later\n    PntB2 = Base.Vector(0.0,0.0,-l-P)\n    #PntB3 = Base.Vector(0.0,0.0,-l)\n\n    edgeB0 = Part.makeLine(Pnt10,PntB1)\n    edgeB1 = Part.makeLine(PntB1,PntB2)\n    #edgeB2 = Part.makeLine(PntB2,PntB3)\n    edgeZ0 = Part.makeLine(PntB2,Pnt0)\n\n\n    aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5,edge6,edge7,edge8, \\\n        edgeB0, edgeB1, edgeZ0])\n    '''\n\n\n\n    if self.rThread:\n      aWire=Part.Wire([edge2,edge3,edge4,edge5,edge6,edge7])\n\n    else:\n      # bolt points\n      cham_t = P*math.sqrt(3.0)/2.0*17.0/24.0\n\n      PntB1 = Base.Vector(dia/2.0,0.0,-l+cham_t)\n      PntB2 = Base.Vector(dia/2.0-cham_t,0.0,-l)\n      PntB3 = Base.Vector(0.0,0.0,-l)\n\n      #edgeB1 = Part.makeLine(Pnt10,PntB1)\n      edgeB2 = Part.makeLine(PntB1,PntB2)\n      edgeB3 = Part.makeLine(PntB2,PntB3)\n\n      if a_point <= r:\n        edgeB1 = Part.makeLine(Pnt9,PntB1)\n        aWire=Part.Wire([edge2,edge3,edge4,edge5,edge6,edge7, \\\n            edgeB1, edgeB2, edgeB3])\n      else:\n        edge8 = Part.makeLine(Pnt9,Pnt10)\n        edgeB1 = Part.makeLine(Pnt10,PntB1)\n        aWire=Part.Wire([edge2,edge3,edge4,edge5,edge6,edge7,edge8, \\\n            edgeB1, edgeB2, edgeB3])\n      #Part.show(aWire)\n\n    headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #head = Part.Solid(headShell)\n    #Part.show(aWire)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n    headFaces = headShell.Faces\n\n\n    if SType == 'ISO14579':\n      #recess = self.makeIso10664(tt, t, k) # hexalobular recess\n      recess, recessShell = self.makeIso10664_3(tt, t, k) # hexalobular recess\n    else:\n      recess, recessShell = self.makeAllen2(s_mean, t, k )\n\n    recessShell = recessShell.cut(hCut)\n    topFace = hCut.Faces[1]\n    #topFace = hCut.Faces[0]\n    topFace = topFace.cut(recess)\n    #Part.show(topFace)\n    #Part.show(recessShell)\n    #Part.show(headShell)\n    headFaces.append(topFace.Faces[0])\n    #headFaces.append(hCut.Faces[2])\n\n    #allenscrew = head.cut(recess)\n    #Part.show(hCut)\n    headFaces.extend(recessShell.Faces)\n\n    #if self.RealThread.isChecked():\n    if self.rThread:\n      #if (dia < 3.0) or (dia > 5.0):\n      if True:\n        # head = self.cutIsoThread(head, dia, P, turns, l)\n        rthread = self.makeShellthread(dia, P, halfturns, True, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point-2.0*P))\n        #Part.show(rthread)\n        for tFace in rthread.Faces:\n          headFaces.append(tFace)\n        headShell = Part.Shell(headFaces)\n        allenscrew = Part.Solid(headShell)\n\n      else:\n        # head = self.cutIsoThread(head, dia, P, turns, l)\n        rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point-2.0*P))\n        for tFace in rthread.Faces:\n          headFaces.append(tFace)\n        headShell = Part.Shell(headFaces)\n        allenscrew = Part.Solid(headShell)\n        cyl = self.cutChamfer(dia, P, l)\n        # FreeCAD.Console.PrintMessage(\"vor Schnitt Ende: \" + str(dia) + \"\\n\")\n        allenscrew = allenscrew.cut(cyl)\n    else:\n      headShell = Part.Shell(headFaces)\n      allenscrew = Part.Solid(headShell)\n\n\n    return allenscrew\n\n\n\n\n  # make ISO 7380-1 Button head Screw\n  # make ISO 7380-2 Button head Screw with collar\n  # make DIN 967 cross recessed pan head Screw with collar\n  def makeIso7380(self, SType ='ISO7380-1', ThreadType ='M6',l=25.0):\n    dia = get_diameter(ThreadType)\n    #todo: different radii for screws with thread to head or with shaft?\n    sqrt2_ = 1.0/math.sqrt(2.0)\n\n    if (SType =='DIN967'):\n      P, b, c, da, dk, r, k, rf, x, cT, mH, mZ = din967def[ThreadType]\n\n      rH = rf # radius of button arc\n      alpha = math.acos((rf-k+c)/rf)\n\n      #Head Points\n      Pnt0 = Base.Vector(0.0,0.0,k)\n      PntArc = Base.Vector(rf*math.sin(alpha/2.0),0.0,k-rf + rf*math.cos(alpha/2.0)) #arc-point of button\n      Pnt1 = Base.Vector(rf*math.sin(alpha),0.0,c)     #end of button arc\n      PntC0 = Base.Vector((dk)/2.0,0.0,c)     #collar points\n      PntC2 = Base.Vector((dk)/2.0,0.0,0.0)     #collar points\n      Pnt4 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n\n      edge1 = Part.Arc(Pnt0,PntArc,Pnt1).toShape()\n      edgeC0 = Part.makeLine(Pnt1,PntC0)\n      edgeC1 = Part.makeLine(PntC0,PntC2)\n      edge2 = Part.Wire([edgeC0, edgeC1])\n      edge3 = Part.makeLine(PntC2,Pnt4)\n      #Points for recessShell cutter\n      PntH0 = Base.Vector(0.0,0.0,2.0*k)\n      PntH1 = Base.Vector(rf*math.sin(alpha),0.0,2.0*k)\n      recess, recessShell = self.makeCross_H3(cT, mH, k)\n\n    else:\n      if (SType =='ISO7380-1'):\n        P, b, a, da, dk, dk_mean,s_mean, t_min, r, k, e, w = iso7380def[ThreadType]\n\n        # Bottom of recess\n        e_cham = 2.0 * s_mean / math.sqrt(3.0) / 0.99\n        #depth = s_mean / 3.0\n\n        ak = -(4*k**2 + e_cham**2 - dk**2)/(8*k) # helper value for button arc\n        rH = math.sqrt((dk/2.0)**2 + ak**2) # radius of button arc\n        alpha = (math.atan(2*(k + ak)/e_cham) + math.atan((2*ak)/dk))/2\n\n        Pnt2 = Base.Vector(rH*math.cos(alpha),0.0,-ak + rH*math.sin(alpha)) #arc-point of button\n        Pnt3 = Base.Vector(dk/2.0,0.0,0.0)   #end of fillet\n        Pnt4 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n        edge3 = Part.makeLine(Pnt3,Pnt4)\n\n      if (SType =='ISO7380-2'):\n        P, b, c, da, dk, dk_c,s_mean,t_min, r, k, e, w = iso7380_2def[ThreadType]\n\n        # Bottom of recess\n        e_cham = 2.0 * s_mean / math.sqrt(3.0) / 0.99\n        #depth = s_mean / 3.0\n\n        ak = -(4*(k-c)**2 + e_cham**2 - dk**2)/(8*(k-c)) # helper value for button arc\n        rH = math.sqrt((dk/2.0)**2 + ak**2) # radius of button arc\n        alpha = (math.atan(2*(k -c + ak)/e_cham) + math.atan((2*ak)/dk))/2\n\n        Pnt2 = Base.Vector(rH*math.cos(alpha),0.0,c -ak + rH*math.sin(alpha)) #arc-point of button\n        Pnt3 = Base.Vector(dk/2.0,0.0,c)   #end of fillet\n        Pnt4 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n        PntC0 = Base.Vector((dk_c-c)/2.0,0.0,c)     #collar points\n        PntC1 = Base.Vector(dk_c/2.0,0.0,c/2.0)     #collar points\n        PntC2 = Base.Vector((dk_c-c)/2.0,0.0,0.0)     #collar points\n\n        edgeC0 = Part.makeLine(Pnt3,PntC0)\n        edgeC1 = Part.Arc(PntC0,PntC1,PntC2).toShape()\n        edge3 = Part.makeLine(PntC2,Pnt4)\n        edge3 = Part.Wire([edgeC0, edgeC1, edge3])\n\n      #Head Points\n      Pnt0 = Base.Vector(e_cham/4.0,0.0,k-e_cham/4.0) #Center Point for chamfer\n      Pnt1 = Base.Vector(e_cham/2.0,0.0,k)     #inner chamfer edge at head\n      #Points for recessShell cutter\n      PntH0 = Base.Vector(e_cham/4.0,0.0,2.0*k)\n      PntH1 = Base.Vector(e_cham/2.0,0.0,2.0*k)\n\n      edge1 = Part.makeLine(Pnt0,Pnt1)\n      edge2 = Part.Arc(Pnt1,Pnt2,Pnt3).toShape()\n      recess, recessShell = self.makeAllen2(s_mean, t_min, k)\n\n    if (b > (l - 1.0*P)):\n       bmax = l- 1.0*P\n    else:\n       bmax = b\n\n    ### make the new code with math.modf(l)\n    residue, turns = math.modf((bmax)/P)\n    halfturns = 2*int(turns)\n    if residue < 0.5:\n      a_point = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a_point = l - (turns+2.0) * P\n    offSet = r - a_point\n\n\n    Pnt5 = Base.Vector(dia/2.0+r-r*sqrt2_,0.0,-r+r*sqrt2_) #arc-point of fillet\n    Pnt6 = Base.Vector(dia/2.0,0.0,-r)        # end of fillet\n    Pnt7 = Base.Vector(dia/2.0,0.0,-a_point)        # start of thread\n\n    edge4 = Part.Arc(Pnt4,Pnt5,Pnt6).toShape()\n    edge5 = Part.makeLine(Pnt6,Pnt7)\n\n    if (SType =='DIN967'):\n      # bolt points\n      PntB1 = Base.Vector(dia/2.0,0.0,-l)\n      PntB2 = Base.Vector(0.0,0.0,-l)\n      edgeB2 = Part.makeLine(PntB1,PntB2)\n    else:\n      # bolt points\n      cham_b = P*math.sqrt(3.0)/2.0*17.0/24.0\n\n      PntB1 = Base.Vector(dia/2.0,0.0,-l+cham_b)\n      PntB2 = Base.Vector(dia/2.0-cham_b,0.0,-l)\n      PntB3 = Base.Vector(0.0,0.0,-l)\n\n      edgeB2 = Part.makeLine(PntB1,PntB2)\n      edgeB3 = Part.makeLine(PntB2,PntB3)\n      edgeB2 = Part.Wire([edgeB2, edgeB3])\n\n    if self.rThread:\n      aWire=Part.Wire([edge2,edge3,edge4])\n    else:\n      if a_point <= r:\n        edgeB1 = Part.makeLine(Pnt6,PntB1)\n        aWire=Part.Wire([edge2,edge3,edge4, edgeB1, edgeB2])\n      else:\n        edge5 = Part.makeLine(Pnt6,Pnt7)\n        edgeB1 = Part.makeLine(Pnt7,PntB1)\n        aWire=Part.Wire([edge2,edge3,edge4,edge5, edgeB1, edgeB2])\n\n    #Part.show(aWire)\n    headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(headShell)\n    headFaces = headShell.Faces\n\n    edgeH1 = Part.makeLine(Pnt1,PntH1)\n    edgeH2 = Part.makeLine(PntH1,PntH0)\n    edgeH3 = Part.makeLine(PntH0,Pnt0)\n    hWire = Part.Wire([edge1,edgeH1,edgeH2,edgeH3]) # Cutter for recess-Shell\n    hFace = Part.Face(hWire)\n    hCut = hFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(hWire)\n    topFace = hCut.Faces[0]\n\n    recessShell = recessShell.cut(hCut)\n    topFace = topFace.cut(recess)\n    #Part.show(topFace)\n    #Part.show(recessShell)\n    #Part.show(headShell)\n    headFaces.append(topFace.Faces[0])\n    headFaces.extend(recessShell.Faces)\n\n\n    if self.rThread:\n      #if (dia < 3.0) or (dia > 5.0):\n      if True:\n        if (SType =='DIN967'):\n          rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        else:\n          rthread = self.makeShellthread(dia, P, halfturns, True, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n        for threadFace in rthread.Faces:\n          headFaces.append(threadFace)\n\n        screwShell = Part.Shell(headFaces)\n        screw = Part.Solid(screwShell)\n      else:\n        rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n        for threadFace in rthread.Faces:\n          headFaces.append(threadFace)\n\n        screwShell = Part.Shell(headFaces)\n        screw = Part.Solid(screwShell)\n        cyl = self.cutChamfer(dia, P, l)\n        screw = screw.cut(cyl)\n    else:\n      screwShell = Part.Shell(headFaces)\n      screw = Part.Solid(screwShell)\n\n    return screw\n\n\n\n\n  def makeHextool(self,s_hex, k_hex, cir_hex):\n    # makes a cylinder with an inner hex hole, used as cutting tool\n    # create hexagon\n    mhex=Base.Matrix()\n    mhex.rotateZ(math.radians(60.0))\n    polygon = []\n    vhex=Base.Vector(s_hex/math.sqrt(3.0),0.0,-k_hex*0.1)\n    for i in range(6):\n       polygon.append(vhex)\n       vhex = mhex.multiply(vhex)\n    polygon.append(vhex)\n    hexagon = Part.makePolygon(polygon)\n    # create circle\n    circ = Part.makeCircle(cir_hex/2.0, Base.Vector(0.0,0.0,-k_hex*0.1), self.circleAxis)\n    # Create the face with the circle as outline and the hexagon as hole\n    face=Part.Face([Part.Wire(circ),hexagon])\n\n    # Extrude in z to create the final cutting tool\n    exHex=face.extrude(Base.Vector(0.0,0.0,k_hex*1.2))\n    # Part.show(exHex)\n    return exHex\n\n\n  def makeShellthread(self, d, P, halfrots, withcham, offSet):\n    d = float(d)\n\n    #rotations = int(rots)-1\n    halfrots_int = int(halfrots)\n    rotations = (halfrots_int // 2) - 1\n    if halfrots_int % 2 == 1:\n      #FreeCAD.Console.PrintMessage(\"got half turn: \" + str(halfrots_int) + \"\\n\")\n      halfturn = True\n      # bot_off = - P/2.0 # transition of half a turn\n      bot_off = 0.0 # nominal length\n    else:\n      halfturn = False\n      bot_off = 0.0 # nominal length\n\n    H=P*math.cos(math.radians(30)) # Gewindetiefe H\n    r=d/2.0\n\n    # helix = Part.makeHelix(P,P,d*511/1000.0,0) # make just one turn, length is identical to pitch\n    helix = Part.makeHelix(P,P,d*self.Tuner/1000.0,0) # make just one turn, length is identical to pitch\n    helix.translate(FreeCAD.Vector(0.0, 0.0,-P*9.0/16.0))\n\n    extra_rad = P\n    # points for screw profile\n    ps0 = (r,0.0, 0.0)\n    ps1 = (r-H*5.0/8.0,0.0, -P*5.0/16.0)\n    ps2 = (r-H*17.0/24.0,0.0, -P*7.0/16.0) # Center of Arc\n    ps3 = (r-H*5.0/8.0,0.0, -P*9.0/16.0 )\n    ps4 =  (r, 0.0, -P*14.0/16.0)\n    ps5 = (r,0.0, -P)\n    ps6 = (r+extra_rad,0.0, -P)\n    ps7 = (r+extra_rad,0.0, 0.0)\n\n    edge0 = Part.makeLine(ps0,ps1)\n    edge1 = Part.Arc(FreeCAD.Vector(ps1),FreeCAD.Vector(ps2),FreeCAD.Vector(ps3)).toShape()\n    edge2 = Part.makeLine(ps3,ps4)\n    edge3 = Part.makeLine(ps4,ps5)\n    edge4 = Part.makeLine(ps5,ps6)\n    edge5 = Part.makeLine(ps6,ps7)\n    edge6 = Part.makeLine(ps7,ps0)\n\n    W0 = Part.Wire([edge0, edge1, edge2, edge3, edge4, edge5, edge6])\n\n    makeSolid=True\n    isFrenet=True\n    pipe0 = Part.Wire(helix).makePipeShell([W0],makeSolid,isFrenet)\n    # pipe1 = pipe0.copy()\n\n    TheFaces = []\n    TheFaces.append(pipe0.Faces[0])\n    #Part.show(pipe0.Faces[0])\n    TheFaces.append(pipe0.Faces[1])\n    #Part.show(pipe0.Faces[1])\n    TheFaces.append(pipe0.Faces[2])\n    #Part.show(pipe0.Faces[2])\n    TheFaces.append(pipe0.Faces[3])\n    #Part.show(pipe0.Faces[3])\n\n    TheShell = Part.Shell(TheFaces)\n    # print \"Shellpoints: \", len(TheShell.Vertexes)\n\n\n    i = 1\n    for i in range(rotations-2):\n       TheShell.translate(FreeCAD.Vector(0.0, 0.0, -P))\n\n       for flaeche in TheShell.Faces:\n         TheFaces.append(flaeche)\n\n    #FreeCAD.Console.PrintMessage(\"Base-Shell: \" + str(i) + \"\\n\")\n    # Make separate faces for the tip of the screw\n    botFaces = []\n    for i in range(rotations-2, rotations, 1):\n       TheShell.translate(FreeCAD.Vector(0.0, 0.0, -P))\n\n       for flaeche in TheShell.Faces:\n         botFaces.append(flaeche)\n    #FreeCAD.Console.PrintMessage(\"Bottom-Shell: \" + str(i) + \"\\n\")\n\n    # making additional faces for transition to cylinder\n\n    pc1 = (r + H/16.0,0.0,P*1/32.0)\n    pc2 = (r-H*5.0/8.0,0.0,-P*5.0/16.0 )\n    pc3 = (r-H*17.0/24.0,0.0, -P*7.0/16.0 ) # Center of Arc\n    pc4 = (r-H*5.0/8.0,0.0, -P*9.0/16.0 )\n    pc5 =  (r+ H/16.0, 0.0, -P*29.0/32.0 )\n\n    edgec0 = Part.makeLine(pc5,pc1)\n    edgec1 = Part.makeLine(pc1,pc2)\n    edgec2 = Part.Arc(FreeCAD.Vector(pc2),FreeCAD.Vector(pc3),FreeCAD.Vector(pc4)).toShape()\n    edgec3 = Part.makeLine(pc4,pc5)\n\n    cut_profile = Part.Wire([edgec1, edgec2, edgec3, edgec0 ])\n\n    alpha_rad = math.atan(2*H*17.0/24.0/P)\n    alpha = math.degrees(alpha_rad)\n    Hyp = P/math.cos(alpha_rad)\n    # tuning = 511/1000.0\n    tuning = self.Tuner/1000.0\n    angled_Helix = Part.makeHelix(Hyp,Hyp*1.002/2.0,d*tuning,alpha)\n\n    SH_faces = []\n\n    if halfturn:\n      half_Helix = Part.makeHelix(P,P/2.0,d*self.Tuner/1000.0,0) # make just half a turn\n      angled_Helix.rotate(Base.Vector(0,0,0),Base.Vector(0,0,1),180)\n      angled_Helix.translate(FreeCAD.Vector(0.0, 0.0,P/2.0))\n      # Part.show(half_Helix)\n      # Part.show(angled_Helix)\n      pipe_cut = Part.Wire([half_Helix, angled_Helix]).makePipeShell([cut_profile],True,isFrenet)\n      SH_faces.append(pipe_cut.Faces[0])\n      SH_faces.append(pipe_cut.Faces[1])\n      SH_faces.append(pipe_cut.Faces[2])\n      SH_faces.append(pipe_cut.Faces[4])\n      SH_faces.append(pipe_cut.Faces[5])\n      SH_faces.append(pipe_cut.Faces[6])\n\n    else:\n      pipe_cut = Part.Wire(angled_Helix).makePipeShell([cut_profile],True,isFrenet)\n      SH_faces.append(pipe_cut.Faces[0])\n      SH_faces.append(pipe_cut.Faces[1])\n      SH_faces.append(pipe_cut.Faces[2])\n\n    # Part.show(pipe_cut)\n\n\n    Shell_helix = Part.Shell(SH_faces)\n\n    # rect_helix_profile, needed for cutting a tube-shell\n    pr1 = (r +H/16.0, 0.0, 0.0)\n    pr2 = (r -H/16.0, 0.0, 0.0)\n    pr3 = (r -H/16.0, 0.0, P)\n    pr4 = (r +H/16.0, 0.0, P)\n\n    edge_r1 = Part.makeLine(pr1,pr2)\n    edge_r2 = Part.makeLine(pr2,pr3)\n    edge_r3 = Part.makeLine(pr3,pr4)\n    edge_r4 = Part.makeLine(pr4,pr1)\n    rect_profile = Part.Wire([edge_r1, edge_r2, edge_r3, edge_r4 ])\n    rect_helix = Part.Wire(helix).makePipeShell([rect_profile], True, isFrenet)\n    # if halfturn:\n    #   rect_helix.rotate(Base.Vector(0,0,0),Base.Vector(0,0,1),180)\n    rect_helix.translate(FreeCAD.Vector(0.0, 0.0,- P))\n    # Part.show(rect_helix)\n\n    # rect_ring, needed for cutting the Shell_helix\n    pr5 = (r +H*1.1, 0.0, P*1.1)\n    pr6 = (r, 0.0, P*1.1)\n    pr7 = (r, 0.0, -P*1.1)\n    pr8 = (r +H*1.1, 0.0, -P*1.1)\n\n    edge_r5 = Part.makeLine(pr5,pr6)\n    edge_r6 = Part.makeLine(pr6,pr7)\n    edge_r7 = Part.makeLine(pr7,pr8)\n    edge_r8 = Part.makeLine(pr8,pr5)\n    rect_profile = Part.Wire([edge_r5, edge_r6, edge_r7, edge_r8 ])\n\n    rect_Face =Part.Face(rect_profile)\n    rect_ring= rect_Face.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(rect_ring)\n\n    Shell_helix = Shell_helix.cut(rect_ring)\n    Shell_helix.translate(FreeCAD.Vector(0.0, 0.0, P))\n    # Part.show(Shell_helix)\n\n    # shell_ring, the transition to a cylinder\n    pr9 = (r, 0.0, P-offSet)\n    pr10 = (r, 0.0, -P )\n    edge_r9 = Part.makeLine(pr9,pr10)\n    shell_ring= edge_r9.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n\n    shell_ring = shell_ring.cut(pipe_cut)\n    #Part.show(shell_ring)\n    shell_ring = shell_ring.cut(rect_helix)\n    shell_ring.translate(FreeCAD.Vector(0.0, 0.0, P))\n    #Part.show(shell_ring)\n\n    for flaeche in shell_ring.Faces:\n      TheFaces.append(flaeche)\n\n    for flaeche in Shell_helix.Faces:\n      TheFaces.append(flaeche)\n\n    if withcham:\n      #FreeCAD.Console.PrintMessage(\"with chamfer: \" + str(i) + \"\\n\")\n      # cutting of the bottom Faces\n      # bot_off = 0.0 # nominal length\n      cham_off = H/8.0\n      cham_t = P*math.sqrt(3.0)/2.0*17.0/24.0\n\n      # points for chamfer: common-Method\n      pch0 =  (0.0, 0.0, -(rotations)*P + bot_off) # bottom center\n      pch1 =  (r-cham_t,0.0, -(rotations)*P + bot_off)\n      pch2 =  (r+cham_off, 0.0, -(rotations)*P + cham_t +cham_off  + bot_off)\n      pch3 =  (r+cham_off, 0.0, -(rotations)*P + 3.0*P + bot_off)\n      pch4 =  (0.0, 0.0, -(rotations)*P + 3.0*P + bot_off)\n\n      edgech0 = Part.makeLine(pch0,pch1)\n      edgech1 = Part.makeLine(pch1,pch2)\n      edgech2 = Part.makeLine(pch2,pch3)\n      edgech3 = Part.makeLine(pch3,pch4)\n      edgech4 = Part.makeLine(pch4,pch0)\n\n      Wch_wire = Part.Wire([edgech0, edgech1, edgech2, edgech3, edgech4])\n      cham_Face =Part.Face(Wch_wire)\n      cham_Solid = cham_Face.revolve(Base.Vector(0.0,0.0,-(rotations-1)*P),Base.Vector(0.0,0.0,1.0),360)\n      # Part.show(cham_Solid)\n\n      BotShell = Part.Shell(botFaces)\n      BotShell = BotShell.common(cham_Solid)\n      # Part.show(BotShell)\n\n      cham_faces = []\n      cham_faces.append(cham_Solid.Faces[0])\n      cham_faces.append(cham_Solid.Faces[1])\n      cham_Shell = Part.Shell(cham_faces)\n      # Part.show(cham_Shell)\n\n      pipe0.translate(FreeCAD.Vector(0.0, 0.0, -(rotations-1)*P))\n      # Part.show(pipe0)\n\n      # Part.show(Fillet_shell)\n      cham_Shell = cham_Shell.cut(pipe0)\n      pipe0.translate(FreeCAD.Vector(0.0, 0.0, -P))\n      # Part.show(pipe0)\n      cham_Shell = cham_Shell.cut(pipe0)\n\n      '''\n      botFaces2 = []\n      for flaeche in BotShell.Faces:\n        botFaces2.append(flaeche)\n      for flaeche in cham_Shell.Faces:\n        botFaces2.append(flaeche)\n      '''\n\n    else: # tip of screw without chamfer\n      #FreeCAD.Console.PrintMessage(\"without chamfer: \" + str(i) + \"\\n\")\n\n      commonbox = Part.makeBox(d+4.0*P, d+4.0*P, 3.0*P)\n      commonbox.translate(FreeCAD.Vector(-(d+4.0*P)/2.0, -(d+4.0*P)/2.0,-(rotations)*P+bot_off))\n      #commonbox.translate(FreeCAD.Vector(-(d+4.0*P)/2.0, -(d+4.0*P)/2.0,-(rotations+3)*P+bot_off))\n      #Part.show(commonbox)\n\n      BotShell = Part.Shell(botFaces)\n      #Part.show(BotShell)\n\n      BotShell = BotShell.common(commonbox)\n      #BotShell = BotShell.cut(commonbox)\n      bot_edges =[]\n      bot_z =  1.0e-5 -(rotations)*P + bot_off\n\n      for kante in BotShell.Edges:\n         if (kante.Vertexes[0].Point.z<=bot_z) and (kante.Vertexes[1].Point.z<=bot_z):\n            bot_edges.append(kante)\n            # Part.show(kante)\n      bot_wire = Part.Wire(Part.__sortEdges__(bot_edges))\n\n      #botFaces2 = []\n      #for flaeche in BotShell.Faces:\n      #  botFaces2.append(flaeche)\n\n      bot_face = Part.Face(bot_wire)\n      bot_face.reverse()\n      #botFaces2.append(bot_face)\n\n    '''\n\n    BotShell2 = Part.Shell(botFaces2)\n    # Part.show(BotShell2)\n\n    TheShell2 = Part.Shell(TheFaces)\n\n    # This gives a shell\n    FaceList = []\n    for flaeche in TheShell2.Faces:\n      FaceList.append(flaeche)\n    for flaeche in BotShell2.Faces:\n      FaceList.append(flaeche)\n\n    TheShell = Part.Shell(FaceList)\n    # Part.show(TheShell)\n    '''\n    for flaeche in BotShell.Faces:\n      TheFaces.append(flaeche)\n    if withcham:\n      for flaeche in cham_Shell.Faces:\n        TheFaces.append(flaeche)\n    else:\n      TheFaces.append(bot_face)\n    TheShell = Part.Shell(TheFaces)\n\n    #print self.Tuner, \" \", TheShell.ShapeType, \" \", TheShell.isValid(), \" hrots: \", halfrots_int, \" Shellpunkte: \", len(TheShell.Vertexes)\n\n    return TheShell\n\n  # if da<>None: make Shell for a nut else: make a screw tap\n  def makeInnerThread_2(self, d, P, rotations, da, l):\n    d = float(d)\n    bot_off = 0.0 # nominal length\n\n    H=P*math.cos(math.radians(30)) # Gewindetiefe H\n    r=d/2.0\n\n    helix = Part.makeHelix(P,P,d*self.Tuner/1000.0,0) # make just one turn, length is identical to pitch\n    helix.translate(FreeCAD.Vector(0.0, 0.0,-P*9.0/16.0))\n\n    extra_rad = P\n\n    # points for inner thread profile\n    ps0 = (r,0.0, 0.0)\n    ps1 = (r-H*5.0/8.0,0.0, -P*5.0/16.0)\n    ps2 = (r-H*5.0/8.0,0.0, -P*9.0/16.0 )\n    ps3 =  (r, 0.0, -P*14.0/16.0)\n    ps4 = (r+H*1/24.0,0.0, -P*31.0/32.0) # Center of Arc\n    ps5 = (r,0.0, -P)\n    ps6 = (r+extra_rad,0.0, -P)\n    ps7 = (r+extra_rad,0.0, 0.0)\n\n    #ps6 = (r-extra_rad,0.0, -P)\n    #ps7 = (r-extra_rad,0.0, 0.0)\n\n    edge0 = Part.makeLine(ps0,ps1)\n    edge1 = Part.makeLine(ps1,ps2)\n    edge2 = Part.makeLine(ps2,ps3)\n    edge3 = Part.Arc(FreeCAD.Vector(ps3),FreeCAD.Vector(ps4),FreeCAD.Vector(ps5)).toShape()\n    edge4 = Part.makeLine(ps5,ps6)\n    edge5 = Part.makeLine(ps6,ps7)\n    edge6 = Part.makeLine(ps7,ps0)\n\n    W0 = Part.Wire([edge0, edge1, edge2, edge3, edge4, edge5, edge6])\n    # Part.show(W0)\n\n    makeSolid=True\n    isFrenet=True\n    pipe0 = Part.Wire(helix).makePipeShell([W0],makeSolid,isFrenet)\n    # pipe1 = pipe0.copy()\n\n    TheFaces = []\n    TheFaces.append(pipe0.Faces[0])\n    TheFaces.append(pipe0.Faces[1])\n    TheFaces.append(pipe0.Faces[2])\n    TheFaces.append(pipe0.Faces[3])\n\n    TheShell = Part.Shell(TheFaces)\n    # print \"Shellpoints: \", len(TheShell.Vertexes)\n\n    # Handling of the top faces\n    if da is not None:\n      TheShell.translate(FreeCAD.Vector(0.0, 0.0, -P))\n      for flaeche in TheShell.Faces:\n       TheFaces.append(flaeche)\n      TheShell.translate(FreeCAD.Vector(0.0, 0.0, -P))\n      for flaeche in TheShell.Faces:\n       TheFaces.append(flaeche)\n\n      cham_i_delta = da/2.0 - (r-H)\n      cham_i = cham_i_delta * math.tan(math.radians(15.0))\n\n      offSet = rotations*P - l\n      #FreeCAD.Console.PrintMessage(\"Der Offset: \" + str(offSet/P) + \"\\n\")\n\n      # points for chamfer: common-Method\n      pch0 =  (da/2.0-cham_i_delta, 0.0, -cham_i - offSet) # bottom chamfer\n      pch1 =  (da/2.0, 0.0, 0.0 - offSet)  #\n      pch2 =  (da/2.0, 0.0, -4.0*P - offSet)\n      pch3 =  (da/2.0-cham_i_delta, 0.0, -4.0*P - offSet)\n\n      edgech0 = Part.makeLine(pch0,pch1)\n      edgech1 = Part.makeLine(pch1,pch2)\n      edgech2 = Part.makeLine(pch2,pch3)\n      edgech3 = Part.makeLine(pch3,pch0)\n\n      Wch_wire = Part.Wire([edgech0, edgech1, edgech2, edgech3])\n      cham_Face =Part.Face(Wch_wire)\n      cham_Solid = cham_Face.revolve(Base.Vector(0.0,0.0,-(rotations-1)*P),Base.Vector(0.0,0.0,1.0),360)\n      #Part.show(cham_Solid)\n      #Part.show(Wch_wire)\n\n      rawTopShell = Part.Shell(TheFaces)\n      topShell = rawTopShell.common(cham_Solid)\n\n      # Making a Cutter for the cham face\n      commonbox = Part.makeBox(d+4.0*P, d+4.0*P, 2.0*P)\n      commonbox.translate(FreeCAD.Vector(-(d+4.0*P)/2.0, -(d+4.0*P)/2.0,-2.0*P))\n      #Part.show(commonbox)\n\n      cutterShell = rawTopShell.common(commonbox)\n      bot_edges =[]\n      bot_z =  1.0e-5 -2.0*P\n\n      for kante in cutterShell.Edges:\n         if (kante.Vertexes[0].Point.z<=bot_z) and (kante.Vertexes[1].Point.z<=bot_z):\n            bot_edges.append(kante)\n            # Part.show(kante)\n      bot_wire = Part.Wire(Part.__sortEdges__(bot_edges))\n\n      bot_face = Part.Face(bot_wire)\n      bot_face.reverse()\n      t_face = bot_face.copy()\n      t_face.translate(Base.Vector(0.0, 0.0, 2.0*P))\n      cutterFaces = cutterShell.Faces\n      cutterFaces.append(bot_face.Faces[0])\n      cutterFaces.append(t_face.Faces[0])\n      cutShell = Part.Shell(cutterFaces)\n      chamFcutter = Part.Solid(cutShell)\n\n      #Part.show(chamFcutter)\n      topCham = cham_Solid.Faces[0]\n      topCham = topCham.cut(chamFcutter)\n\n      #Part.show(topCham)\n      TheFaces = [topCham.Faces[0]]\n      TheFaces.extend(topShell.Faces)\n\n      for i in range(rotations-4):\n         TheShell.translate(FreeCAD.Vector(0.0, 0.0,- P))\n         for flaeche in TheShell.Faces:\n           TheFaces.append(flaeche)\n\n    else:\n      commonbox = Part.makeBox(d+4.0*P, d+4.0*P, 3.0*P)\n      commonbox.translate(FreeCAD.Vector(-(d+4.0*P)/2.0, -(d+4.0*P)/2.0,-(3.0)*P))\n      topShell = TheShell.common(commonbox)\n      top_edges =[]\n      top_z =  -1.0e-5\n\n      for kante in topShell.Edges:\n         if (kante.Vertexes[0].Point.z>=top_z) and (kante.Vertexes[1].Point.z>=top_z):\n            top_edges.append(kante)\n            # Part.show(kante)\n      top_wire = Part.Wire(Part.__sortEdges__(top_edges))\n      top_face = Part.Face(top_wire)\n\n      TheFaces = [top_face.Faces[0]]\n      TheFaces.extend(topShell.Faces)\n\n      for i in range(rotations-2):\n         TheShell.translate(FreeCAD.Vector(0.0, 0.0,- P))\n         for flaeche in TheShell.Faces:\n           TheFaces.append(flaeche)\n\n    #FreeCAD.Console.PrintMessage(\"Base-Shell: \" + str(i) + \"\\n\")\n    # Make separate faces for the tip of the screw\n    botFaces = []\n    for i in range(rotations-2, rotations, 1):\n       TheShell.translate(FreeCAD.Vector(0.0, 0.0,- P))\n\n       for flaeche in TheShell.Faces:\n         botFaces.append(flaeche)\n    #FreeCAD.Console.PrintMessage(\"Bottom-Shell: \" + str(i) + \"\\n\")\n\n    if da is not None:\n      # points for chamfer: common-Method\n      pch0 =  (da/2-cham_i_delta, 0.0, -(rotations)*P + cham_i) # bottom chamfer\n      pch1 =  (da/2, 0.0, -(rotations)*P)  #\n      pch2 =  (da/2, 0.0, -(rotations)*P + 3.0*P)\n      pch3 =  (da/2-cham_i_delta, 0.0, -(rotations)*P + 3.0*P)\n      #pch4 =  (r-2.0*cham_i_delta, 0.0, -(rotations)*P + 3.0*P)\n\n      edgech0 = Part.makeLine(pch0,pch1)\n      edgech1 = Part.makeLine(pch1,pch2)\n      edgech2 = Part.makeLine(pch2,pch3)\n      edgech3 = Part.makeLine(pch3,pch0)\n\n      Wch_wire = Part.Wire([edgech0, edgech1, edgech2, edgech3])\n      cham_Face =Part.Face(Wch_wire)\n      cham_Solid = cham_Face.revolve(Base.Vector(0.0,0.0,-(rotations-1)*P),Base.Vector(0.0,0.0,1.0),360)\n      #Part.show(cham_Solid)\n      #Part.show(Wch_wire)\n\n      BotShell = Part.Shell(botFaces)\n      #Part.show(BotShell)\n      chamFcutter.translate(FreeCAD.Vector(0.0, 0.0,-(rotations-1)*P))\n      #Part.show(chamFcutter)\n\n\n      BotShell = BotShell.common(cham_Solid)\n      #Part.show(BotShell)\n\n      cham_face = cham_Solid.Faces[0]\n      cham_face = cham_face.cut(chamFcutter)\n      #Part.show(cham_face)\n\n      for flaeche in BotShell.Faces:\n        TheFaces.append(flaeche)\n      if da is not None:\n        TheFaces.append(cham_face.Faces[0])\n      else:\n        TheFaces.append(bot_face)\n      TheShell = Part.Shell(TheFaces)\n\n      #print self.Tuner, \" \", TheShell.ShapeType, \" \", TheShell.isValid(), \" hrots: \", halfrots_int, \" Shellpunkte: \", len(TheShell.Vertexes)\n\n      return TheShell\n\n    else: # make of screw tap\n      #FreeCAD.Console.PrintMessage(\"without chamfer: \" + str(i) + \"\\n\")\n\n      commonbox = Part.makeBox(d+4.0*P, d+4.0*P, 3.0*P)\n      commonbox.translate(FreeCAD.Vector(-(d+4.0*P)/2.0, -(d+4.0*P)/2.0,-(rotations)*P+bot_off))\n      #commonbox.translate(FreeCAD.Vector(-(d+4.0*P)/2.0, -(d+4.0*P)/2.0,-(rotations+3)*P+bot_off))\n      #Part.show(commonbox)\n\n      BotShell = Part.Shell(botFaces)\n      #Part.show(BotShell)\n\n      BotShell = BotShell.common(commonbox)\n      #BotShell = BotShell.cut(commonbox)\n      bot_edges =[]\n      bot_z =  1.0e-5 -(rotations)*P + bot_off\n\n      for kante in BotShell.Edges:\n         if (kante.Vertexes[0].Point.z<=bot_z) and (kante.Vertexes[1].Point.z<=bot_z):\n            bot_edges.append(kante)\n            # Part.show(kante)\n      bot_wire = Part.Wire(Part.__sortEdges__(bot_edges))\n\n      bot_face = Part.Face(bot_wire)\n      bot_face.reverse()\n\n      for flaeche in BotShell.Faces:\n        TheFaces.append(flaeche)\n      if da is not None:\n        raise NotImplementedError('da must be None')\n        # TODO: Fix cham_Shell undefined.\n        for flaeche in cham_Shell.Faces:\n          TheFaces.append(flaeche)\n      else:\n        TheFaces.append(bot_face)\n      TheShell = Part.Shell(TheFaces)\n      TheSolid = Part.Solid(TheShell)\n\n      #print self.Tuner, \" \", TheShell.ShapeType, \" \", TheShell.isValid(), \" hrots: \", halfrots_int, \" Shellpunkte: \", len(TheShell.Vertexes)\n\n      return TheSolid\n\n  def makeIso4032(self, SType='ISO4032', ThreadType='M6'):\n    \"\"\"ISO 4032 Hex-nut and 4033 Hex-nut\"\"\"\n    dia = get_diameter(ThreadType)\n    if SType == 'ISO4032':\n      # P, c, damax,  dw,    e,     m,   mw,   s_nom\n      P, c, da, dw, e, m, mw, s = iso4032def[ThreadType]\n    if SType == 'ISO4033':\n      # P, c, damax,  dw,    e,     m,   mw,   s_nom\n      P, c, da, dw, e, m, mw, s = iso4033def[ThreadType]\n    if SType == 'ISO4035':\n      # P, c, damax,  dw,    e,     m,   mw,   s_nom\n      P, c, da, dw, e, m, mw, s = iso4035def[ThreadType]\n\n    residue, turns = math.modf(m/P)\n    #halfturns = 2*int(turns)\n\n    if residue > 0.0:\n      turns += 1.0\n      #halfturns = halfturns +2\n    #offSet = r - a\n\n    sqrt2_ = 1.0/math.sqrt(2.0)\n    cham = (e-s)*math.sin(math.radians(15)) # needed for chamfer at nut top\n    H=P*math.cos(math.radians(30)) # Gewindetiefe H\n    cham_i_delta = da/2.0 - (dia/2.0-H*5.0/8.0)\n    cham_i = cham_i_delta * math.tan(math.radians(15.0))\n\n\n    if self.rThread:\n      Pnt0 = Base.Vector(da/2.0-2.0*cham_i_delta,0.0,m - 2.0*cham_i)\n      Pnt7 = Base.Vector(da/2.0-2.0*cham_i_delta,0.0,0.0+ 2.0*cham_i)\n    else:\n      Pnt0 = Base.Vector(dia/2.0-H*5.0/8.0,0.0,m - cham_i)\n      Pnt7 = Base.Vector(dia/2.0-H*5.0/8.0,0.0,0.0+ cham_i)\n\n    Pnt1 = Base.Vector(da/2.0,0.0,m)\n    Pnt2 = Base.Vector(s/2.0,0.0,m)\n    Pnt3 = Base.Vector(s/math.sqrt(3.0),0.0,m-cham)\n    Pnt4 = Base.Vector(s/math.sqrt(3.0),0.0,cham)\n    Pnt5 = Base.Vector(s/2.0,0.0,0.0)\n    Pnt6 = Base.Vector(da/2.0,0.0,0.0)\n\n    edge0 = Part.makeLine(Pnt0,Pnt1)\n    edge1 = Part.makeLine(Pnt1,Pnt2)\n    edge2 = Part.makeLine(Pnt2,Pnt3)\n    edge3 = Part.makeLine(Pnt3,Pnt4)\n    edge4 = Part.makeLine(Pnt4,Pnt5)\n    edge5 = Part.makeLine(Pnt5,Pnt6)\n    edge6 = Part.makeLine(Pnt6,Pnt7)\n    edge7 = Part.makeLine(Pnt7,Pnt0)\n\n    # create cutting tool for hexagon head\n    # Parameters s, k, outer circle diameter =  e/2.0+10.0\n    extrude = self.makeHextool(s, m, s*2.0)\n\n    aWire=Part.Wire([edge0,edge1,edge2,edge3,edge4,edge5,edge6,edge7])\n    # Part.show(aWire)\n    aFace =Part.Face(aWire)\n    head = aFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360.0)\n    #Part.show(head)\n\n    # Part.show(extrude)\n    nut = head.cut(extrude)\n    # Part.show(nut)\n\n    if self.rThread:\n      '''\n      threadCutter = self.makeInnerThread(dia, P, int(turns), None, m)\n      # Part.show(threadCutter)\n      threadCutter.translate(Base.Vector(0.0, 0.0,turns*P))\n      nut = nut.cut(threadCutter)\n      '''\n      nutFaces = [nut.Faces[2]]\n      for i in range(4,25):\n        nutFaces.append(nut.Faces[i])\n\n\n      threadShell = self.makeInnerThread_2(dia, P, int(turns), da, m)\n      threadShell.translate(Base.Vector(0.0, 0.0,turns*P))\n      #Part.show(threadShell)\n      nutFaces.extend(threadShell.Faces)\n\n      nutShell = Part.Shell(nutFaces)\n      nut = Part.Solid(nutShell)\n      #Part.show(nutShell)\n\n    return nut\n\n  def makeEN1661(self, ThreadType='M8'):\n    \"\"\"EN 1661 Hexagon nuts with flange\n\n    chamfer at top of hexagon is wrong = more than 30\u00b0\n    \"\"\"\n    dia = get_diameter(ThreadType)\n    P, da, c, dc, dw, e, m, mw, r1, s = en1661def[ThreadType]\n\n    residue, turns = math.modf(m/P)\n    #halfturns = 2*int(turns)\n\n    if residue > 0.0:\n      turns += 1.0\n\n    #FreeCAD.Console.PrintMessage(\"the nut with isoEN1661: \" + str(c) + \"\\n\")\n    cham = s*(2.0/math.sqrt(3.0)-1.0)*math.sin(math.radians(25)) # needed for chamfer at head top\n\n    sqrt2_ = 1.0/math.sqrt(2.0)\n\n    # Flange is made with a radius of c\n    beta = math.radians(25.0)\n    tan_beta = math.tan(beta)\n\n    # Calculation of Arc points of flange edge using dc and c\n    arc1_x = dc/2.0 - c/2.0 + (c/2.0)*math.sin(beta)\n    arc1_z = c/2.0 + (c/2.0)*math.cos(beta)\n\n    hF = arc1_z + (arc1_x -s/2.0) * tan_beta  # height of flange at center\n\n    #kmean = arc1_z + (arc1_x - s/math.sqrt(3.0)) * tan_beta + mw * 1.1 + cham\n    #kmean = k * 0.95\n\n\n    #Hex-Head Points\n    #FreeCAD.Console.PrintMessage(\"the nut with kmean: \" + str(m) + \"\\n\")\n    PntH0 = Base.Vector(da/2.0,0.0,m)\n    PntH1 = Base.Vector(s/2.0,0.0,m)\n    edgeH1 = Part.makeLine(PntH0,PntH1)\n\n    hWire=Part.Wire([edgeH1])\n    topShell = hWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(hWire)\n    #Part.show(topShell)\n\n    # create a cutter ring to generate the chamfer at the top of the hex\n    chamHori = s/math.sqrt(3.0) - s/2.0\n    PntC1 = Base.Vector(s/2.0-chamHori,0.0,m+m)\n    PntC2 = Base.Vector(s/math.sqrt(3.0)+chamHori,0.0,m+m)\n    PntC3 = Base.Vector(s/2.0-chamHori,0.0,m+cham)\n    PntC4 = Base.Vector(s/math.sqrt(3.0)+chamHori,0.0,m-cham-cham)   #s/math.sqrt(3.0)\n    edgeC1 = Part.makeLine(PntC3, PntC1)\n    edgeC2 = Part.makeLine(PntC1, PntC2)\n    edgeC3 = Part.makeLine(PntC2, PntC4)\n    edgeC4 = Part.makeLine(PntC4, PntC3)\n    cWire = Part.Wire([edgeC4, edgeC1, edgeC2, edgeC3])\n    cFace = Part.Face(cWire)\n    chamCut = cFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(cWire)\n    #Part.show(chamCut)\n\n\n    # create hexagon\n    mhex=Base.Matrix()\n    mhex.rotateZ(math.radians(60.0))\n    polygon = []\n    vhex=Base.Vector(s/math.sqrt(3.0),0.0,m)\n    for i in range(6):\n       polygon.append(vhex)\n       vhex = mhex.multiply(vhex)\n    polygon.append(vhex)\n    hexagon = Part.makePolygon(polygon)\n    hexFace = Part.Face(hexagon)\n    solidHex = hexFace.extrude(Base.Vector(0.0,0.0,c-m))\n    #Part.show(solidHex)\n    hexCham = solidHex.cut(chamCut)\n    #Part.show(hexCham)\n\n    topFaces = topShell.Faces\n\n    topFaces.append(hexCham.Faces[1])\n    topFaces.append(hexCham.Faces[2])\n    topFaces.append(hexCham.Faces[8])\n    topFaces.append(hexCham.Faces[13])\n    topFaces.append(hexCham.Faces[14])\n    topFaces.append(hexCham.Faces[12])\n    topFaces.append(hexCham.Faces[6])\n\n    hexFaces = [hexCham.Faces[5], hexCham.Faces[11], hexCham.Faces[10]]\n    hexFaces.extend([hexCham.Faces[9], hexCham.Faces[3], hexCham.Faces[0]])\n    hexShell = Part.Shell(hexFaces)\n\n\n    H=P*math.cos(math.radians(30)) # Gewindetiefe H\n    cham_i_delta = da/2.0 - (dia/2.0-H*5.0/8.0)\n    cham_i = cham_i_delta * math.tan(math.radians(15.0))\n\n    # Center of flange:\n    Pnt0 = Base.Vector(0.0,0.0,hF)\n    Pnt1 = Base.Vector(s/2.0,0.0,hF)\n\n    # arc edge of flange:\n    Pnt2 = Base.Vector(arc1_x,0.0,arc1_z)\n    Pnt3 = Base.Vector(dc/2.0,0.0,c/2.0)\n    Pnt4 = Base.Vector((dc-c)/2.0,0.0,0.0)\n    Pnt5 = Base.Vector(da/2.0,0.0,0.0)     #start of fillet between flat and thread\n\n    edge1 = Part.makeLine(Pnt0,Pnt1)\n    edge2 = Part.makeLine(Pnt1,Pnt2)\n    edge3 = Part.Arc(Pnt2,Pnt3,Pnt4).toShape()\n    edge4 = Part.makeLine(Pnt4,Pnt5)\n\n    # make a cutter for the hexShell\n    PntHC1 = Base.Vector(0.0,0.0,arc1_z)\n    PntHC2 = Base.Vector(0.0,0.0,0.0)\n\n    edgeHC1 = Part.makeLine(Pnt2,PntHC1)\n    edgeHC2 = Part.makeLine(PntHC1,PntHC2)\n    edgeHC3 = Part.makeLine(PntHC2,Pnt0)\n\n    HCWire = Part.Wire([edge2, edgeHC1, edgeHC2, edgeHC3, edge1])\n    HCFace = Part.Face(HCWire)\n    hex2Cut = HCFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n\n    hexShell = hexShell.cut(hex2Cut)\n    #Part.show(hexShell)\n\n    topFaces.extend(hexShell.Faces)\n\n    if self.rThread:\n      aWire=Part.Wire([edge2,edge3,edge4])\n      boltIndex = 3\n\n    else:\n      Pnt7 = Base.Vector(dia/2.0-H*5.0/8.0,0.0,m - cham_i)\n      Pnt6 = Base.Vector(dia/2.0-H*5.0/8.0,0.0,0.0+ cham_i)\n      edge5 = Part.makeLine(Pnt5,Pnt6)\n      edge6 = Part.makeLine(Pnt6,Pnt7)\n      edge7 = Part.makeLine(Pnt7,PntH0)\n      aWire=Part.Wire([edge2,edge3,edge4,edge5,edge6,edge7])\n      boltIndex = 6\n\n\n    #aFace =Part.Face(aWire)\n    #Part.show(aWire)\n    headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n    #Part.show(headShell)\n    chamFace = headShell.Faces[0].cut(solidHex)\n    #Part.show(chamFace)\n\n    topFaces.append(chamFace.Faces[0])\n    for i in range(1,boltIndex):\n      topFaces.append(headShell.Faces[i])\n\n\n    if self.rThread:\n      #rthread = self.makeShellthread(dia, P, halfturns, True, offSet)\n      #rthread.translate(Base.Vector(0.0, 0.0,-a_point-2.0*P))\n      threadShell = self.makeInnerThread_2(dia, P, int(turns), da, m)\n      threadShell.translate(Base.Vector(0.0, 0.0,turns*P))\n      #Part.show(threadShell)\n      for tFace in threadShell.Faces:\n        topFaces.append(tFace)\n      headShell = Part.Shell(topFaces)\n      screw = Part.Solid(headShell)\n    else:\n      screwShell = Part.Shell(topFaces)\n      screw = Part.Solid(screwShell)\n\n    return screw\n\n  def makeScrewTap(self, ThreadType ='M6',l=25.0):\n    \"\"\"ISO 7380-1, ISO 7380-2, DIN 967\n\n    make ISO 7380-1 Button head Screw\n    make ISO 7380-2 Button head Screw with collar\n    make DIN 967 cross recessed pan head Screw with collar\n    \"\"\"\n    dia = get_diameter(ThreadType)\n\n    P, tunIn, tunEx  = tuningTable[ThreadType]\n\n    residue, turns = math.modf((l)/P)\n    turns += 1.0\n    #FreeCAD.Console.PrintMessage(\"ScrewTap residue: \" + str(residue) + \" turns: \" + str(turns) + \"\\n\")\n\n\n    if self.rThread:\n      screwTap = self.makeInnerThread_2(dia, P, int(turns), None, 0.0)\n      screwTap.translate(Base.Vector(0.0, 0.0,(1-residue)*P))\n    else:\n      H=P*math.cos(math.radians(30)) # Gewindetiefe H\n      r=dia/2.0\n\n      # points for inner thread profile\n      Pnt0 = Base.Vector(0.0,0.0,(1-residue)*P)\n      Pnt1 = Base.Vector(r-H*5.0/8.0,0.0,(1-residue)*P)\n      Pnt2 = Base.Vector(r-H*5.0/8.0,0.0,-l)\n      Pnt3 = Base.Vector(0.0,0.0,-l)\n\n      edge1 = Part.makeLine(Pnt0,Pnt1)\n      edge2 = Part.makeLine(Pnt1,Pnt2)\n      edge3 = Part.makeLine(Pnt2,Pnt3)\n      aWire=Part.Wire([edge1,edge2,edge3])\n      headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360.0)\n      screwTap = Part.Solid(headShell)\n\n    return screwTap\n\n  def cutChamfer(self, dia_cC, P_cC, l_cC):\n    cham_t = P_cC*math.sqrt(3.0)/2.0*17.0/24.0\n    PntC0 = Base.Vector(0.0,0.0,-l_cC)\n    PntC1 = Base.Vector(dia_cC/2.0-cham_t,0.0,-l_cC)\n    PntC2 = Base.Vector(dia_cC/2.0+cham_t,0.0,-l_cC+cham_t+cham_t)\n    PntC3 = Base.Vector(dia_cC/2.0+cham_t,0.0,-l_cC-P_cC-cham_t)\n    PntC4 = Base.Vector(0.0,0.0,-l_cC-P_cC-cham_t)\n\n    edgeC1 = Part.makeLine(PntC0,PntC1)\n    edgeC2 = Part.makeLine(PntC1,PntC2)\n    edgeC3 = Part.makeLine(PntC2,PntC3)\n    edgeC4 = Part.makeLine(PntC3,PntC4)\n    edgeC5 = Part.makeLine(PntC4,PntC0)\n    CWire=Part.Wire([edgeC1,edgeC2,edgeC3,edgeC4,edgeC5])\n    #Part.show(CWire)\n    CFace =Part.Face(CWire)\n    cyl = CFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    return cyl\n\n  def makeCross_H3(self, CrossType = '2', m = 6.9, h = 0.0):\n    \"\"\"Cross recess type H\n\n    m = diameter of cross at top of screw at reference level for penetration depth\n    \"\"\"\n    b, e_mean, g, f_mean, r, t1, alpha, beta = iso4757def[CrossType]\n\n    rad265 = math.radians(26.5)\n    rad28 = math.radians(28.0)\n    tg = (m-g)/2.0/math.tan(rad265) # depth at radius of g\n    t_tot = tg + g/2.0 * math.tan(rad28) # total depth\n    #FreeCAD.Console.PrintMessage(\"Cross H3: \" + str(b) + \"\\n\")\n\n    # print 'tg: ', tg,' t_tot: ', t_tot\n    hm = m / 4.0\n    hmc = m / 2.0\n    rmax = m / 2.0 + hm*math.tan(rad265)\n\n    Pnt0 = Base.Vector(0.0,0.0,hm)\n    Pnt1 = Base.Vector(rmax,0.0,hm)\n    Pnt3 = Base.Vector(0.0,0.0,0.0)\n    Pnt4 = Base.Vector(g/2.0,0.0,-tg)\n    Pnt5 = Base.Vector(0.0,0.0,-t_tot)\n\n    edge1 = Part.makeLine(Pnt0,Pnt1)\n    edge3 = Part.makeLine(Pnt1,Pnt4)\n    edge4 = Part.makeLine(Pnt4,Pnt5)\n    # FreeCAD.Console.PrintMessage(\"Edges made Pnt1: \" + str(Pnt1) + \"\\n\")\n\n    aWire=Part.Wire([edge1,edge3,edge4])\n    crossShell = aWire.revolve(Pnt3,Base.Vector(0.0,0.0,1.0),360)\n    #FreeCAD.Console.PrintMessage(\"Peak-wire revolved: \" + str(e_mean) + \"\\n\")\n    cross = Part.Solid(crossShell)\n    #Part.show(cross)\n\n    # the need to cut 4 corners out of the above shape.\n    # Definition of corner\n    # The angles 92 degrees and alpha are defined on a plane which has\n    # an angle of beta against our coordinate system.\n    # The projected angles are needed for easier calculation!\n    rad_alpha = math.radians(alpha/2.0)\n    rad92 = math.radians(92.0/2.0)\n    rad_beta = math.radians(beta)\n\n    rad_alpha_p = math.atan(math.tan(rad_alpha)/math.cos(rad_beta))\n    rad92_p = math.atan(math.tan(rad92)/math.cos(rad_beta))\n\n    tb = tg + (g-b)/2.0 * math.tan(rad28) # depth at dimension b\n    rbtop = b/2.0 + (hmc + tb)*math.tan(rad_beta) # radius of b-corner at hm\n    rbtot = b/2.0 - (t_tot - tb)*math.tan(rad_beta) # radius of b-corner at t_tot\n\n    dre = e_mean/2.0 / math.tan(rad_alpha_p)  # delta between corner b and corner e in x direction\n    #FreeCAD.Console.PrintMessage(\"delta calculated: \" + str(dre) + \"\\n\")\n\n    dx = m/2.0 * math.cos(rad92_p)\n    dy = m/2.0 * math.sin(rad92_p)\n\n    PntC0 = Base.Vector(rbtop,0.0,hmc)\n    PntC1 = Base.Vector(rbtot,0.0,-t_tot)\n    PntC2 = Base.Vector(rbtop+dre,+e_mean/2.0,hmc)\n    PntC3 = Base.Vector(rbtot+dre,+e_mean/2.0,-t_tot)\n    PntC4 = Base.Vector(rbtop+dre,-e_mean/2.0,hmc)\n    PntC5 = Base.Vector(rbtot+dre,-e_mean/2.0,-t_tot)\n\n    PntC6 = Base.Vector(rbtop+dre+dx,+e_mean/2.0+dy,hmc)\n    #PntC7 = Base.Vector(rbtot+dre+dx,+e_mean/2.0+dy,-t_tot)\n    PntC7 = Base.Vector(rbtot+dre+2.0*dx,+e_mean+2.0*dy,-t_tot)\n    PntC8 = Base.Vector(rbtop+dre+dx,-e_mean/2.0-dy,hmc)\n    #PntC9 = Base.Vector(rbtot+dre+dx,-e_mean/2.0-dy,-t_tot)\n    PntC9 = Base.Vector(rbtot+dre+2.0*dx,-e_mean-2.0*dy,-t_tot)\n\n    #wire_hm = Part.makePolygon([PntC0,PntC2,PntC6,PntC8,PntC4,PntC0])\n    #face_hm =Part.Face(wire_hm)\n    #Part.show(face_hm)\n\n    wire_t_tot = Part.makePolygon([PntC1,PntC3,PntC7,PntC9,PntC5,PntC1])\n    # Part.show(wire_t_tot)\n    edgeC1 = Part.makeLine(PntC0,PntC1)\n    #FreeCAD.Console.PrintMessage(\"edgeC1 mit PntC9\" + str(PntC9) + \"\\n\")\n\n    makeSolid=True\n    isFrenet=False\n    corner = Part.Wire(edgeC1).makePipeShell([wire_t_tot],makeSolid,isFrenet)\n    #Part.show(corner)\n\n    rot_axis = Base.Vector(0.,0.,1.0)\n    sin_res = math.sin(math.radians(90)/2.0)\n    cos_res = math.cos(math.radians(90)/2.0)\n    rot_axis.multiply(-sin_res) # Calculation of Quaternion-Elements\n    #FreeCAD.Console.PrintMessage(\"Quaternion-Elements\" + str(cos_res) + \"\\n\")\n\n    pl_rot = FreeCAD.Placement()\n    pl_rot.Rotation = (rot_axis.x,rot_axis.y,rot_axis.z,cos_res) #Rotation-Quaternion 90\u00b0 z-Axis\n\n    crossShell = crossShell.cut(corner)\n    # Part.show(crossShell)\n    cutplace = corner.Placement\n\n    cornerFaces = []\n    cornerFaces.append(corner.Faces[0])\n    cornerFaces.append(corner.Faces[1])\n    cornerFaces.append(corner.Faces[3])\n    cornerFaces.append(corner.Faces[4])\n\n    cornerShell = Part.Shell(cornerFaces)\n    cornerShell = cornerShell.common(cross)\n    addPlace = cornerShell.Placement\n\n    crossFaces = cornerShell.Faces\n\n    for i in range(3):\n      #cutplace.Rotation = pl_rot.Rotation.multiply(corner.Placement.Rotation)\n      corner.Placement.Rotation = pl_rot.Rotation.multiply(corner.Placement.Rotation)\n      crossShell = crossShell.cut(corner)\n      #addPlace.Rotation = pl_rot.Rotation.multiply(cornerShell.Placement.Rotation)\n      cornerShell.Placement.Rotation = pl_rot.Rotation.multiply(cornerShell.Placement.Rotation)\n      for coFace in cornerShell.Faces:\n        crossFaces.append(coFace)\n\n    # Part.show(crossShell)\n    for i in range(1,6):\n      crossFaces.append(crossShell.Faces[i])\n\n    crossShell0 = Part.Shell(crossFaces)\n\n    crossFaces.append(crossShell.Faces[0])\n    crossShell = Part.Shell(crossFaces)\n\n    cross = Part.Solid(crossShell)\n\n\n    #FreeCAD.Console.PrintMessage(\"Placement: \" + str(pl_rot) + \"\\n\")\n\n    cross.Placement.Base = Base.Vector(0.0,0.0,h)\n    crossShell0.Placement.Base = Base.Vector(0.0,0.0,h)\n    #Part.show(crossShell0)\n    #Part.show(cross)\n    return cross, crossShell0\n\n  def makeAllen2(self, s_a=3.0, t_a=1.5, h_a=2.0):\n    \"\"\"Allen recess cutting tool\n\n    Parameters used: s_mean, k, t_min, dk\n    \"\"\"\n    # h_a  top height location of cutting tool\n    # s_a hex width\n    # t_a dept of the allen\n    # dk_a diameter not needed anymore\n\n    e_cham = 2.0 * s_a / math.sqrt(3.0)\n    depth = s_a / 3.0\n    #FreeCAD.Console.PrintMessage(\"allen tool: \" + str(s_a) + \"\\n\")\n\n    # Points for an arc at the peak of the cone\n    rCone = e_cham/4.0\n    hyp = (depth*math.sqrt(e_cham**2/depth**2+1.0)*rCone)/e_cham\n    radAlpha = math.atan(e_cham/depth)\n    radBeta = math.pi/2.0 - radAlpha\n    zrConeCenter=hyp - depth -t_a\n    xArc1=math.sin(radBeta)*rCone\n    zArc1=zrConeCenter - math.cos(radBeta)*rCone\n    xArc2=math.sin(radBeta/2.0)*rCone\n    zArc2=zrConeCenter - math.cos(radBeta/2.0)*rCone\n    zArc3 = zrConeCenter - rCone\n\n    # The round part of the cutting tool, we need for the allen hex recess\n    PntH1 = Base.Vector(0.0,0.0,-t_a-depth-depth)\n    PntH2 = Base.Vector(e_cham,0.0,-t_a-depth-depth)\n    PntH3 = Base.Vector(e_cham,0.0,-t_a+depth)\n    PntH4 = Base.Vector(0.0,0.0,-t_a-depth)\n\n    PntA1 = Base.Vector(xArc1,0.0,zArc1)\n    PntA2 = Base.Vector(xArc2,0.0,zArc2)\n    PntA3 = Base.Vector(0.0,0.0,zArc3)\n\n    edgeA1 = Part.Arc(PntA1,PntA2,PntA3).toShape()\n\n    edgeH1 = Part.makeLine(PntH1,PntH2)\n    edgeH2 = Part.makeLine(PntH2,PntH3)\n    edgeH3 = Part.makeLine(PntH3,PntA1)\n    edgeH4 = Part.makeLine(PntA3,PntH1)\n\n    hWire=Part.Wire([edgeH1,edgeH2,edgeH3,edgeA1,edgeH4])\n    # Part.show(hWire)\n    hFace =Part.Face(hWire)\n    roundtool = hFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n\n    # create hexagon\n    mhex=Base.Matrix()\n    mhex.rotateZ(math.radians(60.0))\n    polygon = []\n    vhex=Base.Vector(s_a/math.sqrt(3.0),0.0,1.0)\n    for i in range(6):\n       polygon.append(vhex)\n       vhex = mhex.multiply(vhex)\n    polygon.append(vhex)\n    hexagon = Part.makePolygon(polygon)\n    hexFace = Part.Face(hexagon)\n    solidHex = hexFace.extrude(Base.Vector(0.0,0.0,-1.0-t_a-depth*1.1))\n    allen = solidHex.cut(roundtool)\n    # Part.show(allen)\n\n    allenFaces = [allen.Faces[0]]\n    for i in range(2,9):\n      allenFaces.append(allen.Faces[i])\n    allenShell = Part.Shell(allenFaces)\n    solidHex.Placement.Base = Base.Vector(0.0,0.0,h_a)\n    allenShell.Placement.Base = Base.Vector(0.0,0.0,h_a)\n    return solidHex, allenShell\n\n  def makeIso10664_3(self,RType ='T20',t_hl=3.0, h_hl = 0):\n    \"\"\"ISO 10664 Hexalobular internal driving feature for bolts and screws\"\"\"\n    # t_hl depth of the recess\n    # h_hl top height location of Cutting tool\n    A, B, Re = iso10664def[RType]\n    sqrt_3 = math.sqrt(3.0)\n    depth=A/4.0\n    offSet = 1.0\n\n    # Chamfer cutter for the hexalobular recess\n    PntH1 = Base.Vector(0.0,0.0,-t_hl-depth-1.0)\n    #PntH2 = Base.Vector(A/2.0*1.02,0.0,-t_hl-depth-1.0)\n    #PntH3 = Base.Vector(A/2.0*1.02,0.0,-t_hl)\n    PntH2 = Base.Vector(A,0.0,-t_hl-depth-1.0)\n    PntH3 = Base.Vector(A,0.0,-t_hl+depth)\n    PntH4 = Base.Vector(0.0,0.0,-t_hl-depth)\n\n    # Points for an arc at the peak of the cone\n    rCone = A/4.0\n    hyp = (depth*math.sqrt(A**2/depth**2+1.0)*rCone)/A\n    radAlpha = math.atan(A/depth)\n    radBeta = math.pi/2.0 - radAlpha\n    zrConeCenter=hyp - depth -t_hl\n    xArc1=math.sin(radBeta)*rCone\n    zArc1=zrConeCenter - math.cos(radBeta)*rCone\n    xArc2=math.sin(radBeta/2.0)*rCone\n    zArc2=zrConeCenter - math.cos(radBeta/2.0)*rCone\n    zArc3 = zrConeCenter - rCone\n\n    PntA1 = Base.Vector(xArc1,0.0,zArc1)\n    PntA2 = Base.Vector(xArc2,0.0,zArc2)\n    PntA3 = Base.Vector(0.0,0.0,zArc3)\n\n    edgeA1 = Part.Arc(PntA1,PntA2,PntA3).toShape()\n\n    edgeH1 = Part.makeLine(PntH1,PntH2)\n    edgeH2 = Part.makeLine(PntH2,PntH3)\n    edgeH3 = Part.makeLine(PntH3,PntA1)\n    edgeH4 = Part.makeLine(PntA3,PntH1)\n\n    hWire=Part.Wire([edgeH1,edgeH2,edgeH3,edgeA1])\n    cutShell = hWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    cutTool = Part.Solid(cutShell)\n\n\n    Ri = -((B+sqrt_3*(2.*Re-A))*B+(A-4.*Re)*A)/(4.*B-2.*sqrt_3*A+(4.*sqrt_3-8.)*Re)\n    #print '2nd  Ri last solution: ', Ri\n    beta=math.acos(A/(4*Ri+4*Re)-(2*Re)/(4*Ri+4*Re))-math.pi/6\n    #print 'beta: ', beta\n    Rh=(sqrt_3*(A/2.0-Re))/2.0\n    Re_x = A/2.0 - Re + Re*math.sin(beta)\n    Re_y = Re*math.cos(beta)\n    Ri_y = B/4.0\n    Ri_x = sqrt_3*B/4.0\n\n    mhex=Base.Matrix()\n    mhex.rotateZ(math.radians(60.0))\n    hexlobWireList = []\n\n    PntRe0=Base.Vector(Re_x,-Re_y,offSet)\n    PntRe1=Base.Vector(A/2.0,0.0,offSet)\n    PntRe2=Base.Vector(Re_x,Re_y,offSet)\n    edge0 = Part.Arc(PntRe0,PntRe1,PntRe2).toShape()\n    #Part.show(edge0)\n    hexlobWireList.append(edge0)\n\n    PntRi = Base.Vector(Ri_x,Ri_y,offSet)\n    PntRi2 = mhex.multiply(PntRe0)\n    edge1 = Part.Arc(PntRe2,PntRi,PntRi2).toShape()\n    #Part.show(edge1)\n    hexlobWireList.append(edge1)\n\n    for i in range(5):\n       PntRe1 = mhex.multiply(PntRe1)\n       PntRe2 = mhex.multiply(PntRe2)\n       edge0 = Part.Arc(PntRi2,PntRe1,PntRe2).toShape()\n       hexlobWireList.append(edge0)\n       PntRi = mhex.multiply(PntRi)\n       PntRi2 = mhex.multiply(PntRi2)\n       if i == 5:\n          edge1 = Part.Arc(PntRe2,PntRi,PntRe0).toShape()\n       else:\n          edge1 = Part.Arc(PntRe2,PntRi,PntRi2).toShape()\n       hexlobWireList.append(edge1)\n    hexlobWire=Part.Wire(hexlobWireList)\n    #Part.show(hWire)\n\n    face=Part.Face(hexlobWire)\n\n    # Extrude in z to create the cutting tool for the screw-head-face\n    Helo=face.extrude(Base.Vector(0.0,0.0,-t_hl-depth-offSet))\n    # Make the recess-shell for the screw-head-shell\n\n    hexlob = Helo.cut(cutTool)\n    #Part.show(hexlob)\n    hexlobFaces = [hexlob.Faces[0]]\n    for i in range(2,15):\n      hexlobFaces.append(hexlob.Faces[i])\n\n    hexlobShell = Part.Shell(hexlobFaces)\n\n    hexlobShell.Placement.Base = Base.Vector(0.0,0.0,h_hl)\n    Helo.Placement.Base = Base.Vector(0.0,0.0,h_hl)\n\n    return Helo, hexlobShell\n\n  def setThreadType(self, TType = 'simple'):\n    self.simpThread = False\n    self.symThread = False\n    self.rThread = False\n    if TType == 'simple':\n      self.simpThread = True\n    if TType == 'symbol':\n      self.symThread = True\n    if TType == 'real':\n      self.rThread = True\n\n  def setTuner(self, myTuner = 511):\n    self.Tuner = myTuner\n\n\nclass ScrewMacro(object):\n  d = QtGui.QWidget()\n  d.ui = Ui_ScrewMaker()\n  d.ui.setupUi(d)\n  if __name__ == '__main__':\n    d.show()\n\n\ndef main():\n  o = ScrewMacro()\n\nif __name__ == '__main__':\n  main()\n",
    "url": "http://freecadweb.org/wiki/Macro_screw_maker1_2",
    "raw_code_url": "",
    "wiki": "http://freecadweb.org/wiki/Macro_screw_maker1_2",
    "version": "2.3.1",
    "license": "",
    "date": "2018-10-22",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ObjectCreation\\ScrewMaker.FCMacro",
    "filename_from_url": "",
    "author": "Ulrich Brammer <ulrich1a@users.sourceforge.net>",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "TimingGear",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "GT2/GT3/GT5 Gear Creator Macro (any gear size from 5 to 360 teeth)",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"Macro GT2/GT3/GT5 Timing Gear Creator for FreeCAD.\"\"\"\n#\n# -----------------------------------------------------------------------------\n#                         Copyright (c) 2019 - Emilio Aguirre\n# -----------------------------------------------------------------------------\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLEFOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n# ---------------------------------------------------------------------------------------\n# TimingGear.png courtesy of Wikipedia\n# (https://en.wikipedia.org/wiki/Key_%28engineering%29).\n#\n# Changelog\n# ---------\n# - v 1.5:\n#   - Fix position of base.\n# - v 1.4:\n#   - Fixing bugs related to size of top and base\n#   - Adding code to keep dialog upfront main window (thanks mario52 !)\n# - v 1.3:\n#   - Adding key for shaft hub\n#   - Fixing issue with top\n#   - Fixing issue with shaft (now values are in diameter)\n\n__Name__ = 'GT2/GT3/GT5 Timing Gear Creator'\n__Comment__ = 'GT2/GT3/GT5 Gear Creator Macro (any gear size from 5 to 360 teeth)'\n__Author__ = 'eaguirre,galou'\n__Version__ = '1.5.0'\n__Date__ = '2019-12-29'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'http://www.emilioaguirre.com'\n__Wiki__ = 'https://wiki.freecadweb.org/Macro_TimingGear'\n__Icon__ = 'TimingGear.png'\n__Help__ = 'Click on the TimingGear button/macro, and fill the required data in the dialog window.'\n__Status__ = ''\n__Requires__ = 'FreeCAD ?.??'\n__Communication__ = 'info_at_emilioaguirre.com,https://github.com/FreeCAD/FreeCAD-macros/issues://forum.freecadweb.org/viewtopic.php?t=35899'\n__Files__ = 'TimingGear.png'\n\n# TODO: Fix segfault when clicking a second time on \"Create\".\n\nimport math\n\nfrom PySide import QtCore\nfrom PySide import QtGui\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nimport Part  # From FreeCAD.\nimport ProfileLib.RegularPolygon  # From FreeCAD.\nfrom FreeCAD import Base\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _tr(context, text, disambig=None):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _tr(context, text, disambig=None):\n        return QtGui.QApplication.translate(context, text, disambig)\n\n\ndef _circle_intersect_vline(x, r):\n    y = math.sqrt(r*r - x*x)\n    return y\n\n\ndef _polar(angle_deg, radius, pt):\n    \"\"\"Convert from polar to Cartesian.\n\n    Convert from polar coordinates (theta, radius) to cartesian\n    coordinates. The result is added to the given vector pt\n    \"\"\"\n    p = app.Vector(0, 0, 0)\n    p[0] = pt[0] + radius * math.cos(math.radians(angle_deg))\n    p[1] = pt[1] + radius * math.sin(math.radians(angle_deg))\n    return p\n\n\ndef _bisector_vector(v1, v2, m):\n    \"\"\"Get the vector between two vectors.\"\"\"\n    return (v1 + v2).normalize() * m\n\n\n# -----------------------------------\n# QT Window Class\n# -----------------------------------\nclass TimingGearWindow(object):\n\n    def __init__(self, main_window):\n        self.with_shaft = True\n        self.circular_shaft = True  # Hexagonal if False.\n        self.shaft_diameter = 5.0\n        self.gear_height = 6.0\n        self.base_height = 1.0\n        self.base_diameter = 6.37\n        self.top_height = 1.0\n        self.top_diameter = 6.37\n        self.with_base = False\n        self.with_top = False\n        self.max_shaft_diameter = 100.0\n        self.tooth_count = 20\n        self.with_key = False\n        self.key_b = 2\n        self.key_h = 2\n        self.t1 = 1.2\n        self.t2 = 1\n\n        # UI Definition\n        win_width = 300.0\n        win_height = 340.0\n        self.window = main_window\n        main_window.setObjectName(_fromUtf8('GT2/GT3/GT5 Timing Gear'))\n        main_window.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)\n        main_window.resize(win_width, win_height)\n        self.central_wdgt = QtGui.QWidget(MainWindow)\n\n        # UI Elements\n        self.type_lbl = QtGui.QLabel(self.central_wdgt)\n        self.type_lbl.setGeometry(QtCore.QRect(win_width*0.05, win_height*0.01, 150, 16))\n\n        self.type_combo = QtGui.QComboBox(self.central_wdgt)\n        self.type_combo.addItems(['GT2', 'GT3', 'GT5'])\n        self.type_combo.setGeometry(QtCore.QRect(win_width*0.45, win_height*0.01, 95, 20))\n        self.type_combo.currentIndexChanged.connect(self._on_gt_type_change)\n\n        self.tooth_count_lbl = QtGui.QLabel(self.central_wdgt)\n        self.tooth_count_lbl.setGeometry(QtCore.QRect(win_width*0.05, win_height*0.08, 150, 16))\n\n        self.tooth_count_spin = QtGui.QSpinBox(self.central_wdgt)\n        self.tooth_count_spin.setGeometry(QtCore.QRect(win_width*0.45, win_height*0.08, 100, 22))\n        self.tooth_count_spin.setMinimum(5)\n        self.tooth_count_spin.setMaximum(360)\n        self.tooth_count_spin.setSingleStep(1)\n        self.tooth_count_spin.setValue(self.tooth_count)\n        self.tooth_count_spin.valueChanged.connect(self._on_num_teeth_changed)\n\n        self.range_lbl = QtGui.QLabel(self.central_wdgt)\n        self.range_lbl.setGeometry(QtCore.QRect(win_width*0.80, win_height*0.08, 150, 16))\n\n        self.gear_height_lbl = QtGui.QLabel(self.central_wdgt)\n        self.gear_height_lbl.setGeometry(QtCore.QRect(win_width*0.05, win_height*0.16, 150, 16))\n\n        self.gear_height_spin = QtGui.QDoubleSpinBox(self.central_wdgt)\n        self.gear_height_spin.setGeometry(QtCore.QRect(win_width*0.45, win_height*0.16, 100, 22))\n        self.gear_height_spin.setMinimum(0.01)\n        self.gear_height_spin.setMaximum(100.0)\n        self.gear_height_spin.setSingleStep(0.01)\n        self.gear_height_spin.setValue(self.gear_height)\n        self.gear_height_spin.valueChanged.connect(self._on_hgearear_valuechanged)\n\n        self.gear_height_mm_lbl = QtGui.QLabel(self.central_wdgt)\n        self.gear_height_mm_lbl.setGeometry(QtCore.QRect(win_width*0.80, win_height*0.16, 32, 16))\n\n        # Shaft Information\n        self.with_shaft_check = QtGui.QCheckBox('With shaft', self.central_wdgt)\n        self.with_shaft_check.setGeometry(QtCore.QRect(win_width*0.05, win_height*0.25, 200, 25))\n        self.with_shaft_check.setChecked(self.with_shaft)\n        self.with_shaft_check.clicked.connect(self._on_checkShaft_clicked)\n\n        self.shaft_diam_spin = QtGui.QDoubleSpinBox(self.central_wdgt)\n        self.shaft_diam_spin.setGeometry(QtCore.QRect(win_width*0.45, win_height*0.25, 100, 22))\n        self.shaft_diam_spin.setMinimum(0.01)\n        self.shaft_diam_spin.setMaximum(100.0)\n        self.shaft_diam_spin.setSingleStep(0.01)\n        self.shaft_diam_spin.setValue(self.shaft_diameter)\n        self.shaft_diam_spin.valueChanged.connect(self._on_diameter_shaft_valuechanged)\n\n        self.shaft_diam_mm_lbl = QtGui.QLabel(self.central_wdgt)\n        self.shaft_diam_mm_lbl.setGeometry(QtCore.QRect(win_width*0.8, win_height*0.25, 32, 16))\n\n        self.circular_shaft_radio = QtGui.QRadioButton('Circle', self.central_wdgt)\n        self.circular_shaft_radio.move(win_width*0.25, win_height*0.33)\n        self.circular_shaft_radio.setChecked(self.circular_shaft)\n        self.circular_shaft_radio.clicked.connect(self._on_radioCircle_clicked)\n\n        self.checkKeyHub = QtGui.QCheckBox('Key hub', self.central_wdgt)\n        self.checkKeyHub.setGeometry(QtCore.QRect(win_width*0.55, win_height*0.33, 200, 25))\n        self.checkKeyHub.setChecked(self.with_key)\n        self.checkKeyHub.clicked.connect(self._on_checkKeyHub_clicked)\n        self.checkKeyHub.hide()\n\n        self.hexagonal_shaft_radio = QtGui.QRadioButton('Hexagon', self.central_wdgt)\n        self.hexagonal_shaft_radio.move(win_width*0.25, win_height*0.38)\n        self.hexagonal_shaft_radio.setChecked(not self.circular_shaft)\n        self.hexagonal_shaft_radio.clicked.connect(self._on_radioHex_clicked)\n\n        # Base information\n        self.checkBase = QtGui.QCheckBox('Add base', self.central_wdgt)\n        self.checkBase.move(win_width*0.05, win_height*0.45)\n        self.checkBase.setChecked(self.with_base)\n        self.checkBase.clicked.connect(self._on_checkBase_clicked)\n\n        self.base_height_lbl = QtGui.QLabel(self.central_wdgt)\n        self.base_height_lbl.setGeometry(QtCore.QRect(win_width*0.4, win_height*0.45, 32, 16))\n        self.base_height_lbl.hide()\n\n        self.base_height_spin = QtGui.QDoubleSpinBox(self.central_wdgt)\n        self.base_height_spin.setGeometry(QtCore.QRect(win_width*0.45, win_height*0.45, 100, 22))\n        self.base_height_spin.setMinimum(0.01)\n        self.base_height_spin.setMaximum(100.0)\n        self.base_height_spin.setSingleStep(0.5)\n        self.base_height_spin.setValue(self.base_height)\n        self.base_height_spin.valueChanged.connect(self._on_height_base_valuechanged)\n        self.base_height_spin.hide()\n\n        self.base_height_mm_lbl = QtGui.QLabel(self.central_wdgt)\n        self.base_height_mm_lbl.setGeometry(QtCore.QRect(win_width*0.8, win_height*0.45, 32, 16))\n        self.base_height_mm_lbl.hide()\n\n        self.base_diam_lbl = QtGui.QLabel(self.central_wdgt)\n        self.base_diam_lbl.setGeometry(QtCore.QRect(win_width*0.4, win_height*0.54, 32, 16))\n        self.base_diam_lbl.hide()\n\n        self.base_diam_spin = QtGui.QDoubleSpinBox(self.central_wdgt)\n        self.base_diam_spin.setGeometry(QtCore.QRect(win_width*0.45, win_height*0.54, 100, 22))\n        self.base_diam_spin.setMinimum(self.shaft_diameter)\n        self.base_diam_spin.setMaximum(500.0)\n        self.base_diam_spin.setSingleStep(0.5)\n        self.base_diam_spin.setValue(self.base_diameter)\n        self.base_diam_spin.valueChanged.connect(self._on_diameter_base_valuechanged)\n        self.base_diam_spin.hide()\n\n        self.base_diam_mm_lbl = QtGui.QLabel(self.central_wdgt)\n        self.base_diam_mm_lbl.setGeometry(QtCore.QRect(win_width*0.8, win_height*0.54, 32, 16))\n        self.base_diam_mm_lbl.hide()\n\n        # Top information\n        self.top_check = QtGui.QCheckBox('Add top', self.central_wdgt)\n        self.top_check.move(win_width*0.05, win_height*0.63)\n        self.top_check.setChecked(self.with_base)\n        self.top_check.clicked.connect(self._on_checkTop_clicked)\n\n        self.top_height_lbl = QtGui.QLabel(self.central_wdgt)\n        self.top_height_lbl.setGeometry(QtCore.QRect(win_width*0.4, win_height*0.63, 32, 16))\n        self.top_height_lbl.hide()\n\n        self.top_height_spin = QtGui.QDoubleSpinBox(self.central_wdgt)\n        self.top_height_spin.setGeometry(QtCore.QRect(win_width*0.45, win_height*0.63, 100, 22))\n        self.top_height_spin.setMinimum(0.01)\n        self.top_height_spin.setMaximum(100.0)\n        self.top_height_spin.setSingleStep(0.5)\n        self.top_height_spin.setValue(self.base_height)\n        self.top_height_spin.valueChanged.connect(self._on_height_top_valuechanged)\n        self.top_height_spin.hide()\n\n        self.top_height_mm_lbl = QtGui.QLabel(self.central_wdgt)\n        self.top_height_mm_lbl.setGeometry(QtCore.QRect(win_width*0.8, win_height*0.63, 32, 16))\n        self.top_height_mm_lbl.hide()\n\n        self.top_diam_lbl = QtGui.QLabel(self.central_wdgt)\n        self.top_diam_lbl.setGeometry(QtCore.QRect(win_width*0.4, win_height*0.72, 32, 16))\n        self.top_diam_lbl.hide()\n\n        self.top_diam_spin = QtGui.QDoubleSpinBox(self.central_wdgt)\n        self.top_diam_spin.setGeometry(QtCore.QRect(win_width*0.45, win_height*0.72, 100, 22))\n        self.top_diam_spin.setMinimum(self.shaft_diameter)\n        self.top_diam_spin.setMaximum(500.0)\n        self.top_diam_spin.setSingleStep(0.5)\n        self.top_diam_spin.setValue(self.top_diameter)\n        self.top_diam_spin.valueChanged.connect(self._on_diameter_top_valuechanged)\n        self.top_diam_spin.hide()\n\n        self.top_diam_mm_lbl = QtGui.QLabel(self.central_wdgt)\n        self.top_diam_mm_lbl.setGeometry(QtCore.QRect(win_width*0.8, win_height*0.72, 32, 16))\n        self.top_diam_mm_lbl.hide()\n\n        self.create_btn = QtGui.QPushButton(self.central_wdgt)\n        self.create_btn.setGeometry(QtCore.QRect(win_width*0.65, win_height*0.81, 80, 28))\n        self.create_btn.clicked.connect(self._on_create_clicked)\n\n        self.close_btn = QtGui.QPushButton(self.central_wdgt)\n        self.close_btn.setGeometry(QtCore.QRect(win_width*0.2, win_height*0.81, 80, 28))\n        self.close_btn.clicked.connect(self._on_close_clicked)\n\n        # Set UI elements to window\n        MainWindow.setCentralWidget(self.central_wdgt)\n\n        # Set strings to UI\n        self.retranslateUi(MainWindow)\n\n        # ----------------------------------------------------------------------\n        #  Key Size Chart Standard Metric Keys/Keyways Engineering\n        #  TODO: add a reference\n        # ----------------------------------------------------------------------\n        self.metric_keys = [\n            {'over': 6, 'upto': 8, 'b': 2, 'h': 2, 't1': 1.2, 't2': 1, 'r': 0.08},\n            {'over': 8, 'upto': 10, 'b': 3, 'h': 3, 't1': 1.8, 't2': 1.4, 'r': 0.08},\n            {'over': 10, 'upto': 12, 'b': 4, 'h': 4, 't1': 2.5, 't2': 1.8, 'r': 0.08},\n            {'over': 12, 'upto': 17, 'b': 5, 'h': 5, 't1': 3, 't2': 2.3, 'r': 0.16},\n            {'over': 17, 'upto': 22, 'b': 6, 'h': 6, 't1': 3.5, 't2': 2.8, 'r': 0.16},\n            {'over': 22, 'upto': 30, 'b': 8, 'h': 7, 't1': 4, 't2': 3.3, 'r': 0.16},\n            {'over': 30, 'upto': 38, 'b': 10, 'h': 8, 't1': 5, 't2': 3.3, 'r': 0.25},\n            {'over': 38, 'upto': 44, 'b': 12, 'h': 8, 't1': 5, 't2': 3.3, 'r': 0.25},\n            {'over': 44, 'upto': 50, 'b': 14, 'h': 9, 't1': 5.5, 't2': 3.8, 'r': 0.25},\n            {'over': 50, 'upto': 58, 'b': 16, 'h': 10, 't1': 6, 't2': 4.3, 'r': 0.25},\n            {'over': 58, 'upto': 65, 'b': 18, 'h': 11, 't1': 7, 't2': 4.4, 'r': 0.25},\n            {'over': 65, 'upto': 75, 'b': 20, 'h': 12, 't1': 7.5, 't2': 4.9, 'r': 0.40},\n            {'over': 75, 'upto': 85, 'b': 22, 'h': 14, 't1': 9, 't2': 5.4, 'r': 0.40},\n            {'over': 85, 'upto': 95, 'b': 25, 'h': 14, 't1': 9, 't2': 5.4, 'r': 0.40},\n            {'over': 95, 'upto': 110, 'b': 28, 'h': 16, 't1': 10, 't2': 6.4, 'r': 0.40},\n            {'over': 110, 'upto': 130, 'b': 32, 'h': 18, 't1': 11, 't2': 7.4, 'r': 0.40},\n            {'over': 130, 'upto': 150, 'b': 36, 'h': 20, 't1': 12, 't2': 8.4, 'r': 0.70},\n            {'over': 150, 'upto': 170, 'b': 40, 'h': 22, 't1': 13, 't2': 9.4, 'r': 0.70},\n            {'over': 170, 'upto': 200, 'b': 45, 'h': 25, 't1': 15, 't2': 10.4, 'r': 0.70},\n            {'over': 200, 'upto': 230, 'b': 50, 'h': 28, 't1': 17, 't2': 11.4, 'r': 0.70},\n        ]\n\n        # ----------------------------------------------------------------------\n        # Gear Data\n        # pitch - distance between two teeth\n        # u     - pitch differential. The radial distance between pitch diameter\n        #          and pulley outer diameter is called pitch differential.\n        # h     - Tooth height\n        # H     - Belt height\n        # r0    - Inner circle radius\n        # r1    - Side circle radius that define the side of a tooth\n        # rs    - Small circle radius that define the corner of a tooth\n        # offset- Offset of the side circle center\n        # name  - Gear name\n        # group - Type of Gear\n        # TODO: add a reference\n        # ----------------------------------------------------------------------\n\n        # GT2 Gear Data\n        self.gt2 = {'pitch': 2.0,\n                    'u': 0.254,\n                    'h': 0.75,\n                    'H': 1.38,\n                    'r0': 0.555,\n                    'r1': 1.0,\n                    'rs': 0.15,\n                    'offset': 0.40,\n                    'name': 'GT2',\n                    'group': 'GT'\n                    }\n        # GT3 Gear Data\n        self.gt3 = {'pitch': 3.0,\n                    'u': 0.381,\n                    'h': 1.14,\n                    'H': 2.40,\n                    'r0': 0.85,\n                    'r1': 1.52,\n                    'rs': 0.25,\n                    'offset': 0.61,\n                    'name': 'GT3',\n                    'group': 'GT'\n                    }\n        # GT5 Gear Data\n        self.gt5 = {'pitch': 5.0,\n                    'u': 0.5715,\n                    'h': 1.93,\n                    'H': 3.81,\n                    'r0': 1.44,\n                    'r1': 2.57,\n                    'rs': 0.416,\n                    'offset': 1.03,\n                    'name': 'GT5',\n                    'group': 'GT'\n                    }\n\n    def _gt_tooth(self, step, data):\n        \"\"\"Calculate the coordinates of the GT tooth vertices.\n\n        Calculate the coordinates of the GT tooth vertices (the teeth of the\n        gear, not the teeth of the timing belt). This calculates the right size\n        of the previous tooth and the left side of the next tooth\n        \"\"\"\n        up = app.Vector(0, 0, 1)\n        zero = app.Vector(0, 0, 0)\n\n        r = (data['dr0'] - data['h']) + data['r0']\n        cm = _polar(step, r - data['r0'], zero)\n        pt = _polar(step, data['dr0'], zero)\n        ptn = pt.cross(up).normalize()\n        ptd = app.Vector(pt).normalize() * -1\n\n        pr = pt + (ptn * data['offset'])\n        pl = pt + (ptn * -data['offset'])\n        a = data['r1']/2\n        b = a * math.sqrt(3)\n\n        cl = pr + (ptn * -b) + (ptd * a)\n        cl0 = pr + (ptn * -(data['r1']+data['rs']))\n        cl1 = pr + (ptn * -data['r1']) + (ptd * data['rs'])\n        ecl = cl0 + (ptd * data['rs'])\n        cl2 = ecl + _bisector_vector(cl0 - ecl, cl1 - ecl, data['rs'])\n        cl3 = pr + _bisector_vector(cl - pr, cl1 - pr, data['r1'])\n\n        cr = pl + (ptn * b) + (ptd * a)\n        cr0 = pl + (ptn * (data['r1']+data['rs']))\n        cr1 = pl + (ptn * data['r1']) + (ptd * data['rs'])\n        ecr = cr0 + (ptd * data['rs'])\n        cr2 = ecr + _bisector_vector(cr0 - ecr, cr1 - ecr, data['rs'])\n        cr3 = pl + _bisector_vector(cr - pl, cr1 - pl, data['r1'])\n        return [cr0, cr2, cr1, cr1, cr3, cr, cr, cm, cl, cl, cl3, cl1, cl1, cl2, cl0]\n\n    def create_gear(self, sketch_gear, data):\n        \"\"\"Create the geometry of the gear.\n\n        Create the geometry of the gear. Each tooth is a sequence of arcs\n        (3 points non coincidental vertices).\n        \"\"\"\n        tooth_count = data['tooth_count']\n        angle = 360.0 / tooth_count\n        gear = []\n        for idx in range(tooth_count):\n            step = angle * idx\n            t = None\n            if data['group'] == 'GT':\n                t = self._gt_tooth(step, data)\n            else:\n                raise Exception('Invalid group {}'.format(data['group']))\n            if len(gear) > 0:\n                sketch_gear.addGeometry(Part.LineSegment(gear[-1], t[0]))\n            gear.extend(t)\n            for i in range(0, len(t) - 1, 3):\n                sketch_gear.addGeometry(Part.ArcOfCircle(t[i], t[i+1], t[i+2]))\n        sketch_gear.addGeometry(Part.LineSegment(gear[-1], gear[0]))\n\n    def create_key(self, r, z):\n        y2 = r + self.t2\n        yb = _circle_intersect_vline(-self.key_b/2, r)\n        pt = _polar(90, yb, app.Vector(0, 0, z))\n        c1 = _polar(180, self.key_b/2, pt)\n        c4 = _polar(0, self.key_b, c1)\n        pt = _polar(90, y2, app.Vector(0, 0, z))\n        c2 = _polar(180, self.key_b/2, pt)\n        c3 = _polar(0, self.key_b, c2)\n        c5 = _polar(270, r, app.Vector(0, 0, z))\n        return [c1, c2, c3, c4, c5]\n\n    def create(self, data):\n        \"\"\"Create the FreeCAD elements inside a new document.\"\"\"\n        progress_bar = Base.ProgressIndicator()\n        progress_bar.start('Creating  gear...', 0)\n\n        doc = app.newDocument(data['name'])\n        doc_gui = gui.activeDocument()\n\n        gear = doc.addObject('PartDesign::Body', 'Gear')\n\n        sketch_gear = gear.newObject('Sketcher::SketchObject', 'SketchGear')\n        sketch_gear.ViewObject.hide()\n        sketch_gear.Support = (gear.Origin.OriginFeatures[3], [''])  # The XY Plane.\n        sketch_gear.MapMode = 'FlatFace'\n        sketch_gear.AttachmentOffset = app.Placement(\n            app.Vector(0, 0, 0),\n            app.Rotation(0, 0, 0, 1))\n\n        self.create_gear(sketch_gear, data)\n\n        r = self.shaft_diameter / 2\n        if self.with_shaft:\n            if self.circular_shaft:\n                if self.with_key:\n                    c = self.create_key(r, 0)\n                    key_lst = []\n                    key_lst.append(Part.LineSegment(c[0], c[1]))\n                    key_lst.append(Part.LineSegment(c[1], c[2]))\n                    key_lst.append(Part.LineSegment(c[2], c[3]))\n                    sketch_gear.addGeometry(key_lst, False)\n                    sketch_gear.addGeometry(Part.ArcOfCircle(c[3], c[4], c[0]))\n                else:\n                    sketch_gear.addGeometry(Part.Circle(app.Vector(0, 0, 0),\n                                                        app.Vector(0, 0, 1),\n                                                        r))\n            else:\n                ProfileLib.RegularPolygon.makeRegularPolygon(\n                    sketch_gear, 6, app.Vector(0, 0, 0),\n                    app.Vector(r, 0, 0), False)\n\n        pad = gear.newObject('PartDesign::Pad', 'Pad')\n        pad.Profile = sketch_gear\n        pad.Length = self.gear_height\n\n        # Add base to the Gear\n        if self.with_base:\n            sketch_base = gear.newObject('Sketcher::SketchObject', 'SketchBase')\n            sketch_base.ViewObject.hide()\n            sketch_base.Support = (gear.Origin.OriginFeatures[3], [''])  # The XY Plane.\n            sketch_base.MapMode = 'FlatFace'\n            sketch_base.AttachmentOffset = app.Placement(\n                app.Vector(0, 0, -self.base_height),\n                app.Rotation(0, 0, 0, 1))\n\n            sketch_base.addGeometry(Part.Circle(\n                app.Vector(0, 0, 0),\n                app.Vector(0, 0, 1),\n                self.base_diameter))\n            if self.with_shaft:\n                if self.circular_shaft:\n                    if self.with_key:\n                        c = self.create_key(r, -self.base_height)\n                        key_lst = []\n                        key_lst.append(Part.LineSegment(c[0], c[1]))\n                        key_lst.append(Part.LineSegment(c[1], c[2]))\n                        key_lst.append(Part.LineSegment(c[2], c[3]))\n                        sketch_base.addGeometry(key_lst, False)\n                        sketch_base.addGeometry(Part.ArcOfCircle(c[3], c[4], c[0]))\n                    else:\n                        sketch_base.addGeometry(Part.Circle(app.Vector(0, 0, 0),\n                                                            app.Vector(0, 0, 1),\n                                                            r))\n                else:\n                    ProfileLib.RegularPolygon.makeRegularPolygon(\n                        sketch_base, 6, app.Vector(0, 0, -self.base_height),\n                        app.Vector(self.shaft_diameter/2, 0, 0), False)\n\n            pad_base = gear.newObject('PartDesign::Pad', 'PadBase')\n            pad_base.Profile = sketch_base\n            pad_base.Length = self.base_height\n\n        # Add Top to the Gear\n        if self.with_top:\n            sketch_top = gear.newObject('Sketcher::SketchObject', 'SketchTop')\n            sketch_top.Support = (gear.Origin.OriginFeatures[3], [''])  # The XY Plane.\n            sketch_top.MapMode = 'FlatFace'\n            sketch_top.AttachmentOffset = app.Placement(\n                app.Vector(0, 0, self.gear_height),\n                app.Rotation(0, 0, 0, 1))\n\n            sketch_top.addGeometry(Part.Circle(app.Vector(0, 0, 0),\n                                               app.Vector(0, 0, 1),\n                                               self.top_diameter))\n            if self.with_shaft:\n                if self.circular_shaft:\n                    if self.with_key:\n                        c = self.create_key(r, 0)\n                        key_lst = []\n                        key_lst.append(Part.LineSegment(c[0], c[1]))\n                        key_lst.append(Part.LineSegment(c[1], c[2]))\n                        key_lst.append(Part.LineSegment(c[2], c[3]))\n                        sketch_top.addGeometry(key_lst, False)\n                        sketch_top.addGeometry(Part.ArcOfCircle(c[3], c[4], c[0]))\n                    else:\n                        sketch_top.addGeometry(Part.Circle(\n                            app.Vector(0, 0, 0),\n                            app.Vector(0, 0, 1),\n                            r))\n                else:\n                    ProfileLib.RegularPolygon.makeRegularPolygon(\n                        sketch_top, 6, app.Vector(0, 0, 0),\n                        app.Vector(r, 0, 0), False)\n\n            pad_top = gear.newObject('PartDesign::Pad', 'PadTop')\n            pad_top.Profile = sketch_top\n            pad_top.Length = self.top_height\n\n        doc.recompute()\n        gui.SendMsgToActiveView('ViewFit')\n        progress_bar.stop()\n\n    def retranslateUi(self, window):\n        \"\"\"Set the UI text.\"\"\"\n        window.setWindowTitle(_tr('TimingGear', 'GT2/GT3/GT5 Gear Creator'))\n        self.create_btn.setText(_tr('TimingGear', 'Create'))\n        self.close_btn.setText(_tr('TimingGear', 'Close'))\n        self.tooth_count_lbl.setText(_tr('TimingGear', 'Tooth count:'))\n        self.gear_height_lbl.setText(_tr('TimingGear', 'Gear height:'))\n        self.type_lbl.setText(_tr('TimingGear', 'Type of gear:'))\n        self.gear_height_mm_lbl.setText(_tr('TimingGear', 'mm'))\n        self.shaft_diam_mm_lbl.setText(_tr('TimingGear', 'mm'))\n        self.base_height_mm_lbl.setText(_tr('TimingGear', 'mm'))\n        self.base_diam_mm_lbl.setText(_tr('TimingGear', 'mm'))\n        self.top_height_mm_lbl.setText(_tr('TimingGear', 'mm'))\n        self.top_diam_mm_lbl.setText(_tr('TimingGear', 'mm'))\n        self.range_lbl.setText(_tr('TimingGear', '(5 ~ 360)'))\n        self.with_shaft_check.setText(_tr('TimingGear', 'Add shaft\\n(Diameter)'))\n        self.hexagonal_shaft_radio.setText(_tr('TimingGear', 'Hexagon'))\n        self.base_height_lbl.setText(_tr('TimingGear', 'H:'))\n        self.base_diam_lbl.setText(_tr('TimingGear', 'D:'))\n        self.top_height_lbl.setText(_tr('TimingGear', 'H:'))\n        self.top_diam_lbl.setText(_tr('TimingGear', 'D:'))\n        self.checkKeyHub.setText(_tr('TimingGear', 'Add key hub'))\n\n    def _update_max_shaft_diameter(self):\n        info = None\n        gear_type = str(self.type_combo.currentText())\n        if gear_type == 'GT2':\n            info = dict(self.gt2)\n        elif gear_type == 'GT3':\n            info = dict(self.gt3)\n        else:\n            info = dict(self.gt5)\n\n        self.max_shaft_diameter = ((self.tooth_count * info['pitch']) / math.pi) / 2\n        self.shaft_diam_spin.setMaximum(self.max_shaft_diameter)\n        self.with_shaft_check.setText(_tr('TimingGear',\n                                          'Add shaft\\n(max '\n                                          + '{0:.2f}'.format(self.max_shaft_diameter)\n                                          + ' mm)'))\n        self.base_diam_spin.setValue(self.max_shaft_diameter)\n        self.top_diam_spin.setValue(self.max_shaft_diameter)\n\n    def update_key_hub(self):\n        if self.shaft_diameter < 6:\n            self.with_key = False\n            return\n\n        found = False\n        for k in self.metric_keys:\n            if k['over'] <= self.shaft_diameter < k['upto']:\n                self.key_b = k['b']\n                self.key_h = k['h']\n                self.t1 = k['t1']\n                self.t2 = k['t2']\n                self.checkKeyHub.setText(_tr('TimingGear',\n                                                'Add key hub\\n(b: {} h: {})'.format(\n                                                    self.key_b, self.key_h)))\n                found = True\n                break\n\n        if not found:\n            msg = 'Could not find valid key values for shaft radius: {}'.format(shaft_diameter)\n            self._error_dialog(msg)\n            self.with_key = False\n            self.checkKeyHub.setText(_tr('TimingGear', 'Add key hub'))\n\n    # -----------------------------------\n    #         UI widgets callbacks\n    # -----------------------------------\n    def _on_gt_type_change(self, idx):\n        # app.Console.PrintMessage('Current index %d selection changed %s\\n' % (idx,self.type_combo.currentText()))\n        self._update_max_shaft_diameter()\n\n    def _on_num_teeth_changed(self, value):\n        # app.Console.PrintMessage('%s Number of Teeths\\n' % value)\n        self.tooth_count = value\n        self._update_max_shaft_diameter()\n\n    def _error_dialog(self, msg):\n        diag = QtGui.QMessageBox(QtGui.QMessageBox.Warning,\n                                 'Error in macro TimingGear',\n                                 msg)\n        diag.setWindowModality(QtCore.Qt.ApplicationModal)\n        diag.exec_()\n\n    def _on_create_clicked(self):\n        if 5 <= self.tooth_count <= 360:\n            gear_type = str(self.type_combo.currentText())\n            app.Console.PrintMessage('Creating Gear {}\\n'.format(gear_type))\n            if gear_type == 'GT2':\n                data = dict(self.gt2)\n            elif gear_type == 'GT3':\n                data = dict(self.gt3)\n            else:\n                data = dict(self.gt5)\n            data['tooth_count'] = self.tooth_count\n            data['d'] = (data['tooth_count'] * data['pitch']) / math.pi\n            data['d0'] = data['d'] - (2 * data['u'])\n            data['dr0'] = data['d0'] / 2\n            app.Console.PrintMessage('pitch {}\\n'.format(data['pitch']))\n            app.Console.PrintMessage('tooth_count {}\\n'.format(data['tooth_count']))\n            app.Console.PrintMessage('u {}\\n'.format(data['u']))\n            app.Console.PrintMessage('d {}\\n'.format(data['d']))\n            app.Console.PrintMessage('d0 {}\\n'.format(data['d0']))\n            app.Console.PrintMessage('dr0 {}\\n'.format(data['dr0']))\n            self.create(data)\n        else:\n            msg = 'The number of teeth should be between 5 and 360!'\n            self._error_dialog(msg)\n\n    def _on_close_clicked(self):\n        # app.Console.PrintMessage('Exit Gear Generator\\n')\n        self.window.close()\n\n    def _on_hgearear_valuechanged(self, value):\n        # app.Console.PrintMessage(str(value)+ ' height gear\\n')\n        self.gear_height = value\n\n    def _on_radioCircle_clicked(self):\n        self.circular_shaft = True\n        if self.shaft_diameter >= 6 and self.circular_shaft:\n            self.checkKeyHub.show()\n            self.update_key_hub()\n\n    def _on_radioHex_clicked(self):\n        self.circular_shaft = False\n        self.checkKeyHub.setChecked(False)\n        self.checkKeyHub.hide()\n\n    def _on_diameter_shaft_valuechanged(self, value):\n        # app.Console.PrintMessage(str(value) + ' Shaft radius\\n')\n        if value <= self.max_shaft_diameter:\n            self.shaft_diameter = value\n            self.base_diam_spin.setMinimum(self.shaft_diameter)\n            if self.base_diameter < self.shaft_diameter:\n                self.base_diameter = self.shaft_diameter\n\n            self.top_diam_spin.setMinimum(self.shaft_diameter)\n            if self.top_diameter < self.shaft_diameter:\n                self.top_diameter = self.shaft_diameter\n\n            if self.shaft_diameter >= 6 and self.circular_shaft:\n                self.checkKeyHub.show()\n                self.update_key_hub()\n            else:\n                self.checkKeyHub.hide()\n        else:\n            self.shaft_diameter = self.max_shaft_diameter\n            msg = 'The shaft radius should be less than: {}'.format(\n                self.max_shaft_diameter)\n            self._error_dialog(msg)\n\n    def _on_height_base_valuechanged(self, value):\n        # app.Console.PrintMessage(str(value) + ' Height base\\n')\n        self.base_height = value\n\n    def _on_diameter_base_valuechanged(self, value):\n        # app.Console.PrintMessage(str(value) + ' Radius base\\n')\n        self.base_diameter = value\n\n    def _on_height_top_valuechanged(self, value):\n        # app.Console.PrintMessage(str(value) + ' Height top\\n')\n        self.top_height = value\n\n    def _on_diameter_top_valuechanged(self, value):\n        # app.Console.PrintMessage(str(value) + ' Radius top\\n')\n        self.top_diameter = value\n\n    def _on_checkShaft_clicked(self):\n        self.with_shaft = not self.with_shaft\n        if self.with_shaft:\n            self.circular_shaft_radio.show()\n            self.hexagonal_shaft_radio.show()\n            self.shaft_diam_spin.show()\n            self.shaft_diam_mm_lbl.show()\n            if self.shaft_diameter >= 6 and self.circular_shaft:\n                self.checkKeyHub.show()\n        else:\n            self.circular_shaft_radio.hide()\n            self.hexagonal_shaft_radio.hide()\n            self.shaft_diam_spin.hide()\n            self.shaft_diam_mm_lbl.hide()\n            self.checkKeyHub.setChecked(False)\n            self.checkKeyHub.hide()\n\n    def _on_checkKeyHub_clicked(self):\n        self.with_key = not self.with_key\n        if self.with_key:\n            self.update_key_hub()\n\n    def _on_checkBase_clicked(self):\n        self.with_base = not self.with_base\n        if self.with_base:\n            self.base_height_spin.show()\n            self.base_diam_spin.show()\n            self.base_height_lbl.show()\n            self.base_diam_lbl.show()\n            self.base_height_mm_lbl.show()\n            self.base_diam_mm_lbl.show()\n        else:\n            self.base_height_spin.hide()\n            self.base_diam_spin.hide()\n            self.base_height_lbl.hide()\n            self.base_diam_lbl.hide()\n            self.base_height_mm_lbl.hide()\n            self.base_diam_mm_lbl.hide()\n\n    def _on_checkTop_clicked(self):\n        self.with_top = not self.with_top\n        if self.with_top:\n            self.top_height_spin.show()\n            self.top_diam_spin.show()\n            self.top_height_lbl.show()\n            self.top_diam_lbl.show()\n            self.top_height_mm_lbl.show()\n            self.top_diam_mm_lbl.show()\n        else:\n            self.top_height_spin.hide()\n            self.top_diam_spin.hide()\n            self.top_height_lbl.hide()\n            self.top_diam_lbl.hide()\n            self.top_height_mm_lbl.hide()\n            self.top_diam_mm_lbl.hide()\n\n\n# -----------------------------------\n# Create and display the main window\n# -----------------------------------\nMainWindow = QtGui.QMainWindow()\nui = TimingGearWindow(MainWindow)\nMainWindow.show()\n",
    "url": "http://www.emilioaguirre.com",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_TimingGear",
    "version": "1.5.0",
    "license": "",
    "date": "2019-12-29",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ObjectCreation\\TimingGear.FCMacro",
    "filename_from_url": "",
    "author": "eaguirre,galou",
    "icon": "TimingGear.png",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "TimingGear.png"
    ],
    "parsed": true
  },
  {
    "name": "GeodesicDome",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Geodesic Dome",
    "code": "# -*- coding: utf-8 -*-\n\n# ************************************************************************\n# * Copyright (c)2015 Ulrich Brammer <ulrich1a[at]users.sourceforge.net> *\n# *                                                                      *\n# * This file is a supplement to the FreeCAD CAx development system.     *\n# *                                                                      *\n# * This program is free software; you can redistribute it and/or modify *\n# * it under the terms of the GNU Lesser General Public License (LGPL)   *\n# * as published by the Free Software Foundation; either version 2 of    *\n# * the License, or (at your option) any later version.                  *\n# * for detail see the LICENCE text file.                                *\n# *                                                                      *\n# * This software is distributed in the hope that it will be useful,     *\n# * but WITHOUT ANY WARRANTY; without even the implied warranty of       *\n# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *\n# * GNU Library General Public License for more details.                 *\n# *                                                                      *\n# * You should have received a copy of the GNU Library General Public    *\n# * License along with this macro; if not, write to the Free Software    *\n# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 *\n# * USA                                                                  *\n# *                                                                      *\n# ************************************************************************\n\n__Name__ = 'Geodesic Dome'\n__Comment__ = 'Geodesic Dome'\n__Author__ = 'Ulrich Brammer'\n__Version__ = '1.0.0'\n__Date__ = '2019-03-23'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = ''\n__Wiki__ = ''\n__Icon__ = ''\n__Help__ = ''\n__Status__ = ''\n__Requires__ = ''\n__Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'\n__Files__ = 'geodesic_dome/__init__.py,geodesic_dome/geodesic_dome.py'\n\nif __name__ == '__main__':\n    #running as a macro. Load as module, to support save-restore.\n    try:\n        from geodesic_dome.geodesic_dome import GeodesicDome\n    except ImportError as err:\n        FreeCAD.Console.PrintError(\"Macro Geodesic Dome: failed to import MacroGeodesicDome.py. The parametric object will lose functionality after saving-loading your project, sorry.\")\n    else:\n        from geodesic_dome.geodesic_dome import showDialog\n        showDialog()\n",
    "url": "",
    "raw_code_url": "",
    "wiki": "",
    "version": "1.0.0",
    "license": "",
    "date": "2019-03-23",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ParametricObjectCreation\\GeodesicDome.FCMacro",
    "filename_from_url": "",
    "author": "Ulrich Brammer",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "geodesic_dome/__init__.py",
      "geodesic_dome/geodesic_dome.py"
    ],
    "parsed": true
  },
  {
    "name": "HoneycombSolid",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Macro to create a Honeycomb solid",
    "code": "\"\"\"\nHoneycombSolid --> Honeycomb solid creator.\n(c) 2021 Christian Gonz\u00e1lez Di Antonio <christiangda@gmail.com>\n\n\"\"\"\n\n__Name__ = 'HoneycombSolid'\n__Comment__ = 'Macro to create a Honeycomb solid'\n__Author__ = \"Christian Gonz\u00e1lez Di Antonio <christiangda@gmail.com>\"\n__Version__ = 'v1.2.0'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'https://github.com/christiangda/FreeCAD-macros-HoneycombSolid'\n__Wiki__ = 'https://github.com/christiangda/FreeCAD-macros-HoneycombSolid/blob/main/README.md'\n__Icon__ = 'HoneycombSolid.xpm'\n__Help__ = ''\n__Status__ = 'Stable'\n__Requires__ = ''\n__Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'\n__Files__ = 'honeycomb_solid/__init__.py,honeycomb_solid/honeycomb_solid.py'\n__Xpm__ = '''\n    /* XPM */\n    static const char * ViewProviderHoneycombSolid_xpm[] = {\n    \"16 16 54 1\",\n    \" \tc None\",\n    \".\tc #181818\",\n    \"+\tc #5F5F5F\",\n    \"@\tc #636363\",\n    \"#\tc #353535\",\n    \"$\tc #474747\",\n    \"%\tc #434343\",\n    \"&\tc #606060\",\n    \"*\tc #424242\",\n    \"=\tc #111111\",\n    \"-\tc #444444\",\n    \";\tc #151515\",\n    \">\tc #3F3F3F\",\n    \",\tc #1E1E1E\",\n    \"'\tc #1C1C1C\",\n    \")\tc #1B1B1B\",\n    \"!\tc #2C2C2C\",\n    \"~\tc #535353\",\n    \"{\tc #0A0A0A\",\n    \"]\tc #363636\",\n    \"^\tc #383838\",\n    \"/\tc #2F2F2F\",\n    \"(\tc #252525\",\n    \"_\tc #555555\",\n    \":\tc #393939\",\n    \"<\tc #515151\",\n    \"[\tc #262626\",\n    \"}\tc #161616\",\n    \"|\tc #464646\",\n    \"1\tc #4F4F4F\",\n    \"2\tc #545454\",\n    \"3\tc #3A3A3A\",\n    \"4\tc #131313\",\n    \"5\tc #121212\",\n    \"6\tc #5E5E5E\",\n    \"7\tc #0C0C0C\",\n    \"8\tc #0F0F0F\",\n    \"9\tc #0B0B0B\",\n    \"0\tc #0D0D0D\",\n    \"a\tc #1D1D1D\",\n    \"b\tc #292929\",\n    \"c\tc #3D3D3D\",\n    \"d\tc #222222\",\n    \"e\tc #171717\",\n    \"f\tc #1A1A1A\",\n    \"g\tc #282828\",\n    \"h\tc #272727\",\n    \"i\tc #5A5A5A\",\n    \"j\tc #3C3C3C\",\n    \"k\tc #595959\",\n    \"l\tc #616161\",\n    \"m\tc #505050\",\n    \"n\tc #2E2E2E\",\n    \"o\tc #565656\",\n    \"   .+@@   #$    \",\n    \"    %@&* =-$    \",\n    \"    ;>,')!~&    \",\n    \"    {]^  /@@    \",\n    \"@   ($$   _@@   \",\n    \"@   :$    /@@   \",\n    \"<][}|1     2~3['\",\n    \"445#6@     78889\",\n    \"%  '&@@    #$   \",\n    \"$   $@@   0-$   \",\n    \"    a&@+  b$$   \",\n    \"     c*[de>_    \",\n    \"@    fgh {i@@   \",\n    \"@    ^$   j@@   \",\n    \"@@  4|$   {k@@  \",\n    \"lm ,n$     ]@o^[\"};\n    '''\n\nimport FreeCAD as app\n\n\nif __name__ == '__main__':\n\t# Running as a macro. Load as module, to support save-restore.\n\ttry:\n\t\tfrom honeycomb_solid.honeycomb_solid import HoneycombSolid\n\t\tfrom honeycomb_solid.honeycomb_solid import ViewProviderHoneycombSolid\n\texcept ImportError as err:\n\t\tapp.Console.PrintError('Macro HoneycombSolid: failed to import module honeycomb_solid.honeycomb_solid\\n')\n\telse:\n\t\tfrom honeycomb_solid.honeycomb_solid import makeHoneycombSolid\n\t\tmakeHoneycombSolid(__Version__)\n\t\tif app.GuiUp:\n\t\t\timport FreeCADGui as gui\n\t\t\tgui.SendMsgToActiveView('ViewFit')\n",
    "url": "https://github.com/christiangda/FreeCAD-macros-HoneycombSolid",
    "raw_code_url": "",
    "wiki": "https://github.com/christiangda/FreeCAD-macros-HoneycombSolid/blob/main/README.md",
    "version": "v1.2.0",
    "license": "",
    "date": "",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ParametricObjectCreation\\HoneycombSolid.FCMacro",
    "filename_from_url": "",
    "author": "Christian Gonz\u00e1lez Di Antonio <christiangda@gmail.com>",
    "icon": "HoneycombSolid.xpm",
    "icon_source": null,
    "xpm": "'",
    "other_files": [
      "honeycomb_solid/__init__.py",
      "honeycomb_solid/honeycomb_solid.py"
    ],
    "parsed": true
  },
  {
    "name": "Rectellipse",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Creates a parametric approximation of a rectellipse",
    "code": "#\n# Creates a parametric Rectellipse\n# (c) fcaponi78\n#\n#\n\nfrom __future__ import division\n\n__Comment__ = 'Creates a parametric approximation of a rectellipse'\n__Web__ = 'http://freecadweb.org/wiki/Macro_Rectellipse'\n__Wiki__ = 'http://freecadweb.org/wiki/Macro_Rectellipse'\n__Icon__ = \"\"\n__Help__ = 'Run, zoom fit, and change parameters'\n__Author__ = 'fcaponi78, shoogen and other contributors'\n__Version__ = 0.1\n__Status__ = 'alpha'\n__Requires__ = ''\n\nimport FreeCAD\nfrom FreeCAD import Part\nfrom FreeCAD import Vector\n\n\nclass RectEllipseFeature:\n    def __init__(self, obj):\n        \"\"\"Add the properties: a, b, s, createFace\"\"\"\n        obj.addProperty('App::PropertyLength', 'a', 'Rectellipse',\n                        'Horizontal radius').a = 16.0\n        obj.addProperty('App::PropertyLength', 'b', 'Rectellipse',\n                        'Vertical radius').b = 9.0\n        obj.addProperty('App::PropertyFloat', 's', 'Rectellipse',\n                        'Squareness (0=ellipse, 1=rectangle)').s = 0.2\n        obj.addProperty('App::PropertyBool', 'createFace', 'Rectellipse',\n                        'true => face; false => wire').createFace = True\n        obj.Proxy = self\n\n    def onChanged(self, feature, prop):\n        if prop in ['a',  'b', 's', 'createFace']:\n            self.execute(feature)\n\n    def execute(self, feature):\n        r1 = feature.a\n        r2 = feature.b\n        if feature.s < 0:\n            feature.s = 0\n        elif feature.s > 1:\n            feature.s = 1\n        z = 0.0\n        # TODO: tweak p, so that the curve is the exact definition of a\n        # rectellipse (if possible).\n        p = 1.0\n        # NURBS knots weigts.\n        if feature.s > 0.9999999:\n            # If larger than 1e7, we obtain a rhombus.\n            w = 1e7\n        else:\n            w = 2 ** 0.5 / 2.0 / (1 - feature.s ** p)\n        # TODO: use a real rectangle if feature.s close to 1.\n        curve = Part.BSplineCurve()\n        curve.setPeriodic()\n        curve.increaseDegree(2)\n        # 5 knots, 8 poles\n        curve.insertKnots([i / 4 for i in (1, 2, 3)], [2] * 3)\n        curve.setPole(1, Vector(0, -r2, z), 1)\n        curve.setPole(2, Vector(-r1, -r2, z), w)\n        curve.setPole(3, Vector(-r1, 0, z), 1)\n        curve.setPole(4, Vector(-r1, r2, z), w)\n        curve.setPole(5, Vector(0, r2, z), 1)\n        curve.setPole(6, Vector(r1, r2, z), w)\n        curve.setPole(7, Vector(r1, 0, z), 1)\n        curve.setPole(8, Vector(r1, -r2, z), w)\n        if feature.createFace:\n            feature.Shape = Part.Face(Part.Wire(curve.toShape()))\n        else:\n            feature.Shape = curve.toShape()\n\n\ndef makeRectellipseFeature():\n    doc = FreeCAD.activeDocument()\n    if doc is None:\n        doc = FreeCAD.newDocument()\n        if doc is None:\n            return\n    obj = doc.addObject('Part::FeaturePython', 'RectEllipseFeature')\n    obj.Label = 'RectEllipse'\n    RectEllipseFeature(obj)\n    obj.ViewObject.Proxy = 0\n\nif __name__ == \"__main__\":\n    makeRectellipseFeature()\n",
    "url": "http://freecadweb.org/wiki/Macro_Rectellipse",
    "raw_code_url": "",
    "wiki": "http://freecadweb.org/wiki/Macro_Rectellipse",
    "version": "0.1",
    "license": "",
    "date": "",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\ParametricObjectCreation\\Rectellipse.FCMacro",
    "filename_from_url": "",
    "author": "fcaponi78, shoogen and other contributors",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Camera",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Mario52",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2015 2016 2017 2018  <mario52>                          *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *\n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n# This macro can rotate the screen in a defined angle and a defined axis and\n# creates a plan to face the screen to create a form in the specified plan\n# positions the selected face facing the screen, to detect the position of the\n# camera, align view to face or to axis, align the object to view.\n\n__Name__ = 'Camera'\n__Comment__ = 'Mario52'\n__Author__ = ''\n# Version 0.0.11 corresponds to Mario52's version 00.11.\n__Version__ = '0.0.14'\n__Date__ = '2022-02-23'\n__License__ = ''\n__Web__ = ''\n__Wiki__ = 'http://www.freecadweb.org/wiki/index.php?title=Macro_FCCamera'\n__Icon__ = 'Camera.png'\n__Help__ = ''\n__Status__ = ''\n__Requires__ = ''\n__Communication__ = ''\n__Files__ = 'Camera.png,Camera/accept.png,Camera/align_object_to_view.png,Camera/align_to_axis.png,Camera/align_to_face.png,Camera/axis_rotation_d.png,Camera/axis_rotation_x.png,Camera/axis_rotation_y.png,Camera/axis_rotation_z.png,Camera/create_plane_of_view.png,Camera/detect_orientation.png,Camera/quit.png,Camera/reset.png,Camera/save_view.png'\n\nimport math\nimport os\nimport time\nfrom math import radians, degrees, sqrt, pi, sin, cos, asin\nfrom decimal import *\n\nimport FreeCAD as App\nimport Draft, Part, PartGui, FreeCADGui, DraftVecUtils\n\nimport PySide                    #  FreeCAD's PySide!\nfrom PySide import QtCore, QtGui\nfrom FreeCAD import Base\nfrom FreeCAD import Vector\nimport pivy\nfrom pivy import coin\n\npathFile  = \"\"\nvaleur    = 0.0\nvaleurV   = 0.0\nRname     = [\"\",\"\",\"\"]\nRnameCube = \"\"\nRnameCompound = \"\"\ndatExtract = \"\"\n\npositionX = 0.0\npositionY = 0.0\npositionZ = 0.0\nvertexeS  = Vector(0.0,0.0,0.0)\nbounBoxCenter = Vector(0.0,0.0,0.0)\n\ndim_Horizont = 0\ndim_Vertical = 0\nori_Vertical = 0\nori_Horizont = 0\nnumberPhoto  = 0.0\nvalueTest    = 0.0\n\nformatFichier= \".png\"\ns = \"\"\n\nNameelement2 = \"\"  # new selection\nvueView      = 0   # passe vue\n\n\ndef icon_path(filename):\n    \"\"\"Full path of a file given relative to the macro specific folder\n\n    For example, icon_path('save_view.png') will return\n    $HOME/.FreeCAD/Macro/Camera/save_view.png where $HOME/.FreeCAD/Macro is the\n    path where your macros are saved.\n    \"\"\"\n    macro_dir = App.getUserMacroDir(True)\n    icon_dir = os.path.join(macro_dir, __Name__)\n    return os.path.join(icon_dir, filename)\n\ndoc = App.ActiveDocument\nif doc == None:\n    doc = App.newDocument()\n\nactiveView = FreeCADGui.activeDocument().activeView()\nmainWindow = FreeCADGui.getMainWindow()\nmdi = mainWindow.findChild(QtGui.QMdiArea)\nmwActive = mdi.activeSubWindow()\n\ndim_Horizont = ori_Horizont = mwActive.width()\ndim_Vertical = ori_Vertical = mwActive.height()\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\nclass SelObserver:                                               # SelObserver\n    def addSelection(self,document, object, element, position):  # Selection SelObserver\n        global positionX\n        global positionY\n        global positionZ\n        global vertexeS\n        global bounBoxCenter\n\n        positionX = position[0]\n        positionY = position[1]\n        positionZ = position[2]\n\n        bounBoxCenter = Vector(0.0,0.0,0.0)\n\n        if (element[:4] == \"Edge\"):\n            vertex = App.ActiveDocument.getObject(object).Shape.Edges[int(element[4:])-1].Vertexes\n            bounBoxCenter = App.ActiveDocument.getObject(object).Shape.Edges[int(element[4:])-1].BoundBox.Center\n            try:\n                vertexeS = vertex[1].Point.sub(vertex[0].Point)\n            except Exception:\n                vertexeS = Vector(0.0,0.0,0.0)\n        else:\n            vertexeS = Vector(0.0,0.0,0.0)\n            try:\n                bounBoxCenter = App.ActiveDocument.getObject(object).Shape.Edges[int(element[4:])-1].BoundBox.Center\n            except Exception:\n                bounBoxCenter = App.Vector(positionX, positionY, positionZ)\n\ndef datExtract(data):\n# return a string\n    data = str(data)\n    a    = \"\"\n    for i in data:\n        if i in (\"0123456789e.- \"):\n            a+=i\n    a = a.strip(\" \")\n    a = a.split(\" \")\n    return a\n\ndef centerBoundBoxGlobal():\n\n    doc = App.activeDocument()\n    objs0  = doc.findObjects()\n    midpoint = []\n\n    if len(objs0) != 0:\n        xMin = yMin = zMin = 0.0\n        xMax = yMax = zMax = 0.0\n        for objs in objs0:\n            try:\n                if objs.ViewObject.Visibility:\n                    if hasattr(objs, \"Shape\"):\n                        s = objs.Shape\n                    elif hasattr(objs, \"Mesh\"):      # upgrade with wmayer thanks #http://forum.freecadweb.org/viewtopic.php?f=13&t=22331\n                        s = objs.Mesh\n                    elif hasattr(objs, \"Points\"):\n                        s = objs.Points\n\n                    boundBox_ = s.BoundBox\n                    extractValue = datExtract(boundBox_)\n\n                    if float(extractValue[0]) < xMin:\n                        xMin = float(extractValue[0])\n                    if float(extractValue[1]) < yMin:\n                        yMin = float(extractValue[1])\n                    if float(extractValue[2]) < zMin:\n                        zMin = float(extractValue[2])\n\n                    if float(extractValue[3]) > xMax:\n                        xMax = float(extractValue[3])\n                    if float(extractValue[4]) > yMax:\n                        yMax = float(extractValue[4])\n                    if float(extractValue[5]) > zMax:\n                        zMax = float(extractValue[5])\n            except Exception:\n                None\n        #### diagonal at midpoint\n        points = [App.Vector(xMin, yMin, zMin), App.Vector(xMax, yMax, zMax)]      #diagonal\n        diagonal = Draft.makeWire(points, closed=False, face=False, support=None)  #create diagonal line\n        try:\n            midpoint = diagonal.Shape.copy().discretize(3)                         #cut line for search center\n        except Exception:\n            None\n        doc.removeObject(diagonal.Name)\n        #Draft.makePoint(midpoint[1])\n        try:\n            return midpoint[1]\n        except Exception:\n            return App.Vector(0.0,0.0,0.0)\n    else:\n        return App.Vector(0.0,0.0,0.0)\n\n# Align Face selected to Face or to Axis\ndef To_Face_Or_To_Axis(ToFace):         # 1=NormalAt 0=Axis\n    global vueView\n    global Nameelement2\n    global vertexeS\n\n    try:\n        SubElement = FreeCADGui.Selection.getSelectionEx()\n        Nameelement = SubElement[0].SubElementNames[0]\n        if Nameelement != Nameelement2:\n            vueView = 0\n        Nameelement2 = Nameelement\n\n        if ToFace == 1:\n            v = Gui.Selection.getSelectionEx()[0].SubObjects[0].normalAt(0,0)    # NormalAt\n            App.Console.PrintMessage(\"NormalAt     : \")\n        else:\n            try:\n                v=Gui.Selection.getSelectionEx()[0].SubObjects[0].Surface.Axis   # Axis\n                App.Console.PrintMessage(\"Surface Axis : \")\n            except Exception:\n                v=vertexeS                                                       # Axis Edges\n                App.Console.PrintMessage(\"Axis Edges   : \")\n\n        if vueView == 0:\n            r=App.Rotation(App.Vector(0,0,1),v)\n            App.Console.PrintMessage(\"0,0,1\"+\"\\n\")\n        elif vueView == 1:\n            r=App.Rotation(App.Vector(0,0,-1),v)\n            App.Console.PrintMessage(\"0,0,-1\"+\"\\n\")\n        elif vueView == 2:\n            r=App.Rotation(App.Vector(0,1,0),v)\n            App.Console.PrintMessage(\"0,1,0\"+\"\\n\")\n        elif vueView == 3:\n            r=App.Rotation(App.Vector(0,-1,0),v)\n            App.Console.PrintMessage(\"0,-1,0\"+\"\\n\")\n        elif vueView == 4:\n            r=App.Rotation(App.Vector(1,0,0),v)\n            App.Console.PrintMessage(\"1,0,0\"+\"\\n\")\n        elif vueView == 5:\n            r=App.Rotation(App.Vector(-1,0,0),v)\n            App.Console.PrintMessage(\"-1,0,0\"+\"\\n\")\n            vueView = -1\n\n        Gui.ActiveDocument.ActiveView.setCameraOrientation(r.Q)#\n        vueView += 1\n    except:\n        App.Console.PrintError(\"Select a face\"+\"\\n\")\n\nclass Ui_MainWindow(object):\n    def setupUi(self, MainWindow):\n        global pathFile\n        global valeur\n        global ori_Horizont\n        global ori_Vertical\n        global numberPhoto\n\n        self.window = MainWindow\n\n        MainWindow.setObjectName(_fromUtf8(\"MainWindow\"))\n        MainWindow.resize(209, 500)\n        MainWindow.setMaximumSize(QtCore.QSize(209, 500))\n        self.centralWidget = QtGui.QWidget(MainWindow)\n        self.centralWidget.setObjectName(_fromUtf8(\"centralWidget\"))\n\n        #################################################################################\n        self.FontImpost    = \"Arial\"\n        self.fontGlobal_08 = QtGui.QFont()            # for Windows Linux compatibility\n        self.fontGlobal_08.setFamily(self.FontImpost) # for Windows Linux compatibility\n        self.fontGlobal_08.setPointSize(8)            # for Windows Linux compatibility\n        #self.xxxx.setFont(self.fontGlobal_08)        # for Windows Linux compatibility\n        #self.xxxx.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))  # Bold\n        #################################################################################\n\n        ### ---graphicsView---\n        self.graphicsView = QtGui.QGraphicsView(self.centralWidget)\n        self.graphicsView.setGeometry(QtCore.QRect(20, 10, 171, 101))\n        self.graphicsView.setFrameShape(QtGui.QFrame.StyledPanel)\n        self.graphicsView.setObjectName(_fromUtf8(\"graphicsView\"))\n        pic = QtGui.QPixmap(icon_path('axis_rotation_x.png'))\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(ui.scene)\n        ### ---graphicsView---\n\n        self.groupBox_01 = QtGui.QGroupBox(self.centralWidget)\n        self.groupBox_01.setGeometry(QtCore.QRect(10, 120, 191, 151))\n        self.groupBox_01.setFont(self.fontGlobal_08)        # for Windows Linux compatibility\n        self.groupBox_01.setObjectName(_fromUtf8(\"groupBox_01\"))\n\n        self.label_02 = QtGui.QLabel(self.groupBox_01)\n        self.label_02.setGeometry(QtCore.QRect(10, 20, 181, 16))\n        self.label_02.setFont(self.fontGlobal_08)           # for Windows Linux compatibility\n        self.label_02.setObjectName(_fromUtf8(\"label_02\"))\n\n        self.RB_Angle_X = QtGui.QRadioButton(self.groupBox_01)\n        self.RB_Angle_X.setGeometry(QtCore.QRect(10, 90, 31, 20))\n        self.RB_Angle_X.setFont(self.fontGlobal_08)         # for Windows Linux compatibility\n        self.RB_Angle_X.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))   # Bold\n        self.RB_Angle_X.setStyleSheet(\"color : #ff0000\")                                # Color text\n        self.RB_Angle_X.setMouseTracking(True)\n        self.RB_Angle_X.setChecked(True)\n        self.RB_Angle_X.setObjectName(_fromUtf8(\"RB_Angle_X\"))\n        self.RB_Angle_X.setToolTip(u\"Rotation of the camera on the X axis\")\n        self.RB_Angle_X.clicked.connect(self.on_RB_Angle_X_clicked)\n\n        self.label_03 = QtGui.QLabel(self.groupBox_01)\n        self.label_03.setGeometry(QtCore.QRect(10, 70, 161, 16))\n        self.label_03.setFont(self.fontGlobal_08)           # for Windows Linux compatibility\n        self.label_03.setObjectName(_fromUtf8(\"label_03\"))\n\n        self.RB_Angle_Y = QtGui.QRadioButton(self.groupBox_01)\n        self.RB_Angle_Y.setGeometry(QtCore.QRect(65, 90, 31, 20))\n        self.RB_Angle_Y.setFont(self.fontGlobal_08)         # for Windows Linux compatibility\n        self.RB_Angle_Y.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))  # Bold\n        self.RB_Angle_Y.setStyleSheet(\"color : #008700\")                         # Color text\n        self.RB_Angle_Y.setObjectName(_fromUtf8(\"RB_Angle_Y\"))\n        self.RB_Angle_Y.setToolTip(u\"Rotation of the camera on the Y axis\")\n        self.RB_Angle_Y.clicked.connect(self.on_RB_Angle_Y_clicked)\n\n        self.RB_Angle_Z = QtGui.QRadioButton(self.groupBox_01)\n        self.RB_Angle_Z.setGeometry(QtCore.QRect(115, 90, 31, 20))\n        self.RB_Angle_Z.setFont(self.fontGlobal_08)         # for Windows Linux compatibility\n        self.RB_Angle_Z.setStyleSheet(\"color : #0000ff\")                         # Color text\n        self.RB_Angle_Z.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))  # Bold\n        self.RB_Angle_Z.setObjectName(_fromUtf8(\"RB_Angle_Z\"))\n        self.RB_Angle_Z.setToolTip(u\"Rotation of the camera on the Z axis\")\n        self.RB_Angle_Z.clicked.connect(self.on_RB_Angle_Z_clicked)\n\n        self.RB_Direction = QtGui.QRadioButton(self.groupBox_01)\n        self.RB_Direction.setGeometry(QtCore.QRect(160, 90, 31, 20))\n        self.RB_Direction.setFont(self.fontGlobal_08)       # for Windows Linux compatibility\n        self.RB_Direction.setStyleSheet(\"color : #000066\")                         # Color text\n        self.RB_Direction.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))  # Bold\n        self.RB_Direction.setObjectName(_fromUtf8(\"RB_Direction\"))\n        self.RB_Direction.setToolTip(u\"Rotation of the camera on the Direction axis\" + \"\\n\"\n                                     u\"to edge selected or point selected\" + \"\\n\"\n                                     u\"If the point are selected the mouse coordinates are used.\")\n        self.RB_Direction.clicked.connect(self.on_RB_Direction_clicked)\n\n        self.DS_Angle = QtGui.QDoubleSpinBox(self.groupBox_01)\n        self.DS_Angle.setGeometry(QtCore.QRect(8, 40, 171, 22))\n        self.DS_Angle.setFont(self.fontGlobal_08)           # for Windows Linux compatibility\n        self.DS_Angle.setAlignment(QtCore.Qt.AlignCenter)\n        self.DS_Angle.setDecimals(10)\n        self.DS_Angle.setMinimum(-359.0)\n        self.DS_Angle.setMaximum(359.0)\n        self.DS_Angle.setSingleStep(1.0)\n        self.DS_Angle.setObjectName(_fromUtf8(\"DS_Angle\"))\n        self.DS_Angle.setToolTip(u\"Enter the angle of rotation in degrees.\\n\"\n\" The given angle is added to the angle of the current view\")\n        self.DS_Angle.valueChanged.connect(self.on_DS_Angle_valueChanged) #connection DS_Angle\n\n        self.PB_Accept_View = QtGui.QPushButton(self.groupBox_01)\n        self.PB_Accept_View.setGeometry(QtCore.QRect(10, 110, 171, 28))\n        self.PB_Accept_View.setFont(self.fontGlobal_08)     # for Windows Linux compatibility\n        icon1 = QtGui.QIcon()\n        icon1.addPixmap(QtGui.QPixmap(icon_path('accept.png')),\n                        QtGui.QIcon.Normal,\n                        QtGui.QIcon.Off)\n        self.PB_Accept_View.setIcon(icon1)\n        self.PB_Accept_View.setToolTip(u\"Accept the view given\")\n        self.PB_Accept_View.setObjectName(_fromUtf8(\"PB_Accept_View\"))\n        self.PB_Accept_View.clicked.connect(self.on_PB_Accept_View_clicked)\n\n        self.groupBox_02 = QtGui.QGroupBox(self.centralWidget)\n        self.groupBox_02.setGeometry(QtCore.QRect(10, 280, 191, 181))\n        #self.groupBox_02.setVisible(False)\n        self.groupBox_02.setFont(self.fontGlobal_08)        # for Windows Linux compatibility\n        self.groupBox_02.setObjectName(_fromUtf8(\"groupBox_02\"))\n\n        self.PB_Detect_Camera = QtGui.QPushButton(self.groupBox_02)\n        self.PB_Detect_Camera.setGeometry(QtCore.QRect(10, 20, 171, 28))\n        self.PB_Detect_Camera.setFont(self.fontGlobal_08)   # for Windows Linux compatibility\n        icon2 = QtGui.QIcon()\n        icon2.addPixmap(QtGui.QPixmap(icon_path('detect_orientation.png')),\n                        QtGui.QIcon.Normal,\n                        QtGui.QIcon.Off)\n        self.PB_Detect_Camera.setIcon(icon2)\n        self.PB_Detect_Camera.setObjectName(_fromUtf8(\"PB_Detect_Camera\"))\n        self.PB_Detect_Camera.setToolTip(u\"Detect the position of the camera\\n\"\n\" The returned value is the value provided by the function getCameraOrientation()\")\n        self.PB_Detect_Camera.clicked.connect(self.on_PB_Detect_Camera_clicked)\n\n        self.PB_To_Face = QtGui.QPushButton(self.groupBox_02)\n        self.PB_To_Face.setGeometry(QtCore.QRect(10, 70, 81, 28))\n        self.PB_To_Face.setFont(self.fontGlobal_08)         # for Windows Linux compatibility\n        icon3 = QtGui.QIcon()\n        icon3.addPixmap(QtGui.QPixmap(icon_path('align_to_face.png')),\n                        QtGui.QIcon.Normal,\n                        QtGui.QIcon.Off)\n        self.PB_To_Face.setIcon(icon3)\n        self.PB_To_Face.setObjectName(_fromUtf8(\"PB_To_Face\"))\n        self.PB_To_Face.setToolTip(\"Align the view to the selected face \\n\"\n\"Click and repeat the click for NormalAt: \\n\"\n\"(0,0,1) (0,0,-1) (0,1,0) (0,-1,0) (1,0,0) (-1,0,0)\")\n        self.PB_To_Face.clicked.connect(self.on_PB_To_Face_clicked) # align view to face Face\n\n        self.label_04 = QtGui.QLabel(self.groupBox_02)\n        self.label_04.setGeometry(QtCore.QRect(10, 50, 161, 20))\n        self.label_04.setFont(self.fontGlobal_08)           # for Windows Linux compatibility\n        self.label_04.setObjectName(_fromUtf8(\"label_04\"))\n\n        self.PB_To_Axis = QtGui.QPushButton(self.groupBox_02)\n        self.PB_To_Axis.setGeometry(QtCore.QRect(100, 70, 81, 28))\n        self.PB_To_Axis.setFont(self.fontGlobal_08)         # for Windows Linux compatibility\n        icon4 = QtGui.QIcon()\n        icon4.addPixmap(QtGui.QPixmap(icon_path('align_to_axis.png')),\n                        QtGui.QIcon.Normal,\n                        QtGui.QIcon.Off)\n        self.PB_To_Axis.setIcon(icon4)\n        self.PB_To_Axis.setObjectName(_fromUtf8(\"PB_To_Axis\"))\n        self.PB_To_Axis.setToolTip(\"Align the view to Axis face selected \\n\"\n\"Click and repeat the click for Surface Axis:\\n\"\n\"(0,0,1) (0,0,-1) (0,1,0) (0,-1,0) (1,0,0) (-1,0,0)\")\n        self.PB_To_Axis.clicked.connect(self.on_PB_To_Axis_clicked) # Align view to face Axis\n\n        self.PB_Align_O_To_View = QtGui.QPushButton(self.groupBox_02)\n        self.PB_Align_O_To_View.setGeometry(QtCore.QRect(10, 105, 171, 28))\n        self.PB_Align_O_To_View.setFont(self.fontGlobal_08) # for Windows Linux compatibility\n        icon5 = QtGui.QIcon()\n        icon5.addPixmap(QtGui.QPixmap(icon_path('align_object_to_view.png')),\n                        QtGui.QIcon.Normal,\n                        QtGui.QIcon.Off)\n        self.PB_Align_O_To_View.setIcon(icon5)\n        self.PB_Align_O_To_View.setObjectName(_fromUtf8(\"PB_Align_O_To_View\"))\n        self.PB_Align_O_To_View.setToolTip(\"Align the object selected to the actual view \\n\"\n\"The changed values are: Rotation Axis((X, Y, Z), Angle) \\n\"\n\"Same Euler angles: Yaw, Pitch, Roll \\n\"\n\"The Translation isn't modified\")\n        self.PB_Align_O_To_View.clicked.connect(self.on_PB_Align_O_To_View_clicked) # Align object to view\n\n        self.PB_Create_Plane = QtGui.QPushButton(self.groupBox_02)\n        self.PB_Create_Plane.setGeometry(QtCore.QRect(10, 140, 171, 28))\n        self.PB_Create_Plane.setFont(self.fontGlobal_08)    # for Windows Linux compatibility\n        icon6 = QtGui.QIcon()\n        icon6.addPixmap(QtGui.QPixmap(icon_path('create_plane_of_view.png')), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.PB_Create_Plane.setIcon(icon6)\n        self.PB_Create_Plane.setObjectName(_fromUtf8(\"PB_Create_Plane\"))\n        self.PB_Create_Plane.setToolTip(\"A circular plane is created facing the screen to mouse click coordinates on an object \\n\"\n\"The radius of the plane is equal to the maximum dimension of BoundBox  \\n\"\n\"If no object is selected, the plane is created to 0, 0, 0 coordinates with a radius of 20 mm\")\n        self.PB_Create_Plane.clicked.connect(self.on_PB_Create_Plane_clicked) # create plane\n\n        #####\n        self.groupBox_03 = QtGui.QGroupBox(self.centralWidget)\n        self.groupBox_03.setGeometry(QtCore.QRect(10, 280, 191, 212))\n        self.groupBox_03.setVisible(False)\n        self.groupBox_03.setFont(self.fontGlobal_08)        # for Windows Linux compatibility\n        self.groupBox_03.setObjectName(_fromUtf8(\"groupBox_02\"))\n\n        self.comboBox_01 = QtGui.QComboBox(self.groupBox_03)\n        self.comboBox_01.setGeometry(QtCore.QRect(10, 20, 171, 22))\n        self.comboBox_01.setFont(self.fontGlobal_08)        # for Windows Linux compatibility\n#        self.comboBox_01.setCurrentIndex(0)\n        self.comboBox_01.setObjectName(_fromUtf8(\"comboBox_01\"))\n        self.comboBox_01.addItem(_fromUtf8(\"Actual\"))\n        self.comboBox_01.addItem(_fromUtf8(\"Icon 16 x 16\"))\n        self.comboBox_01.addItem(_fromUtf8(\"Icon 32 x 32\"))\n        self.comboBox_01.addItem(_fromUtf8(\"Icon 64 x 64\"))\n        self.comboBox_01.addItem(_fromUtf8(\"Icon 128 x 128\"))\n        self.comboBox_01.addItem(_fromUtf8(\"CGA 320 x 200\"))\n        self.comboBox_01.addItem(_fromUtf8(\"QVGA 320 x 240\"))\n        self.comboBox_01.addItem(_fromUtf8(\"VGA 640 x 480\"))\n        self.comboBox_01.addItem(_fromUtf8(\"SVGA 800 x 600\"))\n        self.comboBox_01.addItem(_fromUtf8(\"XGA 1024 x 768\"))\n        self.comboBox_01.addItem(_fromUtf8(\"XGA+ 1152 x 864\"))\n        self.comboBox_01.addItem(_fromUtf8(\"SXGA 1280 x 1024\"))\n        self.comboBox_01.addItem(_fromUtf8(\"SXGA+ 1400 x 1050\"))\n        self.comboBox_01.addItem(_fromUtf8(\"UXGA 1600 x 1200\"))\n        self.comboBox_01.addItem(_fromUtf8(\"QXGA 2048 x 1536\"))\n        self.comboBox_01.addItem(_fromUtf8(\"Free\"))\n        QtCore.QObject.connect(self.comboBox_01, QtCore.SIGNAL(\"currentIndexChanged(QString)\"),\n                               self.SIGNAL_comboBox_01_Changed)\n\n        self.DS_01_X = QtGui.QSpinBox(self.groupBox_03)\n        self.DS_01_X.setGeometry(QtCore.QRect(10, 50, 61, 22))\n        self.DS_01_X.setFont(self.fontGlobal_08)            # for Windows Linux compatibility\n        self.DS_01_X.setMinimum(1)\n        self.DS_01_X.setMaximum(ori_Horizont)\n        self.DS_01_X.setSingleStep(1)\n        self.DS_01_X.setValue(ori_Horizont)\n        self.DS_01_X.setObjectName(_fromUtf8(\"DS_01_X\"))\n        self.DS_01_X.setToolTip(u\"Value X\")\n        self.DS_01_X.valueChanged.connect(self.on_DS_01_X_valueChanged) #connection doubleSpinBox\n\n        self.label_05 = QtGui.QLabel(self.groupBox_03)\n        self.label_05.setGeometry(QtCore.QRect(80, 55, 11, 16))\n        self.label_05.setFont(self.fontGlobal_08)           # for Windows Linux compatibility\n        self.label_05.setObjectName(_fromUtf8(\"label_05\"))\n        self.label_05.setStyleSheet(\"color : #ff0000\")                         # text color\n        self.label_05.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))  # Bold\n\n        self.DS_02_Y = QtGui.QSpinBox(self.groupBox_03)\n        self.DS_02_Y.setGeometry(QtCore.QRect(105, 50, 61, 22))\n        self.DS_02_Y.setFont(self.fontGlobal_08)            # for Windows Linux compatibility\n        self.DS_02_Y.setMinimum(1)\n        self.DS_02_Y.setMaximum(ori_Vertical)\n        self.DS_02_Y.setSingleStep(1)\n        self.DS_02_Y.setValue(ori_Vertical)\n        self.DS_02_Y.setObjectName(_fromUtf8(\"DS_02_Y\"))\n        self.DS_02_Y.setToolTip(u\"Value Y\")\n        self.DS_02_Y.valueChanged.connect(self.on_DS_02_Y_valueChanged) #connection doubleSpinBox\n\n        self.label_06 = QtGui.QLabel(self.groupBox_03)\n        self.label_06.setGeometry(QtCore.QRect(175, 55, 11, 16))\n        self.label_06.setFont(self.fontGlobal_08)           # for Windows Linux compatibility\n        self.label_06.setObjectName(_fromUtf8(\"label_06\"))\n        self.label_06.setStyleSheet(\"color : #008700\")                         # text color\n        self.label_06.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))  # Bold\n\n        self.comboBox_02 = QtGui.QComboBox(self.groupBox_03)\n        self.comboBox_02.setGeometry(QtCore.QRect(10, 80, 171, 22))\n        self.comboBox_02.setFont(self.fontGlobal_08)        # for Windows Linux compatibility\n        self.comboBox_02.setObjectName(_fromUtf8(\"comboBox_02\"))\n        self.comboBox_02.addItem(_fromUtf8(\"BMP *.bmp\"))\n        self.comboBox_02.addItem(_fromUtf8(\"ICO *.ico\"))\n        self.comboBox_02.addItem(_fromUtf8(\"JPEG *.jpeg\"))\n        self.comboBox_02.addItem(_fromUtf8(\"JPG *.jpg\"))\n        self.comboBox_02.addItem(_fromUtf8(\"PNG *.png\"))\n        self.comboBox_02.addItem(_fromUtf8(\"PPM *.ppm\"))\n        self.comboBox_02.addItem(_fromUtf8(\"TIF *.tif\"))\n        self.comboBox_02.addItem(_fromUtf8(\"TIFF *.tiff\"))\n        self.comboBox_02.addItem(_fromUtf8(\"XBM *.xbm\"))\n        self.comboBox_02.addItem(_fromUtf8(\"XPM *.xpm\"))\n        #self.comboBox_02.addItem(_fromUtf8(\"GIF *.gif\"))\n        QtCore.QObject.connect(self.comboBox_02,\n                               QtCore.SIGNAL(\"currentIndexChanged(QString)\"),\n                               self.SIGNAL_comboBox_02_Changed)\n\n        self.label_07 = QtGui.QLabel(self.groupBox_03)\n        self.label_07.setGeometry(QtCore.QRect(10, 105, 136, 16))\n        self.label_07.setFont(self.fontGlobal_08)           # for Windows Linux compatibility\n        self.label_07.setObjectName(_fromUtf8(\"label_07\"))\n\n        self.PB_Photo_Adjust = QtGui.QPushButton(self.groupBox_03)\n        self.PB_Photo_Adjust.setGeometry(QtCore.QRect(150, 105, 31, 16))\n        self.PB_Photo_Adjust.setFont(self.fontGlobal_08)    # for Windows Linux compatibility\n        self.PB_Photo_Adjust.setVisible(False)\n        self.PB_Photo_Adjust.setToolTip(u\"Adjust the number image to 360 degrees\")\n        self.PB_Photo_Adjust.setObjectName(_fromUtf8(\"PB_Photo_Adjust\"))\n        self.PB_Photo_Adjust.clicked.connect(self.on_PB_Photo_Adjust_clicked)\n\n        self.label_08 = QtGui.QLabel(self.groupBox_03)\n        self.label_08.setGeometry(QtCore.QRect(10, 120, 171, 16))\n        self.label_08.setFont(self.fontGlobal_08)           # for Windows Linux compatibility\n        self.label_08.setObjectName(_fromUtf8(\"label_08\"))\n\n        self.groupBox_03_B = QtGui.QGroupBox(self.groupBox_03)\n        self.groupBox_03_B.setGeometry(QtCore.QRect(5, 139, 180, 36))\n        self.groupBox_03_B.setFont(self.fontGlobal_08)      # for Windows Linux compatibility\n        self.groupBox_03_B.setObjectName(_fromUtf8(\"groupBox_03_B\"))\n        self.groupBox_03_B.setToolTip(u\"Choose property background image\" + \"\\n\"\n                                      u\"It's possible that the background doesn't appear in the desired color.\" + \"\\n\"\n                                      u\"In this case do a test in FreeCAD :\" + \"\\n\"\n                                      u\"Menu > Tools > Save picture > Extended > Image properties\")\n\n        self.RB_01_Actual = QtGui.QRadioButton(self.groupBox_03_B)\n        self.RB_01_Actual.setGeometry(QtCore.QRect(10, 15, 36, 17))\n        self.RB_01_Actual.setFont(self.fontGlobal_08)       # for Windows Linux compatibility\n        self.RB_01_Actual.setChecked(True)\n        self.RB_01_Actual.setObjectName(_fromUtf8(\"RB_01_Actual\"))\n        self.RB_01_Actual.setToolTip(u\"BackGround image in Actual color\")\n\n        self.RB_02_White = QtGui.QRadioButton(self.groupBox_03_B)\n        self.RB_02_White.setGeometry(QtCore.QRect(55, 15, 36, 17))\n        self.RB_02_White.setFont(self.fontGlobal_08)        # for Windows Linux compatibility\n        self.RB_02_White.setObjectName(_fromUtf8(\"RB_02_White\"))\n        self.RB_02_White.setToolTip(u\"BackGround image in White\")\n\n        self.RB_03_Black = QtGui.QRadioButton(self.groupBox_03_B)\n        self.RB_03_Black.setGeometry(QtCore.QRect(100, 15, 36, 17))\n        self.RB_03_Black.setFont(self.fontGlobal_08)        # for Windows Linux compatibility\n        self.RB_03_Black.setObjectName(_fromUtf8(\"RB_03_Black\"))\n        self.RB_03_Black.setToolTip(u\"BackGround image in Black\")\n\n        self.RB_04_Transparent = QtGui.QRadioButton(self.groupBox_03_B)\n        self.RB_04_Transparent.setGeometry(QtCore.QRect(145, 15, 36, 17))\n        self.RB_04_Transparent.setFont(self.fontGlobal_08)  # for Windows Linux compatibility\n        self.RB_04_Transparent.setObjectName(_fromUtf8(\"RB_04_Transparent\"))\n        self.RB_04_Transparent.setToolTip(u\"BackGround image in Transparent\")\n\n        self.PB_Photo_Launch = QtGui.QPushButton(self.groupBox_03)\n        self.PB_Photo_Launch.setGeometry(QtCore.QRect(10, 180, 52, 23))\n        self.PB_Photo_Launch.setFont(self.fontGlobal_08)    # for Windows Linux compatibility\n        self.PB_Photo_Launch.setIcon(QtGui.QIcon(icon_path('save_view.png')))\n        self.PB_Photo_Launch.setToolTip(u\"Launch the creation files\")\n        self.PB_Photo_Launch.setObjectName(_fromUtf8(\"PB_Photo_Launch\"))\n        self.PB_Photo_Launch.clicked.connect(self.on_PB_Photo_Launch_clicked)\n\n        self.PB_Photo_Reset = QtGui.QPushButton(self.groupBox_03)\n        self.PB_Photo_Reset.setGeometry(QtCore.QRect(71, 180, 52, 23))\n        self.PB_Photo_Reset.setFont(self.fontGlobal_08)     # for Windows Linux compatibility\n        self.PB_Photo_Reset.setIcon(QtGui.QIcon(icon_path('reset.png')))\n        self.PB_Photo_Reset.setToolTip(u\"Refresh all\")\n        self.PB_Photo_Reset.setObjectName(_fromUtf8(\"PB_Photo_Reset\"))\n        self.PB_Photo_Reset.clicked.connect(self.on_PB_Photo_Reset_clicked)\n\n        self.PB_Photo_Quit = QtGui.QPushButton(self.groupBox_03)\n        self.PB_Photo_Quit.setGeometry(QtCore.QRect(130, 180, 52, 23))\n        self.PB_Photo_Quit.setFont(self.fontGlobal_08)      # for Windows Linux compatibility\n        self.PB_Photo_Quit.setIcon(QtGui.QIcon(icon_path('save_view.png')))\n        self.PB_Photo_Quit.setToolTip(u\"Quit the photo panel\")\n        self.PB_Photo_Quit.setObjectName(_fromUtf8(\"PB_Photo_Launch\"))\n        self.PB_Photo_Quit.clicked.connect(self.on_PB_Photo_Quit_clicked)\n        #####\n\n        self.PB_Reset = QtGui.QPushButton(self.centralWidget)\n        self.PB_Reset.setGeometry(QtCore.QRect(10, 465, 60, 28))\n        self.PB_Reset.setFont(self.fontGlobal_08)           # for Windows Linux compatibility\n        icon7 = QtGui.QIcon()\n        icon7.addPixmap(QtGui.QPixmap(icon_path('reset.png')),\n                        QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.PB_Reset.setIcon(icon7)\n        self.PB_Reset.setObjectName(_fromUtf8(\"PB_Reset\"))\n        self.PB_Reset.setToolTip(\"Refresh all\")\n        self.PB_Reset.clicked.connect(self.on_PB_Reset_clicked) # refresh\n\n        self.PB_Photo = QtGui.QPushButton(self.centralWidget)\n        self.PB_Photo.setGeometry(QtCore.QRect(76, 465, 60, 28))\n        self.PB_Photo.setFont(self.fontGlobal_08)           # for Windows Linux compatibility\n        icon1 = QtGui.QIcon()\n        icon1.addPixmap(QtGui.QPixmap(icon_path('save_view.png')),\n                        QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.PB_Photo.setIcon(icon1)\n        self.PB_Photo.setToolTip(u\"Create serial photo to create animation\" + \"\\n\"\n                                 u\"Specify the angle rotation desired\" + \"\\n\"\n                                 u\"Number image = 360 / Angle degrees rotation\" + \"\\n\" + \"\\n\"\n                                 u\"Modify your 3DView windows to the desired dimension\" + \"\\n\"\n                                 u\"Click to accept the rotation for verifying if the object rotation is good\")\n        self.PB_Photo.setObjectName(_fromUtf8(\"PB_Photo\"))\n        self.PB_Photo.clicked.connect(self.on_PB_Photo_clicked)\n\n        self.PB_Quit = QtGui.QPushButton(self.centralWidget)\n        self.PB_Quit.setGeometry(QtCore.QRect(142, 465, 60, 28))\n        self.PB_Quit.setFont(self.fontGlobal_08)            # for Windows Linux compatibility\n        icon8 = QtGui.QIcon()\n        icon8.addPixmap(QtGui.QPixmap(icon_path('quit.png')),\n                        QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.PB_Quit.setIcon(icon8)\n        self.PB_Quit.setObjectName(_fromUtf8(\"PB_Quit\"))\n        self.PB_Quit.setToolTip(\"Quit FCCamera\")\n        self.PB_Quit.clicked.connect(self.on_PB_Quit_clicked)\n\n        MainWindow.setCentralWidget(self.centralWidget)\n\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n        MainWindow.setWindowTitle(\"FCCamera\")\n        MainWindow.setWindowIcon(QtGui.QIcon(icon_path('save_view.png')))\n        MainWindow.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint)\n        global numberPhoto\n        global ori_Horizont\n        global ori_Vertical\n\n        self.groupBox_01.setTitle(\"Camera of Axis (\" + __Version__ + \")\")\n        self.label_02.setText(\"Angle rotation Axis in degrees\")\n        self.label_03.setText(\"Axe of rotation\")\n        self.RB_Angle_X.setText(\"X\")\n        self.RB_Angle_Y.setText(\"Y\")\n        self.RB_Angle_Z.setText(\"Z\")\n        self.RB_Direction.setText(\"D\")\n        self.PB_Accept_View.setText(\"Accept the rotation\")\n\n        self.groupBox_02.setTitle(\"Virtual\")\n        self.PB_Detect_Camera.setText(\"Detect camera orientation\")\n        self.PB_To_Face.setText(\"To Face.\")\n        self.label_04.setText(\"Align view to face selected.\")\n        self.PB_To_Axis.setText(\"To Axis.\")\n        self.PB_Align_O_To_View.setText(\"Align Object to View\")\n        self.PB_Create_Plane.setText(\"Create plane of view.\")\n\n        ##### Photo\n        self.groupBox_03.setTitle(\"Photo\")\n        self.comboBox_01.setCurrentIndex(0)\n        self.comboBox_01.setItemText(0 ,\"Actual\")\n        self.comboBox_01.setItemText(1 ,\"Icon 16 x 16\")\n        self.comboBox_01.setItemText(2 ,\"Icon 32 x 32\")\n        self.comboBox_01.setItemText(3 ,\"Icon 64 x 64\")\n        self.comboBox_01.setItemText(4 ,\"Icon 128 x 128\")\n        self.comboBox_01.setItemText(5 ,\"CGA 320 x 200\")\n        self.comboBox_01.setItemText(6 ,\"QVGA 320 x 240\")\n        self.comboBox_01.setItemText(7 ,\"VGA 640 x 480\")\n        self.comboBox_01.setItemText(8 ,\"SVGA 800 x 600\")\n        self.comboBox_01.setItemText(9 ,\"XGA 1024 x 768\")\n        self.comboBox_01.setItemText(10 ,\"XGA+ 1152 x 864\")\n        self.comboBox_01.setItemText(11,\"SXGA 1280 x 1024\")\n        self.comboBox_01.setItemText(12,\"SXGA+ 1400 x 1050\")\n        self.comboBox_01.setItemText(13,\"UXGA 1600 x 1200\")\n        self.comboBox_01.setItemText(14,\"QXGA 2048 x 1536\")\n        self.comboBox_01.setItemText(15,\"Free\")\n        self.label_05.setText(\"X\")\n        self.label_06.setText(\"Y\")\n        self.comboBox_02.setCurrentIndex(4)\n        self.comboBox_02.setItemText(0,\"BMP *.bmp\")\n        self.comboBox_02.setItemText(1,\"ICO *.ico\")\n        self.comboBox_02.setItemText(2,\"JPEG *.jpeg\")\n        self.comboBox_02.setItemText(3,\"JPG *.jpg\")\n        self.comboBox_02.setItemText(4,\"PNG *.png\")\n        self.comboBox_02.setItemText(5,\"PPM *.ppm\")\n        self.comboBox_02.setItemText(6,\"TIF *.tif\")\n        self.comboBox_02.setItemText(7,\"TIFF *.tiff\")\n        self.comboBox_02.setItemText(8,\"XBM *.xbm\")\n        self.comboBox_02.setItemText(9,\"XPM *.xpm\")\n        #self.comboBox_02.setItemText(10,\"GIF *.gif\")\n\n        self.label_07.setText(\"Number images : \" + str(numberPhoto))\n        self.PB_Photo_Adjust.setText(\"Adj.\")\n        self.label_08.setText(\"\")\n#        self.label_09.setText(\"\")\n        self.groupBox_03_B.setTitle(\"BackGround image\")\n        self.RB_01_Actual.setText(\"Cu\")\n        self.RB_02_White.setText(\"Wh\")\n        self.RB_03_Black.setText(\"Bl\")\n        self.RB_04_Transparent.setText(\"Tr\")\n        self.PB_Photo_Launch.setText(\"Launch\")\n        self.PB_Photo_Reset.setText(\"Reset\")\n        self.PB_Photo_Quit.setText(\"Return\")\n        ##### Photo\n\n        self.PB_Reset.setText(\"Reset\")\n        self.PB_Photo.setText(\"Photo\")\n        self.PB_Quit.setText(\"Quit\")\n\n    def on_RB_Angle_X_clicked(self):\n        pic = QtGui.QPixmap(icon_path('axis_rotation_x.png'))\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(ui.scene)\n\n    def on_RB_Angle_Y_clicked(self):\n        pic = QtGui.QPixmap(icon_path('axis_rotation_y.png'))\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(ui.scene)\n\n    def on_RB_Angle_Z_clicked(self):\n        pic = QtGui.QPixmap(icon_path('axis_rotation_z.png'))\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(ui.scene)\n\n    def on_RB_Direction_clicked(self):\n        pic = QtGui.QPixmap(icon_path('axis_rotation_d.png'))\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(ui.scene)\n\n    def on_DS_Angle_valueChanged(self,value): # connection DS_Angle value given in degrees\n        global valeur\n        global numberPhoto\n        global valueTest\n\n        valeur = 0.0\n        valeur = math.radians(value)         # valeur in degrees converted to radians\n        self.DS_Angle.setStyleSheet(\"color : Base\")\n        self.label_07.setStyleSheet(\"color : Base\")\n\n        try:                                 # section value for angle photo\n            numberPhoto = 360.0 / value\n            if abs(float(360.0 / value)) - int(abs(numberPhoto)) != 0.0:\n                self.PB_Photo_Adjust.setVisible(True)\n                self.label_08.setVisible(True)\n                numberPhoto = (abs(360.0 /value))\n                self.label_07.setStyleSheet(\"color : Red\")\n                self.PB_Photo_Adjust.setStyleSheet(\"background-color : #ff0000\")\n\n                valueTest = abs(int(value))\n                while ((value + valueTest) < (361 + value)) and ((value - valueTest) < (361 + value)):\n                    if abs(float(360.0 / valueTest)) - int(abs(float(360.0 / valueTest))) == 0.0:\n                        if self.DS_Angle.value() < 0:\n                            self.label_08.setText(\"Ideal angle : \" + str(-valueTest) + \" = \" + str(abs(int(360.0 / valueTest))) + \" images\")\n                        else:\n                            self.label_08.setText(\"Ideal angle : \" + str(valueTest) + \" = \" + str(abs(int(360.0 / valueTest))) + \" images\")\n                        self.label_08.setStyleSheet(\"color : #008700\")\n                        break\n                    if self.DS_Angle.value() < 0:\n                        valueTest -= 1\n                    else:\n                        valueTest += 1\n                    FreeCADGui.updateGui()\n                self.PB_Photo_Adjust.setToolTip(u\"Click to adjust the number images to 360 degrees\" + \"\\n\"\n                                                u\"detected \" + str(numberPhoto) + \" = \" + str(int(numberPhoto)) + \" images\" + \"\\n\"\n                                                u\"ideal choice angle : \" + str(valueTest) + \" degrees = \" + str(abs(int(360.0 / valueTest))) + \" images\" + \"\\n\" )\n\n            else:\n                numberPhoto = int(abs(360.0 / value))\n                self.label_07.setStyleSheet(\"color : Base\")\n                self.label_08.setVisible(False)\n                self.label_08.setText(\"\")\n                self.PB_Photo_Adjust.setVisible(False)\n                self.PB_Photo_Adjust.setStyleSheet(\"color : Base\")\n                self.PB_Photo_Adjust.setToolTip(u\"Adjust the number image to 360 degrees\")\n        except Exception:\n            numberPhoto = 0\n\n        self.PB_Photo.setToolTip(u\"Create serial photo to create animation\" + \"\\n\"\n                                 u\"Specify the angle rotation desired\" + \"\\n\"\n                                 u\"Number of image = 360 / \" + str(math.degrees(valeur)) + \" = \" + str(numberPhoto))\n        self.label_07.setText(\"Number image : \" + str(numberPhoto))\n\n    def on_PB_Detect_Camera_clicked(self):         # detect camera orientation\n        global vertexeS\n\n        try:\n            plan = FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation()\n\n            cam=Gui.ActiveDocument.ActiveView.getCameraNode()\n            App.Console.PrintMessage(\"___Camera_Detection_____________________\"+\"\\n\")\n            App.Console.PrintMessage(\"position       : \" + str(cam.position.getValue().getValue()) + \"\\n\")\n\n            first = App.Vector(cam.position.getValue().getValue())\n            distance_3DView_to_Axis = math.sqrt(first.x*first.x + first.y*first.y + first.z*first.z)\n\n            App.Console.PrintMessage(\"               : (position = Distance Center 3DView to Axis base = \" + str(distance_3DView_to_Axis) + \")\" + \"\\n\")\n            App.Console.PrintMessage(\"orientation    : \" + str(FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation().Axis)+\" , \"+str(FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation().Angle) + \"\\n\")\n            App.Console.PrintMessage(\"nearDistance   : \" + str(cam.nearDistance.getValue()) + \"\\n\")\n            App.Console.PrintMessage(\"farDistance    : \" + str(cam.farDistance.getValue()) + \"\\n\")\n            App.Console.PrintMessage(\"aspectRatio    : \" + str(cam.aspectRatio.getValue()) + \"\\n\")\n            App.Console.PrintMessage(\"focalDistance  : \" + str(cam.focalDistance.getValue()) + \"\\n\")\n            App.Console.PrintMessage(\"height         : \" + str(cam.height.getValue()) + \"\\n\" + \"\\n\")\n\n            App.Console.PrintMessage(\"___Camera_Orientation____________________\"+\"\\n\")\n            App.Console.PrintMessage(\"Radians XYZ Q  : \" + str(plan)+\"\\n\")\n\n            extractValue = datExtract(plan)\n            xP = float(extractValue[0])\n            yP = float(extractValue[1])\n            zP = float(extractValue[2])\n            qP = float(extractValue[3])\n\n            App.Console.PrintMessage(\"Degrees XYZ    : \" + str(degrees(xP)) + \" , \" +str(degrees(yP)) + \" , \" + str(degrees(zP)) +\"\\n\")\n            App.Console.PrintMessage(\"Degrees Q      : \" + str(degrees(qP)) + \"\\n\\n\")\n\n            App.Console.PrintMessage(\"Radians Axis.xyz A : \" + str(plan.Axis) + \" , \" + str(plan.Angle) + \"\\n\")\n            App.Console.PrintMessage(\"Degrees Axis.x : \" + str(degrees(plan.Axis.x)) + \"\\n\")\n            App.Console.PrintMessage(\"Degrees Axis.y : \" + str(degrees(plan.Axis.y)) + \"\\n\")\n            App.Console.PrintMessage(\"Degrees Axis.z : \" + str(degrees(plan.Axis.z)) + \"\\n\")\n            App.Console.PrintMessage(\"Degrees Angle  : \" + str(degrees(plan.Angle))  + \"\\n\")\n\n            # http://forum.freecadweb.org/viewtopic.php?f=13&t=14213\n            App.Console.PrintMessage(\"Direction      : \" + str(cam.orientation.getValue().multVec(coin.SbVec3f(0,0,-1)).getValue()) + \"\\n\")\n            if (vertexeS[0] + vertexeS[1] + vertexeS[2]) != 0.0:\n                App.Console.PrintMessage(\"Direction edge : \" + str(vertexeS) + \"\\n\")\n            App.Console.PrintMessage(\"___FCCamera______________________________\"+\"\\n\\n\")\n            App.ActiveDocument.recompute()\n        except Exception:\n            App.Console.PrintError(\"No Document open\" + \"\\n\")\n\n    def on_PB_Accept_View_clicked(self):        # Accept Rotation Camera to Axis\n        global valeur\n        global vertexeS\n        global ori_Horizont\n        global ori_Vertical\n        global bounBoxCenter\n\n        if (valeur != 0):\n\n            Xv = 0.0; Yv = 0.0; Zv = 0.0\n            try:\n                activeView = FreeCADGui.activeDocument().activeView()\n                cam = Gui.ActiveDocument.ActiveView.getCameraNode()\n                rot = coin.SbRotation()\n\n                if self.RB_Direction.isChecked():\n                    cam.position.setValue(App.Vector(bounBoxCenter))  # boundBox edge selected\n                else:\n                    #activeView.fitAll()                              # boundBox all center\n                    cam.position.setValue(centerBoundBoxGlobal())     # boundBox all center calculated\n\n                #####\n                if self.RB_Angle_X.isChecked():\n                    Xv = 1.0\n                    App.Console.PrintMessage(\"(X \")\n                else:\n                    App.Console.PrintMessage(\"(- \")\n                if self.RB_Angle_Y.isChecked():\n                    Yv = 1.0\n                    App.Console.PrintMessage(\"Y \")\n                else:\n                    App.Console.PrintMessage(\"- \")\n                if self.RB_Angle_Z.isChecked():\n                    Zv = 1.0\n                    App.Console.PrintMessage(\"Z \")\n                else:\n                    App.Console.PrintMessage(\"- \")\n\n                if self.RB_Direction.isChecked():\n                    if (vertexeS[0] + vertexeS[1] + vertexeS[2]) != 0.0:\n                        Xv = vertexeS[0]\n                        Yv = vertexeS[1]\n                        Zv = vertexeS[2]\n                        App.Console.PrintMessage(\"D)\" + \"\\n\")\n                    else:\n                        Xv = bounBoxCenter[0]\n                        Yv = bounBoxCenter[1]\n                        Zv = bounBoxCenter[2]\n                        if (Xv + Yv + Zv) == 0.0:\n                            App.Console.PrintMessage(\"!)\" + \"\\n\")\n                            App.Console.PrintError(\"No axis selected (edge) for rotation\" + \"\\n\"\n                                                   \"or Direction is null\" + \"\\n\")\n                    Gui.updateGui()\n                else:\n                    App.Console.PrintMessage(\"-) \" + \"\\n\")\n                #####\n\n                rot.setValue(coin.SbVec3f(Xv,Yv,Zv),valeur)\n                nrot = cam.orientation.getValue() * rot\n                cam.orientation = nrot\n\n                App.Console.PrintMessage(str(valeur)+\" rad. , \"+str(math.degrees(valeur))+\" deg.\"+\"\\n\")\n                App.Console.PrintMessage(\"FCCamera_________________________________\"+\"\\n\\n\")\n            except Exception:\n                App.Console.PrintError(\"No Document open\"+\"\\n\")\n        else:\n            App.Console.PrintError(\"Value angle equals zero. Select one Value\"+\"\\n\")\n            self.DS_Angle.setStyleSheet(\"color : #ff0000\")\n\n    #### photo ################################################\n    def SIGNAL_comboBox_01_Changed(self,text):\n        global dim_Horizont\n        global dim_Vertical\n        global ori_Horizont\n        global ori_Vertical\n\n        if   text == \"Actual\":\n            dim_Horizont = ori_Horizont\n            dim_Vertical = ori_Vertical\n        if   text == \"Icon 16 x 16\":\n            dim_Horizont = 16\n            dim_Vertical = 16\n        elif text == \"Icon 32 x 32\":\n            dim_Horizont = 32\n            dim_Vertical = 32\n        elif text == \"Icon 64 x 64\":\n            dim_Horizont = 64\n            dim_Vertical = 64\n        elif text == \"Icon 128 x 128\":\n            dim_Horizont = 128\n            dim_Vertical = 128\n        elif text == \"CGA 320 x 200\":\n            dim_Horizont = 320\n            dim_Vertical = 200\n        elif text == \"QVGA 320 x 240\":\n            dim_Horizont = 320\n            dim_Vertical = 240\n        elif text == \"VGA 640 x 480\":\n            dim_Horizont = 640\n            dim_Vertical = 480\n        elif text == \"SVGA 800 x 600\":\n            dim_Horizont = 800\n            dim_Vertical = 600\n        elif text == \"XGA 1024 x 768\":\n            dim_Horizont = 1024\n            dim_Vertical = 768\n        elif text == \"XGA+ 1152 x 864\":\n            dim_Horizont = 1152\n            dim_Vertical = 864\n        elif text == \"SXGA 1280 x 1024\":\n            dim_Horizont = 1280\n            dim_Vertical = 1024\n        elif text == \"SXGA+ 1400 x 1050\":\n            dim_Horizont = 1400\n            dim_Vertical = 1050\n        elif text == \"UXGA 1600 x 1200\":\n            dim_Horizont = 1600\n            dim_Vertical = 1200\n        elif text == \"QXGA 2048 x 1536\":\n            dim_Horizont = 2048\n            dim_Vertical = 1536\n        elif text == \"Free\":\n            None\n\n        self.DS_01_X.setValue(dim_Horizont)\n        self.DS_02_Y.setValue(dim_Vertical)\n\n        activeView = FreeCADGui.activeDocument().activeView()\n        mainWindow = FreeCADGui.getMainWindow()\n        mdi = mainWindow.findChild(QtGui.QMdiArea)\n        mwActive = mdi.activeSubWindow()\n        mwActive.setGeometry(0, 0, dim_Horizont, dim_Vertical)\n\n    def SIGNAL_comboBox_02_Changed(self,text):\n        global formatFichier\n\n        if   text == \"BMP *.bmp\":\n            formatFichier = \".bmp\"\n        elif text == \"ICO *.ico\":\n            formatFichier = \".ico\"\n        elif text == \"JPEG *.jpeg\":\n            formatFichier = \".jpeg\"\n        elif text == \"JPG *.jpg\":\n            formatFichier = \".jpg\"\n        elif text == \"PNG *.png\":\n            formatFichier = \".png\"\n        elif text == \"PPM *.ppm\":\n            formatFichier = \".ppm\"\n        elif text == \"TIF *.tif\":\n            formatFichier = \".tif\"\n        elif text == \"TIFF *.tiff\":\n            formatFichier = \".tiff\"\n        elif text == \"XBM *.xbm\":\n            formatFichier = \".xbm\"\n        elif text == \"XPM *.xpm\":\n            formatFichier = \".xpm\"\n\n    def on_DS_01_X_valueChanged(self, value):\n        global dim_Horizont\n        global dim_Vertical\n\n        dim_Horizont = value\n\n        self.DS_01_X.setValue(dim_Horizont)\n        #self.comboBox_01.setCurrentIndex(15)\n\n        activeView = FreeCADGui.activeDocument().activeView()\n        mainWindow = FreeCADGui.getMainWindow()\n        mdi = mainWindow.findChild(QtGui.QMdiArea)\n        mwActive = mdi.activeSubWindow()\n        mwActive.setGeometry(0, 0, dim_Horizont, dim_Vertical)     #\n\n    def on_DS_02_Y_valueChanged(self, value):\n        global dim_Horizont\n        global dim_Vertical\n\n        dim_Vertical = value\n\n        self.DS_02_Y.setValue(dim_Vertical)\n        #self.comboBox_01.setCurrentIndex(15)\n\n        activeView = FreeCADGui.activeDocument().activeView()\n        mainWindow = FreeCADGui.getMainWindow()\n        mdi = mainWindow.findChild(QtGui.QMdiArea)\n        mwActive = mdi.activeSubWindow()\n        mwActive.setGeometry(0, 0, dim_Horizont, dim_Vertical)     #\n\n    def on_PB_Photo_Launch_clicked(self):\n        global pathFile\n        global dim_Horizont\n        global dim_Vertical\n        global formatFichier\n        global valeur\n\n        if (valeur != 0):\n            SaveName, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, \"Save a files \", pathFile,  \"*\" + formatFichier) # PySide\n\n            if SaveName == \"\":\n                App.Console.PrintMessage(\"Process aborted\" + \"\\n\")\n            else:\n                pathFile = SaveName[:SaveName.rfind(\"/\") + 1]\n                App.Console.PrintMessage(\"Registration of \" + SaveName[:-4] + \"_Animate_...\" + \"\\n\")\n                SaveName = SaveName[:-4]\n                try:\n                    Xv = 0.0;Yv = 0.0;Zv = 0.0\n\n                    #####\n                    if self.RB_Angle_X.isChecked():\n                        Xv = 1.0\n                    elif self.RB_Angle_Y.isChecked():\n                        Yv = 1.0\n                    elif self.RB_Angle_Z.isChecked():\n                        Zv = 1.0\n                    elif self.RB_Direction.isChecked():\n                        if (vertexeS[0] + vertexeS[1] + vertexeS[2]) != 0.0:\n                            Xv = vertexeS[0]\n                            Yv = vertexeS[1]\n                            Zv = vertexeS[2]\n                        else:\n                            App.Console.PrintError(\"No axis selected (edge) for rotation\" + \"\\n\"\n                                                   \"or Direction is null\" + \"\\n\")\n                    #####\n                    if (Xv + Yv + Zv) != 0.0:\n                        try:\n                            fileCount = 0\n                            activeView = FreeCADGui.activeDocument().activeView()\n                            cam = Gui.ActiveDocument.ActiveView.getCameraNode()\n\n                            for i in range(int(360.0 / abs(math.degrees(valeur)))):\n                                Gui.updateGui()\n\n                                if self.RB_Direction.isChecked():\n                                    cam.position.setValue(App.Vector(bounBoxCenter))     # boundBox edge selected\n                                else:\n#                                    activeView.fitAll()                                     # boundBox all center\n                                    cam.position.setValue(centerBoundBoxGlobal())            # boundBox all center calculated\n\n                                cam = Gui.ActiveDocument.ActiveView.getCameraNode()\n                                rot = coin.SbRotation()\n                                rot.setValue(coin.SbVec3f(Xv,Yv,Zv),valeur)\n                                nrot = cam.orientation.getValue() * rot\n                                cam.orientation = nrot\n\n                                fileCount += 1\n                                if self.RB_01_Actual.isChecked():\n                                    fileName = SaveName + \"_Animate_\" + '%03d_%03d' % (fileCount, math.degrees(valeur)*fileCount) + \"_Cu\" + formatFichier\n                                    activeView.saveImage(fileName, dim_Horizont, dim_Vertical, \"Current\")\n                                elif self.RB_02_White.isChecked():\n                                    fileName = SaveName + \"_Animate_\" + '%03d_%03d' % (fileCount, math.degrees(valeur)*fileCount) + \"_Wh\" + formatFichier\n                                    activeView.saveImage(fileName, dim_Horizont, dim_Vertical, \"White\")\n                                elif self.RB_03_Black.isChecked():\n                                    fileName = SaveName + \"_Animate_\" + '%03d_%03d' % (fileCount, math.degrees(valeur)*fileCount) + \"_Bl\" + formatFichier\n                                    activeView.saveImage(fileName, dim_Horizont, dim_Vertical, \"Black\")\n                                elif self.RB_04_Transparent.isChecked():\n                                    fileName = SaveName + \"_Animate_\" + '%03d_%03d' % (fileCount, math.degrees(valeur)*fileCount) + \"_Tr\" + formatFichier\n                                    activeView.saveImage(fileName, dim_Horizont, dim_Vertical, \"Transparent\")\n#                                App.Console.PrintMessage(fileName + \"\\n\")\n\n                        except Exception:\n                            App.Console.PrintError(\"Error Creation File\"+\"\\n\")\n                        App.Console.PrintMessage(\"End photos\"+\"\\n\")\n                except Exception:                                                     # if error detected to write\n                    App.Console.PrintError(\"Error write file \"+SaveName+\"\\n\")         # detect error ... display the text in red (PrintError)\n        else:\n            App.Console.PrintError(\"Give angle value for rotation\")\n            App.Console.PrintMessage(\" (Actual 3Dview = X \" + str(dim_Horizont) + \", Y \" + str(dim_Vertical) + \") \" + \"\\n\")\n            self.DS_Angle.setStyleSheet(\"color : #ff0000\")\n\n    def on_PB_Photo_Adjust_clicked(self):\n        global valueTest\n\n        if self.DS_Angle.value() < 0:\n            self.DS_Angle.setValue(-valueTest)\n        else:\n            self.DS_Angle.setValue(valueTest)\n\n        self.PB_Photo_Adjust.setVisible(False)\n        self.label_08.setVisible(False)\n        self.label_08.setText(\"\")\n        # self.label_08.setStyleSheet(\"color : Base\")\n\n    def on_PB_Photo_Quit_clicked(self):\n        global ori_Horizont\n        global ori_Vertical\n\n        self.PB_Photo.setText(\"Photo\")\n        self.groupBox_03.setVisible(False)\n        self.groupBox_02.setVisible(True)\n        self.comboBox_02.setCurrentIndex(4)\n        self.comboBox_01.setCurrentIndex(0)\n\n        self.PB_Photo.setVisible(True)\n        self.PB_Reset.setVisible(True)\n        self.PB_Quit.setVisible(True)\n\n        self.comboBox_01.setCurrentIndex(0)\n        try:\n            activeView = FreeCADGui.activeDocument().activeView()\n            mainWindow = FreeCADGui.getMainWindow()\n            mdi = mainWindow.findChild(QtGui.QMdiArea)\n            mwActive = mdi.activeSubWindow()\n            mwActive.setGeometry(0, 0, ori_Horizont, ori_Vertical)\n        except Exception:\n            App.Console.PrintError('No opened document\\n')\n\n    def on_PB_Photo_Reset_clicked(self):  # Reset photo\n        global ui\n        ui.on_PB_Reset_clicked()\n\n    def on_PB_Photo_clicked(self):  # Create photo\n        global ui\n        global valeur\n        global ori_Horizont\n        global ori_Vertical\n        global dim_Horizont\n        global dim_Vertical\n        global numberPhoto\n\n        try:\n            self.groupBox_02.setVisible(False)\n            self.groupBox_03.setVisible(True)\n\n            self.PB_Photo.setVisible(False)\n            self.PB_Reset.setVisible(False)\n            self.PB_Quit.setVisible(False)\n            self.PB_Photo.setText(\"Reset\")\n        except Exception:\n            App.Console.PrintError(\"Not Document open\" + \"\\n\")\n\n    #### photo #############################################################\n\n    def on_PB_Align_O_To_View_clicked(self):  #Align and Fix Object to View\n\n        sel = FreeCADGui.Selection.getSelection()\n        if (len(sel)==0):\n            App.Console.PrintError(\"Select one object\"+\"\\n\")\n        else:\n            Nameelement = sel[0].Name\n            App.Console.PrintMessage(str(Nameelement)+\"\\n\")\n            pl = App.Placement()\n            pl.Rotation = FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation()\n            pl.Base = sel[0].Placement.Base\n            App.ActiveDocument.getObject(Nameelement).Placement=pl\n\n    def on_PB_Create_Plane_clicked(self):     # Create plane\n        global positionX                      # create plans coordinate mouse\n        global positionY\n        global positionZ\n\n        rayon = 20                            # Radius of plane\n        selEx = FreeCADGui.Selection.getSelectionEx()\n        objs = [selobj.Object for selobj in selEx]\n        if len(objs) != 0.0:                  # radius = > BounBox length\n            s = objs[0].Shape\n            boundBox_ = s.BoundBox\n            boundBoxLX = boundBox_.XLength\n            boundBoxLY = boundBox_.YLength\n            boundBoxLZ = boundBox_.ZLength\n\n            rayon = boundBoxLX\n            if rayon < boundBoxLY:\n                rayon = boundBoxLY\n            elif rayon < boundBoxLZ:\n                rayon = boundBoxLZ\n\n        try:\n            radiusP = rayon                       # Radius of plane\n            FcPlane = doc.addObject(\"App::DocumentObjectGroup\",\"FcPlane\")\n            App.Console.PrintMessage(\"Create plane (\"+str(radiusP)+\" mm)\"+\"\\n\")\n\n            plan = FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation()\n            App.Console.PrintMessage(str(plan)+\"\\n\")\n            App.Console.PrintMessage(str(positionX)+\" \"+str(positionY)+\" \"+str(positionZ)+\"\\n\")\n\n            extractValue = datExtract(plan)\n            xP = float(extractValue[0])\n            yP = float(extractValue[1])\n            zP = float(extractValue[2])\n            qP = float(extractValue[3])\n\n            pl = App.Placement()\n            pl.Rotation.Q = (xP,yP,zP,qP)         # rotation of object\n\n            pl.Base = App.Vector(positionX, positionY, positionZ) # 'plan' XYZ coordinates\n\n            # Draft.makeRectangle(length=radiusP, height=radiusP, placement=pl, face=False, support=None)\n            points = [App.Vector(-(radiusP*1.5),0,0), App.Vector((radiusP*1.5),0,0)]\n            mire01 = Draft.makeWire(points,closed=False,placement=pl,face=False,support=None)\n            FreeCADGui.ActiveDocument.getObject(App.ActiveDocument.ActiveObject.Name).LineColor = (1.0,0.0,0.0)\n            FcPlane.addObject(mire01)  # contain character\n\n            points = [App.Vector(0,-(radiusP*1.5),0), App.Vector(0,(radiusP*1.5),0)]\n            mire02 = Draft.makeWire(points, closed=False, placement=pl, face=False, support=None)\n            FreeCADGui.ActiveDocument.getObject(App.ActiveDocument.ActiveObject.Name).LineColor = (1.0,0.0,0.0)\n            FcPlane.addObject(mire02)  # contain character\n\n            circle = Draft.makeCircle(radius=radiusP,placement=pl,face=False,support=None)\n            Rnameplane = App.ActiveDocument.ActiveObject.Name\n\n            App.ActiveDocument.ActiveObject.Label   = \"PlaneC\"\n            App.ActiveDocument.getObject(Rnameplane).MakeFace = True\n            FreeCADGui.ActiveDocument.getObject(Rnameplane).LineColor = (1.0,0.0,0.0)\n            FreeCADGui.ActiveDocument.getObject(Rnameplane).ShapeColor = (0.0,0.66666669,1.0)\n            FreeCADGui.ActiveDocument.getObject(Rnameplane).Transparency = 80\n            FreeCADGui.ActiveDocument.getObject(Rnameplane).GridSize = '10 mm'\n    #        FreeCADGui.ActiveDocument.getObject(Rnameplane).GridSnap = True\n            FreeCADGui.ActiveDocument.getObject(Rnameplane).ShowGrid = True\n\n            FcPlane.addObject(circle)  # contain character\n            App.ActiveDocument.recompute()\n\n            positionX = 0.0\n            positionY = 0.0\n            positionZ = 0.0\n        except Exception:\n            App.Console.PrintError(\"Not Document open\" + \"\\n\")\n\n    def on_PB_To_Face_clicked(self):        # view to face selected Face\n        To_Face_Or_To_Axis(1)\n\n    def on_PB_To_Axis_clicked(self):        # view to face selected Axis\n        To_Face_Or_To_Axis(0)\n\n    def on_PB_Reset_clicked(self):          # Refresh\n        global valeur\n        global positionX\n        global positionY\n        global positionZ\n        global vueView\n        global fileCount\n        global numberPhoto\n        global ori_Horizont\n        global ori_Vertical\n\n        try:\n            Gui.activeDocument().activeView().viewTop()\n            Gui.SendMsgToActiveView(\"ViewFit\")\n            valeur = 0.0\n            fileCount = 0\n            self.DS_Angle.setProperty(\"value\", 0.0)\n\n            positionX = 0.0\n            positionY = 0.0\n            positionZ = 0.0\n            vueView   = 0\n\n            self.RB_Angle_X.setChecked(True)\n            pic = QtGui.QPixmap(icon_path('axis_rotation_x.png'))\n            self.scene = QtGui.QGraphicsScene()\n            self.scene.addPixmap(QtGui.QPixmap(pic))\n            self.graphicsView.setScene(ui.scene)\n\n            activeView = FreeCADGui.activeDocument().activeView()\n            mainWindow = FreeCADGui.getMainWindow()\n            mdi = mainWindow.findChild(QtGui.QMdiArea)\n            mwActive = mdi.activeSubWindow()\n            mwActive.setGeometry(0, 0, ori_Horizont, ori_Vertical)\n            self.comboBox_01.setCurrentIndex(0)\n            self.DS_01_X.setValue(ori_Horizont)\n            self.DS_02_Y.setValue(ori_Vertical)\n            centerBoundBoxGlobal()\n            self.RB_01_Actual.setChecked(True)\n            App.Console.PrintMessage(\"Refresh (3Dview = X \" + str(ori_Horizont) +\n                                                        \", Y \" + str(ori_Vertical) + \") \" + \"\\n\")\n            numberPhoto = 0\n            self.label_07.setText(\"Image number: \" + str(numberPhoto))\n        except Exception:\n            App.Console.PrintError(\"No Document open\" + \"\\n\")\n\n    def on_PB_Quit_clicked(self): # quit\n        global s\n        global ori_Horizont\n        global ori_Vertical\n\n        try:\n            activeView = FreeCADGui.activeDocument().activeView()\n            mainWindow = FreeCADGui.getMainWindow()\n            mdi = mainWindow.findChild(QtGui.QMdiArea)\n            mwActive = mdi.activeSubWindow()\n            mwActive.setGeometry(0, 0, ori_Horizont, ori_Vertical)     #\n        except Exception:\n            None\n\n        App.Console.PrintMessage(\"Fin FCCamera\" + \"\\n\")\n        FreeCADGui.Selection.removeObserver(s)    # uninstall the resident function\n        self.window.close()\n\n##Start#####\n\n#Gui.ActiveDocument.ActiveView.setAxisCross(True) # GuiAxis true\n\ns=SelObserver()                                   # install the function in resident mode SelObserver\nFreeCADGui.Selection.addObserver(s)               # install the function in resident mode SelObserver\n\nMainWindow = QtGui.QMainWindow()\nui = Ui_MainWindow()\nui.setupUi(MainWindow)\nMainWindow.show()\n\n\n",
    "url": "",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_FCCamera",
    "version": "0.0.14",
    "license": "",
    "date": "2022-02-23",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\PureGui\\Camera.FCMacro",
    "filename_from_url": "",
    "author": "",
    "icon": "Camera.png",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "Camera.png",
      "Camera/accept.png",
      "Camera/align_object_to_view.png",
      "Camera/align_to_axis.png",
      "Camera/align_to_face.png",
      "Camera/axis_rotation_d.png",
      "Camera/axis_rotation_x.png",
      "Camera/axis_rotation_y.png",
      "Camera/axis_rotation_z.png",
      "Camera/create_plane_of_view.png",
      "Camera/detect_orientation.png",
      "Camera/quit.png",
      "Camera/reset.png",
      "Camera/save_view.png"
    ],
    "parsed": true
  },
  {
    "name": "GuiResetToolbars",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Reset Toolbars position",
    "code": "# Reset Toolbars position\n# Author: Milos Petrasinovic <mpetrasinovic@protors.co>\n# PROTORS, Belgrade, Serbia\n# info@protors.co\n#\n# --------------------\n#\n# Copyright (C) 2020 PROTORS <info@protors.co>\n#\n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU Lesser General Public License as\n# published by the Free Software Foundation, either version 3 of the\n# License, or (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public License\n# along with this program.  If not, see <https://www.gnu.org/licenses/>.\n#\n# --------------------\n\n__Name__ = 'GuiResetToolbars'\n__Comment__ = 'Reset Toolbars position'\n__Author__ = 'PROTORS'\n__Version__ = '1.0.0'\n__Date__ = '2020-04-21'\n__License__ = 'LGPL-3.0-or-later'\n__Web__ = \"https://github.com/protors/ResetToolbars/\"\n__Wiki__ = 'https://wiki.freecadweb.org/Macro_GuiResetToolbars'\n__Icon__ = 'GuiResetToolbars.svg'\n__Help__ = 'Run the macro within a workbench that has missing toolbar(s)'\n__Status__ = 'stable'\n__Requires__ = 'Freecad >= 0.18.4'\n__Communication__ = 'https://github.com/protors/ResetToolbars/issues/'\n__Files__ = 'GuiResetToolbars.svg'\n\nimport FreeCADGui as gui\nfrom PySide import QtGui, QtCore # FreeCAD's special PySide!\n\nmw = gui.getMainWindow()\ntb = mw.findChildren(QtGui.QToolBar)\nfor i in tb:\n    mw.addToolBar(QtCore.Qt.TopToolBarArea, i)\n",
    "url": "https://github.com/protors/ResetToolbars/",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_GuiResetToolbars",
    "version": "1.0.0",
    "license": "",
    "date": "2020-04-21",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\PureGui\\GuiResetToolbars.FCMacro",
    "filename_from_url": "",
    "author": "PROTORS",
    "icon": "GuiResetToolbars.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "GuiResetToolbars.svg"
    ],
    "parsed": true
  },
  {
    "name": "GuiSpacemouseRotationOff",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Run to deactivate rotations on Spacemouse device.",
    "code": "# Run to deactivate rotations on Spacemouse device.\n\n__Name__ = 'Spacemouse Rotation Off'\n__Comment__ = 'Run to deactivate rotations on Spacemouse device.'\n__Author__ = 'tja2468,R3D3,galou_breizh'\n__Version__ = '1.0.0'\n__Date__ = '2021-11-01'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'http://forum.freecadweb.org/viewtopic.php?f=?&t=????'\n__Wiki__ = 'http://www.freecadweb.org/wiki/Macro_Title_Of_macro'\n__Icon__ = ''\n__Help__ = 'Run to deactivate rotations on Spacemouse device.'\n__Status__ = 'production'\n__Requires__ = 'FreeCAD 0.20'\n__Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=22&t=61482'\n__Files__ = ''\n\nimport FreeCAD as app\n\n# Activate rotations.\napp.ParamGet('User parameter:BaseApp/Spaceball/Motion').SetBool('Rotations', False)\n\n# display message to convey status\napp.Console.PrintMessage('Spacemouse rotations disabled\\n')\n",
    "url": "http://forum.freecadweb.org/viewtopic.php?f=?&t=????",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/Macro_Title_Of_macro",
    "version": "1.0.0",
    "license": "",
    "date": "2021-11-01",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\PureGui\\GuiSpacemouseRotationOff.FCMacro",
    "filename_from_url": "",
    "author": "tja2468,R3D3,galou_breizh",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "GuiSpacemouseRotationOn",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Run to activate rotations on Spacemouse device.",
    "code": "# Run to activate rotations on Spacemouse device.\n\n__Name__ = 'Spacemouse Rotation On'\n__Comment__ = 'Run to activate rotations on Spacemouse device.'\n__Author__ = 'tja2468,R3D3,galou_breizh'\n__Version__ = '1.0.0'\n__Date__ = '2021-11-01'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'http://forum.freecadweb.org/viewtopic.php?f=?&t=????'\n__Wiki__ = 'http://www.freecadweb.org/wiki/Macro_Title_Of_macro'\n__Icon__ = ''\n__Help__ = 'Run to activate rotations on Spacemouse device.'\n__Status__ = 'production'\n__Requires__ = 'FreeCAD 0.20'\n__Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=22&t=61482'\n__Files__ = ''\n\nimport FreeCAD as app\n\n# Activate rotations.\napp.ParamGet('User parameter:BaseApp/Spaceball/Motion').SetBool('Rotations', True)\n\n# display message to convey status\napp.Console.PrintMessage('Spacemouse rotations enabled\\n')\n",
    "url": "http://forum.freecadweb.org/viewtopic.php?f=?&t=????",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/Macro_Title_Of_macro",
    "version": "1.0.0",
    "license": "",
    "date": "2021-11-01",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\PureGui\\GuiSpacemouseRotationOn.FCMacro",
    "filename_from_url": "",
    "author": "tja2468,R3D3,galou_breizh",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "GuiSpacemouseRotationToggle",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Run to toggle the activation of rotations on Spacemouse device.",
    "code": "# Run to toggle the activation of rotations on Spacemouse device.\n\n__Name__ = 'Spacemouse Rotation Toggle'\n__Comment__ = 'Run to toggle the activation of rotations on Spacemouse device.'\n__Author__ = 'tja2468,R3D3,galou_breizh'\n__Version__ = '1.0.0'\n__Date__ = '2021-11-01'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'http://forum.freecadweb.org/viewtopic.php?f=?&t=????'\n__Wiki__ = 'http://www.freecadweb.org/wiki/Macro_Title_Of_macro'\n__Icon__ = ''\n__Help__ = 'Run to toggle the activation of rotations on Spacemouse device.'\n__Status__ = 'production'\n__Requires__ = 'FreeCAD 0.20'\n__Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=22&t=61482'\n__Files__ = ''\n\nimport FreeCAD as app\n\nrotation_active = app.ParamGet('User parameter:BaseApp/Spaceball/Motion').GetBool('Rotations')\n\n# Toggle the activation state.\napp.ParamGet('User parameter:BaseApp/Spaceball/Motion').SetBool('Rotations', not rotation_active)\n\n# Display a message to convey the new status.\nif rotation_active:\n    app.Console.PrintMessage('Spacemouse rotations disabled\\n')\nelse:\n    app.Console.PrintMessage('Spacemouse rotations enabled\\n')\n",
    "url": "http://forum.freecadweb.org/viewtopic.php?f=?&t=????",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/Macro_Title_Of_macro",
    "version": "1.0.0",
    "license": "",
    "date": "2021-11-01",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\PureGui\\GuiSpacemouseRotationToggle.FCMacro",
    "filename_from_url": "",
    "author": "tja2468,R3D3,galou_breizh",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "SplitPropEditor",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Splits the property editor from the combo view to a new dock widget (panel)",
    "code": "#!/usr/bin/python\n#####################################\n# Copyright (c) openBrain 2019\n# Licensed under LGPL v2\n#\n# This FreeCAD macro will split the property editor from the combo view to a new dockable widget (panel)\n# * The default widget is docked to the right of the window but can be freely moved\n# * When the new widget is closed, the property editor is set back to its location in the combo view\n# * When the macro has been run once, the new widget is registered in FC UI and can (shall) be hidden/shown as original panels are\n# * Mouse middle click on the panel title displays a temporary slider to change font size\n#\n# Version history :\n# *0.63 : add comments in the code\n# *0.62 : property edit subpanel height is recorded and restored\n# *0.61 : property editor split is toggles when 'Model' tab label is double clicked in Combo View\n# *0.6 : improve behavior of macro so it toggles property editor split at each run\n# *0.52 : stop timer when no more needed\n# *0.51 : fix issue when separate Property View is enabled\n# *0.5 : beta release\n#\n#####################################\n\n__Name__ = 'SplitPropEditor'\n__Comment__ = 'Splits the property editor from the combo view to a new dock widget (panel)'\n__Author__ = 'openBrain'\n__Version__ = '0.63'\n__Date__ = '2019-12-27'\n__License__ = 'LGPL v2'\n__Web__ = 'https://www.freecadweb.org/wiki/Macro_SplitPropEditor'\n__Wiki__ = 'https://www.freecadweb.org/wiki/Macro_SplitPropEditor'\n__Icon__ = ''\n__Help__ = 'Run macro once to create the new property editor panel'\n__Status__ = 'Beta'\n__Requires__ = 'FreeCAD >= 0.17'\n__Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=22&t=39345'\n\n### Perform needed imports\nfrom PySide import QtCore, QtGui\nimport FreeCAD as App\nimport FreeCADGui as Gui\n\n### Define a custom QDockWidget class\nclass PropEditor(QtGui.QDockWidget):\n\n    def __init__(self):\n        mw = Gui.getMainWindow()\n        pt = mw.findChild(QtGui.QWidget,'Combo View').findChild(QtGui.QWidget, 'propertyTab') # look for the property editor\n        if not pt:\n            raise Exception(\"Can't find property editor widget, exiting\")\n        self.ptWid = pt.parent() # find property editor widget\n        self.oldParent = pt.parent().parent() # find property editor parent (is a QSplitter)\n        self.oldIndex = self.oldParent.indexOf(self.ptWid) # store index of property editor in the QSplitter\n        self.font = QtGui.QFont(pt.font()) # store current font\n        super(PropEditor, self).__init__() # run inherited class constructor\n        self.setParent(mw)\n        self.setObjectName(\"PropEdit\")\n        self.setWindowTitle(\"Property Editor\")\n        ### create a custom title bar widget so font can be sized when property editor is split\n        self.titleWid = QtGui.QWidget()\n        lay = QtGui.QHBoxLayout()\n        self.fs = QtGui.QSlider(QtCore.Qt.Horizontal) # slider to size font\n        oldPs = self.font.pointSize()\n        self.fs.setSliderPosition(oldPs) # set default slider position\n        self.fs.setMaximum(oldPs) # maximum font size is default one\n        self.fs.setMinimum(int(oldPs/2+1)) # minimum font size is almost half the default one\n        self.fs.setPageStep(1) # needed so mouse wheel step is 1\n        self.fs.valueChanged.connect(self.changeFs)\n        self.fs.sliderReleased.connect(self.changeFs) # needed to manage font sizer hiding when slider is held by user\n        lay.addWidget(QtGui.QLabel(\"Size : \"))\n        lay.addWidget(self.fs)\n        self.titleWid.setLayout(lay)\n        self.timer = QtCore.QTimer(self) # set a timer so font sizer is hidden after some time\n        self.timer.setInterval(2500)\n        self.timer.timeout.connect(self.titleBarTo)\n        ### connect to 'Model' tab label double-clicking to toggle split\n        self.tb = mw.findChild(QtGui.QWidget,'Combo View').findChild(QtGui.QWidget, 'combiTab')\n        self.tb.tabBarDoubleClicked.connect(self.toggleVisibility)\n\n    def changeFs(self, fs=0): # called when font sizer slider is moved\n        self.timer.start() # restart timeout timer\n        if fs != 0:\n            self.font.setPointSize(fs) # compute new font ...\n            self.ptWid.setFont(self.font) # ... then apply\n\n    def showEvent(self, event): # called when custom dock widget is shown\n        self.ptHeight=self.oldParent.sizes() # record property editor height (handled at QSplitter to prevent opaque resizing)\n        self.setWidget(self.ptWid) # transfer property editor widget to custom dock widget\n        self.ptWid.setFont(self.font) # apply custom font size\n\n    def hideEvent(self, event): # called when custom dock widget is hidden\n        self.oldParent.insertWidget(self.oldIndex, self.ptWid) # reset property editor widget to combo view\n        self.oldParent.setSizes(self.ptHeight) # restore property editor height\n        self.ptWid.setFont(QtGui.QFont()) # restore default font of combo view\n\n    def mousePressEvent(self, event): # called when mouse is pressed on the custom dock widget\n        if event.button() == QtCore.Qt.MouseButton.MidButton: # if button is middle one\n            self.setTitleBarWidget(self.titleWid) # show the font sizer in the title bar\n            self.timer.start() # start timeout timer\n\n    def titleBarTo(self): # called when timeout timer expires\n        if not self.fs.isSliderDown(): # if slider is no more held by user\n            self.resetTitleBar() # reset title bar\n\n    def resetTitleBar(self):\n        self.setTitleBarWidget(None) # set title bar to 'None' so it get back its default aspect\n        self.timer.stop() # stop timeout timer\n\n    def toggleVisibility(self, index = -2): # called to toggle property editor split ...\n    # ... 'index' is needed when used as slot for 'Model' tab double-click ...\n    # ... '-2' value can't be sent by signal so we know its a 'manual' call\n        if index == -2 or self.tb.tabText(index).replace('&','') == 'Model': # if manual call or double-click on 'Model' tab label\n            self.setVisible(self.isHidden()) # toggle custom dock widget visibility (behavior handled by show/hide events)\n\ndef run() : # define main function\n    pe = Gui.getMainWindow().findChild(QtGui.QWidget, 'PropEdit') # check if a custom property editor dock widget already exist\n    if not pe: # if doesn't exist yet\n        Gui.getMainWindow().addDockWidget(QtCore.Qt.RightDockWidgetArea, PropEditor()) # create it\n    else: # if already exists\n        pe.toggleVisibility() # toggle property editor split\n\nif __name__ == '__main__': # if macro called to run\n    run()",
    "url": "https://www.freecadweb.org/wiki/Macro_SplitPropEditor",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_SplitPropEditor",
    "version": "0.63",
    "license": "",
    "date": "2019-12-27",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\PureGui\\SplitPropEditor.FCMacro",
    "filename_from_url": "",
    "author": "openBrain",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "ViewRotation",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "This GUI allows the view to be rotated precisely",
    "code": "#\n# FreeCAD macro ViewRotation.\n# This GUI allows the view to be rotated with more precision than when using\n# the mouse. Rotation is according to axes fixed with respect to the user and\n# not the objects, though the aim is that the objects rotate about their\n# approximate shared centre rather than the view centre.\n# The GUI defaults to the top right of the screen, this behaviour can be\n# changed by editing.\n# [http://forum.freecadweb.org/viewtopic.php?f=3&t=1784&hilit=View+Rotation#p12012 View+Rotation]\n\n\n__Name__ = 'View Rotation'\n__Comment__ = 'This GUI allows the view to be rotated precisely'\n__Author__ = 'Joe Dowsett'\n__Version__ = '1.0.1'\n__Date__ = '2024-11-22'\n__License__ = 'CC-BY-3.0'\n__Web__ = 'https://www.freecadweb.org/wiki/Macro_View_Rotation'\n__Wiki__ = 'https://www.freecadweb.org/wiki/Macro_View_Rotation'\n__Icon__ = ''\n__Help__ = 'Rotation is according to axes fixed with respect to the user.'\n__Status__ = ''\n__Requires__ = ''\n__Files__ = 'ViewRotationOut.png,ViewRotationRight.png,ViewRotationUp.png'\n\nfrom math import pi\nfrom functools import partial\nimport os\n\nfrom PySide import QtCore  # FreeCAD's PySide!\nfrom PySide import QtGui  # FreeCAD's PySide!\nfrom pivy import coin\n\nimport FreeCAD as app\nimport FreeCADGui as gui\n\n\ndef find_centre():\n    doc = app.activeDocument()\n    if doc is None:\n        return app.Vector(0.0, 0.0, 0.0)\n\n    xmax = 0.0\n    xmin = 0.0\n    ymax = 0.0\n    ymin = 0.0\n    zmax = 0.0\n    zmin = 0.0\n    for obj in doc.Objects:\n        try:\n            if obj.TypeId[:4] == 'Mesh':\n                box = obj.Mesh.BoundBox\n            elif obj.TypeId[:6] == 'Points':\n                box = obj.Points.BoundBox\n            elif obj.TypeId[:4] == 'Part':\n                box = obj.Shape.BoundBox\n            else:\n                continue\n        except AttributeError:\n            continue\n        xmax = max(xmax, box.XMax)\n        xmin = min(xmin, box.XMin)\n        ymax = max(ymax, box.YMax)\n        ymin = min(ymin, box.YMin)\n        zmax = max(zmax, box.ZMax)\n        zmin = min(zmin, box.ZMin)\n\n    return app.Vector((xmax + xmin) / 2, (ymax + ymin) / 2, (zmax + zmin) / 2)\n\n\nclass RotateGui(QtGui.QWidget):\n    def __init__(self):\n        super().__init__()\n        self.init_ui()\n        self.init_rotate()\n\n    def init_ui(self):\n        macro_dir = app.getUserMacroDir(True)\n        self.sliders = []\n        self.line_edits = []\n\n        vbox = QtGui.QVBoxLayout()\n\n        icons = (\n                'ViewRotationRight.png',\n                'ViewRotationUp.png',\n                'ViewRotationOut.png',\n        )\n        for i, icon in enumerate(icons):\n            slider = QtGui.QSlider(QtCore.Qt.Horizontal, self)\n            slider.setFocusPolicy(QtCore.Qt.NoFocus)\n            slider.setSingleStep(5)\n            slider.setPageStep(15)\n            slider.setValue(0)\n            slider.setMaximum(180)\n            slider.setMinimum(-180)\n            slider.valueChanged.connect(partial(self.on_slider_value_changed, i))\n            self.sliders.append(slider)\n\n            line_edit = QtGui.QLineEdit(self)\n            line_edit.setText('0')\n            line_edit.setAlignment(QtCore.Qt.AlignRight)\n            line_edit.returnPressed.connect(self.valueEntered)\n            self.line_edits.append(line_edit)\n\n            label = QtGui.QLabel(self)\n            label.setPixmap(QtGui.QPixmap(os.path.join(macro_dir, icon)))\n\n            hbox = QtGui.QHBoxLayout()\n            hbox.addWidget(label, 1, QtCore.Qt.AlignCenter)\n            hbox.addWidget(slider, 4)\n            hbox.addWidget(line_edit, 1)\n            vbox.addLayout(hbox)\n\n        reset_button = QtGui.QPushButton('Reset')\n        reset_button.clicked.connect(self.reset)\n\n        ok_button = QtGui.QPushButton('OK')\n        ok_button.clicked.connect(self.close)\n\n        cancel_button = QtGui.QPushButton('Cancel')\n        cancel_button.clicked.connect(self.cancel)\n\n        hbox = QtGui.QHBoxLayout()\n        hbox.addWidget(reset_button, 1)\n        hbox.addWidget(ok_button, 1)\n        hbox.addWidget(cancel_button, 1)\n        vbox.addStretch(1)\n        vbox.addLayout(hbox)\n\n        self.setLayout(vbox)\n\n        qapp = QtCore.QCoreApplication.instance()\n        screen_number = QtGui.QDesktopWidget().screenNumber(self)\n        right = qapp.screens()[screen_number].geometry().width()\n\n        self.setGeometry(right - 300, 0, 300, 150)\n        self.setWindowTitle('Rotate view')\n        self.show()\n\n    def init_rotate(self):\n        # Index in [right, up, out]\n        self._current_axis = 0\n\n        self.cam = gui.activeDocument().ActiveView.getCameraNode()\n        self.centre = coin.SbVec3f(find_centre())\n        self.view = self.cam.orientation.getValue()\n        self.pos = self.cam.position.getValue()\n\n        # Store a copy of the original view to be restored in the case of user\n        # selecting Reset or Cancel.\n        self.original_view = coin.SbRotation(self.view.getValue())\n        self.original_pos = coin.SbVec3f(self.pos.getValue())\n\n        self.config_direction(0)\n\n    def reset(self):\n        # Reset the view to the original one.\n        self.cam.orientation = self.original_view\n        self.cam.position = self.original_pos\n        for slider in self.sliders:\n            # Deactivate callbacks.\n            slider.blockSignals(True)\n            slider.setValue(0)\n            slider.blockSignals(False)\n        for tbox in self.line_edits:\n            tbox.setText('0')\n        self.config_direction(0)\n\n    def cancel(self):\n        self.reset()\n        self.close()\n\n    def config_direction(self, axis_index):\n        \"\"\"\n        Assign `self.direction` to either the right, up or out vector.\n\n        Evaluate the vectors corresponding to the three directions for the\n        current view, and assign `self.direction` to the one at index `axis_index`.\n\n        \"\"\"\n        self.view = self.cam.orientation.getValue()\n        self.view = coin.SbRotation(self.view.getValue())\n        self.pos = self.cam.position.getValue()\n        self.pos = coin.SbVec3f(self.pos.getValue())\n\n        up = coin.SbVec3f(0, 1, 0)\n        self.up = self.view.multVec(up)\n        out = coin.SbVec3f(0, 0, 1)\n        self.out = self.view.multVec(out)\n        u = self.up.getValue()\n        o = self.out.getValue()\n        r = (u[1]*o[2]-u[2]*o[1], u[2]*o[0]-u[0]*o[2], u[0]*o[1]-u[1]*o[0])\n        self.right = coin.SbVec3f(r)\n\n        self.direction = [self.right, self.up, self.out][axis_index]\n\n    def check(self, axis_index):\n        \"\"\"\n        Check if the direction of rotation has changed.\n\n        Check if the direction of rotation has changed, if so then set\n        previous slider and textbox to zero, and setup the new direction.\n\n        \"\"\"\n        if axis_index != self._current_axis:\n            # Deactivate callbacks.\n            self.sliders[self._current_axis].blockSignals(True)\n            self.sliders[self._current_axis].setValue(0)\n            self.sliders[self._current_axis].blockSignals(False)\n            self.line_edits[self._current_axis].blockSignals(True)\n            self.line_edits[self._current_axis].setText(\"0\")\n            self.line_edits[self._current_axis].blockSignals(False)\n            self._current_axis = axis_index\n            self.config_direction(axis_index)\n\n    def rotate(self, value):\n        # Carry out the desired rotation about self.direction.\n        val = value * pi / 180.0\n        rot = coin.SbRotation(self.direction, -val)\n        nrot = self.view*rot\n        prot = rot.multVec(self.pos - self.centre) + self.centre\n        self.cam.orientation = nrot\n        self.cam.position = prot\n\n    def on_slider_value_changed(self, slider_index: int, value: int):\n        \"\"\"\n        Respond to the change in value of a slider.\n\n        Respond to the change in value of a slider, update the corresponding\n        text box, check for a direction change then rotate\n        if the value was changed internally, ignore event.\n\n        \"\"\"\n        self.line_edits[slider_index].setText(str(value))\n        self.check(slider_index)\n        self.rotate(value)\n\n    def valueEntered(self):\n        \"\"\"\n        Respond to a value being entered in a text box.\n\n        Respond to a value being entered in a text box, updating the\n        corresponding slider, checking for direction change then rotate.\n\n        \"\"\"\n        sender = self.sender()\n        for i in range(3):\n            if sender == self.line_edits[i]:\n                break\n        value = round(float(self.line_edits[i].text()))\n        self.sliders[i].blockSignals(True)\n        self.sliders[i].setValue(value)\n        self.sliders[i].blockSignals(False)\n        self.line_edits[i].blockSignals(True)\n        self.line_edits[i].setText(str(value))\n        self.line_edits[i].blockSignals(False)\n        self.check(i)\n        self.rotate(value)\n\n\nif __name__ == '__main__':\n    # We need to set a variable, otherwise, the dialog doesn't appear.\n    rotate = RotateGui()\n",
    "url": "https://www.freecadweb.org/wiki/Macro_View_Rotation",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_View_Rotation",
    "version": "1.0.1",
    "license": "",
    "date": "2024-11-22",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\PureGui\\ViewRotation.FCMacro",
    "filename_from_url": "",
    "author": "Joe Dowsett",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "ViewRotationOut.png",
      "ViewRotationRight.png",
      "ViewRotationUp.png"
    ],
    "parsed": true
  },
  {
    "name": "SketcherBlockAll",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Add a block constraint on all the geometry elements of a sketch.",
    "code": "# Add a block constraint on all the geometry elements of a sketch.\n\n__Name__ = 'Sketcher Block All'\n__Comment__ = 'Add a block constraint on all the geometry elements of a sketch.'\n__Author__ = 'galou_breizh'\n__Version__ = '1.0.0'\n__Date__ = '2021-11-20'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = ''\n__Wiki__ = ''\n__Icon__ = ''\n__Help__ = ''\n__Status__ = ''\n__Requires__ = 'FreeCAD >=0.19'\n__Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'\n__Files__ = ''\n\nfrom typing import Optional\n\nimport FreeCAD as app\n\nimport FreeCADGui as gui\n\nimport Sketcher\n\n\ndef get_sketch() -> Optional[Sketcher.Sketch]:\n    \"\"\"Get the opened or selected sketch.\"\"\"\n    active_workbench = gui.activeWorkbench()\n    if active_workbench.name() == 'SketcherWorkbench':\n        # ActiveSketch is defined by the Sketcher Workbench.\n        return ActiveSketch\n    else:\n        sel = gui.Selection.getSelection()\n        if sel and sel[0].TypeId == 'Sketcher::SketchObject':\n            return sel[0]\n\n\ndef block_sketch(sketch: Sketcher.Sketch) -> None:\n    \"\"\"Add a 'Block' constraint on all geometry elements.\"\"\"\n    for i in range(len(sketch.Geometry)):\n        try:\n            sketch.addConstraint(Sketcher.Constraint('Block', i))\n        except:\n            pass\n\n\nsketch = get_sketch()\nif sketch is not None:\n    block_sketch(sketch)\nelse:\n    app.Console.PrintWarning('No sketch selected, doing nothing')\n\n",
    "url": "",
    "raw_code_url": "",
    "wiki": "",
    "version": "1.0.0",
    "license": "",
    "date": "2021-11-20",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Sketcher\\SketcherBlockAll.FCMacro",
    "filename_from_url": "",
    "author": "galou_breizh",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "SketcherClipView",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Creates a temporary clipping plane at the support plane of the sketch",
    "code": "# -*- coding: utf-8 -*-\n\n###############################################\n#\n#\tSketcherClipView\n#\n# This macro creates a temporary cross section at the\n# sketch plane in order to 'look into' an object when you\n# want to create a feature on the inside (i.e. create a revolved\n# groove on the inner side of a tube).\n#\n# The macro creates a clipping plane at the sketch plane and\n# activates it. Running the macro again deletes the clipping plane.\n#\n# If you map the macro to F7 it behaves almost exactly like\n# in Autodesk Inventor, from which I got the inspiration.\n#\n# (c) Ricardo Beck\n#################################################\n\n__Name__ = 'Sketcher Clip View'\n__Comment__ = 'Creates a temporary clipping plane at the support plane of the sketch'\n__License__ = ''\n__Web__ = 'https://forum.freecadweb.org/viewtopic.php?t=26608'\n__Wiki__ = ''\n__Icon__ = 'SketcherClipView.svg'\n__Help__ = 'Launch while editing a sketch'\n__Author__ = 'Ricardo Beck, galou_breizh'\n__Version__ = '1.1.0'\n__Date__ = '2018-05-29'\n__Status__ = 'Beta'\n__Requires__ = 'FreeCAD >= v0.17'\n__Files__ = 'SketcherClipView.svg'\n\nfrom pivy import coin\n\nimport freecad as fc\nimport FreeCAD as app\nimport FreeCADGui as gui\nfrom PySide import QtCore\n\n\ndef in_edit_mode():\n    \"\"\"Return True if the Sketcher is in edit mode\n\n    This is done by checking whether ActiveSketch is defined and\n    ActiveSketch.ViewObject.TempoVis is not None.\n    \"\"\"\n    in_edit_mode = False\n    try:\n        in_edit_mode = (ActiveSketch.ViewObject.TempoVis is not None)\n    except NameError:\n        pass\n    return in_edit_mode\n\n\ndef check_leave_edit():\n    if not in_edit_mode():\n        clean()\n\n\ndef clean():\n    if hasattr(fc, 'SketcherClipView_clip_plane'):\n        gui.activeDocument().ActiveView.getSceneGraph().removeChild(fc.SketcherClipView_clip_plane)\n        del fc.SketcherClipView_clip_plane\n        del fc.SketcherClipView_timer\n\n\ndef main():\n    # Check if there is a temporary clipping plane from a previous run of the\n    # macro.\n    if hasattr(fc, 'SketcherClipView_clip_plane'):\n        # Clipping plane found, remove from scenegraph and delete the object.\n        clean()\n        return\n\n    if not in_edit_mode():\n        return\n\n    # No clipping plane found, create one at the sketch base.\n\n    # Get the placement information of the active sketch.\n    try:\n        mat = ActiveSketch.getGlobalPlacement()\n    except NameError:\n        # ActiveSketch undefined (i.e. not in sketch editing mode).\n        return\n    point = mat.Base\n    normal = mat.Rotation.multVec(app.Vector(0, 0, 1))\n\n    # Create coin3d vectors of the sketch position.\n    coin_normal_vector = coin.SbVec3f(normal.x, normal.y, normal.z)\n    coin_normal_vector.negate()\n    coin_base_point = coin.SbVec3f(point.x, point.y, point.z)\n\n    # Offset of the clipping plane so the sketch elements (lines, etc) are not cut off.\n    sketch_offset_factor = -0.02\n\n    coin_normal_vector_normalized = coin.SbVec3f(coin_normal_vector)\n    coin_normal_vector_normalized.normalize()\n\n    # Offset the clipping plane base by a fraction of the (normalized) normal vector.\n    coin_base_point += (coin_normal_vector_normalized * sketch_offset_factor)\n\n    # Create the clipping plane at the calculated position.\n    fc.SketcherClipView_clip_plane = coin.SoClipPlane()\n    fc.SketcherClipView_clip_plane.plane.setValue(coin.SbPlane(coin_normal_vector,coin_base_point))\n    gui.activeDocument().ActiveView.getSceneGraph().insertChild(fc.SketcherClipView_clip_plane, 0)\n\n    # Switch clipping plane on.\n    fc.SketcherClipView_clip_plane.on.setValue(True)\n\n    fc.SketcherClipView_timer = QtCore.QTimer()\n    fc.SketcherClipView_timer.timeout.connect(check_leave_edit)\n    fc.SketcherClipView_timer.start(100)  # Pool every 100 ms.\n\nif __name__ == '__main__':\n    main()\n",
    "url": "https://forum.freecadweb.org/viewtopic.php?t=26608",
    "raw_code_url": "",
    "wiki": "",
    "version": "1.1.0",
    "license": "",
    "date": "2018-05-29",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Sketcher\\SketcherClipView.FCMacro",
    "filename_from_url": "",
    "author": "Ricardo Beck, galou_breizh",
    "icon": "SketcherClipView.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "SketcherClipView.svg"
    ],
    "parsed": true
  },
  {
    "name": "SketcherFixAllPoints",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "",
    "code": "__Name__ = 'SketcherFixAllPoints'\n__Author__ = 'edi'\n__Version__ = '0.0.3'\n__Date__  = '2021-11-20'\n__License__ = 'LGPL v2'\n__Web__ = 'https://forum.freecadweb.org/viewtopic.php?f=13&t=52451'\n__Icon__ = ''\n__Help__ = 'Open a sketch. Start the macro. All geometry is fixed by constraints.'\n__Status__ = 'Stable'\n__Requires__ = 'e.g. FreeCAD >= v0.19'\n__Files__ = 'SketcherFixAllPoints.svg'\n\"\"\"\nThis macro is intended to constrain automatically created, incompletely contrained sketches.\nThe sketches usually have been imported from IGES, STEP or DXF files.\n\nAll existing external constraints will be deleted.\nAll points defining the sketch obtain a 'DistanceX' and 'DistanceY' constraint.\nPoints positioned on two elements are connected using a 'Coincident' constraint.\nCircles obtain a 'Diameter' constraint.\n\nWorkflow:\n- Open a sketch or select a sketch in the model tree\n- Start the macro\n\nHint: The created sketch may be over constrained. In this case drag an element.\nThe redundant constraints will be deleted automatically.\n\n\"\"\"\n\nfrom typing import List\n\nimport FreeCAD as app\n\nimport FreeCADGui as gui\n\ng_all_points: List['Point'] = []\n\n\nclass Point:\n    \"\"\"Defining a Point object, containing its position and element id's.\"\"\"\n    def __init__(self, pos, geo_id, pt_id):\n        self.pos = pos\n        self.ident = []\n        self.extend(geo_id, pt_id)\n\n    def extend(self, geo_id, pt_id):\n        self.ident.append([geo_id, pt_id])\n\n\ndef addPoint(pos, geo_id, pt_id):\n    \"\"\"Add a Point to the g_all_points list.\"\"\"\n    pt = Point(pos, geo_id, pt_id)\n    # Extend an existing point if at the same position.\n    for existing_pt in g_all_points:\n        if pt.pos.isEqual(existing_pt.pos, 0.01):\n            existing_pt.extend(geo_id, pt_id)\n            return\n    # No point at the same position, add a point.\n    g_all_points.append(pt)\n\n\ndef get_sketch():\n    \"\"\"Get the opened or selected sketch.\"\"\"\n    active_workbench = gui.activeWorkbench()\n    if active_workbench.name() == 'SketcherWorkbench':\n        # ActiveSketch is defined by the Sketcher Workbench.\n        return ActiveSketch\n    else:\n        sel = gui.Selection.getSelection()\n        if sel and sel[0].TypeId == 'Sketcher::SketchObject':\n            return sel[0]\n\n\ndef delete_constraints(sketch):\n    \"\"\"Delete all external constraints.\"\"\"\n    internals = []\n    for i in range(sketch.ConstraintCount):\n        if sketch.Constraints[0].Type == 'InternalAlignment':\n            internals.append(sketch.Constraints[0])\n        sketch.delConstraint(0)\n    sketch.addConstraint(internals)\n\n\ndef get_elements(sketch):\n    \"\"\"Add points of next geometry to list of points.\"\"\"\n    for i, geo in enumerate(sketch.Geometry):\n        if geo.TypeId == 'Part::GeomLineSegment':\n            addPoint(geo.StartPoint, i, 1)\n            addPoint(geo.EndPoint, i, 2)\n        elif geo.TypeId == 'Part::GeomArcOfCircle':\n            addPoint(geo.StartPoint, i, 1)\n            addPoint(geo.EndPoint, i, 2)\n            addPoint(geo.Center, i, 3)\n        elif geo.TypeId == 'Part::GeomCircle':\n            addPoint(geo.Center, i, 3)\n\n\ndef make_constraints(sketch):\n    \"\"\"Create the new constraints.\"\"\"\n    for pt in g_all_points:\n        sketch.addConstraint(Sketcher.Constraint('DistanceX',\n            pt.ident[0][0], pt.ident[0][1], pt.pos.x))\n        sketch.addConstraint(Sketcher.Constraint('DistanceY',\n            pt.ident[0][0], pt.ident[0][1], pt.pos.y))\n        if len(pt.ident) > 1:\n            sketch.addConstraint(Sketcher.Constraint('Coincident',\n                pt.ident[0][0], pt.ident[0][1], pt.ident[1][0], pt.ident[1][1]))\n\n\ndef make_diameters(sketch):\n    \"\"\"Diameter constraints for all circles.\"\"\"\n    for i, geo in enumerate(sketch.Geometry):\n        if geo.TypeId == 'Part::GeomCircle':\n            sketch.addConstraint(Sketcher.Constraint('Diameter', i, geo.Radius * 2))\n\n\nsketch = get_sketch()\nif sketch is not None:\n    delete_constraints(sketch)\n    get_elements(sketch)\n    make_constraints(sketch)\n    make_diameters(sketch)\n    app.activeDocument().recompute()\nelse:\n    app.Console.PrintWarning('No sketch selected, doing nothing')\n",
    "url": "https://forum.freecadweb.org/viewtopic.php?f=13&t=52451",
    "raw_code_url": "",
    "wiki": "",
    "version": "0.0.3",
    "license": "",
    "date": "2021-11-20",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Sketcher\\SketcherFixAllPoints.FCMacro",
    "filename_from_url": "",
    "author": "edi",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "SketcherFixAllPoints.svg"
    ],
    "parsed": true
  },
  {
    "name": "SketcherOffset",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "",
    "code": "\"\"\"\nThis macro creates a line chain parallel to an existing one.\nThe existing line chain may be composed of line segments and arcs of cirles. All arcs have to be tangential to their neighbours. The line chain may be open or closed.\nExisting and created line chain can be draged using the mouse holding the parallelism.\nWorkflow:\n- Select lines in an opened sketch.\n- Start the macro\n- Show value of distance and side (left/right) of the created lines using the mouse.\n\"\"\"\n\n__Name__   = \"SketcherOffset\"\n__Author__  = \"edi\"\n__Version__ = \"0.0.4\"\n__License__ = 'License identifier from https://spdx.org/licenses/, e.g. LGPL-2.0-or-later as FreeCAD, MIT, CC0-1.0'\n__Web__ = 'https://forum.freecadweb.org/viewtopic.php?f=19&t=49886'\n__Files__ = 'SketcherOffset.svg'\n__Help__ = 'Select some lines in a sketch. Start the macro. Show offset value using the rubber band.'\n__Status__ = 'Stable'\n__Requires__ = 'FreeCAD >= v0.18'\n__Date__    = \"2021-04-30\"\n\nimport re\nimport math\n\nfrom PySide import QtGui  # FreeCAD's PySide!!\n\nfrom pivy.coin import *\n\nmajor, minor = [int(n) for n in App.Version()[:2]]\nif [major, minor] == [0, 18]:\n    import DraftTrackers as gui_trackers\nelif ((major > 0)\n      or ((major == 0) and (minor >= 19))):\n    # The major is the year in the LinkDaily branch so that the condition\n    # major > 0 is true for it.\n    from draftguitools import gui_trackers\n\n\nclass OffsetDialog:\n    \"\"\"\n    read selected items and show the offset distance\n    \"\"\"\n\n    def __init__(self):\n        self.view = FreeCADGui.ActiveDocument.ActiveView\n        self.OffsetLine = []\n        self.tracker = gui_trackers.lineTracker(scolor=(1,1,1),swidth=3,dotted=True)\n        self.tracker.raiseTracker()\n        self.callback = self.view.addEventCallbackPivy(SoMouseButtonEvent.getClassTypeId(), self.getPoint)\n        self.callmouse=self.view.addEventCallbackPivy(SoLocation2Event.getClassTypeId(),self.getMousePoint)\n        self.SelGeoId = self.getElements()\n\n    def getMousePoint(self, event_cb):\n        \"\"\"\n        slot: the mouse has been moved\n        \"\"\"\n        event = event_cb.getEvent()\n        if len(self.OffsetLine)==1:\n            pos = event.getPosition()\n            point = self.view.getPoint(pos[0],pos[1])\n            self.tracker.p2(point)\n\n    def getPoint(self, event_callback):\n        \"\"\"\n        slot: a mouse button has been pressed\n        \"\"\"\n        event = event_callback.getEvent()\n        if event.getState() == SoMouseButtonEvent.DOWN:\n            pos = event.getPosition()\n            point = self.view.getPoint(pos[0], pos[1])\n            self.OffsetLine.append(point)\n            self.tracker.p2(point)\n            self.view.removeEventCallbackPivy(SoMouseButtonEvent.getClassTypeId(), self.callback)\n            self.view.removeEventCallbackPivy(SoLocation2Event.getClassTypeId(),self.callmouse)\n            self.tracker.off()\n            self.tracker.finalize()\n            OffsetInSketcher.addOffset(self.SelGeoId,self.OffsetLine)\n\n    def selectedGeoId(self):\n        \"\"\"\n        returns a list containing GeoId's of selected lines and arcs\n        \"\"\"\n        if not Gui.Selection.getSelectionEx():\n            OffsetDialog.message('Please select elements')\n        SelEx=Gui.Selection.getSelectionEx()[0].SubElementNames\n        SelGeoId = []\n        for El in SelEx:\n            if El.find('Edge') == 0:\n                Number = int(re.findall(r'\\d+',El)[0])-1\n                SelGeoId.append(Number)\n        return SelGeoId\n\n    def getElements(self):\n        \"\"\"\n        get selected elements and offset value\n        \"\"\"\n        SelGeoId = self.selectedGeoId()\n        point = Sketch.getSketchPoint(SelGeoId[0])\n        self.OffsetLine.append(point)\n        self.tracker.on()\n        self.tracker.p1(point)\n        return SelGeoId\n\n    def message(MessageText):\n        msgBox = QtGui.QMessageBox()\n        msgBox.setText(MessageText)\n        msgBox.exec_()\n\nclass Edge:\n    \"\"\"\n    manage the edge-element\n    \"\"\"\n    def __init__(self,Geometry,Number=None):\n        self.Geo = Geometry\n        self.GeoId = Number\n        self.StartPoint = Geometry.StartPoint\n        self.EndPoint = Geometry.EndPoint\n        self.StartPointId = 1\n        self.EndPointId = 2\n        self.Type = 'line'\n        if hasattr(Geometry,'Radius'):\n            self.Type = 'arc'\n            self.Axis = Geometry.Axis\n            if self.Axis.z < 0.0:\n                self.StartPointId = 2\n                self.EndPointId = 1\n            self.Center = Geometry.Center\n            self.Radius = Geometry.Radius\n\n    def addGeometry(self,Mode=False):\n        self.GeoId = Sketch.getGeoNumber()\n        Sketch.addGeometry(self.Geo,Mode)\n\n    def reverse(self):\n        self.Geo.reverse()\n        self.StartPoint = self.Geo.StartPoint\n        self.EndPoint = self.Geo.EndPoint\n        self.StartPointId = 3-self.StartPointId\n        self.EndPointId = 3-self.EndPointId\n        if self.Type == 'arc':\n            self.Axis = self.Geo.Axis\n\n    def isNegative(self):\n        if self.Type == 'arc':\n            if self.Axis.z < 0.0:\n                return True\n\nclass Sketch:\n    \"\"\"\n    manage all connections to the sketch\n    \"\"\"\n    def addGeometry(Element,Mode):\n        ActiveSketch.addGeometry(Element,Mode)\n\n    def getGeometry():\n        return ActiveSketch.Geometry\n\n    def getGeoNumber():\n        return ActiveSketch.GeometryCount\n\n    def getSketchPoint(Element):\n        return ActiveSketch.getPoint(Element,1)\n\n    def coincident(Element1,Point1,Element2,Point2):\n        ActiveSketch.addConstraint(Sketcher.Constraint('Coincident',Element1.GeoId,Point1,Element2.GeoId,Point2))\n\n    def equal(Element1,Element2):\n        ActiveSketch.addConstraint(Sketcher.Constraint('Equal',Element1.GeoId,Element2.GeoId))\n\n    def perpendicular(Element1,Element2):\n        ActiveSketch.addConstraint(Sketcher.Constraint('Perpendicular',Element1.GeoId,Element2.GeoId))\n\n    def pointOnObject(Element1,Point,Element2):\n        ActiveSketch.addConstraint(Sketcher.Constraint('PointOnObject',Element1.GeoId,Point,Element2.GeoId))\n\n    def symmetric(Element,MidVertexNum):\n        ActiveSketch.addConstraint(Sketcher.Constraint('Symmetric',Element.GeoId,1,Element.GeoId,2,MidVertexNum,1))\n\n    def tangent(Element1,Point1,Element2,Point2):\n        ActiveSketch.addConstraint(Sketcher.Constraint('Tangent',Element1.GeoId,Point1,Element2.GeoId,Point2))\n\nclass Tools:\n    \"\"\"\n    diverse geometric tools\n    \"\"\"\n    def createLine(Point1,Point2):\n        return Edge(Part.LineSegment(Point1,Point2))\n\n    def concentricArcOfCircle(Element,Distance,Reverse=False):\n        Arc = Element.Geo.clone()\n        Circle = Arc.Circle\n        ConcentricEdge = Edge(Part.ArcOfCircle(Part.Circle(Circle,Distance),Arc.FirstParameter,Arc.LastParameter))\n        if Reverse: ConcentricEdge.reverse()\n        return ConcentricEdge\n\n    def getMidPoint(Element):\n        XPoint = (Element.EndPoint.x+Element.StartPoint.x)/2\n        YPoint = (Element.EndPoint.y+Element.StartPoint.y)/2\n        return App.Vector(XPoint,YPoint,0)\n\nclass OffsetInSketcher():\n    \"\"\"\n    class containing the addOffset command\n    \"\"\"\n    def addOffset(SelGeoId,OffsetLine):\n        \"\"\"\n        this is the OffsetInSketcher command\n        \"\"\"\n        def getSelectedEdges(SelGeoID):\n            \"\"\"\n            returns a list of all selected lines and arcs\n            \"\"\"\n            AllGeo = Sketch.getGeometry()\n            Selected = []\n            for Id in SelGeoID:\n                Geometry = AllGeo[Id]\n                if Geometry.TypeId == 'Part::GeomCircle':\n                    # Unsupported.\n                    continue\n                Selected.append(Edge(Geometry,Id))\n            return Selected\n\n        def areEqual(V1,V2):\n            \"\"\"\n            check the  identity of two vectors\n            \"\"\"\n            if (V1-V2).Length < 0.001: return True\n\n        def interlinkedEdges(UnsortedEdges):\n            \"\"\"\n            return an interlinked list of lines and arcs\n            \"\"\"\n            def getBackwardElem(Element,UnsortedEdges):\n                \"\"\"\n                get next edge in backward direction\n                \"\"\"\n                if not UnsortedEdges: return\n\n                StartPt = Element.StartPoint\n                Num = 0\n                while Num <= len(UnsortedEdges)-1:\n                    El=UnsortedEdges[Num]\n                    if (areEqual(El.StartPoint,StartPt)) or (areEqual(El.EndPoint ,StartPt)):\n                        if areEqual(El.StartPoint,StartPt):\n                            El.reverse()\n                        SortedEdges.append(El)\n                        UnsortedEdges.pop(Num)\n                        getBackwardElem(El,UnsortedEdges)\n                        break\n                    Num = Num+1\n                return\n\n            def getForwardElem(Element,UnsortedEdges):\n                \"\"\"\n                get next edge in forward direction\n                \"\"\"\n                if not UnsortedEdges: return\n\n                EndPt = Element.EndPoint\n                Num = 0\n                while Num <= len(UnsortedEdges)-1:\n                    El=UnsortedEdges[Num]\n                    if (areEqual(El.StartPoint,EndPt)) or (areEqual(El.EndPoint ,EndPt)):\n                        if areEqual(El.EndPoint,EndPt):\n                            El.reverse()\n                        SortedEdges.append(El)\n                        UnsortedEdges.pop(Num)\n                        getForwardElem(El,UnsortedEdges)\n                        break\n                    Num = Num+1\n                return\n\n            SortedEdges = []\n            SortedEdges.append(UnsortedEdges.pop(0))\n            getBackwardElem(SortedEdges[0],UnsortedEdges)\n            SortedEdges.reverse()\n            getForwardElem(SortedEdges[-1],UnsortedEdges)\n            if len(UnsortedEdges) > 0 :\n                OffsetDialog.message('Selected lines are split')\n            return SortedEdges\n\n        def flection(A,B,C):\n            \"\"\"\n            returns True if flection of polyline is negative\n            \"\"\"\n            M = App.Matrix(\tA.x,\tA.y,\t1,\t0,\n\t\t\t\t\tB.x,\tB.y,\t1,\t0,\n\t\t\t\t\tC.x,\tC.y,\t1,\t0,\n\t\t\t\t\t0,\t0,\t0,\t1)\n            if M.determinant() < 0.0: return True\n\n        def pointBetween(Edge0,Edge1):\n            \"\"\"\n            calculate  vertex between two offset edges\n            \"\"\"\n            if  Edge0.Type == 'arc':\n                delta = Edge0.EndPoint.sub(Edge0.Center).normalize()\n                if Edge0.isNegative(): delta = delta.negative()\n            elif  Edge1.Type == 'arc':\n                delta = Edge1.StartPoint.sub(Edge1.Center).normalize()\n                if Edge1.isNegative(): delta = delta.negative()\n            else:\n                e0=(Edge0.EndPoint.sub(Edge0.StartPoint)).normalize()\n                e1=(Edge1.EndPoint.sub(Edge1.StartPoint)).normalize()\n                Angle = e0.getAngle(e1)\n                if Angle == 0.0:\n                    delta =e0.cross(App.Vector(0,0,1))\n                else:\n                    Factor = 1.0/math.cos(Angle/2)\n                    delta=e0.sub(e1).normalize().multiply(Factor)\n                if flection(Edge0.StartPoint,Edge0.EndPoint,Edge1.EndPoint):\n                    delta=delta.negative()\n            delta = delta.multiply(OffsetValue)\n            pt=Edge0.EndPoint.add(delta)\n            return pt\n\n        def pointAtOpenEnd(Edge,Start):\n            \"\"\"\n            calculate  offset vertex at start or end of open edge\n            \"\"\"\n            e = (Edge.EndPoint.sub(Edge.StartPoint)).normalize()\n            delta =e.cross(App.Vector(0,0,1)).multiply(OffsetValue)\n            if Start:\n                pt = Edge.StartPoint+delta\n            else:\n                pt = Edge.EndPoint+delta\n            return pt\n\n        def createOffsetVertexes(SortedEdges):\n            \"\"\"\n            create vertexes of offset line\n            \"\"\"\n            OffsetPoints = []\n            NumOfEdges = len(SortedEdges)-1\n            if areEqual(SortedEdges[0].StartPoint,SortedEdges[-1].EndPoint):\n                SortedEdges.append(SortedEdges[0])\n                for i in range(NumOfEdges+1):\n                    OffsetPoints.append(pointBetween(SortedEdges[i],SortedEdges[i+1]))\n                OffsetPoints.insert(0,OffsetPoints[-1])\n            else:\n                OffsetPoints.append(pointAtOpenEnd(SortedEdges[0],True))\n                for i in range(NumOfEdges):\n                    OffsetPoints.append(pointBetween(SortedEdges[i],SortedEdges[i+1]))\n                OffsetPoints.append(pointAtOpenEnd(SortedEdges[-1],False))\n            return OffsetPoints\n\n        def drawOffsetEdges(SortedEdges,OffsetPoints):\n            \"\"\"\n            create and draw the offset lines\n            \"\"\"\n            OffsetEdges = []\n            for i in range(len(OffsetPoints)-1):\n                if SortedEdges[i].Type == 'arc':\n                    Arc = SortedEdges[i]\n                    Offset = OffsetValue\n                    if Arc.isNegative():\n                        Offset = -OffsetValue\n                    if Arc.Radius+Offset < 0.0:\n                        OffsetDialog.message('Inner radius becomes negative')\n                    else:\n                        OffsetEdges.append(Tools.concentricArcOfCircle(SortedEdges[i],Offset))\n                else:\n                    OffsetEdges.append(Edge(Part.LineSegment(OffsetPoints[i],OffsetPoints[i+1])))\n                OffsetEdges[-1 ].addGeometry()\n            return OffsetEdges\n\n        def createConstraints(OffsetEdges):\n            \"\"\"\n            create constraints at vertexes\n            \"\"\"\n            def constraintAtVertex(Edge1,Edge2):\n                \"\"\"\n                create constraint between two edges\n                \"\"\"\n                if Edge1.Type == 'arc' or Edge2.Type == 'arc':\n                    Sketch.tangent(Edge1,Edge1.EndPointId,Edge2,Edge2.StartPointId)\n                else:\n                    Sketch.coincident(Edge1,Edge1.EndPointId,Edge2,Edge2.StartPointId)\n\n            for i in range(len(OffsetEdges)-1):\n                constraintAtVertex(OffsetEdges[i],OffsetEdges[i+1])\n            if  areEqual(OffsetEdges[-1].EndPoint,OffsetEdges[0].StartPoint):\n                constraintAtVertex(OffsetEdges[-1],OffsetEdges[0])\n\n        def createParametric(SortedEdges,OffsetEdges,OffsetValue):\n            \"\"\"\n            create constraints generating the parametric behavior\n            \"\"\"\n            def parametricAtOpenEdge(BaseEdge,OffsetEdge,PtNum,OffsetValue):\n                \"\"\"\n                constraints at first and last edge\n                \"\"\"\n                if PtNum == 2:\n                    DistanceLines.append(Tools.createLine(BaseEdge.EndPoint,OffsetEdge.EndPoint))\n                    DistanceLines[-1 ].addGeometry(True)\n                    Sketch.coincident(DistanceLines[-1 ],1,BaseEdge,BaseEdge.EndPointId)\n                    Sketch.coincident(DistanceLines[-1 ],2,OffsetEdge,OffsetEdge.EndPointId)\n                    Sketch.equal(DistanceLines[0 ],DistanceLines[-1])\n                else:\n                    DistanceLines.append(Tools.createLine(BaseEdge.StartPoint,OffsetEdge.StartPoint))\n                    DistanceLines[-1 ].addGeometry(True)\n                    Sketch.coincident(DistanceLines[-1 ],1,BaseEdge,BaseEdge.StartPointId)\n                    Sketch.coincident(DistanceLines[-1 ],2,OffsetEdge,OffsetEdge.StartPointId)\n                Sketch.perpendicular(OffsetEdge,DistanceLines[-1])\n                Sketch.perpendicular(BaseEdge,DistanceLines[-1])\n\n            def parametricAtEdges(BaseEdge,OffsetEdge,OffsetValue):\n                \"\"\"\n                constraints at interior edges\n                \"\"\"\n                if OffsetEdge.Type == 'arc':\n                    Sketch.coincident(BaseEdge,3,OffsetEdge,3)\n                else:\n                    e = (OffsetEdge.EndPoint.sub(OffsetEdge.StartPoint)).normalize()\n                    delta =e.cross(App.Vector(0,0,-1)).multiply(OffsetValue)\n                    MidPoint = Tools.getMidPoint(OffsetEdge)\n                    DistanceLines.append(Tools.createLine(MidPoint,MidPoint.add(delta)))\n                    DistanceLines[-1 ].addGeometry(True)\n                    Sketch.symmetric(OffsetEdge,Sketch.getGeoNumber()-1)\n                    if len(DistanceLines) > 1: Sketch.equal(DistanceLines[0 ],DistanceLines[-1])\n                    Sketch.perpendicular(OffsetEdge,DistanceLines[-1])\n                    Sketch.perpendicular(BaseEdge,DistanceLines[-1])\n                    # Sketch.pointOnObject(DistanceLines[-1],1,OffsetEdge)\n                    Sketch.pointOnObject(DistanceLines[-1],2,BaseEdge)\n\n            DistanceLines = []\n            if  areEqual(OffsetEdges[-1].EndPoint,OffsetEdges[0].StartPoint):\n                parametricAtEdges(SortedEdges[0],OffsetEdges[0],OffsetValue)\n                for i in range(1,len(SortedEdges)-1):\n                    parametricAtEdges(SortedEdges[i],OffsetEdges[i],OffsetValue)\n            else:\n                parametricAtOpenEdge(SortedEdges[0],OffsetEdges[0],1,OffsetValue)\n                for i in range(1,len(SortedEdges)-1):\n                    parametricAtEdges(SortedEdges[i],OffsetEdges[i],OffsetValue)\n                parametricAtOpenEdge(SortedEdges[-1],OffsetEdges[-1],2,OffsetValue)\n\n        def getOffsetValue(FirstEdge,OffsetLine):\n            \"\"\"\n            calculate offsetvalue using the offsetline\n            \"\"\"\n            OffsetValue = (OffsetLine[0].sub(OffsetLine[1])).Length\n            if flection(OffsetLine[0],OffsetLine[1],FirstEdge.EndPoint):\n                OffsetValue = -OffsetValue\n            return OffsetValue\n\n        SelectedEdges = getSelectedEdges(SelGeoId)\n        if not SelectedEdges:\n            App.Console.PrintWarning('No supported edge selected, doing nothing\\n')\n            return\n        OffsetValue = getOffsetValue(SelectedEdges[0],OffsetLine)\n        SortedEdges = interlinkedEdges(SelectedEdges)\n        OffsetPoints = createOffsetVertexes(SortedEdges)\n        OffsetEdges = drawOffsetEdges(SortedEdges,OffsetPoints)\n        createConstraints(OffsetEdges)\n        createParametric(SortedEdges,OffsetEdges,OffsetValue)\n        App.ActiveDocument.recompute()\n\nex = OffsetDialog()\n",
    "url": "https://forum.freecadweb.org/viewtopic.php?f=19&t=49886",
    "raw_code_url": "",
    "wiki": "",
    "version": "0.0.4",
    "license": "",
    "date": "2021-04-30",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Sketcher\\SketcherOffset.FCMacro",
    "filename_from_url": "",
    "author": "edi",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "SketcherOffset.svg"
    ],
    "parsed": true
  },
  {
    "name": "SketchUnmap",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Unmap a sketch & makes its placement absolute\"",
    "code": "#!/usr/bin/python\n#####################################\n# Copyright (c) openBrain 2019\n# Licensed under LGPL v2\n#\n# This FreeCAD macro will unmap a sketch from eg. a face and make its placement absolute in the body. It proposes 3 options (forcely the first if sketch not in a body) :\n# * \"Raw\" mode => the sketch placement is made absolute in the body referential, nothing more\n# * \"DP@Face mode\" => a datum plane is created where the mapping face is, then the sketch is attached to it respecting its attachment offset\n# * \"DP@Sketch\" mode => a datum place is created where the sketch is (including attachment offset), then the sketch is attached to its origin\n#\n# Main use of the macro is to make design more robust to topological naming issue\n#\n# Version history :\n# *0.6.2 : add icon (metadata)\n# *0.6.1 : minor changes after PR review\n# *0.6 : some typo improvement + commenting for official PR\n# *0.5 : beta release\n#\n#####################################\n\n__Name__ = 'SketchUnmap'\n__Comment__ = 'Unmap a sketch & makes its placement absolute\"'\n__Author__ = 'openBrain'\n__Version__ = '0.6.2'\n__Date__ = '2019-06-14'\n__License__ = 'LGPL v2'\n__Web__ = 'https://www.freecadweb.org/wiki/Macro_SketchUnmap'\n__Wiki__ = 'https://www.freecadweb.org/wiki/Macro_SketchUnmap'\n__Icon__ = 'SketchUnmap.svg'\n__Help__ = 'Select the sketch to unmap (eg. in the tree view) then run the macro'\n__Status__ = 'Beta'\n__Requires__ = 'FreeCAD >= 0.17'\n__Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=22&t=36078'\n#    __Files__ = ''\n\n__dbg__ = False  #True for debugging\n\nfrom PySide import QtGui\n\ndef cslM(msg): #Print message in console\n    FreeCAD.Console.PrintMessage('\\n')\n    FreeCAD.Console.PrintMessage(msg)\n\ndef cslW(msg): #Print warning in console\n    FreeCAD.Console.PrintMessage('\\n')\n    FreeCAD.Console.PrintWarning(msg)\n\ndef cslE(msg): #Print error in console\n    FreeCAD.Console.PrintMessage('\\n')\n    FreeCAD.Console.PrintError(msg)\n\ndef cslD(msg): #Print debug message in console\n    if __dbg__:\n        FreeCAD.Console.PrintMessage('\\n')\n        FreeCAD.Console.PrintMessage(\"Debug : \" + str(msg))\n\n_0Vec_ = FreeCAD.Vector(0, 0, 0) #Shortener for null vector\n_ZVec_ = FreeCAD.Vector(0, 0, 1) #Shortener for Z axis\n\nif __dbg__:  ##Clear report view in debug mode\n    FreeCADGui.getMainWindow().findChild(QtGui.QTextEdit, \"Report view\").clear()\n\ncslM(\"Starting SketchUnmap macro\")\ncslD(\"Checking selection\")\n\n##If selection is wrong, print error message and exit\nif (len(Gui.Selection.getSelection()) != 1 or str(Gui.Selection.getSelection()[0]) != '<Sketcher::SketchObject>'):\n    cslE(\"You must select a sketch that you want to unmap (and only one) ... Exiting\")\nelse:\n    cslD(\"Selection OK\")\n    App.ActiveDocument.openTransaction(\"SketchUnmap\") #Open transaction for undo management\n    sk = Gui.Selection.getSelection()[0] #Get target sketch\n    skNatPl = sk.Placement #Store placement\n    skNatAO = sk.AttachmentOffset #Store attachment offset\n    skInBody = False\n    for obj in sk.InList: ##Check if sketch is inside a Body\n        if obj.TypeId == 'PartDesign::Body':\n            skInBody = True\n            skBody = obj\n    cslD(\"Sketch in a body : \" + str(skInBody))\n    msgb = QtGui.QMessageBox() ##Prepare the message box to choose option\n    msgb.setWindowTitle(\"Unmap Sketch : Mode selection\")\n    msgb.setText(\"\"\"Choose which unmapping mode you want to apply :\n    Raw => the sketch placement is made absolute in the body referential, nothing more\n    DP@Face => a datum plane is created where the mapping face is, then the sketch is attached to it respecting its attachment offset\n    DP@Sketch => a datum place is created where the sketch is (including attachment offset), then the sketch is attached to its origin\n        Click 'Cancel' to cancel operation\"\"\")\n    msgb.setIcon(QtGui.QMessageBox.Question)\n    rbut = msgb.addButton(\"Raw\", QtGui.QMessageBox.AcceptRole)\n    fbut = msgb.addButton(\"DP@Face\", QtGui.QMessageBox.AcceptRole)\n    sbut = msgb.addButton(\"DP@Sketch\", QtGui.QMessageBox.AcceptRole)\n    cbut = msgb.addButton(\"Cancel\", QtGui.QMessageBox.RejectRole)\n    if skInBody: #If sketch in a Body\n        msgb.exec_() ##Show message box and get user choice\n        msgbRep = msgb.clickedButton()\n    else:\n        msgbRep = rbut #Else apply raw mode automatically\n    if msgbRep == rbut: #If raw mode\n        sk.Support = None ##Just unmap the sketch so its placement is absolute\n        sk.MapMode = 'Deactivated'\n    elif msgbRep == fbut: #If DP@Face mode\n        newDP = skBody.newObject('PartDesign::Plane','DP' + sk.Name) #Create a datum plane\n        if sk.Label != sk.Name: ##Eventually clarify its label\n            newDP.Label = 'DP' + sk.Label\n        newDP.Support = None ##Plane is placed absolute\n        newDP.MapMode = 'Deactivated'\n        newDP.Placement = skNatPl.multiply(skNatAO.inverse()) #Plane placement is set to former face one\n        sk.Support = [(newDP,'')] #Sketch is mapped to plane keeping its attachment offset\n    elif  msgbRep == sbut: #If DP@Sketch mode\n        newDP = skBody.newObject('PartDesign::Plane','DP' + sk.Name) #Create a datum plane\n        if sk.Label != sk.Name: ##Eventually clarify its label\n            newDP.Label = 'DP' + sk.Label\n        newDP.Support = None ##Plane is placed absolute\n        newDP.MapMode = 'Deactivated'\n        newDP.Placement = skNatPl #Plane placement is set to former sketch one\n        sk.Support = [(newDP,'')] ##Sketch is mapped to plane resetting its attachment offset\n        sk.AttachmentOffset = App.Placement(_0Vec_, App.Rotation(_ZVec_, 0))\n    App.ActiveDocument.commitTransaction() #Commit transaction for undo management\n    cslM(\"SketchUnmap Macro ended correctly\")\n",
    "url": "https://www.freecadweb.org/wiki/Macro_SketchUnmap",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_SketchUnmap",
    "version": "0.6.2",
    "license": "",
    "date": "2019-06-14",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Sketcher\\SketchUnmap.FCMacro",
    "filename_from_url": "",
    "author": "openBrain",
    "icon": "SketchUnmap.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "LasercutterSVGExport",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Creates contour lines for all selected objects and arranges them on a TechDraw page",
    "code": "# -*- coding: utf-8 -*-\n\n__Name__ = 'LasercutterSVGExport'\n__Comment__ = 'Creates contour lines for all selected objects and arranges them on a TechDraw page'\n__Author__ = 'christi'\n__Version__ = '0.7.0'\n__Date__ = '2022-03-03'\n__License__ = 'LGPL-3.0-or-later'\n__Web__ = 'https://github.com/FreeCAD/FreeCAD-macros/tree/master/TechDraw'\n__Wiki__ = 'https://github.com/FreeCAD/FreeCAD-macros/tree/master/TechDraw/LasercutterSVGExport'\n__Icon__ = 'LasercutterSVGExport.svg'\n__Help__ = 'LasercutterSVGExport/README.md'\n__Status__ = 'Alpha'\n__Requires__ = 'FreeCAD >= v0.18'\n__Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=15&t=31796'\n__Files__ = 'LasercutterSVGExport/LasercutterTechdrawExport.py,LasercutterSVGExport/README.md,LasercutterSVGExport/LasercutterSVGExport_screenshot.png,LasercutterSVGExport/lasercuttersvg.ui,LasercutterSVGExport.svg'\n\n# compatible to Python 3\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nfrom LasercutterSVGExport import LasercutterTechdrawExport\n\niconPath = os.path.dirname(__file__)\n\n\nclass LasercutterSVGExport():\n    def Activated(self):\n        '''Will be called when the feature is executed.'''\n        self.ui_file = os.path.join(iconPath, 'LasercutterSVGExport', 'lasercuttersvg.ui')\n        self.form = gui.PySideUic.loadUi(self.ui_file)\n        self.form.pushButton.pressed.connect(self.makeExport)\n        self.form.show()\n\n    def IsActive(self):\n        '''Here you can define if the command must be active or not (greyed) if certain conditions\n        are met or not. This function is optional.'''\n        if app.activeDocument():\n            return(True)\n        else:\n            return(False)\n\n    def makeExport(self):\n        # Generate commands in the FreeCAD python console to create LasercutterTechdrawExport\n        gui.doCommand('from LasercutterSVGExport import LasercutterTechdrawExport')\n\n        gui.doCommand('lcparts = []')\n        selection = gui.Selection.getSelectionEx()\n        for sel in selection:\n            gui.doCommand(\"lcparts.append(FreeCAD.ActiveDocument.getObject('%s'))\"%(sel.ObjectName))\n\n        gui.doCommand(f'LasercutterTechdrawExport.makeLasercutterTechdrawExport(lcparts, BeamWidth={self.form.doubleSpinBox.value()}, doc=FreeCAD.activeDocument())')\n        self.form.close()\n\n\nif __name__ == '__main__':\n\tlc = LasercutterSVGExport()\n\tlc.Activated()\n",
    "url": "https://github.com/FreeCAD/FreeCAD-macros/tree/master/TechDraw",
    "raw_code_url": "",
    "wiki": "https://github.com/FreeCAD/FreeCAD-macros/tree/master/TechDraw/LasercutterSVGExport",
    "version": "0.7.0",
    "license": "",
    "date": "2022-03-03",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\TechDraw\\LasercutterSVGExport.FCMacro",
    "filename_from_url": "",
    "author": "christi",
    "icon": "LasercutterSVGExport.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "LasercutterSVGExport/LasercutterTechdrawExport.py",
      "LasercutterSVGExport/README.md",
      "LasercutterSVGExport/LasercutterSVGExport_screenshot.png",
      "LasercutterSVGExport/lasercuttersvg.ui",
      "LasercutterSVGExport.svg"
    ],
    "parsed": true
  },
  {
    "name": "TechDrawAnnoTextFromv018",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Convert v018 Annotation Text size to v019",
    "code": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n# ***************************************************************************\n# *                                                                         *\n# *   Copyright (c) 2022 - Wanderer Fan <wandererfan@gmail.com>             *\n# *                                                                         *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU Lesser General Public License (LGPL)    *\n# *   as published by the Free Software Foundation; either version 2 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENCE text file.                                 *\n# *                                                                         *\n# *   This program is distributed in the hope that it will be useful,       *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU Library General Public License for more details.                  *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with this program; if not, write to the Free Software   *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\"\"\"Migrates Annotation Text made in FreeCAD v0.18 to v0.19.\"\"\"\n\n__Name__ = 'TechDrawAnnoTextFromv018'\n__Comment__ = 'Convert v018 Annotation Text size to v019'\n__Author__ = 'WandererFan'\n__Version__ = '0.1.0'\n__License__ = 'CC-BY-3.0'\n__Web__ = 'http://www.freecadweb.org/'\n__Wiki__ = 'http://www.freecadweb.org/wiki/Macro_TechDrawAnnoTextFromv018'\n__Icon__ = ''\n__Help__ = 'Open a v018 file in v019, execute'\n__Status__ = 'Alpha'\n__Requires__ = ''\n__Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'\n__Files__ = ''\n\n# font sizes were once set using QFont.setPointSize but are now set using QFont.setPixelSize.\n# text set the old way will be bigger than text set the new way since points are bigger than\n# pixels.  This macro adjusts the text size in old files to give approximately the same size\n# result.\n\nimport FreeCAD as App\nimport TechDraw\n\ndef TechDrawAnnoTextFromv018():\n    factor = 96.0/72.0    # pixels/inch vs points/inch\n    for obj in App.ActiveDocument.Objects:\n        if obj.isDerivedFrom(\"TechDraw::DrawViewAnnotation\"):\n            oldSize = obj.TextSize\n            obj.TextSize = oldSize * factor\n        if obj.isDerivedFrom(\"TechDraw::DrawViewDimension\"):\n            oldSize = obj.ViewObject.Fontsize\n            obj.ViewObject.Fontsize = oldSize * factor\n        if obj.isDerivedFrom(\"TechDraw::DrawViewBalloon\"):\n            oldSize = obj.ViewObject.Fontsize\n            obj.ViewObject.Fontsize = oldSize * factor\n\n\nif __name__ == '__main__':\n    TechDrawAnnoTextFromv018()\n    App.ActiveDocument.recompute()\n\n",
    "url": "http://www.freecadweb.org/",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/Macro_TechDrawAnnoTextFromv018",
    "version": "0.1.0",
    "license": "",
    "date": "",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\TechDraw\\TechDrawAnnoTextFromv018.FCMacro",
    "filename_from_url": "",
    "author": "WandererFan",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "TechDrawMigrateFromv018",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Convert v018 Rotation property to v019",
    "code": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n# ***************************************************************************\n# *                                                                         *\n# *   Copyright (c) 2022 - Wanderer Fan <wandererfan@gmail.com>             *\n# *                                                                         *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU Lesser General Public License (LGPL)    *\n# *   as published by the Free Software Foundation; either version 2 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENCE text file.                                 *\n# *                                                                         *\n# *   This program is distributed in the hope that it will be useful,       *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU Library General Public License for more details.                  *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with this program; if not, write to the Free Software   *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\"\"\"Migrates drawings made in FreeCAD v0.18 to v0.19.\"\"\"\n\n__Name__ = 'TechDrawMigrateFromv018'\n__Comment__ = 'Convert v018 Rotation property to v019'\n__Author__ = 'WandererFan'\n__Version__ = '0.1.0'\n__License__ = 'CC-BY-3.0'\n__Web__ = 'http://www.freecadweb.org/'\n__Wiki__ = 'http://www.freecadweb.org/wiki/Macro_TechDrawViewSet'\n__Icon__ = ''\n__Help__ = 'Open a v018 file in v019, execute'\n__Status__ = 'Alpha'\n__Requires__ = ''\n__Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'\n__Files__ = ''\n\n\n# convert v0.18 Rotation values to v0.19\n\nimport FreeCAD as App\nimport TechDraw\n\ndef TechDrawMigrateFromv018():\n    increment = App.Units.Quantity(270, App.Units.Unit(\"deg\"))\n    for obj in App.ActiveDocument.Objects:\n        if obj.isDerivedFrom(\"TechDraw::DrawViewSection\"):\n            if obj.Rotation != 0.0:\n                obj.Rotation = obj.Rotation + increment\n                obj.touch()\n            for inObj in obj.InList:\n                if obj.isDerivedFrom(\"TechDraw::DrawViewDimension\"):\n                    inObj.touch()\n        elif obj.isDerivedFrom(\"TechDraw::DrawViewPart\"):\n            if obj.Rotation != 0.0:\n                obj.Rotation = -obj.Rotation\n                obj.touch()\n\n\nif __name__ == '__main__':\n    TechDrawMigrateFromv018()\n    App.ActiveDocument.recompute()\n\n",
    "url": "http://www.freecadweb.org/",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/Macro_TechDrawViewSet",
    "version": "0.1.0",
    "license": "",
    "date": "",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\TechDraw\\TechDrawMigrateFromv018.FCMacro",
    "filename_from_url": "",
    "author": "WandererFan",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "TechDrawSymbolsLibrary",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "",
    "code": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#***************************************************************************\n#*                                                                         *\n#*   Copyright (c) 2018 Chakkree Tiyawongsuwan                             *\n#*   Copyright (c) 2015 Yorik van Havre <yorik@uncreated.net>              *\n#*                                                                         *\n#*   This program is free software; you can redistribute it and/or modify  *\n#*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n#*   as published by the Free Software Foundation; either version 2 of     *\n#*   the License, or (at your option) any later version.                   *\n#*   for detail see the LICENCE text file.                                 *\n#*                                                                         *\n#*   This program is distributed in the hope that it will be useful,       *\n#*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n#*   GNU Library General Public License for more details.                  *\n#*                                                                         *\n#*   You should have received a copy of the GNU Library General Public     *\n#*   License along with this program; if not, write to the Free Software   *\n#*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n#*   USA                                                                   *\n#*                                                                         *\n#***************************************************************************\n\"\"\"\nFreeCAD Symbols Library import macro\n\nINSTALLATION\n\nThis script is made to be used as a FreeCAD macro, and to be placed\ninside your macros  (default is $HOME/.FreeCAD/Macro on mac/linux,\nC:/Users/youruser/Application Data/FreeCAD/Macro on windows).\n\nAfter it is installed on the above location, it will be available\nin the macros menu.\n\nOn first launch, you'll be ask to point to the directory where your symbols\nare.\nIf you wish, you can use the official symbols library\nhttps://github.com/FreeCAD/FreeCAD-symbols.\nRun 'git clone --recursive https://github.com/FreeCAD/FreeCAD-symbols.git'\nin a terminal and then point to the created directory 'FreeCAD-symbols'.\n\nUSAGE\n\nThis macro adds a browser window to the FreeCAD interface, from\nwhich you can browse and add items from the library to the current TechDraw\npage by double clicking.\n\"\"\"\nfrom __future__ import division\n\n__Name__ = 'FreeCAD Symbols Library'\n__Author__ = 'Yorik van Havre, Chakkree Tiyawongsuwan, Ga\u00ebl \u00c9corchard'\n__Version__ = '1.0'\n__Date__ = '2018-05-29'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'http://www.freecadweb.org'\n__Wiki__ = ''\n__Icon__ = ''\n__Help__ = 'Launch and double-click to insert a symbol in the current TechDraw page'\n__Status__ = ''\n__Requires__ = 'FreeCAD v0.17+'\n__Communication__ = ''\n__Files__ = ''\n\nimport os\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nfrom PySide import QtGui, QtCore, QtSvg\n\n\ndef get_library_path(force_ask=False, parent=None):\n    \"\"\"Get the user parameter for the library path\n\n    Get the user parameter for the library path (parameter\n    \"Plugins/symbols_library/destination\"). In the case that the parameter\n    isn't defined or that it points to a non-existing directory or that\n    force_ask is True, a dialog opens to set a new path, which is then saved as\n    FreeCAD preference.\n    \"\"\"\n    param = app.ParamGet('User parameter:Plugins/symbols_library')\n    s = param.GetString('destination')\n\n    if not force_ask and s and QtCore.QDir(s).exists():\n        return s\n\n    folderDialog = QtGui.QFileDialog.getExistingDirectory(parent,\n        QtGui.QApplication.translate(\"SymbolsLibrary\", \"Location of your existing Symbols library\", None, QtGui.QApplication.UnicodeUTF8))\n    param.SetString('destination', folderDialog)\n    return param.GetString('destination')\n\n\ndef get_symbol_label(path=None):\n    if not path:\n        return 'Symbol'\n    return 'Symbol_' + os.path.splitext(os.path.basename(path))[0]\n\n\nclass AspectRatioSvgWidget(QtSvg.QSvgWidget):\n    \"\"\"A QSvgWidget preserving aspect ratio\n\n    From http://lists.qt-project.org/pipermail/pyside/2013-March/001207.html.\n    \"\"\"\n    def paintEvent(self, paint_event):\n        painter = QtGui.QPainter(self)\n        default_width, default_height = self.renderer().defaultSize().toTuple()\n        widget_width, widget_height = self.size().toTuple()\n        ratio_x = widget_width / default_width\n        ratio_y = widget_height / default_height\n        if ratio_x < ratio_y:\n            new_width = widget_width\n            new_height = widget_width * default_height / default_width\n            new_left = 0\n            new_top = (widget_height - new_height) / 2\n        else:\n            new_width = widget_height * default_width / default_height\n            new_height = widget_height\n            new_left = (widget_width - new_width) / 2\n            new_top = 0\n        self.renderer().render(painter, QtCore.QRectF(new_left, new_top, new_width, new_height))\n\n\nclass ExpDockWidget(QtGui.QDockWidget):\n    \"\"\"A library explorer dock widget\"\"\"\n\n    def __init__(self, library_path):\n        QtGui.QDockWidget.__init__(self)\n\n        self.setObjectName('SymbolsLibrary')\n        self.setWindowTitle('Symbols Library')\n\n        # setting up a directory model that shows only svg files\n        self.dirmodel = QtGui.QFileSystemModel()\n        self.dirmodel.setRootPath(library_path)\n        self.dirmodel.setNameFilters(['*.svg', '*.SVG'])\n        self.dirmodel.setNameFilterDisables(0)\n\n        container = QtGui.QWidget()\n        layout = QtGui.QVBoxLayout(container)\n        self.folder = QtGui.QTreeView();\n        self.folder.setModel(self.dirmodel)\n        self.folder.clicked[QtCore.QModelIndex].connect(self.clicked)\n        self.folder.doubleClicked[QtCore.QModelIndex].connect(self.doubleclicked)\n        # Don't show columns for size, file type, and last modified\n        self.folder.setHeaderHidden(True)\n        self.folder.hideColumn(1)\n        self.folder.hideColumn(2)\n        self.folder.hideColumn(3)\n        self.folder.setRootIndex(self.dirmodel.index(library_path))\n        layout.addWidget(self.folder)\n        self.preview = AspectRatioSvgWidget()\n        self.preview.setFixedHeight(128)\n        self.preview.setFixedWidth(128)\n        layout.addWidget(self.preview)\n        self.configbutton = QtGui.QPushButton()\n        self.configbutton.setText('Change path')\n        self.configbutton.clicked.connect(self.changepath)\n        layout.addWidget(self.configbutton)\n        layout.setAlignment(self.preview, QtCore.Qt.AlignHCenter)\n        self.setWidget(container)\n\n    def clicked(self, index):\n        path = self.dirmodel.filePath(index)\n        if path.lower().endswith('.svg'):\n            self.preview.load(path)\n            self.preview.show()\n            return\n        self.preview.hide()\n\n    def changepath(self):\n        library_path = get_library_path(force_ask=True, parent=self)\n        self.dirmodel.setRootPath(library_path)\n        self.folder.setRootIndex(self.dirmodel.index(library_path))\n\n    def doubleclicked(self, index):\n        doc = app.activeDocument()\n        if doc is None:\n            app.Console.PrintWarning(\n                QtGui.QApplication.translate('SymbolsLibrary', 'No active document, doing nothing\\n'))\n            return\n\n        path = self.dirmodel.filePath(index)\n        page = None\n        for o in gui.Selection.getSelection():\n            if o.isDerivedFrom('Drawing::FeaturePage'):\n                page = o\n                break\n            if o.isDerivedFrom('TechDraw::DrawPage'):\n                page = o\n                break\n        if not page:\n            page_count = 0\n            for o in doc.Objects:\n                if o.isDerivedFrom('Drawing::FeaturePage'):\n                    page = o\n                    page_count += 1\n                if o.isDerivedFrom('TechDraw::DrawPage'):\n                    page = o\n                    page_count += 1\n            if page_count > 1:\n                app.Console.PrintWarning(\n                    QtGui.QApplication.translate('SymbolsLibrary', 'More than one page, cannot decide where to insert symbol\\n'))\n                return\n\n        if not page:\n            app.Console.PrintWarning(\n                QtGui.QApplication.translate('SymbolsLibrary', 'No page found either in the selection or the document\\n'))\n            return\n\n        f = open(path)\n        svg = f.read()\n        f.close()\n        label = get_symbol_label(path)\n        if page.isDerivedFrom('Drawing::FeaturePage'):\n            import Drawing\n            s = doc.addObject('Drawing::FeatureViewSymbol', label)\n            s.Symbol = Drawing.removeSvgTags(svg)\n            page.addObject(s)\n        if page.isDerivedFrom('TechDraw::DrawPage'):\n            symbol = doc.addObject('TechDraw::DrawViewSymbol', label)\n            symbol.Symbol = svg\n            page.addView(symbol)\n        doc.recompute()\n\ndef main():\n    m = gui.getMainWindow()\n    w = m.findChild(QtGui.QDockWidget, 'SymbolsLibrary')\n    if w:\n        if w.isVisible():\n            w.hide()\n        else:\n            w.show()\n    else:\n        m.addDockWidget(QtCore.Qt.RightDockWidgetArea,\n                        ExpDockWidget(get_library_path()))\n\nif __name__ == '__main__':\n    main()\n",
    "url": "http://www.freecadweb.org",
    "raw_code_url": "",
    "wiki": "",
    "version": "1.0",
    "license": "",
    "date": "2018-05-29",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\TechDraw\\TechDrawSymbolsLibrary.FCMacro",
    "filename_from_url": "",
    "author": "Yorik van Havre, Chakkree Tiyawongsuwan, Ga\u00ebl \u00c9corchard",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "TechDrawTools",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "A container, including 38 helper tools to improve the appearance of drawings",
    "code": "\"\"\"\nThis macro is a container, including 38 helper tools to improve the appearance\nof drawings created in the TechDraw workbench. There are tools to:\n- create circle and bolt cicle center lines\n- draw cosmetic threads in ground and side view\n- create vertexes at intersection of elements\n- change attributes of center lines and cosmetic lines\n- change the number of decimal places of the dimension value\n- append special characters ahead of dimension values\n- create chain- and coordinate dimensions\n- position and cascade dimensions\n- create dimension/development of arches\n- create cosmetic circumferences\n- create a line cosmetic perpendicular\n- create a line cosmetic parallel\n- create a hole table\n- extend and shorten cosmetic lines\n- create a cosmetic line arch\n- position section view orthogonal to ancestor view\n- create an annotation showing the area\n\nAll written user informations appear in English/German/Italian/French/Spanish\ndepending on the selected FreeCAD language.\n\nWorkflow:\n- Start the macro\n- Select the desired line attributes and cascade spacing\n- Select any helper tool\n\"\"\"\n\n__Name__ = 'TechDrawTools'\n__Author__ = 'edi and domad'\n__Version__ = '0.4.5'\n__Comment__ = 'A container, including 38 helper tools to improve the appearance of drawings'\n__License__ = 'LGPL v2'\n__Web__ = 'https://forum.freecadweb.org/viewtopic.php?f=35&t=59334'\n__Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/blob/master/TechDraw/TechDrawTools.FCMacro'\n__Files__ = 'TechDrawTools.svg'\n__Help__ = 'Start the macro. Select one of the 38 helper tools.'\n__Status__ = 'stable'\n__Requires__ = 'e.g. FreeCAD >= v0.19'\n__Date__ = '2022-03-26'\n\n\nfrom functools import partial\nimport math\n\nfrom PySide import QtCore, QtGui  # FreeCAD's special PySide!\nimport FreeCAD as app\nimport FreeCADGui as gui\nimport TechDraw\n\n\nclass LineAttributes:\n    '''Operate all line attributes'''\n    Colors = {\n        'black':   ((0.0, 0.0, 0.0, 0.0), '000000'),\n        'grey':    ((0.7, 0.7, 0.7, 0.0), 'b6b6b6'),\n        'red':     ((1.0, 0.0, 0.0, 0.0), 'ff0000'),\n        'green':   ((0.0, 1.0, 0.0, 0.0), '00ff00'),\n        'blue':    ((0.0, 0.0, 1.0, 0.0), '0000ff'),\n        'magenta': ((1.0, 0.0, 1.0, 0.0), 'ff00ff'),\n        'cyan':    ((0.0, 1.0, 1.0, 0.0), '00ffff'),\n        'yellow':  ((1.0, 1.0, 0.0, 0.0), 'ffff00'),\n    }\n    Styles = {'solid': 1, 'dashed':2, 'dotted':3,'dashdot':4}\n    Width = {'thick 0,70': 0.70, 'middle 0,35': 0.35, 'thin 0,18': 0.18}\n\n    def __init__(self):\n        self.LineColor =  self.Colors['black']\n        self.LineStyle = self.Styles['dashdot']\n        self.LineWidth = self.Width['middle 0,35']\n\n    def setColor(self,Color):\n        self.LineColor = self.Colors[Color]\n\n    def getColorTuple(self):\n        return self.LineColor[0]\n\n    def getColorHex(color):\n        return LineAttributes.Colors[color][1]\n\n    def setStyle(self,Style):\n        self.LineStyle = self.Styles[Style]\n\n    def getStyle(self):\n        return self.LineStyle\n\n    def setWidth(self,Width):\n        self.LineWidth = self.Width[Width]\n\n    def getWidth(self):\n        return self.LineWidth\n\nclass translate:\n    '''do all translations'''\n    def __init__(self):\n        self.langKey = self.getLanguage()\n\n    def getLanguage(self):\n        '''get local language key'''\n        langDict = {}\n        langDict[\"English\"] = 'English'\n        langDict[\"German\"] = 'German'\n        langDict[\"Italian\"] = 'Italian'\n        langDict[\"French\"] = 'French'\n        langDict[\"Spanish\"] = 'Spanish'\n        self.langKey = 'English'\n        if gui.getLocale() in langDict.keys():\n            self.langKey = langDict[gui.getLocale()]\n        return self.langKey\n\n    def tr(self,textEnglish):\n        if self.langKey == 'English':\n            return self.englishDict(textEnglish)\n        elif self.langKey == 'German':\n            return self.germanDict(textEnglish)\n        elif self.langKey == 'Italian':\n            return self.italianDict(textEnglish)\n        elif self.langKey == 'French':\n            return self.frenchDict(textEnglish)\n        elif self.langKey == 'Spanish':\n            return self.spanishDict(textEnglish)\n\n    def englishDict(self,textEnglish):\n        return textEnglish\n\n    def germanDict(self,textEnglish):\n        dict_ = {\"Attributes and Modifications\":\"Eigenschaften und \u00c4nderungen\",\\\n                \"Centerlines and Threading\":\"Mittellinien und Gewinde\",\\\n                \"Dimensions\":\"Bema\u00dfungen\",\\\n                \"Line attributes:\":\"Eigenschaften:\",\\\n                \"Cascade spacing:\":\"Abstand Kaskadierung\",\\\n                \"Quit\":\"Fertig\",\\\n                \"set lines to \":\"setze Linie auf \",\\\n                \"solid\":\"Vollinie\",\\\n                \"dashed\":\"strichliert\",\\\n                \"dotted\":\"punktiert\",\\\n                \"dashdot\":\"strich-punkt\",\\\n                \"set lines width to \":\"setze Linienbreite auf \",\\\n                \"thick 0,70\":\"breit 0,70\",\\\n                \"middle 0,35\":\"mittel 0,35\",\\\n                \"thin 0,18\":\"schmal 0,18\",\\\n                \"set lines color to \":\"setze Linienfarbe auf \",\\\n                \"black\":\"schwarz\",\\\n                \"grey\":\"grau\",\\\n                \"red\":\"rot\",\\\n                \"green\":\"gr\u00fcn\",\\\n                \"blue\":\"blau\",\\\n                \"magenta\":\"magenta\",\\\n                \"cyan\":\"cyan\",\\\n                \"yellow\":\"gelb\"}\n        return dict_.get(textEnglish,textEnglish)\n\n    def italianDict(self,textEnglish):\n        dict_ = {\"Attributes and Modifications\":\"Strumenti di editing\",\\\n                \"Centerlines and Threading\":\"Mezzerie e filettature\",\\\n                \"Dimensions\":\"Quotature\",\\\n                \"Line attributes:\":\"Attributi:\",\\\n                \"Cascade spacing:\":\"Valore distanziamento:\",\\\n                \"Quit\":\"Chiudi\",\\\n                \"set lines to \":\"tipo di linea \",\\\n                \"solid\":\"solida\",\\\n                \"dashed\":\"tratteggiata\",\\\n                \"dotted\":\"a punti\",\\\n                \"dashdot\":\"tratto e punto\",\\\n                \"set lines width to \":\"spessore linea \",\\\n                \"thick 0,70\":\"spessa 0,70\",\\\n                \"middle 0,35\":\"media 0,35\",\\\n                \"thin 0,18\":\"sottile 0,18\",\\\n                \"set lines color to \":\"colore linea \",\\\n                \"black\":\"nero\",\\\n                \"grey\":\"grigio\",\\\n                \"red\":\"rosso\",\\\n                \"green\":\"verde\",\\\n                \"blue\":\"azzurro\",\\\n                \"magenta\":\"magenta\",\\\n                \"cyan\":\"ciano\",\\\n                \"yellow\":\"giallo\"}\n        return dict_.get(textEnglish,textEnglish)\n\n    def frenchDict(self,textEnglish):\n        dict_ = {\"Attributes and Modifications\":\"Outils d'\u00e9dition\",\\\n                \"Centerlines and Threading\":\"Lignes m\u00e9dianes et filettage\",\\\n                \"Dimensions\":\"Dimensionnement\",\\\n                \"Line attributes:\":\"Les attributs:\",\\\n                \"Cascade spacing:\":\"Valeur d'espacement:\",\\\n                \"Quit\":\"Fermez\",\\\n                \"set lines to \":\"type de ligne \",\\\n                \"solid\":\"solide\",\\\n                \"dashed\":\"pointill\u00e8\",\\\n                \"dotted\":\"en points\",\\\n                \"dashdot\":\"trait et point\",\\\n                \"set lines width to \":\"\u00e9paisseur de ligne \",\\\n                \"thick 0,70\":\"\u00e9pais 0,70\",\\\n                \"middle 0,35\":\"moyen 0,35\",\\\n                \"thin 0,18\":\"mince 0,18\",\\\n                \"set lines color to \":\"couleur de la ligne \",\\\n                \"black\":\"noir\",\\\n                \"grey\":\"gris\",\\\n                \"red\":\"rouge\",\\\n                \"green\":\"vert\",\\\n                \"blue\":\"bleu\",\\\n                \"magenta\":\"magenta\",\\\n                \"cyan\":\"cyan\",\\\n                \"yellow\":\"Jaune\"}\n        return dict_.get(textEnglish,textEnglish)\n\n    def spanishDict(self,textEnglish):\n        dict_ = {\"Attributes and Modifications\":\"Herramientas de edici\u00f3n\",\\\n                \"Centerlines and Threading\":\"L\u00edneas centrales y roscado\",\\\n                \"Dimensions\":\"Dimensionamiento\",\\\n                \"Line attributes:\":\"Atributos:\",\\\n                \"Cascade spacing:\":\"Valor de espaciado:\",\\\n                \"Quit\":\"Cerrar\",\\\n                \"set lines to \":\"tipo de l\u00ednea \",\\\n                \"solid\":\"s\u00f3lido\",\\\n                \"dashed\":\"punteado\",\\\n                \"dotted\":\"en puntos\",\\\n                \"dashdot\":\"trazo y punto\",\\\n                \"set lines width to \":\"grosor de la l\u00ednea \",\\\n                \"thick 0,70\":\"m\u00e1s grueso 0,70\",\\\n                \"middle 0,35\":\"promedio 0,35\",\\\n                \"thin 0,18\":\"delgada 0,18\",\\\n                \"set lines color to \":\"color de linea \",\\\n                \"black\":\"negro\",\\\n                \"grey\":\"gris\",\\\n                \"red\":\"rojo\",\\\n                \"green\":\"verde\",\\\n                \"blue\":\"azul\",\\\n                \"magenta\":\"magenta\",\\\n                \"cyan\":\"cian\",\\\n                \"yellow\":\"amarillo\"}\n        return dict_.get(textEnglish,textEnglish)\n\nclass DimensionAttributes:\n    '''Operate all dimension attributes'''\n    def __init__(self):\n        self.DimLineDistance = 7\n\n    def getDimLineDistance(self):\n        return self.DimLineDistance\n\nclass commandWidget(QtGui.QWidget):\n    '''Widget containing the command buttons'''\n    def __init__(self):\n        super().__init__()\n\n    def oneCommandButton(self,cmd,win):\n        '''Create a command push button'''\n        Button = QtGui.QPushButton()\n        Text = cmd.textEnglish()\n        if Lang.langKey == 'German'  and hasattr(cmd,\"textGerman\"):\n            Text = cmd.textGerman()\n        elif Lang.langKey == 'Italian' and hasattr(cmd,\"textItalian\"):\n            Text = cmd.textItalian()\n        elif Lang.langKey == 'French' and hasattr(cmd,\"textFrench\"):\n            Text = cmd.textFrench()\n        elif Lang.langKey == 'Spanish' and hasattr(cmd,\"textSpanish\"):\n            Text = cmd.textSpanish()\n        Button.setText(Text[0])\n        Button.setToolTip(Text[1])\n        if hasattr(cmd,\"Icon\"):\n            Button.setIcon(QtGui.QIcon(cmd.Icon))\n        Button.clicked.connect(partial(win.on_PB_clicked,cmd))\n        self.layout.addWidget(Button)\n\nclass DialogContainer(QtGui.QDialog):\n\n    def __init__(self, parent=gui.getMainWindow()):\n        ''' constructor creating a permanent opened dialog window'''\n        super().__init__(parent, QtCore.Qt.Tool)\n        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)\n        self.setAttribute(QtCore.Qt.WA_WindowPropagation, True)\n        self.setObjectName(\"DialogContainer\")\n        self.initUI()\n\n    def radioButton(self,Box,Slot,Tip,Text,Color='black',Checked = False,Row=-1,Column=-1):\n        ''' create a radio button '''\n        Button = QtGui.QRadioButton(Box)\n        if Checked:\n            Button.setMouseTracking(True)\n            Button.setChecked(True)\n        Button.setText(Lang.tr(Text))\n        Button.setStyleSheet(\"color : #\"+LineAttributes.getColorHex(Color))\n        Button.setToolTip(Lang.tr(Tip)+Lang.tr(Text))\n        Button.clicked.connect(partial(Slot,Text))\n        if Row == -1:\n            Box.layout.addWidget(Button)\n        else:\n            Box.layout.addWidget(Button,Row,Column)\n\n    def initUI(self):\n        \"\"\"Specifically handles the UI initialization\"\"\"\n        self.setWindowTitle(\"TechDrawTools V- \"+__Version__+\"-multilanguage\")\n        self.layout = QtGui.QVBoxLayout(self)\n        # Initialize tab screen\n        self.tabs = QtGui.QTabWidget()\n        self.tabs.setTabPosition(QtGui.QTabWidget.East)\n        self.tabs.setTabShape(QtGui.QTabWidget.Triangular)\n        self.tab1 = QtGui.QWidget()\n        self.tabs.addTab(self.tab1,Lang.tr(\"Attributes and Modifications\"))\n        self.tab2 = commandWidget()\n        self.tabs.addTab(self.tab2,Lang.tr(\"Centerlines and Threading\"))\n        self.tab3 = commandWidget()\n        self.tabs.addTab(self.tab3,Lang.tr(\"Dimensions\"))\n        # Create layouts of tab1\n        self.tab1.layout = QtGui.QVBoxLayout()\n        self.topBox1 = commandWidget()\n        self.topBox1.layout =QtGui.QVBoxLayout()\n        self.bottomBox = QtGui.QWidget()\n        self.bottomBox.layout =QtGui.QHBoxLayout()\n        self.bottomBoxLeftTop = QtGui.QGroupBox(Lang.tr(\"Line attributes:\"))\n        self.bottomBoxLeftTop.layout =QtGui.QVBoxLayout()\n        self.bottomBoxLeftBottom = QtGui.QGroupBox()\n        self.bottomBoxLeftBottom.layout =QtGui.QVBoxLayout()\n        self.bottomBoxRight = QtGui.QGroupBox()\n        self.bottomBoxRight.layout =QtGui.QGridLayout()\n        # Create layouts of tab2\n        self.tab2.layout = QtGui.QVBoxLayout()\n        self.topBox2 = commandWidget()\n        self.topBox2.layout =QtGui.QVBoxLayout()\n        self.bottomBox2 = QtGui.QWidget()\n        self.bottomBox2.layout =QtGui.QHBoxLayout()\n        self.spinContainerBox = QtGui.QWidget()\n        self.spinContainerBox.layout =QtGui.QHBoxLayout()\n        # Create layouts of tab3\n        self.tab3.layout = QtGui.QVBoxLayout()\n        self.topBox3 = commandWidget()\n        self.topBox3.layout =QtGui.QVBoxLayout()\n\n        # Radio buttons for line attributes --------------------------------------------\n\n        self.radioButton(self.bottomBoxLeftTop,self.on_RB_ChangeStyle_Clicked,\"set lines to \",\"solid\")\n        self.radioButton(self.bottomBoxLeftTop,self.on_RB_ChangeStyle_Clicked,\"set lines to \",\"dashed\")\n        self.radioButton(self.bottomBoxLeftTop,self.on_RB_ChangeStyle_Clicked,\"set lines to \",\"dotted\")\n        self.radioButton(self.bottomBoxLeftTop,self.on_RB_ChangeStyle_Clicked,\"set lines to \",\"dashdot\",\"black\",True)\n\n        self.radioButton(self.bottomBoxLeftBottom,self.on_RB_ChangeWidth_Clicked,\"set lines width to \",\"thick 0,70\")\n        self.radioButton(self.bottomBoxLeftBottom,self.on_RB_ChangeWidth_Clicked,\"set lines width to \",\"middle 0,35\",\"black\",True)\n        self.radioButton(self.bottomBoxLeftBottom,self.on_RB_ChangeWidth_Clicked,\"set lines width to \",\"thin 0,18\")\n\n        self.radioButton(self.bottomBoxRight,self.on_RB_ChangeColor_Clicked,\"set lines color to \",\"black\",\"black\",True,0,0)\n        self.radioButton(self.bottomBoxRight,self.on_RB_ChangeColor_Clicked,\"set lines color to \",\"grey\",\"grey\",False,1,0)\n        self.radioButton(self.bottomBoxRight,self.on_RB_ChangeColor_Clicked,\"set lines color to \",\"red\",\"red\",False,2,0)\n        self.radioButton(self.bottomBoxRight,self.on_RB_ChangeColor_Clicked,\"set lines color to \",\"green\",\"green\",False,3,0)\n        self.radioButton(self.bottomBoxRight,self.on_RB_ChangeColor_Clicked,\"set lines color to \",\"blue\",\"blue\",False,0,1)\n        self.radioButton(self.bottomBoxRight,self.on_RB_ChangeColor_Clicked,\"set lines color to \",\"magenta\",\"magenta\",False,1,1)\n        self.radioButton(self.bottomBoxRight,self.on_RB_ChangeColor_Clicked,\"set lines color to \",\"cyan\",\"cyan\",False,2,1)\n        self.radioButton(self.bottomBoxRight,self.on_RB_ChangeColor_Clicked,\"set lines color to \",\"yellow\",\"yellow\",False,3,1)\n\n        # Button: Quit in  centralWidget -------------------------------------------------------------\n        self.PB_Quit = QtGui.QPushButton(self)\n        self.PB_Quit.setText(Lang.tr(\"Quit\"))\n        self.PB_Quit.clicked.connect(self.on_PB_Quit_clicked)\n        # insert buttons into tab 1\n        self.topBox1.oneCommandButton(extendLine(),self)\n        self.topBox1.oneCommandButton(shortenLine(),self)\n        self.topBox1.oneCommandButton(changeLockPosition(),self)\n        self.topBox1.oneCommandButton(positionSectionView(),self)\n        self.topBox1.oneCommandButton(positionHorizDimChain(),self)\n        self.topBox1.oneCommandButton(positionVertDimChain(),self)\n        self.topBox1.oneCommandButton(positionObliqueDimChain(),self)\n        self.topBox1.oneCommandButton(cascadeHorizDimensions(),self)\n        self.topBox1.oneCommandButton(cascadeVertDimensions(),self)\n        self.topBox1.oneCommandButton(cascadeObliqueDimension(),self)\n        self.topBox1.oneCommandButton(ChangeLineStyle(),self)\n        self.topBox1.setLayout(self.topBox1.layout)\n        self.bottomBoxLeftTop.setLayout(self.bottomBoxLeftTop.layout)\n        self.bottomBoxRight.setLayout(self.bottomBoxRight.layout)\n        self.bottomBoxLeftBottom.setLayout(self.bottomBoxLeftBottom.layout)\n        self.bottomBox.layout.addWidget(self.bottomBoxLeftTop)\n        self.bottomBox.layout.addWidget(self.bottomBoxLeftBottom)\n        self.bottomBox.layout.addWidget(self.bottomBoxRight)\n        self.bottomBox.setLayout(self.bottomBox.layout)\n        # create spin label to define cascade spacing\n        self.spinLabel = QtGui.QLabel(Lang.tr(\"Cascade spacing:\"))\n        self.SpinBox = QtGui.QSpinBox()\n        self.SpinBox.setValue(7)\n        self.SpinBox.valueChanged.connect(self.on_SB_clicked)\n        self.spinContainerBox.layout.addWidget(self.spinLabel)\n        self.spinContainerBox.layout.addWidget(self.SpinBox)\n        self.spinContainerBox.setLayout(self.spinContainerBox.layout)\n        self.tab1.layout.addWidget(self.topBox1)\n        self.tab1.layout.addWidget(self.bottomBox)\n        self.tab1.layout.addWidget(self.spinContainerBox)\n        self.tab1.layout.addWidget(self.PB_Quit)\n        self.tab1.setLayout(self.tab1.layout)\n        # insert buttons into tab 2\n        self.topBox2.oneCommandButton(CircleCenterLines(),self)\n        self.topBox2.oneCommandButton(DrawHoleCircle(),self)\n        self.topBox2.oneCommandButton(IntersectionVertex(),self)\n        self.topBox2.oneCommandButton(drawArc(),self)\n        self.topBox2.oneCommandButton(drawCirc(),self)\n        self.topBox2.oneCommandButton(drawPerpendicular(),self)\n        self.topBox2.oneCommandButton(drawParallel(),self)\n        self.topBox2.oneCommandButton(CenterLine(),self)\n        self.topBox2.oneCommandButton(DrawCosmeticThreadHole(),self)\n        self.topBox2.oneCommandButton(DrawCosmeticThreadBolt(),self)\n        self.topBox2.oneCommandButton(DrawCosmeticThreadSideHole(),self)\n        self.topBox2.oneCommandButton(DrawCosmeticThreadSideBolt(),self)\n        self.topBox2.setLayout(self.topBox2.layout)\n        self.tab2.layout.addWidget(self.topBox2)\n        self.tab2.setLayout(self.tab2.layout)\n        # insert buttons into tab 3\n        self.topBox3.oneCommandButton(drawDiameterSign(),self)\n        self.topBox3.oneCommandButton(drawRectangleSign(),self)\n        self.topBox3.oneCommandButton(createHorizDimChain(),self)\n        self.topBox3.oneCommandButton(createVertDimChain(),self)\n        self.topBox3.oneCommandButton(createObliqueDimChain(),self)\n        self.topBox3.oneCommandButton(createHorizCoordDim(),self)\n        self.topBox3.oneCommandButton(createVertCoordDim(),self)\n        self.topBox3.oneCommandButton(createObliqueCoordDim(),self)\n        self.topBox3.oneCommandButton(createHorizChamferDim(),self)\n        self.topBox3.oneCommandButton(createVertChamferDim(),self)\n        self.topBox3.oneCommandButton(createArcLengthDim(),self)\n        self.topBox3.oneCommandButton(holeTable(),self)\n        self.topBox3.oneCommandButton(increaseComma(),self)\n        self.topBox3.oneCommandButton(decreaseComma(),self)\n        self.topBox3.oneCommandButton(areaAnnot(),self)\n        self.topBox3.setLayout(self.topBox3.layout)\n        self.tab3.layout.addWidget(self.topBox3)\n        self.tab3.setLayout(self.tab3.layout)\n        # Add tabs to widget\n        self.layout.addWidget(self.tabs)\n\n# slots --------------------------------------------------------------------------------------------------\n\n    def on_SB_clicked(self):\n        ''' Spinbox value changed'''\n        DimAttrib.DimLineDistance = self.SpinBox.value()\n\n    def on_PB_clicked(self,cmd):\n        ''' Command Push Button clicked  '''\n        cmd.activated()\n\n    def on_RB_ChangeStyle_Clicked(self,style):\n        Attrib.setStyle(style)\n\n    def on_RB_ChangeWidth_Clicked(self,width):\n        Attrib.setWidth(width)\n\n    def on_RB_ChangeColor_Clicked(self,color):\n        Attrib.setColor(color)\n\n    def on_PB_Quit_clicked(self):\n        app.Console.PrintMessage(\"End of TechDraw Tools\" + \"\\n\")\n        super().accept()\n\n# define all commands: each command an own class ---------------------------------\n\nclass commonTools:\n    ''' common tools used by command buttons'''\n\n    def selectionOK():\n        ''' check selection of View and ObjectList '''\n        OK, ObjectList, View = False, [], []\n        if gui.Selection.getCompleteSelection():\n            View = gui.Selection.getCompleteSelection()[0]\n            ObjectList = gui.Selection.getSelectionEx()[0].SubElementNames\n            if len(ObjectList) > 0:\n                OK = True\n        return (OK,ObjectList,View)\n\n    def getPoints(View,ObjectList):\n        '''sort startpoints and endpoints of two lines belonging together'''\n        def circulation(A,B,C):\n            '''returns True if circulation ABC is positive'''\n            M = app.Matrix(A.x, A.y, 1, 0,\n                           B.x, B.y, 1, 0,\n                           C.x, C.y, 1, 0,\n                           0, 0, 0, 1)\n            if M.determinant() > 0.0: return True\n\n        if len(ObjectList) > 1:\n            Edge1 = View.getEdgeBySelection(ObjectList[0])\n            Edge2 = View.getEdgeBySelection(ObjectList[1])\n            if Edge1.Curve.TypeId == 'Part::GeomLine' and Edge2.Curve.TypeId == 'Part::GeomLine':\n                Start1, Start2 = Edge1.Vertexes[0].Point, Edge2.Vertexes[0].Point\n                End1, End2 = Edge1.Vertexes[1].Point, Edge2.Vertexes[1].Point\n                if circulation(Start1,End1,Start2) != circulation(End1,End2,Start2):\n                    Help1, Help2 = Start1, End1\n                    Start1, End1 = Help2, Help1\n            return (Start1,End1,Start2,End2)\n\n    def drawCosmeticThreadLines(View,ObjectList,Hole):\n        '''draw lines at cosmetic thread side view hole or bolt'''\n        (Start1,End1,Start2,End2) = commonTools.getPoints(View,ObjectList)\n        KernelDiam = Start2.sub(Start1).Length\n        if Hole:\n            Factor = (KernelDiam/0.85-KernelDiam)/2\n        else:\n            Factor = (KernelDiam*0.85-KernelDiam)/2\n        Delta =Start2.sub(Start1).normalize()*Factor\n        Style, Width, Color = Attrib.getStyle(), Attrib.getWidth(), Attrib.getColorTuple()\n        View.makeCosmeticLine(Start1-Delta,End1-Delta, Style, Width, Color)\n        View.makeCosmeticLine(Start2+Delta,End2+Delta, Style, Width, Color)\n\n    def drawCosmeticThreadArcs(View,ObjectList,Hole):\n        '''draw arcs at cosmetic thread ground view hole or bolt'''\n        for ObjectString in ObjectList:\n            if ObjectString[0:4] == 'Edge':\n                Edge = View.getEdgeBySelection(ObjectString)\n                if Edge.Curve.TypeId == 'Part::GeomCircle':\n                    Object = Edge.Curve\n                    Center = Object.Center\n                    if Hole:\n                        Radius = Object.Radius/0.85\n                    else:\n                        Radius = Object.Radius*0.85\n                    View.makeCosmeticCircleArc(Center, Radius, 255, 165, Attrib.getStyle(), Attrib.getWidth(), Attrib.getColorTuple())\n\n    def extendShortenLine(View,ObjectList,Extend):\n        '''extend or shorten one cosmetic or centerline'''\n        try:\n            OldFormat = View.getCosmeticEdgeBySelection(ObjectList[0]).Format\n            Edge = View.getEdgeBySelection(ObjectList[0])\n        except (IndexError, AttributeError):\n            app.Console.PrintWarning('Selection error\\n')\n            return\n        # TODO: Check that the selection is a line.\n        #       A DrawProjGroupItem has an edge and is thus translated.\n        StartPt, EndPt = Edge.Vertexes[0].Point, Edge.Vertexes[1].Point\n        Direction = (EndPt-StartPt).normalize()\n        gui.runCommand('TechDraw_CosmeticEraser',0)\n        Delta = Direction*2/View.Scale\n        if Extend:\n            StartPt, EndPt = StartPt - Delta, EndPt + Delta\n        else:\n            StartPt, EndPt = StartPt + Delta, EndPt - Delta\n        View.makeCosmeticLine(StartPt,EndPt,OldFormat[0],OldFormat[1],OldFormat[2])\n\n    def getViewCoords(View):\n        ''' position of View in Template coordinates'''\n        XView, YView = View.X, View.Y\n        if View.TypeId == 'TechDraw::DrawProjGroupItem':\n            XView = XView+View.InList[0].X\n            YView = YView+View.InList[0].Y\n        return (XView,YView)\n\n    def createAnnot(Name,Text,XPos,YPos):\n        '''Create an annotation'''\n        Doc = app.activeDocument()\n        Annot = Doc.addObject('TechDraw::DrawViewAnnotation',Name)\n        Doc.Page.addView(Annot)\n        Annot.Text = Text\n        Annot.TextSize = 4\n        Annot.X = XPos\n        Annot.Y = YPos\n\nclass CircleCenterLines:\n    '''Draw a center line cross at  circles'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 215 2\",\\\n        \"  \tc None\",\\\n        \". \tc #FF0000\",\\\n        \"+ \tc #2C2100\",\\\n        \"@ \tc #2B2200\",\\\n        \"# \tc #2A2200\",\\\n        \"$ \tc #2A2300\",\\\n        \"% \tc #362D00\",\\\n        \"& \tc #635C00\",\\\n        \"* \tc #878300\",\\\n        \"= \tc #B3B000\",\\\n        \"- \tc #ADAA00\",\\\n        \"; \tc #888300\",\\\n        \"> \tc #605900\",\\\n        \", \tc #342C00\",\\\n        \"' \tc #2C2200\",\\\n        \") \tc #4B4400\",\\\n        \"! \tc #9F9B00\",\\\n        \"~ \tc #E0DF00\",\\\n        \"{ \tc #FEFE00\",\\\n        \"] \tc #FFFF00\",\\\n        \"^ \tc #E2E100\",\\\n        \"/ \tc #999400\",\\\n        \"( \tc #4A4200\",\\\n        \"_ \tc #2B2300\",\\\n        \": \tc #2B2400\",\\\n        \"< \tc #2B2100\",\\\n        \"[ \tc #2E2500\",\\\n        \"} \tc #7B7600\",\\\n        \"| \tc #E1DF00\",\\\n        \"1 \tc #777100\",\\\n        \"2 \tc #2D2500\",\\\n        \"3 \tc #817C00\",\\\n        \"4 \tc #F0EF00\",\\\n        \"5 \tc #F2F200\",\\\n        \"6 \tc #807A00\",\\\n        \"7 \tc #2D2400\",\\\n        \"8 \tc #554E00\",\\\n        \"9 \tc #E4E300\",\\\n        \"0 \tc #E6E500\",\\\n        \"a \tc #5A5300\",\\\n        \"b \tc #A3A000\",\\\n        \"c \tc #E7E600\",\\\n        \"d \tc #B5B200\",\\\n        \"e \tc #898400\",\\\n        \"f \tc #8A8500\",\\\n        \"g \tc #B6B400\",\\\n        \"h \tc #E9E800\",\\\n        \"i \tc #A09C00\",\\\n        \"j \tc #3D3500\",\\\n        \"k \tc #D9D700\",\\\n        \"l \tc #DBDA00\",\\\n        \"m \tc #7A7500\",\\\n        \"n \tc #352C00\",\\\n        \"o \tc #372E00\",\\\n        \"p \tc #807B00\",\\\n        \"q \tc #DAD900\",\\\n        \"r \tc #DFDE00\",\\\n        \"s \tc #3C3400\",\\\n        \"t \tc #4B4300\",\\\n        \"u \tc #F3F300\",\\\n        \"v \tc #C0BE00\",\\\n        \"w \tc #474000\",\\\n        \"x \tc #BDBA00\",\\\n        \"y \tc #F2F100\",\\\n        \"z \tc #4C4400\",\\\n        \"A \tc #2A2100\",\\\n        \"B \tc #514900\",\\\n        \"C \tc #F8F800\",\\\n        \"D \tc #DCDB00\",\\\n        \"E \tc #494100\",\\\n        \"F \tc #D7D600\",\\\n        \"G \tc #F9F900\",\\\n        \"H \tc #4E4700\",\\\n        \"I \tc #2C2300\",\\\n        \"J \tc #484100\",\\\n        \"K \tc #FDFD00\",\\\n        \"L \tc #827E00\",\\\n        \"M \tc #847F00\",\\\n        \"N \tc #FCFC00\",\\\n        \"O \tc #F8F600\",\\\n        \"P \tc #473F00\",\\\n        \"Q \tc #3B3200\",\\\n        \"R \tc #F1F000\",\\\n        \"S \tc #514800\",\\\n        \"T \tc #372F00\",\\\n        \"U \tc #DAD800\",\\\n        \"V \tc #E8E700\",\\\n        \"W \tc #3C3300\",\\\n        \"X \tc #E7E500\",\\\n        \"Y \tc #CECD00\",\\\n        \"Z \tc #928D00\",\\\n        \"` \tc #E6E600\",\\\n        \" .\tc #292100\",\\\n        \"..\tc #3A3200\",\\\n        \"+.\tc #EAE900\",\\\n        \"@.\tc #928F00\",\\\n        \"#.\tc #4C4500\",\\\n        \"$.\tc #3F3700\",\\\n        \"%.\tc #F4F400\",\\\n        \"&.\tc #463F00\",\\\n        \"*.\tc #D8D700\",\\\n        \"=.\tc #514A00\",\\\n        \"-.\tc #2C2400\",\\\n        \";.\tc #5B5400\",\\\n        \">.\tc #D5D400\",\\\n        \",.\tc #2C1F00\",\\\n        \"'.\tc #6A6400\",\\\n        \").\tc #928E00\",\\\n        \"!.\tc #938F00\",\\\n        \"~.\tc #656000\",\\\n        \"{.\tc #5D5500\",\\\n        \"].\tc #5C5500\",\\\n        \"^.\tc #5E5700\",\\\n        \"/.\tc #CECB00\",\\\n        \"(.\tc #D0CF00\",\\\n        \"_.\tc #D6D500\",\\\n        \":.\tc #C8C500\",\\\n        \"<.\tc #332B00\",\\\n        \"[.\tc #625B00\",\\\n        \"}.\tc #615B00\",\\\n        \"|.\tc #FDFC00\",\\\n        \"1.\tc #787200\",\\\n        \"2.\tc #ECEC00\",\\\n        \"3.\tc #797400\",\\\n        \"4.\tc #C7C600\",\\\n        \"5.\tc #9E9A00\",\\\n        \"6.\tc #9C9800\",\\\n        \"7.\tc #C3C000\",\\\n        \"8.\tc #544C00\",\\\n        \"9.\tc #564F00\",\\\n        \"0.\tc #3E3600\",\\\n        \"a.\tc #FAFA00\",\\\n        \"b.\tc #D6D400\",\\\n        \"c.\tc #292200\",\\\n        \"d.\tc #5F5800\",\\\n        \"e.\tc #898300\",\\\n        \"f.\tc #AFAC00\",\\\n        \"g.\tc #B1AE00\",\\\n        \"h.\tc #AAA600\",\\\n        \"i.\tc #888200\",\\\n        \"j.\tc #571B00\",\\\n        \"k.\tc #A76E00\",\\\n        \"l.\tc #C17100\",\\\n        \"m.\tc #641900\",\\\n        \"n.\tc #8D8800\",\\\n        \"o.\tc #837F00\",\\\n        \"p.\tc #D4D200\",\\\n        \"q.\tc #2B2000\",\\\n        \"r.\tc #615A00\",\\\n        \"s.\tc #FBFB00\",\\\n        \"t.\tc #F5F400\",\\\n        \"u.\tc #575000\",\\\n        \"v.\tc #C7C500\",\\\n        \"w.\tc #9B9700\",\\\n        \"x.\tc #C6C400\",\\\n        \"y.\tc #7D7700\",\\\n        \"z.\tc #EEED00\",\\\n        \"A.\tc #EFEE00\",\\\n        \"B.\tc #736D00\",\\\n        \"C.\tc #605A00\",\\\n        \"D.\tc #686200\",\\\n        \"E.\tc #322A00\",\\\n        \"F.\tc #C9C700\",\\\n        \"G.\tc #585100\",\\\n        \"H.\tc #E3E100\",\\\n        \"I.\tc #696100\",\\\n        \"J.\tc #928C00\",\\\n        \"K.\tc #989200\",\\\n        \"L.\tc #645D00\",\\\n        \"M.\tc #E1E000\",\\\n        \"N.\tc #2D2000\",\\\n        \"O.\tc #D6D300\",\\\n        \"P.\tc #524C00\",\\\n        \"Q.\tc #292000\",\\\n        \"R.\tc #413900\",\\\n        \"S.\tc #F6F500\",\\\n        \"T.\tc #989400\",\\\n        \"U.\tc #DDDC00\",\\\n        \"V.\tc #D5D300\",\\\n        \"W.\tc #4D4600\",\\\n        \"X.\tc #524B00\",\\\n        \"Y.\tc #EDEC00\",\\\n        \"Z.\tc #483F00\",\\\n        \"`.\tc #868100\",\\\n        \" +\tc #837E00\",\\\n        \".+\tc #4D4400\",\\\n        \"++\tc #DEDD00\",\\\n        \"@+\tc #4D4700\",\\\n        \"#+\tc #BEBB00\",\\\n        \"$+\tc #484000\",\\\n        \"%+\tc #C5C200\",\\\n        \"&+\tc #827D00\",\\\n        \"*+\tc #383000\",\\\n        \"=+\tc #7F7900\",\\\n        \"-+\tc #DFDD00\",\\\n        \";+\tc #9E9B00\",\\\n        \">+\tc #ECEB00\",\\\n        \",+\tc #B9B700\",\\\n        \"'+\tc #8C8700\",\\\n        \")+\tc #B9B600\",\\\n        \"!+\tc #2A2000\",\\\n        \"~+\tc #595200\",\\\n        \"{+\tc #E5E400\",\\\n        \"]+\tc #544D00\",\\\n        \"^+\tc #7C7700\",\\\n        \"/+\tc #F1F100\",\\\n        \"(+\tc #EEEE00\",\\\n        \"_+\tc #746F00\",\\\n        \":+\tc #797300\",\\\n        \"<+\tc #E0DE00\",\\\n        \"[+\tc #9A9400\",\\\n        \"}+\tc #AAA700\",\\\n        \"|+\tc #AFAB00\",\\\n        \"1+\tc #847E00\",\\\n        \"2+\tc #5F5900\",\\\n        \"                                                          . . . . . .                                                           \",\\\n        \"                                                          . . . . . .                                                           \",\\\n        \"                                                + @ @ @ @ . . . . . . @ @ @ # +                                                 \",\\\n        \"                                          $ @ @ @ % & * = . . . . . . - ; > , @ @ @ '                                           \",\\\n        \"                                      @ @ @ ) ! ~ { ] ] ] . . . . . . ] ] ] { ^ / ( @ @ _ :                                     \",\\\n        \"                                  < @ [ } | ] ] ] ] ] ] ] . . . . . . ] ] ] ] ] ] ] ^ 1 [ @ #                                   \",\\\n        \"                              ' @ 2 3 4 ] ] ] ] ] ] ] ] ] . . . . . . ] ] ] ] ] ] ] ] ] 5 6 7 @ @                               \",\\\n        \"                            @ @ 8 9 ] ] ] ] ] ] ] ] ] ] ] . . . . . . ] ] ] ] ] ] ] ] ] ] ] 0 a @ @                             \",\\\n        \"                        @ _ 2 b { ] ] ] ] ] ] ] ] { c d e . . . . . . f g h { ] ] ] ] ] ] ] ] { i [ @ 7                         \",\\\n        \"                      @ @ j k ] ] ] ] ] ] ] ] l m n @ @ @ . . . . . . @ @ @ o p q ] ] ] ] ] ] ] ] r s @ <                       \",\\\n        \"                    _ @ t u ] ] ] ] ] ] { v w @ @ @ $ +   . . . . . .   ' $ ' @ @ ( x { ] ] ] ] ] ] y z @ +                     \",\\\n        \"                  A @ B C ] ] ] ] ] ] D E @ @ <           . . . . . .           $ < @ z F ] ] ] ] ] ] G H @ I                   \",\\\n        \"                @ @ J G ] ] ] ] ] K L @ @ _               . . . . . .               @ @ @ M N ] ] ] ] ] O P @ I                 \",\\\n        \"                @ Q R ] ] ] ] ] R S @ '                   . . . . . .                   < @ z 5 ] ] ] ] ] R T @                 \",\\\n        \"              @ I U ] ] ] ] ] V W @ $                     . . . . . .                     ' @ j X ] ] ] ] ] Y I @               \",\\\n        \"            @ @ Z ] ] ] ] ] ` T @  .                      . . . . . .                       $ @ ..+.] ] ] ] ] @.@ $             \",\\\n        \"            @ #.{ ] ] ] ] u $.@ '                         . . . . . .                         @ @ $.%.] ] ] ] K &.@             \",\\\n        \"          ' @ *.] ] ] ] K =.@ -.                          . . . . . .                           -.@ ;.{ ] ] ] ] >.@ #           \",\\\n        \"        ,.@ '.] ] ] ] ] ).@ <                             . . . . . .                             ' @ !.] ] ] ] ] ~.@           \",\\\n        \"        _ @ ` ] ] ] ] 9 7 @                               . . . . . .                               < [ c ] ] ] ] ~ @ _         \",\\\n        \"        @ {.] ] ] ] ] ].@                                                                             @ ].] ] ] ] ] ^.@         \",\\\n        \"      ' @ /.] ] ] ] (.@ I                                                                             # @ _.] ] ] ] :.@ @       \",\\\n        \"      @ <.K ] ] ] ] [.@                                                                                 @ }.] ] ] ] |., @       \",\\\n        \"      @ 1.] ] ] ] 2.@ <                                                                                 $ I 4 ] ] ] ] 3.@       \",\\\n        \"    + @ 4.] ] ] ] 5.@                                                                                     @ 6.] ] ] ] 7.@ @     \",\\\n        \"    # @ u ] ] ] ] 8.@                                                                                     @ 9.] ] ] ] %.@ @     \",\\\n        \"    @ 0.] ] ] ] a.7 $                                                                                     @ 2 G ] ] ] ] s @     \",\\\n        \"    @ & ] ] ] ] b.@ c.                                                                                    $ @ _.] ] ] ] d.@     \",\\\n        \"    @ e.] ] ] ] f.@                                                                                         @ g.] ] ] ] f @     \",\\\n        \". . . . . . . . . . . . . . . . . . . .                   . . . . . .                   . . . . . . . . . . . . . . . . . . . . \",\\\n        \". . . . . . . . . . . . . . . . . . . .                   . . . . . .                   . . . . . . . . . . . . . . . . . . . . \",\\\n        \". . . . . . . . . . . . . . . . . . . .                   . . . . . .                   . . . . . . . . . . . . . . . . . . . . \",\\\n        \". . . . . . . . . . . . . . . . . . . .                   . . . . . .                   . . . . . . . . . . . . . . . . . . . . \",\\\n        \". . . . . . . . . . . . . . . . . . . .                   . . . . . .                   . . . . . . . . . . . . . . . . . . . . \",\\\n        \"  @ @ h.] ] ] ] i.@                                                                                         j.k.] ] ] ] l.m.    \",\\\n        \"    @ n.] ] ] ] - @                                                                                         @ g.] ] ] ] o.@     \",\\\n        \"    @ & ] ] ] ] p.@ q.                                                                                    < @ F ] ] ] ] r.@     \",\\\n        \"    < $.] ] ] ] C 7 $                                                                                     @ 2 s.] ] ] ] W '     \",\\\n        \"    @ @ t.] ] ] ] 8.@                                                                                     @ u.] ] ] ] 5 @ @     \",\\\n        \"    # @ v.] ] ] ] w.@                                                                                     @ b ] ] ] ] x.@ @     \",\\\n        \"      @ y.] ] ] ] z.I $                                                                                 @ I A.] ] ] ] B.@       \",\\\n        \"      @ n K ] ] ] ] C.@                                                                                 @ D.] ] ] ] |.E._       \",\\\n        \"      < @ F.] ] ] ] _.@ @                                                                             _ @ _.] ] ] ] F.@ <       \",\\\n        \"        @ d.] ] ] ] ] ;.@                                                                             @ r.] ] ] ] ] G.@         \",\\\n        \"        _ @ ^ ] ] ] ] c [ '                               . . . . . .                               @ 2 0 ] ] ] ] H.@ @         \",\\\n        \"          @ I.] ] ] ] ] J.@ $                             . . . . . .                             < @ K.] ] ] ] ] L.@           \",\\\n        \"          ' @ M.] ] ] ] { ;.@ N.                          . . . . . .                           + @ 9.{ ] ] ] ] O.@ '           \",\\\n        \"            @ P.{ ] ] ] ] %.0.@ <                         . . . . . .                         Q.@ R.S.] ] ] ] K t @             \",\\\n        \"            < @ T.] ] ] ] ] +...@ $                       . . . . . .                       $ @ ..V ] ] ] ] ] n.@ <             \",\\\n        \"              @ 2 U.] ] ] ] ] X j @ '                     . . . . . .                     ' @ j +.] ] ] ] ] V.I <               \",\\\n        \"                @ R.R ] ] ] ] ] u W.@ @                   . . . . . .                   < @ X.5 ] ] ] ] ] Y.T @                 \",\\\n        \"                I @ Z.S.] ] ] ] ] N `.@ @ +               . . . . . .               + @ I  +K ] ] ] ] ] C P @ <                 \",\\\n        \"                  @ @ W.G ] ] ] ] ] ] *..+@ @ @           . . . . . .           @ @ @ z ++] ] ] ] ] ] S.@+@ '                   \",\\\n        \"                    + @ ) R ] ] ] ] ] ] { #+t @ @ @ ' <   . . . . . .   $ @ @ @ @ $+%+{ ] ] ] ] ] ] 5 E @ @                     \",\\\n        \"                      A @ W ++] ] ] ] ] ] ] ] l &+*+@ @ @ . . . . . . @ @ @ *+=+-+] ] ] ] ] ] ] ] _.W @ <                       \",\\\n        \"                        Q.@ [ ;+{ ] ] ] ] ] ] ] ] { >+,+'+. . . . . . '+)+h ] ] ] ] ] ] ] ] ] { b 2 @ !+                        \",\\\n        \"                            @ @ ~+{+] ] ] ] ] ] ] ] ] ] ] . . . . . . ] ] ] ] ] ] ] ] ] ] ] ^ ]+@ '                             \",\\\n        \"                              $ @ 7 ^+/+] ] ] ] ] ] ] ] ] . . . . . . ] ] ] ] ] ] ] ] ] (+^+7 @ <                               \",\\\n        \"                                  < @ [ _+~ ] ] ] ] ] ] ] . . . . . . ] ] ] ] ] ] ] U.:+2 @ _                                   \",\\\n        \"                                      ' @ @ P !.<+K ] ] ] . . . . . . ] ] ] K U.[+E @ @ _                                       \",\\\n        \"                                          I @ @ @ E.^.* }+. . . . . . |+1+2+n @ @ < '                                           \",\\\n        \"                                                @ @ ' @ @ . . . . . . @ @ @ _ @                                                 \",\\\n        \"                                                          . . . . . .                                                           \",\\\n        \"                                                          . . . . . .                                                           \"])\n\n    def textEnglish(self):\n        buttonText = \"Draw circle centerLines\"\n        helpText = \"Draw a center line cross at circles:\"+ \"\\n\"\\\n                   \"- pick favoured line attributes\"+ \"\\n\"\\\n                   \"- select many circles or arcs\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Zeichne Kreis Mittellinien\"\n        helpText = \"Zeichne ein Linienkreuz bei einem Kreis:\"+ \"\\n\"\\\n                   \"- w\u00e4hle die gew\u00fcnschten Eigenschaften der Linien\"+ \"\\n\"\\\n                   \"- w\u00e4hle mehrere Kreise und/oder Kreib\u00f6gen\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Mezzerie circonferenza\"\n        helpText = \"Disegna una croce con la linea centrale sulla circonferenza:\"+ \"\\n\"\\\n                   \"- scegliere gli attributi linea\"+ \"\\n\"\\\n                   \"- selezionare i cerchi o gli archi\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Axes de la circonf\u00e9rence\"\n        helpText = \"Tracez une croix avec la ligne centrale sur la circonf\u00e9rence:\"+ \"\\n\"\\\n                   \"- choisir les attributs de ligne\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez des cercles ou des arcs\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Ejes de la circunferencia\"\n        helpText = \"Dibuja una cruz con la l\u00ednea central en la circunferencia:\"+ \"\\n\"\\\n                   \"- elegir atributos de l\u00ednea\"+ \"\\n\"\\\n                   \"- seleccionar c\u00edrculos o arcos\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            for ObjectString in ObjectList:\n                if ObjectString[0:4] == 'Edge':\n                    Edge = View.getEdgeBySelection(ObjectString)\n                    if Edge.Curve.TypeId == 'Part::GeomCircle':\n                        Object = Edge.Curve\n                        Center = Object.Center\n                        Radius = Object.Radius+2/View.Scale\n                        Right = app.Vector(Center.x+Radius,Center.y,0)\n                        Left = app.Vector(Center.x-Radius,Center.y,0)\n                        Top = app.Vector(Center.x,Center.y+Radius,0)\n                        Bottom = app.Vector(Center.x,Center.y-Radius,0)\n                        Style, Width, Color = Attrib.getStyle(), Attrib.getWidth(), Attrib.getColorTuple()\n                        View.makeCosmeticLine(Left,Right,Style, Width, Color)\n                        View.makeCosmeticLine(Top,Bottom,Style, Width, Color)\n            gui.Selection.clearSelection()\n\nclass DrawHoleCircle:\n    '''Draw a center circle and center cross at a bolt circle'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 222 2\",\\\n        \"  \tc None\",\\\n        \". \tc #FF0000\",\\\n        \"+ \tc #2B2200\",\\\n        \"@ \tc #2A2200\",\\\n        \"# \tc #2B2100\",\\\n        \"$ \tc #2B2300\",\\\n        \"% \tc #2C2300\",\\\n        \"& \tc #5C5500\",\\\n        \"* \tc #2D2400\",\\\n        \"= \tc #2C2100\",\\\n        \"- \tc #423900\",\\\n        \"; \tc #EAE900\",\\\n        \"> \tc #FFFF00\",\\\n        \", \tc #E9E800\",\\\n        \"' \tc #443B00\",\\\n        \") \tc #A5A100\",\\\n        \"! \tc #A7A400\",\\\n        \"~ \tc #BBB800\",\\\n        \"{ \tc #FEFE00\",\\\n        \"] \tc #B4B100\",\\\n        \"^ \tc #2A2300\",\\\n        \"/ \tc #746E00\",\\\n        \"( \tc #FDFD00\",\\\n        \"_ \tc #878200\",\\\n        \": \tc #302700\",\\\n        \"< \tc #959100\",\\\n        \"[ \tc #686100\",\\\n        \"} \tc #2C2200\",\\\n        \"| \tc #FAF900\",\\\n        \"1 \tc #FBFB00\",\\\n        \"2 \tc #382F00\",\\\n        \"3 \tc #471D00\",\\\n        \"4 \tc #B20E00\",\\\n        \"5 \tc #2F2600\",\\\n        \"6 \tc #423B00\",\\\n        \"7 \tc #F9F900\",\\\n        \"8 \tc #615B00\",\\\n        \"9 \tc #504900\",\\\n        \"0 \tc #665F00\",\\\n        \"a \tc #534C00\",\\\n        \"b \tc #CECB00\",\\\n        \"c \tc #F0F000\",\\\n        \"d \tc #F3F200\",\\\n        \"e \tc #C3BF00\",\\\n        \"f \tc #FD0B00\",\\\n        \"g \tc #433C00\",\\\n        \"h \tc #DFDD00\",\\\n        \"i \tc #E2E100\",\\\n        \"j \tc #4C4500\",\\\n        \"k \tc #ECEB00\",\\\n        \"l \tc #524B00\",\\\n        \"m \tc #F4F400\",\\\n        \"n \tc #3D3500\",\\\n        \"o \tc #DAD700\",\\\n        \"p \tc #D5D300\",\\\n        \"q \tc #CECC00\",\\\n        \"r \tc #2E2600\",\\\n        \"s \tc #342C00\",\\\n        \"t \tc #F2F100\",\\\n        \"u \tc #F3F300\",\\\n        \"v \tc #E5E400\",\\\n        \"w \tc #BBB900\",\\\n        \"x \tc #C0BE00\",\\\n        \"y \tc #C4C100\",\\\n        \"z \tc #2A2400\",\\\n        \"A \tc #EBEA00\",\\\n        \"B \tc #FCFC00\",\\\n        \"C \tc #999400\",\\\n        \"D \tc #DDDC00\",\\\n        \"E \tc #3B3200\",\\\n        \"F \tc #352D00\",\\\n        \"G \tc #FAFA00\",\\\n        \"H \tc #4E4800\",\\\n        \"I \tc #AFAC00\",\\\n        \"J \tc #302900\",\\\n        \"K \tc #332B00\",\\\n        \"L \tc #645D00\",\\\n        \"M \tc #4E4600\",\\\n        \"N \tc #3C3300\",\\\n        \"O \tc #E4E300\",\\\n        \"P \tc #322900\",\\\n        \"Q \tc #3C1F00\",\\\n        \"R \tc #575100\",\\\n        \"S \tc #393000\",\\\n        \"T \tc #E1E000\",\\\n        \"U \tc #DAD900\",\\\n        \"V \tc #2E2500\",\\\n        \"W \tc #938E00\",\\\n        \"X \tc #BDBA00\",\\\n        \"Y \tc #858000\",\\\n        \"Z \tc #705300\",\\\n        \"` \tc #2F2700\",\\\n        \" .\tc #CCCA00\",\\\n        \"..\tc #534B00\",\\\n        \"+.\tc #C8C600\",\\\n        \"@.\tc #C1BE00\",\\\n        \"#.\tc #423A00\",\\\n        \"$.\tc #431E00\",\\\n        \"%.\tc #422700\",\\\n        \"&.\tc #FFEE00\",\\\n        \"*.\tc #3E2100\",\\\n        \"=.\tc #2C2500\",\\\n        \"-.\tc #322000\",\\\n        \";.\tc #4C2300\",\\\n        \">.\tc #FFDD00\",\\\n        \",.\tc #572D00\",\\\n        \"'.\tc #561A00\",\\\n        \").\tc #574F00\",\\\n        \"!.\tc #EAE800\",\\\n        \"~.\tc #FFF000\",\\\n        \"{.\tc #FFFE00\",\\\n        \"].\tc #B0AD00\",\\\n        \"^.\tc #2A2100\",\\\n        \"/.\tc #5E1A00\",\\\n        \"(.\tc #BEBB00\",\\\n        \"_.\tc #FFF100\",\\\n        \":.\tc #B3B000\",\\\n        \"<.\tc #471E00\",\\\n        \"[.\tc #D1D000\",\\\n        \"}.\tc #E5D400\",\\\n        \"|.\tc #FC0A00\",\\\n        \"1.\tc #2D2300\",\\\n        \"2.\tc #908A00\",\\\n        \"3.\tc #CFCE00\",\\\n        \"4.\tc #393100\",\\\n        \"5.\tc #B7B400\",\\\n        \"6.\tc #332C00\",\\\n        \"7.\tc #E4E200\",\\\n        \"8.\tc #ADAA00\",\\\n        \"9.\tc #2C1F00\",\\\n        \"0.\tc #312700\",\\\n        \"a.\tc #DBD700\",\\\n        \"b.\tc #6B6500\",\\\n        \"c.\tc #EDEC00\",\\\n        \"d.\tc #8A8400\",\\\n        \"e.\tc #5A5500\",\\\n        \"f.\tc #817B00\",\\\n        \"g.\tc #F5F400\",\\\n        \"h.\tc #EEEE00\",\\\n        \"i.\tc #5D5500\",\\\n        \"j.\tc #2A2000\",\\\n        \"k.\tc #D1CE00\",\\\n        \"l.\tc #9E9A00\",\\\n        \"m.\tc #502B00\",\\\n        \"n.\tc #372B00\",\\\n        \"o.\tc #D2D000\",\\\n        \"p.\tc #FFE300\",\\\n        \"q.\tc #2D2500\",\\\n        \"r.\tc #FFB000\",\\\n        \"s.\tc #FF0200\",\\\n        \"t.\tc #2D2000\",\\\n        \"u.\tc #CAC800\",\\\n        \"v.\tc #FF2600\",\\\n        \"w.\tc #CDCB00\",\\\n        \"x.\tc #FF2B00\",\\\n        \"y.\tc #FF0900\",\\\n        \"z.\tc #4E4500\",\\\n        \"A.\tc #D9D800\",\\\n        \"B.\tc #DBDA00\",\\\n        \"C.\tc #4C4400\",\\\n        \"D.\tc #E2DF00\",\\\n        \"E.\tc #726D00\",\\\n        \"F.\tc #E8E700\",\\\n        \"G.\tc #686200\",\\\n        \"H.\tc #292000\",\\\n        \"I.\tc #A29E00\",\\\n        \"J.\tc #3C3400\",\\\n        \"K.\tc #342A00\",\\\n        \"L.\tc #403800\",\\\n        \"M.\tc #6A6200\",\\\n        \"N.\tc #352C00\",\\\n        \"O.\tc #E3E100\",\\\n        \"P.\tc #8F8A00\",\\\n        \"Q.\tc #E8D600\",\\\n        \"R.\tc #3D1F00\",\\\n        \"S.\tc #4F4700\",\\\n        \"T.\tc #322A00\",\\\n        \"U.\tc #F8F800\",\\\n        \"V.\tc #A6A300\",\\\n        \"W.\tc #3F3700\",\\\n        \"X.\tc #F6F600\",\\\n        \"Y.\tc #FF0100\",\\\n        \"Z.\tc #B7B600\",\\\n        \"`.\tc #BFBC00\",\\\n        \" +\tc #6F6800\",\\\n        \".+\tc #342B00\",\\\n        \"++\tc #4D4600\",\\\n        \"@+\tc #696300\",\\\n        \"#+\tc #FC0100\",\\\n        \"$+\tc #2B2000\",\\\n        \"%+\tc #FE0000\",\\\n        \"&+\tc #FF0D00\",\\\n        \"*+\tc #5E5700\",\\\n        \"=+\tc #BAB800\",\\\n        \"-+\tc #F0EF00\",\\\n        \";+\tc #FF1F00\",\\\n        \">+\tc #494000\",\\\n        \",+\tc #716B00\",\\\n        \"'+\tc #FF2000\",\\\n        \")+\tc #D1D100\",\\\n        \"!+\tc #EFEE00\",\\\n        \"~+\tc #DFDE00\",\\\n        \"{+\tc #969100\",\\\n        \"]+\tc #D4D100\",\\\n        \"^+\tc #846600\",\\\n        \"/+\tc #521A00\",\\\n        \"(+\tc #2E2200\",\\\n        \"_+\tc #BDBB00\",\\\n        \":+\tc #797200\",\\\n        \"<+\tc #4D4500\",\\\n        \"[+\tc #342000\",\\\n        \"}+\tc #5F1A00\",\\\n        \"|+\tc #7D7700\",\\\n        \"1+\tc #827D00\",\\\n        \"2+\tc #FBFA00\",\\\n        \"3+\tc #E0DF00\",\\\n        \"4+\tc #E8E600\",\\\n        \"5+\tc #484100\",\\\n        \"6+\tc #C6C400\",\\\n        \"7+\tc #E7E600\",\\\n        \"8+\tc #C1BF00\",\\\n        \"9+\tc #D7D600\",\\\n        \"                                                          . . .                                                                 \",\\\n        \"                                                      + @ . . . + # $                                                           \",\\\n        \"                                                  # + + % . . . & * + + =                                                       \",\\\n        \"                                                + + - ; > . . . > > , ' + $                                                     \",\\\n        \"                                              + + ) > > > . . . > > > > ! + @                                                   \",\\\n        \"                                            $ + ~ > > > > . . . { > > > > ] + ^                                                 \",\\\n        \"                                            + / > > > ( _ . . . : < ( > > > [ +                                                 \",\\\n        \"                                          } + | > > 1 2 + 3 4   } 5 6 1 > > 7 + @                       . . .                   \",\\\n        \"                                          } 8 > > > 9 +             5 0 > > > a +                       . . .                   \",\\\n        \"                                          + b > > c + =             + + d > > e +                       . . .                   \",\\\n        \"                                    . . . . . . . . .     . . . > > > . . . . . . . .               $ ^ . . . + $               \",\\\n        \"                                    . . . . . . . f .     . . . > > > . . . . . . . . >         = + + + . . . + + + #           \",\\\n        \"                                    . . . . . . . . .     . . . > > > . . . . . . . . > >     + + g h { . . . > i j + $         \",\\\n        \"                                        > k > > > > i %   > > >     l j ( > > i m > > > >   + n b > > > . . . > > > o % +       \",\\\n        \"                                        > > > > > > p + #         + + q > > > r s > > >   # : ( > > > > . . . > > > > t * +     \",\\\n        \"                  . . .           >       u ; v > > > w % + + $ + + x > > > y + #       z + A > > > B C . . . C 1 > > > D + $   \",\\\n        \"                  . . .         > > >       E F G > > > 1 . . . ~ G > > > 7 * #         + H > > > > > I J # } + K v > > > L +   \",\\\n        \"                  . . .       > > > > >       * M 1 > > > . . . > > > > G N +           + O > > { > > > >       = P G > > , + # \",\\\n        \"            ^ } Q . . . + R > > > > >           * S T > > . . . > > > U V +           # + { > > W X > >           + Y > > { % = \",\\\n        \"        = + + : Z . . . `  .> > > >               + + ..+.. . . u @.#.+ +             $.%.&.&.&.*.=.>     .       -.;.>.>.>.,.'.\",\\\n        \"      # + ).!.> ~.. . . {.> > ( ].                  + + + . . . + + + ^.          . . . . . . . . #     . . . >   /.. . . . . . \",\\\n        \"    + + (.> > > _.. . . > > > :.+ $                       . . . z                 . . . . . . . . +     . . . > > <.. . . . . . \",\\\n        \"  + + [.> > > { }.|.. . > > > > & + 1.                    . . .                   . . . . . . . . +     . . . > { 2 . . . . . . \",\\\n        \"1.+ 2.> > > 3.4.+ + 5.> > { > > ( 6.$                     . . .                         + 7.> > 1 : $       > > > 8.G > > v + 9.\",\\\n        \"^ 0.( > > 5.+ + $ a.> > { b.7 > > X + %                   . . .                         + R > > > c.: + $ + d.> > > > > > e.*   \",\\\n        \"+ f.> > g.% }     > > > h.+ i.> > ( % #                                                 j.+ k.> > > B l.m.3 n.T > > > > o.+ =   \",\\\n        \". . . . . +     p.. . .   % . . . . . . . .                                               + q.A > > > > . . . > > > > A % +     \",\\\n        \". . . . . $     r.. s..   t.. . . . . . . .                                                 } q.u.> > > v.. . > > > w.+ }       \",\\\n        \". . . . . }     x.s.y..     . . . . . . . .                                                   # + z.A.( . . . B B.C.+ +         \",\\\n        \"+ D.> > E.+               + + F.> > G.#                                                         z + + + . . . + + } H.          \",\\\n        \"+ I.> > A.+ ^             + J.> > > K.@                                                               $ . . . +                 \",\\\n        \"+ L.> > > M.N.g.{ >     } + D > > O.+ ^.                                                                . . .                   \",\\\n        \"$ +  .> > { P.> > Q.R.+ : 3.> > > S.+                                                                   . . .                   \",\\\n        \"  + T.U.> > > > > . . . B > > > V.+ }                                                                   . . .                   \",\\\n        \"  9.+ W.X.> > > > Y.. . > > > Z.+ +                                                                                             \",\\\n        \"    $ + 5 `.> > > s.. . > 7  ++ +                                                                                               \",\\\n        \"        + +  .> > s.. . & + + ^                                                                                                 \",\\\n        \"          ^..+++@+#+. . $ +                                                                                                     \",\\\n        \"                $+%+. .                                                                                                         \",\\\n        \"                  . . .                                                                                                         \",\\\n        \"            > > > &+. .                                                                                                         \",\\\n        \"            > > > >                                                                                                             \",\\\n        \"            > > > >     . . .                                                                                                   \",\\\n        \"              > > > n ^ . . . + $                                                                                               \",\\\n        \"              > > > *++ . . . + + + #                                                                                           \",\\\n        \"              =+> > -+{ ;+. . { h >++ $                                                                                         \",\\\n        \"            + ,+> > > > '+. . > > > )+% +                                                                                       \",\\\n        \"          # + !+> > > > . . . > > > > c % +                                                                                     \",\\\n        \"        z + o.> > > > ~+. . . {+G > > > ]++ $                                                                                   \",\\\n        \"        + H > > > > > ( ^+/+(++ K v > > > S.+                                                                                   \",\\\n        \"        + O > > U._+> > >       = P G > > 7.+ #                                                                                 \",\\\n        \"      # + { > > :+<+> > > >       + Y > > { + =                                                                                 \",\\\n        \"  . . . . . . . . ^ > > . . .     [+. . . . . . . .                                                                             \",\\\n        \"  . . . . . . . . #   > y.. .     }+. . . . . . . .                                                                             \",\\\n        \"  . . . . . . . . +   > . . .     <.. . . . . . . .                                                                             \",\\\n        \"      = + { > > |++               + 1+> > { + ^.                                                                                \",\\\n        \"        + 7.> > 2+V }           + % G > > 3++ 9.                                                                                \",\\\n        \"        + R > > > , 5 + $ + @ + * 4+> > > 5++                                                                                   \",\\\n        \"        j.+ k.> > > B {+. . . < B > > > 6++ =                                                                                   \",\\\n        \"          + q.A > > > > . . . > > > > 7++ +                                                                                     \",\\\n        \"            } q.u.> > > . . . > > > 8++ }                                                                                       \",\\\n        \"              # + z.9+B . . . B p #.+ +                                                                                         \",\\\n        \"                z + + + . . . + + } H.                                                                                          \",\\\n        \"                      $ . . . +                                                                                                 \"])\n\n    def textEnglish(self):\n        buttonText = \"Draw bolt circle centerlines\"\n        helpText = \"Draw the center lines of a bolt circle:\"+ \"\\n\"\\\n                   \"- pick favoured line attributes\"+ \"\\n\"\\\n                   \"- select at least 3 circles of the bolt circle\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Zeichne Lochkreis Mittellinien\"\n        helpText = \"Zeichne die Mittellinien eines Lochkreises:\"+ \"\\n\"\\\n                   \"- w\u00e4hle die gew\u00fcnschten Eigenschaften der Linien\"+ \"\\n\"\\\n                   \"- w\u00e4hle mindestens 3 Kreise des Lochkreises\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Mezzerie bulloni/viti/fori disposti in cerchio\"\n        helpText = \"Disegna gli assi di bulloni/viti/fori disposti in cerchio:\"+ \"\\n\"\\\n                   \"- scegliere gli attributi linea\"+ \"\\n\"\\\n                   \"- selezionare almeno 3 circonferenze aventi asse circonferenziale comune\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Axe des boulons/vis/trou dispos\u00e9s en cercle\"\n        helpText = \"Dessinez les axes des boulons/vis/trou dispos\u00e9s en cercle:\"+ \"\\n\"\\\n                   \"- choisir les attributs de ligne\"+ \"\\n\"\\\n                   \"- s\u00e9lectionner au moins 3 cercles ayant un axe circonf\u00e9rentiel commun\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Ejes de pernos/tornillos/agujero dispuestos en c\u00edrculo\"\n        helpText = \"Dibuja los ejes de los pernos/tornillos/agujero dispuestos en c\u00edrculo:\"+ \"\\n\"\\\n                   \"- elegir atributos de l\u00ednea\"+ \"\\n\"\\\n                   \"- seleccione al menos 3 c\u00edrculos que tengan un eje circunferencial com\u00fan\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            if len(ObjectList) < 3: return\n            Style, Width, Color = Attrib.getStyle(), Attrib.getWidth(), Attrib.getColorTuple()\n            Rot90 = app.Rotation(app.Vector(0,0,1),90)\n            Circles = []\n            for ObjectString in ObjectList:\n                if ObjectString[0:4] == 'Edge':\n                    Edge = View.getEdgeBySelection(ObjectString)\n                    if Edge.Curve.TypeId == 'Part::GeomCircle':\n                        Circles.append((Edge.Curve.Center,Edge.Curve.Radius))\n            Edge1,Edge2 = Circles[1][0]-Circles[0][0],Circles[2][0]-Circles[0][0]\n            Mid1,Mid2 =Circles[0][0]+Edge1/2,Circles[0][0]+Edge2/2\n            Pnt1,Pnt2 = Rot90.multVec(Edge1)+Mid1,Rot90.multVec(Edge2)+Mid2\n            Line1,Line2 = Part.Line(Mid1,Pnt1),Part.Line(Mid2,Pnt2)\n            IP = Line1.intersect(Line2)[0]\n            BigCenter = app.Vector(IP.X,IP.Y,IP.Z)\n            for Circle in Circles:\n                RadVec = Circle[0].sub(BigCenter)\n                Radius = RadVec.Length\n                RadVec1 =RadVec.normalize()\n                StartDist = Radius-Circle[1]-2/View.Scale\n                EndDist = Radius+Circle[1]+2/View.Scale\n                EndPt = BigCenter+RadVec1.scale(EndDist,EndDist,EndDist)\n                RadVec1.normalize()\n                StartPt = BigCenter+RadVec1.scale(StartDist,StartDist,StartDist)\n                View.makeCosmeticLine(StartPt,EndPt,Style, Width, Color)\n            BigRadius =Circles[0][0].sub(BigCenter).Length\n            View.makeCosmeticCircle(BigCenter, BigRadius, Style, Width, Color)\n            gui.Selection.clearSelection()\n\nclass CenterLine:\n    '''Draw center line between two lines'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 12 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"+\tc #2A2400\",\\\n        \"@\tc #2A2100\",\\\n        \"#\tc #2C2300\",\\\n        \"$\tc #2C2200\",\\\n        \"%\tc #2B2200\",\\\n        \"&\tc #2B2300\",\\\n        \"*\tc #FFFF00\",\\\n        \"=\tc #2C2100\",\\\n        \"-\tc #2A2300\",\\\n        \";\tc #292400\",\\\n        \"                             ......                             \",\\\n        \"                             ......                             \",\\\n        \"         +@@@@@@#            ......            #@@@@@@+         \",\\\n        \"        $%%%%%%%%$           ......           $%%%%%%%%$        \",\\\n        \"        %%%%%%%%%&           ......           &%%%%%%%%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&                            &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%*****%%&           ......           &%%*****%%        \",\\\n        \"        %%%%%%%%%=           ......           =%%%%%%%%%        \",\\\n        \"        -%%%%%%%%;           ......           ;%%%%%%%%-        \",\\\n        \"                             ......                             \",\\\n        \"                             ......                             \",\\\n        \"                             ......                             \"])\n\n    def textEnglish(self):\n        buttonText = \"Draw one center line\"\n        helpText = \"Draw a center line between two lines:\"+ \"\\n\"\\\n                   \"- pick favoured line attributes\"+ \"\\n\"\\\n                   \"- select two lines\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Zeichne einzelne Mittellinie\"\n        helpText = \"Zeichne eine Mittellinie zwischen zwei Linien:\"+ \"\\n\"\\\n                   \"- w\u00e4hle die gew\u00fcnschten Eigenschaften der Linien\"+ \"\\n\"\\\n                   \"- w\u00e4hle zwei Linien\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Linea centrale\"\n        helpText = \"Disegna una mezzeria tra due linee:\"+ \"\\n\"\\\n                   \"- scegliere gli attributi linea\"+ \"\\n\"\\\n                   \"- selezionare due linee\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Ligne centrale\"\n        helpText = \"Tracez une ligne centrale entre deux lignes:\"+ \"\\n\"\\\n                   \"- choisir les attributs de ligne\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez deux lignes\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"L\u00ednea central\"\n        helpText = \"Dibuja una l\u00ednea central entre dos l\u00edneas:\"+ \"\\n\"\\\n                   \"- elegir atributos de l\u00ednea\"+ \"\\n\"\\\n                   \"- seleccione dos l\u00edneas\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            (Start1,End1,Start2,End2) = commonTools.getPoints(View,ObjectList)\n            Mid1, Mid2 = (Start1+Start2)/2, (End1+End2)/2\n            Protrusion = Mid2.sub(Mid1).normalize()*2\n            StartPt, EndPt = Mid1-Protrusion, Mid2+Protrusion\n            View.makeCosmeticLine(StartPt,EndPt,Attrib.getStyle(), Attrib.getWidth(), Attrib.getColorTuple())\n            gui.Selection.clearSelection()\n\nclass DrawCosmeticThreadHole:\n    '''Draw a cosmetic hole thread at selected circles'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 147 2\",\\\n        \"  \tc None\",\\\n        \". \tc #2B2200\",\\\n        \"+ \tc #FFFF00\",\\\n        \"@ \tc #FF0000\",\\\n        \"# \tc #2C1F00\",\\\n        \"$ \tc #2B2300\",\\\n        \"% \tc #2B2100\",\\\n        \"& \tc #2A2300\",\\\n        \"* \tc #292400\",\\\n        \"= \tc #2D2400\",\\\n        \"- \tc #554D00\",\\\n        \"; \tc #8F8A00\",\\\n        \"> \tc #928D00\",\\\n        \", \tc #504A00\",\\\n        \"' \tc #2C2200\",\\\n        \") \tc #2B2000\",\\\n        \"! \tc #2C2300\",\\\n        \"~ \tc #625C00\",\\\n        \"{ \tc #E1E000\",\\\n        \"] \tc #DBDA00\",\\\n        \"^ \tc #645C00\",\\\n        \"/ \tc #2A2200\",\\\n        \"( \tc #292000\",\\\n        \"_ \tc #777100\",\\\n        \": \tc #F8F800\",\\\n        \"< \tc #746F00\",\\\n        \"[ \tc #3F3700\",\\\n        \"} \tc #EAE900\",\\\n        \"| \tc #FDFD00\",\\\n        \"1 \tc #EAEA00\",\\\n        \"2 \tc #3C3400\",\\\n        \"3 \tc #7C7600\",\\\n        \"4 \tc #F6F500\",\\\n        \"5 \tc #AAA700\",\\\n        \"6 \tc #595200\",\\\n        \"7 \tc #2F2600\",\\\n        \"8 \tc #322900\",\\\n        \"9 \tc #645D00\",\\\n        \"0 \tc #B4B100\",\\\n        \"a \tc #787200\",\\\n        \"b \tc #2C2100\",\\\n        \"c \tc #A6A200\",\\\n        \"d \tc #FAFA00\",\\\n        \"e \tc #948F00\",\\\n        \"f \tc #2F2700\",\\\n        \"g \tc #989400\",\\\n        \"h \tc #F9F900\",\\\n        \"i \tc #A39F00\",\\\n        \"j \tc #A9A500\",\\\n        \"k \tc #C1BD00\",\\\n        \"l \tc #372E00\",\\\n        \"m \tc #292200\",\\\n        \"n \tc #352C00\",\\\n        \"o \tc #C8C500\",\\\n        \"p \tc #A3A000\",\\\n        \"q \tc #847E00\",\\\n        \"r \tc #969200\",\\\n        \"s \tc #292300\",\\\n        \"t \tc #979400\",\\\n        \"u \tc #7D7800\",\\\n        \"v \tc #453D00\",\\\n        \"w \tc #767100\",\\\n        \"x \tc #797300\",\\\n        \"y \tc #433B00\",\\\n        \"z \tc #2D2300\",\\\n        \"A \tc #EDED00\",\\\n        \"B \tc #979200\",\\\n        \"C \tc #878200\",\\\n        \"D \tc #C4C200\",\\\n        \"E \tc #C1BF00\",\\\n        \"F \tc #837D00\",\\\n        \"G \tc #F8F700\",\\\n        \"H \tc #312800\",\\\n        \"I \tc #8B8600\",\\\n        \"J \tc #8D8800\",\\\n        \"K \tc #736D00\",\\\n        \"L \tc #E4E300\",\\\n        \"M \tc #F5F500\",\\\n        \"N \tc #2E2600\",\\\n        \"O \tc #2B2400\",\\\n        \"P \tc #2A2400\",\\\n        \"Q \tc #2D2500\",\\\n        \"R \tc #382F00\",\\\n        \"S \tc #A09C00\",\\\n        \"T \tc #696200\",\\\n        \"U \tc #4B4300\",\\\n        \"V \tc #4F4600\",\\\n        \"W \tc #686100\",\\\n        \"X \tc #FDFC00\",\\\n        \"Y \tc #FEFE00\",\\\n        \"Z \tc #A19E00\",\\\n        \"` \tc #2A2100\",\\\n        \" .\tc #A5A100\",\\\n        \"..\tc #A4A100\",\\\n        \"+.\tc #6B6500\",\\\n        \"@.\tc #524A00\",\\\n        \"#.\tc #4E4700\",\\\n        \"$.\tc #656000\",\\\n        \"%.\tc #362E00\",\\\n        \"&.\tc #ADAA00\",\\\n        \"*.\tc #362D00\",\\\n        \"=.\tc #E7E500\",\\\n        \"-.\tc #F7F600\",\\\n        \";.\tc #E2E000\",\\\n        \">.\tc #777000\",\\\n        \",.\tc #878300\",\\\n        \"'.\tc #8E8900\",\\\n        \").\tc #2E2500\",\\\n        \"!.\tc #332A00\",\\\n        \"~.\tc #888300\",\\\n        \"{.\tc #BDBB00\",\\\n        \"].\tc #2A2000\",\\\n        \"^.\tc #C5C300\",\\\n        \"/.\tc #827E00\",\\\n        \"(.\tc #ECEC00\",\\\n        \"_.\tc #938E00\",\\\n        \":.\tc #463E00\",\\\n        \"<.\tc #746D00\",\\\n        \"[.\tc #756F00\",\\\n        \"}.\tc #423A00\",\\\n        \"|.\tc #827D00\",\\\n        \"1.\tc #928E00\",\\\n        \"2.\tc #2D2000\",\\\n        \"3.\tc #807A00\",\\\n        \"4.\tc #A9A400\",\\\n        \"5.\tc #C7C500\",\\\n        \"6.\tc #342B00\",\\\n        \"7.\tc #C2BE00\",\\\n        \"8.\tc #A9A600\",\\\n        \"9.\tc #959100\",\\\n        \"0.\tc #A4A000\",\\\n        \"a.\tc #7D7700\",\\\n        \"b.\tc #565000\",\\\n        \"c.\tc #302600\",\\\n        \"d.\tc #EDEC00\",\\\n        \"e.\tc #E9E800\",\\\n        \"f.\tc #3E3700\",\\\n        \"g.\tc #766F00\",\\\n        \"h.\tc #655F00\",\\\n        \"i.\tc #DEDD00\",\\\n        \"j.\tc #E0DF00\",\\\n        \"k.\tc #635D00\",\\\n        \"l.\tc #949000\",\\\n        \"m.\tc #908B00\",\\\n        \"n.\tc #FFEA00\",\\\n        \"o.\tc #FFE600\",\\\n        \"p.\tc #FFE100\",\\\n        \"                                                          . . . . . .                                                           \",\\\n        \"                                                          . + + + + .                                                           \",\\\n        \"                                                @ @ @ @ @ @ @ @ @ @ @                                                           \",\\\n        \"                                          @ @ @ @ @ @ @ @ @ @ @ @ @ @                                                           \",\\\n        \"                                      @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @                                                           \",\\\n        \"                                  @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @                                                           \",\\\n        \"                              @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @                                                           \",\\\n        \"                            @ @ @ @ @ @ @ @ @ @ @ @       . + + + + .                                                           \",\\\n        \"                          @ @ @ @ @ @ @ @ @ @             . + + + + .                                                           \",\\\n        \"                        @ @ @ @ @ @ @ @ @                 . + + + + .                                                           \",\\\n        \"                    @ @ @ @ @ @ @ @ @               # $ $ . + + + + . . % #                                                     \",\\\n        \"                    @ @ @ @ @ @ @               & . . . . . + + + + . . . . . .                                                 \",\\\n        \"                  @ @ @ @ @ @ @           * . . . . = - ; . + + + + . > , = . . . ' )                                           \",\\\n        \"                @ @ @ @ @ @ @           % . . ! ~ { + + + . + + + + . + + + ] ^ . . . /                                         \",\\\n        \"              @ @ @ @ @ @ @         ( . . . _ : + + + + + . + + + + . + + + + + : < . . . (                                     \",\\\n        \"            @ @ @ @ @ @ @         $ . . [ } + + + + + + | . + + + + . | + + + + + + 1 2 . . .                                   \",\\\n        \"            @ @ @ @ @ @         % . . 3 + + + + + 4 5 6 7 . + + + + . 8 9 0 4 + + + + + a . . .                                 \",\\\n        \"          @ @ @ @ @ @         b . . c + + + + d e f . . . . + + + + . . . . 8 g h + + + + i . . b                               \",\\\n        \"          @ @ @ @ @ @       . . . j + + + + k l . . ' m   . + + + + .   % & . . n o + + + + p . . .                             \",\\\n        \"        @ @ @ @ @ @         . . q + + + + r . . ' #       . + + + + .       s ' . ! t + + + + u . .                             \",\\\n        \"        @ @ @ @ @         $ . v + + + + w . . !           . . . . . .           / . . x + + + + y . .                           \",\\\n        \"      @ @ @ @ @ @       z . ' A + + + > . . =                                     % . . B + + + } ! . )                         \",\\\n        \"      @ @ @ @ @ @       . . C + + + D . . z                                         $ . . E + + + F . '                         \",\\\n        \"      @ @ @ @ @       # . ! d + + G H . $                                             b . n d + + : ! .                         \",\\\n        \"    @ @ @ @ @ @       & . _ + + + I . .                                                 % . J + + + K . .                       \",\\\n        \"    @ @ @ @ @ @       . . L + + M N . O                   . . . . . .                   P . Q 4 + + L . .                       \",\\\n        \"    @ @ @ @ @       P . R + + + S . .                     . + + + + .                     . . p + + + n .                       \",\\\n        \"    @ @ @ @ @       & . T + + + U . m                     . + + + + .                     $ . V + + + W . %                     \",\\\n        \"    @ @ @ @ @       / . j + + X = .                       . + + + + .                       . Q Y + + Z . `                     \",\\\n        \". . @ @ @ @ @ . . . . . . . . . . . . . .         . . . . . + + + + . . . . .           . . . . . . . . . . . . . @ @ @ @ @ . . \",\\\n        \"+ + @ @ @ @ @ + + + + + + + + + + + + + .         . + + + + + + + + + + + + .           . + + + + + + + + + + + + @ @ @ @ @ + . \",\\\n        \"+ + @ @ @ @ @ + + + + + + + + + + + + + .         . + + + + + + + + + + + + .           . + + + + + + + + + + + + @ @ @ @ @ + . \",\\\n        \"+ + @ @ @ @ @ + + + + + + + + + + + + + .         . + + + + + + + + + + + + .           . + + + + + + + + + + + + @ @ @ @ @ + . \",\\\n        \"+ + @ @ @ @ @ + + + + + + + + + + + + + .         . + + + + + + + + + + + + .           . + + + + + + + + + + + + @ @ @ @ @ + . \",\\\n        \". . @ @ @ @ @ . . . . . . . . . . . . . .         . . . . . + + + + . . . . .           . . . . . . . . . . . . . @ @ @ @ @ . . \",\\\n        \"    @ @ @ @ @       . .  .+ + | = .                       . + + + + .                       . Q | + + ... $       @ @ @ @ @     \",\\\n        \"    @ @ @ @ @       ' . +.+ + + @.. .                     . + + + + .                     ) . #.+ + + $.. %       @ @ @ @ @     \",\\\n        \"    @ @ @ @ @       s . %.+ + + &.. .                     . + + + + .                     . . p + + + *..         @ @ @ @ @     \",\\\n        \"    @ @ @ @ @ @       . . =.+ + -.Q .                     . . . . . .                   s . N 4 + + ;.. .       @ @ @ @ @ @     \",\\\n        \"      @ @ @ @ @       . . >.+ + + ,.. .                                                 ' . '.+ + + >.. .       @ @ @ @ @       \",\\\n        \"      @ @ @ @ @       O . ).d + + h !.. `                                             $ . 8 : + + h = .         @ @ @ @ @       \",\\\n        \"      @ @ @ @ @ @       . . ~.+ + + {.. . ].                                        ' . . ^.+ + + /.. '       @ @ @ @ @ @       \",\\\n        \"      @ @ @ @ @ @       * . ! (.+ + + > . . *             . . . . . .             = . . _.+ + + (.! . %       @ @ @ @ @ @       \",\\\n        \"        @ @ @ @ @ @       % . :.+ + + + <.. . $           . + + + + .           . . . [.+ + + + }.. /       @ @ @ @ @ @         \",\\\n        \"        @ @ @ @ @ @         . . |.+ + + + 1.. . . O       . + + + + .       2.. . . B + + + + 3.. .         @ @ @ @ @ @         \",\\\n        \"          @ @ @ @ @ @       = . . 4.+ + + + 5.6.. . . b   . + + + + .   m / . . l 7.+ + + + j . . =       @ @ @ @ @ @           \",\\\n        \"          @ @ @ @ @ @         $ . . 8.+ + + + : 9.H . . . . + + + + . . . . f e d + + + + 0.. . /         @ @ @ @ @ @           \",\\\n        \"            @ @ @ @ @ @         ! . . a.+ + + + + M 5 b.c.. + + + + . ).6 5 M + + + + + a . . &         @ @ @ @ @ @             \",\\\n        \"            @ @ @ @ @ @ @         $ . . [ d.+ + + + + + X . + + + + . | + + + + + + e.f.. . $         @ @ @ @ @ @ @             \",\\\n        \"              @ @ @ @ @ @ @         $ . . % _ h + + + + + . + + + + . + + + + + : g.% . . %         @ @ @ @ @ @ @               \",\\\n        \"                @ @ @ @ @ @ @           $ . . $ h.i.+ + + . + + + + . + + + j.k.! . . .           @ @ @ @ @ @ @                 \",\\\n        \"                  @ @ @ @ @ @ @           * . . . . N @.l.. + + + + . m.- = . . . % )           @ @ @ @ @ @ @                   \",\\\n        \"                    @ @ @ @ @ @ @             # % . . . . . + + + + . . . . . .               @ @ @ @ @ @ @                     \",\\\n        \"                    @ @ @ @ @ @ @ @ @               O & . . + + + + . . & #               @ @ @ @ @ @ @ @ @                     \",\\\n        \"                        @ @ @ @ @ @ @ @ @                 . + + + + .                 @ @ @ @ @ @ @ @ @                         \",\\\n        \"                          @ @ @ @ @ @ @ @ @ @             . + + + + .             @ @ @ @ @ @ @ @ @ @                           \",\\\n        \"                            @ @ @ @ @ @ @ @ @ @ @ @       . + + + + .       @ @ @ @ @ @ @ @ @ @ @ @                             \",\\\n        \"                              @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @                               \",\\\n        \"                                  @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @                                   \",\\\n        \"                                      @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @                                       \",\\\n        \"                                          @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @                                           \",\\\n        \"                                                @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @                                                 \",\\\n        \"                                                          . n.o.p.+ .                                                           \",\\\n        \"                                                          . . . . . .                                                           \"])\n\n    def textEnglish(self):\n        buttonText = \"Cosmetic hole thread ground view\"\n        helpText = \"Draw cosmetic hole threads ground view:\"+ \"\\n\"\\\n                   \"- pick favoured line attributes\"+ \"\\n\"\\\n                   \"- select many circles\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Grundri\u00df kosmetisches Bohrungsgewinde\"\n        helpText = \"Zeichne ein kosmetisches Bohrungsgewinde im Grundri\u00df:\"+ \"\\n\"\\\n                   \"- w\u00e4hle die gew\u00fcnschten Eigenschaften der Linien\"+ \"\\n\"\\\n                   \"- w\u00e4hle mehrere Kreise\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Filettatura foro in pianta\"\n        helpText = \"Disegna il simbolo tecnico della filettatura in pianta di un foro:\"+ \"\\n\"\\\n                   \"- scegliere gli attributi linea\"+ \"\\n\"\\\n                   \"- selezionare la/e circonferenza/e che rappresentano i fori filettati\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Filetage du trou en plan\"\n        helpText = \"Dessinez le symbole technique du filetage dans le plan d'un trou:\"+ \"\\n\"\\\n                   \"- choisir les attributs de ligne\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez la (les) circonf\u00e9rence (s) qui repr\u00e9sentent les trous filet\u00e9s\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Rosca de agujero en planta\"\n        helpText = \"Dibujar el s\u00edmbolo t\u00e9cnico de la rosca de un agujero en planta:\"+ \"\\n\"\\\n                   \"- elegir atributos de l\u00ednea\"+ \"\\n\"\\\n                   \"- seleccione la (s) circunferencia (s) que representan los orificios roscados\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            commonTools.drawCosmeticThreadArcs(View,ObjectList,True)\n            gui.Selection.clearSelection()\n\nclass DrawCosmeticThreadBolt:\n    '''Draw a cosmetic bolt thread at selected circles'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 202 2\",\\\n        \"  \tc None\",\\\n        \". \tc #2B2200\",\\\n        \"+ \tc #FFFF00\",\\\n        \"@ \tc #2A2300\",\\\n        \"# \tc #2C2200\",\\\n        \"$ \tc #2B2300\",\\\n        \"% \tc #2A2200\",\\\n        \"& \tc #2F2600\",\\\n        \"* \tc #4C4500\",\\\n        \"= \tc #3F3700\",\\\n        \"- \tc #777100\",\\\n        \"; \tc #B4B100\",\\\n        \"> \tc #E9E800\",\\\n        \", \tc #FDFD00\",\\\n        \"' \tc #FCFC00\",\\\n        \") \tc #E7E700\",\\\n        \"! \tc #767000\",\\\n        \"~ \tc #3E3600\",\\\n        \"{ \tc #2D2000\",\\\n        \"] \tc #2B2100\",\\\n        \"^ \tc #322900\",\\\n        \"/ \tc #D1CF00\",\\\n        \"( \tc #FEFE00\",\\\n        \"_ \tc #756F00\",\\\n        \": \tc #342C00\",\\\n        \"< \tc #8B8600\",\\\n        \"[ \tc #F3F300\",\\\n        \"} \tc #F6F500\",\\\n        \"| \tc #918D00\",\\\n        \"1 \tc #332B00\",\\\n        \"2 \tc #2C2300\",\\\n        \"3 \tc #7C7600\",\\\n        \"4 \tc #F7F600\",\\\n        \"5 \tc #F0F000\",\\\n        \"6 \tc #F5F500\",\\\n        \"7 \tc #7A7400\",\\\n        \"8 \tc #463F00\",\\\n        \"9 \tc #D6D400\",\\\n        \"0 \tc #D8D600\",\\\n        \"a \tc #827D00\",\\\n        \"b \tc #362E00\",\\\n        \"c \tc #858000\",\\\n        \"d \tc #D9D800\",\\\n        \"e \tc #D7D600\",\\\n        \"f \tc #463E00\",\\\n        \"g \tc #2A2100\",\\\n        \"h \tc #6F6900\",\\\n        \"i \tc #FBFB00\",\\\n        \"j \tc #898300\",\\\n        \"k \tc #2E2600\",\\\n        \"l \tc #8A8600\",\\\n        \"m \tc #F6F600\",\\\n        \"n \tc #FAFA00\",\\\n        \"o \tc #6C6700\",\\\n        \"p \tc #A19E00\",\\\n        \"q \tc #F8F800\",\\\n        \"r \tc #756E00\",\\\n        \"s \tc #787300\",\\\n        \"t \tc #9E9A00\",\\\n        \"u \tc #B5B200\",\\\n        \"v \tc #ADAA00\",\\\n        \"w \tc #2E2500\",\\\n        \"x \tc #2C2100\",\\\n        \"y \tc #B2AE00\",\\\n        \"z \tc #B4B000\",\\\n        \"A \tc #BDBA00\",\\\n        \"B \tc #F9F900\",\\\n        \"C \tc #595200\",\\\n        \"D \tc #5C5500\",\\\n        \"E \tc #BDB900\",\\\n        \"F \tc #A6A100\",\\\n        \"G \tc #E9E900\",\\\n        \"H \tc #383000\",\\\n        \"I \tc #393100\",\\\n        \"J \tc #ECEC00\",\\\n        \"K \tc #817C00\",\\\n        \"L \tc #E0DE00\",\\\n        \"M \tc #FF0000\",\\\n        \"N \tc #332C00\",\\\n        \"O \tc #E2E100\",\\\n        \"P \tc #7D7700\",\\\n        \"Q \tc #4A4200\",\\\n        \"R \tc #E6E500\",\\\n        \"S \tc #302700\",\\\n        \"T \tc #E4E400\",\\\n        \"U \tc #484100\",\\\n        \"V \tc #2D2500\",\\\n        \"W \tc #EFED00\",\\\n        \"X \tc #F2F200\",\\\n        \"Y \tc #383100\",\\\n        \"Z \tc #2B2000\",\\\n        \"` \tc #393200\",\\\n        \" .\tc #EDEC00\",\\\n        \"..\tc #9A9600\",\\\n        \"+.\tc #544B00\",\\\n        \"@.\tc #292300\",\\\n        \"#.\tc #504900\",\\\n        \"$.\tc #969200\",\\\n        \"%.\tc #3D3500\",\\\n        \"&.\tc #8B8700\",\\\n        \"*.\tc #8F8A00\",\\\n        \"=.\tc #3C3300\",\\\n        \"-.\tc #C2C000\",\\\n        \";.\tc #E7E500\",\\\n        \">.\tc #2D2400\",\\\n        \",.\tc #E5E400\",\\\n        \"'.\tc #C0BD00\",\\\n        \").\tc #574F00\",\\\n        \"!.\tc #D0CE00\",\\\n        \"~.\tc #D0CF00\",\\\n        \"{.\tc #B1AE00\",\\\n        \"].\tc #5B5400\",\\\n        \"^.\tc #595300\",\\\n        \"/.\tc #615B00\",\\\n        \"(.\tc #E7E600\",\\\n        \"_.\tc #605800\",\\\n        \":.\tc #C9C600\",\\\n        \"<.\tc #C6C300\",\\\n        \"[.\tc #433B00\",\\\n        \"}.\tc #453D00\",\\\n        \"|.\tc #372F00\",\\\n        \"1.\tc #EDED00\",\\\n        \"2.\tc #EEED00\",\\\n        \"3.\tc #372E00\",\\\n        \"4.\tc #716B00\",\\\n        \"5.\tc #B6B200\",\\\n        \"6.\tc #B7B400\",\\\n        \"7.\tc #6F6A00\",\\\n        \"8.\tc #2C2400\",\\\n        \"9.\tc #A39F00\",\\\n        \"0.\tc #888300\",\\\n        \"a.\tc #A09B00\",\\\n        \"b.\tc #D0CD00\",\\\n        \"c.\tc #645E00\",\\\n        \"d.\tc #666000\",\\\n        \"e.\tc #CDCC00\",\\\n        \"f.\tc #CFCD00\",\\\n        \"g.\tc #676000\",\\\n        \"h.\tc #CDCB00\",\\\n        \"i.\tc #868100\",\\\n        \"j.\tc #B8B500\",\\\n        \"k.\tc #292100\",\\\n        \"l.\tc #EFEE00\",\\\n        \"m.\tc #443C00\",\\\n        \"n.\tc #C7C600\",\\\n        \"o.\tc #8F8B00\",\\\n        \"p.\tc #C5C200\",\\\n        \"q.\tc #605A00\",\\\n        \"r.\tc #5E5700\",\\\n        \"s.\tc #5A5400\",\\\n        \"t.\tc #B0AC00\",\\\n        \"u.\tc #D2D000\",\\\n        \"v.\tc #AEAC00\",\\\n        \"w.\tc #C1BE00\",\\\n        \"x.\tc #E6E600\",\\\n        \"y.\tc #3C3400\",\\\n        \"z.\tc #8E8A00\",\\\n        \"A.\tc #908B00\",\\\n        \"B.\tc #3B3200\",\\\n        \"C.\tc #989300\",\\\n        \"D.\tc #544C00\",\\\n        \"E.\tc #514900\",\\\n        \"F.\tc #949000\",\\\n        \"G.\tc #3A3300\",\\\n        \"H.\tc #3A3200\",\\\n        \"I.\tc #F4F400\",\\\n        \"J.\tc #ECEB00\",\\\n        \"K.\tc #EAE900\",\\\n        \"L.\tc #484000\",\\\n        \"M.\tc #7B7600\",\\\n        \"N.\tc #A09C00\",\\\n        \"O.\tc #BBB800\",\\\n        \"P.\tc #B3AF00\",\\\n        \"Q.\tc #B4B200\",\\\n        \"R.\tc #9C9700\",\\\n        \"S.\tc #797500\",\\\n        \"T.\tc #2C1F00\",\\\n        \"U.\tc #9B9600\",\\\n        \"V.\tc #6B6500\",\\\n        \"W.\tc #8C8700\",\\\n        \"X.\tc #302800\",\\\n        \"Y.\tc #8C8800\",\\\n        \"Z.\tc #6B6400\",\\\n        \"`.\tc #D3D100\",\\\n        \" +\tc #DCDB00\",\\\n        \".+\tc #878200\",\\\n        \"++\tc #898500\",\\\n        \"@+\tc #292200\",\\\n        \"#+\tc #797300\",\\\n        \"$+\tc #F1F100\",\\\n        \"%+\tc #766F00\",\\\n        \"&+\tc #312800\",\\\n        \"*+\tc #837D00\",\\\n        \"=+\tc #918C00\",\\\n        \"-+\tc #322A00\",\\\n        \";+\tc #726D00\",\\\n        \">+\tc #CECB00\",\\\n        \",+\tc #736D00\",\\\n        \"'+\tc #B2AF00\",\\\n        \")+\tc #FDFC00\",\\\n        \"!+\tc #B1AD00\",\\\n        \"~+\tc #4B4300\",\\\n        \"                                                          . + + + + .                                                           \",\\\n        \"                                                    @ # . . + + + + . . # $                                                     \",\\\n        \"                                            % . . . . & * . + + + + . * & . . . . %                                             \",\\\n        \"                                        . . . = - ; > , + . + + + + . + ' ) ; ! ~ . . .                                         \",\\\n        \"                                  { ] . ^ ! / ( + + + + + . + + + + . + + + + + ( / _ ^ . .                                     \",\\\n        \"                                . . : < [ + + + + + + + + . + + + + . + + + + + + + + } | 1 . .                                 \",\\\n        \"                            ] $ 2 3 4 + + + + + + + + ( 5 . + + + + . 5 ( + + + + + + + + 6 7 . . #                             \",\\\n        \"                          # . 8 9 + + + + + + + 0 a b . . . + + + + . . . b c d + + + + + + + e f . g                           \",\\\n        \"                        . . h i + + + + + 6 j k . . . . # . + + + + . . . . . . & l m + + + + + n o . .                         \",\\\n        \"                      . . p + + + + + q r . . . # ]       . + + + + .       @ # . . . s q + + + + + t . .                       \",\\\n        \"                    . 2 u + + + + + v w . . x             . . . . . .             $ . . & y + + + + + z 2 .                     \",\\\n        \"                  $ . A + + + + B C . . x                                             x . . D n + + + + E . .                   \",\\\n        \"                ] . F + + + + G H . #                                                     . . I J + + + + p . .                 \",\\\n        \"              . . K + + + + L 1 . x                       M M M M M M                       % . N O + + + + P . 2               \",\\\n        \"            ] . Q , + + + R ^ . ]                 M M M M M M M M M M                         2 . S T + + + , U . #             \",\\\n        \"            $ V W + + + X Y . x               M M M M M M M M M M M M                           Z . ` [ + + +  .V .             \",\\\n        \"          . . ..+ + + ( +.. g             M M M M M M M M M M M M M M                             @.. #.( + + + $.. 2           \",\\\n        \"          . %., + + + &.. $             M M M M M M M M M M M M M M M                               % . *.+ + + , =..           \",\\\n        \"        ] . -.+ + + ;.>..             M M M M M M M M M M . + + + + .                                 . >.,.+ + + '.. #         \",\\\n        \"        . Y ( + + + )..             M M M M M M M M       . + + + + .                                   . C + + + ( H .         \",\\\n        \"      . . y + + + !.. x           M M M M M M M           . + + + + .                                   $ . ~.+ + + {.. #       \",\\\n        \"      . . n + + + ].]           M M M M M M M M           . . . . . .                                     . ^.+ + + n . .       \",\\\n        \"    x . /.+ + + R . $           M M M M M M                                                               $ . (.+ + + _.. $     \",\\\n        \"    . . :.+ + + *..           M M M M M M M                                                                 . | + + + <.. .     \",\\\n        \"    . . q + + + [.#           M M M M M                                                                     $ }.+ + + m . ]     \",\\\n        \"    . |.+ + + 1.. $         M M M M M M                   . . . . . .                                       # . 2.+ + + 3..     \",\\\n        \"  @ . 4.+ + + 5..           M M M M M                     . + + + + .                                         . 6.+ + + 7.. 8.  \",\\\n        \"  . . 9.+ + + c .           M M M M M                     . + + + + .                                         . 0.+ + + a.. $   \",\\\n        \"  . . b.+ + + c.#           M M M M                       . + + + + .                                         . d.+ + + e.. .   \",\\\n        \". . . . . . . . . . . .   M M M M M . . . .       . . . . . + + + + . . . . .       . . . . M M M M M   . . . . . . . . . . . . \",\\\n        \". + + + + + + + + + + .   M M M M M + + + .       . + + + + + + + + + + + + .       . + + + M M M M M   . + + + + + + + + + + . \",\\\n        \". + + + + + + + + + + .   M M M M M + + + .       . + + + + + + + + + + + + .       . + + + M M M M M   . + + + + + + + + + + . \",\\\n        \". + + + + + + + + + + .   M M M M M + + + .       . + + + + + + + + + + + + .       . + + + M M M M M   . + + + + + + + + + + . \",\\\n        \". + + + + + + + + + + .   M M M M M + + + .       . + + + + + + + + + + + + .       . + + + M M M M M   . + + + + + + + + + + . \",\\\n        \". . . . . . . . . . . .   M M M M M . . . .       . . . . . + + + + . . . . .       . . . . M M M M M   . . . . . . . . . . . . \",\\\n        \"  . . f.+ + + c.#           M M M M M                     . + + + + .                     M M M M M           ] g.+ + + h.. .   \",\\\n        \"  # . 9.+ + + i..           M M M M M                     . + + + + .                     M M M M M           ] 0.+ + + a.. $   \",\\\n        \"  $ . 4.+ + + 6..           M M M M M                     . . . . . .                     M M M M M         { . j.+ + + h . k.  \",\\\n        \"    . b + + + 1.. $         M M M M M M                                                 M M M M M           ] . l.+ + + 3..     \",\\\n        \"    . . q + + + m..           M M M M M                                               M M M M M M           . }.+ + + m . .     \",\\\n        \"    . . n.+ + + o..           M M M M M M                                             M M M M M             . | + + + p.. @     \",\\\n        \"    % . q.+ + + (.. $           M M M M M M                                         M M M M M M           % . (.+ + + r.. 8.    \",\\\n        \"      . . B + + + D ]             M M M M M M             . . . . . .             M M M M M M             . s.+ + + n . .       \",\\\n        \"      . . t.+ + + / . $           M M M M M M M           . + + + + .         M M M M M M M M           ] . u.+ + + v.. @       \",\\\n        \"        . H ( + + + C .             M M M M M M M M       . + + + + .       M M M M M M M M             . ^.+ + + ( H .         \",\\\n        \"        . . w.+ + + (.>..             M M M M M M M M M M . + + + + . M M M M M M M M M M             # >.x.+ + + A . .         \",\\\n        \"          . y., + + + z.. %             M M M M M M M M M M M M M M M M M M M M M M M M             @ . A.+ + + , B..           \",\\\n        \"          . . C.+ + + ( D.. x               M M M M M M M M M M M M M M M M M M M M               . . E.( + + + F.. .           \",\\\n        \"            . >. .+ + + [ G.. Z               M M M M M M M M M M M M M M M M M M               @ . H.I.+ + + J.>..             \",\\\n        \"            # . m., + + + K.1 . $                 M M M M M M M M M M M M M M                 . . ^ > + + + , L.. @             \",\\\n        \"              2 . P + + + + O N . #                       M M M M M M                       ] . N O + + + + M.. .               \",\\\n        \"                . . p + + + + J I . .                                                     $ . B. .+ + + + N.. $                 \",\\\n        \"                  . . O.+ + + + i D . . .                                             # . . r.i + + + + O.. #                   \",\\\n        \"                    . 2 P.+ + + + + P.& . ] .             . . . . . .             % . . S Q.+ + + + + y 2 .                     \",\\\n        \"                      . . R.+ + + + + B S.. . . $ #       . + + + + .     T.. . . . . P B + + + + + U.. #                       \",\\\n        \"                        . . V.n + + + + + m W.X.. . . . . . + + + + . . ] . . . X.Y.q + + + + + n Z.. ]                         \",\\\n        \"                          # . }.`.+ + + + + + +  +.+|.. . . + + + + . . . Y ++ ++ + + + + + + 9 m.. g                           \",\\\n        \"                            @+. . #+I.+ + + + + + + + ( $+. + + + + . $+( + + + + + + + + [ %+. . @                             \",\\\n        \"                                @ . &+*+X + + + + + + + + . + + + + . + + + + + + + + m =+-+. ]                                 \",\\\n        \"                                    % . &+;+>+( + + + + + . + + + + . + + + + + ( >+;+&+. .                                     \",\\\n        \"                                        @ . . y.,+'+(.)++ . + + + + . + )+(.!+,+y.. . @                                         \",\\\n        \"                                            8.@ # . . w ~+. + + + + . Q w . . # 2 {                                             \",\\\n        \"                                                    { $ 2 . + + + + . 2 $ 8.                                                    \",\\\n        \"                                                          . . . . . .                                                           \"])\n\n    def textEnglish(self):\n        buttonText = \"Screw/pin/shaft thread in plan\"\n        helpText = \"Draw the technical symbol of the thread in the screw/pin/shaft plant :\"+ \"\\n\"\\\n                   \"- pick favoured line attributes\"+ \"\\n\"\\\n                   \"- select the circumference (s) that represent screw/pin/shaft\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Schraube/Stift/ Wellengewinde im Grundriss\"\n        helpText = \"Zeichne das technische Symbol  Schraube/Stift/ Wellengewinde im Grundriss:\"+ \"\\n\"\\\n                   \"- w\u00e4hle die gew\u00fcnschten Eigenschaften der Linien\"+ \"\\n\"\\\n                   \"- w\u00e4hle die Umrisse von Schraube/Stift/Wellengewinde\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Filettatura vite/perno/albero in pianta\"\n        helpText = \"Disegna il simbolo tecnico della filettatura vite/perno/albero in pianta:\"+ \"\\n\"\\\n                   \"- scegliere gli attributi linea\"+ \"\\n\"\\\n                   \"- selezionare la/e circonferenza/e che rappresentano vite/perno/albero\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Filetage vis/goupille/arbre en plan\"\n        helpText = \"Dessinez le symbole technique du filetage vis/pivot/axe en plan:\"+ \"\\n\"\\\n                   \"- choisir les attributs de ligne\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez la (les) circonf\u00e9rence (s) repr\u00e9sentant la vis/la broche/l'axe\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Rosca de tornillo/pasador/eje en planta\"\n        helpText = \"Dibujar en plano el s\u00edmbolo t\u00e9cnico de la rosca de tornillo/pivote/\u00e1rbol en planta:\"+ \"\\n\"\\\n                   \"- elegir atributos de l\u00ednea\"+ \"\\n\"\\\n                   \"- seleccione la (s) circunferencia (s) que representan tornillo/pasador/eje\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            commonTools.drawCosmeticThreadArcs(View,ObjectList,False)\n            gui.Selection.clearSelection()\n\nclass DrawCosmeticThreadSideHole:\n    '''Draw cosmetic hole thread side view'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 13 1\",\\\n        \" \tc None\",\\\n        \".\tc #2B2200\",\\\n        \"+\tc #FFFF00\",\\\n        \"@\tc #FF0000\",\\\n        \"#\tc #FAFA00\",\\\n        \"$\tc #2D2300\",\\\n        \"%\tc #292400\",\\\n        \"&\tc #2C2300\",\\\n        \"*\tc #2C1F00\",\\\n        \"=\tc #322900\",\\\n        \"-\tc #2B2100\",\\\n        \";\tc #2D2200\",\\\n        \">\tc #2B2400\",\\\n        \"                              ....                              \",\\\n        \"                              .++.                              \",\\\n        \"  @@@@@@                      .#+.            $$$$$%            \",\\\n        \"  @@@@@@   ........           .#+.           ........   @@@@@@  \",\\\n        \"  @@@@@@   ........           .#+.           ........   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .#+.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .#+.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .#+.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .#+.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .#+.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .#+.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           &...           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           ....           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           ....           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           ....           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           ....           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           ....*          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++=-          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++=-          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           &...;          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..                          ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           ....           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ..++++..   @@@@@@  \",\\\n        \"  @@@@@@   ..++++..           .++.           ........   @@@@@@  \",\\\n        \"  @@@@@@   ........           .++.           ........   @@@@@@  \",\\\n        \"           ........           .++.            >$$$$%            \",\\\n        \"                              .++.                              \",\\\n        \"                              ....                              \"])\n\n    def textEnglish(self):\n        buttonText = \"Cosmetic thread side view\"\n        helpText = \"Draw a cosmetic thread:\"+ \"\\n\"\\\n                   \"- pick favoured line attributes\"+ \"\\n\"\\\n                   \"- select two parallel lines\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Seitenri\u00df kosmetisches Bohrungsgewinde\"\n        helpText = \"Zeiche ein symbolisches Bohrungsgewinde von der Seite:\"+ \"\\n\"\\\n                   \"- w\u00e4hle die gew\u00fcnschten Eigenschaften der Linien\"+ \"\\n\"\\\n                   \"- w\u00e4hle zwei parallele Linien\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Filettatura foro vista laterale/sezione\"\n        helpText = \"Disegna il simbolo tecnico della filettatura di un foro in vista laterale o sezione:\"+ \"\\n\"\\\n                   \"- scegliere gli attributi linea\"+ \"\\n\"\\\n                   \"- selezionare due linee parallele che rappresentano il foro da filettare\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Filetage du trou vue c\u00f4t\u00e9/section\"\n        helpText = \"Dessine le symbole technique du filetage d'un trou en vue de c\u00f4t\u00e9 ou en coupe:\"+ \"\\n\"\\\n                   \"- choisir les attributs de ligne\"+ \"\\n\"\\\n                   \"- s\u00e9lectionner deux lignes parall\u00e8les repr\u00e9sentant le trou \u00e0 tarauder\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Rosca del orificio vista lateralde/ secci\u00f3n\"\n        helpText = \"Dibuja el s\u00edmbolo t\u00e9cnico de la rosca de un agujero en la vista lateral o en secci\u00f3n:\"+ \"\\n\"\\\n                   \"- elegir atributos de l\u00ednea\"+ \"\\n\"\\\n                   \"- seleccione dos l\u00edneas paralelas que representen el agujero que se va a roscar\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            commonTools.drawCosmeticThreadLines(View,ObjectList,True)\n            gui.Selection.clearSelection()\n\nclass DrawCosmeticThreadSideBolt:\n    '''Draw cosmetic bolt thread side view'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 10 1\",\\\n        \" \tc None\",\\\n        \".\tc #2B2200\",\\\n        \"+\tc #FFFF00\",\\\n        \"@\tc #FF0000\",\\\n        \"#\tc #2D2300\",\\\n        \"$\tc #2C2300\",\\\n        \"%\tc #2B2300\",\\\n        \"&\tc #292100\",\\\n        \"*\tc #2A2100\",\\\n        \"=\tc #F1F000\",\\\n        \"                             .....                              \",\\\n        \"                             .+++.                              \",\\\n        \"  .......   @@@@@@           .+++.                     ######   \",\\\n        \"  .......   @@@@@@           .+++.            @@@@@@   .......  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   .......  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .....            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@                            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@                            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@                            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@                            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .....            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .....            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@                            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@                            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@                            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           $%%%$            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .....            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .....            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           &%%%*            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@                            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@                            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@                            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .....            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+=+.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .....            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@                            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@                            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@                            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@                            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .....            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  ..+++..   @@@@@@           .+++.            @@@@@@   ..+++..  \",\\\n        \"  .......   @@@@@@           .+++.            @@@@@@   .......  \",\\\n        \"  .......   @@@@@@           .+++.            @@@@@@   .......  \",\\\n        \"                             .+++.                      #####   \",\\\n        \"                             .+++.                              \",\\\n        \"                             .....                              \"])\n\n    def textEnglish(self):\n        buttonText = \"Thread Screw/pin/shaft side view/section\"\n        helpText = \"Draw the technical symbol of the screw/pin/shaft thread in side or section view :\"+ \"\\n\"\\\n                   \"- pick favoured line attributes\"+ \"\\n\"\\\n                   \"- select two parallel lines representing the screw/pin/shaft thread\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Schraube Gewinde/Stift/Welle Seitenansicht/Abschnitt\"\n        helpText = \"Zeiche ein symbolisches Schraubengewinde von der Seite:\"+ \"\\n\"\\\n                   \"- w\u00e4hle die gew\u00fcnschten Eigenschaften der Linien\"+ \"\\n\"\\\n                   \"- W\u00e4hlen Sie zwei parallele Linien, welche Schraube/Stift/Baum repr\u00e4sentieren\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Filettatura vite/perno/albero vista laterale/sezione\"\n        helpText = \"Disegna il simbolo tecnico della filettatura vite/perno/albero in vista laterale o sezione:\"+ \"\\n\"\\\n                   \"- scegliere gli attributi linea\"+ \"\\n\"\\\n                   \"- selezionare due linee parallele che rappresentano vite/perno/albero da filettare\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Filetage vis/goupille/arbre c\u00f4t\u00e9/section\"\n        helpText = \"Dessinez le symbole technique de la vis/goupille/arbre filetage en vue lat\u00e9rale ou en coupe:\"+ \"\\n\"\\\n                   \"- choisir les attributs de ligne\"+ \"\\n\"\\\n                   \"- s\u00e9lectionner deux lignes parall\u00e8les repr\u00e9sentant la vis/goupille/arbre \u00e0 fileter\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Rosca tornillo/pasador/eje vista lateral/secci\u00f3\"\n        helpText = \"Dibuje el s\u00edmbolo t\u00e9cnico del rosca tornillo/pasador/eje en la vista lateral o en secci\u00f3n:\"+ \"\\n\"\\\n                   \"- elegir atributos de l\u00ednea\"+ \"\\n\"\\\n                   \"- seleccione dos l\u00edneas paralelas que representen tornillo/pasador/eje a roscar\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n\n    def activated(self):\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            commonTools.drawCosmeticThreadLines(View,ObjectList,False)\n            gui.Selection.clearSelection()\n\nclass IntersectionVertex:\n    '''Create  vertexes at intersection of two edges (lines and/or circles)'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 38 1\",\\\n        \" \tc None\",\\\n        \".\tc #2B2200\",\\\n        \"+\tc #2D2400\",\\\n        \"@\tc #FFFF00\",\\\n        \"#\tc #FBFB00\",\\\n        \"$\tc #F9F900\",\\\n        \"%\tc #FAFA00\",\\\n        \"&\tc #F8F800\",\\\n        \"*\tc #F6F500\",\\\n        \"=\tc #F5F500\",\\\n        \"-\tc #F4F400\",\\\n        \";\tc #F3F300\",\\\n        \">\tc #F1F000\",\\\n        \",\tc #F0EF00\",\\\n        \"'\tc #EFEF00\",\\\n        \")\tc #EEEE00\",\\\n        \"!\tc #EBEA00\",\\\n        \"~\tc #EAE900\",\\\n        \"{\tc #FF0000\",\\\n        \"]\tc #E9E800\",\\\n        \"^\tc #FF0200\",\\\n        \"/\tc #FF0100\",\\\n        \"(\tc #FF0C00\",\\\n        \"_\tc #FF0600\",\\\n        \":\tc #FD0000\",\\\n        \"<\tc #FDFD00\",\\\n        \"[\tc #302700\",\\\n        \"}\tc #FEFE00\",\\\n        \"|\tc #FDFC00\",\\\n        \"1\tc #2D2500\",\\\n        \"2\tc #3A2900\",\\\n        \"3\tc #F8F700\",\\\n        \"4\tc #FF0A00\",\\\n        \"5\tc #FF1C00\",\\\n        \"6\tc #FAED00\",\\\n        \"7\tc #FF1300\",\\\n        \"8\tc #2B2400\",\\\n        \"9\tc #2F2700\",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                         ..     \",\\\n        \"                       .....                            .+.     \",\\\n        \"                       .@@@.                           ..@.     \",\\\n        \"                       .@@@.                          ..#@.     \",\\\n        \"                       .@@@.                         ..$@@.     \",\\\n        \"                       ..@@..                       ..%@@@.     \",\\\n        \"                        .@@@.                      ..$@@@..     \",\\\n        \"                        ..@@.                     ..&@@@..      \",\\\n        \"                         .@@..                   ..*@@@..       \",\\\n        \"                         .@@@.                  ..=@@@..        \",\\\n        \"                         ..@@.                 ..=@@@..         \",\\\n        \"                          .@@.                ..-@@@..          \",\\\n        \"                         ..@@.               ..;@@@..           \",\\\n        \"                          ..@.              ..>@@@..            \",\\\n        \"                           .@..            ..,@@@..             \",\\\n        \"                           .@@.           ..'@@@..              \",\\\n        \"                           .@@.          ..)@@@..               \",\\\n        \"                           .@@..        ..!@@@..                \",\\\n        \"                           ..@@.       ..~@@@..                 \",\\\n        \"                           ..{{{{{{   ..]@@@..                  \",\\\n        \"                           {{^{{{{{{{{.]@@@..                   \",\\\n        \"                          {{{{{{{{{{{{{@@@..                    \",\\\n        \"                         {{{{{{{{{{{{{/{@..                     \",\\\n        \"                         {{{{{{{{{{{{{{(..                      \",\\\n        \"                 .......{{{{{{{{{{{{{{{{{                       \",\\\n        \"              ....@@@@@@_{{{{{{{{{{{{{{{:                       \",\\\n        \"            ...@@@@@@@@@{{{{{{{{{{{{{{{{{{                      \",\\\n        \"          ...$@@@......{{{{{{{{{{{{{{{{{{{.                     \",\\\n        \"         ..@@<@...     {{{{{{{{{{{{{{{{{{{[.                    \",\\\n        \"        ..}@@..        {{{{{{{{{{{{{{{{{{{@..                   \",\\\n        \"       ..@|..          {{{{{{{{{{{{{{{{{{{@@..                  \",\\\n        \"      ..@*.1            {{{{{{{{{{{{{{{{{2@@@..                 \",\\\n        \"     ..@@..             {{{{{{{{{{{{{{{{{...@@..                \",\\\n        \"    ..3<..               {{{{{{{{{{{{{{{   ..@@..               \",\\\n        \"    .@@..               ..4{{{{{{{{{{{{{    ..@@..              \",\\\n        \"   ..@@.               ..@{5{{{{{{{{{{{      ..@@..             \",\\\n        \"   .@@..              ..@@@6{{{{{{{7{.        ..@@..            \",\\\n        \"   .3@.              ..@@@%.. {{{{{@@.         ..@@.            \",\\\n        \"  ..@..             ..@@@#..    ..@@@.          ..@@.           \",\\\n        \"  .@@.             ..@@@|..      ..@@..          .@@..          \",\\\n        \"  .@@.            ..@@@|..        .@@@.          ..@@.8         \",\\\n        \"  .@@.           ..@@@|..         .@@@.           .@@..         \",\\\n        \"  ....          ..@@@<..          .@@@.           ..@@9         \",\\\n        \"               ..@@@}..           ..@@..           .@@+         \",\\\n        \"              ..@@@@..             .@@@.           .@@..        \",\\\n        \"             ..*@@@..              .@@@.           ..@@.        \",\\\n        \"            ..@@@}..               ..@@.            .@@.        \",\\\n        \"           ..@@@@..                 .@@..           .@@.        \",\\\n        \"          ..@@@@..                  .@@@.           .@@.        \",\\\n        \"         ..@@@@..                   .@@@.           ....        \",\\\n        \"        ..@@@@..                    ..@@..                      \",\\\n        \"       ..@@@@..                      .@@@.                      \",\\\n        \"      ..@@@@..                       .@@@.                      \",\\\n        \"     ..@@@@..                        .....                      \",\\\n        \"     .}@@@..                                                    \",\\\n        \"     .@@@..                                                     \",\\\n        \"     .@@..                                                      \",\\\n        \"     .@..                                                       \",\\\n        \"     ...                                                        \",\\\n        \"     ..                                                         \",\\\n        \"                                                                \",\\\n        \"                                                                \"])\n\n    def textEnglish(self):\n        buttonText = \"Create Vertex(es) at Intersection\"\n        helpText = \"Create the vertexes at intersection of lines:\"+ \"\\n\"\\\n                   \"- select two lines/circles/arcs\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Erzeuge Fangpunkt(e) im Schnittpunkt\"\n        helpText = \"Erzeuge Fangpunkte im Schnitt von Linien:\"+ \"\\n\"\\\n                   \"- w\u00e4hle zwei Linien/Kreise/Kreisb\u00f6gen\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Vertice/i nell'intersezione\"\n        helpText = \"Inserisce vertice/i cosmetico/i nel/i punto/i di intersezione:\"+ \"\\n\"\\\n                   \"- selezionare linee/circonferenze/archi che intersecano\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Sommet (s) \u00e0 l'intersection\"\n        helpText = \"Ins\u00e9rer des sommets cosm\u00e9tiques au (x) point (s) d'intersection:\"+ \"\\n\"\\\n                   \"- s\u00e9lectionner des lignes/cercles/arcs qui se croisent \"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"V\u00e9rtice (s) en la intersecci\u00f3n\"\n        helpText = \"Insertar v\u00e9rtices cosm\u00e9ticos en los puntos de intersecci\u00f3n:\"+ \"\\n\"\\\n                   \"- seleccionar l\u00edneas/c\u00edrculos/arcos que se cruzan\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            if len(ObjectList) < 2: return\n            Edges = []\n            for ObjectString in ObjectList:\n                if ObjectString[0:4] == 'Edge':\n                    Edges.append(View.getEdgeBySelection(ObjectString))\n            if Edges[0].Curve.TypeId == 'Part::GeomCircle':\n                Line1 = Part.Circle(Edges[0].Curve.Center,app.Vector(0,0,1),Edges[0].Curve.Radius)\n            else:\n                Line1 = Part.Line(Edges[0].Vertexes[0].Point,Edges[0].Vertexes[1].Point)\n            if Edges[1].Curve.TypeId == 'Part::GeomCircle':\n                Line2 = Part.Circle(Edges[1].Curve.Center,app.Vector(0,0,1),Edges[1].Curve.Radius)\n            else:\n                Line2 = Part.Line(Edges[1].Vertexes[0].Point,Edges[1].Vertexes[1].Point)\n            InterPnts = Line1.intersect(Line2)\n            for Ip in InterPnts[:2]:\n                View.makeCosmeticVertex(app.Vector(Ip.X,Ip.Y,Ip.Z))\n                Vertex = View.CosmeticVertexes[-1]\n                Vertex.Size = View.CosmeticVertexes[0].Size\n                View.recompute()\n            gui.Selection.clearSelection()\n\nclass ChangeLineStyle:\n    '''Change style/ thickness/color of selected lines'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 31 1\",\\\n        \" \tc None\",\\\n        \".\tc #2B2200\",\\\n        \"+\tc #2B2300\",\\\n        \"@\tc #322900\",\\\n        \"#\tc #393100\",\\\n        \"$\tc #302700\",\\\n        \"%\tc #FF0000\",\\\n        \"&\tc #FFFF00\",\\\n        \"*\tc #2C2200\",\\\n        \"=\tc #FF0100\",\\\n        \"-\tc #FF0200\",\\\n        \";\tc #FF0300\",\\\n        \">\tc #FF0400\",\\\n        \",\tc #FF0500\",\\\n        \"'\tc #2F2100\",\\\n        \")\tc #312100\",\\\n        \"!\tc #FF3500\",\\\n        \"~\tc #FFF600\",\\\n        \"{\tc #FFF500\",\\\n        \"]\tc #FFF400\",\\\n        \"^\tc #FF2400\",\\\n        \"/\tc #FFF200\",\\\n        \"(\tc #FF0900\",\\\n        \"_\tc #FFF300\",\\\n        \":\tc #FFF700\",\\\n        \"<\tc #FF0600\",\\\n        \"[\tc #FF0F00\",\\\n        \"}\tc #FF1D00\",\\\n        \"|\tc #FFFD00\",\\\n        \"1\tc #FFFE00\",\\\n        \"2\tc #2C2100\",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"   ...........................................                  \",\\\n        \"  +............................................                 \",\\\n        \" ...............................................                \",\\\n        \" ....@#####################################$....      %%%%      \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....     %%%%%%     \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....    %%%%%%%%    \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....   %%%%%%%%%%   \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....  %%%%%%%%%%%%  \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&.... %%%%%%%%%%%%%% \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....%%%%%%%%%%%%%%% \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&...%%%%%%%%%%%%%%%% \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&.*%%%%%%%%%%%%%%%%% \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*%%%%%%%%%%%%%%%%%  \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%%%%%%%%%%%%%%%%%   \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%%%%%%%%%%%%%%%%%    \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%%%%%%%%%%%%%%%%%     \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%%%%%%%%%%%%%%%%%      \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%%%%%%%%%%%%%%%%%       \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%%%%%%%%%%%%%%%%%        \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%%%%%%%%%%%%%%%%%         \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%=%%%%%%%%%%%%%%%          \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%=%%%%%%%%%%%%%%%           \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%-%%%%%%%%%%%%%%%            \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%-%%%%%%%%%%%%%%%             \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&%;%%%%%%%%%%%%%%%              \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&%>%%%%%%%%%%%%%%%               \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&%>%%%%%%%%%%%%%%%                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&%,%%%%%%%%%%%%%%%.                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&%%%%%%%%%%%%%%%%..                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&%%%%%%%%%%%%%%%'..                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&%&&%%%%%%%%%%%%%)...                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&=%%&&%%%%%%%%%%%&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&!%%%%&&%%%%%%%%%~&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&%%%%%%&&%%%%%%%{&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&%%%%%%%&&%%%%%]&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&^%%%%%%%%&&%%%/&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&%%%%%%%%%%&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&%%%%%%%%%%%&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&%%%%%%%%%%&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&%%%%%%%%%(&_&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&:<%%%%%%[&&&&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&}%%%%%&&&&&&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&|%%%%&&&&&&&&&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&%%&&&&&&&&&&&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&1&&&&&&&&&&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....                \",\\\n        \" ....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....                \",\\\n        \" ..............................................                 \",\\\n        \"  2...........................................*                 \",\\\n        \"    ..........................................                  \",\\\n        \"     ........................................                   \"])\n\n    def textEnglish(self):\n        buttonText = \"Change the line attributes\"\n        helpText = \"Change the attributes of selected lines:\"+ \"\\n\"\\\n                   \"- pick favoured line attributes\"+ \"\\n\"\\\n                   \"- select many cosmetic or center lines\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Linienart \u00e4ndern\"\n        helpText = \"\u00c4ndern der Eigenschaften von ausgew\u00e4hlten Linien:\"+ \"\\n\"\\\n                   \"- w\u00e4hle die gew\u00fcnschten Eigenschaften der Linien\"+ \"\\n\"\\\n                   \"- w\u00e4hle mehrere kosmetische oder Mittellinien\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Modifica attributi cosmetiche: linee, archi, circonferenze\"\n        helpText = \"Modifica gli attributi di elementi cosmetici:\"+ \"\\n\"\\\n                   \"- scegliere gli attributi\"+ \"\\n\"\\\n                   \"- selezionare gli elementi cosmetici da modificare\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Modifier les attributs cosm\u00e9tiques: lignes, arcs, cercles\"\n        helpText = \"Modifier les attributs des objets cosm\u00e9tiques:\"+ \"\\n\"\\\n                   \"- choisir des attributs\"+ \"\\n\"\\\n                   \"- s\u00e9lectionner les \u00e9l\u00e9ments cosm\u00e9tiques \u00e0 modifier\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Cambiar atributos cosm\u00e9ticos: l\u00edneas, arcos, c\u00edrculos\"\n        helpText = \"Cambiar los atributos de los art\u00edculos cosm\u00e9ticos:\"+ \"\\n\"\\\n                   \"- elegir atributos\"+ \"\\n\"\\\n                   \"- seleccionar los elementos cosm\u00e9ticos a modificar\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            for ObjectString in ObjectList:\n                if ObjectString[0:4] == 'Edge':\n                    Edge = View.getCenterLineBySelection(ObjectString)\n                    if Edge == None:\n                        Edge = View.getCosmeticEdgeBySelection(ObjectString)\n                    if Edge != None:\n                            newFormat = (Attrib.getStyle(),Attrib.getWidth(),Attrib.getColorTuple(),True)\n                            Edge.Format = newFormat\n                            View.requestPaint()\n            gui.Selection.clearSelection()\n\nclass drawDiameterSign:\n    '''Inserta  a '\u2300' sign in a measure'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 10 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"+\tc #2B2200\",\\\n        \"@\tc #2C2300\",\\\n        \"#\tc #FFFF00\",\\\n        \"$\tc #2C2200\",\\\n        \"%\tc #342B00\",\\\n        \"&\tc #FEFE00\",\\\n        \"*\tc #2D2400\",\\\n        \"=\tc #FDFD00\",\\\n        \"                                     ....                       \",\\\n        \"                                    ......                      \",\\\n        \"                                    ......                      \",\\\n        \"                                    ......                      \",\\\n        \"                                   ......                       \",\\\n        \"                           ..............                       \",\\\n        \"                        .................                       \",\\\n        \"                      ....................                      \",\\\n        \"                    .......................                     \",\\\n        \"                   ..........................                   \",\\\n        \"                  ............................                  \",\\\n        \"                 .........       ..............                 \",\\\n        \"                ........         ...... ........                \",\\\n        \"               ........          .....   ........               \",\\\n        \"               .......          ......    .......               \",\\\n        \"              .......           ......     .......              \",\\\n        \"              ......            .....       ......              \",\\\n        \"             ......            ......        ......             \",\\\n        \"             ......            ......        ......             \",\\\n        \"             .....             .....          .....             \",\\\n        \"            ......            ......          ......            \",\\\n        \"            ......            ......          ......            \",\\\n        \"            ......            .....            .....            \",\\\n        \"            .....            ......            .....            \",\\\n        \"            .....            ......            .....            \",\\\n        \"            .....            ......            .....            \",\\\n        \"            .....            .....             .....            \",\\\n        \"            .....           ......             .....            \",\\\n        \"            ......          ......             .....            \",\\\n        \"            ......          .....             ......            \",\\\n        \"            ......         ......             ......            \",\\\n        \"             ......        ......             .....             \",\\\n        \"             ......        .....             ......             \",\\\n        \"             .......      ......            .......             \",\\\n        \"              ......      ......            ......              \",\\\n        \"              .......     .....            .......              \",\\\n        \"               .......   ......           .......               \",\\\n        \"                ........ ......         ........                \",\\\n        \"                ..............         .........                \",\\\n        \"                 .............      ...........                 \",\\\n        \"                  ............................                  \",\\\n        \"                   ..........................                   \",\\\n        \"                     ......................                     \",\\\n        \"                       ..................                       \",\\\n        \"                       ................                         \",\\\n        \"             +++       ............                             \",\\\n        \"            ++@+      ......                     +++            \",\\\n        \"           +++++      ......                     ++++           \",\\\n        \"          +++#++      .....                      +++++          \",\\\n        \"         +++##++       ....                      ++#+++         \",\\\n        \"        +++###++                                 ++##+++        \",\\\n        \"      ++++####+$+++++++++++++++++++++++++++++++++++###+@+       \",\\\n        \"   +++++%#&###+++++++++++++++++++++++++++++++++++++####*+++     \",\\\n        \"+++++####################################################+++++  \",\\\n        \"+++##=######################################################++++\",\\\n        \"+++++######################################################=##++\",\\\n        \"   +++++####################################################++++\",\\\n        \"      +++*####+++++++++++++++++++++++++++++++++++++###&#%+++++  \",\\\n        \"        +@+###+++++++++++++++++++++++++++++++++++$+####++++     \",\\\n        \"         +++##++                                 ++###+++       \",\\\n        \"          +++#++                                 ++##+++        \",\\\n        \"           +++++                                 ++#+++         \",\\\n        \"            ++++                                 +++++          \",\\\n        \"             +++                                 ++++           \"])\n\n    def textEnglish(self):\n        buttonText = \"Insert a '\u00d8' sign\"\n        helpText = \"Insert a '\u00d8' sign in a measure:\"+ \"\\n\"\\\n                   \"- select many measures\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText =\"Einf\u00fcgen eines  '\u00d8' Zeichens\"\n        helpText = \"F\u00fcge ein '\u00d8' Zeichen vor der Ma\u00dfzahl ein:\"+ \"\\n\"\\\n                   \"- w\u00e4hle ein Ma\u00df\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Inserisci il simbolo '\u00d8 ' nella dimensione\"\n        helpText = \"Inserisce il simbolo '\u00d8' (diametro) in una dimensione:\"+ \"\\n\"\\\n                   \"- selezionare le dimensioni\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Entrez le symbole '\u00d8' dans la cote\"\n        helpText = \"Ins\u00e8re le symbole '\u00d8' (diam\u00e8tre) dans une cote:\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez les taille\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Ingrese el s\u00edmbolo '\u00d8' en la dimensi\u00f3n\"\n        helpText = \"Inserta el s\u00edmbolo '\u00d8' (di\u00e1metro) en una dimensi\u00f3n:\"+ \"\\n\"\\\n                   \"- seleccione los tama\u00f1o\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        DiamSign ='\u2300'\n        Sel = gui.Selection.getSelectionEx()\n        for Elem in Sel:\n            if Elem.Object.TypeId == 'TechDraw::DrawViewDimension':\n                OldFormat = Elem.Object.FormatSpec\n                Elem.Object.FormatSpec = DiamSign+OldFormat\n\nclass drawRectangleSign:\n    '''Inserta  a '\u303c' sign in a measure'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 11 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"+\tc #2B2200\",\\\n        \"@\tc #2B2000\",\\\n        \"#\tc #2C2300\",\\\n        \"$\tc #2C2200\",\\\n        \"%\tc #FFFF00\",\\\n        \"&\tc #342B00\",\\\n        \"*\tc #FEFE00\",\\\n        \"=\tc #2D2400\",\\\n        \"-\tc #FDFD00\",\\\n        \"                                     ....                       \",\\\n        \"                                     .....                      \",\\\n        \"                                    ......                      \",\\\n        \"                                    ......                      \",\\\n        \"                                    .....                       \",\\\n        \"                                   ......                       \",\\\n        \"              ....................................              \",\\\n        \"             ......................................             \",\\\n        \"            ........................................            \",\\\n        \"            ........................................            \",\\\n        \"            ........................................            \",\\\n        \"            ......               ......       ......            \",\\\n        \"            ......               ......       ......            \",\\\n        \"            ......               ......       ......            \",\\\n        \"            ......              ......        ......            \",\\\n        \"            ......              ......        ......            \",\\\n        \"            ......              ......        ......            \",\\\n        \"            ......              .....         ......            \",\\\n        \"            ......             ......         ......            \",\\\n        \"            ......             ......         ......            \",\\\n        \"            ......             .....          ......            \",\\\n        \"            ......            ......          ......            \",\\\n        \"            ......            ......          ......            \",\\\n        \"            ......            .....           ......            \",\\\n        \"            ......           ......           ......            \",\\\n        \"            ......           ......           ......            \",\\\n        \"            ......           .....            ......            \",\\\n        \"            ......          ......            ......            \",\\\n        \"            ......          ......            ......            \",\\\n        \"            ......          .....             ......            \",\\\n        \"            ......         ......             ......            \",\\\n        \"            ......         ......             ......            \",\\\n        \"            ......         ......             ......            \",\\\n        \"            ......         .....              ......            \",\\\n        \"            ......        ......              ......            \",\\\n        \"            ......        ......              ......            \",\\\n        \"            ......        .....               ......            \",\\\n        \"            ......       ......               ......            \",\\\n        \"            ......       ......               ......            \",\\\n        \"            ......       .....                ......            \",\\\n        \"            ......      ......                ......            \",\\\n        \"            ........................................            \",\\\n        \"            ........................................            \",\\\n        \"            ........................................            \",\\\n        \"             ......................................             \",\\\n        \"              ....................................              \",\\\n        \"             +++.................................@              \",\\\n        \"            ++#+      ......                    $+++            \",\\\n        \"           +++++      ......                     ++++           \",\\\n        \"          +++%++       ....                      +++++          \",\\\n        \"         +++%%++                                 ++%+++         \",\\\n        \"        +++%%%++                                 ++%%+++        \",\\\n        \"      ++++%%%%+$+++++++++++++++++++++++++++++++++++%%%+#+       \",\\\n        \"   +++++&%*%%%+++++++++++++++++++++++++++++++++++++%%%%=+++     \",\\\n        \"+++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+++++  \",\\\n        \"+++%%-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++\",\\\n        \"+++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-%%++\",\\\n        \"   +++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++\",\\\n        \"      +++=%%%%+++++++++++++++++++++++++++++++++++++%%%*%&+++++  \",\\\n        \"        +#+%%%+++++++++++++++++++++++++++++++++++$+%%%%++++     \",\\\n        \"         +++%%++                                 ++%%%+++       \",\\\n        \"          +++%++                                 ++%%+++        \",\\\n        \"           +++++                                 ++%+++         \",\\\n        \"            ++++                                 +++++          \"])\n\n    def textEnglish(self):\n        buttonText = \"Insert a '\u303c' sign\"\n        helpText = \"Insert a '\u303c' sign in a measure:\"+ \"\\n\"\\\n                   \"- select many measures\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Einf\u00fcgen eines '\u303c' Zeichens\"\n        helpText = \"F\u00fcge ein'\u303c' Zeichen vor der Ma\u00dfzahl ein:\"+ \"\\n\"\\\n                   \"- w\u00e4hle ein Ma\u00df\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Inserisci il simbolo '\u303c' nella dimensione (tubolare)\"\n        helpText = \"Inserisce il segno a '\u303c' (dimensione tubolare) in una dimensione:\"+ \"\\n\"\\\n                   \"- selezionare le dimensioni\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Ins\u00e9rez le symbole '\u303c' dans la dimension (tubulaire)\"\n        helpText = \"Ins\u00e8re la marque '\u303c' (tubulaire) dans une dimension:\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez les taille\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Inserte el s\u00edmbolo '\u303c' en la dimensi\u00f3n (tubular)\"\n        helpText = \"Inserta la marca '\u303c' (tubular) en una dimensi\u00f3n:\"+ \"\\n\"\\\n                   \"- selecciona los tama\u00f1o\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        RectSign ='\u303c'\n        Sel = gui.Selection.getSelectionEx()\n        for Elem in Sel:\n            if Elem.Object.TypeId == 'TechDraw::DrawViewDimension':\n                OldFormat = Elem.Object.FormatSpec\n                Elem.Object.FormatSpec = RectSign+OldFormat\n\nclass positionSectionView:\n    ''' Position a section view at same x or y as its base view'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 4 1\",\\\n        \" \tc None\",\\\n        \".\tc #141000\",\\\n        \"+\tc #FFFF00\",\\\n        \"@\tc #FF0000\",\\\n        \"...............................                                 \",\\\n        \"...............................                                 \",\\\n        \".. +++++++  +++++++  +++++++ ..                                 \",\\\n        \".. +++++++  +++++++  +++++++ ..                                 \",\\\n        \".. +++++++  +++++++  +++++++ ..                                 \",\\\n        \".. +++++++  +++++++  +++++++ ..                                 \",\\\n        \"..++++...................++++..                                 \",\\\n        \"..++++...................++++..                                 \",\\\n        \"..++++..               ..++++..                                 \",\\\n        \"..++++..               ..++++..                                 \",\\\n        \"..++++..               ..++++..                                 \",\\\n        \"..++++..               ..++++..                                 \",\\\n        \"..++++..               ..++++..                                 \",\\\n        \"..    ..               ..    ..                                 \",\\\n        \"..    ..               ..    ..                                 \",\\\n        \"..++++..               ..++++..                                 \",\\\n        \"..++++..               ..++++..                                 \",\\\n        \"..++++..               ..++++..                                 \",\\\n        \"..++++..               ..++++..                                 \",\\\n        \"..++++..               ..++++..                                 \",\\\n        \"..++++..               ..++++..                                 \",\\\n        \"..++++..               ..++++..                                 \",\\\n        \"..    ..               ..    ..                                 \",\\\n        \"..    ..               ..    ..                                 \",\\\n        \"..++++..               ..++++..  @@@@@@@@@   @@@@@@@   @@@@@@@@@\",\\\n        \"..++++..               ..++++..  @@@@@@@@@   @@@@@@@   @@@@@@@@@\",\\\n        \"..++++..               ..++++..  @@@@@@@@@   @@@@@@@   @@@@@@@@@\",\\\n        \"..++++..               ..++++..  @@@@@@@@@   @@@@@@@   @@@@@@@@@\",\\\n        \"..++++..               ..++++..  @@@@@@@@    @@@@@@@    @@@@@@@@\",\\\n        \"..++++..               ..++++..  @@@@                       @@@@\",\\\n        \"..++++..               ..++++..  @@@@                       @@@@\",\\\n        \"..    ..               ..    ..  @@@@                       @@@@\",\\\n        \"..    ..               ..    ..  @@@@           @           @@@@\",\\\n        \"..    ..               ..++++..                @@@          @@@@\",\\\n        \"..++++...................++++..                @@@              \",\\\n        \"..++++...................++++..               @@@@@             \",\\\n        \"..++++  ++++++   ++++++  ++++..  @@@@         @@@@@             \",\\\n        \"..++++  ++++++   ++++++  ++++..  @@@@        @@@@@@         @@@@\",\\\n        \"..++++  ++++++   ++++++  ++++..  @@@@        @@@@@@@        @@@@\",\\\n        \"..++++  ++++++   ++++++  ++++..  @@@@        @@@@@@@        @@@@\",\\\n        \"...............................  @@@@       @@@@@@@@        @@@@\",\\\n        \"...............................  @@@@       @@@@@@@@@       @@@@\",\\\n        \"                                            @@@@@@@@@       @@@@\",\\\n        \"                                           @@@@@@@@@@@      @@@@\",\\\n        \"                                           @@@@@@@@@@@          \",\\\n        \"                                 @@@@      @@@@@@@@@@@          \",\\\n        \"                                 @@@@     @@@@@@@@@@@@@     @@@@\",\\\n        \"                                 @@@@     @@@@@@@@@@@@@     @@@@\",\\\n        \"                                 @@@@    @@@@@@@@@@@@@@@    @@@@\",\\\n        \"                                 @@@@    @@@@@@@@@@@@@@@    @@@@\",\\\n        \"                                 @@@@    @@@@@@@@@@@@@@@    @@@@\",\\\n        \"                                          @@@@@@@@@@@@@     @@@@\",\\\n        \"                                               @@@              \",\\\n        \"                                               @@@              \",\\\n        \"                                 @@@@          @@@              \",\\\n        \"                                 @@@@                       @@@@\",\\\n        \"                                 @@@@                       @@@@\",\\\n        \"                                 @@@@          @@@          @@@@\",\\\n        \"                                 @@@@          @@@          @@@@\",\\\n        \"                                 @@@@                       @@@@\",\\\n        \"                                                            @@@@\",\\\n        \"                                    @@@@@@@  @@@@@@@  @@@@@@@@@@\",\\\n        \"                                    @@@@@@@  @@@@@@@  @@@@@@@@@@\",\\\n        \"                                    @@@@@@@  @@@@@@@  @@@@@@@@@@\"])\n\n    def textEnglish(self):\n        buttonText = \"Orthogonal projection group: section view positioning\"\n        helpText = \"Position a section view at same x or y as its base view\"+ \"\\n\"\\\n                   \"- select a section view\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Orthogonale Projektionsgruppe: Schnittansichtspositionierung\"\n        helpText = \"Positioniere eine Schnittansicht bei der gleichen x oder y Koordinate wie die Basisansicht\"+ \"\\n\"\\\n                   \"- w\u00e4hle eine Schnittansicht\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Gruppo proiezioni ortog.: posizionamento vista in sezione\"\n        helpText = \"Posiziona una vista in sezione alla coordinata 'x' o 'y' della sua vista di base\"+ \"\\n\"\\\n                   \"- selezionare una vista in sezione\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Groupe de projection orthograp.: positionnement de la vue en coupe\"\n        helpText = \"Place une vue en coupe \u00e0 la coordonn\u00e9e \u00abx\u00bb ou \u00aby\u00bb de sa vue de base\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez une vue en coupe\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Grupo de proyecci\u00f3n ortogr\u00e1fica: posicionamiento de vista en secci\u00f3n\"\n        helpText = \"Coloca una vista de secci\u00f3n en la coordenada 'x' o 'y' de su vista base\"+ \"\\n\"\\\n                   \"- seleccionar una vista de secci\u00f3n\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        if gui.Selection.getCompleteSelection():\n            Section = gui.Selection.getCompleteSelection()[0]\n            if Section.TypeId == 'TechDraw::DrawViewSection':\n                BaseView = Section.BaseView\n                if BaseView.TypeId == \"TechDraw::DrawProjGroupItem\":\n                    Base = BaseView.InList[0]\n                else:\n                    Base = BaseView\n                if abs(Section.Direction.x) == 1:\n                    Section.Y=Base.Y\n                if abs(Section.Direction.y) == 1:\n                    Section.X=Base.X\n\nclass changeLockPosition:\n    '''change the LockPosition of the selected view'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 17 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"+\tc #141000\",\\\n        \"@\tc #FFFF00\",\\\n        \"#\tc #FCFC00\",\\\n        \"$\tc #FDFD00\",\\\n        \"%\tc #F9F900\",\\\n        \"&\tc #FBFB00\",\\\n        \"*\tc #231F1B\",\\\n        \"=\tc #FFF800\",\\\n        \"-\tc #FF2000\",\\\n        \";\tc #2C1F0C\",\\\n        \">\tc #FCFB00\",\\\n        \",\tc #FF0100\",\\\n        \"'\tc #FEFE00\",\\\n        \")\tc #F9F901\",\\\n        \"!\tc #FDFC00\",\\\n        \"                    .....                        +++++++        \",\\\n        \"                    .......                    +++++++++++      \",\\\n        \"                    ..........                ++@@@@@@#@+++     \",\\\n        \"                    ............             +++@@@@@@@@@+++    \",\\\n        \"                  ................          +++@@$@@@@@@@@+++   \",\\\n        \"              ......................       +++@@@@++++@@@@@++   \",\\\n        \"           ..........................     +++@@%@++++++@@@@@++  \",\\\n        \"         ............................     ++@@@@+++  +++@@@@++  \",\\\n        \"        ............................     ++@@@@+++    ++@@@@@+  \",\\\n        \"       .........    .............        ++@@@@++     +++@@@@++ \",\\\n        \"      .......       ...........          ++@@@+++      ++@@@@++ \",\\\n        \"     ......         ........            ++@@@@++       ++@@@@@+ \",\\\n        \"    ......          ......              ++&@@@++       ++@@@@@+ \",\\\n        \"   ......             ..               +++@@@+++       ++@@@@@+ \",\\\n        \"   .....                               ++@@@@++        +++@@@@++\",\\\n        \"  .....                                ++@@@@++         ++@@@@++\",\\\n        \"  .....                                ++@@@@++         ++@@@@++\",\\\n        \"  ....                        ++++++++ ++@@@@+          ++++++++\",\\\n        \" .....                   *++++++++++++++++++++          ++++++++\",\\\n        \" .....                   ++++++++++++++++++++++                 \",\\\n        \" ....                   +++@@@@@@@@@@@@@@@@@@++                 \",\\\n        \" ....                   +++@@@@@@@@@@@@@@@@@@+++                \",\\\n        \" ....                   +++@@@@@@@@@@@@@@@@@@+++                \",\\\n        \" ....                   +++@@@@@@@@@@@@@@@@@@+++                \",\\\n        \" .....                  +++@@@@@@@@@@@@@@@@@@+++                \",\\\n        \" .....                  +++@@@@@@@@@@@@@@@@@@+++                \",\\\n        \"  ....                  +++@@@@@@@@@@@@@@@@@@+++                \",\\\n        \"  .....                 +++@@@@@@@@@@@@@@@@@@+++                \",\\\n        \"  .....                 +++@@@@@@@...=@@@@@@@+++                \",\\\n        \"   ...  ......          +++@@@@@@.-...@@@@@@@+++                \",\\\n        \"      ..........        +++@@@@@@.....@@@@@@@+++                \",\\\n        \"     .............      +++@@@@@@.....@@@@@@@+++         ++++   \",\\\n        \"    ...............     +++@@@@@@.....@@@@@@@+++        +++++;  \",\\\n        \"   .................    +++@@@@@@.....@@@@@@@+++       +++++++  \",\\\n        \"  .......     ......    +++@@@@@@.....@@@@@@@+++       ++@@@++  \",\\\n        \"  ......       ......   +++@@@@@@.....@@@@@@@+++       ++@@@@++ \",\\\n        \" ......         .....   +++@@@@@@.....@@@@@@@+++       ++@@@@++ \",\\\n        \" ......         ......  +++@@@@@@.....@@@@@@@+++       ++@@@@++ \",\\\n        \" .....           .....  +++@@@@@@@...@@@@@@@@+++       ++@@@@++ \",\\\n        \" .....           .....  +++@@@@@@@@@@@@@@@@@@+++       ++@@@@++ \",\\\n        \".....             ..... +++@@@@@@@@@@@@@@@@@@+++       ++@@@@++ \",\\\n        \".....   .......   .....  ++++++++++++++++++++++        ++@@@@++ \",\\\n        \".......................   ++++++++++++++++++++         ++@@@@++ \",\\\n        \".......................     +++++++++++++++++          ++@@@@++ \",\\\n        \".......................                                ++>@@+++ \",\\\n        \".......................                               ++@@@@+++ \",\\\n        \".......................                               ++@@@@+++ \",\\\n        \".......................                              +++@@@@++  \",\\\n        \".......................               ++++          +++@@@#+++  \",\\\n        \".......................              ++++++        +++@@@@+++   \",\\\n        \".......................            ++++@@++       +++@@@@@++    \",\\\n        \"..........@@@,.........          ++++@@'@++      +++@@@@)++     \",\\\n        \".........@@@@@.........        ++++@@@@@@++++++++++@@@@$+++     \",\\\n        \".........@@@@@.........      ++++@@@@@@@@+++++++++@@@@)+++      \",\\\n        \".........@@@@@.........    +++@@@@@@@@@@@++@@@@@@@@@@@@++       \",\\\n        \".........@@@@@.........   +++@@@@@@@@@@@@++@@@@@@@@@@+++        \",\\\n        \".........@@@@@.........    +++@!@@@@@@@@@++@@@@@@@@++++         \",\\\n        \".........@@@@@.........      ++++@@@@@@@@++@@@@@+++++           \",\\\n        \".........@@@@@.........        ++++@@@@@@+++++++++              \",\\\n        \".........@@@@@.........          ++++@@@@+++++++                \",\\\n        \".........@@@@@.........            ++++@@++                     \",\\\n        \" .........@@@..........              ++++++                     \",\\\n        \"  ...................                 ++++                      \",\\\n        \"   .................                                            \"])\n\n    def textEnglish(self):\n        buttonText = \"Lock/Unlock a view\"\n        helpText = \"Lock/Unlock a view\"+ \"\\n\"\\\n                   \"- select a view\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Ansichtverschiebung sperren/\u00f6ffnen\"\n        helpText =\"Ansichtverschiebung sperren/\u00f6ffnen\"+ \"\\n\"\\\n                  \"- w\u00e4hle eine Ansicht\"+ \"\\n\"\\\n                  \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Blocca/Sblocca una vista\"\n        helpText = \"Blocca/sblocca una vista (non modificabile/modificabile):\"+ \"\\n\"\\\n                   \"- selezionare una vista\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Verrouiller/d\u00e9verrouiller une vue\"\n        helpText = \"Verrouiller/d\u00e9verrouiller une vue (non modifiable / modifiable):\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez une vue\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Bloquear/desbloquear una vista\"\n        helpText = \"Bloquear/desbloquear una vista (no editable/editable):\"+ \"\\n\"\\\n                   \"- seleccionar una vista\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        if gui.Selection.getCompleteSelection():\n            Select = gui.Selection.getCompleteSelection()[0]\n            if hasattr(Select,'LockPosition'):\n                Select.LockPosition = not Select.LockPosition\n\nclass createVertDimChain:\n    '''create a vertical chain dimension'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 2 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                  ....                          \",\\\n        \"                                 .......                        \",\\\n        \"                                ........                        \",\\\n        \"        ...................................                     \",\\\n        \"        ...................................                     \",\\\n        \"        ...................................                     \",\\\n        \"                                ........                        \",\\\n        \"                                 .......                        \",\\\n        \"                                  .....                         \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                  .....                         \",\\\n        \"                                 .......                        \",\\\n        \"                                ...........                     \",\\\n        \"        ...................................                     \",\\\n        \"        ...................................                     \",\\\n        \"        ...................................                     \",\\\n        \"                                 ........                       \",\\\n        \"                                 .......                        \",\\\n        \"                                   ....                         \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                 .......                        \",\\\n        \"                                ........                        \",\\\n        \"         ..................................                     \",\\\n        \"         ..................................                     \",\\\n        \"         ..................................                     \",\\\n        \"                                .........                       \",\\\n        \"                                 .......                        \",\\\n        \"                                  .....                         \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \",\\\n        \"                                   ...                          \"])\n\n    def textEnglish(self):\n        buttonText = \"Create a vertical chain dimension\"\n        helpText = \"Select three or more vertexes\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Erzeuge senkrechte Kettenbema\u00dfung\"\n        helpText = \"w\u00e4hle drei oder mehr Kontrollpunkte\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Dimensioni verticali in serie continue\"\n        helpText = \"Seleziona tre o pi\u00f9 vertici\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Dimensions verticales en s\u00e9rie continue\"\n        helpText = \"S\u00e9lectionnez trois sommets ou plus\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Dimensiones verticales en serie continua\"\n        helpText = \"Seleccione tres o m\u00e1s v\u00e9rtices\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        def sortVertex(Vertex):\n            return Vertex.Point.y\n\n        (OK,ElementNames,View) = commonTools.selectionOK()\n        if OK:\n            scale = View.Scale\n            VertexNames = [VertexName for VertexName in ElementNames if VertexName[:6]=='Vertex']\n            Vertexes = [View.getVertexBySelection(VertexName) for VertexName in VertexNames]\n            Vertexes.sort(key=sortVertex)\n            if len(Vertexes) > 1:\n                XPos = (Vertexes[0].X) * scale\n                for i  in range(len(Vertexes)-1):\n                    DistanceDim=TechDraw.makeDistanceDim(View,'DistanceY',Vertexes[i].Point, Vertexes[i+1].Point)\n                    DistanceDim.X = XPos\n                    DistanceDim.Y = Y = ((Vertexes[i].Point.y+Vertexes[i+1].Point.y)/2) * scale\n            gui.Selection.clearSelection()\n\nclass createHorizDimChain:\n    '''create a horicontal chain dimension'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 2 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                    ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                   ....                  ...         \",\\\n        \"        ...                   ....                  ...         \",\\\n        \"        ...                   ....                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"       .....                  ....                 .....        \",\\\n        \"      .......                ......               .......       \",\\\n        \"     .........              ........             .........      \",\\\n        \"................................................................\",\\\n        \"................................................................\",\\\n        \"................................................................\",\\\n        \"     .........              ........             .........      \",\\\n        \"      .......               ........              .......       \",\\\n        \"       .....                 ......                .....        \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"        ...                    ...                  ...         \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \"])\n\n    def textEnglish(self):\n        buttonText = \"Create a horizontal chain dimension\"\n        helpText = \"Select three or more vertexes\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Erzeuge waagrechte Kettenbema\u00dfung\"\n        helpText = \"w\u00e4hle drei oder mehr Kontrollpunkte\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Dimensioni orizzontali in serie continue\"\n        helpText = \"Seleziona tre o pi\u00f9 vertici\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Dimensions horizontales en s\u00e9rie continue\"\n        helpText = \"S\u00e9lectionnez trois sommets ou plus\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Dimensiones horizontales en serie continua\"\n        helpText = \"Seleccione tres o m\u00e1s v\u00e9rtices\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        def sortVertex(Vertex):\n            return Vertex.Point.x\n\n        (OK,ElementNames,View) = commonTools.selectionOK()\n        if OK:\n            scale = View.Scale\n            VertexNames = [VertexName for VertexName in ElementNames if VertexName[:6]=='Vertex']\n            Vertexes = [View.getVertexBySelection(VertexName) for VertexName in VertexNames]\n            Vertexes.sort(key=sortVertex)\n            if len(Vertexes) > 1:\n                YPos = Vertexes[0].Y * scale\n                for i  in range(len(Vertexes)-1):\n                    DistanceDim=TechDraw.makeDistanceDim(View,'DistanceX',Vertexes[i].Point,Vertexes[i+1].Point)\n                    DistanceDim.X = X = ((Vertexes[i].Point.x+Vertexes[i+1].Point.x)/2) * scale\n                    DistanceDim.Y = YPos\n            gui.Selection.clearSelection()\n\nclass positionVertDimChain:\n    '''position a vertical chain dimension'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 6 1\",\\\n        \" \tc None\",\\\n        \".\tc #000000\",\\\n        \"+\tc #FF0000\",\\\n        \"@\tc #FFFF00\",\\\n        \"#\tc #F7F700\",\\\n        \"$\tc #F8F800\",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                       .....                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"        +++                            .@@@.                    \",\\\n        \"       +++++                           .@@@..           .....   \",\\\n        \"      +++++++                         ..@@@@..        ...@@@..  \",\\\n        \"     +++++++++                       ..@@@@@@.       ..#@@@@@.  \",\\\n        \"    +++++++++++                 ......@@@@@@@.........@@@@@@@.. \",\\\n        \"  +++++++++++++++++++++++       .@@@@@$@@@@@@@@@@@@@@@@@@@@@@@. \",\\\n        \"  +++++++++++++++++++++++       .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@. \",\\\n        \"  +++++++++++++++++++++++       .@@@@@@@@@@@@@@@@@@@@@@@@@@@@.. \",\\\n        \"    +++++++++++                 .......@@@@@@..........@@@@@@.  \",\\\n        \"     +++++++++                        ..@@@@..        ..@@@@..  \",\\\n        \"      +++++++                          ......          ..@@@.   \",\\\n        \"       +++++                                            .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"        +++                                             .@@@.   \",\\\n        \"                                                        .....   \",\\\n        \"                                                                \",\\\n        \"                                                                \"])\n\n    def textEnglish(self):\n        buttonText = \"Position a vertical chain dimension\"\n        helpText = \"Arranges the selected vertical dimensions on the same line:\"+ \"\\n\"\\\n                   \"- select two or more dimensions\"+\"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Positioniere senkrechte Kettenbema\u00dfung\"\n        helpText = \"Ordnet die ausgew\u00e4hlten vertikalen Abmessungen in derselben Linie an:\"+ \"\\n\"\\\n                   \"- w\u00e4hle zwei oder mehr Ma\u00dfe\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Allinea dimensioni verticali\"\n        helpText = \"Dispone sulla stessa linea le dimensioni verticali selezionate:\"+ \"\\n\"\\\n                   \"- seleziona due o pi\u00f9 dimensioni\"+\"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Aligner les dimensions verticales\"\n        helpText = \"R\u00e9organise les dimensions verticales s\u00e9lectionn\u00e9es sur la m\u00eame ligne:\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez deux ou plusieurs dimensions\"+\"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Alinear dimensiones verticales\"\n        helpText = \"Organiza las dimensiones verticales seleccionadas en la misma l\u00ednea:\"+ \"\\n\"\\\n                   \"- seleccione dos o m\u00e1s dimensiones\"+\"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        Selected = gui.Selection.getSelectionEx()\n        VertictalDimList = [Select.Object for Select in Selected if Select.Object.Type == 'DistanceY']\n        if len(VertictalDimList) > 1:\n            XPos = VertictalDimList[0].X\n            for Dimension in VertictalDimList:\n                Dimension.X = XPos\n\nclass positionHorizDimChain:\n    '''position a horizontal chain dimension'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 6 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"+\tc #000000\",\\\n        \"@\tc #FFFF00\",\\\n        \"#\tc #F8F800\",\\\n        \"$\tc #F7F700\",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                              ...                               \",\\\n        \"                              ...                               \",\\\n        \"                             .....                              \",\\\n        \"                            .......                             \",\\\n        \"                           .........                            \",\\\n        \"                          ...........                           \",\\\n        \"   .........................................................    \",\\\n        \"   .........................................................    \",\\\n        \"   .........................................................    \",\\\n        \"                          ...........                           \",\\\n        \"                           .........                            \",\\\n        \"                            .......                             \",\\\n        \"                             .....                              \",\\\n        \"                              ...                               \",\\\n        \"                              ...                               \",\\\n        \"                              ...                               \",\\\n        \"                              ...                               \",\\\n        \"                              ...                               \",\\\n        \"                              ...                               \",\\\n        \"                              ...                               \",\\\n        \"                              ...                               \",\\\n        \"                              ...                               \",\\\n        \"                              ...                               \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                             +++++                              \",\\\n        \"                             +@@@+                              \",\\\n        \"                             +@@@+                              \",\\\n        \"                             +@@@+                              \",\\\n        \"                             +@@@+                              \",\\\n        \"                             +@@@++                             \",\\\n        \"                            ++@@#@++                            \",\\\n        \"                           ++@@@@@@++++++++++++++++++++++++++   \",\\\n        \"                           +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+   \",\\\n        \"                           +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+   \",\\\n        \"                           +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+   \",\\\n        \"                           +@@@@@@@@+++++++++++++++++++++++++   \",\\\n        \"                           ++@@@@@@++                           \",\\\n        \"                            ++@@@+++                            \",\\\n        \"                             +@@@+                              \",\\\n        \"                             +@@@+                              \",\\\n        \"                             +@@@+                              \",\\\n        \"                             +@@@+                              \",\\\n        \"                             +@@@+                              \",\\\n        \"                             +@@@+                              \",\\\n        \"                             +@@@+                              \",\\\n        \"                             +@@@++                             \",\\\n        \"                            ++@@@@++                            \",\\\n        \"                           ++@@@@@$+                            \",\\\n        \"  ++++++++++++++++++++++++++@@@@@@@++                           \",\\\n        \"  +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+                           \",\\\n        \"  +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+                           \",\\\n        \"  +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+                           \",\\\n        \"  +++++++++++++++++++++++++++@@@@@@++                           \",\\\n        \"                            +++@@+++                            \",\\\n        \"                              ++++                              \",\\\n        \"                                                                \"])\n\n    def textEnglish(self):\n        buttonText = \"Position a horizontal chain dimension\"\n        helpText = \"Arranges the selected horizontal dimensions on the same line:\"+ \"\\n\"\\\n                   \"- select two or more measures\"+\"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Positioniere waagrechte Kettenbema\u00dfung\"\n        helpText = \"Ordnet die ausgew\u00e4hlten horizontalen Abmessungen in derselben Linie an:\"+ \"\\n\"\\\n                   \"- w\u00e4hle zwei oder mehr Ma\u00dfe\"+\"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Allinea dimensioni orizzontali\"\n        helpText = \"Dispone sulla stessa linea le dimensioni orizzontali selezionate:\"+ \"\\n\"\\\n                   \"- seleziona due o pi\u00f9 dimensioni\"+\"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Aligner les dimensions horizontales\"\n        helpText = \"R\u00e9organise les dimensions horizontales s\u00e9lectionn\u00e9es sur la m\u00eame ligne:\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez deux ou plusieurs dimensions\"+\"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Alinear dimensiones horizontales\"\n        helpText = \"Organiza las dimensiones horizontales seleccionadas en la misma l\u00ednea:\"+ \"\\n\"\\\n                   \"- seleccione dos o m\u00e1s dimensiones\"+\"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        Selected = gui.Selection.getSelectionEx()\n        HorizontalDimList = [Select.Object for Select in Selected if Select.Object.Type == 'DistanceX']\n        if len(HorizontalDimList) > 1:\n            YPos = HorizontalDimList[0].Y\n            for Dimension in HorizontalDimList:\n                Dimension.Y = YPos\n\nclass cascadeVertDimensions:\n    '''cascade vertical dimensions'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 14 1\",\\\n        \" \tc None\",\\\n        \".\tc #000000\",\\\n        \"+\tc #FFFF00\",\\\n        \"@\tc #FBFB00\",\\\n        \"#\tc #FFFB00\",\\\n        \"$\tc #FFFD00\",\\\n        \"%\tc #FF0000\",\\\n        \"&\tc #FF1F00\",\\\n        \"*\tc #FF0100\",\\\n        \"=\tc #FF2900\",\\\n        \"-\tc #FF0A00\",\\\n        \";\tc #FF1000\",\\\n        \">\tc #FD0300\",\\\n        \",\tc #FD0000\",\\\n        \"                                                      ......    \",\\\n        \"                                                     ..++++..   \",\\\n        \"                                                    ..++++++..  \",\\\n        \".....................................................+@++++++.. \",\\\n        \".+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++. \",\\\n        \".+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++. \",\\\n        \".+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++. \",\\\n        \".....................................................++++++++.. \",\\\n        \"                                                    ..@++++++.  \",\\\n        \"                                                     ..+++++..  \",\\\n        \"                                                      ..+++..   \",\\\n        \"                                                       .+++.    \",\\\n        \"                                                       .+++.    \",\\\n        \"                                 .......               .+++.    \",\\\n        \"                                ..+++++..              .+++.    \",\\\n        \"                               ..+++++++..             .+++.    \",\\\n        \"................................+++++++++..            .+++.    \",\\\n        \".+++++++++++++++++++++++++++++++++++++++++.            .+++.    \",\\\n        \".+++++++++++++++++++++++++++++++++++++++++.            .+++.    \",\\\n        \".+++++++++++++++++++++++++++++++++++++++++.            .+++.    \",\\\n        \"................................+++++++++..            .+++.    \",\\\n        \"                               .+++++++++.             .+++.    \",\\\n        \"                               ..+++++++..             .+++.    \",\\\n        \"                                ..+++++..              .+++.    \",\\\n        \"                                 ..+++..               .+++.    \",\\\n        \"                                  .+++.                .+++.    \",\\\n        \"                                  .+++.                .+++.    \",\\\n        \"             .......              .+++.                .+++.    \",\\\n        \"            ..+++++..             .+++.                .+++.    \",\\\n        \"           ..+++++++..            .+++.                .+++.    \",\\\n        \"............+++++++++...          .+++.                .+++.    \",\\\n        \".++++++++++++++++++++++.          .+++.                .+++.    \",\\\n        \".++++++++++++++++++++++.          .+++.                .+++.    \",\\\n        \".++++++++++++++++++++++.          .+++.                .+++.    \",\\\n        \"............+++++++++...          .+++.                .+++.    \",\\\n        \"           ..+++++++..            .+++.                .+++.    \",\\\n        \"            ..+++++.....          .+++.                .+++.    \",\\\n        \"             ..+++..              .+++.                .+++.    \",\\\n        \"              .+++.               .+++.                .+++.    \",\\\n        \"              .+++.               .+++.                .+++.    \",\\\n        \"              .+++.               .+++.                .+++.    \",\\\n        \"              .+++.               .+++.                .+++.    \",\\\n        \"              .+++.               .+++.                .+++.    \",\\\n        \"              .+++.               .+++.                .+++.    \",\\\n        \"              .+++.               .+++.                .+++.    \",\\\n        \"              .+++.               .+++.                .+++.    \",\\\n        \"              .+++.               .+++.                .+++.    \",\\\n        \"              .+++.               .+++.                .+++.    \",\\\n        \"              .+++.               .+++.                .+++.    \",\\\n        \"              .+++.               .+#+.                .$$+.    \",\\\n        \"              .%%%.               .&*=.                .-;%.    \",\\\n        \"              %%%%>             %%%%%%%%%            %%%%%%,    \",\\\n        \"            %%%%%%%%            %%%%%%%%%           %%%%%%%%%   \",\\\n        \"           %%%%%%%%%%          %%%%%%%%%%%         %%%%%%%%%%%  \",\\\n        \"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\",\\\n        \"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\",\\\n        \"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\",\\\n        \"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\",\\\n        \"            %%%%%%%%%          %%%%%%%%%%           %%%%%%%%%   \",\\\n        \"            %%%%%%%%            %%%%%%%%             %%%%%%%    \",\\\n        \"             %%%%%%              %%%%%%               %%%%%     \",\\\n        \"              %%%%                %%%%                 %%%      \",\\\n        \"                                                                \",\\\n        \"                                                                \"])\n\n    def textEnglish(self):\n        buttonText = \"Cascade vertical dimensions\"\n        helpText = \"Spaces (horizontally), at the set value, the selected vertical dimensions:\"+ \"\\n\"\\\n                   \"- set the cascade value\"+ \"\\n\"\\\n                   \"- select two or more vertical dimensions\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Kaskadiere senkrechte Bema\u00dfungen\"\n        helpText = \"Stelle den gew\u00fcnschten Abstand zwischen den Ma\u00dfen ein:\"+ \"\\n\"\\\n                   \"- Stellen Sie den Abstand Kaskadierung ein\"+ \"\\n\"\\\n                   \"- w\u00e4hle zwei oder mehr senkrechte Bema\u00dfungen\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Distanziamento dimensioni verticali\"\n        helpText = \"Distanzia (orizzontalmente), al valore impostato, le quote verticali selezionate:\"+ \"\\n\"\\\n                   \"- impostare Valore distanziamento\"+ \"\\n\"\\\n                   \"- selezionare due o pi\u00f9 quote verticali\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Espacement des dimensions verticales\"\n        helpText = \"Espaces (horizontalement), \u00e0 la valeur d\u00e9finie, les dimensions verticales s\u00e9lectionn\u00e9es:\"+ \"\\n\"\\\n                   \"- d\u00e9finir Valeur d'espacement\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez au moins deux dimensions verticales\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Espaciado de dimensi\u00f3n vertical\"\n        helpText = \"Espacios (horizontalmente), en el valor establecido, las dimensiones verticales seleccionadas:\"+ \"\\n\"\\\n                   \"- establecer Valor de espaciado\"+ \"\\n\"\\\n                   \"- seleccione dos o m\u00e1s dimensiones verticales\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        Selected = gui.Selection.getSelectionEx()\n        HorizontalDimList = [Select.Object for Select in Selected if Select.Object.Type == 'DistanceY']\n        if len(HorizontalDimList) > 1:\n            XPos = float(HorizontalDimList[0].X)\n            Sign = XPos/abs(XPos)\n            for Dimension in HorizontalDimList:\n                Dimension.X = XPos\n                XPos = XPos + DimAttrib.getDimLineDistance()*Sign\n\nclass cascadeHorizDimensions:\n    '''cascade horizontal dimensions'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 14 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"+\tc #000000\",\\\n        \"@\tc #FFFF00\",\\\n        \"#\tc #FD0300\",\\\n        \"$\tc #FF1F00\",\\\n        \"%\tc #FF0100\",\\\n        \"&\tc #FFFB00\",\\\n        \"*\tc #FF2900\",\\\n        \"=\tc #FBFB00\",\\\n        \"-\tc #FF0A00\",\\\n        \";\tc #FFFD00\",\\\n        \">\tc #FF1000\",\\\n        \",\tc #FD0000\",\\\n        \"      ....                   +++++         +++++        +++++   \",\\\n        \"      ....                   +@@@+         +@@@+        +@@@+   \",\\\n        \"      ....                   +@@@+         +@@@+        +@@@+   \",\\\n        \"      ....                   +@@@+         +@@@+        +@@@+   \",\\\n        \"      ....                   +@@@+         +@@@+        +@@@+   \",\\\n        \"      ....                   +@@@+         +@@@+        +@@@+   \",\\\n        \"      ....                   +@@@+         +@@@+        +@@@+   \",\\\n        \"      ....                   +@@@+         +@@@+        +@@@+   \",\\\n        \"      ....                   +@@@+         +@@@+        +@@@+   \",\\\n        \"      ....                   +@@@+         +@@@+        +@@@+   \",\\\n        \"      ....                   +@@@+         +@@@+        +@@@+   \",\\\n        \"      .....                 ++@@@++        +@@@+        +@@@+   \",\\\n        \"    ........               ++@@@@@++       +@@@+        +@@@+   \",\\\n        \"   .........              ++@@@@@@@++      +@@@+        +@@@+   \",\\\n        \"  ...........++++++++++++++@@@@@@@@@+      +@@@+        +@@@+   \",\\\n        \"  ............@@@@@@@@@@@@@@@@@@@@@@+      +@@@+        +@@@+   \",\\\n        \"  ............@@@@@@@@@@@@@@@@@@@@@@+      +@@@+        +@@@+   \",\\\n        \"  ............@@@@@@@@@@@@@@@@@@@@@@+      +@@@+        +@@@+   \",\\\n        \"   .........#++++++++++++++@@@@@@@@@+      +@@@+        +@@@+   \",\\\n        \"    ........              ++@@@@@@@++      +@@@+        +@@@+   \",\\\n        \"     ......                ++@@@@@++       +@@@+        +@@@+   \",\\\n        \"      ....                 +++@@@++        +@@@+        +@@@+   \",\\\n        \"      ....                 + +@@@+         +@@@+        +@@@+   \",\\\n        \"      ....                 + +++++         +@@@+        +@@@+   \",\\\n        \"      ....                                 +@@@+        +@@@+   \",\\\n        \"      ....                                 +@@@+        +@@@+   \",\\\n        \"      ....                                 +@@@+        +@@@+   \",\\\n        \"      ....                                 +@@@+        +@@@+   \",\\\n        \"      ....                                 +@@@+        +@@@+   \",\\\n        \"      ....                                 +@@@+        +@@@+   \",\\\n        \"      ....                                 +@@@+        +@@@+   \",\\\n        \"     ......                              +++@@@++       +@@@+   \",\\\n        \"    .........                           ++@@@@@@++      +@@@+   \",\\\n        \"   ..........                          ++@@@@@@@@++     +@@@+   \",\\\n        \"  ...........+++++++++++++++++++++++++++@@@@@@@@@@+     +@@@+   \",\\\n        \"  ...........$@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+     +@@@+   \",\\\n        \"  ...........%&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+     +@@@+   \",\\\n        \"  ...........*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+     +@@@+   \",\\\n        \"   ..........+++++++++++++++++++++++++++@@@@@@@@@@+     +@@@+   \",\\\n        \"    .........                          ++@@@@@@@@++     +@@@+   \",\\\n        \"     ........                           ++@@@@@@++      +@@@+   \",\\\n        \"      .....                              +++@@@++       +@@@+   \",\\\n        \"      ....                                 +++++        +@@@+   \",\\\n        \"      ....                                              +@@@+   \",\\\n        \"      ....                                              +@@@+   \",\\\n        \"      ....                                              +@@@+   \",\\\n        \"      ....                                              +@@@+   \",\\\n        \"      ....                                              +@@@+   \",\\\n        \"      ....                                              +@@@+   \",\\\n        \"      ....                                              +@@@+   \",\\\n        \"      ....                                              +@@@+   \",\\\n        \"      .....                                             +@@@+   \",\\\n        \"     .......                                           ++@@@++  \",\\\n        \"    .........                                         ++@@@@@++ \",\\\n        \"   ..........                                        ++=@@@@=@++\",\\\n        \"  ...........+++++++++++++++++++++++++++++++++++++++++@@@@@@@@@+\",\\\n        \"  ...........-;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+\",\\\n        \"  ...........>;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+\",\\\n        \"   ...........@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+\",\\\n        \"    ........,+++++++++++++++++++++++++++++++++++++++++@@@@@@@@++\",\\\n        \"     .......                                         ++@@@@@@++ \",\\\n        \"      .....                                           +++@@@++  \",\\\n        \"      ....                                              +++++   \",\\\n        \"      ....                                                      \"])\n\n    def textEnglish(self):\n        buttonText = \"Cascade horizontal dimensions\"\n        helpText = \"Spaces (vertically), at the set value, the selected horizontal dimensions::\"+ \"\\n\"\\\n                   \"- set the cascade value\"+ \"\\n\"\\\n                   \"- select two or more horizontal dimensions\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Kaskadiere waagrechte Bema\u00dfungen\"\n        helpText = \"Stelle den gew\u00fcnschten Abstand zwischen den Ma\u00dfen ein:\"+ \"\\n\"\\\n                   \"- Stellen Sie den Abstand Kaskadierung ein\"+ \"\\n\"\\\n                   \"- w\u00e4hle zwei oder mehr waagrechte Bema\u00dfungen\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Distanziamento dimensioni orizzontali\"\n        helpText = \"Distanzia (verticalmente), al valore impostato, le quote orizzontali selezionate:\"+ \"\\n\"\\\n                   \"- impostare Valore distanziamento\"+ \"\\n\"\\\n                   \"- selezionare due o pi\u00f9 quote orizzontali\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Espacement des dimensions horizontale\"\n        helpText = \"Espaces (verticalement), \u00e0 la valeur d\u00e9finie, les dimensions horizontales s\u00e9lectionn\u00e9es:\"+ \"\\n\"\\\n                   \"- d\u00e9finir Valeur d'espacement\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez au moins deux dimensions horizontales\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Espaciado de dimensi\u00f3n horizontal\"\n        helpText = \"Espacios (verticalmente), en el valor establecido, las dimensiones horizontales seleccionadas:\"+ \"\\n\"\\\n                   \"- establecer Valor de espaciado\"+ \"\\n\"\\\n                   \"- seleccione dos o m\u00e1s dimensiones horizontales\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self): # cascadeHorizDimensions\n        Selected = gui.Selection.getSelectionEx()\n        HorizontalDimList = [Select.Object for Select in Selected if Select.Object.Type == 'DistanceX']\n        if len(HorizontalDimList) > 1:\n            YPos = float(HorizontalDimList[0].Y)\n            Sign = YPos/abs(YPos)\n            for Dimension in HorizontalDimList:\n                Dimension.Y = YPos\n                YPos = YPos + DimAttrib.getDimLineDistance()*Sign\n\nclass increaseComma:\n    '''increase the comma of the dimension value (max 9)'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 7 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"+\tc #141000\",\\\n        \"@\tc #FFFF00\",\\\n        \"#\tc #FDFD00\",\\\n        \"$\tc #F9F901\",\\\n        \"%\tc #FEFE00\",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                            ....                \",\\\n        \"                                           .......              \",\\\n        \"                                           .........            \",\\\n        \"                                           ...........          \",\\\n        \"                                           .............        \",\\\n        \"                                           ................     \",\\\n        \"                                            ................... \",\\\n        \"                  ..............................................\",\\\n        \"                  ..............................................\",\\\n        \"                  ..............................................\",\\\n        \"                  ............................................. \",\\\n        \"                                            ................    \",\\\n        \"      ++++++                               ..............       \",\\\n        \"     ++@@@@++                 ....         ...........          \",\\\n        \"    ++@@@@@@++               .......       .........            \",\\\n        \"   ++@@@@@@@@+              ........       .......              \",\\\n        \"   +@@@@@@@@@++             .........      ......               \",\\\n        \"  ++@@@@@@@@@@+            ..........       ...                 \",\\\n        \"  +@@@@@@@@@@@++           ...........                          \",\\\n        \"  +@@@++++++@@@+          ............                          \",\\\n        \" ++@@@+    +@@@+          ............                          \",\\\n        \" +@@@@+    +@@@++         .....  ......                         \",\\\n        \" +@@@++    +@@@@+         .....   .....                         \",\\\n        \" +@@@+     +@@@@+        .....    .....                         \",\\\n        \" +@@@+     +@@@@+        .....    .....                         \",\\\n        \"++@@@+     ++#@@+        .....     ....                         \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@@@+      +@@@+        .....     .....                        \",\\\n        \"+@@#@+      +$@@+        .....     .....                        \",\\\n        \"++@@@+     ++@@@+        .....     .....                        \",\\\n        \" +@@@+     +@@@@+        .....    .....                         \",\\\n        \" +@@%++    +@#@@+  ++++++.....    .....   .....   .....    .....\",\\\n        \" +@@@@+    +@@@++  +@@@@+......   .....   .....   .....    .....\",\\\n        \" ++@@@+    +@@@+   +@@@@+ ......  .....   .....   .....    .....\",\\\n        \"  +@@@++++++@@@+   +@@@@+ ...... ......   .....   .....    .....\",\\\n        \"  +@@@@@@@@@@@@+   +@@@@+ ............    .....   .....    .....\",\\\n        \"  +@@@@@@@@@@@++   +@@@@+ ............    .....   .....    .....\",\\\n        \"  ++@@@@@@@@@@+    +@@@@+  ...........    .....   .....    .....\",\\\n        \"   ++@@@@@@@@++   ++@@@++  ..........     .....   .....    .....\",\\\n        \"    +++@@@@@++    +@@@@+    .........     .....   .....    .....\",\\\n        \"      +@@@@++     +@@@@+    ........      .....   .....    .....\",\\\n        \"      ++++++      +@@@@+     ......       .....   .....    .....\",\\\n        \"                  +@@@++       ...                              \",\\\n        \"                  +@@@+                                         \",\\\n        \"                  +@@++                                         \",\\\n        \"                  +@@+                                          \",\\\n        \"                  ++++                                          \"])\n\n    def textEnglish(self):\n        buttonText = \"Increase decimal places (max 9)\"\n        helpText = \"Increase decimal places of a measure:\"+ \"\\n\"\\\n                   \"- select many  measures\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Erh\u00f6ht die Kommastellen (max 9)\"\n        helpText = \"erh\u00f6ht die Kommastellen der Dimensionen\"+ \"\\n\"\\\n                   \"- w\u00e4hle mehrere Ma\u00dfzahlen\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Incrementa le cifre decimali (max 9)\"\n        helpText = \"Incrementa le cifre decimali di una dimensione:\"+ \"\\n\"\\\n                   \"- selezionare le dimensioni\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Augmenter les d\u00e9cimales (max 9)\"\n        helpText = \"Incr\u00e9mente les d\u00e9cimales d'une dimension:\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez les dimensiones\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Aumentar los lugares decimales (m\u00e1ximo 9)\"\n        helpText = \"Incrementa los lugares decimales en una dimensi\u00f3n:\"+ \"\\n\"\\\n                   \"- selecciona los dimensiones\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        Sel = gui.Selection.getSelectionEx()\n        for Elem in Sel:\n            if Elem.Object.TypeId == 'TechDraw::DrawViewDimension':\n                OldFormat = Elem.Object.FormatSpec\n                NumDig = OldFormat.find(\"%.\")\n                if NumDig != -1:\n                    NumDig = NumDig+2\n                    CharList = list(OldFormat)\n                    Digit = int(CharList[NumDig])\n                    if Digit < 9:\n                        Digit = Digit+1\n                    NewFormat = OldFormat[0:NumDig]+str(Digit)+OldFormat[NumDig+1:]\n                    Elem.Object.FormatSpec = NewFormat\n\nclass decreaseComma:\n    '''decrease the comma of the dimension value'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 7 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"+\tc #141000\",\\\n        \"@\tc #FFFF00\",\\\n        \"#\tc #FDFD00\",\\\n        \"$\tc #F9F901\",\\\n        \"%\tc #FEFE00\",\\\n        \"                                 ...                            \",\\\n        \"                               .....                            \",\\\n        \"                              ......                            \",\\\n        \"                            ........                            \",\\\n        \"                          ..........                            \",\\\n        \"                         ...........                            \",\\\n        \"                      ..............                            \",\\\n        \"                   ...........................................  \",\\\n        \"                 .............................................  \",\\\n        \"                ..............................................  \",\\\n        \"                 .............................................  \",\\\n        \"                   .................                            \",\\\n        \"                      ..............                            \",\\\n        \"                         ...........                 ....       \",\\\n        \"      ++++++               .........                .......     \",\\\n        \"     ++@@@@++               ........               ........     \",\\\n        \"    ++@@@@@@++                ......               .........    \",\\\n        \"   ++@@@@@@@@+                  ....              ..........    \",\\\n        \"   +@@@@@@@@@++                   ..              ...........   \",\\\n        \"  ++@@@@@@@@@@+                                  ............   \",\\\n        \"  +@@@@@@@@@@@++                                 ............   \",\\\n        \"  +@@@++++++@@@+                                 .....  ......  \",\\\n        \" ++@@@+    +@@@+                                 .....   .....  \",\\\n        \" +@@@@+    +@@@++                               .....    .....  \",\\\n        \" +@@@++    +@@@@+                               .....    .....  \",\\\n        \" +@@@+     +@@@@+                               .....     ....  \",\\\n        \" +@@@+     +@@@@+                               ....      ....  \",\\\n        \"++@@@+     ++#@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                               ....      ....  \",\\\n        \"+@@@@+      +@@@+                                ...      ....  \",\\\n        \"+@@@@+      +@@@+                                ....     ....  \",\\\n        \"+@@#@+      +$@@+                                ....     ....  \",\\\n        \"++@@@+     ++@@@+                                ....    .....  \",\\\n        \" +@@@+     +@@@@+                                .....   .....  \",\\\n        \" +@@%++    +@#@@+  ++++++                        .....   .....  \",\\\n        \" +@@@@+    +@@@++  +@@@@+ ....    ....    ....   ...... ......  \",\\\n        \" ++@@@+    +@@@+   +@@@@+ ....    ....    ....   ............   \",\\\n        \"  +@@@++++++@@@+   +@@@@+ ....    ....    ....    ...........   \",\\\n        \"  +@@@@@@@@@@@@+   +@@@@+ ....    ....    ....    ...........   \",\\\n        \"  +@@@@@@@@@@@++   +@@@@+ ....    ....    ....    ..........    \",\\\n        \"  ++@@@@@@@@@@+    +@@@@+ ....    ....    ....     .........    \",\\\n        \"   ++@@@@@@@@++   ++@@@++ ....    ....    ....      .......     \",\\\n        \"    +++@@@@@++    +@@@@+  ....    ....    ....      ......      \",\\\n        \"      +@@@@++     +@@@@+  ....    ....    ....        ..        \",\\\n        \"      ++++++      +@@@@+                                        \",\\\n        \"                  +@@@++                                        \",\\\n        \"                  +@@@+                                         \",\\\n        \"                  +@@++                                         \",\\\n        \"                  +@@+                                          \",\\\n        \"                  ++++                                          \"])\n\n    def textEnglish(self):\n        buttonText = \"Decrease decimal places\"\n        helpText = \"Increase decimal places of a measure:\"+ \"\\n\"\\\n                   \"- select many  measures\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Verkleinere die Anzahl der Kommastellen\"\n        helpText = \"Verkleinere die Anzahl der Kommastellen\"+ \"\\n\"\\\n                   \"- w\u00e4hle mehrere Ma\u00dfzahlen\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Decrementa le cifre decimali\"\n        helpText = \"Decrementa le cifre decimali di una dimensione:\"+ \"\\n\"\\\n                   \"- selezionare le dimensioni\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Diminue les d\u00e9cimales\"\n        helpText = \"Diminue les d\u00e9cimales d'une dimension:\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez les dimensiones\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Disminuye los lugares decimales\"\n        helpText = \"Disminuye los lugares decimales en una dimensi\u00f3n:\"+ \"\\n\"\\\n                   \"- selecciona los dimensiones\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        Sel = gui.Selection.getSelectionEx()\n        for Elem in Sel:\n            if Elem.Object.TypeId == 'TechDraw::DrawViewDimension':\n                OldFormat = Elem.Object.FormatSpec\n                NumDig = OldFormat.find(\"%.\")\n                if NumDig != -1:\n                    NumDig = NumDig+2\n                    CharList = list(OldFormat)\n                    Digit = int(CharList[NumDig])\n                    if Digit > 0:\n                        Digit = Digit-1\n                    NewFormat = OldFormat[0:NumDig]+str(Digit)+OldFormat[NumDig+1:]\n                    Elem.Object.FormatSpec = NewFormat\n\nclass createHorizCoordDim:\n    '''Create horizontal coordinate dimension'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 2 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"       ...                      ...         ...           ...   \",\\\n        \"       ...                      ...         ...           ...   \",\\\n        \"       ...                      ...         ...           ...   \",\\\n        \"       ...                      ...         ...           ...   \",\\\n        \"       ...                      ...         ...           ...   \",\\\n        \"       ...                      ...         ...           ...   \",\\\n        \"       ...                      ...         ...           ...   \",\\\n        \"       ...                      ...         ...           ...   \",\\\n        \"       ...                      ...         ...           ...   \",\\\n        \"       ...                      ...         ...           ...   \",\\\n        \"       ...                      ...         ...           ...   \",\\\n        \"       ...                      ...         ...           ...   \",\\\n        \"       ...                     .....        ...           ...   \",\\\n        \"     .......                  .......       ...           ...   \",\\\n        \"    ........                 ........       ...           ...   \",\\\n        \" ......................................     ...           ...   \",\\\n        \" ......................................     ...           ...   \",\\\n        \" ......................................     ...           ...   \",\\\n        \"    .........                .........      ...           ...   \",\\\n        \"     .......                  .......       ...           ...   \",\\\n        \"      .....                     ...         ...           ...   \",\\\n        \"       ...                      ...         ...           ...   \",\\\n        \"       ...                      ...         ...           ...   \",\\\n        \"       ...                                  ...           ...   \",\\\n        \"       ...                                  ...           ...   \",\\\n        \"       ...                                  ...           ...   \",\\\n        \"       ...                                  ...           ...   \",\\\n        \"       ...                                  ...           ...   \",\\\n        \"       ...                                  ...           ...   \",\\\n        \"       ...                                  ...           ...   \",\\\n        \"       ...                                  ...           ...   \",\\\n        \"       ...                                  ...           ...   \",\\\n        \"       ....                                .....          ...   \",\\\n        \"     .......                              .......         ...   \",\\\n        \"    .........                            ........         ...   \",\\\n        \" ..................................................       ...   \",\\\n        \" ..................................................       ...   \",\\\n        \" ..................................................       ...   \",\\\n        \"    .........                            ........         ...   \",\\\n        \"     .......                              ......          ...   \",\\\n        \"      .....                                ....           ...   \",\\\n        \"       ...                                  ...           ...   \",\\\n        \"       ...                                  ...           ...   \",\\\n        \"       ...                                                ...   \",\\\n        \"       ...                                                ...   \",\\\n        \"       ...                                                ...   \",\\\n        \"       ...                                                ...   \",\\\n        \"       ...                                                ...   \",\\\n        \"       ...                                                ...   \",\\\n        \"       ...                                                ...   \",\\\n        \"       ...                                                ...   \",\\\n        \"       ...                                                ...   \",\\\n        \"       ...                                               ....   \",\\\n        \"     .......                                            ....... \",\\\n        \"    ........                                           ........ \",\\\n        \" ...............................................................\",\\\n        \" ...............................................................\",\\\n        \" ...............................................................\",\\\n        \"  .............................                        .........\",\\\n        \"     .......                                            ....... \",\\\n        \"      .....                                              .....  \",\\\n        \"       ...                                                ...   \",\\\n        \"       ...                                                ...   \",\\\n        \"        ..                                                      \"])\n\n    def textEnglish(self):\n        buttonText = \"Create horizontal coordinate dimensions\"\n        helpText = \"- adjust the desired cascade spacing\"+ \"\\n\"\\\n                   \"- select three or more vertexes\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Erzeuge waagrechte Koordinatenbema\u00dfung\"\n        helpText = \"- stelle den gew\u00fcnschten Abstand Kaskadierung den Ma\u00dfen ein\"+ \"\\n\"\\\n                   \"- w\u00e4hle drei oder mehr Kontrollpunkte\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Dimensioni parallele/coordinate orizzontali\"\n        helpText = \"- impostare Valore distanziamento\"+ \"\\n\"\\\n                   \"- selezionare tre o pi\u00f9 vertici\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Dimensions parall\u00e8les/coordonn\u00e9es horizontales\"\n        helpText = \"- d\u00e9finir Valeur d'espacement\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez trois sommets ou plus\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Dimensiones paralelas/coordenadas horizontales\"\n        helpText = \"- establecer Valor de espaciado\"+ \"\\n\"\\\n                   \"- seleccione tres o m\u00e1s v\u00e9rtices\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self): # createHorizCoordDim\n        def sortVertex(Vertex):\n            return Vertex.Point.x\n\n        (OK,ElementNames,View) = commonTools.selectionOK()\n        if OK:\n            VertexNames = [VertexName for VertexName in ElementNames if VertexName[:6]=='Vertex']\n            Vertexes = [View.getVertexBySelection(VertexName) for VertexName in VertexNames]\n            Vertexes.sort(key=sortVertex)\n            if len(Vertexes) > 1:\n                XPos = float(Vertexes[0].X)\n                YPos = float(Vertexes[0].Y)\n                Sign = YPos/abs(YPos)\n                for i  in range(len(Vertexes)-1):\n                    DistanceDim=TechDraw.makeDistanceDim(View,'DistanceX',Vertexes[0].Point,Vertexes[i+1].Point)\n                    DistanceDim.X = (XPos+Vertexes[i+1].Point.x)/2\n                    YPos = YPos + DimAttrib.getDimLineDistance()*Sign\n                    DistanceDim.Y = YPos\n            gui.Selection.clearSelection()\n\nclass createVertCoordDim:\n    '''Create vertical coordinate dimension'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 2 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"                                                       ....     \",\\\n        \"                                                     .......    \",\\\n        \"                                                     ........   \",\\\n        \"............................................................... \",\\\n        \"............................................................... \",\\\n        \"............................................................... \",\\\n        \"                                                    .........   \",\\\n        \"                                                     .......    \",\\\n        \"                                                      .....     \",\\\n        \"                                                       ...      \",\\\n        \"                                                       ...      \",\\\n        \"                                                       ...      \",\\\n        \"                                                       ...      \",\\\n        \"                                   ...                 ...      \",\\\n        \"                                   ...                 ...      \",\\\n        \"                                 ......                ...      \",\\\n        \"                                ........               ...      \",\\\n        \"...........................................            ...      \",\\\n        \"...........................................            ...      \",\\\n        \"...........................................            ...      \",\\\n        \"                                .........              ...      \",\\\n        \"                                 .......               ...      \",\\\n        \"                                  .....                ...      \",\\\n        \"                                   ...                 ...      \",\\\n        \"                                   ...                 ...      \",\\\n        \"               ...                 ...                 ...      \",\\\n        \"               ....                ...                 ...      \",\\\n        \"             .......               ...                 ...      \",\\\n        \"            ........               ...                 ...      \",\\\n        \".......................            ...                 ...      \",\\\n        \".......................            ...                 ...      \",\\\n        \".......................            ...                 ...      \",\\\n        \"            ........               ...                 ...      \",\\\n        \"             .......               ...                 ....     \",\\\n        \"              .....                ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ....               .....                ....     \",\\\n        \"             .......             .......             .......    \",\\\n        \"             ........           .........            ........   \",\\\n        \"................................................................\",\\\n        \"................................................................\",\\\n        \"............................................................... \",\\\n        \"             ........            ........            ........   \",\\\n        \"             .......             .......             .......    \",\\\n        \"              .....               .....               .....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ....     \",\\\n        \"               ...                 ...                 ...      \",\\\n        \"                                                                \"])\n\n    def textEnglish(self):\n        buttonText = \"Create vertical coordinate dimensions\"\n        helpText = \"- adjust the desired cascade spacing\"+ \"\\n\"\\\n                   \"- select three or more vertexes\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Erzeuge senkrechte Koordinatenbema\u00dfung\"\n        helpText = \"- stelle den gew\u00fcnschten Abstand Kaskadierung den Ma\u00dfen ein\"+ \"\\n\"\\\n                   \"- w\u00e4hle drei oder mehr Kontrollpunkte\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Dimensioni parallele/coordinate verticali\"\n        helpText = \"- impostare Valore distanziamento\"+ \"\\n\"\\\n                   \"- selezionare tre o pi\u00f9 vertici\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Dimensions parall\u00e8les/coordonn\u00e9es verticales\"\n        helpText = \"- d\u00e9finir Valeur d'espacement\"+ \"\\n\"\\\n                          \"- s\u00e9lectionnez trois sommets ou plus\"+ \"\\n\"\\\n                          \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Dimensiones paralelas/coordenadas verticales\"\n        helpText = \"- establecer Valor de espaciado\"+ \"\\n\"\\\n                   \"- seleccione tres o m\u00e1s v\u00e9rtices\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        def sortVertex(Vertex):\n            return Vertex.Point.y\n\n        (OK,ElementNames,View) = commonTools.selectionOK()\n        if OK:\n            VertexNames = [VertexName for VertexName in ElementNames if VertexName[:6]=='Vertex']\n            Vertexes = [View.getVertexBySelection(VertexName) for VertexName in VertexNames]\n            Vertexes.sort(key=sortVertex)\n            Vertexes.reverse()\n            if len(Vertexes) > 1:\n                XPos = float(Vertexes[0].X)\n                YPos = float(Vertexes[0].Y)\n                Sign = XPos/abs(XPos)\n                for i  in range(len(Vertexes)-1):\n                    DistanceDim=TechDraw.makeDistanceDim(View,'DistanceY',Vertexes[0].Point,Vertexes[i+1].Point)\n                    DistanceDim.Y = (YPos+Vertexes[i+1].Point.y)/2\n                    XPos = XPos + DimAttrib.getDimLineDistance()*Sign\n                    DistanceDim.X = XPos\n            gui.Selection.clearSelection()\n\nclass createHorizChamferDim:\n    '''Create horizontal chamfer dimension'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 11 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"+\tc #141000\",\\\n        \"@\tc #FFFF00\",\\\n        \"#\tc #F8F700\",\\\n        \"$\tc #FDFD00\",\\\n        \"%\tc #FDFC00\",\\\n        \"&\tc #F9F900\",\\\n        \"*\tc #FEFE00\",\\\n        \"=\tc #2D2000\",\\\n        \"-\tc #2A2400\",\\\n        \"                          ....             ....                 \",\\\n        \"                          ....             ....                 \",\\\n        \"                          ....             ....                 \",\\\n        \"                          ....             ....                 \",\\\n        \"                          ....             ....                 \",\\\n        \"                         ......            .....                \",\\\n        \"                        ........          .......               \",\\\n        \"                       ..........        .........              \",\\\n        \"                       ..........       ...........             \",\\\n        \".....................................................           \",\\\n        \".....................................................           \",\\\n        \".....................................................           \",\\\n        \"                       ..........       ...........             \",\\\n        \"                        .........        .........              \",\\\n        \"                         .......          .......               \",\\\n        \"                          ....             .....                \",\\\n        \"                          ....             ....                 \",\\\n        \"                          ....             ....                 \",\\\n        \"                          ....             ....                 \",\\\n        \"                          ....             ....                 \",\\\n        \"                          ....             ....                 \",\\\n        \"                          ....                                  \",\\\n        \"                          ....                                  \",\\\n        \"                          ....             +++++++++++++++++++++\",\\\n        \"                          ....           +++++++++++++++++++++++\",\\\n        \"                          ....          +++@@@@@@@@@@@@@@@@@@@@@\",\\\n        \"                          ....         +++@@@@@@@@@@@@@@@@@@@@@@\",\\\n        \"                          ....        +++@@@@#@@@@@@@@@@@@@@@@@@\",\\\n        \"                          ....       +++@@@@++++++++++++++++++++\",\\\n        \"                          ....      +++@@@@+++++++++++++++++++++\",\\\n        \"                          ....     +++@$@@+++                   \",\\\n        \"                          ....    +++@@@@+++                    \",\\\n        \"                          ....   +++@@@@+++                     \",\\\n        \"                          ....  +++@@@@+++                      \",\\\n        \"                          .... +++@@@%+++                       \",\\\n        \"                              +++@@@&+++                        \",\\\n        \"                             +++@@@@+++                         \",\\\n        \"                            +++*@@@+++                          \",\\\n        \"                           +++@@@@+++                           \",\\\n        \"                           ++@@@++++                            \",\\\n        \"                           ++@@++++                             \",\\\n        \"                           ++@@+++                              \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                           ++@@++                               \",\\\n        \"                          =++@@++                               \",\\\n        \"                          -++@@++                               \"])\n\n    def textEnglish(self):\n        buttonText = \"Create a horizontal chamfer dimension\"\n        helpText = \"- select two vertexes\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Erzeuge waagrechte Fasenbema\u00dfung\"\n        helpText = \"- w\u00e4hle zwei Kontrollpunkte\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Dimensione orizzontale smusso\"\n        helpText = \"- Selezionare due vertici\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Chanfrein de dimension horizontale\"\n        helpText = \"- S\u00e9lectionnez deux sommets\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"dimensi\u00f3n horizontal de chafl\u00e1n\"\n        helpText = \"- Seleccione dos v\u00e9rtices\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        (OK,ElementNames,View) = commonTools.selectionOK()\n        if OK:\n            VertexNames = [VertexName for VertexName in ElementNames if VertexName[:6]=='Vertex']\n            Vertexes = [View.getVertexBySelection(VertexName) for VertexName in VertexNames]\n            if len(Vertexes) > 1:\n                ChamferDim=TechDraw.makeDistanceDim(View,'DistanceX',Vertexes[0].Point,Vertexes[1].Point)\n                ChamferDim.X = (Vertexes[0].Point.x+Vertexes[1].Point.x)/2\n                MaxY = max(Vertexes[0].Point.y,Vertexes[1].Point.y)\n                Sign = MaxY/abs(MaxY)\n                ChamferDim.Y = MaxY + 7.0*Sign\n                Dx, Dy  = Vertexes[0].Point.x-Vertexes[1].Point.x, Vertexes[0].Point.y-Vertexes[1].Point.y\n                Alpha = str(int(math.degrees(abs(math.atan(Dx/Dy)))))\n                ChamferDim.FormatSpec = ChamferDim.FormatSpec+'x'+Alpha+'\u00b0'\n            gui.Selection.clearSelection()\n\nclass createVertChamferDim:\n    '''Create vertical chamfer dimension'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 6 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"+\tc #141000\",\\\n        \"@\tc #FFFF00\",\\\n        \"#\tc #FDFD00\",\\\n        \"$\tc #F8F700\",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"      ....                                                      \",\\\n        \"      ....                                                      \",\\\n        \"      ....                                                      \",\\\n        \"      ....                                                      \",\\\n        \"      ....                                                      \",\\\n        \"      ....                                                      \",\\\n        \"      ....                                                      \",\\\n        \"     ......                                                     \",\\\n        \"    ........                                                    \",\\\n        \"   ..........                                                   \",\\\n        \" .....................................                          \",\\\n        \" .....................................    ++++++++++++++++++++++\",\\\n        \" .....................................  ++++++++++++++++++++++++\",\\\n        \" ..................................... +++@@@@@@@@@@@@@@@@@@@@@@\",\\\n        \"   ..........                         +++@@@@@@@@@@@@@@@@@@@@@@@\",\\\n        \"    ........                         +++@@@@@#@@@@@@@@@@@@@@@@@@\",\\\n        \"     ......                         +++@@@@@++++++++++++++++++++\",\\\n        \"      ....                         +++@@@@@+++++++++++++++++++++\",\\\n        \"      ....                        +++@@@@@+++                   \",\\\n        \"      ....                       +++@@@@@+++                    \",\\\n        \"      ....                      +++@@@@@+++                     \",\\\n        \"      ....                     +++@@@@@+++                      \",\\\n        \"     ......                   +++@@@@@+++                       \",\\\n        \"    ........                 +++@@@@@+++                        \",\\\n        \"   ..........               +++@@@@@+++                         \",\\\n        \" .......................   +++@@@@@+++                          \",\\\n        \" .......................  +++@@@@@+++                           \",\\\n        \" .......................  ++@@@@@+++                            \",\\\n        \" .......................  ++@@$@+++                             \",\\\n        \"   ..........             ++@@@+++                              \",\\\n        \"    ........              ++@@@++                               \",\\\n        \"     ......               ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \",\\\n        \"      ....                ++@@@++                               \"])\n\n    def textEnglish(self):\n        buttonText = \"Create a vertical chamfer dimension\"\n        helpText = \"- select two vertexes\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Erzeuge senkrechte Fasenbema\u00dfung\"\n        helpText = \"- w\u00e4hle zwei Kontrollpunkte\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Dimensione verticale smusso\"\n        helpText = \"- Selezionare due vertici\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Dimension verticales de chanfrein\"\n        helpText = \"- S\u00e9lectionnez deux sommets\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"dimensi\u00f3n verticales de chafl\u00e1n\"\n        helpText = \"- Seleccione dos v\u00e9rtices\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        (OK,ElementNames,View) = commonTools.selectionOK()\n        if OK:\n            VertexNames = [VertexName for VertexName in ElementNames if VertexName[:6]=='Vertex']\n            Vertexes = [View.getVertexBySelection(VertexName) for VertexName in VertexNames]\n            if len(Vertexes) > 1:\n                ChamferDim=TechDraw.makeDistanceDim(View,'DistanceY',Vertexes[0].Point,Vertexes[1].Point)\n                ChamferDim.Y = (Vertexes[0].Point.y+Vertexes[1].Point.y)/2\n                MaxX = max(Vertexes[0].Point.x,Vertexes[1].Point.x)\n                Sign = MaxX/abs(MaxX)\n                ChamferDim.X = MaxX + 7.0*Sign\n                Dx, Dy  = Vertexes[0].Point.x-Vertexes[1].Point.x, Vertexes[0].Point.y-Vertexes[1].Point.y\n                Alpha = str(round(math.degrees(abs(math.atan(Dy/Dx)))))\n                ChamferDim.FormatSpec = ChamferDim.FormatSpec+'x'+Alpha+'\u00b0'\n            gui.Selection.clearSelection()\n\nclass holeTable:\n    '''Create a hole table'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 2 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"                                                                \",\\\n        \"................................................................\",\\\n        \"................................................................\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \".. ...........  .. ..      ... .. ...      .....     ...  ..  ..\",\\\n        \".. ...........  .. ..      ..  .. ...      .....    ........  ..\",\\\n        \"..     ...      ..  ...   ...  ..  ...    ... ..   ..   ...   ..\",\\\n        \"..     ...      ..  ...   ..   ..   ...  ...  ..  ..    ...   ..\",\\\n        \"..     ...      ..   ... ...   ..   ...  ..   ..  ..   ....   ..\",\\\n        \"..     ...      ..    ....     ..    ......   .. ..    .. ..  ..\",\\\n        \"..     ...      ..    ....     ..    ......   .. ..   ..  ..  ..\",\\\n        \"..     ...      ..    ....     ..     ....    .. ..  ...  ..  ..\",\\\n        \"..     ...      ..   ......    ..     ...     .. ..  ..   ..  ..\",\\\n        \"..     ...      ..   ... ...   ..     ...     .. .. ..    ..  ..\",\\\n        \"..     ...      ..  ...   ...  ..     ...     .. .....    ..  ..\",\\\n        \"..     ...      .. ...    .... ..     ...     ..  ...    ..   ..\",\\\n        \"..     ...      .. ...     ... ..     ...     ..  ...   ...   ..\",\\\n        \"..     ...      .. ..       .. ..     ...     ..  ........    ..\",\\\n        \"..              ..             ..             .. ..  ...      ..\",\\\n        \"..              ..             ..             .. ..           ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"................................................................\",\\\n        \"................................................................\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"................................................................\",\\\n        \"................................................................\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"................................................................\",\\\n        \"................................................................\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..              ..\",\\\n        \"..              ..             ..             ..                \",\\\n        \"..              ..                                              \",\\\n        \"                                                                \",\\\n        \"                                                                \"])\n\n    def textEnglish(self):\n        buttonText = \"Create hole table\"\n        helpText = \"- select one vertex as origin\"+ \"\\n\"\\\n                   \"- select many hole circles\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Erzeuge eine Bohrungstabelle\"\n        helpText = \"- w\u00e4hle einen Kontrollpunkt als Koordinatenursprung\"+ \"\\n\"\\\n                   \"- w\u00e4hle mehrere Bohrungskreise\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Genera tabella fori\"\n        helpText = \"- Selezionare un vertice come riferimento/origine\"+ \"\\n\"\\\n                   \"- selezionare le circonferenze dei fori\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"G\u00e9n\u00e9rer une table de trous\"\n        helpText = \"- S\u00e9lectionnez un sommet comme r\u00e9f\u00e9rence/origine\"+ \"\\n\"\\\n                   \"- s\u00e9lectionner les circonf\u00e9rences des trous\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Generar tabla de agujeros\"\n        helpText = \"- Seleccione un v\u00e9rtice como referencia/origen\"+ \"\\n\"\\\n                   \"- seleccione las circunferencias de los agujeros\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n\n        def drawArrow(Origin,P1,P2,P3,P4,P5):\n            '''Draw arrows at origin'''\n            View.makeCosmeticLine(Origin,P1,1)\n            View.makeCosmeticLine(P2,P3,1)\n            View.makeCosmeticLine(P3,P4,1)\n            View.makeCosmeticLine(P3,P5,1)\n\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            Doc = app.activeDocument()\n            XView,YView = commonTools.getViewCoords(View)\n            if ObjectList[0][0:6] == 'Vertex':\n                Origin = View.getVertexBySelection(ObjectList[0]).Point\n                P1X, P1Y = Origin + app.Vector(0,-10,0), Origin + app.Vector(-10,0,0)\n                P2X, P2Y = Origin + app.Vector(0,-5,0), Origin + app.Vector(-5,0,0)\n                P3X, P3Y = Origin + app.Vector(10,-5,0), Origin + app.Vector(-5,10,0)\n                P4X, P4Y = Origin + app.Vector(7,-4,0), Origin + app.Vector(-4,7,0)\n                P5X, P5Y = Origin + app.Vector(7,-6,0), Origin + app.Vector(-6,7,0)\n                drawArrow(Origin,P1X,P2X,P3X,P4X,P5X)\n                drawArrow(Origin,P1Y,P2Y,P3Y,P4Y,P5Y)\n                commonTools.createAnnot('OriginX','X',float(XView)+Origin.x+12,float(YView)+Origin.y-7)\n                commonTools.createAnnot('OriginY','Y',float(XView)+Origin.x-5,float(YView)+Origin.y+12)\n                Spread =Doc.addObject('Spreadsheet::Sheet','Spreadsheet')\n                HoleTable = Doc.addObject('TechDraw::DrawViewSpreadsheet','HoleTable')\n                HoleTable.Source = Doc.Spreadsheet\n                Spread.set('A1','Tag')\n                Spread.set('B1','XLoc')\n                Spread.set('C1','YLoc')\n                Spread.set('D1','SIZE \u00d8')\n                Num = 2\n                for ObjectString in ObjectList:\n                    if ObjectString[0:4] == 'Edge':\n                        Edge = View.getEdgeBySelection(ObjectString)\n                        if Edge.Curve.TypeId == 'Part::GeomCircle':\n                            Object = Edge.Curve\n                            Center, Radius = Object.Center, Object.Radius\n                            Spread.set('A'+str(Num),'A'+str(Num-1))\n                            Spread.set('B'+str(Num),str(Center.x-Origin.x))\n                            Spread.set('C'+str(Num),str(Center.y-Origin.y))\n                            Spread.set('D'+str(Num),str(2*Radius))\n                            commonTools.createAnnot('A'+str(Num-1),'A'+str(Num-1),float(XView)+Center.x+Radius,float(YView)+Center.y+Radius)\n                            Num +=1\n                HoleTable.CellEnd = 'D'+str(Num-1)\n                Doc.recompute()\n                Doc.Page.addView(HoleTable)\n            Doc.recompute()\n\nclass drawCirc:\n    '''Draw a Circle'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 16 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"+\tc #FFFF00\",\\\n        \"@\tc #2B2200\",\\\n        \"#\tc #FFFD00\",\\\n        \"$\tc #FFF700\",\\\n        \"%\tc #FF1500\",\\\n        \"&\tc #FFFE00\",\\\n        \"*\tc #FFF300\",\\\n        \"=\tc #FF1400\",\\\n        \"-\tc #FFF600\",\\\n        \";\tc #FFFB00\",\\\n        \">\tc #DFDF00\",\\\n        \",\tc #FBFB00\",\\\n        \"'\tc #C5C400\",\\\n        \")\tc #EAEA00\",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                         .........                              \",\\\n        \"                       ..............                           \",\\\n        \"                     ................                           \",\\\n        \"                   ..................     ..    ++++            \",\\\n        \"                   .........     ...     .... +++@@+++          \",\\\n        \"                   ......               .....++@@@@@@++         \",\\\n        \"                    ..                    .+++@@++++@@++        \",\\\n        \"                                           ++@@++..+#@@++       \",\\\n        \"            ..                            ++@@++....+$@@+       \",\\\n        \"           ....                          ++@@++......++@@+      \",\\\n        \"          ......                         ++@++.......%&+@++     \",\\\n        \"         .....                           ++@++........*+@++     \",\\\n        \"        ......                           ++@++.......=++@++     \",\\\n        \"       ......                            ++@@++......++@@+      \",\\\n        \"       .....                              ++@+++....+-@@+       \",\\\n        \"      .....                                +@@+++..+;@@++.      \",\\\n        \"      .....                                ++@@@+++++@++...     \",\\\n        \"      ....                                +++++@@@@@@@++...     \",\\\n        \"     .....                                +++ +++@@@+++....     \",\\\n        \"     ....                              ++  ++   +++++  ...      \",\\\n        \"    .....                      ++++   ++++              .       \",\\\n        \"    .....                    +++@@+++ ++++                      \",\\\n        \"      ..                    ++@@@@@@++ ++                       \",\\\n        \"                          +++@@++++@@++                         \",\\\n        \"                          ++@@++..+#@@++                  ...   \",\\\n        \"                         ++@@++....+$@@+                 ....   \",\\\n        \"                         +@@++......++@@+                .....  \",\\\n        \"                        ++@++.......%&+@++               .....  \",\\\n        \"                        ++@++........*+@++               .....  \",\\\n        \"     ...                ++@++.......=++@++               .....  \",\\\n        \"    ....                 +@@++......++@@+                .....  \",\\\n        \"    ....                 ++@+++....+-@@+                 .....  \",\\\n        \"   .....                  +@@+++..+;@@++                 ....   \",\\\n        \"   .....                  >,@@@+++++@++                  ....   \",\\\n        \"   .....                   '++@@@@@@@++                 .....   \",\\\n        \"    ....                     )++@@@+++                  ....    \",\\\n        \"    .....                      +++++                    ....    \",\\\n        \"     ....                                              .....    \",\\\n        \"     ....                                              ....     \",\\\n        \"     .....                                            .....     \",\\\n        \"      ....                                             ....     \",\\\n        \"      .....                                              .      \",\\\n        \"       .....                                                    \",\\\n        \"       .....                                                    \",\\\n        \"        ...                                        .            \",\\\n        \"         .                                        ...           \",\\\n        \"                                                 .....          \",\\\n        \"                                                ......          \",\\\n        \"               ...                            .......           \",\\\n        \"               ....                          .......            \",\\\n        \"               .....                        .......             \",\\\n        \"               .......                    ........              \",\\\n        \"                .........               ........                \",\\\n        \"                 .............          .......                 \",\\\n        \"                   ...........          ......                  \",\\\n        \"                     .........          ....                    \",\\\n        \"                         .....                                  \",\\\n        \"                           ...                                  \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \"])\n\n    def textEnglish(self):\n        buttonText = \"Draw an cosmetic circumference (center and 1 vertex)\"\n        helpText = \"Draw a cosmetic circumference using two vertices:\"+ \"\\n\"\\\n                   \"- choose the line attributes:\"+ \"\\n\"\\\n                   \"- select the first vertex (center) -> in sequence the second (radius)\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Kosmetischer Umfang (Zentrum und 1 Scheitelpunkt)\"\n        helpText = \"Zeichnen Sie einen kosmetischen Kreis mit zwei Scheitelpunkt:\"+ \"\\n\"\\\n                   \"- W\u00e4hlen Sie die Linienattribute:\"+ \"\\n\"\\\n                   \"- W\u00e4hlen Sie den ersten Scheitelpunkt (Mitte) -> nacheinander den zweiten (Radius)\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Circonferenza cosmetica (centro e 1 vertice)\"\n        helpText = \"Disegna una circonferenza cosmetica utilizzando due vertici:\"+ \"\\n\"\\\n                   \"- scegliere gli attributi linea\"+\"\\n\"\\\n                   \"- selezionare il primo vertice (centro) -->in sequenza il secondo (raggio)\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Circonf\u00e9rence cosm\u00e9tique (centre et 1 sommet)\"\n        helpText = \"Dessinez une circonf\u00e9rence cosm\u00e9tique en utilisant deux sommets:\"+ \"\\n\"\\\n                   \"- choisir des attributs\"+ \"\\n\"\\\n                   \"- s\u00e9lectionner le premier sommet (centre) --> en s\u00e9quence le second (rayon)\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Circunferencia cosm\u00e9tica (centro y 1 v\u00e9rtice)\"\n        helpText = \"Dibuja un c\u00edrculo cosm\u00e9tico usando dos v\u00e9rtices:\"+ \"\\n\"\\\n                   \"- elegir atributos\"+ \"\\n\"\\\n                   \"- seleccione el primer v\u00e9rtice (centro) --> en secuencia el segundo (radio)\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self): # drawCirc\n\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            if len(ObjectList) == 2:\n                if ObjectList[0][0:6] == 'Vertex' and ObjectList[1][0:6] == 'Vertex':\n                    Center =  View.getVertexBySelection(ObjectList[0]).Point\n                    Point =  View.getVertexBySelection(ObjectList[1]).Point\n                    Radius = (Point-Center).Length\n                    View.makeCosmeticCircle(Center, Radius,Attrib.getStyle(), Attrib.getWidth(), Attrib.getColorTuple())\n            gui.Selection.clearSelection()\n\nclass drawArc:\n    '''Draw an arc rotating math. positive'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 155 2\",\\\n        \"  \tc None\",\\\n        \". \tc #2A2100\",\\\n        \"+ \tc #141000\",\\\n        \"@ \tc #2C2100\",\\\n        \"# \tc #2A2300\",\\\n        \"$ \tc #726E00\",\\\n        \"% \tc #FFFF00\",\\\n        \"& \tc #2D2400\",\\\n        \"* \tc #2B2200\",\\\n        \"= \tc #5E5700\",\\\n        \"- \tc #EFEF00\",\\\n        \"; \tc #2F2800\",\\\n        \"> \tc #DDDD00\",\\\n        \", \tc #2A2200\",\\\n        \"' \tc #D0CC00\",\\\n        \") \tc #3D3500\",\\\n        \"! \tc #FFB700\",\\\n        \"~ \tc #FF6000\",\\\n        \"{ \tc #FF4400\",\\\n        \"] \tc #FF6200\",\\\n        \"^ \tc #FFC000\",\\\n        \"/ \tc #2C2300\",\\\n        \"( \tc #726800\",\\\n        \"_ \tc #FFFD00\",\\\n        \": \tc #FF0000\",\\\n        \"< \tc #FF7300\",\\\n        \"[ \tc #2B2300\",\\\n        \"} \tc #463C00\",\\\n        \"| \tc #FFFA00\",\\\n        \"1 \tc #FFD300\",\\\n        \"2 \tc #FF9100\",\\\n        \"3 \tc #FFA500\",\\\n        \"4 \tc #2F2400\",\\\n        \"5 \tc #FF3C00\",\\\n        \"6 \tc #FF0B00\",\\\n        \"7 \tc #FF0800\",\\\n        \"8 \tc #FFF700\",\\\n        \"9 \tc #FF2000\",\\\n        \"0 \tc #FF3500\",\\\n        \"a \tc #2B2100\",\\\n        \"b \tc #CDC800\",\\\n        \"c \tc #FFB800\",\\\n        \"d \tc #FF0700\",\\\n        \"e \tc #352D00\",\\\n        \"f \tc #FF0E00\",\\\n        \"g \tc #FF4D00\",\\\n        \"h \tc #FF0400\",\\\n        \"i \tc #FF1300\",\\\n        \"j \tc #A29B00\",\\\n        \"k \tc #FFB600\",\\\n        \"l \tc #FFFB00\",\\\n        \"m \tc #FF4A00\",\\\n        \"n \tc #FF5D00\",\\\n        \"o \tc #F7F700\",\\\n        \"p \tc #FFD200\",\\\n        \"q \tc #FF1200\",\\\n        \"r \tc #FFDE00\",\\\n        \"s \tc #FFC700\",\\\n        \"t \tc #FF2800\",\\\n        \"u \tc #FF3100\",\\\n        \"v \tc #FFD100\",\\\n        \"w \tc #2D2000\",\\\n        \"x \tc #302400\",\\\n        \"y \tc #FFCD00\",\\\n        \"z \tc #FFB300\",\\\n        \"A \tc #FFD000\",\\\n        \"B \tc #413C00\",\\\n        \"C \tc #342B00\",\\\n        \"D \tc #312900\",\\\n        \"E \tc #C9C900\",\\\n        \"F \tc #2C2200\",\\\n        \"G \tc #B3AD00\",\\\n        \"H \tc #F2F200\",\\\n        \"I \tc #C4C400\",\\\n        \"J \tc #807A00\",\\\n        \"K \tc #2D2500\",\\\n        \"L \tc #635E00\",\\\n        \"M \tc #292000\",\\\n        \"N \tc #2D2200\",\\\n        \"O \tc #FCFC00\",\\\n        \"P \tc #A8A800\",\\\n        \"Q \tc #C5C000\",\\\n        \"R \tc #494100\",\\\n        \"S \tc #F5F500\",\\\n        \"T \tc #382D00\",\\\n        \"U \tc #352E00\",\\\n        \"V \tc #2D2300\",\\\n        \"W \tc #292200\",\\\n        \"X \tc #2F2700\",\\\n        \"Y \tc #342A00\",\\\n        \"Z \tc #E9E600\",\\\n        \"` \tc #443C00\",\\\n        \" .\tc #BDBD00\",\\\n        \"..\tc #6B6300\",\\\n        \"+.\tc #2A2000\",\\\n        \"@.\tc #646000\",\\\n        \"#.\tc #5F5800\",\\\n        \"$.\tc #FDFD00\",\\\n        \"%.\tc #FAF800\",\\\n        \"&.\tc #322A00\",\\\n        \"*.\tc #E5E100\",\\\n        \"=.\tc #6A6500\",\\\n        \"-.\tc #D6D300\",\\\n        \";.\tc #E3E300\",\\\n        \">.\tc #F4F400\",\\\n        \",.\tc #FFF800\",\\\n        \"'.\tc #FF0A00\",\\\n        \").\tc #FFC300\",\\\n        \"!.\tc #FF4E00\",\\\n        \"~.\tc #FF8900\",\\\n        \"{.\tc #FF8E00\",\\\n        \"].\tc #FFE400\",\\\n        \"^.\tc #FFA300\",\\\n        \"/.\tc #FF7D00\",\\\n        \"(.\tc #FFD700\",\\\n        \"_.\tc #A7A300\",\\\n        \":.\tc #FFDB00\",\\\n        \"<.\tc #FF4900\",\\\n        \"[.\tc #FF0200\",\\\n        \"}.\tc #FF5200\",\\\n        \"|.\tc #C6C300\",\\\n        \"1.\tc #FFE000\",\\\n        \"2.\tc #FF1600\",\\\n        \"3.\tc #FFEB00\",\\\n        \"4.\tc #FFBF00\",\\\n        \"5.\tc #FF2A00\",\\\n        \"6.\tc #FF1C00\",\\\n        \"7.\tc #FFA400\",\\\n        \"8.\tc #FF5700\",\\\n        \"9.\tc #FF6B00\",\\\n        \"0.\tc #FFDC00\",\\\n        \"a.\tc #FF0300\",\\\n        \"b.\tc #FF0100\",\\\n        \"c.\tc #FFBC00\",\\\n        \"d.\tc #FFFC00\",\\\n        \"e.\tc #FF0900\",\\\n        \"f.\tc #FF1A00\",\\\n        \"g.\tc #FFEE00\",\\\n        \"h.\tc #FF1700\",\\\n        \"i.\tc #FF2C00\",\\\n        \"j.\tc #FBFB00\",\\\n        \"k.\tc #FFBE00\",\\\n        \"l.\tc #FF9200\",\\\n        \"m.\tc #FF2B00\",\\\n        \"n.\tc #FF1D00\",\\\n        \"o.\tc #FFA600\",\\\n        \"p.\tc #FF4300\",\\\n        \"q.\tc #FF5400\",\\\n        \"r.\tc #FF9300\",\\\n        \"s.\tc #FF3B00\",\\\n        \"t.\tc #FF2200\",\\\n        \"u.\tc #FF4100\",\\\n        \"v.\tc #FF9F00\",\\\n        \"w.\tc #EEED00\",\\\n        \"x.\tc #2A2400\",\\\n        \"                                                                                                                                \",\\\n        \"                                                                                  . + + + + + +                                 \",\\\n        \"                                                                          @ # + + + + + + + $ %         % % % % %               \",\\\n        \"                                                                    & * + + + + @ = - % % % % % %   % % % % % % % % %           \",\\\n        \"                                                                * + + + + ; > % % % % % % % % % % % % % % % % % % % % %         \",\\\n        \"                                                            * + + + , ' % % % % % % % % % % % % % % % % % % % % % % % % %       \",\\\n        \"                                                        * + + + ) % % % % % % % % % % %       % % % % % ! ~ { ] ^ % % % % %     \",\\\n        \"                                                    / + + + ( % % % % % % % % %             % % % % _ ~ : : : : : < % % % %     \",\\\n        \"                                                [ + + + } % % % % % % % %                   % | 1 % 2 : : : : : : : 3 % % % %   \",\\\n        \"                                              * + + 4 % % % % % % % %                     : 5 6 7 8 9 : : : : : : : 0 % % % %   \",\\\n        \"                                          a + + + b % % % % % % %                   : : : : : : : c : : : : : : : : d % % % %   \",\\\n        \"                                        a + + e % % % % % % %                     : : : : : : f g ^ h : : : : : : : i % % % %   \",\\\n        \"                                      * + + j % % % % % %                 : :     : : : : : k l % % m : : : : : : : n % % % %   \",\\\n        \"                                    + + + o % % % % %                 : : : :       : :     % % % % p 6 : : : : : q r % % % %   \",\\\n        \"                                  + + . % % % % % %               : : : : : : :               % % % % s t : : : u v % % % %     \",\\\n        \"                              w + + x % % % % %                   : : : : : :                 % % % % % _ y z A % % % % % %     \",\\\n        \"                              + + } % % % % %               :       : : :                   %   % % % % % % % % % % % % %       \",\\\n        \"                            + + B % % % % %             : : : :                         % % %     % % % % % % % % % % %         \",\\\n        \"                          + + C % % % % %             : : : : :                     % % % % % %       % % % % % % %             \",\\\n        \"                        + + D % % % % %             : : : : : :                 % % % % % % % %           % % % %               \",\\\n        \"                      + + @ % % % % %             : : : : :                 % % % % % % % E + +           % % % %               \",\\\n        \"                    F + * % % % % %             : : : : :                 % % % % % % G + + + +           % % %                 \",\\\n        \"                    + + H % % % %           : : : : : :               % % % % % % I + + + + a                                   \",\\\n        \"                  + + J % % % %           : : : : :                 % % % % % % K + + a @                                       \",\\\n        \"                * + / % % % %             : : : :               % % % % % % L + + + M                     % % %                 \",\\\n        \"              N + + % % % %             : : : :               % % % % % O F + + a                         % % %                 \",\\\n        \"              + + P % % % %             : : :               % % % % % Q * + +                             % % %                 \",\\\n        \"            + + * % % % %                 :               % % % % % R + + +                                                     \",\\\n        \"            + * S % % %           : :                   % % % % % & + + [                                                       \",\\\n        \"          a + T % % % %           : : :               % % % % % @ + +                                                           \",\\\n        \"          + + % % % %           : : : :             % % % % % F + +                                       % % %                 \",\\\n        \"        a + U % % % %         : : : :             % % % % % * + +                                         % % %                 \",\\\n        \"        + + O % % %           : : : :           % % % % % V + +                                           % % %                 \",\\\n        \"      W + X % % % %           : : :             % % % % Y + +                                                                   \",\\\n        \"      + + Z % % %                             % % % % ` + +                                                                     \",\\\n        \"      + @ % % % %         :                 % % % %  .+ +                                                 % % %                 \",\\\n        \"    a + ..% % %         : : : :             % % % % + + +.                                                % % %                 \",\\\n        \"    + + % % % %         : : : :           % % % % / + +                                                   % % %                 \",\\\n        \"    + * % % % %       : : : :           % % % % @.+ +                                                     % % %                 \",\\\n        \"  / + #.% % %         : : : :           % % % $.+ +                                                                             \",\\\n        \"  + + %.% % %         : : :           % % % % &.+                                                                               \",\\\n        \"  + * % % % %       : : : :           % % % *.+ +                                                         % % %                 \",\\\n        \"  + & % % %         : : : :         % % % % a + *                                                         % % %                 \",\\\n        \"F + =.% % %         : : :           % % % -.+ +                                                           % % %                 \",\\\n        \"* + ;.% % %       : : : :         % % % % + + a                                                                                 \",\\\n        \"[ , % % % %       : : : :         % % % >.+ +                                                                                   \",\\\n        \"    % % % % % % ,.6 : '.8       % % % % &.+ W                                                             + + +                 \",\\\n        \"    % % % % % % ).: : !.% % %     % % % + +                                                           + + + + + + a             \",\\\n        \"      % % % % % ~.: : {.% % % %                                                                     + + + % % % + + +           \",\\\n        \"    % % % % % % ].^./.(.% % % % %                                                                 + + % % % % % O _.+ +         \",\\\n        \"    % % % % :.<.[.: [.}.].% % % %                                                               + + % % % % l % % % |.+ a       \",\\\n        \"  % % % % 1.2.: : : : : 9 3.% % % %                                                           a + + % % 4.5.: 6.7.% % + +       \",\\\n        \"  % % % % 8.: : : : : : : 9.% % % %                                                           + + - % 0.d a.: b.b.c.% % + +     \",\\\n        \"  % % % d.e.: : : : : : : f.% % % % % % %       % % %     % % % %     % % %       % % %       + + % % : h : : : h : % % + +     \",\\\n        \"  % % % g.: : : : : : : : d % % % % % % %       % % %     % % % %     % % %       % % %       + + % % : a.: : : h : % % + +     \",\\\n        \"  % % % _ h.: : : : : : : i.% % % % % % %       % % %     % % % %     % % %       % % %       + + j.% 0.7 a.: b.b.k.% % + +     \",\\\n        \"  % % % % /.: : : : : : : l.% % % % % % %       % % %       % %       % % %       % % %       + + % % % 4.m.b.n.o.% % % + +     \",\\\n        \"  % % % % 8 p.: : : : : q.d.% % %                                                               + + >.% % % | % % % % + +       \",\\\n        \"    % % % % l r.s.t.u.v._ % % % %                                                               # + + w.% % % % % % + + V       \",\\\n        \"      % % % % % % % % % % % % %                                                                     + + % % % % + + + [         \",\\\n        \"      % % % % % % % % % % % %                                                                       x.+ + + + + + *             \",\\\n        \"          % % % % % % % % %                                                                               + + +                 \",\\\n        \"              % % % % %                                                                                                         \",\\\n        \"                                                                                                                                \"])\n\n    def textEnglish(self):\n        buttonText = \"Draw an cosmetic arc (center and two vertexes)\"\n        helpText = \"Draw an arc rotating math. positive:\"+ \"\\n\"\\\n                   \"- Choose the line attributes\"+ \"\\n\"\\\n                   \"- select three vertexes:\"+ \"\\n\"\\\n                   \"- center, start, end\"+ \"\\n\"\\\n                   \"- start defines the radius\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Kosmetischer Bogen (Mitte und 2 Punkte)\"\n        helpText = \"Zeichnet einen math. positiv rotierenden Kreisbogen:\"+ \"\\n\"\\\n                   \"- W\u00e4hlen Sie die Linienattribute\"+ \"\\n\"\\\n                   \"- w\u00e4hle drei Kontrollpunkte:\"+ \"\\n\"\\\n                   \"- Mittelpunkt, Startpunkt , Endpunkt\"+ \"\\n\"\\\n                   \"- der Startpunkt legt den Radius fest\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Arco cosmetico (centro e 2 vertici)\"\n        helpText = \"Disegna un arco cosmetico utilizzando un centro e 2 vertici:\"+ \"\\n\"\\\n                   \"- scegliere gli attributi linea\"+\"\\n\"\\\n                   \"- selezionare i vertici in sequenza: centro--> inizio--> fine\"+ \"\\n\"\\\n                   \"N.B. centro--->inizio definisce il raggio, fine il posizionamento\"+ \"\\n\"\\\n                   \"invertire selezione (inizio-fine) per cambiare posizionamento\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Arc cosm\u00e9tique (centre et 2 sommets)\"\n        helpText = \"Dessinez un arc cosm\u00e9tique en utilisant un centre et 2 sommets:\"+ \"\\n\"\\\n                   \"- choisir des attributs\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez les sommets dans l'ordre: centre --> d\u00e9but --> fin\"+ \"\\n\"\\\n                   \"Noter: Center --> start d\u00e9finit le rayon, terminer le positionnement\"+ \"\\n\"\\\n                   \"- inverser la s\u00e9lection (d\u00e9but-fin) pour modifier le positionnement\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Arco cosm\u00e9tico (centro y 2 v\u00e9rtices)\"\n        helpText = \"Dibuja un arco cosm\u00e9tico usando un centro y 2 v\u00e9rtices:\"+ \"\\n\"\\\n                   \"- elegir atributos\"+ \"\\n\"\\\n                   \"- seleccione los v\u00e9rtices en secuencia: centro --> inicio --> final\"+ \"\\n\"\\\n                   \"Nota: centro --> inicio define el radio, el final el posicionamiento\"+ \"\\n\"\\\n                   \"- invertir selecci\u00f3n (inicio-fin) para cambiar el posicionamiento\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self): # drawArc\n\n        def returnAngle(Center,Point):\n            X= app.Vector(1,0,0)\n            VecPC = Point - Center\n            Dy = VecPC.y\n            Sign = -1.0\n            if Dy < 0.0:\n                Sign = -Sign\n            Angle = math.degrees(X.getAngle(VecPC))*Sign\n            if Angle < 0:\n                Angle = 360 + Angle\n            return Angle\n\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            if len(ObjectList) >= 3:\n                ThreeVertex = True\n                for ObjectString in ObjectList:\n                    if ObjectString[0:6] != 'Vertex':\n                        ThreeVertex = False\n                if ThreeVertex:\n                    Center =  View.getVertexBySelection(ObjectList[0]).Point\n                    End =  View.getVertexBySelection(ObjectList[1]).Point\n                    Start = View.getVertexBySelection(ObjectList[2]).Point\n                    Radius = (End-Center).Length\n                    AStart = returnAngle(Center,Start)\n                    AEnd = returnAngle(Center,End)\n                    View.makeCosmeticCircleArc(Center, Radius, AStart, AEnd, Attrib.getStyle(), Attrib.getWidth(), Attrib.getColorTuple())\n            gui.Selection.clearSelection()\n\nclass extendLine:\n    '''Extend an attached cosmetic or center line at both ends'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 4 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"+\tc #141000\",\\\n        \"@\tc #FFFF00\",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                 ...                        ..                  \",\\\n        \"               .....                        ....                \",\\\n        \"              ......                        ......              \",\\\n        \"            ........                        ........            \",\\\n        \"          ..........                        .........           \",\\\n        \"         ...........                        ...........         \",\\\n        \"      ..............                        ..............      \",\\\n        \"   .................                        .................   \",\\\n        \" ...................                        ................... \",\\\n        \"....................                        ....................\",\\\n        \" ...................                        ................... \",\\\n        \"   .................                        .................   \",\\\n        \"      ..............                        ..............      \",\\\n        \"         ...........                        ...........         \",\\\n        \"           .........                        ..........          \",\\\n        \"            ........                        ........            \",\\\n        \"              ......                        ......              \",\\\n        \"                ....                        .....               \",\\\n        \"                  ..                        ...                 \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \".  .. ...  ....  +++++++++++++++++++++++++++++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  +++++++++++++++++++++++++++++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  ++@@@@@@@@@@@@@@@@@@@@@@@@@++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  ++@@@@@@@@@@@@@@@@@@@@@@@@@++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  ++@@@@@@@@@@@@@@@@@@@@@@@@@++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  ++@@@@@@@@@@@@@@@@@@@@@@@@@++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  ++@@@@@@@@@@@@@@@@@@@@@@@@@++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  ++@@@@@@@@@@@@@@@@@@@@@@@@@++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  ++@@@@@@@@@@@@@@@@@@@@@@@@@++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  +++++++++++++++++++++++++++++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  +++++++++++++++++++++++++++++  ....  ...  ..  .\",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \"])\n\n    def textEnglish(self):\n        buttonText = \"Extend a line\"\n        helpText = \"Extend a line at both ends:\"+ \"\\n\"\\\n                   \"- select one cosmetic or centerline\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Verl\u00e4ngern einer Linie\"\n        helpText = \"Verl\u00e4ngert eine Linie an beiden Enden:\"+ \"\\n\"\\\n                   \"- w\u00e4hle eine kosmetische oder Mittellinie\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Estendi linea cosmetica\"\n        helpText = \"Estende una linea cosmetica da entrambe le estremit\u00e0:\"+ \"\\n\"\\\n                   \"- selezionare la linea cosmetica o linea centrale o di mezzeria\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Extension de ligne cosm\u00e9tique\"\n        helpText = \"Prolonge une ligne cosm\u00e9tique des deux extr\u00e9mit\u00e9s:\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez la ligne cosm\u00e9tique ou la ligne m\u00e9diane\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Extensi\u00f3n de l\u00ednea cosm\u00e9tica\"\n        helpText = \"Extiende una l\u00ednea cosm\u00e9tica desde ambos extremos:\"+ \"\\n\"\\\n                   \"- seleccione la l\u00ednea cosm\u00e9tica o la l\u00ednea central\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            if ObjectList[0][0:4] == 'Edge':\n                commonTools.extendShortenLine(View,ObjectList,True)\n        gui.Selection.clearSelection()\n\nclass shortenLine:\n    '''Shorten an attached cosmetic or center line at both ends'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 4 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"+\tc #141000\",\\\n        \"@\tc #FFFF00\",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"   ..                                                    ...    \",\\\n        \"   ....                                                .....    \",\\\n        \"   ......                                             ......    \",\\\n        \"   ........                                         ........    \",\\\n        \"   .........                                      ..........    \",\\\n        \"   ...........                                   ...........    \",\\\n        \"   ..............                             ..............    \",\\\n        \"   .................                       .................    \",\\\n        \"   ...................                   ...................    \",\\\n        \"   ....................                 ....................    \",\\\n        \"   ...................                   ...................    \",\\\n        \"   .................                       .................    \",\\\n        \"   ..............                             ..............    \",\\\n        \"   ...........                                   ...........    \",\\\n        \"   ..........                                      .........    \",\\\n        \"   ........                                         ........    \",\\\n        \"   ......                                             ......    \",\\\n        \"   .....                                                ....    \",\\\n        \"   ...                                                    ..    \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \".  .. ...  ....  +++++++++++++++++++++++++++++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  +++++++++++++++++++++++++++++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  ++@@@@@@@@@@@@@@@@@@@@@@@@@++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  ++@@@@@@@@@@@@@@@@@@@@@@@@@++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  ++@@@@@@@@@@@@@@@@@@@@@@@@@++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  ++@@@@@@@@@@@@@@@@@@@@@@@@@++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  ++@@@@@@@@@@@@@@@@@@@@@@@@@++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  ++@@@@@@@@@@@@@@@@@@@@@@@@@++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  ++@@@@@@@@@@@@@@@@@@@@@@@@@++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  +++++++++++++++++++++++++++++  ....  ...  ..  .\",\\\n        \".  .. ...  ....  +++++++++++++++++++++++++++++  ....  ...  ..  .\",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \"])\n\n    def textEnglish(self):\n        buttonText = \"Shorten a line\"\n        helpText = \"Shorten a line at both ends:\"+ \"\\n\"\\\n                   \"- select one cosmetic or centerline\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Verk\u00fcrzen einer Linie\"\n        helpText = \"Verk\u00fcrzt eine Linie an beiden Enden:\"+ \"\\n\"\\\n                   \"- w\u00e4hle eine kosmetische oder Mittellinie\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Accorcia linea cosmetica\"\n        helpText = \"Accorcia una linea cosmetica da entrambe le estremit\u00e0:\"+ \"\\n\"\\\n                   \"- selezionare la linea cosmetica o linea centrale o di mezzeria\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Raccourcir ligne cosm\u00e9tique\"\n        helpText = \"Raccourcir une ligne cosm\u00e9tique des deux extr\u00e9mit\u00e9s:\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez la ligne cosm\u00e9tique ou la ligne m\u00e9diane\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n       buttonText = \"Acortar l\u00ednea cosm\u00e9tica\"\n       helpText = \"Acortar una l\u00ednea cosm\u00e9tica de ambos extremos:\"+ \"\\n\"\\\n                  \"- seleccione la l\u00ednea cosm\u00e9tica o la l\u00ednea central\"+ \"\\n\"\\\n                  \"- haga clic en este bot\u00f3n\"\n       return(buttonText,helpText)\n\n    def activated(self):\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            if ObjectList[0][0:4] == 'Edge':\n                commonTools.extendShortenLine(View,ObjectList,False)\n            gui.Selection.clearSelection()\n\nclass createArcLengthDim:\n    '''Create an arc length dimension'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 16 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"+\tc #141000\",\\\n        \"@\tc #FFFF00\",\\\n        \"#\tc #2B2200\",\\\n        \"$\tc #2A2000\",\\\n        \"%\tc #2C2100\",\\\n        \"&\tc #FDFD00\",\\\n        \"*\tc #2C2200\",\\\n        \"=\tc #FEFE00\",\\\n        \"-\tc #2D2300\",\\\n        \";\tc #F8F700\",\\\n        \">\tc #FCFC00\",\\\n        \",\tc #2D2200\",\\\n        \"'\tc #FDFC00\",\\\n        \")\tc #2A2300\",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                            ........                      ...   \",\\\n        \"   ....                    ..........                    ....   \",\\\n        \"   ....                  ..............                  ....   \",\\\n        \"   ....                 ................                 ....   \",\\\n        \"   ....                ........  ........                ....   \",\\\n        \"   ....               .....         ......               ....   \",\\\n        \"   ....              .....            .....              ....   \",\\\n        \"   ....             .....              .....             ....   \",\\\n        \"   ....             ....                ....             ....   \",\\\n        \"   ....            ....                 .....            ....   \",\\\n        \"   ....            ....                  ....            ....   \",\\\n        \"   ....            ....                  .....           ....   \",\\\n        \"   ....           ....                    ....           ....   \",\\\n        \"   ....           ....                    ....           .....  \",\\\n        \"  ......          ....                                 ........ \",\\\n        \" ........                                              .........\",\\\n        \".........                                             ..........\",\\\n        \"................................................................\",\\\n        \"................................................................\",\\\n        \"................................................................\",\\\n        \"..........                                             .........\",\\\n        \" ........                                              ........ \",\\\n        \" .......                                                 .....  \",\\\n        \"   ...                                                    ...   \",\\\n        \"   ...                                                    ...   \",\\\n        \"   ...                                                    ...   \",\\\n        \"   ...                                                    ...   \",\\\n        \"   ...                                                    ...   \",\\\n        \"   ...                                                    ...   \",\\\n        \"   ...                                                    ...   \",\\\n        \"   ...                                                    ...   \",\\\n        \"   ...                   +++++++++++++++                  ...   \",\\\n        \"   ...                 +++@@@@@@@@@@@@+++                 ...   \",\\\n        \"   ...              +++++@@@@@@@@@@@@@@+++++              ...   \",\\\n        \"   ...            +++@@@@@@@@@@@@@@@@@@@@@@+++            ...   \",\\\n        \"   ...          +++@@@@@@@@@@@@@@@@@@@@@@@@@@++           ...   \",\\\n        \"   ...        +++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++#        ...   \",\\\n        \"   ...       ++@@@@@@@@@@++++++++++++@@@@@@@@@@@+++       ...   \",\\\n        \"   ...      ++@@@@@@@@+++++        +++++++@@@@@@@@++      ...   \",\\\n        \"   ...     ++@@@@@@@+++  $             % +++@&@@@@@++     ...   \",\\\n        \"   ...    ++@@@@@@+++                      +++@@@@@@++*   ...   \",\\\n        \"   ...   ++@@@@@+++                          ++@@@@@@++   ...   \",\\\n        \"   ...  ++@@@@@@+                             +++@@@@@++  ...   \",\\\n        \"       ++&@@@@+++                               ++@@@@@++ ...   \",\\\n        \"      ++@@@@@++                                  ++@@@@+++      \",\\\n        \"      +@@@@@++                                    ++@@@@@+      \",\\\n        \"     ++@@@=++                                      ++@@@@++-    \",\\\n        \"     +@@@@@+                                        ++&@@@++    \",\\\n        \"    ++@@@@++                                         +@@@@@+    \",\\\n        \"    +@@@@@+                                          ++;@@@+    \",\\\n        \"   ++>@@@++                                           +@@@@++   \",\\\n        \"   +@@@@@+                                            ++@@@@+   \",\\\n        \"  ,+@@@@++                                             +@@@@++  \",\\\n        \"  ++@@@@+                                              +@@@'++  \",\\\n        \"  ++@@@@+)                                             +@@@@++  \",\\\n        \"  ++@@@@+                                              +@@@@++  \",\\\n        \"  +++++++                                              +++++++  \",\\\n        \"  +++++++                                              +++++++  \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \"])\n\n    def textEnglish(self):\n        buttonText = \"Create Development/length arc\"\n        helpText = \"Enter the development/length of the arc with the symbol '\u2229':\"+ \"\\n\"\\\n                   \"- select one arc\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Bogenentwicklung/L\u00e4nge \"\n        helpText = \"Geben Sie die Entwicklung/L\u00e4nge des Bogens mit dem Symbol '\u2229' ein:\"+ \"\\n\"\\\n                   \"- w\u00e4hle einen Kreisbogen\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Sviluppo/lunghezza dell'arco\"\n        helpText = \"Inserisce lo sviluppo/lunghezza dell'arco con il simbolo '\u2229':\"+ \"\\n\"\\\n                   \"- selezionare l'arco\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"D\u00e9veloppement/longueur d'arc\"\n        helpText = \"Entrez la d\u00e9veloppement/longueur de l'arc avec le symbole '\u2229':\"+ \"\\n\"\\\n                   \"- select one arc\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Desarrollo/longitud del arco\"\n        helpText = \"Ingrese el desarrollo/longitud del arco con el s\u00edmbolo '\u2229':\"+ \"\\n\"\\\n                   \"- seleccione el arco\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            Edge = View.getEdgeBySelection(ObjectList[0])\n            if hasattr(Edge.Curve,'Center'):\n                if len(Edge.Vertexes) > 1:\n                    ArcDim = TechDraw.makeDistanceDim(View, 'Distance',Edge.Vertexes[0].Point,Edge.Vertexes[1].Point)\n                    ArcDim.X = (Edge.Vertexes[0].Point.x+Edge.Vertexes[1].Point.x)/2\n                    ArcDim.Y = (Edge.Vertexes[0].Point.y+Edge.Vertexes[1].Point.y)/2\n                    ArcDim.Arbitrary = True\n                    FormatStr = \"\u2229 \"+str(round(Edge.Length,2))\n                    ArcDim.FormatSpec = FormatStr.replace(\".\",\",\")\n            gui.Selection.clearSelection()\n\nclass drawPerpendicular:\n    '''draw a line perpendicular to another line'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 12 1\",\\\n        \" \tc None\",\\\n        \".\tc #2B2200\",\\\n        \"+\tc #2D2400\",\\\n        \"@\tc #FFFF00\",\\\n        \"#\tc #2F2600\",\\\n        \"$\tc #F9F900\",\\\n        \"%\tc #FF0000\",\\\n        \"&\tc #2C2300\",\\\n        \"*\tc #393100\",\\\n        \"=\tc #F8F800\",\\\n        \"-\tc #342C00\",\\\n        \";\tc #2A2200\",\\\n        \"                                                                \",\\\n        \"                             ......                             \",\\\n        \"                           ..........                           \",\\\n        \"                          ...+@@@@#...                          \",\\\n        \"                         ...@@@@@@@@...                         \",\\\n        \"                         ..@@@@@@@@$@..                         \",\\\n        \"                        ...@@%%%%%%@@&..                        \",\\\n        \"                        ..@@@%%%%%%@@@..                        \",\\\n        \"                        ..@@@%%%%%%@@@..                        \",\\\n        \"                        ..@@@%%%%%%@@@..                        \",\\\n        \"                        ..*=@%%%%%%@@-..                        \",\\\n        \"                         ..@@%%%%%%@@..                         \",\\\n        \"                         ..#@@@@@@@@+..                         \",\\\n        \"                          ..&.@@@@....                          \",\\\n        \"                           ..........                           \",\\\n        \"                            .%%%%%%.                            \",\\\n        \"                             %%%%%%                             \",\\\n        \"                             %%%%%%                             \",\\\n        \"                             %%%%%%                             \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                             %%%%%%                             \",\\\n        \"                             %%%%%%                             \",\\\n        \"                             %%%%%%                             \",\\\n        \"                             %%%%%%                             \",\\\n        \"                             %%%%%%                             \",\\\n        \"                             %%%%%%                             \",\\\n        \"                             %%%%%%                             \",\\\n        \"                             %%%%%%                             \",\\\n        \"                             %%%%%%                             \",\\\n        \"                             %%%%%%                             \",\\\n        \"                             %%%%%%                             \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                            %%%%%%%                             \",\\\n        \"                            %%%%%%%                             \",\\\n        \"                            %%%%%%%                             \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                            %%%%%%%                             \",\\\n        \"                            %%%%%%%                             \",\\\n        \"                            %%%%%%%                             \",\\\n        \"                            %%%%%%%                             \",\\\n        \"                            %%%%%%%                             \",\\\n        \"                            %%%%%%%                             \",\\\n        \" .............................................................; \",\\\n        \" .............................................................; \",\\\n        \" ..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.; \",\\\n        \" ..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.; \",\\\n        \" ..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.; \",\\\n        \" ..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.; \",\\\n        \" ..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.; \",\\\n        \" ...............................;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; \",\\\n        \" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; \",\\\n        \"                                                                \",\\\n        \"                                                                \"])\n\n    def textEnglish(self):\n        buttonText = \"Create a line perpendicular to another line\"\n        helpText = \"Create a line perpendicular to another line through a vertex\"+ \"\\n\"\\\n                   \"- choose the line attributes\"+ \"\\n\"\\\n                   \"- select one line\"+ \"\\n\"\\\n                   \"- select one vertex\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Erzeuge eine Linie im rechten Winkel\"\n        helpText = \"Erzeuge eine Linie im rechten Winkel zu einer Linie durch einen Punkt\"+ \"\\n\"\\\n                   \"- W\u00e4hlen Sie die Linienattribute\"+ \"\\n\"\\\n                   \"- w\u00e4hle eine Linie\"+ \"\\n\"\\\n                   \"- w\u00e4hle einen Punkt\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Perpendicolare cosmetica\"\n        helpText = \"Crea una perpendicolare cosmetica ad una linea da un vertice:\"+ \"\\n\"\\\n                   \"- scegliere gli attributi\"+\"\\n\"\\\n                   \"- selezionare una linea\"+ \"\\n\"\\\n                   \"- selezionare un vertice\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Cosm\u00e9tique perpendiculaire\"\n        helpText = \"Cr\u00e9er une ligne cosm\u00e9tique perpendiculaire \u00e0 une ligne \u00e0 partir d'un sommet:\"+ \"\\n\"\\\n                   \"- choisir des attributs\"+\"\\n\"\\\n                   \"- s\u00e9lectionnez une ligne\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez un sommet\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Cosm\u00e9tica perpendicular\"\n        helpText = \"Crea una l\u00ednea cosm\u00e9tica perpendicular a una l\u00ednea desde un v\u00e9rtice:\"+ \"\\n\"\\\n                   \"- elegir atributos\"+\"\\n\"\\\n                   \"- seleccionar una l\u00ednea\"+ \"\\n\"\\\n                   \"- seleccionar un v\u00e9rtice\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self): # drawPerpendicular\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            if len(ObjectList) == 2:\n                if ObjectList[0][0:4] == \"Edge\" and ObjectList[1][0:6] == \"Vertex\":\n                    Edge = View.getEdgeBySelection(ObjectList[0])\n                    if Edge.Curve.TypeId == 'Part::GeomLine':\n                        StartPt, EndPt = Edge.Vertexes[0].Point, Edge.Vertexes[1].Point\n                        MidPt = View.getVertexBySelection(ObjectList[1]).Point\n                        HalfVec = (StartPt.sub(EndPt)/2).cross(app.Vector(0,0,1))\n                        View.makeCosmeticLine(MidPt.add(HalfVec),MidPt.sub(HalfVec),Attrib.getStyle(), Attrib.getWidth(), Attrib.getColorTuple())\n\nclass drawParallel:\n    '''draw a line parallel to another line'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 26 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"+\tc #2B2200\",\\\n        \"@\tc #2B2100\",\\\n        \"#\tc #2C2400\",\\\n        \"$\tc #FFFF00\",\\\n        \"%\tc #F8F800\",\\\n        \"&\tc #FF0D00\",\\\n        \"*\tc #FFFE00\",\\\n        \"=\tc #FB0200\",\\\n        \"-\tc #FF0200\",\\\n        \";\tc #2C2300\",\\\n        \">\tc #F9F900\",\\\n        \",\tc #342100\",\\\n        \"'\tc #FD0000\",\\\n        \")\tc #FCFC00\",\\\n        \"!\tc #F8F700\",\\\n        \"~\tc #2F2600\",\\\n        \"{\tc #FDFC00\",\\\n        \"]\tc #FBFB00\",\\\n        \"^\tc #F5F500\",\\\n        \"/\tc #332B00\",\\\n        \"(\tc #F7F600\",\\\n        \"_\tc #FDFD00\",\\\n        \":\tc #FEFE00\",\\\n        \"<\tc #F6F500\",\\\n        \"                                              .                 \",\\\n        \"                                             ...                \",\\\n        \"                                            .....               \",\\\n        \"                                           .......              \",\\\n        \"                                          .........             \",\\\n        \"                                           .........            \",\\\n        \"                                            .......             \",\\\n        \"                                      .      .....              \",\\\n        \"                                     ...      ...               \",\\\n        \"                                    .....      .                \",\\\n        \"                                   .......                      \",\\\n        \"                                  .........                     \",\\\n        \"                                 ...........                    \",\\\n        \"                                ...........                     \",\\\n        \"                               ...........                      \",\\\n        \"                         ++++ ...........                       \",\\\n        \"                      +++++++...........                        \",\\\n        \"                     ++@++++...........                         \",\\\n        \"                     ++#++$...........                  +       \",\\\n        \"                    +++++$$..........                  +++      \",\\\n        \"                    +++%$$$$........                  +++++     \",\\\n        \"                   ++++$$$$$$......                  +++++++    \",\\\n        \"                   ++.$$$$$$$$.&..+                 ++++$++++   \",\\\n        \"                   +...*$$$$$$$.=++                ++++$$$++++  \",\\\n        \"                   ..=..$$$$$$$$+++               ++++$$$$$++++ \",\\\n        \"                  .....-.$$$$$$$;++              ++++$$$$$$$++++\",\\\n        \"                 .........$$$$$+++              ++++$$$$$$$++++ \",\\\n        \"                ...........$$+++++             ++++$$$$$$>++++  \",\\\n        \"               ...........+++++++             ++++$$$$$$$++++   \",\\\n        \"              ...........+,+++++             ++++$$$$$$$++++    \",\\\n        \"             ..........'  +++               ++++$$$$$$$++++     \",\\\n        \"            ...........                    ++++$$$$$$$++++      \",\\\n        \"           ...........                    ++++$$$$$$$++++       \",\\\n        \"          ...........                    ++++$$$$$)$++++        \",\\\n        \"           .........                    ++++$$$$$$$++++         \",\\\n        \"            .......                    ++++$$$$$$$++++          \",\\\n        \"      .      .....                    ++++$$$$$$$++++           \",\\\n        \"     ...      ...                    ++++$$$$$$$++;+            \",\\\n        \"    .....      .                    ++++$$$$!$$++++             \",\\\n        \"   .......                         ++++$$$$$$$++++              \",\\\n        \"  .........                       ++++$$$$$$$++++               \",\\\n        \" ...........                     ++++$$$$$$$++++                \",\\\n        \"...........                     ++++$$$$$$$+~++                 \",\\\n        \" .........                     ++++$$$$$${++++                  \",\\\n        \"  .......                     ++++$$$]$$^++++                   \",\\\n        \"   .....                     ++++$$$$$$$++++                    \",\\\n        \"    ...                     ++++$$$$$$$++++                     \",\\\n        \"     .                     ++++$$$$$$$/+++                      \",\\\n        \"                          ++++$$$$$$$++++                       \",\\\n        \"                         ++++$$($$>$++++                        \",\\\n        \"                        ++++$$_$$$>++++                         \",\\\n        \"                       ++++$$$$$$$++++                          \",\\\n        \"                      ++++$$$$$$$++++                           \",\\\n        \"                     ++++$$$$$$$++++                            \",\\\n        \"                    ++++$$$$:$$++++                             \",\\\n        \"                   ++++$$$$<$$++++                              \",\\\n        \"                  ++++$$$$$$$++++                               \",\\\n        \"                 ++++$$$$$$$++++                                \",\\\n        \"                  ++++$$$$$++++                                 \",\\\n        \"                   ++++$$$++++                                  \",\\\n        \"                    ++++$++++                                   \",\\\n        \"                     +++++++                                    \",\\\n        \"                      +++++                                     \",\\\n        \"                       +++                                      \"])\n\n    def textEnglish(self):\n        buttonText = \"Create a line parallel to another line\"\n        helpText = \"Create a line parallel to another line through a vertex\"+ \"\\n\"\\\n                   \"- choose the line attributes\"+ \"\\n\"\\\n                   \"- select one line\"+ \"\\n\"\\\n                   \"- select one vertex\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Erzeuge eine parallele Liniel\"\n        helpText = \"Erzeuge eine parallele zu einer Linie durch einen Punkt\"+ \"\\n\"\\\n                   \"- W\u00e4hlen Sie die Linienattribute\"+ \"\\n\"\\\n                   \"- w\u00e4hle eine Linie\"+ \"\\n\"\\\n                   \"- w\u00e4hle einen Punkt\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Parallela cosmetica\"\n        helpText = \"Crea una parallela cosmetica ad una linea da un vertice:\"+ \"\\n\"\\\n                   \"- scegliere gli attributi\"+\"\\n\"\\\n                   \"- selezionare una linea\"+ \"\\n\"\\\n                   \"- selezionare un vertice\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Parall\u00e8le cosm\u00e9tique\"\n        helpText = \"Cr\u00e9er une ligne cosm\u00e9tique parall\u00e8le \u00e0 une ligne \u00e0 partir d'un sommet:\"+ \"\\n\"\\\n                   \"- choisir des attributs\"+\"\\n\"\\\n                   \"- s\u00e9lectionnez une ligne\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez un sommet\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Cosm\u00e9tica paralela\"\n        helpText = \"Crea una l\u00ednea cosm\u00e9tica paralela a una l\u00ednea desde un v\u00e9rtice:\"+ \"\\n\"\\\n                   \"- elegir atributos\"+\"\\n\"\\\n                   \"- seleccionar una l\u00ednea\"+ \"\\n\"\\\n                   \"- seleccionar un v\u00e9rtice\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self): # drawParallel\n        (OK,ObjectList,View) = commonTools.selectionOK()\n        if OK:\n            if len(ObjectList) == 2:\n                if ObjectList[0][0:4] == \"Edge\" and ObjectList[1][0:6] == \"Vertex\":\n                    Edge = View.getEdgeBySelection(ObjectList[0])\n                    if Edge.Curve.TypeId == 'Part::GeomLine':\n                        StartPt, EndPt = Edge.Vertexes[0].Point, Edge.Vertexes[1].Point\n                        MidPt = View.getVertexBySelection(ObjectList[1]).Point\n                        HalfVec = StartPt.sub(EndPt)/2\n                        View.makeCosmeticLine(MidPt.add(HalfVec),MidPt.sub(HalfVec),Attrib.getStyle(), Attrib.getWidth(), Attrib.getColorTuple())\n\nclass areaAnnot:\n    ''' create an annotation showing the area of a closed polygon'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 15 1\",\\\n        \" \tc None\",\\\n        \".\tc #2B2200\",\\\n        \"+\tc #FFFF00\",\\\n        \"@\tc #2F2600\",\\\n        \"#\tc #2D2400\",\\\n        \"$\tc #FDFC00\",\\\n        \"%\tc #FDFD00\",\\\n        \"&\tc #FAFA00\",\\\n        \"*\tc #F8F800\",\\\n        \"=\tc #2E2500\",\\\n        \"-\tc #2D2300\",\\\n        \";\tc #FF0000\",\\\n        \">\tc #FFAEAE\",\\\n        \",\tc #2C2300\",\\\n        \"'\tc #F7F600\",\\\n        \"    .......                                          .......    \",\\\n        \"   .........                                        .........   \",\\\n        \"  ...+++++@..                                      ...+++++...  \",\\\n        \" ..#+$+++++...                                    ...+++++%+... \",\\\n        \"...+++++++++........................................+%+++++++...\",\\\n        \"..+++++++++++......................................+++++++++++..\",\\\n        \"..+++++++++++..++++++++++++++++++++++++++++++++++..+++++++++++..\",\\\n        \"..+++++++++++#.++++++++++++++++++++++++++++++++++..++++++++++$#.\",\\\n        \"..+++++++++++..++++++++++++++++++++++++++++++++++..+++++++++++..\",\\\n        \"...+++++++++.......................................+++++++++++..\",\\\n        \" ...+++++++.........................................++++++++&...\",\\\n        \"  .#.+++++...                                     ...++++++*... \",\\\n        \"   .......@.                                       ..=+++++...  \",\\\n        \"    .......                                         .........   \",\\\n        \"    ..+++..                                          ......-    \",\\\n        \"    ..+++..                                          ..+++..    \",\\\n        \"    ..+++..                              ;;;;;;      ..+++..    \",\\\n        \"    ..+++..                             ;;;;;;;;     ..+++..    \",\\\n        \"    ..+++..                            ;;;;;;;;;;    ..+++..    \",\\\n        \"    ..+++..            ;;;;;;;;        ;;;   ;;;;    ..+++..    \",\\\n        \"    ..+++..           ;;;;;;;;;        ;;;   ;;;;    ..+++..    \",\\\n        \"    ..+++..           ;;;;;;;;;;             ;;;;    ..+++..    \",\\\n        \"    ..+++..           ;;;;;;;;;;            ;;;;;    ..+++..    \",\\\n        \"    ..+++..          ;;;;;;;;;;;           ;;;;;     ..+++..    \",\\\n        \"    ..+++..          ;;;;;;;;;;;;         ;;;;;      ..+++..    \",\\\n        \"    ..+++..          ;;;;;;;;;;;;        ;;;;;       ..+++..    \",\\\n        \"    ..+++..         ;;;;;;;;;;;;;;      ;;;;;        ..+++..    \",\\\n        \"    ..+++..         ;;;;;;;;;;;;;;      ;;;;         ..+++..    \",\\\n        \"    ..+++..         ;;;;;;  ;;;;;;     ;;;;;;;;;;    ..+++..    \",\\\n        \"    ..+++..        ;;;;;;;  ;;;;;;;    ;;;;;;;;;;    ..+++..    \",\\\n        \"    ..+++..        ;;;;;;;  ;;;;;;;    ;;;;;;;;;;    ..+++..    \",\\\n        \"    ..+++..       ;;;;;;;    ;;;;;;>                 ..+++..    \",\\\n        \"    ..+++..       ;;;;;;;    ;;;;;;;                 ..+++..    \",\\\n        \"    ..+++..       ;;;;;;      ;;;;;;                 ..+++..    \",\\\n        \"    ..+++..      ;;;;;;;      ;;;;;;;                ..+++..    \",\\\n        \"    ..+++..      ;;;;;;;      ;;;;;;;                ..+++..    \",\\\n        \"    ..+++..      ;;;;;;;;;;;;;;;;;;;;                ..+++..    \",\\\n        \"    ..+++..     ;;;;;;;;;;;;;;;;;;;;;;               ..+++..    \",\\\n        \"    ..+++..     ;;;;;;;;;;;;;;;;;;;;;;               ..+++..    \",\\\n        \"    ..+++..     ;;;;;;;;;;;;;;;;;;;;;;               ..+++..    \",\\\n        \"    ..+++..    ;;;;;;;;;;;;;;;;;;;;;;;;              ..+++..    \",\\\n        \"    ..+++..    ;;;;;;;          ;;;;;;;              ..+++..    \",\\\n        \"    ..+++..   ;;;;;;;;          ;;;;;;;;             ..+++..    \",\\\n        \"    ..+++..   ;;;;;;;            ;;;;;;;             ..+++..    \",\\\n        \"    ..+++..   ;;;;;;;            ;;;;;;;             ..+++..    \",\\\n        \"    ..+++..  ;;;;;;;              ;;;;;;;            ..+++..    \",\\\n        \"    ..+++..  ;;;;;;;              ;;;;;;;            ..+++..    \",\\\n        \"    ..+++..  ;;;;;;;              ;;;;;;;            ..+++..    \",\\\n        \"    ..+++..                                          ..+++..    \",\\\n        \"    ..+++..                                          ..+++..    \",\\\n        \"    ........                                         .......    \",\\\n        \"   .........                                        .........   \",\\\n        \"  ...+++++.,.                                      ...+++++...  \",\\\n        \" ...+++++++.,......................................#.+++++++.#. \",\\\n        \"...+++++++++..,.....................................+++++++++...\",\\\n        \"..+++++++++++..++++++++++++++++++++++++++++++++++..+++++++++++..\",\\\n        \"..+++++++++++..++++++++++++++++++++++++++++++++++..+++++++++++..\",\\\n        \"..+++++++++++..++++++++++++++++++++++++++++++++++..+++++++++++..\",\\\n        \"..+++++++++++......................................+++++++++++..\",\\\n        \"..,+++++++++.......................................#+++++++++...\",\\\n        \" ...+++++++.#.                                    ...+++++++... \",\\\n        \"  ...+'+++.#.                                      ...+++++...  \",\\\n        \"   .........                                        .........   \",\\\n        \"    .......                                          .......    \"])\n\n    def textEnglish(self):\n        buttonText = \"Create an annotation showing the area\"\n        helpText = \"Creates an annotation of the area value, the unit\"+ \"\\n\"\\\n                   \"of which is determined by the preferences \"+\"\\n\"\\\n                   \"- select a closed closed polygon of lines\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Erzeuge eine Anmerkung mit dem Fl\u00e4cheninhalt\"\n        helpText = \"Erstellen Sie eine Anmerkung zum Fl\u00e4chenwert, deren Einheit\"+ \"\\n\"\\\n                   \"aus den Einstellungen entnommen wird \"+\"\\n\"\\\n                   \"- W\u00e4hlen Sie Linien die ein geschlossenes Polygon bilden\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Annotazione valore area poligono\"\n        helpText = \"Crea un'annotazione del valore dell'area, la cui \"+ \"\\n\"\\\n                   \"unit\u00e0 viene rilevata dalle preferenze\"+\"\\n\"\\\n                   \"- selezionare le linee che formano il poligono chiuso\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Annotation de valeur de surface de polygone\"\n        helpText = \"Cr\u00e9e une annotation de la valeur de surface, dont \"+ \"\\n\"\\\n                   \"l'unit\u00e9 est extraite des pr\u00e9f\u00e9rences\"+\"\\n\"\\\n                   \"- s\u00e9lectionnez les lignes qui forment le polygone ferm\u00e9\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Anotaci\u00f3n de valor de \u00e1rea de pol\u00edgono\"\n        helpText = \"Cree una anotaci\u00f3n del valor del \u00e1rea, cuya \"+ \"\\n\"\\\n                   \"unidad se toma de las preferencias \"+\"\\n\"\\\n                   \"- seleccione las l\u00edneas que forman el pol\u00edgono cerrado\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self):\n        Sel = gui.Selection.getSelectionEx()[0]\n        ObjectList = Sel.SubElementNames\n        View = gui.Selection.getCompleteSelection()[0]\n        XView,YView = commonTools.getViewCoords(View)\n        selEdges = []\n        for Obj in ObjectList:\n            selEdges.append(View.getEdgeBySelection(Obj))\n        wire = TechDraw.findOuterWire(selEdges)\n        sumArea, sumLength, sumProduct = 0, 0, app.Vector()\n        for Edge in wire.Edges:\n            sumArea = sumArea + Edge.Vertexes[0].Point.x*Edge.Vertexes[1].Point.y-Edge.Vertexes[0].Point.y*Edge.Vertexes[1].Point.x\n            sumLength = sumLength + Edge.Length\n            sumProduct = sumProduct+Edge.Vertexes[0].Point.add(Edge.Vertexes[1].Point)/2*Edge.Length\n        center = app.Vector(sumProduct.x/sumLength,sumProduct.y/sumLength,0)\n        factor = app.Units.Quantity('m').getUserPreferred()[1]\n        sumArea = abs(int(sumArea/(2*factor*factor)))\n        commonTools.createAnnot('Area',str(sumArea)+app.Units.Quantity('m').getUserPreferred()[2]+'2',float(XView)+center.x,float(YView)+center.y-2)\n\nclass createObliqueDimChain:\n    '''create an oblique chain dimension'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 2 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"                                 ..                             \",\\\n        \"                                 ...                            \",\\\n        \"                                .....                           \",\\\n        \"                                 .....                          \",\\\n        \"                                  .....                         \",\\\n        \"                                   .....                        \",\\\n        \"                                    .....                       \",\\\n        \"                                     .....                      \",\\\n        \"                                      .....                     \",\\\n        \"                                       .....                    \",\\\n        \"                                        .....                   \",\\\n        \"                                         .....                  \",\\\n        \"                                          .....            .    \",\\\n        \"                                           .....          ...   \",\\\n        \"                                            .....        .....  \",\\\n        \"                   .                         .....      .....   \",\\\n        \"                  ...                         ..............    \",\\\n        \"                 .....                         ............     \",\\\n        \"                  .....                         ..........      \",\\\n        \"                   .....                        ..........      \",\\\n        \"                    .....                       ..........      \",\\\n        \"                     .....                      ..........      \",\\\n        \"                      .....                     .........       \",\\\n        \"                       .....                    ..........      \",\\\n        \"                        .....                  ............     \",\\\n        \"                         .....                ............      \",\\\n        \"                          .....              .....      .       \",\\\n        \"                           .....            .....               \",\\\n        \"                            .....          .....                \",\\\n        \"                             .....        .....                 \",\\\n        \"                              .....      .....                  \",\\\n        \"                               .....    .....                   \",\\\n        \"  ...                           ............                    \",\\\n        \" .....                           ..........                     \",\\\n        \"  .....                          .........                      \",\\\n        \"   .....                         ..........                     \",\\\n        \"    .....                        ..........                     \",\\\n        \"     .....                       ..........                     \",\\\n        \"      .....                      ..........                     \",\\\n        \"       .....                    ............                    \",\\\n        \"        .....                  ............                     \",\\\n        \"         .....                .....      .                      \",\\\n        \"          .....              .....                              \",\\\n        \"           .....            .....                               \",\\\n        \"            .....          .....                                \",\\\n        \"             .....        .....                                 \",\\\n        \"              .....      .....                                  \",\\\n        \"               ..... .. .....                                   \",\\\n        \"                ............                                    \",\\\n        \"                 ..........                                     \",\\\n        \"                 .........                                      \",\\\n        \"                 ..........                                     \",\\\n        \"                 ..........                                     \",\\\n        \"                 .........                                      \",\\\n        \"                 ..........                                     \",\\\n        \"                ............                                    \",\\\n        \"               ............                                     \",\\\n        \"              .....      .                                      \",\\\n        \"              ....                                              \",\\\n        \"               ..                                               \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \",\\\n        \"                                                                \"])\n\n    def textEnglish(self):\n        buttonText = \"Create an oblique dimension chain\"\n        helpText = \"Create an oblique dimension chain\"+ \"\\n\"\\\n                   \"- select three or more  vertexes\"+ \"\\n\"\\\n                   \"- the first two define the direction\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Erzeuge eine schr\u00e4ge Kettenbema\u00dfung\"\n        helpText = \"Erzeuge ein schr\u00e4ges Kettenma\u00df\"+ \"\\n\"\\\n                   \"- w\u00e4hle drei oder mehr Konstruktionspunkte\"+ \"\\n\"\\\n                   \"- die beiden Ersten bestimmen die Richtung\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Dimensioni oblique in serie continue\"\n        helpText = \"Seleziona tre o pi\u00f9 vertici\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Dimensions obliques en s\u00e9rie continue\"\n        helpText = \"S\u00e9lectionnez trois sommets ou plus\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Dimensiones oblicuas en serie continua\"\n        helpText = \"Seleccione tres o m\u00e1s v\u00e9rtices\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n\n    def activated(self): # createObliqueDimChain\n        def sortPoints(Point):\n            return Point.x\n\n        (OK,ElementNames,View) = commonTools.selectionOK()\n        if OK:\n            VertexNames = [VertexName for VertexName in ElementNames if VertexName[:6]=='Vertex']\n            Vertexes = [View.getVertexBySelection(VertexName) for VertexName in VertexNames]\n            if len(Vertexes) > 2:\n                DimPoints = [Vertexes[0].Point,Vertexes[1].Point]\n                Direction = Vertexes[0].Point.sub(Vertexes[1].Point).normalize()\n                Normal = app.Vector(Direction.y,-Direction.x,0)\n                Carrier = Part.Line(Vertexes[0].Point,Vertexes[1].Point)\n                DistLine = Part.Line(app.Vector(),Normal)\n                Ip = Carrier.intersect(DistLine)\n                Delta = app.Vector(Ip[0].X,Ip[0].Y,Ip[0].Z).normalize()*7\n                for Num in range(2,len(Vertexes)):\n                    Pt = Vertexes[Num].Point\n                    Extension = Part.Line(Pt,Pt.add(Normal))\n                    Ip = Carrier.intersect(Extension)\n                    IpVec = app.Vector(Ip[0].X,Ip[0].Y,Ip[0].Z)\n                    if not IpVec.isEqual(Pt,0.01):\n                        DimPoints.append(IpVec)\n                        View.makeCosmeticLine(Pt,IpVec,1, 0.15, (0,0,0,0))\n                    else:\n                        DimPoints.append(Pt)\n                DimPoints.sort(key=sortPoints)\n                for i  in range(len(DimPoints)-1):\n                    DistanceDim=TechDraw.makeDistanceDim(View,'Distance',DimPoints[i],DimPoints[i+1])\n                    DistanceDim.X = (DimPoints[i].x+DimPoints[i+1].x)/2+Delta.x\n                    DistanceDim.Y = (DimPoints[i].y+DimPoints[i+1].y)/2+Delta.y\n\nclass createObliqueCoordDim:\n    '''Create oblique coordinate dimension'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 2 1\",\\\n        \" \tc None\",\\\n        \".\tc #FF0000\",\\\n        \"                   .......           ......                     \",\\\n        \"         ...        ......           .......                    \",\\\n        \"         ...         ......            ......                   \",\\\n        \"        .....         ......            .....                   \",\\\n        \"         .....         ......           ......                  \",\\\n        \"         ......         ......           ......                 \",\\\n        \"          ......         ......           ......                \",\\\n        \"           ......         ......           ......               \",\\\n        \"            .......        ......           ......              \",\\\n        \"             ...........    ......           ......             \",\\\n        \"              ..........     ......           ......            \",\\\n        \"               .........     ......            ......           \",\\\n        \"               .........      ......            .....           \",\\\n        \"               .........       ......            .....          \",\\\n        \"               .........        ...........       .....         \",\\\n        \"               .........         ...........      ......        \",\\\n        \"              ...........         ..........       ......       \",\\\n        \"             ............         ..........        ......      \",\\\n        \"            ............          ..........         .........  \",\\\n        \"           ......                 ..........          ..........\",\\\n        \"          ......                  ..........           .........\",\\\n        \"         .......                  ..........           .........\",\\\n        \"         ......                  ............           ........\",\\\n        \".       ......                  ............           .........\",\\\n        \"..     .....                    .....                   ........\",\\\n        \"...   ......                  ......                   .........\",\\\n        \"...........                  .......                  ..........\",\\\n        \"..........                   ......                  ...........\",\\\n        \".........                   ......                  .......   ..\",\\\n        \".........                  ......                  ......       \",\\\n        \".........                 ......                  .......       \",\\\n        \".........                ......                  .......        \",\\\n        \".........               ......                   ......         \",\\\n        \"..........             ......                   ......          \",\\\n        \"...........           ......                   ......           \",\\\n        \"............         ......                   ......            \",\\\n        \"..     ......        .....                   ......             \",\\\n        \"        ......      ......                  ......              \",\\\n        \"        .......   .......                  ......               \",\\\n        \"         ...............                  ......                \",\\\n        \"          .............                  .......                \",\\\n        \"           ...........                  .......                 \",\\\n        \"            .........                   ......                  \",\\\n        \"            .........                  ......                   \",\\\n        \"            .........                 ......                    \",\\\n        \"            .........                ......                     \",\\\n        \"           ...........              ......                      \",\\\n        \"           ............            ......                       \",\\\n        \"           .............          ......                        \",\\\n        \"           ....    .....         ......                         \",\\\n        \"            ..      .....       .......                         \",\\\n        \"                     .....     .......                          \",\\\n        \"                      .....   .......                           \",\\\n        \"                       .............                            \",\\\n        \"                       ............                             \",\\\n        \"                        ..........                              \",\\\n        \"                        ..........                              \",\\\n        \"                        ..........                              \",\\\n        \"                        ..........                              \",\\\n        \"                        ..........                              \",\\\n        \"                       ...........                              \",\\\n        \"                       ...........                              \",\\\n        \"                       ...........                              \",\\\n        \"                        ...                                     \"])\n\n    def textEnglish(self):\n        buttonText = \"Create an oblique coordinate dimension\"\n        helpText = \"Create an oblique coordinate dimension\"+ \"\\n\"\\\n                   \"- select three or more  vertexes\"+ \"\\n\"\\\n                   \"- the first two define the direction\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Erzeuge eine schr\u00e4ge Koordinatenbema\u00dfung\"\n        helpText = \"Erzeuge ein schr\u00e4ges Koordinatenma\u00df\"+ \"\\n\"\\\n                   \"- w\u00e4hle drei oder mehr Konstruktionspunkte\"+ \"\\n\"\\\n                   \"- die beiden Ersten bestimmen die Richtung\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Dimensioni parallele/coordinate oblique\"\n        helpText = \"- impostare Valore distanziamento\"+ \"\\n\"\\\n                   \"- selezionare tre o pi\u00f9 vertici\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Dimensions parall\u00e8les/coordonn\u00e9es oblique\"\n        helpText = \"- d\u00e9finir Valeur d'espacement\"+ \"\\n\"\\\n                          \"- s\u00e9lectionnez trois sommets ou plus\"+ \"\\n\"\\\n                          \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Dimensiones paralelas/coordenadas oblicuas\"\n        helpText = \"- establecer Valor de espaciado\"+ \"\\n\"\\\n                   \"- seleccione tres o m\u00e1s v\u00e9rtices\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self): # createObliqueCoordDim\n        def sortPoints(Point):\n            return Point.x\n\n        (OK,ElementNames,View) = commonTools.selectionOK()\n        if OK:\n            VertexNames = [VertexName for VertexName in ElementNames if VertexName[:6]=='Vertex']\n            Vertexes = [View.getVertexBySelection(VertexName) for VertexName in VertexNames]\n            if len(Vertexes) > 2:\n                DimPoints = [Vertexes[0].Point,Vertexes[1].Point]\n                Direction = Vertexes[0].Point.sub(Vertexes[1].Point).normalize()\n                Normal = app.Vector(Direction.y,-Direction.x,0)\n                Carrier = Part.Line(Vertexes[0].Point,Vertexes[1].Point)\n                DistLine = Part.Line(app.Vector(),Normal)\n                Ip = Carrier.intersect(DistLine)\n                Delta = app.Vector(Ip[0].X,Ip[0].Y,Ip[0].Z).normalize()*DimAttrib.getDimLineDistance()\n                for Num in range(2,len(Vertexes)):\n                    Pt = Vertexes[Num].Point\n                    Extension = Part.Line(Pt,Pt.add(Normal))\n                    Ip = Carrier.intersect(Extension)\n                    IpVec = app.Vector(Ip[0].X,Ip[0].Y,Ip[0].Z)\n                    if not IpVec.isEqual(Pt,0.01):\n                        DimPoints.append(IpVec)\n                        View.makeCosmeticLine(Pt,IpVec,1, 0.15, (0,0,0,0))\n                    else:\n                        DimPoints.append(Pt)\n                DimPoints.sort(key=sortPoints)\n                for i  in range(len(DimPoints)-1):\n                    DistanceDim=TechDraw.makeDistanceDim(View,'Distance',DimPoints[0],DimPoints[i+1])\n                    DistanceDim.X = (DimPoints[0].x+DimPoints[i+1].x)/2+Delta.x*(i+1)\n                    DistanceDim.Y = (DimPoints[0].y+DimPoints[i+1].y)/2+Delta.y*(i+1)\n\nclass positionObliqueDimChain:\n    '''Position oblique dimension'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 240 2\",\\\n        \"  \tc None\",\\\n        \". \tc #FF0000\",\\\n        \"+ \tc #262600\",\\\n        \"@ \tc #323200\",\\\n        \"# \tc #4F5000\",\\\n        \"$ \tc #7B7B00\",\\\n        \"% \tc #848400\",\\\n        \"& \tc #4E4E00\",\\\n        \"* \tc #464600\",\\\n        \"= \tc #939400\",\\\n        \"- \tc #CCCD00\",\\\n        \"; \tc #D8D800\",\\\n        \"> \tc #9A9A00\",\\\n        \", \tc #373700\",\\\n        \"' \tc #919100\",\\\n        \") \tc #D5D500\",\\\n        \"! \tc #FBFC00\",\\\n        \"~ \tc #FCFD00\",\\\n        \"{ \tc #DBDC00\",\\\n        \"] \tc #151500\",\\\n        \"^ \tc #8E8E00\",\\\n        \"/ \tc #D9D900\",\\\n        \"( \tc #FBFB00\",\\\n        \"_ \tc #FFFF00\",\\\n        \": \tc #F8F800\",\\\n        \"< \tc #D4D400\",\\\n        \"[ \tc #000000\",\\\n        \"} \tc #898900\",\\\n        \"| \tc #DDDE00\",\\\n        \"1 \tc #FCFC00\",\\\n        \"2 \tc #D0D000\",\\\n        \"3 \tc #737400\",\\\n        \"4 \tc #8A8A00\",\\\n        \"5 \tc #E1E100\",\\\n        \"6 \tc #F7F800\",\\\n        \"7 \tc #CBCB00\",\\\n        \"8 \tc #7A7A00\",\\\n        \"9 \tc #141400\",\\\n        \"0 \tc #E2E300\",\\\n        \"a \tc #F6F700\",\\\n        \"b \tc #C7C700\",\\\n        \"c \tc #808000\",\\\n        \"d \tc #212100\",\\\n        \"e \tc #3D3D00\",\\\n        \"f \tc #929200\",\\\n        \"g \tc #E3E300\",\\\n        \"h \tc #F6F600\",\\\n        \"i \tc #C4C400\",\\\n        \"j \tc #838300\",\\\n        \"k \tc #353500\",\\\n        \"l \tc #4F4F00\",\\\n        \"m \tc #FDFD00\",\\\n        \"n \tc #C2C200\",\\\n        \"o \tc #838400\",\\\n        \"p \tc #595900\",\\\n        \"q \tc #9FA000\",\\\n        \"r \tc #DFDF00\",\\\n        \"s \tc #C1C100\",\\\n        \"t \tc #828200\",\\\n        \"u \tc #404000\",\\\n        \"v \tc #5F5F00\",\\\n        \"w \tc #A4A400\",\\\n        \"x \tc #C0C100\",\\\n        \"y \tc #7D7E00\",\\\n        \"z \tc #3C3C00\",\\\n        \"A \tc #616100\",\\\n        \"B \tc #A7A700\",\\\n        \"C \tc #DDDD00\",\\\n        \"D \tc #F3F400\",\\\n        \"E \tc #767600\",\\\n        \"F \tc #303000\",\\\n        \"G \tc #606000\",\\\n        \"H \tc #A8A800\",\\\n        \"I \tc #DEDE00\",\\\n        \"J \tc #F1F100\",\\\n        \"K \tc #C3C400\",\\\n        \"L \tc #6C6C00\",\\\n        \"M \tc #090900\",\\\n        \"N \tc #5C5C00\",\\\n        \"O \tc #DFE000\",\\\n        \"P \tc #FEFE00\",\\\n        \"Q \tc #F0F000\",\\\n        \"R \tc #C4C500\",\\\n        \"S \tc #242400\",\\\n        \"T \tc #555500\",\\\n        \"U \tc #E2E200\",\\\n        \"V \tc #EFEF00\",\\\n        \"W \tc #6D6D00\",\\\n        \"X \tc #444400\",\\\n        \"Y \tc #6F7000\",\\\n        \"Z \tc #545400\",\\\n        \"` \tc #494900\",\\\n        \" .\tc #E5E600\",\\\n        \"..\tc #2F2F00\",\\\n        \"+.\tc #969700\",\\\n        \"@.\tc #D3D300\",\\\n        \"#.\tc #A3A300\",\\\n        \"$.\tc #646500\",\\\n        \"%.\tc #030300\",\\\n        \"&.\tc #A0A000\",\\\n        \"*.\tc #EAEA00\",\\\n        \"=.\tc #EFF000\",\\\n        \"-.\tc #BEBF00\",\\\n        \";.\tc #6A6A00\",\\\n        \">.\tc #848500\",\\\n        \",.\tc #EAEB00\",\\\n        \"'.\tc #EDEE00\",\\\n        \").\tc #AAAB00\",\\\n        \"!.\tc #5E5E00\",\\\n        \"~.\tc #161600\",\\\n        \"{.\tc #070700\",\\\n        \"].\tc #0A0A00\",\\\n        \"^.\tc #3F3F00\",\\\n        \"/.\tc #9B9B00\",\\\n        \"(.\tc #EEEF00\",\\\n        \"_.\tc #B9B900\",\\\n        \":.\tc #666600\",\\\n        \"<.\tc #9C9C00\",\\\n        \"[.\tc #F5F600\",\\\n        \"}.\tc #EEEE00\",\\\n        \"|.\tc #ACAC00\",\\\n        \"1.\tc #363600\",\\\n        \"2.\tc #1E1E00\",\\\n        \"3.\tc #4A4A00\",\\\n        \"4.\tc #F4F400\",\\\n        \"5.\tc #F3F300\",\\\n        \"6.\tc #B2B300\",\\\n        \"7.\tc #A9A900\",\\\n        \"8.\tc #DADA00\",\\\n        \"9.\tc #F2F200\",\\\n        \"0.\tc #AEAF00\",\\\n        \"a.\tc #474700\",\\\n        \"b.\tc #ABAB00\",\\\n        \"c.\tc #FAFA00\",\\\n        \"d.\tc #FAFB00\",\\\n        \"e.\tc #AAAA00\",\\\n        \"f.\tc #656500\",\\\n        \"g.\tc #1B1B00\",\\\n        \"h.\tc #565600\",\\\n        \"i.\tc #ACAD00\",\\\n        \"j.\tc #E7E700\",\\\n        \"k.\tc #FEFF00\",\\\n        \"l.\tc #F5F500\",\\\n        \"m.\tc #8D8D00\",\\\n        \"n.\tc #414100\",\\\n        \"o.\tc #5A5A00\",\\\n        \"p.\tc #C6C600\",\\\n        \"q.\tc #F0F100\",\\\n        \"r.\tc #343400\",\\\n        \"s.\tc #BCBC00\",\\\n        \"t.\tc #F2F300\",\\\n        \"u.\tc #E9E900\",\\\n        \"v.\tc #7E7E00\",\\\n        \"w.\tc #010100\",\\\n        \"x.\tc #3B3B00\",\\\n        \"y.\tc #BEBE00\",\\\n        \"z.\tc #626200\",\\\n        \"A.\tc #1D1E00\",\\\n        \"B.\tc #313100\",\\\n        \"C.\tc #A8A900\",\\\n        \"D.\tc #E4E400\",\\\n        \"E.\tc #C2C300\",\\\n        \"F.\tc #6F6F00\",\\\n        \"G.\tc #272700\",\\\n        \"H.\tc #686800\",\\\n        \"I.\tc #B3B300\",\\\n        \"J.\tc #E5E500\",\\\n        \"K.\tc #F9F900\",\\\n        \"L.\tc #F1F200\",\\\n        \"M.\tc #BBBB00\",\\\n        \"N.\tc #7B7C00\",\\\n        \"O.\tc #CBCC00\",\\\n        \"P.\tc #C8C800\",\\\n        \"Q.\tc #CECE00\",\\\n        \"R.\tc #E3E400\",\\\n        \"S.\tc #FDFE00\",\\\n        \"T.\tc #7E7F00\",\\\n        \"U.\tc #414200\",\\\n        \"V.\tc #525200\",\\\n        \"W.\tc #9D9E00\",\\\n        \"X.\tc #E6E600\",\\\n        \"Y.\tc #333300\",\\\n        \"Z.\tc #999900\",\\\n        \"`.\tc #C0C000\",\\\n        \" +\tc #7C7C00\",\\\n        \".+\tc #141500\",\\\n        \"++\tc #E4E500\",\\\n        \"@+\tc #727200\",\\\n        \"#+\tc #404100\",\\\n        \"$+\tc #505000\",\\\n        \"%+\tc #979700\",\\\n        \"&+\tc #BABA00\",\\\n        \"*+\tc #959600\",\\\n        \"=+\tc #E1E000\",\\\n        \"-+\tc #DBDB00\",\\\n        \";+\tc #FDFC00\",\\\n        \">+\tc #393900\",\n        \",+\tc #9E9E00\",\\\n        \"'+\tc #B4B400\",\\\n        \")+\tc #020200\",\\\n        \"!+\tc #969600\",\\\n        \"~+\tc #E0E000\",\\\n        \"{+\tc #6A6B00\",\\\n        \"]+\tc #959500\",\\\n        \"^+\tc #939300\",\\\n        \"/+\tc #4A4B00\",\\\n        \"(+\tc #D7D700\",\\\n        \"_+\tc #797A00\",\\\n        \":+\tc #EBEB00\",\\\n        \"<+\tc #E6E700\",\\\n        \"[+\tc #646400\",\\\n        \"}+\tc #B0B000\",\\\n        \"|+\tc #D1D100\",\\\n        \"1+\tc #D2D200\",\\\n        \"2+\tc #9C9D00\",\\\n        \"3+\tc #3A3B00\",\\\n        \"4+\tc #AFB000\",\\\n        \"5+\tc #BDBD00\",\\\n        \"6+\tc #787800\",\\\n        \"7+\tc #202000\",\\\n        \"8+\tc #ADAE00\",\\\n        \"9+\tc #E8E800\",\\\n        \"0+\tc #BCBD00\",\\\n        \"a+\tc #696900\",\\\n        \"b+\tc #1F1F00\",\\\n        \"c+\tc #585800\",\\\n        \"d+\tc #A6A600\",\\\n        \"e+\tc #ECEC00\",\\\n        \"f+\tc #B6B600\",\\\n        \"g+\tc #676700\",\\\n        \"h+\tc #B0B100\",\\\n        \"i+\tc #5D5D00\",\\\n        \"j+\tc #A9AA00\",\\\n        \"k+\tc #AFAF00\",\n        \"l+\tc #A2A300\",\\\n        \"m+\tc #B5B600\",\\\n        \"n+\tc #545500\",\\\n        \"o+\tc #ECED00\",\\\n        \"p+\tc #505100\",\\\n        \"q+\tc #121200\",\\\n        \"                                                      . . . . . .                                                               \",\\\n        \"                                                    . . . . . .                                                                 \",\\\n        \"                                                  . . . . . .                                                                   \",\\\n        \"                                                . . . . . .                                                                     \",\\\n        \"                                              . . . . . .                                                                       \",\\\n        \"                                            . . . . . .                                                                         \",\\\n        \"                                          . . . . . .                                                                           \",\\\n        \"                    . .                 . . . . . .                                                                             \",\\\n        \"                  . . . . . . . . . . . . . . . .                                                                               \",\\\n        \"                  . . . . . . . . . . . . . . .                                                                                 \",\\\n        \"                  . . . . . . . . . . . . . .                                                                                   \",\\\n        \"                    . . . . . . . . . . . .                                                                                     \",\\\n        \"                    . . . . . . . . . . . .                                                                                     \",\\\n        \"                    . . . . . . . . . . . .                                                                                     \",\\\n        \"                    . . . . . . . . . . . .                                                                               + @   \",\\\n        \"                    . . . . . . . . . . . .                                                                             # $ % & \",\\\n        \"                    . . . . . . . . . . . .                                                                           * = - ; > \",\\\n        \"                  . . . . . . . . . . . . . .                                                                       , ' ) ! ~ { \",\\\n        \"                . . . . . . . . . . . . . . . .                                                                   ] ^ / ( _ : < \",\\\n        \"              . . . . . . . . . . . . . . . . . .                                                               [ } | 1 _ : 2 3 \",\\\n        \"            . . . . . .                 . . . . . .                                                           [ 4 5 ( _ 6 7 8 [ \",\\\n        \"          . . . . . . .                   . . . . . .                                                       9 4 0 ( _ a b c d   \",\\\n        \"        . . . . . . .                       . . . . . .                                                   e f g ( _ h i j k     \",\\\n        \"      . . . . . . .                           . . . . . .                                             [ l > 5 m _ h n o e       \",\\\n        \"    . . . . . . .                               . . . . . .                                         [ p q r ~ _ h s t u         \",\\\n        \"  . . . . . . .                                   . . . .                                         [ v w | 1 _ h x y z           \",\\\n        \". . . . . . .                                       . . .                                       [ A B C 1 _ D s E F             \",\\\n        \". . . . . .                                                                                   [ G H I 1 _ J K L M               \",\\\n        \". . . . .                                                                                   [ N H O 1 P Q R L [                 \",\\\n        \". . . .                                                               S [                 [ T B U m P V i W [                   \",\\\n        \". . .                                                               X Y Z d               ` w  .m _ V n L [                     \",\\\n        \".                                                                 ..+.@.#.$.%.          , &.*.P _ =.-.;.[                       \",\\\n        \"                                                                F >.,._ '.).!.[ ~.{.].^./.(.P _ J _.:.[                         \",\\\n        \"                                                              [ e <.[._ _ }.|.Z 1.2.3.<.4._ _ 5.6.A [                           \",\\\n        \"                                                                ] ..7.V P _ V 5 I 8.r J _ _ 9.0.:.[                             \",\\\n        \"                                                                  [ a.b.,.P 1 c.d.( 1 P _ [.e.f.g.                              \",\\\n        \"                                                                    [ h.i.j.m k._ _ _ _ _ l.m.n.[                               \",\\\n        \"                                                                      [ o.p.l._ _ _ _ _ _ q.c r.                                \",\\\n        \"                                                                      [ d s.t._ _ _ _ _ _ u.v.1.                                \",\\\n        \"                                                                      w.x.s l._ _ _ _ _ 1 y.z.A.                                \",\\\n        \"                                                                        B.C.D.m _ _ _ _ ~ E.F.G.                                \",\\\n        \"                                                                        [ H.I.J.K.: K.m _ L.M.N.1.                              \",\\\n        \"                                                                          [ :.b.O.P.Q.R.S._ L.s.T.,                             \",\\\n        \"                                                                            [ U.V.u N W.X.1 _ 9.y.T.@                           \",\\\n        \"                                                                              [ [ [ [ Y.Z. .( _ t.`. +S [ [ .+                  \",\\\n        \"                                                                                        [ Z.++( _ D K @+#+X $+w.+               \",\\\n        \"                                                                                          [ %+0 1 _ l.; s.M.&+p o.F [           \",\\\n        \"                                                                                            [ *+r m _ _ S.m m =+X.w h.[         \",\\\n        \"                                                                                              F %+-+~ _ _ _ _ ;+_ L.b.v [       \",\\\n        \"                                                                                                >+,+5 P _ _ _ _ _ ( '+G [       \",\\\n        \"                                                                                                )+!+~+_ _ _ _ _ _ _ s.{+[       \",\n        \"                                                                                                w.]+O _ _ _ _ _ _ U ^+/+        \",\\\n        \"                                                                                                [ ^ -+k._ _ _ _ _ (+_+~.        \",\\\n        \"                                                                                              [ !.I.:+_ _ m m g <+6.H.[         \",\\\n        \"                                                                                            [ [+}+g ~ S.V |+1+> 2+Y 3+          \",\\\n        \"                                                                                          [ G 4+J.m S.:+5+6+v.%.7+[             \",\\\n        \"                                                                                        [ o.8+9+m P :+0+a+[ %.                  \",\\\n        \"                                                                                      w.$+e.:+P P :+&+;.[                       \",\\\n        \"                                                                                    b+c+d+V _ P e+f+g+[                         \",\\\n        \"                                                                                  ~.N B 4._ _ '.h+z.[                           \",\\\n        \"                                                                                [ i+e.4._ _ Q j+o.[                             \",\\\n        \"                                                                              [ v k+D _ _ 9.l+Z [                               \",\\\n        \"                                                                            [ H.m+q._ _ L.q n+[                                 \",\\\n        \"                                                                          [ W M.V _ P o+,+p+q+                                  \"])\n\n    def textEnglish(self):\n        buttonText = \"Position an oblique dimension chain\"\n        helpText = \"Position an oblique dimension chain\"+ \"\\n\"\\\n                   \"- select some  parallel oblique measures\"+ \"\\n\"\\\n                   \"- the first selected maesure defines the position\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Positioniere eine schr\u00e4ge Kettenbema\u00dfung\"\n        helpText = \"Positioniere eine schr\u00e4ge Kettenbema\u00dfung\"+ \"\\n\"\\\n                   \"- w\u00e4hle mehrere parallele schr\u00e4ge Ma\u00dfe\"+ \"\\n\"\\\n                   \"- das Erste bestimmt die Position\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Allinea dimensioni oblique\"\n        helpText = \"Dispone sulla stessa linea le dimensioni oblique selezionate:\"+ \"\\n\"\\\n                   \"- seleziona due o pi\u00f9 dimensioni\"+\"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Aligner les dimensions obliques\"\n        helpText = \"R\u00e9organise les dimensions obliques s\u00e9lectionn\u00e9es sur la m\u00eame ligne:\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez deux ou plusieurs dimensions\"+\"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Alinear dimensiones oblicuas\"\n        helpText = \"Organiza las dimensiones oblicuas seleccionadas en la misma l\u00ednea:\"+ \"\\n\"\\\n                   \"- seleccione dos o m\u00e1s dimensiones\"+\"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self): # positionObliqueDimChain\n        Selected = gui.Selection.getSelectionEx()\n        ObliqueDimList = [Select.Object for Select in Selected if Select.Object.Type == 'Distance']\n        if len(ObliqueDimList) > 1:\n            DimPoints = ObliqueDimList[0].getArrowPositions()\n            DimPos = app.Vector(ObliqueDimList[0].X,ObliqueDimList[0].Y,0)\n            Direction = DimPoints[0].sub(DimPoints[1])\n            Normal = app.Vector(Direction.y,-Direction.x,0)\n            CarrierLine = Part.Line(DimPos,DimPos.add(Direction))\n            for Dimension in ObliqueDimList:\n                DimPos = app.Vector(Dimension.X,Dimension.Y,0)\n                NormalLine = Part.Line(DimPos,DimPos.add(Normal))\n                Ip = CarrierLine.intersect(NormalLine)\n                Dimension.X, Dimension.Y = Ip[0].X,Ip[0].Y\n\nclass cascadeObliqueDimension:\n    '''Cascade oblique dimension'''\n    Icon = QtGui.QPixmap([  \\\n        \"64 64 356 2\",\\\n        \"  \tc None\",\\\n        \". \tc #1C1C00\",\\\n        \"+ \tc #949400\",\\\n        \"@ \tc #D6D600\",\\\n        \"# \tc #F6F600\",\\\n        \"$ \tc #F5F500\",\\\n        \"% \tc #CACA00\",\\\n        \"& \tc #919100\",\\\n        \"* \tc #585800\",\\\n        \"= \tc #000000\",\\\n        \"- \tc #707100\",\\\n        \"; \tc #CBCB00\",\\\n        \"> \tc #F3F300\",\\\n        \", \tc #FCFC00\",\\\n        \"' \tc #DBDB00\",\\\n        \") \tc #9A9A00\",\\\n        \"! \tc #515100\",\\\n        \"~ \tc #1D1D00\",\\\n        \"{ \tc #9F9F00\",\\\n        \"] \tc #F7F800\",\\\n        \"^ \tc #F2F200\",\\\n        \"/ \tc #C1C100\",\\\n        \"( \tc #888800\",\\\n        \"_ \tc #767600\",\\\n        \": \tc #D0D000\",\\\n        \"< \tc #FBFB00\",\\\n        \"[ \tc #D3D300\",\\\n        \"} \tc #8B8B00\",\\\n        \"| \tc #474700\",\\\n        \"1 \tc #3F3F00\",\\\n        \"2 \tc #3A3A00\",\\\n        \"3 \tc #535300\",\\\n        \"4 \tc #A7A700\",\\\n        \"5 \tc #E1E100\",\\\n        \"6 \tc #FAFA00\",\\\n        \"7 \tc #BDBD00\",\\\n        \"8 \tc #7C7C00\",\\\n        \"9 \tc #424200\",\\\n        \"0 \tc #878700\",\\\n        \"a \tc #D5D500\",\\\n        \"b \tc #F9F900\",\\\n        \"c \tc #CFCF00\",\\\n        \"d \tc #7E7E00\",\\\n        \"e \tc #2A2A00\",\\\n        \"f \tc #6F6F00\",\\\n        \"g \tc #6C6C00\",\\\n        \"h \tc #5E5E00\",\\\n        \"i \tc #ACAD00\",\\\n        \"j \tc #E9E900\",\\\n        \"k \tc #FDFD00\",\\\n        \"l \tc #F1F100\",\\\n        \"m \tc #B7B700\",\\\n        \"n \tc #676700\",\\\n        \"o \tc #303000\",\\\n        \"p \tc #8D8D00\",\\\n        \"q \tc #DDDD00\",\\\n        \"r \tc #FEFE00\",\\\n        \"s \tc #CDCD00\",\\\n        \"t \tc #696900\",\\\n        \"u \tc #838300\",\\\n        \"v \tc #CECE00\",\\\n        \"w \tc #D1D100\",\\\n        \"x \tc #414100\",\\\n        \"y \tc #B5B500\",\\\n        \"z \tc #EBEB00\",\\\n        \"A \tc #ADAD00\",\\\n        \"B \tc #5F5F00\",\\\n        \"C \tc #969600\",\\\n        \"D \tc #E7E700\",\\\n        \"E \tc #FFFF00\",\\\n        \"F \tc #C5C500\",\\\n        \"G \tc #606000\",\\\n        \"H \tc #505000\",\\\n        \"I \tc #B8B800\",\\\n        \"J \tc #EFEF00\",\\\n        \"K \tc #F4F400\",\\\n        \"L \tc #8E8E00\",\\\n        \"M \tc #494900\",\\\n        \"N \tc #BEBE00\",\\\n        \"O \tc #E3E300\",\\\n        \"P \tc #A0A000\",\\\n        \"Q \tc #5A5A00\",\\\n        \"R \tc #555500\",\\\n        \"S \tc #A2A200\",\\\n        \"T \tc #F0F000\",\\\n        \"U \tc #F0F100\",\\\n        \"V \tc #B7B800\",\\\n        \"W \tc #5B5B00\",\\\n        \"X \tc #DEDE00\",\\\n        \"Y \tc #EFEE00\",\\\n        \"Z \tc #C4C400\",\\\n        \"` \tc #8A8A00\",\\\n        \" .\tc #4A4A00\",\\\n        \"..\tc #171700\",\\\n        \"+.\tc #7F7F00\",\\\n        \"@.\tc #C9C900\",\\\n        \"#.\tc #D9D900\",\\\n        \"$.\tc #545400\",\\\n        \"%.\tc #B3B300\",\\\n        \"&.\tc #EEEE00\",\\\n        \"*.\tc #E8E800\",\\\n        \"=.\tc #6D6D00\",\\\n        \"-.\tc #B2B200\",\\\n        \";.\tc #E2E200\",\\\n        \">.\tc #F7F700\",\\\n        \",.\tc #818100\",\\\n        \"'.\tc #333300\",\\\n        \").\tc #1B1B00\",\\\n        \"!.\tc #929200\",\\\n        \"~.\tc #C0C000\",\\\n        \"{.\tc #E0E000\",\\\n        \"].\tc #A6A600\",\\\n        \"^.\tc #575700\",\\\n        \"/.\tc #777700\",\\\n        \"(.\tc #B9B900\",\\\n        \"_.\tc #E6E600\",\\\n        \":.\tc #F8F800\",\\\n        \"<.\tc #E4E400\",\\\n        \"[.\tc #797900\",\\\n        \"}.\tc #242400\",\\\n        \"|.\tc #484800\",\\\n        \"1.\tc #9E9E00\",\\\n        \"2.\tc #4F4F00\",\\\n        \"3.\tc #C8C800\",\\\n        \"4.\tc #FBFA00\",\\\n        \"5.\tc #A09F00\",\\\n        \"6.\tc #3A3B00\",\\\n        \"7.\tc #5C5C00\",\\\n        \"8.\tc #A4A400\",\\\n        \"9.\tc #C6C600\",\\\n        \"0.\tc #858500\",\\\n        \"a.\tc #444400\",\\\n        \"b.\tc #2E2E00\",\\\n        \"c.\tc #D8D800\",\\\n        \"d.\tc #959500\",\\\n        \"e.\tc #464600\",\\\n        \"f.\tc #383800\",\\\n        \"g.\tc #AEAE00\",\\\n        \"h.\tc #979800\",\\\n        \"i.\tc #313100\",\\\n        \"j.\tc #525200\",\\\n        \"k.\tc #BABB00\",\\\n        \"l.\tc #707000\",\\\n        \"m.\tc #373700\",\\\n        \"n.\tc #D2D200\",\\\n        \"o.\tc #808000\",\\\n        \"p.\tc #626200\",\\\n        \"q.\tc #202000\",\\\n        \"r.\tc #ABAB00\",\\\n        \"s.\tc #FEFF00\",\\\n        \"t.\tc #A5A500\",\\\n        \"u.\tc #868500\",\\\n        \"v.\tc #C5C400\",\\\n        \"w.\tc #646400\",\\\n        \"x.\tc #8C8C00\",\\\n        \"y.\tc #DFDF00\",\\\n        \"z.\tc #FCFD00\",\\\n        \"A.\tc #ECED00\",\\\n        \"B.\tc #B0B000\",\\\n        \"C.\tc #4B4B00\",\\\n        \"D.\tc #9C9C00\",\\\n        \"E.\tc #BABA00\",\\\n        \"F.\tc #4E4E00\",\\\n        \"G.\tc #F9FA00\",\\\n        \"H.\tc #DADA00\",\\\n        \"I.\tc #8F8F00\",\\\n        \"J.\tc #727200\",\\\n        \"K.\tc #999900\",\\\n        \"L.\tc #454500\",\\\n        \"M.\tc #3B3B00\",\\\n        \"N.\tc #A9A900\",\\\n        \"O.\tc #CCCC00\",\\\n        \"P.\tc #979700\",\\\n        \"Q.\tc #515200\",\\\n        \"R.\tc #B1B100\",\\\n        \"S.\tc #AFAF00\",\\\n        \"T.\tc #EAEA00\",\\\n        \"U.\tc #CDCE00\",\\\n        \"V.\tc #D0D100\",\\\n        \"W.\tc #E5E500\",\\\n        \"X.\tc #E3E400\",\\\n        \"Y.\tc #B6B700\",\\\n        \"Z.\tc #404000\",\\\n        \"`.\tc #868600\",\\\n        \" +\tc #3D3D00\",\\\n        \".+\tc #FDFE00\",\\\n        \"++\tc #4D4C00\",\\\n        \"@+\tc #898900\",\\\n        \"#+\tc #434300\",\\\n        \"$+\tc #D4D400\",\\\n        \"%+\tc #EAEB00\",\\\n        \"&+\tc #A3A400\",\\\n        \"*+\tc #D8D900\",\\\n        \"=+\tc #717100\",\\\n        \"-+\tc #D7D700\",\\\n        \";+\tc #FBFC00\",\\\n        \">+\tc #BCBC00\",\\\n        \",+\tc #EFF000\",\\\n        \"'+\tc #2D2D00\",\\\n        \")+\tc #FAF900\",\\\n        \"!+\tc #818200\",\\\n        \"~+\tc #747400\",\\\n        \"{+\tc #B6B600\",\\\n        \"]+\tc #C7C700\",\\\n        \"^+\tc #A8A800\",\\\n        \"/+\tc #A1A100\",\\\n        \"(+\tc #868700\",\\\n        \"_+\tc #353500\",\\\n        \":+\tc #BDBE00\",\\\n        \"<+\tc #757500\",\\\n        \"[+\tc #636300\",\\\n        \"}+\tc #6B6B00\",\\\n        \"|+\tc #111100\",\\\n        \"1+\tc #585900\",\\\n        \"2+\tc #F1F200\",\\\n        \"3+\tc #D5D600\",\\\n        \"4+\tc #C7C800\",\\\n        \"5+\tc #DFDE00\",\\\n        \"6+\tc #2B2B00\",\\\n        \"7+\tc #282800\",\\\n        \"8+\tc #4C4D00\",\\\n        \"9+\tc #FF0000\",\\\n        \"0+\tc #1F1F00\",\\\n        \"a+\tc #656400\",\\\n        \"b+\tc #666600\",\\\n        \"c+\tc #040400\",\\\n        \"d+\tc #939300\",\\\n        \"e+\tc #656500\",\\\n        \"f+\tc #B4B400\",\\\n        \"g+\tc #D2D300\",\\\n        \"h+\tc #1E1E00\",\\\n        \"i+\tc #635200\",\\\n        \"j+\tc #929000\",\\\n        \"k+\tc #F2F300\",\\\n        \"l+\tc #EEEF00\",\\\n        \"m+\tc #C0C100\",\\\n        \"n+\tc #777800\",\\\n        \"o+\tc #323200\",\\\n        \"p+\tc #6A6A00\",\\\n        \"q+\tc #BFBF00\",\\\n        \"r+\tc #FE0000\",\\\n        \"s+\tc #DE0000\",\\\n        \"t+\tc #AC5900\",\\\n        \"u+\tc #C6B000\",\\\n        \"v+\tc #EEEA00\",\\\n        \"w+\tc #F8F900\",\\\n        \"x+\tc #5D5D00\",\\\n        \"y+\tc #212100\",\\\n        \"z+\tc #F20000\",\\\n        \"A+\tc #DF4E00\",\\\n        \"B+\tc #EDAC00\",\\\n        \"C+\tc #F9E700\",\\\n        \"D+\tc #E5E400\",\\\n        \"E+\tc #757600\",\\\n        \"F+\tc #090900\",\\\n        \"G+\tc #797A00\",\\\n        \"H+\tc #161600\",\\\n        \"I+\tc #FC1600\",\\\n        \"J+\tc #FD6900\",\\\n        \"K+\tc #EBB100\",\\\n        \"L+\tc #B4A800\",\\\n        \"M+\tc #343400\",\\\n        \"N+\tc #F90D00\",\\\n        \"O+\tc #C23D00\",\\\n        \"P+\tc #734200\",\\\n        \"Q+\tc #727300\",\\\n        \"R+\tc #CECF00\",\\\n        \"S+\tc #8B8A00\",\\\n        \"T+\tc #FE0200\",\\\n        \"U+\tc #EB1800\",\\\n        \"V+\tc #BD2900\",\\\n        \"W+\tc #C3C300\",\\\n        \"X+\tc #CCCD00\",\\\n        \"Y+\tc #6E6E00\",\\\n        \"Z+\tc #737300\",\\\n        \"`+\tc #FC0100\",\\\n        \" @\tc #B8B900\",\\\n        \".@\tc #ECEC00\",\\\n        \"+@\tc #828200\",\\\n        \"@@\tc #909100\",\\\n        \"#@\tc #262600\",\\\n        \"$@\tc #B3B200\",\\\n        \"%@\tc #DCDC00\",\\\n        \"&@\tc #A5A600\",\\\n        \"*@\tc #2F2F00\",\\\n        \"=@\tc #838400\",\\\n        \"-@\tc #EEED00\",\\\n        \";@\tc #A6A700\",\\\n        \">@\tc #4C4C00\",\\\n        \",@\tc #989800\",\\\n        \"'@\tc #C3C400\",\\\n        \")@\tc #3E3E00\",\\\n        \"!@\tc #3C3C00\",\\\n        \"~@\tc #7B7B00\",\\\n        \"{@\tc #F6F700\",\\\n        \"]@\tc #636400\",\\\n        \"^@\tc #565600\",\\\n        \"/@\tc #888900\",\\\n        \"(@\tc #C30000\",\\\n        \"_@\tc #7D6100\",\\\n        \":@\tc #BCBB00\",\\\n        \"<@\tc #E4E500\",\\\n        \"[@\tc #595900\",\\\n        \"}@\tc #E50000\",\\\n        \"|@\tc #CF5D00\",\\\n        \"1@\tc #E9CD00\",\\\n        \"2@\tc #FAF800\",\\\n        \"3@\tc #B9BA00\",\\\n        \"4@\tc #848400\",\\\n        \"5@\tc #787800\",\\\n        \"6@\tc #DFE000\",\\\n        \"7@\tc #676800\",\\\n        \"8@\tc #F60000\",\\\n        \"9@\tc #F23A00\",\\\n        \"0@\tc #FCA200\",\\\n        \"a@\tc #F1D900\",\\\n        \"b@\tc #C1BE00\",\\\n        \"c@\tc #FD4D00\",\\\n        \"d@\tc #D49400\",\\\n        \"e@\tc #8D7E00\",\\\n        \"f@\tc #434500\",\\\n        \"g@\tc #B1B200\",\\\n        \"h@\tc #FB0000\",\\\n        \"i@\tc #C71900\",\\\n        \"j@\tc #890000\",\\\n        \"k@\tc #F40000\",\\\n        \"l@\tc #1A1A00\",\\\n        \"m@\tc #0C0C00\",\n        \"n@\tc #E2E300\",\\\n        \"o@\tc #8F9000\",\\\n        \"p@\tc #E6E700\",\\\n        \"q@\tc #ACAC00\",\\\n        \"r@\tc #AAAA00\",\\\n        \"s@\tc #C2C200\",\\\n        \"t@\tc #7D7D00\",\\\n        \"u@\tc #9D9D00\",\\\n        \"v@\tc #5A1800\",\\\n        \"w@\tc #837F00\",\\\n        \"x@\tc #232400\",\\\n        \"y@\tc #F80000\",\\\n        \"z@\tc #843300\",\\\n        \"A@\tc #CCBC00\",\\\n        \"B@\tc #5E5F00\",\\\n        \"C@\tc #E80E00\",\\\n        \"D@\tc #F78B00\",\\\n        \"E@\tc #FBDF00\",\\\n        \"F@\tc #DDDB00\",\\\n        \"G@\tc #FD4900\",\\\n        \"H@\tc #E79600\",\\\n        \"I@\tc #AA9A00\",\\\n        \"J@\tc #646200\",\\\n        \"K@\tc #FD0E00\",\\\n        \"L@\tc #E14B00\",\\\n        \"M@\tc #915C00\",\\\n        \"N@\tc #EF0000\",\\\n        \"O@\tc #B80000\",\\\n        \"                                      . + @ # $ % & *               = - ; > , ' ) !                                             \",\\\n        \"                                        ~ { ' ] ^ / ( !               = _ : $ < [ } |                                           \",\\\n        \"                    1 2                   3 4 5 6 ^ 7 8 9               = 0 a b < c d e                                         \",\\\n        \"                  = f g 9                   h i j k l m n                 o p q r , s t =                                       \",\\\n        \"                = u v w + x                   t y l k z A B                 ! C D E # F G                                       \",\\\n        \"                H I J K s L M                   f N > < O P Q                 R S T E U V W                                     \",\\\n        \"                1 P X b Y Z `  .                ..+.@.^ b #.) $.                h %.&.k *.A W                                   \",\\\n        \"                  =.-.;.>.j 7 ,.'.                ).!.: > # w C 3                 t ~.&.< {.].^.                                \",\\\n        \"                    /.(._.:.<.y [.}.=               |.1.@ # $ ; !.2.              = +.3.^ 4.' 5.R                               \",\\\n        \"                      ,.~.z 6 ;.i =.* $.R 6.          7.8.X 6 K 9.0.a.              b.` c >.< c.d.e.                            \",\\\n        \"                      f.u 3.^ , {.g.1.) h.f i.          j.4 *.k ^ k.l.                m.` #., 6 n.,.b.                          \",\\\n        \"                        = o.[ b E , k < >.%.p.            q.r.> s.T t.$.                = u.j E :.v.w.                          \",\\\n        \"                          o x.y.z.s.s.s.E A.B.g             C.y U k D D.9                 f.C j r ^ E.B                         \",\\\n        \"                            F.s G.E E E E , H.I.C.            J.~.T < {.K.L.L.M.x           Q N.D , z y Q                       \",\\\n        \"                            1 O.G.E E E E s._.P.Q.            m.x.@.> b ' R.%.S.A B           _ I T.< _.-.B                     \",\\\n        \"                            a.U.6 E E E E E *.K.$.              R C V.:.:.W.D W.X.Y.^.        Z.`.~.T < ;.A Q                   \",\\\n        \"                             +; b E E E E s._.C F.                3 + X..+k .+k k T.r.F.        ++@+3.>.< q P C.                \",\\\n        \"                          #+_ $+6 r r r r r %+&+h                 = t *+k E E E E E 5 =+=         '.( -+G.:.[ L 2.              \",\\\n        \"                          8 7 T ;+# $ K K :.K >+l.                = ) ,+r E E E E E > @+=           '+L y.)+$ 3.!+| j.F.C.      \",\\\n        \"                        ~+{+T., A.V.% ]+]+#.q ^+p.                = /+^ r E E E E E ^ (+=             _++ 5 < ^ :+J.[.<+=+*     \",\\\n        \"                      [+g.<.< J (.~+W $.$.,.I.}+                  |+t.> r E E E E E T ,.=               1+&+<.z.2+n.3+n.4+d..   \",\\\n        \"                    a.8.5+b T >+,. ._+6+7+8+Q                     = { l r E E E E E > @+=                 /.B.j , :.b :.> 3+x.= \",\\\n        \"9+                0+K.#.>.> Z ` $.                                a+9.:.s.E E E k E n.b+=                 |.!+n., E E E r J %.c+\",\\\n        \"9+9+            | d+n.$ $ w C *                                 e+f+z k 2+l &.T g+]+d+M.                    t 3.< E E E E # ~.h+\",\\\n        \"9+9+9+        i+j+% k+>.H.t.b+                                p.N.;.< l+m+E.y (.& n+o+                      p+3.< E E E E # q+|+\",\\\n        \"9+9+9+9+9+r+s+t+u+v+w+{.S.J.                                x+{ ' 6 T 9.t C.2  .y+=                         =.% , E E E E $ >+= \",\\\n        \"9+9+9+9+9+9+z+A+B+C+D+f+E+                                ! C -+)+K O.u F+                                M.G+c , E E E r 2+{+H+\",\\\n        \"9+9+9+9+9+9+r+I+J+K+L+f                                 M+` a 6 6 [ x.9                                   w.&+W.k k k 6 > H.& = \",\\\n        \"9+9+9+9+9+9+9+9+N+O+P+                                = Q+R+:.E X S+9                                   | ` q k , z &.-+].+.o   \",\\\n        \"  9+9+9+9+9+9+9+T+U+V+                                t W+> E D d.H                                   o+_ a < :.X+Y+Z+n F.x     \",\\\n        \"9+9+9+9+9+9+9+9+9+`+                                t  @.@;+D ].h                                   x +@; # >.@ @@#@m.6+=       \",\\\n        \"9+9+9+9+9+9+9+9+9+9+                              b+$@_.6 *.y =.                                  e.@+9.^ b %@&@Q               \",\\\n        \"9+9+9+9+9+9+9+9+9+9+                            n g.5 b .@~.o.*@                                9 =@/ -@, ;.S.f                 \",\\\n        \"9+9+9+9+9+9+9+9+9+9+9+                        h ;@X 6 ^ ]+x.>@                                  ~+I j , j f+Z+                  \",\\\n        \"  9+9+9+9+9+9+9+9+9+9+9+                    >@,@#.b :.c p 2.                                  Q 4 W., J (.b+                    \",\\\n        \"  9+9+9+9+9+9+9+9+9+9+9+9+                |.+@v >., q @+o+                                  ! `.{.r $ '@)@                      \",\\\n        \"              9+9+9+9+9+9+                =+W+K z.5 L M+                                  !@~@#.s.{@; ]@                        \",\\\n        \"                9+9+9+9+9+9+            b+7 J < 5 1.^@                                  i.0.$+< :.n./@M+                        \",\\\n        \"                  9+9+9+9+9+9+9+9+r+(@_@:@z 6 <@B.Z+                                  6+`.v # < *+) [@                          \",\\\n        \"                    9+9+9+9+9+9+9+9+}@|@1@2@T.3@4@                                    5@]+l k 6@P 7@                            \",\\\n        \"                    9+9+9+9+9+9+9+9+8@9@0@a@b@@+$.                                  W >+&.k _.S w.                              \",\\\n        \"                      9+9+9+9+9+9+9+9+9+c@d@e@f@                                  3 ;@j k .@g@|                                 \",\\\n        \"                        9+9+9+9+9+9+9+9+h@i@j@                                  [+P.O k J ~.^@                                  \",\\\n        \"                        9+9+9+9+9+9+9+9+9+8@k@                                Q P.X r > 3.~+                                    \",\\\n        \"                        9+9+9+9+9+9+9+9+9+9+9+                               +L #.r b R+o.l@                                    \",\\\n        \"                        9+9+9+9+9+9+9+9+9+9+9+                            m@d [ b E @ +@M.                                      \",\\\n        \"                        9+9+9+9+9+9+9+9+9+9+9+                            n ; # E q +@H                                         \",\\\n        \"                        9+9+9+9+9+9+9+9+9+9+9+                          j.N ^ k n@o@L.                                          \",\\\n        \"                          9+9+9+9+9+9+9+9+9+9+9+                      g -..@, p@q@x                                             \",\\\n        \"                          9+9+9+9+9+9+9+9+9+9+9+9+                  J.S.D , T.E.}+                                              \",\\\n        \"                                      9+9+9+9+9+9+9+              t r@5 k ,+s@t@                                                \",\\\n        \"                                        9+9+9+9+9+9+            3 u@%@< >.3.+.*@                                                \",\\\n        \"                                          9+9+9+9+9+9+9+9+9+9+v@w@@ 6 , w J.x@                                                  \",\\\n        \"                                            9+9+9+9+9+9+9+9+y@z@A@)+s.#.B@=                                                     \",\\\n        \"                                              9+9+9+9+9+9+9+9+C@D@E@F@@@!@                                                      \",\\\n        \"                                              9+9+9+9+9+9+9+9+h@G@H@I@J@                                                        \",\\\n        \"                                                9+9+9+9+9+9+9+9+K@L@M@                                                          \",\\\n        \"                                                9+9+9+9+9+9+9+9+r+N@O@                                                          \",\\\n        \"                                                9+9+9+9+9+9+9+9+9+r+                                                            \",\\\n        \"                                                9+9+9+9+9+9+9+9+9+9+                                                            \",\\\n        \"                                                9+9+9+9+9+9+9+9+9+9+                                                            \",\\\n        \"                                                9+9+9+9+9+9+9+9+9+9+9+                                                          \",\\\n        \"                                                  9+9+9+9+9+9+9+9+9+9+                                                          \",\\\n        \"                                                    9+9+9+9+9+9+9+9+                                                            \"])\n\n    def textEnglish(self):\n        buttonText = \"Cascade oblique dimensions\"\n        helpText = \"Cascade oblique dimensions\"+ \"\\n\"\\\n                   \"- select the cascading distance\"+ \"\\n\"\\\n                   \"- select some  parallel oblique measures\"+ \"\\n\"\\\n                   \"- the first selected maesure defines the position\"+ \"\\n\"\\\n                   \"- click this button\"\n        return(buttonText,helpText)\n\n    def textGerman(self):\n        buttonText = \"Kaskadiere schr\u00e4ge Bema\u00dfungen\"\n        helpText = \"Kaskadiere schr\u00e4ge Bema\u00dfungen\"+ \"\\n\"\\\n                   \"- stelle den Abstand der Kaskadierung ein\"+ \"\\n\"\\\n                   \"- w\u00e4hle mehrere parallele schr\u00e4ge Ma\u00dfe\"+ \"\\n\"\\\n                   \"- das Erste bestimmt die Position\"+ \"\\n\"\\\n                   \"- dr\u00fccke diesen Knopf\"\n        return(buttonText,helpText)\n\n    def textItalian(self):\n        buttonText = \"Distanziamento dimensioni oblique\"\n        helpText = \"Distanzia (ortogonalmente), al valore impostato, le quote oblique selezionate:\"+ \"\\n\"\\\n                   \"- impostare Valore distanziamento\"+ \"\\n\"\\\n                   \"- selezionare due o pi\u00f9 quote oblique\"+ \"\\n\"\\\n                   \"- fare clic su questo pulsante\"\n        return(buttonText,helpText)\n\n    def textFrench(self):\n        buttonText = \"Espacement des dimensions obliques\"\n        helpText = \"Espaces (orthogonalement), \u00e0 la valeur d\u00e9finie, les dimensions obliques s\u00e9lectionn\u00e9es:\"+ \"\\n\"\\\n                   \"- d\u00e9finir Valeur d'espacement\"+ \"\\n\"\\\n                   \"- s\u00e9lectionnez au moins deux dimensions obliques\"+ \"\\n\"\\\n                   \"- cliquez sur ce bouton\"\n        return(buttonText,helpText)\n\n    def textSpanish(self):\n        buttonText = \"Espaciado de dimensi\u00f3n oblicuas\"\n        helpText = \"Espacios (ortogonalmente), en el valor establecido, las dimensiones oblicuas seleccionadas:\"+ \"\\n\"\\\n                   \"- establecer Valor de espaciado\"+ \"\\n\"\\\n                   \"- seleccione dos o m\u00e1s dimensiones oblicuas\"+ \"\\n\"\\\n                   \"- haga clic en este bot\u00f3n\"\n        return(buttonText,helpText)\n\n    def activated(self): # cascadeObliqueDimension\n        Selected = gui.Selection.getSelectionEx()\n        ObliqueDimList = [Select.Object for Select in Selected if Select.Object.Type == 'Distance']\n        if len(ObliqueDimList) > 1:\n            DimPoints = ObliqueDimList[0].getArrowPositions()\n            DimPos = app.Vector(ObliqueDimList[0].X,ObliqueDimList[0].Y,0)\n            Direction = DimPoints[0].sub(DimPoints[1])\n            Normal = app.Vector(Direction.y,-Direction.x,0)\n            CarrierLine = Part.Line(DimPos,DimPos.add(Direction))\n            DistLine = Part.Line(app.Vector(),Normal)\n            Ip = CarrierLine.intersect(DistLine)\n            Delta = app.Vector(Ip[0].X,Ip[0].Y,Ip[0].Z).normalize()*DimAttrib.getDimLineDistance()\n            for i,Dimension in enumerate(ObliqueDimList):\n                DimPos = app.Vector(Dimension.X,Dimension.Y,0)\n                NormalLine = Part.Line(DimPos,DimPos.add(Normal))\n                Ip = CarrierLine.intersect(NormalLine)\n                Dimension.X, Dimension.Y = Ip[0].X+Delta.x*i,Ip[0].Y+Delta.y*i\n\nAttrib = LineAttributes()\nDimAttrib = DimensionAttributes()\nLang = translate()\nif __name__ == \"__main__\":\n    DialogContainer().show()\n",
    "url": "https://forum.freecadweb.org/viewtopic.php?f=35&t=59334",
    "raw_code_url": "",
    "wiki": "",
    "version": "0.4.5",
    "license": "",
    "date": "2022-03-26",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\TechDraw\\TechDrawTools.FCMacro",
    "filename_from_url": "",
    "author": "edi and domad",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "TechDrawTools.svg"
    ],
    "parsed": true
  },
  {
    "name": "TechDrawViewSet",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Set the parameters of the current view to correspond to the 3D Window",
    "code": "# TechDrawViewSet\n#\n# This allows you to take a view of your part from the the 3D viewer\n# and insert it into a TechDraw document.  It's useful for when you\n# need a tech drawing of your part from a weird angle.\n#\n# 1. Create a TechDrawing and insert a view of your part.\n# 2. Open your part up in the 3D viewer\n# 3. Orient it however you want it\n# 4. While keeping the 3D view active/visible, select the TechDraw\n#     Object/View from step 1.\n# 5. Run the macro.  This will automatically adjust the direction of\n#     techDraw object to match the 3D view.\n\n__Name__ = 'TechDraw View Set'\n__Comment__ = 'Set the parameters of the current view to correspond to the 3D Window'\n__Author__ = 'MechaMecca, galou_breizh'\n__Version__ = '0.1.0'\n__License__ = 'CC-BY-3.0'\n__Web__ = 'http://www.freecadweb.org/wiki/Macro_TechDrawViewSet'\n__Wiki__ = 'http://www.freecadweb.org/wiki/Macro_TechDrawViewSet'\n__Icon__ = ''\n__Help__ = 'Select a TechDraw View while staying in the 3D viewer, execute'\n__Status__ = 'Alpha'\n__Requires__ = ''\n__Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'\n__Files__ = ''\n\nimport freecad as fc\n\n\ndef set_view():\n    gui_doc = fc.gui.activeDocument()\n    if gui_doc is None:\n        fc.app.Console.PrintWarning('No active document\\n')\n        return\n\n    try:\n        cam_orientation = gui_doc.ActiveView.getCameraOrientation()\n    except AttributeError:\n        fc.app.Console.PrintWarning('The current tab is not a 3D view\\n')\n        return\n\n    if not fc.gui.Selection.getSelection():\n        fc.app.Console.PrintWarning('Nothing selected\\n')\n        return\n\n    view_dir = cam_orientation.multVec(fc.app.Vector(0, 0, 1))\n    for tech_view in fc.gui.Selection.getSelection():\n        try:\n            tech_view.Direction = view_dir\n        except AttributeError:\n            fc.app.Console.PrintMessage('\"{}\" is not a TechDraw View, ignoring\\n'.format(tech_view.Label))\n\nif __name__ == '__main__':\n    set_view()\n",
    "url": "http://www.freecadweb.org/wiki/Macro_TechDrawViewSet",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/Macro_TechDrawViewSet",
    "version": "0.1.0",
    "license": "",
    "date": "",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\TechDraw\\TechDrawViewSet.FCMacro",
    "filename_from_url": "",
    "author": "MechaMecca, galou_breizh",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "GroupSorting",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "The macro sorts the groups and pieces of a piece.\\nSelect groups with  key, and execute the macro.",
    "code": "# -*- coding: utf-8 -*-\n# (c) 18Turbo, 2022\n\n__Name__ = 'GroupSorting (Ordenaci\u00f3n)'\n__Comment__ = 'The macro sorts the groups and pieces of a piece.\\nSelect groups with <CTRL> key, and execute the macro.'\n__Author__ = '18Turbo'\n__Version__ = '0.1.0'\n__Date__ = '2022-10-04'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'https://github.com/18turbo/OrdenacionRapidaFreeCAD'\n__Wiki__ = 'https://github.com/18turbo/OrdenacionRapidaFreeCAD'\n__Icon__ = 'GroupSorting.svg'\n__Help__ = ''\n__Status__ = 'beta'\n__Requires__ = 'FreeCAD >= v0.20'\n__Contact__ = 'https://github.com/18turbo'\n__Communication__ = ''\n__Files__ = 'GroupSorting.svg'\n\n\n# (Spanish:)\n#\n# Autor:            18Turbo\n# Fecha Incial:     22-07-2022\n# Versi\u00f3n:          0.1.0 BETA\n#\n# Funcionalidad:   Ordena grupos seg\u00fan sean seleccionados.\n#\n# Notas Importantes:     hay que saber que los grupos sin padre tienen un orden espec\u00edfico en FreeCAD y no se pueden ordenar con este script\n#                   porque aunque se hace el proceso correcto, FreeCAD no permite la ordenaci\u00f3n de estos de una forma simple y escapa\n#                   a los prop\u00f3sitos de este script.\n#\n#\n# Notas de versiones:\n# v.0.1.0:        Adaptaci\u00f3n al Addon Manager\n# v.0.0.5:      Depurado para que funcione con grupos sin padre, es decir, con el documento como padre, aunque FreeCAD no lo permita. As\u00ed,\n#               si en una versi\u00f3n superior se permite, el script no hay que modificarlo.\n# v.0.0.4:      Versi\u00f3n Alfa funcional.\n#\n#\n#\n\nimport FreeCAD as app\nimport FreeCADGui as gui\n\ncIntro = '\\n'\n\nstrLang = [\n    [ # Espa\u00f1ol\n        ## Strings for translation into any language\n        \"Los grupos no tienen un padre y FreeCAD no permite la ordenaci\u00f3n en este nivel\",\n        \"Debes seleccionar Grupos con el mismo padre\",\n        \"Debes elegir m\u00e1s de un objeto\"\n\n    ],\n    [ # English\n        ## Strings for translation into any language (English Strings)\n        \"Groups do not have a parent and FreeCAD does not allow sorting at this level\",\n        \"You must select Groups with the same parent\",\n        \"You must choose more than one object\"\n\n    ]\n        ]\n\ndef tr(text):\n    # Translate\n    if (text not in strLang[0]) or (g_num_lang < 0) or (g_num_lang >= len(strLang)):\n        return text\n    primerIdioma = strLang[0]\n    indice = primerIdioma.index(text)\n    if (indice == -1) or (indice >= len(strLang[g_num_lang])):\n        return text\n    return strLang[g_num_lang][indice]\n\n\nlang = gui.getLocale()\n# Default to English.\ng_num_lang = 1\nif 'Spanish' in lang:\n    g_num_lang = 0\n#elif 'Italian' in lang:\n#    g_num_lang = 2\n\nobjetosSeleccionados = Gui.Selection.getSelection()\n\nif len(objetosSeleccionados) > 1:\n    # Comprobando que todos tienen el mismo padre, siempre que no partan de la ra\u00edz del documento\n    distintoPadre = False\n    padre = \"\"\n    if app.ActiveDocument.getObject(objetosSeleccionados[0].Name).InList: # Esto es que tiene padre\n        tienePadre = True\n        for objeto in objetosSeleccionados:\n            if (app.ActiveDocument.getObject(objeto.Name).InList[0].Name != padre):\n                if (padre == \"\"):\n                    padre = app.ActiveDocument.getObject(objeto.Name).InList[0].Name\n                else:\n                    distintoPadre = True\n                    break;\n    else:\n        tienePadre = False\n        for objeto in objetosSeleccionados:\n            if (app.ActiveDocument.getObject(objeto.Name).InList):\n                distintoPadre = True\n        app.Console.PrintWarning(tr(\"Los grupos no tienen un padre y FreeCAD no permite la ordenaci\u00f3n en este nivel\") + cIntro)\n\n    if not distintoPadre:\n        if tienePadre:\n            nombrePadre = app.ActiveDocument.getObject(objeto.Name).InList[0].Name\n\n        listaNombres = []\n        app.activeDocument().Tip = app.activeDocument().addObject('App::DocumentObjectGroup','GrupoAuxiliarOrdenacion')\n\n        for objetoA in objetosSeleccionados:\n            # Siempre que el objeto sea un grupo\n            if (objetoA.Name.find('Group') > -1) or (objetoA.Name.find('Part') > -1):\n                app.ActiveDocument.getObject(objetoA.Name).removeObject(app.ActiveDocument.getObject(objetoA.Name))\n                app.ActiveDocument.getObject(\"GroupAuxSorting18T\").addObject(app.ActiveDocument.getObject(objetoA.Name))\n                listaNombres.append(objetoA.Name)\n\n        for nombreObjeto in listaNombres:\n            app.ActiveDocument.getObject(\"GroupAuxSorting18T\").removeObject(app.ActiveDocument.getObject(nombreObjeto))\n            if tienePadre:\n                app.ActiveDocument.getObject(nombrePadre).addObject(app.ActiveDocument.getObject(nombreObjeto))\n\n        app.activeDocument().removeObject(\"GroupAuxSorting18T\")\n        app.activeDocument().recompute()\n    else:\n        app.Console.PrintWarning(tr(\"Debes seleccionar Grupos con el mismo padre\") + cIntro)\nelse:\n    app.Console.PrintWarning(tr(\"Debes elegir m\u00e1s de un objeto\") + cIntro)",
    "url": "https://github.com/18turbo/OrdenacionRapidaFreeCAD",
    "raw_code_url": "",
    "wiki": "https://github.com/18turbo/OrdenacionRapidaFreeCAD",
    "version": "0.1.0",
    "license": "",
    "date": "2022-10-04",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Utility\\GroupSorting.FCMacro",
    "filename_from_url": "",
    "author": "18Turbo",
    "icon": "GroupSorting.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "GroupSorting.svg"
    ],
    "parsed": true
  },
  {
    "name": "HighlightCommon",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Compute the common parts between selected shapes",
    "code": "# -*- coding: utf-8 -*-\n\nfrom __future__ import unicode_literals\n\n__Name__ = 'Highlight Common parts'\n__Comment__ = 'Compute the common parts between selected shapes'\n__Author__ = 'JMG, galou and other contributors'\n__Version__ = '2.3.2'\n__Date__ = '2021-07-01'\n__License__ = 'CC0-1.0'\n__Web__ = 'https://freecadweb.org/wiki/Macro_HighlightCommon'\n__Wiki__ = 'https://freecadweb.org/wiki/Macro_HighlightCommon'\n__Icon__ = 'HighlightCommon.png'\n__Help__ = 'Select at least two objects and run'\n__Status__ = 'Production'\n__Requires__ = 'FreeCAD V0.17+'\n__Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'\n__Files__ = 'HighlightCommon.png'\n\nfrom PySide.QtGui import QMessageBox  # FreeCAD's special PySide!\n\nimport FreeCAD as app\nimport FreeCADGui as gui\n\n\nPREFERENCE_PATH = 'User parameter:BaseApp/Preferences/Mod/HighlightCommon'\n\n\ndef load_and_save_settings():\n    param_change = 'change_transparency'\n    param_transparency = 'transparency'\n    p = app.ParamGet(PREFERENCE_PATH)\n    change_transparency = p.GetBool(param_change, True)\n    transparency = p.GetInt(param_transparency, 80)\n    p.SetBool(param_change, change_transparency)\n    p.SetInt(param_transparency, transparency)\n    return change_transparency, transparency\n\n\ndef main():\n    # Store active doc in case it may change during run.\n    doc = app.activeDocument()\n\n    if doc is None:\n        return\n\n    change_transparency, transparency = load_and_save_settings()\n\n    colli_grp = None  # Group object to group collisions.\n    colli_max = 0  # Maximum collision volume.\n\n    # Open a transaction in undo pile.\n    doc.openTransaction('Seeking collisions')\n\n    objectsToEnumerate = gui.Selection.getSelection()\n    if len(objectsToEnumerate) < 2:\n        objectsToEnumerate = doc.Objects\n\n    # Ensure list of unique objects.\n    object_list = []\n    for obj in objectsToEnumerate:\n        if ((obj not in object_list)\n                and hasattr(obj, 'Shape')\n                and hasattr(obj, 'getGlobalPlacement')\n                and hasattr(obj, 'Label')):\n            object_list.append(obj)\n\n    # Going through selected objects (object A).\n    for i, object_a in enumerate(object_list):\n        shape_a = object_a.Shape.copy()\n        shape_a.Placement = object_a.getGlobalPlacement()\n        label_a = object_a.Label\n\n        # Making selected objects transparent.\n        if change_transparency:\n            try:\n                object_a.ViewObject.Transparency = transparency\n            except AttributeError:\n                pass\n\n        # Comparing object A with all\n        # following ones in the list (object B).\n        for object_b in object_list[(i + 1):]:\n\n            shape_b = object_b.Shape.copy()\n            shape_b.Placement = object_b.getGlobalPlacement()\n            label_b = object_b.Label\n            common = shape_a.common(shape_b)\n\n            # Making selected objects transparent.\n            if change_transparency:\n                try:\n                    object_b.ViewObject.Transparency = transparency\n                except AttributeError:\n                    pass\n\n            # If object A & object B have a collision\n            # display a message with collision volume and\n            # add a new representative shape in the group.\n            if common.Volume > 1e-6:\n                app.Console.PrintMessage(\n                    'Volume of the intersection between {} and {}: {:.3f} mm\u00b3\\n'.format(\n                        label_a,\n                        label_b,\n                        common.Volume))\n                colli_max = common.Volume if common.Volume > colli_max else colli_max\n                if not colli_grp:\n                    # Create group if it doesn't already exist.\n                    colli_grp = doc.addObject('App::DocumentObjectGroup',\n                                              'Collisions')\n                intersection_object = doc.addObject(\n                    'Part::Feature')\n                intersection_object.Label = '{} - {}'.format(\n                    label_a, label_b)\n                intersection_object.Shape = common\n                intersection_object.ViewObject.ShapeColor = (1.0, 0.0, 0.0, 1.0)\n                colli_grp.addObject(intersection_object)\n            else:\n                # If no collision, just inform the user.\n                app.Console.PrintMessage(\n                    'No intersection between {} and {}\\n'.format(\n                        label_a,\n                        label_b))\n\n    # If collisions have been found, commit the undo transaction and\n    # give a summary (count + max value) to the user.\n    if colli_grp:\n        doc.commitTransaction()\n        app.Console.PrintMessage(\n            '{} collision(s) found between selected objects\\nMaximum collision: {:.3f} mm\u00b3\\n'.format(\n                len(colli_grp.Group),\n                colli_max))\n        doc.recompute()\n    else:\n        # If no collision has been found, just inform the user about it.\n        doc.abortTransaction()\n        if len(object_list) >= 2:\n            app.Console.PrintWarning('No collision found between selected objects\\n')\n        else:\n            app.Console.PrintWarning('No suitable objects selected, select at least two objects\\n')\n\n\nif __name__ == '__main__':\n    main()\n",
    "url": "https://freecadweb.org/wiki/Macro_HighlightCommon",
    "raw_code_url": "",
    "wiki": "https://freecadweb.org/wiki/Macro_HighlightCommon",
    "version": "2.3.2",
    "license": "",
    "date": "2021-07-01",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Utility\\HighlightCommon.FCMacro",
    "filename_from_url": "",
    "author": "JMG, galou and other contributors",
    "icon": "HighlightCommon.png",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "HighlightCommon.png"
    ],
    "parsed": true
  },
  {
    "name": "HighlightDifference",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Compute the difference between two shapes",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"\nCompute the difference between two shapes. Additions are marked red, removals\nare marked green. Both original parts will be half transparent. The volume of\nthe additions and removals are printed in the console.\n\"\"\"\n\nfrom __future__ import unicode_literals\n\n__Name__ = 'Highlight Difference'\n__Comment__ = 'Compute the difference between two shapes'\n__Author__ = 'galou and other contributors'\n__Version__ = '2.2.0'\n__Date__ = '2021-07-01'\n__License__ = 'CC0-1.0'\n__Web__ = 'https://freecadweb.org/wiki/Macro_HighlightDifference'\n__Wiki__ = 'https://freecadweb.org/wiki/Macro_HighlightDifference'\n__Icon__ = 'HighlightDifference.svg'\n__Help__ = 'Select two objects and run'\n__Status__ = 'Production'\n__Requires__ = 'FreeCAD V0.17+'\n__Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'\n__Files__ = 'HighlightDifference.svg'\n\nfrom PySide import QtCore  # FreeCAD's special PySide!\nfrom PySide.QtGui import QMessageBox  # FreeCAD's special PySide!\n\nimport FreeCAD as app\nimport FreeCADGui as gui\n\n\nPREFERENCE_PATH = 'User parameter:BaseApp/Preferences/Mod/HighlightDifference'\n\n\ndef error_dialog(msg):\n    \"\"\"Create a simple dialog QMessageBox with an error message.\"\"\"\n    app.Console.PrintError(msg + '\\n')\n    diag = QMessageBox(QMessageBox.Icon.Critical,\n                       'Error in macro highlight_difference',\n                       msg)\n    diag.setWindowModality(QtCore.Qt.ApplicationModal)\n    diag.exec_()\n\n\ndef load_and_save_settings():\n    param_change = 'change_transparency'\n    param_transparency = 'transparency'\n    p = app.ParamGet(PREFERENCE_PATH)\n    change_transparency = p.GetBool(param_change, True)\n    transparency = p.GetInt(param_transparency, 80)\n    p.SetBool(param_change, change_transparency)\n    p.SetInt(param_transparency, transparency)\n    return change_transparency, transparency\n\n\ndef main():\n    if len(gui.Selection.getSelection()) < 2:\n        error_dialog('Select two objects')\n        return\n\n    object_a = gui.Selection.getSelection()[0]\n    object_b = gui.Selection.getSelection()[1]\n    try:\n        shape_a = object_a.Shape\n        shape_b = object_b.Shape\n        label_a = object_a.Label\n        label_b = object_b.Label\n    except AttributeError:\n        error_dialog('No suitable objects selected, select two objects\\n')\n        return\n\n    shape_addition = shape_a.cut(shape_b)\n    if shape_addition.Volume < 1e-6:\n        app.Console.PrintMessage('No addition from {} to {}\\n'.format(\n            label_a, label_b))\n    else:\n        app.Console.PrintMessage(\n            'Volume of the addition from {} to {}: {}\\n'.format(\n                label_a, label_b, shape_addition.Volume))\n\n    shape_removal = shape_b.cut(shape_a)\n    if shape_removal.Volume < 1e-6:\n        app.Console.PrintMessage('No removal from {} to {}\\n'.format(\n            label_a, label_b))\n    else:\n        app.Console.PrintMessage(\n            'Volume of the removal from {} to {}: {}\\n'.format(\n                label_a, label_b, shape_removal.Volume))\n\n    if (shape_addition.Volume < 1e-6) and (shape_removal.Volume < 1e-6):\n        app.Console.PrintMessage('{} and {} have the same shape\\n'.format(\n            label_a, label_b))\n\n    added = app.ActiveDocument.addObject('Part::Feature')\n    added.Label = 'Addition ({} \u2212 {})'.format(label_a, label_b)\n    added.Shape = shape_addition\n    added.ViewObject.ShapeColor = (1.0, 0.0, 0.0, 1.0)\n    removed = app.ActiveDocument.addObject('Part::Feature')\n    removed.Label = 'Removal ({} \u2212 {})'.format(label_b, label_a)\n    removed.Shape = shape_removal\n    removed.ViewObject.ShapeColor = (0.0, 0.5, 0.0, 1.0)\n\n    change_transparency, transparency = load_and_save_settings()\n    if change_transparency:\n        try:\n            object_a.ViewObject.Transparency = transparency\n            object_b.ViewObject.Transparency = transparency\n        except AttributeError:\n            pass\n\n\nif __name__ == '__main__':\n    main()\n",
    "url": "https://freecadweb.org/wiki/Macro_HighlightDifference",
    "raw_code_url": "",
    "wiki": "https://freecadweb.org/wiki/Macro_HighlightDifference",
    "version": "2.2.0",
    "license": "",
    "date": "2021-07-01",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Utility\\HighlightDifference.FCMacro",
    "filename_from_url": "",
    "author": "galou and other contributors",
    "icon": "HighlightDifference.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "HighlightDifference.svg"
    ],
    "parsed": true
  },
  {
    "name": "MessageBox",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Show how to give information to the user in macros",
    "code": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\n\n__Name__ = 'Message Box'\n__Comment__ = 'Show how to give information to the user in macros'\n__Web__ = 'http://freecadweb.org/wiki/Macro_MessageBox'\n__Wiki__ = 'http://freecadweb.org/wiki/Macro_MessageBox'\n__Icon__ = \"\"\n__Help__ = 'Run and be warned'\n__Author__ = 'galou, Mario52 and other contributors'\n__Version__ = 1.0\n__Status__ = 'Production'\n__Requires__ = ''\n\nfrom PySide import QtCore, QtGui\n\n\ndef errorDialog(msg):\n    \"\"\"Create a simple dialog QMessageBox\"\"\"\n    # The first argument indicates the icon used: one of\n    # QtGui.QMessageBox.{NoIcon, Information, Warning, Critical, Question}\n    diag = QtGui.QMessageBox(QtGui.QMessageBox.Warning,\n                             u'Warning in macro MessageBox', msg)\n    diag.setWindowModality(QtCore.Qt.ApplicationModal)\n    diag.exec_()\n\n# To display multiple lines in a dialog box Qt, '\\n' can be added between\n# lines. '\\t' inserts a tab. The backslash is a then a special character which\n# must be escaped, i.e. insert '\\\\' to display a backslash. Single quotes must\n# also be escaped in a single-quote-delimited string and double-quotes in a\n# double-quote-delimited string. See Python doc for details.\nmsg = 'Example of warning message\\nYou should\\'t have done this.'\nerrorDialog(msg)\nraise(Exception(msg))\n",
    "url": "http://freecadweb.org/wiki/Macro_MessageBox",
    "raw_code_url": "",
    "wiki": "http://freecadweb.org/wiki/Macro_MessageBox",
    "version": "1.0",
    "license": "",
    "date": "",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Utility\\MessageBox.FCMacro",
    "filename_from_url": "",
    "author": "galou, Mario52 and other contributors",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "pcbway",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "",
    "code": "#***************************************************************************\n#*                                                                         *\n#*   Copyright (c) 2022 Yorik van Havre <yorik@uncreated.net>              *\n#*                                                                         *\n#*   This program is free software; you can redistribute it and/or modify  *\n#*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n#*   as published by the Free Software Foundation; either version 2 of     *\n#*   the License, or (at your option) any later version.                   *\n#*   for detail see the LICENCE text file.                                 *\n#*                                                                         *\n#*   This program is distributed in the hope that it will be useful,       *\n#*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n#*   GNU Library General Public License for more details.                  *\n#*                                                                         *\n#*   You should have received a copy of the GNU Library General Public     *\n#*   License along with this program; if not, write to the Free Software   *\n#*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n#*   USA                                                                   *\n#*                                                                         *\n#***************************************************************************\n\n\"\"\"\nPCBWay Macro for FreeCAD\n\nhttps://pcbway.com\n\nThis macro sends the currently selected object to the PCBWay website\nto get an instant quote for manufacturing. After the object is sent,\na page will be opened on the PCBWay website to allow the user to adjust\ndetails and options.\n\"\"\"\n\n# code inspired / borrowed from:\n# KiCAD PcbWay plugin: https://github.com/pcbway/PCBWay-Plug-in-for-Kicad/blob/main/plugins/thread.py\n# urllib-based upload: http://pymotw.com/2/urllib2/#uploading-files\n# mime stuff: https://stackoverflow.com/questions/27099290/where-is-mimetools-choose-boundary-function-in-python3#27174474\n\n# version history:\n# version 1.0 - 2022.07.22\n\n__title__   = \"Macro_PCBWay\"\n__author__  = \"Yorik van Havre\"\n__wiki__    = \"https://www.freecad.org/wiki/Macro_PCBWay\"\n__url__     = \"https://www.pcbway.com\"\n__version__ = \"1.0\"\n__date__    = \"22/07/2022\"\n\n\nimport tempfile\nimport os\nimport FreeCAD\nimport FreeCADGui\nimport json\nimport webbrowser\nimport urllib.request\nimport urllib.parse\nimport email.generator\nimport itertools\n\n\npcb_url = \"https://www.pcbway.com/common/freecadupfile\"\n\n\ndef msg(message):\n\n    \"\"\"prints a message where appropriate\"\"\"\n\n    FreeCAD.Console.PrintError(message+\"\\n\")\n    if FreeCAD.GuiUp:\n        from PySide import QtGui\n        reply = QtGui.QMessageBox.critical(None,\"PCBWay export\",message)\n\n\nclass MultiPartData(object):\n\n    \"\"\"Gathers data and files to be sent via HTTP POST\"\"\"\n\n    def __init__(self):\n        self.form_fields = []\n        self.files = []\n        self.boundary = email.generator._make_boundary()\n        self.add_field(\"Unit\",\"Millimeter\") #FreeCAD's boundboxes are always in mm\n        return\n\n    def get_content_type(self):\n        return 'multipart/form-data; boundary=%s' % self.boundary\n\n    def add_field(self, name, value):\n        \"\"\"Add a simple field to the form data.\"\"\"\n        self.form_fields.append((name, str(value)))\n        return\n\n    def add_file(self, fieldname, filename, fileHandle, mime):\n        \"\"\"Add a file to be uploaded.\"\"\"\n        body = fileHandle.read()\n        self.files.append((fieldname, filename, mime, body))\n        return\n\n    def get_bytes(self):\n        \"\"\"Return a string representing the form data, including attached files.\"\"\"\n        parts = []\n        part_boundary = '--' + self.boundary\n        parts.extend([part_boundary,'Content-Disposition: form-data; name=\"%s\"' % name,'',value] for name, value in self.form_fields)\n        parts.extend([part_boundary,'Content-Disposition: file; name=\"%s\"; filename=\"%s\"' % (field_name, filename),\n                                    'Content-Type: %s' % content_type,'',body] for field_name, filename, content_type, body in self.files)\n        flattened = list(itertools.chain(*parts))\n        flattened.append('--' + self.boundary + '--')\n        flattened.append('')\n        return bytes('\\r\\n'.join(flattened),'utf8')\n\n\ndef main():\n\n    # validity tests\n    mesh = None\n    shape = None\n    if not FreeCAD.GuiUp:\n        return\n    if not FreeCAD.ActiveDocument:\n        msg(\"There is no opened document. Please open or create a document containing objects before running this macro.\")\n        return\n    # get the selected object, or the only visible body or object if nothing is selected\n    selection = FreeCADGui.Selection.getSelection()\n    if not selection:\n        visibles = [obj for obj in FreeCAD.ActiveDocument.Objects if obj.ViewObject.Visibility]\n        if len(visibles) == 1:\n            obj = visibles[0]\n            if hasattr(obj,\"Shape\"):\n                shape = obj.Shape\n            elif hasattr(obj,\"Mesh\"):\n                mesh = obj.Mesh\n        elif len(visibles) > 1:\n            bodies = [obj for obj in visibles if obj.isDerivedFrom(\"PartDesign::Body\")]\n            if len(bodies) == 1:\n                shape = bodies[0].Shape\n            else:\n                msg(\"No object is selected. Please select one object or body before running this macro.\")\n                return\n    elif len(selection) > 1:\n        msg(\"More than one object is selected. Please select only one object or body before running this macro.\")\n        return\n    else:\n        obj = selection[0]\n        if hasattr(obj,\"Shape\"):\n            shape = obj.Shape\n            if (not shape) or (not hasattr(shape,\"isNull\")) or shape.isNull():\n                msg(\"The selected object has no shape. Please select an object with a shape before running this macro.\")\n                return\n        elif hasattr(obj,\"Mesh\"):\n            mesh = obj.Mesh\n    if (not shape) and (not mesh):\n        msg(\"Unable to find a suitable shape in the selection or in the visible objects. Please select an object before running this macro.\")\n        return\n\n    # offer to add the macro as a button on first run\n    # not working yet!\n    # prefs = FreeCAD.ParamGet(\"User parameter:Plugins/PCBWay\")\n    # if prefs.GetBool(\"FirstTime\",True):\n    #    prefs.SetBool(\"FirstTime\",False)\n    #    from PySide import QtGui\n    #    reply = QtGui.QMessageBox.question(None, \"Install macro?\",\n    #        \"This is the first time you are launching the PCBWay macro. Do you wish to add a toolbar button for it?\",\n    #        QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)\n    #    if reply == QtGui.QMessageBox.Yes:\n    #        icon = \"https://github.com/pcbway/PCBWay-Plug-in-for-Kicad/raw/main/resources/icon.png\"\n    #        u = urllib.request.urlopen(icon)\n    #        idata = u.read()\n    #        u.close()\n    #        idir = os.path.join(FreeCAD.getUserAppDataDir(),\"icons\")\n    #        os.makedirs(idir,exist_ok=False)\n    #        f = open(os.path.join(idir,\"pcbway.png\"),\"wb\")\n    #        f.write(idata)\n    #        f.close()\n\n    if shape:\n        # saving the file as step\n        tf = tempfile.NamedTemporaryFile(suffix=\".stp\")\n        tf.close()\n        shape.exportStep(tf.name)\n        bb = shape.BoundBox\n        mime = \"application/STEP\"\n    elif mesh:\n        # saving the file as step\n        tf = tempfile.NamedTemporaryFile(suffix=\".obj\")\n        tf.close()\n        mesh.write(tf.name)\n        bb = mesh.BoundBox\n        mime = \"model/obj\"\n\n    # prepare and upload data\n    data = MultiPartData()\n    data.add_field('Length', bb.XLength)\n    data.add_field('Width',  bb.YLength)\n    data.add_field('Height', bb.ZLength)\n    data.add_file('upload[file]', os.path.basename(tf.name), open(tf.name,'r'), mime)\n    request = urllib.request.Request(pcb_url)\n    request.add_header('User-agent', 'FreeCAD (https://freecad.org)')\n    body = data.get_bytes()\n    request.add_header('Content-type', data.get_content_type())\n    request.add_header('Content-length', len(body))\n    rsp = urllib.request.urlopen(request,data=body).read()\n    rsp_link = json.loads(rsp.decode('utf8'))['redirect']\n\n    # get the respnse and open a link\n    webbrowser.open(rsp_link)\n\n\n\n# run when macro is launched\nmain()\n\n",
    "url": "",
    "raw_code_url": "",
    "wiki": "https://www.freecad.org/wiki/Macro_PCBWay",
    "version": "1.0",
    "license": "",
    "date": "22/07/2022",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Utility\\pcbway.FCMacro",
    "filename_from_url": "",
    "author": "Yorik van Havre",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "PiecesTemplates",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Create a structured pieces (PiecesTemplates)\\nCreador de estructuras de piezas",
    "code": "# -*- coding: utf-8 -*-\n# (c) 18Turbo, 2022\n\n__Name__ = 'PiecesTemplates'\n__Comment__ = 'Create a structured pieces (PiecesTemplates)\\nCreador de estructuras de piezas'\n__Author__ = '18Turbo'\n__Version__ = '1.4.1'\n__Date__ = '2022-10-06'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'https://github.com/18turbo/PlantillaPiezaFreeCAD'\n__Wiki__ = 'https://github.com/18turbo/PlantillaPiezaFreeCAD'\n__Icon__ = 'PiecesTemplates.svg'\n__Help__ = ''\n__Status__ = 'beta'\n__Requires__ = 'FreeCAD >= v0.20'\n__Contact__ = 'https://github.com/18turbo'\n__Communication__ = ''\n__Files__ = 'PiecesTemplates.svg,/PiecesTemplates/ui/PiecesTemplates.ui,/PiecesTemplates/Groups.txt'\n\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nfrom PySide import QtCore, QtGui\nfrom PySide2.QtWidgets import *\nimport re\n\n# (Spanish):\n#\n# Autor:            18Turbo\n# Fecha Inicial:    1-07-2022\n# Versi\u00f3n:      1.4.1\n#\n# Funcionalidad:    Crea una estructura de una pieza con una serie de subcarpetas dentro con varios nombres\n#\n# Descripci\u00f3n:  Al pinchar la macro (o el bot\u00f3n en la barra de herramientas), su comportamiento siempre es la de crear una pieza\n#               con una serie de directorios (grupos) dentro (que lo define el array del principio de la macro). El nombre de la pieza se le da\n#                a trav\u00e9s de una ventana.\n#\n# Modificaciones del Usuario:\n#               Al cambiar \"listaGrupos\" en la l\u00ednea de c\u00f3digo con las cadenas que uno desee, se crean el n\u00famero de directorios\n#               (grupos) con el nombre de cada elemento de la lista. Es completamente MODIFICABLE. Si listaGrupos fuese\n#               listaGrupos = ['AA',BB'], siempre crear\u00eda dos directorios dentro de la pieza, uno con el nombre AA y otro con el nombre BB.\n#\n# Notas de versiones:\n# v.1.4.1:        Corregido error en la posici\u00f3n al a\u00f1adir un grupo\n# v.1.4.0:        Adaptaci\u00f3n inicial al Addon Manager\n#                Cambio de la ventana a la pesta\u00f1a de tareas\n#                M\u00faltiples Piezas de una vez\n#                Checkbox \"ilimitados\"\n#                Resumen de piezas creadas de una vez (n\u00famero y nombre)\n#                Imposibilidad de crear nombre de Pieza de nombre vac\u00edo, ya que el nombre gen\u00e9rico puede generar algunas confusiones\n#                Scroll en los checkboxes\n# v.1.3.0:      Ahora al pulsar <Return> tras introducir el nombre, crea la pieza con la estructura que hay seleccionada\n#               Se aumenta la capacidad visual de los checkbox a 7\n#               Correcci\u00f3n de errores\n# v.1.2.0:      Se implementa una caja de informaci\u00f3n para indicar al usuario c\u00f3mo cambiar los nombres de los grupos (idea\n#                   de Rafael Garc\u00eda Rodr\u00edguez)\n#               Se crean unos checkbox por defecto para marcar los directorios que se quieren crear\n# v.1.0.0       Creada ventana donde pide el nombre de la pieza\n# v.0.9.8:      Inicial candidata.\n#\n#\n# Agradecimientos:\n#        - Hugo Sala Sala: por la traducci\u00f3n al ingl\u00e9s del script\n#        - Rocco Vicedomini: por la traducci\u00f3n al italiano del script\n#\n\n\nlistGroups = []\nelementosBorrados = []\nmaxElem = 12\ncIntro = '\\n'\n\nstrLang = [\n    [ # Espa\u00f1ol\n        ## Strings for translation into any language\n        \"Creador de Estructuras de Piezas\",\n        \"El documento no est\u00e1 activo\",\n        \"Creaci\u00f3n de Piezas\",\n        \"Nombre de la Pieza:\",\n        \"Informaci\u00f3n de Uso\",\n        \"Grupos/Directorios a crear:\",\n        \"Crear Estructura de Pieza\",\n        \"Versi\u00f3n:\",\n        \"Descripci\u00f3n:\",\n        \"Informaci\u00f3n\",\n        \"Este script (macro) genera una estructura de grupos (directorios) en una pieza, de manera que sea m\u00e1s f\u00e1cil organizar las distintas operaciones,referencias y objetos de esa pieza.\",\n        \"Los grupos inicialmente est\u00e1n predefinidos, pero pueden ser cambiados f\u00e1cilmente.\",\n        \"Operaciones sobre Grupos\",\n        \"A\u00f1adir Grupo\",\n        \"Eliminar Grupo\",\n        \"el primero\",\n        \"el \u00faltimo\",\n        \"Listado Piezas Creadas:\",\n        \"N\u00ba de Piezas Creadas:\"\n\n    ],\n    [ # English\n        ## Strings for translation into any language (English Strings)\n        \"Part Template Creator\",\n        \"The document is not active\",\n        \"Creation of Parts\",\n        \"Part Name:\",\n        \"Usage Information:\",\n        \"Groups/Directories to create:\",\n        \"Create Part Structure\",\n        \"Version:\",\n        \"Description:\",\n        \"Information\",\n        \"This script (macro) generates a structure of groups (directories) in a part, so that it is easier to organize the different operations, references, and objects of that part.\",\n        \"The groups are initially predefined, but can be easily changed.\",\n        \"Operations on Groups\",\n        \"Add Group\",\n        \"Delete Group\",\n        \"first\",\n        \"the last\",\n        \"List Pieces Created:\",\n        \"Number of Pieces Created:\"\n\n    ],\n    [ # Italiano\n        ## Strings for translation into any language (Italian strings)\n        \"Creatore di strutture delle Parti\",\n        \"Il documento non \u00e8 attivo\",\n        \"Creazione delle Parti\",\n        \"Nome della Parte:\",\n        \"Informazioni per l'uso:\",\n        \"Gruppi/Cartelle da creare:\",\n        \"Crea la struttura della Parte\",\n        \"Versione:\",\n        \"Descrizione:\",\n        \"Informazioni\",\n        \"Questo script (macro) genera una struttura di gruppi (cartelle) in una nuova parte, in modo che sia pi\u00f9 semplice organizzare le varie operazioni, i riferimenti e gli elementi di questa parte.\",\n        \"I gruppi inizialmente risultano predefiniti, per\u00f2 si possono modificare facilmente.\",\n        \"Operazioni sui Gruppi\",\n        \"Aggiungi Gruppo\",\n        \"Elimina Gruppo\",\n        \"per primo\",\n        \"per ultimo\",\n        \"Lista delle parti create:\",\n        \"N\u00ba di parti create:\"\n    ]\n        ]\n\nui_path = app.getUserMacroDir(True) + \"/PiecesTemplates/ui/PiecesTemplates.ui\"\ngr_path = app.getUserMacroDir(True) + \"/PiecesTemplates/Groups.txt\"\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\nclass PiecesTemplates:\n\n    def __init__(self):\n        self.doc = app.activeDocument()\n        if not self.doc:\n            app.Console.PrintWarning(tr('El documento no est\u00e1 activo') + cIntro)\n            return\n\n        # Init var\n        self.form = gui.PySideUic.loadUi(ui_path)\n        self.numeroPiezas = 0\n        self.pieza = \"\"\n        self.form.botonCrear.setEnabled(False)\n\n        # Open File \"Groups.txt\"\n        self.openF()\n\n        # Init UI with content\n        self.mostrarCheckbox()\n        self.initStrings()\n\n        # Connect\n        self.form.botonCrear.clicked.connect(self.createPart)\n        self.form.edicionNombrePieza.returnPressed.connect(self.createPart)\n        self.form.edicionNombrePieza.textChanged.connect(self.nombrePiezaCambia)\n        self.form.botonAyuda.clicked.connect(self.mostrarHelp)\n        self.form.eliminarGrupo.clicked.connect(self.on_eliminarGrupo_clicked)\n        self.form.anadirGrupo.clicked.connect(self.on_anadirGrupo_clicked)\n\n    def openF(self):\n        with open(gr_path, \"r\") as groupsFile:\n            for linea in groupsFile.readlines():\n                linea = re.sub(\"\\n\",\"\",linea)\n                if (linea != \"\"):\n                    listGroups.append(linea)\n                    self.form.comboEliminarGrupo.addItem(linea)\n        if (len(listGroups) > maxElem):\n            etError1 = __Name__ + \"(Error)\"\n            error1 = \"En el archivo de texto hay m\u00e1s l\u00edneas de las permitidas.\" + \" \"\n            error1 += \"El m\u00e1ximo es: \" + str(maxElem) + cIntro + cIntro\n            error1 += \"Se aconseja cancelar y corregir el archivo de texto:\" + cIntro + cIntro\n            error1 += gr_path + cIntro + cIntro\n            reply = QtGui.QMessageBox.warning(None,etError1,error1)\n        self.longitudListaGrupos = len(listGroups)\n\n    def translate(self, text):\n        if (text not in strLang[0]) or (g_num_lang < 0) or (g_num_lang >= len(strLang)):\n            return text\n        primerIdioma = strLang[0]\n        indice = primerIdioma.index(text)\n        if (indice == -1) or (indice >= len(strLang[g_num_lang])):\n            return text\n        return strLang[g_num_lang][indice]\n\n    def activarUnCheckbox(self,cad,cont):\n        cad.setText(listGroups[cont])\n        cad.setEnabled(True)\n        cad.setChecked(True)\n\n    def mostrarCheckbox(self):\n        self.initCheckbox()\n        max = self.longitudListaGrupos\n        if max!=0:\n            if max>=1: self.activarUnCheckbox(self.form.cb1,0)\n            if max>=2: self.activarUnCheckbox(self.form.cb2,1)\n            if max>=3: self.activarUnCheckbox(self.form.cb3,2)\n            if max>=4: self.activarUnCheckbox(self.form.cb4,3)\n            if max>=5: self.activarUnCheckbox(self.form.cb5,4)\n            if max>=6: self.activarUnCheckbox(self.form.cb6,5)\n            if max>=7: self.activarUnCheckbox(self.form.cb7,6)\n            if max>=8: self.activarUnCheckbox(self.form.cb8,7)\n            if max>=9: self.activarUnCheckbox(self.form.cb9,8)\n            if max>=10: self.activarUnCheckbox(self.form.cb10,9)\n            if max>=11: self.activarUnCheckbox(self.form.cb11,10)\n            if max>=12: self.activarUnCheckbox(self.form.cb12,11)\n\n    def unCheckbox(self,cad):\n        cad.setText(self.translate(\"(Vac\u00edo)\"))\n        cad.setEnabled(False)\n        cad.setChecked(False)\n\n    def initCheckbox(self):\n        self.unCheckbox(self.form.cb1)\n        self.unCheckbox(self.form.cb2)\n        self.unCheckbox(self.form.cb3)\n        self.unCheckbox(self.form.cb4)\n        self.unCheckbox(self.form.cb5)\n        self.unCheckbox(self.form.cb6)\n        self.unCheckbox(self.form.cb7)\n        self.unCheckbox(self.form.cb8)\n        self.unCheckbox(self.form.cb9)\n        self.unCheckbox(self.form.cb10)\n        self.unCheckbox(self.form.cb11)\n        self.unCheckbox(self.form.cb12)\n\n    def mostrarComboGroups(self):\n        self.form.comboEliminarGrupo.clear()\n        for cont in range(self.longitudListaGrupos):\n            self.form.comboEliminarGrupo.addItem(listGroups[cont])\n\n    def initStrings(self):\n        tr = self.translate\n        if g_num_lang != 1:\n            title = \"(\" + strLang[g_num_lang][0] + \")\"\n        else:\n            title = \"\"\n        self.form.setWindowTitle(__Name__ + \" \" + title)\n        self.form.grupoPrincipal.setTitle(tr(\"Creaci\u00f3n de Piezas\"))\n        self.form.etNombrePieza.setText(tr(\"Nombre de la Pieza:\"))\n        self.form.botonAyuda.setToolTip(tr(\"Informaci\u00f3n de Uso\"))\n        self.form.edicionNombrePieza.setText(tr(\"\"))\n        self.form.etGrupo.setText(tr(\"Grupos/Directorios a crear:\"))\n        self.form.botonCrear.setText(tr(\"Crear Estructura de Pieza\"))\n        self.form.etVersion.setText(tr(\"Versi\u00f3n:\"))\n        self.form.version.setText(__Version__)\n        self.form.tipoVersion.setText(__Status__)\n        self.form.infoPiezasCreadas.setText(\"\")\n        self.form.etPiezasCreadas.setText(tr(\"Listado Piezas Creadas:\"))\n        self.form.numPiezasCreadas.setText(tr(\"N\u00ba de Piezas Creadas:\"))\n        self.form.grupoOperaciones.setTitle(tr(\"Operaciones sobre Grupos\"))\n        self.form.anadirGrupo.setText(tr(\"A\u00f1adir Grupo\"))\n        self.posGroup()\n        self.form.eliminarGrupo.setText(tr(\"Eliminar Grupo\"))\n        self.form.etPiezasCreadas.setEnabled(False)\n        self.form.numPiezas.setEnabled(False)\n\n    def mostrarHelp(self):\n        tr = self.translate\n        titleMH = tr(\"Informaci\u00f3n\") + \" (\" + __Name__ + \")\"\n        stringMH = tr(\"Este script (macro) genera una estructura de grupos (directorios) en una pieza, de manera que sea m\u00e1s f\u00e1cil organizar las distintas operaciones,referencias y objetos de esa pieza.\")\n        stringMH += cIntro + cIntro + tr(\"Los grupos inicialmente est\u00e1n predefinidos, pero pueden ser cambiados f\u00e1cilmente.\")\n        reply = QtGui.QMessageBox.information(None,titleMH,stringMH)\n\n    def posGroup(self):\n        tr = self.translate\n        self.form.comboPosicionGrupo.clear()\n\n        if (self.longitudListaGrupos == 0):\n            self.form.comboPosicionGrupo.addItem(tr(\"el primero\"))\n            self.form.eliminarGrupo.setEnabled(False)\n        else:\n            max = self.longitudListaGrupos\n            for cont in range(max):\n                if cont == 0:\n                    self.form.comboPosicionGrupo.addItem(tr(\"el primero\"))\n                if (cont !=0) and (cont < max):\n                    self.form.comboPosicionGrupo.addItem(str(cont+1))\n                if (cont == max-1):\n                    self.form.comboPosicionGrupo.addItem(tr(\"el \u00faltimo\"))\n\n    def nombrePiezaCambia(self):\n        if (self.form.edicionNombrePieza.text() != ''):\n            self.form.botonCrear.setEnabled(True)\n        else:\n            self.form.botonCrear.setEnabled(False)\n\n    def on_eliminarGrupo_clicked(self):\n        # Delete Group\n        aBorrar = self.form.comboEliminarGrupo.currentText()\n        listGroups.remove(aBorrar)\n        elementosBorrados.append(aBorrar)\n        self.longitudListaGrupos = len(listGroups)\n        self.mostrarCheckbox()\n        self.refreshFichero()\n\n    def on_anadirGrupo_clicked(self):\n        # Add Group\n        nombrePos = self.form.comboPosicionGrupo.currentText()\n        if (nombrePos == \"el primero\"):\n            posicion = 1\n        elif (nombrePos == \"el \u00faltimo\"):\n            posicion = self.longitudListaGrupos+1\n        else:\n            posicion = int(self.form.comboPosicionGrupo.currentText())\n        if self.longitudListaGrupos == 0:\n            listGroups.append(self.form.leAnadirGrupo.text())\n        else:\n            listGroups.insert(posicion-1,self.form.leAnadirGrupo.text())\n        self.longitudListaGrupos = len(listGroups)\n\n        self.mostrarCheckbox()\n        self.refreshFichero()\n        self.form.eliminarGrupo.setEnabled(True)\n\n    def refreshFichero(self):\n        # Refresh File (destroy and create the same file)\n        groupsFile = open(gr_path, \"w\")\n        for cont in range(self.longitudListaGrupos):\n            groupsFile.write(listGroups[cont]+\"\\n\")\n        groupsFile.close()\n\n        self.posGroup()\n        self.mostrarCheckbox()\n        self.mostrarComboGroups()\n        self.form.leAnadirGrupo.setText(\"\")\n\n    def createPart(self):\n        # Create one piece with groups\n        self.nombrePieza = self.form.edicionNombrePieza.text()\n        App.activeDocument().Tip = App.activeDocument().addObject('App::Part','Part')\n        App.ActiveDocument.recompute()\n\n        listaChecked = []\n        if self.longitudListaGrupos < maxElem:\n            longChecked = maxElem\n        else:\n            longChecked = self.longitudListaGrupos\n        for cont in range(longChecked):\n            listaChecked.append(True)\n\n        for nombrePart in FreeCAD.ActiveDocument.Objects:\n            if nombrePart.Name.find('Part') > -1:\n                nombrePartUltimo = nombrePart.Name\n        App.activeDocument().getObject(nombrePartUltimo).Label = self.nombrePieza\n\n        listaChecked[0] = self.form.cb1.isChecked()\n        listaChecked[1] = self.form.cb2.isChecked()\n        listaChecked[2] = self.form.cb3.isChecked()\n        listaChecked[3] = self.form.cb4.isChecked()\n        listaChecked[4] = self.form.cb5.isChecked()\n        listaChecked[5] = self.form.cb6.isChecked()\n        listaChecked[6] = self.form.cb7.isChecked()\n        listaChecked[7] = self.form.cb8.isChecked()\n        listaChecked[8] = self.form.cb9.isChecked()\n        listaChecked[9] = self.form.cb10.isChecked()\n        listaChecked[10] = self.form.cb11.isChecked()\n        listaChecked[11] = self.form.cb12.isChecked()\n\n        App.Console.PrintMessage(listaChecked)\n        contador = 0\n        for labelGrupo in listGroups:\n            if (listaChecked[contador] and contador<maxElem):\n                App.activeDocument().Tip = App.activeDocument().addObject('App::DocumentObjectGroup','Group')\n                nombreGrupo = App.activeDocument().ActiveObject.Name\n                App.activeDocument().getObject(nombreGrupo).Label = labelGrupo+' ('+self.nombrePieza+')'\n                App.activeDocument().getObject(nombrePartUltimo).addObject(App.activeDocument().getObject(nombreGrupo))\n            contador = contador +1\n\n        self.PiecesCreated()\n\n    def PiecesCreated(self):\n        self.form.etPiezasCreadas.setEnabled(True)\n        cad = \"+ \" + self.nombrePieza + cIntro\n        self.pieza = self.pieza + cad\n        self.form.infoPiezasCreadas.setText(self.pieza)\n        self.numeroPiezas += 1\n        self.form.numPiezas.setText(str(self.numeroPiezas))\n        self.form.botonCrear.setEnabled(False)\n        self.form.edicionNombrePieza.setText(\"\")\n\n    def accept(self):\n        # Ending\n        if (self.form.botonCrear.isEnabled() == True):\n            self.createPart()\n\n        elementosBorrados = []\n        gui.Control.closeDialog()\n\n# Se define el g_num_lang con variable global\nlang = gui.getLocale()\n# Default to English.\ng_num_lang = 1\nif 'Spanish' in lang:\n    g_num_lang = 0\nelif 'Italian' in lang:\n    g_num_lang = 2\npanel = PiecesTemplates()\ngui.Control.showDialog(panel)",
    "url": "https://github.com/18turbo/PlantillaPiezaFreeCAD",
    "raw_code_url": "",
    "wiki": "https://github.com/18turbo/PlantillaPiezaFreeCAD",
    "version": "1.4.1",
    "license": "",
    "date": "2022-10-06",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Utility\\PiecesTemplates.FCMacro",
    "filename_from_url": "",
    "author": "18Turbo",
    "icon": "PiecesTemplates.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "PiecesTemplates.svg",
      "/PiecesTemplates/ui/PiecesTemplates.ui",
      "/PiecesTemplates/Groups.txt"
    ],
    "parsed": true
  },
  {
    "name": "PlacementAbsolufy",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Reset part containers to global origin while keeping object positions",
    "code": "#!/usr/bin/python\n#####################################\n# Copyright (c) openBrain 2019\n# Licensed under LGPL v2\n#\n# This macro will reset position of all part containers to document origin while keeping the absolute object positions\n#\n# Version history :\n# *0.2 : some typo improvement + commenting for official PR\n# *0.1 : alpha release, almost no test performed\n#\n#####################################\n\n__Name__ = 'PlacementAbsolufy'\n__Comment__ = 'Reset part containers to global origin while keeping object positions'\n__Author__ = 'openBrain'\n__Version__ = '0.2'\n__Date__ = '2019-06-10'\n__License__ = 'LGPL v2'\n__Web__ = 'https://www.freecadweb.org/wiki/Macro_PlacementAbsolufy'\n__Wiki__ = 'https://www.freecadweb.org/wiki/Macro_PlacementAbsolufy'\n__Icon__ = ''\n__Help__ = 'Run the macro with model active in the GUI'\n__Status__ = 'Alpha'\n__Requires__ = 'FreeCAD >= 0.17'\n__Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=3&t=36869'\n__Files__ = ''\n\ncurrState = {} #initialize a dictionary to store current object placements\n\nfor obj in App.ActiveDocument.Objects: #going through active document objects\n    if \"Placement\" in obj.PropertiesList: #if object has a Placement property\n        currState[obj] = obj.getGlobalPlacement() #store the object pointer with its global placement\n\nApp.ActiveDocument.openTransaction(\"Absolufy\") #open a transaction for undo management\n\nfor obj, plac in currState.items(): #going through all moveable objects\n    if obj.isDerivedFrom(\"App::Part\"): #if object is a part container\n        obj.Placement = App.Placement(App.Vector(0,0,0),App.Rotation(0,0,0)) #reset its placement to global document origin\n    elif obj.TypeId[:5] == \"App::\": #if object is another App type (typically an origin axis or plane)\n        None #do nothing\n    else: #for all other objects\n        obj.Placement = plac #replace them at their global (absolute) placement\n\nApp.ActiveDocument.commitTransaction() #commit transaction\n",
    "url": "https://www.freecadweb.org/wiki/Macro_PlacementAbsolufy",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_PlacementAbsolufy",
    "version": "0.2",
    "license": "",
    "date": "2019-06-10",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Utility\\PlacementAbsolufy.FCMacro",
    "filename_from_url": "",
    "author": "openBrain",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "SelectVisible",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "All visible objects in the tree will be selected",
    "code": "# FreeCAD Macro SelectVisible\n\n__Name__ = 'Select Visible'\n__Comment__ = 'All visible objects in the tree will be selected'\n__Web__ = 'http://www.freecadweb.org/wiki/Macro_SelectVisible'\n__Wiki__ = 'http://www.freecadweb.org/wiki/Macro_SelectVisible'\n__Icon__ = 'SelectVisible.svg'\n__Help__ = 'All visible objects in the tree and only these will be selected'\n__Author__ = 'galou_breizh'\n__Version__ = '1.0'\n__Status__ = 'Production'\n__Requires__ = ''\n\nimport FreeCAD as App\nimport FreeCADGui as Gui\n\ndoc = App.activeDocument()\n\nif not doc:\n    App.Console.PrintWarning('SelectVisible: no active document')\nelse:\n    Gui.Selection.clearSelection()\n    for o in doc.Objects:\n        if o.ViewObject.Visibility:\n            Gui.Selection.addSelection(o)\n",
    "url": "http://www.freecadweb.org/wiki/Macro_SelectVisible",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/Macro_SelectVisible",
    "version": "1.0",
    "license": "",
    "date": "",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Utility\\SelectVisible.FCMacro",
    "filename_from_url": "",
    "author": "galou_breizh",
    "icon": "SelectVisible.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "SketchAp",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Create an INDEPENDENT sketch supported by a face. Update a sketch supported by a new face or DatumPlane.\\n",
    "code": "# -*- coding: utf-8 -*-\n# (c) 18Turbo, 2022\n\n__Name__ = 'SketchAp'\n__Comment__ = 'Create an INDEPENDENT sketch supported by a face. Update a sketch supported by a new face or DatumPlane.\\n'\n__Comment__ += ' It works with Part Design and Part.'\n__Author__ = '18Turbo'\n__Version__ = '0.1.0'\n__Date__ = '2022-10-15'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'https://github.com/18turbo/sketchApoyadoFreeCAD'\n__Wiki__ = 'https://github.com/18turbo/sketchApoyadoFreeCAD'\n__Icon__ = 'SketchAp.svg'\n__Help__ = ''\n__Status__ = 'beta'\n__Requires__ = 'FreeCAD >= v0.20'\n__Contact__ = 'https://github.com/18turbo'\n__Communication__ = ''\n__Files__ = 'SketchAp.svg,SketchAp.FCMacro'\n\n\n# (En espa\u00f1ol:)\n# Funcionalidad:    Crea un sketch apoyado en una cara, sin dependencia\n#\n# Nota importante: Basado inicialmente en el script de *** Sebasti\u00e1n Ernesto Garc\u00eda *** pero sin cuaterniones\n#\n# Agradecimientos: Sebasti\u00e1n Ernesto Garc\u00eda\n\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nfrom PySide import QtGui\nfrom numpy import *\nimport math\n\nstrLang = [\n    [ # Espa\u00f1ol\n\n        \"Debes seleccionar una sola cara (para crear un sketch apoyado en ella),\",\n        \"o una cara y un plano de referencia (para actualizar un sketch a un nuevo plano de referencia).\",\n        \"Debes seleccionar una sola cara y un DatumPlane.\",\n        \"o\",\n        \"Debes seleccionar una sola cara y un plano de referencia.\",\n        \"Debes seleccionar al menos una cara (y debe ser coplanar).\",\n        \"Recuerda: si est\u00e1s actualizando la posici\u00f3n del objeto, ambos objetos deben pertenecer al mismo banco de trabajo.\",\n        \"Si seleccionas una cara en Part Design, un Body debe estar como cuerpo activo.\",\n        \"No necesitas el script para hacer un sketch sobre un Plano de Referencia.\",\n        \"Versi\u00f3n:\"\n\n    ],\n    [ # English\n        ## Strings for translation into any language (English Strings)\n        \"You must select a single face (to create a sketch supported by it),\",\n        \"or a face and a reference plane (to update a sketch to a new reference plane).\",\n        \"You must select a single face and a DatumPlane.\",\n        \"or\",\n        \"You must select a single face and a reference plane.\",\n        \"You must select at least one face (and it must be coplanar).\",\n        \"Note: if you are updating the object position, both objects must belong to the same workbench.\",\n        \"If you select a face in Part Design, a Body must be the active body.\",\n        \"You don't need the script to sketch on a Reference Plane.\",\n        \"Version:\"\n    ]\n    ]\n\ncIntro = \"\\n\"\ncSpace = \" \"\n\ndef translate(text):\n    if (text not in strLang[0]) or (g_num_lang < 0) or (g_num_lang >= len(strLang)):\n        return text\n    primerIdioma = strLang[0]\n    indice = primerIdioma.index(text)\n    if (indice == -1) or (indice >= len(strLang[g_num_lang])):\n        return text\n    return strLang[g_num_lang][indice]\n\ndef messageWindow (msg):\n    version = translate(\"Versi\u00f3n:\")\n    title = __Name__ + \" (\" + version + __Version__ + \")\"\n    reply = QtGui.QMessageBox.warning (None, title, msg)\n\ndef sketchAp (subobjs,tipo,datumPlane,actualizar):\n    if len(subobjs) == 1:\n        face = subobjs[0]\n        if (face.ShapeType == 'Face') and (face.findPlane() != None):\n        # Se comprueba que efectivamente hay una cara seleccionada\n            if not actualizar:\n            # Si no estoy actualizando, creo el DatumPlane\n                if (tipo.find('PartDesign')>-1):\n                # Creo un datumPlane de Part Design\n                    body = Gui.ActiveDocument.ActiveView.getActiveObject('pdbody')\n                    datumPlane = App.ActiveDocument.addObject('PartDesign::Plane','DatumPlane')\n                    body.addObject(datumPlane)\n                    partDesign = True\n                else:\n                # Creo un datumPlane de Part (que es un Plano)\n                    datumPlane = FreeCAD.ActiveDocument.addObject(\"Part::Plane\",\"RefAuxPlaneSketchAp\")\n                    partDesign = False\n\n            longitud = round(face.BoundBox.DiagonalLength,2)\n            datumPlane.Length = longitud\n            datumPlane.Width = longitud\n            vertice = face.Vertexes[0]\n\n            # Esta combinaci\u00f3n funciona siempre\n            datumPlane.Placement.Base = vertice.Point\n            datumPlane.Placement.Rotation = face.Surface.Rotation\n            # Fin combinaci\u00f3n\n\n            # obj.positionBySupport (Comprobar en la siguiente versi\u00f3n)\n            if not actualizar:\n                rotar = False\n                rotarZ = False\n                if partDesign:\n                    if face.Placement.Rotation.Axis.z == 1.0:\n                        rotacion = 180.0\n                        rotar = True\n                        if face.Surface.Rotation.Axis == face.Placement.Rotation.Axis:\n                            rotacionZ = 180\n                            rotarZ = True\n                else:\n                    if face.Placement.Rotation.Axis.z == 1.0:\n                        normalCara = face.normalAt(0,0)\n                        if normalCara.x == 0 and normalCara.y == 0: # 3er cubo, cara superior (debug)\n                            #rotacion = 0\n                            rotar = False\n                        else:\n                            rotacion = -90.0\n                            rotar = True\n\n                # Esto funciona\n                if rotar:\n                    datumPlane.Placement.rotate (face.Surface.Position, face.Placement.Rotation.Axis, rotacion)\n                if rotarZ:\n                    datumPlane.Placement.rotate (face.Surface.Position, App.Vector (0,0,1), rotacionZ)\n\n            datumPlane.Support = ''\n            gui.ActiveDocument.getObject(datumPlane.Name).Transparency = 60\n            gui.ActiveDocument.getObject(datumPlane.Name).ShapeColor = (1.000,0.667,0.000)\n            datumPlane.recompute()\n\n            if not actualizar:\n                #Selecciono el Plano de Referencia\n                Gui.Selection.clearSelection()\n                Gui.Selection.addSelection(datumPlane)\n\n                #Creo el Boceto\n                if partDesign:\n                    sketch = body.newObject('Sketcher::SketchObject','Sketch')\n                else:\n                    sketch = FreeCAD.ActiveDocument.addObject('Sketcher::SketchObject','Sketch')\n                sketch.Support = (datumPlane,'')\n                sketch.MapMode = 'FlatFace'\n                #sketch.MapReversed = reversed\n\n                #Muestra los objetos activos dependientes\n                FreeCADGui.ActiveDocument.activeObject().HideDependent = False\n                FreeCADGui.ActiveDocument.activeObject().ShowSupport = True\n                App.ActiveDocument.recompute()\n\n                #Editar Boceto\n                Gui.Selection.addSelection(sketch)\n                Gui.ActiveDocument.setEdit(sketch,0)\n                App.ActiveDocument.recompute()\n\n            datumPlane.Visibility = False\n\n        else:\n            messageWindow(translate(\"Debes seleccionar al menos una cara (y debe ser coplanar).\") + cIntro + cIntro +\n                translate(\"Recuerda: si est\u00e1s actualizando la posici\u00f3n del objeto, ambos objetos deben pertenecer al mismo banco de trabajo.\"))\n    else:\n        messageWindow(translate(\"Debes seleccionar una sola cara (para crear un sketch apoyado en ella),\") + cSpace +\n            translate(\"o una cara y un plano de referencia (para actualizar un sketch a un nuevo plano de referencia).\"))\n\n\n# **** BEGIN ****\n# Se define el g_num_lang con variable global\nlang = gui.getLocale()\n# Default to English.\ng_num_lang = 1\nif 'Spanish' in lang:\n    g_num_lang = 0\n#elif 'Italian' in lang:\n#    g_num_lang = 2\n\nseleccion = Gui.Selection.getSelectionEx()\nplanoReferencia = 0\nactualizando = False\n\nif len(seleccion) == 1:\n# Create sketch\n    tipoObjeto = seleccion[0].Object.TypeId\n    if tipoObjeto == 'PartDesign::Plane':\n        messageWindow(translate(\"No necesitas el script para hacer un sketch sobre un Plano de Referencia.\"))\n    else:\n        subObjeto = seleccion[0].SubObjects\n        sketchAp (subObjeto, tipoObjeto, planoReferencia, actualizando)\n\nelif len(seleccion) == 2:\n# Update sketch\n    actualizando = True\n    sel1 = seleccion[0]\n    sel2 = seleccion[1]\n    tipoObjeto = seleccion[0].Object.TypeId\n\n    # Asignando las selecciones de Part Design\n    flag = False\n    if sel1.Object.TypeId == 'PartDesign::Plane':\n        planoReferencia = sel1.Object\n        if sel2.Object.TypeId.find('PartDesign::') > -1:\n            subObjeto = sel2.SubObjects\n            flag = True\n    elif sel2.Object.TypeId == 'PartDesign::Plane':\n        planoReferencia = sel2.Object\n        if sel1.Object.TypeId.find('PartDesign::') > -1:\n            subObjeto = sel1.SubObjects\n            flag = True\n\n    # Asignando las selecciones de Part\n    elif sel1.Object.TypeId == 'Part::Plane':\n        planoReferencia = sel1.Object\n        if sel2.Object.TypeId.find('Part::') > -1:\n            subObjeto = sel2.SubObjects\n            flag = True\n    elif sel2.Object.TypeId == 'Part::Plane':\n        planoReferencia = sel2.Object\n        if sel1.Object.TypeId.find('Part::') > -1:\n            subObjeto = sel1.SubObjects\n            flag = True\n\n    if flag == True:\n        sketchAp (subObjeto, tipoObjeto, planoReferencia, actualizando)\n    else:\n        messageWindow(translate(\"Debes seleccionar una sola cara y un DatumPlane.\") + cIntro + \" o \" + cIntro +\n            translate(\"Debes seleccionar una sola cara y un plano de referencia.\"))\nelse:\n    messageWindow(translate(\"Debes seleccionar una sola cara (para crear un sketch apoyado en ella),\") + cSpace +\n            translate(\"o una cara y un plano de referencia (para actualizar un sketch a un nuevo plano de referencia).\"))\n",
    "url": "https://github.com/18turbo/sketchApoyadoFreeCAD",
    "raw_code_url": "",
    "wiki": "https://github.com/18turbo/sketchApoyadoFreeCAD",
    "version": "0.1.0",
    "license": "",
    "date": "2022-10-15",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Utility\\SketchAp.FCMacro",
    "filename_from_url": "",
    "author": "18Turbo",
    "icon": "SketchAp.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "SketchAp.svg",
      "SketchAp.FCMacro"
    ],
    "parsed": true
  },
  {
    "name": "StraightenObject",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Straighten an object by a face and/or an edge (or 2 vertices)",
    "code": "#!/usr/bin/python\n#####################################\n# Copyright (c) openBrain 2019\n# Licensed under LGPL v2\n#\n# This FreeCAD macro will straighten an object vs. root origin based on a selected face or/and a selected edge (or 2 selected vertices)\n# * If only a face is selected -> Center of mass of the face is set at origin, and normal to face at this same point is aligned with Z axis\n# * If only an edge is selected (or 2 vertices) -> Object is rotated around Z axis (centered at the bounding box center) so that the virtual line between the 2 edge endpoints (or between the 2 vertices) is aligned with X axis\n# * If both a face and an edge (or 2 vertices) are selected, both previous effects are applied (at the difference that the Z rotation in centered on the face center of mass)\n#\n# Selected reference items shall belong to the same object\n#\n# Main use of the macro is to re-align imported objects with the FreeCAD origin\n#\n# Version history :\n# *0.8 : some typo improvement + commenting for official PR\n# *0.75 : adding transaction for correct undo management\n# *0.7 : multiple objects support (LIMITATION : reference items shall all belong to first object)(LIMITATION : unexpected results may happen if selected objects are in different coordinate systems)\n# *0.6 : change way of reaching PartDesign Body, older has trouble with objects contained in a part\n# *0.51 : change reference face alignment so it is considered a bottom face rather than a top one\n# *0.5 : beta release\n#\n#####################################\n\n__Name__ = 'StraigthenObject'\n__Comment__ = 'Straighten an object by a face and/or an edge (or 2 vertices)'\n__Author__ = 'openBrain'\n__Version__ = '0.8'\n__Date__ = '2019-06-10'\n__License__ = 'LGPL v2'\n__Web__ = 'https://www.freecadweb.org/wiki/Macro_StraightenObject'\n__Wiki__ = 'https://www.freecadweb.org/wiki/Macro_StraightenObject'\n__Icon__ = ''\n__Help__ = 'Select face and/or edge to guide object straightening then run the macro'\n__Status__ = 'Beta'\n__Requires__ = 'FreeCAD >= 0.17'\n__Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=22&t=35191'\n\n__dbg__ = False #True for debugging\n\nfrom PySide import QtGui\n\ndef cslM(msg):\n    FreeCAD.Console.PrintMessage('\\n')\n    FreeCAD.Console.PrintMessage(msg)\n\ndef cslW(msg):\n    FreeCAD.Console.PrintMessage('\\n')\n    FreeCAD.Console.PrintWarning(msg)\n\ndef cslE(msg):\n    FreeCAD.Console.PrintMessage('\\n')\n    FreeCAD.Console.PrintError(msg)\n\ndef cslD(msg):\n    if __dbg__:\n        FreeCAD.Console.PrintMessage('\\n')\n        FreeCAD.Console.PrintMessage(\"Debug : \" + str(msg))\n\n_0Vec_ = FreeCAD.Vector(0, 0, 0)\n_XVec_ = FreeCAD.Vector(1, 0, 0)\n_YVec_ = FreeCAD.Vector(0, 1, 0)\n_ZVec_ = FreeCAD.Vector(0, 0, 1)\n\nif __dbg__:  ##Clear report view in debug mode\n    FreeCADGui.getMainWindow().findChild(QtGui.QTextEdit, \"Report view\").clear()\n\ncslM(\"Starting Straighten Object macro\")\ncslD(\"Getting selected objects to define targets\")\n\nselError = False #true if incorrect selection made\ncancelOp = False #true if operation canceled by user\n\nif len(FreeCADGui.Selection.getSelection()) > 1:  # if several objects selected\n    cslD(\"Multiple objects selected, asking user what to do\")\n    msgb = QtGui.QMessageBox() ##create a message box to ask for user choice & populate it\n    msgb.setWindowTitle(\"Multiple objects selected\")\n    msgb.setText(\"\"\"You have selected multiple objects\n        This is experimental feature, unexpected results may happen if objects are in different coordinate systems\n        Click 'Parent' to try to find a common parent and apply transformation to it\n        Click 'Multiple' to apply transformation on all objects individually\n        Click 'Cancel' to cancel operation\"\"\")\n    msgb.setInformativeText(\"!!! Reference face and/or line shall belong to the 1st selected object !!!\")\n    msgb.setIcon(QtGui.QMessageBox.Question)\n    pbut = msgb.addButton(\"Parent\", QtGui.QMessageBox.AcceptRole) #button for 'Parent' mode\n    mbut = msgb.addButton(\"Multiple\", QtGui.QMessageBox.AcceptRole) #button for \"Multiple' mode\n    cbut = msgb.addButton(\"Cancel\", QtGui.QMessageBox.RejectRole) #button to cancel operation\n    msgb.exec_() #display message box\n    if msgb.clickedButton() == pbut: #if 'Parent' mode selected\n        cslD(\"Parent mode selected, will search for a common one\")\n        plist = FreeCADGui.Selection.getSelection()[0].InListRecursive #initialize the parent list\n        for obj in FreeCADGui.Selection.getSelection(): #for each object in selection\n            plist = list(set(plist).intersection(obj.InListRecursive)) #search common parent with previous objects\n        cslD(\"Found common parent(s) : \" + str([str(p.Label) for p in plist]) + \" / if several, choose the first one\")\n        if len(plist) == 0: #if no common parent found\n            selError = True\n            cslE(\"No common parent found\")\n        else: #if common parent found\n            target = [plist[0]] #take the lowest level one as target\n            cslD(\"Selected parent as target : \" + str(target[0].Label))\n    elif msgb.clickedButton() == mbut: #if 'Multiple' mode selected\n        cslD(\"Multiple mode selected, will apply on all objects\")\n        target = FreeCADGui.Selection.getSelection() #take all selection as target\n    else: #if operation canceled\n        cancelOp = True\n        cslD(\"Operation canceled by user\")\nelif len(FreeCADGui.Selection.getSelection()) == 1: #if only one object selected\n    target = FreeCADGui.Selection.getSelection() #take it as target\nelse: #no object selected\n    selError = True\n    cslE(\"No object selected\")\n\nif not(selError or cancelOp): #if a valid selection is available\n    cslD(\"Target(s) after mode application : \" + str(target[0].Label))\n    cslD(\"Checking if PartDesign feature selected\")\n    for cnt, t in enumerate(target): #going through the targets\n        try:\n            while str(t.TypeId)[:10] == 'PartDesign' and str(t.TypeId) != 'PartDesign::Body': #while object is in a PartDesign and is not the Body\n                t = t.getParentGeoFeatureGroup() #try its parent as new target\n        except: #if a PartDesign object has no containing Body\n            selError = True\n            cslE(\"Found a PartDesign object not in a Body\")\n            break\n        target[cnt] = t #update target\n\n    target = list(set(target).intersection(target)) #remove duplicates to prevent applying 2 times transformation on same object\n    cslD(\"Final target(s) : \" + str([str(t.Label) for t in target]))\n\n    cslD(\"Getting reference items\")\n\n    refFaceDef = False #true if a reference face is selected\n    refPt1Def = False #true if one reference point is found selected\n    refPt2Def = False #true if another reference point is found selected\n\n    cslD(\"Subobjects : \" +str(FreeCADGui.Selection.getSelectionEx()[0].SubElementNames))\n    for selItem in FreeCADGui.Selection.getSelectionEx()[0].SubObjects: #going through selected items of first object\n        if isinstance(selItem, Part.Face): #if it's a face\n            if not refFaceDef: #if reference face not yet defined\n                refFace = selItem #define it\n                refFaceDef = True #and remember\n            else:\n                selError = True #too much faces selected\n                cslE(\"Too much reference faces selected\")\n        elif isinstance(selItem, Part.Edge): #if it's an edge\n            if not refPt1Def and not refPt2Def: #if reference points not yet defined\n                refPt1 = selItem.Vertexes[0] #define 1st reference point as first edge point\n                refPt1Def = True #and remember\n                refPt2 = selItem.Vertexes[len(selItem.Vertexes)-1] #define 2nd reference point as last edge point\n                refPt2Def = True #and remember\n            else:\n                selError = True #too much points selected\n                cslE(\"Too much reference points selected (vertices or edges)\")\n        elif isinstance(selItem, Part.Vertex): #if it's a vertex\n            if not refPt1Def: #if 1st reference point not yet defined\n                refPt1 = selItem #define it\n                refPt1Def = True #and remember\n            elif not refPt2Def: #if 2nd reference point not yet defined\n                refPt2 = selItem #define it\n                refPt2Def = True #and remember\n            else:\n                selError = True #too much points selected\n                cslE(\"Too much reference points selected (vertices or edges)\")\n        else:\n            selError = True #incorrect type of item selected\n            cslE(\"Incorrect type of item selected\")\n\nif cancelOp:\n    cslM(\"Operation canceled by user ... exiting\")\nelif selError or (bool(refPt1Def) != bool(refPt2Def)) or (not (refPt1Def or refPt2Def or refFaceDef)): #if selection error or only one reference point defined or no reference face/point defined\n    cslE(\"Selection error : see report view & documentation for more details ... Exiting\")\nelse:\n    FreeCAD.ActiveDocument.openTransaction(\"Straighten objects\") #open new transaction for undo management\n    cslD(\"Starting Transformation\")\n    obj = FreeCADGui.Selection.getSelection()[0] # take as reference the first object selected for transformation\n    shiftVec = _0Vec_  # no shift move by default\n    faceRot = FreeCAD.Rotation(_ZVec_, _ZVec_) #no reference rotation by default\n    lineRot = FreeCAD.Rotation(_ZVec_, _ZVec_) #no reference line by default\n    normVec = _ZVec_ #normal is the Z axis by default\n    rotCenter = obj.Shape.BoundBox.Center #center of rotation at object bounding box center by default\n    warning = False #True if a warning appears\n\n    if refFaceDef: #if a reference face has been defined\n        cslD(\"A reference face is available\")\n        faceCurv = refFace.curvatureAt(refFace.Surface.parameter(refFace.CenterOfMass)[0], refFace.Surface.parameter(refFace.CenterOfMass)[1]) #calculating face curvature at center of mass\n        cslD(\"Curvature : \" + str(faceCurv))\n        if faceCurv != (0, 0): #if reference face is not flat at its center of mass\n            warning = True\n            cslW(\"Reference face is not flat at its center of mass, unexpected results may happen\") #warn user about it\n        rotCenter = refFace.CenterOfMass #changing center of rotation to center of mass of reference face\n        shiftVec -= refFace.CenterOfMass #the reference face will be centered\n        normVec = refFace.normalAt(refFace.Surface.parameter(refFace.CenterOfMass)[0], refFace.Surface.parameter(refFace.CenterOfMass)[1]) #getting normal vector at face center of mass\n        faceRot = FreeCAD.Rotation(normVec, -_ZVec_) #calculate needed rotation to align the reference face with Z axis\n        for t in target:\n            t.Placement = FreeCAD.Placement(_0Vec_, faceRot, rotCenter).multiply(t.Placement) #rotate targets to align reference face normal with Z axis\n        cslD(\"Targets rotated to match reference face normal with Z axis\")\n    if refPt1Def: #if reference points have been defined\n        cslD(\"Reference points are available\")\n        lineVec = refPt2.Point - refPt1.Point #calculate vector (reference line) defined by reference points\n        lineVecMod = faceRot.multVec(lineVec) #reference line has maybe been modified by previous object rotation\n        lineNorm = lineVecMod.projectToPlane(_0Vec_, _ZVec_) #calculate line projection on XY plane\n        cslD(\"Normality : \" + str(lineNorm))\n        if lineNorm == _0Vec_: #if reference line is perpendicular to rotating plane\n            warning = True\n            cslW(\"Line reference is aligned with normal, line alignment will be ignored\") #warn user about it\n        else:\n            lineRot = FreeCAD.Rotation(lineNorm, _XVec_) #calculate needed rotation to align with X axis\n            for t in target:\n                t.Placement = FreeCAD.Placement(_0Vec_, lineRot, rotCenter).multiply(t.Placement) #rotate targets to align reference line with X axis\n            cslD(\"Targets rotated to match reference line with X axis\")\n\n    for t in target:\n        t.Placement.move(shiftVec) #finally shift targets if needed\n    cslD(\"Targets shift\")\n    FreeCAD.ActiveDocument.commitTransaction() #commit transaction\n    if warning:\n        cslW(\"Macro terminated with warning(s), see report view & documentation for more details\")\n    else :\n        cslM(\"Macro terminated correctly\")\n",
    "url": "https://www.freecadweb.org/wiki/Macro_StraightenObject",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_StraightenObject",
    "version": "0.8",
    "license": "",
    "date": "2019-06-10",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Utility\\StraightenObject.FCMacro",
    "filename_from_url": "",
    "author": "openBrain",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Transparencies",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "The selected object becomes 50% transparent (if they have no transparency), and is detransparency otherwise.",
    "code": "# -*- coding: utf-8 -*-\n# (c) 18Turbo, 2022\n\n__Name__ = 'Transparencies'\n__Comment__ = 'The selected object becomes 50% transparent (if they have no transparency), and is detransparency otherwise.'\n__Author__ = '18Turbo (Rafael M.) and Rafael Garc\u00eda'\n__Version__ = '0.0.2'\n__Date__ = '2022-10-18'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'https://github.com/18turbo/TransparenciaObjetosFreeCAD'\n__Wiki__ = 'https://github.com/18turbo/TransparenciaObjetosFreeCAD'\n__Icon__ = 'Transparencies.svg'\n__Help__ = ''\n__Status__ = 'beta'\n__Requires__ = 'FreeCAD >= v0.19'\n__Contact__ = 'https://github.com/18turbo'\n__Communication__ = ''\n__Files__ = 'Transparencies.svg'\n\n# Agradecimientos: Rafael Garc\u00eda\n\n#El objeto seleccionado se vuelve un 50% transparente si no tiene transparencia y se le quita la transparencia si la tiene.\n\ncreadaTransparencia = False\n\nobjetosSeleccionados = Gui.Selection.getSelection()\n\nfor objeto in objetosSeleccionados:\n    transparenciaObjeto = objeto.ViewObject.Transparency\n    if (transparenciaObjeto >= 0 and transparenciaObjeto<10):\t# Si no hay transparencia (o muy poca)\n        objeto.ViewObject.Transparency = 50\n        creadaTransparencia = True\n\nif creadaTransparencia == False:\n    # Si no se ha creado ninguna transparencia, es que se debe poner todo opaco\n    for objeto in objetosSeleccionados:\n        objeto.ViewObject.Transparency = 0",
    "url": "https://github.com/18turbo/TransparenciaObjetosFreeCAD",
    "raw_code_url": "",
    "wiki": "https://github.com/18turbo/TransparenciaObjetosFreeCAD",
    "version": "0.0.2",
    "license": "",
    "date": "2022-10-18",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Utility\\Transparencies.FCMacro",
    "filename_from_url": "",
    "author": "18Turbo (Rafael M.) and Rafael Garc\u00eda",
    "icon": "Transparencies.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "Transparencies.svg"
    ],
    "parsed": true
  },
  {
    "name": "treeHelper",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Macro to generate a helper tree that allows you to easily move objects in the tree structure",
    "code": "# coding: utf-8\n\n__Name__ = \"Tree Helper\"\n__Comment__ = \"Macro to generate a helper tree that allows you to easily move objects in the tree structure\"\n__Author__ = \"Daniel Pose\"\n__Version__ = \"0.0.4\"\n__Date__ = \"2022-09-04\"\n__License__ = \"MIT\"\n__Web__ = \"https://github.com/iinjdpa/TreeHelper\"\n__Wiki__ = \"\"\n__Icon__ = \"/treeHelper/treeHelper.svg\"\n__Help__ = \"Select a folder, part or body where helper tree must grow. Drag object from main tree to helper tree\"\n__Status__ = \"Alpha\"\n__Requires__ = \"Freecad >= v0.19\"\n__Communication__ = \"https://github.com/iinjdpa/TreeHelper/issues\"\n__Files__ = \"/treeHelper/ui_treewindow.py,/treeHelper/treeHelper.svg\"\n\n\nimport FreeCAD as App\nimport FreeCADGui as Gui\nfrom PySide import QtCore, QtGui\nfrom PySide.QtCore import Qt, QByteArray, QDataStream, QIODevice\nfrom PySide.QtGui import QDialog, QApplication, QTreeWidgetItem, QDockWidget, QGraphicsDropShadowEffect, QColor,QMainWindow\nfrom PySide.QtGui import QMessageBox, QAbstractItemView, QDrag\nimport PySide2\nimport os\nimport sys\nfrom treeHelper import ui_treewindow\nfrom collections import OrderedDict\nimport time\n\n\nclass Objdoc(object):\n    def __init__(self,doc):\n        self.ViewObject = mViewObject()\n        self.Name = doc.Name\n        self.Label = doc.Name\n\nclass mViewObject(object):\n    def __init__(self):\n        pass\n    def claimChildren(self):\n        # Nombre del documento\n        doc = App.activeDocument()\n        if doc == None:\n            doc = FreeCAD.newDocument()\n        docName = doc.Name\n        # Buscamos el \u00e1rbol de FreeCAD. Es la forma de poder importar todos los objetos por orden\n        mw = Gui.getMainWindow()\n        self.tw = mw.findChildren(QtGui.QTreeWidget)\n        self.tw0 = self.tw[0]\n        self.tw0.repaint()\n        self.FCtreeitems = self.tw0.findItems('*', Qt.MatchWrap | Qt.MatchWildcard  | Qt.MatchRecursive)\n        root_labels = []\n        for it in self.FCtreeitems:\n            if not it.parent(): continue\n            if isinstance(it.parent(), list):\n                for itp in it.parent():\n                    if itp == docName:\n                        root_labels.append(it.text(0))\n            else:\n                if it.parent().text(0) == docName:\n                    root_labels.append(it.text(0))\n        root_objects = App.ActiveDocument.RootObjects\n        root_objects_from_labels = []\n        if len(root_labels) == len(root_objects):\n            for obj in root_labels:\n                obj_by_label = App.ActiveDocument.getObjectsByLabel(obj)\n                if len(obj_by_label) > 1:\n                    QMessageBox.critical(self, \"Error\",\"There are objects with same label!\")\n                    return []\n                else:\n                    root_objects_from_labels.append(App.ActiveDocument.getObjectsByLabel(obj)[0])\n            return root_objects_from_labels\n        else:\n            return root_objects\n\n    def update(self):\n        pass\n\nclass TreeDrops(QtGui.QTreeWidget):\n    itemDropped = QtCore.Signal()\n    customMimeType = \"application/x-qabstractitemmodeldatalist\"\n    def __init__(self, parent=None):\n        super(TreeDrops, self).__init__(parent=None)\n        self.setAcceptDrops(True)\n        self.setDragDropMode(QAbstractItemView.DragDrop)\n        self.dragEnabled()\n        # self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)\n        self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)\n\n    def startDrag(self, supportedActions):\n        drag = QDrag(self)\n        mimedata = self.model().mimeData(self.selectedIndexes())\n\n        encoded = QByteArray()\n        stream = QDataStream(encoded, QIODevice.WriteOnly)\n        self.encodeData(self.selectedItems(), stream)\n        mimedata.setData(self.customMimeType, encoded)\n\n        drag.setMimeData(mimedata)\n        drag.exec_(supportedActions)\n\n    def encodeData(self, items, stream):\n        stream.writeInt32(len(items))\n        for item in items:\n            p = item\n            rows = []\n            while p is not None:\n                rows.append(self.indexFromItem(p).row())\n                p = p.parent()\n            stream.writeInt32(len(rows))\n            for row in reversed(rows):\n                stream.writeInt32(row)\n        return stream\n\n    def dropEvent(self, event):\n        if event.mimeData().hasFormat(\"application/x-qabstractitemmodeldatalist\"):\n            destiny = self.itemAt(event.pos()).text(1)\n            selected_in_TreeHelper= [self.itemFromIndex(index) for index in self.selectionModel().selectedIndexes()]\n            # Solo los elementos distintos\n            selected_in_TreeHelper = list(set(selected_in_TreeHelper))\n            selected_in_FreeCAD = event.source().selectedItems()\n            if selected_in_TreeHelper:\n                selected = selected_in_TreeHelper\n            else:\n                selected = selected_in_FreeCAD\n            # for origin_label in event.source().selectedItems():\n            for origin_label in selected:\n                origin_label = origin_label.text(0)\n                obj_by_label = App.ActiveDocument.getObjectsByLabel(origin_label)\n                if len(obj_by_label) > 1:\n                    QMessageBox.critical(self, \"Error\",\"There are objects with same label!\")\n                    return\n                else:\n                    origin_obj = App.ActiveDocument.getObjectsByLabel(origin_label)[0]\n\n                # Buscamos el objeto padre del origen\n                if event.source().selectedItems()[0].parent():\n                    origin_father_label = event.source().selectedItems()[0].parent().text(0)\n                else:\n                    return\n\n                obj_by_label = App.ActiveDocument.getObjectsByLabel(origin_father_label)\n                if len(obj_by_label) > 1:\n                    QMessageBox.critical(self, \"Error\",\"There are objects with same label!\")\n                    return\n                else:\n                    if App.ActiveDocument.getObjectsByLabel(origin_father_label):\n                        origin_father = App.ActiveDocument.getObjectsByLabel(origin_father_label)[0]\n\n                App.ActiveDocument.openTransaction('moveobject')\n                # Object moved between sub-elements\n                if App.ActiveDocument.getObject(destiny):\n                    origin_obj.adjustRelativeLinks(App.ActiveDocument.getObject(destiny))\n                    App.ActiveDocument.getObject(destiny).addObject(origin_obj)\n                else:\n                    # Object moved to main\n                    origin_father.removeObject(origin_obj)\n\n            # Repaint FreeCAD QtreeWidget for update changes\n            tw = mw.findChildren(QtGui.QTreeWidget)\n            tw0 = [t.repaint() for t in tw]\n\n            App.ActiveDocument.commitTransaction()\n            App.ActiveDocument.recompute()\n\n            self.itemDropped.emit()\n\nclass Treehelper(QDockWidget,ui_treewindow.Ui_DockWidget):\n    window_closed = QtCore.Signal()\n    def __init__(self,parent=None):\n        super(Treehelper,self).__init__(parent,QtCore.Qt.WindowStaysOnTopHint)\n        self.setupUi(self)\n        param = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")\n        self.path = param.GetString(\"MacroPath\",\"\") + \"/\"\n        self.path = self.path.replace(\"\\\\\",\"/\")\n        self.treeWidget2 = TreeDrops(self)\n        self.gridLayout.replaceWidget(self.treeWidget, self.treeWidget2)\n        self.treeWidget.close()\n        qtreewidgetitem0 = self.treeWidget2.headerItem()\n        qtreewidgetitem0.setText(0, u\"Elementos\")\n        qtreewidgetitem1 = self.treeWidget2.headerItem()\n        qtreewidgetitem1.setText(1, u\"Name\")\n        self.gridLayout.update()\n        self.treeWidget2.setColumnCount(2)\n        self.treeWidget2.setLineWidth(6)\n        self.treeWidget2.setAlternatingRowColors(True)\n        self.treeWidget2.setIconSize(QtCore.QSize(18, 18))\n        self.treeWidget2.setAnimated(True)\n        self.treeWidget2.header().sectionSize(1200)\n        self.treeWidget2.header().setDefaultSectionSize(1200)\n        self.treeWidget2.header().setMinimumSectionSize(1200)\n        self.treeWidget2.header().setCascadingSectionResizes(True)\n        self.treeWidget2.header().setHighlightSections(True)\n        self.treeWidget2.header().setStretchLastSection(True)\n        # Creamos una variable para guardar el elemento raiz del \u00e1rbol\n        self.mainelement = ''\n        # Guardamos el estado de plegado\n        self.expandedState = {}\n        # Hacemos la ventana modal\n        # self.setModal(False)\n        # Cargamos el \u00e1rbol\n        self.loadtree()\n\n        # Actualizamos el arbol despues de mover un objeto\n        self.treeWidget2.itemDropped.connect(self.updatetree)\n\n    def updatetree(self):\n        # Actualizamos todos los sub-arboles creados\n        mw = Gui.getMainWindow()\n        qd = mw.findChildren(QtGui.QDockWidget,name='Tree helper')\n        for q in qd:\n            try:\n                if q.isHidden():\n                    # Si el arbol esta oculto, lo eliminamos para no sobrecargar el DockWidget\n                    q.setParent(None)\n                    q.close()\n                    del q\n                else:\n                    q.loadtree()\n            except:\n                pass\n\n    def get_subtree_nodes(self,widget,tree_widget_item):\n        \"\"\"Returns all QTreeWidgetItems in the subtree rooted at the given node.\"\"\"\n        self.expandedState[tree_widget_item.text(0)] = widget.isItemExpanded(tree_widget_item)\n        for i in range(tree_widget_item.childCount()):\n            self.get_subtree_nodes(widget,tree_widget_item.child(i))\n        return\n\n    def get_all_items(self,widget):\n        \"\"\"Returns all QTreeWidgetItems in the given QTreeWidget.\"\"\"\n        for i in range(widget.topLevelItemCount()):\n            top_item = widget.topLevelItem(i)\n            self.get_subtree_nodes(widget,top_item)\n        return\n\n    def loadtree(self):\n        \"\"\"Lee el \u00e1rbol de FreeCAD a partir del elemento seleccionado y lo carga en el \u00e1rbol de ayuda\n        \"\"\"\n        self.get_all_items(self.treeWidget2)\n        self.treeWidget2.clear()\n\n        doc = App.activeDocument()\n        if doc == None:\n            doc = FreeCAD.newDocument()\n\n        isBeingUpdated = False\n\n        # El objeto seleccionado ser\u00e1 el primero del \u00e1rbol\n        if self.mainelement:\n            # NO es la primera vez que se genera el arbol\n            isBeingUpdated = True\n            if self.mainelement.Name == doc.Name:\n                # El objeto principal es el documento\n                primaryTreeItem  = QTreeWidgetItem(self.treeWidget2)\n                primaryTreeItem.setText(0,doc.Name)\n                primaryTreeItem.setText(1,doc.Name)\n                primaryTreeItem.setExpanded(True)\n                objSel = self.mainelement\n            else:\n                # El objeto principal es otro cualquiera\n                objSel = self.mainelement\n                primaryTreeItem  = QTreeWidgetItem(self.treeWidget2)\n                primaryTreeItem.setText(0,objSel.Label)\n                primaryTreeItem.setText(1,objSel.Name)\n                try:\n                    primaryTreeItem.setIcon(0,objSel.ViewObject.Icon)\n                except:\n                    pass\n                primaryTreeItem.setExpanded(True)\n        else:\n            if Gui.Selection.getCompleteSelection():\n                objSel = Gui.Selection.getCompleteSelection()[0]\n                self.mainelement = objSel\n                self.setToolTip(objSel.Label)\n                primaryTreeItem  = QTreeWidgetItem(self.treeWidget2)\n                primaryTreeItem.setText(0,objSel.Label)\n                primaryTreeItem.setText(1,objSel.Name)\n                try:\n                    primaryTreeItem.setIcon(0,objSel.ViewObject.Icon)\n                except:\n                    pass\n                primaryTreeItem.setExpanded(True)\n            else:\n                objSel = Objdoc(doc)\n                self.mainelement = objSel\n                self.setToolTip(objSel.Label)\n                primaryTreeItem  = QTreeWidgetItem(self.treeWidget2)\n                primaryTreeItem.setText(0,doc.Name)\n                primaryTreeItem.setText(1,doc.Name)\n                primaryTreeItem.setExpanded(True)\n\n        # Iteramos sobre los objetos bajo el objeto seleccionado\n        dictObjs = OrderedDict()\n        lstObjs = [[0,objSel,'main']]\n        while lstObjs:\n            crrObj = lstObjs.pop()\n            # crrObj[1].ViewObject.update()\n            for obj in crrObj[1].ViewObject.claimChildren():\n                level = crrObj[0]\n                # Guardamos su nivel dentro del \u00e1rbol, el propio objeto y el nombre del objeto padre\n                dcName = obj.Name\n                ct = 0\n                # Un mismo objeto puede estar en distintas partes del \u00e1rbol. No repetimos clave\n                while dcName in dictObjs:\n                    dcName = f'{dcName}{ct:04d}'\n                    ct+=1\n                dictObjs[dcName] = [level+1,obj,crrObj[1].Name]\n                lstObjs.append(dictObjs[obj.Name])\n\n        # Iteramos ahora sobre los objetos recogidos para insertarlos en el \u00e1rbol\n        dictItems = {}\n        dictItems[objSel.Name] = primaryTreeItem\n        for k,elem in dictObjs.items():\n            itemElem = QTreeWidgetItem(dictItems[dictObjs[k][2]])\n            itemElem.setText(0,dictObjs[k][1].Label)\n            itemElem.setText(1,dictObjs[k][1].Name)\n            try:\n                itemElem.setIcon(0,dictObjs[k][1].ViewObject.Icon)\n            except:\n                pass\n            if not isBeingUpdated:\n                itemElem.setExpanded(True)\n            else:\n                if itemElem.text(0) in self.expandedState:\n                    itemElem.setExpanded(self.expandedState.get(itemElem.text(0)))\n                else:\n                    itemElem.setExpanded(True)\n            dictItems[k] = itemElem\n\nif __name__ == '__main__':\n    mw = Gui.getMainWindow()\n    mform=Treehelper(mw)\n    mform.loadtree()\n    mform.show()\n    mw.addDockWidget(QtCore.Qt.RightDockWidgetArea,mform)",
    "url": "https://github.com/iinjdpa/TreeHelper",
    "raw_code_url": "",
    "wiki": "",
    "version": "0.0.4",
    "license": "",
    "date": "2022-09-04",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Utility\\treeHelper.FCMacro",
    "filename_from_url": "",
    "author": "Daniel Pose",
    "icon": "/treeHelper/treeHelper.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "/treeHelper/ui_treewindow.py",
      "/treeHelper/treeHelper.svg"
    ],
    "parsed": true
  },
  {
    "name": "WikiObjectPropertiesListGenerator",
    "on_wiki": false,
    "on_git": true,
    "desc": "",
    "comment": "Generates lists of object properties for use in the FreeCAD Wiki documentation.",
    "code": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n# (c) 2021 <Evgeniy> LGPL\n# Modified by <hasecilu> on 2024-11-14\n\n\"\"\"\nDescription:\nThis macro generates lists of properties of the selected object in different forms\nin Wiki format. The list is printed to the Report view of FreeCAD. This macro can\nbe used to simplify working with this Wiki with some restrictions. The property\nlists published in Wiki usually contain only unique parameters. Parameters inherited\nfrom parent objects are not published.\n\nThis script automatically removes inherited parameters from the list. But due to the\nsoftware limitations of FreeCAD, it cannot delete absolutely all inherited parameters,\nso the lists generated by this script should be carefully checked before publishing.\n\nUsage:\n- Preparing:\n    - Copy code of Macro from this page and place it in a new *.FCMacro file.\n    - Save FCMacro file, and place it in the FreeCAD Macros folder.\n    - Disable Include a timecode for each entry checkbox in Preferences -> General -> Output window (Tab).\n\n- First using:\n    - Select (or create and select) only one object in tree view the type of you need.\n    - Select Macro -> Macros... item in main menu.\n    - In opened window find *.FCMacro file what you save letter and press Execute Button.\n    - In the dialog that opens, select the type of report that you want to get by pressing button:\n        - Only Main - prints only unique properties of base (parent) classes.\n        - All Properties - prints absolutely all properties of selected object.\n        - Inherits+Unique Properties - prints only unique properties with included inherits report.\n        - Only Unique Properties - prints only unique properties.\n\n- How to use again:\n    - To quickly run this macro again, you can use keyboard shortcut `Shift+Ctrl+1` it will launch the last run macro.\n\"\"\"\n\n__Name__ = \"Wiki Object Properties List Generator\"\n__Comment__ = \"Generates lists of object properties for use in the FreeCAD Wiki documentation.\"\n__Author__ = \"Evgeniy\"\n__Date__ = \"2024-11-23\"\n__Version__ = \"0.16.1\"\n__License__ = \"LGPL-3.0-or-later\"  # 6 matches for LGPL on https://spdx.org/licenses/\n__Web__ = \"\"\n__Wiki__ = \"https://wiki.freecad.org/Macro_Wiki_Object_Properties_List_Generator\"\n__Icon__ = \"./WikiObjectPropertiesListGenerator.svg\"\n__Xpm__ = \"\"\n__Help__ = \"Select a scripted objects on the tree and execute the macro.\"\n__Status__ = \"Beta\"\n__Requires__ = \"\"\n__Communication__ = \"https://forum.freecad.org/viewtopic.php?f=21&t=61998\"\n__Files__ = \"./WikiObjectPropertiesListGenerator.svg\"\n\n# NOTE: Changelog\n# ---------\n# - 0.16.1 - 2024-11-23\n#   - Attend change requests: imports, use semver, f-string, simplify condition, function style.\n#   - Add checkbox to let user decide if wants to clear or not the Report View\n# - 0.16.0 - 2024-11-15\n#   - Refactor code: add custom dataclass, update functions' signatures, make some fixes.\n#   - Include property's value on the list.\n#   - Create custom dialog to add checkbox to let user disable/enable property status.\n# - 0.15.0 - 2021-09\n#   - Initial release.\n\nimport re\nfrom dataclasses import dataclass\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nfrom PySide import QtCore, QtGui, QtWidgets  # FreeCAD's PySide!\n\n\n@dataclass\nclass PropertyInfo:\n    property_type: str\n    data_type: str\n    default_value: str\n    tooltip: str\n    status: str\n\n\n# Based on https://github.com/FreeCAD/FreeCAD/blob/5d49bf78de785a536f941f1a6d06d432582a95d3/src/App/PropertyFile.h\n# and https://github.com/FreeCAD/FreeCAD/blob/5d49bf78de785a536f941f1a6d06d432582a95d3/src/App/PropertyContainerPyImp.cpp\nstatus_dictionary = {\n    0: \"Touched\",  # touched property\n    # 1:\"Immutable\",   # can't modify property\n    # 2:\"ReadOnly\",    # for property editor\n    # 3:\"Hidden\",      # for property editor\n    # 4:\"Transient\",   # for property container save\n    # 5:\"MaterialEdit\", # to turn ON PropertyMaterial edit\n    # 6:\"NoMaterialListEdit\", # to turn OFF PropertyMaterialList edit\n    # 7:\"Output\",      # same effect as Prop_Output\n    # 8:\"LockDynamic\", # prevent being removed from dynamic property\n    # 9:\"NoModify\",    # prevent causing Gui::Document::setModified()\n    # 10:\"PartialTrigger\", # allow change in partial doc\n    11: \"NoRecompute\",  # touch owner for recompute on property change\n    12: \"Single\",  # for save/load of floating point numbers\n    13: \"Ordered\",  # for PropertyLists whether the order of the elements is relevant for the container using it\n    14: \"EvalOnRestore\",  # In case of expression binding, evaluate the expression on restore and touch the object on value change.\n    # The following bits are corresponding to PropertyType set when the\n    # property added. These types are meant to be static, and cannot be\n    # changed in runtime. It is mirrored here to save the linear search\n    # required in PropertyContainer::getPropertyType()\n    21: \"Dynamic\",  # indicating the property is dynamically added\n    22: \"NoPersist\",  # corresponding to Prop_NoPersist\n    23: \"NoRecompute\",  # corresponding to Prop_NoRecompute\n    24: \"ReadOnly\",  # corresponding to Prop_ReadOnly\n    25: \"Transient\",  # corresponding to Prop_Transient\n    26: \"Hidden\",  # corresponding to Prop_Hidden\n    27: \"Output\",  # corresponding to Prop_Output\n}\n\n\ndef clear_report_view():\n    \"\"\"Clear content of Report View panel.\"\"\"\n    main_window = gui.getMainWindow()\n    main_window.findChild(QtGui.QTextEdit, \"Report view\").clear()\n\n\ndef print_sr(text: str, show_report: bool = True):\n    \"\"\"Print the given text if \"show report\" flag is enabled.\"\"\"\n    app.Console.PrintMessage(text) if show_report else None\n\n\ndef generate_markup_list(grouped_properties: dict, print_status: bool = False):\n    \"\"\"Print to the console the Wiki markup code.\"\"\"\n    # NOTE: Group example:\n    # {{Properties_Title|Box features}}\n    # Property example:\n    # * {{PropertyData|BoxOpenFront|Bool}}: Default is {{value|False}}. Leave front of box open\n    # or:\n    # * {{PropertyData|BoxOpenFront|Bool|Dynamic}}: Default is {{value|False}}. Leave front of box open\n\n    # Sort groups and properties within each group\n    for group in sorted(grouped_properties):\n        app.Console.PrintMessage(f\"\\n{{{{Properties_Title|{group}}}}}\\n\\n\")\n        for prop, data in sorted(grouped_properties[group]):\n            if print_status:\n                status = \"|\" + data.status\n            elif \"Hidden\" in data.status:  # make exception, all other status will be ignored\n                status = \"|\" + \"hidden\"  # manually use lowercase\n            else:\n                status = \"\"\n            app.Console.PrintMessage(\n                f\"* {{{{Property{data.property_type}|{prop}|{data.data_type}{status}}}}}: \"\n                f\"Default is {{{{value|{data.default_value}}}}}. {data.tooltip}.\\n\"\n            )\n    app.Console.PrintMessage(\"\\n\\n\")\n\n\ndef print_obj_properties(\n    obj, typ: str, ignore_list: dict, show_inherits: bool = False, print_status: bool = False\n):\n    \"\"\"Print non-ignored properties of the selected object to the Report View.\"\"\"\n    grouped_properties = {}\n    inherits = \"\"\n    for prop in obj.PropertiesList:\n        value = getattr(obj, prop, \"N/A\")\n        typeid = (obj.getTypeIdOfProperty(prop) or \"\").replace(\"App::Property\", \"\")\n        prop_group = obj.getGroupOfProperty(prop) or \"\"\n        tooltip = obj.getDocumentationOfProperty(prop) or \"\"\n        # Get all possible status variants\n        stat = obj.getPropertyStatus(prop) or \"\"\n\n        if stat:\n            for st in stat:\n                # get status without name from dictionary\n                if isinstance(st, int):\n                    stat.insert(stat.index(st), status_dictionary[st])\n                    stat.remove(st)\n            # remove symbols ['] from str by regexp and trim spaces\n            stat = re.sub(r\"[\\[\\]\\']\", \"\", str(stat)).strip()\n            # NOTE: Uncomment next two lines to make the list look like the list of parameters from the editor\n            # if 'Hidden' in stat:\n            #   continue\n        else:\n            stat = \"\"\n\n        if prop not in ignore_list:\n            # Add property information to the respective group\n            if prop_group not in grouped_properties:\n                grouped_properties[prop_group] = []\n            grouped_properties[prop_group].append(\n                (\n                    prop,\n                    PropertyInfo(\n                        property_type=typ,\n                        data_type=typeid,\n                        default_value=value,\n                        tooltip=tooltip,\n                        status=stat,\n                    ),\n                )\n            )\n\n        else:\n            inherits += f\"{prop} inherited from class {ignore_list[prop]}\\n\"\n\n    if inherits != \"\" and show_inherits:\n        # angle brackets is masked as \\x3C and \\x3E so this code can be published in the Wiki\n        print(f\"\\n\\x3c!--\\n{inherits}--\\x3e\")\n\n    generate_markup_list(grouped_properties, print_status)\n\n\ndef add_properties_to_ignore_list(\n    obj,\n    ignore_list: dict,\n    obj_type: str,\n    show_report: bool = True,\n):\n    \"\"\"Add properties to the ignore list if not present\"\"\"\n    for prop in obj.PropertiesList:\n        if prop not in ignore_list:\n            ignore_list[prop] = obj_type\n            atr = str(obj.getPropertyStatus(prop)).replace(\"[]\", \"\")\n            typeid = (obj.getTypeIdOfProperty(prop) or \"\").replace(\"App::Property\", \"\")\n            print_sr(f\"{prop} ({typeid}) {atr}\", show_report)\n    return ignore_list\n\n\ndef add_to_ignore_list(\n    data_ignore_list: dict,\n    view_ignore_list: dict,\n    obj_type: str,\n    temp_obj_name: str,\n    show_report: bool = True,\n):\n    \"\"\"Add properties to ignore_list if they are not present\"\"\"\n    print_sr(f\"Class: '{obj_type}'\", show_report)\n\n    # Make temporary object and get its Data parameters\n    obj = app.activeDocument().addObject(obj_type, temp_obj_name)\n    name = obj.Name\n    print_sr(\"Data parameters list:\", show_report)\n    data_ignore_list = add_properties_to_ignore_list(obj, data_ignore_list, obj_type, show_report)\n\n    # Try to get View parameters if possible\n    view_obj = obj.ViewObject\n\n    try:\n        print_sr(\"View parameters list:\", show_report)\n        view_ignore_list = add_properties_to_ignore_list(\n            view_obj, view_ignore_list, obj_type, show_report\n        )\n    except:\n        print_sr(\"This class does not support View parameters.\", show_report)\n\n    # Remove temporary object\n    app.activeDocument().removeObject(name)\n    print_sr(\"\", show_report)\n\n    return data_ignore_list, view_ignore_list\n\n\ndef fill_ignore_lists(show_report: bool = True):\n    data_ignore_list = {}\n    view_ignore_list = {}\n\n    # List of object types to process\n    object_types = [\n        # \"App::OriginGroupExtension\", # Interfaces are not supported\n        # \"Part::AttachExtension\",\n        # \"Sketcher::PropertyConstrainList\",\n        \"App::DocumentObject\",\n        \"App::GeoFeature\",\n        \"App::Part\",\n        \"Mesh::Feature\",\n        \"Fem::FemMeshObject\",\n        \"Path::Feature\",\n        \"Part::Part2DObject\",\n        # \"Part::Primitive\",  # Part::Primitive is not possible to create\n        \"PartDesign::Feature\",\n        \"Part::BodyBase\",\n        \"PartDesign::Body\",\n    ]\n\n    # Add properties for each object type\n    for obj_type in object_types:\n        data_ignore_list, view_ignore_list = add_to_ignore_list(\n            data_ignore_list, view_ignore_list, obj_type, \"Temp\", show_report\n        )\n\n    print_sr(\n        f\"List of all not unique properties of Data:\\n{str(data_ignore_list)}\\n\\n\"\n        f\"List of all not unique properties of View:\\n{str(view_ignore_list)}\\n\",\n        show_report,\n    )\n\n    return data_ignore_list, view_ignore_list\n\n\nclass CustomDialog(QtWidgets.QDialog):\n    def __init__(self, parent=None):\n        super().__init__(parent)\n\n        self.setWindowTitle(\"Properties Generator\")\n        self.resize(300, 150)\n        self.button_strings = [\n            \"Only Main\",\n            \"All Properties\",\n            \"Inherits + Unique Properties\",\n            \"Only Unique Properties\",\n        ]\n\n        # Layouts\n        layout = QtWidgets.QVBoxLayout(self)\n        button_layout = QtWidgets.QHBoxLayout()\n\n        # Instruction Label\n        self.instruction_label = QtWidgets.QLabel()\n        self.instruction_label.setTextFormat(QtCore.Qt.RichText)\n        self.instruction_label.setText(\n            \"Select the type of report you need:<br><br>\"\n            \"<b>Only Main</b> -> print only unique properties of main classes with types.<br>\"\n            \"<b>All Properties</b> -> print all properties of selected object.<br>\"\n            \"<b>Inherits + Unique Properties</b> -> print unique properties with inherits report.<br>\"\n            \"<b>Only Unique Properties</b> -> print only unique properties of selected object.<br>\",\n        )\n        layout.addWidget(self.instruction_label)\n\n        # Checkboxes\n        self.include_prop_status = QtWidgets.QCheckBox(\"Include status of the property\", self)\n        layout.addWidget(self.include_prop_status)\n        self.clear_report_view = QtWidgets.QCheckBox(\"Clear all content on Report View\", self)\n        layout.addWidget(self.clear_report_view)\n\n        # Buttons\n        button_om = QtWidgets.QPushButton(self.button_strings[0], self)\n        button_om.clicked.connect(self.handle_button_click)\n        button_layout.addWidget(button_om)\n        button_ap = QtWidgets.QPushButton(self.button_strings[1], self)\n        button_ap.clicked.connect(self.handle_button_click)\n        button_layout.addWidget(button_ap)\n        button_iup = QtWidgets.QPushButton(self.button_strings[2], self)\n        button_iup.clicked.connect(self.handle_button_click)\n        button_layout.addWidget(button_iup)\n        button_oup = QtWidgets.QPushButton(self.button_strings[3], self)\n        button_oup.clicked.connect(self.handle_button_click)\n        button_layout.addWidget(button_oup)\n\n        layout.addLayout(button_layout)\n\n        # Cancel Button\n        self.cancel_button = QtWidgets.QPushButton(\"Cancel\", self)\n        self.cancel_button.clicked.connect(self.reject)\n        layout.addWidget(self.cancel_button)\n\n        # State tracking\n        self.pressed_button = None\n\n    def handle_button_click(self):\n        sender = self.sender()\n        if sender:\n            self.pressed_button = sender.text()\n            self.accept()\n\n\n# Function to display dialog and retrieve data\ndef show_dialog():\n    dialog = CustomDialog(gui.getMainWindow())\n    result = dialog.exec()\n\n    if result == QtWidgets.QDialog.Accepted:\n        if dialog.clear_report_view.isChecked():\n            clear_report_view()\n        if dialog.pressed_button == dialog.button_strings[0]:\n            data_ignore_list, view_ignore_list = fill_ignore_lists(True)\n        elif dialog.pressed_button in dialog.button_strings[1:4]:  # 1,2,3\n            name = sel[0].Name\n            act_obj = gui.activeDocument().getObject(name)\n            data_ignore_list = {}\n            view_ignore_list = {}\n            if dialog.pressed_button in dialog.button_strings[2:4]:  # 2,3\n                data_ignore_list, view_ignore_list = fill_ignore_lists(False)\n            print(\"\\n== Properties ==\")\n            print(\"\\n=== View ===\")\n            print_obj_properties(\n                act_obj,\n                \"View\",\n                view_ignore_list,\n                dialog.pressed_button == dialog.button_strings[3],\n                dialog.include_prop_status.isChecked(),\n            )\n            print(\"\\n=== Data ===\")\n            act_obj = app.activeDocument().getObject(name)\n            print_obj_properties(\n                act_obj,\n                \"Data\",\n                data_ignore_list,\n                dialog.pressed_button == dialog.button_strings[3],\n                dialog.include_prop_status.isChecked(),\n            )\n    else:\n        print(\"Dialog canceled\")\n\n\n####################################################################################################\n# Main code\n\nsel = gui.Selection.getSelection()\nif len(sel) != 1:\n    msgbox = QtGui.QMessageBox(\n        QtGui.QMessageBox.Question,\n        \"Properties Generator\",\n        \"You must select exactly one object in tree view!\",\n    )\n    msgbox.exec()\nelse:\n    show_dialog()\n",
    "url": "",
    "raw_code_url": "",
    "wiki": "https://wiki.freecad.org/Macro_Wiki_Object_Properties_List_Generator",
    "version": "0.16.1",
    "license": "",
    "date": "2024-11-23",
    "src_filename": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\Macros\\Utility\\WikiObjectPropertiesListGenerator.FCMacro",
    "filename_from_url": "",
    "author": "Evgeniy",
    "icon": "./WikiObjectPropertiesListGenerator.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      "./WikiObjectPropertiesListGenerator.svg"
    ],
    "parsed": true
  },
  {
    "name": "Align Face Object to View",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro directs the face of the object on the side of the ActiveView.<br /><br />Macro version: 0.1<br />Last modified: 2015-01-16<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/d/d5/Macro_Align_Face_Object_to_View.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "This macro directs the face of the object on the side of the ActiveView.",
    "code": "# This macro directs the face of the object on the side of the ActiveView (camera)\n# extact FCCamera\n# 16/01/2015\n\n__title__=\"Macro_Align_Face_Object_to_View\"\n__author__ = \"Mario52\"\n\nimport pivy\nfrom pivy import coin\n\ntry:\n    v=Gui.Selection.getSelectionEx()[0].SubObjects[0].Surface.Axis    # to Axis\n#    v = Gui.Selection.getSelectionEx()[0].SubObjects[0].normalAt(0,0) # normalAt\n    r=App.Rotation(App.Vector(0,0,1),v)\n    Gui.ActiveDocument.ActiveView.setCameraOrientation(r.Q)\nexcept Exception:\n    App.Console.PrintError(\"Select a face and run the macro\"+\"\\n\")",
    "url": "https://wiki.freecad.org/Macro_Align_Face_Object_to_View",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2015-01-16",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Align_Face_Object_to_View.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/d/d5/Macro_Align_Face_Object_to_View.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Align View to Face",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro aligns the current view to a selected face<br /><br />Macro version: 3.1<br />Last modified: 2023/11/12<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/d/d7/Macro_Align_View_to_Face.png\">ToolBar Icon</a><br />Author: Rockn<br /> ",
    "comment": "This macro aligns the current view to a selected face",
    "code": "# -*- coding: utf-8 -*-\n# Set the current view perpendicular to the selected line\n# Place la vue perpendiculairement a la line selectionnee\n# 2013 Jonathan Wiedemann,\n# 2016 Werner Mayer, \n# 2022 tchernomax, https://forum.freecadweb.org/viewtopic.php?p=630019#p630019\n# 2023 FreeCutter, modifications towards linked objects like in workbench Assembly 4 , https://forum.freecad.org/viewtopic.php?p=718516#p718516\n#\n__title__   = \"Align_View_to_Face\"\n__author__  = \"Jonathan Wiedemann (Rockn)\"\n__url__     = \"https://www.freecadweb.org/\"\n__Wiki__    = \"https://wiki.freecadweb.org/Macro_Align_View_to_Face\"\n__version__ = \"3.1\"\n__date__    = \"2023/11/12\"  #YYYY/MM/DD\n\nfrom pivy import coin\n\nimport FreeCAD as app\nimport FreeCADGui as gui\n\ndef pointAt(normal, up):\n    z = normal\n    y = up\n    x = y.cross(z)\n    y = z.cross(x)\n   \n    rot = App.Matrix()\n    rot.A11 = x.x\n    rot.A21 = x.y\n    rot.A31 = x.z\n   \n    rot.A12 = y.x\n    rot.A22 = y.y\n    rot.A32 = y.z\n   \n    rot.A13 = z.x\n    rot.A23 = z.y\n    rot.A33 = z.z\n\n    return App.Placement(rot).Rotation\n\ndef get_selection_and_turn_view():\n\tdoc = app.activeDocument()\n\tif doc is None:\n\t\tapp.Console.PrintWarning('Align_view_to_face: No file open, nothing to do\\n')\n\t\treturn\n\t\n\tselection = gui.Selection.getSelectionEx('', 0) # Returns a vector of selection objects\n\t\n\tif not selection:\n\t\tapp.Console.PrintWarning('Align_view_to_face: Nothing selected, nothing to do\\n')\n\t\treturn\n\t\n\tcam = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()\n\t\n\t''' used to understand the 'getSelection' results\n\tfor selection_object in selection:\n\t\tobject_ = selection_object.Object\n\t\tsub_fullpaths = selection_object.SubElementNames\n\t\tif not sub_fullpaths:\n\t\t\t# An object is selected, not a face, edge, vertex.\n\t\t\tprint(object_.Name)\n\t\tfor sub_fullpath in sub_fullpaths:\n\t\t\t# One or more subelements are selected.\n\t\t\tprint(object_.Name, sub_fullpath)\n\t'''\n\t\n\tsel = selection[0]\n\tface = sel.SubObjects[0]\n\tif face.Area == 0:\t\t\t# trying to avoid errors due to wrong selected objects\n\t\tapp.Console.PrintWarning('Align_view_to_face: Please select a face - not an edge or vertex\\n')\n\t\treturn\n\tdir = face.normalAt(0,0)\n\t\n\tif dir.z == 1 :\n\t    rot = pointAt(dir, App.Vector(0.0,1.0,0.0))\n\telif dir.z == -1 :\n\t    rot = pointAt(dir, App.Vector(0.0,1.0,0.0))\n\telse :\n\t    rot = pointAt(dir, App.Vector(0.0,0.0,1.0))\n\t\n\tcam.orientation.setValue(rot.Q)\n\tgui.SendMsgToActiveView(\"ViewSelection\")\n\tapp.Console.PrintWarning('Align_view_to_face: Done\\n')\n\nif __name__ == '__main__':\n\tget_selection_and_turn_view()",
    "url": "https://wiki.freecad.org/Macro_Align_View_to_Face",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_Align_View_to_Face",
    "version": "3.1",
    "license": "",
    "date": "2023/11/12",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Jonathan Wiedemann (Rockn)",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Align_View_to_Face.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/d/d7/Macro_Align_View_to_Face.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Copy3DViewToClipboard",
    "on_wiki": true,
    "on_git": false,
    "desc": "Macro will copy the contents of the 3D view to the clipboard in bitmap (BMP) image.<br />Copying in Gimp is not possible. Gimp uses its own method for the copy function.<br /><br />Macro version: 00.01<br />Last modified: 2016-09-14<br />FreeCAD version: &lt;=0.17<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/8/84/Macro_Copy3DViewToClipboard.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Macro will copy the contents of the 3D view to the clipboard in bitmap (BMP) image.",
    "code": "# -*- coding: utf-8 -*-\nimport PySide\nfrom PySide.QtGui import *\nfrom PySide import QtGui ,QtCore\nfrom PySide import QtOpenGL\n#from gimpfu import *\n \n__title__   = \"Macro_Copy3DViewToClipboard\"\n__author__  = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__version__ = \"00.01\"\n__date__    = \"14/09/2016\"\n           \nclass ViewObserver:\n    print \"run FCGrab ..\"\n \n    def logPosition(self, info):\n        import tempfile\n        import os\n        from PySide import QtGui\n \n        pos = info[\"Key\"]\n        if pos.upper() == \"G\":\n            pos = \"\"\n           \n            mw=Gui.getMainWindow()\n            gl=mw.findChildren(QtOpenGL.QGLWidget)\n            glw=gl[0] # just use the first element\n \n            originalsize = glw.size()                               # originalsize SubWindow\n            print \"originalsize : \",originalsize.width(),\", \", originalsize.height()\n \n            glw.resize(640, 480)                                    # reduce the SubWindow\n            glw.show()\n            Gui.SendMsgToActiveView(\"ViewFit\")\n            print \"resize in : \",glw.frameGeometry().width(),\" \",glw.frameGeometry().height()\n \n            i=glw.grabFrameBuffer()\n            cb=QtGui.qApp.clipboard()\n            cb.setImage(i)\n            glw.resize(originalsize.width(), originalsize.height()) # restore originalsize SubWindow\n            print \"Grab\"\n \n        if (pos.upper() == \"Q\"):\n            v.removeEventCallback(\"SoKeyboardEvent\",c)\n            print \"End FCGrab\"\n \n \nv=Gui.activeDocument().activeView()\no = ViewObserver()\nc = v.addEventCallback(\"SoKeyboardEvent\",o.logPosition)",
    "url": "https://wiki.freecad.org/Macro_Copy3DViewToClipboard",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/f5c3738f858f7b058897c6c235232cbe/raw/a10bc3b8789badc1e405541d4697d7286d9f0fd3/Macro_Copy3DViewToClipboard.FCMacro",
    "wiki": "",
    "version": "00.01",
    "license": "",
    "date": "14/09/2016",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Copy3DViewToClipboard.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/8/84/Macro_Copy3DViewToClipboard.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FCCamera",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro can rotate the screen in a defined angle and the defined axis and creates a plan to face the screen to create a form in the specified plan positions the selected face facing the screen, to detect the position of the camera, align view to face or to axis, align the object to view.<br /><br />Macro version: 0.15b<br />Last modified: 2024/12/19<br />FreeCAD version: 1.00 and more<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/2/25/FCCamera_00.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "This macro can rotate the screen in a defined angle and the defined axis and creates a plan to face the screen to create a form in the specified plan positions the selected face facing the screen, to detect the position of the camera, align view to face or to axis, align the object to view.",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2015 2016 2017 2018 2019 2020 2024 <mario52>            *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n# FCCamera 0.5 18/03/2015 28/02/2016 06/09/2016 06_13/12/2016 07_03/01/2018 08_08/01/2018 09_08/01/2018 10+11_13/01/2018 12_01/08/2019\n# 12.1_12/02/2020 13_2020/06/28 14_2020/10/20 15_17/12/2024 15b_19/12/2024\n#\n#OS: Windows 10 build 19045\n#Architecture: x86_64\n#Version: 1.1.0dev.39240 (Git) Conda\n#Build type: Release\n#Branch: main\n#Hash: f9ba94c70b139ece6ba5ffba47632d91b5c9c645\n#Python 3.11.10, Qt 5.15.15, Coin 4.0.3, Vtk 9.3.0, OCC 7.8.1\n#Locale: French/Mars (fr_MA)\n###############################################################################################################################\n#\n#\n__title__   = \"FCCamera\"\n__author__  = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/wiki/index.php?title=Macro_FCCamera\"\n__version__ = \"0.15b\"\n__date__    = \"2024/12/19\"    #YYYY/MM/DD\n__Web__     = \"https://gist.github.com/mario52a/4aa545c23b323cf68824\"\n#\n\n## Icon easyw-fc method\n## https://forum.freecadweb.org/viewtopic.php?f=9&t=24742&start=100#p363271\n\nimport base64\n\nFCCamera_Axis_rotation_X_BMP=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAKYAAABiCAYAAADa8ajVAAAABmJLR0QAQABAAG8MJxI/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gYdEjslocfhfAAAACFpVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVAgMi44F49tcQAAHPlJREFUeNrtnfmTHOd53z/v+3ZPzz2z9+7sjcVJEOB9iBJFUpRoSiTIKBVXRWVJKTnKUbZiRhXnv0hFZZWV0C5V7Eh0ORVHjiHKdGTKlEWT4iFBIAHwAnFj73t2zp7pft/80L0XAJIACJKzg3mrpnZ2d7a33/f99vN8n/MVt932b35ujBmlNVqjMYaxlM5awLCUYri1Hq3RKEMIgSWlAERrNVqjgYAJlhAtYLZGgwFTCixxvWBSAMrHYBCe1dr9Bt8qSwh5fTBqu4aXKiA8C3u5HSP9FgIaW2IKrgepWVd1anaeiMkghcRI3UJAg8pLucoxmx6YwuA7FSrxKbxaFUd0BuDEtHDQgMAMrXKa3vjRwsOLFNDJCrLahlQSIVoGX0MD83qwyo1Vx4sXMLE6CIMxHlI6QEudNyQw1zlm8wLTYPBUiVo0D0rj6mVcnScV6UOblipvTI7Z9MAUIHxMtI6J1xHCAmXA8hBsPXXuvPW/Lvlzd8+//Fiv8dHv2XUgMREGhY3jZfD8Mo7pJKKSCGEQW5DCPJ7Lbfr+4OTkFe/fF3ODRPA/1DU+Wo7JRmA2p1oTRIhXezB5n4qYJ+OO4YgMRuimYNaP53IcfPMvqe/9ygd+1n7jL0Ngbwal2fMvGsozE1rlMjR+mpVvCZACFAgElrERQoIwW87o8278HQ4e+wsO5HLIizbzygMlq6afr5wGWgmBECYISQZPS/Oqc18aUD4CEMZCKjBblL7o/V/l6SNPbVLpj/T187fH/gK9/6vv+XfyyFM82reZBjw9OYne/1UaKfZn1t1FEikNzWugimB+UiOERKFotiisJUyg0o88hbnpYnCK15+6JDdl31caLrgiWMsuApAI0cyqHIzSYATKqK2vIW7+Ggdf+yGP5vpRF1CwyzFi/NW5K6sBV0EgQpcRUgbis1lfSIMQGolEYjXHvG75Oj+ZnNi0pY/lcvDaDzfP/bUfXiQtfzI5gbjl6w09P9nMgAwniJBgpEEYhQz9l00xt1u+HqjkDWrw8VwOc/gHCCEwh3/AQ/3DF6lw2ciglKGDXcpmjxsHEhOhUZss8maYmnhflwtAzNTXflYPzRwhZWPv17q7iCbNMAomZaTGSI2q2YHhI0TT+CDkHd/g4K/+bJO6fiyX48eH/vwiFf7M5Dj2Hd9o/D0zTZ9dJMAYhNIgDUrbSCRGmKaasnPX73Lwlf+xBsRVlX6hCnfu+t0tsmcbsouMaU5wCglIgxEGZSykBC0E5jqqc6rKyKp83RK4FKwBs2nlZfAAqlCVazvgLKL5dET07m9y8OXv81gut2luGvjp+Bmid39zy/DmsOZHhN+b5oSmACMCB7tlIkghQWqaNQSrDagNyFzVDFJurX0LQ5LNmyxsBAEQwywjKcPYeZPNt/jCn17EKwEUYVTol98n+Zl/u2U2rekbHhgRqHGBQBoLIcV1W1axdebd7KUVYQLRKjAVQTiy2YC58vyTHLiEFX6RC+mf/oT0Z//9lgBmU0d+pJRIBUgfiYUSFkLSVHNcef5JHh4Y3WRvH5ycJPPZf3fJqNDK809uiXlZQsjmLt8VBi0N0gRxcrme59c0w9Hu2vu6CLqMSKUAqEmbiF6P/jyey3HwF/+dtgd+r3EVnb4OGh4YAUb6SCTKqMAd0SQTXnzuexdHdybO0f653weg/XO/z99d4jMNzzfDHIemTuIQ0oD0Ec2UWSQEi899j0f6By/ilR0PfmvT5zoe/NYmlQ7wpYFhFp/7XkMncjS5VR4kcOhVjokV5ghs7fkaExRFWMa/bElYtaJEvSoAtq4HKv0f/pjOz/+HllX+SXFMIzXSKBQWWnpbfr7zP/veJWPhXV/4g0t+vusLf8BPn/3uRVGhRlXphusgHxMJBo00Fqspflv5Nffsd3m0f+AiUHY/9MT7/l33Q0/w4wtU+oH+Aeae/W5D5tBaTWikbvZjhlEfS9sE2fpbeD46UN3K6E2g7HvoW5jLmFffQ9/i4N//8Zq0lUYHKv3v/4jeh59oGDVuDE3uLgqd6wiwiCCl2LLVkQBTG0AF4K+G+y+3dkcFriQfsalW6PFcjoP/74/o++J/bCyO2bzuIrMWkrRMhGvVdcQYs+k6F37/UYzJZ75zUXTnJ1OT5L707Su6Tu5L3+Ynz3xnE8B1w/FNgWzeQjQZJGuEDVptIlwL19jqBl4YYfoo56L8wEF+YXSn/0vfvqrr9X/p25tcSBJ4eGiMyWe+00iRnyZNEEYECcFSY0QoMaX40P2K3ktSmrAwX9er1ErL1IqLIARG2mA08fY+IrH0Vf3P8z+9QIXLQCVfde1OeM91ZWOHoHe8SqDS//a/MvDof/qE/etNrMpXAaiFxgiDZZzA+LmmkxX4dRe/VkG7JUpnXqc2ewqFwFISbQDbQQhJ4XwM1TmM0zGAsKMo2yESTVx2a5cLneRDj/3hh7rzocf+kGd+/F8u+bvAt/1JGj96Yz5mEwIzDEeCwRY217qzXa24SOncMbyp44hqgZhSZJTEXm1SJkD7gVPbr5eolBapzZ/FtaLIdBfRziFi6U7siPO+AB1+/D9/JGv0UV33w41gHZq2DaEI29khNEKC4toBU/setfwMhXdeQi+cJ20pYo6zuqCblzn0y0kgDZTKC1R9n1JhjpWFcbzBvWT6d2JZkcC1fJ2cIvKBVrmUskmnJjAiUOXKWCihrgnHBKhMvUv1zGvEinPEIjbOB6yhNgYdgrYnGqWuNRXfZ6k4Q23WwU9lUZkehLKu+97wQgh0c2cXCRAaLXwkCiUU16JUuTR7lsrJXxEtL5FQCltKXK2JKYVvDFIIMrZN2fM2uWNW22qXPQ9LStojEdojEc4tjbP0y1PI3C6yu+/BSbWvP1rXJUgFUorm5pgi5JgKCylU2K7p6ueqvTr54y+TKC+hhKDs+9Q1CGUx59aIYagZzVy1Ssa2yUQia/+trtejNZ7WrGhN3LLYn8ngGcPrsyeZq5bI3fU4VjSB73sIoa5DcAa5G83d6lqaNWAqwlzMqwSm0ZrK5HHqc+cQtkUBiUqkifSMEe8ZJRNL4S2M092/i7l3f83MOy+xVC+RtCxysRgxpaj4/hpALSkpex7nPI+0bbM3k+Gt0gKlU4dIbr8Dy4lft/yyqSM/AccMVLki4JjmCtscGN/Dr1Wxognq5WXy776KwKA7h0i15cjc8OlNn4+k2jBA+667yG67ieLZoyy98wrlQoHuaJSRRIKS51EM1XzcCvyRngnu65ZUksOnDnH67JuM/dY3UZZ93XLN5vZjCvCFR8TEkCi0uPxzfeqVAotvvkh1cYrcPV+mPH2S8tI0ifY+2m56ECfdjvce3UuUZaGsJJmx24j1bqMyeYKJ06+RX15mWzIZcFB/cy5lwfMwlsWnOzt5cXGJwrk3yIzuR0p1nQlMifGbnGMaGUpME3BMI/QHGj9G+7j5OWZefw5ZWqZtx+0o2yF/+gjJvjE6dt2Fle7E54OzslTEIRbpJZJsw+7I4c6c5tT5N9iXiBFViqVaDQOsQq/q+5Q9j3vb2/jFOy8x73t077wjaCkYGk9NzzkFG0+taE6mggiSOBQKKSRafDCPdJenmTn8D9Tnz9O7+y4SA7sozJzGXZ6h55YHifWMXvF6WRGHdN826m09zC7P8ObyFDdmMiQsi+oFknO5HoQI98ZsXjp5iKVYko7hGzBG0/RH32wGZvM+hVr4GBN04BDyg8/1qeVnKb/7K/TCOLFMF07vKDKewnZitO+8g1h7jg/j97UiUdK776Zw4jDHlif4VCZNwfNYqdc3+fGqWrM9mcSIMr85c4RK9xDxeAqt/TXpuXHPtA4PPmgKtR8GJKRs3idPCw+Exsb5QL1bWpoh/+aLWNMn6RrYQcctn8fp246QinjXEF17P420I+vS9SpOU5DKIt03RsdND1BJ93A0nydjWUTDUlsRRohcrTlXLtNtW9jL08y+9RK+763xzVVQ1usu5cUpChPH8dxK82ydEEF1VrNJTEEQ8dHCw6CxtQz6ZK7Oc22+Abi8SonFY8/zgC7S39/P38gkya7B9TQ3O4K0I4jVg6QNYDQgryrDJ5LMEhvZz9SbedoqVbYl4kxUKvjGoIRAATWtiVkWD7Rn+dnSFNX8HMmOXPhQaFZmzlGZO0fh/Nso2yHdv6s59lGI9bryprTIEfhViXAlMTePYgIsiVE2WDYoBVLhY6jnZ+irLvOp++/luRdepCig04mu53hrg0SjhUQYA1JgtMH4NYSIXDE4LcuifXQvSgnOHXueMaA/FmOiEki9iJTElCJtWQx1dTEzMc3JhQlEZ4785Ekq598mXVnGWpqmUKuTvvFelKWaRFqCFqxKzCYDpoBa2ZAfTxAr5cjYy6j6mwglMVYEVARsG2NFqHselfF3uD/mhE+rjxWPIbwaSAVCIoTGrPUvD9i5ijgY30P7XgjOK1/EaHuOubY+Xp05ycO9vWRsG98YHClJWBZCSoRlcXNnN2dqFYonDpGdPsHNtQK37d7NqVM+f+NHad95e9NoPREGQZqyGM3zDPPzdUrLEYb7b8Du8qm7VYRbRlaLiGoJqiXwl3EXponkZ9hz9504PT3Mui7xuEFNnwylawSUjbGs4L1lY0JpK6REGInRHkjr0u0cN52GuJmXxtJtdO6+i2q1QERKukdHKZ8/v9lT4Hm093Xz2ytFKE2S6GsnOXIrXrHI8yslnJ37sJ1oc/Gw9QOomgeZxhiWljxmZ2t0dUfoGXTwhcLE0kG7mNWnUBuM51I+9iJjlUViQ8P41SpxpZitu7A8j0KHlZYS5DoNMCFAA5DaaKGCgrBoIij4khIjZFiSGT75a0dXbl7rWEcfhb7tvDr5Jl/QGjuToZ7Pr9EDYwyy7tLelkIno2jXRSjF4cOHWWkfpGtod1Pt32o+Q9NxzFLJZ3raxXEkAwNRlBT4vn/x1gmB73tEgT4nQiSbwS+X+dzoKP9tfJ7q0G6cZBuiVgW3hKiWEG4FalVkcRm0B8aAEGihMFKA5YAdRUQiGMuGUOIaO3yvLJAKIxVIGQYBJFYiw+tll5Hjx9k2NLTOWYVAuy71lRW8QgG/UiHW30/57FleLlaIbd9JNJZoOhomRJBL0BQHAwgBrquZnq5Rq2l27EgQi0l8/739tMb38UvLDMfjGM/DaI2dTmMvHeXsC/+XbV/4GlaqDTIdoaQ1oDVoH1GvQS2gB9QqSLcM1QrCLUElH1jtBlCrQLTWpawVCaWvhbFsOtq76f7iN5goLdFnF3GqVfxqlXw8S6a8jKnX0VojlCLW38+zzzyDP7CL9t7hgNuaS6+HuZg9bAmOycaan618yKkQq7yyxuJinYGBKJ2dEbQ278ufLdtmeXmO+HAvulbD+D6J0W3sOXqUtzI9SMtCGB82RmdWT+F0ohCNY0THZvboe4HhVK8hahVEtRyA162gqyW051IrF4gnsiAlSqmAwyqLFcvmOSsCnXvXAGwL0FYEKQQdos6dZ97gULFM5pZdOPHE+j1tfuRCR3Xw1qz+zGwhibnusDVbFpTGwMqKx9SUSzZr098f3fT79+YzBtuJ4Vcq+K4LWqMchwf27ePoCy8w4cQZvuu3LiVrg3+6oSPGGn8UQMTBRKKQygb5TOFNLp18ncVTxxALk+Tw2HHr/WTSMSYLNUzNxSsWKCPXpYSQaMvGSIVWijnb4SdWP7k7OwNnfGEhdH3ZgQch5MK+7+O5leAztoO07HV6sFECNaA0Wo1EWqtm0FalmkJAuewzNeUipWBkJEYkIvH9y2hCIAXZ7kGW82fpSaWoLS6iXZfsjTfyeysrPPnWUcYjEXL7Po2ynSuxwFg59zbVlUU6tu/HiiYAgR1LEokl8CIOY5Eot8fqWNEow3PT1PN5pB2kua04KTCad1K9tJeXqdUNi9rBrRbxfA8HgSguw1JgdAX81QY7ApEo2nOpz07gezVUugOnrQuVSCMiUYSyw8OPxEWBhsbYTwkC1Gc/e+AJIUTbmp2+hV5CCOp1w8RElaUlj9HROJ2dTqh5L+PvpaI4fYb0yhz9g0Gkx/g+2nWxUyn6CyscO3cKHU8Tb++7ontzVxaZOvI8WkgSnTmElDjJLJnBnch0B28WSxw68S4di3P07t6N096OVy7jV6tEjYfj1+mvLNHuVejyK9i338vckVeYcpIkBnchovHAZWUMwg9oA5USopxHzk8ixt9BTJ9GLk4jVuYwK4uY0graLWO8eiiQ1brubKA9NWjUvfceeEIp0bZRv2+F16pmmp+vcf58lZ4eh6Gh+Ib0sMt5CTytmR9/lxuzaaxUKjBuAGnbpLJZ0suLHDtxDB1Pk+jouazrYjTu8izeicP48+OITBfxtq6130fTbXSM7EGnO3h5ZppX3jhCb3GFgbvvJtbbi7uwgHbdEDySaG8vXbUV/urQr8nd92Wsjj7IdkJHL6azH9PRB+09kO2GeIq6V6NeryFjCaQTBd+DaglTWQm+uhWkXw+c2ZaNsKzVc7kaYG/DuvL1Q07NluOVhYLH5GSVZFIxPBwNjuPTVxYwyPQOMZfqwJ2fJ9rXF4TBfR/jeahEgv333EP0lVf43y89ja5VyAzuwEmkkWGDqvdyEtfdMhnb5tG+Pr7/j39F5a6HGbjhzk0f6xgYo2NgjOXpszx16OfIH/yQL/f2cPuBAxitWX7tNer5PInRUQ7+6EfEd9xMLJEOXFUbJ6kUWAlETGDSbZhEBt01gPG9sH1NkPMptUYaA5hAWkq5QaM3hp0hhcAXG8qgt5I/c9U1NDFRpV437NiRJBazLo9XXsIh72d7+PFbv+are/YgHQe/XF6LugDsO3CA3Msv8/TZoxRLS7i9o7QN736f1ZV4lSI3ZNvJ7dvHvwb+5+vPM2nZ9G2/aa1x/+po6xuh7dFvUJib4K9ffZa/fvJJHunr454DB7DTaSrT07yyUmT3Q5+99PyMgbC7sACi8SSxVJYL402bYKd16NLSG4ytBsBAKDXVffc9FnLMrQNK3zdMTbnMzroMDcXp7XXQ+iqfUGVhJ7PMzk8SO/kO3as9grTGaI2p1fDLZZzOTka9Gm3Lc7z+1m9YXJoLHOCAHYluAowQgvnjh7ld+lRnZ+keHWXMq/H6xFlUtoto6tLL7STS9Oy8meTIHn4zNcHP//FZ9MmTHDn+Lgu5HfTsuOmyjS+jNUb7GO0HfTUvfK2CsuH2V6KNh7r//sefEIK2VeLZ2Of2hI3xF+ucOVOmvd1hdDSBlKtBmKu7ru3EkE6MxflpRqolot3dGN8PLqp1AFLPI9LRQdfgIHf29pCeGcddmmF6bhJhWVQrRaxINOC4WlOdPU9PcYFOx+GN8XGGslmcaokjJ98iNbgj7Fv0HvcTS9I+vJvEyB7eXpjj3MIMYw/+NrYTu4J5XR6fa8Q91tpHPfDAusRsdGNHyiDkePp0GSEEO3cmiMWsNUf6h7q+7ZAvFynPTtCnJE5XF7pWY6MoNvU6ulbDSiTozKQZxsebHWfixOu4cxNUlufx3QrFpVkKp9+gTXsMJBLMV6uUazVuGBxEFvP88vCLxLv7iafb3xMwyrJwEmkSvUNkRvaQaOveUsbpVb+kBO1tjJWLhlfh9XrAK0slze7dCVIpOwTlh7/3SDxBcnQvJ8sF0idOsrdSIbVzJ34IyFU+anwfr1AAIDk2xv39/dyTzzN+5gzn5s8wfu5N8r4himakp4dl10UDi7Ua1tQU995yC9ljx/i7Qz/HisTIdOXe9/5jyQwkM1wvQ4rgPHkrMM8b2yoXIhBcc3M1ZmddcrkoXV3rvPJacHYhJPG2Lurb93Po+GsUzk9wZ71Oavt2DKA3tHyBoHCtOjODUIrawgKOlNwxMMCt5TJWMsn8wgKd3d2cm5pChtbmuXKZytGj3LhnDytHj3LotV8Q/8wBnESK1li3fsLIz0Z3QeMCc2WlxvnzFTIZm+HhGEqJEJjX7r4tywrcN8ri1Jm3mJs4xSNAdv9+vGIRXa1uqvURoXWt4nFqhQKnZmdRQiDLZSJSMjMzQ8nz1lpJR6VkqV7n2FtvcfvgIKfefpvjP/8RNzz8O1gb6ola2BSoBx4IjJ9G5ZVCCKpVzalTZVxXs2tXknTaRut1J/u1/r/RZAaVypIXil++fZQdSwsoy8JOpQJr1/PQ9XropgmoRK1YpOr7GMA3hpLnrTU10Mbgh4CWYRWk5Xk8+LnPceroYU68e4yObXuwIs71wSM/YL+N8VdPRmvUB0fgeT4TExXy+TrbtsXJZiOhE118ZK43IQTxti6imXaME+PPjvySGys19pw9y8gdd6AtC2FZ1JaXMb6PCCsdpRDrAAR8wNd67Wew3vlNCUF1ZobBeJzTWETiqeu+BeHq2gtCVd6INydlUD+9uFhnaqpKd7dDf39sU1eKj/oelLIY2HsHpb4hpsZPcvzdI+x//nl2xON0Dg2holFENIpXKuGkUkjXxQ2l5MY2BnrD/da05lM9PaholKdefZXC6I3csP+eFigvUOUNm8FeLFYoFDzOn6+RSFgMD8exbXXNrPArGYn2bpxUG1a2izfGT3BsYZqOI8f4dFuWjs4O4r29qGiU7kKBvJT4xlDxfVytqW8ApWcMN2ezxAcG+O5zzyF23MzoXZ/HibeMn00Sc/VktEa6KWMM+XyBY8fOs7DgobXFbbcNkEpZBK2gP5loRMRx6BrZScfQGG4hz8LpN/nR1Dl45wTWkaPcms0wEouRsixsKZGWxUypxLTvowFHSsbicbIDAzz5wovUhvdw84P/vIXESxi6bGwR0wg5o0GbY834+DRvvz1JsVgnm5Uo1YEQjeHLU8oinu3A2f8p1C33UpiforqyxLHxU7w4fhIpBJHiMl8bHEAJQU1rIlKyr6uLlVKJ7x86jL/jZvbe9WBLfb+/xPzojIir81f6zM0VqVRc4nGfkZFuUqnY5ieqAYYV9rZMdfaS7uqj1j/C6H2PUpyb5Oj/+VNKnsdCrYZvDLeNjFBZXOTPz5yh7/5/Rs/OfdhOrIXC9zR+QonZSMVopVKVfL5KW1uE3bt72b17hGQy3TBS/VILCRCJBvU30nLIprMIIGvb7EgmqRcK/Mm583R95hH6b7yjdTLFZQiohjF+VnMsXdcjmbTZtWuM7dsHicViQSjQmC1R/lEpLhGLBGUYQ6OjnDt9mqen58jeeh+jt36mhbrL4pibIj+NIHkM6XScm28eo6Mji+PY+L75xIyeqxl1t4J0K3SM7uDw22/zQs2n8+7P07frJlqU8opUuWiom0omoySTsTD9ybDVOoUk021MFPP86sQJfraU58bH/xXZ/tEm7vd47SXmmruoUerKAxCut0bZihKmXlphwXX5J9dnzyNfoWNorIW2y+Tpq/Xwa3XljVi+u1VdKUuTZ4nmRhi94z66x25ooe4yxqoNYVnWWrdka71DmWmt0Icc2vdoHxhlYN+dxNs7WwtymQKoXnfJ55eIxRK4boWIE9vYIqbFzD/skMqic2zP9XcEytWCEoGSFr7wqFTKzM5OY1kWvX0D68DcSuW7jbzU64ejtMYHrZVvPEq6gIooUukM09PjDPQPk0ymNsbKWxKzNT5eaVkxJV5zXyZlZdge30tvTz/t7V1ggrzVFihb4xPglpIaLmf940yaczjJOKOjO0mls1Sr5RbHbI1PCphhb6+iT3F+ijP263R3DdLe3YdUcuu3IWyNrWmJgyE/K/He6CJ6/A3G/acRuWGS+2/HtHdvNH5aErM1Pp5hDMzPuxz5lYs/PUhbtEiuPUrGiuDNTuInkusO9pbEbI2Pz3NhcF1NLCIZ29ZGPLYLu7OTWKadaDSKcqJYIji6r8UxW+Pj45ZC0NMTJZ3uBtLU6n0IBE4qjRVLYOoulhCizoZTRlqjNT6O4TiSaNQBHCAbqnhDkHVr5P8HHXJjAOGFLnsAAAAASUVORK5CYII=\n\"\"\"\n\nFCCamera_Axis_rotation_Y_BMP=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAKYAAABiCAYAAADa8ajVAAAABmJLR0QASwDCAEulRQgRAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gcFDDAOUPoZTQAAACFpVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVAgMi44F49tcQAAF7lJREFUeNrtnfuXHdV15z/7nKq6z36on1KrpZasNyCDJDD2EHuFBAYTnITENolX8kPGXv4x/8z8yposrzwmmfEww4CBEJFA7JiHnciDETIIBEKvfkn9vK+6VXXO/FB1X+qWEEi07m3VXqvW6nX7Vt06db713d+9zz7nyLFjP3zVWrub1FLrDrOONoMOMKWUTKXPI7VuMRHBUUoASZ9Gal0ETHBEUmCm1mXAVIIjdwomBdARFouETtr7Xd5Vjoi6MxS1WyfsW0VCB3dpCKuiFAHdzZjCncCagQ6ou8t4dgAlCqtMioAu5UvV0JibHphiiTJVqvlpwnqNjIzE4MSmOOhCYCZROT0b/BgToZTGWotc4+2y1hBZH18WiQoV3MoASOf3r3d+arcJmL0QlVtrkzRC531q7az7eRTViaIQowOsjqhlr2D6y9hsQDVYxJrTDMk+lNLEGjsFZlcBs6Uxu7tToihAa6/Jko2ATUSaoLXWUKkusDhyGiZ8cC3K1ShPUfxwFyu5C4hr8fa4yLDPTP5nYCEqWbZdfBDPFluPpu26VwPfWou1BqU0xoRcGXuXkfkvp8C+pRqzR4CplNvOnyilOkBjTMjc8K8IxpZx+lwyI0WcgQxKS5ytLYXgRYg4aOVQ/N0cg4UCpm6oL9RYnj+JP1vBlC19Z3bTJxN4Xr4NiK3fjEErWGuY3fYfhFtKMG+5U7IbG5Is6hVgaq0T5gxxHK+DvQwB5w+8htvv0bd9EOVpUHF7TGRjIA+HeIt9hFqT2Vog8gOiuqA8hTecI7utgPLGqFwoUR6/SGnpLM4HAwxUdpHLDeL7JbLZPkDQ2kFEmHF+jd1WhRqJJEgZ89ZpTNqB2f0RquM4HaAsOdMs7HmX/PYi3pYMzfSCsU1wioDdWaUwO0FNLeFWikTD5fhrdYOpG5SngIDsWI6+fQP4c1UWB+dZWHibzG+2MpLZ19SzUeRzRX1Ifd9lDn3nPk797a+wNkKpNGl/y6AZR+UqCX66F5hRFKK1gzEGpRRBUGMx+zHl3efI7+zD7XfpyHm1gbLZ2KqD5EDQnTLBa7ngsBQQlgK8wQzbnthF5dwqC7lZLi0tMPLRYYqFEa6UL1A7Ns3upw6xPbeVU4DWbsqYt5QxbTwkGT/T7n2wSrlEUYhSijCsEimf8q42UK554+LRgyYyQ8H2+0h0Y+2sL/mE5YDc9gK7njrA5RMzzBdPUP5wgsp9lxj/3UmmCtvbfq9T96Z2ExmYVrpIoZTFdrknd5yYMbV2mNl5AqfPRec07dSoXAUi2Mi09KWWWHe6IIHGLbhQcDDBtUd+RAvWWPy5KrJNce9DRziz92OmXzjLlqOj3DV1kMv+AluzY60XISXMWxX6NDQmgEKk+zWm1hrciMArxYFOAkSUEC77+JdrRNUQ0YpGkGwNEMCAvwPrQn2mht1q8IazEFnCSoipRx2ghGS8tuCS0R5X/AX2jO9m13/ZSU7nmPcvE1nTdl+pvrylrpykukgp6XrGbNjlofdxim4TlOFqneqlCjqnmbr0W3iSIVoRbBg3EYTQq7A88jHKKsozK1Rfv4I4UNw7QH5nH5nRLMFynbAUNEHpDmbIF+OUUWBD5v0r9LtFFuqLhCbsSA99Hn155sDLRLW1hST7P/m9m3o+p6deXPfzm73ubQCm9JRwLxdnyQxnQYTadJmwFLBz6CiZX8Ru1cQqpeVaLSAWIwaFw7bZQ9g5Qzk3z1L5E1bfO09+qo+Bw8Pkd2YJSwFOMWbKJiOKRiGUgvI1o8jPantPf5P3d77Aoz98vOPz40+/yIFzT3yuZ/P+zhd4+NuP4wy1PiudtLzxxj/2Th+LoGwSlfcSMCMboHOFBJQh+z74ZqxMpF2ldDZUNIiyKOuSzfZhCPFMni1zU4TaZ6b2a6Y/OcvgkRHuOnIPga2zWF/uAOUaWXGTjPlp6ZLPrcXbQBlV4I03/pGD57/VQ+UQSYK9NaLR/bfs6xKiBVM3BCsBB5YeRbS6TqYrbpRVBqsMuu4iClQyPg6gyTG18CB1VeH8ibf45cevM/XEPiZy41z2F4nsp9dtKvX5Ht5dF3+f408/38Gaj/zgcV75bz/hrou//5mudWr78zzyg072XXpRbur+bhswbY9VF9W9VZSnqc1UGChsxZ3zMNetQRGwFtEGlEUbF4XCil1zTpYC+2Z/h4WVT/jw797mylfmOXLvERbqi/iR/4UAE+Ce6T/g+NPPNcEpCh794eMcf/p57pn+gxu6xsltz/GNP/om7aOilffhxOKL8TV6KpOVALNRXWSt9MRNR7UQ5Wq2n74f06T+mABtoi87zlCAslixaOugFBgR7DXQPFTdzfzAaeqXa2hRBCa8jstt9PjN97ypgcqugfwNn58ZkY5r/fynL3HP9JM9mS+SuJBDmnm4bj9CHTOXa7NIJPGhbDP3pa5qSyPHbnXiyk0yQnSd3/hky5uorcKx37mfef8K5gZc+c226/DMk/zz37zUcc1HfvA4J7c9+6nnntz27BoXvvxP+pbc1+05pNGXcVSuFF1/5KM+AAqrw63Pr3PvouLaPisWqwyO9VCiUGr9c2b7TlHZcpmjv3c/1aj2qS685cpv/rh37kmOP/1SB9M/+sPHeWfrs9c8552tz/KNP+x04f4Z4d9nf8K9c0/2RJ+uORJwOg2U9oLOLNqRmDFN/oaHAK0AyoBYNG6sB9eZS7/oXeTy4BkOfftetGiWkqj8uhFwgohbORxpfFCZq4F/7etnxqTj3J/+y4scufzHPaYr13ZaTy14oHHaXJTcYBtjNy4Iyjoxi151blWv8MngL5j8471sz28DIO/km2kilXxfi77l6Z12O3rl2/zzXz/TEaU//P3HePWv/jdHr3y747snhp/h4e8/1pnjfdX9QtJXt0No9tyCB8cWvrNuunJ9VCZBXgJMjV4D6kB8TvX/E2KES899zPnqBxuad/xUVtYqidKfabb9P4b+Fw//4RM4ujUs6p8V3jz/XPydnh+3l829EoeIYDWgIhQOWhxE0RG5e2R5YPmpxJ9//kjyVtn9i9/l+NM/5pG/eBxxr/0COGMtUNoAfnr8Re5f/O4m6cqkumhTV8aIxSiLsgqFE7vlLm/wV5af4pUf/c/OxPv3H+eVv/px8+92e+VHL/GV5ad6W1e2OzqzSRY8iCTomDzWboHUMRKiUGirQYSSXuBU8ZWb+s0HV/5kY98vzZpxdYD6BdkkurIz/+Z8lkDidtmbff/AocpvMxBtXV+H4V3ThVkVIdogxIwpIvTbEfZXvs7HW97i4FOH6XP6OqPgtudxdeDjiMPxp1/6wp/ZV1f/lONP/wMP/8VjOO76VBgGhn996WW+uvqnm0uNqR6Iyk0yvhP0V5ElwagIlEWFThxx20ahlKwv/pTFNDQmTpJcF4bNJMFyldPPvsuhPzrMFX+RcKUe/2ZouFYd4F27Dm0YQ32t9D1e/dHfr8uUAK/+6GW+VvreJgwReiD4CaQKQC2zivFCdOBC1Ii2QRuNxVwDmLHGtMqgrEbjYFTYbO+2aD/RQp0PXn6Pg9+8m9lojqgcNt3J9YpUb7eXiWb05nPhzWSKtEZ+uvWoqxiYy8yAsh3/UygQixJ9zfNRYDEo69Ao8Ws/dgSHKUyP8MHr7zNeGEPc60cQjWqjjWr/Q5U/6xgRati/PP8THqr8Gd3ef5/nUC2N2dVyA1FCNVrFCzPNyNMSVwiJlWvzvaU56uMYNx6DXQd3++sPcvLMa3zofcDuY19iNprrmG6x7n11QQS8Oee/xbMpuj5d5OBRGBnAZCLMSoS2DhYbl6/RKl9bF55Jch2Jr6OUYNdpbJUSvi0hK4IWjc7pGJjXcefd4EI375ThHkgXuWQIqwG7H9nLm3M/5mjwBLlafxOIgqxb7tbk1WRI0rEeV08jiQg577zLpdx7jDy8jfGxcWZWZjG1COWoOAi6Ohi7xgJfKTBvMTC7vbo5R5GoFjJZmGDmrmlOnHqR3/K/1wSlJMWYa4EpWDGxKwdcvOZwpMUwp87yUeZX5Pbn2HvkEIENmVuax0Z2TU5tPdZMgbkhUXl3W14GmKnN8cADD/BW/U3+7cO/5+vl7zWhadvYs9U0iQuClcFKzJihqnNRTnPOfYfMZIaxr00w6PWzVF8hqoZYY1vC1qzvwlPG3Jh29cTIz1htiun3L7LjyAQPPvRV3tlxkp+9+t9jUCp4qPIdtO2sFVPESwlWKVEJVjnjnKDiLTN4ZJTD++9jyBukFJZZDlZbD0RJB2MqR+H0e0TVkKgStGWgBCsRWm7vfPLemsvzWYIf0xsjPxPs4+zbvya4N0SL5vDOe6j9+R4+mP6IhX+f4+fmxyQh+lUSU8gM5yjs6WNo5wjbc0exGAITshTE9ZY5nSWns9Rcn5VglbAcJNG8UBgoUHQKkCGO1P0Qi6GRuJfbnP/dnIwZpxp6Yl65R5Yxs5O333uHo4fuAyCrcxyevBsm7yYw8XTbugmIbIQjDnknS9Ep4IhDaEMiG1E3dYy1Cbg6LaszuMrBd3x8E9DvFpm9PMeHL77L4JdH2XXfbmbnZwnjlRSaMiIF5hcW/PRGMmx/8CCv/+IZZnbPMZYdbZGiNTjiMJoZjiNta5rAi2xEZKOmLuxIQyWAVSLN/2vRjGbj65w6+RtWf7nMUR7jvZNvcHHgImNT4x0adsOAYe8cYMYL8fZQdVGGLHcHX+fkMz8l99RX6HP7rtGHLVA2nUMb+GJQqQ7WVCJkVIacznKm9AkXXzjLcGWCr/MojvYYsCO8/vr/QXnC5OSOpr5TG/XgojtLYyrVI9VFDRuXKUz1P3HimTc49ORhxrKjiChs2wJXDdBp0Z+6WIErHo5SOOIyU5vj3GsfY6ct99qHGVYTzVGmrOR50H6LN177v6jHnGRW5u2XQJvTlQv04tpFE3ovbjnLO//jNeZ+e4y7dx7qAKcWRWivvcSgSsZidVIefrZ8nis/n8W/WGM/DzCpDqyrHYsyyIPmW7z58nMYTArMjQFmb936mJ7kG+a7vPfaW/ws868MfW2MqYmdcQSd6MfIGhxRSeWRAolB6xufC5UZVj5aYvntKxTtIPvC+xlXU5+6wP+AHuZY9J95ixc2fE3M9Qo5NvPMA/nLv/yvH4mwu1cb4Nsq5+Q3XJIzRIU62W1FnC0ueiCZ0RhZTD0imA2pzVWozpXYkhlja7ibcT1FQQY+82/ORGcZURM44pHarUakwkT13tKY61lW8uznGPs5RlDyWXx/lqotUbVlarrEiponY/Psie6joPopZAZQEq8w/Hltm7M7BdAX6Mlls+0l6UmGcbWzmc5Z0Vc4451gIBplh3+AUPy043sHmJs3UWskwtp4BQ7pgpGa1G4wXSSyiTdbEDASghhcMunq/b3UdSLx7KzNxpgCGDEYice2XaPidTIb7exYBxvS3aG7CpWteeWbjyzjXFhUU4ivyPnLaC6Co7DaBccFrUFpbLwsHK0JebJ2bp5N0buBuMQIDcbcfI2rVyzLFwrkyhMMuEvo4BSiFdbxQHvguvHfjgeuh3W8BLQeaAeUwipNsqYMbXM46PzDJkvKpcC9VW68uZ3KZgNmGFouXw4oL3lMbb8LdzQi8GuIX0HVSkitDLUyREtIFAdIaAfrxMC0jhuDtQFUxwPHabKtTdi2ybTNKdCWtZsTtGM2Be8N6bDWBlSbB5nWWhYXQ+bm6oyOeYzvyBCJxub6sUJrMpqxENUhqCP1GlKrIH4J/Aqq7kO1BCZMajPjVUWbwHS8WA40gZwB7caAbrCtJCuRNoDbxOz6c5NSzLZkmLAJNWa5HDEz45PJKCYns2glRFG0Fg4iMYi0i80VsYOqhRkTIVEEYYDUa+CXkVoZ8atQr6FKSwlobSzWlQOOE4O0KRNcSBjXusnf2kl0rQal4gr8BtvKdd+2O0pjihDvWtEbGwN8eoN83zAzU6deN+zbVyCXU0TRdfK01raxVdR5MaUgk8Vm8yDDCYAsGBMDN6hDPZYH1KuIX0H8GlIrQSWM9wq0gG4A0WmybFPbOi7WTdhXO1jlINpp9k4LtNdF7bps2yDpXmNiSdreHPnp5ZdSpKEr6ywsBExOZhkZ8TDGfk79bFvAvbpSqbETQSYL2TxWhjvVYxQiYUMiVBOJUAG/CkEC3CiMJ9ApFWcHtIvVTlMarAWwg9UOIrolK9q1rax3/xKv6N3EbW/IhSZjNlHaoyKn8VKtrIRMT/sMDrps357t+P8XoGTXglbaUk1eBjI5rAy2AGQtmAjCesy2foNly+DXkDCASjVmZBrTjlTCpLopFdqzCLiN1JcbB2MJaKMoIvSr8XIrbgbluEhjJKWdgbqQjRojkU4jDOpVqSkClUrE9LSPUsKuXTk8TxFF9vYNHFgLa4qUE9A6HrhZKAxgG+7aGoiiWLcGQaJlK1i/ivg1VL0KtQrWrjaBK0onbOsk+jXOJOBlMaFPMHeRKKyj+4fJbBlFF/oRL4to96psQnf5e0nSc810US/qTBEIAsPMjE+pFLFnT57+fpcwtN2ZaWiIvqtB22Bb7YL2sPkijT1SLBYxBqIQ6n6sZ+u1WBr4VSTwIfTBr2AT6eKUl8lOf0RQWYFsETs4TNQ/gvQNQXEAyfUjuSLKyyVpL+myfpXYlSvVfBF7zoUvLATMztYZH88wPp69CV3ZBahtuNZoPdBqyBegUOzY1c1aC1GQ6NoAWysTzJwlqKyiCv3xN4M6dmEGW1pE8v3YwiC6fwj6h5HCQCw9uoQ4peFYWpuc2p4D5epqyKVLNYpFzdRUtvmCbb5R1oamveohNExrcApITrD9W7CFAczoJDYKk6UXQQPKGFSSiZCGJm169O6IM5QIUSvB3lulb43U0MWLNYLAsm9fkVzOub268rbitiUPBMjmi+T6Bq/OMXTCzpgkpdW2enI3PDtpc+Uics3F9bsRlFFkmZ31WVoKmJrKs2WL23NS5AvFqYmwN/RAurHPY+Zuq2CXngAlwNJSwKVLNYaHM2zfnusQzal9VhB0lykFEtG+X7ntelCKQKkUceFCFc9T7NqVw3UVUWTSOuBN867EAwNtY+XS9cAMglhXlsuGgwcL9PW5SRSeonKzmJJ4P3kn1pfdHZWLxFp9fr7O3JzPxESW0dFMU1emuNxc8qIt+OluxhSBlZU6589XGRhwmZrKobUkwExRuRndudPNjNN4YarViHPnahgDu3fnm6mhuDIq7cdNhEcg9o5dvQa7iBCGERcvVlleDvjSl/IMDnpJEl1SN74pwRkXCqtuvTmt4xGLhYWA6ekaY2NxaigNdO4QV96tHV0qVVldDTl/vk6h4DA1lcd1dRqF3wmM2dgZrZtuylrL8vIqJ0+e58qVEGMcjh2bpK/PAWzquu8Endm+RIy13QFMYwwXLszw3nuXKJUCBgcVWg8jn2NVttR6mjG7J4iI85UR8/MlqlWffD5i164x+vpyayK31DZz8JMwZjcVCZfLNZaXa2zZ4nHw4FYOHtxFsdjfNaye2sYQVNcEP40aS98PKRZdDhzYw969O8jlclhrsTbVl3eOxuyiBHtjQlx/f5777tvD8PAgmYxLFNk06LkzXbl01U0Vi1mKxRxKSds0iRSVdxJjNtNF3TKvPAZhMgkrdd13FEvGFk8ibM4r78bpu2kS/c6xRgzhOE5CSM10UbqMXmq3j4CCwGd5eZFcroDvV/EyufYlYlKGSm2DQYmglUMkIdVqhbm5GRzHYeu2yRYwe2n6bmqbA5aRDSmbVbSn6esfYGbmApPbpygW+9rHylPGTG1j2bJqy/w//036nAH25u9m6/h2hoZGwdLYQDYFZWobrS0VdXw+iU5zyZ4jU8yze/d++voHqdUqqcZM7XYBM1meqRRRujzNWfdtxkZ3MDS2DaVV7y9DmFpvRuJgWZ5ThO+Okj39Lhei55GJKYpfvh87NNYe/KSMmdrGmLVw+bLPr3/pE83sYEu2xMRQlgHHI5y7RFQothLsKWOmtlFhD1h835DzFHu+tIV87gDuyAi5gSGy2Sw6k8VJ9pVPNWZqG6ctRRgfz9LfPwb0Uw+2IQiZvn6cXAEb+DgiEtC2y0hqqW2EZTKKbDYDZIDBxMVb4qpbq/4/AKwW9JyDTc8AAAAASUVORK5CYII=\n\"\"\"\n\nFCCamera_Axis_rotation_Z_BMP=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAKYAAABiCAYAAADa8ajVAAAM3npUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjarZlrduy4DYT/cxVZAt8gl0MS5DnZQZafD5K6r+3x3BlP4j5uS5DEBwooFGS3//Pv4/7FT5IUXS7Saq/V85N77nFw0Pz9M67v4PP1fZvqcy18trsanwsRU+Jvuk/b64GNnXvCc97WM87AXj4MNJ6Bwvx8YYxn/PZM8NhfE6VwT+D1GWg+A6X4zJzv82diX3uTj1vQ/NrZY2n3r7OvnCTWUoNkvnP0IrVz3KLPgt+0MEOKcSfuTXKt4z3h69y9DF8eCclf3/lebbp/B7+V78g9L0u5LS7djsa5naUw07Pn8wIBr37y0evvlx/3OvjJ9p7w+Az/+/BLXHT5PiykPnekz2g6/4qX+gXmxx7K9/BfGH9ckaznMH6+EMIrQp6f9uv3HG3n7Ht3I1e2Xt2zqZcbryNunOa167HKR/gtHMv16Xwa6bNAXAm4yWe50EME6xNy0DDCCfv6u8JiiTnuKPyNccV02RqY9LgAntCwTzhRUk/qUiMeFmgkzPG9lnDN26/5VmjMrIE7Y2CwYHH09eO+M/6Tz3ugc9bt4nZBH26Ao4UlyzDk7Ju7ACScx6fl8u/1cd9EqgGbQLBcbm5scPh5DzFL+BVb6cI5cV/x2fk714LoMwAuYu7CYkICAV9DKqEGLzFKCPixgc9g5THlOEEglBI1uAM2KVXAIRuYm2ckXPfGEm8zrAkQlpwCND0NwMq5ED+SGzE0SirZlVJqkdJKL6OmaplWq1Sj3yFJshSpItKky2ip5VZabdJa62302BPsXDpp6XrrvY/BpIOhB08P7hhjxplmnmXWKbPNPscifFZeZdUlq62+hkZNSj5rVXHatOvYYRNKO++y65bddt/jEGsnnXzKqUdOO/2MN2oPqp9RC1+Q+z1q4UHNEMvXffILNcwiryGC0UkxzEAs5gDiYggQ0NEw8y3kHA05w8z3SFKUCGqhGDgaDDEQzDvEcsIbu1/I/RY3V/KPcIt/hpwz6P4fyDmD7kHuj7h9g5qOq+ilCyDLQvOpTwdiO2nozFVHl6qB2bUm/PrJ1vxfGdyf3rJOvUxpsdbkZZJzfe0RcWbiDy7WGufWkarm6XhSZ4E327zGGeUeFpb9kcH9g2e+NbjLAov0ax+se1cI9tnmkPu2DME9+z+v/X8xOP+Xt4ANhi1ZNcR2IJTIVUTaWQNCGjMUHObq0bVYRZJweS7jsXR7sK7acnic2GsYtU0tPbRFJNe+xJMbkg7KCviJmTDPPn1oKER/oeCHuMimuJlB7mXN4c9ePh/Yup9W7e/ctT1GTKzoYOlnxs6lWfL74bFWx3cS56iSZmnDArX2ybhRSNkhZM/LEe7lidB9vUPiXJvJhO5PDO6Xpfi5yJrnptVnPdDPFB1v8KgLds4NW1+e9LfRfWv9gdEC3GZ33UetJZ22Y5V4Wg9+K9mRbD3PJsDMQr/WziU4sxb4re2MVE6HrClniivbEFhnhRuJImdFcygw472+SLE8IL4OEUoefW81/YCfFRJEgujqvix3CjS054bVxCBS+KylXVVh0wa2ckrK3aom2HoOY6plHd317BZnZGpWWl3t5aQeBfEz/V5xikRWv+ck4kKLY6YjpfRIEPvS20TX5L6MAIjiX/t3syyVpCiv9VM/fzK6n+P01XgHjCvxoaaGEx6SesXbTwzuZQllxz7aXAXalpYyRC6bqtbJxBhPjuGQxPXTUIUKRlkie7sbmEIddEO6ssFlvs3tzGnhoDJqGYUSQoD1vmoF+Qbhr3SFi98jwSK6l9vKjIuCyEyBBrAkysvUMWFlVgdNrLYpDwROLHttX8rs/Ww1HKMNNkbZyBpKzNRcjDRN9aG6mRCGsdxahDDBQH3MmqiNVIT2hWJRuLfF/U9E/cHgPlg8Tv5QlET7Ned9b/eWhJej9c0iHwzuD5bvDUXVsrU1BYw6S8y4O3SSMB6yT7ZDuCF95jo9BErzzllYaprNF+OoiG8Cxfi0Uqwga20rDQRM6Pw2HA6nogwCPqJ057sDYw9KcnVNUdsMdeVOFsZ8etN14GGPTKDNyHIzBYATWgeZVLajzcEIBSITVEhAoVQojQKtSiozRSE61rzonjQ9sEG4n3/Ml9HarNtOlbgGbmY8z7jsNTHsFXr73IMFokZH0Aa9CLVv0eCY3obYsnVDBh11JCCVkDFQIq6m550oMjZpZF33gIvkdM0AOT3qKonJsMJkbZG0Nac7cdKTR/2rxfqlvzK4397i0chgH18z3MHQfHsqX34H5nFfLX2SPKy6kffHsqvtXewFSiRPFl5BlNI+yaJvg+kbLb/uXYcLTaFOawQrZWRRwKkLUwbiuU5GqWOaVt2FdZhiPErEEZa9sFxV3FAALna3bcAlhb0ArQ5DhrFDLfBFRwZX0VWBKBSSvdaT1e8qcGQde4NGWdK52Zn7hVhDOZxIQxsaIWvaBapPjSVlk7jTaAbGQgXyZGPm2UbrO4DcIoxDR2fPgJyNVnYoJC37zjpmbxdtIS/iYixEDehu4zPPyNVrobxMn003o4dCcVK3j7TkNIQmBhR2RODEUmEvoUdEu2+CD9hKs6ag0XlzAfGiaHwKZi0kkwRnYDVhraQxNZOUSiygWKKQlwT90ToDXtG2rUqf3MMr4NK8Eh8+98cpMXDCYDGF7n8eewdAe4/SCxtlpv7RPSOilULYswd8QMBA5K3MATOb4BIXEpzC/Q/piSesafELDkhaxyCDeg8PPdF7WNDSJT1Em14smNwfLN8bdryC1ooWtrKs332FMfUlbBcbtaK/C97+fN5IbTiA8lBB6uyhZXXrTOrQXjJJEIo1fGLvj4zMILppb51K1978Av6YAgqlQtgFVwFF8NPmgaG20ZcJymUMQ+Tvog0+Ai3GL2BG6OecgiTEy6LlgUZN5YwIAXkiY524BLIte49dI+pUK4QCstbTEnobnQw5busldeeDQKBUaqsp5o2iPhvWITgzYcvSpNWdULyL1dFE7m3tj1tKPFAWqROsAeqmkLIBmqA11kROiaf0o+Go5Cg1iHcGSylKgZfV413Ya3ekao50BVF1xbHCXHPO7aksZ/ZRFY1JZ8w+sOOrCgDVb/wVMWX4hs7q+OmpIqytdaFGv/HcxCy6gzurSfkLwbJ848mmWkI+ap0x/vNIAjhC1DtU3f00RdwIrq41qPF06+rhDfVKyW1wBfkD44PLeal0Gg1OEIF4T50iPY5v9iKmz3b3GtZNK7K32wvZnYhGlCVL9mdYYtOv0FWgienFZyLJSYLlxgYxYrPQ1iO1DhKLGZVyDBu083HHnircLj305nfOEa6e5HEmD8bx9Q78YCrifthbGeLgtprMCAbV3gIVw2kEl4enFDmcVJoL8AZLDfisHsSv2ps+Np42ZfZAyRBw3tRFKHHqaldPTAkOxdPoLRMxMFwSZ296Lc1X524iESLtXDlapLBnVB4irAEtrH/3a40GghSxkAWFmdKcRVH+xAfVwOT6yHOYACezSBYaBNgT4qcF7PCLqUMkIAlDdGUkREu21w1m1L7qIqoxUgwYMAV7NxHh8zi1tT6OCJtG3y7EdUs0H1ccn5HhNRRh9WwByZOWHEc15C7rEYhsbgjipS2p5D6kemmQReUiQe240tRV6g8tBrLyoAsOMRQZCT6yUh9JP9wEe14v/xmIIkHBSfmEnu/4GvRguB8vriL9JArroiWik1psysWPmPsRP57b242/e+p+dPdzSiBC/8a3ISx7ld+vckTwXbdm/w5c49s7bgdZHmnzoJQImXnKYUt9d2sMCLnJ1ktY1ANnTqBeMYvFHHKRmGB+vwWg1jG5tSNOThXRJYt2me5ntRTnpR2CpVbZKUEjI8Gyl6yjVFCNkWZrVZWS0srXfzAOtY7aZ63r8igbQrVaeE3UySBBjEYdTyVspvQyXQm106MxgNwaX1rMbiqZ+CQKaChz0BPU+laIYAnpRGnZw15pLKRTpGp22zMpZC/qIQ+Kt712oJlBViyUiOkhjYjUjqO6/adBBMlFOYI7cK+TjIog0GnKAgqDDtheqnd6XgSXBIXNT2yHyOgVIaVxW1GB/8OCh/bwFBIcPhwAhDFWFCgZkVc0eZqydwiKVRAjB1rtwXLgEepM7vZaphckgtI+WTFzRGnMykW4akaWD1P2V8G9o6GEj+cf6vHHU/f7y3//1EVIs1d7DSBe4Y6ACCP/lU1QivfVn+xJlld7s6lQvdr/F8lELhMLkLjFVHTNgGx0ixbcVGGk2+vQ/q1nacExrSVxxwFoHwJITFXcFwoFudAcF0KEsoQeCrnYP9uu/OCYGLjW/TeNLv30+YDiBVv0NAsLKHyT8Gs7whudQVyflY7XFun1T0cQidj20HoTjYLHCAjqt3f/BV2uobTtzsUiAAABhWlDQ1BJQ0MgcHJvZmlsZQAAeJx9kT1Iw0AcxV9TtSKVDhYRccjQioMFURFHqWIRLJS2QqsOJpd+QZOGJMXFUXAtOPixWHVwcdbVwVUQBD9AnBydFF2kxP81hRYxHhz34929x907QKiXmWp2TQCqZhnJWFTMZFdF3yt6MIgAxhCWmKnHU4tpuI6ve3j4ehfhWe7n/hz9Ss5kgEcknmO6YRFvEM9sWjrnfeIgK0oK8TnxuEEXJH7kuuzwG+dCkwWeGTTSyXniILFY6GC5g1nRUImniUOKqlG+kHFY4bzFWS1XWeue/IX+nLaS4jrNEcSwhDgSECGjihLKsBChVSPFRJL2oy7+4aY/QS6ZXCUwciygAhVS0w/+B7+7NfNTk06SPwp0v9j2Rxjw7QKNmm1/H9t24wTwPgNXWttfqQOzn6TX2lroCAhsAxfXbU3eAy53gKEnXTKkpuSlKeTzwPsZfVMWGLgF+tac3lr7OH0A0tTV8g1wcAiMFih73eXdvZ29/Xum1d8PtghywpdpVfQAAAAGYktHRAD/AP8A/6C9p5MAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfkBhYSOBZH2nBjAAAAHXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QIDIuOJVb3x8AABbkSURBVHja7Z3rcxzXmd5/7zndPXcM7uAFEEiQIilT1F2WVopditebrLNVu/mSbKWyX/OXZav2Q2qTqjgVe9dblrNembrZa0uiZdIWRZkgCZK4YzCXvpw3H7pnMCRAShRJYDTs84ECRWDQ3efp533e65GXX/5vb6vqcfKVr8FY6lk36gHzxsh8/jzyNShLRPCMEUDyp5GvAQImeCI5MPM1YMA0gidPCiYFsAmKIrGX7/6Ab5UnYp4MRe2HxLUtJPbw18dRk+QIGGzGFJ4E1oxsROhvEGgdIwY1LkfAgPKl6WrMoQemKEmhRat8gzhsU5DJFJxojoMBBGbmlTP0zo+TmDjYwlVbmPYYxhpEcodvoIH5JHjl6kXE5S20FIEoqjHGFIDcnA8kMHc05vACU1Fiu01Y3ADr6Lh1Om6DWnAYp7kpH0yNOfTAFJAELUZoOULEA6vgxQi5OR/cPXsCGBNRLD6FuE6cNCnoJIGtIqJInlgYUI1JPzB1SG8zoNyeQTcSWrJMvXOCgtRRcTksB3XPUq/cZM6PDu0biBGwIAie+ogYECVPxQ4qY2qakkwt+fBuUmIUbIIAoh7Ggub6ckCd1V64yGCMMrwOqqT3ZxwiBovlCcnCflPtW1djAhhEhtmUg1oHKli1X8tCfBEEj/zK5sMwR+JeppysusgYGWrGxCgiDoPB4GX68sHX6Td/8Miu6uI7P8rDVfcH5nCHiwRBDKhRRC0Gg8pgZHxyYO75UDCaeeXD/YBSxkQc9g6PPAfmwO7XTriIIa0wSm9KjUONw4Z+6vjIYITW07aWfO3aMx366iIBVcQ6MIp1fmbK9cFvWVNd+Ci06cV3fsQpUcgZ897A7FYXqQ7nQxIDGEVFsephDDgR9AGReeprPJ5Lqpx67fu7QPm0MZAXkNzbktMD5tDeY/oC2syUOz9lKXn8NuKi011MqVGUmnA0Tzrdx/nJen4k+7sO6+uHShpg9zTAiAHjeOwp2D0c/0vv/xPPeDkiv8q+ZSnJ4S0WViEFYlZlZEyWO3+M93shTPbUlWcDm2PuK27a0A88UEnNuCAY9RDzeOO2n3RiTr/+73eDsuDl1vvBGHOIgZkVEHWBaUnTkY8LmB+3o93ZobCT6srcA8+BuaOjBbWASTB4WPEQw2MpEP6oFe52dpxy6YOf8lwpyLH24MA0wx1OE8UZxWiaJzc7dX6PfV06/2NeqBRynD2ooXNPwMADFVCTYDBYtWk44hHf8L822px6Y7eufLFazFH29Uxdv1c+pPdoFEyCZJVF8ogZ81dbLU699j3uGLXTbvakRL6+xjJD75WnBRyuqzHxshqBR3O/v9xs7nZ2nOPiL/8fL4+Uc4Dlzs/9NaYah1GLxcOZ+JHc74cb23vWZ148/w+8Uq/k2HqoYMqTAEwDisNoAWPMY+31ufjOj3h1tJoj66G3TPqb0Yby1etlfTznk1brP/zHvrfa4PRdxRm9h5r3Ez20GVdlyMNFWXAdAY8gbSF5yJt9d2VrtwmPYy6+9xNen6jluHqUGnN4nUftpSQ9DXjYNpLzy5t768r3fsKfTI7keHqUwBzeKmpJe3uyAa0+wUOlI39xe2NvUL7zI96YqudYejxe+TDemqQFwcahkjGmkYdLRzq3p4jM45WPeO9kiE15F4BOHCqKp4XU+fkaN/vzpbV7suV3Do3lSHrkzo8b3syPdIuETQIovvhfS2P+843VvYszzv+4B9qHWd89PJ5j8c64BsDw9pVLNs4OcYgBi8+julcx8kiGH+RDD+7r/JghvTVBJTXlVj2s2IfXmI9JT+Xrzufhhru6SEAcThIMFiuWQWxVznvLd++bMTLcGlMyjWnxMGKzqTg5Yw48oQz97CKjPWBaslrMrwHMrzvoIAfmQwNzWDVmasotqcbUBx5zAH92bCbHygGs4Y5jCiQSE2gJg8VJfq7P4G+cQZMh15hqMsbUVGOm4wdz0znwPutBniWp6ngUJ/+qpmDrf7k0mwukpOlIi8WIwcndP6uo6h0ThnPNNzDA3P/NcM5hjO2Bo/v77wXWJElwLqEThdze3GCrE+EclAOfUuDjGxiv1THG4Hn+zucZh2o6gUPM7nN99gJztxk9B+jBIdN0Dznd78Fj/Zt+JwCEOI7wPL8HyK12iysbLVoJiDGEWkD8MsYYGiQQKmEcE66tgCpVOkyXLAuHj+K8GOdifAoggjp3X2Z0znFpeY1Tk2NYm49zOTBoiqTdWfvNDvf6faqK7weoKh8tXmepA34Q4FfHkVINweIbm6ZT1SBWEGMJjEWMhSREN1dYbtzi8uUl5qZCklGHb9O3r8vS3MHQApp+/fvbq3y+FXJmOj/O7wBRudNXPggrSZL0vy7hl9dX2MKnPHUI/CADj0t7xF2CqKTeW0g354+QgtPWpyiMzzFjDK2NRRpXiqz468yWr6FWwAvA88FaMBaX9Zbc2tjgaiPuaVMxfYypvT/y9fhxiRO6jHlwF9LVmNZa4iThvcUV4lKNoFwHNek4v6zYFwdipfd1F5SoAQtKQtxRxHQw1sPUjzI5cZJWY4l/+OICp5o3qCcNxstV1PNQL8D6BUJj+WjD55k3vs8n7/wjJuxgUNRYspkyO9689Kn0LmpVcuA+QmsqB9WM1u/wdE3qdrvDP/9xhfLYJFKq9YW1tAc+sZICUkwKyuzr/v8vRsGBSkLS3iLRbfxynckX/x03b1/hwpVLzHSW+XbcgGQd4xw/Lhzn5MtvMTVaARR7/RK2WEKtnzFsAJ6X/d1HM7bNBrpnD1B6jtPdXuYOZnPwfhWvnJ0DqPZfY6oqziVY66Hq+MXiKuXRcShWu4hML8sBxkM8yZgxBaWgKMnOpZu+fTfp/BuxgDii5jZJu0VQn2P+1afY+uIjPuw0ePHwKP946Tozp1/i0OF6NudVsXGI2WyBi7NOSwPG7ACzKwe8FLjqFcD6qOeD9dLvFZNVu2fA7WF2r2etOWZ7uJSDHXWdxk8t4Lhwax0TFKA0kulJk16eZ8F6GBeiUZj+m/EwJkAKZUR81CUoCS4Md0x+l127L0GmTTvNFfxgkqdfeJ2r12/xvz86z5HZORYW5ljeCpkeCcB4JM+8kYYq4ggJ29DZRtrbSKcFYRvTWM9Amw74V+OB56UgtQH4XZBmwPWzr60HxqYSwZgsbZpRhNzXxDxRGlOEbrjo4MDpVLm60aQ0fTSbK5SBMlyjs9KgHUaps9OrG3W9wHjJt5RqY3j1afyRCTRWkqiFi8OeHlUEcQrW4PlVAmNY3g45emSSI9P/gXIxYLkR4jRjacB2n06hiBbLIBMZgDTt+3EJEoUQtpFOE8IW0mkinTbSbkAzBnUpC9ouEL0ey2pPHvio33XGPNR4iPV6u7MD2vuidk+27ZL0N42Ju7Olepmfg3opr65vEwQBYv0UgK01tjY2CPwCby7MUfEU46L0WJS7Nmij2eTyyia3F1foJEp9fIpg+iSmPEoUpeYbA1iDXxmjVvJ7MmJtO2Kk5LHWiujEijUZgEnNeY+p1O2hgVLQUiyjMnGnekxiJA4hCpGwhbSbKXg7LYgy4CZxWk5iTBodsD5qvZ402A1gD7VeamG6sqJf28oeYEXSid493H4z5EKPMXfiigdz1Vc3mthqDdSQbNyg2e7w1jMnGZUWEHatZV/sUbNgeELZt5w7XEcVrt1uc+naKmvLv2B8rEbhyDmK41OEnTaloITvW0S1d3w5wGYr3rPe6MvVje4GbVc/ChAUoFBCZXQHQKrgEojDlG07XZbdhk4biSNotlJGznbDiMmY1PakAl4AfpCC1s90rvVTZywDbZIkxJ0WIoLxCxjPR7oWp5+BBlAidDORXtcNOqiQ0WY7pDhSwW3cIIkj/uPZWYR2z0mQewTnd9KP0GjEbK9FTGiFU8cq3Oo0+fTT80wenmXhW88ROsN2M8L1gTLd/DszUJqd3PHQulsVNNntbgoZsIpQqaNdc60OkiTVrVGUadkm2mkhnTYmbEG7iepWD7hibMa2XqZfffADCIq4uEN06xpJHGJHJiiMTWErI0hQRKx/VzRhsOy9ZE5vL1x0EDqzE6ebZ6I2rU6bvzh7bLfp/JK3K4ocN2+GbG87TpwoMzFWoB4HzI/W+HhpnQvv/BNHz/0bJkdrrDZDnLvP5/fy9I/pWXRF392g7bKt9cEGaLnauxZFEecgidN57mErc8haKetGHYg70GmiLi1I8bY3KN64TNTchGIVHZ0gGZlEauNQrSOlEaRUxQSlLOw1eFX9Hlk0xB1AqWInTjAitDbWePbINFa+eiFv1zqurkbcvBkyM1NgZqaIyzan4FtemZtgZbvN+Q/fZvPIUzx97iXWmh06UbK3Ce9qzAPZJ90xrcleoLVQrkClese1qyokUaZrI7S9TbR0hai5hamMpN8ZhejqEtpYQ8ojaGUUOzIOIxNIpZ5KjwEhTukalp1DTg/mqsIkwTPKyYliXwlav4S/Nyi3tmKuX29TrVrm54u9F6z/MyarRaaqRcLtNYyAi93eoES5K5U+QKurae8hhK0Fr4KUBB0ZQyt13NQsmsSkpyuDBYxzGNVUxHQ1ac+iD0b2yoiQ7ATYD6YOMVbFOeXwaHmneawPjHKft6rTcVy71iaKlKefrlIqeSTJbs/90q0Nmg6+9fq/Za3ZIVK99yeLyZzub1gBR5+mFaBYrlKqjd6pIO6GnXNZSMvtMPUg3Lf0mfJuCGW/V8lLKWqmb4j+lz0aEUgS5ebNDuvrEfPzZcbG/D2lyLWNbX53c5MXvvMDwiimFSb37frpmvJv+lKXZCV+X0n0DppfDmh/Bfv+vy2VYlp3WfDtV2Kp7resr0dcv95mYqLA0aOlXR47wHor5MM/3uZbb/4ZxoO1e4SG7vh8+6RVsQ/efRoDktB/Xvn+vz32joLhrxZ4bTQSFhdbBIHh2LESvm9IEnfHz7eimJ/9/jpPPf/dtDBDDLWS38uhmzQTmubcJQtEO0g4SOcnX92Hb4T+XPnB7MZ/eeXkA4WGrl1rs73tOHOmQq3mZ174zrXHieP/XlgkShIWf/NzPv8Vvfhk13i5LzFzeZHwQTo/6XnyXqovB/tYaJFUq9++HXLrVocjR4pMTRV6urIfR75n+E8vHc93+BssL/qcn8HUG/3A3NwMuXq1Rb3uMz9fwlrJgJmz2zCac2+QNFWUJPQ7xt0Xpt1KuPxFk8Qpx4+Xe6GhlWaLH3+y+FC/829eezoHwgAREKTWcV9nsP/3dy/x/TNHOTy69wFNgeft0npxnHD7Zsj2ZsLCQpnR0SALogtT1TJvnTrCu58vc/aNP8X3/T1bL7oOjmjq+KSHwRne/uHf53py4MCZFQrv1y9MMiZsZ5SYZIkML+uKUE2DOSYb8mVMGltdXY24caPN9HQaGro75jo3XqUZxlz84KecePVPWV2LaYfNNDQUx6knvkeM9uzC4RwFg2zK94sxWp0QgEYnIVaDb/rLr8AzadFw93oajRZbWzFXr4ZUKh7z82V83+7ywgHOHB4jdI7Fj/6FuRe/w9JqiThpZ6eiCTjdaVzLltPcAx9YxuyevrsvwIzSlNmNtQZnDo3eoWvTdh3FswZVZWNji08+ucrKSoxzHi+/PEut5gF6Tz38/OwE258tce3CBxw5+21urDk0StJs2x6TaLosmuNyAHVm/4iYx52RTI/LM6y12hS9/uqY9EIM3THHjsXFJX73u+s0GhGjowZrJxD58rN03jhxiJ98eo0bn/6Kw6df4vpqhCRR2qaQ3Mmams8qGnTGlH1hjsBapuplnCqJcz12NEaQvvZW5xJu327QanUolxOOHZumVivt8tz2WputkEY7okADY8G3BSIXp2bbaM6Y3xjnJ2PM/SgSDjxLJ4yYP/cmf/f+z/jLF08yUsgqqdFsmJayvd1mY6PN2FjAmTOHOHPmGNXqyH1ZPXaOTxZX+XRpjZkTLzE2Pc31tTYubqNikSQGc6fTtBOWypE5iOZ835yfWsmn1UmYnqyzcmSe//Prz/ivrz/d043GQOKg04mpVn1Onz7ByZNzlEqlu8YF9jswyue3N/nwi2XqY+OcfPX7JCrcXGuhSZR2SWYa824nKGfMQdaY+xxgn6gUWNvc5lvPP4+L2/zt+Uv8zRunejWQglKrlXjhhRNMTIxSKPgkie5yejpRwh9ubfDR4iq1WpUjz75JsVRmqxkRRlm/t03BKKSVw7ucIEcOzME25fu3M09NVlm6epnJc8/x7Ct/wmeXL/O35z9Oc/XG8NevLlCtFqlWSxgjWdWQoCpstjpcW93mj2sNVjbbzMyf5Pk3X6JYKdNshzRaDrWCRgJWkVhQk4aWHJZyuUSnFZFEaUuvZm0czinW5oeMDxJj9sJF+9VXfurQKL9+/w+cePYcnjWcPHGC2bl5/rh4jfUrH/N37/0Bq+BEM7bTngocq1epjM8yceYsJ8bSI5jD2NFshjiBUkEoFgLCksfmVkgoMZCgYhmtlagEAuWA66sJLg5xSRolcChezpoHzpJd57fbset1HYD9IM5i4DE/WeOzTy9x+tkzABQKlqdPPAUnniLuOBrNNnEck6D4xhIUPIp+gPiCix2xGsLYpfWTbqf01ygkAr4VxkeLtNoJsYupFAqsr61w6ePzHDo8x8ypcyytbO6YdcmnBx/06voQnuf1Bq5lpnz/CoVfO3GI//HBJaZn5xgb2cmZuwTUWmr1EurS0S6ow+GInKCx4hJJe1uy/L4RcNo9aIp0oIGmGmV8JMAzAVd+e4GVG1f48+ee4vzvl1i5WmFm9viBtJLka2+2jKIOGxtrlEoVOp0WQaHUPyJmf1ijFHi8dfoIP3/vp7zwxveoVCq9Qt5uPYkaSV10cb1W1rQAQ3Fx35vWDTU5RbNhBp4nFIo+N2+tsfjxvzA9UuGvXzuJ71mmaiX+/sPPEK/E1OzsjtjOGfNgQIlgjUciMa1Wk1u3lvA8j0OHZ3eAuZ+Fwsema8Qu4b13fsqZb3+P0bEyxmaFHtptClMSZ8C4FHi9wakGcWkLrpHsZ8RQ8IVAYG2rxWe//DmdTou3zhzh6Hi193srRY+/fHGe//nhbzCFYu9lMLnvcyCwTDRm221hA0ttpM7S0iKzR+epVmv9ufL9ZY2Th8Yo+B5vv/82MwvnWDg+izWGRAxiHA6LSVwa1cmGtErf5F6xgkUIgvTfbi6vsf75b9jcavDthWlOHzmK2YMJRytF/urlBf7XB++S9A4LyBnzINiypdv8uvMuNa/OyfJZDs0cZXx8Ki3q2THj+6+55iZq/OfXyrz32WXe/9nHTM0+y+G5GQrFEmg2J8qlqUv1Uib1DWAMUSysLG+wtXyV5RtXqBcCnj82wfGpo19qmieqRf78uaf44b9eyRFyYNrSENLhi+QS43aGs9VXOX78FMZa1tdX9l9j7qk5n5mlFcb89to1Lr7/WxLnqI1NYQujUChDOhEdFzdx2+tsbyyzsdVmpl5mYWaE775ygno5eLCXYnKEHzw/n+bqc415MPFKAzQSGss3uOL/humpOcanD2OsOfgxhN1VLni8sjDNKwvTdKKYpY0WjdYa261bRE7xTXoo0ch4gbGn5hgtB9iHFIcLM/UcIQcWt1Q2bhniC1MUL11gMfkhcmSe6nOvoOPT/c7P4LBGqeBzfNrPd3BIlyosL3f46IMOydIcY8UGR8aL1L2A+NZ1kkp1J8CeT6fP1365PaB0Oo5SYDixMEa5dBp/cpJSfZxisYgtFPEkPbrvwDRmvp5AbSnCzEyRkZFpYIQwOowgFGojeKUKGnXwRCSCbA59vvK1T6tQMBSLBaAAjGYmXknrwNT8f5QBIqFn0okNAAAAAElFTkSuQmCC\n\"\"\"\n\nFCCamera_Axis_rotation_D_BMP=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAKYAAABiCAYAAADa8ajVAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gEDChUAgq/1tQAAACFpVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVAgMi44F49tcQAAIABJREFUeNrtnXmQZVd93z/n3P3t/fr1OvsiNCOBEEswEEqxwYFyuShX4QXi2MaueKEiA4boDyOzxMIJcsUBs8jBaxziYIxdToCyncTBEFcKs8gYeTSyNKORZumZ6b377Xc9J3/c16+7Z0bSzLz7ehnPqXrVt2+//p5zfvd3f+e3nd8Rr3jFz3xFa32IwdoEYF7H9wxA3AR+fJ2YMdk2A0gywhE3OK8babL3GVY7x9Y1bRqqYgIHpBQHBkLSIMRQB2teZ99mphRKsc2McG5oXjuM/ge2kDERQmBKKW5SiG0E0gNj7MS+s8IeNn2+9a1PA/CqV72DW6EJAaYQIiOiie2cyi7AHs4Yv/GN/7RJ0twSjCkF5i0yl3/U7dWvfgcguFWepQBMIeSOlQa3peULt9e85l+TzTPccRJz8DdtC5Tvbek7K+xh02c76T8MYSDXdMwsJrWdhBlm31lhD5s+txJj9qzywZea21b59tJnO+k/NMa8bZXvDj3zr//6E9x337t2KP0zZsx1HXOwSaU6zvYQZph9Z4U9KM5Xv/rxPnN+93e/e0fRfzg6ZkaMmS4n20eYYfadFfbN4nzlK7/ev/6e7/mF58S5lRiT24y5sxnzr/7qY/3r17/+Pc+LcSsxpli3ygWgB1ZYB8PYiX1nhX3jOF/+8jpTvuEN73kBq3s76T8cYWBKKXuKsx4AiIExdmLfWWEPivNCDvTtpP9whIFOQ5LrE7tZ5V4PjLET+84K+2Zx3vjGBwBIE212Jv0zp/m6u0gipUbrwbhcSgbE2Il9Z4V94zhvetMDN+A03076Z276rOmYALLnpB1cBG+n+N/Z2MOmz3bSP+N50MsuklIM+LbpDDB2Yt9ZYQ+bPttJ/6Ex5m130VZgD5s+t4y7SAik7lnlg04qK+beaX1n+dI+F86f/dnDfP/3/+Kupf9QtMx1d1EW2Snbmag6zL6zwr4a50tf+kifOd/85vftYvpnzJg6o+yidXtqO225nY69GecLX/j3/esf+IEHX9AllNU4v/jFx29Qd5WYpsS2DTzPplJxmZ4uUS7nhsuYa9lFWg9CGI0Qg2LsxL6zwt6M84Uv/MoGpnw/g++8HRYNBEppwjAhDBNarZCFhRanTy9SKDgcOzbB9HQl+5WcPmPeXsa3ehnfoOvvSvq3WgGPPnqeqalV7r13L7ad0c5pIdb2/Ije77f9mMPFTnH+9E/XpeVb3vJ+pNwNNHjudvlyg3b7DK973REcx8xsLr2Q5GDJwmlILKuE453Td1bYazh/8icf7t/7oR/6IDIjrhxknD/4g/c+59+UUr2lPKbbjanXu1y6tMrcXGvT9xqNgG984yz33XdHBroya8ZPFgUPts/4EeLaobhs3DzZzEsI+OM/fqj/+w//8Icyde8MMs7nG4dhGBgGWJZJPg+1WoEjR8ZYWmrzzW+epd0O+99dWurw5JOz3H33dFYSc/durdBao1RCksQkidiga8kNEkTcGJ4W6NScQGmNUun/S5kulVIIBAopwZRgGC/sQ/z853+5f/0jP/Jvr/n9dam3tfS/mT5rtQJveMOdfPWrp2k0/P79p56a5/DhGrmc84+bMQGSRFGvCxYamoawSGojjJQ9HMtACxDSAAEGxuZRimRNM0NrjRYCFQvm6x06UUxttMB0rUw+72FKUIkmSWLCSBEHAR3fp9Pyibs+dhJQFDEeMbYBlqExDYGUgj/6ow/1x/rWt/7yVYwQxZp6KyFOBMUc5D254xkTwHVtXve6o/zlXz5BFKne0q85fXqBe+/dlwVjygz2lW+XVS5wHJfRUY1pxRiRQcOxmNw/zR0HxikXHTQQJqB6y728whJey2I0Dcg7cP5yh1NnF5mo5bnnjhql4nrJtzhO1YZEQaw0SQRhDPVmyPJqi5VGk5V6h069RdhucvILD/T7edvbHtqkf2mt8QPNbEPwbMtFAIfiANfWWJbcMvoPohOWSi4veckevv3tC/17Z88uc++9+wbC1Urs/n3lUgoMA8ZqBpUoptGYY+E7K/zF6RIHDu3j2KFpKmWHQAn8UG9QTDcIGa0hFtgOuJ6Fl7OIEk3cKxK4VofQkBArkAaYMk01M23wcg6TEw4wShJDGGr+3Y+/vD/Gl/3ob6HbLiNJQMlROJagG8Kzy5J6bYz9d0/SaYcsXDhH2e9QtcWW0X9QXffo0XFOnrxEEKRUCsOYxcUmExPlgZhpg1U+kMzcxljtet+2bVGrWeS7PsbcLE/44OU8KqUpDLHOZMY1t2FrklggZZqfWm90mFtoIWQe1yY1AkyBKXuMqkD1pK3SoJP1641M+YHPfpvv+d5XsLTa4cKFZU5enCVcXkUlENVGeeVLDlAbLbK80uGJTofFpYvkAoXnyi2h/6DPzTQN9u6tcubMQv/ewkKbyckBHO/yFrHK1/pWSuH7MZfqJiuT07zy+CEO7x/HV9CJ1pOhE6ExdFqKBCDqMasCDFPS6cY8euICj/3dGcoVh0rBxXMtpGFjOyYjJY+RSoFKuUDOkRgWSFOgY3jobS/rj+1ffepb1P2EbhATJQq7WuV4rUoUxaBjPNelGyY8O+9Tdi1Gx6vMN1epdBq4jrhuH+ewrPLrbRMTxU2MubzcHtiQu2UKHsRxTKMRc9E3WalMMLl/L9rOMbPcxXVMPMvAEBJhCCxD4NlgS1AKIiXohKnuKIWk5NlMerC322SEDmYg0H6qy0WJoqUll5RFIxFoz6VULZMrlNi78AT0GPOtH/s6rU6MHyckiSZRoIhRPb3ANEza7YSuHxNpsCzBVK1EZ3WMxbmAYhBTyMmh0z8Lxrwybt5uBwPh6luBMbVWBEGXubmQC7pIOLmX2tQEXQxWFnyEhJGcwUTZZaTgULAMUAnnzte5NLeKbZkc2DvKaCVHzhZEMbiOTd6zsDHxHLBtY+M6A8AkCUpp4jigPV+ndV7xX//nBwG47xf+B0GsGBktULA9YkPgxwl+rNFAohKiKFUJ1oyyRjeiVHaoTtaYaTdYbi3h2inD7nTGLBQ2u4c6nXAgXLke+RmUObbP+Ol0ImZnfZ5RRdT0PsYmx1GGSaMToQCJZDFWKA2ua2G0E85dnOfMqRlG6kvEhuRrZ4pUp8Y5fnia8Vqegmth2pKoI4GY1HMhrml4maaB68Jozx31kz/5ESr1mJXI5MLTknaugjdS5dihGmXXYtWPaXZTptwYGAgjWOkm1Cp52mM1lrodKoHPiGMMlf5ZBJ82v7gQx2oA3DQTPxN30XYlcYShz8pKl4tdi+6+KWqjNUJh0O5E/Y2sqseeUQyXFlZZuryEPzfHQdpMTggsS9DuNFg82+BvLs1jVytow6DejPCSdKm/3kTcn/qphxFCMFqxGFGaSiPi6cUFZjohByYr1MZytILkOWnVCmJGPIPJ8RHOrrRYaszj2RrPE0OjfxYS0zCMzIMFu9ZdFMcRi4ttzjUM5ivjjI6MEQpBHMTEG86ZcAzIOQYqDDl7fgF3ZY6jTsR4Rfbf9HLJoJDXTARtlhdbXK4r3CBBFSRJzmC9oMB1ji1RLNUVZ5smnfEa//T4fkqlHIuNiEZX9ZfvK1sUw1I7YbzkUpmosOA3KHdbOI6BYcih0D+b2kzqKgk6MGNmEXTfaqZUKqHTqTMz02R29AiV/YcpVPIs1IM1b0O6TAoYKecwkoiF5TrG3BzHRiJGK/Kqt9w0BUUTinmYHtV0ApMk0TiORMrrf4BKaVaa8Pj5GOeeQ3zvK45QG7F5YiYAGVMqWChl9ZdxrZMNNDRIdEKtUqDs2Tza8lk+36ZSSMc3DPpnwZhBEF/BmGZWVvnuau12m3PnAmbsCaypvViOTaObkGgwxNryC55lYgDziw3E0jzHc11qIx6G8fxzti2Bbd34shTFmstLCd840UK+7Cjftb9GEEQ8e8nHAzwT0qIaxpVuOwxhpGaVYeB3ulgGREJySXqUVzvsnTKHQsssnn+nE2763XEGY0whdmmp604nYUXn6JbHGC8WiJQijBQkCm1IkgRyrkkxZzA7t0wyd4k7aDI5ad9QuE/ra4fsfuu3HuBnf/bXrrqfKM1SQ7FnTw4xf4kL/2uGmSuWubVsqCjWhIkgMQyweudTbUqTEmgBEk13RND1FfmcMQTjZ/AHt7LS3vT76GhxAFyB1mr3RX6U0rRairYsQCGPNE38SBElCkma1GEYEssSRJFifmGFfat1itUY2/YGntdv/ua/6TPnz/3cf9z0t7xn8Mpj3jUYZzOO1jC3knDi2ZDFco3CnnEK5RIrzYAE1Xs8kqJrMbewTP3yJbqr87z4riqWZWRK/yye28WLq1c53G8eNxUcu25feRQldLvgWy6G64E0iKIYhUKR6oO2BFTCSrOL2WpStBWed3PLy8b/+fSn39u/fsc7PnpDeFd+10gCch4YSRcBqCjCMaHjK4SERCnCCEZGiiy1SywuN5mdbbF/fyVT+g/63LrdkAsXljfdm5ysZGH8yF3DlKminRBgEFkulmESKU2k1vxmKXNalknXD1ldqlPudKhUJZ5n3/A4s6pHeeV3hQDLMrBFRKSM9GVyJEGisEzJ2uIfRIpywcEbqbDQalKZn6VaDSgW3czoP+ize/zxGZJEb1jGC1SrhYHGo9Qu1DGDIMZXBpESuJaJ7jnRU7YEi9TibgchRtfH05J8wcHNW0ipb3pejzzyC/3799//6zekQ12LPsWig3fZp2gqoijCcx06AYgoxmDdQR1GEaWyx9xKkcWwzvx8k1LZ2xTn2S4dc3W1zYkTFzfdO358akC9Nc1j3XU65kpD0eiAbjfoNp+mm3bfj8iFGLQtIIwQUcRionn0WY0zEyFF6mzX6zRIrxOFSDSuqbhjr8fBKXvTvD71qfW65z//8x+/iblerWOCxirnsZWJ4VpEUYhtCXwfpCF7YQGV7hiUEq+UZ3k1x1KjTW2lQbVa3lYdMwhi/vzPTxBF607jXM7m+PHpDDLxd1ntoihSNJshfjHP3hft576XH8S1LPwo6cnLNPacXHGQ89rSqDT92qaWBNOQnJ+r8/XHL+A8dY5jx4tM16xNcxFC8M53foJPfvJdvPOdn7hqntcrrTZjQreb4CeSruMxnXcxLYtWx8c00yEaQKIljiURhqSY81g2BI12QrNZp1QqYFnmtuiYFy+u8OUvn9y0rQLgNa85iuNYg3ISGUZ+tiYkGQQxSmu8qRGOHxxnYjzHzHzCUivCEBJQaa5kz5+ZDk2y4RJTSqaqDjkbZpe6PHryHPsX5rjnn1QZGzGv8HGuz+td7/rENecYJ5og0iSJ7vk/BcZVS9lm+sRxTDc2WPbBK7kYMv0/KdeF/5pbKY4UZc8iNg1k3kUvh0hpkcbwzYHp/3z/p7UmjhN8P6LR6DI31+TUqVkWFppXfffIkXGOH5/KjA92VUgySRRW0SGXdxCGZLkpODPXot6J2BjIkaTxfyHSh2wY6XXRtZgeLRAFir87Nce3v3KCu8qao8dKjFbMm5qXBlrdhLOXfZIIqkXJ/kmHQsF8TpxuFxaWQ1aNIjnXoVzyqHfi9aKlGzwnhpGuAJ4pCRFQKBHHMaZpXyWFb6Z98pP/Z+DnMjVV4U1venE225GFRCe7TMeMY4nKFXFdF8eyiGJNrBIMg57E7KmaAoSRSk0JSAxqJYda0cEl4X//zVOET8/wiimDw5MOuZx50/MyJdgGRNLgvA+nQ8mFbsTBcsyeqqRYdDbhRFFCs52wEBiEFZf9FS+VeECkFJvclDG4loVlgA/YOkbHEaYpiOMA08xvuY5/ZTt+fIrXv/4uTNPIBlCw8dSKnb+Ua8APErrCwrRsXNsiijRRvG6V9yfW09HQ4FgmYwWbfRMe84tt/vCLjzLtt3nJtMmxw7mB52UY4FqakYpDayTH+N5JEiU4s7TC2bML7Ldb7Jk0qVRSF48faC6uxKyWKxzcO8aeyTJ1H1pdH5M1oyfVi00zLTiQ91wiP0A7HiYghIXjeBvGtvXZXdPTFV7zmqPs21fNFlhsKHW9GyRmFCmCSBNYNjnHwnIsmkF8VbGDjUu31uDYJtWKSxwqVupttGVgYBAncGk+pFo28dz1t/2jH72f9773keuel2EILEtSMBS21kyPONx5aBzb2svfPrnEYydnOHtuicNLHSo5zWo9YcHMMTJa4bX37EHYJnI5ZG5VECcKY205VAqBpOAaaGIcyyQOY2I7RxSFJIneoA8Pi/469bfaJoWCw+hokYmJEocPj1MqeUN60r2T0bIoKr8Vb2sYpFasyFlYpokhJX4YpS51sV7j0zDWPEep47rdjTg102SqluPwwXEO7qvx7Sdm+H9PXaZ4scvehS77i4LqiM2nf+PnNzHn9c7LMAQ5U2P6IfOLLabHq9xx0OSfv3qU44dGOXlmkaeevkx4cZ4k0CSTeb7r6BjlgonjQbtrcqCWY67p02wlxFohpUQphW0a5EyTRtjERmEEHRzHRuuINW30Ruj/nve8iZ3ehBCYN5pr+Pxm/hAZM1T4gDBNXNtESIEfpVsVhbFu6Gxazo10WdRozi+2WVg1qZYtXvuy/bz23v2cODXPidOXOXlxhbcc2M/vfvZR7jpa4/d/70vkPAPXNa5rXoZh4FmaQqBptzrU2z4XFwoUCuDl4NUvrfHSO2o8+uQ8S/UupZzJ/okRDAtWm+BaksmKR94xWXB8FhshLT/BcyykFKg4xg8CrCSmWrZxHAPbdq94brdOqev+vvKdzpQAQajwkWhh4ToGsdKEUbzB87W+hAvSVDK5YVyOKVAkLNcTVpsRJc/k2B3jvOz4OKuNkG8+doH//tm/RTW6TOdhb0ExmYvJOwLHljiOxLavvcXCsgw8L6HY1dQ7Aa1OSBj1En8b6Sa38Qq89mXjfT+qAnwf/ACiWGGagmrJxnMNSq7JUicmSaCaN1ldbRO3u4wmXSoFh5GRXK9kzS3GlD3pr1LPxM4PSSZJWrXClzaWbWObJrGCINYg075zbpp7GSYgNpwQJuX6YzMA0ct77AQx52YV5ZxBrWzz1u87gmMdod2Gk8+s8uipi3zzqVm8KGJyxGZPWVLLC/K2xDIEondSRKoOajrthKQL7dhnZaXD1HgFKSQ5GxbrmplFyNuCch5ME+IIGiEkaISxLu4928Ase9TKYJqSZiegvZrQabeYcmCiZuK6zibXzHbuuRrGMi6y2ow2bD0zihV+rPFNg7wlMByTMFGEcYIhJKNFlxcfyFNwYaUFM8tdllthKpZUGg+WvSXfNKGctxjJ2VRyYJvpch+FaZUNz4P7XlHhja+qILmb2VV44uk6J87M8rVzi6i5BkYck3NMCp6BJdPqE516SDtISEoFGKlz6OAoKvbwXLA6EGsIYpjfkCG2Vj3J7NW1XNug5poS14aREqzUHc48HZDXIQUS8vk8pmlui56/NZyZfswsihWkBUOHR5kgUPiJJrIsDMfCMi06YYJlwN37q+Qs+NrfXyRKYiaqBY7sG+XQpMeFuYB6J0BpKOcsqnmHck5iW6nZIHtMuXHoYQxRGxqkpWAsB175kjLf9dIyUt6JAfghrDQ1q42Q+ZUO8ysdZpcaLK80qXdi4iSh2QkIIo+CBY4liAN9VfG5vi9Ar5lrOmVWAZUiRBEs17u0m03cbkCpbF6zDuaw6b+1fCmyLXU9VP3STwgSiTAtHNPEEpKpislYyabR6PCdZ+Z4+rFnIQh5spDj22Ml7nnRHl770nFynkMQQafTk4hmasyuLYRrfkNhbC5lhKBfnGDNjyoUqF69otqIYKTscGifA4zgB3tYWFU8+cw8M4tt/CCi6ysKOYlrQTtgc72ka5Av0WBIQTnXG18Mp84tMTtf545ug8J0nkLB2xYdfyt1TCFYcxcN7sccFnHSqmip4YOwKOUdxsopFz17scmXv3mG4soyr6woHCnxE5+FeZ/vdDosrDR58eEadx4os3csxat30j3cqjdk+UKGrQatoFdprxdvX3fiSzPdGeFaadLF2GiR+ZUu3TCNMSfKwXPB7ECiNcbz0MnovRVJryZnIQfH9o5w8fIKM/UmxtMNLAtGR8tXbKa7hSRmjzP7kZ9BDzkdHOPaLY7BDxW+dLAci0rOBQRfP3GJx/5hhtrCIvfstbj7WLkv7S7O+Zw732Dma4v8xYUxzt2xhzsP1piq5SkUwLFTZot1KhUTfY23ls3FAHr1YDc9/qQn1cIN38lZJqYp6XZC/CgmjBxcBwxTEHU1hvk8Ak8IEq3p+OmGuoIHhw7keLN3nFPnqzx+6iKLz66w9/wCB/c5jI7msSy7X1D/ljjkVGzIF8jiEPZhHeQehgl+lBo+0hBcXq1z6sIcT/3Nae50Il732irlgoXuPRUhYN+Uy74pl2Y75uTpDmf++gQXHyth7hvln738MAf3ehQ8sIBYpIypNu8ZW2fKK2ppXuXZlOsEtUwo5izynkW9GRAEEVGQSr6CDUH4wiuvIQQK6IQQKCjYgokJg+mJaY7uG+P0zDInT51n5kKdg/N19o7b1EZdbMflVjivfC0Saa5p5IOomilPDCdeG0QaX0HQjVhoLnD+sfPUjJjvO+ayb7xEzjOes+9i3uRV9xS564483/3G+/jiXz7F537v/xJWCxw4OMbLj01x18ESU7W0cGsnTH2PUby50Gv/4rmSZ9RamUJwbEmp4LDU8On4EVEc45gmo0WIYtFXB656jTe8GLoXLFeAH6X/Vy7A0UM2x45Mcu+dE5w8s8CJJ2d45twyRxeb7JuIqFa9TTmau5Mx5bpVni7Dg+wb0QNjPFfzQ00QahqXm4hYc6xmcecBj4P7PCwzjes8V99CpEVdP/Xxd1Cvd3nRgSrty2dZ9iMW52f5q0tzfEGaOJbFnokSxw/WODRdZc/EZn9j3Kt9GSuuHZsn1TtdE1wXSnkXqFNvBnS6EZY0mRyDnJsyvbiGhp5cwaBasaHMTfqixDE4Lty5T3B83zivOjbON/9hnsefusiTpxd5UanBgQmTWq34gpU7drqeaa4tW1cuZTcqMQfFuKZjXWnaQUIYKUooJicdXv3SEiMl67r7/pVf+RkAymWPz/+HP+D4HSVarYillZCl5YBGp4Xfgrbf4ESjwVPPzON5OcpFK42yFHLkcxaOZWD1CiG4DulPCxwrzYaPNXSjNJoTRTGdTsjsYpOVRsDFhSJ7xor4sSLoRas2SkjVY0GtkrQIrE7/rjcwbtzPvk9zA4xe5Y44URTLec4sd1k6V+f0uSaHpgMO7MkxOuLiueYuY0rWtpPIDb6wQfTL7A9AimJN10+oliyOHcpRK1uUi9Z19/3hD/9M//oDH/jt/nJfLFoUixYH96f5jFGkWK6njHTp9ALzqwkzWqNKHsZUlbHRPHnXoZCzcB0H1zbJWQLLMrEsC8sUBHFCqxOy2vRZWG2xUm/iL3d4dmGVcxcsqiUX2+qlqOtUyq/F9HtsidCgUT2pnO5NEjpd+pXq/U0p4kSjtOqHXkEzaYbogiTpwuxiF1MqVBwxPubhuna6RO6CJoUgWXewsyP3/ZiG4NCeXJq940rM5zm65Mr7Dz300/3rD37wd553bJYlGR91GR1xuOtIAaWh2UmotxLqnRbNuQZBpJmLNd1Q40eKIFREoSaKE0I/QasUx3UlhbzFqKVxhEYmGrMLXtzAMSW2tV4LSfcPblnzS4l+deArjcn133WviJXa8FODByInUVgkwsEyIIkTut0A0xSYpvWc5RR3WuRHCIH4wAd++xkhxCGtB7fK9Tb5K56r74ce+mk++MHfGSDilBBFijBMSNIKNCiV7u9ROr3WvQ+ANASGmZ5Wa5gSQ6YSTZA6zqXUVyRfrGmp186nXGfGa22huPq+UskV99UmRk/PppeZncg2LOMnToKNGey3Rh32je1DH/rdgSSE65p4Xjb+wWH5eTfjX61PKtWTqD2GXUs82amSU8r0CKYN55XvTD/mdvedFfawxqi17q8W6fXVEjV9xmsb9Ha4rinSQxs2xMpvjfMks5YEWZ4nOQz6rJ+efGtEfqQAtRaSTPP5dvux0Ko3DzEEbL2DcHYi/bOeh1gLSWb1Nm/PQae/9Es/wYc//J/J0sMwnHmJoT/UW6IJ0UtHFIN9ssC42c/73/+TKKV43/t+HFi3erP4ZDWvYdNnO+mf5UfKnvGTpr3tvhrsa+3BB99OkiQopfjIR34/cz9dVlDDpo+4ddIx+1srdm1A9cEH3953hTz88Gd2tAvkdrvxN21XHg7w4INv77tIUqYUfaX5NnPeAhJz7fTd3dTe97639yfw8MOf6U1Eb9KzbrddLSw3pr2JAX1gOgOM62sPP/wZfvEXf4KPfOS/9J3WhiFQyhhCLDireQ2bPltH/y2UmCIDBToLjOtvv/qrn0HK9EFonZZSuXYcOhv3SxZFx4ZLn62l//CNn57E3Mmb0V5oEmmigmB9b2y2EjMbvGHT59bZjLb2gu2aEjHPPQl5xTKQvSTa+fS5tZiSzZGf3dt2esbM7XZTS/nOfZgPPPBj/Nqv/cF1Lum3260iMYVIa2T2w0CDhpOyDE898MCP9Zlzq/seBvYwx7gV+MMdu+h91tUxc01HGWz7ribL7bvvfe+/7F9/9KP/7XklYtZ9DwN7mGPcCvxht7WcUtM0++dumusW7eCb0bJIhL2SKbey72FhD3OMW4E/bJ0yigLq9RU8L08QdLEdb2OJmMEThQfFeM97frR//bGPffa6dcdh7WnPEnuYY9wK/OH4EgSGNElETLfbYX5+FtM0mZzau86YgySZriXoDoLx7nevM+XHP/5Zrne/VBZ9Dxt7mGPcCvxhsWWiY9qqiWEbFEtlZmdn2LvnAIVCcWOsXAz0tg6C8e53/4sNTPmHN4QzzHLPWWEPuyT1bix5LRB0dZvvBF+naJY5mrubyYk9VKtjoNP95Wxn9vrVTLl1fW8t9m0n++aXSRIScC45xSV9HqeQ49AMfk2dAAABPElEQVShF1EsVfD9zvbqmO9619v615/4xOcGOKjzto6523RMIdIKI7QSWouXOWs9xvjYPqrjU0hDbl8Zwne+c50pP/nJzw3k6vjHvH13q/CHMdb6vCQ+OYZ76iQzyZcQ0wco3PNKdHV8o/Fz85yxdmrC9WLcf/9b+9ePPPJHAx28fqN9bwf2MMe4FfjDGO/iYsDffysgmd3HiNtiuupSNm3i+Usk+cK6g33wt+36MK5kyuz0q2FJi6ywhy3RdovETMcZBArPlhw5PELOuxOrVsMrV3FdF8NxEZ/61OfOCiEObGWi8P33/wiPPPL5rN6/ISbJ3k4UHpYHIQwV3W4M+IRRF4EgXyyR8/JEUVq7KAL0gInCYrPb4vnbb/zG5zMMnw0zSfZ2onCf8zNujiNxXQdwgEpvidf00r/l/wfuCXJa6CkpIQAAAABJRU5ErkJggg==\n\"\"\"\n\n\nhelpIcon = [\n\"24 24 4 1\",\n\"   c None\",\n\".  c #016AC5\",\n\"+  c #F8F8FF\",\n\"@  c #FFFFFF\",\n\"........................\",\n\".++++++++++++++++++++++.\",\n\".++++++++++++++++++++++.\",\n\".++..................++.\",\n\".++..................++.\",\n\".++......@@@@@@......++.\",\n\".++.....@@@@@@@@.....++.\",\n\".++.....@@@..@@@.....++.\",\n\".++.....@@....@@.....++.\",\n\".++.....@@....@@.....++.\",\n\".++...........@@.....++.\",\n\".++..........@@@.....++.\",\n\".++.........@@@......++.\",\n\".++........@@@.......++.\",\n\".++........@@........++.\",\n\".++........@@........++.\",\n\".++..................++.\",\n\".++........@@........++.\",\n\".++........@@........++.\",\n\".++..................++.\",\n\".++..................++.\",\n\".++++++++++++++++++++++.\",\n\".++++++++++++++++++++++.\",\n\"........................\"]\n\n\nexecuteIcon = [\n\"24 24 3 1\",\n\"   c None\",\n\".  c #4E9A06\",\n\"+  c #000000\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                  .     \",\n\"                 .+.    \",\n\"                .+.+.   \",\n\"               .+...+.  \",\n\"              .+.....+. \",\n\"     .       .+.......+.\",\n\"    .+.     .+.......+. \",\n\"   .+.+.   .+.......+.  \",\n\"  .+...+. .+.......+.   \",\n\" .+.....+.+.......+.    \",\n\".+.......+.......+.     \",\n\" .+.............+.      \",\n\"  .+...........+.       \",\n\"   .+.........+.        \",\n\"    .+.......+.         \",\n\"     .+.....+.          \",\n\"      .+...+.           \",\n\"       .+.+.            \",\n\"        .+.             \",\n\"         .              \",\n\"                        \"]\n\n\nquitIcon = [\n\"24 24 3 1\",\n\"   c None\",\n\".  c #FFFFFF\",\n\"+  c #CC0000\",\n\"          ....          \",\n\"++++++++++....++++++++++\",\n\"+.......++....++.......+\",\n\"+.......++....++.......+\",\n\"+.......++....++.......+\",\n\"+...++++++....++++++...+\",\n\"+...++++++....++++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+......................+\",\n\"+......................+\",\n\"+......................+\",\n\"++++++++++++++++++++++++\"]\n\n\nresetIcon = [\n\"24 24 3 1\",\n\"   c None\",\n\".  c #3465A4\",\n\"+  c #888A85\",\n\"                        \",\n\"      ........          \",\n\"     .++++++++.         \",\n\"    .++..+....+.  ..... \",\n\"    .+.. .+....+. .+++. \",\n\"    .+.   .+....+..+.+. \",\n\"    ...    .+....+.+.+. \",\n\"            .+....+..+. \",\n\"             .+......+. \",\n\"              .+.....+. \",\n\"               .+....+. \",\n\"  ......        .+...+. \",\n\"  .++++.         .++++. \",\n\"  .+...+.        ...... \",\n\"  .+....+.              \",\n\"  .+.....+.             \",\n\"  .+......+.            \",\n\"  .+..+....+.           \",\n\"  .+.+.+....+.    ...   \",\n\"  .+.+..+....+.   .+.   \",\n\"  .+++. .+....+. ..+.   \",\n\"  .....  .+....+..++.   \",\n\"          .++++++++.    \",\n\"           ........     \"]\n\n\nDetectCamera = [\n\"24 24 17 1\",\n\"   c None\",\n\".  c #444453\",\n\"+  c #4245AE\",\n\"@  c #4247D9\",\n\"#  c #4F4F8E\",\n\"$  c #5B5A52\",\n\"%  c #676625\",\n\"&  c #6468EA\",\n\"*  c #7E81BC\",\n\"=  c #8C8B3B\",\n\"-  c #8183EE\",\n\";  c #909074\",\n\">  c #B8B859\",\n\",  c #B4B4DE\",\n\"'  c #CDCECE\",\n\")  c #F5F57D\",\n\"!  c #F8F86B\",\n\"                        \",\n\"      @@@@   @@@@       \",\n\"     @---@   @---@      \",\n\"   @@----@   @----@@    \",\n\"  @------&@@@&------@   \",\n\"  @-----&@@&@@&-----@   \",\n\"  @----&@@&&&@@&----@   \",\n\"  @---&@&&&&&&&@&---@   \",\n\"  @&&&@#########@&&&@   \",\n\"   ++#$%%%%%%%%%$#++    \",\n\"   .===============.    \",\n\" >>>>>>==%%%%%==>>>>>>  \",\n\">>!!!!>>=$$$$$=>>!!!!>> \",\n\">!!!!!!>=$...$=>!!!!!!> \",\n\">!!!!!!>=$@@@$=>!!!!!!> \",\n\">!!!!!!>=#@-@#=>!!!!!!> \",\n\">!!!!!!>=@---@=>!!!!!!> \",\n\">!!!!!!>=-----=>!!!!!!> \",\n\">>!!!!>>=-----=>>!!!!>> \",\n\" >>>>>> +-----+ >>>>>>  \",\n\"         +---+          \",\n\"          +-+           \",\n\"           +            \",\n\"                        \"]\n\n\nCameraToFace = [\n\"24 24 9 1\",\n\"   c None\",\n\".  c #05268B\",\n\"+  c #162567\",\n\"@  c #821E25\",\n\"#  c #3A355C\",\n\"$  c #C62921\",\n\"%  c #4D69A2\",\n\"&  c #956F83\",\n\"*  c #6AA4EC\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"       +++++++++++++++  \",\n\"      ++%%%%%%%%%%%%++  \",\n\"     ++%%%%%%%%%%%%+++  \",\n\"    ++++++++++++++++.+  \",\n\"    +**************+.+  \",\n\"    +**************+.+  \",\n\"    +**************+.+  \",\n\"    +**************+.+  \",\n\"    +*****$$$******+.+  \",\n\"    +****$$$$$*****+.+  \",\n\"    +***$$$$$$$****+.+  \",\n\"    +***$$$$$$$****+.+  \",\n\"    +***$$$$$$$****+.+  \",\n\"    +****$$$$$*****+.+  \",\n\"    +***$*$$$******+.+  \",\n\"    +*$$$**********+++  \",\n\"    +$$************++   \",\n\"    $$++++++++++++++    \",\n\"  $$$                   \",\n\" $$                     \",\n\"                        \"]\n\n\nCameraToAxis = [\n\"24 24 9 1\",\n\"   c None\",\n\".  c #FF0000\",\n\"+  c #A9352E\",\n\"@  c #7B624B\",\n\"#  c #000000\",\n\"$  c #B1AAA0\",\n\"%  c #F3A500\",\n\"&  c #DEBF17\",\n\"*  c #ECEDE9\",\n\"            ..          \",\n\"            ..          \",\n\"         ###..#######   \",\n\"      ###&&&..&&%%%##   \",\n\"    ##&&&&&&&&%%%%#%#   \",\n\"   ###############%%#   \",\n\"   #&&&&&&&%%%%%%#%%#   \",\n\"   #&&&&&&&%%%%%%#%%#   \",\n\"   #&&&&&&&%%%%%%#%%#   \",\n\"...#&&&&&&&%%%%%%#%%#   \",\n\"...#&&&&&&.%%%%%%#%.....\",\n\"   #&&&&&..%%%%%%#%.....\",\n\"   #&&&&..%%%%%%%#%%#   \",\n\"   #&&&..&%%%%%%%#%%#   \",\n\"   #&&..&%%%%%%%%#%%#   \",\n\"   #&&.&&%%%%%%%%#%##   \",\n\"   #&&..&%%%%%%%%###    \",\n\"   #&&...%%%%%%%%##     \",\n\"   ###....########      \",\n\"      .... ..           \",\n\"      .... ..           \",\n\"      .... ..           \",\n\"         . ..           \",\n\"           ..           \"]\n\n\nAlignToView = [\n\"24 24 9 1\",\n\"   c None\",\n\".  c #FF0000\",\n\"+  c #000000\",\n\"@  c #819803\",\n\"#  c #789A70\",\n\"$  c #AC9134\",\n\"%  c #13DB00\",\n\"&  c #BFB1A2\",\n\"*  c #E2CA0B\",\n\"                        \",\n\"        +               \",\n\"      ++%++             \",\n\"    ++%%%%%++           \",\n\"  ++%%%%%%%%%++         \",\n\" +%%%%%%%%%%%%%+        \",\n\" +++%%%%%%%%%+++        \",\n\" +%%++%%%%%++%%+        \",\n\" +%%%%++%++%%%%+        \",\n\" +%%%%%%+%%$$$$$$$$$$$$$\",\n\" +%%%%%%+%%$***********$\",\n\" +%%%%%%+%%$***********$\",\n\" +%%%%%%+%%$***********$\",\n\" +%%%.%%+%%$***********$\",\n\" +%%%%.%+%%$***..*..***$\",\n\" +%%%%%.+%%$****...****$\",\n\"  ++%%%%.%%$****...****$\",\n\"    ++%%+..$***..*..***$\",\n\"      ++++ ....********$\",\n\"        +  $***********$\",\n\"           $***********$\",\n\"           $***********$\",\n\"           $$$$$$$$$$$$$\",\n\"                        \"]\n\n\nPlaneAxis = [\n\"24 24 9 1\",\n\"   c None\",\n\".  c #CF0106\",\n\"+  c #DB4244\",\n\"@  c #CF5A59\",\n\"#  c #C47983\",\n\"$  c #AD8FA3\",\n\"%  c #B7B3CA\",\n\"&  c #B1C7E2\",\n\"*  c #D6D3D7\",\n\"           ..           \",\n\"           ..           \",\n\"           ..           \",\n\"        &&&..&&&        \",\n\"       &&&&..&&&&       \",\n\"      &&&&&..&&&&&      \",\n\"     &&&&&&..&&&&&&     \",\n\"    &&&&&&&++&&&&&&&    \",\n\"   &&&&&&&&++&&&&&&&&   \",\n\"   &&&&&&&&++&&&&&&&&   \",\n\"   &&&&&&&&..&&&&&&&&   \",\n\".......+++....+++.......\",\n\".......+++....+++.......\",\n\"   &&&&&&&&..&&&&&&&&   \",\n\"   &&&&&&&&++&&&&&&&&   \",\n\"   &&&&&&&&++&&&&&&&&   \",\n\"    &&&&&&&++&&&&&&&    \",\n\"     &&&&&&..&&&&&&     \",\n\"      &&&&&..&&&&&      \",\n\"       &&&&..&&&&       \",\n\"        &&&..&&&        \",\n\"           ..           \",\n\"           ..           \",\n\"           ..           \"]\n\n\nCameraPhoto = [\n\"24 24 9 1\",\n\"   c None\",\n\".  c #161817\",\n\"+  c #313332\",\n\"@  c #424544\",\n\"#  c #515452\",\n\"$  c #686B68\",\n\"%  c #838582\",\n\"&  c #A8ABA8\",\n\"*  c #D9DBD8\",\n\"                        \",\n\"                        \",\n\"            &***&       \",\n\"            &****%      \",\n\"            %&&&&#      \",\n\"            +   ++      \",\n\"           .+#$$#.      \",\n\"          +$$$$$$$+     \",\n\"   +#$%%%%%%%%%%%%%$$@  \",\n\"  %&&$$%%%*$$$$%%%%$$%+ \",\n\" +&%%$#%+$%$$$$###%$$%+ \",\n\" +%%&%%@+@#$&%$###@$$%+ \",\n\" +$###@++@#%###@####$%+ \",\n\" +$###@++@$@@....++#$$+ \",\n\" +$###@++@#+.@#..+++$%+ \",\n\" +$###@++@++.%&&@+@+#%+ \",\n\" +$###@++@++.$*&%@@+#%+ \",\n\" +$###@+@#++.+$%%##+#$+ \",\n\" +$$####++@++.@###@+++  \",\n\"  .+@@+.   ++@@##@++    \",\n\"            +++++++     \",\n\"              @@@       \",\n\"                        \",\n\"                        \"]\n\n\nCameraPhotoOk = [\n\"24 24 9 1\",\n\"   c None\",\n\".  c #000100\",\n\"+  c #161815\",\n\"@  c #323331\",\n\"#  c #4C4E4B\",\n\"$  c #686A67\",\n\"%  c #4B9A00\",\n\"&  c #898B88\",\n\"*  c #D8DBD7\",\n\"                       %\",\n\"                     %%.\",\n\"                   %%.. \",\n\"                 %%..%  \",\n\"%              %%...%   \",\n\".%%          %%..%.%    \",\n\"%..%%      %%..%%.%     \",\n\"%.%..%%  %%..%%%.%      \",\n\" %.%%..%%..%%%%.%       \",\n\" %.%%%%..%%%%%.%&**&    \",\n\"  %.%%%%%%%%%.% &**&    \",\n\"   %.%%%%%%%.%  #  #    \",\n\"   %.%%%%%%.%  @#$$#$   \",\n\"    %.%%%%.%  @$&&&&$   \",\n\"     %.%%.%$&&&&$$&&&$$$\",\n\"     %.%.%&$&@$$$$##$$$#\",\n\"      %+%&$$#@#$$$####$#\",\n\"       %$###@@#$#@@@@#$#\",\n\"        $###@@#@@##@@@$#\",\n\"        $###@@#@@*&$#@##\",\n\"        $###@@#@+$&&#@##\",\n\"        $###@##@@@###@##\",\n\"        $$$$$$$$@###@#  \",\n\"                 ###    \"]\n\n\nimport PySide\nfrom PySide import (QtWidgets, QtCore, QtGui)\nfrom PySide.QtWidgets import * #(QWidget, QApplication, QSlider, QGraphicsView, QGraphicsScene, QVBoxLayout, QStyle)\nfrom PySide.QtGui import * #(QPainter, QColor, QIcon)\nfrom PySide.QtSvg import *\ntry:\n    import webbrowser\nexcept Exception:\n    None\n\nimport Draft, Part, FreeCAD, math, PartGui, FreeCADGui, DraftVecUtils\n#import os, WorkingPlane \nApp = FreeCAD\nfrom math import radians, degrees, sqrt, pi, sin, cos, asin\nfrom decimal import *\nfrom FreeCAD import Base\nfrom FreeCAD import Vector\nimport pivy\nfrom pivy import coin\n\n#### Detect version macro ###########################################\nglobal switchVesionMacroSearch#; switchVesionMacroSearch = False\ndef vesionSearch():\n    try:\n        import urllib\n        from urllib import request\n\n        contentPage = request.urlopen(\"https://wiki.freecadweb.org/Macro_FCCamera\").readlines()\n\n        for i in contentPage:\n            if \"ctEven macro-version\" in str(i):\n                versionDetect = (str(i).split(\">\")[1].split(\"\\\\\")[0])\n            if \"ctEven macro-date\" in str(i):\n                dateDetect = (str(i).split(\">\")[1].split(\"\\\\\")[0])\n            try:\n                if (len(versionDetect) != 0) and (len(dateDetect) != 0):\n                    break\n            except Exception:\n                None\n        try:\n            if (versionDetect == __version__) and (dateDetect == __date__):\n                None\n            else:\n                msg = (\"New version availlable : \" + \"\\n\" + \n                      str(versionDetect) + \":\" + str(dateDetect) + \"\\n\" + \n                      \"You can install with AddonManager\")\n                FreeCAD.Console.PrintMessage(\"your actual version    : \" + str(__version__) + \" : \" + str(__date__) + \"\\n\")\n                FreeCAD.Console.PrintMessage(\"new version availlable : \" + str(versionDetect) + \" : \" + str(dateDetect) + \"\\n\")\n                diag = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Information, 'New Version', msg)\n                diag.setWindowModality(QtCore.Qt.ApplicationModal)\n                diag.exec_()\n        except Exception:\n            None\n        return versionDetect, dateDetect\n    except Exception:\n        None\n\nswitchVesionMacroSearch = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switchVesionMacroSearch\")\nif switchVesionMacroSearch == True:\n    vesionSearch()\n#### Detect version macro ###########################################\n\nglobal path     ; path      = \"\"\nglobal pathFile ; pathFile  = \"\"\nglobal valeur   ; valeur    = 0.0\nglobal valeurV  ; valeurV   = 0.0\nglobal Rname    ; Rname     = [\"\",\"\",\"\"]\nglobal RnameCube; RnameCube = \"\"\nglobal RnameCompound; RnameCompound = \"\"\nglobal datExtract; datExtract = \"\"\n\nglobal positionX ; positionX = 0.0\nglobal positionY ; positionY = 0.0\nglobal positionZ ; positionZ = 0.0\nglobal vertexeS  ; vertexeS  = Vector(0.0,0.0,0.0)\nglobal bounBoxCenter; bounBoxCenter = Vector(0.0,0.0,0.0)\n\nglobal dim_Horizont ; dim_Horizont = 0\nglobal dim_Vertical ; dim_Vertical = 0\nglobal ori_Vertical ; ori_Vertical = 0\nglobal ori_Horizont ; ori_Horizont = 0\nglobal numberPhoto  ; numberPhoto  = 0.0\nglobal valueTest    ; valueTest    = 0.0\n\nglobal formatFichier; formatFichier= \".png\"\nglobal s            ; s  = \"\"\nglobal ui           ; ui = \"\"\nglobal Nameelement2 ; Nameelement2 = \"\"  # new selection\nglobal vueView      ; vueView      = 0   # passe vue\n\ntry:\n    activeView = Gui.ActiveDocument.ActiveView\nexcept Exception:\n    ### Begin command Std_New\n    App.newDocument(\"FCCamera\")\n    App.setActiveDocument(\"FCCamera\")\n    App.ActiveDocument=App.getDocument(\"FCCamera\")\n    Gui.ActiveDocument=Gui.getDocument(\"FCCamera\")\n    activeView = Gui.ActiveDocument.ActiveView\n    ### End command Std_New\n\nglobal doc\ndoc = FreeCAD.ActiveDocument\nif doc == None:\n    doc = FreeCAD.newDocument(\"FCCamera\")         # create one document\n\n####\nmainWindow = FreeCADGui.getMainWindow()\nmdi = mainWindow.findChild(QtWidgets.QMdiArea)\nmwActive = mdi.activeSubWindow()\n\ntry:\n    dim_Horizont = ori_Horizont = mwActive.width()\n    dim_Vertical = ori_Vertical = mwActive.height()\nexcept Exception:\n    dim_Horizont = ori_Horizont = mdi.width()\n    dim_Vertical = ori_Vertical = mdi.height()\n####\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\nclass SelObserver:                                               # SelObserver\n    def addSelection(self,document, object, element, position):  # Selection SelObserver\n        global positionX\n        global positionY\n        global positionZ\n        global vertexeS\n        global bounBoxCenter\n\n        positionX = position[0]\n        positionY = position[1]\n        positionZ = position[2]\n\n        bounBoxCenter = Vector(0.0,0.0,0.0)\n\n        if (element[:4] == \"Edge\"):\n            vertex = FreeCAD.ActiveDocument.getObject(object).Shape.Edges[int(element[4:])-1].Vertexes\n            bounBoxCenter = FreeCAD.ActiveDocument.getObject(object).Shape.Edges[int(element[4:])-1].BoundBox.Center\n            try:\n                vertexeS = vertex[1].Point.sub(vertex[0].Point)\n            except Exception:\n                vertexeS = Vector(0.0,0.0,0.0)\n        else:\n            vertexeS = Vector(0.0,0.0,0.0)\n            try:\n                bounBoxCenter = FreeCAD.ActiveDocument.getObject(object).Shape.Edges[int(element[4:])-1].BoundBox.Center\n            except Exception:\n                bounBoxCenter = FreeCAD.Vector(positionX, positionY, positionZ)\n\ndef datExtract(data):\n# return a string\n    data = str(data)\n    a    = \"\"\n    for i in data:\n        if i in (\"0123456789e.- \"):\n            a+=i\n    a = a.strip(\" \")\n    a = a.split(\" \")\n    return a\n\ndef centerBoundBoxGlobal():\n    global doc\n\n    doc = App.activeDocument()\n    objs0  = doc.findObjects()\n    pointMilieu = []\n\n    if len(objs0) != 0:\n        xMin = yMin = zMin = 0.0\n        xMax = yMax = zMax = 0.0\n        for objs in objs0:\n            try:\n                if objs.ViewObject.Visibility:\n                    if hasattr(objs, \"Shape\"):\n                        s = objs.Shape\n                    elif hasattr(objs, \"Mesh\"):      # upgrade with wmayer thanks #http://forum.freecadweb.org/viewtopic.php?f=13&t=22331\n                        s = objs.Mesh\n                    elif hasattr(objs, \"Points\"):\n                        s = objs.Points\n\n                    boundBox_ = s.BoundBox\n                    extractValue = datExtract(boundBox_)\n\n                    if float(extractValue[0]) < xMin:\n                        xMin = float(extractValue[0])\n                    if float(extractValue[1]) < yMin:\n                        yMin = float(extractValue[1])\n                    if float(extractValue[2]) < zMin:\n                        zMin = float(extractValue[2])\n\n                    if float(extractValue[3]) > xMax:\n                        xMax = float(extractValue[3])\n                    if float(extractValue[4]) > yMax:\n                        yMax = float(extractValue[4])\n                    if float(extractValue[5]) > zMax:\n                        zMax = float(extractValue[5])\n            except Exception:\n                None\n        #### diagonale et pointMilieu\n        points=[FreeCAD.Vector(xMin, yMin, zMin),FreeCAD.Vector(xMax, yMax, zMax)]    #diagonal\n        diagonal = Draft.makeWire(points,closed=False,face=False,support=None)        #create diagonal line\n        try:\n            pointMilieu = diagonal.Shape.copy().discretize(3)                         #cut line for search center\n        except Exception:\n            None\n        doc.removeObject(diagonal.Name)\n        #Draft.makePoint(pointMilieu[1])\n        try:\n            return pointMilieu[1]\n        except Exception:\n            return FreeCAD.Vector(0.0,0.0,0.0)\n    else:\n        return FreeCAD.Vector(0.0,0.0,0.0)\n\ndef To_Face_Or_To_Axis(ToFace):         # 1=NormalAt 0=Axis   #Align Face selected to Face or to Axis\n    global vueView\n    global Nameelement2\n    global vertexeS\n\n    try:\n        FreeCAD.ActiveDocument.openTransaction(\"To_Face_Or_To_Axis\")# memorise les actions (avec annuler restore)\n        #FreeCAD.ActiveDocument.commitTransaction()         # restore les actions  (avec annuler restore)\n        #FreeCAD.ActiveDocument.abortTransaction()          # abandonne les actions(avec annuler restore)\n\n        sel = FreeCADGui.Selection.getSelection()\n        SubElement = FreeCADGui.Selection.getSelectionEx()\n\n        try:\n            Nameelement = SubElement[0].SubElementNames[0]\n            if Nameelement != Nameelement2:\n                vueView = 0\n            Nameelement2 = Nameelement\n        except Exception:\n            Nameelement = \"\"\n    ##https://forum.freecadweb.org/viewtopic.php?t=37580\n        if ToFace == 1:                                           # To_Face\n            if SubElement[0].TypeName == \"PartDesign::Plane\":\n                v = sel[0].Shape.normalAt(0,0)                    # NormalAt Object\n            else:\n                v = SubElement[0].SubObjects[0].normalAt(0,0)     # NormalAt SubObject\n            App.Console.PrintMessage(\"NormalAt     : \")\n        else:                                                     # To_Axis\n            try:\n                v=SubElement[0].SubObjects[0].Surface.Axis        # Axis Surface\n                App.Console.PrintMessage(\"Surface Axis : \")\n            except Exception:\n                v=vertexeS                                        # Axis Edges\n                App.Console.PrintMessage(\"Axis Edges   : \")\n\n        if vueView == 0:\n            r=App.Rotation(App.Vector(0,0,1),v)\n            App.Console.PrintMessage(\"0,0,1\"+\"\\n\")\n        elif vueView == 1:\n            r=App.Rotation(App.Vector(0,0,-1),v)\n            App.Console.PrintMessage(\"0,0,-1\"+\"\\n\")\n        elif vueView == 2:\n            r=App.Rotation(App.Vector(0,1,0),v)\n            App.Console.PrintMessage(\"0,1,0\"+\"\\n\")\n        elif vueView == 3:\n            r=App.Rotation(App.Vector(0,-1,0),v)\n            App.Console.PrintMessage(\"0,-1,0\"+\"\\n\")\n        elif vueView == 4:\n            r=App.Rotation(App.Vector(1,0,0),v)\n            App.Console.PrintMessage(\"1,0,0\"+\"\\n\")\n        elif vueView == 5:\n            r=App.Rotation(App.Vector(-1,0,0),v)\n            App.Console.PrintMessage(\"-1,0,0\"+\"\\n\")\n            vueView = -1\n\n        Gui.ActiveDocument.ActiveView.setCameraOrientation(r.Q)#\n        vueView += 1\n    except:\n        App.Console.PrintError(\"Select a face\"+\"\\n\")\n\nclass Ui_MainWindow(object):\n    def setupUi(self, MainWindow):\n        global path\n        global pathFile\n        global valeur\n        global ori_Horizont\n        global ori_Vertical\n        global numberPhoto\n\n        self.window = MainWindow\n\n        #################################################################################\n        #path = FreeCAD.ConfigGet(\"AppHomePath\")\n        #path = FreeCAD.ConfigGet(\"UserAppData\")\n        #path = \"your path\"\n        param = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")# macro path\n        path = param.GetString(\"MacroPath\",\"\") + \"/\"                        # macro path\n        path = path.replace(\"\\\\\",\"/\") #pathFile = \n#        App.Console.PrintMessage(\"Path locality to FCCamera.....images.png [ \" + path + \" ]\"+\"\\n\")\n        #################################################################################\n\n        MainWindow.setObjectName(_fromUtf8(\"MainWindow\"))\n#        MainWindow.resize(200, 625)\n#        MainWindow.move(900, 200)                           # deplace la fenetre\n        self.centralWidget = QtWidgets.QWidget(MainWindow)\n        self.centralWidget.setObjectName(_fromUtf8(\"centralWidget\"))\n\n        self.FontImpost    = \"Arial\"\n#        #self.xxxx.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))  # Bold\n\n        self.groupBox_00 = QtWidgets.QGroupBox()\n        ####\n        self.groupBox_001 = QtWidgets.QGroupBox()\n\n        self.label_02 = QtWidgets.QLabel()\n\n        ### ---graphicsView---\n        self.graphicsView = QtWidgets.QGraphicsView()\n        self.graphicsView.setFrameShape(QtWidgets.QFrame.StyledPanel)\n        pic = QtGui.QPixmap()\n        pic.loadFromData(base64.b64decode(FCCamera_Axis_rotation_X_BMP))\n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(ui.scene)\n\n        ### ---graphicsView---\n        ####\n        self.groupBox_002 = QtWidgets.QGroupBox()\n\n        self.DS_Angle = QtWidgets.QDoubleSpinBox()\n        self.DS_Angle.setAlignment(QtCore.Qt.AlignCenter)\n        self.DS_Angle.setDecimals(4)\n        self.DS_Angle.setMinimum(-359.0)\n        self.DS_Angle.setMaximum(359.0)\n        self.DS_Angle.setSuffix(\" degrees\")\n        self.DS_Angle.setSingleStep(1.0)\n        self.DS_Angle.valueChanged.connect(self.on_DS_Angle_valueChanged) #connection DS_Angle\n\n        self.CB_Multiply_10 = QtWidgets.QCheckBox()\n        self.CB_Multiply_10.clicked.connect(self.on_CB_Multiply_10) #connection checkBox\n\n        self.label_03 = QtWidgets.QLabel()\n\n        self.RB_Angle_X = QtWidgets.QRadioButton()\n        self.RB_Angle_X.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))   # Bold\n        self.RB_Angle_X.setStyleSheet(\"color : #ff0000\")                                # Color text\n        self.RB_Angle_X.setMouseTracking(True)\n        self.RB_Angle_X.setChecked(True)\n        self.RB_Angle_X.clicked.connect(self.on_RB_Angle_X_clicked)\n\n        self.RB_Angle_Y = QtWidgets.QRadioButton()\n        self.RB_Angle_Y.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))  # Bold\n        self.RB_Angle_Y.setStyleSheet(\"color : #008700\")                         # Color text\n        self.RB_Angle_Y.clicked.connect(self.on_RB_Angle_Y_clicked)\n\n        self.RB_Angle_Z = QtWidgets.QRadioButton()\n        self.RB_Angle_Z.setStyleSheet(\"color : #0000ff\")                         # Color text\n        self.RB_Angle_Z.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))  # Bold\n        self.RB_Angle_Z.clicked.connect(self.on_RB_Angle_Z_clicked)\n\n        self.RB_Direction = QtWidgets.QRadioButton()\n        self.RB_Direction.setStyleSheet(\"color : #000066\")                         # Color text\n        self.RB_Direction.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))  # Bold\n        self.RB_Direction.clicked.connect(self.on_RB_Direction_clicked)\n\n        self.PB_Accept_View = QtWidgets.QPushButton()\n        self.PB_Accept_View.setIcon(QtGui.QIcon(QtGui.QPixmap(executeIcon)))# execute icone dans une variable \n        self.PB_Accept_View.clicked.connect(self.on_PB_Accept_View_clicked)\n        ####\n        self.groupBox_003 = QtWidgets.QGroupBox()\n        #self.groupBox_003.setVisible(False)\n\n        self.PB_Detect_Camera = QtWidgets.QPushButton()\n        self.PB_Detect_Camera.setIcon(QtGui.QIcon(QtGui.QPixmap(DetectCamera))) # DetectCamera icone dans une variable \n        self.PB_Detect_Camera.clicked.connect(self.on_PB_Detect_Camera_clicked)\n\n        self.label_04 = QtWidgets.QLabel()\n\n        self.PB_To_Face = QtWidgets.QPushButton()\n        self.PB_To_Face.setIcon(QtGui.QIcon(QtGui.QPixmap(CameraToFace))) # CameraToFace icone dans une variable \n        self.PB_To_Face.clicked.connect(self.on_PB_To_Face_clicked) # align view to face Face\n\n        self.PB_To_Axis = QtWidgets.QPushButton()\n        self.PB_To_Axis.setIcon(QtGui.QIcon(QtGui.QPixmap(CameraToAxis))) # CameraToAxis icone dans une variable \n        self.PB_To_Axis.clicked.connect(self.on_PB_To_Axis_clicked) # Align view to face Axis\n\n        self.PB_Align_O_To_View = QtWidgets.QPushButton()\n        self.PB_Align_O_To_View.setIcon(QtGui.QIcon(QtGui.QPixmap(AlignToView))) # AlignToView icone dans une variable \n        self.PB_Align_O_To_View.clicked.connect(self.on_PB_Align_O_To_View_clicked) # Align object to view\n        ####\n        self.groupBox_004 = QtWidgets.QGroupBox()\n\n        self.PB_Create_Plane = QtWidgets.QPushButton()\n        self.PB_Create_Plane.setIcon(QtGui.QIcon(QtGui.QPixmap(PlaneAxis))) # PlaneAxis icone dans une variable \n        self.PB_Create_Plane.clicked.connect(self.on_PB_Create_Plane_clicked) # create plane\n\n        self.RB_01_Plane_Point = QtWidgets.QRadioButton()\n        self.RB_01_Plane_Point.setChecked(True)\n        self.RB_02_Plane_Face = QtWidgets.QRadioButton()\n        self.RB_03_Plane_CMass = QtWidgets.QRadioButton()\n        self.RB_04_Center_BBox = QtWidgets.QRadioButton()\n        ####\n        self.groupBox_005 = QtWidgets.QGroupBox()\n\n        self.PB_Reset = QtWidgets.QPushButton(self.centralWidget)\n        self.PB_Reset.setIcon(QtGui.QIcon(QtGui.QPixmap(resetIcon)))  # reset icone dans une variable \n        self.PB_Reset.clicked.connect(self.on_PB_Reset_clicked) # refresh\n\n        self.PB_Photo = QtWidgets.QPushButton()\n        self.PB_Photo.setIcon(QtGui.QIcon(QtGui.QPixmap(CameraPhoto))) # Camera icone dans une variable \n        self.PB_Photo.clicked.connect(self.on_PB_Photo_clicked)\n\n        self.PB_Quit = QtWidgets.QPushButton()\n        self.PB_Quit.setIcon(QtGui.QIcon(QtGui.QPixmap(quitIcon))) # quit icone dans une variable \n        self.PB_Quit.clicked.connect(self.on_PB_Quit_clicked) # quit\n\n        self.PB_Help = QtWidgets.QPushButton()\n        self.PB_Help.setIcon(QtGui.QIcon(QtGui.QPixmap(helpIcon)))      # icone dans une variable help\n        self.PB_Help.clicked.connect(self.on_PB_Help) ###\n        ####\n        self.groupBox_00PH = QtWidgets.QGroupBox()\n        self.groupBox_00PH.setVisible(False)\n        ####\n        self.groupBox_00PH01 = QtWidgets.QGroupBox()\n        self.CBox_01_Ecran = QtWidgets.QComboBox()\n\n#        self.CBox_01_Ecran.setCurrentIndex(0)\n#        CBox_01_Ecran = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"CBox_01_Ecran\")# \n#        print(CBox_01_Ecran)\n#        self.CBox_01_Ecran.setCurrentIndex(int(CBox_01_Ecran))\n        \n        self.CBox_01_Ecran.addItem(_fromUtf8(\"Actual\"))\n        self.CBox_01_Ecran.addItem(_fromUtf8(\"Icon 16 x 16\"))\n        self.CBox_01_Ecran.addItem(_fromUtf8(\"Icon 32 x 32\"))\n        self.CBox_01_Ecran.addItem(_fromUtf8(\"Icon 64 x 64\"))\n        self.CBox_01_Ecran.addItem(_fromUtf8(\"Icon 128 x 128\"))\n        self.CBox_01_Ecran.addItem(_fromUtf8(\"CGA 320 x 200\"))\n        self.CBox_01_Ecran.addItem(_fromUtf8(\"QVGA 320 x 240\"))\n        self.CBox_01_Ecran.addItem(_fromUtf8(\"VGA 640 x 480\"))\n        self.CBox_01_Ecran.addItem(_fromUtf8(\"SVGA 800 x 600\"))\n        self.CBox_01_Ecran.addItem(_fromUtf8(\"XGA 1024 x 768\"))\n        self.CBox_01_Ecran.addItem(_fromUtf8(\"XGA+ 1152 x 864\"))\n        self.CBox_01_Ecran.addItem(_fromUtf8(\"SXGA 1280 x 1024\"))\n        self.CBox_01_Ecran.addItem(_fromUtf8(\"SXGA+ 1400 x 1050\"))\n        self.CBox_01_Ecran.addItem(_fromUtf8(\"UXGA 1600 x 1200\"))\n        self.CBox_01_Ecran.addItem(_fromUtf8(\"QXGA 2048 x 1536\"))\n        self.CBox_01_Ecran.addItem(_fromUtf8(\"Free\"))\n        QtCore.QObject.connect(self.CBox_01_Ecran, QtCore.SIGNAL(\"currentIndexChanged(QString)\"), self.SIGNAL_CBox_01_Ecran_Changed)\n\n        self.DS_01_X = QtWidgets.QSpinBox()\n        self.DS_01_X.setMinimum(1)\n        self.DS_01_X.setMaximum(ori_Horizont)\n        self.DS_01_X.setSingleStep(1)\n        self.DS_01_X.setValue(ori_Horizont)\n        self.DS_01_X.valueChanged.connect(self.on_DS_01_X_valueChanged) #connection doubleSpinBox\n\n        self.label_05 = QtWidgets.QLabel()\n        self.label_05.setStyleSheet(\"color : #ff0000\")                         # Color text\n        self.label_05.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))  # Bold\n\n        self.DS_02_Y = QtWidgets.QSpinBox()\n        self.DS_02_Y.setMinimum(1)\n        self.DS_02_Y.setMaximum(ori_Vertical)\n        self.DS_02_Y.setSingleStep(1)\n        self.DS_02_Y.setValue(ori_Vertical)\n        self.DS_02_Y.valueChanged.connect(self.on_DS_02_Y_valueChanged) #connection doubleSpinBox\n\n        self.label_06 = QtWidgets.QLabel()\n        self.label_06.setStyleSheet(\"color : #008700\")                         # Color text\n        self.label_06.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))  # Bold\n\n        self.label_07 = QtWidgets.QLabel()\n\n        self.PB_Photo_Adjust = QtWidgets.QPushButton()\n        self.PB_Photo_Adjust.setVisible(False)\n#        self.PB_Photo_Adjust.setIcon(QtGui.QIcon(path + \"FCCamera_07.png\"))\n        self.PB_Photo_Adjust.clicked.connect(self.on_PB_Photo_Adjust_clicked)\n\n        self.label_08 = QtWidgets.QLabel()\n        self.CBox_02_FileFormat = QtWidgets.QComboBox()\n\n#        CBox_02_FileFormat = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"CBox_02_FileFormat\")# \n#        print(CBox_02_FileFormat)\n#        self.CBox_02_FileFormat.setCurrentIndex(int(CBox_02_FileFormat))\n\n        self.CBox_02_FileFormat.addItem(_fromUtf8(\"BMP *.bmp\"))\n        self.CBox_02_FileFormat.addItem(_fromUtf8(\"ICO *.ico\"))\n        self.CBox_02_FileFormat.addItem(_fromUtf8(\"JPEG *.jpeg\"))\n        self.CBox_02_FileFormat.addItem(_fromUtf8(\"JPG *.jpg\"))\n        self.CBox_02_FileFormat.addItem(_fromUtf8(\"PNG *.png\"))\n        self.CBox_02_FileFormat.addItem(_fromUtf8(\"PPM *.ppm\"))\n        self.CBox_02_FileFormat.addItem(_fromUtf8(\"TIF *.tif\"))\n        self.CBox_02_FileFormat.addItem(_fromUtf8(\"TIFF *.tiff\"))\n        self.CBox_02_FileFormat.addItem(_fromUtf8(\"XBM *.xbm\"))\n        self.CBox_02_FileFormat.addItem(_fromUtf8(\"XPM *.xpm\"))\n        #self.CBox_02_FileFormat.addItem(_fromUtf8(\"GIF *.gif\"))\n        QtCore.QObject.connect(self.CBox_02_FileFormat, QtCore.SIGNAL(\"currentIndexChanged(QString)\"), self.SIGNAL_CBox_02_FileFormat_Changed)\n        ####\n        self.groupBox_00PH02 = QtWidgets.QGroupBox()\n\n        self.RB_01_Actual = QtWidgets.QRadioButton()\n        self.RB_01_Actual.setChecked(True)\n#        self.RB_01_Actual.clicked.connect(self.on_RB_01_Actual_clicked)\n\n        self.RB_02_White = QtWidgets.QRadioButton()\n#        self.RB_02_White.clicked.connect(self.on_RB_02_White_clicked)\n\n        self.RB_03_Black = QtWidgets.QRadioButton()\n#        self.RB_03_Black.clicked.connect(self.on_RB_03_Black_clicked)\n\n        self.RB_04_Transparent = QtWidgets.QRadioButton()\n#        self.RB_04_Transparent.clicked.connect(self.on_RB_04_Transparent_clicked)\n        ####\n        self.groupBox_00PH03 = QtWidgets.QGroupBox()\n\n        self.PB_Photo_Launch = QtWidgets.QPushButton()\n        self.PB_Photo_Launch.setIcon(QtGui.QIcon(QtGui.QPixmap(CameraPhotoOk)))# execute icone dans une variable \n        self.PB_Photo_Launch.clicked.connect(self.on_PB_Photo_Launch_clicked)\n\n        self.PB_Photo_Reset = QtWidgets.QPushButton()\n        self.PB_Photo_Reset.setIcon(QtGui.QIcon(QtGui.QPixmap(resetIcon)))  # reset icone dans une variable \n        self.PB_Photo_Reset.clicked.connect(self.on_PB_Photo_Reset_clicked)\n\n        self.PB_Photo_Quit = QtWidgets.QPushButton()\n#        self.PB_Photo_Quit.setIcon(QtGui.QIcon(QtGui.QPixmap(quitIcon))) # quit icone dans une variable \n        iconRotate = QtGui.QPixmap(quitIcon).transformed(QtGui.QTransform().rotate(-90), QtCore.Qt.SmoothTransformation)#Rotation\n        self.PB_Photo_Quit.setIcon(iconRotate)\n        self.PB_Photo_Quit.clicked.connect(self.on_PB_Photo_Quit_clicked)\n        #####\n\n        #### GridLayout begin ######\n        self.grid0 = QtWidgets.QGridLayout(self.centralWidget)\n        self.grid0.setContentsMargins(10, 10, 10, 10)\n        self.grid0.addWidget(self.groupBox_00, 0, 0, 1, 1)\n        self.grid_00 = QtWidgets.QGridLayout(self.groupBox_00)\n        ####\n        self.gridLayout_3 = QtWidgets.QGridLayout(self.groupBox_001)\n        self.gridLayout_3.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_3.addWidget(self.graphicsView, 0, 0, 1, 1)\n        self.grid_00.addWidget(self.groupBox_001, 0, 0, 1, 1)\n        ####\n        self.gridLayout_4 = QtWidgets.QGridLayout(self.groupBox_002)\n        self.gridLayout_4.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_4.addWidget(self.label_02, 0, 0, 1, 4)\n        self.gridLayout_4.addWidget(self.DS_Angle, 1, 0, 1, 3)\n        self.gridLayout_4.addWidget(self.CB_Multiply_10, 1, 3, 1, 1)\n        self.gridLayout_4.addWidget(self.label_03, 2, 0, 1, 1)\n        self.gridLayout_4.addWidget(self.RB_Angle_X, 3, 0, 1, 1)\n        self.gridLayout_4.addWidget(self.RB_Angle_Y, 3, 1, 1, 1)\n        self.gridLayout_4.addWidget(self.RB_Angle_Z, 3, 2, 1, 1)\n        self.gridLayout_4.addWidget(self.RB_Direction, 3, 3, 1, 1)\n        self.gridLayout_4.addWidget(self.PB_Accept_View, 4, 0, 1, 4)\n        self.grid_00.addWidget(self.groupBox_002, 1, 0, 1, 1)\n        ####\n        self.gridLayout_5 = QtWidgets.QGridLayout(self.groupBox_003)\n        self.gridLayout_5.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_5.addWidget(self.PB_Detect_Camera, 0, 0, 1, 2)\n        self.gridLayout_5.addWidget(self.label_04, 1, 0, 1, 2)\n        self.gridLayout_5.addWidget(self.PB_To_Face, 2, 0, 1, 1)\n        self.gridLayout_5.addWidget(self.PB_To_Axis, 2, 1, 1, 1)\n        self.gridLayout_5.addWidget(self.PB_Align_O_To_View, 3, 0, 1, 2)\n        self.grid_00.addWidget(self.groupBox_003, 2, 0, 1, 1)\n        ####\n        self.gridLayout_6 = QtWidgets.QGridLayout(self.groupBox_004)\n        self.gridLayout_6.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_6.addWidget(self.PB_Create_Plane, 0, 0, 1, 4)\n        self.gridLayout_6.addWidget(self.RB_01_Plane_Point, 1, 0, 1, 1)\n        self.gridLayout_6.addWidget(self.RB_02_Plane_Face, 1, 1, 1, 1)\n        self.gridLayout_6.addWidget(self.RB_03_Plane_CMass, 1, 2, 1, 1)\n        self.gridLayout_6.addWidget(self.RB_04_Center_BBox, 1, 3, 1, 1)\n        self.grid_00.addWidget(self.groupBox_004, 3, 0, 1, 1)\n        ####\n        self.gridLayout_7 = QtWidgets.QGridLayout(self.groupBox_005)\n        self.gridLayout_7.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_7.addWidget(self.PB_Reset, 0, 0, 1, 1)\n        self.gridLayout_7.addWidget(self.PB_Photo, 0, 1, 1, 1)\n        self.gridLayout_7.addWidget(self.PB_Quit, 0, 2, 1, 1)\n        self.gridLayout_7.addWidget(self.PB_Help, 0, 3, 1, 1)\n        self.grid_00.addWidget(self.groupBox_005, 4, 0, 1, 1)\n        ####\n        #####photo\n        self.gridLayout_9 = QtWidgets.QGridLayout(self.groupBox_00PH)\n        self.gridLayout_11 = QtWidgets.QGridLayout(self.groupBox_00PH01)\n        self.gridLayout_11.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_11.addWidget(self.CBox_01_Ecran, 0, 0, 1, 4)\n        self.gridLayout_11.addWidget(self.DS_01_X, 1, 0, 1, 1)\n        self.gridLayout_11.addWidget(self.label_05, 1, 1, 1, 1)\n        self.gridLayout_11.addWidget(self.DS_02_Y, 1, 2, 1, 1)\n        self.gridLayout_11.addWidget(self.label_06, 1, 3, 1, 1)\n        self.gridLayout_11.addWidget(self.CBox_02_FileFormat, 2, 0, 1, 4)\n        self.gridLayout_11.addWidget(self.label_07, 3, 0, 1, 2)\n        self.gridLayout_11.addWidget(self.PB_Photo_Adjust, 3, 2, 1, 2)\n        self.gridLayout_11.addWidget(self.label_08, 4, 0, 1, 4)\n        self.gridLayout_9.addWidget(self.groupBox_00PH01, 0, 0, 1, 1)\n        ####\n        self.gridLayout_8 = QtWidgets.QGridLayout(self.groupBox_00PH02)\n        self.gridLayout_8.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_8.addWidget(self.RB_01_Actual, 0, 0, 1, 1)\n        self.gridLayout_8.addWidget(self.RB_02_White, 0, 1, 1, 1)\n        self.gridLayout_8.addWidget(self.RB_03_Black, 0, 2, 1, 1)\n        self.gridLayout_8.addWidget(self.RB_04_Transparent, 0, 3, 1, 1)\n        self.gridLayout_9.addWidget(self.groupBox_00PH02, 1, 0, 1, 1)\n        ####\n        self.gridLayout_10 = QtWidgets.QGridLayout(self.groupBox_00PH03)\n        self.gridLayout_10.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_10.addWidget(self.PB_Photo_Reset, 0, 1, 1, 1)\n        self.gridLayout_10.addWidget(self.PB_Photo_Quit, 0, 2, 1, 1)\n        self.gridLayout_10.addWidget(self.PB_Photo_Launch, 0, 3, 1, 1)\n        self.gridLayout_9.addWidget(self.groupBox_00PH03, 2, 0, 1, 1)\n        self.grid_00.addWidget(self.groupBox_00PH, 2, 0, 1, 1)\n        #### GridLayout end ######\n\n        MainWindow.setCentralWidget(self.centralWidget)\n\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n        MainWindow.setWindowTitle(\"FCCamera\")\n        MainWindow.setWindowIcon(QtGui.QIcon(path+'FCCamera_00.png'))         # change l'icone de la fenetre principale\n        MainWindow.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint)      # PySide cette fonction met la fenetre en avant\n        _translate = QtCore.QCoreApplication.translate\n        global numberPhoto\n        global ori_Horizont\n        global ori_Vertical\n\n        self.groupBox_00.setTitle(_translate(\"MainWindow\", \"Version : \" +  __version__ + \" : \" + __date__) + \" (rmu)\")\n        self.groupBox_001.setTitle(_translate(\"MainWindow\", \"View\"))\n        self.groupBox_002.setTitle(_translate(\"MainWindow\", \"Camera of Axis\"))\n        ####\n        self.CB_Multiply_10.setText(_translate(\"MainWindow\", \"Step by 10\"))\n        self.CB_Multiply_10.setToolTip(_translate(\"MainWindow\", \"If checked the value is Multiply by 10\"))\n        self.label_02.setText(_translate(\"MainWindow\", \"Angle rotation Axis in degrees\"))\n        self.DS_Angle.setToolTip(_translate(\"MainWindow\", \"Enter the angle of rotation in degrees.\\n\"\n                                  \"The given angle is added to the angle of the current view\"))\n        self.label_03.setText(_translate(\"MainWindow\", \"Axe of rotation\"))\n        self.RB_Angle_X.setText(_translate(\"MainWindow\", \"X\"))\n        self.RB_Angle_X.setToolTip(_translate(\"MainWindow\", \"Rotation of the camera on the X axis\"))\n        self.RB_Angle_Y.setText(_translate(\"MainWindow\", \"Y\"))\n        self.RB_Angle_Y.setToolTip(_translate(\"MainWindow\", \"Rotation of the camera on the Y axis\"))\n        self.RB_Angle_Z.setText(_translate(\"MainWindow\", \"Z\"))\n        self.RB_Angle_Z.setToolTip(_translate(\"MainWindow\", \"Rotation of the camera on the Z axis\"))\n        self.RB_Direction.setText(_translate(\"MainWindow\", \"D\"))\n        self.RB_Direction.setToolTip(_translate(\"MainWindow\", \"Rotation of the camera on the Direction axis\" + \"\\n\"\n                                     \"to edge selected or point selected\" + \"\\n\"\n                                     \"If the point are selected the mouse coordinates are used\"))\n        self.PB_Accept_View.setText(_translate(\"MainWindow\", \"Accept the rotation\"))\n        self.PB_Accept_View.setToolTip(_translate(\"MainWindow\", \"Accept the view given\"))\n        ####\n        self.groupBox_003.setTitle(_translate(\"MainWindow\", \"Virtual\"))\n        self.PB_Detect_Camera.setText(_translate(\"MainWindow\", \"Detect camera orientation\"))\n        self.PB_Detect_Camera.setToolTip(_translate(\"MainWindow\", \"Detect the position of the camera\\n\"\n                                         \" The returned value is the value provided by the function getCameraOrientation()\"))\n        self.label_04.setText(_translate(\"MainWindow\", \"Align view :\"))\n        self.PB_To_Face.setText(_translate(\"MainWindow\", \"To Face.\"))\n        self.PB_To_Face.setToolTip(_translate(\"MainWindow\", \"Align the view to the selected face \\n\"\n                                   \"Click and repeat the click for NormalAt : \\n\"\n                                   \"(0,0,1) (0,0,-1) (0,1,0) (0,-1,0) (1,0,0) (-1,0,0)\"))\n        self.PB_To_Axis.setText(_translate(\"MainWindow\", \"To Axis.\"))\n        self.PB_To_Axis.setToolTip(_translate(\"MainWindow\", \"Align the view to Axis face selected \\n\"\n                                   \"Click and repeat the click for Surface Axis : \\n\"\n                                   \"(0,0,1) (0,0,-1) (0,1,0) (0,-1,0) (1,0,0) (-1,0,0)\"))\n        self.PB_Align_O_To_View.setText(_translate(\"MainWindow\", \"Align Object to View\"))\n        self.PB_Align_O_To_View.setToolTip(_translate(\"MainWindow\", \"Align the object selected to the actual view \\n\"\n                                           \"The changed values are : Rotation Axis((X, Y, Z), Angle) \\n\"\n                                           \"Same Euler angles : Yaw, Pitch, Roll \\n The Translation is not modify\"))\n        ####\n        self.groupBox_004.setTitle(_translate(\"MainWindow\", \"Plane\"))\n        self.PB_Create_Plane.setText(_translate(\"MainWindow\", \"Create plane of view.\"))\n        self.PB_Create_Plane.setToolTip(_translate(\"MainWindow\", \"A circular plane is created facing the screen to mouse click coordinates on an object \\n\"\n                                        \"The radius of the plane is equal to the maximum dimension of BoundBox  \\n\"\n                                        \"If no object is selected, the plane is created to 0, 0, 0 coordinates with a radius of 20 mm\"))\n        self.RB_01_Plane_Point.setText(_translate(\"MainWindow\", \"To Point\"))\n        self.RB_01_Plane_Point.setToolTip(_translate(\"MainWindow\", \"Crate plane to Point mouse click\"))\n        self.RB_02_Plane_Face.setText(_translate(\"MainWindow\", \"Center Face\"))\n        self.RB_02_Plane_Face.setToolTip(_translate(\"MainWindow\", \"Crate plane to Center face\"))\n        self.RB_03_Plane_CMass.setText(_translate(\"MainWindow\", \"Center Mass\"))\n        self.RB_03_Plane_CMass.setToolTip(_translate(\"MainWindow\", \"Crate plane to Center mass\"))\n        self.RB_04_Center_BBox.setText(_translate(\"MainWindow\", \"Center BBox\"))\n        self.RB_04_Center_BBox.setToolTip(_translate(\"MainWindow\", \"Crate plane to Center bounding Box\"))\n        ####\n        self.groupBox_005.setTitle(_translate(\"MainWindow\", \"Command\"))\n        self.PB_Reset.setText(_translate(\"MainWindow\", \"Reset\"))\n        self.PB_Reset.setToolTip(_translate(\"MainWindow\", \"Refresh alls\"))\n        self.PB_Photo.setText(_translate(\"MainWindow\", \"Photo\"))\n        self.PB_Photo.setToolTip(_translate(\"MainWindow\", \"Create serial photo for create animation\" + \"\\n\"\n                                 \"Give the angle rotation desired\" + \"\\n\"\n                                 \"Number image = 360 / Angle degrees rotation\" + \"\\n\" + \"\\n\"\n                                 \"Modify your window 3DView to the desirate dimension\" + \"\\n\"\n                                 \"Click the Accept the rotation for verify if the object rotation is good\"))\n        self.PB_Quit.setText(_translate(\"MainWindow\", \"Quit\"))\n        self.PB_Quit.setToolTip(_translate(\"MainWindow\", \"Quit FCCamera\"))\n        self.PB_Help.setText(_translate(\"MainWindow\", \"Help\"))\n        self.PB_Help.setToolTip(_translate(\"MainWindow\", \"Help on line  \" + __version__ + \"  \" + __date__ + \" rmu\"))\n        #####\n        ##### Photo\n        self.groupBox_00PH.setTitle(_translate(\"MainWindow\", \"Photo\"))\n        self.groupBox_00PH01.setTitle(_translate(\"MainWindow\", \"Definition\"))\n        self.groupBox_00PH01.setToolTip(_translate(\"MainWindow\", \"Definition image\"))\n        ####\n        self.CBox_01_Ecran.setCurrentIndex(0)\n        #CBox_01_Ecran = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"CBox_01_Ecran\")# \n        #print(CBox_01_Ecran)\n        #self.CBox_01_Ecran.setCurrentIndex(int(CBox_01_Ecran))\n        self.CBox_01_Ecran.setItemText(0 ,\"Actual\")\n        self.CBox_01_Ecran.setItemText(1 ,\"Icon 16 x 16\")\n        self.CBox_01_Ecran.setItemText(2 ,\"Icon 32 x 32\")\n        self.CBox_01_Ecran.setItemText(3 ,\"Icon 64 x 64\")\n        self.CBox_01_Ecran.setItemText(4 ,\"Icon 128 x 128\")\n        self.CBox_01_Ecran.setItemText(5 ,\"CGA 320 x 200\")\n        self.CBox_01_Ecran.setItemText(6 ,\"QVGA 320 x 240\")\n        self.CBox_01_Ecran.setItemText(7 ,\"VGA 640 x 480\")\n        self.CBox_01_Ecran.setItemText(8 ,\"SVGA 800 x 600\")\n        self.CBox_01_Ecran.setItemText(9 ,\"XGA 1024 x 768\")\n        self.CBox_01_Ecran.setItemText(10,\"XGA+ 1152 x 864\")\n        self.CBox_01_Ecran.setItemText(11,\"SXGA 1280 x 1024\")\n        self.CBox_01_Ecran.setItemText(12,\"SXGA+ 1400 x 1050\")\n        self.CBox_01_Ecran.setItemText(13,\"UXGA 1600 x 1200\")\n        self.CBox_01_Ecran.setItemText(14,\"QXGA 2048 x 1536\")\n        self.CBox_01_Ecran.setItemText(15,\"Free\")\n        ####\n        self.DS_01_X.setToolTip(_translate(\"MainWindow\", \"Value X\"))\n        self.label_05.setText(_translate(\"MainWindow\", \"X\"))\n        self.label_05.setToolTip(_translate(\"MainWindow\", \"Definition X image\"))\n        self.DS_02_Y.setToolTip(_translate(\"MainWindow\", \"Value Y\"))\n        self.label_06.setText(_translate(\"MainWindow\", \"Y\"))\n        self.label_06.setToolTip(_translate(\"MainWindow\", \"Definition Y image\"))\n        self.label_07.setText(_translate(\"MainWindow\", \"Number images : \" + str(numberPhoto)))\n        self.label_07.setToolTip(_translate(\"MainWindow\", \"Number image theoretic\"))\n        self.PB_Photo_Adjust.setText(_translate(\"MainWindow\", \"Adj.\"))\n        self.PB_Photo_Adjust.setToolTip(_translate(\"MainWindow\", \"Adjust the definition on int number\"))\n        self.PB_Photo_Adjust.setToolTip(_translate(\"MainWindow\", \"Adjust the number image to 360 degrees\"))\n        self.label_08.setText(_translate(\"MainWindow\", \"\"))\n        ####\n        self.CBox_02_FileFormat.setCurrentIndex(4)\n        #CBox_02_FileFormat = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"CBox_02_FileFormat\")# \n        #self.CBox_02_FileFormat.setCurrentIndex(int(CBox_02_FileFormat))\n        self.CBox_02_FileFormat.setItemText(0,\"BMP *.bmp\")\n        self.CBox_02_FileFormat.setItemText(1,\"ICO *.ico\")\n        self.CBox_02_FileFormat.setItemText(2,\"JPEG *.jpeg\")\n        self.CBox_02_FileFormat.setItemText(3,\"JPG *.jpg\")\n        self.CBox_02_FileFormat.setItemText(4,\"PNG *.png\")\n        self.CBox_02_FileFormat.setItemText(5,\"PPM *.ppm\")\n        self.CBox_02_FileFormat.setItemText(6,\"TIF *.tif\")\n        self.CBox_02_FileFormat.setItemText(7,\"TIFF *.tiff\")\n        self.CBox_02_FileFormat.setItemText(8,\"XBM *.xbm\")\n        self.CBox_02_FileFormat.setItemText(9,\"XPM *.xpm\")\n        #self.CBox_02_FileFormat.setItemText(10,\"GIF *.gif\")\n        ####\n        self.groupBox_00PH02.setTitle(\"BackGround image\")\n        self.groupBox_00PH02.setToolTip(_translate(\"MainWindow\", \"Choice of property backGround image\" + \"\\n\"\n                                      \"It is possible that the backGround does not appear in the desired color\" + \"\\n\"\n                                      \"in this case do a test in FreeCAD :\" + \"\\n\"\n                                      \"Menu > Tools > Save picture > Extended > Image properties\"))\n        self.RB_01_Actual.setText(_translate(\"MainWindow\", \"Current\"))\n        self.RB_01_Actual.setToolTip(_translate(\"MainWindow\", \"BackGround image in Actual color\"))\n        self.RB_02_White.setText(_translate(\"MainWindow\", \"White\"))\n        self.RB_02_White.setToolTip(_translate(\"MainWindow\", \"BackGround image in White\"))\n        self.RB_03_Black.setText(_translate(\"MainWindow\", \"Black\"))\n        self.RB_03_Black.setToolTip(_translate(\"MainWindow\", \"BackGround image in Black\"))\n        self.RB_04_Transparent.setText(_translate(\"MainWindow\", \"Transparent\"))\n        self.RB_04_Transparent.setToolTip(_translate(\"MainWindow\", \"BackGround image in Transparent\"))\n        ####\n        self.groupBox_00PH03.setTitle(_translate(\"MainWindow\", \"Command photo\"))\n        self.PB_Photo_Launch.setText(_translate(\"MainWindow\", \"Launch\"))\n        self.PB_Photo_Launch.setToolTip(_translate(\"MainWindow\", \"Launch the creation files\"))\n        self.PB_Photo_Reset.setText(_translate(\"MainWindow\", \"Reset\"))\n        self.PB_Photo_Reset.setToolTip(_translate(\"MainWindow\", \"Refresh alls\"))\n        self.PB_Photo_Quit.setText(_translate(\"MainWindow\", \"Return\"))\n        self.PB_Photo_Quit.setToolTip(_translate(\"MainWindow\", \"Quit the photo panel\"))\n\n    def on_RB_Angle_X_clicked(self):     #  X\n\n#        App.Console.PrintMessage(\"X\"+\"\\n\")\n        pic = QtGui.QPixmap()\n        pic.loadFromData(base64.b64decode(FCCamera_Axis_rotation_X_BMP))\n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(ui.scene)\n\n    def on_RB_Angle_Y_clicked(self):     # Y\n\n#        App.Console.PrintMessage(\"Y\"+\"\\n\")\n        pic = QtGui.QPixmap()\n        pic.loadFromData(base64.b64decode(FCCamera_Axis_rotation_Y_BMP))\n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(ui.scene)\n\n    def on_RB_Angle_Z_clicked(self):     # Z\n\n#        App.Console.PrintMessage(\"Z\"+\"\\n\")\n        pic = QtGui.QPixmap()\n        pic.loadFromData(base64.b64decode(FCCamera_Axis_rotation_Z_BMP))\n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(ui.scene)\n\n\n    def on_RB_Direction_clicked(self):   # D\n\n#        App.Console.PrintMessage(\"D\"+\"\\n\")\n        pic = QtGui.QPixmap()\n        pic.loadFromData(base64.b64decode(FCCamera_Axis_rotation_D_BMP))\n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(ui.scene)\n\n    def on_DS_Angle_valueChanged(self,value): # connection DS_Angle value donnee en degres\n        global valeur\n        global numberPhoto\n        global valueTest\n\n        valeur = 0.0\n        valeur = math.radians(value)         # valeur en degres convertie en radian\n        self.DS_Angle.setStyleSheet(\"color : Base\")\n        self.label_07.setStyleSheet(\"color : Base\")\n\n        try:                                 # section value for angle photo\n            numberPhoto = 360.0 / value\n            if abs(float(360.0 / value)) - int(abs(numberPhoto)) != 0.0:\n                self.PB_Photo_Adjust.setVisible(True)\n                self.label_08.setVisible(True)\n                numberPhoto = (abs(360.0 /value))\n                self.label_07.setStyleSheet(\"color : Red\")\n                self.PB_Photo_Adjust.setStyleSheet(\"background-color : #ff0000\")\n\n                valueTest = abs(int(value))\n                while ((value + valueTest) < (361 + value)) and ((value - valueTest) < (361 + value)):\n                    if abs(float(360.0 / valueTest)) - int(abs(float(360.0 / valueTest))) == 0.0:\n                        if self.DS_Angle.value() < 0:\n                            self.label_08.setText(\"Ideal angle : \" + str(-valueTest) + \" = \" + str(abs(int(360.0 / valueTest))) + \" images\")\n                        else:\n                            self.label_08.setText(\"Ideal angle : \" + str(valueTest) + \" = \" + str(abs(int(360.0 / valueTest))) + \" images\")\n                        self.label_08.setStyleSheet(\"color : #008700\")\n                        break\n                    if self.DS_Angle.value() < 0:\n                        valueTest -= 1\n                    else:\n                        valueTest += 1\n                    FreeCADGui.updateGui()\n                self.PB_Photo_Adjust.setToolTip(u\"Click to adjust the number images to 360 degrees\" + \"\\n\"\n                                                u\"detected \" + str(numberPhoto) + \" = \" + str(int(numberPhoto)) + \" images\" + \"\\n\"\n                                                u\"ideal choice angle : \" + str(valueTest) + \" degrees = \" + str(abs(int(360.0 / valueTest))) + \" images\" + \"\\n\" )\n\n            else:\n                numberPhoto = int(abs(360.0 / value))\n                self.label_07.setStyleSheet(\"color : Base\")\n                self.label_08.setVisible(False)\n                self.label_08.setText(\"\")\n                self.PB_Photo_Adjust.setVisible(False)\n                self.PB_Photo_Adjust.setStyleSheet(\"color : Base\")\n                self.PB_Photo_Adjust.setToolTip(u\"Adjust the number image to 360 degrees\")\n        except Exception:\n            numberPhoto = 0\n\n        self.PB_Photo.setToolTip(u\"Create serial photo for create animation\" + \"\\n\"\n                                 u\"Give the angle rotation desired\" + \"\\n\"\n                                 u\"Number image = 360 / \" + str(math.degrees(valeur)) + \" = \" + str(numberPhoto))\n        self.label_07.setText(\"Number image : \" + str(numberPhoto))\n\n    def on_CB_Multiply_10(self):\n\n        if self.CB_Multiply_10.isChecked():\n            self.DS_Angle.setSingleStep(10.0)\n        else:\n            self.DS_Angle.setSingleStep(1.0)\n\n    def on_PB_Detect_Camera_clicked(self):         # detection Orientation camera\n        global vertexeS\n\n        try:\n            plan = FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation()\n\n            cam=Gui.ActiveDocument.ActiveView.getCameraNode()\n            App.Console.PrintMessage(\"___Camera_Detection_____________________\"+\"\\n\")\n            App.Console.PrintMessage(\"position       : \" + str(cam.position.getValue().getValue()) + \"\\n\")\n\n            first = FreeCAD.Vector(cam.position.getValue().getValue())\n            distance_3DView_to_Axis = math.sqrt(first.x*first.x + first.y*first.y + first.z*first.z)\n\n            App.Console.PrintMessage(\"               : (position = Distance Center 3DView to Axis base = \" + str(distance_3DView_to_Axis) + \")\" + \"\\n\")\n            App.Console.PrintMessage(\"orientation    : \" + str(FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation().Axis)+\" , \"+str(FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation().Angle) + \"\\n\")\n            App.Console.PrintMessage(\"nearDistance   : \" + str(cam.nearDistance.getValue()) + \"\\n\")\n            App.Console.PrintMessage(\"farDistance    : \" + str(cam.farDistance.getValue()) + \"\\n\")\n            App.Console.PrintMessage(\"aspectRatio    : \" + str(cam.aspectRatio.getValue()) + \"\\n\")\n            App.Console.PrintMessage(\"focalDistance  : \" + str(cam.focalDistance.getValue()) + \"\\n\")\n            App.Console.PrintMessage(\"height         : \" + str(cam.height.getValue()) + \"\\n\" + \"\\n\")\n\n            App.Console.PrintMessage(\"___Camera_Orientation____________________\"+\"\\n\")\n            App.Console.PrintMessage(\"Radians XYZ Q  : \" + str(plan)+\"\\n\")\n\n            extractValue = datExtract(plan)\n            xP = float(extractValue[0])\n            yP = float(extractValue[1])\n            zP = float(extractValue[2])\n            qP = float(extractValue[3])\n\n            App.Console.PrintMessage(\"Degrees XYZ    : \" + str(degrees(xP)) + \" , \" +str(degrees(yP)) + \" , \" + str(degrees(zP)) +\"\\n\")\n            App.Console.PrintMessage(\"Degrees Q      : \" + str(degrees(qP)) +\"\\n\"+\"\\n\")\n\n            App.Console.PrintMessage(\"Radians Axis.xyz A : \" + str(plan.Axis) + \" , \" + str(plan.Angle) +\"\\n\")\n            App.Console.PrintMessage(\"Degrees Axis.x : \" + str(degrees(plan.Axis.x)) +\"\\n\")\n            App.Console.PrintMessage(\"Degrees Axis.y : \" + str(degrees(plan.Axis.y)) +\"\\n\")\n            App.Console.PrintMessage(\"Degrees Axis.z : \" + str(degrees(plan.Axis.z)) +\"\\n\")\n            App.Console.PrintMessage(\"Degrees Angle  : \" + str(degrees(plan.Angle)) +\"\\n\")\n\n            #http://forum.freecadweb.org/viewtopic.php?f=13&t=14213\n            App.Console.PrintMessage(\"Direction      : \" + str(cam.orientation.getValue().multVec(coin.SbVec3f(0,0,-1)).getValue()) + \"\\n\")\n            if (vertexeS[0] + vertexeS[1] + vertexeS[2]) != 0.0:\n                App.Console.PrintMessage(\"Direction edge : \" + str(vertexeS) + \"\\n\")\n            App.Console.PrintMessage(\"___FCCamera______________________________\"+\"\\n\\n\")\n            App.ActiveDocument.recompute()\n        except Exception:\n            App.Console.PrintError(\"Not Document open\" + \"\\n\")\n\n    def on_PB_Accept_View_clicked(self):        # Accept Rotation Camera to Axis\n        global valeur\n        global vertexeS\n        global ori_Horizont\n        global ori_Vertical\n        global bounBoxCenter\n\n        if (valeur != 0):\n\n            Xv = 0.0; Yv = 0.0; Zv = 0.0\n            try:\n                FreeCAD.ActiveDocument.openTransaction(\"Accept_View\") #str(valeur))    # memorise les actions (avec annuler restore)\n                #FreeCAD.ActiveDocument.commitTransaction()         # restore les actions  (avec annuler restore)\n                #FreeCAD.ActiveDocument.abortTransaction()          # abandonne les actions(avec annuler restore)\n\n                activeView = Gui.ActiveDocument.ActiveView\n                cam = Gui.ActiveDocument.ActiveView.getCameraNode()\n                rot = coin.SbRotation()\n\n                if self.RB_Direction.isChecked():\n                    cam.position.setValue(FreeCAD.Vector(bounBoxCenter))     # boundBox edge selected\n                else:\n#                    activeView.fitAll()                                     # boundBox all center\n                    cam.position.setValue(centerBoundBoxGlobal())            # boundBox all center calculated\n\n                #####\n                if self.RB_Angle_X.isChecked():\n                    Xv = 1.0\n                    App.Console.PrintMessage(\"(X \")\n                else:\n                    App.Console.PrintMessage(\"(- \")\n                if self.RB_Angle_Y.isChecked():\n                    Yv = 1.0\n                    App.Console.PrintMessage(\"Y \")\n                else:\n                    App.Console.PrintMessage(\"- \")\n                if self.RB_Angle_Z.isChecked():\n                    Zv = 1.0\n                    App.Console.PrintMessage(\"Z \")\n                else:\n                    App.Console.PrintMessage(\"- \")\n\n                if self.RB_Direction.isChecked():\n                    if (vertexeS[0] + vertexeS[1] + vertexeS[2]) != 0.0:\n                        Xv = vertexeS[0]\n                        Yv = vertexeS[1]\n                        Zv = vertexeS[2]\n                        App.Console.PrintMessage(\"D)\" + \"\\n\")\n                    else:\n                        Xv = bounBoxCenter[0]\n                        Yv = bounBoxCenter[1]\n                        Zv = bounBoxCenter[2]\n                        if (Xv + Yv + Zv) == 0.0:\n                            App.Console.PrintMessage(\"!)\" + \"\\n\")\n                            App.Console.PrintError(\"Not axis selected (edge) for rotation\" + \"\\n\"\n                                                   \"or Direction is nul\" + \"\\n\")\n                    Gui.updateGui()\n                else:\n                    App.Console.PrintMessage(\"-) \" + \"\\n\")\n                #####\n\n                rot.setValue(coin.SbVec3f(Xv,Yv,Zv),valeur)\n                nrot = cam.orientation.getValue() * rot\n                cam.orientation = nrot\n\n                App.Console.PrintMessage(str(valeur)+\" rad. , \"+str(math.degrees(valeur))+\" deg.\"+\"\\n\")\n                App.Console.PrintMessage(\"FCCamera_________________________________\"+\"\\n\\n\")\n            except Exception:\n                App.Console.PrintError(\"Not Document open\"+\"\\n\")\n        else:\n            App.Console.PrintError(\"Value angle egal zero select one Value\"+\"\\n\")\n            self.DS_Angle.setStyleSheet(\"color : #ff0000\")\n\n    #### photo ################################################\n    def SIGNAL_CBox_01_Ecran_Changed(self,text):\n        global dim_Horizont\n        global dim_Vertical\n        global ori_Horizont\n        global ori_Vertical\n\n        if   text == \"Actual\":\n            dim_Horizont = ori_Horizont\n            dim_Vertical = ori_Vertical\n        if   text == \"Icon 16 x 16\":\n            dim_Horizont = 16\n            dim_Vertical = 16\n        elif text == \"Icon 32 x 32\":\n            dim_Horizont = 32\n            dim_Vertical = 32\n        elif text == \"Icon 64 x 64\":\n            dim_Horizont = 64\n            dim_Vertical = 64\n        elif text == \"Icon 128 x 128\":\n            dim_Horizont = 128\n            dim_Vertical = 128\n        elif text == \"CGA 320 x 200\":\n            dim_Horizont = 320\n            dim_Vertical = 200\n        elif text == \"QVGA 320 x 240\":\n            dim_Horizont = 320\n            dim_Vertical = 240\n        elif text == \"VGA 640 x 480\":\n            dim_Horizont = 640\n            dim_Vertical = 480\n        elif text == \"SVGA 800 x 600\":\n            dim_Horizont = 800\n            dim_Vertical = 600\n        elif text == \"XGA 1024 x 768\":\n            dim_Horizont = 1024\n            dim_Vertical = 768\n        elif text == \"XGA+ 1152 x 864\":\n            dim_Horizont = 1152\n            dim_Vertical = 864\n        elif text == \"SXGA 1280 x 1024\":\n            dim_Horizont = 1280\n            dim_Vertical = 1024\n        elif text == \"SXGA+ 1400 x 1050\":\n            dim_Horizont = 1400\n            dim_Vertical = 1050\n        elif text == \"UXGA 1600 x 1200\":\n            dim_Horizont = 1600\n            dim_Vertical = 1200\n        elif text == \"QXGA 2048 x 1536\":\n            dim_Horizont = 2048\n            dim_Vertical = 1536\n        elif text == \"Free\":\n            None\n\n        self.DS_01_X.setValue(dim_Horizont)\n        self.DS_02_Y.setValue(dim_Vertical)\n\n        activeView = Gui.ActiveDocument.ActiveView\n        mainWindow = FreeCADGui.getMainWindow()\n        mdi = mainWindow.findChild(QtWidgets.QMdiArea)\n        mwActive = mdi.activeSubWindow()\n        try:                    # FC: 1.1.0Dev\n            mwActive.setGeometry(0, 0, dim_Horizont, dim_Vertical)\n            #mwActive.tileSubWindows()\n            mwActive.showFullScreen()\n            #print(\"mwActive\")\n        except Exception:       # FC: 1.0.0\n            mdi.setGeometry(0, 0, dim_Horizont, dim_Vertical)\n            #mdi.tileSubWindows()\n            mdi.showFullScreen()\n            #print(\"mdi\")\n\n    def SIGNAL_CBox_02_FileFormat_Changed(self,text):\n        global formatFichier\n\n        if   text == \"BMP *.bmp\":\n            formatFichier = \".bmp\"\n        elif text == \"ICO *.ico\":\n            formatFichier = \".ico\"\n        elif text == \"JPEG *.jpeg\":\n            formatFichier = \".jpeg\"\n        elif text == \"JPG *.jpg\":\n            formatFichier = \".jpg\"\n        elif text == \"PNG *.png\":\n            formatFichier = \".png\"\n        elif text == \"PPM *.ppm\":\n            formatFichier = \".ppm\"\n        elif text == \"TIF *.tif\":\n            formatFichier = \".tif\"\n        elif text == \"TIFF *.tiff\":\n            formatFichier = \".tiff\"\n        elif text == \"XBM *.xbm\":\n            formatFichier = \".xbm\"\n        elif text == \"XPM *.xpm\":\n            formatFichier = \".xpm\"\n#        elif text == \"GIF .gif\":\n#            formatFichier = \"*.gif\"\n\n    def on_DS_01_X_valueChanged(self, value):\n        global dim_Horizont\n        global dim_Vertical\n\n        dim_Horizont = value\n\n        self.DS_01_X.setValue(dim_Horizont)\n        #self.CBox_01_Ecran.setCurrentIndex(15)\n\n        activeView = Gui.ActiveDocument.ActiveView\n        mainWindow = FreeCADGui.getMainWindow()\n        mdi = mainWindow.findChild(QtWidgets.QMdiArea)\n        mwActive = mdi.activeSubWindow()\n        try:\n            mwActive.setGeometry(0, 0, dim_Horizont, dim_Vertical)\n            #mwActive.tileSubWindows()\n        except Exception:\n            mdi.setGeometry(0, 0, dim_Horizont, dim_Vertical)\n            #mdi.tileSubWindows()\n\n    def on_DS_02_Y_valueChanged(self, value):\n        global dim_Horizont\n        global dim_Vertical\n\n        dim_Vertical = value\n\n        self.DS_02_Y.setValue(dim_Vertical)\n        #self.CBox_01_Ecran.setCurrentIndex(15)\n\n        activeView = Gui.ActiveDocument.ActiveView\n        mainWindow = FreeCADGui.getMainWindow()\n        mdi = mainWindow.findChild(QtWidgets.QMdiArea)\n        mwActive = mdi.activeSubWindow()\n        try:\n            mwActive.setGeometry(0, 0, dim_Horizont, dim_Vertical)\n            #mwActive.tileSubWindows()\n        except Exception:\n            mdi.setGeometry(0, 0, dim_Horizont, dim_Vertical)\n            #mdi.tileSubWindows()\n\n    def on_PB_Photo_Launch_clicked(self):\n        global pathFile\n        global dim_Horizont\n        global dim_Vertical\n        global formatFichier\n        global valeur\n\n        if (valeur != 0):\n            SaveName, Filter = PySide.QtWidgets.QFileDialog.getSaveFileName(None, \"Save a files \", pathFile,  \"*\" + formatFichier) # PySide\n\n            if SaveName == \"\":\n                App.Console.PrintMessage(\"Process aborted\" + \"\\n\")\n            else:\n                pathFile = SaveName[:SaveName.rfind(\"/\") + 1]\n                App.Console.PrintMessage(\"Registration of \" + SaveName[:-4] + \"_Animate_...\" + \"\\n\")\n                SaveName = SaveName[:-4]\n                try:\n                    Xv = 0.0;Yv = 0.0;Zv = 0.0\n                    #####\n                    if self.RB_Angle_X.isChecked():\n                        Xv = 1.0\n                    elif self.RB_Angle_Y.isChecked():\n                        Yv = 1.0\n                    elif self.RB_Angle_Z.isChecked():\n                        Zv = 1.0\n                    elif self.RB_Direction.isChecked():\n                        if (vertexeS[0] + vertexeS[1] + vertexeS[2]) != 0.0:\n                            Xv = vertexeS[0]\n                            Yv = vertexeS[1]\n                            Zv = vertexeS[2]\n                        else:\n                            App.Console.PrintError(\"Not axis selected (edge) for rotation\" + \"\\n\"\n                                                \"or Direction is nul\" + \"\\n\")\n                        #####\n                    if (Xv + Yv + Zv) != 0.0:\n                        try:\n                            fileCount = 0\n                            activeView = Gui.ActiveDocument.ActiveView\n                            cam = Gui.ActiveDocument.ActiveView.getCameraNode()\n\n                            for i in range(int(360.0 / abs(math.degrees(valeur)))):\n                                Gui.updateGui()\n\n                                if self.RB_Direction.isChecked():\n                                    cam.position.setValue(FreeCAD.Vector(bounBoxCenter))     # boundBox edge selected\n                                else:\n                                    #activeView.fitAll()                                     # boundBox all center\n                                    cam.position.setValue(centerBoundBoxGlobal())            # boundBox all center calculated\n\n                                cam = Gui.ActiveDocument.ActiveView.getCameraNode()\n                                rot = coin.SbRotation()\n                                rot.setValue(coin.SbVec3f(Xv,Yv,Zv),valeur)\n                                nrot = cam.orientation.getValue() * rot\n                                cam.orientation = nrot\n\n                                fileCount += 1\n                                if self.RB_01_Actual.isChecked():\n                                    fileName = SaveName + \"_Animate_\" + '%03d_%03d' % (fileCount, math.degrees(valeur)*fileCount) + \"_Cu\" + formatFichier\n                                    activeView.saveImage(fileName, dim_Horizont, dim_Vertical, \"Current\")\n                                elif self.RB_02_White.isChecked():\n                                    fileName = SaveName + \"_Animate_\" + '%03d_%03d' % (fileCount, math.degrees(valeur)*fileCount) + \"_Wh\" + formatFichier\n                                    activeView.saveImage(fileName, dim_Horizont, dim_Vertical, \"White\")\n                                elif self.RB_03_Black.isChecked():\n                                    fileName = SaveName + \"_Animate_\" + '%03d_%03d' % (fileCount, math.degrees(valeur)*fileCount) + \"_Bl\" + formatFichier\n                                    activeView.saveImage(fileName, dim_Horizont, dim_Vertical, \"Black\")\n                                elif self.RB_04_Transparent.isChecked():\n                                    fileName = SaveName + \"_Animate_\" + '%03d_%03d' % (fileCount, math.degrees(valeur)*fileCount) + \"_Tr\" + formatFichier\n                                    activeView.saveImage(fileName, dim_Horizont, dim_Vertical, \"Transparent\")\n                                #App.Console.PrintMessage(fileName + \"\\n\")\n\n                        except Exception:\n                            App.Console.PrintError(\"Error Creation File\"+\"\\n\")\n                        App.Console.PrintMessage(\"End photos\"+\"\\n\")\n                except Exception:                                                     # if error detected to write\n                    App.Console.PrintError(\"Error write file \"+SaveName+\"\\n\")         # detect error ... display the text in red (PrintError)\n        else:\n            App.Console.PrintError(\"Give angle value for rotation\"+\"\\n\")\n            App.Console.PrintMessage(\"(Actual 3Dview = X \" + str(dim_Horizont) + \", Y \" + str(dim_Vertical) + \") \" + \"\\n\")\n            self.DS_Angle.setStyleSheet(\"color : #ff0000\")\n\n    def on_PB_Photo_Adjust_clicked(self):\n        global valueTest\n\n        if self.DS_Angle.value() < 0:\n            self.DS_Angle.setValue(-valueTest)\n        else:\n            self.DS_Angle.setValue(valueTest)\n\n        self.PB_Photo_Adjust.setVisible(False)\n        self.label_08.setVisible(False)\n        self.label_08.setText(\"\")\n#        self.label_08.setStyleSheet(\"color : Base\")\n\n    def on_PB_Photo_Quit_clicked(self):\n        global ori_Horizont\n        global ori_Vertical\n\n        self.PB_Photo.setText(\"Photo\")\n        self.groupBox_00PH.setVisible(False)\n        self.groupBox_003.setVisible(True)\n        self.groupBox_004.setVisible(True)\n        self.groupBox_005.setVisible(True)\n\n#        self.CBox_02_FileFormat.setCurrentIndex(4)\n#        self.CBox_01_Ecran.setCurrentIndex(0)\n\n        activeView = Gui.ActiveDocument.ActiveView\n        mainWindow = FreeCADGui.getMainWindow()\n        mdi = mainWindow.findChild(QtWidgets.QMdiArea)\n        mwActive = mdi.activeSubWindow()\n        try:\n            mwActive.setGeometry(0, 0, ori_Horizont, ori_Vertical)\n            #mwActive.tileSubWindows()\n        except Exception:\n            mdi.setGeometry(0, 0, ori_Horizont, ori_Vertical)\n            #mdi.tileSubWindows()\n        Gui.SendMsgToActiveView(\"ViewFit\")\n\n    def on_PB_Photo_Reset_clicked(self):  # Reset photo\n        global ui\n\n        ui.on_PB_Reset_clicked()\n\n    def on_PB_Photo_clicked(self):  # Create photo\n        global ui\n        global valeur\n        global ori_Horizont\n        global ori_Vertical\n        global dim_Horizont\n        global dim_Vertical\n        global numberPhoto\n\n        try:\n            self.groupBox_003.setVisible(False)\n            self.groupBox_004.setVisible(False)\n            self.groupBox_005.setVisible(False)\n            self.groupBox_00PH.setVisible(True)\n            self.PB_Photo.setText(\"Reset\")\n        except Exception:\n            App.Console.PrintError(\"Not Document open\" + \"\\n\")\n\n    #### photo #############################################################\n\n    def on_PB_Align_O_To_View_clicked(self):  #Align and Fix Object to View\n\n        FreeCAD.ActiveDocument.openTransaction(\"Align_O_To_View\")# memorise les actions (avec annuler restore)\n        sel = FreeCADGui.Selection.getSelection()  \n        if (len(sel)==0):\n            App.Console.PrintError(\"Select one object\"+\"\\n\")\n        else:\n            Nameelement = sel[0].Name\n            App.Console.PrintMessage(str(Nameelement)+\"\\n\")\n            pl = FreeCAD.Placement()\n            pl.Rotation = Gui.ActiveDocument.ActiveView.getCameraOrientation()\n            pl.Base = sel[0].Placement.Base\n            App.ActiveDocument.getObject(Nameelement).Placement=pl\n\n    def on_PB_Create_Plane_clicked(self):     # Create plane\n        global doc\n        global positionX                      # create plans coordinate mouse\n        global positionY\n        global positionZ\n\n        FreeCAD.ActiveDocument.openTransaction(\"FCC_FCPlane\")    # memorise les actions (avec annuler restore)\n        #FreeCAD.ActiveDocument.commitTransaction()         # restore les actions  (avec annuler restore)\n        #FreeCAD.ActiveDocument.abortTransaction()          # abandonne les actions(avec annuler restore)\n\n        rayon = 20                            # Radius of plane\n        sel = FreeCADGui.Selection.getSelection()  \n        selEx = FreeCADGui.Selection.getSelectionEx()\n        objs = [selobj.Object for selobj in selEx]\n        if len(objs) != 0.0:                    # radius plane = > BounBox length\n            s = objs[0].Shape\n            boundBox_  = s.BoundBox\n            boundBoxLX = boundBox_.XLength\n            boundBoxLY = boundBox_.YLength\n            boundBoxLZ = boundBox_.ZLength\n\n            rayon = boundBoxLX\n            if rayon < boundBoxLY:\n                rayon = boundBoxLY\n            elif rayon < boundBoxLZ:\n                rayon = boundBoxLZ\n\n            if self.RB_01_Plane_Point.isChecked():                     # Point mouse\n                None\n            elif self.RB_02_Plane_Face.isChecked():                    # Face, Wire BoundBox Center\n                positionX = selEx[0].SubObjects[0].BoundBox.Center.x\n                positionY = selEx[0].SubObjects[0].BoundBox.Center.y\n                positionZ = selEx[0].SubObjects[0].BoundBox.Center.z\n            elif self.RB_03_Plane_CMass.isChecked():                   # Center O fMass\n                positionX = sel[0].Shape.CenterOfMass.x\n                positionY = sel[0].Shape.CenterOfMass.y\n                positionZ = sel[0].Shape.CenterOfMass.z\n            elif self.RB_04_Center_BBox.isChecked():                   # BoundBox Center\n                positionX = sel[0].Shape.BoundBox.Center.x\n                positionY = sel[0].Shape.BoundBox.Center.y\n                positionZ = sel[0].Shape.BoundBox.Center.z\n\n        if len(sel) == 0:\n            boundBoxLX = rayon\n\n        try:\n            doc = FreeCAD.ActiveDocument\n            radiusP = rayon                       # Radius of plane      \n            FcPlane = doc.addObject(\"App::DocumentObjectGroup\",\"FcPlane\")\n\n            plan = Gui.ActiveDocument.ActiveView.getCameraOrientation()\n            App.Console.PrintMessage(\"\\n\"+\"Create plane radius : \" + str(radiusP) + \" mm)\"+\"\\n\")\n            App.Console.PrintMessage(\"Camera Orientation  : \" + str(plan)+\"\\n\")\n            App.Console.PrintMessage(\"Point position      : \" + str(positionX)+\" \"+str(positionY)+\" \"+str(positionZ)+\"\\n\")\n            App.Console.PrintMessage(\"____________________\"+\"\\n\")\n\n            extractValue = datExtract(plan)\n            xP = float(extractValue[0])\n            yP = float(extractValue[1])\n            zP = float(extractValue[2])\n            qP = float(extractValue[3])\n\n            pl = FreeCAD.Placement()\n            pl.Rotation.Q = (xP,yP,zP,qP)         # rotation of object\n            pl.Base = FreeCAD.Vector(positionX,positionY,positionZ) # here coordinates XYZ of plan\n\n            #create axis\n            points=[FreeCAD.Vector(0.0,0.0,0.0),FreeCAD.Vector(0.0,0.0,boundBoxLX * 3.0)]\n            centerX = Draft.makeWire(points,closed=False,face=False,support=None)\n            centerX.Placement = pl\n            centerX.Placement.Rotation = centerX.Placement.Rotation.multiply(App.Rotation(0,90,0))\n            centerX.Placement = centerX.Placement.multiply(App.Placement(App.Vector(0.0,0.0,-float(boundBoxLX * 3.0)/2.0), App.Rotation(App.Vector(0.0,0.0,0.0),0.0), App.Vector(0,0,0)))\n            centerX.ViewObject.LineColor = (1.0,1.0,1.0)\n            centerX.ViewObject.LineWidth = 1.0\n            centerX.ViewObject.DrawStyle = str(\"Dashdot\")\n            centerX.Label = str(\"Axis White PlaneX\")\n            FcPlane.addObject(centerX)\n\n            points=[FreeCAD.Vector(0.0,0.0,0.0),FreeCAD.Vector(0.0,0.0,boundBoxLX * 3.0)]\n            centerY = Draft.makeWire(points,closed=False,face=False,support=None)\n            centerY.Placement = pl\n            centerY.Placement.Rotation = centerY.Placement.Rotation.multiply(App.Rotation(0,90,90))\n            centerY.Placement = centerY.Placement.multiply(App.Placement(App.Vector(0.0,0.0,-float(boundBoxLX * 3.0)/2.0), App.Rotation(App.Vector(0.0,0.0,0.0),0.0), App.Vector(0,0,0)))\n            centerY.ViewObject.LineColor = (1.0,1.0,1.0)\n            centerY.ViewObject.LineWidth = 1.0\n            centerY.ViewObject.DrawStyle = str(\"Dashdot\")\n            centerY.Label = str(\"Axis White PlaneY\")\n            FcPlane.addObject(centerY)\n\n            cercle = Draft.makeCircle(radius=radiusP, placement=pl, face=True, support=None)\n            Rnameplane = App.ActiveDocument.ActiveObject.Name\n            App.ActiveDocument.ActiveObject.Label   = \"PlaneC\"\n            FreeCAD.ActiveDocument.getObject(Rnameplane).MakeFace = True\n            FreeCADGui.ActiveDocument.getObject(Rnameplane).LineColor = (1.0,0.0,0.0)\n            FreeCADGui.ActiveDocument.getObject(Rnameplane).ShapeColor = (0.0,0.66666669,1.0)\n            FreeCADGui.ActiveDocument.getObject(Rnameplane).Transparency = 80\n            FcPlane.addObject(cercle)  # contener character\n            FreeCAD.ActiveDocument.recompute()\n\n            positionX = 0.0\n            positionY = 0.0\n            positionZ = 0.0\n        except Exception:\n            App.Console.PrintError(\"Not Document open\" + \"\\n\")\n\n    def on_PB_To_Face_clicked(self):        # view to face selected Face\n        To_Face_Or_To_Axis(1)\n\n    def on_PB_To_Axis_clicked(self):        # view to face selected Axis\n        To_Face_Or_To_Axis(0)\n\n    def on_PB_Reset_clicked(self):          # Refresh\n        global valeur\n        global positionX\n        global positionY\n        global positionZ\n        global vueView\n        global path\n        global fileCount\n        global numberPhoto\n        global ori_Horizont\n        global ori_Vertical\n\n        try:\n            Gui.ActiveDocument.ActiveView.viewTop()\n            Gui.SendMsgToActiveView(\"ViewFit\")\n            valeur = 0.0\n            fileCount = 0\n            self.DS_Angle.setProperty(\"value\", 0.0)\n\n            positionX = 0.0\n            positionY = 0.0\n            positionZ = 0.0\n            vueView   = 0\n\n            self.CB_Multiply_10.setChecked(False)\n            self.DS_Angle.setSingleStep(1.0)\n            self.RB_Angle_X.setChecked(True)\n            pic = QtGui.QPixmap()\n            pic.loadFromData(base64.b64decode(FCCamera_Axis_rotation_X_BMP))\n            self.scene = QtWidgets.QGraphicsScene()\n            self.scene.addPixmap(QtGui.QPixmap(pic))\n            self.graphicsView.setScene(ui.scene)\n\n            activeView = Gui.ActiveDocument.ActiveView\n            mainWindow = FreeCADGui.getMainWindow()\n            mdi = mainWindow.findChild(QtWidgets.QMdiArea)\n            mwActive = mdi.activeSubWindow()\n            try:\n                mwActive.setGeometry(0, 0, ori_Horizont, ori_Vertical)\n                #mwActive.tileSubWindows()\n            except Exception:\n                mdi.setGeometry(0, 0, ori_Horizont, ori_Vertical)\n                #mdi.tileSubWindows()\n\n            self.CBox_01_Ecran.setCurrentIndex(0)\n            self.DS_01_X.setValue(ori_Horizont)\n            self.DS_02_Y.setValue(ori_Vertical)\n            centerBoundBoxGlobal()\n            self.RB_01_Plane_Point.setChecked(True)\n            self.RB_01_Actual.setChecked(True)\n            App.Console.PrintMessage(\"Refresh (3Dview = X \" + str(ori_Horizont) + \", Y \" + str(ori_Vertical) + \") \" + \"\\n\")\n            numberPhoto = 0\n            self.label_07.setText(\"Number image : \" + str(numberPhoto))\n        except Exception:\n            App.Console.PrintError(\"Not Document open\" + \"\\n\")\n\n    def on_PB_Quit_clicked(self): # quit\n        global s\n        global ori_Horizont\n        global ori_Vertical\n        global pathFile\n        global switchVesionMacroSearch\n\n        activeView = Gui.ActiveDocument.ActiveView\n        mainWindow = FreeCADGui.getMainWindow()\n        mdi = mainWindow.findChild(QtWidgets.QMdiArea)\n        mwActive = mdi.activeSubWindow()\n        try:\n            #mwActive.setGeometry(0, 0, ori_Horizont, ori_Vertical)\n            #mwActive.resize(ori_Horizont, ori_Vertical)\n            mwActive.showFullScreen()\n        except Exception:\n            #mdi.setGeometry(0, 0, ori_Horizont, ori_Vertical)\n            #mdi.resize(ori_Horizont, ori_Vertical)\n            mdi.showFullScreen()\n\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchVesionMacroSearch\", switchVesionMacroSearch)\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"setPathFile\", pathFile)# \n\n        #FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"CBox_01_Ecran\", self.CBox_01_Ecran.currentIndex())# \n        #FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"CBox_02_FileFormat\", self.CBox_02_FileFormat.currentIndex())# \n\n        Gui.SendMsgToActiveView(\"ViewFit\")\n        App.Console.PrintMessage(\"Fin FCCamera\" + \"\\n\")\n        FreeCADGui.Selection.removeObserver(s)    # desinstalle la fonction residente\n        self.window.close()\n\n    def on_PB_Help(self): # \n        webbrowser.open(\"http://www.freecadweb.org/wiki/index.php?title=Macro_FCCamera\")\n        App.Console.PrintMessage(\"http://www.freecadweb.org/wiki/index.php?title=Macro_FCCamera\" + \"\\n\")\n\n##################################################################################################\n#read parameter\npathFile = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetString(\"setPathFile\")\nif pathFile == \"\":\n    pathFile = path\n\n#        CBox_01_Ecran = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"CBox_01_Ecran\")# \n#        print(CBox_01_Ecran)\n#        CBox_02_FileFormat = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"CBox_02_FileFormat\")# \n#        print(CBox_02_FileFormat)\n##################################################################################################\n##Start#####\nFreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"Version\",__version__ + \" (\" + __date__ + \")\")# \n\n#Gui.ActiveDocument.ActiveView.setAxisCross(True) # GuiAxis true\n\ns=SelObserver()                                   # installe the function in resident mode SelObserver\nFreeCADGui.Selection.addObserver(s)               # installe the function in resident mode SelObserver\n\nMainWindow = QtWidgets.QMainWindow()\nui = Ui_MainWindow()\nui.setupUi(MainWindow)\nMainWindow.show()\n\n",
    "url": "https://gist.github.com/mario52a/4aa545c23b323cf68824",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/4aa545c23b323cf68824/raw/b31c64d26788b796750095eca4a6b92803537732/Macro%2520FCCamera.FCMacro",
    "wiki": "",
    "version": "0.15b",
    "license": "",
    "date": "2024/12/19",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\FCCamera_00.png",
    "icon_source": "https://wiki.freecad.org/images/2/25/FCCamera_00.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Mouse Cross",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro turns the arrow of the mouse in a precision cross.<br /><br />Macro version: 0.05<br />Last modified: 2020-08-06<br />FreeCAD version: 0.18 and more<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/f/ff/Macro_Mouse_Cross.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "This macro turns the arrow of the mouse in a precision cross.",
    "code": "# -*- coding: utf-8 -*-\n# mouse cursor to Cross or Arrow + Grig \n# ver 0.2 08/08/2014  PyQt4 and PySide\n# ver 0.4 07/06/2019 compatible Python 3.\n# ver 0.5 06/08/2020 PySide2 and add image in macro\n#\n__title__   = \"Macro_Mouse_Cross\"\n__author__  = \"Mario52\"\n__wiki__    = \"https://www.freecadweb.org/wiki/Macro_Mouse_Cross\"\n__url__     = \"https://www.freecadweb.org/\"\n__version__ = \"0.05\"\n__date__    = \"06/08/2020\"\n\nimport PySide2\nfrom PySide2 import QtWidgets, QtCore, QtGui\nfrom PySide2.QtGui import QColor, QPixmap, QImage, QPainter, QCursor\nfrom PySide2.QtCore import Qt,QUrl\nfrom PySide2.QtWidgets import QApplication\nfrom pivy import coin\n\nFCCursor24x24_Icon = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #3A0202\",\n\"+\tc #0E1245\",\n\"@\tc #640A0A\",\n\"#\tc #B10A0B\",\n\"$\tc #2A3E71\",\n\"%\tc #DF1F20\",\n\"&\tc #49699A\",\n\"*\tc #638EC0\",\n\"..............          \",\n\".%%%%%%%%%%%%.          \",\n\".%%%%%%%%%%%%.          \",\n\".%%%%%%%%%%%%.          \",\n\".%%%%%%%%%%%%.          \",\n\".%%%%.........          \",\n\".%%%%.       ++++       \",\n\".%%%%.       +**+       \",\n\".%%%%.   +++ +**+ +++   \",\n\".%%%%.....**+****+**+   \",\n\".%%%%%%%%.**********+   \",\n\".%%%%%%%%.+********+    \",\n\".%%%%%%%%.***++++***+   \",\n\".%%%%%....**++  ++**+++ \",\n\".%%%%..+****+    +****+ \",\n\".%%%%. +****+    +****+ \",\n\".%%%%. +++**++  ++**+++ \",\n\".%%%%.   +***++++***+   \",\n\".%%%%.    +********+    \",\n\".%%%%.   +**********+   \",\n\".%%%%.   +**+****+**+   \",\n\".%%%%.   +++ +**+ +++   \",\n\".%%%%.       +**+       \",\n\"......       ++++       \"\n]\n\nglobal xx ;xx = -1\n\n#################### create document if not exist #######################\ndoc = FreeCAD.ActiveDocument                                         ####\nif doc == None:                                                      ####\n    doc = FreeCAD.newDocument()                                      ####\n#########################################################################\nclass ViewObserver:\n   def logPosition(self, info):\n       global xx\n       self.pos = info[\"Key\"]\n       if (self.pos.upper() == \"Q\"):\n           QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))\n           v.removeEventCallback(\"SoKeyboardEvent\",c)\n           FreeCAD.Console.PrintMessage(\"End Macro_Mouse_Cross\"+\"\\n\")\n       if (self.pos.upper() == \"C\"):\n           # change the cursor cross ( + )\n           QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))\n       elif (self.pos.upper() == \"A\"):\n           # change the cursor in Arrow\n           QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))\n       elif (self.pos.upper() == \"X\") and (info[\"State\"] == \"DOWN\"):\n           # change the cursor and visualise all model \n           xx += 1\n           if xx == 0:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : ArrowCursor\"+\"\\n\")\n           if xx == 1:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.UpArrowCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : UpArrowCursor\"+\"\\n\")\n           if xx == 2:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : CrossCursor\"+\"\\n\")\n           if xx == 3:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : WaitCursor\"+\"\\n\")\n           if xx == 4:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : IBeamCursor\"+\"\\n\")\n           if xx == 5:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.SizeVerCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : SizeVerCursor\"+\"\\n\")\n           if xx == 6:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.SizeHorCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : SizeHorCursor\"+\"\\n\")\n           if xx == 7:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.SizeBDiagCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : SizeBDiagCursor\"+\"\\n\")\n           if xx == 8:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.SizeFDiagCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : SizeFDiagCursor\"+\"\\n\")\n           if xx == 9:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.SizeAllCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : SizeAllCursor\"+\"\\n\")\n           if xx == 10:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.BlankCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : BlankCursor\"+\"\\n\")\n           if xx == 11:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.SplitVCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : SplitVCursor\"+\"\\n\")\n           if xx == 12:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.SplitHCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : SplitHCursor\"+\"\\n\")\n           if xx == 13:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : PointingHandCursor\"+\"\\n\")\n           if xx == 14:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.ForbiddenCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : ForbiddenCursor\"+\"\\n\")\n           if xx == 15:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : OpenHandCursor\"+\"\\n\")\n           if xx == 16:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.ClosedHandCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : ClosedHandCursor\"+\"\\n\")\n           if xx == 17:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WhatsThisCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : WhatsThisCursor\"+\"\\n\")\n           if xx == 18:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.BusyCursor))\n               FreeCAD.Console.PrintMessage(str(xx)+\" : BusyCursor\"+\"\\n\")\n           if xx == 19:\n               QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QPixmap(FCCursor24x24_Icon))) # image include in macro\n               #QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QPixmap(\"C:/completePath/image.png\"))) # image to disk\n               FreeCAD.Console.PrintMessage(str(xx)+\" : FCCursor24x24_Icon\"+\"\\n\")\n               xx = -1\n       elif (self.pos.upper() == \"G\"):\n           # \"wmayer\" http://forum.freecadweb.org/viewtopic.php?f=3&t=1065&hilit=cross#p8818\n           # Create Grida\n           grid=coin.SoType.fromName(\"SoDrawingGrid\").createInstance()\n           Gui.ActiveDocument.ActiveView.getSceneGraph().addChild(grid)\n\nxx = -1 \n\ntry:\n    v=Gui.activeDocument().activeView()\n    o = ViewObserver()\n    c = v.addEventCallback(\"SoKeyboardEvent\",o.logPosition)\n    App.Console.PrintMessage(\"Type Key C to Cross\"+\"\\n\")\n    App.Console.PrintMessage(\"Type Key A to Arrow\"+\"\\n\")\n    App.Console.PrintMessage(\"Type Key X to Visualise all cursor\"+\"\\n\")\n    App.Console.PrintMessage(\"Type Key G to Grid (not editable)\"+\"\\n\")\n    App.Console.PrintMessage(\"Type Key Q to Quit\"+\"\\n\")\nexcept Exception:\n    FreeCAD.Console.PrintError(\"\\n\"+\"Not document open\"+\"\\n\")",
    "url": "https://wiki.freecad.org/Macro_Mouse_Cross",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_Mouse_Cross",
    "version": "0.05",
    "license": "",
    "date": "06/08/2020",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Mouse_Cross.png",
    "icon_source": "https://wiki.freecad.org/images/f/ff/Macro_Mouse_Cross.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Rotate View",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro rotates the current view by 90\u00b0 to the left. Only works if you are in <a href=\"/Std_ViewTop\" title=\"Std ViewTop\">Top view</a>.<br /><br />Macro version: 01.00<br />Last modified: 2010-11-17<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/a/a0/Macro_Rotate_View_view_90_Degrees.png\">ToolBar Icon</a><br />Author: Yorik<br /> ",
    "comment": "This macro rotates the current view by 90\u00b0 to the left. Only works if you are in Top view.",
    "code": "import math\nfrom pivy import coin\ncam = Gui.ActiveDocument.ActiveView.getCameraNode()\nrot = coin.SbRotation()\nrot.setValue(coin.SbVec3f(0,0,1),math.pi/2)\nnrot = cam.orientation.getValue() * rot\ncam.orientation = nrot",
    "url": "https://wiki.freecad.org/Macro_Rotate_View",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2010-11-17",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Yorik",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Rotate_View_view_90_Degrees.png",
    "icon_source": "https://wiki.freecad.org/images/a/a0/Macro_Rotate_View_view_90_Degrees.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Rotate View Free",
    "on_wiki": true,
    "on_git": false,
    "desc": "This def pasted in the Python console FreeCAD (or your macro) allows you to rotate the view in 3-axis and the angle (in degrees) give interesting to create a plan to a desired position<br /><br />Macro version: 01.00<br />Last modified: 2010-11-17<br />FreeCAD version: All<br />Author: Yorik<br /> ",
    "comment": "This def pasted in the Python console FreeCAD (or your macro) allows you to rotate the view in 3-axis and the angle (in degrees) give interesting to create a plan to a desired position",
    "code": "#Paste in the Python console and tip ex:\n#RotateView(0,1,0,45)\ndef RotateView(axisX=1.0,axisY=0.0,axisZ=0.0,angle=45.0):\n    import math\n    from pivy import coin\n    try:\n        cam = Gui.ActiveDocument.ActiveView.getCameraNode()\n        rot = coin.SbRotation()\n        rot.setValue(coin.SbVec3f(axisX,axisY,axisZ),math.radians(angle))\n        nrot = cam.orientation.getValue() * rot\n        cam.orientation = nrot\n        print( axisX,\" \",axisY,\" \",axisZ,\" \",angle)\n    except Exception:\n        print( \"Not ActiveView \")",
    "url": "https://wiki.freecad.org/Macro_Rotate_View_Free",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2010-11-17",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Yorik",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Rotate ViewAxonometric",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro rotates the current view in ViewAxonometric.<br /><br />Macro version: 01.00<br />Last modified: 2010-11-17<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/2/2e/Macro_Rotate_View_with_Y_pointing_upwards_.png\">ToolBar Icon</a><br />Author: Yorik<br /> ",
    "comment": "This macro rotates the current view in ViewAxonometric.",
    "code": "import math\nimport pivy\nfrom pivy import coin\n\nGui.activeDocument().activeView().viewAxonometric()\nGui.SendMsgToActiveView(\"ViewFit\")\n\ncam = Gui.ActiveDocument.ActiveView.getCameraNode()\nrot = coin.SbRotation()\n\nrot.setValue(coin.SbVec3f(1,0,0),-math.pi/2) # Y pointing upwards (mode 1)\n#rot.setValue(coin.SbVec3f(0,0,1),math.pi/2) # Z pointing upwards (mode 2 uncomment for use)\nnrot = cam.orientation.getValue() * rot\ncam.orientation = nrot\nGui.SendMsgToActiveView(\"ViewFit\")",
    "url": "https://wiki.freecad.org/Macro_Rotate_ViewAxonometric",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2010-11-17",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Yorik",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Rotate_View_with_Y_pointing_upwards_.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/2/2e/Macro_Rotate_View_with_Y_pointing_upwards_.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Screen Wiki",
    "on_wiki": true,
    "on_git": false,
    "desc": "Special macro for the Wiki user. This macro allows to save the 3D view in the desired format. The 3D view or the full 3D window of FreeCAD takes the desired dimensions. A rotation of the selected object or of the 3D view is possible to give a rotation angle the number of images is calculated automatically it is possible to give a departure angle and an arrival angle. You must use another Gimp example program to assemble the images and create the animated file.<br /><br />Macro version: 00.06c<br />Last modified: 2024/10/10<br />FreeCAD version: 0.19 and more<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/f/f5/Macro_Screen_Wiki.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Special macro for the Wiki user. This macro allows to save the 3D view in the desired format. The 3D view or the full 3D window of FreeCAD takes the desired dimensions. A rotation of the selected object or of the 3D view is possible to give a rotation angle the number of images is calculated automatically it is possible to give a departure angle and an arrival angle. You must use another Gimp example program to assemble the images and create the animated file.",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2019 2020 2021 2022 2023 2024 <mario52>                 *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n## http://forum.freecadweb.org/viewtopic.php?f=22&t=9295     # piffpoof code\n## http://forum.freecadweb.org/viewtopic.php?f=22&t=10488    # microelly2 code\n## http://forum.freecadweb.org/viewtopic.php?f=22&t=19620    # microelly2 code\n## https://forum.freecadweb.org/viewtopic.php?f=22&t=10157   # wmayer code\n##\n#Macro_Screen_Wiki 10/03/2019, 2020/03/21, 2020/05/04, 2020/10/29, 2021/01/13, 2021/05/21, 26/06/2023, 10/10/2024\n#\n#OS: Windows 10 build 19045                                  #OS: Linux Mint 20.1 (X-Cinnamon/cinnamon)\n#Word size of FreeCAD: 64-bit                                #Word size of FreeCAD: 64-bit\n#Version: 0.21.0.33263 (Git)                                 #Version: 0.20.24847 (Git) AppImage\n#Build type: Release                                         #Build type: Release\n#Branch: master                                              #Branch: master\n#Hash: 864f99bf984c237ef38d9451fd6f3a5ec34e6eb4              #Hash: 20e756306d9aa624fcbf465f0345d721673ce720\n#Python 3.10.11, Qt 5.15.8, Coin 4.0.0, Vtk 9.1.0, OCC 7.6.3 #Python version: 3.9.2\n                                                             #Qt version: 5.12.9\n                                                             #Coin version: 4.0.0\n                                                             #OCC version: 7.5.1\n#Locale: French/Mars (fr_MA)                                 #Locale: French/Mars (fr_MA)\n#\n\n__title__   = \"Screen_Wiki\"\n__author__  = \"Mario52\"\n__url__     = \"https://forum.freecadweb.org/index.php\"\n__Wiki__    = \"https://wiki.freecadweb.org/index.php?title=Macro_Screen_Wiki\" #Macro_Screen_Wiki\n__Forum__   = \"https://forum.freecad.org/viewtopic.php?t=50457\"               #Screen_Wiki macro\n__Gist__    = \"https://gist.github.com/mario52a/61571ce0bd41af0471995df7c3ea855f\"\n__version__ = \"00.06c\"\n__date__    = \"2024/10/10\"    #YYYY/MM/DD\n\nimport PySide2\nfrom PySide2 import (QtWidgets, QtCore, QtGui)\nfrom PySide2.QtWidgets import (QWidget, QApplication, QSlider, QGraphicsView, QGraphicsScene, QVBoxLayout, QStyle, QDockWidget, QToolBar, QDialog)\n\nfrom PySide2.QtGui import (QPainter, QColor, QIcon)\nfrom PySide2.QtCore import *\nfrom PySide2.QtGui import *\n\nfrom PySide2.QtSvg import *\nimport PySide2.QtXml\n\nfrom PySide2 import QtOpenGL\nfrom PySide2.QtOpenGL import *\n\nimport pivy\nfrom pivy import coin\n\nimport time, math\nimport FreeCADGui, FreeCAD\nimport os\nimport os.path\n\nimport Draft\n\n##############################################\nglobal path\n#path  = FreeCAD.ConfigGet(\"AppHomePath\")\n#path  = FreeCAD.ConfigGet(\"UserAppData\")\n#path  = \"your path\"\nparam = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")# macro path\npath = param.GetString(\"MacroPath\",\"\") + \"/\"                        # macro path\npath = path.replace(\"\\\\\",\"/\")\n#App.Console.PrintMessage(\"Path for the icons : \" + path + \"\\n\")\n##############################################\n\n#####################################################################################################\n#global testing                ; testing        = 3    # if testing == 1 MainWindow separate\n#                                                      # if testing == 2 RightDock\n#                                                      # else       == other LeftDock\n#####################################################################################################\n\nGui = FreeCADGui\nApp = FreeCAD\n\nglobal ui         ; ui         = \"\"\nglobal so         ; so         = \"\"\nglobal sel        ; sel        = \"\"\n\nglobal pathFile   ; pathFile   = \"\"\nglobal mainWindowCoinSupX   ; mainWindowCoinSupX   = 0   # depart coin gauche X\nglobal mainWindowCoinSupY   ; mainWindowCoinSupY   = 0   # depart coin gauche Y\nglobal originalState        ; originalState        = \"\"  # etat original en entree\nglobal switchMainWindow     ; switchMainWindow     = 0   # switch wainWindowFC \nglobal ecranCompletX        ; ecranCompletX        = 0   # ecran Complet X\nglobal ecranCompletY        ; ecranCompletY        = 0   # ecran Complet Y\nglobal parameterBackground  ; parameterBackground  = \"\"  # pour couleur de fond\nglobal pos_X_Tile_Window    ; pos_X_Tile_Window    = 0   # Position fenetre Tile\nglobal pos_Y_Tile_Window    ; pos_Y_Tile_Window    = 0   # Position fenetre Tile\n\nglobal counterName          ; counterName          = 0   # compteur pour Follow\nglobal switchFollow         ; switchFollow         = 0   # switch Follow/New\nglobal SaveName             ; SaveName             = \"\" \nglobal SaveNameMemo         ; SaveNameMemo         = \"\"\nglobal neutralImage         ; neutralImage         = 0   # switch nom neutre\nglobal switchToolBarActived ; switchToolBarActived = 0   # switch toolBar actived\nglobal switchRunning        ; switchRunning        = 0   # switch macro running\nglobal switchTitleBoxToolBar; switchTitleBoxToolBar= 0   # switch Title Box of ToolBar\nglobal switchMini           ; switchMini           = 0   # switch Mini toolBar\n\n#### section Rotation\nglobal dim_Horizont         ; dim_Horizont         = 0\nglobal dim_Vertical         ; dim_Vertical         = 0\nglobal formatFichier        ; formatFichier        = 0\nglobal axis                 ; axis                 = \"X\"\nglobal ctPoint              ; ctPoint              = \"\"\nglobal itemctPoint          ; itemctPoint          = \"\"\nglobal switch_Create_Point  ; switch_Create_Point  = True\nglobal switchValue          ; switchValue          = False\n\nglobal valeurAngle          ; valeurAngle          = 0.0\nglobal delayTime            ; delayTime            = 0.0\nglobal beginRotation        ; beginRotation        = 0.0\nglobal endRotation          ; endRotation          = 360.0\nglobal angleRotation        ; angleRotation        = 0.0\nglobal numberPhoto          ; numberPhoto          = 0.0    # float convert in int() after calcul\nglobal switchTestRotation   ; switchTestRotation   = False\n\nglobal degreesNumberDecimal #; degreesNumberDecimal = 4\ndegreesNumberDecimal = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"degreesNumberDecimal\", 4)    # degreesNumberDecimal\n\n###Config begin##############################################\n\nglobal pos_X_Window; pos_X_Window = 0    # Position begin X window\nglobal pos_Y_Window; pos_Y_Window = 0    # Position begin Y window\n\n###Config end##############################################\n\nminiMaxiIcon = [\n\"24 24 7 1\",\n\" \tc None\",\n\".\tc #01040C\",\n\"+\tc #000A0B\",\n\"@\tc #CC0000\",\n\"#\tc #71A0CF\",\n\"$\tc #18CFD1\",\n\"%\tc #BABDB6\",\n\"                        \",\n\" @@@@@@@@@@@@@@@@@@     \",\n\" @++++++++++++++++@     \",\n\" @+##############+@%    \",\n\"%%+++#++#+#######+@%    \",\n\"%%+##############+@%    \",\n\" @++++++#########+@%    \",\n\" @+##############+@%    \",\n\" @++#++++#++#####+@%    \",\n\" @+##############+@%    \",\n\" @++++++#########+@%    \",\n\" @+##############+@%    \",\n\" @+++++##########+@%    \",\n\" @+###########%##%%% %  \",\n\" @++++#+#####@%@@%%@@%@ \",\n\" @+##########@........@ \",\n\"%%+++#++++###@.$$$$$$.@%\",\n\"%%+##########@...$.$$.@%\",\n\" @+##########@.$$$$$$.@%\",\n\" @+++++++++++@..$.$$$.@%\",\n\" @@@@@@@@@@@@@.$$$$$$.@%\",\n\"  %%%%%%%%%%%@........@%\",\n\"             @@@@@@@@@@%\",\n\"               %%%%%%%%%\"]\n\nminiToolBarIcon = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #8D0401\",\n\"+\tc #4F514F\",\n\"@\tc #355799\",\n\"#\tc #365F8E\",\n\"$\tc #929491\",\n\"%\tc #A4B0BE\",\n\"&\tc #D5D7D4\",\n\"*\tc #F6F4F2\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"   $$$$$$$$$$$$$$$$$$$$ \",\n\"   $%%%%%%%%%%%%%%%%%*$ \",\n\" ...................... \",\n\" .@***@****@***@***@**. \",\n\" .@***@****@***@***@**. \",\n\" ...................... \",\n\"   &############@@@@%&$ \",\n\"   &############@@@@%&$ \",\n\"   &############@@@@%&$ \",\n\"   &#########@@@@@@@%&$ \",\n\"   &@@@@@@@@@@@@@@@@%&$ \",\n\"   &@@@@@@@@@@@@@@@@%&$ \",\n\"   &@@@@@@@@@@@@@@@@%&$ \",\n\"   &%%%%%%%%%%%%%%%%%&$ \",\n\"   &&&&&&&&&&&&&&&&&&&$ \",\n\"   ++++++++++++++&+&+&$ \",\n\"         ++++++++       \",\n\"        +$$%%$%$$+      \",\n\"        +$$$$$$$$+      \",\n\"         ++++++++       \",\n\"                        \"]\n\nnewImageIcon = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #154A89\",\n\"+\tc #235C19\",\n\"@\tc #4B9414\",\n\"#\tc #61B600\",\n\"$\tc #C3A000\",\n\"%\tc #6CC118\",\n\"&\tc #82DB32\",\n\"*\tc #FDFFFC\",\n\"                        \",\n\" ...................... \",\n\" . $   $              . \",\n\" .$$$ $ $             . \",\n\" .$ $$   $            . \",\n\" .   $ $              . \",\n\" .$$$ $               . \",\n\" .  $  $  @@ @@ @@    . \",\n\" . $ $    @&%&&%&@    . \",\n\" .       @&&%&&%&&@   . \",\n\" .       @&&&&&&&&@   . \",\n\" .       @&&&&&&&&@   . \",\n\" .        #&&&&&&%    . \",\n\" .     +  @#&&&&#@ ++ . \",\n\" .     @&   +@&+   @@ . \",\n\" .     @%&   @&   &&@ . \",\n\" .     @%%&  @&  &%&@ . \",\n\" .     @%%%& @& &%%&@ . \",\n\" .     @&%%& @&&%%&@@ . \",\n\" .      @&&& @@&&&@@  . \",\n\" .       @@@ @@@@@    . \",\n\" .                    . \",\n\" ...................... \",\n\"                        \"]\n\n#### Detect version macro ###########################################\nglobal switchVesionMacroSearch#; switchVesionMacroSearch = False\ntry:\n    def vesionSearch():\n        import requests\n        contentPage = requests.get(\"https://wiki.freecadweb.org/Macro_\" + __title__).text\n        for i in contentPage.split(\"\\n\"):            # list page to line\n            if \"ctEven macro-version\" in i:\n                versionDetect = (i.split(\">\")[1])\n            if \"ctEven macro-date\" in i:\n                dateDetect = (i.split(\">\")[1])\n            try:\n                if (len(versionDetect) != 0) and (len(dateDetect) != 0):\n                    break\n            except Exception:\n                None\n        try:\n            if (versionDetect == __version__) and (dateDetect == __date__):\n                None\n            else:\n                msg = (\"New version availlable : \" + \"\\n\" + \n                      str(versionDetect) + \":\" + str(dateDetect) + \"\\n\" + \n                      \"You can install with AddonManager\")\n                FreeCAD.Console.PrintMessage(\"your actual version    : \" + str(__version__) + \" : \" + str(__date__) + \"\\n\")\n                FreeCAD.Console.PrintMessage(\"new version availlable : \" + str(versionDetect) + \" : \" + str(dateDetect) + \"\\n\")\n                diag = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Information, 'New Version', msg)\n                diag.setWindowModality(QtCore.Qt.ApplicationModal)\n                diag.exec_()\n        except Exception:\n            None\n        return versionDetect, dateDetect\n    \n    switchVesionMacroSearch = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switchVesionMacroSearch\")\n    if switchVesionMacroSearch == 0:\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchVesionMacroSearch\", switchVesionMacroSearch)\n    if switchVesionMacroSearch == True:\n        vesionSearch()\nexcept Exception:\n    FreeCAD.Console.PrintMessage(\"Failed to establish a connection or...\" + \"\\n\")\n#### Detect version macro ###########################################\n\n#def errorDialog(msg):\n#    diag = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Critical,u\"Error FreeCAD Version\",msg )\n#    diag.setWindowFlags(PySide2.QtCore.Qt.WindowStaysOnTopHint) # PySide #cette fonction met la fenetre en avant\n#    diag.setStyleSheet(\"QLabel {color : #ffffff; background-color : #FF3300;  font: bold}\")\n#    diag.exec_()\n#    diag.setStyleSheet(\"QLabel {Base}\")\n#if int(FreeCAD.Version()[1]) < 19:      # Version de FreeCAD\n#    errorDialog(\"\\n\" + \"This macro work only with FreeCAD 0.19 +\" + \"\\n\"\n#                \"The image saved with other version give Black image\" + \"\\n\")\n\n####\n\nglobal switchQFileDialogMint\nswitchQFileDialogMint = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switchQFileDialogMint\")\nif switchQFileDialogMint == 0:\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchQFileDialogMint\", switchQFileDialogMint)\ntry:\n    if os.uname()[1] == \"mint\":\n        switchQFileDialogMint = 1\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchQFileDialogMint\", switchQFileDialogMint)\nexcept Exception:\n    None\n\nglobal switchAppConsolePrintMessage\nswitchAppConsolePrintMessage = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switchAppConsolePrintMessage\")\nif switchAppConsolePrintMessage == 0:\n    FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchAppConsolePrintMessage\", switchAppConsolePrintMessage)\n\ndef AppConsolePrintMessage(text):\n    global switchAppConsolePrintMessage\n\n    if switchAppConsolePrintMessage == True:\n        App.Console.PrintMessage(text)\n####\nglobal switchAppConsolePrintError\nswitchAppConsolePrintError = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switchAppConsolePrintError\")\nif switchAppConsolePrintError == 0:\n    FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchAppConsolePrintError\", switchAppConsolePrintError)\n\ndef AppConsolePrintError(text):\n    global switchAppConsolePrintError\n\n    if switchAppConsolePrintError == True:\n        App.Console.PrintError(text)\n####\n\nclass Ui_MainWindow(object):\n\n    def __init__(self, MainWindow):\n        global path\n        global pathFile\n        self.window = MainWindow\n        self.PointSize     = 8    #heigth text\n        ####\n        self.Color  = \"\"\n\n        self.Length = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"setLengthImage\")\n        if self.Length == 0:\n            self.Length = 640\n        self.Heigth = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"setHeigthImage\")\n        if self.Heigth == 0:\n            self.Heigth = 480\n\n        self.path = path\n\n    def setupUi(self, MainWindow):\n        self.window = MainWindow\n        global sel\n        global delayTime\n        global beginRotation\n        global endRotation\n        global angleRotation\n        global ui\n\n        #MainWindow.setObjectName(\"MainWindow\")\n#        MainWindow.setMinimumSize(QtCore.QSize(295, 600))\n        MainWindow.resize(295, 600)\n\n#        MainWindow.setMinimumSize(QtCore.QSize(295, 680))\n#        MainWindow.resize(295, 680)\n##        MainWindow.setGeometry(0, 0, 295, 680)    # demarrage sans rotation x0 y0\n##        MainWindow.resize(590, 680)               # demarrage avec Rotation\n##        MainWindow.move(1150, 100)                # position window dans l ecran\n\n        self.centralwidget = QtWidgets.QWidget(MainWindow)\n        self.groupBox_img_01_definition = QtWidgets.QGroupBox()\n\n        self.RD_01_400x200 = QtWidgets.QRadioButton()\n        self.RD_01_400x200.clicked.connect(self.on_radioButton_Config)\n\n        self.RD_02_600x400 = QtWidgets.QRadioButton()\n#        self.RD_02_600x400.setEnabled(True)\n#        self.RD_02_600x400.setChecked(True)\n        self.RD_02_600x400.clicked.connect(self.on_radioButton_Config)\n\n        self.RD_03_1024x768 = QtWidgets.QRadioButton()\n        self.RD_03_1024x768.clicked.connect(self.on_radioButton_Config)\n\n        self.RD_04_320x240 = QtWidgets.QRadioButton()\n        self.RD_04_320x240.clicked.connect(self.on_radioButton_Config)\n\n        self.RD_05_320x480 = QtWidgets.QRadioButton()\n        self.RD_05_320x480.clicked.connect(self.on_radioButton_Config)\n\n        self.RD_06_400x300 = QtWidgets.QRadioButton()\n        self.RD_06_400x300.clicked.connect(self.on_radioButton_Config)\n\n        self.RD_07_480x360 = QtWidgets.QRadioButton()\n        self.RD_07_480x360.clicked.connect(self.on_radioButton_Config)\n\n        self.RD_08_640x480 = QtWidgets.QRadioButton()\n        self.RD_08_640x480.clicked.connect(self.on_radioButton_Config)\n\n        self.RD_09_768x576 = QtWidgets.QRadioButton()\n        self.RD_09_768x576.clicked.connect(self.on_radioButton_Config)\n\n        self.RD_10_800x600 = QtWidgets.QRadioButton()\n        self.RD_10_800x600.clicked.connect(self.on_radioButton_Config)\n\n        self.RD_11_960x720 = QtWidgets.QRadioButton()\n        self.RD_11_960x720.clicked.connect(self.on_radioButton_Config)\n\n        self.RD_12_1024x768 = QtWidgets.QRadioButton()\n        self.RD_12_1024x768.clicked.connect(self.on_radioButton_Config)\n\n        self.RD_13_1400x600 = QtWidgets.QRadioButton()\n#        self.RD_13_1400x600.setChecked(True)     # (actif) or False (inactif)\n        self.RD_13_1400x600.clicked.connect(self.on_radioButton_Config)\n\n        self.RD_14_1600x800 = QtWidgets.QRadioButton()\n        self.RD_14_1600x800.clicked.connect(self.on_radioButton_Config)\n        ####\n\n        self.groupBox_img_02_Format = QtWidgets.QGroupBox()\n\n        self.LAB_01_Length = QtWidgets.QLabel()\n\n        self.LAB_02_Heigth = QtWidgets.QLabel()\n\n        self.SPB_01_Length = QtWidgets.QSpinBox()\n        self.SPB_01_Length.setMinimum(1)\n        self.SPB_01_Length.setMaximum(9999999)\n        self.SPB_01_Length.setValue(self.Length)\n        self.SPB_01_Length.valueChanged.connect(self.on_SPB_01_Length)\n\n        self.SPB_02_Heigth = QtWidgets.QSpinBox()\n        self.SPB_02_Heigth.setMinimum(1)\n        self.SPB_02_Heigth.setMaximum(9999999)\n        self.SPB_02_Heigth.setValue(self.Heigth)\n        self.SPB_02_Heigth.valueChanged.connect(self.on_SPB_02_Heigth)\n        ####\n        self.groupBox_img_03_Window = QtWidgets.QGroupBox()\n\n        self.RD_01_MWindow = QtWidgets.QRadioButton()\n\n        self.RD_02_Screen = QtWidgets.QRadioButton()\n        self.RD_02_Screen.setChecked(True)\n        ####\n        self.groupBox_img_04_BackGround = QtWidgets.QGroupBox()\n\n        self.RB_01_Actual = QtWidgets.QRadioButton()\n        self.RB_01_Actual.setChecked(True)\n        self.RB_01_Actual.clicked.connect(self.on_radioButton_FreeCAD)\n\n        self.RB_02_Color = QtWidgets.QRadioButton()\n        self.RB_02_Color.clicked.connect(self.on_radioButton_Color)\n\n        self.PB_01_Color = QtWidgets.QPushButton()\n        self.PB_01_Color.setVisible(False)\n        self.PB_01_Color.clicked.connect(self.on_PB_01_Color)\n\n        self.RB_03_Transparent = QtWidgets.QRadioButton()\n        self.RB_03_Transparent.clicked.connect(self.on_radioButton_FreeCAD)\n\n        self.PB_02_OriginalBaGr = QtWidgets.QPushButton()\n        self.PB_02_OriginalBaGr.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_BrowserReload))) #\n        self.PB_02_OriginalBaGr.setVisible(False)\n        self.PB_02_OriginalBaGr.clicked.connect(self.on_PB_02_OriginalBaGr)\n        ####\n        self.groupBox_img_05_Command = QtWidgets.QGroupBox()\n        self.PB_01_SetScreen = QtWidgets.QPushButton()\n        self.PB_01_SetScreen.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_ComputerIcon)))\n        self.PB_01_SetScreen.clicked.connect(self.on_PB_01_SetScreen)\n\n        self.PB_02_SetScreenTile = QtWidgets.QPushButton()\n        self.PB_02_SetScreenTile.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DesktopIcon)))\n        self.PB_02_SetScreenTile.clicked.connect(self.on_PB_02_SetScreenTile)\n\n        self.PB_03_SaveImage = QtWidgets.QPushButton()\n        self.PB_03_SaveImage.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton)))\n        self.PB_03_SaveImage.clicked.connect(self.on_PB_03_SaveImage)\n\n        self.PB_03B_Follow = QtWidgets.QPushButton()\n        self.PB_03B_Follow.setEnabled(False)\n        self.PB_03B_Follow.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_CommandLink)))\n        self.PB_03B_Follow.clicked.connect(self.on_PB_03B_Follow)\n\n        self.PB_03C_NewImage = QtWidgets.QPushButton()\n        self.PB_03C_NewImage.setIcon(QtGui.QIcon(QtGui.QPixmap(newImageIcon))) # miniWindowIcon icone dans une variable \n        self.PB_03C_NewImage.clicked.connect(self.on_PB_03C_New)\n\n        self.PB_03D_Mini = QtWidgets.QPushButton()\n        self.PB_03D_Mini.setIcon(QtGui.QIcon(QtGui.QPixmap(miniMaxiIcon))) # miniMaxiIcon icone dans une variable \n        self.PB_03D_Mini.setVisible(False)\n        self.PB_03D_Mini.clicked.connect(self.on_PB_03D_Mini)\n\n        self.PB_04_Quit = QtWidgets.QPushButton()\n        self.PB_04_Quit.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogCloseButton)))\n        self.PB_04_Quit.clicked.connect(self.on_PB_04_Quit)\n\n        self.PB_05_Rotation = QtWidgets.QPushButton()\n        self.PB_05_Rotation.clicked.connect(self.on_PB_05_Rotation)\n        self.PB_05_Rotation.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogOkButton))) #\n\n        self.PB_06_Reduction = QtWidgets.QPushButton()\n        self.PB_06_Reduction.clicked.connect(self.on_PB_06_Reduction)\n        self.PB_06_Reduction.setIcon(QtGui.QIcon(QtGui.QPixmap(miniToolBarIcon))) # miniWindowIcon icone dans une variable \n\n        self.LAB_Date = QtWidgets.QLabel()\n\n        self.frame_Reduction = QtWidgets.QFrame()\n        self.frame_Reduction.setVisible(False)\n        self.frame_Reduction.setFrameShape(QtWidgets.QFrame.StyledPanel)\n        self.frame_Reduction.setFrameShadow(QtWidgets.QFrame.Plain) #.Raised) Sunken\n\n        ################################\n        #### section rotation Debut ####\n        ## position modifiee\n        self.PB_03_Create_Point = QtWidgets.QPushButton()\n        self.PB_03_Create_Point.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogYesButton))) #\n        self.PB_03_Create_Point.clicked.connect(self.on_PB_03_Create_Point)\n\n        self.PB_Save_Animation = QtWidgets.QPushButton()\n        self.PB_Save_Animation.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton)))\n        self.PB_Save_Animation.clicked.connect(self.on_PB_Photo_Rotation_Object_clicked)\n        ## position modifiee\n\n        self.groupBox_00_01_00_Rotation = QtWidgets.QGroupBox()\n#        self.groupBox_00_01_00_Rotation.setVisible(False)\n\n        self.groupBox_rot_01_Rotation = QtWidgets.QGroupBox()\n\n        self.RB_01_3D_View = QtWidgets.QRadioButton()\n        self.RB_01_3D_View.setChecked(False)\n        self.RB_01_3D_View.clicked.connect(self.on_RB_01_3D_View)\n\n        self.RB_02_Object = QtWidgets.QRadioButton()\n        self.RB_02_Object.setChecked(True)\n        self.RB_02_Object.clicked.connect(self.on_RB_02_Object)\n        ####\n\n        self.groupBox_rot_02_Axis = QtWidgets.QGroupBox()\n\n        self.RB_01_Rotation_X = QtWidgets.QRadioButton()\n        self.RB_01_Rotation_X.setChecked(True)\n        self.RB_01_Rotation_X.clicked.connect(self.on_RB_01_Rotation_X)\n        self.RB_01_Rotation_X.setStyleSheet(\"QRadioButton {color : #ff0000; font: bold}\")\n\n        self.RB_02_Rotation_Y = QtWidgets.QRadioButton()\n        self.RB_02_Rotation_Y.clicked.connect(self.on_RB_02_Rotation_Y)\n        self.RB_02_Rotation_Y.setStyleSheet(\"QRadioButton {color : #008500; font: bold}\")\n\n        self.RB_03_Rotation_Z = QtWidgets.QRadioButton()\n        self.RB_03_Rotation_Z.clicked.connect(self.on_RB_03_Rotation_Z)\n        self.RB_03_Rotation_Z.setStyleSheet(\"QRadioButton {color : #0000ff; font: bold}\")\n\n        self.RB_04_Rotation_D = QtWidgets.QRadioButton()\n        self.RB_04_Rotation_D.clicked.connect(self.on_RB_04_Rotation_D)\n        self.RB_04_Rotation_D.setStyleSheet(\"QRadioButton {color : #995500; font: bold}\")\n        ####\n\n        self.groupBox_rot_03_Point = QtWidgets.QGroupBox()\n\n        self.RB_01_CenterObject = QtWidgets.QRadioButton()\n        self.RB_01_CenterObject.setChecked(True)\n        #self.RB_01_CenterObject.clicked.connect(self.on_RB_01_CenterObject)\n\n        self.RB_02_CenterSubObject = QtWidgets.QRadioButton()\n        #self.RB_02_CenterSubObject.clicked.connect(self.on_RB_02_CenterSubObject)\n\n        ####\n        self.groupBox_rot_04_Angles = QtWidgets.QGroupBox()\n\n        self.LAB_01_AngRot = QtWidgets.QLabel()\n\n        self.PB_00_Decrement = QtWidgets.QPushButton()\n        self.PB_00_Decrement.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_ArrowDown))) #\n        self.PB_00_Decrement.clicked.connect(self.on_PB_00_Decrement)\n\n        self.SPB_01_Angle_Rotation = QtWidgets.QDoubleSpinBox ()\n        self.SPB_01_Angle_Rotation.setPrefix(\"\")\n        self.SPB_01_Angle_Rotation.setDecimals(degreesNumberDecimal)\n        self.SPB_01_Angle_Rotation.setMaximum(360.0)\n        self.SPB_01_Angle_Rotation.setMinimum(0.000000001)\n        #self.SPB_01_Angle_Rotation.setSingleStep(1.0) \n        #self.SPB_01_Angle_Rotation.setValue(1.0)\n        self.SPB_01_Angle_Rotation.valueChanged.connect(self.on_SPB_01_Angle_Rotation)\n\n        self.PB_00_Increment = QtWidgets.QPushButton()\n        self.PB_00_Increment.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_ArrowUp))) #\n        self.PB_00_Increment.clicked.connect(self.on_PB_00_Increment)\n\n        self.LAB_00_Numb_Image = QtWidgets.QLabel()\n\n        self.PB_00_Decrement_Number_Images = QtWidgets.QPushButton()\n        self.PB_00_Decrement_Number_Images.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_ArrowDown))) #\n        self.PB_00_Decrement_Number_Images.clicked.connect(self.on_PB_00_Decrement_Number_Images)\n\n        self.SPB_02_Number_Images = QtWidgets.QSpinBox()\n        self.SPB_02_Number_Images.setMinimum(1) #1\n        self.SPB_02_Number_Images.setMaximum(9999999)\n        #self.SPB_02_Number_Images.setValue()\n        self.SPB_02_Number_Images.valueChanged.connect(self.on_SPB_02_Number_Images)\n\n        self.PB_00_Increment_Number_Images = QtWidgets.QPushButton()\n        self.PB_00_Increment_Number_Images.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_ArrowUp))) #\n        self.PB_00_Increment_Number_Images.clicked.connect(self.on_PB_00_Increment_Number_Images)\n\n        self.LAB_02_BegRot = QtWidgets.QLabel()\n\n        self.PB_01_Decrement_DegBeg = QtWidgets.QPushButton()\n        self.PB_01_Decrement_DegBeg.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_ArrowDown))) #\n        self.PB_01_Decrement_DegBeg.clicked.connect(self.on_PB_01_Decrement_DegBeg)\n\n        self.SPB_02_Angle_Begin_Rotation = QtWidgets.QDoubleSpinBox ()\n        self.SPB_02_Angle_Begin_Rotation.setDecimals(degreesNumberDecimal)\n        self.SPB_02_Angle_Begin_Rotation.setMaximum(360.0)\n        self.SPB_02_Angle_Begin_Rotation.setValue(beginRotation)\n        self.SPB_02_Angle_Begin_Rotation.valueChanged.connect(self.on_SPB_02_Angle_Begin_Rotation)\n\n        self.PB_01_Increment_DegBeg = QtWidgets.QPushButton()\n        self.PB_01_Increment_DegBeg.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_ArrowUp))) #\n        self.PB_01_Increment_DegBeg.clicked.connect(self.on_PB_01_Increment_DegBeg)\n\n        self.LAB_03_EndRot = QtWidgets.QLabel()\n\n        self.PB_02_Decrement_DegEnd = QtWidgets.QPushButton()\n        self.PB_02_Decrement_DegEnd.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_ArrowDown))) #\n        self.PB_02_Decrement_DegEnd.clicked.connect(self.on_PB_02_Decrement_DegEnd)\n\n        self.SPB_03_Angle_End_Rotation = QtWidgets.QDoubleSpinBox ()\n        self.SPB_03_Angle_End_Rotation.setDecimals(degreesNumberDecimal)\n        self.SPB_03_Angle_End_Rotation.setMaximum(360.0)\n        self.SPB_03_Angle_End_Rotation.setValue(endRotation)\n        self.SPB_03_Angle_End_Rotation.valueChanged.connect(self.on_SPB_03_Angle_End_Rotation)\n\n        self.PB_02_Increment_DegEnd = QtWidgets.QPushButton()\n        self.PB_02_Increment_DegEnd.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_ArrowUp))) #\n        self.PB_02_Increment_DegEnd.clicked.connect(self.on_PB_02_Increment_DegEnd)\n        ####\n        self.groupBox_rot_05_Command_Rotation = QtWidgets.QGroupBox()\n\n        self.LAB_Delay = QtWidgets.QLabel(self.groupBox_rot_05_Command_Rotation)\n\n        self.DSPB_01_Delay_Time = QtWidgets.QDoubleSpinBox()\n        self.DSPB_01_Delay_Time.setDecimals(3)\n        self.DSPB_01_Delay_Time.setMaximum(10000.0)\n        self.DSPB_01_Delay_Time.setValue(delayTime)\n        self.DSPB_01_Delay_Time.valueChanged.connect(self.on_DSPB_01_Delay_Time)\n\n        self.CB_01_Reverse = QtWidgets.QCheckBox()\n        self.CB_01_Reverse.clicked.connect(self.on_CB_01_Reverse)\n\n        self.CB_02_Original_Position = QtWidgets.QCheckBox()\n        self.CB_02_Original_Position.setChecked(True)\n        #self.CB_02_Original_Position.clicked.connect(self.on_CB_02_Original_Position)\n\n        self.PB_00_Test_Rotation = QtWidgets.QPushButton()\n        self.PB_00_Test_Rotation.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_BrowserReload))) #\n        self.PB_00_Test_Rotation.clicked.connect(self.on_PB_00_Test_Rotation)\n\n#placer plus haut test...        self.PB_03_Create_Point = QtWidgets.QPushButton()\n#placer plus haut test...        self.PB_03_Create_Point.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogYesButton))) #\n#placer plus haut test...        self.PB_03_Create_Point.clicked.connect(self.on_PB_03_Create_Point)\n\n#placer plus haut test...        self.PB_Save_Animation = QtWidgets.QPushButton()\n#placer plus haut test...        self.PB_Save_Animation.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton)))\n#placer plus haut test...        self.PB_Save_Animation.clicked.connect(self.on_PB_Photo_Rotation_Object_clicked)\n\n        #### section rotation Fin ####\n        ##############################\n\n        #### layout debut ##################\n        #### grid\n        self.gridLayoutWidget = QtWidgets.QWidget(MainWindow)\n        self.grid_principal = QtWidgets.QGridLayout(MainWindow)\n        self.groupBox_00_00_00_Image = QtWidgets.QGroupBox(self.gridLayoutWidget)\n        self.grid_00_01_00 = QtWidgets.QGridLayout(self.groupBox_00_00_00_Image)\n        #### Definition\n        self.grid_00_01_01 = QtWidgets.QGridLayout(self.groupBox_img_01_definition)\n        self.grid_00_01_01.addWidget(self.RD_04_320x240, 0, 0, 1, 1)\n        self.grid_00_01_01.addWidget(self.RD_05_320x480, 0, 1, 1, 1)\n        self.grid_00_01_01.addWidget(self.RD_01_400x200, 1, 0, 1, 1)\n        self.grid_00_01_01.addWidget(self.RD_06_400x300, 1, 1, 1, 1)\n        self.grid_00_01_01.addWidget(self.RD_07_480x360, 2, 0, 1, 1)\n        self.grid_00_01_01.addWidget(self.RD_02_600x400, 2, 1, 1, 1)\n        self.grid_00_01_01.addWidget(self.RD_08_640x480, 3, 0, 1, 1)\n        self.grid_00_01_01.addWidget(self.RD_09_768x576, 3, 1, 1, 1)\n        self.grid_00_01_01.addWidget(self.RD_10_800x600, 4, 0, 1, 1)\n        self.grid_00_01_01.addWidget(self.RD_11_960x720, 4, 1, 1, 1)\n        self.grid_00_01_01.addWidget(self.RD_03_1024x768, 5, 0, 1, 1)\n        self.grid_00_01_01.addWidget(self.RD_12_1024x768, 5, 1, 1, 1)\n        self.grid_00_01_01.addWidget(self.RD_13_1400x600, 6, 0, 1, 1)\n        self.grid_00_01_01.addWidget(self.RD_14_1600x800, 6, 1, 1, 1)\n        self.grid_00_01_00.addWidget(self.groupBox_img_01_definition, 1, 0, 1, 1)\n        #### Format image\n        self.grid_00_01_02 = QtWidgets.QGridLayout(self.groupBox_img_02_Format)#\n        self.grid_00_01_02.addWidget(self.LAB_01_Length, 0, 0, 1, 1)\n        self.grid_00_01_02.addWidget(self.LAB_02_Heigth, 0, 1, 1, 1)\n        self.grid_00_01_02.addWidget(self.SPB_01_Length, 1, 0, 1, 1)\n        self.grid_00_01_02.addWidget(self.SPB_02_Heigth, 1, 1, 1, 1)\n        self.grid_00_01_00.addWidget(self.groupBox_img_02_Format, 2, 0, 1, 1)\n        #### Window\n        self.grid_00_01_03 = QtWidgets.QGridLayout(self.groupBox_img_03_Window)#\n        self.grid_00_01_03.addWidget(self.RD_01_MWindow, 0, 0, 1, 1)\n        self.grid_00_01_03.addWidget(self.RD_02_Screen, 0, 1, 1, 1)\n        self.grid_00_01_00.addWidget(self.groupBox_img_03_Window, 3, 0, 1, 1)\n        #### BackGround color\n        self.grid_00_01_04 = QtWidgets.QGridLayout(self.groupBox_img_04_BackGround)#\n        self.grid_00_01_04.addWidget(self.RB_01_Actual, 0, 0, 1, 1)\n        self.grid_00_01_04.addWidget(self.RB_02_Color, 0, 1, 1, 1)\n        self.grid_00_01_04.addWidget(self.RB_03_Transparent, 1, 0, 1, 1)\n        self.grid_00_01_04.addWidget(self.PB_02_OriginalBaGr, 1, 1, 1, 1)\n        self.grid_00_01_00.addWidget(self.groupBox_img_04_BackGround, 4, 0, 1, 1)\n        #### Command\n        self.grid_00_01_05 = QtWidgets.QGridLayout(self.groupBox_img_05_Command)#\n        self.grid_00_01_05.addWidget(self.PB_01_SetScreen, 0, 0, 1, 1)\n        self.grid_00_01_05.addWidget(self.PB_02_SetScreenTile, 0, 1, 1, 1)\n        self.grid_00_01_05.addWidget(self.PB_03_SaveImage, 1, 0, 1, 1)\n        self.grid_00_01_05.addWidget(self.PB_03B_Follow, 1, 1, 1, 1)\n        self.grid_00_01_05.addWidget(self.PB_03C_NewImage, 2, 0, 1, 1)\n        self.grid_00_01_05.addWidget(self.PB_05_Rotation, 2, 1, 1, 1)\n#        self.grid_00_01_05.addWidget(self.LAB_Date, 3, 0, 1, 1)\n        self.grid_00_01_05.addWidget(self.PB_04_Quit, 3, 0, 1, 1)\n        self.grid_00_01_05.addWidget(self.PB_06_Reduction, 3, 1, 1, 1)\n        self.grid_00_01_00.addWidget(self.groupBox_img_05_Command, 5, 0, 1, 1)\n        ####\n        #### Rotation\n        self.grid_principal.addWidget(self.groupBox_00_01_00_Rotation, 0, 1, 1, 1)\n        self.grid_principal.addWidget(self.groupBox_00_00_00_Image, 0, 0, 1, 1)\n        self.grid_00_02_00 = QtWidgets.QGridLayout(self.groupBox_00_01_00_Rotation)\n        #### Rotation on\n        self.grid_00_02_01 = QtWidgets.QGridLayout(self.groupBox_rot_01_Rotation)\n        self.grid_00_02_01.addWidget(self.RB_01_3D_View, 0, 0, 1, 1)\n        self.grid_00_02_01.addWidget(self.RB_02_Object, 0, 1, 1, 1)\n        self.grid_00_02_00.addWidget(self.groupBox_rot_01_Rotation, 0, 0, 1, 1)\n        #### Axis\n        self.grid_00_02_02 = QtWidgets.QGridLayout(self.groupBox_rot_02_Axis)\n        self.grid_00_02_02.addWidget(self.RB_01_Rotation_X, 0, 0, 1, 1)\n        self.grid_00_02_02.addWidget(self.RB_02_Rotation_Y, 0, 1, 1, 1)\n        self.grid_00_02_02.addWidget(self.RB_03_Rotation_Z, 0, 2, 1, 1)\n        self.grid_00_02_02.addWidget(self.RB_04_Rotation_D, 0, 3, 1, 1)\n        self.grid_00_02_00.addWidget(self.groupBox_rot_02_Axis, 1, 0, 1, 1)\n        #### Point Rotation BoundBox\n        self.grid_00_02_03 = QtWidgets.QGridLayout(self.groupBox_rot_03_Point)\n        self.grid_00_02_03.addWidget(self.RB_01_CenterObject, 0, 0, 1, 1)\n        self.grid_00_02_03.addWidget(self.RB_02_CenterSubObject, 0, 1, 1, 1)\n        self.grid_00_02_00.addWidget(self.groupBox_rot_03_Point, 2, 0, 1, 1)\n        #### Angles\n        self.grid_00_02_04 = QtWidgets.QGridLayout(self.groupBox_rot_04_Angles)\n        self.grid_00_02_04.addWidget(self.LAB_01_AngRot, 0, 0, 1, 3)\n        self.grid_00_02_04.addWidget(self.PB_00_Decrement, 1, 0, 1, 1)\n        self.grid_00_02_04.addWidget(self.SPB_01_Angle_Rotation, 1, 1, 1, 1)\n        self.grid_00_02_04.addWidget(self.PB_00_Increment, 1, 2, 1, 1)\n        self.grid_00_02_04.addWidget(self.LAB_00_Numb_Image, 2, 0, 1, 1)\n        self.grid_00_02_04.addWidget(self.PB_00_Decrement_Number_Images, 3, 0, 1, 1)\n        self.grid_00_02_04.addWidget(self.SPB_02_Number_Images, 3, 1, 1, 1)\n        self.grid_00_02_04.addWidget(self.PB_00_Increment_Number_Images, 3, 2, 1, 1)\n        self.grid_00_02_04.addWidget(self.LAB_02_BegRot, 4, 0, 1, 3)\n        self.grid_00_02_04.addWidget(self.PB_01_Decrement_DegBeg, 5, 0, 1, 1)\n        self.grid_00_02_04.addWidget(self.SPB_02_Angle_Begin_Rotation, 5, 1, 1, 1)\n        self.grid_00_02_04.addWidget(self.PB_01_Increment_DegBeg, 5, 2, 1, 1)\n        self.grid_00_02_04.addWidget(self.LAB_03_EndRot, 6, 0, 1, 3)\n        self.grid_00_02_04.addWidget(self.PB_02_Decrement_DegEnd, 7, 0, 1, 1)\n        self.grid_00_02_04.addWidget(self.SPB_03_Angle_End_Rotation, 7, 1, 1, 1)\n        self.grid_00_02_04.addWidget(self.PB_02_Increment_DegEnd, 7, 2, 1, 1)\n        self.grid_00_02_00.addWidget(self.groupBox_rot_04_Angles, 3, 0, 1, 1)\n        #### Command\n        self.grid_00_02_05 = QtWidgets.QGridLayout(self.groupBox_rot_05_Command_Rotation)\n        self.grid_00_02_05.addWidget(self.LAB_Delay, 0, 0, 1, 2)\n        self.grid_00_02_05.addWidget(self.DSPB_01_Delay_Time, 1, 0, 1, 2)\n        self.grid_00_02_05.addWidget(self.CB_01_Reverse, 2, 0, 1, 1)\n        self.grid_00_02_05.addWidget(self.PB_03_Create_Point, 2, 1, 1, 1)\n        self.grid_00_02_05.addWidget(self.CB_02_Original_Position, 3, 0, 1, 1)\n        self.grid_00_02_05.addWidget(self.PB_00_Test_Rotation, 3, 1, 1, 1)\n        self.grid_00_02_05.addWidget(self.PB_Save_Animation, 4, 0, 1, 2)\n        self.grid_00_02_00.addWidget(self.groupBox_rot_05_Command_Rotation, 4, 0, 1, 1)\n        ####\n        #### layout fin ##################\n\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n\n        MainWindow.setWindowTitle( __title__) #+\" (\"+__version__+\", \"+__date__+\")\")\n        MainWindow.setWindowIcon(QtGui.QIcon(self.path+\"Macro_Screen_Wiki.png\")) # change l'icone de la fenetre principale\n        MainWindow.setWindowFlags(PySide2.QtCore.Qt.WindowStaysOnTopHint)        # PySide2 cette fonction met la fenetre en avant\n\n        self.groupBox_00_00_00_Image.setTitle(u\"Image options\" + \" (Ver rmu : \" +  __version__ + \" : \" + __date__ + \")\")\n        self.groupBox_img_01_definition.setTitle(u\"Definition :\")\n        self.groupBox_img_01_definition.setToolTip(u\"Other standard Definition\" + \"\\n\" +\n                                 u\"_________________________\" + \"\\n\" +\n                                 u\"Icon\" + \"\\t\" + \"16 x 16\" + \"\\n\" +\n                                 u\"Icon\" + \"\\t\" + \"32 x 32\" + \"\\n\" +\n                                 u\"Icon\" + \"\\t\" + \"64 x 64\" + \"\\n\" +\n                                 u\"Icon\" + \"\\t\" + \"128 x 128\" + \"\\n\" +\n                                 u\"CGA\" + \"\\t\" + \"320 x 200\" + \"\\n\" +\n                                 u\"XGA+\" + \"\\t\" + \"1152 x 864\" + \"\\n\" +\n                                 u\"SXGA\" + \"\\t\" + \"1280 x 1024\" + \"\\n\" +\n                                 u\"SXGA+\" + \"\\t\" + \"1400 x 1050\" + \"\\n\" +\n                                 u\"UXGA\" + \"\\t\" + \"1600 x 1200\" + \"\\n\" +\n                                 u\"QXGA\" + \"\\t\" + \"2048 x 1536\")\n        self.RD_01_400x200.setText(u\"400 x 200\")\n        self.RD_02_600x400.setText(u\"600 x 400\")\n        self.RD_03_1024x768.setText(u\"1024 x 768\")\n        self.RD_04_320x240.setText(u\"320 x 240 (QVGA)\")\n        self.RD_05_320x480.setText(u\"320 x 480 (HVGA)\")\n        self.RD_06_400x300.setText(u\"400 x 300\")\n        self.RD_07_480x360.setText(u\"480 x 360\")\n        self.RD_08_640x480.setText(u\"640 x 480 (VGA)\")\n        self.RD_09_768x576.setText(u\"768 x 576 (PAL)\")\n        self.RD_10_800x600.setText(u\"800 x 600 (SVGA)\")\n        self.RD_11_960x720.setText(u\"960 x 720\")\n        self.RD_12_1024x768.setText(u\"1024 x 768 (XGA)\")\n        self.RD_13_1400x600.setText(u\"1400 x 600\")\n        self.RD_14_1600x800.setText(u\"1600 x 800\")\n\n        self.groupBox_img_02_Format.setTitle(u\"Format image :\")\n        self.LAB_01_Length.setText(u\"Length\")\n        self.SPB_01_Length.setSuffix(u\" Length px\")\n        self.LAB_02_Heigth.setText(u\"Height\")\n        self.SPB_02_Heigth.setSuffix(u\" Heigth px\")\n\n        self.groupBox_img_03_Window.setTitle(u\"Window :\")\n#        self.groupBox_img_03_Window.setToolTip(\"Choice:\" + \"\\n\" +\n#                                               \"_______\" + \"\\n\" +\n#                                               \"Window FreeCAD\" + \"\\n\" +\n#                                               \"Window Vieuw 3D\")\n        self.RD_01_MWindow.setText(u\"Window FC\")\n        self.RD_01_MWindow.setToolTip(u\"Window FreeCAD complete\" + \"\\n\" +\n                                      u\"The dimension of small screen can be influenced\" + \"\\n\" +\n                                      u\"by the presence of Python console, Report view\")\n        self.RD_02_Screen.setText(u\"Screen 3D\")\n        self.RD_02_Screen.setToolTip(u\"Window View 3D active\" + \"\\n\" +\n                                     u\"or sub Window active\")\n\n        self.groupBox_img_04_BackGround.setTitle(u\"BackGround Color :\")\n        self.RB_01_Actual.setText(u\"Current\")\n        self.RB_01_Actual.setToolTip(u\"BackGround image color Current color\")\n        self.RB_02_Color.setText(u\"Color\")\n        self.RB_02_Color.setToolTip(u\"BackGround Color a choice.\" + \"\\n\" +\n                                    u\"Standard Color Tango\")\n        self.RB_03_Transparent.setText(u\"Transparent\")\n        self.RB_03_Transparent.setToolTip(u\"BackGround image color Transparent\")\n        # self.PB_01_Color.setToolTip(u\"Color a choice\" + \"\\n\" +\n                                    # u\"Tango line\")\n        self.PB_02_OriginalBaGr.setText(u\"Restore\")\n        self.PB_02_OriginalBaGr.setToolTip(u\"Restore the original BackGround\")\n\n        self.groupBox_img_05_Command.setTitle(u\"Command :\")\n        self.PB_01_SetScreen.setText(u\"Set Screen\")\n        self.PB_01_SetScreen.setToolTip(u\"Set Screen\" + \"\\n\" + \"This mode reflect the exact image that will be saved\")\n\n        self.PB_02_SetScreenTile.setText(u\"Tile Screen\")\n        self.PB_02_SetScreenTile.setToolTip(u\"Tile Screen\" + \"\\n\" +\n                                            u\"If you work with this mode,\" + \"\\n\" +\n                                            u\"visualise the window with Set Screen\" + \"\\n\" +\n                                            u\"for visualise the exact image saved\" + \"\\n\" + \"\\n\" +\n                                            u\"PS: If the screen is too small\" + \"\\n\" +\n                                            u\"the definition can be modified if moving the window\" + \"\\n\" +\n                                            u\"ex: (400 x 200 modified on 413 x 333)\")\n\n        self.PB_03_SaveImage.setText(u\"Save Image\")\n        self.PB_03_SaveImage.setToolTip(u\"Save Image with number begin to 0 in format _000.\" + \"\\n\"\n                                        u\"This button adding always the number.\" + \"\\n\"\n                                        u\"A follow-up can be done with the follow button\")\n\n        self.PB_03B_Follow.setText(u\"Follow\")\n        self.PB_03B_Follow.setToolTip(u\"If you desire create many view with the same name\" + \"\\n\"\n                                      u\"the counter increment the saved image\" + \"\\n\"\n                                      u\"and the number images saved hare displayed in the button\")\n\n        self.PB_03C_NewImage.setText(u\"New Image\")                      # Single\n        self.PB_03C_NewImage.setToolTip(u\"Save the image without number\")\n\n        self.PB_03D_Mini.setText(u\"Mini\")                      # MiniToolBar\n        self.PB_03D_Mini.setToolTip(u\"Minimize toolBar\")\n\n        self.PB_04_Quit.setText(u\"Quit\")\n        self.PB_04_Quit.setToolTip(u\"Quit ScreenWindowWiki Ciao\")\n\n        self.PB_05_Rotation.setText(u\"Rotation\")\n        self.PB_05_Rotation.setToolTip(u\"Go to rotation menu\")\n\n        self.PB_06_Reduction.setText(u\"ToolBar\")\n        self.PB_06_Reduction.setToolTip(u\"Go to minimise the macro window in a ToolBar\" + \"\\n\"\n                                        u\"The rotation option is inaccessible in this mode\")\n\n        #### section rotation\n        self.groupBox_00_01_00_Rotation.setTitle(u\"Rotation \")\n        self.groupBox_00_01_00_Rotation.setVisible(False)\n\n        self.groupBox_rot_01_Rotation.setTitle(u\"Rotation on : \")\n        self.RB_01_3D_View.setText(u\"3D View\")\n        self.RB_01_3D_View.setToolTip(u\"The 3D view is rotate\")\n        self.RB_02_Object.setText(u\"Object\")\n        self.RB_02_Object.setToolTip(u\"Object to rotate\")\n\n        self.groupBox_rot_02_Axis.setTitle(u\"Axis :\")\n        self.RB_01_Rotation_X.setText(u\"X\")\n        self.RB_01_Rotation_X.setToolTip(u\"Rotation on X axis\")\n        self.RB_02_Rotation_Y.setText(u\"Y\")\n        self.RB_02_Rotation_Y.setToolTip(u\"Rotation on Y axis\")\n        self.RB_03_Rotation_Z.setText(u\"Z\")\n        self.RB_03_Rotation_Z.setToolTip(u\"Rotation on Z axis\")\n        self.RB_04_Rotation_D.setText(u\"Dir.\")\n        self.RB_04_Rotation_D.setToolTip(u\"\\n\" + \"Rotation on Direction axis\"\n                                         u\"The direction is a wire, line, edge\" + \"\\n\"\n                                         u\"For use this option 2 selections are request\" + \"\\n\"\n                                         u\"first the object to rotate, second the direction axis\" + \"\\n\"\n                                         u\"If not direction given, the direction is Vector(0, 0, 0)\")\n\n        self.groupBox_rot_03_Point.setTitle(u\"Point Rotation BoundBox :\")\n        self.RB_01_CenterObject.setText(u\"Object\")\n        self.RB_01_CenterObject.setToolTip(u\"The point rotation is the BoundBox center of the object\")\n        self.RB_02_CenterSubObject.setText(u\"Sub Object\")\n        self.RB_02_CenterSubObject.setToolTip(u\"The point rotation is the BoundBox center of the Subobject\")\n\n        self.groupBox_rot_04_Angles.setTitle(u\"Angles :\")\n        self.LAB_01_AngRot.setText(u\"Angle Rotation\")\n        self.PB_00_Decrement.setText(u\"-\")\n        self.PB_00_Increment.setText(u\"+\")\n        self.SPB_01_Angle_Rotation.setSuffix(u\" Degrees\")\n        self.SPB_01_Angle_Rotation.setToolTip(u\"Give the angle of rotation of the object\" + \"\\n\"\n                                              u\"The - and + button increment the value by step 10 degrees\")\n        self.LAB_00_Numb_Image.setText(u\"Number images\")\n        self.PB_00_Decrement_Number_Images.setText(u\"-\")\n        self.PB_00_Increment_Number_Images.setText(u\"+\")\n        self.SPB_02_Number_Images.setSuffix(u\" Images (+1)\")\n        self.SPB_02_Number_Images.setToolTip(u\"Number of images + 1)\")\n\n        self.LAB_02_BegRot.setText(u\"Angle Begin Rotation\")\n        self.PB_01_Decrement_DegBeg.setText(u\"-\")\n        self.PB_01_Increment_DegBeg.setText(u\"+\")\n        self.SPB_02_Angle_Begin_Rotation.setSuffix(u\" Degrees\")\n        self.SPB_02_Angle_Begin_Rotation.setToolTip(u\"The begin angle rotation\" + \"\\n\"\n                                                    u\"The - and + button increment the value by step 10 degrees\")\n        self.LAB_03_EndRot.setText(u\"Angle End Rotation\")\n        self.PB_02_Decrement_DegEnd.setText(u\"-\")\n        self.PB_02_Increment_DegEnd.setText(u\"+\")\n        self.SPB_03_Angle_End_Rotation.setSuffix(u\" Degrees\")\n        self.SPB_03_Angle_End_Rotation.setToolTip(u\"The end angle rotation\" + \"\\n\"\n                                                  u\"The - and + button increment the value by step 10 degrees\")\n        self.groupBox_rot_05_Command_Rotation.setTitle(u\"Command :\")\n        self.LAB_Delay.setText(u\"Delay betwen 2 images\")\n        self.DSPB_01_Delay_Time.setSuffix(u\" Delay second\")\n        self.DSPB_01_Delay_Time.setToolTip(u\"If you have a problem for save your rotation (too fast)\" + \"\\n\"\n                                           u\"give a delay for write the images\")\n        self.CB_01_Reverse.setText(u\"Reverse\")\n        self.CB_01_Reverse.setToolTip(u\"Check this checkBox for reverse the rotation\")\n        self.PB_03_Create_Point.setText(u\"Point center\")\n        self.PB_03_Create_Point.setToolTip(u\"Visualize the point center of rotation\" + \"\\n\"\n                                           u\"If the point is visible the point is include in the image\" + \"\\n\"\n                                           u\"Actual : x:\" + str(\"0\") + \", y:\" + str(\"0\") + \", z:\" + str(\"0\") + \"\\n\" + \"\\n\"\n                                           u\"PS: the point can be hidden by an object\")\n        self.CB_02_Original_Position.setText(u\"Original position\")\n        self.CB_02_Original_Position.setToolTip(u\"The object or the screen return in original position\" + \"\\n\"\n                                                u\"case the rotation is not complete\")\n        self.PB_00_Test_Rotation.setText(u\"Test Rot.\")\n        self.PB_00_Test_Rotation.setToolTip(u\"Testing the rotation without saving images\")\n        self.PB_Save_Animation.setText(u\"Save the animation\")\n        self.PB_Save_Animation.setToolTip(u\"Launch the animation\" + \"\\n\"\n                                          u\"The name is saved as is : MyName_Animate_035_Z_340-0200_Current.png\" + \"\\n\"\n                                          u\"MyName_\\t: file name\" + \"\\n\"\n                                          u\"Animate_\\t: serial images for animation\" + \"\\n\"\n                                          u\"035_\\t\\t: number of image\" + \"\\n\"\n                                          u\"Z_\\t\\t: axis of rotation\" + \"\\n\"\n                                          u\"340-\\t\\t: angle of rotation of the image\" + \"\\n\"\n                                          u\"0200_\\t\\t: angle decimal degrees\" + \"\\n\"\n                                          u\"Current\\t\\t: screen backGround, (Current, Color, Transparent)\" + \"\\n\"\n                                          u\".png\\t\\t: extension request\")\n        ########\n\n    def on_RB_01_Rotation_X(self):    #\n        global axis\n        axis = \"X\"\n\n    def on_RB_02_Rotation_Y(self):    #\n        global axis\n        axis = \"Y\"\n\n    def on_RB_03_Rotation_Z(self):    #\n        global axis\n        axis = \"Z\"\n\n    def on_RB_04_Rotation_D(self):    #\n        global axis\n        axis = \"D\"\n\n    def formuleNumberPhoto(self):\n        global beginRotation\n        global endRotation\n        global valeurAngle\n        global numberPhoto\n        global parcours\n        global switchValue\n\n        self.SPB_01_Angle_Rotation.setValue(valeurAngle)\n        if (valeurAngle != 0) or (switchValue == True):\n            self.PB_00_Decrement.setStyleSheet(\"QDoubleSpinBox {background-color: QPalette.Base}\")            # origin system\n            self.SPB_01_Angle_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: QPalette.Base}\")      # origin system\n            self.PB_00_Increment.setStyleSheet(\"QDoubleSpinBox {background-color: QPalette.Base}\")            # origin system\n\n            if switchValue == True:\n                parcours = (endRotation - beginRotation)\n                valeurAngle = parcours / numberPhoto\n                self.SPB_01_Angle_Rotation.setValue(valeurAngle)\n            else:\n                parcours = (endRotation - beginRotation)\n                numberPhoto = int((parcours / valeurAngle) + 1)\n            switchValue = False\n\n            self.SPB_02_Number_Images.setValue(numberPhoto)\n        else:\n            self.PB_00_Decrement.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(215, 10, 22)};\")      # bord white and red\n            self.SPB_01_Angle_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: white; border:2px solid rgb(10, 215, 22)};\")# bord white and green\n            self.PB_00_Increment.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(10, 215, 22)};\")      # bord white and red\n\n        if endRotation == beginRotation:\n#            self.groupBox_rot_04_Angles.setStyleSheet(\"QGroupBox {color : #ffff00; background-color: #F66961 ; font: bold 10px};\")\n            if endRotation == 0:\n                self.PB_01_Decrement_DegBeg.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(215, 10, 22)};\")      # bord white and red\n                self.SPB_02_Angle_Begin_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: white; border:2px solid rgb(215, 10, 22)};\") # bord white and green\n                self.SPB_02_Angle_Begin_Rotation.setEnabled(False)\n                self.PB_01_Increment_DegBeg.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(215, 10, 22)};\")      # bord white and red\n    \n                self.PB_02_Decrement_DegEnd.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(215, 10, 22)};\")      # bord white and red\n                self.SPB_03_Angle_End_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: white; border:2px solid rgb(10, 215, 22)};\")   # bord white and green\n                self.PB_02_Increment_DegEnd.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(10, 215, 22)};\")      # bord white and green\n\n            else:\n                self.PB_01_Decrement_DegBeg.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(10, 215, 22)};\")      # bord white and green\n                self.SPB_02_Angle_Begin_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: white; border:2px solid rgb(10, 215, 22)};\") # bord white and green\n                self.SPB_02_Angle_Begin_Rotation.setEnabled(True)\n                self.PB_01_Increment_DegBeg.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(215, 10, 22)};\")      # bord white and red\n    \n                self.PB_02_Decrement_DegEnd.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(215, 10, 22)};\")      # bord white and red\n                self.SPB_03_Angle_End_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: white; border:2px solid rgb(10, 215, 22)};\")   # bord white and green\n                self.PB_02_Increment_DegEnd.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(10, 215, 22)};\")      # bord white and green\n\n            if endRotation == 360:\n                self.PB_02_Increment_DegEnd.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(215, 10, 22)};\")   # bord white and red\n\n            self.PB_Save_Animation.setEnabled(False)\n            self.PB_Save_Animation.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(215, 10, 22)};\")      # bord white and red\n            #print(\"endRotation 1\")\n        else:\n#            self.groupBox_rot_04_Angles.setStyleSheet(\"QGroupBox {background-color: QPalette.Base}\")\n            if beginRotation == 0:\n                self.PB_01_Decrement_DegBeg.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(215, 10, 22)};\")      # bord white and green\n#                self.PB_01_Increment_DegBeg.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(215, 10, 22)};\")      # bord white and red\n            else:\n                self.PB_01_Decrement_DegBeg.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")\n#                self.PB_01_Increment_DegBeg.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")\n\n            self.SPB_02_Angle_Begin_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: QPalette.Base}\")\n            self.SPB_02_Angle_Begin_Rotation.setEnabled(True)\n            self.PB_01_Increment_DegBeg.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")\n\n            self.PB_02_Decrement_DegEnd.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")\n            self.SPB_03_Angle_End_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: QPalette.Base}\")\n            if endRotation == 360:\n                self.PB_02_Increment_DegEnd.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(215, 10, 22)};\")      # bord white and green\n            else:\n                self.PB_02_Increment_DegEnd.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")\n\n            self.PB_Save_Animation.setEnabled(True)\n            self.PB_Save_Animation.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")\n\n        self.groupBox_rot_04_Angles.setGeometry(QtCore.QRect(10, 185, 161, 196))\n\n    #### rotation\n\n    def on_SPB_01_Angle_Rotation(self, value):    #\n        global valeurAngle\n        global ui\n\n        valeurAngle = value\n        self.SPB_01_Angle_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: QPalette.Base}\") # origin system\n        self.PB_Save_Animation.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")        # origin system\n        self.PB_03_Create_Point.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")       # origin system\n        ui.formuleNumberPhoto()\n\n    def on_PB_00_Decrement(self):    #\n        global valeurAngle\n        global ui\n\n        self.SPB_01_Angle_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: QPalette.Base}\") # origin system\n        self.PB_Save_Animation.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")        # origin system\n        self.PB_03_Create_Point.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")       # origin system\n        valeurAngle -= 10\n        if valeurAngle < 0:\n            valeurAngle = 0\n        self.SPB_01_Angle_Rotation.setValue(valeurAngle)\n        ui.formuleNumberPhoto()\n\n    def on_PB_00_Increment(self):    # angle rotation\n        global valeurAngle\n        global ui\n\n        self.SPB_01_Angle_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: QPalette.Base}\") # origin system\n        self.PB_Save_Animation.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")        # origin system\n        self.PB_03_Create_Point.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")       # origin system\n        valeurAngle += 10\n        if valeurAngle > 360:\n            valeurAngle = 360\n        self.SPB_01_Angle_Rotation.setValue(valeurAngle)\n        ui.formuleNumberPhoto()\n\n    def on_SPB_02_Number_Images(self, value):    # nombre d'images\n        global ui\n        global valeurAngle\n        global endRotation\n        global beginRotation\n        global parcours\n        global numberPhoto\n        global switchValue\n\n        numberPhoto = value\n        switchValue = True\n        ui.formuleNumberPhoto()\n\n    def on_PB_00_Decrement_Number_Images(self):    # nombre d'images\n        global numberPhoto\n\n        numberPhoto -= 10+1\n        if numberPhoto < 1:\n            numberPhoto = 1\n        self.SPB_02_Number_Images.setValue(numberPhoto)\n        ui.formuleNumberPhoto()\n\n    def on_PB_00_Increment_Number_Images(self):    # nombre d'images\n        global numberPhoto\n\n        numberPhoto += 10-1\n        self.SPB_02_Number_Images.setValue(numberPhoto)\n        ui.formuleNumberPhoto()\n\n    def on_PB_00_Test_Rotation(self):    # \n        global switchTestRotation\n\n        switchTestRotation = True\n        self.on_PB_Photo_Rotation_Object_clicked()\n\n    def on_SPB_02_Angle_Begin_Rotation(self,value):    #\n        global valeurAngle\n        global beginRotation\n        global endRotation\n\n        beginRotation = value\n        if beginRotation > endRotation:\n            beginRotation = value = endRotation\n            self.SPB_02_Angle_Begin_Rotation.setValue(beginRotation)\n        ui.formuleNumberPhoto()\n\n    def on_PB_01_Decrement_DegBeg(self):    #\n        global valeurAngle\n        global beginRotation\n        global endRotation\n\n        beginRotation -= 10\n        if beginRotation > endRotation:\n            beginRotation = endRotation\n        if beginRotation < 0:\n            beginRotation = 0\n        self.SPB_02_Angle_Begin_Rotation.setValue(beginRotation)\n        ui.formuleNumberPhoto()\n\n    def on_PB_01_Increment_DegBeg(self):    #\n        global valeurAngle\n        global beginRotation\n        global endRotation\n\n        beginRotation += 10\n        if beginRotation > endRotation:\n            beginRotation = endRotation\n        self.SPB_02_Angle_Begin_Rotation.setValue(beginRotation)\n        ui.formuleNumberPhoto()\n    ####\n    def on_SPB_03_Angle_End_Rotation(self,value):    #\n        global valeurAngle\n        global beginRotation\n        global endRotation\n\n        endRotation = value\n        if endRotation < beginRotation:\n            endRotation = value = beginRotation\n            self.SPB_03_Angle_End_Rotation.setValue(endRotation)\n        ui.formuleNumberPhoto()\n\n    def on_PB_02_Decrement_DegEnd(self):    #\n        global valeurAngle\n        global beginRotation\n        global endRotation\n\n        endRotation -= 10\n        if endRotation < beginRotation:\n            endRotation = beginRotation\n        if endRotation < 0:\n            endRotation = 0\n        self.SPB_03_Angle_End_Rotation.setValue(endRotation)\n        ui.formuleNumberPhoto()\n\n    def on_PB_02_Increment_DegEnd(self):    #\n        global valeurAngle\n        global beginRotation\n        global endRotation\n\n        endRotation += 10\n        if endRotation < beginRotation:\n            endRotation = beginRotation\n        if endRotation >= 360:\n            endRotation = 360\n#            self.SPB_03_Angle_End_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: white; border:2px solid rgb(215, 10, 22)};\")      # bord white and green\n#        else:\n#            self.SPB_03_Angle_End_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: QPalette.Base}\")            # origin system\n\n        self.SPB_03_Angle_End_Rotation.setValue(endRotation)\n        ui.formuleNumberPhoto()\n\n    ####\n    def on_DSPB_01_Delay_Time(self,value):    #\n        global delayTime\n\n        delayTime = value\n\n    def on_CB_01_Reverse(self):\n\n        if self.CB_01_Reverse.isChecked():\n            self.CB_01_Reverse.setText(u\"Reverse\")\n        else:\n            self.CB_01_Reverse.setText(u\"ClockWise\")\n\n    def on_PB_03_Create_Point(self):    # Create Point for visualize the point XYZ rotation\n        global ctPoint\n        global itemctPoint\n        global switch_Create_Point\n\n        pointRotation = \"\"\n        self.PB_03_Create_Point.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")        # origin system\n        if self.RB_01_3D_View.isChecked():    #3DView\n            cam = \"\"\n            cam = Gui.ActiveDocument.ActiveView.getCameraNode()\n            activeView = FreeCADGui.activeDocument().activeView()\n            try:\n                sel = FreeCADGui.Selection.getSelection()\n                if hasattr(sel[0], \"Shape\"):\n                    s = sel[0].Shape\n                elif hasattr(sel[0], \"Mesh\"):         # upgrade with wmayer thanks #http://forum.freecadweb.org/viewtopic.php?f=13&t=22331\n                    s = sel[0].Mesh\n                elif hasattr(sel[0], \"Points\"):\n                    s = sel[0].Points\n                pointRotation = pointRotation2 = s.BoundBox.Center    # boundbox center of the object\n                cam.position.setValue(pointRotation) # boundBox edge selected\n            except Exception:\n                #### pas de selection\n                #https://forum.freecadweb.org/viewtopic.php?f=22&t=10157\n                cam = Gui.ActiveDocument.ActiveView.getCameraNode()\n                position = cam.position.getValue()\n                orient = cam.orientation.getValue()\n                focalDistance = cam.focalDistance.getValue()\n                viewdir = coin.SbVec3f(0, 0, -1)\n                viewdir = orient.multVec(viewdir)\n                pointRotation = position + viewdir * focalDistance\n                pointRotation = pointRotation2 = App.Vector(pointRotation.getValue()[0], pointRotation.getValue()[1], pointRotation.getValue()[2])\n\n            if (valeurAngle != 0):\n                try:\n                    sel = FreeCADGui.Selection.getSelection()\n                    if hasattr(sel[0], \"Shape\"):\n                        objectRotation         = Gui.Selection.getSelection()[0]                          # object of rotation\n                        objectPlacementOrigine = objectRotation.Placement                                 # object Placement Origine\n                        objectPlacementBase    = objectRotation.Placement.Base                            # object Placement Base\n                        \n                        try:\n                            selectedEdge = FreeCADGui.Selection.getSelectionEx()[1].SubObjects[0]         # select one element and axis second object (2 selections)\n                        except Exception:\n                            try:\n                                selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[1]     # select one element and axis same object   (2 selections)\n                            except Exception:\n                                try:\n                                    selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0] # select one element and axis same object   (1 selection)\n                                except Exception:\n                                    None\n                        #### section point rotation\n                        if self.RB_01_CenterObject.isChecked():# and (axis != \"D\"):\n                            pointRotation = objectRotation.Shape.BoundBox.Center                       # point rotation single object BoundBox.Center\n                        else:\n                            pointRotation = selectedEdge.BoundBox.Center                               # point rotation sub object BoundBox.Center\n                except Exception:\n                    pointRotation = pointRotation2\n\n        elif self.RB_02_Object.isChecked():        # Object selected\n            sel = FreeCADGui.Selection.getSelection()\n            if len(sel) != 0:\n                if hasattr(sel[0], \"Shape\"):\n                    s = sel[0].Shape\n                elif hasattr(sel[0], \"Mesh\"):      # upgrade with wmayer thanks #http://forum.freecadweb.org/viewtopic.php?f=13&t=22331\n                    s = sel[0].Mesh\n                elif hasattr(sel[0], \"Points\"):\n                    s = sel[0].Points\n                pointRotation = s.BoundBox.Center # boundbox center of the object\n                if (valeurAngle != 0):\n                    sel = FreeCADGui.Selection.getSelection()\n                    if hasattr(sel[0], \"Shape\"):\n                        objectRotation         = Gui.Selection.getSelection()[0]                          # object of rotation\n                        objectPlacementOrigine = objectRotation.Placement                                 # object Placement Origine\n                        objectPlacementBase    = objectRotation.Placement.Base                            # object Placement Base\n                        \n                        try:\n                            selectedEdge = FreeCADGui.Selection.getSelectionEx()[1].SubObjects[0]         # select one element and axis second object (2 selections)\n                        except Exception:\n                            try:\n                                selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[1]     # select one element and axis same object   (2 selections)\n                            except Exception:\n                                try:\n                                    selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0] # select one element and axis same object   (1 selection)\n                                except Exception:\n                                    None\n                        \n                        #### section point rotation\n                        if self.RB_01_CenterObject.isChecked():# and (axis != \"D\"):\n                            pointRotation = objectRotation.Shape.BoundBox.Center                       # point rotation single object BoundBox.Center\n                        else:\n                            pointRotation = selectedEdge.BoundBox.Center                               # point rotation sub object BoundBox.Center\n                       \n                    elif (hasattr(sel[0], \"Mesh\")) or (hasattr(sel[0], \"Points\")):      # upgrade with wmayer thanks #http://forum.freecadweb.org/viewtopic.php?f=13&t=22331\n                        if hasattr(sel[0], \"Mesh\"):\n                            s = sel[0].Mesh \n                        else:\n                            s = sel[0].Points\n                        pointRotation = s.BoundBox.Center                                # boundbox center of the object\n                        #### section point rotation\n                        if self.RB_01_CenterObject.isChecked():\n                            pointRotation = s.BoundBox.Center                            # point rotation single object BoundBox.Center\n                        else:\n                            try:\n                                selectedEdge = FreeCADGui.Selection.getSelectionEx()[1].SubObjects[0]       # select one element and axis second object (2 selections)\n                                pointRotation = selectedEdge.BoundBox.Center                                # point rotation sub object BoundBox.Center\n                            except Exception:\n                                pointRotation = App.Vector(0.0,0.0,0.0)\n\n        if (pointRotation != \"\") and (valeurAngle != 0):\n            if switch_Create_Point == True:\n                ##https://forum.freecadweb.org/viewtopic.php?f=22&t=69130\n                ctPoint = FreeCADGui.ActiveDocument.ActiveView.getSceneGraph()\n                itemctPoint = coin.SoSeparator()\n                sphere = coin.SoSphere()\n                sphere.radius = 0.5\n                color = coin.SoBaseColor()\n                color.rgb = (1.0, 1.0, 0.0)\n                move = coin.SoTranslation()\n                move.translation.setValue(pointRotation)\n                itemctPoint.addChild(color)\n                itemctPoint.addChild(move)\n                itemctPoint.addChild(sphere)\n                ctPoint.addChild(itemctPoint)\n                switch_Create_Point = False\n                AppConsolePrintMessage(u\"Point of rotation : \" + str(pointRotation) + \"\\n\")\n                self.PB_03_Create_Point.setText(u\"Del Point center\")\n                self.PB_03_Create_Point.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogNoButton))) #\n                self.PB_03_Create_Point.setToolTip(u\"Visualize the point center rotation\" + \"\\n\"\n                                                   u\"If the point is visible the point is include in the image\" + \"\\n\"\n                                                   u\"Actual : x:\" + str(round(pointRotation[0], 2)) + \", y:\" + str(round(pointRotation[1], 2)) + \", z:\" + str(round(pointRotation[2], 2)) + \"\\n\" + \"\\n\"\n                                                   u\"PS: the point can be hidden by an object\")\n            else:\n                switch_Create_Point = True\n                ctPoint.removeChild(itemctPoint)\n                self.PB_03_Create_Point.setText(u\"Point center\")\n                self.PB_03_Create_Point.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogYesButton))) #\n                self.PB_03_Create_Point.setToolTip(u\"Visualize the point center rotation\" + \"\\n\"\n                                                   u\"If the point is visible the point is include in the image\" + \"\\n\"\n                                                   u\"Actual : x:\" + str(u\"0\") + \", y:\" + str(u\"0\") + \", z:\" + str(u\"0\") + \"\\n\" + \"\\n\"\n                                                   u\"PS: the point can be hidden by an object\")\n        else:\n            AppConsolePrintError(u\"Point not availlable in this mode\" + \"\\n\"\n                                 u\"select an object or give an angle or revise your configuration\" + \"\\n\")\n            self.PB_03_Create_Point.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogYesButton))) #\n            self.PB_03_Create_Point.setStyleSheet(\"QPushButton {background-color: white;\\n\"\n                                                  \"border:4px solid rgb(215, 10, 22)};\")  # bord white and green\n            self.PB_03_Create_Point.setToolTip(u\"Point not availlable in this mode\" + \"\\n\"\n                                               u\"Select an object or give an angle or revise your configuration\" + \"\\n\"\n                                               u\"If the point is visible the point is include in the image\" + \"\\n\"\n                                               u\"Actual : x:\" + str(u\"0\") + \", y:\" + str(u\"0\") + \", z:\" + str(u\"0\"))\n            try:\n                switch_Create_Point = True\n                ctPoint.removeChild(itemctPoint)\n            except Exception:\n                None\n\n    def on_SPB_01_Length(self,value):     # \n\n        self.Length = value\n\n    def on_SPB_02_Heigth(self,value):     # \n\n        self.Heigth = value\n\n    def on_radioButton_Config(self):\n\n        if   self.RD_01_400x200.isChecked():#\"400 x 200\"\n            self.Length = 400\n            self.Heigth = 200\n        elif self.RD_02_600x400.isChecked():#\"600 x 400\"\n            self.Length = 600\n            self.Heigth = 400\n        elif self.RD_03_1024x768.isChecked():#\"1024 x 768\"\n            self.Length = 1024\n            self.Heigth = 768\n        elif self.RD_04_320x240.isChecked():#\"320 x 240 (QVGA)\"\n            self.Length = 320\n            self.Heigth = 240\n        elif self.RD_05_320x480.isChecked():#\"320 x 480 (HVGA)\"\n            self.Length = 320\n            self.Heigth = 480\n        elif self.RD_06_400x300.isChecked():#\"400 x 300\"\n            self.Length = 400\n            self.Heigth = 300\n        elif self.RD_07_480x360.isChecked():#\"480 x 360\"\n            self.Length = 480\n            self.Heigth = 360\n        elif self.RD_08_640x480.isChecked():#\"640 x 480 (VGA)\"\n            self.Length = 640\n            self.Heigth = 480\n        elif self.RD_09_768x576.isChecked():#\"768 x 576 (PAL)\"\n            self.Length = 768\n            self.Heigth = 576\n        elif self.RD_10_800x600.isChecked():#\"800 x 600 (SVGA)\"\n            self.Length = 800\n            self.Heigth = 600\n        elif self.RD_11_960x720.isChecked():#\"960 x 720\"\n            self.Length = 960\n            self.Heigth = 720\n        elif self.RD_12_1024x768.isChecked():#\"1024 x 768 (XGA)\"\n            self.Length = 1024\n            self.Heigth = 768\n        elif self.RD_13_1400x600.isChecked():#\"1400x600 (???)\"\n            self.Length = 1400\n            self.Heigth = 600\n        elif self.RD_14_1600x800.isChecked():#\"1600x800 (???)\"\n            self.Length = 1600\n            self.Heigth = 800\n\n        self.SPB_01_Length.setValue(self.Length)\n        self.SPB_02_Heigth.setValue(self.Heigth)\n        AppConsolePrintMessage(u\"Definition : \" + str(self.Length) + \" X \" + str(self.Heigth) + \"\\n\")\n\n    def on_radioButton_FreeCAD(self):\n        global ui\n\n        self.RB_02_Color.setText(u\"Color\")\n        self.PB_02_OriginalBaGr.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")        # origin system\n        self.PB_02_OriginalBaGr.setVisible(False)\n#        self.RB_02_Color.setVisible(True)\n        ui.refreshBackGround()\n\n    def on_radioButton_Color(self):\n        global ui\n\n        self.PB_02_OriginalBaGr.setVisible(True)\n#        self.RB_02_Color.setVisible(False)\n        ui.on_PB_01_Color()\n\n    def on_PB_01_Color(self):\n        global parameterBackground\n        global switchToolBarActived\n        ##https://doc.qt.io/qtforpython/PySide2/QtGui/QColor.html#PySide2.QtGui.PySide2.QtGui.QColor.colorNames\n\n        self.PB_02_OriginalBaGr.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")        # origin system\n        self.window.hide()                                                              # hide the window open color\n#        dummy = self.Color\n\n        color_Dialog   = QtWidgets.QColorDialog()    # PySide2\n        # FreeCAD-Tango\n        #### Dialog line 1\n        color_Dialog.setStandardColor( 0, QtGui.QColor(252, 233,  79 , 0).rgba())    # Butte 1\n        color_Dialog.setStandardColor( 6, QtGui.QColor(237, 212,   0 , 0).rgba())    # Butte 2\n        color_Dialog.setStandardColor(12, QtGui.QColor(196, 160,   0 , 0).rgba())    # Butte 3\n        color_Dialog.setStandardColor(18, QtGui.QColor( 48,  43,   0 , 0).rgba())    # Butte 4\n\n        color_Dialog.setStandardColor(24, QtGui.QColor(138, 226,  52 , 0).rgba())    # Chameleo 1\n        color_Dialog.setStandardColor(30, QtGui.QColor(115, 210,  22 , 0).rgba())    # Chameleo 2\n        color_Dialog.setStandardColor(36, QtGui.QColor( 78, 154,   6 , 0).rgba())    # Chameleo 3\n        color_Dialog.setStandardColor(42, QtGui.QColor( 23,  42,   4 , 0).rgba())    # Chameleo 4\n        #### Dialog line 2\n        color_Dialog.setStandardColor( 1, QtGui.QColor(252, 175,  62 , 0).rgba())    # Orang 1\n        color_Dialog.setStandardColor( 7, QtGui.QColor(245, 121,   0 , 0).rgba())    # Orang 2\n        color_Dialog.setStandardColor(13, QtGui.QColor(206,  92,   0 , 0).rgba())    # Orang 3\n        color_Dialog.setStandardColor(19, QtGui.QColor( 50,  25,   0 , 0).rgba())    # Orang 4\n\n        color_Dialog.setStandardColor(25, QtGui.QColor(114, 159, 207 , 0).rgba())    # Sky Blu 1\n        color_Dialog.setStandardColor(31, QtGui.QColor( 52, 101, 164 , 0).rgba())    # Sky Blu 2\n        color_Dialog.setStandardColor(37, QtGui.QColor( 32,  74, 135 , 0).rgba())    # Sky Blu 3\n        color_Dialog.setStandardColor(43, QtGui.QColor( 11,  21,  33 , 0).rgba())    # Sky Blu 4\n        #### Dialog line 3\n        color_Dialog.setStandardColor( 2, QtGui.QColor(173, 127, 168 , 0).rgba())    # Plu 1\n        color_Dialog.setStandardColor( 8, QtGui.QColor(117,  80, 123 , 0).rgba())    # Plu 2\n        color_Dialog.setStandardColor(14, QtGui.QColor( 92,  53, 102 , 0).rgba())    # Plu 3\n        color_Dialog.setStandardColor(20, QtGui.QColor( 23,  16,  24 , 0).rgba())    # Plu 4\n\n        color_Dialog.setStandardColor(26, QtGui.QColor(233, 185, 110 , 0).rgba())    # Chocolat 1\n        color_Dialog.setStandardColor(32, QtGui.QColor(193, 125,  17 , 0).rgba())    # Chocolat 2\n        color_Dialog.setStandardColor(38, QtGui.QColor(143,  89,   2 , 0).rgba())    # Chocolat 3\n        color_Dialog.setStandardColor(44, QtGui.QColor( 39,  25,   3 , 0).rgba())    # Chocolat 4\n        #### Dialog line 4\n        color_Dialog.setStandardColor( 3, QtGui.QColor(239,  41,  41 , 0).rgba())    # Scarle Re 1\n        color_Dialog.setStandardColor( 9, QtGui.QColor(204,   0,   0 , 0).rgba())    # Scarle Re 2\n        color_Dialog.setStandardColor(15, QtGui.QColor(164,   0,   0 , 0).rgba())    # Scarle Re 3\n        color_Dialog.setStandardColor(21, QtGui.QColor( 40,   0,   0 , 0).rgba())    # Scarle Re 4\n\n        color_Dialog.setStandardColor(27, QtGui.QColor( 52, 224, 226 , 0).rgba())    # FreeTea 1\n        color_Dialog.setStandardColor(33, QtGui.QColor( 22, 208, 210 , 0).rgba())    # FreeTea 2\n        color_Dialog.setStandardColor(39, QtGui.QColor(  6, 152, 154 , 0).rgba())    # FreeTea 3\n        color_Dialog.setStandardColor(45, QtGui.QColor(  4,  42,  42 , 0).rgba())    # FreeTea 4\n        #### Dialog line 5\n        color_Dialog.setStandardColor( 4, QtGui.QColor(255, 255, 255 , 0).rgba())    # Snow White\n\n        color_Dialog.setStandardColor(10, QtGui.QColor(238, 238, 236 , 0).rgba())    # Aluminiu 1\n        color_Dialog.setStandardColor(16, QtGui.QColor(211, 215, 207 , 0).rgba())    # Aluminiu 2\n        color_Dialog.setStandardColor(22, QtGui.QColor(186, 189, 182 , 0).rgba())    # Aluminiu 3\n\n        color_Dialog.setStandardColor(28, QtGui.QColor(136, 138, 133 , 0).rgba())    # Aluminiu 4\n        color_Dialog.setStandardColor(34, QtGui.QColor( 85,  87,  83 , 0).rgba())    # Aluminiu 5\n        color_Dialog.setStandardColor(40, QtGui.QColor( 46,  52,  54 , 0).rgba())    # Aluminiu 6\n\n        color_Dialog.setStandardColor(46, QtGui.QColor(  0,   0,   0 , 0).rgba())    # Je Black\n        #### Dialog line 6\n        color_Dialog.setStandardColor( 5, QtGui.QColor(255, 255, 255 , 0).rgba())    # Snow White\n        color_Dialog.setStandardColor(11, QtGui.QColor(255,   0,   0 , 0).rgba())    # Aluminiu 1\n        color_Dialog.setStandardColor(17, QtGui.QColor(  0, 255,   0 , 0).rgba())    # Aluminiu 2\n        color_Dialog.setStandardColor(23, QtGui.QColor(  0,   0, 255 , 0).rgba())    # Aluminiu 3\n\n        color_Dialog.setStandardColor(29, QtGui.QColor(255, 255,   0 , 0).rgba())    # Aluminiu 4\n        color_Dialog.setStandardColor(35, QtGui.QColor(255,   0, 255 , 0).rgba())    # Aluminiu 5\n        color_Dialog.setStandardColor(41, QtGui.QColor(  0, 255, 255 , 0).rgba())    # Aluminiu 6\n        color_Dialog.setStandardColor(47, QtGui.QColor(  0,   0,   0 , 0).rgba())    # Je Black\n\n        #### Dialog CustomColor\n#        #|Use the Yellow tones for tools that create objects.\n#        color_Dialog.setCustomColor(0, QtGui.QColor( int(\"fc\",16),int(\"e9\",16),int(\"4f\",16) , 0).rgba())\n#        color_Dialog.setCustomColor(2, QtGui.QColor( int(\"ed\",16),int(\"d4\",16),int(\"00\",16) , 0).rgba())\n#        color_Dialog.setCustomColor(4, QtGui.QColor( int(\"c4\",16),int(\"a0\",16),int(\"00\",16) , 0).rgba())\n#        color_Dialog.setCustomColor(6, QtGui.QColor( int(\"30\",16),int(\"2b\",16),int(\"00\",16) , 0).rgba())\n#\n#        #|Use the Blue tones for tools that modify objects\n#        color_Dialog.setCustomColor(8, QtGui.QColor( int(\"72\",16),int(\"9f\",16),int(\"cf\",16) , 0).rgba())\n#        color_Dialog.setCustomColor(10,QtGui.QColor( int(\"34\",16),int(\"65\",16),int(\"a4\",16) , 0).rgba())\n#        color_Dialog.setCustomColor(12,QtGui.QColor( int(\"20\",16),int(\"4a\",16),int(\"87\",16) , 0).rgba())\n#        color_Dialog.setCustomColor(14,QtGui.QColor( int(\"0b\",16),int(\"15\",16),int(\"21\",16) , 0).rgba())\n#\n#        #|Use the Teal tones for view-related tools\n#        color_Dialog.setCustomColor(1, QtGui.QColor( int(\"34\",16),int(\"e0\",16),int(\"e2\",16) , 0).rgba())\n#        color_Dialog.setCustomColor(3, QtGui.QColor( int(\"16\",16),int(\"d0\",16),int(\"d2\",16) , 0).rgba())\n#        color_Dialog.setCustomColor(5, QtGui.QColor( int(\"06\",16),int(\"98\",16),int(\"9a\",16) , 0).rgba())\n#        color_Dialog.setCustomColor(7, QtGui.QColor( int(\"04\",16),int(\"2a\",16),int(\"2a\",16) , 0).rgba())\n#\n#        #|Use the Red tones for Constraint related tools\n#        color_Dialog.setCustomColor(9, QtGui.QColor( int(\"ef\",16),int(\"29\",16),int(\"29\",16) , 0).rgba())\n#        color_Dialog.setCustomColor(11,QtGui.QColor( int(\"cc\",16),int(\"00\",16),int(\"00\",16) , 0).rgba())\n#        color_Dialog.setCustomColor(13,QtGui.QColor( int(\"a4\",16),int(\"00\",16),int(\"00\",16) , 0).rgba())\n#        color_Dialog.setCustomColor(15,QtGui.QColor( int(\"28\",16),int(\"00\",16),int(\"00\",16) , 0).rgba())\n\n        self.Color = color_Dialog.getColor()           # Color.name() extract the color in Hexadecimal (#ad7fa8)\n        \n        if self.Color.isValid():\n            FreeCAD.Console.PrintMessage(u\"Ok Color : \" + str(self.Color.name())+\"\\n\")\n            self.PB_02_OriginalBaGr.setStyleSheet(\"QPushButton {background-color : }\"  + str(self.Color.name()))\n            ## colored the backGround\n            parameterBackground.SetBool(\"Gradient\",False)\n            sorendermanager=Gui.ActiveDocument.ActiveView.getViewer().getSoRenderManager()\n            sorendermanager.setBackgroundColor(coin.SbColor4f(self.Color.redF(), self.Color.greenF(), self.Color.blueF(), self.Color.alphaF()))\n            sorendermanager.activate()\n            sorendermanager.render(True, True)\n#            ## colored the backGround\n            self.Color = self.Color.name()         # self.Color change state to hex #ffffff\n            self.RB_02_Color.setText(u\"Color \" + self.Color)\n        else:\n##            #### for conserve the color but little problem\n##            parameterBackground.SetBool(\"Gradient\",True)\n##            self.Color = dummy\n##            self.PB_02_OriginalBaGr.setStyleSheet(\"QPushButton {background-color : }\"  + str(self.Color))\n##            #self.RB_02_Color.setText(u\"Color \" + self.Color)\n##            dummy = \"\"\n            #### for reset the color\n            parameterBackground.SetBool(\"Gradient\",True)\n            self.Color = \"\"\n            self.RB_02_Color.setText(u\"Color \")\n            self.PB_02_OriginalBaGr.setVisible(False)\n            self.RB_01_Actual.setChecked(True)\n\n        if switchToolBarActived == 0:\n            self.window.show()                                                        # show the window and close color\n#        FreeCAD.Console.PrintMessage(str(u\"on_PB_01_Color \")+\"\\n\")\n\n    def refreshBackGround(self):\n        global parameterBackground\n\n        parameterBackground.SetBool(\"Gradient\",True)\n        mainWindow = FreeCADGui.getMainWindow()\n        mdi = mainWindow.findChild(QtWidgets.QMdiArea)    #PySide2\n        mwActive = mdi.activeSubWindow()\n        mwActive.hide()\n        #mwActive.showMaximized()\n        mwActive.show()\n#        FreeCAD.Console.PrintMessage(str(u\"on_PB_02_OriginalBaGr \")+\"\\n\")\n\n    def on_PB_02_OriginalBaGr(self):\n        global ui\n\n        self.Color = \"\"\n        self.RB_02_Color.setText(u\"Color\")\n        self.PB_02_OriginalBaGr.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")        # origin system\n        self.PB_02_OriginalBaGr.setVisible(False)\n        self.RB_02_Color.setVisible(True)\n        self.RB_01_Actual.setChecked(True)\n        ui.refreshBackGround()\n#        FreeCAD.Console.PrintMessage(str(u\"on_PB_02_OriginalBaGr \")+\"\\n\")\n\n    def on_PB_05_Rotation(self):\n        global ctPoint\n        global itemctPoint\n\n        try: \n            ctPoint.removeChild(itemctPoint)\n        except Exception:\n            None\n\n        if self.groupBox_00_01_00_Rotation.isVisible():\n            self.groupBox_00_00_00_Image.setTitle(u\"Image options\" + \" (Ver rmu : \" +  __version__ + \" : \" + __date__ + \")\")\n            self.PB_05_Rotation.setText(u\"Rotation\")\n            self.PB_05_Rotation.setToolTip(u\"Go to rotation menu\")\n            self.PB_05_Rotation.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\") # origin system\n            self.PB_05_Rotation.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogOkButton))) #\n            MainWindow.setMinimumSize(QtCore.QSize(295, 600)) # sans rotation\n            MainWindow.resize(295, 600)                       # sans rotation\n            self.groupBox_00_01_00_Rotation.setVisible(False)\n            self.PB_03_SaveImage.setEnabled(True)\n            self.PB_03B_Follow.setEnabled(True)\n            self.PB_06_Reduction.setEnabled(True)\n        else:\n            self.groupBox_00_00_00_Image.setTitle(u\"Rotation options\" + \" (Ver rmu : \" +  __version__ + \" : \" + __date__ + \")\")\n            self.PB_05_Rotation.setText(u\"Quit Rotation\")\n            self.PB_05_Rotation.setToolTip(u\"Go to image menu\")\n            self.PB_05_Rotation.setStyleSheet(\"QPushButton {background-color: white; border:2px solid rgb(10, 215, 22)};\")# bord white and green\n            self.PB_05_Rotation.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogCloseButton))) #\n            self.groupBox_00_01_00_Rotation.setVisible(True)\n            self.PB_03_SaveImage.setEnabled(False)\n            self.PB_03B_Follow.setEnabled(False)\n            self.PB_06_Reduction.setEnabled(False)\n            MainWindow.resize(590, 600)                       # avec Rotation\n            #MainWindow.move(1150, 100)                        # move the window macro\n#        FreeCAD.Console.PrintMessage(str(u\"on_PB_05_Rotation \")+\"\\n\")\n\n    def on_PB_06_Reduction(self):    ##https://doc.qt.io/qtforpython/PySide2/QtWidgets/QToolBar.html\n        global ui\n        global switchToolBarActived\n        global switchTitleBoxToolBar\n\n        switchtbar = 0\n        switchToolBarActived = 0\n\n        mw   = FreeCADGui.getMainWindow()\n        tbar = mw.findChildren(QtWidgets.QToolBar)\n        for i in tbar:    # Test if duplicate\n            if i.objectName() == \"ScreenWikiToolBar\":\n                switchtbar = 1\n                i.setVisible(True)\n                AppConsolePrintError(u\"ScreenWikiToolBar is already installed\" + \"\\n\")\n                break\n\n        if switchtbar == 0:\n            switchToolBarActived = 1\n            self.toolbarScreen = QtWidgets.QToolBar()\n            self.toolbarScreen.setObjectName(u\"ScreenWikiToolBar\")\n            self.toolbarScreen.setWindowTitle(u\"ScreenWikiToolBar\")\n            mw.addToolBar(self.toolbarScreen) \n\n            if switchTitleBoxToolBar == 0:\n                self.groupBox_img_02_Format.setTitle(\"\")\n                self.groupBox_img_03_Window.setTitle(\"\")\n                self.groupBox_img_04_BackGround.setTitle(\"\")\n                self.groupBox_img_05_Command.setTitle(\"\")\n\n            #### Command minimise\n            #### Format image D_SpinBox\n            self.toolbarScreen.addWidget(self.groupBox_img_02_Format)\n            self.LAB_01_Length.setVisible(False)\n            self.LAB_02_Heigth.setVisible(False)\n            #### Window\n            self.toolbarScreen.addWidget(self.groupBox_img_03_Window)\n            #### Color\n            self.grid_00_01_04.addWidget(self.RB_01_Actual, 0, 0, 1, 1)\n            self.grid_00_01_04.addWidget(self.RB_03_Transparent, 0, 1, 1, 1)\n            self.grid_00_01_04.addWidget(self.RB_02_Color, 0, 2, 1, 1)\n            self.grid_00_01_04.addWidget(self.PB_02_OriginalBaGr, 0, 3, 1, 1)\n            self.toolbarScreen.addWidget(self.groupBox_img_04_BackGround)\n            #### Command\n            self.grid_00_01_05.addWidget(self.PB_01_SetScreen, 0, 0, 1, 1)\n            self.grid_00_01_05.addWidget(self.PB_02_SetScreenTile, 0, 1, 1, 1)\n            self.grid_00_01_05.addWidget(self.PB_03_SaveImage, 0, 2, 1, 1)\n            self.grid_00_01_05.addWidget(self.PB_03B_Follow, 0, 3, 1, 1)\n            self.PB_03D_Mini.setVisible(True)\n            self.grid_00_01_05.addWidget(self.PB_03C_NewImage, 0, 4, 1, 1)\n            self.grid_00_01_05.addWidget(self.PB_03D_Mini, 0, 5, 1, 1)\n            self.grid_00_01_05.addWidget(self.PB_04_Quit, 0, 6, 1, 1)\n            self.PB_06_Reduction.setVisible(False)\n            self.PB_05_Rotation.setVisible(False)\n            self.toolbarScreen.addWidget(self.groupBox_img_05_Command)\n            ####\n            self.window.hide()                                                   # hide the window and close the macro\n\n    def on_PB_03D_Mini(self):\n        global switchMini\n\n        if switchMini == 0:\n            self.PB_03_SaveImage.setText(u\"\")\n            self.PB_03B_Follow.setText(u\"\")\n            self.PB_03C_NewImage.setText(u\"\")\n            self.PB_03D_Mini.setIcon(QtGui.QIcon(QtGui.QPixmap(miniMaxiIcon))) # miniToolBarIcon icone dans une variable \n            self.PB_03D_Mini.setText(u\"\")\n            self.PB_03D_Mini.setToolTip(u\"Maximize the toolBar\")\n            self.PB_04_Quit.setText(u\"\")\n            #### Format image\n            self.SPB_01_Length.setVisible(False)\n            self.SPB_02_Heigth.setVisible(False)\n            #### Window\n            self.RD_01_MWindow.setVisible(False)\n            self.RD_02_Screen.setVisible(False)\n            #### Color\n            self.RB_01_Actual.setVisible(False)\n            self.RB_03_Transparent.setVisible(False)\n            self.RB_02_Color.setVisible(False)\n            self.PB_02_OriginalBaGr.setVisible(False)\n            #### Command\n            self.PB_01_SetScreen.setVisible(False)\n            self.PB_02_SetScreenTile.setVisible(False)\n            switchMini = 1\n        else:\n            self.PB_03_SaveImage.setText(u\"Save Image\")\n            self.PB_03B_Follow.setText(u\"Follow\")\n            self.PB_03C_NewImage.setText(u\"New Image\")\n            self.PB_03D_Mini.setIcon(QtGui.QIcon(QtGui.QPixmap(miniMaxiIcon))) # miniToolBarIcon icone dans une variable \n            self.PB_03D_Mini.setText(u\"Mini\")\n            self.PB_03D_Mini.setToolTip(u\"Minimize the toolBar\")\n            self.PB_04_Quit.setText(u\"Quit\")\n            #### Format image\n            self.SPB_01_Length.setVisible(True)\n            self.SPB_02_Heigth.setVisible(True)\n            #### Window\n            self.RD_01_MWindow.setVisible(True)\n            self.RD_02_Screen.setVisible(True)\n            #### Color\n            self.RB_01_Actual.setVisible(True)\n            self.RB_03_Transparent.setVisible(True)\n            self.RB_02_Color.setVisible(True)\n            self.PB_02_OriginalBaGr.setVisible(True)\n            #### Command\n            self.PB_01_SetScreen.setVisible(True)\n            self.PB_02_SetScreenTile.setVisible(True)\n            switchMini = 0\n\n    ####Rotation begin#################################################################################\n    def on_RB_02_Object(self):\n        self.groupBox_rot_03_Point.setEnabled(True)\n\n    def on_RB_01_3D_View(self):\n        self.groupBox_rot_03_Point.setEnabled(False)\n        self.PB_Save_Animation.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")            # origin system\n\n    def on_PB_Photo_Rotation_Object_clicked(self):\n        global sel\n        global pathFile\n        global ori_Horizont\n        global ori_Vertical\n        global dim_Horizont\n        global dim_Vertical\n        global originalState\n        global parameterBackground\n        global formatFichier\n        global valeurAngle\n        global axis\n        global delayTime\n        global pathFile\n        global beginRotation\n        global endRotation\n        global switchQFileDialogMint\n        global switchTestRotation\n\n#3DView\n        if self.RB_01_3D_View.isChecked():    #3DView\n            if (valeurAngle != 0):\n#                self.PB_Save_Animation.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")            # origin system\n                dim_Horizont = self.Length\n                dim_Vertical = self.Heigth\n\n#                try:\n#                    0 = sauve fichier   Gui.runCommand('Std_FreezeViews',0)\n#                    1 = charge fichier\n#                    2 = ?\n#                    3 = sauve\n#                    4 = effacer\n#                    5 = ?\n#                    autre restitue la x vue\n#                    Gui.runCommand('Std_FreezeViews',3)    # sauve la vue\n#                except Exception:\n                #### original Camera\n                originalcamera       = FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation()\n                originalPosition     = FreeCADGui.ActiveDocument.ActiveView.getCameraNode().position.getValue().getValue()\n                originalorientation  = originalcamera.Q\n                #### original Camera\n\n                direction = pointRotation = App.Vector(0.0,0.0,0.0)\n                cam = SaveName = Filter = \"\"\n                cam = Gui.ActiveDocument.ActiveView.getCameraNode()\n                try:\n                    sel = FreeCADGui.Selection.getSelection()\n                    if hasattr(sel[0], \"Shape\"):\n                        s = sel[0].Shape\n                    elif hasattr(sel[0], \"Mesh\"):         # upgrade with wmayer thanks #http://forum.freecadweb.org/viewtopic.php?f=13&t=22331\n                        s = sel[0].Mesh\n                    elif hasattr(sel[0], \"Points\"):\n                        s = sel[0].Points\n                \n                    pointRotation = s.BoundBox.Center    # boundbox center of the object\n                    cam.position.setValue(pointRotation) # boundBox edge selected\n                except Exception:\n                    #### pas de selection\n                    #https://forum.freecadweb.org/viewtopic.php?f=22&t=10157\n                    cam = Gui.ActiveDocument.ActiveView.getCameraNode()\n                    position = cam.position.getValue()\n                    orient = cam.orientation.getValue()\n                    focalDistance = cam.focalDistance.getValue()\n                    viewdir = coin.SbVec3f(0, 0, -1)\n                    viewdir = orient.multVec(viewdir)\n                    pointRotation = position + viewdir * focalDistance\n                    pointRotation = pointRotation2 = App.Vector(pointRotation.getValue()[0], pointRotation.getValue()[1], pointRotation.getValue()[2])\n                    ####\n                    None\n\n                if switchTestRotation == False:\n                    SaveName, Filter = PySide2.QtWidgets.QFileDialog.getSaveFileName(None, \"Export a file\",  pathFile, \"Image PNG Portable Network Graphics  (*.png);;\"\n                                                                                                                  \"Image BMP  Windows Bitmap (*.bmp);;\"\n                                                                                                                  \"Icone ICO  (*.ico);;\"\n                                                                                                                  \"Image JPEG Joint Photographic Experts Group (*.jpeg);;\"\n                                                                                                                  \"Image JPG Joint Photographic Experts Group (*.jpg);;\"\n                                                                                                                  \"Image PPM Portable Pixmap (*.ppm);;\"\n                                                                                                                  \"Image TIF Tagged Image File Format (*.tif);;\"\n                                                                                                                  \"Image TIFF Tagged Image File Format (*.tiff);;\"\n                                                                                                                  \"Image XBM X11 Pixmap (*.xbm);;\"\n                                                                                                                  \"Image XPM X11 Pixmap (*.xpm);;\"\n                                                                                                                  \"All files  (*.*);;\")\n\n                    ####  mint\n                    if switchQFileDialogMint == True:   #\n                        Filter = Filter[Filter.find(\".\"):Filter.find(\")\")]\n                        SaveName = SaveName + Filter\n                    ####  mint\n\n                    if SaveName == \"\":\n                        AppConsolePrintMessage(u\"Process aborted\" + \"\\n\")\n                    else:\n                        ####new2\n                        pathFile      = os.path.dirname(SaveName) + \"/\"  #= C:/Provisoire400/\n                        formatFichier = os.path.splitext(SaveName)[1]    #= .png\n                        SaveName      = os.path.splitext(SaveName)[0]    #= /home/kubuntu/.FreeCAD/Macro/Texture_007_H #= C:/Provisoire400/image3D\n                        SaveNameformatFichier = SaveName + formatFichier #= C:/Provisoire400/image3D.png\n                        ####new2\n\n                        AppConsolePrintMessage(u\"Axis            : \" + axis + \"\\n\")\n                        AppConsolePrintMessage(u\"Registration of : \" + pathFile + \"\\n\")\n                        AppConsolePrintMessage(u\"Registration of : \" + formatFichier + \"\\n\")\n                        AppConsolePrintMessage(u\"Registration of : \" + SaveName + \"_Animate_...\" + \"\\n\")\n                        AppConsolePrintMessage(u\"BackgroundColor : \" + str(self.Color) + \"\\n\")\n\n                        fondEcran = \"Current\"\n                        if self.RB_01_Actual.isChecked():\n                            fondEcran = \"Current\"\n                        elif self.RB_02_Color.isChecked():\n                            fondEcran = str(self.Color)\n                        elif self.RB_03_Transparent.isChecked():\n                            fondEcran = \"Transparent\"\n        \n                        AppConsolePrintMessage(u\"BackGround      : \" + fondEcran + \"\\n\")\n                        AppConsolePrintMessage(u\"Image           : \" + str(dim_Horizont) + \"px x \" + str(dim_Vertical) + \"px\" + \"\\n\")\n                        AppConsolePrintMessage(u\"_________________________________________\" + \"\\n\")\n\n                if (valeurAngle != 0):\n                    activeView = FreeCADGui.activeDocument().activeView()\n    \n                    fileCount = 0\n                    compensation = 0\n\n                    if ((beginRotation - endRotation) / valeurAngle) % valeurAngle != 0:\n                        compensation = valeurAngle\n    \n                    if beginRotation > endRotation:\n                        beginRotation, endRotation = endRotation, beginRotation\n\n                    try:\n                        sel = FreeCADGui.Selection.getSelection()\n                        if hasattr(sel[0], \"Shape\"):\n                            objectRotation         = Gui.Selection.getSelection()[0]                          # object of rotation\n                            objectPlacementOrigine = objectRotation.Placement                                 # object Placement Origine\n                            objectPlacementBase    = objectRotation.Placement.Base                            # object Placement Base\n                            \n                            try:\n                                selectedEdge = FreeCADGui.Selection.getSelectionEx()[1].SubObjects[0]         # select one element and axis second object (2 selections)\n                            except Exception:\n                                try:\n                                    selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[1]     # select one element and axis same object   (2 selections)\n                                except Exception:\n                                    try:\n                                        selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0] # select one element and axis same object   (1 selection)\n                                    except Exception:\n                                        None\n                            \n                            #### section point rotation\n                            if self.RB_01_CenterObject.isChecked():# and (axis != \"D\"):\n                                pointRotation = objectRotation.Shape.BoundBox.Center                       # point rotation single object BoundBox.Center\n                            else:\n                                pointRotation = selectedEdge.BoundBox.Center                               # point rotation sub object BoundBox.Center\n                    except Exception:\n                        pointRotation = pointRotation2\n\n                    ## section choice axis or Direction\n                    if   axis == \"X\":\n                        direction = App.Vector(1.0,0.0,0.0)\n                    elif axis == \"Y\":\n                        direction = App.Vector(0.0,1.0,0.0)\n                    elif axis == \"Z\":\n                        direction = App.Vector(0.0,0.0,1.0)\n                    elif axis == \"D\":                        # Direction\n                        try:\n                            direction = selectedEdge.Vertexes[1].Point.sub(selectedEdge.Vertexes[0].Point)# search the direction line or sub\n                        except Exception:\n                            try:\n                                direction = objectRotation.Vertexes[0].Point\n                            except Exception:\n                                direction = App.Vector(0.0,0.0,0.0)\n\n                    cam = Gui.ActiveDocument.ActiveView.getCameraNode()\n                    #### new\n                    beginRotationTr = beginRotation * float(\"1e\" + str(degreesNumberDecimal))\n                    endRotationTr = endRotation * float(\"1e\" + str(degreesNumberDecimal))\n                    compensationTr = compensation * float(\"1e\" + str(degreesNumberDecimal))\n                    valeurAngleTr = valeurAngle * float(\"1e\" + str(degreesNumberDecimal))\n                    #### new\n                    if self.CB_01_Reverse.isChecked():\n                        angleRotation = (- valeurAngle)\n                    else:\n                        angleRotation = valeurAngle\n\n                    for i in range(int(beginRotationTr), int(endRotationTr) + int(compensationTr), int(valeurAngleTr)):\n                        fileCount += 1\n                        #### \n                        if (switchTestRotation == False) and (SaveName != \"\"):\n                            deg = (u\"000000\" + str(i))[:-degreesNumberDecimal][-3:] + \"-\" + (u\"0000000000\" + str(i))[-degreesNumberDecimal:]   #i = 2694000 to deg = 269-4000\n                            strfileCount = (u\"0000000000\" + str(fileCount))[-len(str(numberPhoto)):]\n                            fileName = SaveName + \"_Animate_\" + strfileCount + \"_\" + axis + \"_\" + deg + \"_\" + fondEcran + formatFichier # create complete name\n                            activeView.saveImage(fileName, dim_Horizont, dim_Vertical, fondEcran)\n                        #### \n                        cam.position.setValue(FreeCAD.Vector(pointRotation))     # centre rotation\n                        cam = Gui.ActiveDocument.ActiveView.getCameraNode()\n                        rot = coin.SbRotation()\n                        rot.setValue(coin.SbVec3f(direction[0],direction[1],direction[2]),math.radians(angleRotation))\n                        nrot = cam.orientation.getValue() * rot\n                        cam.orientation = nrot\n                        #### \n                        Gui.updateGui()                                             # rafraichi l'ecran\n                        ####\n                        try:\n                            self.DSPB_01_Delay_Time.setSuffix(u\" Delay second (image \" + str(fileCount) + \"/\" + str(numberPhoto) + \") (\" + str(i / float(\"1e\" + str(degreesNumberDecimal))) + \" deg.)\")\n                            time.sleep(delayTime)\n                        except Exception: None\n                        ####\n\n                    if self.CB_02_Original_Position.isChecked():\n                            #### restore Camera\n                            originalcamera = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()\n                            originalcamera.position.setValue(originalPosition)\n                            originalcamera.orientation.setValue(float(originalorientation[0]), float(originalorientation[1]), float(originalorientation[2]), float(originalorientation[3]))\n                            #### restore Camera\n\n            else:\n                AppConsolePrintError(u\"Give one angle value\" + \"\\n\")\n                self.SPB_01_Angle_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: white;\\n\"\n                                                         \"border:2px solid rgb(215, 10, 22)};\")  # bord white and green\n            self.DSPB_01_Delay_Time.setSuffix(u\" Delay second\")\n            switchTestRotation = False\n# Object selected\n        elif self.RB_02_Object.isChecked():        # Object selected\n            try:\n                sel = FreeCADGui.Selection.getSelection()\n                if len(sel) != 0:\n                    dim_Horizont = self.Length\n                    dim_Vertical = self.Heigth\n\n                    if hasattr(sel[0], \"Shape\"):\n                        s = sel[0].Shape\n                    elif hasattr(sel[0], \"Mesh\"):      # upgrade with wmayer thanks #http://forum.freecadweb.org/viewtopic.php?f=13&t=22331\n                        s = sel[0].Mesh\n                    elif hasattr(sel[0], \"Points\"):\n                        s = sel[0].Points\n\n                    centreRotation = s.BoundBox.Center # boundbox center of the object\n\n                    if (valeurAngle != 0):\n                        if switchTestRotation == False:\n                            SaveName, Filter = PySide2.QtWidgets.QFileDialog.getSaveFileName(None, \"Export a file\",  pathFile, \"Image PNG Portable Network Graphics  (*.png);;\"\n                                                                                                                          \"Image BMP  Windows Bitmap (*.bmp);;\"\n                                                                                                                          \"Icone ICO  (*.ico);;\"\n                                                                                                                          \"Image JPEG Joint Photographic Experts Group (*.jpeg);;\"\n                                                                                                                          \"Image JPG Joint Photographic Experts Group (*.jpg);;\"\n                                                                                                                          \"Image PPM Portable Pixmap (*.ppm);;\"\n                                                                                                                          \"Image TIF Tagged Image File Format (*.tif);;\"\n                                                                                                                          \"Image TIFF Tagged Image File Format (*.tiff);;\"\n                                                                                                                          \"Image XBM X11 Pixmap (*.xbm);;\"\n                                                                                                                          \"Image XPM X11 Pixmap (*.xpm);;\"\n                                                                                                                          \"All files  (*.*);;\")\n\n                            ####  mint\n                            if switchQFileDialogMint == True:   #\n                                Filter = Filter[Filter.find(u\".\"):Filter.find(\")\")]\n                                SaveName = SaveName + Filter\n                            ####  mint\n\n                            if SaveName == \"\":\n                                AppConsolePrintMessage(u\"Process aborted\" + \"\\n\")\n                            else:\n                                originlPlacement = sel[0].Placement\n\n                                ####new2\n                                pathFile      = os.path.dirname(SaveName) + \"/\"  #= C:/Provisoire400/\n                                formatFichier = os.path.splitext(SaveName)[1]    #= .png\n                                SaveName      = os.path.splitext(SaveName)[0]    #= /home/kubuntu/.FreeCAD/Macro/Texture_007_H #= C:/Provisoire400/image3D\n                                SaveNameformatFichier = SaveName + formatFichier #= C:/Provisoire400/image3D.png\n                                ####new2\n\n                                AppConsolePrintMessage(u\"Axis            : \" + axis + \"\\n\")\n                                AppConsolePrintMessage(u\"Registration of : \" + pathFile + \"\\n\")\n                                AppConsolePrintMessage(u\"Registration of : \" + formatFichier + \"\\n\")\n                                AppConsolePrintMessage(u\"Registration of : \" + SaveName + \"_Animate_...\" + \"\\n\")\n                                AppConsolePrintMessage(u\"Image           : \" + str(dim_Horizont) + \"px x \" + str(dim_Vertical) + \"px\" + \"\\n\")\n\n                                fondEcran = \"Current\"\n                                if self.RB_01_Actual.isChecked():\n                                    fondEcran = \"Current\"\n                                elif self.RB_02_Color.isChecked():\n                                    fondEcran = str(self.Color)\n                                elif self.RB_03_Transparent.isChecked():\n                                    fondEcran = \"Transparent\"\n                \n                                AppConsolePrintMessage(u\"BackGround      : \" + fondEcran + \"\\n\")\n                                AppConsolePrintMessage(u\"_________________________________________\" + \"\\n\")\n                        if (valeurAngle != 0):\n                            activeView = FreeCADGui.activeDocument().activeView()\n            \n                            fileCount = 0\n                            compensation = 0\n\n                            if ((beginRotation - endRotation) / valeurAngle) % abs(valeurAngle) != 0:\n                                compensation = valeurAngle\n            \n                            if beginRotation > endRotation:\n                                beginRotation, endRotation = endRotation, beginRotation\n\n                            sel = FreeCADGui.Selection.getSelection()\n                            if hasattr(sel[0], \"Shape\"):\n                                objectRotation         = Gui.Selection.getSelection()[0]                          # object of rotation\n                                objectPlacementOrigine = objectRotation.Placement                                 # object Placement Origine\n                                objectPlacementBase    = objectRotation.Placement.Base                            # object Placement Base\n                                \n                                try:\n                                    selectedEdge = FreeCADGui.Selection.getSelectionEx()[1].SubObjects[0]         # select one element and axis second object (2 selections)\n                                except Exception:\n                                    try:\n                                        selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[1]     # select one element and axis same object   (2 selections)\n                                    except Exception:\n                                        try:\n                                            selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0] # select one element and axis same object   (1 selection)\n                                        except Exception:\n                                            None\n                                \n                                #### section point rotation\n                                if self.RB_01_CenterObject.isChecked():# and (axis != \"D\"):\n                                    pointRotation = objectRotation.Shape.BoundBox.Center                       # point rotation single object BoundBox.Center\n                                else:\n                                    pointRotation = selectedEdge.BoundBox.Center                               # point rotation sub object BoundBox.Center\n                               \n                                ## section choice axis or Direction\n                                if   axis == \"X\":\n                                    direction = App.Vector(1.0,0.0,0.0)\n                                elif axis == \"Y\":\n                                    direction = App.Vector(0.0,1.0,0.0)\n                                elif axis == \"Z\":\n                                    direction = App.Vector(0.0,0.0,1.0)\n                                elif axis == \"D\":                        # Direction\n                                    try:\n                                        direction = selectedEdge.Vertexes[1].Point.sub(selectedEdge.Vertexes[0].Point)# search the direction line or sub\n                                    except Exception:\n                                        try:\n                                            direction = objectRotation.Vertexes[0].Point\n                                        except Exception:\n                                            direction = App.Vector(0.0,0.0,0.0)\n\n                                #### new\n                                beginRotationTr = beginRotation * float(\"1e\" + str(degreesNumberDecimal))\n                                endRotationTr = endRotation * float(\"1e\" + str(degreesNumberDecimal))\n                                compensationTr = compensation * float(\"1e\" + str(degreesNumberDecimal))\n                                valeurAngleTr = valeurAngle * float(\"1e\" + str(degreesNumberDecimal))\n                                #### new\n\n                                for i in range(int(beginRotationTr), int(endRotationTr) + int(compensationTr), int(valeurAngleTr)):\n                                    angleRotation = 0.0\n                                    angleRotation = i / float(\"1e\" + str(degreesNumberDecimal))\n                                    if self.CB_01_Reverse.isChecked():\n                                        angleRotation = -angleRotation\n                                    objectRotation.Placement = App.Placement(App.Vector(0.0,0.0,0.0), App.Rotation(direction, angleRotation), App.Vector(pointRotation)).multiply(objectPlacementOrigine) # other method\n\n                                    Gui.updateGui()                                             # rafraichi l'ecran\n                                    fileCount += 1\n                                    if switchTestRotation == False:\n                                        #### \n                                        deg = (u\"000000\" + str(i))[:-degreesNumberDecimal][-3:] + \"-\" + (u\"0000000000\" + str(i))[-degreesNumberDecimal:]   #i = 2694000 to deg = 269-4000\n                                        strfileCount = (u\"0000000000\" + str(fileCount))[-len(str(numberPhoto)):]\n                                        fileName = SaveName + \"_Animate_\" + strfileCount + \"_\" + axis + \"_\" + deg + \"_\" + fondEcran + formatFichier # create complete name\n                                        activeView.saveImage(fileName, dim_Horizont, dim_Vertical, fondEcran)\n                                        ####\n\n                                    try:\n                                        #self.DSPB_01_Delay_Time.setSuffix(u\" Delay second (image \" + str(fileCount) + \"/\" + str(numberPhoto) + \")\")\n                                        self.DSPB_01_Delay_Time.setSuffix(u\" Delay second (image \" + str(fileCount) + \"/\" + str(numberPhoto) + \") (\" + str(i / float(\"1e\" + str(degreesNumberDecimal))) + \" deg.)\")\n                                        time.sleep(delayTime)\n                                    except Exception: None\n                                switchTestRotation = False\n                                if self.CB_02_Original_Position.isChecked():\n                                    objectRotation.Placement = objectPlacementOrigine           # return in original position\n                        \n                            elif (hasattr(sel[0], \"Mesh\")) or (hasattr(sel[0], \"Points\")):      # upgrade with wmayer thanks #http://forum.freecadweb.org/viewtopic.php?f=13&t=22331\n                                if hasattr(sel[0], \"Mesh\"):\n                                    s = sel[0].Mesh \n                                    #print(\"Mesh\")\n                                else:\n                                    s = sel[0].Points\n                                    #print(\"Points\")\n                                objectRotation = sel[0]\n                                pointRotation = s.BoundBox.Center                                # boundbox center of the object\n                                objectPlacementOrigine = s.Placement                             # object Placement Origine\n                                fileCount = 0\n                                activeView = FreeCADGui.activeDocument().activeView()\n                                compensation = 1\n                        \n                                #### section point rotation\n                                if self.RB_01_CenterObject.isChecked():# and (axis != \"D\"):\n                                    pointRotation = s.BoundBox.Center                            # point rotation single object BoundBox.Center\n                                else:\n                                    try:\n                                        selectedEdge = FreeCADGui.Selection.getSelectionEx()[1].SubObjects[0]       # select one element and axis second object (2 selections)\n                                        pointRotation = selectedEdge.BoundBox.Center                                # point rotation sub object BoundBox.Center\n                                    except Exception:\n                                        pointRotation = App.Vector(0.0,0.0,0.0)\n                        \n                                ## section choice axis or Direction\n                                if   axis == \"X\":\n                                    direction = App.Vector(1.0,0.0,0.0)\n                                elif axis == \"Y\":\n                                    direction = App.Vector(0.0,1.0,0.0)\n                                elif axis == \"Z\":\n                                    direction = App.Vector(0.0,0.0,1.0)\n                                elif axis == \"D\":                        # Direction\n                                    try:\n                                        selectedEdge = FreeCADGui.Selection.getSelectionEx()[1].SubObjects[0]         # select one element and axis second object (2 selections)\n                                        direction = selectedEdge.Vertexes[1].Point.sub(selectedEdge.Vertexes[0].Point)# search the direction line or sub\n                                    except Exception:\n                                        try:\n                                            direction = objectRotation.Vertexes[0].Point\n                                        except Exception:\n                                            direction = App.Vector(0.0,0.0,0.0)\n                        \n                                #### new\n                                beginRotationTr = beginRotation * float(\"1e\" + str(degreesNumberDecimal))\n                                endRotationTr = endRotation * float(\"1e\" + str(degreesNumberDecimal))\n                                compensationTr = compensation * float(\"1e\" + str(degreesNumberDecimal))\n                                valeurAngleTr = valeurAngle * float(\"1e\" + str(degreesNumberDecimal))\n                                #### new\n\n                                for i in range(int(beginRotationTr), int(endRotationTr) + int(compensationTr), int(valeurAngleTr)):\n                                    angleRotation = 0.0\n                                    angleRotation = i / float(\"1e\" + str(degreesNumberDecimal))\n                                    if self.CB_01_Reverse.isChecked():\n                                        angleRotation = -angleRotation\n                                    objectRotation.Placement = App.Placement(App.Vector(0,0,0), App.Rotation(direction, angleRotation), App.Vector(pointRotation)).multiply(objectPlacementOrigine)\n\n                                    Gui.updateGui()\n                                    fileCount += 1\n                                    if switchTestRotation == False:\n                                        #### \n                                        deg = (u\"000000\" + str(i))[:-degreesNumberDecimal][-3:] + \"-\" + (u\"0000000000\" + str(i))[-degreesNumberDecimal:]   #i = 2694000 to deg = 269-4000\n                                        strfileCount = (u\"0000000000\" + str(fileCount))[-len(str(numberPhoto)):]\n                                        fileName = SaveName + \"_Animate_\" + strfileCount + \"_\" + Axis + \"_\" + deg + \"_\" + fondEcran + formatFichier # create complete name\n                                        activeView.saveImage(fileName, dim_Horizont, dim_Vertical, fondEcran)\n                                        ####\n\n                                    try:\n                                        #self.DSPB_01_Delay_Time.setSuffix(u\" Delay second (image \" + str(fileCount) + \"/\" + str(numberPhoto) + \")\")\n                                        self.DSPB_01_Delay_Time.setSuffix(u\" Delay second (image \" + str(fileCount) + \"/\" + str(numberPhoto) + \") (\" + str(i / float(\"1e\" + str(degreesNumberDecimal))) + \" deg.)\")\n                                        time.sleep(delayTime)\n                                    except Exception: None\n                        \n                                switchTestRotation = False\n                                if self.CB_02_Original_Position.isChecked():\n                                    objectRotation.Placement = objectPlacementOrigine    # return in original position\n                            App.activeDocument().recompute()\n                        self.DSPB_01_Delay_Time.setSuffix(u\" Delay second\")\n                    else:\n                        AppConsolePrintError(u\"Give one angle value\" + \"\\n\")\n                        self.SPB_01_Angle_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: white;\\n\"\n                                                                 \"border:2px solid rgb(215, 10, 22)};\")  # bord white and green\n                else:\n                    self.PB_Save_Animation.setStyleSheet(\"QPushButton {background-color: white;\\n\"\n                                                         \"border:2px solid rgb(215, 10, 22)};\")              # bord white and green\n                    if len(sel) == 0:\n                        self.PB_Save_Animation.setText(u\"Save the animation (select on object)\")\n                    if (valeurAngle == 0):\n                        self.PB_Save_Animation.setText(u\"Save the animation (select on angle value)\")\n                    AppConsolePrintError(u\"\\n\" + \" Select one object : \" + \"\\n\"\n                                         u\" Select the axis rotaion, X, Y, Z or D \" + \"\\n\"\n                                         u\" Give the angle rotation \" + \"\\n\"\n                                         u\" Mode (D)irection, Select First the object to rotate, second the axis \" + \"\\n\"\n                                         u\" (or check the '3D View' button) \" + \"\\n\" + \"\\n\")\n\n            except Exception:\n                AppConsolePrintError(u\"Give one angle value !\" + \"\\n\" + \"\\n\")\n                self.SPB_01_Angle_Rotation.setStyleSheet(\"QDoubleSpinBox {background-color: white;\\n\"\n                                                         \"border:2px solid rgb(215, 10, 22)};\")              # bord white and green\n    \n    ####Rotation end#######################################################################################\n\n    def on_PB_03_SaveImage(self):\n        global pathFile\n        global pos_X_Window   # Position begin X window\n        global pos_Y_Window   # Position begin Y window\n        global counterName  \n        global switchFollow\n        global SaveName\n        global SaveNameMemo\n        global neutralImage\n        global switchQFileDialogMint\n\n        #SaveName, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, \"Export a file\",  pathFile, \"All files  (*.*);;\")\n        if switchFollow == 0:\n            SaveName, Filter = PySide2.QtWidgets.QFileDialog.getSaveFileName(None, \"Export a file\",  pathFile, \"Image PNG Portable Network Graphics  (*.png);;\"\n                                                                                                          \"Image BMP  Windows Bitmap (*.bmp);;\"\n                                                                                                          \"Icone ICO  (*.ico);;\"\n                                                                                                          \"Image JPEG Joint Photographic Experts Group (*.jpeg);;\"\n                                                                                                          \"Image JPG Joint Photographic Experts Group (*.jpg);;\"\n                                                                                                          \"Image PPM Portable Pixmap (*.ppm);;\"\n                                                                                                          \"Image TIF Tagged Image File Format (*.tif);;\"\n                                                                                                          \"Image TIFF Tagged Image File Format (*.tiff);;\"\n                                                                                                          \"Image XBM X11 Pixmap (*.xbm);;\"\n                                                                                                          \"Image XPM X11 Pixmap (*.xpm);;\"\n                                                                                                          \"All files  (*.*);;\")\n\n            ####  mint\n            if switchQFileDialogMint == True:   #\n                Filter = Filter[Filter.find(u\".\"):Filter.find(\")\")]\n                SaveName = SaveName + Filter\n            ####  mint\n\n            if neutralImage == 0:\n                counterName = 0\n                self.PB_03B_Follow.setEnabled(False)\n                self.PB_03B_Follow.setText(u\"Follow\")\n                SaveNameMemo = SaveName\n\n        switchFollow = 0\n        \n        if SaveName == \"\":\n            AppConsolePrintMessage(u\"Process aborted\"+\"\\n\")\n        else:\n            if neutralImage == 1:\n                SaveNamefileCount = SaveName\n                neutralImage = 0\n            else:\n                #### insert the numer image betwen name and extension\n                fileCount = \"_\" + '%03d' % (counterName)\n                SaveName = SaveNameMemo\n                dummy = SaveName.split('.')\n                SaveNamefileCount = dummy[0] + fileCount + \".\" + dummy[1]\n                self.PB_03B_Follow.setEnabled(True)\n                self.PB_03B_Follow.setText(u\"Follow (\" + str(counterName + 1) + \")\")                      # WL\n                ####\n                AppConsolePrintMessage(u\"Registration of ( \" + SaveNamefileCount + \" )\" + \"\\n\")\n\n            if self.RD_02_Screen.isChecked():\n                try:\n                    #file = open(SaveNamefileCount, 'w')\n                    try:\n                        if (self.RB_01_Actual.isChecked()):\n                            Gui.activeDocument().activeView().saveImage(SaveNamefileCount, self.Length, self.Heigth,\"Current\")\n                            AppConsolePrintMessage(u\"BackGround Current\" + \"\\n\")\n                        elif self.RB_02_Color.isChecked():\n                            Gui.activeDocument().activeView().saveImage(SaveNamefileCount, self.Length, self.Heigth, str(self.Color))\n                            AppConsolePrintMessage(u\"BackGround \" + self.Color + \"\\n\")\n                        elif (self.RB_03_Transparent.isChecked()):\n                            Gui.activeDocument().activeView().saveImage(SaveNamefileCount, self.Length, self.Heigth, \"Transparent\")\n                            AppConsolePrintMessage(u\"BackGround Transparent\" + \"\\n\")\n                        AppConsolePrintMessage(u\"Saved definition : \" + str(self.Length) + \" \" + str(self.Heigth) + \"\\n\")\n                        AppConsolePrintMessage(u\"File Name        : \" + SaveNamefileCount + \"\\n\")\n                    except Exception:\n                        AppConsolePrintError(u\"Error write file \"+\"\\n\")\n\n                    #finally:\n                    #    file.close()\n\n                    #self.PB_03B_Follow.setEnabled(True)\n                    AppConsolePrintMessage(u\"__________________________\"+\"\\n\")\n                    pathFile = str(os.path.dirname(SaveNamefileCount))\n                except Exception:\n                    AppConsolePrintError(u\"Error Open file \" + SaveNamefileCount + \"\\n\")\n            else:\n                try:\n#################### fonctionne mais l'ecran 3D est noir ( screenShot window ) ########\n##                    mainWindow = FreeCADGui.getMainWindow()\n##                    screenShot = QtGui.QPixmap(mainWindow.size())\n##                    mainWindow.render(screenShot)\n##                    pix.save(SaveName)\n#######################################################################################\n                    mainWindow = FreeCADGui.getMainWindow()\n                    AppConsolePrintMessage(u\"Real window saved \" + str(mainWindow.geometry()) + \"\\n\")\n                    mainWindowCoinSupX = mainWindow.geometry().x()\n                    mainWindowCoinSupY = mainWindow.geometry().y()\n                    mainWindowWidth    = mainWindow.geometry().width()\n                    mainWindowHeight   = mainWindow.geometry().height()\n                    QPixmap.grabWindow(QApplication.desktop().winId(), mainWindowCoinSupX + pos_X_Window, mainWindowCoinSupY + pos_Y_Window, mainWindowWidth, mainWindowHeight).save(SaveNamefileCount, \"\")\n                except Exception:\n                    try:\n                        AppConsolePrintError(u\"Error Open file \" + SaveName + fileCount + \"\\n\")\n                    except Exception:\n                        None\n\n    def on_PB_03B_Follow(self):\n        global ui\n        global counterName\n        global switchFollow\n\n        switchFollow = 1\n        counterName += 1\n        ui.on_PB_03_SaveImage()        \n\n    def on_PB_03C_New(self):\n        global neutralImage\n\n        neutralImage = 1\n        ui.on_PB_03_SaveImage()        \n\n    def on_PB_01_SetScreen(self):\n        global pos_X_Window\n        global pos_Y_Window\n        global switchMainWindow\n        global pos_X_Tile_Window\n        global pos_Y_Tile_Window\n        global ecranCompletX\n        global ecranCompletY\n\n        mainWindow = FreeCADGui.getMainWindow()\n        mdi = mainWindow.findChild(QtWidgets.QMdiArea)\n        mwActive = mdi.activeSubWindow()\n        \n        pos_X_Tile_Window = mwActive.frameGeometry().x()\n        pos_Y_Tile_Window = mwActive.frameGeometry().y()\n\n        mwActive.hide()\n        mwActive.showMaximized()\n        mwActive.show()\n\n        if self.RD_02_Screen.isChecked():\n            if (switchMainWindow == 1):\n                switchMainWindow = 0\n                mainWindow.restoreGeometry(originalState.value(\"geometry\"))\n                mainWindow.restoreState(originalState.value(\"state\"))\n                mainWindow.showNormal()\n            mwActive.setGeometry(pos_X_Tile_Window + pos_X_Window, pos_Y_Tile_Window + pos_Y_Window, self.Length, self.Heigth)        # sur fenetre de travail 3D\n        else:\n            mainWindow.setGeometry(((ecranCompletX - self.Length) / 2) + pos_X_Window, ((ecranCompletY - self.Heigth) / 2) + pos_Y_Window, self.Length, self.Heigth)  # sur fenetre FreeCAD\n            switchMainWindow = 1\n\n    def on_PB_02_SetScreenTile(self):\n        global pos_X_Window\n        global pos_Y_Window\n        global switchMainWindow\n        global pos_X_Tile_Window\n        global pos_Y_Tile_Window\n        global ecranCompletX\n        global ecranCompletY\n        global originalState\n        global pathFile\n\n        mainWindow = FreeCADGui.getMainWindow()\n        mdi = mainWindow.findChild(QtWidgets.QMdiArea)\n        mwActive = mdi.activeSubWindow()\n        mdi.tileSubWindows()    #### encadre la fenetre\n        \n        if self.RD_02_Screen.isChecked():\n            if (switchMainWindow == 1):\n                switchMainWindow = 0\n                mainWindow.restoreGeometry(originalState.value(\"geometry\"))\n                mainWindow.restoreState(originalState.value(\"state\"))\n                mainWindow.showNormal()\n            mwActive.setGeometry(pos_X_Tile_Window + pos_X_Window, pos_Y_Tile_Window + pos_Y_Window, self.Length, self.Heigth)        # sur fenetre de travail 3D\n        else:\n            mainWindow.setGeometry(((ecranCompletX - self.Length) / 2) + pos_X_Window, ((ecranCompletY - self.Heigth) / 2) + pos_Y_Window, self.Length, self.Heigth)  # sur fenetre FreeCAD\n            switchMainWindow = 1\n\n    def on_PB_04_Quit(self):\n        global originalState\n        global parameterBackground\n        global so\n        global pathFile        \n        global switchToolBarActived\n        global switchTitleBoxToolBar\n        global switchQFileDialogMint\n        global ctPoint\n        global itemctPoint\n\n        #### Config ####\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchTitleBoxToolBar\", switchTitleBoxToolBar)# True or False\n        if self.RD_01_MWindow.isChecked():\n            FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switch_RD_01_MWindow\", True)     # True or False\n        else:\n            FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switch_RD_01_MWindow\", False)    # True or False\n        if self.RD_02_Screen.isChecked():\n            FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switch_RD_02_Screen\", True)      # True or False\n        else:\n            FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switch_RD_02_Screen\", False)     # True or False\n        if self.RB_01_Actual.isChecked():\n            FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switch_RB_01_Actual\", True)      # True or False\n        else:\n            FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switch_RB_01_Actual\", False)     # True or False\n\n        if self.RB_03_Transparent.isChecked():\n            FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switch_RB_03_Transparent\", True) # True or False\n        else:\n            FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switch_RB_03_Transparent\", False)# True or False\n\n        if self.RB_02_Color.isChecked():\n            FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switch_RB_02_Color\", True)       # True or False\n            FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"setColorUser\", self.Color)     # \n        else:\n            FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switch_RB_02_Color\", False)      # True or False\n\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"setLastPath\", pathFile)            # pathFile\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"setLengthImage\", self.Length)         # Length X\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"setHeigthImage\", self.Heigth)         # Heigth Y\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchQFileDialogMint\", switchQFileDialogMint) # True or False\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"degreesNumberDecimal\", degreesNumberDecimal)    # degreesNumberDecimal\n        #### Config ####\n\n        try: \n            ctPoint.removeChild(itemctPoint)\n        except Exception:\n            None\n\n        try:\n            FreeCADGui.Selection.removeObserver(so)   # Uninstalls resident function (desactivated for read after LeftDock RightDock)\n            parameterBackground.SetBool(\"Gradient\",True)\n            mainWindow = FreeCADGui.getMainWindow()\n            mainWindow.restoreGeometry(originalState.value(\"geometry\"))\n            #mainWindow.restoreState(originalState.value(\"state\"))\n            mainWindow.restoreState(originalState.value(\"windowState\"))\n            mainWindow.showNormal()\n    \n            mdi = mainWindow.findChild(QtWidgets.QMdiArea)\n            mwActive = mdi.activeSubWindow()\n            mwActive.showNormal()\n            mwActive.showMaximized()\n            self.window.hide()                                                   # hide the window and close the macro\n            #self.window.close()\n        except Exception:\n            None\n\n        if switchToolBarActived == 1:\n            try:\n                self.toolbarScreen.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)    # destroy\n                self.toolbarScreen.deleteLater()                                     # destroy\n                self.toolbarScreen.destroy()                                         # destroy\n            except Exception:\n                None\n        \n        AppConsolePrintMessage(\"___Screen_Wiki end__________ \" + \"\\n\\n\")\n\nclass SelObserver:\n    def addSelection(self,document, object, element, position):  # Selection\n        global sel\n        global ui\n\n        sel = FreeCADGui.Selection.getSelection()\n\n        ui.PB_Save_Animation.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")        # origin system\n        ui.PB_Save_Animation.setText(u\"Save the animation\")\n        ui.PB_03_Create_Point.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")        # origin system\n\n        if len(sel)!= 0:\n            ui.groupBox_rot_03_Point.setEnabled(True)\n        else:\n            ui.groupBox_rot_03_Point.setEnabled(False)\n#            ui.PB_Save_Animation.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")        # origin system\n#        else:\n#            ui.on_pushButton_Raf_clicked()\n        #####################################################################################\n\n### debut test QWidget, QDockWidget, QToolBar ##################################################\nmw = FreeCADGui.getMainWindow()\nswitchRunning = 0\nww = mw.findChildren(QtWidgets.QWidget)        # pour QWidget\nfor i in ww:\n    if (str(i.objectName()) == __title__):\n        switchRunning = 1\n        i.setVisible(True)                     # visible True\n        break\n####\ndw = mw.findChildren(QtWidgets.QDockWidget)    # pour QtWidgets Docked et pas les Flotants\nfor i in dw:\n    if (str(i.objectName()) == __title__):\n        switchRunning = 1\n        i.setVisible(True)                     # visible True\n        AppConsolePrintError(__title__ + \" is already open\" + \"\\n\")\n        break\n####\nswitchtbar = 0\ntb = mw.findChildren(QtWidgets.QToolBar)\nfor i in tb:\n    if (str(i.objectName()) == \"ScreenWikiToolBar\"):\n        switchRunning = 1\n        switchtbar = 1\n        i.setVisible(True)                     # visible True\n        AppConsolePrintError(u\"ScreenWikiToolBar is already open\" + \"\\n\")\n        i.setStyleSheet(\"background-color: #ff0000;\")        # white red bold\n        Gui.updateGui()                                      # rafraichi l'ecran\n        try:\n            time.sleep(0.05)\n        except Exception: None\n        i.setStyleSheet(\"background-color: QPalette.Base\")   # origin system\n        break\n### fin test QWidget, QDockWidget, QToolBar ####################################################\n\nif (switchRunning == 1) or (switchtbar == 1):\n    None\nelse:\n    sel = FreeCADGui.Selection.getSelection()   \n    \n    so=SelObserver()\n    FreeCADGui.Selection.addObserver(so)               # installe la fonction en mode resident\n    \n    mainWindowOverture = FreeCADGui.getMainWindow()    # fenetre FreeCAD\n    mainWindow = FreeCADGui.getMainWindow()\n    \n    #https://srinikom.github.io/pyside-docs/PySide/QtGui/QMainWindow.html\n    #PySide.QtGui.PySide.QtGui.QMainWindow.restoreState\n    originalState = QSettings(u\"Mario52\", __title__)\n    originalState.setValue(\"geometry\", mainWindow.saveGeometry())\n    originalState.setValue(\"state\", mainWindow.saveState())\n    ##################\n\n    if QtCore.__version_info__ [0] >= 5:\n        ecranComplet  = QtWidgets.QApplication.screens()[0].availableGeometry() #https://github.com/enthought/traitsui/pull/1311\n    else:\n        ecranComplet = QtWidgets.QDesktopWidget().availableGeometry() # disponible (PySide2) .center()\n\n#    ecranComplet = QtWidgets.QDesktopWidget().screenGeometry()    # complet    (PySide2)\n#    ecranComplet = QtWidgets.QDesktopWidget().availableGeometry() # disponible (PySide2)\n    ecranCompletX = ecranComplet.width()\n    ecranCompletY = ecranComplet.height()\n\n    doc = FreeCAD.ActiveDocument\n    if doc == None:\n        doc = FreeCAD.newDocument(u\"Screen_Window\")\n\n    MainWindow = QtWidgets.QWidget()     #(PySide2)\n    MainWindow.setObjectName(__title__)  # macro internal Name\n    ui = Ui_MainWindow(MainWindow)\n    ui.setupUi(MainWindow)\n\n    ####Configuration##############\n    #\n    FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"Version\",__version__ + \" (\" + __date__ + \")\")# \n    parameterBackground = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/View\")\n    #parameterBackground = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/View\").GetUnsigned(\"BackgroundColor\")\n    #parameterBackgroundColor2 = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/View\").GetUnsigned(\"BackgroundColor2\")\n    #parameterBackgroundColor3 = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/View\").GetUnsigned(\"BackgroundColor3\")\n    #parameterBackgroundColor4 = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/View\").GetUnsigned(\"BackgroundColor4\")\n    ####\n    switchTitleBoxToolBar = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switchTitleBoxToolBar\")\n    pathFile  = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetString(\"setLastPath\")\n    if pathFile == \"\":\n        pathFile = path\n    if FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switch_RD_01_MWindow\"):\n        ui.RD_01_MWindow.setChecked(True)\n    if FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switch_RD_02_Screen\"):\n        ui.RD_02_Screen.setChecked(True)\n    if FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switch_RB_01_Actual\"):\n        ui.RB_01_Actual.setChecked(True)\n    if FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switch_RB_03_Transparent\"):\n        ui.RB_03_Transparent.setChecked(True)\n    if FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switch_RB_02_Color\"):\n        ui.Color = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetString(\"setColorUser\")\n        if ui.Color == \"\": ui.Color = \"4289331455\"\n        ui.RB_02_Color.setChecked(True)\n        ui.RB_02_Color.setText(u\"Color \" + ui.Color)\n        ui.PB_02_OriginalBaGr.setVisible(True)\n        ui.PB_02_OriginalBaGr.setStyleSheet(\"QPushButton {background-color : }\"  + str(ui.Color))\n        parameterBackground.SetBool(\"Gradient\",False)\n        sorendermanager=Gui.ActiveDocument.ActiveView.getViewer().getSoRenderManager()\n        redX   = (1.0/256.0) * int(ui.Color[1:3],16)\n        greenX = (1.0/256.0) * int(ui.Color[3:5],16)\n        blueX  = (1.0/256.0) * int(ui.Color[5:7],16)\n        sorendermanager.setBackgroundColor(coin.SbColor4f(redX, greenX, blueX, 00))\n        sorendermanager.activate()\n        sorendermanager.render(True, True)\n    #\n    ####Configuration##############\n    \n    MainWindow.show()\n    \n\n",
    "url": "https://wiki.freecad.org/Macro_Screen_Wiki",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/61571ce0bd41af0471995df7c3ea855f/raw/14deef95d2276c1095ea7eefb75dc5b5e4be4e04/Macro_Screen_Wiki.FCMacro",
    "wiki": "https://wiki.freecadweb.org/index.php?title=Macro_Screen_Wiki",
    "version": "00.06c",
    "license": "",
    "date": "2024/10/10",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Screen_Wiki.png",
    "icon_source": "https://wiki.freecad.org/images/f/f5/Macro_Screen_Wiki.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Snip",
    "on_wiki": true,
    "on_git": false,
    "desc": "Use this macro to easily post screenshots to the FreeCAD forum.<br />It is best to add this macro to your global custom macros toolbar for quick and easy access.<br />When posting to the FreeCAD forum it is often useful to be able to include screenshots. The problem is this is a somewhat tedious task. This macro is to make that task a bit easier.<br />The macro can take screenshots or it can use existing screenshots that have already been copied to the system clipboard. To bypass the image already in clipboard press the Shift key while invoking the macro. To use the macro to take the screenshot adjust the size and placement of the dialog that pops up, then click OK. Upon clicking OK the macro will attempt to take a screenshot of the area of the screen covered by the dialog. The dialog itself is semi-transparent, so you can see the contents beneath.<br /><br />Macro version: 1.3<br />Last modified: 2024.07.23<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/images/a/a0/Snip.png\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Use this macro to easily post screenshots to the FreeCAD forum.",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2019 <TheMarkster>                                      *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the          *\n*   GNU Library General Public License at http://www.gnu.org/licenses     *\n*   for more details.                                                     *\n*                                                                         *\n*   For more information about the GNU Library General Public License     *\n*   write to the Free Software Foundation, Inc., 59 Temple Place,         *\n*   Suite 330, Boston, MA  02111-1307 USA                                 *\n*                                                                         *\n***************************************************************************\n\"\"\"\n\n\n\n\"\"\"\nSnip Macro\n\nThis is a macro to make it easier to post screenshots to the FreeCAD forum.\n\nThe forum supports a drag and drop interface -- just drag and drop an image to the\ntextarea where you type in your post. But it still requires many\ntedious steps. This macro is to reduce some of those steps.\n\nYou should add the macro to your custom macro toolbar to save as many clicks as possible.\n\nThe first thing the macro does is to check if there is an image already saved to the\nsystem clipboard, and if so, it uses that one. To bypass the clipboard, press Shift\nwhile invoking the macro.\n\n\"\"\"\n\n__title__ = \"Snip\"\n__author__ = \"TheMarkster\"\n__url__ = \"\"\n__Wiki__ = \"\"\n__date__ = \"2024.07.23\"\n__version__ = 1.3\nimport FreeCAD\nfrom PySide import QtGui,QtCore\nimport uuid\nimport time\nimport tempfile, os, shutil\n\n# class SnipBox(QtGui.QDialog):\n#     def __init__(self, scale, desired_width):\n#         QtGui.QDialog.__init__(self)\n#         self.scale = scale\n#         self.desired_width = desired_width\n#\n#         self.detailsTextEdit = QtGui.QTextEdit(\"Details\")\n#         self.Details = QtGui.QPushButton(\"Details\")\n#         self.Scaling = QtGui.QPushButton(\"Scaling\")\n#         self.Details.clicked.connect(self.onDetailsClicked)\n#         self.Scaling.clicked.connect(self.onScalingClicked)\n#         layout = QtGui.QVBoxLayout()\n#         layout.addWidget(self.detailsTextEdit)\n#         layout.addStretch()\n#         buttons = QtGui.QDialogButtonBox(\n#             QtGui.QDialogButtonBox.Ok,\n#             QtCore.Qt.Horizontal, self)\n#         buttons.accepted.connect(self.accept)\n#         buttons.rejected.connect(self.reject)\n#         buttons.addButton(self.Details, QtGui.QDialogButtonBox.ActionRole)\n#         buttons.addButton(self.Scaling, QtGui.QDialogButtonBox.ActionRole)\n#         buttons.setCenterButtons(True)\n#         layout.addWidget(buttons)\n#         self.setLayout(layout)\n#         self.detailsTextEdit.setVisible(False)\n#\n#     def setDetailedText(self, txt):\n#         self.detailsTextEdit.setText(txt)\n#\n#     def setTitle(self, rectwidth, rectheight):\n#         if self.scale != 1.0:\n#            out_width = rect.width()*scale_factor\n#         elif self.desired_width != 0:\n#             out_width = desired_width\n#         self.setWindowTitle(f\"Snip macro v{__version__} {rectwidth} x {rectheight} output width {out_width}\")\n#\n#\n#     def onDetailsClicked(self):\n#         self.detailsTextEdit.setVisible(not self.detailsTextEdit.isVisible())\n#\n#     def onScalingClicked(self):\n#         pass\n#\n#     def event(self, e): #credit serge_gubenko of stackoverflow for this\n#         result = QtGui.QDialog.event(self, e)\n#         self.setMinimumHeight(0)\n#         self.setMaximumHeight(16777215)\n#         self.setMinimumWidth(0)\n#         self.setMaximumWidth(16777215)\n#         self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)\n#         textEdit = self.findChild(QtGui.QTextEdit)\n#         if textEdit != None :\n#             textEdit.setMinimumHeight(0)\n#             textEdit.setMaximumHeight(16777215)\n#             textEdit.setMinimumWidth(0)\n#             textEdit.setMaximumWidth(16777215)\n#             textEdit.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)\n# #thanks to mario52 for this\n#         if result == True:\n#             try:\n#                 rect = mb.frameGeometry()\n#                 rectwidth  = rect.width()\n#                 rectheight = rect.height()\n#                 mb.setTitle(rectwidth,rectheight)\n#\n#             except Exception:\n#                 None\n# ##############\n#         return result\nclass SnipBox(QtGui.QDialog):\n    def __init__(self, scale, desired_width):\n        QtGui.QDialog.__init__(self)\n        self.pg = FreeCAD.ParamGet(\"User parameter:Plugins/Snip_Macro\")\n        self.scale = scale\n        self.desired_width = desired_width\n\n        self.detailsTextEdit = QtGui.QTextEdit(\"Details\")\n        self.Details = QtGui.QPushButton(\"Details\")\n        self.Scaling = QtGui.QPushButton(\"Scaling\")\n        self.Details.clicked.connect(self.onDetailsClicked)\n        self.Scaling.clicked.connect(self.onScalingClicked)\n\n        layout = QtGui.QVBoxLayout()\n        layout.addWidget(self.detailsTextEdit)\n        layout.addStretch()\n\n        # Scaling widgets\n        self.scaleLabel = QtGui.QLabel(\"Scale:\")\n        self.scaleSpinBox = QtGui.QDoubleSpinBox()\n        self.scaleSpinBox.setDecimals(2)\n        self.scaleSpinBox.setSingleStep(0.1)\n        self.scaleSpinBox.setValue(self.scale)\n        self.scaleSpinBox.valueChanged.connect(self.updateScale)\n\n        self.fixedWidthLabel = QtGui.QLabel(\"Fixed Width:\")\n        self.fixedWidthSpinBox = QtGui.QSpinBox()\n        self.fixedWidthSpinBox.setRange(0, 10000)\n        self.fixedWidthSpinBox.setValue(self.desired_width)\n        self.fixedWidthSpinBox.valueChanged.connect(self.updateDesiredWidth)\n\n        self.scaleLayout = QtGui.QVBoxLayout()\n        self.scaleText = QtGui.QLabel(\"Scale values other than 1.0 will override fixed width setting\")\n        self.scaleLayout.addWidget(self.scaleText)\n        scaleHBox1 = QtGui.QHBoxLayout()\n        scaleHBox1.addWidget(self.scaleLabel)\n        scaleHBox1.addWidget(self.scaleSpinBox)\n\n        scaleHBox2 = QtGui.QHBoxLayout()\n        scaleHBox2.addWidget(self.fixedWidthLabel)\n        scaleHBox2.addWidget(self.fixedWidthSpinBox)\n\n        self.scaleLayout.addLayout(scaleHBox1)\n        self.scaleLayout.addLayout(scaleHBox2)\n\n        self.scaleWidget = QtGui.QWidget()\n        self.scaleWidget.setLayout(self.scaleLayout)\n        self.scaleWidget.setVisible(False)\n\n        layout.addWidget(self.scaleWidget)\n\n        buttons = QtGui.QDialogButtonBox(\n            QtGui.QDialogButtonBox.Ok,\n            QtCore.Qt.Horizontal, self)\n        buttons.accepted.connect(self.accept)\n        buttons.rejected.connect(self.reject)\n        buttons.addButton(self.Details, QtGui.QDialogButtonBox.ActionRole)\n        buttons.addButton(self.Scaling, QtGui.QDialogButtonBox.ActionRole)\n        buttons.setCenterButtons(True)\n        layout.addWidget(buttons)\n        self.setLayout(layout)\n        self.detailsTextEdit.setVisible(False)\n\n    def setDetailedText(self, txt):\n        self.detailsTextEdit.setText(txt)\n\n    def setTitle(self, rectwidth, rectheight):\n        if self.scale != 1.0:\n            out_width = rectwidth * self.scale\n        elif self.desired_width != 0:\n            out_width = self.desired_width\n        self.setWindowTitle(f\"Snip macro v{__version__} {rectwidth} x {rectheight} output width {out_width}\")\n\n    def onDetailsClicked(self):\n        if self.scaleWidget.isVisible():\n            self.scaleWidget.setVisible(False)\n        self.detailsTextEdit.setVisible(not self.detailsTextEdit.isVisible())\n\n    def onScalingClicked(self):\n        if self.detailsTextEdit.isVisible():\n            self.detailsTextEdit.setVisible(False)\n        self.scaleWidget.setVisible(not self.scaleWidget.isVisible())\n\n    def updateScale(self, value):\n        self.scale = value\n        self.pg.SetFloat(\"ScaleFactor\", self.scale)\n\n    def updateDesiredWidth(self, value):\n        self.desired_width = value\n        self.pg.SetInt(\"DesiredWidth\", self.desired_width)\n\n    def event(self, e): #credit serge_gubenko of stackoverflow for this\n        result = QtGui.QDialog.event(self, e)\n        self.setMinimumHeight(0)\n        self.setMaximumHeight(16777215)\n        self.setMinimumWidth(0)\n        self.setMaximumWidth(16777215)\n        self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)\n        textEdit = self.findChild(QtGui.QTextEdit)\n        if textEdit != None :\n            textEdit.setMinimumHeight(0)\n            textEdit.setMaximumHeight(16777215)\n            textEdit.setMinimumWidth(0)\n            textEdit.setMaximumWidth(16777215)\n            textEdit.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)\n#thanks to mario52 for this\n        if result == True:\n            try:\n                rect = mb.frameGeometry()\n                rectwidth  = rect.width()\n                rectheight = rect.height()\n                mb.setTitle(rectwidth,rectheight)\n            except Exception:\n                None\n##############\n        return result\n\ndef get_screen_for_widget(widget):\n    screen_geometry = widget.geometry()\n    for screen in QtGui.QApplication.screens():\n        if screen.geometry().contains(screen_geometry.center()):\n            return screen\ndef get_widget_screen_coordinates(widget):\n    screen = get_screen_for_widget(widget)\n    widget_geometry = widget.geometry()\n    screen_geometry = screen.geometry()\n    return QtCore.QRect(widget_geometry.x() - screen_geometry.x(),\n                        widget_geometry.y() - screen_geometry.y(),\n                        widget_geometry.width(),\n                        widget_geometry.height())\n\n\npg = FreeCAD.ParamGet(\"User parameter:Plugins/Snip_Macro\")\n#parameters were originally in BaseApp, but should be in Plugins, so relocate if necessary\nif FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences\").HasGroup(\"Snip_Macro\"):\n    deprecated = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Snip_Macro\")\n    pg.SetInt(\"LastX\",deprecated.GetInt(\"LastX\",0))\n    pg.SetInt(\"LastY\",deprecated.GetInt(\"LastY\",0))\n    pg.SetInt(\"LastWidth\",deprecated.GetInt(\"LastWidth\",0))\n    pg.SetInt(\"LastHeight\",deprecated.GetInt(\"LastHeight\",0))\n    pg.SetFloat(\"WindowOpacity\",deprecated.GetFloat(\"WindowOpacity\",0.85))\n    pg.SetFloat(\"SnipDelay\",deprecated.GetFloat(\"SnipDelay\",0.5))\n    FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences\").RemGroup(\"Snip_Macro\")\n\ndesired_width = pg.GetInt(\"DesiredWidth\",0) #used for scaling to desired width, maintaining aspect ratio\npg.SetInt(\"DesiredWidth\", desired_width)\nscale_factor = pg.GetFloat(\"ScaleFactor\", 1.0) #scale by scale factor instead of desired width\npg.SetFloat(\"ScaleFactor\", scale_factor)\n\nskipClipboard = False\nmodifiers = QtGui.QApplication.keyboardModifiers()\nif modifiers == QtCore.Qt.ShiftModifier:\n    skipClipboard = True\n\nuserCanceled = False\nfname = \"Snip macro screenshot-\"+str(uuid.uuid4())[:6]+\".png\"\nimage = None\nif not skipClipboard:\n    clip = QtGui.QClipboard()\n    image = clip.image(QtGui.QClipboard.Clipboard)\nif not image:\n\n    #use our own screen grabber\n    mb = SnipBox(scale_factor, desired_width)\n    details = \"\"\"\nMove and resize this box to cover the part of the screen you wish to grab.\nIf it succeeds an open file dialog will appear. Drag and drop the file\nfrom the open file dialog to the forum. The file will be deleted after\nyou close the dialog.\n\nIf this fails you can still use this macro to handle screenshots you\ncopied to the clipboard using other tools:\n\nWindows snip tool: Window Key + Shift + S\nMac snip tool: Command + Shift + 4\nLinux: gnome-screenshot utility\n\nIf the macro finds there is already an image copied to the clipboard\nit uses that image instead of bringing up this dialog. Press Shift\nwhile invoking this macro to bypass the clipboard. Alternatively,\nyou can clear the image from the clipboard by copying some text to it.\n\nThe Open button will open the file in the system\ndefault application for handling png files, e.g. Paint in windows. This\ncan be useful if you wish to annotate the screenshot. But most of the\ntime you will simply want to drag and drop the file to the forum, then\nCancel to close the open file dialog afterwards.\n\nIf you wish to open the screenshot file with another application, right-click\nthe file and select open with... option or drag/drop to that other application.\n\nUser Parameters: These can be accessed via Tools menu -> Edit Parameters in\nPlugins -> Snip_Macro:\n\nLastX, LastY, LastWidth, LastHeight -- location and size of snip box last use\nWindowOpacity (0.85) -- value between 0.0 (less opaque) and 1.0 (more opaque)\nSnipDelay (0.5) -- time (in seconds) delay between snip box close and snip\nDesiredWidth -- image will be scaled to this width (unless it is 0) maintaining\ncurrent aspect ratio.\nScaleFactor -- float value, e.g. 0.5 -- image will be scaled to that scale factor.\nNote: ScaleFactor (if not 1.0) will take precedence over DesiredWidth\nHold down Ctrl key to ignore scaling.\n\nThe SnipDelay parameter can be adjusted to speed things up a bit, but if it\nis too small the screenshot taken might include the snip box itself because\nwe need to wait for it to close before taking the screenshot.\n\n\"\"\"\n   # mb.setWindowTitle(\"Snip macro v\"+str(__version__))\n    mb.setDetailedText(details)\n    if pg.GetFloat(\"WindowOpacity\",0.85) == 0.85:\n        pg.SetFloat(\"WindowOpacity\",0.85)\n    mb.setWindowOpacity(pg.GetFloat(\"WindowOpacity\",0.85))\n    lastX = pg.GetInt(\"LastX\",0)\n    lastY = pg.GetInt(\"LastY\",0)\n    lastWidth = pg.GetInt(\"LastWidth\",100)\n    lastHeight = pg.GetInt(\"LastHeight\",100)\n    mb.setGeometry(lastX, lastY, lastWidth, lastHeight)\n    mb.resize(lastWidth, lastHeight)\n    mb.setWindowFlags(QtCore.Qt.Tool)\n    result = mb.exec_()\n    if not result:\n        userCanceled = True\n    if not userCanceled:\n        clientRect = mb.geometry()\n        scale_factor = mb.scale\n        desired_width = mb.desired_width\n        rect = get_widget_screen_coordinates(mb)\n        diff = rect.height()-clientRect.height()\n        pg.SetInt(\"LastX\", rect.x())\n        pg.SetInt(\"LastY\", rect.y())\n        pg.SetInt(\"LastWidth\", rect.width())\n        pg.SetInt(\"LastHeight\", rect.height()-diff)\n        QtGui.QApplication.processEvents()\n        snipDelay = pg.GetFloat(\"SnipDelay\", 0.5)\n        if snipDelay == 0.5:\n            pg.SetFloat(\"SnipDelay\", 0.5)\n        time.sleep(snipDelay) #give time for dialog to close before taking screenshot\n        QtGui.QApplication.processEvents()\n        if hasattr(QtGui.QApplication,\"primaryScreen\"):\n            #screen = QtGui.QApplication.primaryScreen()\n            screen = get_screen_for_widget(mb)\n            image = screen.grabWindow(0,rect.x(),rect.y(),rect.width(),rect.height()).toImage()\n        else:\n            long_qdesktop_id = QtGui.QApplication.desktop().winId()\n            image = QtGui.QPixmap.grabWindow(long_qdesktop_id, rect.x(), rect.y(), rect.width(), rect.height()).toImage()\n        if not image:\n            raise Exception(\"Snip Macro Error: Unable to grab screen image\\n\")\n        modifiers = QtGui.QApplication.keyboardModifiers()\n        skipScaling = False\n        if modifiers == QtCore.Qt.ControlModifier:\n            skipScaling = True\n        if not skipScaling:\n            if scale_factor != 1.0:\n                image = image.smoothScaled(rect.width()*scale_factor, rect.height()*scale_factor)\n            elif desired_width != 0:\n                image = image.smoothScaled(desired_width, rect.height()*float(desired_width)/float(rect.width()))\n\nif not userCanceled:\n    dirPath = tempfile.mkdtemp()\n    filePath = dirPath + os.path.sep + fname\n    image.save(filePath)\n    fileName = QtGui.QFileDialog.getOpenFileName(QtGui.QApplication.activeWindow(),\n    \"Drag the image to the forum, then Cancel will delete the temporary file\", dirPath, \"PNG (*.png)\")\n    if fileName[0]:  #user selected Open or double-clicked file\n        import subprocess, os, platform\n        if platform.system() == 'Darwin':       # macOS\n            subprocess.call(('open', fileName[0]))\n        elif platform.system() == 'Windows':    # Windows\n            os.startfile(fileName[0])\n        else:                                   # linux variants\n            subprocess.call(('xdg-open', fileName[0]))\n        QtGui.QApplication.processEvents() #allow some time for file to open before deleting temp folder and contents\n        time.sleep(1)\n        QtGui.QApplication.processEvents()\n    shutil.rmtree(dirPath)",
    "url": "https://wiki.freecad.org/Macro_Snip",
    "raw_code_url": "",
    "wiki": "",
    "version": "1.3",
    "license": "",
    "date": "2024.07.23",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Snip.png",
    "icon_source": "https://wiki.freecadweb.org/images/a/a0/Snip.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "View Rotation",
    "on_wiki": true,
    "on_git": false,
    "desc": "This GUI allows the view to be rotated with more precision than when using the mouse.  Rotation is according to axes fixed with respect to the user and not the objects, though the aim is that the objects rotate about their approximate shared centre rather than the view centre.<br /> <p>The GUI defaults to the top right of the screen, this behaviour can be changed by editing.<br /> <br /> <a rel=\"nofollow\" class=\"external text\" href=\"http://forum.freecadweb.org/download/file.php?id=453\">Icons Package</a><br /><br />Macro version: 1.0<br />Last modified: 2012-01-04<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/a/af/Macro_View_Rotation.png\">ToolBar Icon</a><br />Author: Joe Dowsett<br /> </p> ",
    "comment": "This GUI allows the view to be rotated precisely",
    "code": "#\n# FreeCAD macro ViewRotation.\n# This GUI allows the view to be rotated with more precision than when using\n# the mouse. Rotation is according to axes fixed with respect to the user and\n# not the objects, though the aim is that the objects rotate about their\n# approximate shared centre rather than the view centre.\n# The GUI defaults to the top right of the screen, this behaviour can be\n# changed by editing.\n# [http://forum.freecadweb.org/viewtopic.php?f=3&t=1784&hilit=View+Rotation#p12012 View+Rotation]\n\n\n__Name__ = 'View Rotation'\n__Comment__ = 'This GUI allows the view to be rotated precisely'\n__Author__ = 'Joe Dowsett'\n__Version__ = '1.0.1'\n__Date__ = '2024-11-22'\n__License__ = 'CC-BY-3.0'\n__Web__ = 'https://www.freecadweb.org/wiki/Macro_View_Rotation'\n__Wiki__ = 'https://www.freecadweb.org/wiki/Macro_View_Rotation'\n__Icon__ = ''\n__Help__ = 'Rotation is according to axes fixed with respect to the user.'\n__Status__ = ''\n__Requires__ = ''\n__Files__ = 'ViewRotationOut.png,ViewRotationRight.png,ViewRotationUp.png'\n\nfrom math import pi\nfrom functools import partial\nimport os\n\nfrom PySide import QtCore  # FreeCAD's PySide!\nfrom PySide import QtGui  # FreeCAD's PySide!\nfrom pivy import coin\n\nimport FreeCAD as app\nimport FreeCADGui as gui\n\n\ndef find_centre():\n    doc = app.activeDocument()\n    if doc is None:\n        return app.Vector(0.0, 0.0, 0.0)\n\n    xmax = 0.0\n    xmin = 0.0\n    ymax = 0.0\n    ymin = 0.0\n    zmax = 0.0\n    zmin = 0.0\n    for obj in doc.Objects:\n        try:\n            if obj.TypeId[:4] == 'Mesh':\n                box = obj.Mesh.BoundBox\n            elif obj.TypeId[:6] == 'Points':\n                box = obj.Points.BoundBox\n            elif obj.TypeId[:4] == 'Part':\n                box = obj.Shape.BoundBox\n            else:\n                continue\n        except AttributeError:\n            continue\n        xmax = max(xmax, box.XMax)\n        xmin = min(xmin, box.XMin)\n        ymax = max(ymax, box.YMax)\n        ymin = min(ymin, box.YMin)\n        zmax = max(zmax, box.ZMax)\n        zmin = min(zmin, box.ZMin)\n\n    return app.Vector((xmax + xmin) / 2, (ymax + ymin) / 2, (zmax + zmin) / 2)\n\n\nclass RotateGui(QtGui.QWidget):\n    def __init__(self):\n        super().__init__()\n        self.init_ui()\n        self.init_rotate()\n\n    def init_ui(self):\n        macro_dir = app.getUserMacroDir(True)\n        self.sliders = []\n        self.line_edits = []\n\n        vbox = QtGui.QVBoxLayout()\n\n        icons = (\n                'ViewRotationRight.png',\n                'ViewRotationUp.png',\n                'ViewRotationOut.png',\n        )\n        for i, icon in enumerate(icons):\n            slider = QtGui.QSlider(QtCore.Qt.Horizontal, self)\n            slider.setFocusPolicy(QtCore.Qt.NoFocus)\n            slider.setSingleStep(5)\n            slider.setPageStep(15)\n            slider.setValue(0)\n            slider.setMaximum(180)\n            slider.setMinimum(-180)\n            slider.valueChanged.connect(partial(self.on_slider_value_changed, i))\n            self.sliders.append(slider)\n\n            line_edit = QtGui.QLineEdit(self)\n            line_edit.setText('0')\n            line_edit.setAlignment(QtCore.Qt.AlignRight)\n            line_edit.returnPressed.connect(self.valueEntered)\n            self.line_edits.append(line_edit)\n\n            label = QtGui.QLabel(self)\n            label.setPixmap(QtGui.QPixmap(os.path.join(macro_dir, icon)))\n\n            hbox = QtGui.QHBoxLayout()\n            hbox.addWidget(label, 1, QtCore.Qt.AlignCenter)\n            hbox.addWidget(slider, 4)\n            hbox.addWidget(line_edit, 1)\n            vbox.addLayout(hbox)\n\n        reset_button = QtGui.QPushButton('Reset')\n        reset_button.clicked.connect(self.reset)\n\n        ok_button = QtGui.QPushButton('OK')\n        ok_button.clicked.connect(self.close)\n\n        cancel_button = QtGui.QPushButton('Cancel')\n        cancel_button.clicked.connect(self.cancel)\n\n        hbox = QtGui.QHBoxLayout()\n        hbox.addWidget(reset_button, 1)\n        hbox.addWidget(ok_button, 1)\n        hbox.addWidget(cancel_button, 1)\n        vbox.addStretch(1)\n        vbox.addLayout(hbox)\n\n        self.setLayout(vbox)\n\n        qapp = QtCore.QCoreApplication.instance()\n        screen_number = QtGui.QDesktopWidget().screenNumber(self)\n        right = qapp.screens()[screen_number].geometry().width()\n\n        self.setGeometry(right - 300, 0, 300, 150)\n        self.setWindowTitle('Rotate view')\n        self.show()\n\n    def init_rotate(self):\n        # Index in [right, up, out]\n        self._current_axis = 0\n\n        self.cam = gui.activeDocument().ActiveView.getCameraNode()\n        self.centre = coin.SbVec3f(find_centre())\n        self.view = self.cam.orientation.getValue()\n        self.pos = self.cam.position.getValue()\n\n        # Store a copy of the original view to be restored in the case of user\n        # selecting Reset or Cancel.\n        self.original_view = coin.SbRotation(self.view.getValue())\n        self.original_pos = coin.SbVec3f(self.pos.getValue())\n\n        self.config_direction(0)\n\n    def reset(self):\n        # Reset the view to the original one.\n        self.cam.orientation = self.original_view\n        self.cam.position = self.original_pos\n        for slider in self.sliders:\n            # Deactivate callbacks.\n            slider.blockSignals(True)\n            slider.setValue(0)\n            slider.blockSignals(False)\n        for tbox in self.line_edits:\n            tbox.setText('0')\n        self.config_direction(0)\n\n    def cancel(self):\n        self.reset()\n        self.close()\n\n    def config_direction(self, axis_index):\n        \"\"\"\n        Assign `self.direction` to either the right, up or out vector.\n\n        Evaluate the vectors corresponding to the three directions for the\n        current view, and assign `self.direction` to the one at index `axis_index`.\n\n        \"\"\"\n        self.view = self.cam.orientation.getValue()\n        self.view = coin.SbRotation(self.view.getValue())\n        self.pos = self.cam.position.getValue()\n        self.pos = coin.SbVec3f(self.pos.getValue())\n\n        up = coin.SbVec3f(0, 1, 0)\n        self.up = self.view.multVec(up)\n        out = coin.SbVec3f(0, 0, 1)\n        self.out = self.view.multVec(out)\n        u = self.up.getValue()\n        o = self.out.getValue()\n        r = (u[1]*o[2]-u[2]*o[1], u[2]*o[0]-u[0]*o[2], u[0]*o[1]-u[1]*o[0])\n        self.right = coin.SbVec3f(r)\n\n        self.direction = [self.right, self.up, self.out][axis_index]\n\n    def check(self, axis_index):\n        \"\"\"\n        Check if the direction of rotation has changed.\n\n        Check if the direction of rotation has changed, if so then set\n        previous slider and textbox to zero, and setup the new direction.\n\n        \"\"\"\n        if axis_index != self._current_axis:\n            # Deactivate callbacks.\n            self.sliders[self._current_axis].blockSignals(True)\n            self.sliders[self._current_axis].setValue(0)\n            self.sliders[self._current_axis].blockSignals(False)\n            self.line_edits[self._current_axis].blockSignals(True)\n            self.line_edits[self._current_axis].setText(\"0\")\n            self.line_edits[self._current_axis].blockSignals(False)\n            self._current_axis = axis_index\n            self.config_direction(axis_index)\n\n    def rotate(self, value):\n        # Carry out the desired rotation about self.direction.\n        val = value * pi / 180.0\n        rot = coin.SbRotation(self.direction, -val)\n        nrot = self.view*rot\n        prot = rot.multVec(self.pos - self.centre) + self.centre\n        self.cam.orientation = nrot\n        self.cam.position = prot\n\n    def on_slider_value_changed(self, slider_index: int, value: int):\n        \"\"\"\n        Respond to the change in value of a slider.\n\n        Respond to the change in value of a slider, update the corresponding\n        text box, check for a direction change then rotate\n        if the value was changed internally, ignore event.\n\n        \"\"\"\n        self.line_edits[slider_index].setText(str(value))\n        self.check(slider_index)\n        self.rotate(value)\n\n    def valueEntered(self):\n        \"\"\"\n        Respond to a value being entered in a text box.\n\n        Respond to a value being entered in a text box, updating the\n        corresponding slider, checking for direction change then rotate.\n\n        \"\"\"\n        sender = self.sender()\n        for i in range(3):\n            if sender == self.line_edits[i]:\n                break\n        value = round(float(self.line_edits[i].text()))\n        self.sliders[i].blockSignals(True)\n        self.sliders[i].setValue(value)\n        self.sliders[i].blockSignals(False)\n        self.line_edits[i].blockSignals(True)\n        self.line_edits[i].setText(str(value))\n        self.line_edits[i].blockSignals(False)\n        self.check(i)\n        self.rotate(value)\n\n\nif __name__ == '__main__':\n    # We need to set a variable, otherwise, the dialog doesn't appear.\n    rotate = RotateGui()\n",
    "url": "https://www.freecadweb.org/wiki/Macro_View_Rotation",
    "raw_code_url": "https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/master/PureGui/ViewRotation.FCMacro",
    "wiki": "https://www.freecadweb.org/wiki/Macro_View_Rotation",
    "version": "1.0.1",
    "license": "",
    "date": "2024-11-22",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Joe Dowsett",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_View_Rotation.png",
    "icon_source": "https://wiki.freecad.org/images/a/af/Macro_View_Rotation.png",
    "xpm": "",
    "other_files": [
      "ViewRotationOut.png",
      "ViewRotationRight.png",
      "ViewRotationUp.png"
    ],
    "parsed": true
  },
  {
    "name": "Zoom1 1",
    "on_wiki": true,
    "on_git": false,
    "desc": "1:1 Zooming so objects appear their actual size on the screen.<br /><br />Macro version: 1.0<br />Last modified: 2021-11-9<br />FreeCAD version: Python3+<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/File:Zoom1_1.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "1:1 Zooming so objects appear their actual size on the screen.",
    "code": "# -*- coding: utf-8 -*-\n#Zoom 1:1 macro\n#2021, by <TheMarkster>, based on work of kisolre\n#Attempts to zoom 3D view such that objects on the screen\n#appear to be their actual size\n#For example, a 100mm cube should measure 100mm on your screen\n#This relies on information provided by Qt about the underlying\n#hardware, which Qt admits is not always reliable\n#Thus we have a Tweak parameter to workaround such cases.\n#Press Ctrl key while executing the macro to bring up the\n#calibration dialog and set the tweak for your hardware.\n\n\nimport FreeCAD, FreeCADGui\nfrom PySide import QtGui, QtCore\n\n__version__ = \"1.0\"\n\ndef zoomActual(tweak=1.0):\n    gv = av.graphicsView()\n    height = gv.heightMM()\n    width = gv.widthMM()\n    node = av.getCameraNode()\n    node.height.setValue(tweak*min(width,height))\n\ndoc = FreeCAD.ActiveDocument\nif not doc:\n    doc = FreeCAD.newDocument()\n    FreeCAD.Console.PrintMessage(\"No document, creating one.\\n\")\nav = FreeCADGui.activeView()\npg = FreeCAD.ParamGet(\"User parameter:Plugins/Zoom1_1_Macro\")\ntweak = pg.GetFloat(\"Tweak\",1.0)\nif hasattr(av,\"graphicsView\") and hasattr(av.getCameraNode(),\"height\"):\n    zoomActual(tweak)\n    modifiers = QtGui.QApplication.keyboardModifiers()\n    if modifiers == QtCore.Qt.ControlModifier:\n        visible = [obj for obj in doc.Objects if hasattr(obj,\"ViewObject\") and obj.ViewObject.Visibility == True]\n        for obj in doc.Objects:\n            if hasattr(obj,\"ViewObject\"):\n                obj.ViewObject.Visibility = False\n        cube = doc.addObject(\"Part::Box\",\"TemporaryCalibrationCube\")\n        cube.Length = cube.Height = cube.Width = 100\n        cube.ViewObject.DisplayMode = \"Shaded\"\n        av.viewFront()\n        doc.recompute()\n        zoomActual(1.0)\n        text = \"\\\nCalibration dialog\\n\\\n\\n\\\nA temporary 100x100x100 mm cube has been created for this\\n\\\ncalibration. Measure this cube and enter your measurements.\\n\\\nA tweak value will be calculated based on what you enter and \\n\\\nwill be stored in user parameters / Plugins / Zoom1_1_Macro\\n\\\n\\n\\\nYou can move this dialog if necessary, but be sure not to zoom\\n\\\nin or out before measuring the cube. If the cube does not fit\\n\\\ncancel this dialog, resize the 3D view, and try again.\\n\\\n\\n\\\nEnter measured Cube Width or Height (in MM):\\n\"\n        win = FreeCADGui.getMainWindow()\n        title = \"Zoom1_1 macro v\"+__version__\n        dlg = QtGui.QInputDialog()\n        usertweak,ok = dlg.getDouble(win,title,text,100.0)\n        doc.removeObject(cube.Name)\n        for obj in visible:\n            obj.ViewObject.Visibility = True\n        if not ok:\n            FreeCAD.Console.PrintMessage(\"Canceled, keeping current tweak value\\n\")\n        else:\n            tweak = usertweak/100.0\n            pg.SetFloat(\"Tweak\", tweak)\n            zoomActual(tweak)\n    FreeCAD.Console.PrintMessage(\"Zoom 1:1 macro -- Ctrl + execute to calibrate, if necessary\\n\")\n    FreeCAD.Console.PrintMessage(\"Tweak = \"+str(tweak)+\"\\n\")\nelif not hasattr(av.getCameraNode(),\"height\"):\n    FreeCAD.Console.PrintError(\"Error: Only orthographic camera types are supported.\\n\")\nelse:\n    FreeCAD.Console.PrintError(\"Error acquiring QGraphicsView. You might need to update your version of FreeCAD.\\n\")",
    "url": "https://wiki.freecad.org/Macro_Zoom1_1",
    "raw_code_url": "",
    "wiki": "",
    "version": "1.0",
    "license": "",
    "date": "2021-11-9",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Zoom1_1.svg",
    "icon_source": "https://wiki.freecad.org//images/3/38/Zoom1_1.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Animated Constrain",
    "on_wiki": true,
    "on_git": false,
    "desc": "Simple macro to animate angles constraints in the sketcher.<br /><br />Macro version: 1.0<br />Last modified: 2015-05-20<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/a/af/Macro_Animated_Constrain.png\">ToolBar Icon</a><br />Not file for testing <a rel=\"nofollow\" class=\"external text\" href=\"https://www.youtube.com/watch?v=kmqDcomLnk0\">See the animation on YouTube.</a><br />Author: psicofil<br /> ",
    "comment": "Simple macro to animate angles constraints in the sketcher.",
    "code": "# -*- coding: utf-8 -*-\n# Mesh with GMSH inside of FreeCAD\n# Author: Gomez Lucio\n# License: LGPL v 2.1\n# Date: 17/05/2015\n\nimport FreeCAD\nfrom PySide import QtGui,QtCore\nimport math\nimport time\n\nclass AnimConstrain(QtGui.QWidget):\n    def __init__(self):\n        super(AnimConstrain, self).__init__()\n        self.initUI()\n    def initUI(self):\n        # Window\n        self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)\n        self.setWindowTitle(\"Animated Constrain\")\n        self.resize(240, 240)\n        # Content\n        self.l_initial = QtGui.QLabel(\" Initital (deg)\",self)\n        self.le_initial = QtGui.QLineEdit(self)\n        self.le_initial.setText(\"0\")\n        self.l_final = QtGui.QLabel(\" Final (deg)\",self)\n        self.le_final = QtGui.QLineEdit(self)\n        self.le_final.setText(\"360\")\n        self.l_interval = QtGui.QLabel(\" Interval (deg/step) \",self)\n        self.le_interval = QtGui.QLineEdit(self)\n        self.le_interval.setText(\"5\")\n        # Constrain Type\n        self.l_type_constrain = QtGui.QLabel(\"<b>Type of Constrain :<b>\",self)\n        self.rb_angle = QtGui.QRadioButton(\" Angle(deg)\",self)\n        self.rb_angle.setChecked(QtCore.Qt.Checked)\n        self.rb_length = QtGui.QRadioButton(\" Length(mm)\",self)\n        self.rb_length.setEnabled(False)\n        # Parameters\n        self.l_parameters = QtGui.QLabel(\"<b>Parameters :<b>\",self)\n        self.cb_repeat = QtGui.QCheckBox(\"  Repeat\",self)\n        self.bt_start = QtGui.QPushButton(\"Start\",self)\n        self.bt_stop = QtGui.QPushButton(\"Stop\",self)\n        # LAYOUT\n        layout = QtGui.QGridLayout()\n        layout.addWidget(self.l_type_constrain, 0, 0)\n        layout.addWidget(self.rb_angle, 1, 0)\n        layout.addWidget(self.rb_length, 1, 1)\n        layout.addWidget(self.l_parameters, 2, 0)\n        layout.addWidget(self.l_initial, 3, 0)\n        layout.addWidget(self.le_initial, 3, 1)\n        layout.addWidget(self.l_final, 4, 0)\n        layout.addWidget(self.le_final, 4, 1)\n        layout.addWidget(self.l_interval, 5, 0)\n        layout.addWidget(self.le_interval, 5, 1)\n        layout.addWidget(self.cb_repeat, 6, 0)\n        layout.addWidget(self.bt_start, 7, 0)\n        layout.addWidget(self.bt_stop, 7, 1)\n        self.setLayout(layout)\n        self.show()\n        # CONNECTS\n        QtCore.QObject.connect(self.bt_start, QtCore.SIGNAL(\"pressed()\"),self.start)\n        QtCore.QObject.connect(self.bt_stop, QtCore.SIGNAL(\"pressed()\"),self.stop)\n        self.cb_repeat.stateChanged.connect(self.repeat_state)\n        self.repeat = True\n        \n    def repeat_state(self, state):   \n        if state == QtCore.Qt.Checked:\n            self.repeat = False\n        else:\n            self.repeat = True\n        \n    def start(self):\n        App.Console.PrintMessage('Start ')\n        self.timer = QtCore.QTimer()\n        QtCore.QObject.connect(self.timer, QtCore.SIGNAL(\"timeout()\"), self.proceed)\n        self.timer.start(50)\n        self.an = float(eval(self.le_initial.text()))\n        self.interv = float(eval(self.le_interval.text()))\n        self.final = float(eval(self.le_final.text()))\n        #self.proceed()\n        \n    def proceed(self):\n        if self.an >= self.final and self.repeat:\n\t  self.stop()\n\telse:\n          try:\n             self.an = self.an + self.interv if self.an < (360.0) else 0.0\n             angle = self.an\n             App.Console.PrintMessage(str(angle)+\"  \")\n             App.ActiveDocument.Sketch.setDatum(cs,App.Units.Quantity((str(angle)+' deg')))\n             App.ActiveDocument.recompute()\n          except:\n\t     App.Console.PrintError('Error on setDatum in constrain  ')\n\t     self.stop()\n\n    def stop(self):\n        self.timer.stop()\n        App.Console.PrintMessage(\" End\")\n        App.ActiveDocument.recompute()\n\n\n# RUN WIDGET\ntry:\n   s = Gui.Selection.getSelectionEx()\n   cs=s[0].SubElementNames[0]\n   cs=int(cs[10:])-1\n   AnimConstrain()\nexcept:\n   App.Console.PrintError('Select one anlge constrain First  ')\n   \n\n",
    "url": "https://wiki.freecad.org/Macro_Animated_Constrain",
    "raw_code_url": "https://raw.githubusercontent.com/psicofil/Macros_FreeCAD/master/Macros/AnimatedConstrain.FCMacro",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2015-05-20",
    "src_filename": "",
    "filename_from_url": "",
    "author": "psicofil",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Animated_Constrain.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/a/af/Macro_Animated_Constrain.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Animator",
    "on_wiki": true,
    "on_git": false,
    "desc": "Animate your model by animating its properties with this feature Python object<br /><br />Macro version: 0.2023.09.30c<br />Last modified: 2022-09-30<br />FreeCAD version: Python 3 versions<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/File:Animator.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Animate your model by animating its properties with this feature Python object",
    "code": "# -*- coding: utf-8 -*-\n__version__ = \"0.2023.09.30c\"\n#__version__ = \"0.2023.09.30c\"\n##Animator, 2023, by <TheMarkster>, LGPL2.1 or later\n##Credit to Dan Miel for some of the A2Plus-related stuff\n#DEBUG = False\n#import FreeCAD, FreeCADGui, Part\n#import time\n#import math\n#import re\n#from pivy import coin\n#from PySide import QtCore, QtGui\n#import os, subprocess, glob\n#try:\n#    import a2p_solversystem\n#    a2p_present = True\n#except:\n#    a2p_present = False\n#    pass\n#DEFAULT_MACRO_STRING =[\\\n#\"#python code goes here\",\\\n#\"#fp = Animator object\",\\\n#\"#doc = document containing Animator object\",\\\n#\"#props = list of properties in Variables\",\\\n#\"#objs = list of objects in Variables\",\\\n#\"#con = FreeCAD.Console\",\\\n#\"#setExpression(idx,string_val) = objs[idx].setExpression(string_val)\",\\\n#\"#getValue(idx) = get value contained in VariableNNN where NNN is idx-1\",\\\n#\"#fp.CurrentFrame = current frame in animation loop\",\\\n#\"#AnimatorLastFrame = True if current frame is last frame in loop\",\\\n#\"#cam = active view's camera object\",\\\n#\"#cam.Position -> vector, cam.Position = (x,y,z) or cam.Position = vector\",\\\n#\"#cam.Orientation -> returns a tuple (axis,angle), or set with cam.Orientation = (axis,angle) or camOrientation = rot (a FreeCAD.Rotation)\",\\\n#\"#cam.OrientationEuler -> (yaw, pitch, roll), cam.OrientationEuler = (yaw,pitch,roll)\",\\\n#\"#cam.Height, cam.FocalDistance, cam.AspectRatio, cam.NearDistance, cam.FarDistance, (all floats)\",\\\n#\"#cam.Placement -> FreeCAD.Placement object\",\\\n#]\n\n#class Animator:\n#    def __init__(self, obj):\n#        animv = \"Animator.v\"+__version__\n#        obj.addProperty(\"App::PropertyBool\",\"FreezeCamera\",\"Camera\",\"Keep camera position each frame\").FreezeCamera = False\n#        obj.addProperty(\"App::PropertyLink\",\"CamPlacementObject\",\"Camera\",\"Sets cam to this object's placement each frame in the loop\")\n#        obj.addProperty(\"App::PropertyBool\",\"ReverseCam\",\"Camera\",\"Reverses camera orientation, applicable only if CamPlacementObject is set\").ReverseCam = False\n#        obj.addProperty(\"App::PropertyBool\",\"MakeGif\",\"AnimatedGif\",\"Make an animated gif using ffmpeg (requires ffmpeg binary be installed)\").MakeGif = False\n#        obj.addProperty(\"App::PropertyFile\",\"PathToFFMPEG\",\"AnimatedGif\",\"Browse to locate the ffmpeg binary with this property\")\n#        pg = FreeCAD.ParamGet(\"User parameter:Plugins/Animator_Macro\")\n#        obj.PathToFFMPEG = pg.GetString(\"PathToFFMPEG\",\"\")\n#        obj.addProperty(\"App::PropertyIntegerConstraint\",\"GifHeight\",\"AnimatedGif\", \"Height in pixels of the animated gif to be produced\").GifHeight = (480,1,1000000,1)\n#        obj.addProperty(\"App::PropertyIntegerConstraint\",\"GifWidth\",\"AnimatedGif\",\"Width in pixels of the animated gif to be produced\").GifWidth = (640,1,1000000,1)\n#        obj.addProperty(\"App::PropertyIntegerConstraint\",\"GifFrameRate\",\"AnimatedGif\",\"Frame rate in milliseconds (1000 = 1 second)\").GifFrameRate = (20,1,10000,1)\n#        obj.addProperty(\"App::PropertyPath\",\"PathToGif\",\"AnimatedGif\",\"Folder in which to place frame_NNN.png files and animated gif file (default: macros/Animator/screen_grabs/)\")\n#        obj.PathToGif = pg.GetString(\"PathToGif\",\"\")\n#        obj.addProperty(\"App::PropertyString\",\"AnimatedGifFilename\",\"AnimatedGif\",\"Name for animated gif\\nReplaces any files of the same name!\").AnimatedGifFilename = \"Animated.gif\"\n#        obj.addProperty(\"App::PropertyBool\",\"FitAllEachFrame\", \"AnimatedGif\", \\\n#                        \"If True send 'ViewFit' message to active view before taking the screenshot each frame\").FitAllEachFrame = True\n#        obj.addProperty(\"App::PropertyString\",\"BGColor\",\"AnimatedGif\",\"Color to use for background.  Example: 'Yellow'.  Default: 'Transparent'\").BGColor=\"Transparent\"\n#        obj.addProperty(\"App::PropertyFloat\",\"ScrapString\",\"RunMacro\", \"Internal use during loop as a scrap memory register\")\n#        obj.setEditorMode(\"ScrapString\",2)# hidden\n#        obj.addProperty(\"App::PropertyBool\",\"RunMacro\",\"RunMacro\",\"Whether to execute code contained in MacroFile each time through loop\").RunMacro=True\n#        obj.addProperty(\"App::PropertyFile\",\"MacroFile\",\"RunMacro\",\"Macro file to execute each time through the loop\")\n#        obj.addProperty(\"App::PropertyStringList\",\"MacroString\",\"RunMacro\",\"Quick and Dirty macro string to run each time through the loop\").MacroString = DEFAULT_MACRO_STRING\n#        obj.addProperty(\"App::PropertyBool\",\"RunMacroString\",\"RunMacro\",\"Whether to execute code contained in MacroString each time through loop\").RunMacroString=True\n#        obj.addProperty(\"App::PropertyBool\",\"A2PlusSolve\",\"Assemblers\",\"Be sure to open A2Plus workbench first.  Executes solve command each step in the loop\").A2PlusSolve = False\n#        obj.addProperty(\"App::PropertyStringList\",\"A2PlusConstraints\",\"Assemblers\",\"List of A2Plus constraints to solve, solve all if blank\\nPut # in front of those to ignore\")\n#        obj.addProperty(\"App::PropertyBool\",\"A2PlusRefreshConstraints\",\"Assemblers\", \\\n#                        \"Refresh A2PlusConstraints will all constraints in document on Refresh, if  True\").A2PlusRefreshConstraints=True\n#        obj.addProperty(\"App::PropertyBool\",\"Asm3Solve\",\"Assemblers\",\"Be sure to open Assembly 3 workbench first.  Executes solve command each step in the loop\").Asm3Solve = False\n#        obj.addProperty(\"App::PropertyBool\",\"Asm4Solve\",\"Assemblers\",\"Be sure to open Assembly 4 workbench first.  Executues solve command each step in the loop\").Asm4Solve = False\n#        obj.addProperty(\"App::PropertyBool\",\"ShowProgress\",animv,\"Whether to show progress in Description/Label2 column during animation\").ShowProgress = True\n#        obj.addProperty(\"App::PropertyBool\",\"StartAnimating\",animv,\"[Trigger] Start animating (or double click Animator in tree)\").StartAnimating = False\n#        obj.addProperty(\"App::PropertyBool\",\"StopAnimating\",animv,\"[Trigger] Stop animating (or double click Animator in tree)\").StopAnimating = False\n#        obj.addProperty(\"App::PropertyBool\",\"ResetAfterAnimation\",animv,\"Reset animated properties back to initial values after the animation is done\\n\\\n#You may use Undo after the animation to manually reset the values if this is False.\").ResetAfterAnimation = True\n#        obj.addProperty(\"App::PropertyBool\",\"Refresh\",animv,\"[Trigger] Refreshes Variables property lists, sets self back to False\\nUse this if objects/properties have changed\")\\\n#.Refresh = False\n#        obj.addProperty(\"App::PropertyInteger\",\"Frames\",animv,\"Number of frames / iterations per loop\").Frames = 100\n#        obj.addProperty(\"App::PropertyInteger\",\"CurrentFrame\",animv,\"Current frame in loop\")\n#        obj.setEditorMode(\"CurrentFrame\",2) #hidden\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"Sleep\",animv,\"Optional sleep time (in seconds) per frame / iteration\").Sleep = (0,0,float(\"inf\"),.1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"InitialDelay\",animv,\"Initial delay (in seconds) before animation starts\").InitialDelay = (0,-.045,60,.1)\n#        obj.addProperty(\"App::PropertyIntegerConstraint\",\"VariableCount\",animv,\"Number of variables to use\\nIncrease for more VariableNNN properties\").VariableCount = (3,0,100,1)\n#        obj.addProperty(\"App::PropertyStringList\",\"BlacklistedObjects\",\"SettingsAdvanced\",\"Object types not to include in Properties\").BlacklistedObjects =\\\n#[\"App::Origin\",\"App::Line\",\"App::Plane\"]\n#        obj.addProperty(\"App::PropertyStringList\",\"Supported\",\"SettingsAdvanced\",\"Supported property types\")\n#        obj.Supported = [\"App::PropertyInteger\",\"App::PropertyIntegerConstraint\",\"App::PropertyFloat\",\"App::PropertyFloatConstraint\",\n#\"App::PropertyLength\",\"App::PropertyAngle\",\"App::PropertyArea\",\"App::PropertyDistance\",\"App::PropertyPercent\",\"App::PropertyQuantity\",\n#\"App::PropertyQuantityConstraint\",\"App::PropertySpeed\",\"App::PropertyVolume\",\"App::PropertyPlacement\",\"App::PropertyVector\",\n#\"App::PropertyMatrix\",\"Sketcher::PropertyConstraintList\"]\n#        self.properties = []\n#        self.fpName = obj.Name\n#        self.isAnimating = False\n#        self.expressionDict = {} #to hold objects' initial ExpressionEngine before animation\n#        self.stringToRun = \"\" #from macro file\n#        self.stringToRunFromMacroString = \"\"\n#        self.macroPermissions = 0 #you have to giver permission at least once each session\n#        self.cameraPosition = \"\" #used if FreezeCamera = True\n#        obj.Proxy = self\n#\n#    def getSubProperties(self,prop,typeId,obj):\n#        if not \"Placement\" in typeId and not \"Vector\" in typeId and not \"Matrix\" in typeId and not \"ConstraintList\" in typeId \\\n#                                                          and not \"Spreadsheet::Sheet\" in typeId and not \"Rotation\" in typeId:\n#            return [prop]\n#        elif \"Rotation\" in typeId:\n#            return [prop+\".Angle\",prop+\".Axis.x\",prop+\".Axis.y\",prop+\".Axis.z\",prop+\".Roll\",prop+\".Pitch\",prop+\".Yaw\"]\n#        elif \"Placement\" in typeId:\n#            return [prop+\".Rotation.Angle\",prop+\".Rotation.Axis.x\",prop+\".Rotation.Axis.y\",prop+\\\n#                   \".Rotation.Axis.z\",prop+\".Rotation.Pitch\",prop+\".Rotation.Yaw\",prop+\\\n#                   \".Rotation.Roll\",prop+\".Base.x\",prop+\".Base.y\",prop+\".Base.z\"]\n#        elif \"Vector\" in typeId:\n#            return [prop+\".x\",prop+\".y\",prop+\".z\"]\n#        elif \"Matrix\" in typeId:\n#            return [prop+\".A11\",prop+\".A12\",prop+\".A13\",prop+\".A14\",prop+\".A21\",prop+\".A22\",prop+\".A23\",prop+\\\n#                   \".A24\",prop+\".A31\",prop+\".A32\",prop+\".A33\",prop+\".A34\",\n#prop+\".A41\",prop+\".A42\",prop+\".A43\",prop+\".A44\"]\n#        elif \"ConstraintList\" in typeId:\n#            conlist = getattr(obj,prop)\n#            names = [prop + \".\" + con.Name for con in conlist if con.Name]\n#            return names\n#        elif \"Spreadsheet::Sheet\" in typeId:\n#            FreeCAD.Console.PrintMessage(\"Spreadsheet aliases\\n\")\n#            ignore = [\"columnWidths\",\"rowHeights\"]\n#            aliases = [prop + \".\" + pl for pl in obj.PropertiesList if pl not in ignore]\n#            FreeCAD.Console.PrintMessage(str(aliases)+\"\\n\")\n#            return aliases\n#\n#    def onDocumentRestored(self, obj):\n#        self.macroPermissions = 0 #require permission at least once per session\n#\n#    def onChanged(self, fp, prop):\n#        if prop == \"Refresh\" and fp.Refresh:\n#            fp.Refresh = False\n#            self.setupVariables(fp) #calls refresh()\n#            if hasattr(fp,\"A2PlusRefreshConstraints\") and fp.A2PlusRefreshConstraints:\n#                self.setupA2PlusConstraints(fp)\n#        elif prop == \"VariableCount\":\n#            self.setupVariables(fp)\n#        elif prop == \"StartAnimating\" and fp.StartAnimating:\n#            fp.StartAnimating = False\n#            t = QtCore.QTimer()\n#            t.singleShot(50+fp.InitialDelay*1000, self.startAnimating) #avoid warning message about selection changing while committing data\n#        elif \"Variable\" in prop and not bool(\"Count\" in prop or \"Nth\" in prop or \"Start\" in prop or \"Step\" in prop):\n#            self.checkAndWarnAliases(fp,prop)\n#        elif \"MacroFile\" in prop and fp.MacroFile:\n#            self.readMacroFile(fp)\n#        elif \"MacroString\" in prop and fp.MacroString != DEFAULT_MACRO_STRING:\n#            self.readMacroString(fp)\n#        elif \"PathToFFMPEG\" in prop and hasattr(fp,\"PathToFFMPEG\"):\n#            pg = FreeCAD.ParamGet(\"User parameter:Plugins/Animator_Macro\")\n#            pg.SetString(\"PathToFFMPEG\",fp.PathToFFMPEG)\n#        elif \"PathToGif\" in prop and hasattr(fp,\"PathToGif\"):\n#            pg = FreeCAD.ParamGet(\"User parameter:Plugins/Animator_Macro\")\n#            pg.SetString(\"PathToGif\",fp.PathToGif)\n#\n#    def setupGifFolder(self,fp):\n#        \"\"\"cleans up folder of any existing PNG and GIF files, creates folder if necessary\"\"\"\n#        if not hasattr(fp,\"MakeGif\") or not fp.MakeGif:\n#            return\n#        if not fp.PathToFFMPEG:\n#            pg = FreeCAD.ParamGet(\"User parameter:Plugins/Animator_Macro\")\n#            fp.PathToFFMPEG = pg.GetString(\"PathToFFMPEG\",\"\")\n#            if not fp.PathToFFMPEG:\n#                FreeCAD.Console.PrintError(\"You must set the path to FFMPEG in order to make the animated gif\\n\")\n#                return False\n#        if not fp.PathToGif:\n#            macro_path = FreeCAD.getUserMacroDir(True)\n#            subfolder = \"Animator/screen_grabs\"\n#            fp.PathToGif = os.path.join(macro_path,subfolder)\n#        if not os.path.exists(fp.PathToGif):\n#            os.makedirs(fp.PathToGif)\n#        existing_pngs = glob.glob(os.path.join(fp.PathToGif,\"*.png\"))\n#        for file_path in existing_pngs:\n#            os.remove(file_path)\n#        if not fp.AnimatedGifFilename:\n#            FreeCAD.Console.PrintError(\"You must provide a name for the new animated gif file in the AnimatedGifFilename property\\n\")\n#            return False\n#        return True #success\n#\n#    def makeGifFrame(self,fp, frame):\n#        \"\"\"called during animation loop.  Makes the screen shot for the current frame\"\"\"\n#        if not hasattr(fp,\"MakeGif\") or not fp.MakeGif:\n#            return\n#        screenshot_file = os.path.join(fp.PathToGif,f\"frame_{frame:03d}.png\")\n#        if fp.FitAllEachFrame:\n#            FreeCADGui.SendMsgToActiveView(\"ViewFit\")\n#        if os.path.exists(screenshot_file):\n#            os.remove(screenshot_file)\n#        FreeCADGui.ActiveDocument.ActiveView.saveImage(screenshot_file, fp.GifWidth, fp.GifHeight, fp.BGColor)\n#\n#    def makeGif(self,fp):\n#        \"\"\"make the final animated gif from all the screen shot frames\"\"\"\n#        output_gif = os.path.join(fp.PathToGif,fp.AnimatedGifFilename)\n#        if os.path.exists(output_gif):\n#            os.remove(output_gif)\n#        frame_duration = fp.GifFrameRate / 1000.0\n#        path_to_ffmpeg = fp.PathToFFMPEG\n#        ffmpeg_command = [\n#           path_to_ffmpeg,\n#           \"-framerate\", f\"1/{frame_duration}\",\n#           \"-i\", os.path.join(fp.PathToGif, \"frame_%03d.png\"),\n#           \"-y\", #overwrite output_gif if it exits\n#           output_gif\n#        ]\n#        subprocess.run(ffmpeg_command)\n#        FreeCAD.Console.PrintMessage(f\"{output_gif} created.\\n\")\n#\n#\n#    def getCameraPosition(self):\n#        v = FreeCADGui.activeView()\n#        self.cameraPosition = v.getCamera()\n#\n#    def restoreCameraPosition(self):\n#        v = FreeCADGui.activeView()\n#        v.setCamera(self.cameraPosition)\n#\n#    def readMacroFile(self,fp):\n#        if DEBUG:\n#            print(\"reading macro file\")\n#        import os\n#        if not fp.MacroFile:\n#            self.stringToRun = \"\"\n#            return\n#        fin = open(fp.MacroFile, 'r')\n#        self.stringToRun = fin.read()\n#        fin.close()\n#\n#    def readMacroString(self,fp):\n#        if DEBUG:\n#            print(\"reading macro string\")\n#        self.stringToRunFromMacroString = \"\\n\".join(fp.MacroString)\n#\n#    def runString(self, lastFrame = False, bRunMacroString=False):\n#        if DEBUG:\n#            print (\"running macro file...\")\n#        macro_string = self.stringToRun if not bRunMacroString else self.stringToRunFromMacroString\n#        import FreeCAD, FreeCADGui\n#        fp = FreeCAD.ActiveDocument.getObject(self.fpName)\n#        import sys, importlib\n#        my_name = 'my_macro'\n#        my_spec = importlib.util.spec_from_loader(my_name, loader=None)\n#        my_macro = importlib.util.module_from_spec(my_spec)\n#        my_macro.FreeCAD = FreeCAD\n#        my_macro.App = FreeCAD\n#        my_macro.Gui = FreeCADGui\n#        my_macro.FreeCADGui = FreeCADGui\n#        my_macro.AnimatorLastFrame = lastFrame\n#        my_macro.doc = fp.Document\n#        my_macro.Animator = fp\n#        my_macro.con = FreeCAD.Console\n#        my_macro.fp = fp\n#        my_macro.cam = Camera()\n#        my_macro.props = [getattr(fp,p) for p in fp.PropertiesList if \"Enumeration\" in fp.getTypeIdOfProperty(p) if getattr(fp,p) != 'Select Property']\n#        my_macro.objs = [fp.Document.getObject(p.split(\".\")[0]) for p in my_macro.props]\n#        my_macro.props = [p[p.index(\".\")+1:] for p in my_macro.props]\n#        def setExpression(idx,expr):\n#            my_macro.objs[idx].setExpression(my_macro.props[idx],expr)\n#            my_macro.doc.recompute()\n#        my_macro.setExpression = lambda idx,expr: setExpression(idx,expr)\n#        def getValue(idx):\n#              cur_obj = my_macro.objs[idx]\n#              cur_prop = my_macro.props[idx]\n#              fp.setExpression(\"ScrapString\",f\"{cur_obj.Name}.{cur_prop}\")\n#              return round(float(fp.ScrapString),6)\n#        my_macro.getValue = lambda idx: getValue(idx)\n#        def setStep(idx,val):\n#            setattr(fp,f\"Variable{format(idx+1,'03')}Step\",val)\n#        my_macro.setStep = lambda idx,val:setStep(idx,val)\n#        try:\n#            exec(macro_string, my_macro.__dict__)\n#        except Exception as e:\n#            FreeCAD.Console.PrintError(f\"Animator: error running script: {e}\\n\")\n#            self.isAnimating = False\n#            raise\n#\n#    def getPermissionFromUser(self,fp,bRunMacroString=False):\n#        msgBox = QtGui.QMessageBox()\n#        msgBox.setWindowTitle(\"Animator Macro Security Warning\")\n#        msgBox.setIcon(QtGui.QMessageBox.Warning)\n#        if not bRunMacroString:\n#            msgBox.setText(\"Warning: The following file will be executed: \" + fp.MacroFile)\n#            info = \"Do you want to execute the contents of this file?\\n\\n\"\n#        else:\n#            msgBox.setText(\"Warning: Contents of property Macro String will be executed as python code\")\n#            info = \"Do you want to execute the contents of this string?\\n\\n\"\n#        info += \"DO NOT ALLOW IF YOU GOT THIS FILE FROM AN UNTRUSTED SOURCE!!!\\n\\n\"\n#        msgBox.setInformativeText(info)\n#        msgBox.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No | QtGui.QMessageBox.Help)\n#        yesBtn = msgBox.button(QtGui.QMessageBox.StandardButton.Yes)\n#        noBtn = msgBox.button(QtGui.QMessageBox.StandardButton.No)\n#        helpBtn = msgBox.button(QtGui.QMessageBox.StandardButton.Help)\n#        helpBtn.setText(\"Show me the code, but do not run\")\n#        yesBtn.setText(\"Yes, run python code\")\n#        noBtn.setText(\"No, do not run python code\")\n#        ret = msgBox.exec()\n#        if ret == QtGui.QMessageBox.Yes:\n#            self.macroPermissions += 1\n#            return True\n#        elif ret == QtGui.QMessageBox.No: #permission denied\n#            self.macroPermissions = 0\n#            return False\n#        elif ret == QtGui.QMessageBox.Help: #show code\n#            msgBox2 = QtGui.QDialog()\n#            layout = QtGui.QVBoxLayout()\n#            text_browser = QtGui.QTextBrowser()\n#            if bRunMacroString:\n#                text_browser.setPlainText(self.stringToRunFromMacroString)\n#            else:\n#                text_browser.setPlainText(self.stringToRun)\n#            layout.addWidget(text_browser)\n#            ok = QtGui.QPushButton(\"OK\")\n#            msgBox2.setWindowTitle(\"Animator: Code to run:\")\n#            ok.clicked.connect(msgBox2.accept)\n#            msgBox2.setLayout(layout)\n#            ret = msgBox2.exec_()\n#            return False\n#\n#    def startAnimating(self, skip_permission = False):\n#        self.isAnimating = True\n#        fp = FreeCAD.ActiveDocument.getObject(self.fpName)\n#        cam = None\n#        camObj = None\n#        if hasattr(fp,\"CamPlacementObject\") and fp.CamPlacementObject:\n#            camObj = fp.CamPlacementObject\n#            if not hasattr(camObj,\"Placement\"):\n#                FreeCAD.Console.PrintError(\"Cam Placement Object has no Placement property!\\n\")\n#            else:\n#                cam = Camera()\n#                cam.Placement = camObj.Placement\n#        animated = 0 #check if there is any animation work to do\n#        if hasattr(fp,\"RunMacro\") and fp.RunMacro and fp.MacroFile:\n#            self.readMacroFile(fp)\n#            animated += 1\n#            if not skip_permission or self.macroPermissions == 0:\n#                if not self.getPermissionFromUser(fp):\n#                    FreeCAD.Console.PrintWarning(\"Animator: Animation was canceled by user.\\n\")\n#                    self.isAnimating = False\n#                    return\n#        if hasattr(fp,\"RunMacroString\") and fp.RunMacroString and fp.MacroString != DEFAULT_MACRO_STRING:\n#            self.readMacroString(fp)\n#            animated += 1\n#            if not skip_permission or self.macroPermissions == 0:\n#                if not self.getPermissionFromUser(fp,bRunMacroString=True):\n#                    FreeCAD.Console.PrintWarning(\"Animator: Animation was canceled by user.\\n\")\n#                    self.isAnimating = False\n#                    return\n#        variables = {} #tuple ii:(prop,start,step)\n\n#\n#        for ii in range(1,fp.VariableCount+1):\n#            variables[ii] = (getattr(fp,\"Variable\"+format(ii,'03')),getattr(fp,\"Variable\"+format(ii,'03')+\"Start\"),\\\n#                             getattr(fp,\"Variable\"+format(ii,'03')+\"Step\"),getattr(fp,\"Variable\"+format(ii,'03')+\"Nth\"))\n#            if getattr(fp,\"Variable\"+format(ii,'03')) != \"Select Property\":\n#                animated += 1\n#        if animated == 0:\n#            FreeCAD.Console.PrintError(\"No properties to animate.  Select some properties and try again.\\n\")\n#            self.isAnimating = False\n#            return\n#        else:\n#            for k,v in variables.items(): #save obj.ExpressionEngine for each obj in self.expressionsDict\n#                prop = v[0]\n#                objname = prop.split(\".\")[0]\n#                obj = FreeCAD.ActiveDocument.getObject(objname)\n#                self.saveExpressions(fp,obj)\n#        counter = 1\n#        oldLabel2 = fp.Label2\n#        if hasattr(fp,\"A2PlusConstraints\") and fp.A2PlusSolve:\n#            uncommented = [con for con in fp.A2PlusConstraints if con[0] != \"#\"]\n#            runlist = [fp.Document.getObject(con) for con in uncommented]\n#            FreeCAD.Console.PrintMessage(f\"Animator: using these constraints: {uncommented}\"+chr(10))\n#        if hasattr(fp,\"CurrentFrame\"):\n#            fp.CurrentFrame = 0 #use this to ensure we have undone everything later\n#        if hasattr(fp, \"MakeGif\") and fp.MakeGif:\n#            if not self.setupGifFolder(fp): #returns false if some animated gif properties are not properly configured\n#                FreeCAD.Console.PrintError(\"Error setting up animation folder.\\n\")\n#                return\n#        if hasattr(fp,\"FreezeCamera\") and fp.FreezeCamera:\n#            self.getCameraPosition()\n#        fp.Document.openTransaction(\"Reset animated objects\")\n#        while (counter <= fp.Frames and not fp.StopAnimating):\n#            if hasattr(fp,\"CurrentFrame\"):\n#                fp.CurrentFrame = counter\n#            QtGui.QApplication.instance().processEvents()\n#            if cam and camObj:\n#                if not fp.ReverseCam:\n#                    cam.Placement = camObj.Placement\n#                else:\n#                    plm = camObj.Placement\n#                    plm.Rotation = plm.Rotation * (FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180))\n#                    cam.Placement = plm\n#            for jj in range(1,fp.VariableCount+1):\n#                if variables[jj][0] != \"Select Property\":\n#                    nth = counter % variables[jj][3] #remainder of dividing counter by Nth property\n#                    step = getattr(fp,\"Variable\"+format(jj,'03')+\"Step\")\n#                    if nth == 0 and step != 0.0: #set step to 0 to not animate this property\n#                        self.setProperty(fp,variables[jj][0],variables[jj][1] + step * counter)\n#            if fp.ShowProgress:\n#                fp.Label2 = str(counter)+\"/\"+str(fp.Frames)\n#            if fp.A2PlusSolve:\n#                if not hasattr(fp,\"A2PlusConstraints\") or len(fp.A2PlusConstraints) == 0:\n#                    FreeCADGui.runCommand('a2p_SolverCommand',0)\n#                else: #run only selected constraints\n#                    if a2p_present:\n#                        a2p_solversystem.solveConstraints(fp.Document, None, False, matelist = runlist, showFailMessage=False)\n#            if fp.Asm3Solve:\n#                FreeCADGui.runCommand('asm3CmdSolve',0)\n#            if fp.Asm4Solve:\n#                FreeCADGui.runCommand('Asm4_updateAssembly',0)\n#            if fp.RunMacro and self.stringToRun:\n#                self.runString(counter == fp.Frames)\n#            if hasattr(fp,\"RunMacroString\") and fp.RunMacroString and fp.MacroString != DEFAULT_MACRO_STRING:\n#                self.runString(counter == fp.Frames, bRunMacroString=True)\n#            if hasattr(fp,\"MakeGif\") and fp.MakeGif:\n#                self.makeGifFrame(fp,counter) #make the current frame\n#                if counter == fp.Frames:\n#                    self.makeGif(fp) #make animated gif\n#            FreeCADGui.updateGui()\n#            if hasattr(fp,\"FreezeCamera\") and fp.FreezeCamera:\n#                self.restoreCameraPosition()\n#            time.sleep(fp.Sleep)\n#            counter += 1\n#        fp.Document.commitTransaction()\n#        if hasattr(fp,\"ResetAfterAnimation\") and fp.ResetAfterAnimation:\n#            fp.Document.undo()\n#            if hasattr(fp,\"CurrentFrame\") and fp.CurrentFrame != 0:\n#                while fp.CurrentFrame != 0:\n#                    fp.Document.undo()\n#        fp.StopAnimating = False\n#        self.isAnimating = False\n#        self.restoreExpressions(fp)\n#        fp.Label2 = oldLabel2\n#        FreeCAD.ActiveDocument.recompute()\n#\n#    def setupA2PlusConstraints(self,fp):\n#        if not a2p_present:\n#            return\n#        constraints = [obj.Name for obj in fp.Document.Objects if \"ConstraintInfo\" in obj.Content and not \"mirror\" in obj.Name]\n#        fp.A2PlusConstraints = constraints\n#\n#    def setupVariables(self,fp):\n#        self.refresh(fp)\n#        ii = fp.VariableCount+1\n#        while hasattr(fp,\"Variable\"+format(ii,'03')):\n#            fp.removeProperty(\"Variable\"+format(ii,'03'))\n#            fp.removeProperty(\"Variable\"+format(ii,'03')+\"Start\")\n#            fp.removeProperty(\"Variable\"+format(ii,'03')+\"Step\")\n#            fp.removeProperty(\"Variable\"+format(ii,'03')+\"Nth\")\n#            ii += 1\n#        for ii in range(1,fp.VariableCount+1):\n#            baseName = \"Variable\"+format(ii,'03')\n#            if not hasattr(fp,baseName):\n#                fp.addProperty(\"App::PropertyEnumeration\",baseName,\"AnimatorVariables\",\"Object.Property to use for this variable\")\n#                setattr(fp,baseName,self.properties)\n#            else:\n#                saved = getattr(fp,baseName)\n#                setattr(fp,baseName,self.properties)\n#                if saved in self.properties:\n#                    setattr(fp,baseName,saved)\n#            if not hasattr(fp,baseName+\"Start\"):\n#                fp.addProperty(\"App::PropertyFloat\",baseName+\"Start\",\"AnimatorVariables\",\"Starting value for this variable\")\n#                setattr(fp,baseName+\"Start\",0)\n#            if not hasattr(fp,baseName+\"Step\"):\n#                fp.addProperty(\"App::PropertyFloat\",baseName+\"Step\",\"AnimatorVariables\",\"Step -- amount by which this variable is incremented (or decremented if negative) each frame.\")\n#                setattr(fp,baseName+\"Step\",1)\n#            if not hasattr(fp,baseName+\"Nth\"):\n#               fp.addProperty(\"App::PropertyIntegerConstraint\",baseName+\"Nth\",\"AnimatorVariables\",\"If other than 1, only increment/decrement every nth frame.\")\n#               setattr(fp,baseName+\"Nth\",(1,1,10000,1))\n#\n#    def isSupportedType(self,fp,typeId):\n#        '''returns False if not supported, else True'''\n#        if typeId not in fp.Supported:\n#            return False\n#        else:\n#            return True\n#\n#    def editMacroString(self):\n#        fp = FreeCAD.ActiveDocument.getObject(self.fpName)\n#        dlg = MacroStringEditor(fp)\n#        dlg.exec_()\n#\n#    def getProperties(self,fp,obj):\n#        '''get the supported properties of obj'''\n#        if obj.TypeId != \"Spreadsheet::Sheet\":\n#            props = [prop for prop in obj.PropertiesList if self.isSupportedType(fp,obj.getTypeIdOfProperty(prop)) \\\n#                     and  bool(obj.getEditorMode(prop) == [] or prop == \"AttachmentOffset\" or prop == \"Placement\")]\n#        else:\n#            props = [prop for prop in obj.PropertiesList if self.isSupportedType(fp,obj.getTypeIdOfProperty(prop))]\n#        return props\n#\n#    def saveExpressions(self,fp,obj):\n#        '''saves expression engine property of obj the first time setProperty() is called for obj'''\n#        if not obj in self.expressionDict.keys() and hasattr(obj,\"ExpressionEngine\"):\n#            self.expressionDict[obj.Name] = obj.ExpressionEngine\n#\n#    def restoreExpressions(self,fp):\n#        for k,v in self.expressionDict.items():\n#            obj = FreeCAD.ActiveDocument.getObject(k)\n#            for expr in v:\n#                obj.setExpression(expr[0],expr[1])\n#        self.expressionDict = {}\n#\n#    def checkAndWarnAliases(self,fp,prop):\n#        '''if user has selected an alias, then warn'''\n#        objname = getattr(fp,prop).split(\".\")[0]\n#        obj = FreeCAD.ActiveDocument.getObject(objname)\n#        if hasattr(obj,\"TypeId\") and obj.TypeId == \"Spreadsheet::Sheet\":\n#            FreeCAD.Console.PrintWarning(\"Warning: Spreadsheet aliases containing expressions will not be restored after animation is complete.\\n\")\n#\n#    def setProperty(self,fp,prop,val):\n#        '''prop is in form \"objectname.property.subproperty.subproperty\" ,e.g. \"Box.Placement.Base.x\"'''\n#        objname = prop.split(\".\")[0]\n#        obj = FreeCAD.ActiveDocument.getObject(objname)\n#        if obj.TypeId != \"Spreadsheet::Sheet\":\n#            obj.setExpression(prop[len(objname)+1:],str(val))\n#            FreeCAD.ActiveDocument.recompute()\n#            obj.setExpression(prop[len(objname)+1:],None)\n#        else:\n#            obj.set(prop[len(objname)+1:],str(val))\n#            FreeCAD.ActiveDocument.recompute()\n#\n#    def refresh(self,fp):\n#        '''setup Properties enumeration to contain each property of the objects supported objectname.propertyname format'''\n#        doc = FreeCAD.ActiveDocument\n#        objects = [obj for obj in doc.Objects if obj != fp and not obj.TypeId in fp.BlacklistedObjects]\n#        self.properties = []\n#        for obj in objects:\n#            props = self.getProperties(fp,obj)\n#            if props:\n#                for prop in props:\n#                    subprops = self.getSubProperties(prop,obj.getTypeIdOfProperty(prop),obj)\n#                    for sub in subprops:\n#                        self.properties.extend([obj.Name+\".\"+sub])\n#        self.properties.sort()\n#        self.properties = [\"Select Property\"] + self.properties\n#\n#\n#class PythonSyntaxHighlighter(QtGui.QSyntaxHighlighter):\n#    def __init__(self, parent=None):\n#        super().__init__(parent)\n#        self.highlighting_rules = []\n#        variable_format = QtGui.QTextCharFormat()\n#        variable_format.setForeground(QtGui.QColor(255, 170, 0))  # Yellow color for variables\n#        variable_format.setFontWeight(QtGui.QFont.Bold)\n#        self.highlighting_rules.append((r'\\b\\w+\\b', variable_format))\n#\n#        keyword_format = QtGui.QTextCharFormat()\n#        keyword_format.setForeground(QtGui.QColor(0, 0, 255))  # Blue color for keywords\n#        keyword_format.setFontWeight(QtGui.QFont.Bold)\n#        self.highlighting_rules.append((r'\\b(?:import|from|def|class|if|else|for|while|return|break|continue)\\b',\\\n#                                          keyword_format))\n#\n#        comment_format = QtGui.QTextCharFormat()\n#        comment_format.setForeground(QtGui.QColor(0, 170, 0))  # Green color for comments\n#        self.highlighting_rules.append((r'#.*$', comment_format))\n#\n#        string_format = QtGui.QTextCharFormat()\n#        string_format.setForeground(QtGui.QColor(255,0,0))  # red color for strings\n#        self.highlighting_rules.append((r'\".*?\"', string_format))\n#\n#        numeral_format = QtGui.QTextCharFormat()\n#        numeral_format.setForeground(QtGui.QColor(0,0,255))  # Blue color for numerals\n#        self.highlighting_rules.append((r'\\b\\d+\\b', numeral_format))\n#\n#        operator_format = QtGui.QTextCharFormat()\n#        operator_format.setForeground(QtGui.QColor(160, 160, 164))  # Color for operators\n#        self.highlighting_rules.append((r'[-+,:*/%=<>&|!^]', operator_format))\n#\n#    def highlightBlock(self, text):\n#        for pattern, char_format in self.highlighting_rules:\n#            regex = re.compile(pattern)\n#            for match in regex.finditer(text):\n#                self.setFormat(match.start(), match.end() - match.start(), char_format)\n#\n#\n#class MacroStringEditor(QtGui.QDialog):\n#    def __init__(self,fp,parent=FreeCADGui.getMainWindow()):\n#        super().__init__(parent)\n#        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)\n#        self.setAttribute(QtCore.Qt.WA_WindowPropagation, True)\n#        self.fp = fp\n#        layout = QtGui.QVBoxLayout()\n#        self.setLayout(layout)\n#        self.editor = QtGui.QPlainTextEdit()\n#        self.editor.setPlainText(\"\\n\".join(fp.MacroString))\n#        self.editor.setMinimumWidth(600)\n#        self.editor.setMinimumHeight(600)\n#        highlighter = PythonSyntaxHighlighter(self.editor.document())\n#        layout.addWidget(self.editor)\n#        buttons = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel)\n#        buttons.accepted.connect(self.accept)\n#        buttons.rejected.connect(self.reject)\n#        layout.addWidget(buttons)\n#\n#    def accept(self):\n#        self.fp.MacroString = self.editor.toPlainText().splitlines()\n#        self.fp.Document.recompute()\n#        super().accept()\n#\n#    def reject(self):\n#        print(\"rejected\")\n#        super().reject()\n#\n#\n#\n#class Camera:\n#    def __init__(self):\n#        # Get the active view and camera\n#        self.view = FreeCADGui.activeView()\n#        self.camera = self.view.getCamera()\n#        self.height = \"\"\n#        self.orientation = \"\"\n#        self.position = \"\"\n#        self.header = \"\"\n#        self.cam_type = \"\"\n#        self.nearDistance = \"\"\n#        self.farDistance = \"\"\n#        self.aspectRatioStr = \"\"\n#        self.aspectRatio = \"\"\n#        self.focalDistance = \"\"\n#        self.mappingStr = \"\"\n#        self.posStr = \"\"\n#        self.orientationStr = \"\"\n#        self.heightStr = \"\"\n#        self.focalDistanceStr = \"\"\n#        self.parse()\n#\n#    def __repr__(self):\n#        self.refresh()\n#        return self.camera\n#\n#    def refresh(self):\n#        \"\"\"refresh some internal variables\"\"\"\n#        self.camera = self.view.getCamera()\n#        self.parse()\n#\n#    def getHeader(self):\n#        \"\"\"returns the version of Open Inventor\"\"\"\n#        self.refresh()\n#        return self.header\n#\n#    def getType(self):\n#        \"\"\"returns Orthographic or Perspective\"\"\"\n#        self.refresh()\n#        return self.cam_type\n#\n#    @property\n#    def NearDistance(self):\n#        \"\"\"nearDistance sets clipping plane for near objects\"\"\"\n#        self.refresh()\n#        return float(self.nearDistance)\n#\n#    @property\n#    def FarDistance(self):\n#        \"\"\"farDistance sets clipping plane for far objects\"\"\"\n#        self.refresh()\n#        return float(self.farDistance)\n#\n#    @NearDistance.setter\n#    def NearDistance(self,val):\n#        \"\"\"nearDistance sets clipping plane for near objects\"\"\"\n#        self.refresh()\n#        self.nearDistance = str(val)\n#        self.unParse()\n#\n#    @FarDistance.setter\n#    def FarDistance(self,val):\n#        \"\"\"farDistance sets clipping plane for far objects\"\"\"\n#        self.refresh()\n#        self.farDistance = str(val)\n#        self.unParse()\n#\n#    @property\n#    def AspectRatio(self):\n#        \"\"\"width to height ratio\"\"\"\n#        self.refresh()\n#        return float(self.aspectRatio)\n#\n#    @AspectRatio.setter\n#    def AspectRatio(self, val):\n#        \"\"\"width to height ratio, must be greater than 0\"\"\"\n#        self.refresh()\n#        self.aspectRatio = str(val)\n#        self.unParse()\n#\n#    @property\n#    def FocalDistance(self):\n#        \"\"\"distance form viewpoint to point of focus, usually ignored\"\"\"\n#        self.refresh()\n#        return float(self.focalDistance)\n#\n#    @FocalDistance.setter\n#    def FocalDistance(self,val):\n#        \"\"\"distance form viewpoint to point of focus, usually ignored\"\"\"\n#        self.refresh()\n#        self.focalDistance = str(val)\n#        self.unParse()\n#\n#    def parse(self):\n#        \"\"\"parse camera string into separate self.values, called by refresh()\"\"\"\n#        d = self.camera.split()\n#        try:\n#            self.header = d[0]+' '+d[1] + ' '+d[2] # '#Inventor v2.1 ascii'\n#            self.cam_type = d[3] #'OrthographicCamera' #d[4] = '{'\n#            self.mappingStr = d[5] #viewportMapping\n#            self.mapping = d[6] #ADJUST_CAMERA\n#            self.posStr = d[7] #'position'\n#            self.position = d[8] + ' '+d[9]+' ' + d[10]\n#            self.orientationStr = d[11] #'orientation'\n#            self.orientation = d[12]+' '+d[13]+' '+d[14]+'  '+d[15]\n#            self.nearDistanceStr = d[16]#'nearDistance'\n#            self.nearDistance = d[17]\n#            self.farDistanceStr = d[18]#'farDistance'\n#            self.farDistance = d[19] #13.163915\n#            self.aspectRatioStr = d[20]#'aspectRatio'\n#            self.aspectRatio = d[21] #1\n#            self.focalDistanceStr = d[22] #'focalDistance'\n#            self.focalDistance = d[23]\n#            self.heightStr = d[24]\n#            self.height = d[25]\n#        except:\n#            FreeCAD.Console.PrintError(\"Failed to parse camera data\\n\")\n#\n#    def unParse(self):\n#        \"\"\"write the self.values into the camera string, set camera to it\"\"\"\n#        new_cam = self.header + '\\n' + self.cam_type + '{\\n' + self.mappingStr+' '+self.mapping+'\\n'\\\n#        + self.posStr + ' ' + self.position + '\\n' \\\n#        + self.orientationStr + ' ' + self.orientation + '\\n'\\\n#        + self.nearDistanceStr + ' ' + self.nearDistance + '\\n'\\\n#        + self.farDistanceStr + ' ' + self.farDistance + '\\n'\\\n#        + self.aspectRatioStr + ' ' + self.aspectRatio + '\\n'\\\n#        + self.focalDistanceStr + ' ' + self.focalDistance + '\\n'\\\n#        + self.heightStr + ' ' + self.height + '\\n'\\\n#        + '}\\n'\n#        self.camera = new_cam\n#        self.view.setCamera(self.camera)\n#\n#    @property\n#    def Height(self):\n#        \"\"\"height of the camera above scene\"\"\"\n#        self.refresh()\n#        height = float(self.height)\n#        return height\n#\n#    @Height.setter\n#    def Height(self, height):\n#        \"\"\"height of camera above scene\"\"\"\n#        self.refresh()\n#        self.height = str(height)\n#        self.unParse()\n#\n#    @property\n#    def Position(self):\n#        \"\"\"returns a vector of the current camera position\"\"\"\n#        self.refresh()\n#        position_str = self.position\n#        position_values = [float(val) for val in position_str.split()]\n#        position = FreeCAD.Vector(*position_values)\n#        return position\n#\n#    @Position.setter\n#    def Position(self, vector):\n#        \"\"\"set camera position, vector can be FreeCAD.Vector or (x,y,z) tuple\"\"\"\n#        self.refresh()\n#        new_position_str = ' '.join([str(val) for val in vector])\n#        self.position = new_position_str\n#        self.unParse()\n#\n#    @property\n#    def Orientation(self):\n#        \"\"\"returns the orientation as a tuple containing (axis,angle) which is (vector, float in degrees)\"\"\"\n#        self.refresh()\n#        orientation_str = self.orientation\n#        vals = [float(val) for val in orientation_str.split()]\n#        axis = FreeCAD.Vector(vals[0],vals[1],vals[2])\n#        angle = math.degrees(vals[3])\n#        return (axis,angle)\n#\n#    @property\n#    def OrientationEuler(self):\n#        \"\"\"cam orientation returns (yaw,pitch,roll)\"\"\"\n#        self.refresh()\n#        axis,angle = self.Orientation\n#        rot = FreeCAD.Rotation(axis, angle)\n#        euler_angles = rot.getYawPitchRoll()\n#        return euler_angles\n#\n#    @Orientation.setter\n#    def Orientation(self, orientation_data):\n#        \"\"\"sets orientation, Orientation = (axis, angle), which is (vector, float in degrees) or Orientation = Rotation\"\"\"\n#        isRotation = isinstance(orientation_data,FreeCAD.Rotation)\n#        if not isRotation and len(orientation_data) != 2:\n#            raise ValueError(\"Orientation must be a tuple or list containing (axis, angle), or a FreeCAD.Rotation\")\n#\n#        axis, angle = orientation_data\n#        self.refresh()\n#        if not isRotation:\n#            self.orientation = f\"{axis.x} {axis.y} {axis.z} {math.radians(angle)}\"\n#        else:\n#            self.orientation = f\"{axis.x} {axis.y} {axis.z} {angle}\" #angle in radians already if from a FreeCAD.Rotation object.\n#        self.unParse()\n#\n#    @OrientationEuler.setter\n#    def OrientationEuler(self, ypr_tuple):\n#        \"\"\"OrientationEuler = (yaw,pitch,roll) (3 floats)\"\"\"\n#        self.refresh()\n#        if not len(ypr_tuple) == 3:\n#            raise ValueError(\"Use a tuple of floats to set OrientationEuler, e.g. cam.OrientationEuler = (yaw,pitch,roll)\")\n#        yaw,pitch,roll = ypr_tuple\n#        rotation = FreeCAD.Rotation(float(yaw), float(pitch), float(roll))\n#        self.Orientation = (rotation.Axis, math.degrees(rotation.Angle))\n#\n#    @property\n#    def Placement(self):\n#        rot = FreeCAD.Rotation(self.Orientation)\n#        pos = self.Position\n#        plm = FreeCAD.Placement(pos,rot)\n#        return plm\n#\n#    @Placement.setter\n#    def Placement(self,plm):\n#        rot = plm.Rotation\n#        pos = plm.Base\n#        axis = rot.Axis\n#        angle = math.degrees(rot.Angle)\n#        self.Orientation = axis,angle\n#        self.Position = pos\n#\n#\n#\n#class AnimatorVP:\n#    def __init__(self, obj):\n#        '''Set this object to the proxy object of the actual view provider'''\n#        obj.Proxy = self\n#\n#    def doubleClicked(self,vobj):\n#        if vobj.Object.Proxy.isAnimating:\n#            vobj.Object.StopAnimating = True\n#        else:\n#            vobj.Object.StartAnimating = True\n#\n#    def attach(self,vobj):\n#        self.Object = vobj.Object\n#        self.standard = coin.SoGroup()\n#        vobj.addDisplayMode(self.standard,\"Standard\")\n#\n#    def onDelete(self, vobj, subelements):\n#        return True\n#\n#    def setupContextMenu(self, vobj, menu):\n#         text = {True:\"Unrefresh %1\",False:\"Refresh properties for %1\"}\n#         action = menu.addAction(text[vobj.Object.Refresh].replace(\"%1\",vobj.Object.Label))\n#         action.triggered.connect(lambda: setattr(vobj.Object,\"Refresh\",True))\n#         text = {True:\"Stop Animating %1\",False:\"Start Animating %1\"}\n#         action = menu.addAction(text[vobj.Object.StartAnimating].replace(\"%1\",vobj.Object.Label))\n#         action.triggered.connect(lambda: setattr(vobj.Object,\"StartAnimating\",True))\n#         text = {True:\"Start Animating %1\",False:\"Stop Animating %1\"}\n#         action = menu.addAction(text[vobj.Object.StopAnimating].replace(\"%1\",vobj.Object.Label))\n#         action.triggered.connect(lambda: setattr(vobj.Object,\"StopAnimating\",True))\n#         text = \"Edit Macro String\"\n#         action = menu.addAction(text)\n#         action.triggered.connect(vobj.Object.Proxy.editMacroString)\n#\n#    def updateData(self, fp, prop):\n#        '''If a property of the handled feature has changed we have the chance to handle this here'''\n#        if prop == \"StartAnimating\" or prop == \"StopAnimating\":\n#            fp.ViewObject.signalChangeIcon()\n#\n#    def getDisplayModes(self,obj):\n#        '''Return a list of display modes.'''\n#        modes=[\"Standard\"]\n#        return modes\n#\n#    def claimChildren(self):\n#        return[]\n#\n#    def getDefaultDisplayMode(self):\n#        '''Return the name of the default display mode. It must be defined in getDisplayModes.'''\n#        return \"Standard\"\n#\n#    def setDisplayMode(self,mode):\n#        '''Map the display mode defined in attach with those defined in getDisplayModes.\\\n#                Since they have the same names nothing needs to be done. This method is optional'''\n#        return mode\n#\n#    def onChanged(self, vp, prop):\n#        '''Here we can do something when a single property got changed'''\n#        #FreeCAD.Console.PrintMessage(\"Change property: \" + str(prop) + \"\\n\")\n#        pass\n#\n#    def getIcon(self):\n#        '''Return the icon in XPM format which will appear in the tree view. This method is\\\n#                optional and if not defined a default icon is shown.'''\n#        iconAnimating = \"\"\"\n#/* XPM */\n#static char *_635391677201[] = {\n#/* columns rows colors chars-per-pixel */\n#\"64 64 4 1 \",\n#\"  c black\",\n#\". c #FFFF7F7F2727\",\n#\"X c #FFFFF2F20000\",\n#\"o c None\",\n#/* pixels */\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXXooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"ooo   XXXooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"ooo   XXXooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"ooo   XXXooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\"\n#};\"\"\"\n\n#        iconNormal = \"\"\"\n#/* XPM */\n#static char *_635391677201[] = {\n#/* columns rows colors chars-per-pixel */\n#\"64 64 4 1 \",\n#\"  c black\",\n#\". c #FFFF7F7F2727\",\n#\"X c #FFFFF2F20000\",\n#\"o c None\",\n#/* pixels */\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"ooooooooooooooooooooooooooooooooooooooooooXXX   XXX   XXX    ooo\",\n#\"ooooooooooooooooooooooooooooooooooooooooooXXX   XXX   XXX    ooo\",\n#\"ooooooooooooooooooooooooooooooooooooooooooXXX   XXX   XXX    ooo\",\n#\"ooooooooooooooooooooooooooooooooooooooooooXXX   XXX   XXX    ooo\",\n#\"ooooooooooooooooooooooooXXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooooooooooooooooooooooooXXX   XXX   XXX   XXXooooooooooooooooooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXXooooooooooooooooooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXXooooooooooooooooooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXXooooooooooooooooooo\",\n#\"ooo   XXX   XXX   XXX   oooooooooooooooooooooooooooooooooooooooo\",\n#\"ooo   XXX   XXX   XXX   oooooooooooooooooooooooooooooooooooooooo\",\n#\"ooo   XXXooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"ooo   XXXooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"ooo   XXXooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"ooo   XXXooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"ooo   XXXooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo     ................................................     ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"ooo                                                          ooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n#\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\"\n#};\"\"\"\n#        if self.Object.Proxy.isAnimating:\n#            return iconAnimating\n#        else:\n#            return iconNormal\n#\n#    def __getstate__(self):\n#        '''When saving the document this object gets stored using Python's json module.\\\n#                Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\\\n#                to return a tuple of all serializable objects or None.'''\n#        return None\n#\n#    def __setstate__(self,state):\n#        '''When restoring the serialized object from document we have the chance to set some internals here.\\\n#                Since no data were serialized nothing needs to be done here.'''\n#        return None\n\n\n########################################\n#CODE_ENDS_HERE\n\nBASENAME = 'animator'\n\ndef makeObject(FP):\n\n    doc = FreeCAD.ActiveDocument if FreeCAD.ActiveDocument else FreeCAD.newDocument()\n    fp = doc.addObject(\"App::FeaturePython\",\"Animator\")\n    FP.Animator(fp)\n    FP.AnimatorVP(fp.ViewObject)\n    fp.Proxy.setupVariables(fp)\n    fp.Proxy.setupA2PlusConstraints(fp)\n    sel = FreeCADGui.Selection.getSelection()\n    if sel:\n        obj = sel[0]\n        if hasattr(obj,\"Placement\"):\n            fp.CamPlacementObject = obj\n\n\n#################\ndef writeFile():\n    with open(py_file,\"w\") as outfile:\n        for line in code.splitlines():\n            if \"#CODE_ENDS_HERE\" in line:\n                break\n            if line.startswith('#'):\n                if line == \"# -*- coding: utf-8 -*-\":\n                    line = \"#\" + line\n                outfile.write(line[1:]+\"\\n\") #skip first character (#)\n\n\n\n############\n#if __name__ == \"__main__\":\n#    makeObject(None)\n#    raise Exception(\"quick exit for testing/debugging\")\n############\n\n#following is for benefit of addon manager to install toolbar icon\n__icon__ = \"\"\"\n/* XPM */\nstatic char *_635391677201[] = {\n\"64 64 4 1 \",\n\"  c black\",\n\". c #FFFF7F7F2727\",\n\"X c #FFFFF2F20000\",\n\"o c None\",\n/* pixels */\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"ooooooooooooooooooooooooooooooooooooooooooXXX   XXX   XXX    ooo\",\n\"ooooooooooooooooooooooooooooooooooooooooooXXX   XXX   XXX    ooo\",\n\"ooooooooooooooooooooooooooooooooooooooooooXXX   XXX   XXX    ooo\",\n\"ooooooooooooooooooooooooooooooooooooooooooXXX   XXX   XXX    ooo\",\n\"ooooooooooooooooooooooooXXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n\"ooooooooooooooooooooooooXXX   XXX   XXX   XXXooooooooooooooooooo\",\n\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXXooooooooooooooooooo\",\n\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXXooooooooooooooooooo\",\n\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXXooooooooooooooooooo\",\n\"ooo   XXX   XXX   XXX   oooooooooooooooooooooooooooooooooooooooo\",\n\"ooo   XXX   XXX   XXX   oooooooooooooooooooooooooooooooooooooooo\",\n\"ooo   XXXooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"ooo   XXXooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"ooo   XXXooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"ooo   XXXooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"ooo   XXXooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n\"ooo   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX   XXX    ooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"ooo                                                          ooo\",\n\"ooo                                                          ooo\",\n\"ooo                                                          ooo\",\n\"ooo                                                          ooo\",\n\"ooo     ................................................     ooo\",\n\"ooo     ................................................     ooo\",\n\"ooo     ................................................     ooo\",\n\"ooo     ................................................     ooo\",\n\"ooo                                                          ooo\",\n\"ooo                                                          ooo\",\n\"ooo                                                          ooo\",\n\"ooo                                                          ooo\",\n\"ooo                                                          ooo\",\n\"ooo     ................................................     ooo\",\n\"ooo     ................................................     ooo\",\n\"ooo     ................................................     ooo\",\n\"ooo     ................................................     ooo\",\n\"ooo                                                          ooo\",\n\"ooo                                                          ooo\",\n\"ooo                                                          ooo\",\n\"ooo                                                          ooo\",\n\"ooo                                                          ooo\",\n\"ooo     ................................................     ooo\",\n\"ooo     ................................................     ooo\",\n\"ooo     ................................................     ooo\",\n\"ooo     ................................................     ooo\",\n\"ooo                                                          ooo\",\n\"ooo                                                          ooo\",\n\"ooo                                                          ooo\",\n\"ooo                                                          ooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\"\n};\"\"\"\n\nif __name__ == \"__main__\":\n    import os\n    fin = open(__file__, 'r')\n    code = fin.read()\n    fin.close()\n    version = code.splitlines()[1][16:]\n    real_path = os.path.realpath(__file__)\n    dir_path = os.path.dirname(real_path)\n    py_file = real_path.replace(\".FCMacro\",\".py\").replace('Animator','animator')\n    bHasFile = os.path.exists(py_file)\n    noImport = False #user elects not to save import file\n\n    if not bHasFile:\n        from PySide import QtGui\n        window = QtGui.QApplication.activeWindow()\n        mb = QtGui.QMessageBox()\n        mb.setWindowTitle(BASENAME+\" setup\")\n        mb.setIcon(mb.Information)\n        mb.setStandardButtons(mb.Ok | mb.Cancel)\n        mb.setDefaultButton(mb.Cancel)\n        okBtn = mb.button(QtGui.QMessageBox.StandardButton.Ok)\n        cancelBtn = mb.button(QtGui.QMessageBox.StandardButton.Cancel)\n        okBtn.setText(\"Create file\")\n        cancelBtn.setText(\"Do not create file\")\n        caption = \"In order for \"+BASENAME+\" objects to be parametric after saving and reloading file\\n\\\nwe need to create another file on this computer.  File to be created will be: \\n\\n\"+py_file+\"\\n\\n\\\nThis makes it available to the system upon restarting FreeCAD and loading documents containing the \\\n\"+BASENAME+\" feature python objects.  Create file now?\\n\\n\"\n        mb.setText(caption)\n        ret = mb.exec_()\n        if ret == mb.Ok:\n            writeFile()\n            QtGui.QMessageBox.information(window,\"Success\",\"File successfully created.  Please note: if you uninstall \"+BASENAME+\" macro you need to manually remove \"+py_file+\", too.\\n\")\n        else:\n            new_lines = []\n            for line in code.splitlines():\n                if line.startswith('#'):\n                    if \"CODE_ENDS_HERE\" in line:\n                        break\n                    if line == \"# -*- coding: utf-8 -*-\":\n                        new_lines.append(line+\"\\n\")\n                        continue\n                    new_lines.append(line[1:]+\"\\n\")\n            code = \"\".join(new_lines)\n\n            #credit to Mila Nautikus for his answer to a question on stackoverflow, which I modified here\n            #in this example the filename is pdwrapper.py\n            #https://stackoverflow.com/questions/5362771/how-to-load-a-module-from-code-in-a-string\n\n            ##########\n            import sys, importlib\n            my_name = BASENAME\n            my_spec = importlib.util.spec_from_loader(my_name, loader=None)\n\n            my_macro = importlib.util.module_from_spec(my_spec)\n\n            exec(code,my_macro.__dict__)\n            sys.modules[BASENAME] = my_macro\n            makeObject(my_macro)\n            noImport = True\n\n    if not noImport: #don't never use no double negatives\n        import addonmanager_utilities as utils\n        import animator as FP\n        if FP.__version__ != __version__:\n            writeFile()\n            from PySide import QtCore,QtGui\n            window = QtGui.QApplication.activeWindow()\n            mbox = QtGui.QMessageBox()\n            mbox.setWindowTitle(BASENAME+\" updated\")\n\n            mbox.setText(BASENAME+\".py has been updated to version \"+__version__+\". \\\nYou must restart FreeCAD for the new changes to take effect and to use the macro.\")\n            mbox.setIcon(mbox.Warning)\n            mbox.setStandardButtons(mbox.Ok | mbox.Cancel)\n            mbox.setDefaultButton(mbox.Cancel)\n            okBtn = mbox.button(QtGui.QMessageBox.StandardButton.Ok)\n            cancelBtn = mbox.button(QtGui.QMessageBox.StandardButton.Cancel)\n            okBtn.setText(\"Restart now\")\n            cancelBtn.setText(\"Restart later\")\n            ret = mbox.exec_()\n            if ret == mbox.Ok:\n                QtCore.QTimer.singleShot(1000, utils.restart_freecad)\n        else:\n            makeObject(FP)",
    "url": "https://wiki.freecad.org/Macro_Animator",
    "raw_code_url": "https://gist.github.com/mwganson/dace9e8dcfd861500647f9405c668358/raw/1ee79040c95862cf416d6fb6e3f7975c1c8a7f74/Animator.FCMacro",
    "wiki": "",
    "version": "0.2023.09.30c",
    "license": "",
    "date": "2022-09-30",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Animator.svg",
    "icon_source": "https://wiki.freecad.org//images/1/19/Animator.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Assemblage Imprimante 3D",
    "on_wiki": true,
    "on_git": false,
    "desc": "Simulates the motion of a 3D printer in the Z axis.<br />The script author is Javier Mart\u00ednez Garc\u00eda (JMG) and has been adapted for this project.<br /><br />Macro version: 1.0<br />Last modified: 2015-07-13<br />FreeCAD version: 0.15<br />Download: Not file .FCStd for testing<br /><a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/8/8c/Macro_Assemblage_Imprimante_3D.png\">ToolBar Icon</a><br />Author: fran6t<br /> ",
    "comment": "Simulates the motion of a 3D printer in the Z axis.",
    "code": "# Mouvement va et vient du chariot et tete selon axe Z\n#\n# Pour arreter l'animation il faut taper animation.stop() dans la console\n\n__author__ = \"Javier Mart\u00ednez Garc\u00eda\"\n\nimport FreeCAD as App, FreeCADGui as Gui, Part, time, sys, math, Draft, DraftGeomUtils\n\ntry:\n    from PyQt4 import QtGui,QtCore\nexcept Exception:\n    from PySide import QtGui,QtCore\n\nclass Animation(object):\n   def __init__(self):\n      App.Console.PrintMessage('init')\n      App.ActiveDocument.recompute()\n      self.timer = QtCore.QTimer()\n      QtCore.QObject.connect(self.timer, QtCore.SIGNAL(\"timeout()\"), self.my_update)\n      self.timer.start(50)\n\n      self.an = 0\n      self.Tige_Guide_X = 142\n      self.X_End_Tendeur = 90\n      self.X_Chariot = 102\n      self.Nema_17_motor_X = 119\n      self.Anti_Backslash_Z_Gauche = 88\n      self.Jhead_droite = 126.5\n      self.enstopX = 168\n      self.sens = 1\n\n   def my_update(self):\n      if ( self.an == 0 ) :\n         self.sens = 1\n      if ( self.an == 245 ) :\n         self.sens = -1\n      self.an = self.an + self.sens\n      self.Tige_Guide_X = self.Tige_Guide_X + self.sens\n      self.X_End_Tendeur = self.X_End_Tendeur + self.sens\n      self.X_Chariot = self.X_Chariot + self.sens\n      self.Nema_17_motor_X = self.Nema_17_motor_X + self.sens\n      self.Jhead_droite = self.Jhead_droite + self.sens\n      self.Anti_Backslash_Z_Gauche = self.Anti_Backslash_Z_Gauche + self.sens\n      self.enstopX = self.enstopX + self.sens\n\n      #12-X-End-Moteur\n      #FreeCAD.getDocument(\"_0_assemblage_total\").getObject(\"Pocket013\").Placement = App.Placement(App.Vector(-133,0,self.an),App.Rotation(App.Vector(0,0,1),0))\n      FreeCAD.getDocument(\"_0_assemblage_total\").getObject(\"refine002\").Placement = App.Placement(App.Vector(0,0,self.an),App.Rotation(App.Vector(0,0,1),0))      \n      #Tige-Guide-X      \n      FreeCAD.getDocument(\"_0_assemblage_total\").getObject(\"Pad025\").Placement = App.Placement(App.Vector(-180,13.55,self.Tige_Guide_X),App.Rotation(App.Vector(0.57735,0.57735,0.57735),120))\n      #14-X-End-Tendeur      \n      FreeCAD.getDocument(\"_0_assemblage_total\").getObject(\"Pocket011\").Placement = App.Placement(App.Vector(236,0,self.X_End_Tendeur),App.Rotation(App.Vector(0,0,1),0))\n      #13-X-Chariot\n      FreeCAD.getDocument(\"_0_assemblage_total\").getObject(\"Pocket014\").Placement = App.Placement(App.Vector(-18,25,self.X_Chariot),App.Rotation(App.Vector(1,0,0),90))\n      #Nema-17-motor-X\n      FreeCAD.getDocument(\"_0_assemblage_total\").getObject(\"Chamfer003\").Placement = App.Placement(App.Vector(-205.2,63,self.Nema_17_motor_X),App.Rotation(App.Vector(1,0,0),90))\n      #15-Anti-Backslash-Z-x2-1\n      FreeCAD.getDocument(\"_0_assemblage_total\").getObject(\"Pad012\").Placement = App.Placement(App.Vector(-156,-15,self.Anti_Backslash_Z_Gauche),App.Rotation(App.Vector(0.999985,0.00555547,0),180))\n      #Jhead-Droite\n      FreeCAD.getDocument(\"_0_assemblage_total\").getObject(\"Pocket015\").Placement = App.Placement(App.Vector(-50.8,-4.4,self.Jhead_droite),App.Rotation(App.Vector(0,0,1),0))\n      #Endstop X\n      FreeCAD.getDocument(\"_0_assemblage_total\").getObject(\"refine003\").Placement = App.Placement(App.Vector(-154.2,15,self.enstopX),App.Rotation(App.Vector(0.57735,0.57735,-0.57735),120))\n   def stop(self):\n      self.timer.stop()     \n\nanimation = Animation()",
    "url": "https://wiki.freecad.org/Macro_Assemblage_Imprimante_3D",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2015-07-13",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Javier Mart\u00ednez Garc\u00eda",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Assemblage_Imprimante_3D.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/8/8c/Macro_Assemblage_Imprimante_3D.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Assembly",
    "on_wiki": true,
    "on_git": false,
    "desc": "FreeCad Python assembly animation.<br /><br />Macro version: 1.0<br />Last modified: 2014-08-08<br />FreeCAD version: 0.18 and below<br />Download: The file <a rel=\"nofollow\" class=\"external text\" href=\"http://forum.freecadweb.org/download/file.php?id=6740\">Assy.fcstd</a><br /><a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/a/a2/Macro_Assembly.png\">ToolBar Icon</a><br />Author: ralvejd<br /> ",
    "comment": "FreeCad Python assembly animation.",
    "code": "#******************************************************************************\n#\n# Assembly animation by Joakim Isaksson 20140803\n#\n#******************************************************************************\n\nimport FreeCAD, FreeCADGui, Draft, Part\nfrom FreeCAD import Gui\nimport math\nfrom pivy import coin\nfrom PySide import QtCore, QtGui\nfrom time import sleep\n\n# + + + + + + BEGIN Animation configuration  + + + + + +\n\ndoc_name = \"Assy\"      # The document name of the FreeCAD model\nani_startwait = 3000   # Milliseconds before the animation starting\nani_partwait   = 50   # Milliseconds before the part begin to move\nani_bitrate = 10      # Milliseconds between part moves\nani_dist = 5         # Distance part moves each time\nani_offset_dist = 200   # Distance part is moved before the animation starts\n\n# Tuples for all parts label\n#  *  First item in Tuples is the animation view angle\n#  *  The remaining items are label on parts to be assembled in list sequence\nani_1  = ( \"z-\" , \"ChassieBack_001\" , \"ChassieWall_001\" , \"ChassieWall_002\" ,\n           \"ChassieWall_003\" , \"ChassieWall_004\" , \"ChassieWall_005\" ,\n           \"ChassieFront_001\" ) ;\nani_2  = ( \"z-\" , \"ISO4762_M4x12_001\" , \"ISO4762_M4x12_002\" ,\n           \"ISO4762_M4x12_003\" , \"ISO4762_M4x12_004\" , \"ISO4762_M4x12_005\" ,\n           \"ISO4762_M4x12_006\" , \"ISO4762_M4x12_007\" , \"ISO4762_M4x12_008\" ,\n           \"ISO4762_M4x12_009\" , \"ISO4762_M4x12_010\" ) ;\nani_3  = ( \"z+\" , \"ISO4762_M4x12_011\" , \"ISO4762_M4x12_012\" ,\n           \"ISO4762_M4x12_013\" , \"ISO4762_M4x12_014\" , \"ISO4762_M4x12_015\" ,\n           \"ISO4762_M4x12_016\" , \"ISO4762_M4x12_017\" , \"ISO4762_M4x12_018\" ,\n           \"ISO4762_M4x12_019\" , \"ISO4762_M4x12_020\" ) ;\nani_4  = ( \"z+\" , \"EuroCard_001\" , \"EuroCard_002\" , \"EuroCard_003\" ,\n           \"EuroCard_004\" ) ;\nani_5  = ( \"z+\" , \"Panel_005\" ,  \"Panel_006\" , \"Panel_007\" , \"Panel_008\" ) ;\nani_6  = ( \"z+\" , \"ISO7380_M3x8_\" , \"ISO7380_M3x8_001\" , \"ISO7380_M3x8_002\" ,\n           \"ISO7380_M3x8_003\" , \"ISO7380_M3x8_004\" , \"ISO7380_M3x8_005\" ,\n           \"ISO7380_M3x8_006\" , \"ISO7380_M3x8_007\" , \"ISO7380_M3x8_008\" ,\n           \"ISO7380_M3x8_009\" ) ;\nani_7  = ( \"z-\" , \"Panel_001\" , \"Panel_002\" , \"Panel_003\" , \"Panel_004\" ) ;\nani_8  = ( \"z-\" , \"ISO7380_M3x8_010\" , \"ISO7380_M3x8_011\" ,\n           \"ISO7380_M3x8_012\" , \"ISO7380_M3x8_013\" , \"ISO7380_M3x8_014\" ,\n           \"ISO7380_M3x8_015\" , \"ISO7380_M3x8_016\" , \"ISO7380_M3x8_017\" ,\n           \"ISO7380_M3x8_018\" , \"ISO7380_M3x8_019\" ) ;\nani_9  = ( \"y-\" , \"LidBottom_001\" ) ;\nani_10 = ( \"y-\" , \"ISO10642_M3x8_\" , \"ISO10642_M3x8_001\" ,\n           \"ISO10642_M3x8_002\" , \"ISO10642_M3x8_003\" , \"ISO10642_M3x8_004\" ,\n           \"ISO10642_M3x8_005\" , \"ISO10642_M3x8_006\" , \"ISO10642_M3x8_007\" ,\n           \"ISO10642_M3x8_008\" , \"ISO10642_M3x8_009\" ) ;\nani_11 = ( \"y+\" , \"LidTop_001\" ) ;\nani_12 = ( \"y+\" , \"ISO10642_M3x8_010\" , \"ISO10642_M3x8_011\" ,\n           \"ISO10642_M3x8_012\" , \"ISO10642_M3x8_013\" , \"ISO10642_M3x8_014\" ,\n           \"ISO10642_M3x8_015\" , \"ISO10642_M3x8_016\" , \"ISO10642_M3x8_017\" ,\n           \"ISO10642_M3x8_018\" , \"ISO10642_M3x8_019\" ) ;\n\n# Set the animation end view\nani_end = \"z-\"\n\n# Camera oriantations\n#  *  Edit this tuples to your need\nrear_view_pos    = ( -400 , -80 , 480 ) ;\nrear_view_ang    = ( 0 , 1 , 0  ) ;\nfront_view_pos    = ( -400 , 80 , 480 ) ;\nfront_view_ang    = ( 0 , -1 , 0  ) ;\ntop_view_pos    = ( -400 , -80 , 480  ) ;\ntop_view_ang    = ( -1 , 0 , 0 ) ;\nbottom_view_pos = ( -400 , 80 , -480 );\nbottom_view_ang = ( 1 , 0 , 0 ) ;\n\n# + + + + + + END Animation configuration  + + + + + +\n\n# + + + + + + Function  + + + + + +\n\ndef pulse(milliseconds):\n   for i in range(milliseconds/10  ):\n      Gui.updateGui( )\n      sleep(0.01)\n\ndef setView(axis_vector, rotation_vector):\n   r=App.Rotation(App.Vector(axis_vector),App.Vector(rotation_vector))\n   Gui.ActiveDocument.ActiveView.setCameraOrientation(r.Q)\n\ndef getPartName(label):\n   for i in App.ActiveDocument.Objects:\n      if str(i.Label) == label:\n         #App.Console.PrintMessage(str(i.Name) + \"  <->  \" + i.Label + \"\\n\")\n         return str(i.Name)\n\ndef animate(aniList):\n   total = len(aniList)\n   for n in range(1,total):\n      direction = aniList[0]\n      #App.Console.PrintMessage(str(aniList) + \" : \" + str(direction) + \"\\n\")\n      part_name = getPartName(aniList[n])\n      tmpX = App.getDocument(doc_name).getObject(part_name).Placement.Base[0]\n      tmpY = App.getDocument(doc_name).getObject(part_name).Placement.Base[1]\n      tmpZ = App.getDocument(doc_name).getObject(part_name).Placement.Base[2]\n      tmpRotation=App.ActiveDocument.getObject(part_name).Placement.Rotation\n      #Show the part\n      if direction == \"x+\":   #TODO not tested\n         setView(rear_view_pos , rear_view_ang)\n         tmpDist = tmpX + ani_offset_dist\n         sel = FreeCADGui.Selection.clearSelection (doc_name )\n         App.ActiveDocument.getObject(part_name).Placement=App.Placement\\\n               (App.Vector(tmpX,tmpDist,tmpZ), App.Rotation(tmpRotation),\\\n                App.Vector(0,0,0))\n         Gui.getDocument(doc_name).getObject(part_name).Visibility=True\n         pulse(ani_partwait)\n         \n         for i in range(0,ani_step):\n            tmpDist = tmpDist - ani_dist\n            App.ActiveDocument.getObject(part_name).Placement=\\\n                   App.Placement(App.Vector(tmpX,tmpDist,tmpZ),\\\n                   App.Rotation(tmpRotation), App.Vector(0,0,0))\n            pulse(ani_bitrate)\n\n      elif direction == \"x-\":   #TODO not tested\n         setView(front_view_pos , front_view_ang)\n         tmpDist = tmpX - ani_offset_dist\n         sel = FreeCADGui.Selection.clearSelection (doc_name )\n         App.ActiveDocument.getObject(part_name).Placement=App.Placement\\\n               (App.Vector(tmpX,tmpDist,tmpZ),\\\n               App.Rotation(tmpRotation), App.Vector(0,0,0))\n         Gui.getDocument(doc_name).getObject(part_name).Visibility=True\n         pulse(ani_partwait)\n         \n         for i in range(0,ani_step):\n            tmpDist = tmpDist + ani_dist\n            App.ActiveDocument.getObject(part_name).Placement=App.\\\n                   Placement(App.Vector(tmpX,tmpDist,tmpZ),\\\n                   App.Rotation(tmpRotation), App.Vector(0,0,0))\n            pulse(ani_bitrate)\n\n      elif direction == \"y+\":\n         setView(rear_view_pos , rear_view_ang)\n         tmpDist = tmpY + ani_offset_dist\n         sel = FreeCADGui.Selection.clearSelection (doc_name )\n         App.ActiveDocument.getObject(part_name).Placement=App.Placement\\\n               (App.Vector(tmpX,tmpDist,tmpZ), App.Rotation(tmpRotation),\\\n               App.Vector(0,0,0))\n         Gui.getDocument(doc_name).getObject(part_name).Visibility=True\n         pulse(ani_partwait)\n         \n         for i in range(0,ani_step):\n            tmpDist = tmpDist - ani_dist\n            App.ActiveDocument.getObject(part_name).Placement=App.\\\n                   Placement(App.Vector(tmpX,tmpDist,tmpZ),\\\n                   App.Rotation(tmpRotation),App.Vector(0,0,0))\n            pulse(ani_bitrate)\n\n      elif direction == \"y-\":\n         setView(front_view_pos , front_view_ang)\n         tmpDist = tmpY - ani_offset_dist\n         sel = FreeCADGui.Selection.clearSelection (doc_name )\n         App.ActiveDocument.getObject(part_name).Placement=App.Placement\\\n               (App.Vector(tmpX,tmpDist,tmpZ), App.Rotation(tmpRotation),\\\n               App.Vector(0,0,0))\n         Gui.getDocument(doc_name).getObject(part_name).Visibility=True\n         pulse(ani_partwait)\n         \n         for i in range(0,ani_step):\n            tmpDist = tmpDist + ani_dist\n            App.ActiveDocument.getObject(part_name).Placement=App.\\\n                   Placement(App.Vector(tmpX,tmpDist,tmpZ),\\\n                   App.Rotation(tmpRotation), App.Vector(0,0,0))\n            pulse(ani_bitrate)\n\n      elif direction == \"z+\":\n         setView(top_view_pos , top_view_ang)\n         tmpDist = tmpZ +ani_offset_dist\n         sel = FreeCADGui.Selection.clearSelection (doc_name )\n         App.ActiveDocument.getObject(part_name).Placement=App.Placement\\\n               (App.Vector(tmpX,tmpY,tmpDist), App.Rotation(tmpRotation),\\\n               App.Vector(0,0,0))\n         Gui.getDocument(doc_name).getObject(part_name).Visibility=True\n         pulse(ani_partwait)\n         \n         for i in range(0,ani_step):\n            tmpDist = tmpDist - ani_dist\n            App.ActiveDocument.getObject(part_name).Placement=App.\\\n                   Placement(App.Vector(tmpX,tmpY,tmpDist),\\\n                   App.Rotation(tmpRotation), App.Vector(0,0,0))\n            pulse(ani_bitrate)\n\n      elif direction == \"z-\":\n         setView(bottom_view_pos , bottom_view_ang)\n         tmpDist = tmpZ - ani_offset_dist\n         sel = FreeCADGui.Selection.clearSelection (doc_name )\n         App.ActiveDocument.getObject(part_name).Placement=App.Placement\\\n               (App.Vector(tmpX,tmpY,tmpDist), App.Rotation(tmpRotation),\\\n               App.Vector(0,0,0))\n         Gui.getDocument(doc_name).getObject(part_name).Visibility=True\n         pulse(ani_partwait)\n         \n         for i in range(0,ani_step):\n            tmpDist = tmpDist + ani_dist\n            App.ActiveDocument.getObject(part_name).Placement=App.\\\n                   Placement(App.Vector(tmpX,tmpY,tmpDist),\\\n                   App.Rotation(tmpRotation), App.Vector(0,0,0))\n            pulse(ani_bitrate)\n\ndef theend(direction):\n   if direction == \"x+\":\n      setView(rear_view_pos , rear_view_ang)\n   elif direction == \"x-\":\n      setView(front_view_pos , front_view_ang)\n   elif direction == \"y+\":\n      setView(rear_view_pos , rear_view_ang)\n   elif direction == \"y-\":\n      setView(front_view_pos , front_view_ang)\n   elif direction == \"z+\":\n      setView(top_view_pos , top_view_ang)\n   elif direction == \"z-\":\n      setView(bottom_view_pos , bottom_view_ang)\n\ndef startAnimation():\n # Animation sequence\n   animate(ani_1)\n   animate(ani_2)\n   animate(ani_3)\n   animate(ani_4)\n   animate(ani_5)\n   animate(ani_6)\n   animate(ani_7)\n   animate(ani_8)\n   animate(ani_9)\n   animate(ani_10)\n   animate(ani_11)\n   animate(ani_12)\n   theend(ani_end)\n   Gui.ActiveDocument.ActiveView.startAnimating(0,1,0,0.2) #TODO fixit\n\n# + + + + + + Main + + + + + +\n# Set full screen\nApp.setActiveDocument(doc_name)\nApp.ActiveDocument=App.getDocument(doc_name)\nActiveDocument=Gui.getDocument(doc_name)\nGui.updateGui ( )\nmw=QtGui.qApp.activeWindow()\nev=QtGui.QKeyEvent(QtCore.QEvent.KeyPress,\\\n   QtCore.Qt.Key_F11,QtCore.Qt.NoModifier)\nQtGui.qApp.sendEvent(mw,ev)\n\n# A short break for the GUI to catch up\npulse(ani_startwait)\n\n# Adjust ani_offset if Modulus != 0\nani_offset_dist = ani_offset_dist - ani_offset_dist % ani_dist\n\n# Calculate the required number of steps for the animation\nani_step = ani_offset_dist / ani_dist\n\nstartAnimation()",
    "url": "https://wiki.freecad.org/Macro_Assembly",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-08-08",
    "src_filename": "",
    "filename_from_url": "",
    "author": "ralvejd",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Assembly.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/a/a2/Macro_Assembly.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Constraint Draft",
    "on_wiki": true,
    "on_git": false,
    "desc": "Create simulation using the <a href=\"/Expressions\" title=\"Expressions\">expressions</a> for link all objects (This macro run with FreeCAD version 16 ).<br /><br />Macro version: 1.0<br />Last modified: 2017-04-19<br />FreeCAD version: 0.16<br />Download: The file example <a rel=\"nofollow\" class=\"external text\" href=\"http://forum.freecadweb.org/download/file.php?id=36559\">Constraint_Draft00.FCStd</a><br /><a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/d/d8/Macro_Constraint_Draft.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Create simulation using the expressions for link all objects (This macro run with FreeCAD version 16 ).",
    "code": "# Copy and pate this snippet in the FreeCAD console Python \n# mario52 19/04/2017\n\nimport FreeCADGui\nimport FreeCAD\n\n#FreeCAD.Console.PrintMessage(str(FreeCAD.Version()) + \"\\n\")\nif int(FreeCAD.Version()[1]) == 16:    # Version de FreeCAD\n    try:\n        for i in range(0,360,5):\n            App.getDocument(\"Constraint_Draft00\").Circle.Placement=App.Placement(App.Vector(0,0,0), App.Rotation(i,0,0), App.Vector(0,0,0))\n            FreeCADGui.updateGui()\n            FreeCAD.ActiveDocument.recompute()\n    except Exception:\n        FreeCAD.Console.PrintMessage(\"You must download the Constraint_Draft00.FCStd file for run this macro\" + \"\\n\")\n        import webbrowser \n        webbrowser.open(\"http://forum.freecadweb.org/download/file.php?id=36559\")\n\nelse:\n    FreeCAD.Console.PrintError(\"This macro run with the FreeCAD.Version 16 \" + \"\\n\")",
    "url": "https://wiki.freecad.org/Macro_Constraint_Draft",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2017-04-19",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Constraint_Draft.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/d/d8/Macro_Constraint_Draft.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "crank simul",
    "on_wiki": true,
    "on_git": false,
    "desc": "My simple animation uses sketch and sketcher solver to determine piston position and conrod position/rotation.<br /><br />Macro version: 1.0<br />Last modified: 2014-06-13<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/0/04/Macro_crank_simul.png\">ToolBar Icon</a><br />The file <a rel=\"nofollow\" class=\"external text\" href=\"http://forum.freecadweb.org/download/file.php?id=5954\">crank_simul.fcstd</a><br />Author: kwahoo<br /> ",
    "comment": "My simple animation uses sketch and sketcher solver to determine piston position and conrod position/rotation.",
    "code": "import FreeCAD as App, FreeCADGui as Gui, Part, time, sys, math, Draft, DraftGeomUtils\nfrom PySide import QtGui,QtCore\n\nclass Animation(object):\n    def __init__(self):\n        App.Console.PrintMessage('init')\n\n        App.ActiveDocument.recompute()\n\n        self.timer = QtCore.QTimer()\n        QtCore.QObject.connect(self.timer, QtCore.SIGNAL(\"timeout()\"), self.my_update)\n        self.timer.start(50)\n\n        self.an = 0.1\n\n    def my_update(self):\n        string = '{0}'.format(self.an)\n        self.an = self.an + 0.01 if self.an < (2 * math.pi) else 0.0\n\n        angle = math.degrees(self.an)\n        App.ActiveDocument.Sketch.setDatum(5,App.Units.Quantity(str(angle)+' deg'))\n        App.ActiveDocument.recompute()\n        p1 = App.ActiveDocument.Sketch.Shape.Vertexes[0].Point\n        p2 = App.ActiveDocument.Sketch.Shape.Vertexes[1].Point\n        conrodangle = math.degrees(Draft.DraftVecUtils.angle(App.Vector(1,0,0),(p1-p2))) - 90\n        App.ActiveDocument.getObject(\"Cylinder\").Placement = App.Placement(p1,App.Rotation(App.Vector(1,0,0),-90))\n        App.ActiveDocument.getObject(\"Sketch001\").Placement = App.Placement(p1,App.Rotation(App.Vector(0,0,1),conrodangle))\n\n    def stop(self):\n        self.timer.stop()\n         \n\nanimation = Animation()",
    "url": "https://wiki.freecad.org/Macro_crank_simul",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-06-13",
    "src_filename": "",
    "filename_from_url": "",
    "author": "kwahoo",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_crank_simul.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/0/04/Macro_crank_simul.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "hinge",
    "on_wiki": true,
    "on_git": false,
    "desc": "Hinge simulation.<br /><br />Macro version: 1.0<br />Last modified: 2014-09-09<br />FreeCAD version: All<br />Download: The File <a rel=\"nofollow\" class=\"external text\" href=\"http://forum.freecadweb.org/download/file.php?id=7628\">20140908b_Hinge-1.fcstd</a><br /><a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/a/a8/Macro_hinge.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Hinge simulation.",
    "code": "import FreeCAD, FreeCADGui, Draft, Part\nfrom FreeCAD import Base\nimport time\n\nii = 0\npas = 0\nfor ii2 in range(180):\n    if pas == 0:\n        if ii > 90:\n            pas = 1\n        ii += 5\n    else:\n        if ii < 1:\n            pas = 0\n        ii -= 5\n   \n    App.getDocument(\"_0140908b_Hinge_1\").Fusion.Placement=App.Placement(App.Vector(0,0,0), App.Rotation(App.Vector(0,0,1),ii), App.Vector(44.4,6.9,0))\n    App.Console.PrintMessage(str(ii2)+\"  \" + str(ii)+\"  \" + str(pas) +\"\\n\")\n    Gui.updateGui()\n    time.sleep(0) #modify the time here",
    "url": "https://wiki.freecad.org/Macro_hinge",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-09-09",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_hinge.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/a/a8/Macro_hinge.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Spring",
    "on_wiki": true,
    "on_git": false,
    "desc": "Simulates the compression and decompression of a spring.<br /><br />Macro version: 1.0<br />Last modified: 2014-09-29<br />FreeCAD version: All<br />Download: The file <a rel=\"nofollow\" class=\"external text\" href=\"http://forum.freecadweb.org/download/file.php?id=7679\">Spring.FCStd</a><br /><a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/2/2d/Macro_Spring.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Simulates the compression and decompression of a spring.",
    "code": "import FreeCAD, FreeCADGui, Draft, Part\nfrom FreeCAD import Base\nimport time\n\nii = iib = FreeCAD.getDocument(\"Spring\").getObject(\"Helix001\").Pitch.Value\ni = ib = FreeCAD.getDocument(\"Spring\").getObject(\"Helix001\").Height.Value\n\npas = 1\n\nfor ii2 in range(int(60)):\n    if pas == 0:\n        if ii > iib-1:\n            pas = 1\n        else:\n            ii += 1\n            i = (ii * 10)\n    else:\n        if ii < 2:\n            pas = 0\n        else:\n            ii -= 1\n            i = (ii * 10)\n   \n    FreeCAD.getDocument(\"Spring\").getObject(\"Helix001\").Pitch = ii\n    FreeCAD.getDocument(\"Spring\").getObject(\"Helix001\").Height = i\n    App.Console.PrintMessage(str(ii2)+\"  \" + str(ii)+\"  \" + str(i)+\"  \" + str(pas) +\"\\n\")\n    Gui.updateGui()\n    time.sleep(0.1)",
    "url": "https://wiki.freecad.org/Macro_Spring",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-09-29",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Spring.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/2/2d/Macro_Spring.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Build Utility",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro provides a Build Utility to assemble multiple project files into one project file.<br /><br />Macro version: 1.0<br />Last modified: 2015-01-21<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/8/87/Macro_Build_Utility.png\">ToolBar Icon</a><br />Author: Piffpoof<br /> ",
    "comment": "This macro provides a Build Utility to assemble multiple project files into one project file.",
    "code": "#\n#\t\t\t\t\t\tBuild Utility\n#                       v 0.0 - build from files and files in sub-folders\n#\n#***********************************************************************************\n# routine to read in a build file and merge all specified projects\n\"\"\"\nThis function asks the user for a \"build file\". It then parses that build file, there\nare 3 legal line types:\n- lines starting with the comment character \"#\" which are ignored\n- lines starting with the subfile character \"@\" which are ignored\n\tNote:\tthe \"@\" character is for future enhancement when sub-build files \n\t\t\twill be handled\n- all other lines which may be a project file or a subfolder (sub-directory)\nIf the line is a subfolder then the project file is read from that subfolder.\nOtherwise it is assumed the line specifies a project file.\nA new document is created and each project is \"Project Merged\" into that new and empty document.\nThe document is not saved at the end, this is left for the user if desired.\nIf the file does not exist then the file name is Printed to the Report view\n\"\"\"\n\"\"\"\nExample file:\n#this is a sample build file\n#==============================\n@sub-build-files - not presently inplemented\n# first the top-level file\nmetal\n# now some misc files\n./black/black\n./blue/blue\n# file does not exist\nzebra \n# folder does not exist\n/bear/bear\n# multiple files in one sub-folder\n./engineering/green\n./engineering/grey\n#multiple files in hierarchical folders\n./externalModules/white\n./externalModules/red/red\n#./externalModules/red/stackerAssembly - commented out as not currently loading\n./externalModules/red/orange\n./externalModules/red/level3/yellow\n\"\"\"\n# import statements\nimport FreeCAD\nimport os.path\nfrom PySide import QtGui\n\n# UI Class definitions\n\n# Class definitions\n\n# Function definitionss\n\n# Constant definitions\nbuildTargetDocument = \"build_target\"\ncommentTag = \"#\"\nsubfileTag = \"@\"\nlineFeed = \"\\n\"\nsubfolder = \"./\"\ncarriageReturn = \"\\r\"\nfileSeparator = \"/\"\nfcFileExtension      = \".FCStd\"\nfcFileExtensionUC  = \".FCSTD\"\nfcFileExtensionLen = -6\n\n# code ***********************************************************************************\nbuildFilePathName=QtGui.QFileDialog.getOpenFileName()[0]\nif len(buildFilePathName) > 0:\n\t# set up a new empty \"build_target\" document\n\tFreeCAD.newDocument(buildTargetDocument)\n\tFreeCAD.setActiveDocument(buildTargetDocument)\n\tFreeCAD.ActiveDocument=FreeCAD.getDocument(buildTargetDocument)\n\tguiDoc=FreeCADGui.ActiveDocument\n\t#\n\tlastFileSeparator = buildFilePathName.rindex(fileSeparator)\n\tbuildFilePath = buildFilePathName[: lastFileSeparator]\n\tbuildFileName = buildFilePathName[lastFileSeparator +1:]\n\t#\n\tbuildFileContents = open(buildFilePathName,\"r\")\n\tbuildFileLines = buildFileContents.readlines()\n\tbuildFileContents.close()\n\t#\n\tfor line in buildFileLines:\n\t\tif line[0] == commentTag:\n\t\t\t# line of internal comment\n\t\t\tpass\n\t\telif line[0] == subfileTag:\n\t\t\t# line of sub-build-file (not presently implemented)\n\t\t\tpass\n\t\telse:\n\t\t\t# a line which should specify a FreeCAD project file\n\t\t\t# - may be preceded by a sub-directory e.g. \"./subdir309/\"\n\t\t\t# - project file may be missing file extension\n\t\t\t#\n\t\t\t# if line break at end of file spec then remove\n\t\t\tif line[-1:] == lineFeed:\n\t\t\t\tline = line[:-1]\n\t\t\tif line[-1:] == carriageReturn:\n\t\t\t\tline = line[:-1]\n\t\t\t# if no FreeCAD project file extension supplied then append one\n\t\t\t# make an uppercase comparison in case of mixed case\n\t\t\ttempLine = fcFileExtension + line.upper()\n\t\t\tif fcFileExtensionUC != tempLine[fcFileExtensionLen:]:\n\t\t\t\tline = line + fcFileExtension\n\t\t\t# if there is a leading subdirectory then remove \"./\" from beginning\n\t\t\tif subfolder[0:2] == line[0:2]:\n\t\t\t\tline = line[2:]\n\t\t\tprojectFileSpec = str(buildFilePath) + str(\"/\") + str(line)\n\t\t\tif os.path.exists(projectFileSpec):\n\t\t\t\tguiDoc.mergeProject(projectFileSpec)\n\t\t\telse:\n\t\t\t\tFreeCAD.Console.PrintMessage('project file \"' + projectFileSpec + '\" not found' + \"\\n\")\n\n\t# set view back to \"build_target\", it is up to user to save it (if they want)\n\tFreeCAD.setActiveDocument(buildTargetDocument)\n\tFreeCAD.ActiveDocument=FreeCAD.getDocument(buildTargetDocument)\n\tFreeCADGui.ActiveDocument=FreeCADGui.getDocument(buildTargetDocument)\n\tFreeCADGui.SendMsgToActiveView(\"ViewFit\")\n\tFreeCADGui.activeDocument().activeView().viewAxometric()\n#\n#OS: Mac OS X\n#Word size: 64-bit\n#Version: 0.14.3703 (Git)\n#Branch: releases/FreeCAD-0-14\n#Hash: c6edd47334a3e6f209e493773093db2b9b4f0e40\n#Python version: 2.7.5\n#Qt version: 4.8.6\n#Coin version: 3.1.3\n#SoQt version: 1.5.0\n#OCC version: 6.7.0\n#\n#thus ends the macro...",
    "url": "https://wiki.freecad.org/Macro_Build_Utility",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2015-01-21",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Piffpoof",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Build_Utility.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/8/87/Macro_Build_Utility.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "clone explicit",
    "on_wiki": true,
    "on_git": false,
    "desc": "Creates a copy of each selected object and sets its properties to an expression linking to the original object, making it an explicit and editable clone.<br /><br />Macro version: 0.1<br />Last modified: 2018-12-15<br />FreeCAD version: 18 and after<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/a/ab/Macro_clone_explicit.png\">ToolBar Icon</a><br />Author: Raph82<br /> ",
    "comment": "This macro creates a copy of the selected objects and sets their properties to an expression linking to the original object, making it an explicit and editable clone",
    "code": "__Title__ = \"clone_explicit\"\n__Author__ = \"Raph82\"\n__URL__     = \"http://www.freecadweb.org/index-fr.html\"\n__Version__ = \"0.1\"\n__Date__    = \"2018-12-15\" #YYYY-MM-DD\n__Comment__ = \"This macro creates a copy of the selected objects and sets their properties to an expression linking to the original object, making it an explicit and editable clone\"\n__Web__ = \"http://www.freecadweb.org/\"\n__Wiki__ = \"http://www.freecadweb.org/wiki/index.php?title=Macro_clone_explicit\"\n__Icon__  = \"https://wiki.freecad.org/images/a/ab/Macro_clone_explicit.png\"\n__IconW__  = \"C:/Users/User Name/AppData/Roaming/FreeCAD/Macro_clone_explicit.png\"\n__Help__ = \"Select at least one object and run the macro to make explicit and editable clone(s)\"\n__Status__ = \"dev\"\n__Requires__ = \"All FreeCAD\"\n__Communication__ = \"http://www.freecadweb.org/wiki/index.php?title=User:raph82\"\n\n#IMPORTS:\nimport sys\n\n##################################################\ndef set_expression(obj, property_to_set, expression):\n    \"\"\"\"\"\"\n    try:\n        print type(obj)\n        obj.setExpression(property_to_set, expression)\n#    except 'Base.FreeCADError':\n    except Exception as detail:\n        print detail\n        print type(detail)\n        if detail['swhat'] == 'Property not found':\n            App.Console.PrintMessage('Object \"{obj}\" has no property \"{prop}\"\\r\\n'.format(obj=obj.Name, prop=property_to_set))\n        else:\n            raise\n\n##################################################\ndef clone_explicit(mode):\n    \"\"\"Copy the selected objects and sets their properties to an expression, making it an explicit and editable clone.\n\n     This clone is called \"explicit and editable\" because the link with its parent is visible and can be changed in the object properties.\n\n     The link to the original object can be either \"direct\" or \"transient\", depending on the mode argument:\n     - a direct clone has expressions pointing to its parent: clone.Length = parent.Length\n     - a transient clone has expressions pointing to its ancestor. Say parent.Length = Box001.Length. With a transient clone, clone.Length = Box001.Length, whereas with a direct clone, clone.Length = parent.Length.\n       This indirect link to Box001 (via the parent object) could be severed, accidentally or not, depending on what relationship you're looking for.\n\n     If you're lost, try with a direct clone first.\"\"\"\n\n    App.Console.PrintMessage(\"Start of clone_explicit macro\"+\"\\r\\n\")\n\n    #Current selection check:\n    sel = FreeCADGui.Selection.getSelection()\n\n    App.Console.PrintMessage(str(len(sel))+\" object(s) selected\\r\\n\")\n    if len(sel) != 0:\n        for i in range(len(sel)):\n            obj=sel[i]\n\n            #copying current object:\n            App.Console.PrintMessage('Copying \"'+obj.Label+'\" ('+obj.Name+')\\r\\n')\n            obj_copy=App.ActiveDocument.copyObject(obj, False) #https://www.freecadweb.org/api/d8/d3e/classApp_1_1Document.html#a08f1d7d90f4a7276a02918fb6445a04a\n            App.Console.PrintMessage('\"'+obj_copy.Label+'\" ('+obj_copy.Name+') created\\r\\n')\n\n            if mode == 'direct':\n                #defining expressions pointing to the original object:\n                set_expression(obj_copy, 'Placement.Base.x',          obj.Name+u'.Placement.Base.x')\n                set_expression(obj_copy, 'Placement.Base.y',          obj.Name+u'.Placement.Base.y')\n                set_expression(obj_copy, 'Placement.Base.z',          obj.Name+u'.Placement.Base.z')\n                set_expression(obj_copy, 'Placement.Rotation.Angle',  obj.Name+u'.Placement.Rotation.Angle')\n                set_expression(obj_copy, 'Placement.Rotation.Axis.x', obj.Name+u'.Placement.Rotation.Axis.x')\n                set_expression(obj_copy, 'Placement.Rotation.Axis.y', obj.Name+u'.Placement.Rotation.Axis.y')\n                set_expression(obj_copy, 'Placement.Rotation.Axis.z', obj.Name+u'.Placement.Rotation.Axis.z')\n                set_expression(obj_copy, 'Length',                    obj.Name+u'.Length')\n                set_expression(obj_copy, 'Width',                     obj.Name+u'.Width')\n                set_expression(obj_copy, 'Height',                    obj.Name+u'.Height')\n\n            elif mode == 'transient':\n                #defining expressions pointing to the utmost original object:\n                define_transient_expression(obj, obj_copy, 'Placement.Base.x')\n                define_transient_expression(obj, obj_copy, 'Placement.Base.y')\n                define_transient_expression(obj, obj_copy, 'Placement.Base.z')\n                define_transient_expression(obj, obj_copy, 'Placement.Rotation.Angle')\n                define_transient_expression(obj, obj_copy, 'Placement.Rotation.Axis.x')\n                define_transient_expression(obj, obj_copy, 'Placement.Rotation.Axis.y')\n                define_transient_expression(obj, obj_copy, 'Placement.Rotation.Axis.z')\n                define_transient_expression(obj, obj_copy, 'Length')\n                define_transient_expression(obj, obj_copy, 'Width')\n                define_transient_expression(obj, obj_copy, 'Height')\n            else:\n                App.Console.PrintError('Programming error: mode value not recognized.\\r\\n')\n\n            App.Console.PrintMessage('('+obj_copy.Label+'\" ('+obj_copy.Name+') expressions set\\r\\n')\n\n        FreeCAD.ActiveDocument.recompute()\n        App.Console.PrintMessage('End of clone_explicit macro\\r\\n')\n\n    else:\n        App.Console.PrintError('Select at least one object first\\r\\n')\n\n    sel = \"\"\n    obj = \"\"\n    obj_copy = \"\"\n\n##################################################\ndef find_expression(source_object, property_to_define):\n    \"\"\"\"\"\"\n\n    for var_tuple in source_object.ExpressionEngine: #https://forum.freecadweb.org/viewtopic.php?f=22&t=21950\n        # .ExpressionEngine returns tuple like [('Placement.Base.z', 'Length')], see https://docs.python.org/2.7/tutorial/datastructures.html#tuples-and-sequences\n        App.Console.PrintMessage('var_tuple[0]='+var_tuple[0]+'\\r\\n')\n        if var_tuple[0] == property_to_define:\n           return var_tuple[1]\n\n##################################################\ndef define_transient_expression(source_object, target_object, property_to_define):\n    \"\"\"\"\"\"\n    expressions = source_object.ExpressionEngine #https://forum.freecadweb.org/viewtopic.php?f=22&t=21950\n    # returns tuple like [('Placement.Base.z', 'Length')], see https://docs.python.org/2.7/tutorial/datastructures.html#tuples-and-sequences\n\n    expression = find_expression(source_object, property_to_define)\n    if expression != None:\n#        App.Console.PrintMessage(\"target_object.Name=\"+target_object.Name+\"\\r\\n\")\n#        App.Console.PrintMessage(\"property_to_define=\"+property_to_define+\"\\r\\n\")\n#        App.Console.PrintMessage(\"expressions[property_to_define]=\"+expressions[property_to_define]+\"\\r\\n\")\n\n        set_expression(target_object, property_to_define, expression)\n    else:\n        set_expression(target_object, property_to_define, source_object.Name+'.'+property_to_define)\n\n    expressions = \"\"\n\n##################################################\nclone_explicit('direct')\n#clone_explicit('transient')",
    "url": "http://www.freecadweb.org/",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_clone_explicit",
    "version": "0.1",
    "license": "",
    "date": "2018-12-15",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Raph82",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_clone_explicit.png",
    "icon_source": "https://wiki.freecad.org/images/a/ab/Macro_clone_explicit.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Editor Assistant",
    "on_wiki": true,
    "on_git": false,
    "desc": "Extend functionality of FreeCAD's integrated Python editor<br /><br />Macro version: 2.01<br />Last modified: 2024-10-10<br />FreeCAD version: 0.21 or later<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/File:Editor_Assistant_Icon.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Extend functionality of FreeCAD's integrated Python editor",
    "code": "# -*- coding: utf-8 -*-\n##from __future__ import unicode_literals\n#\n#Editor Assistant\n#Adds some capabilities to the python editor\n#as a new task panel dialog\n#https://forum.freecadweb.org/viewtopic.php?f=22&t=67242\n#2022, <TheMarkster> LGPL2.1 or later\n#\n#\n#OS: Windows 10 build 19045                                 #OS: Windows 10 build 19045                                  #OS: Ubuntu 20.04.3 LTS (KDE/plasma)                         #OS: Linux Mint 20.1 (X-Cinnamon/cinnamon)\n#Word size of FreeCAD: 64-bit                               #Word size of FreeCAD: 64-bit                                #Word size of FreeCAD: 64-bit                                #Word size of FreeCAD: 64-bit\n#Version: 0.21.2.33771 (Git)                                #Version: 0.22.0dev.38079 (Git)                              #Version: 0.22.0dev.37928 (Git) AppImage                     #Version: 0.22.0dev.37928 (Git) AppImage\n#Build type: Release                                        #Build type: Release                                         #Build type: Release                                         #Build type: Release\n#Branch: releases/FreeCAD-0-21                              #Branch: main                                                #Branch: main                                                #Branch: main\n#Hash: b9bfa5c5507506e4515816414cd27f4851d00489             #Hash: de508e437d13e7eb35baffceea496fb9107888cb              #Hash: e7699b531eba4bee262f7214699f07b96f66ba7b              #Hash: e7699b531eba4bee262f7214699f07b96f66ba7b\n#Python 3.8.10, Qt 5.15.2, Coin 4.0.1, Vtk 8.2.0, OCC 7.6.3 #Python 3.11.9, Qt 5.15.13, Coin 4.0.2, Vtk 9.2.6, OCC 7.7.2 #Python 3.11.9, Qt 5.15.13, Coin 4.0.2, Vtk 9.2.6, OCC 7.7.2 #Python 3.11.9, Qt 5.15.13, Coin 4.0.2, Vtk 9.2.6, OCC 7.7.2\n#Locale: French/Mars (fr_MA)                                #Locale: French/Mars (fr_MA)                                 #Locale: French/Mars (fr_MA)                                 #Locale: C/Default (C)\n#\n#\n__title__   = \"Editor_Assistant\"\n__author__  = \"TheMarkster\"\n__url__     = \"https://forum.freecadweb.org/viewtopic.php?f=22&t=67242\"\n__github__  = \"https://github.com/mwganson/Editor_Assistant/\"\n__wiki__    = \"https://wiki.freecad.org/Macro_Editor_Assistant\"\n__forum__   = \"https://forum.freecad.org/viewtopic.php?t=67242\"\n__requires__= \"0.21.2.33771 and higher\" \n__version__ = \"2.01\"\n__date__    = \"2024/11/11\"\n#\n##\n####path#########################################################################\nglobal path          ; path          = \"\"                            #\n#path  = FreeCAD.ConfigGet(u\"AppHomePath\")                           # path FreeCAD installation\n#path  = FreeCAD.ConfigGet(u\"UserAppData\")                           # path FreeCAD User data\n#path  = \"your path\"                                                 # your directory path\nparam = FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macro\")# macro path\npath = param.GetString(u\"MacroPath\",\"\") + \"/\"                        # macro path\npath = path.replace(u\"\\\\\",\"/\")                                       # convert the \"\\\" to \"/\"\n#print( u\"Path for the icons : \" , path )                            #\n#################################################################################\n##\npg = FreeCAD.ParamGet(\"User parameter:Plugins/\"+__title__)\n\npg.SetString(\"Version\", __version__ + \" (\" + __date__ + \")\")\n\nCOLOR_ACTIVE_TAB = pg.GetString(\"ColorActiveTab\", \"#B3F88C\")    #  \"0\"= color system , \"#B3F88C\"= color code html\npg.SetString(u\"ColorActiveTab\", \"#B3F88C\")\n\nCOLOR_ERROR_DETECTED = pg.GetString(\"COLOR_ERROR_DETECTED\", \"#a40000\")  #  \"0\"= color system , \"#a40000\"= color code html\npg.SetString(u\"COLOR_ERROR_DETECTED\", \"#a40000\")\n\nswitch_Unicode_Read_File = pg.GetBool(\"switch_Unicode_Read_File\", 0)\npg.SetBool(\"switch_Unicode_Read_File\",switch_Unicode_Read_File)\n\nsetPathFileBackup = pg.GetString(\"setPathFileBackup\", path)\npg.SetString(\"setPathFileBackup\", setPathFileBackup)\n\nsetPathFileSecondStorage = pg.GetString(\"setPathFileSecondStorage\", \"\")\npg.SetString(\"setPathFileSecondStorage\", setPathFileSecondStorage)\n\nsetFormatBackupDateTime = \"yyyy_MM_dd_HH_mm_ss\"\n#setFormatBackupDateTime = pg.GetString(\"setFormatBackupDateTime\", \"yyyy_MM_dd_HH_mm_ss\")\n#pg.SetString(u\"setFormatBackupDateTime\",  setFormatBackupDateTime)\n\nswitchReplaceInterrogationFFFD = pg.GetBool(\"switchReplaceInterrogationFFFD\", False)\npg.SetBool(\"switchReplaceInterrogationFFFD\", switchReplaceInterrogationFFFD)\n\nswitchDisplayConsolePrintError = pg.GetBool(\"switchDisplayConsolePrintError\", True)\npg.SetBool(\"switchDisplayConsolePrintError\", switchDisplayConsolePrintError)\n\nswitchFrameInfoBackUpOnFile = pg.GetBool(\"switchFrameInfoBackUpOnFile\", False)\npg.SetBool(\"switchFrameInfoBackUpOnFile\", switchFrameInfoBackUpOnFile)\n\nswitchFrameInfoOnBeginOrEnd = pg.GetBool(\"switchFrameInfoOnBeginOrEnd\", False)\npg.SetBool(\"switchFrameInfoOnBeginOrEnd\", switchFrameInfoOnBeginOrEnd)\n\nswitchMemoBakUpDisplayOnComboBox = pg.GetBool(\"switchMemoBakUpDisplayOnComboBox\", True)\npg.SetBool(\"switchMemoBakUpDisplayOnComboBox\", switchMemoBakUpDisplayOnComboBox)\n\nswitchMemoIncludeOnFile = pg.GetBool(\"switchMemoIncludeOnFile\", True)\npg.SetBool(\"switchMemoIncludeOnFile\", switchMemoIncludeOnFile)\n\nUNDO_QUEUE_MAX_SIZE = pg.GetInt(\"UndoQueueMaxSize\", 100)\npg.SetInt(\"UndoQueueMaxSize\",UNDO_QUEUE_MAX_SIZE)\n\nBOOKMARK_MARKER = pg.GetString(\"BookmarkMarker\",\"#\"+\"#:\") #+ is so we don't toggle this accidentally\npg.SetString(\"BookmarkMarker\", BOOKMARK_MARKER)\n\nMAX_ICONIZED_BUTTON_WIDTH = pg.GetInt(\"MaxIconizedButtonWidth\", 32)\npg.SetInt(\"MaxIconizedButtonWidth\", MAX_ICONIZED_BUTTON_WIDTH)\n\nimport PySide   \nfrom PySide import QtCore, QtGui, QtWidgets\nfrom PySide.QtGui import QImage, QPainter\n#from PySide.QtCore import * \n#from PySide.QtGui import * \n#from PySide.QtWidgets import * \nimport FreeCAD, FreeCADGui\n\nimport difflib\nimport json\nimport re, itertools\nimport random\nimport operator\nfrom operator import itemgetter, attrgetter, methodcaller    # pour sort dans un tableau\nimport os, platform, sys, shutil\n\nimport importlib\nimport modulefinder\nfrom modulefinder import ModuleFinder\nimport logging\nimport traceback\n\n## used for help -> reference menus\nglobal setPathLatestDirectory   #; setPathLatestDirectory   = \"C:\\ ???\"\nsetPathLatestDirectory = pg.GetString(\"setPathLatestDirectory\")\nif setPathLatestDirectory == \"\": setPathLatestDirectory = path\npg.SetString(\"setPathLatestDirectory\", setPathLatestDirectory)\n\nglobal duplicate_Find   ; duplicate_Find    = []\nglobal duplicate_Replace; duplicate_Replace = []\nglobal duplicate_Indent_Memo; duplicate_Indent_Memo = []\nglobal fileNameBAK      ; fileNameBAK = \"\"\nglobal buttonDelBak     ; buttonDelBak = False\n\nglobal takenBakFiles    ; takenBakFiles = []\n\nhasQtXmlPatterns = False\ntry:\n    from PySide import QtXmlPatterns\n    hasQtXmlPatterns = True\nexcept ImportError:\n    pass\n\nhasQtXml = False\ntry:\n    from PySide import QtXml\n    hasQtXml = True\nexcept ImportError:\n    pass\n\nhasQtWidgets = False\ntry:\n    from PySide import QtWidgets\n    hasQtWidgets = True\nexcept ImportError:\n    pass\n\nhasQtHelp = False\ntry:\n    from PySide import QtHelp\n    hasQtHelp = True\nexcept ImportError:\n    pass\n\nhasQtNetwork = False\ntry:\n    from PySide import QtNetwork\n    hasQtNetwork = True\nexcept ImportError:\n    pass\n\nhasQtMultimedia = False\ntry:\n    from PySide import QtMultimedia\n    hasQtMultimedia = True\nexcept ImportError:\n    pass\n\nhasQtOpenGL = False\ntry:\n    from PySide import QtOpenGL\n    hasQtOpenGL = True\nexcept ImportError:\n    pass\n\nhasQtPrintSupport = False\ntry:\n    from PySide import QtPrintSupport\n    hasQtPrintSupport = True\nexcept ImportError:\n    pass\n\nhasQtSql = False\ntry:\n    from PySide import QtSql\n    hasQtSql = True\nexcept ImportError:\n    pass\n\nhasQtSvg = False\ntry:\n    from PySide import QtSvg\n    hasQtSvg = True\nexcept ImportError:\n    pass\n\nhasQtTest = False\ntry:\n    from PySide import QtTest\n    hasQtTest = True\nexcept ImportError:\n    pass\n\ntry:\n    import shiboken2 as shiboken\nexcept:\n    shiboken = None\nmw = FreeCADGui.getMainWindow()\n\nclass FindEdit(QtWidgets.QLineEdit):\n    def __init__(self, parent=None, form=None):\n        super(FindEdit, self).__init__()\n        self.form = form\n        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)\n        self.customContextMenuRequested.connect(self.__contextMenu)\n        self.installEventFilter(self)\n        self.setToolTip(\"Double click to set text from current selection in editor\")\n\n    def eventFilter(self, watched, event):\n        if watched == self and event.type() == QtCore.QEvent.MouseButtonDblClick:\n            if shiboken.isValid(self.form.currentEditor) and self.form.currentEditor:\n                sel = self.form.currentEditor.textCursor().selectedText()\n                if sel:\n                    self.setText(sel)\n                else:\n                    self.form.toast(\"Nothing selected in editor\",\"Error\")\n            else:\n                self.form.toast(\"Editor is invalid\",\"Error\")\n        elif hasattr(self.form, \"findEdit\") and watched == self.form.findEdit and event.type() == QtCore.QEvent.KeyPress and event.key() == QtCore.Qt.Key_Down:\n            self.form.replaceEdit.setFocus()\n            event.accept()\n        elif hasattr(self.form, \"replaceEdit\") and watched == self.form.replaceEdit and event.type() == QtCore.QEvent.KeyPress and event.key() == QtCore.Qt.Key_Up:\n            self.form.findEdit.setFocus()\n            event.accept()\n        return QtWidgets.QLineEdit.eventFilter(self, watched, event)\n\n    def __contextMenu(self):\n        self._normalMenu = self.createStandardContextMenu()\n        self._addCustomMenuItems(self._normalMenu)\n        self._normalMenu.exec_(QtGui.QCursor.pos())\n\n    def _addCustomMenuItems(self, menu):\n        menu.addSeparator()\n        action = QtWidgets.QAction(\"Use selected\", self)\n        action.triggered.connect(self.useSelected)\n        action.setEnabled(self.form.currentEditor.textCursor().selectedText() != \"\" if self.form.currentEditor else False)\n        menu.addAction(action)\n\n        actionClear = QtWidgets.QAction(\"Clear\", self)\n        actionClear.triggered.connect(self.clear)\n        actionClear.setEnabled(len(self.text()))\n        menu.addAction(actionClear)\n\n        actionHighlight = QtWidgets.QAction(\"Highlight\",self)\n        actionHighlight.triggered.connect(self.highlight)\n        actionHighlight.setEnabled(len(self.text()))\n        if self == self.form.findEdit:\n            menu.addAction(actionHighlight)\n\n    def highlight(self):\n        if self == self.form.findEdit:\n            self.form.highlightFromFind()\n\n    def clear(self):\n        self.setText(\"\")\n\n    def useSelected(self):\n        txt_cur = self.form.currentEditor.textCursor()\n        txt = txt_cur.selectedText()\n        self.setText(txt)\n\nclass CustomQWidget(QtWidgets.QWidget):\n    def __init__(self, parent=None, form=None):\n        super(CustomQWidget, self).__init__()\n        self.form = form\n        self.hide()\n        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)\n    def setFound(self,found):\n        self.form.found = found\n\nclass FileFilterProxyModel (QtCore.QSortFilterProxyModel):\n    \"\"\"Used when setting up drag/drop from file browser to drag/drop macro file to forum\"\"\"\n    def __init__(self, path):\n        super(FileFilterProxyModel, self).__init__()\n        self.path = path #path is full path to macro file\n    def filterAcceptsRow(self, sourceRow, sourceParent):\n        idx0 = self.sourceModel().index(sourceRow, 0, sourceParent)\n        fileModel = self.sourceModel()\n        #idx0.data() returns a string, such as \"Macros\" or \"C:\"\n        if fileModel.isDir(idx0) and not idx0.data() in self.path:\n            return False #do not show this folder\n        else:\n            return True\n\nclass TaskEditorAssistant:\n    def __init__(self):\n        #super(TaskEditorAssistant, self).__init__(mw, QtCore.Qt.Tool)\n        #GetInt(), SetInt(), GetFloat(), SetFloat(), GetBool(), SetBool(), GetString(), SetString()\n        self.isTabbed=False\n        self.found = False #find result\n        self.lastHighlightMode = \"find\" #can be None, \"find\", or \"selection\"\n        self.gotoLineDict = {} #to save goto line edit value for each editor\n        self.editorDict = {}\n        self.editors = []\n        self.parents = []\n        self.grandparents = []\n        self.titles = []\n        self.templateDictString = self.getTemplateString()\n        self.undoQueue = [] #dictionary list {reason, old_text, name, tc}\n        self.redoQueue = [] #tc holds a tuple (start, end) of selected text position\n        self.snaps = [] #dictionary list {reason, old_text, name, tc}\n        self.currentEditor = None\n        self.timers = [] #toasts use this\n        self.toastsLog = [tuple([\"No previous toasts\",\"Message\"])]\n        self.getEditors()\n        self.blockSignals = False\n        self.form = CustomQWidget(form=self)\n        self.form.setObjectName(\"Editor assistant\")\n        self.form.setWindowTitle(\" Editor assistant v\"+__version__)\n        self.form.setWindowIcon(QIconFromXPMString(__icon__))\n        self.Indent_Memo = \"\"\n\n        for ed in self.editors:\n            self.editorDict [ed.parent().parent().windowTitle()] = ed\n        self.mdi = mw.findChild(QtWidgets.QMdiArea)\n        self.mdi.subWindowActivated.connect(self.onSubWindowActivated)\n        #self.layout = VBox = main layout (rest are all HBox)\n        #topLabelLayout = toast label\n        #editorLayout = editor list widget\n        #refreshLayout = refresh button + goto menu button + goto line edit\n        #gotoLayout = goto home button + goto end button (hidden by default)\n        #undoLayout =  undo + pop undos + redo\n        #findEditLayout = Find edit + search + search previous + clear\n        #findEditLayout2 = ComboBox_Find\n        #replaceEditLayout = Replace edit + replace + replace all + reverse\n        #replaceEditLayout2 = ComboBox_replace\n        #indentLayout = unindent button + indent button + combo box indent memo + match case checkbox + whole words checkbox\n        #snapLayout = snap button + discard button + snap menu + pop button\n        #consoleLayout = to console label + console line edit\n\n        self.layout = QtWidgets.QVBoxLayout()\n        self.form.setLayout(self.layout)\n        topLabelLayout = QtWidgets.QHBoxLayout()\n        self.mainMenuBtn = QtWidgets.QPushButton()\n        self.mainMenuBtn.setIcon(QIconFromXPMString(__icon__))\n        self.mainMenuBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.mainMenuBtn.setToolTip(\"Main menu\")\n        self.mainMenuBtn.clicked.connect(self.onMainMenuBtnClicked)\n        topLabelLayout.addWidget(self.mainMenuBtn)\n        topLabelLayout.addStretch() \n\n        self.msgBtn = QtWidgets.QPushButton()\n        self.msgBtn.clicked.connect(self.onMsgBtnClicked)\n        self.msgBtn.setIcon(QIconFromXPMString(File_Dialog_Info_View_icon))\n        self.msgBtn.setFixedWidth(300)  \n        self.msgBtn.setToolTip(\"Toast message area,\" + \"\\n\" +\n                               \"click to see most recent message displayed in the report view\")\n        topLabelLayout.addWidget(self.msgBtn)\n        self.layout.addLayout(topLabelLayout)\n\n        editorLayout = QtWidgets.QHBoxLayout()\n        showEditorList = pg.GetBool(\"ShowEditorList\",True)\n\n        self.editorList = QtWidgets.QListWidget()\n        editorListMinimumHeight = pg.GetInt(\"EditorListMinimumHeight\",32)\n        pg.SetInt(\"EditorListMinimumHeight\", editorListMinimumHeight)\n        self.editorList.setMinimumHeight(editorListMinimumHeight)\n        self.editorList.currentItemChanged.connect(self.onEditorListCurrentItemChanged)\n        self.editorList.doubleClicked.connect(self.onRefreshBtnClicked)\n        self.editorList.setToolTip(\"Open editors, press Refresh to update\")\n        editorLayout.addWidget(self.editorList)\n        if not showEditorList:\n            self.editorList.setVisible(showEditorList)\n        self.layout.addLayout(editorLayout)\n        self.populateList()\n\n        refreshLayout = QtWidgets.QHBoxLayout()\n        showRefreshLine = pg.GetBool(\"ShowRefreshLine\", True)\n\n        ShowRunMacroBtn = pg.GetBool(\"ShowRunMacroBtn\", True)\n        ShowRunBackUpAction = pg.GetBool(\"ShowRunBackUpAction\", True)\n        ShowRunShowFilesBak = pg.GetBool(\"ShowRunShowFilesBak\", True)\n\n        self.refreshBtn = QtWidgets.QPushButton()#\"Refresh\"\n        self.refreshBtn.setToolTip(\"Refresh list of editors in the list widget above\")\n        self.refreshBtn.setIcon(QIconFromXPMString(BrowserReload_icon))\n        self.refreshBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.refreshBtn.clicked.connect(self.onRefreshBtnClicked)\n        refreshLayout.addWidget(self.refreshBtn)\n\n        self.gotoLineEdit = QtWidgets.QLineEdit()\n        self.gotoLineEdit.returnPressed.connect(self.onGotoLineEditReturnPressed)\n        self.gotoLineEdit.textChanged.connect(self.onGotoLineEditTextChanged)\n        self.gotoLineEdit.setPlaceholderText(\"Goto Line numbers\")\n\n        self.gotoMenuBtn = QtWidgets.QPushButton()\n        self.gotoMenuBtn.setToolTip(f\"\\\nGoto menu\\n\\\nLine numbers = comma separated lines in Goto line edit\\n\\\nBookmarks = lines with {BOOKMARK_MARKER} bookmark description\\n\\\nFind results = results of searches for text in Find line edit\\n\\\n\")\n        self.gotoMenuBtn.clicked.connect(self.onGotoMenuBtnClicked)\n        self.gotoMenuBtn.setIcon(QIconFromXPMString(snap_Menu_Btn_icon))\n        self.gotoMenuBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        refreshLayout.addWidget(self.gotoMenuBtn)\n        refreshLayout.addWidget(self.gotoLineEdit)\n        self.layout.addLayout(refreshLayout)\n\n\n        if not showRefreshLine:\n            self.refreshBtn.setVisible(showRefreshLine)\n            self.gotoMenuBtn.setVisible(showRefreshLine)\n            self.gotoLineEdit.setVisible(showRefreshLine)\n\n        self.runMacroBtn = QtWidgets.QPushButton()\n        self.runMacroBtn.setIcon(QIconFromXPMString(runSave_icon))\n        self.runMacroBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.runMacroBtn.setToolTip(\"<html><body>\"\n                                    \"<b>Save and Run the macro.</b>\" + \"<br/>\"\n                                    \"The executed code has the extension <b>.FCMacro</b> and <b>.py</b> other extensions are ignored\" + \"<br/>\"\n                                    \"It is possible <font color='#ef2929'> the macro may not work</font> with this button\" + \"<br/>\"\n                                    \"ex: macro search data in another macro or\" + \"<br/>\"\n                                    \"the macro depends on another macro with one error or...\" + \"<br/>\"\n                                    \"Then try run with the conventional method.\" + \"<br/>\"\n                                    \"<br/>\"\n                                    \"<u>Options</u> : \" + \"<i>(Tools > Parameters > Plugins > Editor_Assistant)</i>\" + \"<br/>\"\n                                    \"<br/>\"\n                                    \"<b>switch_Unicode_Read_File</b>\" + \"<br/>\"\n                                    \"True : only in read file, detect 'UnicodeDecodeError' display Toast, stop the run\" + \"<br/>\"\n                                    \"False: only in read file, skip error detection not display Toast, skip or not the run (by default)\" + \"<br/>\"\n                                    \"Actual : <b>\" + str(switch_Unicode_Read_File) + \"</b>\" + \"<br/>\"\n                                    \"<br/>\"\n                                    \"<b>switchMemoIncludeOnFile</b>\" + \"<br/>\"\n                                    \"You can include one little memo, this memo is adding in the name of file\" + \"<br/>\"\n                                    \"This memo is displayed while hovering the list on ComboBox\" + \"<br/>\"\n                                    \"The maximum lenght of the path + name + memo is automatically cut off to 255 characters\" + \"<br/>\"\n                                    \"Actual : <b>'\" + str(switchMemoIncludeOnFile) + \"'</b>\" + \"<br/>\"\n                                    \"<br/>\"\n                                    \"Save one backup file in desidered directory\" + \"<br/>\"\n                                    \"The button display and give the number of backup file\" + \"<br/>\"\n                                    \"Press the button for delette the complete file(s) and directory\" + \"<br/>\"\n                                    \"<br/>\"\n                                    \"<b>setPathFileBackup</b>\" + \"<br/>\"\n                                    \"Path for the backup files (Default: the macro directory)\" + \"<br/>\"\n                                    \"Actual : <b>'\" + setPathFileBackup + \"'</b><br/>\"\n                                    \"<br/>\"\n                                    \"<b>setPathFileSecondStorage</b>\" + \"<br/>\"\n                                    \"You have the possibility to save the macro in a second storage space\" + \"<br/>\"\n                                    \"This option save the file only if the code is good\" + \"<br/>\"\n                                    \"Go to preferences space and give the path in the <b>setPathFileSecondStorage</b> variable\" + \"<br/>\"\n                                    \"If setPathFileSecondStorage is empty the function is ignored\" + \"<br/>\"\n                                    \"If the path is erroneous the function is also ignored\" + \"<br/>\"\n                                    \"Actual : <b>'\" + setPathFileSecondStorage + \"'</b>\" + \"<br/>\"\n                                    \"<br/>\"\n                                    \"<b>switchDisplayConsolePrintError</b>\" + \"<br/>\"\n                                    \"Display or not the complete error info in the reportView\" + \"<br/>\"\n                                    \"Actual : <b>'\" + str(switchDisplayConsolePrintError) + \"'</b>\" + \"<br/>\"\n                                    \"<br/>\"\n                                    \"</body></html>\")\n        if not ShowRunMacroBtn:\n            self.runMacroBtn.setVisible(ShowRunMacroBtn)\n        self.runMacroBtn.clicked.connect(self.runMacroBtnClicked)\n\n        self.fileBackupDelBtn = QtWidgets.QPushButton()\n        self.fileBackupDelBtn.setIcon(QIconFromXPMString(directory_Backup_Empty_icon))\n        self.fileBackupDelBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH * 2)    # enlarge button\n        if not ShowRunBackUpAction:\n            self.fileBackupDelBtn.setVisible(ShowRunBackUpAction)\n        self.fileBackupDelBtn.clicked.connect(self.fileBackupDelBtnClicked)\n\n        self.ComboBox_Bak_Files = QtWidgets.QComboBox()\n        self.ComboBox_Bak_Files.setMaxVisibleItems(25)\n        self.ComboBox_Bak_Files.setEditable(False)              # not editable\n        ## later    #self.ComboBox_Bak_Files.setEditable(True)  # editable\n        self.ComboBox_Bak_Files.setFixedWidth(270)  \n\n        if not ShowRunShowFilesBak:\n            self.ComboBox_Bak_Files.setVisible(ShowRunShowFilesBak)\n        QtCore.QObject.connect(self.ComboBox_Bak_Files, QtCore.SIGNAL(\"textActivated (QString)\"), self.on_ComboBox_Bak_Files_Clicked)\n        self.ComboBox_Bak_Files.textHighlighted.connect(self.on_Header_Bak_File_Info) \n        ## later    #self.ComboBox_Bak_Files.currentTextChanged.connect(self.on_Header_Bak_File_Info_Changed)  # avec editable\n\n        runMacroLayout = QtWidgets.QHBoxLayout()\n        runMacroLayout.addWidget(self.runMacroBtn)\n        runMacroLayout.addWidget(self.fileBackupDelBtn)\n        runMacroLayout.addStretch()\n        runMacroLayout.addWidget(self.ComboBox_Bak_Files)\n        self.layout.addLayout(runMacroLayout)\n\n        gotoLayout = QtWidgets.QHBoxLayout()\n        showGotoLine = pg.GetBool(\"ShowGotoLine\", True)\n        self.gotoHomeBtn = QtWidgets.QPushButton()\n        self.gotoHomeBtn.setIcon(QIconFromXPMString(home_icon))\n        self.gotoHomeBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.gotoHomeBtn.setToolTip(\"Go to first line\")\n        self.gotoHomeBtn.clicked.connect(self.onGotoHomeBtnClicked)\n        gotoLayout.addWidget(self.gotoHomeBtn)\n        self.gotoEndBtn = QtWidgets.QPushButton()\n        self.gotoEndBtn.setIcon(QIconFromXPMString(end_icon))\n        self.gotoEndBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n\n        self.gotoEndBtn.setToolTip(\"Go to last line\")\n        self.gotoEndBtn.clicked.connect(self.onGotoEndBtnClicked)\n        gotoLayout.addWidget(self.gotoEndBtn)\n        gotoLayout.addStretch()\n        self.previousBookmarkBtn = QtWidgets.QPushButton(\"\")\n        nextIcon = QIconFromXPMString(next_bookmark_icon)\n        prevIcon = QtGui.QPixmap(nextIcon.pixmap(64,64)).transformed(QtGui.QTransform().scale(-1,1), QtCore.Qt.SmoothTransformation)\n        self.previousBookmarkBtn.setIcon(prevIcon)\n        self.previousBookmarkBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        gotoLayout.addWidget(self.previousBookmarkBtn)\n        self.previousBookmarkBtn.setToolTip(\"Goto previous bookmark\")\n        self.previousBookmarkBtn.clicked.connect(self.previousBookmark)\n\n        self.nextBookmarkBtn = QtWidgets.QPushButton()\n        self.nextBookmarkBtn.setIcon(QIconFromXPMString(next_bookmark_icon))\n        self.nextBookmarkBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        gotoLayout.addWidget(self.nextBookmarkBtn)\n        self.nextBookmarkBtn.setToolTip(\"Goto next bookmark\")\n        self.nextBookmarkBtn.clicked.connect(self.nextBookmark)\n\n        self.toggleBookmarkBtn = QtWidgets.QPushButton(\"\")\n        self.toggleBookmarkBtn.setIcon(QIconFromXPMString(toggle_bookmark_icon))\n        self.toggleBookmarkBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        gotoLayout.addWidget(self.toggleBookmarkBtn)\n        self.toggleBookmarkBtn.setToolTip(\"Toggle bookmark\")\n        self.toggleBookmarkBtn.clicked.connect(self.toggleBookmark)\n\n        self.removeAllBookmarksBtn = QtWidgets.QPushButton()\n        self.removeAllBookmarksBtn.setIcon(QIconFromXPMString(remove_all_bookmarks_icon))\n        self.removeAllBookmarksBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        gotoLayout.addWidget(self.removeAllBookmarksBtn)\n        self.removeAllBookmarksBtn.setToolTip(\"Remove all bookmarks\")\n        self.removeAllBookmarksBtn.clicked.connect(self.removeAllBookmarks)\n\n        self.layout.addLayout(gotoLayout)\n        if not showGotoLine:\n            self.gotoHomeBtn.setVisible(showGotoLine)\n            self.gotoEndBtn.setVisible(showGotoLine)\n\n        showUndoLine = pg.GetBool(\"ShowUndoLine\",True)\n        undoLayout = QtWidgets.QHBoxLayout()\n        self.undoBtn = QtWidgets.QPushButton()\n        self.undoBtn.setEnabled(False)\n        undoLayout.addWidget(self.undoBtn)\n        self.undoBtn.clicked.connect(self.onUndoBtnClicked)\n        self.undoBtn.setIcon(QIconFromXPMString(undo_icon))\n        self.undoClearBtn = QtWidgets.QPushButton()\n        self.undoClearBtn.setIcon(QIconFromXPMString(Reset_Button_icon))\n        self.undoClearBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.undoClearBtn.setToolTip(\"Purge undo/redo queues.  Clears both queues.\")\n        self.undoClearBtn.clicked.connect(self.onUndoClearBtnClicked)\n        self.undoClearBtn.setEnabled(False)\n        undoLayout.addWidget(self.undoClearBtn)\n        self.redoBtn = QtWidgets.QPushButton()\n        self.redoBtn.setEnabled(False)\n        undoLayout.addWidget(self.redoBtn)\n        self.redoBtn.clicked.connect(self.onRedoBtnClicked)\n        self.redoBtn.setIcon(QIconFromXPMString(redo_icon))\n        self.redoBtn\n        if not showUndoLine:\n            self.undoBtn.setVisible(showUndoLine)\n            self.redoBtn.setVisible(showUndoLine)\n            self.undoClearBtn.setVisible(showUndoLine)\n        self.layout.addLayout(undoLayout)\n\n        showFindLine = pg.GetBool(\"ShowFindLine\",True)\n        findEditLayout = QtWidgets.QHBoxLayout()\n        self.Clear_FindReplaceCB = QtWidgets.QPushButton()  #\"Clear\"\n        self.Clear_FindReplaceCB.setToolTip(\"Clear the fields Find / Replace\")\n        self.Clear_FindReplaceCB.setIcon(QIconFromXPMString(Reset_Button_icon))\n        self.Clear_FindReplaceCB.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.Clear_FindReplaceCB.clicked.connect(self.on_Clear_FindReplaceCB_Clicked)\n        findEditLayout.addWidget(self.Clear_FindReplaceCB)\n\n\n        self.Refresh_Aqua_HighlightS = QtWidgets.QPushButton()  #\"Refresh_Aqua_Highlight Search\"\n        self.Refresh_Aqua_HighlightS.setToolTip(\"Refresh / Restaure Highlight Selection (Find)\")\n        self.Refresh_Aqua_HighlightS.setIcon(QIconFromXPMString(Btn_Refresh_Aqua_Highlight_icon))\n        self.Refresh_Aqua_HighlightS.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.Refresh_Aqua_HighlightS.clicked.connect(self.on_Refresh_Aqua_HighlightS_clicked)\n        findEditLayout.addWidget(self.Refresh_Aqua_HighlightS)\n\n        self.findEdit = FindEdit(form=self)\n        self.findEdit.setPlaceholderText(\"Find:\")\n        self.findEdit.returnPressed.connect(self.onFindEditReturnPressed)\n        self.findEdit.textChanged.connect(self.onFindEditTextChanged)\n        findEditLayout.addWidget(self.findEdit)\n\n        self.findBtn = QtWidgets.QPushButton()\n        self.findBtn.setIcon(QIconFromXPMString(find_next_icon))\n        self.findBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.findBtn.setToolTip(\"Find next\\nCtrl+Click = Find from start\\nAlt+Click = Find from selection\")\n        self.findBtn.clicked.connect(self.onFindBtnClicked)\n\n        self.findBackBtn = QtWidgets.QPushButton()\n        self.findBackBtn.setIcon(QIconFromXPMString(find_previous_icon))\n        self.findBackBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.findBackBtn.setToolTip(\"Find previous\\nCtrl+Click = Find from end\\nAlt+Click = Find from selection\")\n        self.findBackBtn.clicked.connect(self.onFindBackBtnClicked)\n        findEditLayout.addWidget(self.findBtn)\n        findEditLayout.addWidget(self.findBackBtn)\n\n        showFindLine2 = pg.GetBool(\"ShowFindLine2\",False)\n        findEditLayout2 = QtWidgets.QHBoxLayout()\n        self.ComboBox_Find = QtWidgets.QComboBox()\n        self.ComboBox_Find.setMaxVisibleItems(16)\n        self.ComboBox_Find.setDuplicatesEnabled(False)    # not work ?\n        self.ComboBox_Find.setEditable(True)              # editable\n        #QtCore.QObject.connect(self.ComboBox_Find, QtCore.SIGNAL(\"currentIndexChanged(QString)\"), self.on_ComboBox_Find_Clicked)\n        QtCore.QObject.connect(self.ComboBox_Find, QtCore.SIGNAL(\"textActivated (QString)\"), self.on_ComboBox_Find_Clicked)\n        findEditLayout2.addWidget(self.ComboBox_Find)\n\n        if not showFindLine:\n            self.findEdit.setVisible(showFindLine)\n            self.findBtn.setVisible(showFindLine)\n            self.findBackBtn.setVisible(showFindLine)\n            self.Clear_FindReplaceCB.setVisible(showFindLine)\n\n            self.Refresh_Aqua_HighlightS.setVisible(showFindLine)\n\n        if not showFindLine2:\n            self.ComboBox_Find.setVisible(showFindLine2)\n\n        self.layout.addLayout(findEditLayout)\n        self.layout.addLayout(findEditLayout2)\n\n        showReplaceLine = pg.GetBool(\"ShowReplaceLine\",True)\n        replaceEditLayout = QtWidgets.QHBoxLayout()\n        self.Reverse_FindReplaceCB = QtWidgets.QPushButton()    #\"Reverse\"\n        self.Reverse_FindReplaceCB.setToolTip(\"Reverse the fields Find / Replace\")\n        self.Reverse_FindReplaceCB.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.Reverse_FindReplaceCB.setIcon(QIconFromXPMString(reverse_find_replace_icon))\n        self.Reverse_FindReplaceCB.clicked.connect(self.on_Reverse_FindReplaceCB_Clicked)\n        replaceEditLayout.addWidget(self.Reverse_FindReplaceCB)\n\n        self.Refresh_Aqua_HighlightR = QtWidgets.QPushButton()  #\"Refresh_Aqua_Highlight Search\"\n        self.Refresh_Aqua_HighlightR.setToolTip(\"Refresh / Restaure Highlight Selection (Replace)\")\n        self.Refresh_Aqua_HighlightR.setIcon(QIconFromXPMString(Btn_Refresh_Aqua_Highlight_icon))\n        self.Refresh_Aqua_HighlightR.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.Refresh_Aqua_HighlightR.clicked.connect(self.on_Refresh_Aqua_HighlightR_clicked)\n        replaceEditLayout.addWidget(self.Refresh_Aqua_HighlightR)\n\n        self.replaceEdit = FindEdit(form=self)\n        self.replaceEdit.setPlaceholderText(\"Replace:\")\n        replaceEditLayout.addWidget(self.replaceEdit)\n        self.replaceBtn = QtWidgets.QPushButton()\n        self.replaceBtn.setToolTip(\"Replace current selection and find next\")\n        self.replaceBtn.clicked.connect(self.onReplaceBtnClicked)\n        self.replaceBtn.setIcon(QIconFromXPMString(replace_icon))\n        self.replaceBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.replaceAllBtn = QtWidgets.QPushButton()\n        self.replaceAllBtn.setToolTip(\"Replace all\\nCtrl+Click = Replace only in selection\")\n        self.replaceAllBtn.setIcon(QIconFromXPMString(replace_all_icon))\n        self.replaceAllBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.replaceAllBtn.clicked.connect(self.onReplaceAllBtnClicked)\n        replaceEditLayout.addWidget(self.replaceBtn)\n        replaceEditLayout.addWidget(self.replaceAllBtn)\n\n        showReplaceLine2 = pg.GetBool(\"ShowReplaceLine2\",False)\n        replaceEditLayout2 = QtWidgets.QHBoxLayout()\n        self.ComboBox_replace = QtWidgets.QComboBox()\n        self.ComboBox_replace.setMaxVisibleItems(16)\n        self.ComboBox_replace.setDuplicatesEnabled(False)    # not work ?\n        self.ComboBox_replace.setEditable(True)              # editable\n\n        #QtCore.QObject.connect(self.ComboBox_replace, QtCore.SIGNAL(\"currentIndexChanged(QString)\"), self.on_ComboBox_Replace_Clicked)\n        QtCore.QObject.connect(self.ComboBox_Find, QtCore.SIGNAL(\"textActivated (QString)\"), self.on_ComboBox_Find_Clicked)\n        replaceEditLayout2.addWidget(self.ComboBox_replace)\n\n        if not showReplaceLine:\n            self.replaceEdit.setVisible(showReplaceLine)\n            self.Refresh_Aqua_HighlightR.setVisible(showReplaceLine)\n            self.replaceBtn.setVisible(showReplaceLine)\n            self.replaceAllBtn.setVisible(showReplaceLine)\n            self.Reverse_FindReplaceCB.setVisible(showReplaceLine)\n\n            self.Clear_FindReplaceCB.setVisible(showReplaceLine)\n\n        if not showReplaceLine2:\n            self.ComboBox_replace.setVisible(showReplaceLine2)\n\n        self.layout.addLayout(replaceEditLayout)\n        self.layout.addLayout(replaceEditLayout2)\n\n        showIndentLine = pg.GetBool(\"ShowIndentLine\", True)\n        indentLayout = QtWidgets.QHBoxLayout()\n        self.indentBackBtn = QtWidgets.QPushButton()\n        self.indentBackBtn.setIcon(QIconFromXPMString(unindent_icon))\n        self.indentBackBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.indentBackBtn.setToolTip(\"Decrease indentation of selection\")\n        self.indentBackBtn.clicked.connect(self.onIndentBackBtnClicked)\n        indentLayout.addWidget(self.indentBackBtn)\n        self.indentBtn = QtWidgets.QPushButton()\n        self.indentBtn.setIcon(QIconFromXPMString(indent_icon))\n        self.indentBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.indentBtn.setToolTip(\"Increase indentation of selection\")\n        self.indentBtn.clicked.connect(self.onIndentBtnClicked)\n        indentLayout.addWidget(self.indentBtn)\n\n        self.ComboBox_Indent_Memo = QtWidgets.QComboBox()\n        self.ComboBox_Indent_Memo.setMaxVisibleItems(16)\n        self.ComboBox_Indent_Memo.setToolTip(\"Insert the text in front on line(s) selected instead of the indentation \" + \"\\n\"\n                                             \"(the button indentation icon change)\" + \"\\n\"\n                                             \"Ex: '#ori'\" + \"\\n\"\n                                             \"Validate by Enter\" + \"\\n\"\n                                             \"If the field is empty the normal indentation is used\" + \"\\n\")\n        self.ComboBox_Indent_Memo.setDuplicatesEnabled(False)    # not work ?\n        self.ComboBox_Indent_Memo.setEditable(True)              # editable\n        QtCore.QObject.connect(self.ComboBox_Indent_Memo, QtCore.SIGNAL(\"currentIndexChanged(QString)\"), self.on_ComboBox_Indent_Memo_Clicked)\n        QtCore.QObject.connect(self.ComboBox_Indent_Memo, QtCore.SIGNAL(\"editTextChanged (QString)\"), self.on_ComboBox_Indent_Memo_Changed_Clicked)\n        indentLayout.addWidget(self.ComboBox_Indent_Memo)\n\n        #indentLayout.addStretch()\n        self.matchWholeCheckBox = QtWidgets.QCheckBox()\n        self.matchWholeCheckBox.setIcon(QIconFromXPMString(match_whole_word_icon))\n\n        self.matchWholeCheckBox.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH + 5)\n        self.matchWholeCheckBox.setToolTip(\"Match whole words\")\n        self.matchWholeCheckBox.stateChanged.connect(self.onMatchWholeCheckBoxStateChanged)\n\n        self.matchCaseCheckBox = QtWidgets.QCheckBox()\n        self.matchCaseCheckBox.stateChanged.connect(self.onMatchCaseCheckBoxStateChanged)\n\n        self.matchCaseCheckBox.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH + 5)\n        self.matchCaseCheckBox.setIcon(QIconFromXPMString(match_case_icon))\n        self.matchCaseCheckBox.setToolTip(\"Match case\")\n\n        self.loopCheckBox = QtWidgets.QCheckBox()\n        loop_icon = reverse_find_replace_icon.replace(\"#EF2B29\",\"#3F48CC\").replace(\"#8AE138\",\"#3F48CC\")\n        loop_icon = loop_icon.replace(\"#4E990D\",\"black\").replace(\"#A70002\",\"black\")\n\n        self.loopCheckBox.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH + 5)\n        self.loopCheckBox.setIcon(QIconFromXPMString(loop_icon))\n        self.loopCheckBox.setCheckState(QtCore.Qt.Checked)\n        self.loopCheckBox.setToolTip (\"Loop to start/end if text not found\")\n\n        indentLayout.addWidget(self.matchCaseCheckBox)\n        indentLayout.addWidget(self.matchWholeCheckBox)\n        indentLayout.addWidget(self.loopCheckBox)\n        self.matchCaseCheckBox.stateChanged.connect(self.onFindEditTextChanged)\n        if not showIndentLine:\n\n            self.indentBackBtn.setVisible(showIndentLine)\n            self.indentBackBtn.setVisible(showIndentLine)\n            self.indentBackBtn.setVisible(showIndentLine)\n            self.loopCheckBox.setVisible(showIndentLine)\n            self.matchCaseCheckBox.setVisible(showIndentLine)\n            self.matchWholeCheckBox.setVisible(showIndentLine)\n        self.layout.addLayout(indentLayout)\n\n        showSnapsLine = pg.GetBool(\"ShowSnapLine\",True)\n        snapLayout = QtWidgets.QHBoxLayout()\n        self.takeSnapBtn = QtWidgets.QPushButton()\n        self.takeSnapBtn.setIcon(QIconFromXPMString(snapshot_icon))\n        self.takeSnapBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.takeSnapBtn.setToolTip(\"Take a snapshot of the text\")\n        self.snapCenterBtn = QtWidgets.QPushButton()\n\n        self.snapMenuBtn = QtWidgets.QPushButton()\n\n        snapCenterBtnLayout = QtWidgets.QHBoxLayout()\n        snapCenterBtnLayoutMargins = QtCore.QMargins(0,0,0,0)\n        snapCenterBtnLayout.setContentsMargins(snapCenterBtnLayoutMargins)\n        snapCenterBtnLayout.setSpacing(0)\n        self.snapCenterBtn.setLayout(snapCenterBtnLayout)\n        self.snapCenterBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH *2)\n        self.discardSnapBtn = QtWidgets.QPushButton()\n        self.discardSnapBtn.setIcon(QIconFromXPMString(Reset_Button_icon))\n        self.discardSnapBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.discardSnapBtn.clicked.connect(self.discardSnap)\n        self.discardSnapBtn.setToolTip(\"Discard the latest snap\")\n        snapCenterBtnLayout.addWidget(self.discardSnapBtn)\n        snapCenterBtnLayout.addWidget(self.snapMenuBtn)\n        self.snapMenuBtn.setIcon(QIconFromXPMString(snap_Menu_Btn_icon))\n        self.snapMenuBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.snapMenuBtn.setToolTip(\"\\\nSnapshots menu\\n\\\nRestore = replace current text with snap and keep snap\\n\\\nRestore to clipboard and keep snap in memory\\n\\\nRestore to Text document and keep snap in memory\\n\\\nRestore any = Possibility to restore to different document or a snap out of order\\n\\\nSave to new text file and keep snap in memory\\n\\\nSave all snaps to JSON file and keep all in memory\\n\\\nLoad = load all snaps from JSON file, replacing any in memory\\n\\\nPop = restore and discard snap\\n\\\nDiff = show difference between snap and current text\\n\\\n\")\n        self.popSnapBtn = QtWidgets.QPushButton(\"Restore\")\n        self.popSnapBtn.setVisible(showSnapsLine)\n        self.takeSnapBtn.clicked.connect(self.onTakeSnapBtnClicked)\n        self.snapMenuBtn.clicked.connect(self.onSnapMenuBtnClicked)\n        self.popSnapBtn.clicked.connect(self.onPopSnapBtnClicked)\n        snapLayout.addWidget(self.takeSnapBtn)\n        snapLayout.addWidget(self.snapCenterBtn)\n        snapLayout.addWidget(self.popSnapBtn)\n        self.layout.addLayout(snapLayout)\n        if not showSnapsLine:\n            self.takeSnapBtn.setVisible(showSnapsLine)\n            self.snapCenterBtn.setVisible(showSnapsLine)\n            self.discardSnapBtn.setVisible(showSnapsLine)\n            self.snapMenuBtn.setVisible(showSnapsLine)\n\n        showConsoleLine = pg.GetBool(\"ShowConsoleLine\", True)\n        consoleLayout = QtWidgets.QHBoxLayout()\n        self.consoleLabel = QtWidgets.QLabel(\"To console:\")\n\n        consoleLayout.addWidget(self.consoleLabel)\n        self.consoleEdit = QtWidgets.QLineEdit()\n\n        self.consoleEdit.returnPressed.connect(self.onConsoleEditReturnPressed)\n        self.consoleEdit.setToolTip(\"Access QPlainTextEdit of current editor directly.\\n\\\nEnter command here and press return\\n\\\nVariable 'editor' will remain afterwards for direct access from the console.\\n\\\nType 'help(editor)' in the console for help.\\n\\\n\")\n        choices = [\"editor.selectAll()\", \"qSearch('QLineEdit')\", \"wSearch('topological naming problem')\",\n                   \"search('Part.makeFace')\", \"help('Qt.Key')\", \"menu('Draft')\", \"dlg.close()\",\n                   \"dlg.highlight('def', 'yellow')\", \"help('numpy')\", \"dlg.refresh()\"]\n        self.consoleEdit.setText(random.choice(choices))\n        self.consoleSendBtn = QtWidgets.QPushButton(\"Send\")\n        self.consoleSendBtn.clicked.connect(self.onConsoleBtnClicked)\n        consoleLayout.addWidget(self.consoleEdit)\n        self.layout.addLayout(consoleLayout)\n        if not showConsoleLine:\n            self.consoleLabel.setVisible(showConsoleLine)\n            self.consoleEdit.setVisible(showConsoleLine)\n        self.updateSnapBtns()\n\n    def getEditors(self):\n        self.editors = [child for child in mw.findChildren(QtWidgets.QPlainTextEdit) if child.objectName() != \"Python console\"]\n        self.parents = [ed.parent() for ed in self.editors]\n        self.grandparents = [p.parent() for p in self.parents]\n        self.titles = [g.windowTitle() for g in self.grandparents]\n        if hasattr(self, \"editorList\") and shiboken.isValid(self.editorList):\n            curNames = [self.editorList.item(ii).text() for ii in range(0, self.editorList.count())]\n            for ii,title in enumerate(self.titles):\n                if not title in curNames:\n                    cursor = self.editors[ii].textCursor()\n                    self.takeSnap(title, cursor, \"Auto snapshot\",self.editors[ii].toPlainText())\n        else:\n            for ii,title in enumerate(self.titles):\n                cursor = self.editors[ii].textCursor()\n                self.takeSnap(title, cursor, \"Auto snapshot\",self.editors[ii].toPlainText())\n\n        ##https://doc.qt.io/qt-6/stylesheet-examples.html\n        if (COLOR_ACTIVE_TAB == \"0\") or (COLOR_ACTIVE_TAB == \"\"):\n            mw.findChild(QtWidgets.QMdiArea).setStyleSheet(\"QTabBar::tab:selected, QTabBar::tab:hover {background-color: QPalette.Base;}\")\n        else:\n            #mw.findChild(QtWidgets.QMdiArea).setStyleSheet(\"QTabBar::tab:selected, QTabBar::tab:hover {background-color: \" + COLOR_ACTIVE_TAB + \";}\")\n            mw.findChild(QtWidgets.QMdiArea).setStyleSheet(\"QTabBar::tab:selected, QTabBar::tab:only-one {background-color: \" + COLOR_ACTIVE_TAB + \";}\")\n\n    def highlightFromSelection(self):\n        editor = self.currentEditor\n        if not editor:\n            self.toast(\"No editor\",\"Error\")\n            return\n        txt = self.currentEditor.textCursor().selectedText()\n        if not txt:\n            self.toast(\"Nothing selected\",\"Error\")\n            return\n        self.lastHighlightMode = \"selection\"\n        self.highlight(txt)\n\n    def highlightFromFind(self):\n        editor = self.currentEditor\n        if not editor:\n            self.toast(\"No editor\",\"Error\")\n            return\n        txt = self.findEdit.text()\n        self.lastHighlightMode = \"find\"\n        self.highlight(txt)\n\n    def highlight(self, txt, color=\"aqua\"):\n        \"\"\"highlight occurrences of txt with background color\"\"\"\n        if not self.currentEditor:\n            self.toast(\"No current editor\",\"Error\")\n            return\n        if not txt:\n            return\n        plainText = self.currentEditor.toPlainText()\n        indices = self.reFindIndices(plainText, txt, 0)\n        extraSelections = []\n        count = len(indices)\n        for ind in indices:\n            extraSelection = QtWidgets.QTextEdit.ExtraSelection()\n            extraSelection.cursor = self.currentEditor.textCursor()\n            extraSelection.cursor.setPosition(ind[0])\n            extraSelection.cursor.setPosition(ind[1], QtGui.QTextCursor.KeepAnchor)\n            extraSelection.format.setBackground(QtGui.QColor(color))\n            extraSelections.append(extraSelection)\n\n        self.currentEditor.setExtraSelections(extraSelections)\n        self.toast(f\"Highlighted {count} occurrences of {txt}\",\"Message\")\n\n    def setIconCurrentEditor(self, fileNameBAK = \"\"):   # change icon in backUp button\n        try:\n            lenBackUpFile = 0\n            lenBackUpFile = len(os.listdir(fileNameBAK))\n            self.fileBackupDelBtn.setText(str(lenBackUpFile))\n            self.fileBackupDelBtn.setIcon(QIconFromXPMString(directory_Backup_Taken_icon))\n            self.fileBackupDelBtn.setToolTip(\"Number of .bak file stored\" + \"\\n\" +\n                                             \"Actual : \" + str(lenBackUpFile) + \" file(s)\" + \"\\n\"\n                                             \"Push the button for delette complete file(s) and directory\" + \"\\n\"\n                                             \"If the button is not visible the feature not run\")\n        except Exception:\n            try:\n                self.fileBackupDelBtn.setText(\"\")\n                self.fileBackupDelBtn.setIcon(QIconFromXPMString(directory_Backup_Empty_icon))\n                self.fileBackupDelBtn.setToolTip(\"Number of .bak file stored\" + \"\\n\" +\n                                                 \"Push the button for delette complete file(s) and directory\" + \"\\n\"\n                                                 \"If the button is not visible the feature not run\")\n            except Exception:\n                None\n        try:\n            self.ComboBox_Bak_Files.setToolTip(\"<html><body>\"\n                                               \"Click the backup file for reload the .BAK file\" + \"<br/>\"\n                                               \"One new text document is created\" + \"<br/>\"\n                                               \"<br/>\"\n                                               \"<b>\" + fileNameBAK + \"</b><br/>\"\n                                               \"<br/>\"\n                                               \"<b>Format of file saved, example:</b>\" + \"<br/>\"\n                                               \"<b>C:/MyPath/MyMacro.FCMacro.BAK_2023_11_26_19_29_34_##my_memo</b>\" + \"<br/>\"\n                                               \"<br/>\"\n                                               \"<b><font color='#0000AA'> C:/MyPath/</font> </b>\" + \"<br/>\"\n                                               \"\\t the complete path of .Bak file <i>(modifiable by : <b>setPathFileBackup</b>)</i>\" + \"<br/>\"\n                                               \"<b><font color='#0000AA'> MyMacro.FCMacro</font> </b>\" + \"<br/>\"\n                                               \"\\t the real name of the macro can be <b>FCMacro</b> or <b>py</b>\" + \"<br/>\"\n                                               \"<b><font color='#0000AA'> .BAK_2023_11_26_19_29_34</font> </b>\" + \"<br/>\"\n                                               \"\\t the Bak extension with the date and time format YYYY_MM_DD_HH_MM_SS\" + \"<br/>\"\n                                               \"<b><font color='#0000AA'> _##</font></b>\" + \"<br/>\"\n                                               \"\\t the key separation of file to memo <i>(not modifiable)</i>\" + \"<br/>\"\n                                               \"<b><font color='#0000AA'> my_memo</font> </b>\" + \"<br/>\"\n                                               \"\\t the memo attached on file\" + \"<br/>\"\n                                               \"<br/>\"\n                                               \"<i><b><font color='#AA0000'>PS:</font></b> all spaces of the memo are replaced by the character underline <b>'_'</b></i>\" + \"<br/>\"\n                                               \"<br/>\"\n                                               \"<u>Options</u> : \" + \"<i>(Tools > Parameters > Plugins > Editor_Assistant)</i>\"+ \"<br/>\"\n                                               \"<br/>\"\n                                               \"<b>switchMemoIncludeOnFile</b>\" + \"<br/>\"\n                                               \"You can include one little memo, this memo is adding in the name of file\" + \"<br/>\"\n                                               \"This memo is displayed while hovering the list on ComboBox\" + \"<br/>\"\n                                               \"The maximum lenght of the path + name + memo is automatically cut off to 255 characters\" + \"<br/>\"\n                                               \"Actual : <b>'\" + str(switchMemoIncludeOnFile) + \"'</b>\" + \"<br/>\"\n                                               \"<br/>\"\n                                               \"<b>switchFrameInfoBackUpOnFile</b><br/>\"\n                                               \"Write info of backup file loaded<br/>\"\n                                               \"Actual : \" + \"<b>'\" + str(switchFrameInfoBackUpOnFile) + \"'</b><br/>\"\n                                               \"<br/>\"\n                                               \"<b>switchFrameInfoOnBeginOrEnd</b><br/>\"\n                                               \"Choice the position of the info : <b>Begin (True)</b>/<b>End (False)</b> of the file<br/>\"\n                                               \"Actual : \" + \"<b>'\" + str(switchFrameInfoOnBeginOrEnd) + \"'</b><br/>\"\n                                               \"<br/>\"\n                                               \"<b>switchMemoBakUpDisplayOnComboBox</b><br/>\"\n                                               \"Display the memo of the file in the ComboBox <br/>\"\n                                               \"Actual : \" + \"<b>'\" + str(switchMemoBakUpDisplayOnComboBox) + \"'</b><br/>\"\n                                               \"<br/>\"\n                                               \"If the ComboBox is not visible the feature not run\" + \"<br/>\"\n                                               \"</body></html>\")\n        except Exception:\n            None\n\n    def setCurrentEditor(self, name=\"\", focus=True):\n        global fileNameBAK\n\n        if not shiboken.isValid(self.editorList):\n            return\n        if name:\n            if not name in self.editorDict:\n                self.getEditors()\n            self.currentEditor = self.editorDict[name]\n            if name in self.titles:\n                self.blockSignals=True\n                self.editorList.setCurrentRow(self.titles.index(name))\n                self.blockSignals=False\n        else:\n            if self.editorList.currentItem():\n                name = self.editorList.currentItem().text()\n                self.currentEditor = self.editorDict[name]\n        if shiboken and shiboken.isValid(self.currentEditor) and self.currentEditor and not self.currentEditor.hasFocus():\n            if focus and self.form.parent():\n                self.form.parent().hide()\n                self.currentEditor.setFocus()\n                self.form.parent().show()\n\n        if (name.find(\"\\\\\") == -1) and (name.find(\"/\") == -1):  ## for case drag/drop the complete path is already given\n            nameBAK = name\n        else:\n            nameBAK = name.split(\"[\")[0].split(\"/\")[-1] # case drag/drop !?\n        nameBAK = nameBAK.replace(\"[*]\",\"\")             # case drag/drop !?\n        fileNameBAK = setPathFileBackup + nameBAK + \".BAK\"\n        self.setIconCurrentEditor(fileNameBAK)\n        self.setListFilesBak(fileNameBAK)\n\n    def onSubWindowActivated(self, arg1):\n        if not shiboken.isValid(self.editorList):\n            return\n        sub = self.mdi.activeSubWindow()\n        ed = sub.findChild(QtWidgets.QPlainTextEdit) if sub else None\n        if ed:\n            p = ed.parent()\n            gp = p.parent()\n            name = gp.windowTitle()\n\n            ed.setMaximumWidth(1600)\n\n            if not name in self.editorDict:\n                QtCore.QTimer().singleShot(50, self.refresh)\n\n    def FreeCAD_Console_PrintError(self, txt):\n        switchDisplayConsolePrintError = pg.GetBool(\"switchDisplayConsolePrintError\")\n        if switchDisplayConsolePrintError:\n            FreeCAD.Console.PrintMessage(\"_____Info Editor assistant_____Begin\" + \"\\n\")\n            FreeCAD.Console.PrintError(str(txt) + \"\\n\")\n            FreeCAD.Console.PrintMessage(\"_____Info Editor assistant_____End\" + \"\\n\")\n\n    def fileBackupDelBtnClicked(self):  \n        global fileNameBAK\n        global buttonDelBak\n\n        if \".FCMACRO - \" in fileNameBAK.upper():                                    ##cause : /media/mint/cd01/Macro/000x.FCMacro - Editor.BAK\n            fileNameBAK = fileNameBAK.split(\".FCMacro - \")[0] + \".FCMacro\" + \".BAK\" ##result: /media/mint/cd01/Macro/000x.FCMacro.BAK\n        elif \".PY - \" in fileNameBAK.upper():                                       ##cause : /media/mint/cd01/Macro/000x.py - Editor.BAK\n            fileNameBAK = fileNameBAK.split(\".py - \")[0] + \".py\" + \".BAK\"           ##result: /media/mint/cd01/Macro/000x.py.BAK\n\n        if (fileNameBAK != \"\") and (os.path.exists(fileNameBAK)):\n            lenBackUpFile = 0\n            lenBackUpFile = len(os.listdir(fileNameBAK))\n\n            self.infoBackupNewInputDialog(title = \"Warning Delete BAK\", \n                                          backUp_Or_Info = False, \n                                          texto = \"<b>\" + \"Warning Delete BAK\" + \"</b>\" + \"<br/><br/>\" +\n                                                  \"Delete the complete \" + \"<b>\" + \".BAK\" + \"</b>\" + \" directory\" + \"<br/><br/>\" +\n                                                  \"Number of .BAK file(s) : \" + \"<b>\" + str(lenBackUpFile) + \"</b>\" + \"<br/><br/>\" +\n                                                  \"Name of .BAK directory : \" + \"<br/><br/>\" +\n                                                  \"<b>\" + str(fileNameBAK) + \"</b>\")\n\n            if buttonDelBak == True:\n                try:\n                    try:\n                        FreeCAD.ActiveDocument.openTransaction(\"Del_BAK\")    # memorise les actions (avec annuler restore)\n                    except Exception:\n                        None\n                    shutil.rmtree(fileNameBAK)  # del the complete directory and files\n                    self.ComboBox_Bak_Files.clear()\n                except OSError as erreur:\n                    self.FreeCAD_Console_PrintError(erreur) # in windows the error can be cause to the name shortcut ex: C:\\....\\BACKUP~1\\EDITOR~1.BAK\\EDITOR~2.BAK\n                    self.toast(str(erreur),\"Error\")\n                self.setIconCurrentEditor(fileNameBAK)\n        else:\n            self.FreeCAD_Console_PrintError(os.path.exists(fileNameBAK))\n            self.toast(str(os.path.exists(fileNameBAK)),\"Error\")\n\n    def colorError(self, text_cursor=\"\"):\n        lenTextDetected = len(text_cursor.selectedText())\n        extraSelection = QtWidgets.QTextEdit.ExtraSelection()\n        extraSelection.cursor = self.currentEditor.textCursor()\n        text_cursor.clearSelection()\n        extraSelection.format.setBackground(QtGui.QColor(COLOR_ERROR_DETECTED))\n        self.currentEditor.setExtraSelections([extraSelection])\n\n    #######################################################################\n    ########## infoBackupNewInputDialog() \n    global memo_Testing; memo_Testing = []\n    global memo_Last_memo_Entry; memo_Last_memo_Entry = \"\"\n\n    def on_Dialog_accept(self):\n        global memo_Testing\n        global memo_Last_memo_Entry\n\n        self.run = False\n        if self.lineEdit_memo_Bak_Txt.text() != \"\":\n            memox = memo_Last_memo_Entry = self.lineEdit_memo_Bak_Txt.text() \n            memo_Testing.append((memox, True))\n            self.ComboBox_Memo.addItem(memox)\n        else:\n            memo_Testing.append((\"\", True))\n        memo_Testing = memo_Testing[0]\n        self.Dialog_memo_Bak.setVisible(False)\n        self.Dialog_memo_Bak.deleteLater()\n\n    def on_Dialog_cancel(self):\n        global memo_Testing\n\n        memo_Testing.append((\"\", False))\n        memo_Testing = memo_Testing[0]\n        self.run = False\n        self.Dialog_memo_Bak.deleteLater()\n\n    def on_Dialog_accept_Delete(self):\n        global buttonDelBak\n\n        buttonDelBak = True\n        self.run = False\n        self.Dialog_memo_Bak.setVisible(False)\n        self.Dialog_memo_Bak.deleteLater()\n\n    def infoBackupNewInputDialog(self, title = \"\", backUp_Or_Info = True, texto = \"\"):     # instead QtWidgets.QInputDialog, here for adding QComboBox and texto\n        global memo_Last_memo_Entry\n        global memo_Testing\n        global buttonDelBak\n\n        buttonDelBak = False\n        memo_Testing = []\n        grid = QtWidgets.QGridLayout()\n\n        self.Dialog_memo_Bak = QtWidgets.QDialog()\n        self.Dialog_memo_Bak.setWindowModality(QtCore.Qt.ApplicationModal)\n        self.Dialog_memo_Bak.setWindowTitle(title)\n        self.Dialog_memo_Bak.setLayout(grid)\n\n        self.buttonAccept = QtWidgets.QPushButton()\n        self.buttonAccept.setIcon(QIconFromXPMString(accept_Template_icon))\n        grid.addWidget(self.buttonAccept,2, 0)\n\n        self.buttonReject = QtWidgets.QPushButton()\n        self.buttonReject.setText(\"Abord\")\n        self.buttonReject.setIcon(QIconFromXPMString(reject_Template_icon))\n        self.buttonReject.setToolTip(\"Abord the command\")\n        self.buttonReject.clicked.connect(self.on_Dialog_cancel)\n        grid.addWidget(self.buttonReject,2, 1)\n\n        if backUp_Or_Info == False: #backUp_Or_Info = False = Warning window\n            self.Dialog_memo_Bak.resize(300, 100)\n            self.Dialog_memo_Bak.setWindowIcon(QIconFromXPMString(msgBtn_Warning_icon))\n\n            self.buttonAccept.setText(\"Ok Delete\")\n            self.buttonAccept.setToolTip(\"Delete the complete directory\")\n            self.buttonAccept.clicked.connect(self.on_Dialog_accept_Delete)\n            label = QtGui.QLabel()\n            label.setVisible(False)\n            ####\n            #### def QIconFromXPMString(xpm_string):    # cutted for use here\n            xpm = msgBtn_Warning_icon.replace(\"\\\"\",\"\").replace(',','').splitlines()[4:-1]\n            for line in reversed(xpm):\n                if line.startswith(\"/*\") and line.endswith(\"*/\"):\n                    xpm.pop(xpm.index(line))\n            pixmap = QtGui.QPixmap(xpm)\n            #### icon = QtGui.QIcon(pixmap)\n            #### return icon\n            ####\n            label.setPixmap(QtGui.QPixmap(pixmap))\n            grid.addWidget(label,0, 0)\n            label2 = QtGui.QLabel()\n            label2.setText(str(texto))\n            grid.addWidget(label2,0, 1)\n            self.Dialog_memo_Bak.show()\n            label.show()\n            # center screen\n            ecran = FreeCADGui.getMainWindow().frameGeometry()\n            fenetre = self.Dialog_memo_Bak.frameGeometry()\n            xF = fenetre.width()\n            yF = fenetre.height()\n            xW = (ecran.width()/2) - (xF/2)\n            yW = (ecran.height()/2)- (yF/2)\n            self.Dialog_memo_Bak.setGeometry(xW, yW, xF, yF)\n            ####\n        else:                       # backUp_Or_Info = True = Yes/No run\n            self.Dialog_memo_Bak.setMinimumWidth(200)\n            self.Dialog_memo_Bak.setWindowIcon(QIconFromXPMString(__icon__))\n\n            self.buttonAccept.clicked.connect(self.on_Dialog_accept)\n            self.buttonAccept.setText(\"Ok Run\")\n            self.buttonAccept.setToolTip(\"Run the macro\")\n            self.ComboBox_Memo = QtWidgets.QComboBox()\n            self.ComboBox_Memo.addItem(memo_Last_memo_Entry)\n            self.ComboBox_Memo.setToolTip(\"Latest memo entry\")\n            QtCore.QObject.connect(self.ComboBox_Memo, QtCore.SIGNAL(\"textActivated (QString)\"), self.on_ComboBox_Memo_Clicked)\n            grid.addWidget(self.ComboBox_Memo, 0, 0, 1, 2)\n            self.lineEdit_memo_Bak_Txt = QtWidgets.QLineEdit()\n            self.lineEdit_memo_Bak_Txt.setPlaceholderText(\"Memo text goes here\")\n            grid.addWidget(self.lineEdit_memo_Bak_Txt, 1, 0, 1, 2)\n            self.Dialog_memo_Bak.show()\n\n        self.run = True\n        while self.run:\n            #https://forum.freecadweb.org/viewtopic.php?f=22&t=41377\n            QtWidgets.QApplication.instance().processEvents()\n\n    def on_ComboBox_Memo_Clicked(self, text):\n        #self.lineEdit_memo_Bak_Txt.clear()\n        self.lineEdit_memo_Bak_Txt.setText(text)\n    ########## infoBackupNewInputDialog()\n    #######################################################################\n\n    def saveFileSecondStorage(self, text = \"\", storeFile = \"\"):\n        storePath = pg.GetString(\"setPathFileSecondStorage\")\n        if storePath != \"\":\n            if (storePath[-1] == \"/\") or (storePath[-1] == \"\\\\\"):\n                None\n            else:\n                storePath = storePath + \"/\"\n            try:\n                fileSaveSecondStorage = open(storePath + storeFile,'w') # save and display the window Yes/No (case execute macro with EditorAss and work in a 3D window)\n                fileSaveSecondStorage.write(text)\n            except Exception:\n                self.toast(\"The path \" + storePath + \" not exist\",\"Error\")\n            finally:\n                try:\n                    fileSaveSecondStorage.close()\n                except Exception:\n                    None\n\n    def runMacroBtnClicked(self):\n        global path\n        global fileNameBAK\n        global memo_Testing\n\n        try:\n            FreeCAD.ActiveDocument.openTransaction(\"EdAss\")    # memorise les actions (avec annuler restore)\n        except Exception:\n            None\n        self.refresh()\n        try:\n            windowTitleName0 = Gui.getMainWindow().findChild(QtWidgets.QMdiArea).currentSubWindow().windowTitle()\n            windowName0 = self.editorList.currentItem().text()\n            windowName = windowName0.split(\"[\")[0]        #Air_Foild_00_PY.py #Air_Foild_00.FCMacro\n            macroName  = windowName.split(\".\")[0]         #Air_Foild_00_PY    #Air_Foild_00\n            dummy = windowName.split(\".\")[1].upper()\n            dummy = dummyPy = dummy.split(\"[\")[0].upper() #PY   #FCMACRO\n        except Exception:\n            dummy = dummyPy = \"\"\n\n        if (dummy == \"FCMACRO\" or dummyPy == \"PY\"):\n            filename = windowName\n\n            if (windowName.find(\"\\\\\") == -1) and (windowName.find(\"/\") == -1):  ## for case drag/drop the complete path is already given\n                filename = path + windowName\n            filenameSecondStorage = windowName\n\n            switchAllIsGood = True\n\n            try:\n                FreeCAD.ActiveDocument.openTransaction(\"Run Macro\")\n            except Exception:\n                None\n            if self.fileBackupDelBtn.isVisible():  # save Bak file\n                ####\n                curLine = self.getLineNumberAtCursor()\n                ####\n                self.infoBackupNewInputDialog(title = \"Info Backup\") # QDialog with comboView and icon in Button\n                ####\n                if str(memo_Testing[1]) == \"True\":\n                    memo_Bak_Txt = memo_Testing[0]\n                    ii = \"\"\n                    if memo_Bak_Txt != \"\":\n                        for i in memo_Bak_Txt:\n                            if i in \"\\x3c\\x3e\\x3a\\x22\\x2f\\x5c\\x7C\\x3f\\x2a\\x2e\\x20\":\n                                i = \"_\"\n                            ii += i\n                        memo_Bak_Txt = \"_##\" + ii\n                    else:\n                        memo_Bak_Txt = \"_##Curent_Line_\" + str(curLine) # ici\n\n                    self.addBookmark([f\"Bookmark line {curLine} last line of work \", curLine])  # for the file copy\n                    plainText = self.getText()\n                    ####\n                    now = QtCore.QDateTime.currentDateTime().toString(setFormatBackupDateTime)\n                    windowName2 = windowName.split(\"[\")[0].split(\"/\")[-1] # case drag/drop !? \"000x.FCMacro[*] - Editor.BAK\"\n                    windowName2 = windowName2.replace(\"[*]\",\"\")\n                    fileNameBAK = setPathFileBackup + windowName2 + \".BAK\"\n                    try:\n                        os.makedirs(fileNameBAK, exist_ok=True) #11:59:18  OSError: [WinError 123] La syntaxe du nom de fichier, de repertoire ou de volume est incorrecte ex: 'C:/Users/xxxx/AppData/Roaming/FreeCAD/Macro/C:' add \"C:\"\n                    except OSError as erreur:\n                        self.FreeCAD_Console_PrintError(erreur)\n                        self.toast(str(erreur),\"Error\")\n                    completeBakName = fileNameBAK + \"/\" + windowName2 + \".BAK_\" + now + memo_Bak_Txt    #complete name with memo\n                    if len(completeBakName) > 255:\n                        completeBakName = completeBakName[:255] # cut 255 characters\n                    try:\n                        fileSave = open(completeBakName, 'w') # .BAK_ + setFormatBackupDateTime default: \"yyyy-MM-dd_hhmmss\"\n                        try:\n                            fileSave.write(plainText)   # .Bak file\n                            self.setListFilesBak(fileNameBAK) # upgrade\n                                                        # .py .FCMacro file\n                        except (UnicodeEncodeError):    # character '\\ufffd'  RuntimeError, TypeError, NameError): # only in write file switch True detect \"UnicodeDecodeError, UnicodeEncodeError\" display toast\n                            switchAllIsGood = False     # not .Bak file\n                            try:\n                                fileSave.close()\n                            except Exception as e:\n                                classErr = str(sys.exc_info()[0]) # error detected in editor_assistant_dlg.FCMacro\n                                self.toast(str(erreur),\"Error\")\n                                self.FreeCAD_Console_PrintError(str(erreur))\n                                switchAllIsGood = False     # not .Bak file\n                            try:\n                                os.remove(completeBakName)\n                            except Exception:\n                                None\n                            #### search formule for positioned the cursor example in position point 49710 (characters)\n                            erreur = str(traceback.format_exc())     # error detected in executed macro and position the cursor in a eroneous line\n                            erreur = errorSave = str(erreur.split(\"UnicodeEncodeError:\")[1])\n                            lineErrorStr = erreur.split(\"position\")[1].split(\":\")[0]\n                            if \"-\" in lineErrorStr:                  # a cause de ex:  ' 2261-2267' \n                                dummy = \"\"\n                                dummy = str(lineErrorStr)\n                                lineErrorStr = dummy.split(\"-\")[0]\n                            lineError = int(lineErrorStr)            # position error ex: 49710\n\n                            #### begin calcul position X and Y of text ex: position 49710\n                            numberCR = plainText.count('\\n', 0, lineError)   # line error (number of \"\\n\" Carriage return)\n                            text_cursor = self.currentEditor.textCursor()\n\n                            text_cursor.setPosition(lineError)\n                            pos01 = text_cursor.blockNumber()        #  767\n                            text_cursor.setPosition(lineError - numberCR)\n                            pos02 = text_cursor.blockNumber()        #  752\n                            pos03 = pos01 - pos02                    #  15\n                            text_cursor.setPosition(lineError - numberCR + pos03)   #   48958 ( = 752, 106)\n                            text_cursor.positionInBlock()\n                            self.currentEditor.setTextCursor(text_cursor)\n                            line_y = text_cursor.blockNumber() + 1   #  753\n                            colon_x = text_cursor.columnNumber() + 1 #  107\n\n                            self.gotoLineEdit.setText(str(line_y))\n                            self.currentEditor.centerCursor()\n                            #\n                            text_cursor.setPosition(lineError - numberCR + pos03 + 1, QtGui.QTextCursor.KeepAnchor) # for select 1 character\n                            self.currentEditor.setTextCursor(text_cursor)\n                            #### end calcul position X and Y of text\n\n                            self.colorError(text_cursor)\n\n                            classErr = str(sys.exc_info()[0]) # <class 'SyntaxError'>    # error detected in editor_assistant_dlg.FCMacro\n                            self.toast(\"Error on line : (\" + str(line_y) + \",\" + str(colon_x) + \" : \" + classErr + \"\\n\" + \" \" + errorSave + \" (Bak not saved)\")\n                            self.toast(\"Error on line : (\" + str(line_y) + \",\" + str(colon_x) + \")\" + \"\\n\" + \" : \" + classErr + \"\\n\" + \" (Bak not saved)\", \"Python\")\n                            self.FreeCAD_Console_PrintError(erreur)\n                        finally:\n                            try:\n                                fileSave.close()\n                            except OSError as erreur:\n                                classErr = str(sys.exc_info()[0]) # error detected in editor_assistant_dlg.FCMacro\n                                self.toast(str(erreur),\"Error\")\n                                self.FreeCAD_Console_PrintError(str(erreur))\n                                switchAllIsGood = False     # not .Bak file\n                            self.setIconCurrentEditor(fileNameBAK)\n                            None\n                    except OSError as erreur:\n                        classErr = str(sys.exc_info()[0]) # error detected in editor_assistant_dlg.FCMacro\n                        self.toast(str(erreur),\"Error\")\n                        self.FreeCAD_Console_PrintError(str(erreur))\n                        switchAllIsGood = False     # not .Bak file\n                    curLine = self.getLineNumberAtCursor()\n                    self.toggleBookmark()           # delete for restitue the original document\n\n            if (switchAllIsGood) and (str(memo_Testing[1]) == \"True\"):\n                plainText = self.getText()\n                if windowName0 == windowTitleName0:\n                    Gui.SendMsgToActiveView(\"Save\")   # save without display the window Yes/No (if it is in a 3D View, the 3D View is saved in a .FCstd file)\n                else:\n                    try:\n                        fileSave = fileSaveSecondStorage = open(filename,'w') # save and display the window Yes/No (case execute macro with EditorAss and work in a 3D window)\n                        fileSave.write(plainText)\n                    except (UnicodeEncodeError):      # character '\\ufffd'  RuntimeError, TypeError, NameError): # only in write file switch True detect \"UnicodeDecodeError, UnicodeEncodeError\" display toast\n                        None\n                    finally:\n                        fileSave.close()\n                try:\n                    switch_Unicode_Read_File = pg.GetBool(\"switch_Unicode_Read_File\")\n                    if switch_Unicode_Read_File == 0:\n                        with open(filename, 'r',errors='ignore') as file:        # only in read file switch False not error detection not display toast skip or not run\n                            data = file.read()\n                    else:\n                        with open(filename, 'r') as file:\n                            data = file.read()\n                except (UnicodeDecodeError, RuntimeError, TypeError, NameError, FileNotFoundError): # only in read file switch True detect \"UnicodeDecodeError\" display toast stop the run\n                    self.toast(str(sys.exc_info()[0]),\"Python\")\n                finally:    #except OSError:\n                    try:\n                        file.close()\n                    except Exception:\n                        None\n\n                my_name = 'my_macro'\n                my_spec = importlib.util.spec_from_loader(my_name, loader=None)\n                my_macro = importlib.util.module_from_spec(my_spec)\n                my_macro.FreeCAD = FreeCAD\n                my_macro.App = FreeCAD\n                my_macro.Gui = FreeCADGui\n                my_macro.FreeCADGui = FreeCADGui\n                try:\n                    exec(data, my_macro.__dict__)\n                    self.saveFileSecondStorage(text = plainText, storeFile = filenameSecondStorage) # save only if the code is good \n                except Exception as err:\n                    erreur = str(traceback.format_exc())      # !! error detected in executed macro and position the cursor in a eroneous line\n                    counterCirconflex = erreur.count(\"^\")\n                    counterCirconflexPos = erreur.find(\"^\")\n                    numberCRCirconflex = erreur.count('\\n')   # line error (number of \"\\n\" Carriage return)\n                    argument = str(err.args)\n                    lineError = colError = lineColError = switchSelectCompleteLine = 0\n                    text_cursor = self.currentEditor.textCursor()\n                    try:\n                        lineError = err.lineno\n                    except Exception:\n                        lineError = 0\n                        None\n                    if str(type(err)) == \"<class 'UnboundLocalError'>\": # if error detected  and not line detected : select all correspondence word (variable)\n                        wordError = (str(err.args).replace(\"'\",\"\").split(\",\")[0].split(\" \"))[2]\n                        lineError = None\n                        self.findEdit.setText(wordError)\n                        self.onFindBtnClicked(True)     # change every run\n                        ##\n                        errS = str(erreur).split(\"\\n\")\n                        try:\n                            lineError = errS[-3].split()\n                            lineError = lineError[3].split(\",\")\n                            lineError = int(lineError[0])\n                        except TypeError:\n                            self.matchCaseCheckBox.setChecked(True) #???\n                        ##\n                        self.gotoLine(lineError)\n                        self.gotoLineEdit.setText(str(lineError))\n                        try:\n                            self.matchCaseCheckBox.setChecked(True) #???\n                            text_cursor = self.currentEditor.textCursor()\n                            pos01 = text_cursor.blockNumber()\n                            pos02 = text_cursor.position()\n                            numberCR = plainText.count('\\n', 0, pos02)   # line error (number of \"\\n\" Carriage return)\n                            curPos = pos03 = pos01 + pos02 - numberCR + colError\n                            text_cursor.setPosition(pos03)\n                            text_cursor.select(QtGui.QTextCursor.WordUnderCursor)       # select the word\n                            if not text_cursor.hasSelection() or switchSelectCompleteLine == True:\n                                text_cursor.select(QtGui.QTextCursor.LineUnderCursor)   # select the complete line text (case not line number)\n                            self.currentEditor.centerCursor()\n                            self.currentEditor.setTextCursor(text_cursor)\n                            self.colorError(text_cursor)\n                        except Exception:\n                            None\n                    else:\n                        if str(type(err)) == \"<class 'NameError'>\":\n                            errS = str(erreur).split(\"\\n\")\n                            lineError = errS[-3].split()\n                            lineError = lineError[3].split(\",\")\n                            lineError = int(lineError[0])\n\n                        elif str(type(err)) == \"<class 'SyntaxError'>\":\n                            lineError = err.lineno\n                            colError = err.offset\n                        elif str(type(err)) == \"<class 'IndentationError'>\": # verifier erreur si l'indentation est negative (fccircularText line 3147)\n                            lineError = err.lineno\n                            colError = err.offset\n                        elif str(type(err)) == \"<class 'TabError'>\":\n                            lineError = err.lineno\n                            colError = err.offset\n                        ####\n                        elif str(type(err)) == \"<class 'IndexError'>\":\n                            lineColError = erreur.replace(\"'\",\" \")\n                            lineError = int(lineColError.split('\"<string>\",')[-1].split(\"line\")[1].split(\",\")[0])\n                            switchSelectCompleteLine = True\n                        elif str(type(err)) == \"<class 'TypeError'>\":\n                            lineColError = erreur.replace(\"'\",\" \")\n                            lineError = int(lineColError.split('\"<string>\",')[-1].split(\"line\")[1].split(\",\")[0])\n                            switchSelectCompleteLine = True\n                        else:\n                            lineError = erreur.split(\"\\n\")\n#ori                            for i00 in reversed(lineError):\n                            for i00 in lineError:\n                                if \"line\" in i00:\n                                    i01 = i00.replace(\",\",\"\").split()\n                                    for i02 in i01:\n                                        try:\n                                            lineError = int(i02)\n                                            break\n                                        except Exception:\n                                            None\n\n                        #<class 'ZeroDivisionError'> to do\n                        ####\n                        self.gotoLine(lineError)\n                        self.gotoLineEdit.setText(str(lineError))\n                        text_cursor = self.currentEditor.textCursor()\n                        pos01 = text_cursor.blockNumber()\n                        pos02 = text_cursor.position()\n                        numberCR = plainText.count('\\n', 0, pos02)   # line error (number of \"\\n\" Carriage return)\n                        curPos = pos03 = pos01 + pos02 - numberCR + colError\n                        text_cursor.setPosition(pos03)\n                        ####\n#                        if str(type(err)) == \"<class 'NameError'>\":\n#                            erreurSplit = erreur.split(\"NameError: name\")[1]\n#                            erreurSplit = erreurSplit.split()[0]\n#                            text_cursor.setPosition(pos03 + len(erreurSplit)-2)\n#                            if len(erreurSplit) == 3:\n#                                text_cursor.setPosition(pos03 + len(erreurSplit)-2)\n#                                curPos = pos03 + len(erreurSplit)-2\n#                            else:\n#                                text_cursor.setPosition(pos03 + len(erreurSplit))\n#                                curPos = pos03 + len(erreurSplit)\n                        ####\n                        if str(type(err)) == \"<class 'SyntaxError'>\":\n                            text_cursor.setPosition(pos03-1)\n                            curPos = pos03 - 1\n                            argument = argument[:50] + \" ...\"\n                        text_cursor.select(QtGui.QTextCursor.WordUnderCursor)       # select the word\n                        if not text_cursor.hasSelection() or switchSelectCompleteLine == True:\n                            text_cursor.select(QtGui.QTextCursor.LineUnderCursor)   # select the complete line text (case not line number)\n                        self.currentEditor.centerCursor()\n                        self.currentEditor.setTextCursor(text_cursor)\n\n                        self.colorError(text_cursor)\n                        ####\n#                        lenTextDetected = len(text_cursor.selectedText())\n#                        text_cursor.clearSelection()\n#                        extraSelection = QtWidgets.QTextEdit.ExtraSelection()\n#                        extraSelection.cursor = self.currentEditor.textCursor()\n#                        #extraSelection.cursor.setPosition(pos01)\n#                        #extraSelection.cursor.setPosition(curPos - lenTextDetected, QtGui.QTextCursor.KeepAnchor)\n#                        color = QColor(COLOR_ERROR_DETECTED)   #a40000\n#                        extraSelection.format.setBackground(QtGui.QColor(color))\n#                        self.currentEditor.setExtraSelections([extraSelection])\n                        ####\n\n##                        self.highlight(text_cursor.selectedText(),color=\"red\")\n\n                        self.currentEditor.centerCursor()\n                        self.currentEditor.setTextCursor(text_cursor)\n\n                    classErr = str(sys.exc_info()[0]) # <class 'SyntaxError'>       # error detected in editor_assistant_dlg.FCMacro\n                    self.toast(str(erreur),\"Error\")\n                    self.toast(\"Error on line : \" + str(lineError) + \"\\n\" + argument + \"\\n\" + \" : \" + str(classErr), \"Python\")\n                    self.FreeCAD_Console_PrintError(erreur)\n\n    def refresh(self):\n        self.onRefreshBtnClicked(True)\n        #self.getEditors()\n        #cur = self.mdi.currentSubWindow()\n        #ed = cur.findChild(QtWidgets.QPlainTextEdit) if cur else None\n        #if ed:\n        #    p = ed.parent()\n        #    gp = p.parent()\n        #    curName = gp.windowTitle()\n        #    self.setCurrentEditor(curName)\n\n    def checkForTabs(self):\n        txt = self.getText()\n        counterTab = txt.count(\"\\t\")\n\n        counterInterrogation = txt.count(\"\\ufffd\")\n        counterTabStr = counterInterogationStr = CReturn = \"\"\n        if counterTab > 0:\n            counterTabStr = \"contains (\" + str(counterTab) + \") tabs.\"\n            CReturn = \"\\n\" + \"    \"\n\n        if counterInterrogation > 0:\n            switchReplaceInterrogationFFFD = pg.GetBool(\"switchReplaceInterrogationFFFD\")\n            if switchReplaceInterrogationFFFD:\n                txt = txt.replace(\"\\ufffd\", \"_\")\n            self.currentEditor.setPlainText(txt)\n            counterInterogationStr = \"contains (\" + str(counterInterrogation) + \") character ufffd '\\ufffd' \" + \"\\n\" + \"replaced by '_'.\"\n\n        if counterTab + counterInterrogation != 0:\n            self.toast(f\"{self.editorList.currentItem().text()}: \" + counterTabStr +\n                         CReturn + counterInterogationStr, \"Warning\")\n\n    def onEditorListCurrentItemChanged(self, current, previous):\n        if self.blockSignals:\n            return\n        self.onRefreshBtnClicked(True)\n        self.currentEditor.setFocus()\n        if not self.currentEditor.hasFocus():\n            self.toast(f\"cannot set focus on {self.editorList.currentItem().text()}\",\"Warning\")\n        self.checkForTabs()\n        self.onFindEditTextChanged(None)\n        self.updateUndoBtn()\n        self.updateSnapBtns()\n        name = self.editorList.currentItem().text() if self.editorList.currentItem() else \"\"\n        if name:\n            if name in self.gotoLineDict:\n                self.gotoLineEdit.setText(self.gotoLineDict[name])\n            else:\n                self.gotoLineEdit.setText(\"\")\n\n    def doCommand(self, cmd):\n        FreeCADGui.doCommand(cmd)\n\n    def setText(self, name, txt, reason):\n        old_text = self.getText(name)\n        old_cursor = self.editorDict[name].textCursor()\n        self.editorDict[name].setPlainText(txt)\n        self.setModified(name, old_text, reason, self.getTC(old_cursor))\n\n    def getTC(self, text_cursor):\n        return tuple([text_cursor.selectionStart(), text_cursor.selectionEnd()])\n\n    def setTextCursor(self, name, tc):\n        ed = self.editorDict[name]\n        text_cursor = ed.textCursor()\n        text_cursor.setPosition(tc[0])\n        text_cursor.setPosition(tc[1], QtGui.QTextCursor.KeepAnchor)\n        ed.setTextCursor(text_cursor)\n\n    def getText(self, name=None):\n        if not name:\n            self.onRefreshBtnClicked(True)\n            if not self.editorList.currentItem():\n                self.toast(\"No editor\",\"Error\")\n                return \"\"\n            else:\n                name = self.editorList.currentItem().text()\n        return self.editorDict[name].toPlainText() if name in self.editorDict else \"\"\n\n    def filterBackSlashes(self, instring):\n            txt = instring.replace('\\\\t',chr(9)).replace('\\\\n',chr(10)).replace('\\\\r',chr(13))\n            txt = txt.replace('\\\\b',chr(8)).replace('\\\\f',chr(12)).replace('\\'',chr(39))\n            txt = txt.replace('\\\\',chr(92))\n            return txt\n\n    def replace(self, name, txt, newTxt):\n        \"\"\"replace txt with newTxt in editor name\"\"\"\n        #only used by replace all\n        if not txt:\n            self.toast(\"nothing to replace\",\"Error\")\n            return\n        inSelectionOnly = False\n        modifiers = QtGui.QGuiApplication.keyboardModifiers()\n        if modifiers == QtCore.Qt.ControlModifier:\n            inSelectionOnly = True\n        if not inSelectionOnly:\n            fullText = self.getText(name)\n        else:\n            fullText = self.currentEditor.textCursor().selectedText()\n        txt = self.filterBackSlashes(txt)\n        indices = self.reFindIndices(fullText, txt, 0)\n        chunks = []\n        last = -1\n        for ii,i in enumerate(reversed(indices)):\n            if ii == 0:\n                chunks.insert(0, fullText[i[1]:])\n            else:\n                chunks.insert(0, fullText[i[1]:last])\n            chunks.insert(0, newTxt)\n            last = i[0]\n        chunks.insert(0, fullText[:last])\n        newText = \"\".join(chunks)\n        count = len(indices)\n        self.toast(f\"{count} instances of {txt} replaced in {name}\",\"Message\")\n        if not count == 0:\n            if not inSelectionOnly:\n                self.setText(name, newText, f\"replace {txt}\")\n            else:\n                self.setModified(name,self.currentEditor.toPlainText(), \"Replace in selection\",self.getTC(self.currentEditor.textCursor()))\n                tc = self.currentEditor.textCursor()\n                tc.setKeepPositionOnInsert(True)\n                tc.insertText(newText)\n                self.currentEditor.setTextCursor(tc)\n\n    def reFindIndices(self, plainText, txt, searchFrom = 0):\n        \"\"\"replaces plainText.find(txt, searchFrom=0) with same find using re\n           respecting states of match case checkbox and whole words checkbox\n            returns list of tuples[(idx, idx2),(idx, idx2),...]\"\"\"\n        flags = 0 if self.matchCaseCheckBox.checkState() else re.IGNORECASE\n        compiled = re.compile(r\"\\b\" + re.escape(txt) + r\"\\b\", flags=flags) if self.matchWholeCheckBox.checkState() else re.compile(re.escape(txt), flags=flags)\n        reIter = compiled.finditer(plainText, pos=searchFrom)\n        indices = []\n        for ii, match in enumerate(reIter):\n            indices.append(match.span())\n        return indices\n\n    def onMatchCaseCheckBoxStateChanged(self, arg1):\n        if self.lastHighlightMode == \"selection\":\n            self.highlightFromSelection()\n        elif self.lastHighlightMode == \"find\":\n            self.highlightFromFind()\n\n    def onMatchWholeCheckBoxStateChanged(self, arg1):\n        if self.lastHighlightMode == \"selection\":\n            self.highlightFromSelection()\n        elif self.lastHighlightMode == \"find\":\n            self.highlightFromFind()\n\n    def find(self, name, txt, backward = False):\n        self.setCurrentEditor()\n        if not self.currentEditor:\n            self.toast(\"No editor selected\")\n            return\n        if not txt:\n            self.toast(\"Nothing to find.\")\n            return\n        str1 = \"'\"\n        findFlagsList = []\n\n        if self.matchCaseCheckBox.checkState():\n            findFlagsList.append(\"QtGui.QTextDocument.FindFlag.FindCaseSensitively\")\n        if self.matchWholeCheckBox.checkState():\n            findFlagsList.append(\"QtGui.QTextDocument.FindFlag.FindWholeWords\")\n        if backward:\n            findFlagsList.append(\"QtGui.QTextDocument.FindFlag.FindBackward\")\n        if findFlagsList:\n            str1 = \"', \"\n            findFlags = \"|\".join(findFlagsList)\n        else:\n            findFlags = \"\"\n        newtxt = txt.replace('\"', '\\\\\"').replace(\"'\",\"\\\\'\")\n\n        cmd = \"\"\"\nfrom PySide import QtGui, QtWidgets\n__editors__ = [child for child in FreeCADGui.getMainWindow().findChildren(QtWidgets.QPlainTextEdit)]\n__parents__ = [ed.parent() for ed in __editors__]\n__grandparents__ = [p.parent().windowTitle() for p in __parents__]\n__editor__ = __editors__[__grandparents__.index('\"\"\" + name + \"\"\"')]\n__dlg__ = Gui.getMainWindow().findChild(QtWidgets.QWidget,\"Editor assistant\")\n__dlg__.setFound(__editor__.find('\"\"\" + newtxt + str1 + findFlags + \"\"\"))\n__editor__.centerCursor()\n\ndel(__editors__, __parents__, __grandparents__, __editor__,__dlg__)\n\n\"\"\"\n        self.doCommand(cmd)\n\n    def qSearch(self,txt):\n        qText = txt.replace(\" \",\"+\")\n        queryUrl = f\"https://wiki.qt.io/index.php?search={qText}&title=Special%3ASearch&go=Go\"\n        import webbrowser\n        webbrowser.open_new_tab(queryUrl)\n\n    def wSearch(self, txt):\n        \"\"\"open a new tab in default browser the wiki search page, search results for txt\"\"\"\n        qText = txt.replace(\" \",\"+\")\n        queryUrl = f\"https://wiki.freecadweb.org/index.php?search={qText}&title=Special%3ASearch&go=Go\"\n        import webbrowser\n        webbrowser.open_new_tab(queryUrl)\n\n    def search(self,txt):\n        \"\"\"do a search for txt on github FreeCAD repo\"\"\"\n        import webbrowser\n        qText = txt.replace(\" \",\"+\")\n        queryUrl = f\"https://github.com/FreeCAD/FreeCAD/search?q={qText}\"\n        webbrowser.open_new_tab(queryUrl)\n\n    def onMsgBtnClicked(self, arg1):\n        self.toast(\"Toast log sent to report view\",\"Information\",log=False)\n        self.print(\"Toasts log:\\n\")\n        for ii,toast in enumerate(self.toastsLog):\n            if ii==0:\n                continue\n            self.print(f\"{ii}) {toast[0]}\",toast[1])\n\n    def onConsoleEditReturnPressed(self):\n        self.onConsoleBtnClicked(True)\n\n    def toast(self,msg,msgType='Error',length=5000,log=True,priority=\"high\"):\n        if not hasattr(self, \"msgBtn\") or not shiboken.isValid(self.msgBtn):\n            return\n        self.timers.append(msg)\n        if priority == \"high\" or not self.msgBtn.text():\n            self.msgBtn.setText(msg)\n        if log:\n            self.toastsLog.append(tuple([msg, msgType]))\n\n        if msgType == 'Error':\n            self.msgBtn.setStyleSheet(\"color:red\")\n            self.msgBtn.setIcon(QIconFromXPMString(msgBtn_Critical_icon))\n        elif msgType == 'Python':\n            self.msgBtn.setStyleSheet(\"color:yellow;background-color:red;font-weight:bold\")\n            self.msgBtn.setIcon(QIconFromXPMString(pythonPY_icon))\n        elif msgType == 'Message':\n            self.msgBtn.setStyleSheet(\"color:black\")\n        elif msgType == 'Warning':\n            self.msgBtn.setStyleSheet(\"color:yellow;background-color:navy;font-weight:bold\")\n            self.msgBtn.setIcon(QIconFromXPMString(msgBtn_Warning_icon))\n        elif msgType == 'Information':\n            self.msgBtn.setStyleSheet(\"color:blue\")\n\n        #self.msgBtn.setIcon(QIconFromXPMString(File_Dialog_Info_View_icon))\n        QtCore.QTimer().singleShot(length,self.clearToast)\n\n    def clearToast(self):\n        #in case there are new messages we don't want to delete them yet, let their timers do it later\n        if not shiboken.isValid(self.msgBtn) or not self.form or not self.form.parent():\n            return\n        if len(self.timers) == 1:\n            self.msgBtn.setText(\"\")\n            self.msgBtn.setStyleSheet(\"color:black\")\n            self.msgBtn.setIcon(QIconFromXPMString(File_Dialog_Info_View_icon))\n            self.timers.pop()\n        elif len(self.timers) > 1:\n            self.timers.pop()\n\n    def onConsoleBtnClicked(self, arg1):\n        self.onRefreshBtnClicked(True)\n        consoleCmd = self.consoleEdit.text()\n        consoleCmd = consoleCmd.replace(\"qsearch\",\"qSearch\")\n        consoleCmd = consoleCmd.replace(\"dir(\", \"dlg.dir(\")\n        consoleCmd = consoleCmd.replace(\"help(\", \"dlg.showHelp(\")\n        consoleCmd = consoleCmd.replace(\"menu(\",\"dlg.makeReferenceMenu(\")\n        if not \"qSearch\" in consoleCmd:\n            consoleCmd = consoleCmd.replace(\"search(\", \"dlg.search(\")\n        consoleCmd = consoleCmd.replace(\"qSearch(\", \"dlg.qSearch(\")\n        consoleCmd = consoleCmd.replace(\"wSearch(\", \"dlg.wSearch(\")\n        consoleCmd = consoleCmd.replace(\"\\\\n\",chr(10))\n        name = self.editorList.currentItem().text() if self.editorList.currentItem() else \"\"\n        if not name:\n            self.toast(\"No editor selected\")\n        if name:\n            old_text = self.getText(name)\n            old_cursor = self.editorDict[name].textCursor()\n            cmd = \"\"\"\nfrom PySide import QtGui\nfrom PySide import QtWidgets\n__editors__ = [child for child in FreeCADGui.getMainWindow().findChildren(QtWidgets.QPlainTextEdit)]\n__parents__ = [ed.parent() for ed in __editors__]\n__grandparents__ = [p.parent().windowTitle() for p in __parents__]\neditor = __editors__[__grandparents__.index('\"\"\" + name + \"\"\"')]\ndlg = Gui.getMainWindow().findChild(QtWidgets.QWidget,\"Editor assistant\").form\n\"\"\"+ consoleCmd + \"\"\"\ndel(__editors__, __parents__, __grandparents__)\n\"\"\"\n        else: #not name\n            if consoleCmd.startswith(\"editor\"):\n                self.toast(\"No open editor\",\"Error\")\n                return\n            cmd = \"\"\"\nfrom PySide import QtGui\nfrom PySide import QtWidgets\ndlg = Gui.getMainWindow().findChild(QtWidgets.QWidget,\"Editor assistant\").form\n\"\"\"+ consoleCmd + \"\"\"\n\"\"\"\n        self.doCommand(cmd)\n        if name:\n            if not old_text == self.getText():\n                self.setModified(name, old_text, \"Console command\", self.getTC(old_cursor))\n            self.toast(\"editor now available as variable in python console\",\"Message\")\n        pyconsole = mw.findChild(QtWidgets.QPlainTextEdit,\"Python console\")\n        pyconsole.setFocus()\n        self.form.parent().hide()\n        pyconsole.parent().show()\n        self.form.parent().show()\n\n    def onFindEditReturnPressed(self):\n        self.onFindBtnClicked(True)\n\n    def on_ComboBox_Find_Clicked(self, text):\n        global duplicate_Find\n\n        if text not in duplicate_Find:\n            duplicate_Find.append(text)\n            duplicate_Find = sorted(list(set(duplicate_Find))) # sort\n            self.ComboBox_Find.addItem(text)\n        self.ComboBox_Find.setCurrentText(text)\n        self.findEdit.setText(text)\n\n    def convertToNewFormatBAK(self, completePath):  # convert Name To New Format BAK \"-\" to \"_\"\n        import os\n\n        if os.path.exists(completePath):\n            #print(\"exists, and convert\")\n            for i in os.listdir(completePath):   #list of files in directory\n                if \"-\" in i:\n                    new = i.replace(\"-\",\"_\")\n                    os.rename(completePath + \"/\" + i, completePath + \"/\" + new)\n\n    def setListFilesBak(self, text):\n        global takenBakFiles\n\n        try:\n            self.convertToNewFormatBAK(text)\n            if \".FCMACRO\" in text.upper():\n                text = text.split(\".FCMacro\")[0]\n                text = text + \".FCMacro.BAK\"\n            elif \".PY\" in text.upper():\n                text = text.split(\".py\")[0]\n                text = text + \".py.BAK\"\n            text = text.replace(\"[*]\",\"\")\n            try:\n                self.ComboBox_Bak_Files.clear()\n            except Exception:\n                self.ComboBox_Bak_Files = QtWidgets.QComboBox()\n\n            takenBakFiles = []\n            if os.path.exists(text):\n                for i in enumerate(os.listdir(text)):   #list of files in directory\n                    dummy = i[1].split(\"_##\")\n                    convertName = dummy[0].split(\".\")[-1]\n                    if len(dummy) == 2:\n                        memo_Bak_Txt = dummy[1]\n                    else:\n                        memo_Bak_Txt = \"\"\n                    #\n                    if switchMemoBakUpDisplayOnComboBox:\n                        memo_Bak_Display = \"_\" + memo_Bak_Txt[:254]\n                    else:\n                        memo_Bak_Display = \"\"\n\n                    self.ComboBox_Bak_Files.addItem( str((i[0] + 1)) + \" : \" + convertName + memo_Bak_Display) # text in comboBox\n                    takenBakFiles.append([str(i[0]), convertName, text, i[1], memo_Bak_Txt])\n                self.setIconCurrentEditor(text)\n\n        except Exception:\n            None\n\n    def on_ComboBox_Bak_Files_Clicked(self, text):\n        global takenBakFiles\n        global fileNameBAK  #            lenBackUpFile = len(os.listdir(fileNameBAK))\n\n        try:\n            if len(takenBakFiles) != 0:\n                filename = bakNickName = pathBak = nameBak = memo_Bak_Txt = \"\"\n                itemFile = int(text.split(\":\")[0]) -1\n                ##itemFile = takenBakFiles[itemFile][0])    # 5 # index\n                bakNickName = takenBakFiles[itemFile][1]    # BAK_2023-09-04_174848\n                pathBak  = takenBakFiles[itemFile][2]       # C:/Users/Tyty/AppData/Roaming/FreeCAD/Macro/Tyty.py.BAK\n                nameRealFile = pathBak.split(\"/\")[-1]\n                nameRealFile = nameRealFile[:-4]            # Tyty.py\n                nameBak  = takenBakFiles[itemFile][3]       # Tyty.py.BAK_2023-09-04_174848_memo_Bak_Txt\n\n                memo_Bak_Txt = takenBakFiles[itemFile][4]   # memo_Bak_Txt\n\n                filename = pathBak + \"/\" + nameBak\n                doc = FreeCAD.ActiveDocument if FreeCAD.ActiveDocument else FreeCAD.newDocument()\n                textDoc = doc.addObject(\"App::TextDocument\", bakNickName)\n                with open(filename, 'r') as file:\n                    data = file.read()\n                file.close()\n\n                #### include info begin\n                switchFrameInfoBackUpOnFile = pg.GetBool(\"switchFrameInfoBackUpOnFile\")\n                switchFrameInfoOnBeginOrEnd = pg.GetBool(\"switchFrameInfoOnBeginOrEnd\")\n                if switchFrameInfoBackUpOnFile == True:\n                    curLine = self.getLineNumberAtCursor()\n                    bookmarkSaved = \"Bookmark to line \" + str(curLine) + \" last line of work \"\n                    lDataII = len(data)\n                    lDataI = len(str(lDataII))\n                    aI = len(bakNickName)\n                    bI = len(nameBak.split('.BAK_')[0])\n                    cI = len(nameBak.split('.BAK_')[1].split('_##')[0])\n                    d = \"(Info include by Editor_Assistant \" + __version__ + \")\"\n                    dI = len(d)\n                    e = pathBak.split('.BAK')[0]\n                    eI = len(e)\n                    f = memo_Bak_Txt\n                    fI = len(f)\n                    g = bookmarkSaved\n                    gI = len(bookmarkSaved)\n\n                    x = max(aI, bI, cI, dI, eI, lDataI, fI) + 2\n                    a = bakNickName + \" \"*(x - aI)\n                    b = nameBak.split('.BAK_')[0] + \" \"*(x - bI)\n                    c = nameBak.split('.BAK_')[1].split('_##')[0] + \" \"*(x - cI)\n                    e = e + \" \"*(x - eI)\n                    f = \" \" + f + \" \"*(x - fI)\n                    lData = str(lDataII) + \" byte(s)\" + \" \"*(x - lDataI - 8)\n                    g = \" \" + g + \" \"*(x - gI)\n\n                    ## create frame info begin\n                    backInfo = \"\"\"####\"\"\" + \"#\"*(x + 2) + \"\"\"####\n######\"\"\" + d + '#'*(x - dI) + \"\"\"####\n#### This document : \"\"\" + ' '*(x - 15) + \"\"\"####\n####  \"\"\" + a + \"\"\"####\n#### Length : \"\"\" + ' '*(x - 8) + \"\"\"####\n####  \"\"\" + lData + \"\"\"####\n#### is one backUp of the file : \"\"\" + ' '*(x - 27) + \"\"\"####\n####  \"\"\" + b + \"\"\"####\n#### Date Time : \"\"\" + ' '*(x - 11) + \"\"\"####\n####  \"\"\" + c + \"\"\"####\n#### Original (without memo) : \"\"\" + ' '*(x - 25) +\"\"\"####\n####  \"\"\" + e + \"\"\"####\n#### Memo : \"\"\" + ' '*(x - 6) + \"\"\"####\n#### \"\"\" + g + \"\"\"####\n#### \"\"\" + f + \"\"\"####\n####\"\"\" + '#'*(x + 2) + \"\"\"####\n\"\"\"\n                    ## create frame info end\n                    if switchFrameInfoOnBeginOrEnd == True:\n                        data = backInfo + \"\\n\" + data   # info en haut\n                    else:\n                        data = data + \"\\n\" + backInfo   # info en bas\n                #### include info end\n                textDoc.Text = data\n                self.toast(\"Back file reload \" + \"\\n\" + filename,\"Message\") # restablished after add : line 337 self.msgBtn.setFixedWidth(300)\n                #self.toast(\"Back file reload \" + \"\\n\" + pathBak,\"Message\")\n                textDoc.ViewObject.doubleClicked()\n                doc.recompute()\n        except Exception:\n            try:\n                self.toast(\"Back file reload Error \" + \"\\n\" + filename,\"Error\")\n            except Exception:\n                self.toast(\"Back file reload Error \" + \"\\n\" + \"XXXX\", \"Error\")\n\n    def on_Header_Bak_File_Info(self, text):\n        global takenBakFiles\n        global fileNameBAK  #            lenBackUpFile = len(os.listdir(fileNameBAK))\n\n        try:\n            if len(takenBakFiles) != 0:\n                itemFile = int(text.split(\":\")[0]) -1\n                ##itemFile = takenBakFiles[itemFile][0])    # 5 # index\n                bakNickName = takenBakFiles[itemFile][1]    # BAK_2023-09-04_174848\n                pathBak  = takenBakFiles[itemFile][2]       # C:/Users/Tyty/AppData/Roaming/FreeCAD/Macro/Tyty.py.BAK\n                nameRealFile = pathBak.split(\"/\")[-1]\n                nameRealFile = nameRealFile[:-4]            # Tyty.py\n                nameBak  = takenBakFiles[itemFile][3]       # Tyty.py.BAK_2023-09-04_174848_##memo_Bak_Txt\n                memo_Bak_Txt = takenBakFiles[itemFile][4]   # memo_Bak_Txt\n                filename = pathBak + \"/\" + nameBak\n\n                if memo_Bak_Txt == \"\" : memo_Bak_Txt = \"?\"\n                toolTipComboBox = \"\\n\" + nameRealFile + \"\\n\\n\" + bakNickName + \"\\n\\n\" + pathBak + \"\\n\\n\" + memo_Bak_Txt + \"\\n\"\n                self.ComboBox_Bak_Files.setItemData(itemFile, toolTipComboBox, QtCore.Qt.ToolTipRole)\n        except Exception:\n            try:\n                self.toast(\"Back file reload Error \" + \"\\n\" + filename,\"Error\")\n            except Exception:\n                self.toast(\"Back file reload Error \" + \"\\n\" + \"XXXX\", \"Error\")\n\n    def on_Clear_FindReplaceCB_Clicked(self):\n        self.findEdit.clear()\n        self.ComboBox_Find.clear()\n        self.replaceEdit.clear()\n        self.ComboBox_replace.clear()\n\n    def onFindEditTextChanged(self, arg1):\n        matchCase = self.matchCaseCheckBox.checkState()\n        if not shiboken.isValid(self.currentEditor) or not self.currentEditor:\n            self.toast(\"current editor is invalid\", \"Error\")\n            return\n        plainText = self.currentEditor.toPlainText()\n        txt = self.filterBackSlashes(self.findEdit.text())\n        if not matchCase:\n            plainText = plainText.lower()\n            txt = txt.lower()\n        name = self.editorList.currentItem().text() if self.editorList.currentItem() else \"\"\n        count = plainText.count(txt)\n        if name and txt:\n            self.toast(f\"{txt} count in {name}: {count}\",\"Message\")\n        if self.lastHighlightMode == \"find\":\n            self.highlightFromFind()\n\n    def onFindBtnClicked(self, arg1=True):\n        self.onRefreshBtnClicked(True)\n        if not shiboken.isValid(self.currentEditor) or not self.currentEditor:\n            self.toast(\"current editor is invalid\",\"Error\")\n            return\n        self.currentEditor.setFocus()\n        name = self.editorList.currentItem().text()\n\n        self.highlight(name)\n\n        txt = self.findEdit.text()\n        matchCase = self.matchCaseCheckBox.checkState()\n        modifiers = QtWidgets.QApplication.keyboardModifiers()\n        if modifiers == QtCore.Qt.AltModifier:\n            selText = self.currentEditor.textCursor().selectedText()\n            self.findEdit.setText(selText if selText else txt)\n            txt = self.findEdit.text()\n        elif modifiers == QtCore.Qt.ControlModifier:\n            self.gotoLine(1, silent=True)\n        self.found = False\n        self.find(name, txt)\n        if not self.found:\n            if self.loopCheckBox.checkState():\n                self.toast(f\"{txt} not found in {name} --Looping back to start\",\"Warning\")\n                self.gotoLine(1, silent=True)\n        self.on_ComboBox_Find_Clicked(txt)\n\n        self.highlight(txt)\n\n\n    def on_Refresh_Aqua_HighlightS_clicked(self):\n        newTxt = self.findEdit.text()\n        self.highlight(newTxt)\n\n\n    def on_Refresh_Aqua_HighlightR_clicked(self):\n        newTxt = self.replaceEdit.text()\n        self.highlight(newTxt)\n\n    def updateSnapBtns(self,refresh=True):\n        if refresh:\n            self.onRefreshBtnClicked(True)\n        if not hasattr(self, \"editorList\"):\n            return\n        curName = self.editorList.currentItem().text() if self.editorList.count() else None\n        snaps = [snap for snap in reversed(self.snaps) if snap[\"name\"] == curName]\n        if not snaps and hasattr(self, \"popSnapBtn\"):\n            self.popSnapBtn.setEnabled(False)\n            self.popSnapBtn.setText(\"Pop\")\n            self.popSnapBtn.setToolTip(\"Pop/restore and discard latest snap\")\n            self.discardSnapBtn.setEnabled(False)\n        elif hasattr(self, \"popSnapBtn\"):\n            self.popSnapBtn.setEnabled(True)\n            self.popSnapBtn.setText(f\"Pop {snaps[0]['reason']}\")\n            self.popSnapBtn.setToolTip(f\"Pop/restore and discard {snaps[0]['reason']}\")\n            self.discardSnapBtn.setEnabled(True)\n\n    def takeSnap(self, curName, curCursor=None, reason=\"\", plainText=\"\"):\n        \"\"\"takeSnap(curName, curCursor=None, reason=\"\")\n           if not curCursor it is taken from current editor\n           if not reason it is Snap #NNN\"\"\"\n        curText = self.getText(curName) if not plainText else plainText\n        curCursor = self.currentEditor.textCursor() if not curCursor else curCursor\n        tc = self.getTC(curCursor)\n        count = 1\n        for snap in self.snaps:\n            if snap[\"name\"] == curName:\n                count += 1\n        if reason:\n            thisReason = reason\n        else:\n            thisReason = f\"Snap #{count}\"\n        thisSnap = {\"name\":curName, \"old_text\":curText, \"reason\":thisReason, \"tc\":tc}\n        self.snaps.append(thisSnap)\n        self.toast(f\"{thisSnap['reason']} taken of {curName}\",\"Message\")\n        if len(self.snaps) > UNDO_QUEUE_MAX_SIZE:\n            self.snaps.pop(0)\n            self.toast(\"Snaps count exceeds {UNDO_QUEUE_MAX_SIZE}, discarding oldest snap\",\"Warning\")\n        self.updateSnapBtns(refresh=False)\n\n    def onTakeSnapBtnClicked(self, arg1):\n        self.onRefreshBtnClicked(True)\n        self.updateSnapBtns()\n        curName = self.editorList.currentItem().text() if self.editorList.count() else \"\"\n        if not curName:\n            self.toast(\"No current editor\",\"Error\")\n            return\n        self.takeSnap(curName)\n\n    def getSnaps(self):\n        self.onRefreshBtnClicked(True)\n        curName = self.editorList.currentItem().text() if self.editorList.currentItem() else \"\"\n        snaps = [snap for snap in reversed(self.snaps) if snap[\"name\"] == curName]\n        return snaps\n\n    def discardSnap(self,idx=0):\n        \"\"\"discard a snap, default=0 = latest snap\"\"\"\n        snaps = self.getSnaps()\n        if not snaps:\n            self.toast(\"No snaps to discard for this editor\",\"Error\")\n            self.updateSnapBtns()\n            return\n        else:\n            self.snaps.remove(snaps[idx])\n            self.updateSnapBtns()\n\n    def discardAllSnaps(self):\n        self.onRefreshBtnClicked(True)\n        self.snaps = []\n        self.updateSnapBtns()\n\n    def onPopSnapBtnClicked(self, arg1):\n        self.onRefreshBtnClicked(True)\n        curName = self.editorList.currentItem().text()\n        snaps = [snap for snap in reversed(self.snaps) if snap[\"name\"] == curName]\n        if not snaps:\n            self.toast(\"No snaps to restore for this editor\",\"Error\")\n            self.updateSnapBtns()\n            return\n        else:\n            old_text = self.getText(curName)\n            old_cursor = self.currentEditor.textCursor()\n            self.currentEditor.setPlainText(snaps[0][\"old_text\"])\n            self.setTextCursor(self.editorList.currentItem().text(), snaps[0]['tc'])\n            self.snaps.remove(snaps[0])\n            self.updateSnapBtns()\n            self.toast(f\"Popped and restored {snaps[0]['reason']} to {snaps[0]['name']}\",\"Message\")\n            self.setModified(curName, old_text, f\"Pop {snaps[0]['reason']}\", self.getTC(old_cursor))\n\n    def showWidgets(self,groupName,show):\n        showDict = {\n            \"ShowEditorList\": [self.editorList],\n            \"ShowRefreshLine\": [self.refreshBtn, self.gotoMenuBtn, self.gotoLineEdit],\n            \"ShowGotoLine\": [self.gotoEndBtn, self.gotoHomeBtn, self.nextBookmarkBtn, \\\n                                self.previousBookmarkBtn, \\\n                                self.removeAllBookmarksBtn, self.toggleBookmarkBtn],\n\n            \"ShowRunMacroBtn\": [self.runMacroBtn],\n            \"ShowRunBackUpAction\": [self.fileBackupDelBtn],\n            \"ShowRunShowFilesBak\": [self.ComboBox_Bak_Files],\n            \"ShowUndoLine\": [self.undoBtn, self.undoClearBtn, self.redoBtn],\n\n            \"ShowFindLine\": [self.findEdit, self.findBtn, self.findBackBtn, self.Clear_FindReplaceCB, self.Refresh_Aqua_HighlightS],\n            \"ShowFindLine2\": [self.ComboBox_Find],\n\n            \"ShowReplaceLine\": [self.replaceEdit, self.Refresh_Aqua_HighlightR, self.replaceBtn, self.replaceAllBtn, self.Reverse_FindReplaceCB],\n            \"ShowReplaceLine2\": [self.ComboBox_replace],\n            \"ShowIndentLine\": [self.indentBackBtn, self.indentBtn, self.ComboBox_Indent_Memo, self.matchCaseCheckBox, \\\n                                self.matchWholeCheckBox, self.loopCheckBox],\n            \"ShowSnapsLine\": [self.takeSnapBtn, self.discardSnapBtn, self.snapCenterBtn, self.snapMenuBtn, self.popSnapBtn],\n            \"ShowConsoleLine\": [self.consoleLabel, self.consoleEdit]\n            }\n        for widget in showDict[groupName]:\n            widget.setVisible(show)\n\n    def setBool(self, name, value):\n        pg.SetBool(name,value)\n        self.showWidgets(name,value)\n\n    def onMainMenuBtnClicked(self, arg1):\n        \"\"\"general purpose menu for things not related to going to a line\n           or managing snaps or diffs\"\"\"\n\n        def makeToggler(name,value): return lambda: self.setBool(name,value)\n\n#begin settings menu\n        showEditorList = pg.GetBool(\"ShowEditorList\", True)\n        showRefreshLine = pg.GetBool(\"ShowRefreshLine\", True)\n        showGotoLine = pg.GetBool(\"ShowGotoLine\", True)\n\n        ShowRunMacroBtn = pg.GetBool(\"ShowRunMacroBtn\", True)\n        ShowRunBackUpAction = pg.GetBool(\"ShowRunBackUpAction\", True)\n        ShowRunShowFilesBak = pg.GetBool(\"ShowRunShowFilesBak\", True)\n        showUndoLine = pg.GetBool(\"ShowUndoLine\", True)\n        showFindLine = pg.GetBool(\"ShowFindLine\", True)\n        showFindLine2 = pg.GetBool(\"ShowFindLine2\", False)\n        showReplaceLine = pg.GetBool(\"ShowReplaceLine\", True)\n        showReplaceLine2 = pg.GetBool(\"ShowReplaceLine2\", False)\n        showIndentLine = pg.GetBool(\"ShowIndentLine\", True)\n        showSnapsLine = pg.GetBool(\"ShowSnapsLine\", True)\n        showConsoleLine = pg.GetBool(\"ShowConsoleLine\", True)\n\n        allLines = [\"ShowEditorList\",\"ShowRefreshLine\",\"ShowGotoLine\",\"ShowUndoLine\",\\\n                    \"ShowRunMacroBtn\",\"ShowRunBackUpAction\",\"ShowRunShowFilesBak\",\\\n                    \"ShowFindLine\",\"ShowFindLine2\",\"ShowReplaceLine\",\"ShowReplaceLine2\",\\\n                    \"ShowIndentLine\",\"ShowSnapsLine\",\"ShowConsoleLine\"]\n\n        defaultLines = [\"ShowEditorList\",\"ShowRefreshLine\",\"ShowGotoLine\", \"ShowUndoLine\",\"ShowFindLine\",\\\n                        \"ShowReplaceLine\",\"ShowIndentLine\",\"ShowSnapsLine\",\"ShowConsoleLine\"]\n\n        minimalLines = [\"ShowEditorList\",\"ShowRefreshLine\",\"ShowUndoLine\",\"ShowFindLine\",\\\n                        \"ShowReplaceLine\",\"ShowIndentLine\"]\n\n        def show(lines):\n            for line in allLines:\n                self.setBool(line, False)\n            for line in lines:\n                self.setBool(line, True)\n\n        mainMenu = QtWidgets.QMenu(\"Main menu\")\n        settingsMenu = QtWidgets.QMenu(\"Settings\")\n\n        settingsMenu.setIcon(QIconFromXPMString(tools_icon))\n        layoutMenu = QtWidgets.QMenu(\"Layout lines\")\n        settingsMenu.addMenu(layoutMenu)\n        togglers = []\n#settings -> layout\n        editorListAction = QtWidgets.QAction(\"Editor list\", layoutMenu, checkable=True)\n        editorListAction.setChecked(showEditorList)\n        togglers.append(makeToggler(\"ShowEditorList\",not editorListAction.isChecked()))\n        editorListAction.toggled.connect(togglers[-1])\n        layoutMenu.addAction(editorListAction)\n\n        refreshLineAction = QtWidgets.QAction(\"Refresh line/Run\",layoutMenu, checkable=True)\n        refreshLineAction.setChecked(showRefreshLine)\n        togglers.append(makeToggler(\"ShowRefreshLine\", not refreshLineAction.isChecked()))\n        refreshLineAction.toggled.connect(togglers[-1])\n        layoutMenu.addAction(refreshLineAction)\n\n        gotoLineAction = QtWidgets.QAction(\"Goto/Bookmark line\",layoutMenu, checkable=True)\n        gotoLineAction.setChecked(showGotoLine)\n        togglers.append(makeToggler(\"ShowGotoLine\", not gotoLineAction.isChecked()))\n        gotoLineAction.toggled.connect(togglers[-1])\n        layoutMenu.addAction(gotoLineAction)\n\n        runMacroAction = QtWidgets.QAction(\"Run Macro\",layoutMenu, checkable=True)\n        runMacroAction.setChecked(ShowRunMacroBtn)\n        togglers.append(makeToggler(\"ShowRunMacroBtn\", not runMacroAction.isChecked()))\n        runMacroAction.toggled.connect(togglers[-1])\n        layoutMenu.addAction(runMacroAction)\n\n#        runBackUpAction = QtWidgets.QAction(\"Backup\",layoutMenu, checkable=True)\n        runBackUpAction = QtWidgets.QAction(\"Run Backup\",layoutMenu, checkable=True)\n        runBackUpAction.setChecked(ShowRunBackUpAction)\n        togglers.append(makeToggler(\"ShowRunBackUpAction\", not runBackUpAction.isChecked()))\n        runBackUpAction.toggled.connect(togglers[-1])\n        layoutMenu.addAction(runBackUpAction)\n\n#        runShowFilesBak = QtWidgets.QAction(\"Show Bak files\",layoutMenu, checkable=True)\n        runShowFilesBak = QtWidgets.QAction(\"Run Show Bak files\",layoutMenu, checkable=True)\n        runShowFilesBak.setChecked(ShowRunShowFilesBak)\n        togglers.append(makeToggler(\"ShowRunShowFilesBak\", not runShowFilesBak.isChecked()))\n        runShowFilesBak.toggled.connect(togglers[-1])\n        layoutMenu.addAction(runShowFilesBak)\n\n        undoLineAction = QtWidgets.QAction(\"Undo line\", layoutMenu, checkable=True)\n        undoLineAction.setChecked(showUndoLine)\n        togglers.append(makeToggler(\"ShowUndoLine\", not undoLineAction.isChecked()))\n        undoLineAction.toggled.connect(togglers[-1])\n        layoutMenu.addAction(undoLineAction)\n\n        findLineAction = QtWidgets.QAction(\"Find line\", layoutMenu, checkable=True)\n        findLineAction.setChecked(showFindLine)\n        togglers.append(makeToggler(\"ShowFindLine\", not findLineAction.isChecked()))\n        findLineAction.toggled.connect(togglers[-1])\n        layoutMenu.addAction(findLineAction)\n\n        findLine2Action = QtWidgets.QAction(\"Find line2\", layoutMenu, checkable=True)\n        findLine2Action.setChecked(showFindLine2)\n        togglers.append(makeToggler(\"ShowFindLine2\", not findLine2Action.isChecked()))\n        findLine2Action.toggled.connect(togglers[-1])\n        layoutMenu.addAction(findLine2Action)\n\n        replaceLineAction = QtWidgets.QAction(\"Replace line\", layoutMenu, checkable=True)\n        replaceLineAction.setChecked(showReplaceLine)\n        togglers.append(makeToggler(\"ShowReplaceLine\", not replaceLineAction.isChecked()))\n        replaceLineAction.toggled.connect(togglers[-1])\n        layoutMenu.addAction(replaceLineAction)\n\n        replaceLine2Action = QtWidgets.QAction(\"Replace line2\", layoutMenu, checkable=True)\n        replaceLine2Action.setChecked(showReplaceLine2)\n        togglers.append(makeToggler(\"ShowReplaceLine2\", not replaceLine2Action.isChecked()))\n        replaceLine2Action.toggled.connect(togglers[-1])\n        layoutMenu.addAction(replaceLine2Action)\n\n        indentLineAction = QtWidgets.QAction(\"Indent line\", layoutMenu, checkable=True)\n        indentLineAction.setChecked(showIndentLine)\n        togglers.append(makeToggler(\"ShowIndentLine\", not indentLineAction.isChecked()))\n        indentLineAction.toggled.connect(togglers[-1])\n        layoutMenu.addAction(indentLineAction)\n\n        snapsLineAction = QtWidgets.QAction(\"Snaps line\", layoutMenu, checkable=True)\n        snapsLineAction.setChecked(showSnapsLine)\n        togglers.append(makeToggler(\"ShowSnapsLine\", not snapsLineAction.isChecked()))\n        snapsLineAction.toggled.connect(togglers[-1])\n        layoutMenu.addAction(snapsLineAction)\n\n        consoleLineAction = QtWidgets.QAction(\"Console line\", layoutMenu, checkable=True)\n        consoleLineAction.setChecked(showConsoleLine)\n        togglers.append(makeToggler(\"ShowConsoleLine\", not consoleLineAction.isChecked()))\n        consoleLineAction.toggled.connect(togglers[-1])\n        layoutMenu.addAction(consoleLineAction)\n\n        settingsMenu.addSeparator()\n        showAllAction = QtWidgets.QAction(\"Show all\", layoutMenu)\n        showAllAction.triggered.connect(lambda: show(allLines))\n        settingsMenu.addAction(showAllAction)\n\n        showDefaultsAction = QtWidgets.QAction(\"Show defaults\", settingsMenu)\n        showDefaultsAction.triggered.connect(lambda: show(defaultLines))\n        settingsMenu.addAction(showDefaultsAction)\n\n        showMinimalAction = QtWidgets.QAction(\"Show Minimal\", settingsMenu)\n        showMinimalAction.triggered.connect(lambda: show(minimalLines))\n        settingsMenu.addAction(showMinimalAction)\n\n#end settings->layout\n        settingsMenu.addSeparator()\n        bHighlightActiveTab = pg.GetString(\"ColorActiveTab\",\"#B3F88C\") == \"#B3F88C\"\n        highlightActiveTabAction = QtWidgets.QAction(\"Highlight active tab\", settingsMenu, checkable = True)\n        highlightActiveTabAction.setChecked(bHighlightActiveTab)\n        highlightActiveTabAction.triggered.connect(self.toggleActiveTabHighlighting)\n        settingsMenu.addAction(highlightActiveTabAction)\n\n        mainMenu.addMenu(settingsMenu)\n#end of settings\n\n#start goto menu\n        gotoMenu = self.makeGotoMenu()\n\n        gotoMenu.setIcon(QIconFromXPMString(goto_To_Menu_icon))\n        mainMenu.addMenu(gotoMenu)\n#start snaps menu\n        snapsMenu = self.makeSnapsMenu()\n\n        snapsMenu.setIcon(QIconFromXPMString(snapshot_icon))\n        mainMenu.addMenu(snapsMenu)\n#start templates menu\n        templatesMenu = QtWidgets.QMenu(\"Templates\")\n\n        templatesMenu.setIcon(QIconFromXPMString(template_icon))\n        insertFromTemplateAction = QtWidgets.QAction(\"Insert from dialog\")\n        insertFromTemplateAction.triggered.connect(self.setupInsertFromTemplate)\n        templatesMenu.addAction(insertFromTemplateAction)\n\n        insertMenu = QtWidgets.QMenu(\"Insert\")\n        templatesMenu.addMenu(insertMenu)\n        insertSubmenus = []\n\n        templateDict = self.getTemplateString()\n        def makeTemplateLambda(x): return lambda : self.testTemplateItem(key=x, execute=True)\n        templateActions = []\n        templateLambdas = [makeTemplateLambda(k) for k in sorted(templateDict.keys())]\n\n        for ii, k in enumerate(sorted(templateDict.keys())):\n            if ii % 25 == 0:\n                insertSubmenus.append(QtWidgets.QMenu(f\"Start from -- {k}\"))\n            templateActions.append(QtWidgets.QAction(k))\n            templateActions[-1].triggered.connect(templateLambdas[ii])\n            insertSubmenus[-1].addAction(templateActions[-1])\n        for sub in insertSubmenus:\n            insertMenu.addMenu(sub)\n\n        editTemplateAction = QtWidgets.QAction(\"Edit templates\")\n        editTemplateAction.triggered.connect(self.editTemplates)\n        templatesMenu.addAction(editTemplateAction)\n\n        mainMenu.addMenu(templatesMenu)\n\n#start help menu\n        helpMenu = QtWidgets.QMenu(\"Help\")\n\n        helpMenu.setIcon(QIconFromXPMString(help_To_Web_icon))\n        mainMenu.addMenu(helpMenu)\n\n#start help -> reference menu\n        helpReferenceMenu = QtWidgets.QMenu(\"Reference\")\n        helpMenu.addMenu(helpReferenceMenu)\n\n#start help -> reference ->\n\n        moduleMenu = QtWidgets.QMenu(\"FreeCAD Modules\")\n        helpReferenceMenu.addMenu(moduleMenu)\n        def makeModule(x): return lambda : self.makeReferenceMenu(x)\n\n        packagesDict = {\n        \"Draft\":\"Draft\",\n        \"DraftUtils\":\"DraftUtils\",\n        \"Fem\":\" Fem\",\n        \"FemGui\":\" FemGui\",\n        \"Image\":\" Image\",\n        \"ImageGui\":\" ImageGui\",\n        \"Measure\":\" Measure\",\n        \"Mesh\":\" Mesh\",\n        \"MeshGui\":\" MeshGui\",\n        \"MeshPart\":\" MeshPart\",\n        \"MeshPartGui\":\"MeshPartGui\",\n        \"PartDesign\":\" PartDesign\",\n        \"PartDesignGui\":\"PartDesignGui\",\n        \"Part\":\"Part\",\n        \"PartGui\":\"PartGui\",\n        \"Path\":\"Path\",\n        \"PathGui\":\"PathGui\",\n        \"PathSimulator\":\"PathSimulator\",\n        \"Points\":\"Points\",\n        \"PointsGui\":\"PointsGui\",\n        \"Sketcher\":\"Sketcher\",\n        \"SketcherGui\":\"SketcherGui\",\n        \"Spreadsheet\":\"Spreadsheet\",\n        \"SpreadsheetGui\":\"SpreadsheetGui\",\n        \"TechDraw\":\"TechDraw\",\n        \"TechDrawGui\":\"TechDrawGui\",\n        \"Web\":\"Web\",\n        \"WebGui\":\"WebGui\"\n        }\n        moduleActions = []\n        modules = []\n        for k,v in packagesDict.items():\n            moduleActions.append(QtWidgets.QAction(k))\n            modules.append(makeModule(v))\n            moduleActions[-1].triggered.connect(modules[-1])\n            moduleMenu.addAction(moduleActions[-1])\n\n        FreeCADAction = QtWidgets.QAction(\"FreeCAD/App\")\n        FreeCADAction.triggered.connect(lambda :self.makeReferenceMenu(FreeCAD))\n        helpReferenceMenu.addAction(FreeCADAction)\n\n        FreeCADGuiAction = QtWidgets.QAction(\"FreeCADGui/Gui\")\n        FreeCADGuiAction.triggered.connect(lambda :self.makeReferenceMenu(FreeCADGui))\n        helpReferenceMenu.addAction(FreeCADGuiAction)\n\n\n        qtMenu = QtWidgets.QMenu(\"Qt/PySide\")\n        helpReferenceMenu.addMenu(qtMenu)\n\n        QtCoreAction = QtWidgets.QAction(\"QtCore\")\n        QtCoreAction.triggered.connect(lambda :self.makeReferenceMenu(QtCore))\n        qtMenu.addAction(QtCoreAction)\n\n        QtCore_QtAction = QtWidgets.QAction(\"QtCore.Qt\")\n        QtCore_QtAction.triggered.connect(lambda :self.makeReferenceMenu(QtCore.Qt))\n        qtMenu.addAction(QtCore_QtAction)\n\n        QtGuiAction = QtWidgets.QAction(\"QtGui\")\n        QtGuiAction.triggered.connect(lambda :self.makeReferenceMenu(QtGui))\n        qtMenu.addAction(QtGuiAction)\n\n        QtWidgetsAction = QtWidgets.QAction(\"QtWidgets\")\n        QtWidgetsAction.triggered.connect(lambda :self.makeReferenceMenu(QtWidgets))\n        qtMenu.addAction(QtWidgetsAction)\n\n        QtNetworkAction = QtWidgets.QAction(\"QtNetwork\") if hasQtNetwork else QtWidgets.QAction(\"QtNetwork (not installed)\")\n        QtNetworkAction.triggered.connect(lambda :self.makeReferenceMenu(QtNetwork))\n        qtMenu.addAction(QtNetworkAction)\n        if not hasQtNetwork:\n            QtNetWorkAction.setEnabled(False)\n\n        QtHelpAction = QtWidgets.QAction(\"QtHelp\") if hasQtHelp else QtWidgets.QAction(\"QtHelp (not installed)\")\n        QtHelpAction.triggered.connect(lambda :self.makeReferenceMenu(QtHelp))\n        qtMenu.addAction(QtHelpAction)\n        if not hasQtHelp:\n            QtHelpAction.setEnabled(False)\n\n        QtMultimediaAction = QtWidgets.QAction(\"QtMultimedia\") if hasQtMultimedia else QtWidgets.QAction(\"QtMultimedia (not installed)\")\n        QtMultimediaAction.triggered.connect(lambda :self.makeReferenceMenu(QtMultimedia))\n        qtMenu.addAction(QtMultimediaAction)\n        if not hasQtMultimedia:\n            QtMultimediaAction.setEnabled(False)\n\n        QtOpenGLAction = QtWidgets.QAction(\"QtOpenGL\") if hasQtOpenGL else QtWidgets.QAction(\"QtOpenGL (not installed)\")\n        QtOpenGLAction.triggered.connect(lambda :self.makeReferenceMenu(QtOpenGL))\n        qtMenu.addAction(QtOpenGLAction)\n        if not hasQtOpenGL:\n            QtOpenGLAction.setEnabled(False)\n\n        QtPrintSupportAction = QtWidgets.QAction(\"QtPrintSupport\") if hasQtPrintSupport else QtWidgets.QAction(\"QtPrintSupport (not installed)\")\n        QtPrintSupportAction.triggered.connect(lambda :self.makeReferenceMenu(QtPrintSupport))\n        qtMenu.addAction(QtPrintSupportAction)\n        if not hasQtPrintSupport:\n            QtPrintSupportAction.setEnabled(False)\n\n        QtSqlAction = QtWidgets.QAction(\"QtSql\") if hasQtSql else QtWidgets.QAction(\"QtSql (not installed)\")\n        QtSqlAction.triggered.connect(lambda :self.makeReferenceMenu(QtSql))\n        qtMenu.addAction(QtSqlAction)\n        if not hasQtSql:\n            QtSqlAction.setEnabled(False)\n\n        QtSvgAction = QtWidgets.QAction(\"QtSvg\") if hasQtSvg else QtWidgets.QAction(\"QtSvg (not installed)\")\n        QtSvgAction.triggered.connect(lambda :self.makeReferenceMenu(QtSvg))\n        qtMenu.addAction(QtSvgAction)\n        if not hasQtSvg:\n            QtSvgAction.setEnabled(False)\n\n        QtTestAction = QtWidgets.QAction(\"QtTest\") if hasQtTest else QtWidgets.QAction(\"QtTest (not installed)\")\n        QtTestAction.triggered.connect(lambda :self.makeReferenceMenu(QtTest))\n        qtMenu.addAction(QtTestAction)\n        if not hasQtTest:\n            QtTestAction.setEnabled(False)\n\n        QtWidgetsAction = QtWidgets.QAction(\"QtWidgets\") if hasQtWidgets else QtWidgets.QAction(\"QtWidgets (not installed)\")\n        QtWidgetsAction.triggered.connect(lambda :self.makeReferenceMenu(QtWidgets))\n        qtMenu.addAction(QtWidgetsAction)\n        if not hasQtWidgets:\n            QtWidgetsAction.setEnabled(False)\n\n        QtXmlAction = QtWidgets.QAction(\"QtXml\") if hasQtXml else QtWidgets.QAction(\"QtXml (not installed)\")\n        QtXmlAction.triggered.connect(lambda :self.makeReferenceMenu(QtXml))\n        qtMenu.addAction(QtXmlAction)\n        if not hasQtXml:\n            QtXmlAction.setEnabled(False)\n\n        QtXmlPatternsAction = QtWidgets.QAction(\"QtXmlPatterns\") if hasQtXmlPatterns else QtWidgets.QAction(\"QtXmlPatterns (not installed)\")\n        QtXmlPatternsAction.triggered.connect(lambda :self.makeReferenceMenu(QtXmlPatterns))\n        qtMenu.addAction(QtXmlPatternsAction)\n        if not hasQtXmlPatterns:\n            QtXmlPatternsAction.setEnabled(False)\n\n        searchMenu = QtWidgets.QMenu(\"Search source code\")\n        searchAction = QtWidgets.QAction(\"Use find edit text\")\n        searchAction.triggered.connect(self.makeSearchFromFindEdit)\n        searchMenu.addAction(searchAction)\n\n        searchSelAction = QtWidgets.QAction(\"Use selected text\")\n        searchSelAction.triggered.connect(self.makeSearchFromSelection)\n        searchMenu.addAction(searchSelAction)\n\n        searchAskAction = QtWidgets.QAction(\"Ask for query\")\n        searchAskAction.triggered.connect(self.makeSearchFromImmediate)\n        searchMenu.addAction(searchAskAction)\n\n        helpMenu.addMenu(searchMenu)\n\n        qSearchMenu = QtWidgets.QMenu(\"Search Qt\")\n        qSearchAction = QtWidgets.QAction(\"Use find edit text\")\n        qSearchAction.triggered.connect(self.makeqSearchFromFindEdit)\n        qSearchMenu.addAction(qSearchAction)\n\n        qSearchSelAction = QtWidgets.QAction(\"Use selected text\")\n        qSearchSelAction.triggered.connect(self.makeqSearchFromSelection)\n        qSearchMenu.addAction(qSearchSelAction)\n\n        qSearchAskAction = QtWidgets.QAction(\"Ask for query\")\n        qSearchAskAction.triggered.connect(self.makeqSearchFromImmediate)\n        qSearchMenu.addAction(qSearchAskAction)\n\n        helpMenu.addMenu(qSearchMenu)\n\n        wSearchMenu = QtWidgets.QMenu(\"Search wiki\")\n        wSearchAction = QtWidgets.QAction(\"Use find edit text\")\n        wSearchAction.triggered.connect(self.makewSearchFromFindEdit)\n        wSearchMenu.addAction(wSearchAction)\n\n        wSearchSelAction = QtWidgets.QAction(\"Use selected text\")\n        wSearchSelAction.triggered.connect(self.makewSearchFromSelection)\n        wSearchMenu.addAction(wSearchSelAction)\n\n        wSearchAskAction = QtWidgets.QAction(\"Ask for query\")\n        wSearchAskAction.triggered.connect(self.makewSearchFromImmediate)\n        wSearchMenu.addAction(wSearchAskAction)\n\n        helpMenu.addMenu(wSearchMenu)\n\n#highlight menu\n        highlightMenu = QtWidgets.QMenu(\"Highlight\", mw)\n\n        highlightMenu.setIcon(QIconFromXPMString(high_Light_icon))\n        highlightFromSelectionAction = QtWidgets.QAction(\"From selection\")\n        highlightFromSelectionAction.triggered.connect(self.highlightFromSelection)\n        highlightMenu.addAction(highlightFromSelectionAction)\n\n        highlightFromFindAction = QtWidgets.QAction(\"From find\")\n        highlightFromFindAction.triggered.connect(self.highlightFromFind)\n        highlightMenu.addAction(highlightFromFindAction)\n        mainMenu.addMenu(highlightMenu)\n\n        highlightFromReplaceAction = QtWidgets.QAction(\"From replace\")\n        highlightFromReplaceAction.triggered.connect(self.on_Refresh_Aqua_HighlightR_clicked)\n        highlightMenu.addAction(highlightFromReplaceAction)\n        mainMenu.addMenu(highlightMenu)\n        mainMenu.addSeparator()\n\n#drag to forum\n        dragToForumAction = QtWidgets.QAction(\"Drag to forum\")\n        dragToForumAction.setIcon(QIconFromXPMString(pythonToForum_icon))\n        dragToForumEnabled = hasattr(self.editorList.currentItem(),\"text\")\n        dragToForumAction.setEnabled(dragToForumEnabled)\n        dragToForumAction.triggered.connect(lambda: self.dragToForum(self.editorList.currentItem()))\n        mainMenu.addAction(dragToForumAction)\n\n#close menu\n        if self.isTabbed:\n            closeAction = QtWidgets.QAction(\"Close\")\n            closeAction.setIcon(QIconFromXPMString(Btn_Quit_icon))\n            closeAction.triggered.connect(self.close)\n            mainMenu.addAction(closeAction)\n        mainMenu.exec_(self.mainMenuBtn.mapToGlobal(QtCore.QPoint()))\n\n    def toggleActiveTabHighlighting(self):\n        COLOR_ACTIVE_TAB = pg.GetString(\"ColorActiveTab\",\"#B3F88C\")\n        bHighlightActiveTab = bool(COLOR_ACTIVE_TAB != \"\" and COLOR_ACTIVE_TAB != \"0\")\n        if bHighlightActiveTab: #is active, so toggle it false by setting parameter to \"0\"\n            pg.SetString(\"ColorActiveTab\",\"0\")\n            mw.findChild(QtWidgets.QMdiArea).setStyleSheet(\"QTabBar::tab:selected, QTabBar::tab:hover {background-color: QPalette.Base;}\")\n        else:\n            pg.SetString(\"ColorActiveTab\",\"#B3F88C\")\n            COLOR_ACTIVE_TAB = pg.GetString(\"ColorActiveTab\",\"#B3F88C\")\n            mw.findChild(QtWidgets.QMdiArea).setStyleSheet(\"QTabBar::tab:selected, QTabBar::tab:only-one {background-color: \" + COLOR_ACTIVE_TAB + \";}\")\n\n    #credit Amartel at stackoverflow for this bit of code\n    def getLineNumberAtCursor(self):\n        cursor = self.currentEditor.textCursor()\n        cursor.movePosition(QtGui.QTextCursor.StartOfLine)\n        lines = 1\n        lines_text = cursor.block().text().splitlines()\n        lines_pos = 0\n        for line_text in lines_text:\n            lines_pos += len(line_text) + 1\n            if lines_pos > cursor.position() - cursor.block().position():\n                break\n            lines += 1\n        block = cursor.block().previous()\n        while block.isValid():\n            lines += block.lineCount()\n            block = block.previous()\n        return lines\n\n    def setupInsertFromTemplate(self):\n        templateDict = self.getTemplateString()\n        items=[]\n        for k,v in templateDict.items():\n            items.append(k)\n        if not items:\n            self.toast(\"No keys in template\",\"Error\")\n            return\n        item,ok = QtWidgets.QInputDialog.getItem(mw, \"Select template\",\"Select which template to insert\", sorted(items))\n        if ok:\n            self.testTemplateItem(key=item, execute=True)\n\n    def testTemplateItem(self, key, testText=\"\", execute=False):\n        \"\"\"test template from editor, but also can execute\"\"\"\n        def inp(title=\"Input\",label=\"Enter a value:\"): return lambda:QtWidgets.QInputDialog.getMultiLineText(Gui.getMainWindow(), title, label)\n        def inp1(title=\"Input\",label=\"Enter a value:\"): return lambda:QtWidgets.QInputDialog.getText(Gui.getMainWindow(), title, label)\n        if not testText:\n            templateDict = self.getTemplateString()\n            rawDict = templateDict[key]\n        else:\n            rawDict = json.loads(testText, strict=False)\n        if not \"output\" in rawDict:\n            self.toast(\"Test failed: no key named 'output'\",\"Error\")\n            return \"\"\n        if rawDict[\"output\"] == \"input\":\n            retval,ok = inp(f\"Input for {key}\",f\"Enter a value for {replacement[0]}\")()\n            rawOutString = retval if ok else None\n        elif rawDict[\"output\"] == 'input1':\n            retval,ok = inp1Line(f\"Input for {key}\",f\"Enter a value for {replacement[0]}\")()\n            rawOutString = retval if ok else None\n        elif rawDict[\"output\"] == \"clipboard\":\n            rawOutString = QtGui.QClipboard().text()\n        elif rawDict[\"output\"] == \"selection\":\n            rawOutString = self.currentEditor.textCursor().selectedText()\n        else:\n            rawOutString = rawDict[\"output\"]\n        if not rawOutString:\n            self.toast(\"Empty output value\",\"Error\")\n            return \"\"\n        replacements = [(k,v) for k,v in rawDict.items() if k != \"output\" and k!= \"goto\"]\n        for replacement in replacements:\n            if replacement[1] == 'input':\n                retval,ok = inp(f\"Input for {key}\",f\"Enter a value for {replacement[0]}\")()\n                rawDict[replacement[0]] = retval if ok else None\n            elif replacement[1] == 'input1':\n                retval,ok = inp1Line(f\"Input for {key}\",f\"Enter a value for {replacement[0]}\")()\n                rawDict[replacement[0]] = retval if ok else None\n            elif replacement[1] == \"selection\":\n                rawDict[replacement[0]] = self.currentEditor.textCursor().selectedText()\n            elif replacement[1] == 'clipboard':\n                clipTxt = QtGui.QClipboard().text()\n                rawDict[replacement[0]] = clipTxt\n                if not clipTxt:\n                    self.toast(\"Clipboard is empty\",\"Warning\")\n            elif replacement[1] == 'selection':\n                selTxt = self.currentEditor.textCursor().selectedText()\n                rawDict[replacement[0]] = selTxt\n                if not selTxt:\n                    self.toast(\"Selection is empty\",\"Warning\")\n            elif replacement[1] == 'find':\n                findTxt = self.findEdit.text()\n                rawDict[replacement[0]] = findTxt\n                if not findTxt:\n                    self.toast(\"Find edit is empty\",\"Warning\")\n            elif replacement[1] == 'replace':\n                replaceTxt = self.replaceEdit.text()\n                rawDict[replacement[0]] = replaceTxt\n                if not replaceTxt:\n                    self.toast(\"Replace edit is empty\",\"Warning\")\n        for replacement in replacements:\n            rawOutString = rawOutString.replace(replacement[0],rawDict[replacement[0]])\n        if not execute:\n            return rawOutString\n        if self.currentEditor:\n            old_cursor = self.getTC(self.currentEditor.textCursor())\n            self.setModified(self.editorList.currentItem().text(), \\\n                self.currentEditor.toPlainText(), f\"Insert template: {key}\", old_cursor)\n            if  \"goto\" in rawDict:\n                if rawDict[\"goto\"] == \"home\":\n                    self.gotoLine(1)\n                elif rawDict[\"goto\"] == '' or rawDict[\"goto\"] == \"current\":\n                    pass\n                elif rawDict[\"goto\"] == \"end\":\n                    self.gotoLine(-1, eol=True)\n                elif rawDict[\"goto\"] == \"input\" or rawDict[\"goto\"] == \"input1\":\n                    line,ok = inp1(\"Line number\",\"Input line number for goto\\nCancel for current cursor position: \")()\n                    if ok and line != \"\":\n                        self.gotoLine(self.parseLine(line))\n                elif rawDict[\"goto\"].startswith(\"relative:\"):\n                    relativeMove = rawDict[\"goto\"][len(\"relative:\"):]\n                    relativeLine = self.parseLine(relativeMove)\n                    curLine = self.getLineNumberAtCursor()\n                    self.gotoLine(curLine + relativeLine)\n                else:\n                    lineNumber = self.parseLine(rawDict[\"goto\"])\n                    if lineNumber != 0:\n                        self.gotoLine(lineNumber)\n            self.currentEditor.insertPlainText(rawOutString)\n        else:\n            self.toast(\"No editor to insert template into\",\"Error\")\n\n    def getTemplateString(self):\n        \"\"\"updates self.templateDictString from templates file, returns dict\"\"\"\n        import os\n\n        real_path = os.path.realpath(__file__)\n        dir_path = os.path.dirname(real_path)\n        template_file = real_path.replace(\".FCMacro\",\"_Templates.txt\")\n        bHasFile = os.path.exists(template_file)\n        if not bHasFile:\n            dictString = pg.GetString(\"TemplateDictString\",\"{}\")\n            if dictString == \"{}\": #no parameter\n                templateDict = {\n\"button\":{\"label\":\"input\", \"name\":\"input\",\"output\":\"name = QtWidgets.QPushButton('label')\"},\n\"import QtGui, QtWidgets, QtCore\":{\"output\":\"from PySide import QtGui, QtWidgets, QtCore\"}\n}\n            else:\n                templateDict = json.loads(dictString) #preserve existing templates from parameters\n            pg.RemString(\"TemplateDictString\")\n            self.setTemplateString(templateDict) #make the file with default samples\n        else: #file already exists\n            with open(template_file, 'r') as infile:\n                self.templateDictString = infile.read()\n            templateDict = json.loads(self.templateDictString, strict=False)\n        return templateDict\n\n    def setTemplateString(self, new_dict):\n        \"\"\"saves to text file in json format\"\"\"\n        formatted = json.dumps(new_dict,indent=0,separators=(','+chr(10),':'+chr(10)))\n        formatted = formatted.replace('\\\\n',chr(10))\n\n        import os\n        real_path = os.path.realpath(__file__)\n        dir_path = os.path.dirname(real_path)\n        template_file = real_path.replace(\".FCMacro\",\"_Templates.txt\")\n        with open(template_file, 'w') as outfile:\n            outfile.write(formatted)\n        #pg.SetString(\"TemplateDictString\", dumped)\n\n    def editTemplates(self):\n        dlg = TemplateEditor(form=self)\n        #dlg.exec_()\n        dlg.show()\n\n    def makeSearchFromFindEdit(self):\n        findTxt = self.findEdit.text()\n        if not findTxt:\n            self.toast(\"Nothing in Find edit\",\"Error\")\n            return\n        self.search(findTxt)\n\n    def makeSearchFromSelection(self):\n        self.onRefreshBtnClicked(True)\n        if not self.currentEditor:\n            self.toast(\"No current editor\",\"Error\")\n            return\n        tc = self.currentEditor.textCursor()\n        findTxt = tc.selectedText()\n        if not findTxt:\n            self.toast(\"Nothing in selection\",\"Error\")\n            return\n        self.search(findTxt)\n\n    def makeSearchFromImmediate(self):\n        findTxt, ok = QtWidgets.QInputDialog.getText(mw, \"Search source\",\"Enter search query:\")\n        if ok:\n            self.search(findTxt)\n\n    def makewSearchFromFindEdit(self):\n        findTxt = self.findEdit.text()\n        if not findTxt:\n            self.toast(\"Nothing in Find edit\",\"Error\")\n            return\n        self.wSearch(findTxt)\n\n    def makewSearchFromSelection(self):\n        self.onRefreshBtnClicked(True)\n        if not self.currentEditor:\n            self.toast(\"No current editor\",\"Error\")\n            return\n        tc = self.currentEditor.textCursor()\n        findTxt = tc.selectedText()\n        if not findTxt:\n            self.toast(\"Nothing in selection\",\"Error\")\n            return\n        self.wSearch(findTxt)\n\n    def makewSearchFromImmediate(self):\n        findTxt, ok = QtWidgets.QInputDialog.getText(mw, \"Search wiki\",\"Enter search query:\")\n        if ok:\n            self.wSearch(findTxt)\n\n    def makeqSearchFromFindEdit(self):\n        findTxt = self.findEdit.text()\n        if not findTxt:\n            self.toast(\"Nothing in Find edit\",\"Error\")\n            return\n        self.qSearch(findTxt)\n\n    def makeqSearchFromSelection(self):\n        self.onRefreshBtnClicked(True)\n        if not self.currentEditor:\n            self.toast(\"No current editor\",\"Error\")\n            return\n        tc = self.currentEditor.textCursor()\n        findTxt = tc.selectedText()\n        if not findTxt:\n            self.toast(\"Nothing in selection\",\"Error\")\n            return\n        self.qSearch(findTxt)\n\n    def makeqSearchFromImmediate(self):\n        findTxt, ok = QtWidgets.QInputDialog.getText(mw, \"Search Qt\",\"Enter qSearch query:\")\n        if ok:\n            self.qSearch(findTxt)\n\n    def makeReferenceMenu(self, mod):\n        def makeReference(name): return lambda: self.showHelp(name)\n        if isinstance(mod, str):\n            mod = __import__(mod.strip())\n        refMenu = QtWidgets.QMenu(mod.__name__)\n        subMenus = []\n\n        attributeStrings = [att for att in dir(mod) if not \"__\" in att]\n\n        attrActions = []\n        attrActions.append(QtWidgets.QAction(f\"{mod.__name__}\"))\n        attrActions[-1].triggered.connect(makeReference(f\"{mod.__name__}\"))\n        refMenu.addAction(attrActions[-1])\n        if not attributeStrings:\n            self.showHelp(mod)\n        ii = 0\n        for attr in attributeStrings:\n            if ii % 50 == 0:\n                subMenus.append(QtWidgets.QMenu(f\"Start from -- {mod.__name__}.{attr}\"))\n                ii += 1\n            if not hasattr(mod, \"__name__\"):\n                continue\n            attrActions.append(QtWidgets.QAction(f\"{mod.__name__}.{attr}\"))\n            attrActions[-1].triggered.connect(makeReference(f\"{mod.__name__}.{attr}\"))\n            subMenus[-1].addAction(attrActions[-1])\n            ii += 1\n\n        for sub in subMenus:\n            refMenu.addMenu(sub)\n        if exec:\n            refMenu.exec_(QtCore.QPoint())\n        else:\n            return refMenu\n\n    def showHelp(self, name):\n        if isinstance(name, str) and name[:3] == \"Qt.\":\n            name = \"PySide.QtCore.\" + name\n        from contextlib import redirect_stdout\n        import io\n        f = io.StringIO()\n        with redirect_stdout(f):\n            print(f\"help({name}):\")\n            help(f\"{name}\")\n        #self.print(f.getvalue())\n        self.makeWindow(name, f.getvalue())\n\n    def dir(self, name):\n        from PySide import QtCore, QtGui\n        Qt = QtCore.Qt\n        if isinstance(name, str) and name[:3] == \"Qt.\":\n            name = getattr(Qt,name[3:])\n        elif isinstance(name,str):\n            try:\n                name = __import__(name.strip())\n            except ModuleNotFoundError as ex:\n                pass\n        text = f\"dir({name}):\"\n        text += f\"{dir(name)}\"\n        #self.print(f.getvalue())\n        title = f\"dir({name})\".replace(\"'\",\"\")\n        self.makeWindow(name, text, title=title)\n\n    def makeWindow(self, name, txt, title=\"\"):\n        \"\"\"make a window to show some text\"\"\"\n        dlg = QtWidgets.QDockWidget()\n        dlg.setObjectName(\"Editor assistant dockwidget\")\n        edit = QtWidgets.QPlainTextEdit()\n        edit.setPlainText(txt)\n        layout = QtWidgets.QVBoxLayout()\n        layout.addWidget(edit)\n        dlg.setLayout(layout)\n        # dlg.resize(800,600)\n        dlg.setWindowTitle(f\"help on {name}\" if not title else title)\n        # dlg.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)\n        # self.mdi.addSubWindow(dlg)\n        dlg.show()\n\n    def close(self):\n\n        mw.findChild(QtWidgets.QMdiArea).setStyleSheet(\"QTabBar::tab:selected, QTabBar::tab:hover {background-color: QPalette.Base;}\")\n        self.mdi.subWindowActivated.disconnect(self.onSubWindowActivated)\n        self.form.close()\n\n    def onSnapMenuBtnClicked(self, arg1):\n        qp = QtCore.QPoint()\n        self.snapMenuBtnContextMenu(qp)\n\n    def makeSnapsMenu(self):\n        snapsMenu = QtWidgets.QMenu(\"Snaps\")\n        self.onRefreshBtnClicked(True)\n        curName = self.editorList.currentItem().text() if self.editorList.count() else \"\"\n        if not curName:\n            self.toast(\"No current editor\",\"Error\")\n        snaps = [snap for snap in reversed(self.snaps) if snap[\"name\"] == curName]\n\n        takeSnapshotAction = QtWidgets.QAction(\"Take snapshot\", mw)\n        takeSnapshotAction.triggered.connect(lambda: self.onTakeSnapBtnClicked(True))\n        snapsMenu.addAction(takeSnapshotAction)\n        takeSnapshotAction.setEnabled(curName != \"\")\n\n        restoreMenu = QtWidgets.QMenu(\"Restore last snap\")\n        restoreToCurrentEditorAction = QtWidgets.QAction(\"Restore to current editor\", mw)\n        restoreToCurrentEditorAction.triggered.connect(self.doRestoreToCurrentEditor)\n        restoreToCurrentEditorAction.setEnabled(len(snaps) > 0)\n        restoreMenu.addAction(restoreToCurrentEditorAction)\n\n        restoreToClipboardAction = QtWidgets.QAction(\"Restore to clipboard\", mw)\n        restoreToClipboardAction.triggered.connect(self.doRestoreToClipboard)\n        restoreToClipboardAction.setEnabled(len(snaps) > 0)\n        restoreMenu.addAction(restoreToClipboardAction)\n\n        restoreToTextDocumentAction = QtWidgets.QAction(\"Restore to new Text document\", mw)\n        restoreToTextDocumentAction.triggered.connect(self.doRestoreToTextDocument)\n        restoreToTextDocumentAction.setEnabled(len(snaps) > 0)\n        restoreMenu.addAction(restoreToTextDocumentAction)\n        snapsMenu.addMenu(restoreMenu)\n        if not len(self.getSnaps()):\n            restoreMenu.setEnabled(False)\n\n        def makeRestoreAnyLambda(name,reason,idx): return lambda: self.restoreAny(name,reason,idx)\n\n        restoreAnys = self.getRestoreAnys()\n        restoreAnysMenu = QtWidgets.QMenu(\"Restore Any\")\n        restoreAnyActions = []\n        restoreAnyLambdas = [makeRestoreAnyLambda(tup[0],tup[1],ii) for ii,tup in enumerate(restoreAnys)]\n        for ii,tup in enumerate(restoreAnys):\n            restoreAnyActions.append(QtWidgets.QAction(f\"Restore {tup[0]}: {tup[1]}\", mw))\n            restoreAnyActions[-1].triggered.connect(restoreAnyLambdas[ii])\n            restoreAnysMenu.addAction(restoreAnyActions[-1])\n        snapsMenu.addMenu(restoreAnysMenu)\n        if not restoreAnys:\n            restoreAnysMenu.setEnabled(False)\n\n        saveMenu = QtWidgets.QMenu(\"Save\")\n        saveSnapshotAsAction = QtWidgets.QAction(\"Save snapshot as...\", mw)\n        saveSnapshotAsAction.triggered.connect(self.doSaveSnapshotAs)\n        saveSnapshotAsAction.setEnabled(len(snaps) > 0)\n        saveMenu.addAction(saveSnapshotAsAction)\n\n        saveAllSnapshotAsAction = QtWidgets.QAction(\"Save all snaps to JSON file...\", mw)\n        saveAllSnapshotAsAction.triggered.connect(self.saveSnapsToJSON)\n        saveAllSnapshotAsAction.setEnabled(len(snaps) > 0)\n        saveMenu.addAction(saveAllSnapshotAsAction)\n        snapsMenu.addMenu(saveMenu)\n        if not len(self.getSnaps()):\n            saveMenu.setEnabled(False)\n\n        loadMenu = QtWidgets.QMenu(\"Load\")\n        loadSnapshotAction = QtWidgets.QAction(\"Load snapshots from JSON...\", mw)\n        loadSnapshotAction.triggered.connect(self.loadSnapsFromJSON)\n        loadMenu.addAction(loadSnapshotAction)\n\n        snapsMenu.addMenu(loadMenu)\n        discardMenu = QtWidgets.QMenu(\"Discard\")\n\n        def makeDiscardSnapLambda(x): return lambda: self.discardSnap(x)\n\n        discardAction = QtWidgets.QAction(\"Discard latest snap\", mw)\n        discardAction.setToolTip(\"Discards most recent snap for the current editor\")\n        discardAction.triggered.connect(self.discardSnap)\n        discardAction.setEnabled(len(snaps) > 0)\n        discardMenu.addAction(discardAction)\n\n        discardAllAction = QtWidgets.QAction(\"Discard all snaps\", mw)\n        discardAllAction.setToolTip(\"Disards all snaps for all editors\")\n        discardAllAction.triggered.connect(self.discardAllSnaps)\n        discardAllAction.setEnabled(len(snaps) > 0)\n        discardMenu.addAction(discardAllAction)\n\n        discardSnaps = self.getSnaps()\n        discardSnapActions = []\n        discardSnapLambdas = [makeDiscardSnapLambda(ii) for ii,snap in enumerate(discardSnaps)]\n        for ii,snap in enumerate(discardSnaps):\n            discardSnapActions.append(QtWidgets.QAction(f\"Discard {snap['reason']}\", mw))\n            discardSnapActions[-1].triggered.connect(discardSnapLambdas[ii])\n            discardMenu.addAction(discardSnapActions[-1])\n        if not discardSnaps:\n            discardMenu.setEnabled(False)\n\n        snapsMenu.addMenu(discardMenu)\n\n        def makeDiffLambda(x,y,xlab=\"\",ylab=\"\"): return lambda: self.showDiff(x,y,xlab,ylab)\n\n        diffSnaps = self.getDiffSnaps(curName)\n        diffSnapsMenu = QtWidgets.QMenu(\"Diff current editor\")\n        diffSnapActions = []\n        diffSnapLambdas = [makeDiffLambda(snap['name'],ii) for ii,snap in enumerate(diffSnaps)]\n        for ii,snap in enumerate(diffSnaps):\n            diffSnapActions.append(QtWidgets.QAction(f\"Diff {snap['reason']}\", mw))\n            diffSnapActions[-1].triggered.connect(diffSnapLambdas[ii])\n            diffSnapsMenu.addAction(diffSnapActions[-1])\n\n        for edName in self.editorDict.keys():\n            if edName == curName:\n                continue\n            diffSnapActions.append(QtWidgets.QAction(f\"Diff {edName}\", mw))\n            diffSnapLambdas.append(makeDiffLambda(self.getText(edName), self.getText(curName), curName, edName))\n            diffSnapActions[-1].triggered.connect(diffSnapLambdas[-1])\n            diffSnapsMenu.addAction(diffSnapActions[-1])\n\n        clipText = QtGui.QClipboard().text()\n\n        diffSnapActions.append(QtWidgets.QAction(f\"Diff clipboard text\", mw))\n        diffSnapLambdas.append(makeDiffLambda(clipText, self.getText(curName),curName, \"Clipboard text\"))\n        diffSnapActions[-1].triggered.connect(diffSnapLambdas[-1])\n        diffSnapsMenu.addAction(diffSnapActions[-1])\n        if not clipText:\n            diffSnapActions[-1].setEnabled(False)\n\n        snapsMenu.addMenu(diffSnapsMenu)\n        if not diffSnapActions:\n            diffSnapsMenu.setEnabled(False)\n\n        def makeEditReasonLambda(name,reason,idx): return lambda: self.editReason(name,reason,idx)\n\n        editReasons = self.getEditReasons(curName)\n        editReasonsMenu = QtWidgets.QMenu(\"Edit reason\")\n        editReasonActions = []\n        editReasonLambdas = [makeEditReasonLambda(tup[0],tup[1],ii) for ii,tup in enumerate(editReasons)]\n        for ii,tup in enumerate(editReasons):\n            editReasonActions.append(QtWidgets.QAction(f\"Edit reason {tup[0]}: {tup[1]}\", mw))\n            editReasonActions[-1].triggered.connect(editReasonLambdas[ii])\n            editReasonsMenu.addAction(editReasonActions[-1])\n        snapsMenu.addMenu(editReasonsMenu)\n        if not editReasons:\n            editReasonsMenu.setEnabled(False)\n        return snapsMenu\n\n\n    def snapMenuBtnContextMenu(self, point):\n        snapsMenu = self.makeSnapsMenu()\n\n        snapsMenu.exec_(self.snapMenuBtn.mapToGlobal(point))\n\n    def editReason(self, name, reason, idx):\n        snap = self.snaps[idx]\n        new_reason,ok = QtWidgets.QInputDialog.getText(mw,\"Edit reason\",f\"Enter a new reason in place of:\\n\\\n{reason}\\n\", text=reason)\n        if not ok:\n            return\n        snap['reason'] = new_reason\n        self.snaps[idx] = snap\n        self.toast(f\"snap of {name}:{reason} updated to {new_reason}\",\"Information\")\n        return\n\n    def getEditReasons(self,curName):\n        \"\"\"list of tuple(name, reason, idx)\"\"\"\n        editReasons = [tuple([snap['name'],snap['reason'],ii]) for ii,snap in enumerate(self.snaps)]\n        return editReasons\n\n    def doRestoreToCurrentEditor(self):\n        snaps = self.getSnaps()\n        if not snaps:\n            self.toast(\"No snaps to restore\", \"Error\")\n            return\n        self.restoreAny(snaps[0]['name'], snaps[0]['reason'],0)\n\n    def restoreAny(self, name, reason, idx):\n        \"\"\"restore any snap to current document\"\"\"\n        snap = self.snaps[idx]\n        curName = self.editorList.currentItem().text() if self.editorList.currentItem() else \"\"\n        if not curName:\n            self.toast(\"Invalid current editor\",\"Error\")\n            return\n        if curName != name:\n            items = [\"Oops, wrong document -- cancel\",f\"I confirm: overwrite {curName} with this snap\"]\n            item,ok = QtWidgets.QInputDialog.getItem(mw,f\"Restore\",f\"You are about to restore:{name}: {reason} to a different document: {curName}.\\n\",items)\n            if not bool (ok and item == items[1]):\n                return\n        old_text = self.getText(curName)\n        old_cursor = self.currentEditor.textCursor()\n        self.currentEditor.setPlainText(snap[\"old_text\"])\n        self.setTextCursor(self.editorList.currentItem().text(), snap['tc'])\n        self.setModified(curName, old_text, f\"Restore {snap['reason']}\", self.getTC(old_cursor))\n        self.toast(f\"snap of {name}:{reason} updated to {curName}: {snap['reason']}\",\"Information\")\n        return\n\n    def getRestoreAnys(self):\n        \"\"\"list of tuple(name, reason, idx)\"\"\"\n        restoreAnys = [tuple([snap['name'],snap['reason'],ii]) for ii,snap in enumerate(self.snaps)]\n        return restoreAnys\n\n    def saveSnapsToJSON(self):\n        \"\"\"save all snaps to a JSON text file\"\"\"\n        global setPathLatestDirectory\n\n        if platform.node() == \"mint\":   \n            fname, filter = QtWidgets.QFileDialog.getSaveFileName(None, \"Save all snaps to a JSON file\", setPathLatestDirectory, \"(*.json);; (*.*);; (*)\")#PySide Mint\n            filter = filter[filter.find(\".\"):filter.find(\")\")]\n            if filter[-2:] == \".*\":\n                 filter = filter[:-2]\n            fname = fname + filter\n        else:   \n            fname, filter =  QtWidgets.QFileDialog.getSaveFileName(None, \"Save all snaps to a JSON file\", setPathLatestDirectory, \"json (*.json);; Any (*.*);; Any (*)\")\n\n        if not fname:\n            return\n\n        pathFile = os.path.dirname(fname) + \"/\"  #1# = C:/Tmp/\n        setPathLatestDirectory = pathFile\n        pg.SetString(\"setPathLatestDirectory\",setPathLatestDirectory)\n\n        with open(fname, \"w\") as outfile:\n            json.dump(self.snaps, outfile)\n        self.toast(f\"All snaps saved to {outfile}\", \"Information\")\n\n    def loadSnapsFromJSON(self):\n        \"\"\"load previously saved snaps from a JSON file\"\"\"\n        global setPathLatestDirectory\n\n        if platform.node() == \"mint\":   \n            fname, filter = QtWidgets.QFileDialog.getOpenFileName(None, \"Open a JSON file\", setPathLatestDirectory, \" (*.*);; (*)\")#PySide Mint\n        else:   \n            fname, filter =  QtWidgets.QFileDialog.getOpenFileName(None, \"Open a JSON file\", setPathLatestDirectory, \"Any (*.*);; Any (*)\")\n\n        if not fname:\n            return\n\n        pathFile = os.path.dirname(fname) + \"/\"  #1# = C:/Tmp/\n        setPathLatestDirectory = pathFile\n        pg.SetString(\"setPathLatestDirectory\",setPathLatestDirectory)\n\n        try:\n            f = open(fname)\n        except Exception as ex:\n            self.toast(f\"{ex}\",\"Error\")\n            return\n        try:\n            self.snaps = json.load(f)\n        except Exception as ex:\n            self.toast(f\"{ex}\",\"Error\")\n            f.close()\n            return\n        self.updateSnapBtns()\n        self.toast(f\"Snaps loaded and restored from {fname}\",\"Message\")\n\n\n    def getDiffSnaps(self, name):\n        self.onRefreshBtnClicked(True)\n        curName = name\n        snaps = [snap for snap in reversed(self.snaps) if snap[\"name\"] == curName]\n        return snaps\n\n    def showDiff(self, name, idx, firstLabel = \"\", secondLabel = \"\"):\n        \"\"\"make a diff of the snap and the text in the current editor\"\"\"\n        if isinstance(idx, int):\n            snaps = self.getDiffSnaps(name)\n            plainText = self.getText(name).splitlines()\n            plainLabel = name\n            snapText = snaps[idx]['old_text'].splitlines()\n            snapLabel = snaps[idx]['reason']\n        else: #presume to be strings passed in to be diffed\n            snapText = name.splitlines()\n            plainText = idx.splitlines()\n            plainLabel = firstLabel\n            snapLabel = secondLabel\n        d = difflib.HtmlDiff(tabsize=4)\n        ds = DiffSaver(form=self, snapText=snapText, plainText=plainText, label2=plainLabel, label1=snapLabel)\n        ds.setWindowFlag(QtCore.Qt.WindowMinimizeButtonHint, True)\n        ds.setWindowFlag(QtCore.Qt.WindowMaximizeButtonHint, True)\n        ds.resizeEvent = ds.onResize\n        self.mdi.addSubWindow(ds)\n        layout = QtWidgets.QVBoxLayout()\n        ds.setLayout(layout)\n        ds.setWindowIcon(QIconFromXPMString(__icon__))\n        try:\n            from PySide import QtWebEngineWidgets as Web\n            ds.webView = Web.QWebEngineView()\n        except:\n            ds.webView = QtWidgets.QTextBrowser()\n        #ds.webView.setHtml(ds.diff)\n        saveBtn = QtWidgets.QPushButton(\"Save to html...\")\n        saveBtn.clicked.connect(ds.saveDiffToHtml)\n        sliderLayout=QtWidgets.QHBoxLayout()\n        sliderLayout.addWidget(saveBtn)\n        ds.numlinesSpinBox = QtWidgets.QSpinBox()\n        ds.numlinesSpinBox.setValue(5)\n        ds.contextCheckBox = QtWidgets.QCheckBox()\n        ds.contextCheckBox.setCheckState(QtCore.Qt.Checked)\n        sliderLayout.addWidget(QtWidgets.QLabel(\"Context:\"))\n        sliderLayout.addWidget(ds.contextCheckBox)\n        sliderLayout.addWidget(QtWidgets.QLabel(\"Context lines:\"))\n        sliderLayout.addWidget(ds.numlinesSpinBox)\n        ds.contextCheckBox.stateChanged.connect(ds.onContextCheckBoxStateChanged)\n        ds.numlinesSpinBox.valueChanged.connect(ds.onNumlinesSpinBoxValueChanged)\n        sliderLayout.addWidget(QtWidgets.QLabel(\"Zoom:\"))\n        ds.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)\n        ds.slider.setRange(25, 500)\n        ds.slider.valueChanged.connect(ds.onSliderValueChanged)\n        ds.slider.setMinimum(25)\n        ds.slider.setMaximum(500)\n        ds.slider.setTickPosition(QtWidgets.QSlider.TicksBelow)\n        ds.slider.setTickInterval(25)\n        ds.slider.setValue(100)\n        sliderLayout.addWidget(ds.slider)\n        sliderLayout.addWidget(QtWidgets.QLabel(\"Col width:\"))\n        ds.widthSlider = QtWidgets.QSlider(QtCore.Qt.Horizontal)\n        ds.widthSlider.setRange(25, 2000)\n        ds.widthSlider.valueChanged.connect(ds.onWidthSliderValueChanged)\n        ds.widthSlider.setMinimum(25)\n        ds.widthSlider.setMaximum(2000)\n        ds.widthSlider.setTickPosition(QtWidgets.QSlider.TicksBelow)\n        ds.widthSlider.setTickInterval(25)\n        ds.widthSlider.setValue(500)\n        sliderLayout.addWidget(ds.widthSlider)\n        layout.addLayout(sliderLayout)\n        layout.addWidget(ds.webView)\n\n        ds.show()\n        ds.resize(640,480)\n        self.onRefreshBtnClicked(True)\n        #self.toast(f\"make diff of snap = {idx}\",\"Message\")\n\n    def doSaveSnapshotAs(self):\n        global setPathLatestDirectory\n\n        self.onRefreshBtnClicked(True)\n        curName = self.editorList.currentItem().text()\n        snaps = [snap for snap in reversed(self.snaps) if snap[\"name\"] == curName]\n        if not snaps:\n            self.toast(\"No saved snapshot to save as\",\"Error\")\n            self.updateSnapBtns()\n            return\n        else:\n\n            if platform.node() == \"mint\":   \n                fname, filter = QtWidgets.QFileDialog.getSaveFileName(None, \"Save snapshot to text file\", setPathLatestDirectory, \" (*.FCMacro);; (*.py);; (*.txt);; (*.*);; (*)\")#PySide Mint\n                filter = filter[filter.find(\".\"):filter.find(\")\")]\n                if filter[-2:] == \".*\":\n                     filter = filter[:-2]\n                fname = fname + filter\n            else:   \n                fname, filter =  QtWidgets.QFileDialog.getSaveFileName(None, \"Save snapshot to text file\", setPathLatestDirectory, \"Macro (*.FCMacro *.py);;Text file (*.txt);;Any (*.*);;Any (*)\")\n\n            if not fname:\n                return\n\n            pathFile = os.path.dirname(fname) + \"/\"  #1# = C:/Tmp/\n            setPathLatestDirectory = pathFile\n            pg.SetString(\"setPathLatestDirectory\",setPathLatestDirectory)\n\n            with open(fname,\"w\") as outfile:\n                outfile.write(snaps[0]['old_text'])\n            self.toast(f\"Snapshot: {snaps[0]['reason']} saved to {fname}\",\"Message\")\n\n    def doRestoreToClipboard(self):\n        self.onRefreshBtnClicked(True)\n        curName = self.editorList.currentItem().text()\n        snaps = [snap for snap in reversed(self.snaps) if snap[\"name\"] == curName]\n        if not snaps:\n            self.toast(\"No saved snapshot to send to clipboard\",\"Error\")\n            self.updateSnapBtns()\n            return\n        else:\n            clipboard = QtGui.QClipboard()\n            clipboard.setText(snaps[0][\"old_text\"])\n            self.toast(f\"Snapshot: {snaps[0]['reason']} sent to clipboard\",\"Message\")\n\n    def doRestoreToTextDocument(self):\n        self.onRefreshBtnClicked(True)\n        curName = self.editorList.currentItem().text()\n        snaps = [snap for snap in reversed(self.snaps) if snap[\"name\"] == curName]\n        if not snaps:\n            self.toast(\"No saved snapshot to restore to text document\",\"Error\")\n            self.updateSnapBtns()\n            return\n        else:\n            doc = FreeCAD.ActiveDocument if FreeCAD.ActiveDocument else FreeCAD.newDocument()\n            textDoc = doc.addObject(\"App::TextDocument\",\"Text document\")\n            textDoc.Text = snaps[0]['old_text']\n            self.toast(f\"Snapshot: {snaps[0]['reason']} sent to {textDoc.Name}\",\"Message\")\n            textDoc.ViewObject.doubleClicked()\n            doc.recompute()\n\n    def onUndoBtnClicked(self, arg1):\n        self.onRefreshBtnClicked(True)\n        self.updateUndoBtn()\n        curName = self.editorList.currentItem().text()\n        curCursor = self.editorDict[curName].textCursor()\n        for queue in reversed(self.undoQueue):\n            if curName == queue[\"name\"]:\n                redo = {\"name\":curName, \"reason\":queue[\"reason\"], \"old_text\":self.getText(curName), \"tc\":self.getTC(curCursor)}\n                self.currentEditor.setPlainText(queue[\"old_text\"])\n                self.setTextCursor(curName, queue['tc'])\n                self.redoQueue.append(redo)\n                self.undoQueue.pop()\n                self.updateUndoBtn()\n                break\n\n    def onUndoClearBtnClicked(self, arg1):\n        count = len(self.undoQueue) + len(self.redoQueue)\n        self.undoQueue = []\n        self.redoQueue = []\n        self.updateUndoBtn()\n        self.toast(f\"Undo/redo queues purged ({count} items)\",\"Message\")\n\n    def onRedoBtnClicked(self, arg1):\n        self.onRefreshBtnClicked(True)\n        self.updateUndoBtn()\n        curName = self.editorList.currentItem().text()\n        for queue in reversed(self.redoQueue):\n            if curName == queue[\"name\"]:\n                undo = {\"name\":curName, \"reason\":queue[\"reason\"], \"old_text\":self.getText(curName), \"tc\":self.getTC(self.currentEditor.textCursor())}\n                self.currentEditor.setPlainText(queue[\"old_text\"])\n                self.setTextCursor(curName, queue['tc'])\n                self.undoQueue.append(undo)\n                self.redoQueue.pop()\n                self.updateUndoBtn()\n                break\n\n    def updateUndoBtn(self):\n        self.undoBtn.setText(\"\")\n        if not self.editorList.currentItem():\n            return\n        curName = self.editorList.currentItem().text()\n\n        self.undoBtn.setEnabled(False)\n        for queue in reversed(self.undoQueue):\n            if curName == queue[\"name\"]:\n                self.undoBtn.setText(f\"Undo {queue['reason']}\")\n                self.undoBtn.setEnabled(True)\n                break\n        self.redoBtn.setText(\"\")\n        self.redoBtn.setEnabled(False)\n        for queue in reversed(self.redoQueue):\n            if curName == queue[\"name\"]:\n                self.redoBtn.setText(f\"Redo {queue['reason']}\")\n                self.redoBtn.setEnabled(True)\n                break\n        self.undoClearBtn.setEnabled(len(self.undoQueue)+len(self.redoQueue))\n\n    def onFindBackBtnClicked(self, arg1):\n        self.onRefreshBtnClicked(True)\n        if not shiboken.isValid(self.currentEditor) or not self.currentEditor:\n            self.toast(\"current editor is invalid\",\"Error\")\n            return\n        self.currentEditor.setFocus()\n        name = self.editorList.currentItem().text()\n        txt = self.findEdit.text()\n        modifiers = QtWidgets.QApplication.keyboardModifiers()\n        if modifiers == QtCore.Qt.AltModifier:\n            selText = self.currentEditor.textCursor().selectedText()\n            self.findEdit.setText(selText if selText else txt)\n            txt = self.findEdit.text()\n        elif modifiers == QtCore.Qt.ControlModifier:\n            self.gotoLine(-1, silent=True, eol=True)\n\n        self.found = False\n        self.find(name, txt, True)\n        if not self.found:\n            if self.loopCheckBox.checkState():\n                self.toast(f\"{txt} not found in {name} --Looping back to end\",\"Warning\")\n                self.gotoLine(-1, silent=True, eol=True)\n            else:\n                self.toast(f\"{txt} not found backwards in {name}\",\"Message\")\n        self.on_ComboBox_Find_Clicked(txt)\n\n        self.highlight(txt)\n\n    def setModified(self, name, old_text, reason, tc):\n        self.undoQueue.append({\"name\":name, \"old_text\": old_text, \"reason\":reason, \"tc\":tc})\n        if len(self.undoQueue) > UNDO_QUEUE_MAX_SIZE:\n            self.toast(f\"undo queue reached max size {UNDO_QUEUE_MAX_SIZE}\\ndiscarding {self.undoQueue[0]['reason']}\",\"Warning\")\n            self.undoQueue.pop(0)\n        self.updateUndoBtn()\n        self.currentEditor.document().setModified(True)\n        self.currentEditor.centerCursor()\n\n    def onIndentBtnClicked(self, arg1):\n        self.onRefreshBtnClicked(True)\n        if not shiboken.isValid(self.currentEditor) or not self.currentEditor:\n            self.toast(\"current editor is invalid\", \"Error\")\n            return\n        self.currentEditor.setFocus()\n        old_text = self.getText()\n        tc = self.currentEditor.textCursor()\n        txt = tc.selectedText()\n        if not txt:\n            self.toast(\"nothing selected to indent\")\n            return\n        lines = txt.splitlines()\n\n        if len(self.ComboBox_Indent_Memo.currentText()) == 0:\n            self.Indent_Memo = \"\"\n        else:\n            self.Indent_Memo = self.ComboBox_Indent_Memo.currentText()\n            self.on_ComboBox_Indent_Memo_Clicked(self.Indent_Memo)\n\n        if self.Indent_Memo == \"\":\n            lines2 = ['    ' + line for line in lines]\n        else:\n            lines2 = [self.Indent_Memo + line for line in lines]\n\n        joined = '\\u2029'.join(lines2)\n        tc.insertText(joined)\n        self.setModified(self.editorList.currentItem().text(), old_text, \"Indent >>\", self.getTC(tc))\n        tc.movePosition(QtGui.QTextCursor.Up, QtGui.QTextCursor.KeepAnchor, len(lines2)-1)\n        tc.movePosition(QtGui.QTextCursor.StartOfLine, QtGui.QTextCursor.KeepAnchor)\n        self.currentEditor.setTextCursor(tc)\n\n    def on_ComboBox_Indent_Memo_Changed_Clicked(self, text):    # change indentBtn icon\n        self.Indent_Memo = \"\"\n        if text == \"\":\n            self.indentBtn.setIcon(QIconFromXPMString(indent_icon))\n        else:\n            self.indentBtn.setIcon(QIconFromXPMString(indent_Memo_icon))\n\n    def on_ComboBox_Indent_Memo_Clicked(self, text):\n        global duplicate_Indent_Memo\n        global duplicate_Find\n\n        if text not in duplicate_Indent_Memo:\n            duplicate_Indent_Memo.append(text)\n            duplicate_Indent_Memo = sorted(list(set(duplicate_Indent_Memo))) # sort duplicate\n            duplicate_Find.append(text)\n            duplicate_Find = sorted(list(set(duplicate_Find))) # sort duplicate\n            self.ComboBox_Indent_Memo.setCurrentText(text)\n            self.ComboBox_Find.addItem(text)\n            self.ComboBox_Find.setCurrentText(text)\n            self.findEdit.setText(text)\n            self.Indent_Memo = self.ComboBox_Indent_Memo.currentText()\n\n    def onIndentBackBtnClicked(self, arg1):\n        self.onRefreshBtnClicked(True)\n        if not shiboken.isValid(self.currentEditor) or not self.currentEditor:\n            self.toast(\"current editor is invalid\", \"Error\")\n            return\n        self.currentEditor.setFocus()\n        old_text = self.getText()\n        old_cursor = self.currentEditor.textCursor()\n        name = self.editorList.currentItem().text()\n        tc = self.currentEditor.textCursor()\n        txt = tc.selectedText()\n        if not txt:\n            self.toast(\"nothing selected to unindent\")\n            return\n        lines = txt.splitlines()\n        hasLeading = True\n        for line in lines:\n            if not line[:4] == '    ':\n                hasLeading = False\n        if not hasLeading:\n            self.toast(\"Editor assistant: Cannot unindent selected block\",\"Error\")\n            return\n        lines2 = [line[4:] for line in lines]\n        joined = '\\u2029'.join(lines2)\n        tc.insertText(joined)\n        self.setModified(self.editorList.currentItem().text(), old_text, \"<< Unindent\", self.getTC(old_cursor))\n        tc.movePosition(QtGui.QTextCursor.Up, QtGui.QTextCursor.KeepAnchor, len(lines2)-1)\n        tc.movePosition(QtGui.QTextCursor.StartOfLine, QtGui.QTextCursor.KeepAnchor)\n        self.currentEditor.setTextCursor(tc)\n\n    def onReplaceAllBtnClicked(self, arg1):\n        self.onRefreshBtnClicked(True)\n        if not shiboken.isValid(self.currentEditor) or not self.currentEditor:\n            self.toast(\"current editor is invalid\", \"Error\")\n            return\n        self.currentEditor.setFocus()\n        name = self.editorList.currentItem().text()\n        txt = self.findEdit.text()\n        newTxt = self.replaceEdit.text()\n        self.on_ComboBox_Replace_Clicked(newTxt)\n        self.replace(name, txt, newTxt)\n\n    def onReplaceBtnClicked(self, arg1):\n        self.onRefreshBtnClicked(True)\n        if not shiboken.isValid(self.currentEditor) or not self.currentEditor:\n            self.toast(\"current editor is invalid\", \"Error\")\n            return\n        self.currentEditor.setFocus()\n        document = self.currentEditor.document()\n        name = self.editorList.currentItem().text()\n        text_cursor = self.currentEditor.textCursor()\n        txt = self.getText(name)\n        start = text_cursor.selectionStart()\n        end = text_cursor.selectionEnd()\n        if start == end:\n            self.toast(\"Nothing selected, press Find and try again\")\n            return\n        txt1 = txt[:start]\n        txt2 = txt[end:]\n        newtxt = self.replaceEdit.text()\n        self.on_ComboBox_Replace_Clicked(newtxt)\n        newText = txt1 + newtxt + txt2\n        self.setText(name,newText,f\"replace {txt[start:end]}\")\n        text_cursor.setPosition(end)\n        self.currentEditor.setTextCursor(text_cursor)\n        self.onFindBtnClicked(True)\n\n    def on_ComboBox_Replace_Clicked(self, text):\n        global duplicate_Replace\n        if text not in duplicate_Replace:\n            duplicate_Replace.append(text)\n            duplicate_Replace = sorted(list(set(duplicate_Replace))) # sort\n            self.ComboBox_replace.addItem(text)\n        self.ComboBox_replace.setCurrentText(text)\n        self.replaceEdit.setText(text)\n\n    def on_Reverse_FindReplaceCB_Clicked(self):\n        txtf = self.findEdit.text()\n        txtr = self.replaceEdit.text()\n        self.replaceEdit.setText(txtf)\n        self.on_ComboBox_Replace_Clicked(txtf)\n        self.findEdit.setText(txtr)\n        self.on_ComboBox_Find_Clicked(txtr)\n\n    def onRefreshBtnClicked(self, arg1):\n        self.getEditors()\n        self.toast(f\"Refreshed\",\"Information\",1000,priority=\"low\",log=False)\n        self.editorDict = {}\n        for zz in zip(self.editors, self.parents, self.grandparents):\n            self.editorDict [zz[2].windowTitle()] = zz[0]\n        self.populateList()\n        self.setCurrentEditor()\n\n    def onGotoHomeBtnClicked(self, arg1):\n        self.gotoLine(1)\n\n    def onGotoEndBtnClicked(self, arg1):\n        self.gotoLine(-1, eol=True)\n\n    def gotoLineActionTriggered(self):\n        line = self.getFirstLine()\n        self.gotoLine(line)\n\n    def parseLine(self, line_as_string):\n        try:\n            parsed = int(line_as_string)\n            return parsed\n        except ValueError as ve:\n            self.print(f\"{ve}\",\"Error\")\n            return 0\n\n    def getFirstLine(self):\n        \"\"\"gets first line in the Goto line edit\"\"\"\n        if not self.gotoLineEdit.text():\n            return 0\n        else:\n            lines = self.gotoLineEdit.text().split(',')\n            if lines:\n                return self.parseLine(lines[0])\n            else:\n                self.toast(\"Unable to parse lines\",\"Error\")\n                return 0\n\n    def getGotoLines(self):\n        if not self.gotoLineEdit.text():\n            return []\n        lines = self.gotoLineEdit.text().split(',')\n        parsed = [self.parseLine(line) for line in lines if self.parseLine(line)]\n        return parsed\n\n    def onGotoLineEditTextChanged(self, arg1):\n        \"\"\"save the goto line edit text for each editor\"\"\"\n        name = self.editorList.currentItem().text() if self.editorList.currentItem() else \"\"\n        if not name:\n            return\n        self.gotoLineDict[name] = arg1\n\n    def makeGotoMenu(self):\n        gotoMenu = QtWidgets.QMenu(\"Goto\")\n        self.onRefreshBtnClicked(True)\n        curName = self.editorList.currentItem().text() if self.editorList.count() else \"\"\n        if not curName:\n            self.toast(\"No current editor\",\"Error\")\n\n        lineNumsMenu = QtWidgets.QMenu(\"Line numbers\")\n        lineNums = self.getGotoLines()\n        def makeLambda(x): return lambda: self.gotoLine(x)\n        gotoLineLambdas = [makeLambda(lineNum) for lineNum in lineNums]\n        gotoLineActions = []\n        for ii,lineNum in enumerate(lineNums):\n            gotoLineActions.append(QtWidgets.QAction(f\"Go to line {lineNum}\", mw))\n            gotoLineActions[-1].triggered.connect(gotoLineLambdas[ii])\n            gotoLineActions[-1].setEnabled(len(self.gotoLineEdit.text()) > 0)\n            lineNumsMenu.addAction(gotoLineActions[-1])\n        gotoMenu.addMenu(lineNumsMenu)\n        if not gotoLineLambdas:\n            lineNumsMenu.setEnabled(False)\n\n        #classDefLines = (class name, def/class text, line number)\n        classDefLinesMenu = QtWidgets.QMenu(\"Class/Def lines\")\n        classDefLines = sorted(self.getClassDefLines())\n        classDefLineActions = []\n        classDefSubmenus = []\n        classDefLineLambdas = [makeLambda(cl[2]) for cl in classDefLines]\n        for ii,classDefLine in enumerate(classDefLines):\n            if ii % 25 == 0:\n                classDefSubmenus.append(QtWidgets.QMenu(f\"Start from -- {classDefLine[2]}\"))\n            if \"class\" in classDefLine[1]:\n                classDefLineActions.append(QtWidgets.QAction(f\"{classDefLine[2]}..{classDefLine[1]}\", mw))\n            else: #def line\n                classDefLineActions.append(QtWidgets.QAction(f\"{classDefLine[2]}..({classDefLine[0]}) {classDefLine[1]}\", mw))\n            classDefLineActions[-1].triggered.connect(classDefLineLambdas[ii])\n            classDefSubmenus[-1].addAction(classDefLineActions[-1])\n        for sub in classDefSubmenus:\n            classDefLinesMenu.addMenu(sub)\n        gotoMenu.addMenu(classDefLinesMenu)\n        if not classDefLineLambdas:\n            classDefLinesMenu.setEnabled(False)\n\n        bookmarks = sorted(self.getBookmarks())\n        bookmarksMenu = QtWidgets.QMenu(\"Bookmarks\")\n        toggleBookmarkAction = QtWidgets.QAction(\"Toggle Bookmark current line\", mw)\n        toggleBookmarkAction.triggered.connect(self.toggleBookmark)\n        toggleBookmarkAction.setEnabled(curName != \"\")\n        bookmarksMenu.addAction(toggleBookmarkAction)\n\n        removeAllBookmarksAction = QtWidgets.QAction(\"Remove all bookmarks\", mw)\n        removeAllBookmarksAction.triggered.connect(self.removeAllBookmarks)\n        removeAllBookmarksAction.setEnabled(bool(bookmarks))\n        bookmarksMenu.addAction(removeAllBookmarksAction)\n\n        nextBookmarkAction = QtWidgets.QAction(\"Goto next bookmark\", mw)\n        nextBookmarkAction.triggered.connect(self.nextBookmark)\n        nextBookmarkAction.setEnabled(bool(bookmarks))\n        bookmarksMenu.addAction(nextBookmarkAction)\n\n        previousBookmarkAction = QtWidgets.QAction(\"Goto previous bookmark\", mw)\n        previousBookmarkAction.triggered.connect(self.previousBookmark)\n        previousBookmarkAction.setEnabled(bool(bookmarks))\n        bookmarksMenu.addAction(previousBookmarkAction)\n\n        bookmarksMenu.addSeparator()\n        bookmarkActions = []\n        bookmarkLambdas = [makeLambda(bm[1]) for bm in bookmarks]\n        for ii,bm in enumerate(bookmarks):\n            bookmarkActions.append(QtWidgets.QAction(f\"{bm[0]} ({bm[1]})\", mw))\n            bookmarkActions[-1].triggered.connect(bookmarkLambdas[ii])\n            bookmarksMenu.addAction(bookmarkActions[-1])\n        gotoMenu.addMenu(bookmarksMenu)\n\n        findResults = sorted(self.getFindResults())\n        findResultsMenu = QtWidgets.QMenu(\"Find results\")\n        findResultsSubmenus = []\n        findResultActions = []\n        findResultLambdas = [makeLambda(fr[0]) for fr in findResults]\n        for ii,fr in enumerate(findResults):\n            if ii % 25 == 0:\n                findResultsSubmenus.append(QtWidgets.QMenu(f\"Start from -- {fr[0]}\"))\n            findResultActions.append(QtWidgets.QAction(f\"{fr[0]}..{fr[1]}{fr[2]}{fr[3]}..\", mw))\n            findResultActions[-1].triggered.connect(findResultLambdas[ii])\n            findResultsSubmenus[-1].addAction(findResultActions[-1])\n        for sub in findResultsSubmenus:\n            findResultsMenu.addMenu(sub)\n        gotoMenu.addMenu(findResultsMenu)\n        if not findResults:\n            findResultsMenu.setEnabled(False)\n        else:\n            if self.matchWholeCheckBox.checkState():\n                self.toast(\"Whole words checkbox ignored in Find results menu\",\"Warning\")\n\n        findSelResults = sorted(self.getFindResults(useSelection=True))\n        findSelResultsMenu = QtWidgets.QMenu(\"Find selection results\")\n        findSelResultsSubmenus = []\n        findSelResultActions = []\n        findSelResultLambdas = [makeLambda(fsr[0]) for fsr in findSelResults]\n        for ii,fsr in enumerate(findSelResults):\n            if ii % 25 == 0:\n                findSelResultsSubmenus.append(QtWidgets.QMenu(f\"Start from --{fsr[0]}\"))\n            findSelResultActions.append(QtWidgets.QAction(f\"{fsr[0]}..{fsr[1]}{fsr[2]}{fsr[3]}..\", mw))\n            findSelResultActions[-1].triggered.connect(findSelResultLambdas[ii])\n            findSelResultsSubmenus[-1].addAction(findSelResultActions[-1])\n        for sub in findSelResultsSubmenus:\n            findSelResultsMenu.addMenu(sub)\n        gotoMenu.addMenu(findSelResultsMenu)\n        if not findSelResults:\n            findSelResultsMenu.setEnabled(False)\n        else:\n            if self.matchWholeCheckBox.checkState():\n                self.toast(\"Whole words checkbox ignored in Find selection results menu\",\"Warning\")\n\n        gotoHomeAction = QtWidgets.QAction(\"Home\", mw)\n        gotoHomeAction.triggered.connect(lambda: self.onGotoHomeBtnClicked(True))\n        gotoHomeAction.setEnabled(curName != \"\")\n        gotoMenu.addAction(gotoHomeAction)\n\n        gotoEndAction = QtWidgets.QAction(\"End\", mw)\n        gotoEndAction.triggered.connect(lambda: self.onGotoEndBtnClicked(True))\n        gotoEndAction.setEnabled(curName != \"\")\n        gotoMenu.addAction(gotoEndAction)\n        return gotoMenu\n\n    def onGotoMenuBtnClicked(self, arg1):\n        gotoMenu = self.makeGotoMenu()\n        gotoMenu.exec_(self.gotoMenuBtn.mapToGlobal(QtCore.QPoint()))\n\n    def removeAllBookmarks(self):\n        if not self.currentEditor:\n            return\n        curName = self.editorList.currentItem().text() if self.editorList.currentItem() else \"\"\n        if not curName:\n            self.toast(\"No editor to remove bookmarks from\",\"Error\")\n            return\n        bookmarks = self.getBookmarks()\n        self.setModified(curName, self.currentEditor.toPlainText(),\\\n            \"Remove all bookmarks\", self.getTC(self.currentEditor.textCursor()))\n        for bookmark in bookmarks:\n            self.removeBookmark(bookmark, setModified=False)\n\n    def removeBookmark(self, bookmark, setModified=True):\n        \"\"\"bookmark is a tuple (desc, line)\"\"\"\n        curName = self.editorList.currentItem().text() if self.editorList.currentItem() else \"\"\n        if not curName:\n            self.toast(\"No current editor for bookmarking\",\"Error\")\n            return\n        lines = self.getLines()\n        curLine = bookmark[1]\n        idx = lines[curLine-1].index(BOOKMARK_MARKER)\n        lines[curLine-1] = lines[curLine-1][:idx]\n        plainText = '\\n'.join(lines)\n        if lines[-1] == '':\n            plainText += \"\\n\"\n        if setModified:\n            self.setModified(curName, self.currentEditor.toPlainText(),\"toggle \" + bookmark[0], self.getTC(self.currentEditor.textCursor()))\n        self.currentEditor.setPlainText(plainText)\n        self.gotoLine(curLine)\n\n    def addBookmark(self, bookmark):\n        \"\"\"bookmark is a tuple (desc, line)\"\"\"\n        curName = self.editorList.currentItem().text() if self.editorList.currentItem() else \"\"\n        if not curName:\n            self.toast(\"No current editor for bookmarking\",\"Error\")\n            return\n        lines = self.getLines()\n        curLine = bookmark[1]\n        recul = 1\n        while True:\n            try:\n                lines[curLine-recul] = lines[curLine-recul] + BOOKMARK_MARKER + bookmark[0]\n                break\n            except Exception:\n                recul += 1\n        plainText = '\\n'.join(lines)\n        if lines[-1] == '':\n            plainText += \"\\n\"\n        self.setModified(curName, self.currentEditor.toPlainText(),\"toggle \" + bookmark[0], self.getTC(self.currentEditor.textCursor()))\n        self.currentEditor.setPlainText(plainText)\n        self.gotoLine(curLine)\n\n    def toggleBookmark(self):\n        if not self.currentEditor:\n            return\n        bookmarks = self.getBookmarks()\n        curLine = self.getLineNumberAtCursor()\n        hasBookmark = False\n        for bookmark in bookmarks:\n            if curLine == bookmark[1]:\n                hasBookmark = True\n                self.removeBookmark(bookmark)\n                return\n        #no bookmark on curLine if we get here\n        self.addBookmark(tuple([f\"Bookmark line {curLine}\", curLine]))\n\n    def nextBookmark(self):\n        curName = self.editorList.currentItem().text() if self.editorList.currentItem() else \"\"\n        if not curName:\n            self.toast(\"No current editor for bookmarking\",\"Error\")\n            return\n        curLine = self.getLineNumberAtCursor()\n        bookmarks = self.getBookmarks()\n        for bookmark in bookmarks:\n            if bookmark[1] > curLine:\n                self.gotoLine(bookmark[1])\n                return\n        self.toast(f\"No next bookmark found from {curLine}\",\"Warning\")\n\n    def previousBookmark(self):\n        curName = self.editorList.currentItem().text() if self.editorList.currentItem() else \"\"\n        if not curName:\n            self.toast(\"No current editor for bookmarking\",\"Error\")\n            return\n        curLine = self.getLineNumberAtCursor()\n        bookmarks = reversed(self.getBookmarks())\n        for bookmark in bookmarks:\n            if bookmark[1] < curLine:\n                self.gotoLine(bookmark[1])\n                return\n        self.toast(f\"No previous bookmark found from {curLine}\",\"Warning\")\n\n    def onGotoLineEditReturnPressed(self):\n        lines = self.getGotoLines()\n        if len(lines) == 1:\n            self.gotoLine(lines[0])\n        else:\n            self.onGotoMenuBtnClicked(True)\n\n    def gotoLine(self,line,silent=False,eol=False):\n        self.onRefreshBtnClicked(True)\n        if not shiboken.isValid(self.currentEditor):\n            self.toast(\"No valid current editor\",\"Error\")\n            return\n        document = self.currentEditor.document()\n        if line < 0:\n            txt = self.getText()\n            txt_lines = txt.splitlines()\n            txt_len = len(txt_lines)\n            line = txt_len + 1 + line\n        text_block = document.findBlockByLineNumber(line-1)\n        if not text_block.isValid():\n            self.toast(f\"Cannot goto Line# {line} of {self.editorList.currentItem().text()}\")\n            return\n        text_cursor = self.currentEditor.textCursor()\n        text_cursor.setPosition(text_block.position())\n        if eol:\n            text_cursor.movePosition(QtGui.QTextCursor.EndOfLine)\n        self.currentEditor.setTextCursor(text_cursor)\n        self.currentEditor.centerCursor()\n        if not silent:\n            self.toast(f\"Goto Line #{line} of {self.editorList.currentItem().text()}\",\"Message\")\n\n    def getLines(self,name=None):\n        \"\"\"get plain text as string list\"\"\"\n        txt = self.getText(name)\n        return txt.splitlines()\n\n    def getTrimmedLines(self, name=None):\n        \"\"\"remove all leading whitespace\"\"\"\n        lines = self.getLines(name)\n        lines2 = []\n        for line in lines:\n            lines2.append(line.strip())\n        return lines2\n\n    def getFindResults(self, useSelection=False):\n        lines = self.getTrimmedLines()\n        findResults = []\n        if not shiboken.isValid(self.currentEditor):\n            return []\n        selTxt = self.currentEditor.textCursor().selectedText() if self.currentEditor else \"\"\n        find = self.findEdit.text() if not useSelection else selTxt\n        description_range = 35\n        preContext = 10\n        if not find:\n            return []\n        matchCase = self.matchCaseCheckBox.checkState()\n        if not matchCase:\n            find = find.lower()\n        for ii,line in enumerate(lines):\n            if find in line or bool(not matchCase and find in line.lower()):\n                idx = line.find(find) if matchCase else line.lower().find(find)\n                preDesc = line[:idx]# what comes before the find text\n                desc = line[idx:]\n                if len(preDesc) > preContext:\n                    preDesc = preDesc[-preContext:]\n                if len(desc) > description_range:\n                    desc = desc[:description_range]\n                    desc = line[idx:idx+description_range]\n                findResults.append(tuple([ii+1, preDesc, find, desc[len(find):]]))\n        return findResults\n\n    def getBookmarks(self, trimmed=True):\n        if trimmed:\n            lines = self.getTrimmedLines()\n        else:\n            lines = self.getLines()\n        bookmarks = []\n        for ii,line in enumerate(lines):\n            if BOOKMARK_MARKER in line:\n                descIdx = line.find(BOOKMARK_MARKER) + len(BOOKMARK_MARKER)\n                desc = line[descIdx:].strip() if trimmed else line[descIdx:]\n                if desc:\n                    bookmarks.append(tuple([desc, ii+1]))\n        return bookmarks\n\n    def getClassDefLines(self):\n        \"\"\"tuple(class name, class/def line, line number)\"\"\"\n        lines = self.getTrimmedLines()\n        classDefLines = []\n        curClass = \"\"\n        prevClass = \"\"\n        for ii,line in enumerate(lines):\n            if \"class \" in line and \":\" in line:\n                prevClass = curClass\n                idx = line.find(\"class \")\n                pretext = line[:idx].replace(' ','').replace('#','')\n                idx2 = line.find(\":\", idx)\n                curClass = line[idx + len(\"class \"):idx2] if not pretext else prevClass\n                if \"(\" in curClass and \")\" in curClass:\n                    idx3 = curClass.find(\"(\")\n                    idx4 = curClass.find(\")\",idx3)\n                    if idx4 > idx3:\n                        curClass = curClass[:idx3]\n                    else:\n                        curClass = \"\"\n                classDefLines.append(tuple([curClass, line[idx:idx2], ii+1]))\n            elif \"def \" in line and \":\" in line:\n                idx = line.find(\"def \")\n                idx2 = line.find(\":\", idx)\n                classDefLines.append(tuple([curClass, line[idx:idx2], ii+1]))\n        return classDefLines\n\n    def dragToForum(self, item):\n        \"\"\"make it easier to drag/drop files to the forum\"\"\"\n        macroDir = FreeCAD.getUserMacroDir(True)\n        filename = item.text() if item else \"\"\n        if not filename:\n            return\n        if \"[*]\" in filename:\n            filename = filename[:filename.find(\"[*]\")]\n        path = os.path.join(macroDir, filename)\n        dlg = QtWidgets.QFileDialog(mw)\n        dlg.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)\n        dlg.setOption(QtWidgets.QFileDialog.DontUseNativeDialog)\n        dlg.setWindowTitle(\"Drag file to forum\")\n        dlg.setFileMode(QtWidgets.QFileDialog.ExistingFile)\n        dlg.setNameFilter(os.path.basename(path))\n        model = FileFilterProxyModel(path)\n        dlg.setProxyModel(model)\n        if os.path.exists(path):\n            dlg.setDirectory(os.path.dirname(path))\n            dlg.selectFile(os.path.basename(path))\n            dlg.exec()\n\n    def populateList(self):\n        self.blockSignals = True\n        current = None\n        if not shiboken.isValid(self.editorList):\n            return\n        if self.editorList.count() != 0:\n            current = self.editorList.currentItem().text() if self.editorList.currentItem() else \"\"\n        self.editorList.clear()\n        for k in sorted(self.editorDict.keys()):\n\n            # line original self.editorList.addItem(k)   # commented for display icon : .py, .FCMacro, .txt file\n            if (k[-8:].upper() == \".FCMACRO\") or (k[-11:].upper() == \".FCMACRO[*]\") or (\".FCMACRO[*] -\" in k.upper()):\n                iconItem = pythonFC_icon    # Icon FreeCAD (.FCMacro)\n            elif (k[-3:].upper() == \".PY\") or (k[-6:].upper() == \".PY[*]\") or (\".PY[*] -\" in k.upper()):\n                iconItem = pythonPY_icon    # Icon Python  (.py)\n            else:\n                iconItem = file_Txt_icon    # Icon file_Txt() or other\n            self.editorList.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(QIconFromXPMString(iconItem)),k))\n\n        if current and current in self.editorDict:\n            items = self.editorList.findItems(current, QtCore.Qt.MatchExactly)\n            self.editorList.setCurrentItem(items[0] if items else self.editorList.item(0))\n            pass\n        else:\n            self.editorList.setCurrentRow(0)\n\n        self.setCurrentEditor()\n        self.blockSignals = False\n\n    def print(self,message,type=\"Message\"):\n        if type == \"Message\" or type == \"Information\":\n            FreeCAD.Console.PrintMessage(message+\"\\n\")\n        elif type == \"Error\":\n            FreeCAD.Console.PrintError(message+\"\\n\")\n        elif type == \"Warning\":\n            FreeCAD.Console.PrintWarning(message+\"\\n\")\n\n    def getStandardButtons(self):\n        return int(QtWidgets.QDialogButtonBox.Close)\n\n    def reject(self):\n        FreeCADGui.Control.closeDialog()\n        if FreeCADGui.activeDocument():\n            FreeCADGui.activeDocument().resetEdit()\n\nclass TemplateEditor(QtWidgets.QWidget):\n    def __init__(self, parent=mw, form=None):\n        super(TemplateEditor, self).__init__(parent, QtCore.Qt.Tool)\n        self.form=form\n        self.blockSignals = False\n        self.setWindowTitle(f\"Template editor v{__version__}\")\n        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)\n        self.layout = QtWidgets.QVBoxLayout()\n        self.setLayout(self.layout)\n        self.templateList = QtWidgets.QListWidget()\n        self.templateList.currentItemChanged.connect(self.onTemplateListCurrentItemChanged)\n        self.templateDict = {}\n        filterLine = QtWidgets.QHBoxLayout()\n        self.layout.addLayout(filterLine)\n        self.useFilterCheckBox = QtWidgets.QCheckBox(\"Filter\")\n        self.useFilterCheckBox.setCheckState(QtCore.Qt.Checked)\n        self.useFilterCheckBox.stateChanged.connect(self.onUseFilterCheckBoxStateChanged)\n        filterLine.addWidget(self.useFilterCheckBox)\n        self.filterEdit = QtWidgets.QLineEdit()\n        filterLine.addWidget(self.filterEdit)\n        self.filterEdit.setPlaceholderText(\"Filter text goes here\")\n        self.filterEdit.textChanged.connect(self.onFilterEditTextChanged)\n        self.matchCaseCheckBox = QtWidgets.QCheckBox()\n        self.matchCaseCheckBox.setIcon(QIconFromXPMString(match_case_icon))\n        self.matchCaseCheckBox.stateChanged.connect(self.onMatchCaseCheckBoxStateChanged)\n        filterLine.addWidget(self.matchCaseCheckBox)\n        topLine = QtWidgets.QHBoxLayout()\n        topLine.addWidget(self.templateList)\n        buttonBox = QtWidgets.QVBoxLayout()\n        buttonBox.setAlignment(QtCore.Qt.AlignTop)\n        topLine.addLayout(buttonBox)\n\n        self.plusBtn = QtWidgets.QPushButton()#\"+\"\n        self.plusBtn.setToolTip(\"Adding\")\n        self.plusBtn.setIcon(QIconFromXPMString(plus_Template_icon))\n        self.plusBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        buttonBox.addWidget(self.plusBtn)\n        self.plusBtn.clicked.connect(self.onPlusBtnClicked)\n\n        self.minusBtn = QtWidgets.QPushButton()#\"-\"\n        self.minusBtn.setToolTip(\"Delete\")\n        self.minusBtn.setIcon(QIconFromXPMString(moins_Template_icon))\n        self.minusBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        buttonBox.addWidget(self.minusBtn)\n        self.minusBtn.clicked.connect(self.onMinusBtnClicked)\n\n        self.renameBtn = QtWidgets.QPushButton()#\"Rename\"\n        self.renameBtn.setToolTip(\"Rename\")\n        self.renameBtn.setIcon(QIconFromXPMString(rename_Template_icon))\n        self.renameBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        buttonBox.addWidget(self.renameBtn)\n        self.renameBtn.clicked.connect(self.onRenameBtnClicked)\n\n        editLine = QtWidgets.QHBoxLayout()\n        self.edit = QtWidgets.QPlainTextEdit()\n        editLine.addWidget(self.edit)\n        bottomButtonBox = QtWidgets.QVBoxLayout()\n        bottomButtonBox.setAlignment(QtCore.Qt.AlignTop)\n        editLine.addLayout(bottomButtonBox)\n\n        self.testBtn = QtWidgets.QPushButton()#\"Test\"\n        self.testBtn.setToolTip(\"Test\")\n        self.testBtn.setIcon(QIconFromXPMString(test_Template_icon))\n        self.testBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.testBtn.clicked.connect(self.onTestBtnClicked)\n        bottomButtonBox.addWidget(self.testBtn)\n\n        self.executeBtn = QtWidgets.QPushButton()#\"Execute\"\n        self.executeBtn.setToolTip(\"Execute\")\n        self.executeBtn.setIcon(QIconFromXPMString(execute_Template_icon))\n        self.executeBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.executeBtn.clicked.connect(self.onExecuteBtnClicked)\n        bottomButtonBox.addWidget(self.executeBtn)\n\n        self.executeToClipboardBtn = QtWidgets.QPushButton()#\"Execute to\\nclipboard\"\n        self.executeToClipboardBtn.setToolTip(\"Execute current template, but send text to clipboard\")\n        self.executeToClipboardBtn.setIcon(QIconFromXPMString(execute_Clipboard_Template_icon))\n        self.executeToClipboardBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.executeToClipboardBtn.clicked.connect(self.onExecuteToClipboardBtnClicked)\n        bottomButtonBox.addWidget(self.executeToClipboardBtn)\n\n        self.helpBtn = QtWidgets.QPushButton()#\"Help\"\n        self.helpBtn.setToolTip(\"Help\")\n        self.helpBtn.setIcon(QIconFromXPMString(File_Dialog_Info_View_icon))\n        self.helpBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.helpBtn.clicked.connect(self.onHelpBtnClicked)\n        bottomButtonBox.addWidget(self.helpBtn)\n\n        self.applyBtn = QtWidgets.QPushButton()#\"Apply\"\n        self.applyBtn.setToolTip(\"Apply changes, saves to templates file\")\n        self.applyBtn.setIcon(QIconFromXPMString(save_Template_icon))\n        self.applyBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.applyBtn.clicked.connect(self.onApplyBtnClicked)\n\n        self.acceptBtn = QtWidgets.QPushButton()#\"Accept\"\n        self.acceptBtn.setToolTip(\"Accept and quit\")\n        self.acceptBtn.setIcon(QIconFromXPMString(accept_Template_icon))\n        self.acceptBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.acceptBtn.clicked.connect(self.accept)\n\n        self.rejectBtn = QtWidgets.QPushButton()#\"Reject\"\n        self.rejectBtn.setToolTip(\"Reject and quit\")\n        self.rejectBtn.setIcon(QIconFromXPMString(reject_Template_icon))\n        self.rejectBtn.setMaximumWidth(MAX_ICONIZED_BUTTON_WIDTH)\n        self.rejectBtn.clicked.connect(self.reject)\n\n        self.layout.addLayout(topLine)\n        self.layout.addLayout(editLine)\n        dlgButtonBox = QtWidgets.QHBoxLayout()\n        self.layout.addLayout(dlgButtonBox)\n        self.layout.setAlignment(dlgButtonBox, QtCore.Qt.AlignBottom)\n        self.layout.setAlignment(dlgButtonBox, QtCore.Qt.AlignCenter)\n\n        dlgButtonBox.addWidget(self.applyBtn)\n        dlgButtonBox.addWidget(self.acceptBtn)\n        dlgButtonBox.addWidget(self.rejectBtn)\n\n        self.resize(800,600)\n        self.updateList()\n\n    def onFilterEditTextChanged(self, arg1):\n        self.updateList(fetch=False)\n\n    def onMatchCaseCheckBoxStateChanged(self, arg1):\n        self.updateList(fetch=False)\n\n    def onUseFilterCheckBoxStateChanged(self, arg1):\n        self.updateList(fetch=False)\n\n    def updateList(self, fetch=True):\n        self.templateList.clear()\n        if fetch:\n            self.templateDict = self.form.getTemplateString()\n        self.blockSignals = True\n        items=[]\n        filter = self.filterEdit.text()\n        for k,v in self.templateDict.items():\n            if self.useFilterCheckBox.checkState():\n                if self.matchCaseCheckBox.checkState():\n                    if filter == \"\" or filter in k:\n                        items.append(k)\n                else:\n                    if filter == \"\" or filter.lower() in k.lower():\n                        items.append(k)\n            else:\n                items.append(k)\n        self.templateList.addItems(sorted(items))\n        self.blockSignals = False\n        if self.templateList.count():\n            self.templateList.setCurrentRow(0)\n\n    def setCurrentByName(self, name):\n        if self.templateList.count() == 0:\n            return\n        match = 0\n        for ii in range(self.templateList.count()):\n            if self.templateList.item(ii).text() == name:\n                match = ii\n                break\n        idx = self.templateList.setCurrentRow(match)\n\n    def setCurrentByRow(self, row):\n        if self.templateList.count() == 0:\n            return\n        if self.templateList.count() <= row:\n            self.templateList.setCurrentRow(self.templateList.count()-1)\n        else:\n            self.templateList.setCurrentRow(row)\n\n    def onExecuteToClipboardBtnClicked(self, arg1):\n        \"\"\"test current template\"\"\"\n        curName = self.templateList.currentItem().text() if self.templateList.currentItem() else \"\"\n        if not curName:\n            return\n        txt = self.edit.toPlainText()\n        if not txt:\n            return\n        clipTxt = self.form.testTemplateItem(curName, txt)\n        QtGui.QClipboard().setText(clipTxt)\n        self.form.toast(f\"{curName} to clipboard\",\"Message\")\n\n    def onTestBtnClicked(self,arg1):\n        \"\"\"test current template\"\"\"\n        curName = self.templateList.currentItem().text() if self.templateList.currentItem() else \"\"\n        if not curName:\n            return\n        txt = self.edit.toPlainText()\n        if not txt:\n            return\n        testTxt = \"<pre>\" + self.form.testTemplateItem(curName, txt) + \"</pre>\"\n        QtWidgets.QMessageBox.information(self, f\"{curName}\", testTxt)\n\n    def onExecuteBtnClicked(self, arg1):\n        \"\"\"execute current template\"\"\"\n        curName = self.templateList.currentItem().text() if self.templateList.currentItem() else \"\"\n        if not curName:\n            return\n        txt = self.edit.toPlainText()\n        if not txt:\n            return\n        self.form.testTemplateItem(curName, txt, execute=True)\n\n    def shallowCopy(self, fromDict):\n        toDict = {}\n        for k,v in fromDict.items():\n            toDict[k] = v\n        return toDict\n\n    def onPlusBtnClicked(self, arg1):\n        \"\"\"add a new template item\"\"\"\n        curName = self.templateList.currentItem().text() if self.templateList.currentItem() else \"\"\n        curDict = {}\n        if curName:\n            curDict = self.shallowCopy(self.templateDict[curName])\n        newTemplateName,ok = QtWidgets.QInputDialog.getText(self, \"Add template\",\"Enter name for new template:\")\n        if ok and newTemplateName:\n            if newTemplateName in self.templateDict:\n                self.form.print(f\"{newTemplateName} already exists\",\"Error\")\n                return\n            if not curName:\n                self.templateDict[newTemplateName] = {\"label\" : \"input\",\"name\" : \"input\",\"output\" : \"name = QtGui.QPushButton('label') #QtWidgets.QPushButton('label') for PySide\"}\n            else:\n                self.templateDict[newTemplateName] = curDict\n            self.updateList(fetch=False)\n            self.setCurrentByName(newTemplateName)\n\n    def onMinusBtnClicked(self, arg1):\n        curName = self.templateList.currentItem().text() if self.templateList.currentItem() else \"\"\n        if not curName:\n            return\n        curRow = self.templateList.currentRow()\n        self.templateDict.pop(curName)\n        self.blockSignals = True\n        self.updateList(fetch=False)\n        self.blockSignals = False\n        self.setCurrentByRow(curRow)\n        if self.templateList.count() == 0:\n            self.blockSignals = True\n            self.templateList.addItem(\"template\")\n            self.edit.setPlainText(\"{}\")\n            self.templateDict = {\"template\":{\"label\":\"input\",\"name\":\"input\",\"output\":\"name = QtGui.QPushButton('label') # QtWidgets.QPushButton('label') for PySide\"}}\n            self.blockSignals = False\n            self.setCurrentByRow(0)\n\n    def onHelpBtnClicked(self, arg1):\n        helpText = \"\"\"<pre>\nTemplates are a way to insert text into the current editor\nat the current cursor position.  The templates are stored\nin memory as a python dictionary of dictionaries.  In the\nsimplest case the text is copied directly into the editor,\nbut some text may also be replaced during execution.\n\nThe template item dictionary must contain a key named\n\"output\".  This key contains the text to be inserted.\nIt can also hold some special values:\n\n\"input\" -- user types in value for output in dialog.\n\"input1\" -- like \"input\", but a single line edit.\n\"clipboard\" -- output text comes from clipboard.\n\"selection\" -- output text comes from current selection.\nAny other value means use that value as the output text.\n\nIf \"output\" contains text matching the name of one of\nthe other keys, then that text gets replaced, depending\non the key's value:\n\n'input' -- replacement text from multiple line QInputDialog\n'input1' -- like input, but use single line dialog\n'selection' -- taken from selection in current editor\n'clipboard' -- replacement text is from the system clipboard\n'find' -- replacement text is from the Find QLineEdit\n'replace' -- replacement text is from the Replace QLineEdit\nAny other value means use that value as the replacement text.\n\nThe \"goto\" key, if it exists, positions the cursor before the\ntext is inserted.  The \"goto\" key can have these values:\n\n'input' (or 'input1') -- line is from single line QInputDialog\n'home' -- position cursor at start of line 1\n'end' -- position cursor at end of document\n'current' or '' -- ignore and use current cursor position\n'42' -- example, go to line 42 and insert output there\n'relative:7' -- example, go 7 lines down from current\n'relative:-3' -- example, go 3 lines up from current\n</pre>\n\"\"\"\n        QtWidgets.QMessageBox.information(self, \"\", helpText)#Help\n\n    def onRenameBtnClicked(self, arg1):\n        curName = self.templateList.currentItem().text() if self.templateList.currentItem() else \"\"\n        if not curName:\n            return\n        newName,ok = QtWidgets.QInputDialog.getText(self, \"Editor assisant\", f\"Enter new name for {curName}\",text=curName)\n        if ok:\n            if newName in self.templateDict:\n                self.form.toast(f\"{newName} already in dictionary\",\"Error\")\n                return\n            self.templateDict[newName] = {}\n            for k,v in self.templateDict[curName].items():\n                self.templateDict[newName][k] = v\n            self.templateDict.pop(curName)\n            self.blockSignals = True\n            self.updateList(fetch=False)\n            self.blockSignals = False\n            self.setCurrentByName(newName)\n\n    def updateParameters(self):\n        \"\"\"update parameter string\"\"\"\n        self.form.setTemplateString(self.templateDict)\n\n    def updateDict(self, name, templateItemText):\n        templateItem = json.loads(templateItemText,strict=False)\n        self.templateDict[name] = templateItem\n\n    def onTemplateListCurrentItemChanged(self, current, previous):\n        if not self.templateList.count():\n            return\n        if self.blockSignals:\n            return\n        if previous:\n            self.updateDict(previous.text(), self.edit.toPlainText())\n        if current:\n            self.updateEdit(current.text())\n\n    def updateEdit(self, name):\n        txt = self.formatTemplate(self.templateDict[name])\n        self.edit.setPlainText(txt)\n\n    def formatTemplate(self,template):\n        \"\"\"formats a single dictionary template, returns formatted string\"\"\"\n        formatted = json.dumps(template,indent=0,separators=(','+chr(10),':'+chr(10)))\n        formatted = formatted.replace('\\\\n',chr(10))\n        return formatted\n\n    def onApplyBtnClicked(self, arg1):\n        self.updateDict(self.templateList.currentItem().text(),self.edit.toPlainText())\n        self.updateParameters()\n\n    def accept(self):\n        self.updateDict(self.templateList.currentItem().text(),self.edit.toPlainText())\n        self.updateParameters()\n        self.close()\n\n    def reject(self):\n        self.close()\n\nclass DiffSaver (QtWidgets.QDialog):\n    def __init__(self, parent=mw, form=None, plainText=None, snapText=None, label1=None, label2=None):\n        super(DiffSaver, self).__init__(parent, QtCore.Qt.Tool)\n        self.form=form\n        self.slider=None\n        self.webView=None\n        self.widthSlider=None\n        self.contextCheckBox = None\n        self.numlinesSpinBox = None\n        self.plainText = plainText\n        self.snapText = snapText\n        self.label1 = label1\n        self.label2 = label2\n        self.diff = \"\"\n        self.makeDiff()\n        self.blockSignals = False\n\n    def setMaxWidthString(self, width=None):\n        if not self.webView:\n            return\n        colWidth = width if width else self.width()/2-70\n        MAXWIDTH=f\"{colWidth}\" #chr(123) = {, 125 = }\n        width_string= f\"<style>table td {chr(123)}overflow:auto;max-width:{MAXWIDTH}px;word-wrap:break-word;{chr(125)}</style></head>\"\n        new_diff = self.diff.replace(\"</head>\",width_string)\n        self.webView.setHtml(new_diff)\n\n    def onContextCheckBoxStateChanged(self, arg1):\n        self.makeDiff()\n        self.setMaxWidthString()\n\n    def onNumlinesSpinBoxValueChanged(self, val):\n        self.makeDiff()\n        self.setMaxWidthString()\n\n    def makeDiff(self):\n        \"\"\"make the diff, expensive operation should only be done when necessary\"\"\"\n        d = difflib.HtmlDiff(tabsize=4)\n        numlines2 = 5 if not self.numlinesSpinBox else self.numlinesSpinBox.value()\n        context2 = self.contextCheckBox.checkState() if self.contextCheckBox else True\n        self.diff = d.make_file(fromlines = self.snapText, tolines = self.plainText, fromdesc = self.label1, todesc = self.label2, context=context2, numlines=numlines2)\n\n    def updateTitle(self):\n        if self.widthSlider and self.slider:\n            self.setWindowTitle(f\"Ea v{__version__} Diff Saver zoom:{self.slider.value()}%; Col width: {self.widthSlider.value()}px\")\n\n    def onResize(self, event):\n        if not self.widthSlider:\n            return\n        self.blockSignals = True\n        width = self.width()/2-70\n        self.widthSlider.setValue(width)\n        self.setColWidth(width)\n\n    def onSliderValueChanged(self, value):\n        if self.blockSignals:\n            self.blockSignals = False\n            return\n        if hasattr(self.webView,\"setZoomFactor\"):\n            self.webView.setZoomFactor(value/100.0)\n        self.updateTitle()\n\n    def saveDiffToHtml(self):\n        global setPathLatestDirectory\n        if platform.node() == \"mint\":\n            fname, filter = PySide.QtWidgets.QFileDialog.getSaveFileName(None, \"Save diff to html file\", setPathLatestDirectory, \"*.html\")#PySide Mint\n            filter = filter[filter.find(\".\"):filter.find(\")\")]\n            if filter[-2:] == \".*\":\n                 filter = filter[:-2]\n            fname = fname + filter\n        else:\n            fname, filter =  PySide.QtWidgets.QFileDialog.getSaveFileName(None, \"Save diff to html file\", setPathLatestDirectory, \"*.html\")\n\n        if not fname:\n            return\n\n        pathFile = os.path.dirname(fname) + \"/\"  #1# = C:/Tmp/\n        setPathLatestDirectory = pathFile\n        pg.SetString(\"setPathLatestDirectory\",setPathLatestDirectory)\n\n        with open(fname,\"w\") as outfile:\n            outfile.write(self.diff)\n        self.form.toast(f\"Diff saved to {fname}\",\"Message\")\n\n    def setColWidth(self, value):\n        self.setMaxWidthString(value)\n        self.updateTitle()\n\n    def onWidthSliderValueChanged(self, value):\n        self.setColWidth(value)\n\ndef QIconFromXPMString(xpm_string):\n    xpm = xpm_string.replace(\"\\\"\",\"\").replace(',','').splitlines()[4:-1]\n    for line in reversed(xpm):\n        if line.startswith(\"/*\") and line.endswith(\"*/\"):\n            xpm.pop(xpm.index(line))\n    pixmap = QtGui.QPixmap(xpm)\n    icon = QtGui.QIcon(pixmap)\n    return icon\n\ndef QIconFromStandard(name):\n    ##self.xxxx.setIcon(QIconFromStandard(\"xxxx\"))\n    pixmap = getattr(QtWidgets.QStyle,name)\n    icon = QtWidgets.QPushButton().style().standardIcon(pixmap)\n    return icon\n\ndef showEditorAssistantAsDockWidget(floating = False):\n    dockWidget = mw.findChild(QtGui.QDockWidget,\"Editor assistant dockwidget\")\n    if not dockWidget:\n        dockWidget = QtWidgets.QDockWidget()\n        dockWidget.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)\n        dockWidget.setWindowTitle(f\"Editor assistant v{__version__}\")\n        dockWidget.setObjectName(\"Editor assistant dockwidget\")\n        edit = QtWidgets.QPlainTextEdit()\n        edit.setPlainText(\"Plain Text\")\n        layout = QtWidgets.QVBoxLayout()\n        layout.addWidget(edit)\n        dockWidget.setLayout(layout)\n        mw.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dockWidget)\n    dockWidget.setFloating(floating)\n    dlg = TaskEditorAssistant()\n    dockWidget.setWidget(dlg.form)\n    modelView = mw.findChild(QtGui.QDockWidget,'Model')\n    # taskspanel = mw.findChild(QtGui.QDockWidget,\"Tasks\")\n    if dockWidget and modelView:\n        # dock = mw.tabifyDockWidget(modelView, taskspanel)\n        dock2 = mw.tabifyDockWidget(modelView, dockWidget)\n        modelView.raise_()\n        dockWidget.raise_()\n\ndef showEditorAssistantDialog():\n    '''show the editor assistant dialog'''\n    dlg = TaskEditorAssistant()\n#ori    comboView = mw.findChild(QtGui.QDockWidget,\"Combo View\")\n    comboView = mw.findChild(QtWidgets.QDockWidget,\"Combo View\")\n    tabWidget = None\n    if comboView:\n        tabWidget = comboView.findChild(QtWidgets.QTabWidget)\n    else: #no combo view, so show as a tabbed dock widget\n        showEditorAssistantAsDockWidget(floating=False)\n        return\n\n    if tabWidget:\n        tabWidget.addTab(dlg.form,f\"Editor assistant v{__version__}\")\n        dlg.isTabbed = True\n        tabWidget.setCurrentWidget(dlg.form)\n        if not comboView.isVisible():\n            FreeCAD.Console.PrintWarning(\"Editor assistant: Making Combo View visible\\n\")\n            FreeCAD.Console.PrintMessage(\"Tip: press Alt while executing to open as dockable widget\\n\")\n            comboView.setVisible(True)\n    elif not FreeCADGui.Control.activeDialog():\n        FreeCADGui.Control.showDialog(dlg.form)\n    else:\n        FreeCAD.Console.PrintError(\"Another task dialog is active.  Showing as dockable widget instead.\\n\")\n        showEditorAssistantAsDockWidget()\n\n\n\n\n__icon__=\"\"\"\n/* XPM */\nstatic char *_647719150564[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 7 1 \",\n\"  c black\",\n\". c #EDED1C1C2424\",\n\"X c #2222B1B14C4C\",\n\"o c #FFFFC9C90E0E\",\n\"O c #3F3F4848CCCC\",\n\"+ c #DFDFDFDFDFDF\",\n\"@ c None\",\n/* pixels */\n\"                                                   @@@@@@@@@@@@@\",\n\"                                                   @@@@@@@@@@@@@\",\n\"                                                    @@@@@@@@@@@@\",\n\"                                                     @@@@@@@@@@@\",\n\"    ++++++++++++++++++++++++++++++++++++++++++++      @@@@@@@@@@\",\n\"    ++++++++++++++++++++++++++++++++++++++++++++       @@@@@@@@@\",\n\"    ++++++++++++++++++++++++++++++++++++++++++++        @@@@@@@@\",\n\"    ++++++++++++++++++++++++++++++++++++++++++++   +     @@@@@@@\",\n\"    ++++++++++++++++++++++++++++++++++++++++++++   ++     @@@@@@\",\n\"    ++++++++++++++++++++++++++++++++++++++++++++   +++     @@@@@\",\n\"    ++++++++++++++++++++++++++++++++++++++++++++   ++++     @@@@\",\n\"    ++++++++++++++++++++++++++++++++++++++++++++   +++++     @@@\",\n\"    ++++++++++++++++++++++++++++++++++++++++++++   ++++++     @@\",\n\"    ++++++++++++++++++++++++++++++++++++++++++++   +++++++     @\",\n\"    ++++++++++++++++++++++++++++++++++++++++++++   ++++++++    @\",\n\"    +++++++OOOOOOOOOOOXXXXXXXXXX          ++++++                \",\n\"    +++++++OOOOOOOOOOOXXXXXXXXXX          ++++++                \",\n\"    +++++++OOOOOOOOOOOXXXXXXXXXX          ++++++                \",\n\"    +++++++OOOOOOOOOOOXXXXXXXXXX          ++++++++++++++++++    \",\n\"    +++++++OOOOOOOOOOOXXXXXXXXXX          ++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    +++++++ooooo        ............         XXXXX++++++++++    \",\n\"    +++++++ooooo        ............         XXXXX++++++++++    \",\n\"    +++++++ooooo        ............         XXXXX++++++++++    \",\n\"    +++++++ooooo        ............         XXXXX++++++++++    \",\n\"    +++++++ooooo        ............         XXXXX++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    +++++++     XXXXXXXXXXXXXXOOOOOXXXXXXXXX      ++++++++++    \",\n\"    +++++++     XXXXXXXXXXXXXXOOOOOXXXXXXXXX      ++++++++++    \",\n\"    +++++++     XXXXXXXXXXXXXXOOOOOXXXXXXXXX      ++++++++++    \",\n\"    +++++++     XXXXXXXXXXXXXXOOOOOXXXXXXXXX      ++++++++++    \",\n\"    +++++++     XXXXXXXXXXXXXXOOOOOXXXXXXXXX      ++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    +++++++.......             ooooooOOOOOOOOOOOOO++++++++++    \",\n\"    +++++++.......             ooooooOOOOOOOOOOOOO++++++++++    \",\n\"    +++++++.......             ooooooOOOOOOOOOOOOO++++++++++    \",\n\"    +++++++.......             ooooooOOOOOOOOOOOOO++++++++++    \",\n\"    +++++++.......             ooooooOOOOOOOOOOOOO++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\n\nrunSave_icon = \"\"\"\n/* XPM */\nstatic char *runSave_icon_XPM[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"   c None\",\n\".  c #1A2A01\",\n\"+  c #2E6C9F\",\n\"@  c #3A76AA\",\n\"#  c #3E84B7\",\n\"$  c #5BA900\",\n\"%  c #84E033\",\n\"&  c #FFD63E\",\n\"*  c #FFDF58\",\n\"                                                                \",\n\"                        ##############@@                        \",\n\"                     ##################@@@                      \",\n\"                    ################@#@@@@@                     \",\n\"                   ###############@@@##@@@@@                    \",\n\"                  ###################@@@@@@@@                   \",\n\"                  ####   ###########@@@@@@@@@+                  \",\n\"                 ####     #########@@@@@@@@@@+                  \",\n\"                 ####     ########@@@@@@@@@@++                  \",\n\"                 ####     #######@@@@@@@@@@++++                 \",\n\"                 #####   ####@@@@#@@@@@@@@+++++   ...           \",\n\"                 ###########@#@##@@@@@@@@++++++  .....          \",\n\"                 ##############@@@@@@@@@+++++++ ..$$$..         \",\n\"                  ############@@@@@@@@@@+++++++..$%%%$..        \",\n\"                   ############@@@@@@@@+++++++..$%%%%%$..       \",\n\"                                @@@@@@+++++++..$%%%$%%%$..      \",\n\"             ##################@@@@@@+++++++..$%%%$$$%%%$..     \",\n\"       ################@@@@#@@@@@@@@+++++++..$%%%$$$$$%%%$..    \",\n\"      ################@###@@@@@@@@@+++++++..$%%%$$$$$$$%%%$..   \",\n\"     ####################@@@@@@@@@+++++++..$%%%$$$$$$$$$%%%$..  \",\n\"     ###################@@@@@@@@@@++++++..$%%%$$$$$$$$$$$%%$..  \",\n\"    ###################@@@@@@@@@@++++++..$%%%$$$$$$$$$$$%%$..   \",\n\"   #########.#########@@@@@@@@@@++++++..$%%%$$$$$$$$$$$%%$..    \",\n\"   ########...#####@@@#@@@@@@@@++++++..$%%%$$$$$$$$$$$%%$..**   \",\n\"   #######.....##@#@##@@@@@@@@++++++..$%%%$$$$$$$$$$$%%$..***   \",\n\"  #######..$$$..####@@@@@@@@@++++++..$%%%$$$$$$$$$$$%%$..****   \",\n\"  ######..$%%%$..##@@@@@@@@@@+++++..$%%%$$$$$$$$$$$%%$..******  \",\n\"  #####..$%%%%%$..@@@@@@@@@@+++++..$%%%$$$$$$$$$$$%%$..*******  \",\n\"  ####..$%%%$$%%$..@@@@@@@@+++++..$%%%$$$$$$$$$$$%%$..********  \",\n\"  ###..$%%%$$$$%%$..@@@@@@+++++..$%%%$$$$$$$$$$$%%$..*********  \",\n\"  ##..$%%%$$$$$$%%$..@@@@+++++..$%%%$$$$$$$$$$$%%$..********&&  \",\n\"  #..$%%%$$$$$$$$%%$..       ..$%%%$$$$$$$$$$$%%$..********&&&  \",\n\"  ..$%%%$$$$$$$$$$%%$..*****..$%%%$$$$$$$$$$$%%$..********&&&&  \",\n\"  ..$%%$$$$$$$$$$$$%%$..***..$%%%$$$$$$$$$$$%%$..*******&&&&&&  \",\n\"  #..$%%$$$$$$$$$$$$%%$..*..$%%%$$$$$$$$$$$%%$..*******&&&&&&&  \",\n\"  ##..$%%$$$$$$$$$$$$%%$...$%%%$$$$$$$$$$$%%$..******&&&&&&&&&  \",\n\"  ###..$%%$$$$$$$$$$$$%%$.$%%%$$$$$$$$$$$%%$..******&&&&&&&&&&  \",\n\"  ####..$%%$$$$$$$$$$$$%%$%%%$$$$$$$$$$$%%$..******&&&&&&&&&&&  \",\n\"   ####..$%%$$$$$$$$$$$$%%%%$$$$$$$$$$$%%$..*****&&&&&&&&&&&&&  \",\n\"   #####..$%%$$$$$$$$$$$$%%$$$$$$$$$$$%%$..*****&&&&&&&&&&&&&   \",\n\"    ###@@..$%%$$$$$$$$$$$$$$$$$$$$$$$%%$..****&&&&&&&&&&&&&&&   \",\n\"    ##@@@@..$%%$$$$$$$$$$$$$$$$$$$$$%%$..****&&&&&&&&&&&&&&&&   \",\n\"     @@@@@@..$%%$$$$$$$$$$$$$$$$$$$%%$..****&&&&&&&&&&&&&&&&    \",\n\"     #@@@@@@..$%%$$$$$$$$$$$$$$$$$%%$..***&&&&&&&&&&&&&&&&&     \",\n\"       @@@@@@..$%%$$$$$$$$$$$$$$$%%$..***&&&&&&&&&&&&&&&&&      \",\n\"        @@@@++..$%%$$$$$$$$$$$$$%%$..**&&&&&&&&&&&&&&&&&&       \",\n\"               ..$%%$$$$$$$$$$$%%$..                            \",\n\"                ..$%%$$$$$$$$$%%$..                             \",\n\"                 ..$%%$$$$$$$%%$..*&&&&&&&&&&                   \",\n\"                 *..$%%$$$$$%%$..*&&&&&&&&&&&&                  \",\n\"                 **..$%%$$$%%$..&&&&&&&&&&&&&&&                 \",\n\"                 ***..$%%$%%$..&&&&&&&&&&&&&&&&                 \",\n\"                 ****..$%%%$..&&&&&&&&&   &&&&&                 \",\n\"                 *****..$%$..&&&&&&&&&     &&&&                 \",\n\"                 ******.....&&&&&&&&&&     &&&&                 \",\n\"                 *******...&&&&&&&&&&&     &&&                  \",\n\"                  ******&.&&&&&&&&&&&&&   &&&&                  \",\n\"                  *****&&&&&&&&&&&&&&&&&&&&&&                   \",\n\"                    *&&&&&&&&&&&&&&&&&&&&&&&                    \",\n\"                      &&&&&&&&&&&&&&&&&&&&&                     \",\n\"                        &&&&&&&&&&&&&&&&&                       \",\n\"                          &&&&&&&&&&&&&                         \",\n\"                                                                \",\n\"                                                                \"}\n\n\"\"\"\n\nundo_icon = \"\"\"\n/* XPM */\nstatic char *edit_undo_XPM[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 7 1\",\n\"   c None\",\n\".  c #FF8000\",\n\"+  c #FFFF80\",\n\"@  c #666666\",\n\"#  c #FFFF00\",\n\"$  c #FF8080\",\n\"%  c None\",\n/* pixels */\n\"                                                                \",\n\"                                                                \",\n\"                            ..                                  \",\n\"                            ...                                 \",\n\"                          .....                                 \",\n\"                         ......                                 \",\n\"                        ...+...                                 \",\n\"                        ..++...                                 \",\n\"                      ...+++...                                 \",\n\"                     ...++++...                                 \",\n\"                    ...+++++...                                 \",\n\"                    ..++++++...                                 \",\n\"                  ...+++++++...                                 \",\n\"                ....++++++++...                                 \",\n\"               ...++++++++++...                                 \",\n\"              ...+++++++++++.@.                                 \",\n\"             ...++++++++++++...........                         \",\n\"            ...+++++++++++++.+++++++.....                       \",\n\"           ...++++++++++++++++++++++++++....                    \",\n\"          ...+++++++++++++++++++#+++++++....                    \",\n\"         ...++++++++++++++++++########+++++...                  \",\n\"        ...++++++++++++++++++##########+++++...                 \",\n\"       ...+++++++++++++++++##############++++...                \",\n\"      ....++++++++++++++++################++++..                \",\n\"      ...+++++++++++++++####################+++...              \",\n\"      ....++++++++++++++####################++++...             \",\n\"       ....++++++++++++######################+++#...            \",\n\"         ...+++++++++++#######################++##..            \",\n\"          ...+++++++++##########################++..            \",\n\"           ...+++++++#######++++++++############++..            \",\n\"            ...++++#########++++++++++++########++..            \",\n\"             ....+++########++....++++++########+++.            \",\n\"                ..++++######++.. .....++++#######++...          \",\n\"                ...++++#####++..  .....++++######++...          \",\n\"                 ...++++####++..     ...++++#####++...          \",\n\"                  ...+++####++..      ...+++#####++...          \",\n\"                   ...++++##++..        ..$+++###++...          \",\n\"                    ...++++#++..        ...+++###++...          \",\n\"                     ...++++++..         ..#++###++...          \",\n\"                      ...+++++..         ...++###++...          \",\n\"                        ..++++..          ..++###++...          \",\n\"                        %$.++#.$%   %  %  ..+++##++..           \",\n\"               %    %%  %%$.##.$%%%%%%%%  +.+++#+++.            \",\n\"              %%    %%% %%%....$%%%%%%%% %%.+++#+++.            \",\n\"            %%  %%%%%%%%%%%%....%%%%%%%%%%%.++##++..            \",\n\"           %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.++#++#.. %%         \",\n\"        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.++++++...%%%        \",\n\"        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%..++++...%%%%%        \",\n\"    %%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%..+++++..%%%%%         \",\n\"    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%..++++++.%%%%%%%%%% %%  \",\n\"   %%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%..++++++..%%%%%%%%%%%%%  \",\n\"  %%%%  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%...++++++..%%%%%%% %%%%    \",\n\"     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%..+++++++..%%%%%%%%% %%     \",\n\"     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%..++++++...%%%%%%%%%  %%     \",\n\"    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%..+++++...%%%%%%%%%%%%%%%     \",\n\"    %%%% %%%%%%%%%%%%%%%%%%%%%%%%..++++...%%%%%%%%% %%%%%%      \",\n\"         %%%%%%%%%%%%%%%%%%%%%%%%.......%%%%%%%%%%%%%%% %%      \",\n\"         %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %       \",\n\"         %%  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %           \",\n\"              %%  %%%%%%%%%%%%%%%%%%%%%%%%%%%  %%%              \",\n\"                 %%   %%%%  %%%%%%%% %%%                        \",\n\"                 %%    %%%% %%%%%%%%  %%                        \",\n\"                         %%     %                               \",\n\"                                                                \"\n};\"\"\"\n\nredo_icon = \"\"\"\n/* XPM */\nstatic char *edit_redo_XPM[] = {\n/* format */\n\"64 64 7 1\",\n\"   c None\",\n\".  c #FF8000\",\n\"+  c #FFFF80\",\n\"@  c #666666\",\n\"#  c #FFFF00\",\n\"$  c #FF8080\",\n\"%  c None\",\n/* pixels */\n\"                                                                \",\n\"                                                                \",\n\"                                  ..                            \",\n\"                                 ...                            \",\n\"                                 .....                          \",\n\"                                 ......                         \",\n\"                                 ...+...                        \",\n\"                                 ...++..                        \",\n\"                                 ...+++...                      \",\n\"                                 ...++++...                     \",\n\"                                 ...+++++...                    \",\n\"                                 ...++++++..                    \",\n\"                                 ...+++++++...                  \",\n\"                                 ...++++++++....                \",\n\"                                 ...++++++++++...               \",\n\"                                 .@.+++++++++++...              \",\n\"                         ...........++++++++++++...             \",\n\"                       .....+++++++.+++++++++++++...            \",\n\"                    ....++++++++++++++++++++++++++...           \",\n\"                    ....+++++++#+++++++++++++++++++...          \",\n\"                  ...+++++########++++++++++++++++++...         \",\n\"                 ...+++++##########++++++++++++++++++...        \",\n\"                ...++++##############+++++++++++++++++...       \",\n\"                ..++++################++++++++++++++++....      \",\n\"              ...+++####################+++++++++++++++...      \",\n\"             ...++++####################++++++++++++++....      \",\n\"            ...#+++######################++++++++++++....       \",\n\"            ..##++#######################+++++++++++...         \",\n\"            ..++##########################+++++++++...          \",\n\"            ..++############++++++++#######+++++++...           \",\n\"            ..++########++++++++++++#########++++...            \",\n\"            .+++########++++++....++########+++....             \",\n\"          ...++#######++++..... ..++######++++..                \",\n\"          ...++######++++.....  ..++#####++++...                \",\n\"          ...++#####++++...     ..++####++++...                 \",\n\"          ...++#####+++...      ..++####+++...                  \",\n\"          ...++###+++$..        ..++##++++...                   \",\n\"          ...++###+++...        ..++#++++...                    \",\n\"          ...++###++#..         ..++++++...                     \",\n\"          ...++###++...         ..+++++...                      \",\n\"          ...++###++..          ..++++..                        \",\n\"           ..++##+++..  %  %   %$.#++.$%                        \",\n\"            .+++#+++.+  %%%%%%%%$.##.$%%  %%    %               \",\n\"            .+++#+++.%% %%%%%%%%$....%%% %%%    %%              \",\n\"            ..++##++.%%%%%%%%%%%....%%%%%%%%%%%%  %%            \",\n\"         %% ..#++#++.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%           \",\n\"        %%%...++++++.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%        \",\n\"        %%%%%...++++..%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%        \",\n\"         %%%%%..+++++..%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%    \",\n\"  %% %%%%%%%%%%.++++++..%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    \",\n\"  %%%%%%%%%%%%%..++++++..%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%   \",\n\"    %%%% %%%%%%%..++++++...%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%%%  \",\n\"     %% %%%%%%%%%..+++++++..%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%     \",\n\"     %%  %%%%%%%%%...++++++..%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%     \",\n\"     %%%%%%%%%%%%%%%...+++++..%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    \",\n\"      %%%%%% %%%%%%%%%...++++..%%%%%%%%%%%%%%%%%%%%%%%% %%%%    \",\n\"      %% %%%%%%%%%%%%%%%.......%%%%%%%%%%%%%%%%%%%%%%%%         \",\n\"       %  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%         \",\n\"           % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%         \",\n\"              %%%  %%%%%%%%%%%%%%%%%%%%%%%%%%%  %%              \",\n\"                        %%% %%%%%%%%  %%%%   %%                 \",\n\"                        %%  %%%%%%%% %%%%    %%                 \",\n\"                               %     %%                         \",\n\"                                                                \"\n};\"\"\"\n\nindent_icon = \"\"\"\n/* XPM */\nstatic char *indent_xpm[] = {\n/* format */\n\"64 64 9 1\",\n\"   c None\",\n\".  c black\",\n\"+  c #DFDFDF\",\n\"@  c #3F48CC\",\n\"#  c green\",\n\"$  c red\",\n\"%  c black\",\n\"&  c #ED1C24\",\n\"*  c #E2D9D6\",\n/* pixels */\n\"...................................................             \",\n\"...................................................             \",\n\"....................................................            \",\n\".....................................................           \",\n\"....++++++++++++++++++++++++++++++++++++++++++++......          \",\n\"....++++++++++++++++++++++++++++++++++++++++++++.......         \",\n\"....++++++++++++++++++++++++++++++++++++++++++++........        \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...+.....       \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...++.....      \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...+++.....     \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...++++.....    \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...+++++.....   \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...++++++.....  \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...+++++++..... \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...++++++++.... \",\n\"....+++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++++................\",\n\"....+++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++++................\",\n\"....+++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++++................\",\n\"....+++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++++++++++++++++....\",\n\"....+++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++++++++++++++++....\",\n\"....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....\",\n\"....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....\",\n\"....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....\",\n\"....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++....+++++++++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++.....++++++++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$..++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$...++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$...++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%++....\",\n\"....++++..$$$$$$...++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++++..$$$$$$$...++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++++++..$$$$$$$...+++++++++++++++++++++++++++++++++++++....\",\n\"....+++++++++..$$$$$$...++++++++++++++++++++++++++++++++++++....\",\n\"....+++++++++++..$$$$$$..+++++++++++++++++++++++++++++++++++....\",\n\"....+++++++++++++..$$$$$$..+++++++++++++++++++++++++++++++++....\",\n\"....+++++++++++++++..$$$$$..++++++++++++++++++++++++++++++++....\",\n\"....+++++++++++++++++..$$$$..+++++++++++++++++++++++++++++++....\",\n\"....++++++++++++++++++..$$$$..+++%%%%%%%%%%%%%%%%%%%%%%%%%++....\",\n\"....++++++++++++++++++..$$$$..+++%%%%%%%%%%%%%%%%%%%%%%%%%++....\",\n\"....++++++++++++++++++..$$$$..+++%%%%%%%%%%%%%%%%%%%%%%%%%++....\",\n\"....++++++++++++++++..$$$$$..++++%%%%%%%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++++++++++++++..$$$$$..+++++%%%%%%%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++++++++++++..$$$$$$..+++++++++++++++++++++++++++++++++....\",\n\"....+++++++++++..$$$$$$$..++++++++++++++++++++++++++++++++++....\",\n\"....+++++++++..$$$$$$$..++++++++++++++++++++++++++++++++++++....\",\n\"....+++++++..$$$$$$$$..+++++++++++++++++++++++++++++++++++++....\",\n\"....+++++..$$$$$$$$..+++++++++++++++++++++++++++++++++++++++....\",\n\"....++++..$$$$$$$..+++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$..++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$..+++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++.....+++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%++....\",\n\"....++++...++++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%++....\",\n\"....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....\",\n\"....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....\",\n\"....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....\",\n\"....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....\",\n\"....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....\",\n\"....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....\",\n\"....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\"\n};\"\"\"\n\nindent_Memo_icon = \"\"\"\n/* XPM */\nstatic char *indent_xpm[] = {\n/* format */\n\"64 64 9 1\",\n\"   c None\",\n\".  c black\",\n\"+  c #DFDFDF\",\n\"@  c #3F48CC\",\n\"#  c green\",\n\"$  c red\",\n\"%  c black\",\n\"&  c #ED1C24\",\n\"*  c #E2D9D6\",\n/* pixels */\n\"...................................................             \",\n\"...................................................             \",\n\"....................................................            \",\n\".....................................................           \",\n\"....++++++++++++++++++++++++++++++++++++++++++++......          \",\n\"....++++++++++++++++++++++++++++++++++++++++++++.......         \",\n\"....++++++++++++++++++++++++++++++++++++++++++++........        \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...+.....       \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...++.....      \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...+++.....     \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...++++.....    \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...+++++.....   \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...++++++.....  \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...+++++++..... \",\n\"....++++++++++++++++++++++++++++++++++++++++++++...++++++++.... \",\n\"....+++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++++................\",\n\"....+++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++++................\",\n\"....+++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++++................\",\n\"....+++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++++++++++++++++....\",\n\"....+++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++++++++++++++++....\",\n\"....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"....+++..$$$$$$..++++++++++++++++++++++++++++++++++++++++++++...\",\n\"....+++..$$$$$$..+++++++++++++++++++++++++++++++++++++++++++....\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\"\n};\"\"\"\n\nreplace_icon = \"\"\"\n/* XPM */\nstatic char *_647894170722[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1 \",\n\"  c black\",\n\". c #2B0000\",\n\"X c #2B2B00\",\n\"o c gray17\",\n\"O c #552B2B\",\n\"+ c #3F48CC\",\n\"@ c #C3C3C3\",\n\"# c #FFFFD4\",\n\"$ c None\",\n\"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$@@@@@@@@$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@$$@@@@@@@@$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@$$@@    @@$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@@@@+++++++++++++++++++++++@@$$@@    @@$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@@@++++++++++++++++++++++++@@$$@@    @@$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@@+++++++++++++++++++++++++@@$$@@    @@$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@++++++++++++++++++++++++++@@$$@@    @@$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@++++++++++++++++++++++++++@@$$@@    @@@@@@@@@@@@@$$$\",\n\"$$$$@@@@@@@+++++++++++++++++++++++++++@@$$@@    @@@@@@@@@@@@@$$$\",\n\"$$$$@@@@@@++++++++++++++++++++++++++++@@$$@@               @@$$$\",\n\"$$$$@@@@@+++++++++++@@@@@@@@@@@@@@@@@@@@$$@@               @@$$$\",\n\"$$$$@@@@@++++++++++@@@@@@@@@@@@@@@@@@@@@$$@@               @@$$$\",\n\"$$$$@@@@@+++++++++@@@@@@$$$$$$$$$$$$$$$$$$@@    @@@@@@@@   @@$$$\",\n\"$$$$@@@@@++++++++@@@@@@@$$$$$$$$$$$$$$$$$$@@    @@@@@@@@   @@$$$\",\n\"$$$$@@@@@++++++++@@@@@@@$$$$$$$$$$$$$$$$$$@@    @@@@@@@@   @@#$$\",\n\"$$$$@@@@++++++++++@@@@@@$$$$$$$$$$$$$$$$$$@@    @@@@@@@@   @@#$$\",\n\"$$$$@@@++++++++++++@@@@@$$$$$$$$$$$$$$$$$$@@    @@@@@@@@   @@#$$\",\n\"$$$$@++++++++++++++++@@@$$$$$$$$$$$$$$$$$$@@    @@@@@@@@   @@$$$\",\n\"$$$$@+++++++++++++++++@@$$$$$$$$$$$$$$$$$$@@    @@@@@@@@   @@$$$\",\n\"$$$$@+++++++++++++++++@@$$$$$$$$$$$$$$$$$$@@    @@@@@@@@   @@$$$\",\n\"$$$$@@@++++++++++++@@@@@$$$$$$$$$$$$$$$$$$@@               @@$$$\",\n\"$$$$@@@++++++++++++@@@@@$$$$$$$$$$$$$$$$$$@@               @@$$$\",\n\"$$$$@@@++++++++++++@@@@@$$$$$$$$$$$$$$$$$$@@               @@$$$\",\n\"$$$$@@@@+++++++++++@@@@@$$$$$$$$$$$$$$$$$$@@@@@@@@@@@@@@@@@@@$$$\",\n\"$$$$@@@@++++++++++@@@@@@$$$$$$$$$$$$$$$$$$@@@@@@@@@@@@@@@@@@@$$$\",\n\"$$$$@@@@++++++++++@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@++++++++++@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@++++++++@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@++++++++@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@++++++++@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@++++++@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@++++++@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@++++++@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@++++@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@++++@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@++@@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@@@@@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@@@@@    XO@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@@          .@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@             @@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@               @@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@@      @@@@@     .@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@      @@@@@@      @@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@     .@@@@@@@     @@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@     @@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@     @@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@     @@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@     @@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@     @@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@      @@@@@@@     @@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@@      @@@@@      @@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@@                @@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@              @@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@@           @@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@@@@o    .o@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@@@@@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@@@@@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\"\n};\"\"\"\n\nfind_previous_icon = \"\"\"\n/* XPM */\nstatic char *_647896432515[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 8 1 \",\n\"  c black\",\n\". c #ED1C24\",\n\"X c #22B14C\",\n\"o c #FFC90E\",\n\"O c #3F48CC\",\n\"+ c #7A82DC\",\n\"@ c #DFDFDF\",\n\"# c None\",\n\"################################################################\",\n\"################################################################\",\n\"#######                            #############################\",\n\"######                               ###########################\",\n\"#####   @@@@@@@@@@@@@@@@              ##########################\",\n\"####  @ @@@@@@@@@@@@@@@                 ########################\",\n\"###  @@ @@@@@@@@@@@@@@                   #######################\",\n\"##  @@@ @@@@@@@@@@@@@@       +++++       #######################\",\n\"#  @@@@ @@@@@@@@@@@@@       +++++++       ######################\",\n\"        @@@     XXXXX     ++++++++++      ######################\",\n\"        @@@     XXXX      +++++++++++      #####################\",\n\"  @@@@@@@@@     XXXX     +++++++++++++     #####################\",\n\"  @@@@@@@@@@@@@@@@@      +++++++++++++      ####################\",\n\"  @@@@@@@@@@@@@@@@@     +++++++++++++++     ####################\",\n\"  @@@@@@@@@@@@@@@@@     +++++++++++++++     ####################\",\n\"  @@@@@XXX    ....     +++++++++++++++++     ###################\",\n\"  @@@@@XXX    ....     +++++++++++++++++     ###################\",\n\"  @@@@@@@@@@@@@@@@     +++++++++++++++++     ###################\",\n\"  @@@@@@@@@@@@@@@@     +++++++++++++++++     ###################\",\n\"  @@@@@@@@@@@@@@@@     +++++++++++++++++     ###################\",\n\"  @@@@@   XXXXXOOX     +++++++++++++++++     ###################\",\n\"  @@@@@   XXXXXOOX     +++++++++++++++++     ###################\",\n\"  @@@@@   XXXXXOOX     +++++++++++++++++     ###################\",\n\"  @@@@@@@@@@@@@@@@@     +++++++++++++++     ###############OOO##\",\n\"  @@@@@@@@@@@@@@@@@     +++++++++++++++     ##############OOOOO#\",\n\"  @@@@@@@@@@@@@@@@@     +++++++++++++++     ##############OOOOO#\",\n\"  @@@@@OOOOOOOooo        +++++++++++++      ############OOOOOOO#\",\n\"  @@@@@OOOOOOOooo         +++++++++++      ############OOOOOOOO#\",\n\"  @@@@@@@@@@@@@@@@@@      +++++++++++      ############OOOOOOO##\",\n\"  @@@@@@@@@@@@@@@@@@@      +++++++++      #############OOOOOOO##\",\n\"  @@@@@@@@@@@@@@@@@@@        +++++       ##############OOOOOOO##\",\n\"  @@@@@@@@@@@@@@@@@@@@                   ##############OOOOOOO##\",\n\"                                        ##############OOOOOOOO##\",\n\"                                      ################OOOOOOOO##\",\n\"##########################           #################OOOOOOO###\",\n\"############################       ###################OOOOOOO###\",\n\"#############################     ####################OOOOOOO###\",\n\"#############################     ###################OOOOOOOO###\",\n\"#############################     ###################OOOOOOOO###\",\n\"#############################     ###################OOOOOOOO###\",\n\"#############################     ###################OOOOOOOO###\",\n\"#############################     ##################OOOOOOOO####\",\n\"#############################     #################OOOOOOOOO####\",\n\"#############################     #################OOOOOOOOO####\",\n\"#############################     ###############OOOOOOOOOOO####\",\n\"#############################     #############OOOOOOOOOOOO#####\",\n\"#####################OOO######################OOOOOOOOOOOOO#####\",\n\"##################OOOOOOO####################OOOOOOOOOOOOO######\",\n\"##############OOOOOOOOOOOO##################OOOOOOOOOOOOOO######\",\n\"###########OOOOOOOOOOOOOOO##################OOOOOOOOOOOOO#######\",\n\"########OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO########\",\n\"####OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO########\",\n\"###OOOOOOOOOOOOOOO###OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#########\",\n\"##OOOOOOOOOOOOO#######OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO##########\",\n\"##OOOOOOOOOOOOO#######OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO############\",\n\"###OOOOOOOOOOOOOOO###OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#############\",\n\"####OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO##############\",\n\"#######OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO################\",\n\"###########OOOOOOOOOOOOOOOO#####################################\",\n\"##############OOOOOOOOOOOO######################################\",\n\"#################OOOOOOOO#######################################\",\n\"#####################OOO########################################\",\n\"################################################################\",\n\"################################################################\"\n};\"\"\"\n\nfind_next_icon = \"\"\"\n/* XPM */\nstatic char *_647896407113[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 8 1 \",\n\"  c black\",\n\". c #ED1C24\",\n\"X c #22B14C\",\n\"o c #FFC90E\",\n\"O c #3F48CC\",\n\"+ c #7A82DC\",\n\"@ c #DFDFDF\",\n\"# c None\",\n\"################################################################\",\n\"################################################################\",\n\"#############################           ########################\",\n\"###########################                               ######\",\n\"##########################              @@@@@@@@@@@@@@@@   #####\",\n\"########################                 @@@@@@@@@@@@@@@ @  ####\",\n\"#######################                   @@@@@@@@@@@@@@ @@  ###\",\n\"#######################       +++++       @@@@@@@@@@@@@@ @@@  ##\",\n\"######################       +++++++       @@@@@@@@@@@@@ @@@@  #\",\n\"######################      ++++++++++     XXXXX     @@@        \",\n\"#####################      +++++++++++      XXXX     @@@        \",\n\"#####################     +++++++++++++     XXXX     @@@@@@@@@  \",\n\"####################      +++++++++++++      @@@@@@@@@@@@@@@@@  \",\n\"####################     +++++++++++++++     @@@@@@@@@@@@@@@@@  \",\n\"####################     +++++++++++++++     @@@@@@@@@@@@@@@@@  \",\n\"###################     +++++++++++++++++     ....    XXX@@@@@  \",\n\"###################     +++++++++++++++++     ....    XXX@@@@@  \",\n\"###################     +++++++++++++++++     @@@@@@@@@@@@@@@@  \",\n\"###################     +++++++++++++++++     @@@@@@@@@@@@@@@@  \",\n\"###################     +++++++++++++++++     @@@@@@@@@@@@@@@@  \",\n\"###################     +++++++++++++++++     XOOXXXXX   @@@@@  \",\n\"###################     +++++++++++++++++     XOOXXXXX   @@@@@  \",\n\"###################     +++++++++++++++++     XOOXXXXX   @@@@@  \",\n\"##OOO###############     +++++++++++++++     @@@@@@@@@@@@@@@@@  \",\n\"#OOOOO##############     +++++++++++++++     @@@@@@@@@@@@@@@@@  \",\n\"#OOOOO##############     +++++++++++++++     @@@@@@@@@@@@@@@@@  \",\n\"#OOOOOOO############      +++++++++++++        oooOOOOOOO@@@@@  \",\n\"#OOOOOOOO############      +++++++++++         oooOOOOOOO@@@@@  \",\n\"##OOOOOOO############      +++++++++++      @@@@@@@@@@@@@@@@@@  \",\n\"##OOOOOOO#############      +++++++++      @@@@@@@@@@@@@@@@@@@  \",\n\"##OOOOOOO##############       +++++        @@@@@@@@@@@@@@@@@@@  \",\n\"##OOOOOOO##############                   @@@@@@@@@@@@@@@@@@@@  \",\n\"##OOOOOOOO##############                                        \",\n\"##OOOOOOOO################                                      \",\n\"###OOOOOOO#################           ##########################\",\n\"###OOOOOOO###################       ############################\",\n\"###OOOOOOO####################     #############################\",\n\"###OOOOOOOO###################     #############################\",\n\"###OOOOOOOO###################     #############################\",\n\"###OOOOOOOO###################     #############################\",\n\"###OOOOOOOO###################     #############################\",\n\"####OOOOOOOO##################     #############################\",\n\"####OOOOOOOOO#################     #############################\",\n\"####OOOOOOOOO#################     #############################\",\n\"####OOOOOOOOOOO###############     #############################\",\n\"#####OOOOOOOOOOOO#############     #####OOOO####################\",\n\"#####OOOOOOOOOOOOO######################OOOO####################\",\n\"######OOOOOOOOOOOOO####################OOOOOOOO#################\",\n\"######OOOOOOOOOOOOOO##################OOOOOOOOOOOOO#############\",\n\"#######OOOOOOOOOOOOOOO##############OOOOOOOOOOOOOOOOOO##########\",\n\"########OOOOOOOOOOOOOOO###########OOOOOOOOOOOOOOOOOOOOOOO#######\",\n\"########OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO####\",\n\"#########OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO###OOOOOOOOOOOOOOO###\",\n\"##########OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#######OOOOOOOOOOOOO##\",\n\"############OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#######OOOOOOOOOOOOO##\",\n\"#############OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO###OOOOOOOOOOOOOOO###\",\n\"##############OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO####\",\n\"################OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#######\",\n\"##################OOOOO############OOOOOOOOOOOOOOOOOO###########\",\n\"######################################OOOOOOOOOOOOO#############\",\n\"#######################################OOOOOOOOO################\",\n\"########################################OOOO####################\",\n\"########################################OOOO####################\",\n\"################################################################\"\n};\"\"\"\n\nreplace_all_icon = \"\"\"\n/* XPM */\nstatic char *_647894950477[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1 \",\n\"  c black\",\n\". c #2B0000\",\n\"X c #2B2B00\",\n\"o c gray17\",\n\"O c #552B2B\",\n\"+ c #3F48CC\",\n\"@ c #C3C3C3\",\n\"# c #FFFFD4\",\n\"$ c None\",\n\"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$@@@@@@@@@$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@    @@$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@@@@+++++++++++++++++++++++@@@@@@    @@$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@@@++++++++++++++++++++++++@@@@@@    @@$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@@+++++++++++++++++++++++++@@@@@@    @@$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@++++++++++++++++++++++++++@   @@    @@$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@++++++++++++++++++++++++++@   @@    @@@@@@@@@@@@@$$$\",\n\"$$$$@@@@@@@++++++++++++@@@@@@@@@@@@@@@@   @@    @@@@@@@@@@@@@$$$\",\n\"$$$$@@@@@@+++++++++++++@@@@@              @@               @@$$$\",\n\"$$$$@@@@@+++++++++++@@@@@@@@              @@               @@$$$\",\n\"$$$$@@@@@++++++++++@@@@@@@@@              @@               @@$$$\",\n\"$$$$@@@@@+++++++++@@@@@@@@@@   @@@@@@@@   @@    @@@@@@@@   @@$$$\",\n\"$$$$@@@@@++++++++@@@@@@@@@@@   @@@@@@@@   @@    @@@@@@@@   @@$$$\",\n\"$$$$@@@@@++++++++@@@@@@@@@@@   @@@@@@@@   @@    @@@@@@@@   @@#$$\",\n\"$$$$@@@@++++++++++@@@@@@@@@@   @@@@@@@@   @@    @@@@@@@@   @@#$$\",\n\"$$$$@@@++++++++++++@@@@@@@@@   @@@@@@@@   @@    @@@@@@@@   @@#$$\",\n\"$$$$@++++++++++++++++@@@@@@@   @@@@@@@@   @@    @@@@@@@@   @@$$$\",\n\"$$$$@+++++++++++++++++@@@@@@   @@@@@@@@   @@    @@@@@@@@   @@$$$\",\n\"$$$$@+++++++++++++++++@@@@@@   @@@@@@@@   @@    @@@@@@@@   @@$$$\",\n\"$$$$@@@++++++++++++@@@@@@@@@              @@               @@$$$\",\n\"$$$$@@@++++++++++++@@@@@@@@@              @@               @@$$$\",\n\"$$$$@@@++++++++++++@@@@@@@@@              @@               @@$$$\",\n\"$$$$@@@@+++++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@$$$\",\n\"$$$$@@@@++++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@$$$\",\n\"$$$$@@@@++++++++++@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@++++++++++@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@++++++++@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@++++++++@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@++++++++@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@++++++@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@++++++@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@++++++@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@++++@@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@++++@@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@++@@@@@@@@@@@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$@@@@@@@@@@@@@@     @@@@@@@@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@@@@@@@@@@@@     @@@@@@@@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@@@@@      @     @@@@@@@@@@    XO@@@@@@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@@               @@@@@@@          .@@@@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@                @@@@@@             @@@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@                 @@@@@               @@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@@      @@@@@       @@@@      @@@@@     .@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@      @@@@@@       @@@      @@@@@@      @@$$$$$$$$$$$$$$$$$$\",\n\"$$@@     .@@@@@@@      @@@     .@@@@@@@     @@$$$$$$$$$$$$$$$$$$\",\n\"$$@@     @@@@@@@@@     @@@     @@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@     @@@@@@@@@     @@@     @@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@     @@@@@@@@@     @@@     @@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@     @@@@@@@@@     @@@     @@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@     @@@@@@@@@     @@@     @@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@      @@@@@@@      @@@      @@@@@@@     @@$$$$$$$$$$$$$$$$$$\",\n\"$$@@@      @@@@@       @@@@      @@@@@      @@$$$$$$$$$$$$$$$$$$\",\n\"$$@@@                  @@@@                @@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@                 @@@@@              @@@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@@               @@@@@@@           @@@@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@@@@     . @     @@@@@@@@@o    .o@@@@@@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@@@@@@@@@@@@     @@@@@@@@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$\",\n\"$$@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$$$\",\n\"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\",\n\"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\"\n};\"\"\"\n\nunindent_icon = \"\"\"\n/* XPM */\nstatic char * unindent_xpm[] = {\n/* format */\n\"64 64 9 1\",\n\"   c None\",\n\"z  c #000000\",\n\"+  c #DFDFDF\",\n\"@  c #3F48CC\",\n\"#  c #22B14C\",\n\"x  c red\",\n\"%  c black\",\n\"&  c #ED1C24\",\n\"*  c #E2D9D6\",\n/* pixels */\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz              \",\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz             \",\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz            \",\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz           \",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++zzzzzz          \",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++zzzzzzz         \",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++zzzzzzzz        \",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++zzz+zzzzz       \",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++zzz++zzzzz      \",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++zzz+++zzzzz     \",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++zzz++++zzzzz    \",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++zzz+++++zzzzz   \",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++zzz++++++zzzzz  \",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++zzz+++++++zzzzz \",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++zzz++++++++zzzz \",\n\"zzzz+++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++++zzzzzzzzzzzzzzzz\",\n\"zzzz+++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++++zzzzzzzzzzzzzzzz\",\n\"zzzz+++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++++zzzzzzzzzzzzzzzz\",\n\"zzzz+++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++++++++++++++++zzzz\",\n\"zzzz+++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++++++++++++++++++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++++++++++++++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++++++++++++++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++++++++++++++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++++++++++++++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++++++++++++++zzzz\",\n\"zzzz+++++++++++++++++++++++++++++++++++++++++++++++++zz+++++zzzz\",\n\"zzzz++++%%%%%%%%%%%%%%%%%%%%%%%%%+++++++++++++++++++zzzzz+++zzzz\",\n\"zzzz++++%%%%%%%%%%%%%%%%%%%%%%%%%++++++++++++++++++zzxxzz+++zzzz\",\n\"zzzz++++%%%%%%%%%%%%%%%%%%%%%%%%%++++++++++++++++zzxxxxzz+++zzzz\",\n\"zzzz++++%%%%%%%%%%%%%%%%%%%%%%%%%++++++++++++++zzxxxxxxzz+++zzzz\",\n\"zzzz++++%%%%%%%%%%%%%%%%%%%%%%%%%++++++++++++zzxxxxxxxzz++++zzzz\",\n\"zzzz+++++++++++++++++++++++++++++++++++++++zzxxxxxxxxzz+++++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++++++zzxxxxxxxxzz++++++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++++zzxxxxxxxxzz++++++++zzzz\",\n\"zzzz+++++++++++++++++++++++++++++++++++zzxxxxxxxzz++++++++++zzzz\",\n\"zzzz+++++++++++++++++++++++++++++++++zzxxxxxxxzz++++++++++++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++zzxxxxxxzz++++++++++++++zzzz\",\n\"zzzz++++%%%%%%%%%%%%%%%%%%%%%%%%%++zzxxxxxxzz+++++++++++++++zzzz\",\n\"zzzz++++%%%%%%%%%%%%%%%%%%%%%%%%%++zzxxxxzz+++++++++++++++++zzzz\",\n\"zzzz++++%%%%%%%%%%%%%%%%%%%%%%%%%++zzxxxxxzz++++++++++++++++zzzz\",\n\"zzzz++++%%%%%%%%%%%%%%%%%%%%%%%%%+++zzxxxxxzzz++++++++++++++zzzz\",\n\"zzzz++++%%%%%%%%%%%%%%%%%%%%%%%%%++++zzxxxxxxzz+++++++++++++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++zzxxxxxxxzz+++++++++++zzzz\",\n\"zzzz+++++++++++++++++++++++++++++++++++zzzxxxxxxzzz+++++++++zzzz\",\n\"zzzz+++++++++++++++++++++++++++++++++++++zzzxxxxxxzz++++++++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++++++zzzxxxxxxzz+++++++zzzz\",\n\"zzzz+++++++++++++++++++++++++++++++++++++++zzzzxxxxxxzz+++++zzzz\",\n\"zzzz+++++++++++++++++++++++++++++++++++++++++zzzzxxxxxxzz+++zzzz\",\n\"zzzz++++%%%%%%%%%%%%%%%%%%%%%%%%%++++++++++++++zzzzxxxxzz+++zzzz\",\n\"zzzz++++%%%%%%%%%%%%%%%%%%%%%%%%%+++++++++++++++++zzxxxxzz++zzzz\",\n\"zzzz++++%%%%%%%%%%%%%%%%%%%%%%%%%++++++++++++++++++zzxxxzz++zzzz\",\n\"zzzz++++%%%%%%%%%%%%%%%%%%%%%%%%%+++++++++++++++++++zzxxzz++zzzz\",\n\"zzzz++++%%%%%%%%%%%%%%%%%%%%%%%%%++++++++++++++++++++zzzzz++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++++++++zzz+++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++++++++++++++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++++++++++++++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++++++++++++++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++++++++++++++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++++++++++++++zzzz\",\n\"zzzz++++++++++++++++++++++++++++++++++++++++++++++++++++++++zzzz\",\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\",\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\",\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\",\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\"\n};\"\"\"\n\nsnapshot_icon = \"\"\"\n/* XPM */\nstatic char *_647898900207[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 8 1\",\n\"   c None\",\n\".  c #000000\",\n\"+  c #0A0A0A\",\n\"@  c #302B01\",\n\"#  c #CC0000\",\n\"$  c #888A85\",\n\"%  c #FCE94F\",\n\"&  c #FFFFFF\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                         ............                           \",\n\"                        ..##########..                          \",\n\"                       ..############..                         \",\n\"                       .###........###.                         \",\n\"                      ..##..........##..                        \",\n\"                     +.##..%%%%%%%%..##.+                       \",\n\"           ......   ..###.%%%%%%%%%%.###..                      \",\n\"           .&&&&.  ..###+.%%%&&&&%%%.+###..                     \",\n\"           .&&&&. ..###++.%%%&&&&%%%.++###..                    \",\n\"          .........###+++.%%%%%%%%%%.+++###.........            \",\n\"        ...##########++++++%%%%%%%%++++++##########....         \",\n\"      ...###########++++++++++++++++++++++############..        \",\n\"     ..#####++++++++++++++++++++++++++++++++++++++#####..       \",\n\"    ..####+++++++++++++++++++++++++++++++++++++++++++###..      \",\n\"    .###++++++++++++++++++++++++++++++++++++++++++++++###..     \",\n\"   ..##++++++++++++++++++++++++++++++++++++++++++++++++###.     \",\n\"   .###+++++++++++++++++++++++++++++++++++++++++++++++++##..    \",\n\"   .##++++++++++++++++++++++++++++++++++++++++++++++++++###.    \",\n\"   .##++++++++++++++++++++++#######+++++++++++$$$+$$$++++##.    \",\n\"   .##++++++++++++++++++++###@@@@@###+++++++++$$$+$$+++++##.    \",\n\"   .##++++++++++++++++++###@@@@@@@@@###+++++++$$$+$++++++##.    \",\n\"   .##+++++++++++++++++##@@@@@@@@@@@@@##+++++++++++++++++##.    \",\n\"   .##++++++++++++++++##@@@@@@@@@@@@@@@##++++++++++++++++##.    \",\n\"   .##++++++++++++++++#@@@@@@@@@@@@@@@@@##+++++++++++++++##.    \",\n\"   .##+++++++++++++++##@@@@@@@@@@@@@@@@@@#+++++++++++++++##.    \",\n\"   .##+++++++++++++++#@@@@@@@@+++@@@@@@@@#+++++++++++++++##.    \",\n\"   .##++++++++++++++##@@@@@@+++++++@@@@@@##++++++++++++++##.    \",\n\"   .##++++++++++++++#@@@@@@@+++++++@@@@@@@#++++++++++++++##.    \",\n\"   .##++++++++++++++#@@@@@@+++++++++@@@@@@#++++++++++++++##.    \",\n\"   .##++++++++++++++#@@@@@@+++++++++@@@@@@#++++++++++++++##.    \",\n\"   .##++++++++++++++#@@@@@@+++++++++@@@@@@#++++++++++++++##.    \",\n\"   .##++++++++++++++##@@@@@@+++++++@@@@@@@#++++++++++++++##.    \",\n\"   .##+++++++++++++++#@@@@@@+++++++@@@@@@##++++++++++++++##.    \",\n\"   .##+++++++++++++++##@@@@@@@+++@@@@@@@@#+++++++++++++++##.    \",\n\"   .##++++++++++++++++#@@@@@@@@@@@@@@@@@##+++++++++++++++##.    \",\n\"   .##++++++++++++++++##@@@@@@@@@@@@@@@##++++++++++++++++##.    \",\n\"   .##+++++++++++++++++##@@@@@@@@@@@@@##+++++++++++++++++##.    \",\n\"   .##++++++++++++++++++###@@@@@@@@@###++++++++++++++++++##.    \",\n\"   .##++++++++++++++++++++###@@@@@###++++++++++++++++++++##.    \",\n\"   .##++++++++++++++++++++++#######++++++++++++++++++++++##.    \",\n\"   .##++++++++++++++++++++++++++++++++++++++++++++++++++###.    \",\n\"   .##++++++++++++++++++++++++++++++++++++++++++++++++++##..    \",\n\"   .###+++++++++++++++++++++++++++++++++++++++++++++++++##.     \",\n\"   ..###+++++++++++++++++++++++++++++++++++++++++++++++###.     \",\n\"    ..###+++++++++++++++++++++++++++++++++++++++++++++###..     \",\n\"     ..###++++++++++++++++++++++++++++++++++++++++++####..      \",\n\"      ..######+++++++++++++++++++++++++++++++++++######..       \",\n\"       ..############################################...        \",\n\"        .....#####################################....          \",\n\"            .......................................             \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\nmatch_case_icon = \"\"\"\n/* XPM */\nstatic char *_647901377770[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 3 1 \",\n\"  c black\",\n\"z c #C3C3C3\",\n\"x c None\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxzzzzzzzzzzzzzzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxzzzzzzzzzzzzzzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxzz          zzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxzz           zzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxzz           zzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxzz             zzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxzz             zzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxzz              zzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxzz               zzxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzxxxxx\",\n\"xxxxxxxxxzz               zzxxxxxxxxxxxxzzzzzzzzzzzzzzzzzxxxxxxx\",\n\"xxxxxxxxxzz       z        zzxxxxxxxxxxxzz           zzzzzxxxxxx\",\n\"xxxxxxxxzz        z        zzxxxxxxxxzz                 zzzzxxxx\",\n\"xxxxxxxxzz       zzz       zzxxxxxxxzz                   zzzxxxx\",\n\"xxxxxxxxzz       zzz        zzxxxxxzz                    zzzxxxx\",\n\"xxxxxxxzz        zzz        zzxxxxxzz                     zzxxxx\",\n\"xxxxxxxzz        zzzz       zzxxxxzz         zzzzz        zzxxxx\",\n\"xxxxxxzz        zzzzz        zzxxxxxzzzz    zzzzzzz       zzxxxx\",\n\"xxxxxxzz        zzzzz        zzxxxxxzzzzzzzzzzzzzz        zzxxxx\",\n\"xxxxxxzz        zzzzzz        zzxxxxxxxzzzzzz             zzxxxx\",\n\"xxxxxzz                       zzxxxxxxzzz                 zzxxxx\",\n\"xxxxxzz                       zzxxxxzz                    zzxxxx\",\n\"xxxxxzz                        zzxxzz            zz       zzxxxx\",\n\"xxxxzz                         zzxzz         zzzzzz       zzxxxx\",\n\"xxxxzz                         zzxzz        zzzzzzz       zzxxxx\",\n\"xxxxzz                          zzzz       zzzzzzz        zzxxxx\",\n\"xxxzz                           zzzz        zzzzz         zzxxxx\",\n\"xxxzz        zzzzzzzzzzz        zzzz                      zzxxxx\",\n\"xxxzz        zzzzzzzzzzz         zzz                      zzxxxx\",\n\"xxxzz        zzxxxxxxxzz         zzzz             z        zzxxx\",\n\"xxxzz       zzxxxxxxxxxzz         zzzz           zzz       zzxxx\",\n\"xxxzz       zzxxxxxxxxxzz         zzxxzz       zzzzz       zzxxx\",\n\"xxzzzzzzzzzzzzxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxx\",\n\"xxzzzzzzzzzzzzxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n};\"\"\"\n\nmatch_whole_word_icon = \"\"\"\n/* XPM */\nstatic char *_647901969918[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 3 1 \",\n\"  c black\",\n\"z c #C3C3C3\",\n\"x c None\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\",\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\",\n\"zz                                                            zz\",\n\"zz                                                            zz\",\n\"zz                                                            zz\",\n\"zz                                                            zz\",\n\"zz                                                            zz\",\n\"zz                                                            zz\",\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\",\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxzzzzzzzzzzzzzzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxzzzzzzzzzzzzzzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxzz          zzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxzz           zzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxzz           zzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxzz             zzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxzz             zzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxzz              zzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxzz               zzxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzxxxxx\",\n\"xxxxxxxxxzz               zzxxxxxxxxxxxxzzzzzzzzzzzzzzzzzxxxxxxx\",\n\"xxxxxxxxxzz       z        zzxxxxxxxxxxxzz           zzzzzxxxxxx\",\n\"xxxxxxxxzz        z        zzxxxxxxxxzz                 zzzzxxxx\",\n\"xxxxxxxxzz       zzz       zzxxxxxxxzz                   zzzxxxx\",\n\"xxxxxxxxzz       zzz        zzxxxxxzz                    zzzxxxx\",\n\"xxxxxxxzz        zzz        zzxxxxxzz                     zzxxxx\",\n\"xxxxxxxzz        zzzz       zzxxxxzz         zzzzz        zzxxxx\",\n\"xxxxxxzz        zzzzz        zzxxxxxzzzz    zzzzzzz       zzxxxx\",\n\"xxxxxxzz        zzzzz        zzxxxxxzzzzzzzzzzzzzz        zzxxxx\",\n\"xxxxxxzz        zzzzzz        zzxxxxxxxzzzzzz             zzxxxx\",\n\"xxxxxzz                       zzxxxxxxzzz                 zzxxxx\",\n\"xxxxxzz                       zzxxxxzz                    zzxxxx\",\n\"xxxxxzz                        zzxxzz            zz       zzxxxx\",\n\"xxxxzz                         zzxzz         zzzzzz       zzxxxx\",\n\"xxxxzz                         zzxzz        zzzzzzz       zzxxxx\",\n\"xxxxzz                          zzzz       zzzzzzz        zzxxxx\",\n\"xxxzz                           zzzz        zzzzz         zzxxxx\",\n\"xxxzz        zzzzzzzzzzz        zzzz                      zzxxxx\",\n\"xxxzz        zzzzzzzzzzz         zzz                      zzxxxx\",\n\"xxxzz        zzxxxxxxxzz         zzzz             z        zzxxx\",\n\"xxxzz       zzxxxxxxxxxzz         zzzz           zzz       zzxxx\",\n\"xxxzz       zzxxxxxxxxxzz         zzxxzz       zzzzz       zzxxx\",\n\"xxzzzzzzzzzzzzxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxx\",\n\"xxzzzzzzzzzzzzxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxx\",\n\"xxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\",\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\",\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\",\n\"zz                                                            zz\",\n\"zz                                                            zz\",\n\"zz                                                            zz\",\n\"zz                                                            zz\",\n\"zz                                                            zz\",\n\"zz                                                            zz\",\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\",\n\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n};\"\"\"\n\nhome_icon = \"\"\"\n/* XPM */\nstatic char *_649035328466[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 3 1 \",\n\"  c black\",\n\". c #C3C3C3\",\n\"X c None\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX      XXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXX        XXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXX          XXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXX            XXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXX              XXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXX       ..       XXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXX        ....        XXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXX        ......        XXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXX        ........        XXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXX        ..........        XXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXX        ............        XXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXX       ................       XXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXX       ..................       XXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXX        ....................        XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX        ......................        XXXXXXXXXXXXX\",\n\"XXXXXXXXXXXX        ........................        XXXXXXXXXXXX\",\n\"XXXXXXXXXXX        ..........................        XXXXXXXXXXX\",\n\"XXXXXXXXXX        ............................        XXXXXXXXXX\",\n\"XXXXXXXXX       ................................       XXXXXXXXX\",\n\"XXXXXXXX       ..................................       XXXXXXXX\",\n\"XXXXXX        ....................................        XXXXXX\",\n\"XXXXX        ......................................        XXXXX\",\n\"XXXX        ........................................        XXXX\",\n\"XXX                                                          XXX\",\n\"XX                                                            XX\",\n\"XX                                                            XX\",\n\"XX                                                            XX\",\n\"XXX                                                          XXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX     ...........................     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX                                     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX                                     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX                                     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX                                     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXX                                     XXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\n};\"\"\"\n\nend_icon = \"\"\"\n/* XPM */\nstatic char *_649036163438[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 8 1 \",\n\"  c black\",\n\". c #ED1C24\",\n\"X c #22B14C\",\n\"o c #FFC90E\",\n\"O c #3F48CC\",\n\"+ c red\",\n\"@ c #DFDFDF\",\n\"# c None\",\n\"################################################################\",\n\"################################################################\",\n\"#####++++++++++++++++++++++++++++++++++++++++++++++++++++#######\",\n\"####++++++++++++++++++++++++++++++++++++++++++++++++++++++######\",\n\"####+++++++++++++++++++++++++++++++++++++++++++++++++++++++#####\",\n\"####++++++++++++++++++++++++++++++++++++++++++++++++++++++++####\",\n\"#####+++++++++++++++++++++++++++++++++++++++++++++++++++++++####\",\n\"#####+++++++++++++++++++++++++++++++++++++++++++++++++++++++####\",\n\"#####################################################+++++++####\",\n\"#####################################################+++++++####\",\n\"#####################################################+++++++####\",\n\"###                                      ############+++++++####\",\n\"###                                       ###########+++++++####\",\n\"###                                        ##########+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@    ##########+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@      ########+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @    #######+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@   #######+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@    #####+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@    ####+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@   ####+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@@   ###+++++++####\",\n\"###   @@@@@OOOOOOOOXXXXXXXX       @@@@@            ##+++++++####\",\n\"###   @@@@@OOOOOOOOXXXXXXXX       @@@@@            ##+++++++####\",\n\"###   @@@@@OOOOOOOOXXXXXXXX       @@@@@@@@@@@@@@   ##+++++++####\",\n\"###   @@@@@OOOOOOOOXXXXXXXX       @@@@@@@@@@@@@@   ##+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   ##+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   ##+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   ##+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   ##+++++++####\",\n\"###   @@@@@oooo      .........       XXX@@@@@@@@   ##+++++++####\",\n\"###   @@@@@oooo      .........       XXX@@@@@@@@   ##+++++++####\",\n\"###   @@@@@oooo      .........       XXX@@@@@@@@   ##+++++++####\",\n\"###   @@@@@oooo      .........       XXX@@@@@@@@   ##+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   ##+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   ##+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   ##+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   ##+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   ##+++++++####\",\n\"###   @@@@@    XXXXXXXXXXOOOOXXXXXXX    @@@@@@@@   ##+++++++####\",\n\"###   @@@@@    XXXXXXXXXXOOOOXXXXXXX    @@@@@@@@   ##+++++++####\",\n\"###   @@@@@    XXXXXXXXXXOOOOXXXXXXX    @@@@@@@@   ##+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   ##+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++++@   ##+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++++@   ##+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++++@@   ##+++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++++@@@   ##+++++++####\",\n\"###   @@@@@.....          oooooOOOOOOOO+++++@@@@   ##+++++++####\",\n\"###   @@@@@.....          oooooOOOOOOO++++++++++++++++++++++####\",\n\"###   @@@@@.....          oooooOOOOOO+++++++++++++++++++++++####\",\n\"###   @@@@@.....          oooooOOOOOO+++++++++++++++++++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++++++++++++++++++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++++++++++++++++++++++####\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++++@@@@   #############\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++++@@@   #############\",\n\"###   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++++@@   #############\",\n\"###                                       ++++     #############\",\n\"###                                        +++     #############\",\n\"###                                                #############\",\n\"################################################################\",\n\"################################################################\",\n\"################################################################\",\n\"################################################################\",\n\"################################################################\"\n};\"\"\"\n\ntoggle_bookmark_icon = \"\"\"\n/* XPM */\nstatic char *_649037028270[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 3 1 \",\n\"  c black\",\n\". c #C3C3C3\",\n\"X c None\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXX............................................XXXXXXXXXX\",\n\"XXXXXXXXXX............................................XXXXXXXXXX\",\n\"XXXXXXXXXX............................................XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                                      ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                   .                  ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                  ...                 ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                 .....                ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                 .....                ...XXXXXXXXXX\",\n\"XXXXXXXXXX...                ...X...               ...XXXXXXXXXX\",\n\"XXXXXXXXXX...               ....X....              ...XXXXXXXXXX\",\n\"XXXXXXXXXX...               ...XXX...              ...XXXXXXXXXX\",\n\"XXXXXXXXXX...              ....XXX....             ...XXXXXXXXXX\",\n\"XXXXXXXXXX...              ...XXXXX...             ...XXXXXXXXXX\",\n\"XXXXXXXXXX...             ...XXXXXXX...            ...XXXXXXXXXX\",\n\"XXXXXXXXXX...            ....XXXXXXX....           ...XXXXXXXXXX\",\n\"XXXXXXXXXX...           ....XXXXXXXXX...           ...XXXXXXXXXX\",\n\"XXXXXXXXXX...           ....XXXXXXXXX....          ...XXXXXXXXXX\",\n\"XXXXXXXXXX...          ....XXXXXXXXXXX................XXXXXXXXXX\",\n\"XXXXXXXXXX................XXXXXXXXXXXX................XXXXXXXXXX\",\n\"XXXXXXXXXX................XXXXXXXXXXXXX...............XXXXXXXXXX\",\n\"XXXXXXXXXX...............XXXXXXXXXXXXXXX..............XXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\n};\"\"\"\n\nnext_bookmark_icon = \"\"\"\n/* XPM */\nstatic char *_649037522124[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 5 1 \",\n\"  c black\",\n\". c red\",\n\"X c darkorange\",\n\"o c #C3C3C3\",\n\"O c None\",\n\"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\",\n\"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\",\n\"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\",\n\"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\",\n\"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\",\n\"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\",\n\"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\",\n\"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\",\n\"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\",\n\"OOOOOOOOOOooooooooooooooooooooooooooooooooooooooooooooOOOOOOOOOO\",\n\"OOOOOOOOOOooooooooooooooooooooooooooooooooooooooooooooOOOOOOOOOO\",\n\"OOOOOOOOOOooooooooooooooooooooooooooooooooooooooooooooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                                      oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                                      oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                                      oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                                      oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                                      oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                                      oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                                      oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                                           oooOOOOO\",\n\"OOOOOOOOOOooo                                ...        oooOOOOO\",\n\"OOOOOOOOOOooo                                ......     oooOOOOO\",\n\"OOOOOOOOOOooo                                .........  oooOOOOO\",\n\"OOOOOOOOOOooo              ................................OOOOO\",\n\"OOOOOOOOOOooo             ......................XXX.........OOOO\",\n\"OOOOOOOOOOooo             ......................XXXXXX.........O\",\n\"OOOOOOOOOOooo             ...XXXXXXXXXXXXXXXXXXXXXXXXXXX........\",\n\"OOOOOOOOOOooo             ...XXXXXXXXXXXXXXXXXXXXXXXXXXX........\",\n\"OOOOOOOOOOooo             ...XXXXXXXXXXXXXXXXXXXXXXXXXXX........\",\n\"OOOOOOOOOOooo             ...XXXXXXXXXXXXXXXXXXXXXXXXXXX........\",\n\"OOOOOOOOOOooo             ......................XXXXXX.........O\",\n\"OOOOOOOOOOooo             ......................XXX.........OOOO\",\n\"OOOOOOOOOOooo              ................................OOOOO\",\n\"OOOOOOOOOOooo                                .........  oooOOOOO\",\n\"OOOOOOOOOOooo                                ......     oooOOOOO\",\n\"OOOOOOOOOOooo                                 ..        oooOOOOO\",\n\"OOOOOOOOOOooo                                           oooOOOOO\",\n\"OOOOOOOOOOooo                                      oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                                      oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                                      oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                                      oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                   o                  oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                  ooo                 oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                 ooooo                oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                 ooooo                oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo                oooOooo               oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo               ooooOoooo              oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo               oooOOOooo              oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo              ooooOOOoooo             oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo              oooOOOOOooo             oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo             oooOOOOOOOooo            oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo            ooooOOOOOOOoooo           oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo           ooooOOOOOOOOOooo           oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo           ooooOOOOOOOOOoooo          oooOOOOOOOOOO\",\n\"OOOOOOOOOOooo          ooooOOOOOOOOOOOooooooooooooooooOOOOOOOOOO\",\n\"OOOOOOOOOOooooooooooooooooOOOOOOOOOOOOooooooooooooooooOOOOOOOOOO\",\n\"OOOOOOOOOOooooooooooooooooOOOOOOOOOOOOOoooooooooooooooOOOOOOOOOO\",\n\"OOOOOOOOOOoooooooooooooooOOOOOOOOOOOOOOOooooooooooooooOOOOOOOOOO\",\n\"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\",\n\"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\",\n\"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\",\n\"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\",\n\"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\",\n\"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\"\n};\"\"\"\n\nremove_all_bookmarks_icon = \"\"\"\n/* XPM */\nstatic char *_649039201346[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 4 1 \",\n\"  c black\",\n\". c #ED1C24\",\n\"X c #C3C3C3\",\n\"o c None\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooo...ooooooooooooooooooooooooooooooooooooooooooooooooo.....ooo\",\n\"oooo....ooooooooooooooooooooooooooooooooooooooooooooooo......ooo\",\n\"oooo.....ooooooooooooooooooooooooooooooooooooooooooooo.......ooo\",\n\"oooo......ooooooooooooooooooooooooooooooooooooooooooo.......oooo\",\n\"oooo.......ooooooooooooooooooooooooooooooooooooooooo.......ooooo\",\n\"ooooo.......XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.......oooooo\",\n\"oooooo.......XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.......ooooooo\",\n\"ooooooo.......XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.......oooooooo\",\n\"oooooooo.......                                 .......ooooooooo\",\n\"ooooooooo.......                               .......oooooooooo\",\n\"oooooooooo.......                             .......Xoooooooooo\",\n\"ooooooooooX.......                           .......XXoooooooooo\",\n\"ooooooooooXX.......                         .......XXXoooooooooo\",\n\"ooooooooooXXX.......                       ....... XXXoooooooooo\",\n\"ooooooooooXXX .......                     .......  XXXoooooooooo\",\n\"ooooooooooXXX  .......                   .......   XXXoooooooooo\",\n\"ooooooooooXXX   .......                 .......    XXXoooooooooo\",\n\"ooooooooooXXX    .......               .......     XXXoooooooooo\",\n\"ooooooooooXXX     .......             .......      XXXoooooooooo\",\n\"ooooooooooXXX      .......           .......       XXXoooooooooo\",\n\"ooooooooooXXX       .......         .......        XXXoooooooooo\",\n\"ooooooooooXXX        .......       .......         XXXoooooooooo\",\n\"ooooooooooXXX         .......     .......          XXXoooooooooo\",\n\"ooooooooooXXX          .......   .......           XXXoooooooooo\",\n\"ooooooooooXXX           ....... .......            XXXoooooooooo\",\n\"ooooooooooXXX            .............             XXXoooooooooo\",\n\"ooooooooooXXX             ...........              XXXoooooooooo\",\n\"ooooooooooXXX              .........               XXXoooooooooo\",\n\"ooooooooooXXX               .......                XXXoooooooooo\",\n\"ooooooooooXXX              .........               XXXoooooooooo\",\n\"ooooooooooXXX             ...........              XXXoooooooooo\",\n\"ooooooooooXXX            .............             XXXoooooooooo\",\n\"ooooooooooXXX           ....... .......            XXXoooooooooo\",\n\"ooooooooooXXX          .......   .......           XXXoooooooooo\",\n\"ooooooooooXXX         .......     .......          XXXoooooooooo\",\n\"ooooooooooXXX        .......       .......         XXXoooooooooo\",\n\"ooooooooooXXX       .......         .......        XXXoooooooooo\",\n\"ooooooooooXXX      .......      X    .......       XXXoooooooooo\",\n\"ooooooooooXXX     .......      XXX    .......      XXXoooooooooo\",\n\"ooooooooooXXX    .......      XXXXX    .......     XXXoooooooooo\",\n\"ooooooooooXXX   .......       XXXXX     .......    XXXoooooooooo\",\n\"ooooooooooXXX  .......       XXXoXXX     .......   XXXoooooooooo\",\n\"ooooooooooXXX .......       XXXXoXXXX     .......  XXXoooooooooo\",\n\"ooooooooooXXX.......        XXXoooXXX      ....... XXXoooooooooo\",\n\"ooooooooooXX.......        XXXXoooXXXX      .......XXXoooooooooo\",\n\"ooooooooooX.......         XXXoooooXXX       .......XXoooooooooo\",\n\"oooooooooo.......         XXXoooooooXXX       .......Xoooooooooo\",\n\"ooooooooo.......         XXXXoooooooXXXX       .......oooooooooo\",\n\"oooooooo.......         XXXXoooooooooXXX        .......ooooooooo\",\n\"ooooooo.......          XXXXoooooooooXXXX        .......oooooooo\",\n\"oooooo.......          XXXXoooooooooooXXXXXXXXXXXX.......ooooooo\",\n\"ooooo.......XXXXXXXXXXXXXXooooooooooooXXXXXXXXXXXXX.......oooooo\",\n\"oooo.......XXXXXXXXXXXXXXXoooooooooooooXXXXXXXXXXXXX.......ooooo\",\n\"oooo......XXXXXXXXXXXXXXXoooooooooooooooXXXXXXXXXXXXX.......oooo\",\n\"oooo.....ooooooooooooooooooooooooooooooooooooooooooooo.......ooo\",\n\"oooo....ooooooooooooooooooooooooooooooooooooooooooooooo......ooo\",\n\"oooo...ooooooooooooooooooooooooooooooooooooooooooooooooo.....ooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\"\n};\"\"\"\n\nreverse_find_replace_icon = \"\"\"\n/* XPM */\nstatic char * reverse_find_replace_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 5 1\",\n\"   c None\",\n\".  c #A70002\",\n\"+  c #EF2B29\",\n\"@  c #4E990D\",\n\"#  c #8AE138\",\n\"                                                                \",\n\"                                                                \",\n\"                               .........                        \",\n\"                             .............                      \",\n\"                            ..+++++++++++....                   \",\n\"                           ..+++++++++++++++..                  \",\n\"                          ..+++++++++++++++++..                 \",\n\"                         ..+++++++++++++++++++..                \",\n\"                        ..+++++++++++++++++++++..               \",\n\"                       ..+++++++++++++++++++++++..              \",\n\"                      ..+++........++++++++++++++..             \",\n\"                      ..++..      ..+++++++++++++..             \",\n\"                     ..++..        ..+++++++++++++..            \",\n\"                     .++..          ..+++++++++++++.            \",\n\"                     .++..           ..++++++++++++..           \",\n\"                     .++.             ..+++++++++++..           \",\n\"                     ....             ..++++++++++++.           \",\n\"                                       .++++++++++++.           \",\n\"                                       .++++++++++++.           \",\n\"                              ..........++++++++++++.           \",\n\"                              .+++++++++++++++++++++........... \",\n\"                              .+++++++++++++++++++++........... \",\n\"                              ..+++++++++++++++++++++++++++++.. \",\n\"                               ..+++++++++++++++++++++++++++..  \",\n\"                                ..+++++++++++++++++++++++++..   \",\n\"                                 ..+++++++++++++++++++++++..    \",\n\"                 @@               ..+++++++++++++++++++++..     \",\n\"                @@@@               ..+++++++++++++++++++..      \",\n\"               @@##@@               ..+++++++++++++++++..       \",\n\"              @@####@@               ..+++++++++++++++..        \",\n\"             @@######@@               ..+++++++++++++..         \",\n\"            @@########@                ..+++++++++++..          \",\n\"           @@#########@@                ..+++++++++..           \",\n\"          @@###########@@                .++++++++..            \",\n\"         @@#############@@               ..++++++..             \",\n\"        @@###############@@               ..++++..              \",\n\"       @@#################@@               ..++..               \",\n\"      @@###################@@               ....                \",\n\"     @@#####################@@               ..                 \",\n\"    @@#######################@@                                 \",\n\"   @@#########################@@                                \",\n\"  @@###########################@@                               \",\n\" @@#############################@@                              \",\n\" @@@@@@@@@@@#####################@                              \",\n\" @@@@@@@@@@@#####################@                              \",\n\"           @############@@@@@@@@@@                              \",\n\"           @############@                                       \",\n\"           @############@                                       \",\n\"           @############@@             @@@@                     \",\n\"           @@###########@@             @##@                     \",\n\"           @@############@@           @@##@                     \",\n\"            @#############@@          @@##@                     \",\n\"            @@#############@@        @@##@@                     \",\n\"             @@#############@@      @@##@@                      \",\n\"             @@##############@@@@@@@@###@@                      \",\n\"              @@#######################@@                       \",\n\"               @@#####################@@                        \",\n\"                @@###################@@                         \",\n\"                 @@#################@@                          \",\n\"                  @@###############@@                           \",\n\"                   @@@@###########@@                            \",\n\"                      @@@@@@@@@@@@@                             \",\n\"                        @@@@@@@@@                               \",\n\"                                                                \"\n};\"\"\"\n\nexecute_Template_icon = \"\"\"\n/* XPM */\nstatic char * execute_Template_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 5 1\",\n\"   c None\",\n\".  c #192A02\",\n\"+  c #5AA909\",\n\"@  c #7CD124\",\n\"#  c #85E033\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                  ...           \",\n\"                                                 .....          \",\n\"                                                ..+++..         \",\n\"                                               ..+###+..        \",\n\"                                              ..+#####+..       \",\n\"                                             ..+###+###+..      \",\n\"                                            ..+###+++###+..     \",\n\"                                           ..+###+++++###+..    \",\n\"                                          ..+###+++++++###+..   \",\n\"                                         ..+###+++++++++###+..  \",\n\"                                        ..+###+++++++++++##+..  \",\n\"                                       ..+###+++++++++++##+..   \",\n\"            .                         ..+###+++++++++++##+..    \",\n\"           ...                       ..+###+++++++++++##+..     \",\n\"          .....                     ..+###+++++++++++##+..      \",\n\"         ..+++..                   ..+###+++++++++++##+..       \",\n\"        ..+###+..                 ..+###+++++++++++##+..        \",\n\"       ..+#####+..               ..+###+++++++++++##+..         \",\n\"      ..+###++##+..             ..+###+++++++++++##+..          \",\n\"     ..+###++++##+..           ..+###+++++++++++##+..           \",\n\"    ..+###++++++##+..         ..+###+++++++++++##+..            \",\n\"   ..+###++++++++##+..       ..+###+++++++++++##+..             \",\n\"  ..+###++++++++++##+..     ..+###+++++++++++##+..              \",\n\"  ..+##++++++++++++##+..   ..+###+++++++++++##+..               \",\n\"   ..+##++++++++++++##+.. ..+###+++++++++++##+..                \",\n\"    ..+##++++++++++++##+...+###+++++++++++##+..                 \",\n\"     ..+##++++++++++++##+.+###+++++++++++##+..                  \",\n\"      ..+##++++++++++++##+###+++++++++++##+..                   \",\n\"       ..+##++++++++++++####+++++++++++##+..                    \",\n\"        ..+##++++++++++++##+++++++++++##+..                     \",\n\"         ..+##+++++++++++++++++++++++##+..                      \",\n\"          ..+##+++++++++++++++++++++##+..                       \",\n\"           ..+##+++++++++++++++++++##+..                        \",\n\"            ..+##+++++++++++++++++##+..                         \",\n\"             ..+##+++++++++++++++##+..                          \",\n\"              ..+##+++++++++++++##+..                           \",\n\"               ..+##+++++++++++##+..                            \",\n\"                ..+##+++++++++##+..                             \",\n\"                 ..+##+++++++##+..                              \",\n\"                  ..+##+++++##+..                               \",\n\"                   ..+##+++##+..                                \",\n\"                    ..+##+##+..                                 \",\n\"                     ..+###+..                                  \",\n\"                      ..+#+..                                   \",\n\"                       .....                                    \",\n\"                        ...                                     \",\n\"                         .                                      \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\nplus_Template_icon = \"\"\"\n/* XPM */\nstatic char * plus_Template_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"   c None\",\n\".  c #1B2B03\",\n\"+  c #365712\",\n\"@  c #56A506\",\n\"#  c #66BA15\",\n\"$  c #6EC21B\",\n\"%  c #7ACD22\",\n\"&  c #7DD728\",\n\"*  c #86E235\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                        ................                        \",\n\"                        ................                        \",\n\"                        ..************..                        \",\n\"                        ..************..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"    ......................**@@@@@@@@**......................    \",\n\"    ......................**@@@@@@@@**......................    \",\n\"    ..**********************@@@@@@@@**********************..    \",\n\"    ..**********************@@@@@@@@**********************..    \",\n\"    ..**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**..    \",\n\"    ..**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**..    \",\n\"    ..**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**..    \",\n\"    ..**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**..    \",\n\"    ..**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**..    \",\n\"    ..**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**..    \",\n\"    ..**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**..    \",\n\"    ..**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**..    \",\n\"    ..**********************@@@@@@@@**********************..    \",\n\"    ..**********************@@@@@@@@**********************..    \",\n\"    ......................**@@@@@@@@**......................    \",\n\"    ......................**@@@@@@@@**......................    \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..**@@@@@@@@**..                        \",\n\"                        ..************..                        \",\n\"                        ..************..                        \",\n\"                        ................                        \",\n\"                        ................                        \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\nmoins_Template_icon = \"\"\"\n/* XPM */\nstatic char * moins_Template_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"   c None\",\n\".  c #290000\",\n\"+  c #2C0001\",\n\"@  c #AA0004\",\n\"#  c #B60008\",\n\"$  c #C30D0D\",\n\"%  c #D61819\",\n\"&  c #E51E22\",\n\"*  c #EE2A28\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"    ........................................................    \",\n\"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++..    \",\n\"    .+****************************************************+.    \",\n\"    .+****************************************************+.    \",\n\"    .+**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**+.    \",\n\"    .+**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**+.    \",\n\"    .+**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**+.    \",\n\"    .+**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**+.    \",\n\"    .+**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**+.    \",\n\"    .+**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**+.    \",\n\"    .+**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**+.    \",\n\"    .+**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**+.    \",\n\"    .+****************************************************+.    \",\n\"    .+****************************************************+.    \",\n\"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++..    \",\n\"    ........................................................    \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\nrename_Template_icon = \"\"\"\n/* XPM */\nstatic char * rename_Template_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"   c None\",\n\".  c #000000\",\n\"+  c #A70002\",\n\"@  c #154A89\",\n\"#  c #3167A7\",\n\"$  c #4B9A00\",\n\"%  c #499B1C\",\n\"&  c #898B88\",\n\"*  c #C3A000\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                        @@@@@@@                                 \",\n\"                    @@@@@@@@@@@@@@@@                            \",\n\"                 @@@@#############@@@@@                 @       \",\n\"                @@####################@@@              @@       \",\n\"              @@########################@@@           @@@       \",\n\"             @@###########################@@@        @@#@       \",\n\"            @@##############################@@@      @##@       \",\n\"           @@#################################@@    @@##@       \",\n\"           @###################################@@@ @@###@       \",\n\"          @@####################################@@@@####@       \",\n\"         @@########@@@@@@@@@######################@##@##@       \",\n\"         @@#####@@@@@@@@@@@@@@@@####################@@##@       \",\n\"         @####@@@@@@@@@        @@@#################@@@##@       \",\n\"        @@###@@@  @@@@           @@@@#############@@@@##@       \",\n\"        @@##@@    @@@               @@@##########@@@@@##@       \",\n\"        @##@@     @@@                 @@@#######@@@@@@##@       \",\n\"        @#@@      @@                   @@@#####@@@@@@@##@       \",\n\"        @#@       @@                     @@@##@@@@@@@@##@       \",\n\"        @@@      @@@                      @@#@@@@@@@@@##@       \",\n\"        @@       @@@                     @@#@@@@@@@@@@##@       \",\n\"        @@       @@                     @@#@@@@@@@@@@@##@       \",\n\"        @@........*                    @@#@@@@@@@@@@@@##@       \",\n\"        @@.++++++.*                    @#@@@@@@@@@@@@@##@       \",\n\"        @@.++++++.*                   @@################@       \",\n\"        @.+++++++.*                  @@#################@       \",\n\"         .+++*++++.*                @@@@@@@@@@@@@@@@@@@@@       \",\n\"         .+++*++++.*                                            \",\n\"        .++++*+++++.*        .........                          \",\n\"        .+++* .++++.*        .&&&&&&&.                          \",\n\"        .+++* .++++.*        .&&&&&&&.                          \",\n\"       .+++*   .++++.*       ...&&&...   .................*     \",\n\"       .+++*   .++++.*         .&&&.     .$$$$$$$$$$$$$%%.*     \",\n\"      .++++*   .+++++.*        .&&&.     .$$$$$$$$$$$$$$$%.*    \",\n\"      .+++*     .++++.*        .&&&.     .$$$$$$$$$$$$$$$$%.*   \",\n\"      .+++*     .++++.*        .&&&.     .$$$%*.......$$$$%.*   \",\n\"     .+++*       .++++.*       .&&&.     .$$$%*       .$$$$%.*  \",\n\"     .++++++++++++++++.*       .&&&.     .$$$%*        .$$$%.*  \",\n\"    .+++++++++++++++++.*       .&&&.     .$$$%*        .$$$%.*  \",\n\"    .++++++++++++++++++.*      .&&&.     .$$$%*        .$$$%.*  \",\n\"    .+++***********++++.*      .&&&.     .$$$%*********$$$%.*   \",\n\"   .++++*          .++++.*     .&&&.     .$$$%%%%%%%%%$$$$%.*   \",\n\"   .+++*           .++++.*     .&&&.     .$$$$$$$$$$$$$$$%.*    \",\n\"   .+++*           .++++.*     .&&&.     .$$$$$$$$$$$$$$$%.*    \",\n\"  .+++*             .++++.*    .&&&.     .$$$$$$$$$$$$$$$$%.*   \",\n\"  .+++*             .++++.*    .&&&.     .$$$%*.......$$$$$%.*  \",\n\" .++++*             .+++++.*   .&&&.     .$$$%*       ..$$$%.*  \",\n\" .+++*               .++++.*   .&&&.     .$$$%*         .$$$%.* \",\n\" *****               ......*   .&&&.     .$$$%*         .$$$%.* \",\n\"                      ******   .&&&.     .$$$%*         .$$$%.* \",\n\"                               .&&&.     .$$$%*         .$$$%.* \",\n\"                               .&&&.     .$$$%*         .$$$%.* \",\n\"                               .&&&.     .$$$%**********$$$%.*  \",\n\"                             ...&&&...   .$$$%%%%%%%%%%$$$$%.*  \",\n\"                             .&&&&&&&.   .$$$$$$$$$$$$$$$$%.*   \",\n\"                             .&&&&&&&.   .$$$$$$$$$$$$$$$%.*    \",\n\"                             .........   .$$$$$$$$$$$$$%%.*     \",\n\"                                         .%%%%%%%%%%%%%..*      \",\n\"                                         ..............**       \",\n\"                                         **************         \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\ntest_Template_icon = \"\"\"\n/* XPM */\nstatic char * test_Template_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"   c None\",\n\".  c #1A2A01\",\n\"+  c #313436\",\n\"@  c #184C8A\",\n\"#  c #565855\",\n\"$  c #616360\",\n\"%  c #5BA900\",\n\"&  c #84E033\",\n\"*  c #D3DAE2\",\n\"                                   +###+                        \",\n\"                                  ++***#+                       \",\n\"                                 ++#****+                       \",\n\"                                ++####*#+                       \",\n\"                               ++######++                       \",\n\"                              ++######++                        \",\n\"                             ++######++                         \",\n\"                            ++#######++                         \",\n\"                           ++#######++                          \",\n\"           +++++++++++++  ++#######++                           \",\n\"          +#############+++#######++                            \",\n\"         +###*************########+               ...           \",\n\"        +##***@@@@@@@@@****######++              .....          \",\n\"       +##***@@@@@@@@@@@@***####++              ..%%%..         \",\n\"      +##**@@@@@******@@@@****#++              ..%&&&%..        \",\n\"     +##***@@@**********@@@***#+              ..%&&&&&%..       \",\n\"     +##**@@@************@@@***#+            ..%&&&%&&&%..      \",\n\"     +#**@@@*************@@@***#+           ..%&&&%%%&&&%..     \",\n\"     +#**@@************@@@@@@**#+          ..%&&&%%%%%&&&%..    \",\n\"     +#*@@@************@@@@@@**#+         ..%&&&%%%%%%%&&&%..   \",\n\"     +#*@@@***********@@@@@@@**#+        ..%&&&%%%%%%%%%&&&%..  \",\n\"     +#*@@************@@@@@@@**#+       ..%&&&%%%%%%%%%%%&&%..  \",\n\"     +#*@@***********@@@@@@@@**#+      ..%&&&%%%%%%%%%%%&&%..   \",\n\"     +#*@@@*********@@@@@@@@@**#+     ..%&&&%%%%%%%%%%%&&%..    \",\n\"     +#*@@@*********@@@@@@@@@**#+    ..%&&&%%%%%%%%%%%&&%..     \",\n\"     +#*@@@********@@@@@@@@@@**#+   ..%&&&%%%%%%%%%%%&&%..      \",\n\"     +#**@@@*****@@@@@@@@@@@@**#+  ..%&&&%%%%%%%%%%%&&%..       \",\n\"     +#**@@@@**@@@@@@@@@@@@@***#+ ..%&&&%%%%%%%%%%%&&%..        \",\n\"     +##**@@@@@@@@@@@@@@@@@@**##+..%&&&%%%%%%%%%%%&&%..         \",\n\"      +##**@@@@@@@@@@@@@@@@**##+..%&&&%%%%%%%%%%%&&%..          \",\n\"     ..+##**@@@@@@@@@@@@@@**##+..%&&&%%%%%%%%%%%&&%..           \",\n\"    ..%&+##**@@@@@@@@@@@@**##+..%&&&%%%%%%%%%%%&&%..            \",\n\"   ..%&&&+##**@@@@@@@@@***##+..%&&&%%%%%%%%%%%&&%..             \",\n\"  ..%&&&%%+##************##+..%&&&%%%%%%%%%%%&&%..              \",\n\"  ..%&&%%%%+##############+..%&&&%%%%%%%%%%%&&%..               \",\n\"   ..%&&%%%%++++++++++++++..%&&&%%%%%%%%%%%&&%..                \",\n\"    ..%&&%%%%%%%%%%%%&&%...%&&&%%%%%%%%%%%&&%..                 \",\n\"     ..%&&%%%%%%%%%%%%&&%.%&&&%%%%%%%%%%%&&%..                  \",\n\"      ..%&&%%%%%%%%%%%%&&%&&&%%%%%%%%%%%&&%..                   \",\n\"       ..%&&%%%%%%%%%%%%&&&&%%%%%%%%%%%&&%..                    \",\n\"        ..%&&%%%%%%%%%%%%&&%%%%%%%%%%%&&%..                     \",\n\"         ..%&&%%%%%%%%%%%%%%%%%%%%%%%&&%..                      \",\n\"          ..%&&%%%%%%%%%%%%%%%%%%%%%&&%..                       \",\n\"           ..%&&%%%%%%%%%%%%%%%%%%%&&%..                        \",\n\"            ..%&&%%%%%%%%%%%%%%%%%&&%..                         \",\n\"             ..%&&%%%%%%%%%%%%%%%&&%..                          \",\n\"              ..%&&%%%%%%%%%%%%%&&%..                           \",\n\"               ..%&&%%%%%%%%%%%&&%..                            \",\n\"                ..%&&%%%%%%%%%&&%..                             \",\n\"                 ..%&&%%%%%%%&&%..                              \",\n\"                  ..%&&%%%%%&&%..                               \",\n\"                   ..%&&%%%&&%..                                \",\n\"                    ..%&&%&&%..                                 \",\n\"                     ..%&&&%..                                  \",\n\"                      ..%&%..                                   \",\n\"                       .....                                    \",\n\"                        ...                                     \",\n\"                         .                                      \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\nexecute_Clipboard_Template_icon = \"\"\"\n/* XPM */\nstatic char * execute_Clipboard_Template_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"   c None\",\n\".  c #1A2A01\",\n\"+  c #303436\",\n\"@  c #56A506\",\n\"#  c #898B88\",\n\"$  c #949693\",\n\"%  c #A9ABA8\",\n\"&  c #86E235\",\n\"*  c #FFFFFF\",\n\"                            +++++++++                           \",\n\"                           +++++++%+++                          \",\n\"                         ++%*****+++%++                         \",\n\"                         +********+++%++                        \",\n\"               ++++++++++********+++++%++                       \",\n\"             ++#######++%*******++++++++++++++                  \",\n\"            ++#********%*******++++++++%$%%%%$++                \",\n\"            +#********+********+++++++++++++++++                \",\n\"           +#********+++******+++++++++*****++++++              \",\n\"           +********+++++********+++++*****++++++++             \",\n\"          +#******+++++++**********++*****+++++++++             \",\n\"          +#****+++$++$+%*********+++****+++++++++...           \",\n\"          +*****$$%****+..*******+++++**+++++++++.....          \",\n\"          +****$%******++..******+++++++++++++++..@@@..         \",\n\"          +#####********++.%%%%++++++++++++++++..@&&&@..        \",\n\"         +######********++%.......++++++++++++..@&&&&&@..       \",\n\"      +++*****#*******+++++%+++++..%+%$.....%..@&&&@&&&@..      \",\n\"      +#**************++++++****++%.$...**%%..@&&&@@@&&&@..     \",\n\"     +#******##*********+++*****+++$.#*****..@&&&@@@@@&&&@..    \",\n\"     +******+***********++*****+++++.#****..@&&&@@@@@@@&&&@..   \",\n\"    ++*****++**********++++**+++++++.#***..@&&&@@@@@@@@@&&&@..  \",\n\"    +*****++**********++++++++++++++.#**..@&&&@@@@@@@@@@@&&@..  \",\n\"    ++***+++********++++++++++++++++.#*..@&&&@@@@@@@@@@@&&@..   \",\n\"     +**+++********++++**+++++++++++.%..@&&&@@@@@@@@@@@&&@..    \",\n\"    ++**+++*******++++**+++++++++++....@&&&@@@@@@@@@@@&&@..     \",\n\"   ++*****+*****+++++**+++++++++++....@&&&@@@@@@@@@@@&&@..      \",\n\"  ++******+****++++++*+++++++++++++..@&&&@@@@@@@@@@@&&@..       \",\n\"  +******++***++++++++++++++++++++..@&&&@@@@@@@@@@@&&@....      \",\n\"  +*****++++*++++++++++++++++++++..@&&&@@@@@@@@@@@&&@..%.       \",\n\"  +****+++++++++++++++++++++++++..@&&&@@@@@@@@@@@&&@..%...      \",\n\"  +#**+++++++++++++++++++++++++..@&&&@@@@@@@@@@@&&@..%%....     \",\n\"  +#*+++++++++++++++++++++++++..@&&&@@@@@@@@@@@&&@..%%.%%%..    \",\n\"  +.#*+++++++++++++++++++++++..@&&&@@@@@@@@@@@&&@..%%%%%%%..    \",\n\"  +..#*****+++++++++++++++++..@&&&@@@@@@@@@@@&&@..%%%%%%%%..    \",\n\"  ......+++++++++++++........@&&&@@@@@@@@@@@&&@..%%%%%%%%%%..   \",\n\"   ..@&.....................@&&&@@@@@@@@@@@&&@..%%%%%%%%%%..    \",\n\"    ..@&&@@@@@@@@@@@@&&@...@&&&@@@@@@@@@@@&&@..%%%%%%%%%%%..    \",\n\"     ..@&&@@@@@@@@@@@@&&@.@&&&@@@@@@@@@@@&&@..%%%%%%%%%%%%..    \",\n\"      ..@&&@@@@@@@@@@@@&&@&&&@@@@@@@@@@@&&@..%%%%%%%%%%%...     \",\n\"       ..@&&@@@@@@@@@@@@&&&&@@@@@@@@@@@&&@................      \",\n\"        ..@&&@@@@@@@@@@@@&&@@@@@@@@@@@&&@................       \",\n\"         ..@&&@@@@@@@@@@@@@@@@@@@@@@@&&@..                      \",\n\"          ..@&&@@@@@@@@@@@@@@@@@@@@@&&@..                       \",\n\"           ..@&&@@@@@@@@@@@@@@@@@@@&&@..                        \",\n\"            ..@&&@@@@@@@@@@@@@@@@@&&@..                         \",\n\"             ..@&&@@@@@@@@@@@@@@@&&@..                          \",\n\"              ..@&&@@@@@@@@@@@@@&&@..                           \",\n\"               ..@&&@@@@@@@@@@@&&@..                            \",\n\"                ..@&&@@@@@@@@@&&@..                             \",\n\"                 ..@&&@@@@@@@&&@..                              \",\n\"                  ..@&&@@@@@&&@..                               \",\n\"                   ..@&&@@@&&@..                                \",\n\"                    ..@&&@&&@..                                 \",\n\"                     ..@&&&@..                                  \",\n\"                      ..@&@..                                   \",\n\"                       .....                                    \",\n\"                        ...                                     \",\n\"                         .                                      \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\nannuler_Template_icon = \"\"\"\n/* XPM */\nstatic char * annuler_Template_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"   c None\",\n\".  c #290000\",\n\"+  c #1A2A01\",\n\"@  c #A30500\",\n\"#  c #C41015\",\n\"$  c #DE2221\",\n\"%  c #EE2A28\",\n\"&  c #5BA900\",\n\"*  c #84E033\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                     .                   .        +++           \",\n\"                    ...                 ...      +++++          \",\n\"                   ..#..               ..#..    ++&&&++         \",\n\"                  ..#%#..             ..#%#..  ++&***&++        \",\n\"                 ..#%%%#..           ..#%%%#..++&*****&++       \",\n\"                ..#%%#%%#..         ..#%%#%%#..&***&***&++      \",\n\"               ..#%%###%%#..       ..#%%###%%#..**&&&***&++     \",\n\"              ..#%%#####%%#..     ..#%%#####%%#..&&&&&***&++    \",\n\"             ..#%%#######%%#..   ..#%%#######%%#..&&&&&***&++   \",\n\"            ..#%%#########%%#.. ..#%%#########%%#..&&&&&***&++  \",\n\"             ..#%%#########%%#...#%%#########%%#..&&&&&&&**&++  \",\n\"              ..#%%#########%%#.#%%#########%%#..&&&&&&&**&++   \",\n\"            +  ..#%%#########%%#%%#########%%#..&&&&&&&**&++    \",\n\"           +++  ..#%%#########%%%#########%%#..&&&&&&&**&++     \",\n\"          +++++  ..#%%#########%#########%%#..&&&&&&&**&++      \",\n\"         ++&&&++  ..#%%#################%%#..&&&&&&&**&++       \",\n\"        ++&***&++  ..#%%###############%%#..&&&&&&&**&++        \",\n\"       ++&*****&++  ..#%%#############%%#..&&&&&&&**&++         \",\n\"      ++&***&&**&++  ..#%%###########%%#..&&&&&&&**&++          \",\n\"     ++&***&&&&**&++  ..#%%#########%%#..&&&&&&&**&++           \",\n\"    ++&***&&&&&&**&++..#%%###########%%#..&&&&&**&++            \",\n\"   ++&***&&&&&&&&**&..#%%#############%%#..&&&**&++             \",\n\"  ++&***&&&&&&&&&&*..#%%###############%%#..&**&++              \",\n\"  ++&**&&&&&&&&&&&..#%%#################%%#..*&++               \",\n\"   ++&**&&&&&&&&&..#%%#########%#########%%#..++                \",\n\"    ++&**&&&&&&&..#%%#########%%%#########%%#..                 \",\n\"     ++&**&&&&&..#%%#########%%#%%#########%%#..                \",\n\"      ++&**&&&..#%%#########%%#.#%%#########%%#..               \",\n\"       ++&**&..#%%#########%%#...#%%#########%%#..              \",\n\"        ++&*..#%%#########%%#..&..#%%#########%%#..             \",\n\"         ++&*..#%%#######%%#..&&&..#%%#######%%#..              \",\n\"          ++&*..#%%#####%%#..&&&&&..#%%#####%%#..               \",\n\"           ++&*..#%%###%%#..&&&&&&&..#%%###%%#..                \",\n\"            ++&*..#%%#%%#..&&&&&&&**..#%%#%%#..                 \",\n\"             ++&*..#%%%#..&&&&&&&**&+..#%%%#..                  \",\n\"              ++&*..#%#..&&&&&&&**&++ ..#%#..                   \",\n\"               ++&*..#..&&&&&&&**&++   ..#..                    \",\n\"                ++&*...&&&&&&&**&++     ...                     \",\n\"                 ++&*.&&&&&&&**&++       .                      \",\n\"                  ++&**&&&&&**&++                               \",\n\"                   ++&**&&&**&++                                \",\n\"                    ++&**&**&++                                 \",\n\"                     ++&***&++                                  \",\n\"                      ++&*&++                                   \",\n\"                       +++++                                    \",\n\"                        +++                                     \",\n\"                         +                                      \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\nhelp_Template_icon = \"\"\"\n/* XPM */\nstatic char * help_Template_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"   c None\",\n\".  c #5D5F5C\",\n\"+  c #7A7C78\",\n\"@  c #867D44\",\n\"#  c #DDC91B\",\n\"$  c #F4E135\",\n\"%  c #ECDF6D\",\n\"&  c #FEF8C7\",\n\"*  c #FDFEF9\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                      #  # #     #       #                      \",\n\"                             #      # ##   #  #                 \",\n\"                   # #     #   #          # #                   \",\n\"                #       #   #     #  # #       #   #            \",\n\"                     #   #      #           # #   #             \",\n\"               #   #                                            \",\n\"             #  ##    # # # # # # # # # # #   #    #            \",\n\"           #        #   #  ##$ $ $ $$$ # #         #            \",\n\"           #  #  #   ###  ##$$$$$$$$$$$$# #      #   #          \",\n\"                         # #$$$$$$$$$$$$$# #         #          \",\n\"                   ## # ##$$$$$$$$$$$$$$$$###   #               \",\n\"            # # # #    ###$$$$$$$$$$$$$$$$$# #     #            \",\n\"                  # # #$#$$$$$$$$$$$$$$$$$$$###      #          \",\n\"                    ##$$$$$$$$$%%%%%%$$$$$$$$# #                \",\n\"            ##   #  ##$$$$$$$$$%&&&&&%$$$$$$$$###   #           \",\n\"         #  #  #   ###$$$$$$$$%&****&%$$$$$$$$$# #    #         \",\n\"                  ##$$$$$$$$%%&&****&&%%$$$$$$$$# #             \",\n\"              #  ###$$$$$$$$%&&*******&&$$$$$$$$ # #            \",\n\"             #  ##$$$$$$$$%%&&*********&%%$$$$$$$$$##  #        \",\n\"         #  #    $$$$$$$$$%&&**********&&&%$$$$$$$$#            \",\n\"            #   #$$$$$$$$$&&*************&%$$$$$$$$##  #        \",\n\"           ##    $$$$$$$$$&**************&%$$$$$$$$#            \",\n\"                #$$$$$$$$$&**************&%$$$$$$$$ #           \",\n\"              #  $$$$$$$$$&**************&%$$$$$$$ #  #         \",\n\"            #   #$$$$$$$$$&**************&%$$$$$$$$##           \",\n\"          #      $$$$$$$$$&**************&%$$$$$$$$#            \",\n\"              # #$$$$$$$$$%&&***********&&%$$$$$$$$##           \",\n\"          # #    $$$$$$$$$%%&&*********&&%%$$$$$$$$#            \",\n\"                ####$$$$$$$$%&********&&%$$$$$$$$####  #        \",\n\"                 # #$$$$$$$$%&&&*****&&%$$$$$$$$ # #            \",\n\"                # ###$$$$$$$$%%&****&&%$$$$$$$$$# # #           \",\n\"             #     # #$$$$$$$$%%&&&&&%$$$$$$$$## #              \",\n\"                    # #$$$$$$$$%%&&%%%$$$$$$$$# #               \",\n\"                 #     $ $$$$$$$%%%%$$$$$$$$ #           #      \",\n\"             #   ## # # ##$$$$$$$$$$$$$$$$$#### #    #          \",\n\"                #        #$#$$$$$$$$$$$$$$$#      #             \",\n\"                        ######$$$$$$$$#######                   \",\n\"               #    #      @%##$$$$$$$##%% #    #               \",\n\"                          @.@%#########%@@@ #        #          \",\n\"                  #        .@@%%%%%%%%%@....                    \",\n\"                          ...@@@@@@@@@@.....                    \",\n\"                          ..................                    \",\n\"                          ...++++++++++.....                    \",\n\"                          ...+++++++++++....                    \",\n\"                          ...++++++++++.....                    \",\n\"                          ..................                    \",\n\"                          ..................                    \",\n\"                          ...++++++++++.....                    \",\n\"                          ...+++++++++++....                    \",\n\"                          ...++++++++++.....                    \",\n\"                          ..................                    \",\n\"                          .................                     \",\n\"                          +++++++++++++++++                     \",\n\"                            ++++++++++++++                      \",\n\"                            ++++++++++++++                      \",\n\"                             +++++++++++                        \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\nsave_Template_icon = \"\"\"\n/* XPM */\nstatic char * save_Template_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 10 1\",\n\"   c None\",\n\".  c #4E9A06\",\n\"+  c #FFFFFF\",\n\"@  c #345F9A\",\n\"#  c #7495BF\",\n\"$  c #545653\",\n\"%  c #BABDB6\",\n\"&  c #555754\",\n\"*  c #D6D8D5\",\n\"=  c #888A85\",\n\"                                                                \",\n\"                                                         .      \",\n\"                                                        .+.     \",\n\"                                                       .+.+.    \",\n\"                                                      .+...+.   \",\n\"                  @@@@@@@@@                          .+.....+.  \",\n\"               @@@@#######@@@@              .       .+.......+. \",\n\"              @@#############@@            .+.     .+.......+.  \",\n\"             @@###############@@          .+.+.   .+.......+.   \",\n\"             @#################@@        .+...+. .+.......+.    \",\n\"           @@###################@@      .+.....+.+.......+.     \",\n\"           @###@@@@@@@###########@@    .+.......+.......+.      \",\n\"          @@##@@     @@###########@@    .+.............+.       \",\n\"         @@#@@        @@##########@@     .+...........+.        \",\n\"         @#@           @@@#########@      .+.........+.         \",\n\"         @@              @#########@       .+.......+.          \",\n\"        @@     $$$$$$$$$$@#########@@$$$$$$$.+.....+.           \",\n\"        @     $$%%%%%%%%%@@#########@%%%%%%%%.+...+.            \",\n\"             $$$%%%%%%%%%%@#########@%%%%%%%%%.+.+.             \",\n\"             $$%@@@@@@@@@@@#########@@@@@@@@@@@.+.              \",\n\"             $$%@@############################@@.$              \",\n\"             $%%%@@##########################@@%%$              \",\n\"            $$%%%%@@#############@@@@@@@@@##@@%%%$$             \",\n\"           $$%%%%%%@@##########@@@@@@@@@@##@@%%%%$$             \",\n\"           $$%%%%%%%@@#######@@@@@@@@@@@##@@%%%%%%$$            \",\n\"          $$%%%%%%%%%@@####@@@@@@@@@@@@##@@%%%%%%%$$            \",\n\"          $$%%%%%%%%%%@@##@@@@@@@@@@@@##@@%%%%%%%%%$            \",\n\"          $$%%%%%%%%%%%@@##@@@@@@@@@@##@@%%%%%%%%%%$$           \",\n\"         $$%%%%%%%%%%%%%@@##@@@@@@@@##@@%%%%%%%%%%%$$           \",\n\"         $$%%%%%%%%%%%%%%@@##@@@@@@##@@%%%%%%%%%%%%%$           \",\n\"        $$%%%%%%%%%%%%%%%%@@##@@@@##@@%%%%%%%%%%%%%%$$          \",\n\"        $$%%%%%%%%%%%%%%%%%@@##@@##@@%%%%%%%%%%%%%%%%$          \",\n\"       $$%%%%%%%%%%%%%%%%%%%@@#@##@@%%%%%%%%%%%%%%%%%$$         \",\n\"       $$%%%%%%%%%%%%%%%%%%%%@@##@@%%%%%%%%%%%%%%%%%%$$         \",\n\"       $$%%%%%%%%%%%%%%%%%%%%%@@@@%%%%%%%%%%%%%%%%%%%%$$        \",\n\"       $%%%%%%%%%%%%%%%%%%%%%%%@@%%%%%%%%%%%%%%%%%%%%%$$        \",\n\"      $$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%$        \",\n\"      $$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%$$       \",\n\"     $$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%$$$      \",\n\"     $$%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&$$      \",\n\"     $$%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&$$      \",\n\"     $$%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&$$      \",\n\"     $$%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&$$      \",\n\"     $$%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&$$      \",\n\"     $$%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&***&***&***&***&&&$$      \",\n\"     $$%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&***&***&***&***&&&$$      \",\n\"     $$%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&***&***&***&***&&&$$      \",\n\"     $$%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&***&***&***&***&&&$$      \",\n\"     $$%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&***&***&***&***&&&$$      \",\n\"     $$%&&&&*************&&&&&&&&&&&&&***&***&***&***&&&$$      \",\n\"     $$%&&&&*************&&&&&&&&&&&&&***&***&***&***&&&$$      \",\n\"     $$%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&$$      \",\n\"     $$=**********************&&&&&&&&&&&&&&&&&&&&&&&&&$$$      \",\n\"      $$&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&$$        \",\n\"       $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$         \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\naccept_Template_icon = \"\"\"\n/* XPM */\nstatic char * accept_Template_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 5 1\",\n\"   c None\",\n\".  c #192A02\",\n\"+  c #5AA909\",\n\"@  c #7CD124\",\n\"#  c #85E033\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                  ...           \",\n\"                                                 .....          \",\n\"                                                ..+++..         \",\n\"                                               ..+###+..        \",\n\"                                              ..+#####+..       \",\n\"                                             ..+###+###+..      \",\n\"                                            ..+###+++###+..     \",\n\"                                           ..+###+++++###+..    \",\n\"                                          ..+###+++++++###+..   \",\n\"                                         ..+###+++++++++###+..  \",\n\"                                        ..+###+++++++++++##+..  \",\n\"                                       ..+###+++++++++++##+..   \",\n\"            .                         ..+###+++++++++++##+..    \",\n\"           ...                       ..+###+++++++++++##+..     \",\n\"          .....                     ..+###+++++++++++##+..      \",\n\"         ..+++..                   ..+###+++++++++++##+..       \",\n\"        ..+###+..                 ..+###+++++++++++##+..        \",\n\"       ..+#####+..               ..+###+++++++++++##+..         \",\n\"      ..+###++##+..             ..+###+++++++++++##+..          \",\n\"     ..+###++++##+..           ..+###+++++++++++##+..           \",\n\"    ..+###++++++##+..         ..+###+++++++++++##+..            \",\n\"   ..+###++++++++##+..       ..+###+++++++++++##+..             \",\n\"  ..+###++++++++++##+..     ..+###+++++++++++##+..              \",\n\"  ..+##++++++++++++##+..   ..+###+++++++++++##+..               \",\n\"   ..+##++++++++++++##+.. ..+###+++++++++++##+..                \",\n\"    ..+##++++++++++++##+...+###+++++++++++##+..                 \",\n\"     ..+##++++++++++++##+.+###+++++++++++##+..                  \",\n\"      ..+##++++++++++++##+###+++++++++++##+..                   \",\n\"       ..+##++++++++++++####+++++++++++##+..                    \",\n\"        ..+##++++++++++++##+++++++++++##+..                     \",\n\"         ..+##+++++++++++++++++++++++##+..                      \",\n\"          ..+##+++++++++++++++++++++##+..                       \",\n\"           ..+##+++++++++++++++++++##+..                        \",\n\"            ..+##+++++++++++++++++##+..                         \",\n\"             ..+##+++++++++++++++##+..                          \",\n\"              ..+##+++++++++++++##+..                           \",\n\"               ..+##+++++++++++##+..                            \",\n\"                ..+##+++++++++##+..                             \",\n\"                 ..+##+++++++##+..                              \",\n\"                  ..+##+++++##+..                               \",\n\"                   ..+##+++##+..                                \",\n\"                    ..+##+##+..                                 \",\n\"                     ..+###+..                                  \",\n\"                      ..+#+..                                   \",\n\"                       .....                                    \",\n\"                        ...                                     \",\n\"                         .                                      \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\nreject_Template_icon = \"\"\"\n/* XPM */\nstatic char * reject_Template_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"   c None\",\n\".  c #000000\",\n\"+  c #860002\",\n\"@  c #BF0001\",\n\"#  c #FA1F1F\",\n\"$  c #CA3432\",\n\"%  c #DF4846\",\n\"&  c #F99B9B\",\n\"*  c #EBE9E6\",\n\"                    @@@@@@@@@@@@@@@@@@@@@@@@                    \",\n\"                   @@@@@@@@@@@@@@@@@@@@@@@@@@                   \",\n\"                  @@************************@@                  \",\n\"                 @@**@@@@@@@@@@@@@@@@@@@@@@**@@                 \",\n\"                @@**@@@@@@@@@@@@@@@@@@@@@@@@**@@                \",\n\"               @@**@@@@@@@@@@@@@@@@@@@@@@@@@@**@@               \",\n\"              @@**@@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@              \",\n\"             @@**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@             \",\n\"            @@**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@            \",\n\"           @@**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@           \",\n\"          @@**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@          \",\n\"         @@**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@         \",\n\"        @@**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@        \",\n\"       @@**@@@@@@@@@@...@@@@@@@@@@@@@@@@@@...@@@@@@@@**@@       \",\n\"      @@**@@@@@@@@@@..*..@@@@@@@@@@@@@@@@..*..@@@@@@@@**@@      \",\n\"     @@**@@@@@@@@@@..***..@@@@@@@@@@@@@@..***..@@@@@@@@**@@     \",\n\"    @@**@@@@@@@@@@..*****..@@@@@@@@@@@@..*****..@@@@@@@@**@@    \",\n\"   @@**@@@@@@@@@@..*******..@@@@@@@@@@..*******..@@@@@@@@**@@   \",\n\"   @@*@@@@@@@@@@..*********..@@@@@@@@..*********..@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@.***********..@@@@@@..***********.@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@..***********..@@@@..***********..@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@..***********..@@..***********..@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@..***********....***********..@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@@..***********..***********..@@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@@@..**********************..@@@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@@@@..********************..@@@@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@@@@@..******************..@@@@@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@@@@@@..****************..@@@@@@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@@@@@@@..**************..@@@@@@@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@@@@@@@@..************..@@@@@@@@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@@@@@@@@..************..@@@@@@@@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@@@@@@@..**************..@@@@@@@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@@@@@@..****************..@@@@@@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@@@@@..******************..@@@@@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@@@@..********************..@@@@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@@@..**********************..@@@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@@..***********..***********..@@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@@..***********....***********..@@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@@..***********..@@..***********..@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@..***********..@@@@..***********.@@@@@@@@@*@@   \",\n\"   @@*@@@@@@@@@@.***********..@@@@@@..*********..@@@@@@@@@*@@   \",\n\"   @@**@@@@@@@@@..*********..@@@@@@@@..*******..@@@@@@@@@@*@@   \",\n\"    @@**@@@@@@@@@..*******..@@@@@@@@@@..*****..@@@@@@@@@@**@@   \",\n\"     @@**@@@@@@@@@..*****..@@@@@@@@@@@@..***..@@@@@@@@@@**@@    \",\n\"      @@**@@@@@@@@@..***..@@@@@@@@@@@@@@..*..@@@@@@@@@@**@@     \",\n\"       @@**@@@@@@@@@..*..@@@@@@@@@@@@@@@@...@@@@@@@@@@**@@      \",\n\"        @@**@@@@@@@@@...@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@       \",\n\"         @@**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@        \",\n\"          @@**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@         \",\n\"           @@**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@          \",\n\"            @@**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@           \",\n\"             @@**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@            \",\n\"              @@**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@             \",\n\"               @@**@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@              \",\n\"                @@**@@@@@@@@@@@@@@@@@@@@@@@@@**@@               \",\n\"                 @@**@@@@@@@@@@@@@@@@@@@@@@@**@@                \",\n\"                  @@*************************@@                 \",\n\"                   @@@@@@@@@@@@@@@@@@@@@@@@@@@                  \",\n\"                    @@@@@@@@@@@@@@@@@@@@@@@@@                   \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\nReset_Button_icon = \"\"\"\n/* XPM */\nstatic char * Reset_Button_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 7 1\",\n\"   c None\",\n\".  c #6E4600\",\n\"+  c #957311\",\n\"@  c #E6CB34\",\n\"#  c #C2AC17\",\n\"$  c #710808\",\n\"%  c #D31515\",\n\"                                                                \",\n\"         ...                                                    \",\n\"        .......                                                 \",\n\"       ..+@+@@..                                                \",\n\"       .++...+@..                                               \",\n\"      ..@.. ..@+.                                               \",\n\"      ..@.. ..+@.                                               \",\n\"      ..@....++@+.                                              \",\n\"      ..+++.+++++..                                             \",\n\"       ..@++++++@..                                             \",\n\"        .+@+++++++.                                             \",\n\"         .++++++++..                                            \",\n\"         ..@+++++++..                                           \",\n\"          ..+++++++..                                           \",\n\"          ..+++...+..                                           \",\n\"           ..++.......   ++                                     \",\n\"            ..++...... ++#+                                     \",\n\"             ..+.....+++@@#+                                    \",\n\"              .....+++@@@@#+                                    \",\n\"               ..+++#@@@@@#+                                    \",\n\"               .++#@@@@@@@@.$$$                                 \",\n\"               ++#@@@@@@@@$$$$$                                 \",\n\"            +++#@@@@@@@@.$$%%%$$                                \",\n\"           ++######@@@.$$%%%%%$$+                               \",\n\"           ++#######+$$$%%%%%$$$++                              \",\n\"             +####+$$$%%%%%%$$$++++                             \",\n\"              ++#.$$%%%%%%$$$@@@@#++                            \",\n\"               .$$$%%%%%$$$.@###@@#++                           \",\n\"              $$$%%%%%%$$.@@######@#+++                         \",\n\"              $$%%%%%$$$@@@########@@#+                         \",\n\"              $$$%%$$$@@@@###########@#++                       \",\n\"               $$$$$.@################@#++                      \",\n\"                $$$+#@#################@@++                     \",\n\"                  ++@###################@@++                    \",\n\"                  ++@####################@@++                   \",\n\"                  ++@@####################@@++                  \",\n\"                   +#@#####################@@#+                 \",\n\"                   +#@######################@@@+                \",\n\"                   +#@#######################@@@+               \",\n\"                   +#@########################@@@+              \",\n\"                    +@###########.##########.###@@#++           \",\n\"                    +@#######################.###@@@++          \",\n\"                    +#@###########.###.#######..##@@@#++        \",\n\"                    +#@############.###.#######..##@@@++        \",\n\"                    ++@############.####.########.#@@++         \",\n\"                     +#@##########@..####.#######@.+++          \",\n\"                      #@######.###@#.####..#####@@.++           \",\n\"                      +@#############.####.####@@#.+            \",\n\"                      +#@######.######.####.#@@#++.             \",\n\"                      ++@######.######.####.+##++               \",\n\"                      .+#@#.####.######.#@@@.++                 \",\n\"                      .++@@######.#####.#@@++.                  \",\n\"                        +#@#.#####.##@@.+++                     \",\n\"                         +#@#.###@.#@@#.++                      \",\n\"                          +@@.@@@@.++++.                        \",\n\"                           +@.@##+.+                            \",\n\"                           ++.++++.                             \",\n\"                             .+                                 \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\nBrowserReload_icon = \"\"\"\n/* XPM */\nstatic char * BrowserReload_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"   c None\",\n\".  c #2B5B93\",\n\"+  c #3368A7\",\n\"@  c #5082BD\",\n\"#  c #6196CA\",\n\"$  c #7499C5\",\n\"%  c #80A9D3\",\n\"&  c #A1BEDE\",\n\"*  c #B9CFE7\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                        .......                                 \",\n\"                    ....+@@@@@+.....                            \",\n\"                 ...@%&&&&&&&&&&%%@+...                 .       \",\n\"                ..#&&&&&&&&&&&&&&&&&%#+..              ..       \",\n\"              ..#&&&&&&&&&&&&&&&&&&&&&&%@..           ...       \",\n\"             ..%&&&&&&&&&&&&&&&&&&%%%%&&&%@..        ..#.       \",\n\"            .+&&&&&&&&&&&&&&&&&&&&%%%%%%&&&%+..      .#&.       \",\n\"           .+&&&&&&&&&&&&&&&&&&&&&%%%%%%%%%&&%..    .@%&.       \",\n\"           .%&&&&&&&&&&&&&&&&&&&&%%%%%%%%%%%&&&@.. .@%%&.       \",\n\"          .@&&&&&&&&&&&&&&&&&&&&&%%%%%%%%%%%%%%%@..@%##&.       \",\n\"         ..&&&&&&%#@......+@%%&&&&%%%%%%%%%%@@@@%%@%#@#&.       \",\n\"         .@&&&&#+..............@%&&&%%%%%%@@@@@@@%%%@@#&.       \",\n\"         .&&&%+........        ...#&&&%%@@@@@@@@@@@@@@#&.       \",\n\"        .+&&%...&&&..            ...@#%%@@@@@@@@@@@@@@#&.       \",\n\"        .@&#..&&&&..                ..@%%@@@@@@@@@@@@@#&.       \",\n\"        .%%..&&&&&.                   ..@%%@@@@@@@@@@@#&.       \",\n\"        .%+.&&&&&&.                    ..+%%@@@@@@@@@@#&.       \",\n\"        .#.+@&&&&&.                      ..@%%@@@@@@@@#&.       \",\n\"        .+.@@@&&&..                       .+%%@@@@@@@@#&.       \",\n\"        ..+@@@@&&.                       ..%%@@@@@@@@@#&.       \",\n\"        ..+@     .                      ..%%@@@@@@@@@@#&.       \",\n\"        ..@                            ..#%@@@@@@@@@@@#&.       \",\n\"        ..                             .#%@@@@@@@@@@@@#&.       \",\n\"        ..                            .@%%@@@@@@@@@@@@#&.       \",\n\"        ..                           .@&&&&&&&&&&&&&&&&&.       \",\n\"                                    .....................       \",\n\"        .....................                                   \",\n\"        .+@@@@@@@@@@@@@@@@+..                                   \",\n\"        .%&&&&&&&&&&&&&&&&..                            .       \",\n\"        .%&%%%%%%%%%%%%&&+.                             .       \",\n\"        .%&%%%%%%%%%%%%&@.                             ..       \",\n\"        .%&%%%%%%%%%%%&@.                              ...      \",\n\"        .%&%%%%%%%%%%&#.                      @        ...      \",\n\"        .%&%%%%%%%%%&%..                      @&       ...      \",\n\"        .%&%%%%%%%%&&@..                      @&      ....      \",\n\"        .%&%%%%%%%%%%&#..                     @&&&    .@..      \",\n\"        .%&%%%%%%%%%%%&%+..                   @&&&&  ..@.       \",\n\"        .%&%%%%%%%%%%%%&&#..                 +#&&&&&..@@.       \",\n\"        .%&%%%%%%%%%%%%%%%#+...             .+&&&&%..@@@.       \",\n\"        .%&%%%%%%%%%%%%#@@###+...          ..%&&&@..@@@@.       \",\n\"        .%&%%%&%%%%%%#@@@@@@###@.....   ...+%%@+...@@@@.        \",\n\"        .%&%%&&&&%%%#@@@@@@@@@###@++............++@@@@@.        \",\n\"        .%&%%&++%&%#@@@@@@@@@@@@@@##@@@@@@@@@@@@@@@@@@..        \",\n\"        .%&%&@...#&#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.         \",\n\"        .%&&#.  ..+#%#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.          \",\n\"        .%&%..    ..@##@@@@@@@@@@@@@@@@@@@@@@@@@@@@@..          \",\n\"        .%%..      ..+@##@@@@@@@@@@@@@@@@@@@@@@@@@@..           \",\n\"        .@..         ..+@##@@@@@@@@@@@@@@@@@@@@@@@..            \",\n\"        ...           ....@###@@@@@@@@@@@@@@@@@@...             \",\n\"        ..               ...+@@@@@@@@@@@@@@@@@...               \",\n\"        .                  .....@@@@@@@@@@@....                 \",\n\"                              ..............                    \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\nsnap_Menu_Btn_icon = \"\"\"\n/* XPM */\nstatic char * snap_Menu_Btn_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 4 1\",\n\"   c None\",\n\".  c #060706\",\n\"+  c #011515\",\n\"@  c #CB0808\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                 +++++++++++++++++++++++++++++                  \",\n\"                 +@@@@@@@@@@@@@@@@@@@@@@@@@@@+                  \",\n\"                 +@@@@@@@@@@@@@@@@@@@@@@@@@@@+                  \",\n\"                 +@@+++++++++++++++++++++++@@+                  \",\n\"                 +@@+++++++++++++++++++++++@@+                  \",\n\"                 +@@+++++++++++++++++++++++@@+                  \",\n\"                 +@@+++++++++++++++++++++++@@+                  \",\n\"                 +@@+++++++++++++++++++++++@@+                  \",\n\"       +++++++++++@@+++++++++++++++++++++++@@+++++++++.+        \",\n\"       +@@@@@@@@@@@@+++++++++++++++++++++++@@@@@@@@@@@@+        \",\n\"       +@@@@@@@@@@@@+++++++++++++++++++++++@@@@@@@@@@@@+        \",\n\"       ++@@@+++++++++++++++++++++++++++++++++++++++@@@++        \",\n\"        ++@@@+++++++++++++++++++++++++++++++++++++@@@++         \",\n\"         ++@@@+++++++++++++++++++++++++++++++++++@@@++          \",\n\"          ++@@@+++++++++++++++++++++++++++++++++@@@++           \",\n\"           ++@@@+++++++++++++++++++++++++++++++@@@++            \",\n\"            ++@@@+++++++++++++++++++++++++++++@@@++             \",\n\"             ++@@@+++++++++++++++++++++++++++@@@++              \",\n\"              ++@@@+++++++++++++++++++++++++@@@++               \",\n\"               ++@@@+++++++++++++++++++++++@@@++                \",\n\"                ++@@@+++++++++++++++++++++@@@++                 \",\n\"                 ++@@@+++++++++++++++++++@@@++                  \",\n\"                  ++@@@+++++++++++++++++@@@++                   \",\n\"                   ++@@@+++++++++++++++@@@++                    \",\n\"                    ++@@@+++++++++++++@@@++                     \",\n\"                     ++@@@+++++++++++@@@++                      \",\n\"                      ++@@@+++++++++@@@++                       \",\n\"                       ++@@@+++++++@@@++                        \",\n\"                        ++@@@+++++@@@++                         \",\n\"                         ++@@@+++@@@++                          \",\n\"                          ++@@@+@@@++                           \",\n\"                           ++@@@@@++                            \",\n\"                            ++@@@++                             \",\n\"                             ++@++                              \",\n\"                              +++                               \",\n\"                               +                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\nFile_Dialog_Info_View_icon = \"\"\"\n/* XPM */\nstatic char * File_Dialog_Info_View_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 3 1\",\n\"   c None\",\n\".  c #1E4C89\",\n\"+  c #F1F6F8\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                         ..............                         \",\n\"                       ..................                       \",\n\"                     ......................                     \",\n\"                    ......++++++++++++......                    \",\n\"                  .....++++++++++++++++++.....                  \",\n\"                .....++++++++++++++++++++++.....                \",\n\"               ....++++++..............++++++....               \",\n\"              ...++++++..................++++++...              \",\n\"             ...+++++......................+++++...             \",\n\"            ...++++..........................++++...            \",\n\"           ...++++...........++++++...........++++...           \",\n\"          ...++++...........++++++++...........++++...          \",\n\"         ...++++...........++++++++++...........++++...         \",\n\"        ...++++............++++++++++............++++...        \",\n\"       ...++++.............++++++++++.............++++...       \",\n\"      ...++++..............++++++++++..............++++...      \",\n\"      ...+++...............++++++++++...............+++...      \",\n\"      ..++++................++++++++................++++..      \",\n\"     ...+++..................++++++..................+++...     \",\n\"    ...++++..........................................++++...    \",\n\"    ...+++............................................+++...    \",\n\"    ...+++............................................+++...    \",\n\"   ....+++............................................+++....   \",\n\"   ...+++................++++++++++++..................+++...   \",\n\"   ...+++................++++++++++++..................+++...   \",\n\"   ...+++................++++++++++++..................+++...   \",\n\"   ...+++....................++++++++..................+++...   \",\n\"   ...+++....................++++++++..................+++...   \",\n\"   ...+++....................++++++++..................+++...   \",\n\"   ...+++....................++++++++..................+++...   \",\n\"   ...+++....................++++++++..................+++...   \",\n\"   ...+++....................++++++++..................+++...   \",\n\"   ...+++....................++++++++..................+++...   \",\n\"   ...+++....................++++++++..................+++...   \",\n\"   ...+++....................++++++++..................+++...   \",\n\"   ....+++...................++++++++.................+++....   \",\n\"    ...+++...................++++++++.................+++...    \",\n\"    ...+++...................++++++++.................+++...    \",\n\"    ...++++..................++++++++................++++...    \",\n\"     ...+++..................++++++++................+++...     \",\n\"      ..++++.................++++++++...............++++..      \",\n\"      ...+++.................++++++++...............+++...      \",\n\"      ...++++................++++++++..............++++...      \",\n\"       ...++++...............++++++++.............++++...       \",\n\"        ...++++..............++++++++............++++...        \",\n\"         ...++++..........++++++++++++++........++++...         \",\n\"          ...++++.........++++++++++++++.......++++...          \",\n\"           ...++++........++++++++++++++......++++...           \",\n\"            ...++++..........................++++...            \",\n\"             ...+++++......................+++++...             \",\n\"              ...++++++..................++++++...              \",\n\"               ....++++++..............++++++....               \",\n\"                .....++++++++++++++++++++++.....                \",\n\"                  .....++++++++++++++++++.....                  \",\n\"                    ......++++++++++++......                    \",\n\"                     ......................                     \",\n\"                       ..................                       \",\n\"                         ..............                         \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\nmsgBtn_Critical_icon = \"\"\"\n/* XPM */\nstatic char * msgBtn_Critical_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 6 1\",\n\"   c None\",\n\".  c #000000\",\n\"+  c #BF0001\",\n\"@  c #BE0209\",\n\"#  c #EBE9E6\",\n\"$  c #F1F6F8\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                         @@@@@@@@@@@@@@                         \",\n\"                       @@@@@@@@@@@@@@@@@@                       \",\n\"                     @@@@@@@@@@@@@@@@@@@@@@                     \",\n\"                    @@@@@@$$$$$$$$$$$$@@@@@@                    \",\n\"                  @@@@@$$$$$$$$$$$$$$$$$$@@@@@                  \",\n\"                @@@@@$$$$$$$$$$$$$$$$$$$$$$@@@@@                \",\n\"               @@@@$$$$$$++++++++++++++$$$$$$@@@@               \",\n\"              @@@$$$$$$++++++++++++++++++$$$$$$@@@              \",\n\"             @@@$$$$$++++++++++++++++++++++$$$$$@@@             \",\n\"            @@@$$$$++++++++++++++++++++++++++$$$$@@@            \",\n\"           @@@$$$$++++++++++++++++++++++++++++$$$$@@@           \",\n\"          @@@$$$$++++++++++++++++++++++++++++++$$$$@@@          \",\n\"         @@@$$$$+++++...++++++++++++++++++...+++$$$$@@@         \",\n\"        @@@$$$$+++++..#..++++++++++++++++..#..+++$$$$@@@        \",\n\"       @@@$$$$+++++..###..++++++++++++++..###..+++$$$$@@@       \",\n\"      @@@$$$$+++++..#####..++++++++++++..#####..+++$$$$@@@      \",\n\"      @@@$$$+++++..#######..++++++++++..#######..+++$$$@@@      \",\n\"      @@$$$$++++..#########..++++++++..#########..++$$$$@@      \",\n\"     @@@$$$+++++.###########..++++++..###########.+++$$$@@@     \",\n\"    @@@$$$$+++++..###########..++++..###########..+++$$$$@@@    \",\n\"    @@@$$$+++++++..###########..++..###########..+++++$$$@@@    \",\n\"    @@@$$$++++++++..###########....###########..++++++$$$@@@    \",\n\"   @@@@$$$+++++++++..###########..###########..+++++++$$$@@@@   \",\n\"   @@@$$$+++++++++++..######################..+++++++++$$$@@@   \",\n\"   @@@$$$++++++++++++..####################..++++++++++$$$@@@   \",\n\"   @@@$$$+++++++++++++..##################..+++++++++++$$$@@@   \",\n\"   @@@$$$++++++++++++++..################..++++++++++++$$$@@@   \",\n\"   @@@$$$+++++++++++++++..##############..+++++++++++++$$$@@@   \",\n\"   @@@$$$++++++++++++++++..############..++++++++++++++$$$@@@   \",\n\"   @@@$$$++++++++++++++++..############..++++++++++++++$$$@@@   \",\n\"   @@@$$$+++++++++++++++..##############..+++++++++++++$$$@@@   \",\n\"   @@@$$$++++++++++++++..################..++++++++++++$$$@@@   \",\n\"   @@@$$$+++++++++++++..##################..+++++++++++$$$@@@   \",\n\"   @@@$$$++++++++++++..####################..++++++++++$$$@@@   \",\n\"   @@@$$$+++++++++++..######################..+++++++++$$$@@@   \",\n\"   @@@@$$$+++++++++..###########..###########..+++++++$$$@@@@   \",\n\"    @@@$$$++++++++..###########....###########..++++++$$$@@@    \",\n\"    @@@$$$+++++++..###########..++..###########..+++++$$$@@@    \",\n\"    @@@$$$$+++++..###########..++++..###########.++++$$$$@@@    \",\n\"     @@@$$$+++++.###########..++++++..#########..++++$$$@@@     \",\n\"      @@$$$$++++..#########..++++++++..#######..++++$$$$@@      \",\n\"      @@@$$$+++++..#######..++++++++++..#####..+++++$$$@@@      \",\n\"      @@@$$$$+++++..#####..++++++++++++..###..+++++$$$$@@@      \",\n\"       @@@$$$$+++++..###..++++++++++++++..#..+++++$$$$@@@       \",\n\"        @@@$$$$+++++..#..++++++++++++++++...+++++$$$$@@@        \",\n\"         @@@$$$$+++++...++++++++++++++++++++++++$$$$@@@         \",\n\"          @@@$$$$++++++++++++++++++++++++++++++$$$$@@@          \",\n\"           @@@$$$$++++++++++++++++++++++++++++$$$$@@@           \",\n\"            @@@$$$$++++++++++++++++++++++++++$$$$@@@            \",\n\"             @@@$$$$$++++++++++++++++++++++$$$$$@@@             \",\n\"              @@@$$$$$$++++++++++++++++++$$$$$$@@@              \",\n\"               @@@@$$$$$$++++++++++++++$$$$$$@@@@               \",\n\"                @@@@@$$$$$$$$$$$$$$$$$$$$$$@@@@@                \",\n\"                  @@@@@$$$$$$$$$$$$$$$$$$@@@@@                  \",\n\"                    @@@@@@$$$$$$$$$$$$@@@@@@                    \",\n\"                     @@@@@@@@@@@@@@@@@@@@@@                     \",\n\"                       @@@@@@@@@@@@@@@@@@                       \",\n\"                         @@@@@@@@@@@@@@                         \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\nmsgBtn_Warning_icon = \"\"\"\n/* XPM */\nstatic char * msgBtn_Warning_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 6 1\",\n\"   c None\",\n\".  c #000000\",\n\"+  c #BC9100\",\n\"@  c #FBE500\",\n\"#  c #FCE500\",\n\"$  c #FCE600\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                             ++++++                             \",\n\"                            ++++++++                            \",\n\"                            +++$$+++                            \",\n\"                           +++$$$$+++                           \",\n\"                           ++$$$$$$++                           \",\n\"                          ++$$$$$$$+++                          \",\n\"                          ++$$@$$$$$++                          \",\n\"                         ++$$@@@$$$$+++                         \",\n\"                        +++$$@@@$$$$$+++                        \",\n\"                        ++$$@@@@@$$$$+++                        \",\n\"                       +++$$@@@$$$$$$$+++                       \",\n\"                       ++$$@@@$$#$$$$$$++                       \",\n\"                      ++$$$@@@$$#$$$$$$+++                      \",\n\"                      ++$$@@@$$$$$$@$$$$++                      \",\n\"                     ++$$$@$@......@$$$$+++                     \",\n\"                    +++$$@@$@......@$$$$$+++                    \",\n\"                    ++$$$@@$@......@$$$$$+++                    \",\n\"                   +++$$@@$$@......@$$$$$$+++                   \",\n\"                   ++$$$@@$$@......@$$$$$$$++                   \",\n\"                  ++$$$@$$$$$......$$$$$$$$+++                  \",\n\"                  ++$$$@$$$$$......$$$$$$$$$++                  \",\n\"                 ++$$$@@$$$$$......$$$$$$$$$+++                 \",\n\"                +++$$$@@$$$$$......$$$$$$$$$$+++                \",\n\"                ++$$$@@$$$#$$......$$$$$$$$$$$++                \",\n\"               +++$$$@@$$$#$$......$$$$$$$$$$$+++               \",\n\"               ++$$$@$$$$$$$$......$$$$$$$$$$$$++               \",\n\"              ++$$$@@$$$$$$$$......$$$$$$$$$$$$+++              \",\n\"              ++$$$@$$$$$$$$$......$$$$$$$$$$$$$++              \",\n\"             ++$$$@@@$$$###$$......$$$$$$$$$$$$$+++             \",\n\"            +++$$$$$$$$$$$$$$......$$$$$$$$$$$$$$+++            \",\n\"            ++$$$@@$$#$#####$......$$$$$$$$$$$$$$$++            \",\n\"           +++$$$@@$$$$$$$$$$......$$$$$$$$$$$$$$$+++           \",\n\"           ++$$$@@$$$$$$$$$$$$@@@@$$$$$$$$$$$$$$$$$++           \",\n\"          ++$$$$@$$$$$$$$$$$$@@@@@@$$$$$$$$$$$$$$$$+++          \",\n\"          ++$$$@$$$$$$$$$$$$$@@@@@@$$$$$$$$$$$$$$$$$++          \",\n\"         ++$$$$@$$$$$$$$$$$$$$....$$$$$$$$$$$$$$$$$$+++         \",\n\"        +++$$$@@$$$$$$$$$$$$$......$$$$$$$$$$$$$$$$$$+++        \",\n\"        ++$$$$@@$$$$$$$$$$$$$......$$$$$$$$$$$$$$$$$$$++        \",\n\"       +++$$$@@$$$$$$$$$$$$$$......$$$$$$$$$$$$$$$$$$$+++       \",\n\"       ++$$$$$@$$$$$$$$$$$$$$......$$$$$$$$$####$$$$$$$++       \",\n\"      +++$$$$$$$###$$$$####$$......$$####$$$$$$$$$$$$$$+++      \",\n\"      ++$$$$$$$$$$$$$$$$$$$$$$....$$$$$$$$$$$$$$$$$$$$$$++      \",\n\"     +++$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+++     \",\n\"     ++$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$++     \",\n\"     ++$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$++     \",\n\"     ++$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$++     \",\n\"     ++++++++++++++++++++++++++++++++++++++++++++++++++++++     \",\n\"     ++++++++++++++++++++++++++++++++++++++++++++++++++++++     \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\n\nBtn_Refresh_Aqua_Highlight_icon = \"\"\"\n/* XPM */\nstatic char * Btn_Refresh_Aqua_Highlight_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 5 1\",\n\"   c None\",\n\".  c #191ED6\",\n\"+  c #19EED7\",\n\"@  c #1913D7\",\n\"#  c #0FD902\",\n\"                                                                \",\n\"                                                                \",\n\"                               .........                        \",\n\"                             .............                      \",\n\"                            ..+++++++++++....                   \",\n\"                           ..+++++++++++++++..                  \",\n\"                          ..+++++++++++++++++..                 \",\n\"                         ..+++++++++++++++++++..                \",\n\"                        ..+++++++++++++++++++++..               \",\n\"                       ..+++++++++++++++++++++++..              \",\n\"                      ..+++........++++++++++++++..             \",\n\"                      ..++..      ..+++++++++++++..             \",\n\"                     ..++..        ..+++++++++++++..            \",\n\"                     .++..          ..+++++++++++++.            \",\n\"                     .++..           ..++++++++++++..           \",\n\"                     .++.             ..+++++++++++..           \",\n\"                     ....             ..++++++++++++.           \",\n\"                                       .++++++++++++.           \",\n\"                                       .++++++++++++.           \",\n\"                              ..........++++++++++++.           \",\n\"                              .+++++++++++++++++++++........... \",\n\"                              .+++++++++++++++++++++........... \",\n\"                              ..+++++++++++++++++++++++++++++.. \",\n\"                               ..+++++++++++++++++++++++++++..  \",\n\"                                ..+++++++++++++++++++++++++..   \",\n\"                                 ..+++++++++++++++++++++++..    \",\n\"                 @@               ..+++++++++++++++++++++..     \",\n\"                @@@@               ..+++++++++++++++++++..      \",\n\"               @@##@@               ..+++++++++++++++++..       \",\n\"              @@####@@               ..+++++++++++++++..        \",\n\"             @@######@@               ..+++++++++++++..         \",\n\"            @@########@                ..+++++++++++..          \",\n\"           @@#########@@                ..+++++++++..           \",\n\"          @@###########@@                .++++++++..            \",\n\"         @@#############@@               ..++++++..             \",\n\"        @@###############@@               ..++++..              \",\n\"       @@#################@@               ..++..               \",\n\"      @@###################@@               ....                \",\n\"     @@#####################@@               ..                 \",\n\"    @@#######################@@                                 \",\n\"   @@#########################@@                                \",\n\"  @@###########################@@                               \",\n\" @@#############################@@                              \",\n\" @@@@@@@@@@@#####################@                              \",\n\" @@@@@@@@@@@#####################@                              \",\n\"           @############@@@@@@@@@@                              \",\n\"           @############@                                       \",\n\"           @############@                                       \",\n\"           @############@@             @@@@                     \",\n\"           @@###########@@             @##@                     \",\n\"           @@############@@           @@##@                     \",\n\"            @#############@@          @@##@                     \",\n\"            @@#############@@        @@##@@                     \",\n\"             @@#############@@      @@##@@                      \",\n\"             @@##############@@@@@@@@###@@                      \",\n\"              @@#######################@@                       \",\n\"               @@#####################@@                        \",\n\"                @@###################@@                         \",\n\"                 @@#################@@                          \",\n\"                  @@###############@@                           \",\n\"                   @@@@###########@@                            \",\n\"                      @@@@@@@@@@@@@                             \",\n\"                        @@@@@@@@@                               \",\n\"                                                                \"\n};\"\"\"\n\nBtn_Quit_icon = \"\"\"\n/* XPM */\nstatic char * Btn_Quit_icon_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 6 1\",\n\"   c None\",\n\".  c #000000\",\n\"+  c #BF0001\",\n\"@  c #BE0209\",\n\"#  c #EBE9E6\",\n\"$  c #F1F6F8\",\n\"                                                                \",\n\"                                                                \",\n\"                          ...........                           \",\n\"                      .....@@@@@@@@@.....                       \",\n\"                   ....@@@@@@@@@@@@@@@@@....                    \",\n\"                 ...@@@@@@@@@@@@@@@@@@@@@@@...                  \",\n\"               ...@@@@@@@@@@@@@@@@@@@@@@@@@@@...                \",\n\"              ..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@..               \",\n\"             ..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@..              \",\n\"            ..@@@@@@@@@@@+++++$$$++++++@@@@@@@@@@..             \",\n\"          ...@@@@@@@@@@++++++$$$$$+++++++@@@@@@@@@...           \",\n\"          .@@@@@@@@@@+++++++$$$$$$$++++++++@@@@@@@@@.           \",\n\"         ..@@@@@@@@+++++++@$$$$$$$$$+++++++++@@@@@@@..          \",\n\"        ..@@@@@@@@+++++@@+@$$$$$$$$$@+@+++++++@@@@@@@..         \",\n\"       ..@@@@@@@@++++++@@@@$$$$$$$$$@@@@+++++++@@@@@@@..        \",\n\"      ..@@@@@@@@+++++$$@@@@$$$$$$$$$@@@@$$++++++@@@@@@@..       \",\n\"      .@@@@@@@@+++++$$$@@@@$$$$$$$$$@@@@$$$++++++@@@@@@@.       \",\n\"     ..@@@@@@@++++$$$$$@@@@$$$$$$$$$@@@@$$$$$+++++@@@@@@..      \",\n\"     .@@@@@@@++++$$$$$$@@+@$$$$$$$$$@+@@$$$$$$+++++@@@@@@.      \",\n\"    ..@@@@@@+++++$$$$$$@@++$$$$$$$$$@+++$$$$$$++++++@@@@@..     \",\n\"    .@@@@@@@++++$$$$$@@@@@+$$$$$$$$$++++++$$$$$+++++@@@@@@.     \",\n\"    .@@@@@@++++$$$$$@@@@@@+$$$$$$$$$+++++++$$$$$+++++@@@@@.     \",\n\"   ..@@@@@@++++$$$$$+@@@@@@$$$$$$$$$+++++@@$$$$$+++++@@@@@..    \",\n\"   .@@@@@@++++$$$$$++++@@@@$$$$$$$$$++++@@@@$$$$$+++++@@@@@.    \",\n\"   .@@@@@@++++$$$$++++++@@@$$$$$$$$$++@@@@@@+$$$$+++++@@@@@.    \",\n\"   .@@@@@@++++$$$$+++++++@@$$$$$$$$$@@@@@@@++$$$$+++++@@@@@.    \",\n\"  ..@@@@@++++$$$$+++++++++@$$$$$$$$$@@@@@@++++$$$$+++++@@@@..   \",\n\"  .@@@@@@+++$$$$$++++++++++$$$$$$$$$@@@@@+++++$$$$$++++@@@@@.   \",\n\"  .@@@@@@+++$$$$$++++++++++$$$$$$$$$@@@@++++++$$$$$++++@@@@@.   \",\n\"  .@@@@@@+++$$$$+++++++++++$$$$$$$$$@@@++++++++$$$$++++@@@@@.   \",\n\"  .@@@@@@+++$$$$++++++++++++$$$$$$$@@@@++++++++$$$$++++@@@@@.   \",\n\"  .@@@@@@+++$$$$+++++++++++++$$$$$@@@@+++++++++$$$$++++@@@@@.   \",\n\"  .@@@@@@+++$$$$+++++++++++++@$$$@@@@@@++++++++$$$$++++@@@@@.   \",\n\"  .@@@@@@+++$$$$+++++++++++++@@@@@@@@@@++++++++$$$$++++@@@@@.   \",\n\"  .@@@@@@+++$$$$$++++++++++++@@@@@@@@@@@++++++$$$$$++++@@@@@.   \",\n\"  .@@@@@@+++$$$$$++++++++++++@@@@@@@@@@@++++++$$$$$++++@@@@@.   \",\n\"  ..@@@@@++++$$$$++++++++++++@@@@@@@@@@@++++++$$$$+++++@@@@..   \",\n\"   .@@@@@+++++$$$$++++++++++@@@@@@@@@@@@@++++$$$$++++++@@@@.    \",\n\"   .@@@@@@++++$$$$++++++++@@@@@@++++@@@@@++++$$$$+++++@@@@@.    \",\n\"   .@@@@@@++++$$$$$++++@@@@@+++++++++@@@@@++$$$$$+++++@@@@@.    \",\n\"   ..@@@@@+++++$$$$$++@@@@+++++++++++@@@@@@$$$$$++++++@@@@..    \",\n\"    .@@@@@@++++$$$$$++@@@++++++++++++@@@@@@$$$$$+++++@@@@@.     \",\n\"    .@@@@@@+++++$$$$$++@++++++++++++++++++$$$$$++++++@@@@@.     \",\n\"    ..@@@@@@+++++$$$$$$+++++++++++++++++$$$$$$++++++@@@@@..     \",\n\"     .@@@@@@+++++$$$$$$$+++++++++++++++$$$$$$$++++++@@@@@.      \",\n\"     ..@@@@@@+++++$$$$$$$$+++++++++++$$$$$$$$++++++@@@@@..      \",\n\"      .@@@@@@@++++++$$$$$$$$$+++++$$$$$$$$$+++++++@@@@@@.       \",\n\"      ..@@@@@@@++++++$$$$$$$$$$$$$$$$$$$$$+++++++@@@@@@..       \",\n\"       ..@@@@@@@+++++++$$$$$$$$$$$$$$$$$++++++++@@@@@@..        \",\n\"        ..@@@@@@@+++++++++$$$$$$$$$$$++++++++++@@@@@@..         \",\n\"         ..@@@@@@@++++++++++$$$$$$$+++++++++++@@@@@@..          \",\n\"          .@@@@@@@@++++++++++++++++++++++++++@@@@@@@.           \",\n\"          ...@@@@@@@@++++++++++++++++++++++@@@@@@@...           \",\n\"            ..@@@@@@@@@++++++++++++++++++@@@@@@@@..             \",\n\"             ..@@@@@@@@@@++++++++++++++@@@@@@@@@..              \",\n\"              ..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@..               \",\n\"               ...@@@@@@@@@@@@@@@@@@@@@@@@@@@...                \",\n\"                 ...@@@@@@@@@@@@@@@@@@@@@@@...                  \",\n\"                   ....@@@@@@@@@@@@@@@@@....                    \",\n\"                      .....@@@@@@@@@.....                       \",\n\"                          ...........                           \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\n\npythonFC_icon = \"\"\"\n/* XPM */\nstatic char * Python_FC_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 7 1\",\n\"   c None\",\n\".  c #390602\",\n\"+  c #630E02\",\n\"@  c #FF3302\",\n\"#  c #366E9E\",\n\"$  c #3D74CC\",\n\"%  c #FCE84F\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"   ...............................                              \",\n\"   .+++++++++++++++++++++++++++++.                              \",\n\"   .+@@@@@@@@@@@@@@@@@@@@@@@@@@@+.                              \",\n\"   .+@@@@@@@@@@@@@@@@@@@@@@@@@@@+.                              \",\n\"   .+@@@@@@@@@@@@@@@@@@@@@@@@@@@+.                              \",\n\"   .+@@@@@@@@@@@@@@@@@@@@@@@@@@@+.                              \",\n\"   .+@@@@@@@@@@@@@@@@@@@@@@@@@@@+.                              \",\n\"   .+@@@@@@@@@@@@@@@@@@@@@@@@@@@+.                              \",\n\"   .+@@@@@@@@@@@@@@@@@@@@@@@@@@@+.                              \",\n\"   .+@@@@@@@@@@@@@@@@@@@@@@@@@@@+.                              \",\n\"   .+@@@@@@@@@@@@@@@@@@@@@@@@@@@+.                              \",\n\"   .+@@@@@@@@@@@@@@@@@@@@@@@@@@@+.                              \",\n\"   .+@@@@@@@@@@@@@@@@@@@@@@@@@@@+.                              \",\n\"   .+@@@@@@@@++++++++++++++++++++.                              \",\n\"   .+@@@@@@@@+....................                              \",\n\"   .+@@@@@@@@+.                     ########                    \",\n\"   .+@@@@@@@@+.                  ##############                 \",\n\"   .+@@@@@@@@+.                 ################                \",\n\"   .+@@@@@@@@+.                ##################               \",\n\"   .+@@@@@@@@+.               ###   ##############              \",\n\"   .+@@@@@@@@+.               ###   ##############              \",\n\"   .+@@@@@@@@+.               ###   ##############              \",\n\"   .+@@@@@@@@+........        ####################              \",\n\"   .+@@@@@@@@++++++++.        ####################              \",\n\"   .+@@@@@@@@@@@@@@@+.        ####################              \",\n\"   .+@@@@@@@@@@@@@@@+.                  ##########              \",\n\"   .+@@@@@@@@@@@@@@@+. ########################### %%%%%%       \",\n\"   .+@@@@@@@@@@@@@@@+.############################ %%%%%%%%     \",\n\"   .+@@@@@@@@++++++++.############################ %%%%%%%%     \",\n\"   .+@@@@@@@@+........############################ %%%%%%%%%    \",\n\"   .+@@@@@@@@+.     ############################## %%%%%%%%%    \",\n\"   .+@@@@@@@@+.     ############################## %%%%%%%%%    \",\n\"   .+@@@@@@@@+.     ############################## %%%%%%%%%    \",\n\"   .+@@@@@@@@+.    ##############################  %%%%%%%%%%   \",\n\"   .+@@@@@@@@+.    ############################## %%%%%%%%%%%   \",\n\"   .+@@@@@@@@+.    ############################  %%%%%%%%%%%%   \",\n\"   .+@@@@@@@@+.    ##############              %%%%%%%%%%%%%%   \",\n\"   .+@@@@@@@@+.    ############  %%%%%%%%%%%%%%%%%%%%%%%%%%%%   \",\n\"   .+@@@@@@@@+.    ########### %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%   \",\n\"   .+@@@@@@@@+.    ##########  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%   \",\n\"   .+@@@@@@@@+.     ######### %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    \",\n\"   .+@@@@@@@@+.     ######### %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    \",\n\"   .+@@@@@@@@+.     ######### %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    \",\n\"   .+@@@@@@@@+.     ######### %%%%%%%%%%%%%%%%%%%%%%%%%%%%%     \",\n\"   .+@@@@@@@@+.      ######## %%%%%%%%%%%%%%%%%%%%%%%%%%%%%     \",\n\"   .+@@@@@@@@+.      ######## %%%%%%%%%%%%%%%%%%%%%%%%%%%%      \",\n\"   .+@@@@@@@@+.        ###### %%%%%%%%%%%%%%%%%%%%%%%%%%%       \",\n\"   .++++++++++.               %%%%%%%%%%                        \",\n\"   ............               %%%%%%%%%%%%%%%%%%%%              \",\n\"                              %%%%%%%%%%%%%%%%%%%%              \",\n\"                              %%%%%%%%%%%%%%%%%%%%              \",\n\"                              %%%%%%%%%%%%%%   %%%              \",\n\"                              %%%%%%%%%%%%%%   %%%              \",\n\"                              %%%%%%%%%%%%%%   %%%              \",\n\"                               %%%%%%%%%%%%%%%%%%               \",\n\"                                %%%%%%%%%%%%%%%%                \",\n\"                                 %%%%%%%%%%%%%%                 \",\n\"                                    %%%%%%%%                    \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\n\npythonPY_icon = \"\"\"\n/* XPM */\nstatic char * python_xpm[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 6 1\",\n\"   c None\",\n\".  c #2E6C9F\",\n\"+  c #3A76AA\",\n\"@  c #3E84B7\",\n\"#  c #FFD63E\",\n\"$  c #FFDF58\",\n\"                                                                \",\n\"                        @@@@@@@@@@@@@@++                        \",\n\"                     @@@@@@@@@@@@@@@@@@+++                      \",\n\"                    @@@@@@@@@@@@@@@@+@+++++                     \",\n\"                   @@@@@@@@@@@@@@@+++@@+++++                    \",\n\"                  @@@@@@@@@@@@@@@@@@@++++++++                   \",\n\"                  @@@@   @@@@@@@@@@@+++++++++.                  \",\n\"                 @@@@     @@@@@@@@@++++++++++.                  \",\n\"                 @@@@     @@@@@@@@++++++++++..                  \",\n\"                 @@@@     @@@@@@@++++++++++....                 \",\n\"                 @@@@@   @@@@++++@++++++++.....                 \",\n\"                 @@@@@@@@@@@+@+@@++++++++......                 \",\n\"                 @@@@@@@@@@@@@@+++++++++.......                 \",\n\"                  @@@@@@@@@@@@++++++++++.......                 \",\n\"                   @@@@@@@@@@@@++++++++........                 \",\n\"                                ++++++.........                 \",\n\"             @@@@@@@@@@@@@@@@@@++++++..........                 \",\n\"       @@@@@@@@@@@@@@@@++++@++++++++...........                 \",\n\"      @@@@@@@@@@@@@@@@+@@@+++++++++............                 \",\n\"     @@@@@@@@@@@@@@@@@@@@+++++++++.............                 \",\n\"     @@@@@@@@@@@@@@@@@@@++++++++++.............                 \",\n\"    @@@@@@@@@@@@@@@@@@@++++++++++..............                 \",\n\"   @@@@@@@@@@@@@@@@@@@++++++++++...............  $$$$$$         \",\n\"   @@@@@@@@@@@@@@@@+++@++++++++................ $$$$$$$$$       \",\n\"   @@@@@@@@@@@@@@+@+@@++++++++................. $$$$$$$$$$$     \",\n\"  @@@@@@@@@@@@@@@@@@@@@++++++.................. $$$$$$$$$$$$    \",\n\"  @@@@@@@@@@@@@@@@@@@++++++++.................  $$$$$$$$$$$$$   \",\n\"  @@@@@@@@@@@@@@@@++++++++++.................   $$$$$$$$$$$$$   \",\n\"  @@@@@@@@@@@@@@@++++++++++.................    $$$$$$$$$$$$$$  \",\n\"  @@@@@@@@@@@@@@++++++++++.................    $$$$$$$$$$$$$$$  \",\n\"  @@@@@@@@@@@@@++++++++++................     $$$$$$$$$$$$$$##  \",\n\"  @@@@@@@@@@@@@++++                          $$$$$$$$$$$$$$###  \",\n\"  @@@@@@@@@@@@++++    $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$####  \",\n\"  @@@@@@@@@@@++++    $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$######  \",\n\"  @@@@@@@@@@++++    $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$#######  \",\n\"  @@@@@@@@@+++++   $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$#########  \",\n\"  @@@@@@@@++++++  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$##########  \",\n\"  @@@@@@@@++++++  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$###########  \",\n\"   @@@@@@+++++++  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$#############  \",\n\"   @@@@@+++++++   $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$#############   \",\n\"    @@@++++++++   $$$$$$$$$$$$$$$$$$$$$$$$$$$$###############   \",\n\"    @@+++++++++   $$$$$$$$$$$$$$$$$$$$$$$$$$$################   \",\n\"     ++++++++++  $$$$$$$$$$$$$$$$$$$$$$$$$$$################    \",\n\"     @+++++++++  $$$$$$$$$$$$$$$$$$$$$$$$$#################     \",\n\"       ++++++++  $$$$$$$$$$$$$$$$$$$$$$$$#################      \",\n\"        ++++.+   $$$$$$$$$$$$$$$$$$$$$$##################       \",\n\"                 $$$$$$$$$$$$$$$$$$$                            \",\n\"                 $$$$$$$$$$$$$$$$$$                             \",\n\"                 $$$$$$$$$$$$$$$$$$##########                   \",\n\"                 $$$$$$$$$$$$$$$$$############                  \",\n\"                 $$$$$$$$$$$$$$$###############                 \",\n\"                 $$$$$$$$$$$$$$################                 \",\n\"                 $$$$$$$$$$$$$#########   #####                 \",\n\"                 $$$$$$$$$$$$#########     ####                 \",\n\"                 $$$$$$$$$$$##########     ####                 \",\n\"                 $$$$$$$$$$###########     ###                  \",\n\"                  $$$$$$$$#############   ####                  \",\n\"                  $$$$$######################                   \",\n\"                    $#######################                    \",\n\"                      #####################                     \",\n\"                        #################                       \",\n\"                          #############                         \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\n\ntools_icon = \"\"\"\n/* XPM */\nstatic char * tools_icon[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 8 1\",\n\"   c None\",\n\".  c #000000\",\n\"+  c #11468A\",\n\"@  c #3167A7\",\n\"#  c #6295D2\",\n\"$  c #ADB2B4\",\n\"%  c #EDD400\",\n\"&  c #D7DCDF\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                   .......                                      \",\n\"                  ..%%%%%%...                       ...         \",\n\"                  .%%%%%%%%%..                     .$$.         \",\n\"                   .%%%%%%%%%..                  ..&&$$..       \",\n\"                    ..%%%%%%%%.                 ..&&&&$$..      \",\n\"                     ..%%%%%%%.               ..&&&&&&&$$..     \",\n\"                       .%%%%%%%.             ..&&&&&&&&&$..     \",\n\"                       .%%%%%%%.            ..&&&&&&&&&&&.      \",\n\"                       .%%%%%%%%.           .&&&&&&&&&&&.       \",\n\"                       .%%%%%%%%.           .&&$$&&&&&&..       \",\n\"         ...           .%%%%%%%%.           .&&$&&&&&&&.        \",\n\"        ..%%.         ..%%%%%%%%.           .&&$&&$&&&.         \",\n\"        .%%%%.        .%%%%%%%%%.          ..&&$$$$&&.          \",\n\"        .%%%%%.     ..%%%%%%%%%.          ..&&$&&&&&..          \",\n\"        .%%%%%%......%%%%%%%%%%.         ..&&$&&&&&&.           \",\n\"        ..%%%%%%%%%%%%%%%%%%%%%..       ..&&$&&.....            \",\n\"         .%%%%%%%%%%%%%%%%%%%%%%..     ..&&$&&..                \",\n\"         .%%%%%%%%%%%%%%%%%%%%%%%..   ..&&$&&..                 \",\n\"          .%%%%%%%%%%%%%%%%%%%%%%%.. ..&&$&&..                  \",\n\"          ..%%%%%%%%%%%%%%%%%%%%%%%...&&$&&..                   \",\n\"           ..%%%%%%%%%%%%%%%%%%%%%%..&&$&&..                    \",\n\"            ...%%%%%%%...%%%%%%%%%..&&$&&..                     \",\n\"               .......  ..%%%%%%%..&&$&&..                      \",\n\"                         ..%%%%%..&&$&&..                       \",\n\"                          ..%%%..&&$&&....                      \",\n\"                           ..%..&&$&&..%%..                     \",\n\"                         +++@..&&$&&..%%%%..                    \",\n\"                        ++++++&&$&&..%%%%%%..                   \",\n\"                       ++#&##++&&&..%%%%%%%%..                  \",\n\"                      ++##&&##++&..%%%%%%%%%%..                 \",\n\"                     ++##&&&@##++.%%%%%%%%%%%%..                \",\n\"                    ++#####@@@##+@%%%%%%%%%%%%%..               \",\n\"                   ++######@@@@#@+.%%%%%%%%%%%%%..              \",\n\"                  ++######@@@@@#++..%%%%%%%%%%%%%..             \",\n\"                 ++######@@@@@#++  ..%%%%%%%%%%%%%..            \",\n\"                ++######@@@@@@#++   ..%%%%%%%%%%%%%..           \",\n\"              +++######@@@@@@#++     ..%%%%%%%%%%%%%..          \",\n\"             ++######&@@@@@@#++       ..%%%%%%%%%%%%%..         \",\n\"            ++#####&&@@@@@@#++         ..%%%%%%%%%%%%%..        \",\n\"          +++####&&#@@@@@@#++           ..%%%%%%%%%%%%%..       \",\n\"         ++####&&&#@@@@@@#++             ..%%%%%%%%%%%%%.       \",\n\"        ++###&&&&#@@@@@@#++               ..%%%%%%%...%%..      \",\n\"       ++###&&&&#@@@@@@#++                 ..%%%%%.. ..%%.      \",\n\"      ++##&&&&&#@@@@@@#++                   ..%%%%.   .%%.      \",\n\"      ++##&&&#@@@@@@@@#+                     ..%%%.. ..%%.      \",\n\"      ++#####@@@@@@@@#++                      ..%%%...%%..      \",\n\"       +####@@@@@@@@##+                        ..%%%%%%%.       \",\n\"       ++##@@@@@@@@@#++                         ..%%%%...       \",\n\"        ++##@@@@@@@#++                           ......         \",\n\"        +++##@@@@@##+                                           \",\n\"         +++##@@@##+                                            \",\n\"          ++++###+++                                            \",\n\"            ++++++                                              \",\n\"              +++                                               \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\n\nhigh_Light_icon = \"\"\"\n/* XPM */\nstatic char * high_Light_icon[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"   c None\",\n\".  c #000000\",\n\"+  c #05989A\",\n\"@  c #888A87\",\n\"#  c #00EED5\",\n\"$  c #14EBD9\",\n\"%  c #30E5E2\",\n\"&  c #DDEFE8\",\n\"*  c #ECEFEB\",\n\"     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@     \",\n\"     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@     \",\n\"     @@**************************************************@@     \",\n\"     @@**************************************************@@     \",\n\"     @@**************************************************@@     \",\n\"     @@**************************************************@@     \",\n\"     @@**************************************************@@     \",\n\"     @@**************************************************@@     \",\n\"     @@**************************************************@@     \",\n\"     @@***##########################################*****@@     \",\n\"     @@***##########################################*****@@     \",\n\"     @@***##########################################*****@@     \",\n\"     @@***##+++++++++++++++##+++++++++++++++++++++##*****@@     \",\n\"     @@***##+++++++++++++++##+++++++++++++++++++++##*****@@     \",\n\"     @@***##+++++++++++++++##+++++++++++++++++++++##*****@@     \",\n\"     @@***##+++++++++++++++#########################*****@@     \",\n\"     @@***##+++++++++++++++#########################*****@@     \",\n\"     @@***##+++++++++++++++******************************@@     \",\n\"     @@***##+++++++++++++++######################********@@     \",\n\"     @@***##+++++++++++++++######################********@@     \",\n\"     @@***##+++++++++++++++##++++++++++++++++++##********@@     \",\n\"     @@***##+++++++++++++++##++++++++++++++++++##********@@     \",\n\"     @@***##+++++++++++++++##++++++++++++++++++##********@@     \",\n\"     @@***##+++++++++++++++######################********@@     \",\n\"     @@***##+++++++++++++++######################********@@     \",\n\"     @@***##+++++++++++++++******************************@@     \",\n\"     @@***##################################*************@@     \",\n\"     @@***##################################*************@@     \",\n\"     @@***##++++++++++++++++++++++++++++++##*************@@     \",\n\"     @@***##++++++++++++++++++++++++++++++##*************@@     \",\n\"     @@***##++++++++++++++++++++++++++++++##*************@@     \",\n\"     @@***##################################*************@@     \",\n\"     @@***##################################*************@@     \",\n\"     @@***##*********************************************@@     \",\n\"     @@***########################################*******@@     \",\n\"     @@***########################################*******@@     \",\n\"     @@***##++++++++++++++++++++++++++++++++++++##*******@@     \",\n\"     @@***##++++++++++++++++++++++++++++++++++++##*******@@     \",\n\"     @@***##++++++++++++++++++++++++++++++++++++##*******@@     \",\n\"     @@***########################################*******@@     \",\n\"     @@***##########################....##########*******@@     \",\n\"     @@***##************************....*&&&&&&&&&*******@@     \",\n\"     @@***##########################*..*##$$$$######*****@@     \",\n\"     @@***##########################*..*#######$$$$#*****@@     \",\n\"     @@***##++++++++++++++++++++++##*..*$$++++++++%%*****@@     \",\n\"     @@***##++++++++++++++++++++++##*..*$$++++++++##*****@@     \",\n\"     @@***##++++++++++++++++++++++##*..*$$++++++++#%*****@@     \",\n\"     @@***##########################*..*$#%%%%%%%%##*****@@     \",\n\"     @@***##########################*..*$#%%%%%%%%%%*****@@     \",\n\"     @@******************************..******************@@     \",\n\"     @@*****************************....*****************@@     \",\n\"     @@*****************************....*****************@@     \",\n\"     @@**************************************************@@     \",\n\"     @@**************************************************@@     \",\n\"     @@**************************************************@@     \",\n\"     @@**************************************************@@     \",\n\"     @@**************************************************@@     \",\n\"     @@**************************************************@@     \",\n\"     @@**************************************************@@     \",\n\"     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@     \",\n\"     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@     \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\n\ngoto_To_Menu_icon = \"\"\"\n/* XPM */\nstatic char * goto_To_Menu_icon[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 7 1\",\n\"   c None\",\n\".  c #000000\",\n\"+  c #2E3436\",\n\"@  c #234A88\",\n\"#  c #555753\",\n\"$  c #888A85\",\n\"%  c #F6F9F6\",\n\"                                                                \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%...........................................%%%%+++    \",\n\"    +%%%%%$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%+++    \",\n\"    +%%%%%$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%+++    \",\n\"    +%%%%%$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%+++    \",\n\"    +%%%%%$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%+++    \",\n\"    +%%%%%$$$$$$$$$$$$$$$$$..$$$$$$$$$$$$$$$$$$$$$$$$%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%.@@.%%%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%.@@@@.%%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%.@@@@@@.%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%.@@@@@@@@.%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%.............@@@@@@@@@@....................%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%.@@@@@@@@@@@@.%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%.@@@@@@@@@@@@@.%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%.@@@@@@@@@@@@@@@.%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%.@@@@@@@@@@@@@@@@@.%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%.@@@@@@@@@@@@@@@@@@@.%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%.@@@@@@@@@@@@@@@@@@@@@.%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%.@@@@@@@@@@@@@@@@@@@@@@@.%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%.@@@@@@@@@@@@@@@@@@@@@@@@@.%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%.@@@@@@@@@@@@@@@@@@@@@@@@@@@.%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@...........%%%%+++    \",\n\"    +%%%%%..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.%%%%%%%%%%%%%+++    \",\n\"    +%%%%%.@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.%%%%%%%%%%%%+++    \",\n\"    +%%%%%.@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.%%%%%%%%%%%%+++    \",\n\"    +%%%%%.@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.%%%%%%%%%%%%+++    \",\n\"    +%%%%%...........@@@@@@@@@@@@@@@@@@@@@@@.%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%.@@@@@@@@@@@@@@..........%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%.@@@@@@@@@@@@@@..%%%%%%%%%%%......%%%+++    \",\n\"    +%%%%%%%%%%%%%%%.@@@@@@@@@@@@@@@.%%%%%%%%%%%.@@@@.%%%+++    \",\n\"    +%%%%%%%%%%%%%%%.@@@@@@@@@@@@@@@.%%%%%%%%%%%.@@@@.%%%+++    \",\n\"    +%%%%%...........@@@@@@@@@@@@@@@@...........@@@@@.%%%+++    \",\n\"    +%%%%%%%%%%%%%%%..@@@@@@@@@@@@@@@@.%%%%%%%%.@@@@@.%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%.@@@@@@@@@@@@@@@@@.%%%%%%.@@@@@@.%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%..@@@@@@@@@@@@@@@@@......@@@@@@..%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%.@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%.@@@@@@@@@@@@@@@@@@@@@@@@@@@.%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%.@@@@@@@@@@@@@@@@@@@@@@@@@.%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%.@@@@@@@@@@@@@@@@@@@@@@@.%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%.@@@@@@@@@@@@@@@@@@@@@.%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%.@@@@@@@@@@@@@@@@@@@.%%%%%%%%%+++    \",\n\"    +%%%%%...................@@@@@@@@@@@@@@@@@.......%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%...@@@@@@@@@@@@@.%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%%%%..@@@@@@@@@..%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.........%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++    \",\n\"                                                                \"\n};\"\"\"\n\n\n\npythonToForum_icon = \"\"\"\n/* XPM */\nstatic char * pythonToForum_icon[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"   c None\",\n\".  c #000000\",\n\"+  c #1A1B4D\",\n\"@  c #284F84\",\n\"#  c #FF3000\",\n\"$  c #6B8CB4\",\n\"%  c #94999E\",\n\"&  c #D2D7D9\",\n\"*  c #FEE849\",\n\"                                                                \",\n\" .....................                                          \",\n\" .###################.                                          \",\n\" .###################.                                          \",\n\" .###################.       ++++++++                           \",\n\" .###################.     ++++++++++++                         \",\n\" .###################.+++++$%%%&&&%%$$@++++                     \",\n\" .###################.+@&&&&&&&&&&&&&&&&$@++                    \",\n\" .###################.&&&&&&&&&&&&&$$$$$&&&$+++                 \",\n\" .###################.&&&$%&&&&&&&%&%%$$$$$&%@++                \",\n\" .###################.&&%&&&&&&&&&%&&%%$$$$$&&%++               \",\n\" .######..............%@@@@@&&&%%%&&&&%$$%&&&&&&@+              \",\n\" .######.     +$&&&&$@@@@@@@@@%&&&&%&&%%%&&%%&&%&%+             \",\n\" .######.    +$&&%$%@@@@@@@@@@@&&&%%&&&%&&&$&&&&&&%+            \",\n\" .######.   +@&&%&&@@@&@@@@@@@@@&&&&&&%%&%&$%&&&&&&%+           \",\n\" .######.  ++&&&%&&@@&&&@@@@@@@@@&&&&&%%%%%$&&&&&&&&@+          \",\n\" .######......&&&&&@@@&@@@@@@@@@@&&&&%&%&&&&&&&&&&&&&@+         \",\n\" .###########.&&&&&@@@@@@@@@@@@@@&&&&%&&&&&&&&&&&&&&&&+         \",\n\" .###########.&&&&&&&%&&&&@@@@@@@....&&&&&&&&&&&&&&&&&%+        \",\n\" .###########.@@@@@@@@@@@@@@@@@@@****.&&&&&&&&&&&&&&&&&+        \",\n\" .###########.@@@@@@@@@@@@@@@@@@@*****.&%%&%&&&&&&&&&&&%+       \",\n\" .######......@@@@@@@@@@@@@@@@@@@******.%$%%&%&&&&&&&&&&++      \",\n\" .######.&&&&@@@@@@@@@@@@@@@@@@@@******.%$$$%$%&&&&&&&&&@+      \",\n\" .######.&&&@@@@@@@@@@@@@@@@@@@@@******.&&%$$$$@@&&&&&%&%+      \",\n\" .######.&&&@@@@@@@@@@@@@@@@@@@@@*******.&&%&%$$%&&&&&%&&++     \",\n\" .######.&&&@@@@@@@@@@@@@@@@@@@@********.&&&&&&&&&&&&%%%&@+     \",\n\" .######.&&$@@@@@@@@............********.&&&&&&&&%&&&$%%&%+     \",\n\" .######.&$$@@@@@@@@********************.&&&&&&&&@%&&%@@%%+     \",\n\" .######.&$$@@@@@@@@********************.&&&&&&&&%$&&&%%$$+     \",\n\" .######.&$$@@@@@@@********************.&&&&&&&&&&@%&%%%$$+     \",\n\" .######.&&&@@@@@@@********************.&&&&&&&&&&%$&%%@@$+     \",\n\" .######.%&&&@@@@@@*******************.&&&&&&&&&&&&@%%@@@$+     \",\n\" .######.$$%&&@@@@@*******************.&&&&&&&&&&&&$%@@@$$+     \",\n\" ........$$$$&%%&&.********...........&&&&&&&&&&&&&&%%@@$$+     \",\n\"      ++&$$$$$%%&&.**************.$&&&&&&&&&&&&&&&&%%%@@$@+     \",\n\"      ++&$$$$$$&&&.**********.***.$$&%%$%%&&&&&&&&&%%@@@$@+     \",\n\"      ++&$$$$$$&&&.*********...**.$$$$$$$$&&&&&&&&%%%@@@$@+     \",\n\"       +$%$$$$$&&&&.*********.***.$$$$$$$$&&&&&&&%%%@@@@$++     \",\n\"       +@&$$$$%&&&&&.***********.$$$$$$$$$%&&&&&&%%%@@@$$++     \",\n\"       ++&$$$$&&&&&&&.********..$$$$$$$$$@%&&&&&%%%@@@@$@+      \",\n\"        +$$$$$%&&&&&&&..*****.$$$$$$$$$$@@$&&&&%%%%@@@@$++      \",\n\"        +@&$$$$&&&&&&&&&.....$$$$$$$$$$@@@@&&&%%%%%@@@$$+       \",\n\"        ++$$$$$$&&&&&&&&&&&%$$$$$$$$$@@@@@$&&%%%%%%@@@$++       \",\n\"         +@%$@$$%&&&&&&&&&&$$$$$$$$$@@@@@@$%%%%%%%%@@$@+        \",\n\"          +$$@@@$$&&&&&&&&&$$$$$$@@@@@@@@@$%%%%%%%@@@$++        \",\n\"           +$$@@@@%&&&&&&&&@$@@@@@@@@@@@@@$%%%%%%@@@$@+         \",\n\"           +@$$@@@%&&&&&&%%@@@@@@@@@@@@@@@@%%%%%%@@$@++         \",\n\"            +@$$@@%&&&&&%@@@@@@@@@@@@@@@@@@%%%%%%@$$++          \",\n\"            ++$$$@$&&&&&%@@@@@@@@@@@@@@@@@@@%%%%%$$++           \",\n\"             ++$$$$%%%%%%@@@@@@@@@@@@@@@@@@@%%%%$$++            \",\n\"              ++@$%%%%%%@@@@@@@@@@@@@@@@@@@@%%@$$++             \",\n\"               ++@%&%%%@@@@@@@@@@@@@@@@@@@@@%@$@++              \",\n\"                +++%&%@@@@@@@@@@@@@@@@@@@@@@$$@++               \",\n\"                 ++++%$$@@@@@@@@@@@@@@@@@@$$@+++                \",\n\"                    ++@$$$$@@@@@@@@@@@@$$$@++                   \",\n\"                     ++++@$$$$$$$$$$$$$@ +++                    \",\n\"                         +++++@@@@@++++++++                     \",\n\"                         +++++++++++++++++                      \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\n\nhelp_To_Web_icon = \"\"\"\n/* XPM */\nstatic char * help_To_Web_icon[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"   c None\",\n\".  c #020A4A\",\n\"+  c #144893\",\n\"@  c #4E5D73\",\n\"#  c #4F6EA7\",\n\"$  c #7A9ECE\",\n\"%  c #A5A9AC\",\n\"&  c #CBDCEA\",\n\"*  c #FFFFFF\",\n\"            +++++++++++                                         \",\n\"           +++########+++                                       \",\n\"          ++&**********&+++                                     \",\n\"        ++$**************$++                                    \",\n\"       +$***%#++++++++#%***$+........                           \",\n\"      +%**&++++++++++++++&**%+.........                         \",\n\"     +$**#+++++#****&#++++#**$+&&&&%$$+....                     \",\n\"    +%**$+++++&********++++$**%+&&&&&&&&$+..                    \",\n\"  ++$**$+++++&**********++++$**$+&&$$$$&&&&$...                 \",\n\"  +$**#+++++&***********#++++#**$+%&&&&$$$$&&+..                \",\n\"  +&*&++++++*****#+&*****+++++&*&+%&&&&&$$$$&&%..               \",\n\" +#**+++++++****++++&****++++++**#+&&&&&&&*****&@.              \",\n\"++**%+++++++$**#++++&****++++++%**+$&&&&&&*%%*&$*%.             \",\n\"++**#++++++++++++++$*****++++++#**++&&&&***@&**&**%.            \",\n\"+#**++++++++++++++$*****++++++++**#+&&&&&&*@%******%.           \",\n\"+#**+++++++++++++%****&+++++++++**#+&&&&%%%$********@.          \",\n\"+#**++++++++++++$*****++++++++++**#+&%*%&*&*******&&&..         \",\n\"+#**+++++++++++%****&+++++++++++**#+&%&&***********&&&.         \",\n\"+#**+++++++++++&****&+++++++++++**#+&&*************&&&@.        \",\n\"+#**+++++++++++&****&+++++++++++**#+&&&************&&&&.        \",\n\"+#**+++++++++++&****&+++++++++++**#+&***%%*%*******&&&&@.       \",\n\"+#**++++++++++++****++++++++++++**#+***@&&$%&%*****&&&&&..      \",\n\"++**#++++++++++++++++++++++++++#**++&*%&&&$$$@$****&&&&&@.      \",\n\"++**%++++++++++++++++++++++++++%**+$&&&**&%$$$$+@&*&&&&&%.      \",\n\"++#**+++++++++++****+++++++++++**#+&&******$&&$$%**&&&%&&..     \",\n\"  +&*&+++++++++******+++++++++&*&+&&***************&&%%%&@.     \",\n\"  +$**#++++++++******++++++++#**$+&*************&%*&&@@%&@.     \",\n\"   +$**$+++++++******+++++++$**$+&&**************+%&&%++%@.     \",\n\"    +%**$++++++******++++++$**%+&&***************%$&&&%%@@.     \",\n\"     +$**#+++++#****#+++++#**$+&&&****************@%&%%%@$.     \",\n\"      +%**&++++++++++++++&**%+&&&&****************@@&%%@+$.     \",\n\"      .+$***%#++++++++#%***$+&&&&&***************&&+%%@++$.     \",\n\"      .@++$**************$++&&&&$&***************&&@%@+++$.     \",\n\"      .+$#++&**********&++#$$$$$$$&*************&&&&%%@+@@.     \",\n\"      ..$$$+++########+++$$$$$$$$$$&************&&&%%%++$@.     \",\n\"       .$$$$$#++++++++$$$$$$$$$$$$$$&@%@@%*****&&&&%%@++$@.     \",\n\"       .$$$$$$$********%$$$$$$$$$$$$$$$$$$****&&&&%%%+++$+.     \",\n\"       .$$$$$$$*********&$$$$$$$$$$$$$$$$$***&&&&&%%++++$.      \",\n\"       .+$$$$$&***********&$$$$$$$$$$$$$$$%*&&&&&%%@+++@@.      \",\n\"       ..$$$$$&*************%$$$$$$$$$$$++$&&&&&%%%@+++$+.      \",\n\"        .$$$$$%*************%$$$$$$$$$$+++$&&&&%%%%@+++$..      \",\n\"        .+$$$$$&************@$$$$$$$$$+++++&&&%%%%%@++@@.       \",\n\"        ..$$+$$$***********@$$$$$$$$++++++$&&%%%%%%@++$..       \",\n\"         .+$$++$%**********@$$$$$$++++++++$&%%%%%%%@+@@.        \",\n\"          .$$++++$*********@$$$+++++++++++$%%%%%%%@++$..        \",\n\"           .$$++++%********@++++++++++++++@%%%%%%@++$@.         \",\n\"           .+$$+++%&&&&&&%@++++++++++++++++%%%%%%@+@@..         \",\n\"            .+$$++%&&&&&%++++++++++++++++++@%%%%@@@@..          \",\n\"            ..$$$+@&&&&&%++++++++++++++++++@%%%%@@@..           \",\n\"             ..$$$$%%%%%@+++++++++++++++++++%%%@@@..            \",\n\"              ..+$%%%%%%++++++++++++++++++++%@@@@..             \",\n\"                .+%%%%@+++++++++++++++++++++.@@@..              \",\n\"                 ..%%%@++++++++++++++++++++@@@+..               \",\n\"                   ..@$$+++++++++++++++++@@@+...                \",\n\"                    ..+$$$$+++++++++++@@$@+..                   \",\n\"                      ...+$$$$$$$$$$$$@++...                    \",\n\"                         .....+++++......                       \",\n\"                           .............                        \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\n\ntemplate_icon = \"\"\"\n/* XPM */\nstatic char * template_icon[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"   c None\",\n\".  c #000000\",\n\"+  c #862122\",\n\"@  c #3C5A3B\",\n\"#  c #884E4C\",\n\"$  c #5D5F5C\",\n\"%  c #A1A09D\",\n\"&  c #CEC9C8\",\n\"*  c #FFFFFF\",\n\"        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%$$$$$$$$$$$$$$$$$$$$   \",\n\"       $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  \",\n\"       $%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%$  \",\n\"       $%***************************************************%$  \",\n\"       $%*%%%%%%******************@%************************%$  \",\n\"       $%*%%%%%%*$*$%%$&***********@%************$****&&****%$  \",\n\"       $%*%%%%%%*$&$%@$@@@@@@@@@&&$@$@@@@@@&@@@%%@@$@@@@@&&*%$  \",\n\"       $%*%%%%%%*&$%&@%$@@$%@@@@@$$@$@$@@@@%@@@@@@@@@@@@$$$*%$  \",\n\"       $%*%%%%%%**&&*&*&&&&*&&&&&&&&&&&&&&&*&&&&&&&&&&&&&&&*%$  \",\n\"       $%*%%%%%%*%%%%&***%%&****%****&*****%&**&%%%%%%%%*&%*%$  \",\n\"       $%*%%%%%%*@@@@$%%%@@@%%%%@%%%$$%%%%%$@&**%$@$$@@@&%@*%$  \",\n\"       $%*%%%%%%*@$@$@@@@@@..@@$@@@@@@@@@@@$@&*&$@@@@@@@@@@*%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%  %%***********&&***#++#%%&%*#&&&&&&**##&&&&&%#*%$  \",\n\"       $%*%%  %%***********%%&**&&++#+##&#+#+++%**+##+++++#*%$  \",\n\"       $%*%%%%%%*&&&&*************&&&&&&&&&&&&&&&&&&&&&&&&&*%$  \",\n\"       $%*%%%%%%*&&&************&&**&&**********%&**********%$  \",\n\"       $%*%%%%%%*%*********%%&**#+%###%%%%%%%%%%#%%%%%%%%%%*%$  \",\n\"       $%*%%%%%%*$*********$$&****&##+++++++++#&%##+###+++#*%$  \",\n\"       $%*%%%%%%*$****************$########+###%#+##$######*%$  \",\n\"       $%*%%%%%%**$$$$%*************************************%$  \",\n\"       $%*%%%%%%************&***#+#&&%&$&&&*&&&**#*#%+%&&&&*%$  \",\n\"       $%*%%%%%%***********$$&**&%++++#+#++#+##&%$&#*+#++++*%$  \",\n\"       $%*%%%%%%***********&&&****&&&&&&&+&&&&&&%%#&*&&&&&&*%$  \",\n\"       $%*%%%%%%*************************&******&%&*&**&****%$  \",\n\"       $%*%%%%%%*%*********%%&**%%%&&%%%%%%*%%%&&#*%%%%#&%%*%$  \",\n\"       $%*%%%%%%*$%********$$&****+###$#$+##+##&%&%+#+##&#$*%$  \",\n\"       $%*%%%%%%*$****************+#++%##++#+####*+%*+#+##+*%$  \",\n\"       $%*%%%%%%**$$$$$******************%***********%&*****%$  \",\n\"       $%*%%%%%%****************####%***********************%$  \",\n\"       $%*%%  %%***********$$&**&%%%&***********************%$  \",\n\"       $%*%%  %%***********&&&******************************%$  \",\n\"       $%*%%%%%%*%&*****************************************%$  \",\n\"       $%*%%%%%%*&**************%%%&**&%%%%*%&**************%$  \",\n\"       $%*%%%%%%*$$$&******%$&**%#%#**&#+$#*#&**************%$  \",\n\"       $%*%%%%%%*.$@%*************#+######+*****************%$  \",\n\"       $%*%%%%%%****$$$$$***********************************%$  \",\n\"       $%*%%%%%%****************%#&%&#&%&%#*&%&&*&*$%%*%&%#*%$  \",\n\"       $%*%%%%%%***********$$&**&%#+#+###+#*#%+#++&#*###+%%*%$  \",\n\"       $%*%%%%%%***********&&&****###+#####&%&#%#+#&*###%***%$  \",\n\"       $%*%%%%%%*%&***************&&&&&&&&&&&*&*&&&**&&&****%$  \",\n\"       $%*%%%%%%*&******************************************%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%%%%%*$&%%$$.$.$%*&.$$$$$$$$$$..$$$$&%$%#%+#####*%$  \",\n\"       $%*%%%%%%*.$..$$$..$$&%.$..$.$......$..$%%$*&&++++++*%$  \",\n\"       $%*%%%%%%*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&***&&&&&&*%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%*%%%%%%********************************************%$  \",\n\"       $%***************************************************%$  \",\n\"       $%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%$  \",\n\"       $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  \"\n};\"\"\"\n\n\ndirectory_Backup_Empty_icon = \"\"\"\n/* XPM */\nstatic char * directory_Backup_Empty_icon[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 8 1\",\n\"   c None\",\n\".  c #4F514F\",\n\"+  c #315E97\",\n\"@  c #808381\",\n\"#  c #5C90C6\",\n\"$  c #73A3D2\",\n\"%  c #ADB1AF\",\n\"&  c #A1BDDE\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"    .................................................           \",\n\"    .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.           \",\n\"    .@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@.           \",\n\"    .@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@.           \",\n\"    .@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@.           \",\n\"    .@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@.           \",\n\"    .@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@.           \",\n\"    .@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@.           \",\n\"    .@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.           \",\n\"    .@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.           \",\n\"    .@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.           \",\n\"    .@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.           \",\n\"    .@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.           \",\n\"    .@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.           \",\n\"    .@%%%%%++++++++++++++++++++++++++++++++++++++++++++++++     \",\n\"    .@%%%%%+&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&+     \",\n\"    .@%%%%%+&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&+     \",\n\"    .@%%%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+     \",\n\"    .@%%%%++&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$++     \",\n\"    ..%%%%+&&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+      \",\n\"    ..%%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+      \",\n\"    ..%%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+      \",\n\"    ..%%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+      \",\n\"    ..%%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+      \",\n\"    ..%%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+      \",\n\"    ..%%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+      \",\n\"    ..%%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+      \",\n\"    ..%%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+      \",\n\"    ..%%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+      \",\n\"    ..%%%++&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$++      \",\n\"    ..%%%++&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$++      \",\n\"     .%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$++      \",\n\"     .%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+       \",\n\"     .%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+       \",\n\"     .%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+       \",\n\"     .%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+       \",\n\"     .%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$#+       \",\n\"     .%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$#+       \",\n\"     .%%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$#+       \",\n\"     ..%%+&&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$#+       \",\n\"     ..%%+&&############################################+       \",\n\"     ..%%+&&###########################################++       \",\n\"     ..%++&############################################++       \",\n\"      .%++&############################################++       \",\n\"      .%+##############################################++       \",\n\"      .%+##############################################+        \",\n\"      .+++++++++++++++++++++++++++++++++++++++++++++++++        \",\n\"      .+++++++++++++++++++++++++++++++++++++++++++++++++        \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\n\ndirectory_Backup_Taken_icon = \"\"\"\n/* XPM */\nstatic char * directory_Backup_Taken_icon[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"     c None\",\n\".    c #290000\",\n\"+    c #C60916\",\n\"@    c #ED2928\",\n\"#    c #2C5C96\",\n\"$    c #5D5F5C\",\n\"%    c #70A2D4\",\n\"&    c #FEE849\",\n\"*    c #FFFFFF\",\n\"                                                                \",\n\"                                     ########                   \",\n\"                                  ##############                \",\n\"                                 ################               \",\n\"                                ##################              \",\n\"                               ###   ##############             \",\n\"                               ###   ##############             \",\n\"                               ###   ##############             \",\n\"              $$$$$$$$$$$$$$$$$####################$$$$$$$$     \",\n\"              $$$$$$$$$$$$$$$$$####################$$$$$$$$     \",\n\"              $$***************####################*******$     \",\n\"              $$*************************##########*******$     \",\n\" $$$$$$$$$$$$$$$********###########################*&&&&&&$     \",\n\" $$$$$$$$$$$$$$$*******############################*&&&&&&&&    \",\n\" $$************$*******############################*&&&&&&&&    \",\n\" $$************$*******############################*&&&&&&&&&   \",\n\"  $**$$$$$$$$$$$*****##############################*&&&&&&&&&   \",\n\"  $***********$$*****##############################$&&&&&&&&&   \",\n\"  $**$$$$$$$$$$******##############################*&&&&&&&&&   \",\n\"  $**$$$$$$$$$$*****##############################**&&&&&&&&&&  \",\n\"  $**$$$$$$$$$$*****##############################*&&&&&&&&&&&  \",\n\"  $**$$$$$$$$$$*****############################**&&&&&&&&&&&&  \",\n\"  $**********$******##############**************&&&&&&&&&&&&&&  \",\n\"  $$*$$$$$$$$$******############**&&&&&&&&&&&&&&&&&&&&&&&&&&&&  \",\n\"  $$**$$$$$$$*******###########*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&  \",\n\"  $$*******$$******$##########$$&&.&&&&&&&&&&&&&&&&&&&.&&&&&&&  \",\n\"  $$**$$$$$$$********#########*&&...&&&&&&&&&&&&&&&&&...&&&&&   \",\n\"  $$**$$$$$$*********#########*&..+..&&&&&&&&&&&&&&&..+..&&&&   \",\n\"  $$**$$$$$$*********#########*..+@+..&&&&&&&&&&&&&..+@+..&&&   \",\n\"   $**$$$$$$*********#########..+@@@+..&&&&&&&&&&&..+@@@+..$$$$$\",\n\"   $**$$$$$****##############..+@@+@@+..#########..+@@+@@+..###$\",\n\"   $**$$$$$***$#%%%%%%%%%%%%..+@@+++@@+..%%%%%%%..+@@+++@@+..%#$\",\n\"   $$*$$$$$***$#***********..+@@+++++@@+..*****..+@@+++++@@+..#$\",\n\"   $$*$$$$****$#*%%%%%%%%%..+@@+++++++@@+..%%%..+@@+++++++@@+..$\",\n\"   $$*$$$$****##*%%%%%%%%..+@@+++++++++@@+..%..+@@+++++++++@@+..\",\n\"   $$*$$$$****#%*%%%%%%%%%..+@@+++++++++@@+...+@@+++++++++@@+..$\",\n\"   $$*$$$*****#%*%%%%%%%%%%..+@@+++++++++@@+.+@@+++++++++@@+..#$\",\n\"   $$*$$$*****#*%%%%%%%%%%%%..+@@+++++++++@@+@@+++++++++@@+..#$ \",\n\"    $**$$*****#*%%%%%%%%%%%%%..+@@+++++++++@@@+++++++++@@+..%#$ \",\n\"    $*$$$****$#*%%%%%%%%%%%%%%..+@@+++++++++@+++++++++@@+..%##$ \",\n\"    $**$$****##%%%%%%%%%%%%%%%%..+@@+++++++++++++++++@@+..%%#$  \",\n\"    $**$*****#%%%%%%%%%%%%%%%%%%..+@@+++++++++++++++@@+..%%%#$  \",\n\"    $$$$*****#%%%%%%%%%%%%%%%%%%%..+@@+++++++++++++@@+..%%%##$  \",\n\"    $$*$*****#%%%%%%%%%%%%%%%%%%%%..+@@+++++++++++@@+..%%%%#$   \",\n\"    $$*$*****#%%%%%%%%%%%%%%%%%%%%%..+@@+++++++++@@+..%%%%%#$   \",\n\"    $$$$****%#%%%%%%%%%%%%%%%%%%%%..+@@+++++++++++@@+..%%%%#$   \",\n\"    $$*$****#%%%%%%%%%%%%%%%%%%%%..+@@+++++++++++++@@+..%%#$    \",\n\"    $$*$$***#%%%%%%%%%%%%%%%%%%%..+@@+++++++++++++++@@+..%#$    \",\n\"    $$*$$$$$#%%%%%%%%%%%%%%%%%%..+@@+++++++++++++++++@@+..#$    \",\n\"    $$*$$$$$#%%%%%%%%%%%%%%%%%..+@@+++++++++@+++++++++@@+..$    \",\n\"    $$$$$$$##%%%%%%%%%%%%%%%%..+@@+++++++++@@@+++++++++@@+..    \",\n\"     $$$$$$#%%%%%%%%%%%%%%%%..+@@+++++++++@@+@@+++++++++@@+..   \",\n\"     $$$$$$#%%%%%%%%%%%%%%%..+@@+++++++++@@+.+@@+++++++++@@+..  \",\n\"     $$$$$##%%%%%%%%%%%%%%..+@@+++++++++@@+...+@@+++++++++@@+.. \",\n\"     $$$$$#%%%%%%%%%%%%%%..+@@+++++++++@@+..%..+@@+++++++++@@+..\",\n\"     $$$$##%%%%%%%%%%%%%%%..+@@+++++++@@+..%%%..+@@+++++++@@+.. \",\n\"     $$$##%%%%%%%%%%%%%%%%%..+@@+++++@@+..%%%%%..+@@+++++@@+..  \",\n\"     $$##%%%%%%%%%%%%%%%%%%%..+@@+++@@+..%%%%%%%..+@@+++@@+..   \",\n\"      $######################..+@@+@@+..#########..+@@+@@+..    \",\n\"       $######################..+@@@+..###########..+@@@+..     \",\n\"        $$$$$$$$$$$$$$$$$$$$$$$..+@+..$$$$$$$$$$$$$..+@+..      \",\n\"                                ..+..               ..+..       \",\n\"                                 ...                 ...        \",\n\"                                  .                   .         \"\n};\"\"\"\n\n\nfile_Txt_icon = \"\"\"\n/* XPM */\nstatic char * directory_Backup_Taken_icon[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 9 1\",\n\"     c None\",\n\".    c #C92415\",\n\"+    c #635E51\",\n\"@    c #7F6411\",\n\"#    c #A7A8A3\",\n\"$    c #CCA735\",\n\"%    c #D0A36C\",\n\"&    c #D6D7D1\",\n\"*    c #FFFFFF\",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"           @@@@ @@@@ @@@@  @@@@ @@@@ @@@@  @@@@ @@@@            \",\n\"           @$$@ @$$@ @$$@  @$$@ @$$@ @$$@  @$$@ @$$@            \",\n\"         #%@$$@%@$$@%@$$@%%@$$@%@$$@%@$$@%%@$$@%@$$@%%          \",\n\"        ###@$$@#@$$@#@$$@##@$$@#@$$@#@$$@##@$$@#@$$@###         \",\n\"       #&&#@$$@&@$$@&@$$@&&@$$@&@$$@&@$$@&&@$$@&@$$@####        \",\n\"       #&#%@$$@%@$$@%@$$@%%@$$@%@$$@%@$$@%%@$$@%@$$@%%%#        \",\n\"       #&##@@@@#@@@@#@@@@##@@@@#@@@@#@@@@##@@@@#@@@@####        \",\n\"       #&###@@###@@###@@####@@###@@###@@####@@###@@#####        \",\n\"       #&###############################################        \",\n\"       #&**********************************************#        \",\n\"       #***********************************************#        \",\n\"       #***********************************************#        \",\n\"      ##***********************************************#        \",\n\"      ##****######################################&****#        \",\n\"      ##****&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&****#        \",\n\"      #&***********************************************#        \",\n\"      #&***********************************************#        \",\n\"      #&****######################################&****#        \",\n\"      #&****&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&****##       \",\n\"      #&***********************************************#@@@@@   \",\n\"      #&*********************************************&#@@...@@  \",\n\"      #*****#################&*********************&#@@......@@ \",\n\"      #*****&&&&&&&&&&&&&&&&&&*******************&#@@##.......@ \",\n\"      #****************************************&#@@%%###......@ \",\n\"      #**************************************&+@@%%%%####.....@ \",\n\"      #************************************&+@@%%%%%%%###....@  \",\n\"      #**********************************&+@@%%%%%%$$$###..@@@  \",\n\"     ##*****&&&&&&&&&&&&&&&&&&&&&&&&&&&#+@@%%%%%$$$$$$$##@@@    \",\n\"     ##*****##########################@@@%%%%%$$$$$$$@+@@@      \",\n\"     #&****************************#@@@%%%%%$$$$$$@@@@@##       \",\n\"     #&**************************#@@@%%%%%$$$$$$@@@@@+&*#       \",\n\"     #&*****&&&&&&&&&&&&&&&&&&&#@@@%%%%%$$$$$$@@@@@+&&&*#       \",\n\"     #&*****##################@@@%%%%%$$$$$$@@@@@+#&&&&*#+      \",\n\"     #&*********************&@@%%%%%$$$$$$@@@@@+&&&&&&&*#+      \",\n\"     #&********************&@@%%%%$$$$$$@@@@+&&&&&&&&&&*#+      \",\n\"     #&*****&&&&&&&&&&&&&&&@@%%%%$$$$$@@@@+#&&&&&&&&&&&*&+      \",\n\"     #&*****##############@@%%%%%$$@@@@@+##########&&&&*&+      \",\n\"     #*****&&&&&&&&&&&&&&@@%%%%%%%@@@@+#&&&&&&&&&&&&&&&*&+      \",\n\"     #**&&&&&&&&&&&&&&&&@@+%%%%%%@@@+###&&&&&&&&&&&&&&&*&+      \",\n\"     #**&&&&&&&&&&&&&&#++++@@@@@@++######&&&&&&&&&&&&&&*&+      \",\n\"     #**&&&&##########++++#############&&&&&&&&&&&&&&&&&&+      \",\n\"    +#*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*+      \",\n\"    +#*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*+      \",\n\"    +#*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*+      \",\n\"    +#*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*+      \",\n\"    +#*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*+      \",\n\"    +&*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*#+     \",\n\"    +&*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*#+     \",\n\"    +&*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*#+     \",\n\"    +&***************************************************#+     \",\n\"    +&&#################################################&#+     \",\n\"    +&##################################################&#+     \",\n\"    +&##################################################&#+     \",\n\"    +#&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#+     \",\n\"    ++++++++++++++++++++++++++++++++++++++++++++++++++++++      \",\n\"      +++++++++++++++++++++++++++++++++++++++++++++++++++       \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"\n};\"\"\"\n\n\nchildren = mw.findChildren(QtWidgets.QWidget,\"Editor assistant\")\nif not children:\n    modifiers = QtWidgets.QApplication.keyboardModifiers()\n    if modifiers == QtCore.Qt.AltModifier:\n        showEditorAssistantAsDockWidget(floating=True)\n    else:\n        showEditorAssistantDialog()\n\nelse:\n    FreeCAD.Console.PrintError(\"Editor assistant already running\\n\")",
    "url": "https://wiki.freecad.org/Macro_Editor_Assistant",
    "raw_code_url": "https://gist.github.com/mwganson/20475dad57d9b659190f082d20e3bde6/raw/f3a9d8fa95e8c3f264f376b06f5566c8b03eff5a/Editor_Assistant.FCMacro",
    "wiki": "https://wiki.freecad.org/Macro_Editor_Assistant",
    "version": "2.01",
    "license": "",
    "date": "2024/11/11",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Editor_Assistant_Icon.svg",
    "icon_source": "https://wiki.freecad.org//images/1/18/Editor_Assistant_Icon.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Global Variable Watcher",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro displays the global variables within the FreeCAD system, (e.g. FreeCAD.myVariable).<br /><br />Macro version: 1.0<br />Last modified: 2015-02-09<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/c/c1/Macro_Global_Variable_Watcher.png\">ToolBar Icon</a><br />Author: Piffpoof<br /> ",
    "comment": "This macro displays the global variables within the FreeCAD system, (e.g. FreeCAD.myVariable).",
    "code": "# -*- coding: utf-8 -*-\n#\n#\t\t\tVariable Watcher\n#\t\t\tdisplays variables of the form FreeCAD.*,\n#\t\t\teither manually or on a timed basis\n#\n################################\n# routine to <description goes here>\n\"\"\"\nscript does <long winded description goes here>\n\"\"\"\n################################\n\n# import statements\nimport FreeCAD\nimport math, collections, time\nfrom datetime import datetime\nfrom threading import Timer\nfrom PySide import QtGui, QtCore\n\n# UI Class definitions\n\nclass VariableWatcher(QtGui.QDialog):\n\t\"\"\"\"\"\"\n\tdef __init__(self):\n\t\tsuper(VariableWatcher, self).__init__()\n\t\tself.initUI()\n\tdef initUI(self):\n\t\tcolumn1LH\t= 10\n\t\tcolumn2LH\t= 350\n\t\theaderY\t\t= 20\n\t\trow1\t\t= 50\n\t\trow2\t\t= 75\n\t\trow3\t\t= 100\n\t\trow4\t\t= 125\n\t\trow5\t\t= 150\n\t\t# define window\t\txLoc,yLoc,xDim,yDim\n\t\tself.setGeometry(\t250, 250, 750, 200)\n\t\tself.setWindowTitle(\"Variable Watcher\")\n\t\tself.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)\n\t\tself.intervalDefault = str(2)\n\t\t# labels\n\t\tself.name1 = QtGui.QLabel(varLabelSpaces, self)\n\t\tself.name1.move(column1LH, row1)\n\t\tself.value1 = QtGui.QLabel(varValueSpaces, self)\n\t\tself.value1.move(column2LH, row1)\n\t\tself.name2 = QtGui.QLabel(varLabelSpaces, self)\n\t\tself.name2.move(column1LH, row2)\n\t\tself.value2 = QtGui.QLabel(varValueSpaces, self)\n\t\tself.value2.move(column2LH, row2)\n\t\tself.name3 = QtGui.QLabel(varLabelSpaces, self)\n\t\tself.name3.move(column1LH, row3)\n\t\tself.value3 = QtGui.QLabel(varValueSpaces, self)\n\t\tself.value3.move(column2LH, row3)\n\t\tself.name4 = QtGui.QLabel(varLabelSpaces, self)\n\t\tself.name4.move(column1LH, row4)\n\t\tself.value4 = QtGui.QLabel(varValueSpaces, self)\n\t\tself.value4.move(column2LH, row4)\n\t\tself.name5 = QtGui.QLabel(varLabelSpaces, self)\n\t\tself.name5.move(column1LH, row5)\n\t\tself.value5 = QtGui.QLabel(varValueSpaces, self)\n\t\tself.value5.move(column2LH, row5)\n\t\tself.intervalLbl = QtGui.QLabel(\"interval\", self)\n\t\tself.intervalLbl.move(90, headerY)\n\t\tself.timestampLbl = QtGui.QLabel(\"                 \", self)\n\t\tself.timestampLbl.move(300, 180)\n\t\t# radio buttons\n\t\tself.timerOnRB  = QtGui.QRadioButton(\"Timer On\",self)\n\t\tself.timerOnRB.setEnabled(True)\n\t\tself.timerOnRB.clicked.connect(self.onTimerOnRB)\n\t\tself.timerOnRB.move(150,headerY-10)\n\t\tself.timerOffRB = QtGui.QRadioButton(\"Timer Off\",self)\n\t\tself.timerOffRB.setEnabled(True)\n\t\tself.timerOffRB.setChecked(True)\n\t\tself.timerOffRB.clicked.connect(self.onTimerOffRB)\n\t\tself.timerOffRB.move(150,headerY+10)\n\t\t#\n\t\tnowButton = QtGui.QPushButton('Display Now', self)\n\t\tnowButton.clicked.connect(self.onDisplayNow)\n\t\tnowButton.move(250, headerY-7)\n\t\t# set up lists for pop-ups\n\t\tself.intervalPopupItems = (\"0.5\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"10\")\n\t\t# set up pop-up menu for timer interval\n\t\tself.intervalPop = QtGui.QComboBox(self)\n\t\tself.intervalPop.addItems(self.intervalPopupItems)\n\t\tself.intervalPop.setCurrentIndex(self.intervalPopupItems.index(self.intervalDefault))\n\t\tself.interval = self.intervalDefault\n\t\tself.intervalPop.move(10,headerY-5)\n\t\tself.intervalPop.activated[str].connect(self.onIntervalActivated)\n\t\t# set up pop-up menu FreeCAD global variables to watch\n\t\tself.globVar = QtGui.QComboBox(self)\n\t\tself.globVar.addItems(fcGlobalVars())\n\t\tself.globVar.setCurrentIndex(0)\n\t\tself.globVar.setGeometry(0,0,250,30)\n\t\tself.globVar.move(375,headerY-7)\n\t\tself.globVar.activated[str].connect(self.onMenuChoice)\n\t\t#\n\t\tcancelButton = QtGui.QPushButton('Cancel', self)\n\t\tcancelButton.clicked.connect(self.onCancel)\n\t\tcancelButton.move(650, headerY-7)\n\t\t# contextual menu for removing variable from watch list\n\t\tmnuRemove = QtGui.QAction(self)\n\t\tmnuRemove.setText(\"remove variable\")\n\t\tmnuRemove.triggered.connect(self.onRemoveVariable)\n\t\t# define menu and add option\n\t\tself.name1.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)\n\t\tself.name1.addAction(mnuRemove)\n\t\tself.name2.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)\n\t\tself.name2.addAction(mnuRemove)\n\t\tself.name3.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)\n\t\tself.name3.addAction(mnuRemove)\n\t\tself.name4.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)\n\t\tself.name4.addAction(mnuRemove)\n\t\tself.name5.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)\n\t\tself.name5.addAction(mnuRemove)\n\t\tself.value1.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)\n\t\tself.value1.addAction(mnuRemove)\n\t\tself.value2.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)\n\t\tself.value2.addAction(mnuRemove)\n\t\tself.value3.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)\n\t\tself.value3.addAction(mnuRemove)\n\t\tself.value4.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)\n\t\tself.value4.addAction(mnuRemove)\n\t\tself.value5.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)\n\t\tself.value5.addAction(mnuRemove)\n\n\t\tself.show()\n\t\t#\n\tdef onIntervalActivated(self, text):\n\t\tself.interval = text\n\t\n\tdef onTimerOffRB(self):\n\t\t# don't do much, this button serves as a semaphore for the timer routine\n\t\tpass\n\n\tdef onTimerOnRB(self):\n\t\t# launch timer routine which is based on the Off radio button\n\t\tself.timerRoutine()\n\n\tdef timerRoutine(self):\n\t\tif self.timerOnRB.isChecked():\n\t\t\t# if the On button is still checked then launch another timer event\n\t\t\t#print self.interval\n\t\t\tTimer(float(self.interval), self.timerRoutine, ()).start()\n\t\t\t#Timer(2, self.timerRoutine, ()).start()\n\t\telse:\n\t\t\tFreeCAD.Console.PrintMessage(\"Timer ceasing\\n\")\n\t\t# now do what should be done\n\t\tself.timerRoutineActions()\n\n\tdef timerRoutineActions(self):\n\t\tglobal watchedVariables\n\t\tif len(watchedVariables)>0:\n\t\t\tself.displayVariables()\n\t\telse:\n\t\t\tFreeCAD.Console.PrintMessage(\"Timer found no variables\\n\")\n\t\tself.timestamp()\n\n\tdef timestamp(self):\n\t\tself.timestampLbl.setText(datetime.now().strftime('%H:%M:%S'))\n\n\tdef onDisplayNow(self):\n\t\tself.timestamp()\n\t\tif len(watchedVariables)>0:\n\t\t\tself.displayVariables()\n\t\telse:\n\t\t\tFreeCAD.Console.PrintMessage(\"Found no variables\\n\")\n\n\tdef onMenuChoice(self,aChoice):\n\t\t# handle the user choice from the list of FreeCAD global variables\n\t\tif aChoice==topOfMenuChoices:\n\t\t\t# wants to update list of Global variable in FreeCAD\n\t\t\tself.globVarPopupItems  = fcGlobalVars()\n\t\t\tself.globVar.clear()\n\t\t\tself.globVar.addItems(self.globVarPopupItems)\n\t\telse:\n\t\t\tif hasattr(FreeCAD,aChoice):\n\t\t\t\tvarStr = \"FreeCAD.\"+aChoice\n\t\t\t\texec \"varVal = \"+varStr\n\t\t\t\texec \"dataTypeStr = str(type(\" + varStr + \"))\"\n\t\t\t\tself.addVariable(varStr,varVal.__repr__())\n\n\tdef addVariable(self, aNameStr, aValueStr):\n\t\tglobal watchedVariables\n\t\tif len(watchedVariables)<watchVariableLimit:\n\t\t\t# screen limited in size for now\n\t\t\tif aNameStr not in watchedVariables.keys():\n\t\t\t\t# prevent adding same variable twice\n\t\t\t\twatchedVariables[aNameStr] = aValueStr\n\t\t\t\tself.displayVariables()\n\t\t\n\tdef onRemoveVariable(self):\n\t\tglobal watchedVariables\n\t\tif self.name1.underMouse() or self.value1.underMouse():\n\t\t\tvariableToRemove = self.name1.text()\n\t\tif self.name2.underMouse() or self.value2.underMouse():\n\t\t\tvariableToRemove = self.name2.text()\n\t\tif self.name3.underMouse() or self.value3.underMouse():\n\t\t\tvariableToRemove = self.name3.text()\n\t\t#print variableToRemove\n\t\twatchedVariables.pop(variableToRemove)\n\t\tself.displayVariables()\n\n\tdef displayVariables(self):\n\t\tglobal watchedVariables\n\t\t\n\t\tsortedKeys = watchedVariables.keys()\n\t\tsortedKeysCount = len(sortedKeys)\n\t\t# clear display variables\n\t\tself.name1.setText(\"\")\n\t\tself.value1.setText(\"\")\n\t\tself.name2.setText(\"\")\n\t\tself.value2.setText(\"\")\n\t\tself.name3.setText(\"\")\n\t\tself.value3.setText(\"\")\n\t\tself.name4.setText(\"\")\n\t\tself.value4.setText(\"\")\n\t\tself.name5.setText(\"\")\n\t\tself.value5.setText(\"\")\n\t\t# now display variable names and values\n\t\t# use 'if hasattr(FreeCAD,\"ABC\"):' to ensure that variable still exists\n\t\tfor i in range(0,min(len(watchedVariables),5)):\n\t\t\taNameStr = sortedKeys[i]\n\t\t\texec \"aValueStr = \"+aNameStr+\".__repr__()\"\n\t\t\t#print aNameStr, \" \", aValueStr\n\t\t\tif i==0:\n\t\t\t\tself.name1.setText(aNameStr)\n\t\t\t\tself.value1.setText(aValueStr)\n\t\t\telif i==1:\n\t\t\t\tself.name2.setText(aNameStr)\n\t\t\t\tself.value2.setText(aValueStr)\n\t\t\telif i==2:\n\t\t\t\tself.name3.setText(aNameStr)\n\t\t\t\tself.value3.setText(aValueStr)\n\t\t\telif i==3:\n\t\t\t\tself.name4.setText(aNameStr)\n\t\t\t\tself.value4.setText(aValueStr)\n\t\t\telif i==4:\n\t\t\t\tself.name5.setText(aNameStr)\n\t\t\t\tself.value5.setText(aValueStr)\n\n\tdef onCancel(self):\n\t\t# need to shut down timer if running\n\t\tself.close()\n\n# Class definitions\n\n# Functions definitions\n\ndef fcGlobalVars():\n\tvarDict = list()\n\tvarDict.append(topOfMenuChoices)\n\tfor i in FreeCAD.__dict__.keys():\n\t\ttypeStr = type(FreeCAD.__dict__[i])\n\t\t# disregard functions or methods, module\n\t\tif str(typeStr) in (\"<type 'type'>\",\"<type 'builtin_function_or_method'>\",\"<type 'module'>\"):\n\t\t\tpass\n\t\telse:\n\t\t\t# ignore reserved variable names\n\t\t\tif str(i) in (\"PythonAssistantWindowStatus\",\"GuiUp\",\"ActiveDocument\", \"__path__\", \"__package__\", \"__doc__\", \"__name__\"):\n\t\t\t\tpass\n\t\t\telse:\n\t\t\t\tvarDict.append(i)\n\treturn varDict\n\n# Constant definitions\ntopOfMenuChoices = \">Update list of global variables<\"\nvarLabelSpaces = \">                                                                    <\"\nvarValueSpaces = \">                                                                                      <\"\n\n# code ***********************************************************************************\nglobal watchVariables, watchVariableLimit\nwatchedVariables = {}\nwatchVariableLimit = 5 # number of lines on screen\n\nform = VariableWatcher()\nform.exec_()\n#\n#OS: Mac OS X\n#Word size: 64-bit\n#Version: 0.14.3703 (Git)\n#Branch: releases/FreeCAD-0-14\n#Hash: c6edd47334a3e6f209e493773093db2b9b4f0e40\n#Python version: 2.7.5\n#Qt version: 4.8.6\n#Coin version: 3.1.3\n#SoQt version: 1.5.0\n#OCC version: 6.7.0\n#\n#thus ends the macro...",
    "url": "https://wiki.freecad.org/Macro_Global_Variable_Watcher",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2015-02-09",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Piffpoof",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Global_Variable_Watcher.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/c/c1/Macro_Global_Variable_Watcher.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Packages",
    "on_wiki": true,
    "on_git": false,
    "desc": "Gui front end for pip for installing/removing pypi packages in the FreeCAD Python environment.<br /><br />Macro version: 0.4<br />Last modified: 2025.01.18<br />FreeCAD version: 1.0<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/c/c7/Packages_icon.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Gui front end for pip for installing/removing pypi packages in the FreeCAD Python environment.",
    "code": "# packages.py\n# 2024, <TheMarkster> LGPL 2.1 or later\n# thanks to forum member hasecilu for help with setting pyside6 icons\n# a utility to install Python packages in FreeCAD\n\n__version__ = \"0.4\"\n\nfrom PySide import QtWidgets, QtGui, QtCore\nQDialog = QtWidgets.QDialog\nQVBoxLayout = QtWidgets.QVBoxLayout\nQHBoxLayout = QtWidgets.QHBoxLayout\nQLabel = QtWidgets.QLabel\nQLineEdit = QtWidgets.QLineEdit\nQSpinBox = QtWidgets.QSpinBox\nQPushButton = QtWidgets.QPushButton\nQListWidget = QtWidgets.QListWidget\nQMessageBox = QtWidgets.QMessageBox\nQCheckBox = QtWidgets.QCheckBox\nQApplication = QtGui.QApplication\nQFileDialog = QtGui.QFileDialog\nQt = QtCore.Qt\n\nimport requests\nimport re\nimport webbrowser\nimport subprocess, sys, platform\nimport freecad.utils as utils\nimport addonmanager_utilities as amutils\nimport shutil\nimport json\nimport importlib\n\nclass Packages:\n    def __init__(self):\n        self.python_version = f\"{sys.version_info.major}.{sys.version_info.minor}\"\n        self.pg = FreeCAD.ParamGet(f\"User parameter:Plugins/Packages_Macro/{self.python_version}\")\n        layout = QVBoxLayout()\n        self.mw = FreeCADGui.getMainWindow()\n        self.pathEdit = QLineEdit()\n        self.pathEdit.setToolTip(\"Path to python executable.\")\n        self.pathEdit.setText(self.findExecutable())\n        self.form = QtWidgets.QWidget()\n        self.form.setLayout(layout)\n        self.mode = \"install\" # can also be \"uninstall\"\n        filterLayout = QHBoxLayout()\n        self.filterEdit = QLineEdit()\n        self.filterEdit.setPlaceholderText(\"Filter packages\")\n        self.filterEdit.returnPressed.connect(self.applyFilter)\n        self.filterEdit.textChanged.connect(self.enableButtons)\n        filterLayout.addWidget(QLabel(\"Filter:\"))\n        filterLayout.addWidget(self.filterEdit)\n        self.sortedCheckBox = QCheckBox(\"Sort\")\n        self.sortedCheckBox.setToolTip(\"\"\"\nDefault is sorting by popularity in terms of most downloads in the last 30 days.\nChecked = sort A to Z.\nNote toggling applies the filter.\"\"\")\n        self.sortedCheckBox.setChecked(False)\n        self.sortedCheckBox.stateChanged.connect(self.applyFilter)\n        # this is to initialize stateChanged, otherwise first toggle does not update\n        checked = self.sortedCheckBox.isChecked()\n        filterLayout.addWidget(self.sortedCheckBox)\n        \n        self.filterButton = QPushButton(\"Apply Filter\")\n        self.filterButton.clicked.connect(self.applyFilter)\n        filterLayout.addWidget(self.filterButton)\n        \n        self.searchButton = QPushButton(\"Search\")\n        self.searchButton.setIcon(FreeCADGui.getIcon(\"internet-web-browser\"))\n        self.searchButton.setToolTip(\"Search for filter on pypi.org in default browser\")\n        self.searchButton.setEnabled(False)\n        filterLayout.addWidget(self.searchButton)\n        self.searchButton.clicked.connect(self.search)\n        \n        self.packageList = QListWidget()\n        self.packageList.itemSelectionChanged.connect(self.enableButtons)\n\n        self.fetchButton = QPushButton(\"Fetch summary\")\n        self.fetchButton.setIcon(FreeCADGui.getIcon(\"internet-web-browser\"))\n        self.fetchButton.setEnabled(False)\n        self.fetchButton.clicked.connect(self.fetchSummary)\n\n        layout.addLayout(filterLayout)\n\n        layout.addWidget(self.packageList)\n        buttonLayout = QHBoxLayout()\n        buttonLayout.addWidget(self.fetchButton)\n        \n        self.installButton = QPushButton(\"Install / Update\")\n        self.installButton.clicked.connect(self.install)\n        self.installButton.setEnabled(False)\n        self.installButton.setToolTip(\"\"\"\nIf this is disabled with an active selection it means the package is a base package.\nYou are allowed to install again an added package because there might be an update\navailable for it.\"\"\")\n        buttonLayout.addWidget(self.installButton)\n        \n        self.uninstallButton = QPushButton(\"Uninstall\")\n        style = self.form.style()\n        try:\n            trashIcon = style.standardIcon(style.SP_TrashIcon)\n        except:\n            trashIcon = style.standardIcon(style.StandardPixmap.SP_TrashIcon)\n        self.uninstallButton.setIcon(trashIcon)\n        self.uninstallButton.clicked.connect(self.uninstall)\n        self.uninstallButton.setEnabled(False)\n        self.uninstallButton.setToolTip(\"\"\"\nIf this is disabled with an active selection it means the selected package is\neither not already installed or it is a base package included with the packaging\nor distribution.\"\"\")\n        buttonLayout.addWidget(self.uninstallButton)\n        \n        self.openUrlButton = QPushButton(\"Open Url\")\n        self.openUrlButton.setIcon(FreeCADGui.getIcon(\"internet-web-browser\"))\n        self.openUrlButton.clicked.connect(self.openUrl)\n        self.openUrlButton.setEnabled(False)\n        buttonLayout.addWidget(self.openUrlButton)\n        \n        layout.addLayout(buttonLayout)\n        \n        pathLayout = QHBoxLayout()\n        layout.addLayout(pathLayout)\n\n        self.pathEdit.setPlaceholderText(\"Path to python executable\")\n        pathLayout.addWidget(QLabel(\"Python:\"))\n        pathLayout.addWidget(self.pathEdit)\n        self.pathButton = QPushButton(\"...\")\n        try:\n            self.pathButton.setIcon(style.standardIcon(style.SP_FileDialogStart))\n        except:\n            self.pathButton.setIcon(style.standardIcon(style.StandardPixmap.SP_FileDialogStart))\n        self.pathButton.setFixedWidth(self.pathButton.sizeHint().width())\n        self.pathButton.setToolTip(\"Click to browse for python executable.\")\n        self.pathButton.clicked.connect(self.setupPath)\n        pathLayout.addWidget(self.pathButton)\n        \n        additionalLayout = QHBoxLayout()\n        layout.addLayout(additionalLayout)\n        additionalLayout.addWidget(QLabel(\"AdditionalPythonPackages folder:\"))\n        self.additionalEdit = QLineEdit()\n        self.additionalEdit.setPlaceholderText(\"AdditionalPythonPackages folder goes here\")\n        pathToPackages = self.pg.GetString(\"PathToPackages\",\"\")\n        if not pathToPackages:\n            pathToPackages = amutils.get_pip_target_directory()\n            if not os.path.exists(pathToPackages):\n                os.makedirs(pathToPackages)\n                self.pg.SetString(\"PathToPackages\", pathToPackages)\n                FreeCAD.Console.PrintMessage(\"AdditionalPythonPackages folder has been created.  You will likely need to restart FreeCAD to use any newly installed packages.\\n\")\n        self.additionalEdit.setText(pathToPackages)\n        self.additionalEdit.setReadOnly(True)\n        additionalLayout.addWidget(self.additionalEdit)\n        self.additionalButton = QPushButton(\"Open\")\n        try:\n            self.additionalButton.setIcon(style.standardIcon(style.SP_DirOpenIcon))\n        except:\n            self.additionalButton.setIcon(style.standardIcon(style.StandardPixmap.SP_DirOpenIcon))\n        self.additionalButton.clicked.connect(self.openAdditional)\n        self.additionalButton.setToolTip(\"\"\"\nOpens the AdditionalPythonPackages folder.  Note that the only things\nthat should be in this folder are things installed using this macro\nor additional dependencies installed via the addon manager.  It should\nbe relatively safe to remove things from here.  You should take note\nof what extra folders were added when you install something.  These\ndependencies are not being tracked as pip doesn't support tracking\npackages added to custom folders.  When we uninstall something we\nonly install what we added, not the additional dependencies pip might\nhave added.\"\"\")\n        additionalLayout.addWidget(self.additionalButton)\n        \n        self.packages = self.loadPackageData()\n        title = f\"Packages {__version__} ({len(self.packages)} packages)\"\n        self.form.setWindowTitle(title)\n        self.applyFilter()\n\n        self.form.setWindowIcon(self.QIconFromXPMString(__icon__))\n\n    def loadPackageData(self):\n        # would be faster to cache this locally, but this way it's always up to date\n        url = \"https://hugovk.github.io/top-pypi-packages/top-pypi-packages-30-days.json\"\n        try:\n            response = requests.get(url)\n            response.raise_for_status()\n            data = response.json()\n            return data[\"rows\"]\n        except requests.RequestException as e:\n            QMessageBox.critical(self.mw, \"Error\", f\"Could not load data: {e}\")\n            return []\n            \n    def openAdditional(self):\n        \"\"\"\n        open the addtional python packages folder.  note that this is a different\n        folder for each version of python used by various freecad installations, \n        for example if the user has multiple versions in simultaneous use.  this\n        folder is really for the addon manager to install dependencies when installing\n        various addons, so we do not have exclusive use of it.  but the advantage\n        is the addon manager can also update these for use when updates are available.\n        this folder is made available to python via initGui,py in src/App, which\n        is how addons are able to import the packages installed here.\n        \"\"\"\n        sys = platform.system()\n        userFolder = self.additionalEdit.text()\n        if 'Windows' in sys:\n            subprocess.Popen('start explorer.exe '+userFolder, shell=True)\n        elif 'Linux' in sys:\n            os.system(\"xdg-open '%s'\" % userFolder)\n        elif 'Darwin' in sys:\n            subprocess.Popen([\"open\", userFolder])\n        else:\n            msgBox = QtGui.QMessageBox()\n            msg = \"We were unable to determine your platform, and thus cannot open your '+userFolder+' for you, but you can still do it manually.\\n\"\n            msgBox.exec_()\n                    \n    def getStandardButtons(self):\n        return (QtWidgets.QDialogButtonBox.Close)\n        \n    def setupPath(self):\n        \"\"\"\n        This is for the user to bre able to set a python that he wants to use\n        rather than the default found with the freecad.utils function\n        \"\"\"\n        path, ok = QFileDialog.getOpenFileName(self.mw, \n                \"Select Python Executable\",\n                \"\",\n                \"Python Executable (python*);;All Files (*)\")\n        if path:\n            self.pathEdit.setText(path)\n            self.pg.SetString(\"PathToPython\", path)\n\n\n    def applyFilter(self):\n        \"\"\"\n        This is called when the user clicks the Apply filters button, and also\n        when the user toggles the sort checkbox, and when the enter key is pressed\n        in the filter line edit widget.  If sorting is active, then the filtered\n        packages are sorted alphabetically, otherwise they are sorted based on the \n        popularity as measured by the number of downloads in the last 30 days.\n        \"\"\"\n        filter = self.filterEdit.text()\n        try:\n            filtered = [pkg for pkg in self.packages if re.search(filter, pkg[\"project\"], re.IGNORECASE)]\n            exactMatch = False\n            self.packageList.clear()\n            for pkg in filtered:\n                self.packageList.addItem(pkg[\"project\"])\n                if pkg == filter:\n                    exactMatch = True\n            self.packageList.setSortingEnabled(self.sortedCheckBox.isChecked())\n            if filter and not exactMatch:\n                description, version = self.getInfo(filter)\n                if description:\n                    self.packageList.insertItem(0, filter + \" (not in top 8000)\")\n\n        except re.error as e:\n            QMessageBox.warning(self.mw, \"Invalid Regex\", f\"Error in regular expression: {e}\")\n            self.form.setWindowTitle(f\"Packages {__version__}\")\n\n    def enableButtons(self):\n        \"\"\"enables or disables buttons based on whether a package is selected\n        in the list widget and whether that package is already installed.\"\"\"\n        hasSelection = bool(self.packageList.selectedItems())\n        self.openUrlButton.setEnabled(hasSelection)\n        self.fetchButton.setEnabled(hasSelection)\n        hasFilter = bool(self.filterEdit.text())\n        self.searchButton.setEnabled(hasFilter)\n            \n        added, base = (False, False)\n        if hasSelection:\n            added, base = self.isInstalled()\n        self.installButton.setEnabled(not base)\n        self.uninstallButton.setEnabled(added)\n\n    def install(self):\n        self.mode = \"install\"\n        self.managePackages()\n        \n    def uninstall(self):\n        self.mode = \"uninstall\"\n        self.managePackages()\n        \n    def findExecutable(self):\n        \"\"\"\n        find the python executable in use, luckily there is a function for this\n        already in FreeCAD, but we still want to allow the user the flexibility\n        of setting a different python executable if the function gets it wrong\n        \"\"\"\n        \n        path = self.pg.GetString(\"PathToPython\",\"\")\n        if path:\n            return path\n        \n        pyEx = utils.get_python_exe()\n    \n        if os.path.exists(pyEx):\n            self.pg.SetString(\"PathToPython\", pyEx)\n            return pyEx\n        else:\n            FreeCAD.Console.PrintError(f\"Python executable not found.  You may try to find it manually by clicking the '...' button at the bottom of the dialog.\\n\")\n            return \"Path to python executable\"\n\n    def managePackages(self):\n        \"\"\"\n        Here is where the installing and uninstalling happens.  We track which\n        packages we have installed and which dependencies were installed along\n        with them.  The caveat here is the AddonManager might also install stuff\n        in our folder, but I don't think the AM tracks extra dependencies.\n        \"\"\"\n        package = self.packageList.currentItem().text().replace(\" (not in top 8000)\", \"\")\n        python_exe = self.pathEdit.text()\n        vendor_path = self.additionalEdit.text()\n        if \"APPIMAGE\" in os.environ:\n            \n            os.environ['PYTHONHOME'] = '/usr'\n            os.environ['PYTHONPATH'] = f\"/usr/lib/python{self.python_version}/site-packages\" \n\n        if self.mode == \"uninstall\":\n            added = self.loadAddedSubfolders(package)\n            self.pg.RemString(f\"{package}_Subfolders\")\n\n            for subfolder in added:\n                item_path = os.path.join(vendor_path, subfolder)\n                if os.path.exists(item_path):\n                    shutil.rmtree(item_path)\n                    print(f\"{subfolder} removed\\n\")\n\n            self.enableButtons()\n            return\n\n        existing = set(os.listdir(vendor_path))\n\n        command = [python_exe, \"-m\", \"pip\", self.mode, \"--target\", vendor_path, package]\n\n        try:\n            result = subprocess.run(\n                command,\n                stdout=subprocess.PIPE,\n                stderr=subprocess.PIPE,\n                text=True,\n                check=True\n            )\n            FreeCAD.Console.PrintMessage(f\"{result.stdout}\\n\")\n\n\n            new_folders = set(os.listdir(vendor_path)) - existing\n            added = list(new_folders)\n\n            self.saveAddedSubfolders(package, added)\n\n        except subprocess.CalledProcessError as e:\n            FreeCAD.Console.PrintError(f\"Error: {e.stderr}\\n\")\n        except Exception as e:\n            FreeCAD.Console.PrintError(f\"An unexpected error occurred: {e}\\n\")\n        finally:\n            self.enableButtons()\n\n    def saveAddedSubfolders(self, package, added):\n        \"\"\"\n        Here we track the folders that we added to this AdditionalPythonPackages\n        folder and removed them during uninstallation.  The complication is that\n        sometimes additional dependencies are also added, and when they are, we \n        should also track them and remove them.  Further complicating this is other\n        packages might have also added the same dependencies.  These we reconcile\n        in the loadAddedSubfolders() method below.\n        \"\"\"\n        json_string = json.dumps(added)\n        self.pg.SetString(f\"{package}_Subfolders\", json_string)\n\n    def loadAddedSubfolders(self, package):\n        \"\"\"\n        We get all of the packages that were added by all installations, this is\n        in allPackages list.  The added list only includes the new subfolders that\n        were added when this package was installed.  Anything in added that is not\n        also in allPackages can be safely removed during uninstallation.\n        \"\"\"\n        json_string = self.pg.GetString(f\"{package}_Subfolders\", \"\")\n        added = json.loads(json_string) if json_string else []\n\n        allPackages = []\n        for key in self.pg.GetStrings():\n            if key.endswith(\"_Subfolders\") and key != f\"{package}_Subfolders\":\n                other_json = self.pg.GetString(key, \"\")\n                try:\n                    otherPackages = json.loads(other_json)\n                    allPackages.extend(otherPackages)\n                except json.JSONDecodeError:\n                    print(f\"Error decoding subfolder list for {key}.\")\n\n        unique = [folder for folder in added if folder not in allPackages]\n        return unique\n\n    def isInstalled(self):\n        \"\"\"\n        Called only by the enable buttons function.  We return a tuple (added, base)\n        added = True means this was something we added to the additional packages \n        folder.  base = True means this is installed, but as a base package either\n        through the packaging or user installed into the system environment, either\n        way we don't try to install or uninstall anything we didn't add or that the\n        addon manager didn't add as an additional dependency in our user addon folder\n        \"\"\"\n        added = False\n        base = False\n        package = self.packageList.currentItem().text().replace(\" (not in top 8000)\", \"\")\n        python_exe = self.pathEdit.text()\n        vendor_path = amutils.get_pip_target_directory()\n        if not os.path.exists(vendor_path):\n            os.makedirs(vendor_path)\n        fullpath = os.path.join(vendor_path,package)\n        if os.path.exists(fullpath):\n            added = True\n        try:\n            importlib.import_module(package)\n            if not added: # we didn't add this\n                base = True\n        except ImportError:\n            # added might or might not be false because this might not yet be\n            # available to import if the additionalpythonpackages folder was\n            # only just created this FreeCAD session, so we don't set it False\n            # here, but instead rely on the above test\n            base = False\n\n        return (added, base)\n\n    def fetchSummary(self):\n        selectedItem = self.packageList.currentItem()\n        if not selectedItem:\n            return\n        \n        package = selectedItem.text().replace(\" (not in top 8000)\",\"\")\n        description, version = self.getInfo(package)\n        \n        QMessageBox.information(self.mw, \"Package Summary\", \n                                f\"{package} (v{version}): {description}\")\n        \n\n    def getInfo(self, package):\n        \"\"\"\n        called by fetchSummary(), pops up a very brief description of the package\n        in a message box.  User can use the OpenUrl button to get more details.\n        We also use this to check if a custom entered package is available outside\n        the top 8000 list.\n        \"\"\"\n        \n        url = f\"https://pypi.org/pypi/{package}/json\"\n        try:\n            response = requests.get(url)\n            response.raise_for_status()\n            data = response.json()\n            description = data[\"info\"].get(\"summary\", \"No description available.\")\n            version = data[\"info\"].get(\"version\", \"Unknown version\")\n            return description, version\n        except requests.RequestException:\n            return \"\", \"Unknown version\"\n\n    def search(self):\n        filter = self.filterEdit.text()\n        if not filter:\n            return\n        url = f\"https://pypi.org/search/?q={filter}\"\n        try:\n            webbrowser.open(url)\n        except Exception as e:\n            QMessageBox.critical(self.mw, \"Error\", \n                                f\"Unable to open the browser. Error: {e}\")\n\n    def openUrl(self):\n        package = self.packageList.currentItem().text().replace(\" (not in top 8000)\", \"\")\n        url = f\"https://pypi.org/pypi/{package}\"\n        try:\n            webbrowser.open(url)\n        except Exception as e:\n            QMessageBox.critical(self.mw, \"Error\", \n                                f\"Unable to open the browser. Error: {e}\")\n\n    def QIconFromXPMString(self, xpm_string):\n        if \"/*pixels*/\" in xpm_string:\n            xpm = xpm_string.replace(\"\\\"\",\"\").replace(',','').splitlines()[4:]\n        else:\n            xpm = xpm_string.replace(\"\\\"\",\"\").replace(',','').splitlines()[3:]\n        for line in reversed(xpm):\n            if line.startswith(\"/*\") and line.endswith(\"*/\"):\n                xpm.pop(xpm.index(line))\n        pixmap = QtGui.QPixmap(xpm)\n        icon = QtGui.QIcon(pixmap)\n        return icon\n\n\n__icon__ = \"\"\"\n/* XPM */\nstatic char *dummy[]={\n\"64 64 1050 2\",\n\"Qt c None\",\n\".g c #010101\",\n\"br c #020202\",\n\"a3 c #030202\",\n\"h3 c #030303\",\n\"ej c #030304\",\n\".I c #040404\",\n\"ao c #050504\",\n\".# c #050505\",\n\"m9 c #060605\",\n\"dI c #060606\",\n\".J c #070707\",\n\"a2 c #090907\",\n\"nl c #090909\",\n\"mW c #0a0a0a\",\n\"mV c #0b0a09\",\n\"aL c #0b0b09\",\n\"bh c #0b0b0b\",\n\".s c #0b0c0c\",\n\"nz c #0c0b0b\",\n\"oj c #0c0c0c\",\n\"d3 c #0c0c0d\",\n\"n9 c #0d0c0c\",\n\"dJ c #0d0d0d\",\n\"#b c #0d0d0e\",\n\".W c #0d0e0f\",\n\"mL c #0e0e0f\",\n\"eI c #0f0f10\",\n\"#T c #0f1317\",\n\"#x c #0f1417\",\n\"mK c #100f0d\",\n\"nN c #11100e\",\n\"nk c #11100f\",\n\"mA c #111111\",\n\"bM c #111112\",\n\"#a c #111417\",\n\"c# c #121212\",\n\"#U c #121415\",\n\"mo c #131313\",\n\".t c #131315\",\n\"mU c #15130e\",\n\"nA c #151516\",\n\"aK c #16140d\",\n\"#y c #16181b\",\n\"mM c #171717\",\n\"fj c #181819\",\n\".X c #181a1c\",\n\"gY c #191919\",\n\".f c #191b1d\",\n\"h# c #1a1a1b\",\n\"#7 c #1a1e21\",\n\"m8 c #1c1a15\",\n\"an c #1d1b15\",\n\"oi c #1d1d1e\",\n\"ot c #1e1e1e\",\n\"mX c #202020\",\n\"ap c #212328\",\n\"aM c #212428\",\n\"nY c #22211c\",\n\"bs c #222223\",\n\"h4 c #232325\",\n\"#8 c #23252a\",\n\"#c c #23272e\",\n\"cx c #242425\",\n\".H c #242629\",\n\"#z c #242b34\",\n\"o. c #252526\",\n\".h c #25272a\",\n\"ek c #262627\",\n\".K c #262a2f\",\n\"cP c #282729\",\n\"d# c #282829\",\n\"iM c #29292a\",\n\"du c #29292b\",\n\"#d c #2c3845\",\n\"#A c #2e3d4b\",\n\"am c #2f2919\",\n\"aJ c #2f2a1c\",\n\"m7 c #2f2a1d\",\n\"nO c #2f2f30\",\n\".A c #2f6491\",\n\"mY c #303030\",\n\".B c #306491\",\n\".Q c #306591\",\n\"ib c #306592\",\n\"nj c #312d23\",\n\"ny c #312f2a\",\n\".Y c #313942\",\n\"#E c #316591\",\n\"eS c #316592\",\n\"ja c #323233\",\n\"a5 c #326592\",\n\".z c #326692\",\n\"mT c #332e21\",\n\"av c #336692\",\n\"#p c #336792\",\n\"dC c #336793\",\n\"a6 c #346792\",\n\".R c #346793\",\n\"aw c #346893\",\n\"n. c #353536\",\n\".Z c #354658\",\n\".l c #35658f\",\n\".m c #356792\",\n\".6 c #356893\",\n\"ev c #356894\",\n\"os c #363637\",\n\".u c #363d46\",\n\".P c #366792\",\n\"#i c #366894\",\n\"dW c #366994\",\n\"bg c #373630\",\n\"mz c #373737\",\n\"#e c #374d61\",\n\"#h c #376893\",\n\"f. c #376994\",\n\"ax c #376a95\",\n\"#R c #3775a9\",\n\".y c #386891\",\n\".n c #386993\",\n\"ac c #386994\",\n\"ew c #386a95\",\n\"ba c #3875a9\",\n\"bA c #3876a9\",\n\"dl c #3876aa\",\n\".o c #39678f\",\n\"lj c #3976a9\",\n\"c2 c #3977aa\",\n\"nm c #3a3a3c\",\n\".x c #3a648a\",\n\"ab c #3a6a94\",\n\".C c #3a6b95\",\n\"dB c #3a6b96\",\n\"aR c #3a6c96\",\n\"#Q c #3a77aa\",\n\"#Z c #3b6c96\",\n\"ad c #3b6c97\",\n\"ea c #3b6d96\",\n\"b# c #3b77aa\",\n\"dK c #3c3b3d\",\n\".a c #3c4149\",\n\".0 c #3c5974\",\n\"#Y c #3c6c94\",\n\"iw c #3c6c96\",\n\"aC c #3c78aa\",\n\"ht c #3c78ab\",\n\".k c #3d6589\",\n\".O c #3d688f\",\n\"#D c #3d6b94\",\n\"fw c #3d6d95\",\n\"b. c #3d78aa\",\n\"k2 c #3d79ab\",\n\"bi c #3e3e40\",\n\".D c #3e6c93\",\n\"fr c #3e6c95\",\n\"eT c #3e6e98\",\n\"ae c #3e6f9a\",\n\"dX c #3e79ab\",\n\"iq c #3f3f42\",\n\".w c #3f607d\",\n\"g# c #3f6c95\",\n\"gm c #3f6e96\",\n\".7 c #3f6e98\",\n\"#F c #3f6f98\",\n\"lE c #3f79ab\",\n\"#5 c #3f7aab\",\n\"cH c #3f7aac\",\n\"nM c #403c30\",\n\"gQ c #406e96\",\n\"au c #406e97\",\n\"g4 c #406f96\",\n\"#o c #406f98\",\n\"cI c #407aab\",\n\"fY c #407aac\",\n\"#V c #414b56\",\n\"aq c #415c76\",\n\".E c #416789\",\n\"ds c #417bab\",\n\"#v c #417bac\",\n\".r c #42474d\",\n\"#B c #425a73\",\n\"a4 c #425c75\",\n\"aN c #425c76\",\n\".S c #426f97\",\n\"ay c #42729b\",\n\"dD c #427bac\",\n\"b0 c #427dae\",\n\"jb c #434343\",\n\"mN c #434344\",\n\"#g c #436b91\",\n\"kk c #437199\",\n\"ic c #43719a\",\n\"hr c #43729a\",\n\"hV c #437cac\",\n\"iN c #444446\",\n\"#f c #446482\",\n\"fs c #446f96\",\n\"hd c #447299\",\n\"ia c #44729a\",\n\"aV c #447dad\",\n\"ok c #454547\",\n\"bN c #454548\",\n\".v c #45576a\",\n\"fP c #456f97\",\n\"fx c #45739b\",\n\"iB c #457dad\",\n\".i c #465161\",\n\".T c #466e91\",\n\"hf c #467dad\",\n\"n8 c #474541\",\n\"a7 c #477198\",\n\"ft c #477298\",\n\"e9 c #477299\",\n\"k1 c #47739b\",\n\"eh c #477ead\",\n\"eZ c #477eae\",\n\"cn c #4780b0\",\n\"ar c #487197\",\n\"fR c #487298\",\n\"aa c #487398\",\n\"e6 c #487399\",\n\"dV c #48759c\",\n\"dE c #487fae\",\n\"nx c #49422f\",\n\"#C c #496c8e\",\n\"fQ c #497398\",\n\"iU c #49749a\",\n\"eu c #49759b\",\n\"gn c #4979a2\",\n\"c3 c #497fae\",\n\"bV c #4980ad\",\n\"nB c #4a4a4c\",\n\"fS c #4a7399\",\n\"j8 c #4a79a2\",\n\"g5 c #4a7aa3\",\n\"bz c #4a80ad\",\n\"go c #4a80ae\",\n\"eY c #4a80af\",\n\".j c #4b647d\",\n\".N c #4b6b87\",\n\"eR c #4b769b\",\n\"cp c #4b80ae\",\n\"bm c #4b81ae\",\n\"fu c #4c7398\",\n\"fv c #4c7499\",\n\"#M c #4c7ba2\",\n\"gS c #4c80aa\",\n\"#P c #4c82af\",\n\"nn c #4d4d4f\",\n\"d4 c #4d4d50\",\n\"e7 c #4d7499\",\n\"#j c #4d789e\",\n\"#q c #4d799f\",\n\"gC c #4d81ad\",\n\"bD c #4d84b2\",\n\"ca c #4e4e4f\",\n\"ex c #4e789e\",\n\"kl c #4e7ea6\",\n\"hs c #4e7ea8\",\n\"i2 c #4e83af\",\n\"he c #4f7ea7\",\n\"n# c #504f51\",\n\".1 c #507495\",\n\"aQ c #50789c\",\n\".5 c #507a9f\",\n\"#L c #507ca2\",\n\"by c #507fa6\",\n\"id c #5083b0\",\n\"lF c #5083b1\",\n\"ci c #5084b0\",\n\"dk c #5086b4\",\n\"#9 c #51667b\",\n\"hU c #517a9f\",\n\"ee c #517ea6\",\n\"ch c #517fa6\",\n\"dY c #5184b0\",\n\"fX c #5184b1\",\n\"aE c #5185b1\",\n\"aO c #527699\",\n\"e8 c #52779a\",\n\"eA c #527ba0\",\n\"af c #527ea3\",\n\"#s c #5280a8\",\n\"c8 c #5284b0\",\n\"fB c #5285b0\",\n\"aj c #5285b1\",\n\"bF c #5285b2\",\n\"nZ c #535355\",\n\".L c #535c67\",\n\".F c #536b81\",\n\".p c #537390\",\n\"#X c #537697\",\n\"a. c #53789a\",\n\"e# c #53799b\",\n\"h9 c #537b9f\",\n\"eU c #537ca0\",\n\"#J c #537ca1\",\n\"fA c #5383ad\",\n\"fc c #5383ae\",\n\"k3 c #5385b1\",\n\"do c #5386b1\",\n\"l2 c #5386b2\",\n\"ni c #544e3b\",\n\"ga c #54799c\",\n\"iX c #547ca0\",\n\"fT c #547ca1\",\n\"f# c #547ea2\",\n\"#r c #5480a6\",\n\"fV c #5482aa\",\n\"cJ c #5485b1\",\n\"aB c #5487b1\",\n\"#I c #557da1\",\n\"fU c #5581a7\",\n\"eF c #5586b2\",\n\"cY c #5588b3\",\n\"iz c #567da1\",\n\"#K c #567ea1\",\n\"bl c #5681a7\",\n\"a9 c #5686af\",\n\"c4 c #5687b2\",\n\".G c #57626e\",\n\"at c #577b9d\",\n\"eB c #5783a8\",\n\"#u c #5788b2\",\n\"al c #58543e\",\n\".b c #586a80\",\n\"a# c #587b9c\",\n\"ix c #587da1\",\n\"#m c #5880a3\",\n\".8 c #5881a6\",\n\"fb c #5886ad\",\n\"fW c #5887b0\",\n\"bB c #588cb7\",\n\"iA c #597fa2\",\n\"iy c #597fa3\",\n\"#l c #5980a3\",\n\".9 c #5984a9\",\n\"fz c #5985ab\",\n\"cD c #598ab4\",\n\"c1 c #598cb7\",\n\"jf c #5a7fa2\",\n\"#t c #5a88b0\",\n\"iC c #5a89b3\",\n\"i# c #5b80a4\",\n\".2 c #5b81a2\",\n\"gp c #5b89ae\",\n\"#4 c #5b8ab3\",\n\"eJ c #5c5c60\",\n\"iW c #5c80a4\",\n\"#G c #5c82a5\",\n\"#N c #5c88ad\",\n\"#. c #5c88ae\",\n\"ig c #5c8bb3\",\n\"ox c #5d5d61\",\n\".U c #5d7386\",\n\"#W c #5d738c\",\n\".c c #5d7c99\",\n\"as c #5d7c9c\",\n\".3 c #5d82a4\",\n\"#n c #5d83a4\",\n\"fy c #5d85a8\",\n\"jj c #5d8bb3\",\n\"c5 c #5d8bb4\",\n\"nX c #5e5742\",\n\"l1 c #5e88ad\",\n\"cL c #5e8bb3\",\n\"fC c #5e8cb4\",\n\"gc c #5e8db4\",\n\"ir c #5f5f61\",\n\".V c #5f6a75\",\n\"ed c #5f83a5\",\n\"aS c #5f86a8\",\n\"lk c #5f8cb5\",\n\"iD c #5f8db4\",\n\"m6 c #60563a\",\n\"i. c #6082a4\",\n\"iY c #6084a5\",\n\"l0 c #6085a5\",\n\"#k c #6185a6\",\n\"cK c #618db5\",\n\"#O c #618eb5\",\n\"oh c #626266\",\n\".e c #626d78\",\n\".M c #627181\",\n\".q c #627384\",\n\"#0 c #6288a9\",\n\"h5 c #636366\",\n\"iV c #6385a5\",\n\"gb c #6388aa\",\n\"fe c #638fb5\",\n\"dp c #638fb6\",\n\"dn c #638fb7\",\n\"nP c #646467\",\n\"aP c #64819f\",\n\"gD c #648ea8\",\n\"bt c #656569\",\n\"fa c #658cae\",\n\"c6 c #658fb6\",\n\"i0 c #6590b6\",\n\"bW c #6594bd\",\n\"nL c #665b3c\",\n\"mJ c #666152\",\n\".4 c #6688a8\",\n\"lG c #6692b9\",\n\"iO c #676768\",\n\"az c #678caf\",\n\"iZ c #678cb0\",\n\"ie c #6790b7\",\n\"if c #6791b7\",\n\"aU c #6792b7\",\n\"dS c #6888a7\",\n\"eb c #688aa9\",\n\"ef c #6891b8\",\n\"li c #698aa9\",\n\"a8 c #698cab\",\n\"ah c #6992b7\",\n\"i1 c #6992b8\",\n\"a1 c #6a6452\",\n\"nC c #6a6a6c\",\n\"dR c #6a87a4\",\n\"#H c #6a8baa\",\n\"dU c #6a8bab\",\n\"#S c #6a8fb1\",\n\"eC c #6a92b6\",\n\"dr c #6a93b7\",\n\"g. c #6b87a3\",\n\"#w c #6b90b1\",\n\"bk c #6c87a1\",\n\"fq c #6c87a3\",\n\"et c #6c89a6\",\n\"ag c #6c91b3\",\n\"#6 c #6c92b2\",\n\"gB c #6c94b8\",\n\"iT c #6d88a5\",\n\"je c #6d89a5\",\n\"jI c #6d89a6\",\n\"kj c #6d8aa6\",\n\"gR c #6d94b8\",\n\"eX c #6d95b8\",\n\".d c #6e879f\",\n\"iv c #6e88a5\",\n\"gl c #6e89a5\",\n\"jv c #6e89a6\",\n\"hg c #6f94b7\",\n\"nw c #70623b\",\n\"bC c #709dc1\",\n\"c7 c #7197b9\",\n\"hc c #728da9\",\n\"gA c #728daa\",\n\"ey c #7290ae\",\n\"hI c #7296b6\",\n\"dj c #729ec2\",\n\"ou c #737376\",\n\"ez c #7391af\",\n\"dZ c #7397bb\",\n\"ak c #7398b6\",\n\"aA c #7398b9\",\n\"ji c #7398bb\",\n\"l3 c #739bbe\",\n\"no c #747474\",\n\"bO c #747477\",\n\"mn c #747478\",\n\"hH c #7499ba\",\n\"lU c #757578\",\n\"jg c #7591ad\",\n\"#3 c #7599b9\",\n\"eg c #7599ba\",\n\"mZ c #767676\",\n\"dq c #7699bb\",\n\"eV c #7795b1\",\n\"gT c #7797aa\",\n\"jh c #7896b5\",\n\"dt c #789cbc\",\n\"d2 c #789dbd\",\n\"e5 c #798fa8\",\n\"## c #7995af\",\n\"ff c #799dbd\",\n\"dA c #7a95ae\",\n\"lD c #7a97b1\",\n\"aF c #7a9cb3\",\n\"eG c #7a9fbf\",\n\"c9 c #7b9ebd\",\n\"aD c #7b9fbe\",\n\"ei c #7b9fbf\",\n\"fD c #7ba0bf\",\n\"aT c #7c9db9\",\n\"eD c #7c9dbe\",\n\"dH c #7c9ebd\",\n\"bn c #7c9fbf\",\n\"co c #7ca0c0\",\n\"dT c #7d96b2\",\n\"fd c #7d9ebc\",\n\"bE c #7d9fc0\",\n\"b1 c #7da0c0\",\n\"h8 c #7e94ac\",\n\"bx c #7e98b1\",\n\"eE c #7e9ebe\",\n\"ll c #7ea2c2\",\n\"cb c #7f7f80\",\n\"el c #7f7f83\",\n\"eQ c #7f97af\",\n\"dm c #7fa1c0\",\n\"e. c #8095ac\",\n\"di c #809ab3\",\n\"gq c #809b9f\",\n\"bU c #819cb4\",\n\"bj c #82858c\",\n\"ec c #829ab4\",\n\"k0 c #8398af\",\n\"#1 c #839eb9\",\n\"cG c #83aaca\",\n\"gd c #84a3bf\",\n\"mB c #858589\",\n\"g6 c #85a2bd\",\n\"bZ c #85aaca\",\n\"nW c #877748\",\n\"n0 c #88888a\",\n\"or c #88888d\",\n\"hT c #889bb1\",\n\"nQ c #89898a\",\n\"hu c #89a3b8\",\n\"cq c #89a5bb\",\n\"dG c #89a5c2\",\n\"dF c #89a6c0\",\n\"ai c #89a7c2\",\n\"n7 c #8a8884\",\n\"e1 c #8a898c\",\n\"d0 c #8aa5c1\",\n\"cM c #8aa6c0\",\n\"mc c #8b8b90\",\n\"j9 c #8ba2a8\",\n\"lZ c #8ba2b9\",\n\"jJ c #8ba3a8\",\n\"kL c #8ba3a9\",\n\"iE c #8ca4a8\",\n\"lH c #8dacc9\",\n\"is c #919192\",\n\"eK c #919195\",\n\"gE c #91a4a1\",\n\"jc c #929293\",\n\"#2 c #92a7bd\",\n\"hW c #92aabf\",\n\"nK c #938146\",\n\"bu c #949496\",\n\"ol c #949498\",\n\"eW c #94a9bf\",\n\"lh c #95abbe\",\n\"mS c #968964\",\n\"ih c #96aab3\",\n\"my c #999797\",\n\"g7 c #99acbb\",\n\"d1 c #9aafc6\",\n\"aI c #9b8c5f\",\n\"nD c #9b9a9b\",\n\"cy c #9b9a9e\",\n\"og c #9b9ba0\",\n\"es c #9ba9ba\",\n\"mg c #9bafc4\",\n\"cm c #9cbad4\",\n\"dQ c #9dabbb\",\n\"k4 c #9daeb4\",\n\"cj c #9dbbd5\",\n\"d5 c #9e9ea3\",\n\"hJ c #9eacaa\",\n\"nh c #9f9473\",\n\"l4 c #9fb6cf\",\n\"bf c #a09268\",\n\"o# c #a1a0a3\",\n\"bP c #a1a1a3\",\n\"hh c #a1b0b6\",\n\"eP c #a3acbb\",\n\"gU c #a3aeaa\",\n\"lC c #a3b3c4\",\n\"mf c #a4b2c3\",\n\"mO c #a5a5a8\",\n\"na c #a7a7aa\",\n\"lm c #a7bed3\",\n\"n1 c #a9a9a8\",\n\"cQ c #acabae\",\n\"n6 c #acacae\",\n\"da c #adacaf\",\n\"mm c #adadb2\",\n\"c0 c #adc6dc\",\n\"lg c #afb7c3\",\n\"dv c #b0afb3\",\n\"iP c #b0b0b2\",\n\"gr c #b1b9ad\",\n\"lY c #b1bcc9\",\n\"mh c #b1c1d4\",\n\"em c #b2b2b5\",\n\"js c #b3b3b6\",\n\"dz c #b3b9c4\",\n\"bX c #b3cade\",\n\"nv c #b49d59\",\n\"m5 c #b6a36a\",\n\"nV c #b6a573\",\n\"cc c #b6b6b6\",\n\"nR c #b6b6b7\",\n\"e2 c #b7b7b9\",\n\"ow c #b7b7bd\",\n\"lI c #b7c7d9\",\n\"cE c #b9cfe1\",\n\"gF c #baba9d\",\n\"np c #bbbabb\",\n\"mI c #bcaa78\",\n\"hv c #bcba99\",\n\"ov c #bcbcbf\",\n\"m0 c #bdbdc0\",\n\"gZ c #bdbdc2\",\n\"g8 c #bebea8\",\n\"fk c #bebec1\",\n\"d9 c #bec4cc\",\n\"hX c #bfbc98\",\n\"om c #bfbec0\",\n\"dL c #bfbec2\",\n\"eL c #bfbfbf\",\n\"gJ c #c0c0c2\",\n\"fK c #c0c0c3\",\n\"bv c #c1c1c0\",\n\"gk c #c1c5cc\",\n\"a0 c #c3ae6f\",\n\"it c #c3c3c5\",\n\"jd c #c3c3c6\",\n\"mC c #c4c3c8\",\n\"lB c #c4cad2\",\n\"bq c #c5b582\",\n\"oa c #c5c4c3\",\n\"mp c #c6c6c6\",\n\"me c #c6cbd1\",\n\"of c #c7c7c9\",\n\"l5 c #c7d1de\",\n\"d6 c #c8c7cb\",\n\"lT c #c8c8c9\",\n\"ln c #cacdc7\",\n\"dy c #cbccd1\",\n\"f9 c #cbd0d5\",\n\"ha c #cccccf\",\n\"bw c #cccfd3\",\n\"hK c #cdbf7a\",\n\"hl c #cdcccf\",\n\"jV c #cdccd0\",\n\"nE c #cdcdcd\",\n\"g0 c #cdcdd2\",\n\"ng c #ceb568\",\n\"hi c #cec9b0\",\n\"hC c #cecdcf\",\n\"h6 c #cecdd1\",\n\"nb c #ceced0\",\n\"j5 c #ceced2\",\n\"kf c #ceced3\",\n\"nJ c #cfb35b\",\n\"kE c #cfcdd1\",\n\"le c #cfced1\",\n\"lx c #cfced2\",\n\"bQ c #cfcfcf\",\n\"mx c #d0be88\",\n\"lz c #d0ced2\",\n\"iu c #d0cfd2\",\n\"jE c #d0cfd3\",\n\"md c #d0d0d3\",\n\"hS c #d0d2d7\",\n\"h7 c #d0d3d7\",\n\"gz c #d0d4da\",\n\"ms c #d1d0d4\",\n\"mE c #d1d0d5\",\n\"jt c #d1d1d3\",\n\"iS c #d1d1d4\",\n\"nc c #d1d1d5\",\n\"kK c #d1d5d8\",\n\"be c #d2b65c\",\n\"n2 c #d2d1d0\",\n\"jW c #d2d1d6\",\n\"dP c #d2d6d9\",\n\"j7 c #d2d6da\",\n\"ki c #d2d7da\",\n\"mR c #d3ba71\",\n\"m1 c #d3d2d4\",\n\"n5 c #d3d3d5\",\n\"gN c #d3d3d7\",\n\"jH c #d3d6da\",\n\"ju c #d3d7da\",\n\"bY c #d3e1ec\",\n\"jD c #d4d3d5\",\n\"eq c #d4d3d6\",\n\"cZ c #d4e1ed\",\n\"hY c #d5c270\",\n\"gV c #d5c78e\",\n\"d7 c #d5d4d6\",\n\"iQ c #d5d5d6\",\n\"lf c #d5d5d8\",\n\"hp c #d5d5d9\",\n\"er c #d5d8da\",\n\"ho c #d6d5d7\",\n\"de c #d6d6d8\",\n\"hG c #d6dbdf\",\n\"j6 c #d7d7d9\",\n\"lX c #d7dadb\",\n\"dh c #d7dadd\",\n\"cd c #d8d8d9\",\n\"fp c #d8dce0\",\n\"aH c #d9bc62\",\n\"cz c #d9d9d9\",\n\"g1 c #d9d9db\",\n\"cS c #dad9db\",\n\"kg c #dad9dd\",\n\"jC c #dadad9\",\n\"e4 c #dadee1\",\n\"g3 c #dadee2\",\n\"gP c #dadfe2\",\n\"jT c #dbdad9\",\n\"gx c #dbdadb\",\n\"lw c #dbdbd9\",\n\"gM c #dbdbdb\",\n\"f8 c #dbdbdc\",\n\"gy c #dbdbdd\",\n\"lJ c #dbe1e8\",\n\"on c #dcdbd8\",\n\"lV c #dcdbda\",\n\"en c #dcdcdb\",\n\"kI c #dcdcde\",\n\"m4 c #ddc67d\",\n\"j4 c #dddcdc\",\n\"fn c #dddcde\",\n\"ko c #ded0a6\",\n\"fL c #dedddd\",\n\"cT c #dedede\",\n\"hb c #dededf\",\n\"ob c #dfdedc\",\n\"dd c #dfdede\",\n\"kq c #dfdee1\",\n\"f7 c #dfdfde\",\n\"nu c #e0c162\",\n\"fi c #e0cd94\",\n\"kH c #e0dfdf\",\n\"mb c #e0e0e2\",\n\"bT c #e0e2e4\",\n\"cg c #e0e2e5\",\n\"mi c #e0e5ea\",\n\"bp c #e1c87e\",\n\"k5 c #e1cc87\",\n\"nU c #e1dbcd\",\n\"df c #e1e1e1\",\n\"gs c #e2cd86\",\n\"jZ c #e2cd8c\",\n\"ka c #e2ce94\",\n\"j0 c #e2ce95\",\n\"fM c #e2e1e1\",\n\"kZ c #e2e1e2\",\n\"eM c #e2e2e0\",\n\"fl c #e2e2e1\",\n\"fO c #e2e2e2\",\n\"oq c #e2e2e3\",\n\"eO c #e2e3e5\",\n\"hw c #e3c865\",\n\"ge c #e3cb75\",\n\"jP c #e3cd8f\",\n\"k# c #e3ce90\",\n\"jz c #e3cf93\",\n\"ip c #e3cf94\",\n\"jA c #e3dac3\",\n\"ly c #e3e2e1\",\n\"mD c #e3e2e2\",\n\"fm c #e3e3e2\",\n\"cA c #e3e3e3\",\n\"gO c #e3e3e4\",\n\"lA c #e3e4e2\",\n\"kM c #e4cc7b\",\n\"hQ c #e4e3e1\",\n\"hR c #e4e3e2\",\n\"kG c #e4e3e3\",\n\"dx c #e4e4e2\",\n\"fN c #e4e4e3\",\n\"kJ c #e4e4e4\",\n\"ii c #e5cd77\",\n\"kn c #e5ce88\",\n\"iL c #e5dfd1\",\n\"gj c #e5e4e2\",\n\"kh c #e5e4e4\",\n\"bR c #e5e5e4\",\n\"aG c #e6c550\",\n\"hL c #e6c960\",\n\"mq c #e6e5e1\",\n\"cR c #e6e5e3\",\n\"hF c #e6e5e4\",\n\"fo c #e6e5e5\",\n\"d8 c #e6e7e4\",\n\"dO c #e6e7e5\",\n\"gG c #e7cc70\",\n\"gw c #e7e6e4\",\n\"jF c #e7e6e6\",\n\"hn c #e7e7e4\",\n\"kp c #e7e7e5\",\n\"cU c #e7e7e6\",\n\"lS c #e7e7e9\",\n\"cN c #e8cd6d\",\n\"fJ c #e8cf82\",\n\"ky c #e8d28f\",\n\"jq c #e8e3d8\",\n\"hE c #e8e7e4\",\n\"nd c #e8e7e5\",\n\"ep c #e8e7e7\",\n\"gL c #e8e8e5\",\n\"cV c #e8e8e8\",\n\"oe c #e8e8e9\",\n\"cr c #e9ca5f\",\n\"hZ c #e9cb64\",\n\"mH c #e9cb6a\",\n\"jK c #e9cc6c\",\n\"ks c #e9cd6c\",\n\"hy c #e9d28a\",\n\"ke c #e9e8e5\",\n\"gv c #e9e8e6\",\n\"nF c #e9e8e7\",\n\"cB c #e9e8e8\",\n\"mt c #e9e8e9\",\n\"kr c #e9e9e7\",\n\"mF c #e9e9e9\",\n\"m2 c #e9e9ea\",\n\"iF c #eacd6c\",\n\"jQ c #eace7d\",\n\"kO c #eacf7a\",\n\"lo c #ead17f\",\n\"jR c #ead38a\",\n\"jp c #eadcb4\",\n\"nS c #eae8e7\",\n\"hm c #eae9e6\",\n\"gK c #eae9e7\",\n\"hq c #eaeae9\",\n\"oo c #eaeaec\",\n\"fG c #ebcf79\",\n\"ku c #ebcf7a\",\n\"kv c #ebd07f\",\n\"jm c #ebd286\",\n\"k. c #ebd287\",\n\"i8 c #ebe2c8\",\n\"j3 c #ebeae7\",\n\"dN c #ebebe7\",\n\"lW c #ebebe8\",\n\"dg c #ebebea\",\n\"jO c #ecce71\",\n\"fh c #ecce74\",\n\"gH c #ecd385\",\n\"mk c #ecd386\",\n\"mr c #eceae7\",\n\"nq c #eceae8\",\n\"dc c #ecebe7\",\n\"gi c #ecebe8\",\n\"nI c #edc95a\",\n\"gg c #edce72\",\n\"bL c #edd076\",\n\"hO c #edd384\",\n\"lp c #edd484\",\n\"kY c #edece8\",\n\"hD c #edece9\",\n\"ne c #edeced\",\n\"eo c #ededeb\",\n\"ce c #ededec\",\n\"n4 c #ededef\",\n\"l6 c #edf0f2\",\n\"aZ c #eec954\",\n\"d. c #eecc53\",\n\"fZ c #eecc54\",\n\"f2 c #eecf70\",\n\"gh c #eecf72\",\n\"i3 c #eed385\",\n\"j2 c #eed483\",\n\"ik c #eed484\",\n\"iG c #eed485\",\n\"ml c #eeebe3\",\n\"i9 c #eeede8\",\n\"dM c #eeede9\",\n\"jU c #eeedea\",\n\"cW c #eeeeed\",\n\"nr c #eeeeee\",\n\"nG c #eeeeef\",\n\"aW c #efc431\",\n\"b2 c #efc432\",\n\"mw c #efc84d\",\n\"nf c #efcb5d\",\n\"eH c #efcc53\",\n\"g9 c #efce60\",\n\"kN c #efcf6a\",\n\"km c #efcf6b\",\n\"f1 c #efcf6c\",\n\"f4 c #efd06e\",\n\"fH c #efd171\",\n\"iI c #efd172\",\n\"gX c #efd47f\",\n\"hA c #efd480\",\n\"lc c #efd483\",\n\"kX c #efd484\",\n\"iJ c #efd992\",\n\"mG c #efe7d3\",\n\"mP c #efe8d3\",\n\"lL c #efe9d3\",\n\"kF c #efedea\",\n\"dw c #efeee9\",\n\"db c #efeeea\",\n\"iR c #efefef\",\n\"cF c #eff4f8\",\n\"bd c #f0c12b\",\n\"bH c #f0cd5d\",\n\"io c #f0cf69\",\n\"kP c #f0d068\",\n\"k7 c #f0d069\",\n\"e0 c #f0d06a\",\n\"h2 c #f0d06b\",\n\"nH c #f0d379\",\n\"h1 c #f0d380\",\n\"im c #f0d480\",\n\"i7 c #f0dea8\",\n\"iK c #f0e4bf\",\n\"ns c #f0e7d3\",\n\"lv c #f0f0f3\",\n\"ck c #f0f5f9\",\n\"fF c #f1cf65\",\n\"k6 c #f1cf67\",\n\"bI c #f1cf68\",\n\"hj c #f1d064\",\n\"jY c #f1d066\",\n\"gf c #f1d067\",\n\"c. c #f1d16b\",\n\"cw c #f1d16c\",\n\"jo c #f1d98d\",\n\"e3 c #f1f1ef\",\n\"ld c #f1f1f2\",\n\"j# c #f1f1f3\",\n\"bo c #f2c848\",\n\"hx c #f2cd52\",\n\"b4 c #f2ce5e\",\n\"f3 c #f2cf63\",\n\"kb c #f2d16a\",\n\"i6 c #f2d478\",\n\"jG c #f2f2f0\",\n\"hM c #f3cf56\",\n\"i5 c #f3d062\",\n\"jn c #f3d26c\",\n\"jB c #f3f2f0\",\n\"bS c #f3f3f0\",\n\"cC c #f3f3f1\",\n\"ma c #f3f3f4\",\n\"mQ c #f4cf5a\",\n\"jy c #f4d05d\",\n\"fI c #f4d05f\",\n\"kQ c #f4d060\",\n\"kw c #f4d061\",\n\"m3 c #f4d370\",\n\"lM c #f4d470\",\n\"g2 c #f4f4f1\",\n\"b3 c #f5cb49\",\n\"b5 c #f5cf57\",\n\"bJ c #f5cf58\",\n\"iH c #f5d05b\",\n\"kt c #f5d05d\",\n\"kR c #f5d15e\",\n\"f5 c #f5d161\",\n\"eN c #f5f5f2\",\n\"op c #f5f5f6\",\n\"cs c #f6cf58\",\n\"f0 c #f6d057\",\n\"ct c #f6d260\",\n\"cX c #f6f6f3\",\n\"od c #f6f6f7\",\n\"nt c #f7d053\",\n\"b6 c #f7d157\",\n\"kx c #f7d158\",\n\"kz c #f7d25d\",\n\"cf c #f7f7f4\",\n\"lK c #f7f7f8\",\n\"gW c #f8d150\",\n\"jx c #f8d153\",\n\"k8 c #f8d154\",\n\"j1 c #f8d157\",\n\"b7 c #f8d259\",\n\"hP c #f8d25b\",\n\"hz c #f8d25c\",\n\"jX c #f8d25d\",\n\"jk c #f8d35b\",\n\"il c #f8d35c\",\n\"lR c #f8f8f9\",\n\"h0 c #f9d14e\",\n\"fg c #f9d151\",\n\"bK c #f9d153\",\n\"gt c #f9d256\",\n\"cu c #f9d257\",\n\"bc c #fac723\",\n\"mv c #facf46\",\n\"i4 c #fad14f\",\n\"jN c #fad151\",\n\"jr c #fafaf9\",\n\"n3 c #fafafb\",\n\"jw c #fbd14c\",\n\"kc c #fbd24d\",\n\"bG c #fcc925\",\n\"hk c #fcd147\",\n\"jM c #fcd14a\",\n\"in c #fcd24a\",\n\"gI c #fcd24b\",\n\"h. c #fcd24c\",\n\"b8 c #fcd24d\",\n\"jS c #fcf9f0\",\n\"mj c #fcfcfc\",\n\"m# c #fcfcfd\",\n\"mu c #fdd145\",\n\"fE c #fdd146\",\n\"jl c #fdd147\",\n\"jL c #fdd246\",\n\"hN c #fdd247\",\n\"kd c #fdd248\",\n\"cO c #fdd249\",\n\"hB c #fdd24c\",\n\"oc c #fdfdfd\",\n\"nT c #fdfdfe\",\n\"aY c #fec91f\",\n\"bb c #fec921\",\n\"gu c #fed243\",\n\"cv c #fed244\",\n\"ij c #fed246\",\n\"j. c #fefefe\",\n\"aX c #ffc91d\",\n\"b9 c #ffd242\",\n\"f6 c #ffd243\",\n\"m. c #ffd347\",\n\"kD c #ffd348\",\n\"l7 c #ffd449\",\n\"kS c #ffd44b\",\n\"kA c #ffd54f\",\n\"lu c #ffd654\",\n\"kW c #ffd757\",\n\"lb c #ffd85d\",\n\"l9 c #ffda65\",\n\"kC c #ffdc6c\",\n\"k9 c #ffdd71\",\n\"l8 c #ffde74\",\n\"lQ c #ffdf77\",\n\"lN c #ffdf78\",\n\"kB c #ffe07e\",\n\"lq c #ffe48e\",\n\"kT c #ffe9a2\",\n\"lt c #ffefbf\",\n\"kV c #fff2c6\",\n\"lO c #fff2c8\",\n\"lP c #fff3cc\",\n\"kU c #fff5d7\",\n\"l. c #fff7de\",\n\"la c #fffae9\",\n\"lr c #fffaec\",\n\"l# c #fffefd\",\n\"ls c #fffffe\",\n\"cl c #ffffff\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.#.a.b.c.d.e.f.gQtQtQtQtQtQtQtQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.g.h.i.j.k.l.m.n.o.p.q.r.sQtQtQtQtQtQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.t.u.v.w.x.y.z.A.A.A.B.C.D.E.F.G.H.IQtQtQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.J.K.L.M.N.O.P.Q.A.A.A.A.A.A.A.A.R.S.T.U.V.WQtQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.g.X.Y.Z.0.1.2.3.4.5.6.A.A.A.A.A.A.A.A.7.8.9#.###aQtQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#b#c#d#e#f#g#h.A#i#j#k#l#m#n#o.Q.A.A#p#q#r#s#t#u#v#w#xQtQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.##y#z#A#B#C#D#E.A.A.A.A.A.A#F#G#H#I#J#K#L#M#N#O#P#Q#R#R#S#TQtQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#U#V#W#X#Y.A.A.A.A.A.A.A.A.A.A.A#Z#0#1#2#3#4#5#R#R#R#R#R#6#7.gQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#8#9a.a#aaabac.z.A.A.A.A.A.zadaeafagahaiaj#R#R#R#R#R#R#RakalamanaoQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtapaq.A#parasatau.mav.QawaxayazaAaBaC#RaDaE#R#R#R#R#R#R#RaFaGaHaIaJaKaL.gQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaMaN.A.A.A.AabaOaPaQaRaSaTaUaV#R#R#R#RaDaE#R#R#R#R#R#R#RaFaWaXaYaZa0a1a2a3.g\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaMa4.A.A.A.A.Ba5a6a7a8a9b.b#ba#R#R#R#RaDaE#R#R#R#R#R#R#RaFaWaXaXbbbcbdbebfbg\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbhbibjbk.A.A.A.A.A.A.A#hblbm#R#R#R#R#R#R#RbnaE#R#R#R#R#R#R#RaFaWaXaXaXaXaYbobpbq\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbrbsbtbubvbwbx.A.A.A.A.A.A.A#pbybzbAbBbCbD#R#R#RbEbF#R#R#R#R#R#R#RaFaWaXaXbGbHbIbJbKbL\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbMbNbObPbQbRbSbTbU.A.A.A.A.A.A.A#pbybVbWbXbYbZb0#R#Rb1bF#R#R#R#R#R#R#RaFb2b3b4b5b6b7b8b9c.\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtc#cacbcccdcecfcfcfcgbU.A.A.A.A.A.A.A#pchcicjckclcmcn#R#RcobF#R#R#R#R#Rbacpcqcrcsctcucvb9b9b9cw\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtcxcyczcAcBcCcfcfcfcgbU.A.A.A.A.A.A.A#pchcDcEclcFcGcH#R#RcobF#R#R#RcIcJcKcLcMcNcOb9b9b9b9b9b9cw\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtcPcQcRcScTcUcVcWcXbTbU.A.A.A.A.A.A.A#pbycYcjcZc0c1#R#R#Rb1bFc2c3c4c5c6c7c8c9d.b9b9b9b9b9b9b9c.\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtd#dadbdbdcdddedfdgdhdi.B.A.A.A.A.A.A#pbybzc1djdkdl#R#R#Rdmdndodpdqdrds#R#Rdtd.b9b9b9b9b9b9b9cw\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtdudvdbdbdbdbdwdxdydzdA#odBdC.A.A.A.A#pchbV#R#R#R#Rb#dDdEdFdGdHbmbA#R#R#R#Rdtd.b9b9b9b9b9b9b9cw\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQt.gdIdJdKdLdbdbdMdNdOdPdQdRdSdTdUdVdWav.B.A#pchbz#Rbab#dXdYdZd0d1do#R#R#R#R#R#R#Rd2d.b9b9b9b9b9b9b9cw\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtd3d4d5d6d7dbdbd8d9e.e#.6.B.B.QeaebeceddB.AdCeebV#RdDefd0egehbAeiaE#R#R#R#R#R#R#Rd2d.b9b9b9b9b9b9b9c.\",\n\"QtQtQtQtQtQtQtQtQtQtQtejekelemeneoepeqereseteuacav.A.A.A.A.QevewexeyezeAeBeCeDeEeF#vdXbA#ReGaE#R#R#R#R#R#R#Rd2eHb9b9b9b9b9b9b9cw\",\n\"QtQtQtQtQtQtQtQtQteIeJeKeLeMeoeNcfeOePeQeRaceS.A.A.A.A.A.A.A.A.A.6eTeUeVeWeXeYeZb.#R#R#R#ReGaE#R#R#R#R#R#R#Rd2d.b9b9b9b9b9b9b9e0\",\n\"QtQtQtQtQtQtQtQtbMe1e2cTe3cfcfcfcfe4e5e6e7e8e9eS.A.A.A.A.A.A.Af.f#fafbfcfdfebA#R#R#R#R#R#ReiaE#R#R#R#R#R#R#RffeHb9b9b9b9b9fgfhfi\",\n\"QtQtQtQtQtQtQtQtfjfkflfmfnfocXcfcffpfqavfrfsftfufvfw.A.A#EfxfyfzfAfBeh#QeXfC#R#R#R#R#R#R#RfDaE#R#R#R#R#R#R#Rd2d.b9b9fEfFfGfHfIfJ\",\n\"QtQtQtQtQtQtQtQtfjfKdMcRfLfMfNfOeofpfq.A.A.B#hfPfQfRfSfTfUfVfWfXfY#R#R#ReXfC#R#R#R#R#R#R#RfDaE#R#R#R#R#R#R#Rd2fZf0f1f2f3f4f5f6cw\",\n\"QtQtQtQtQtQtQtQtfjfKdbdbdbdcf7f8cAf9g..A.A.A.A.A.zg#gagb#4dEba#R#R#R#R#ReXgc#R#R#R#R#R#R#RfDaE#R#R#R#R#R#RdDgdgegfggghcOb9b9b9c.\",\n\"QtQtQtQtQtQtQtQtfjfKdbdbdbdbgigjddgkgl.A.A.A.A.A.A.Agmgn#R#R#R#R#R#R#R#ReXfC#R#R#R#R#R#R#RfDaE#R#R#Rb#gogpgqgrgsgtgub9b9b9b9b9cw\",\n\"QtQtQtQtQtQtQtQtfjfKdbdMgvgwcRgxgygzgA.A.A.A.A.A.A.Agmgn#R#R#R#R#R#R#R#RgBfC#R#R#R#R#R#R#ReiaEba#vgCgDgEgFgGgHgIb9b9b9b9b9b9b9c.\",\n\"QtQtQtQtQtQtQtQtfjgJgKgLgMgNgOcXcfgPgA.A.A.A.A.A.A.AgQgn#R#R#R#R#R#R#R#RgRfC#R#R#R#R#R#R#Rbn#4gSgTgUgVgWb9b9gXgIb9b9b9b9b9b9b9cw\",\n\"QtQtQtQtQtQtQtQtgYgZg0g1g2cfcfcfcfg3gA.A.A.A.A.A.A.Ag4g5#R#R#R#R#R#R#R#RgRfC#R#R#R#Rba#Qb.g6g7g8g9cvb9b9b9b9gXh.b9b9b9b9b9b9b9cw\",\n\"QtQtQtQtQtQtQtQth#d6hahbcfcfcfcfcfg3hc.A.A.A.A.A.A.Ahdhe#R#R#R#R#R#R#R#RgRfC#R#R#R#Rhfhghhhihjhkgub9b9b9b9b9gXh.b9b9b9b9b9b9b9cw\",\n\"QtQtQtQtQtQtQtQth#hlhmhnhohphqcfcfgPhc.A.A.A.A.A.A.Ahrhs#R#R#R#R#R#R#R#RgRfC#Rhtc5huhvhwhxhyhzb9b9b9b9b9b9b9hAhBb9b9b9b9b9b9b9cw\",\n\"QtQtQtQtQtQtQtQth#hCdbhDhEhFfOdehbhGhc.A.A.A.A.A.A.Ahrhs#R#R#R#R#R#R#R#ReXhHhIhJhKhLhMhNb9hOhPb9b9b9b9b9b9b9hAgIb9b9b9b9b9b9b9c.\",\n\"QtQtQtQtQtQtQtQth#hCdbdbdbdMgKhQhRhShThUaw.A.A.A.A.Ahrhs#R#R#R#R#R#RhVfChWhXhYhZh0f6b9b9b9hOhPb9b9b9b9b9b9b9h1h.b9b9b9b9b9b9b9h2\",\n\"QtQtQtQtQtQth3h4h5h6dbdbdbdbdbdbhDh7h8h9i.i#iaib.A.Aichs#R#R#RaCidieifigihiiijb9b9b9b9b9b9ikilb9b9b9b9b9b9b9imhBb9b9b9b9b9inioip\",\n\"QtQtQt.gdJiqirisitiudbdbdbdbdbdbdbdPiviwixiyiziAex.ChrhsbAiBiCdpiDcK#4dDiEiFb9b9b9b9b9b9b9iGhzb9b9b9b9b9b9b9imhBb9b9cviHiIiJiKiL\",\n\"QtbriMiNiOiPiQiRe3iSdbdbdbdbdbdbdbdPiT.A.AaviUiViWiXiYiZiCc5i0i1i2#R#R#RiEiFb9b9b9b9b9b9b9i3hzb9b9b9b9b9b9b9imh.i4i5i6i7i8i9j.j#\",\n\"jajbjcjdcUcfcfcfe3iSdbdbdbdbdbdbdbdPje.A.A.A.A.A.Cjfjgjhjijjb##R#R#R#R#RiEiFb9b9b9b9b9b9b9i3jkb9b9b9b9b9b9jljmjnjojpjqjrclclclj#\",\n\"jsjteog2cfcfcfcfe3iSdbdbdbdbdbdbdbjujv.A.A.A.A.A.A.Agmgn#R#R#R#R#R#R#R#RiEiFb9b9b9b9b9b9b9i3ilb9b9b9gujwjxjyjzjAjBj.clclclclclj#\",\n\"jCjDjEjFjGcCcXcfe3iSdbdbdbdbdbdbdbjHjI.A.A.A.A.A.A.Agmgn#R#R#R#R#R#R#R#RjJjKb9b9b9b9b9b9b9i3ilb9jLjMjNjOjPjQjRjSclclclclclclclj#\",\n\"jTdbjUgjjVjWe3cXe3iSdbdbdbdbdbdbdbjHjI.A.A.A.A.A.A.Agmgn#R#R#R#R#R#R#R#RjJjKb9b9b9b9b9b9b9i3jXcvjYjZj0j1f6b9j2jSclclclclclclclj#\",\n\"jTdbdbdMgij3j4j5j6iQdbdbdbdbdbdbdbj7jv.A.A.A.A.A.A.AgQj8#R#R#R#R#R#R#R#Rj9jKb9b9b9b9b9b9b9k.k#kakbkckdcvb9b9j2jSclclclclclclclj#\",\n\"jTdbdbdbdbdbj3kecRkfkgkhdMdbdbdbdbkikj.A.A.A.A.A.A.Akkkl#R#R#R#R#R#R#R#Rj9jKb9b9b9b9inkmknkokbfgcOf6b9b9b9b9j2jSclclclclclclclj#\",\n\"jTdbdbdbdbdbdbdbhmh6kpfNg1kqkrdbdbkikj.A.A.A.A.A.A.Ahrhs#R#R#R#R#R#R#R#Rj9ksb9cvktkukvkwkxkykzb9b9b9kAkBkCkDj2jSclclclclclclclj#\",\n\"jTdbdbdbdbdbdbdbhmkEkFj3kGkhkHkIkJkKjI.A.A.A.A.A.A.Ahrhs#R#R#R#R#R#R#R#RkLkMkNkOkPkQkRgIb9hOhPb9b9kSkTkUkVkWkXjSclclclclclclclj#\",\n\"jTdbdbdbdbdbdbdbhmkEdbdbdbkYcRkZkGbwk0k1eS.A.A.A.A.Ahrhs#R#R#R#R#R#Rk2k3k4k5k6k7k8gub9b9b9hOhPb9b9k9l.l#lalblcjSclclclclclclclld\",\n\"jTdbdbdbdbdbdbdbhmledbdbdbdbdbdbj3lflglhlihUiw.A.A.Ahrhs#R#R#RljeZlklllmlnloinb9b9b9b9b9b9lpilb9b9lqlrlsltlulcjSclclclclclj.lvj6\",\n\"lwdbdbdbdbdbdbdbhmlxdbdbdbdbdbdbdblylzlAlBlClD#Kia.6hrhs#RlElFlGlHlIlJlKlLlMb9b9b9b9b9b9b9iGjkb9b9lNlOlPlQkDkXjSclclcllRlSlTeKlU\",\n\"lVdbdbdbdbdbdbdbhmlxdbdbdbdbdbdbdblyiudbdblWlXlYlZl0#ll1l2l3l4l5l6j.clcllLlMb9b9b9b9b9b9b9i3hzb9b9l7l8l9m.b9lcjSm#mambjsmcd4.#Qt\",\n\"jTdbdbdbdbdbdbdbhmlxdbdbdbdbdbdbdblymddbdbdbdbdbcRmemfmgmhmimjclclclclcllLlMb9b9b9b9b9b9b9i3hzb9b9b9b9b9b9cvmkmliQmmmnmo.gQtQtQt\",\n\"mpmqmrdMdbdbdbdbhmlxdbdbdbdbdbdbdblymsdbdbdbdbdbdbdbgjmtclclclclclclclcllLlMb9b9b9b9b9b9b9i3hzb9b9b9b9mumvmwmxmymz.IQtQtQtQtQtQt\",\n\"mAmBmCkhdbdbdbdbhmlxdbdbdbdbdbdbdbmDmEdbdbdbdbdbdbdbcRmFclclclclclclclclmGlMb9b9b9b9b9b9b9i3ilb9b9b9cvmHmImJmKh3.gQtQtQtQtQtQtQt\",\n\"brmLmMmNmOd7gidbhmlxdbdbdbdbdbdbdbmDmEdbdbdbdbdbdbdbcRmFclclclclclclclclmPlMb9b9b9b9b9b9b9i3ilb9mQmRmSmTmUmV.gQtQtQtQtQtQtQtQtQt\",\n\"QtQtQtmWmXmYmZm0f8m1dbdbdbdbdbdbdbfmmsdbdbdbdbdbdbdbcRm2clclclclclclclclmPm3b9b9b9b9b9b9b9gHm4m5m6m7m8m9QtQtQtQtQtQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtbrh#n.n#nanbkpdbdbdbdbdbmDncdbdbdbdbdbdbdbndneclclclclclclclclmPlMb9b9b9b9ijnfngnhninjnkbrQtQtQtQtQtQtQtQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtnlnmnnnonpgxnqdbdbfmncdbdbdbdbdbdbdbgKnrclclclclclclclclnsm3b9b9ntnunvnwnxnynzQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtbrnAnBnCnDnEhRlyncdbdbdbdbdbdbdbnFnGclclclclclclclclnsnHnInJnKnLnMnNQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQt.JnOnPnQnRh6gKdbdbdbdbdbdbnSnGclclclclclclnTlKnUnVnWnXnYh3QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtc#nZn0n1n2hQhDdbdbdbkrnGclclclcln3n4n5n6n7n8n9QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQth3o.bOo#oaobhmdMgKnGclocodoeofogohoiQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtojokolomonlyooopoqgZorosbrQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt\",\n\"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtotouovgNowoxmLQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt\"};\n\"\"\"\n\nif __name__ == \"__main__\":\n    dlg = Packages()\n    if not FreeCADGui.Control.activeDialog():\n        FreeCADGui.Control.showDialog(dlg)\n    else:\n        FreeCAD.Console.PrintError(\"Already there is an active task dialog.\\n\")",
    "url": "https://wiki.freecad.org/Macro_Packages",
    "raw_code_url": "",
    "wiki": "",
    "version": "0.4",
    "license": "",
    "date": "2025.01.18",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Packages_icon.svg",
    "icon_source": "https://wiki.freecad.org/images/c/c7/Packages_icon.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Print SceneGraph",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro traverses the SceneGraph and prints all the nodes and their fields in the Report View window. It can be used just for information or you can add code to modify parts of the SceneGraph in some way or print more details for particular types of node.<br /><br />Macro version: 00.03<br />Last modified: 2017-10-24<br />FreeCAD version: 0.16.6703<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/0/0b/Macro_Print_SceneGraph.png\">ToolBar Icon</a><br />Author: Aleph0<br /> ",
    "comment": "SceneGraph explorer",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"\n***************************************************************************\n*                                                                         *\n*   This macro traverses the SceneGraph and prints all the nodes and      *\n*   their fields in the Report View window. It can be used just for       *\n*   information or you can add code to modify parts of the SceneGraph in  *\n*   some way or print more details for particular types of node.          *\n*                                                                         *\n***************************************************************************\n*   Copyright \u00a9 2017 Richard P. Parkins, M. A.                          *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n\"\"\"\n__title__   = \"Print_SceneGraph\"\n__author__  = \"Aleph0\"\n__version__ = \"00.03\"\n__date__    = \"24/10/2017\"\n__Comment__ = \"SceneGraph explorer\"\n__Wiki__ = \"http://www.freecadweb.org/wiki/index.php?title=Macro_Print_SceneGraph\"\n__Help__ = \"see first few lines of macro text\"\n__Status__ = \"stable\"\n__Requires__ = \"freecad 0.16\"\n\n#OS: Ubuntu 14.04.5 LTS\n#Word size of OS: 64-bit\n#Word size of FreeCAD: 64-bit\n#Version: 0.16.6703 (Git)\n#Build type: None\n#Branch: releases/FreeCAD-0-16\n#Hash: 2ce5c8d2e3020d05005ed71f710e09e9aa561f40\n#Python version: 2.7.6\n#Qt version: 4.8.6\n#Coin version: 4.0.0a\n#OCC version: 6.8.0.oce-0.17\n\nimport FreeCAD\nfrom pivy import coin\nimport PySide\nfrom PySide import QtGui, QtCore\n\ndef printFields(node,indent):\n    nm = node.getName().__str__()\n    if nm != \"\":\n        FreeCAD.Console.PrintLog(indent+\"name: \"+nm+\"\\n\") \n    fl = node.getFieldData()\n    for i in range(fl.getNumFields()):\n        name = fl.getFieldName(i)\n        if name.__str__() != \"point\":\n            val = node.getField(fl.getFieldName(i)).get()\n            FreeCAD.Console.PrintLog(indent+str(name)+\" -> \"+str(val)+\"\\n\")\n\ndef printTree(node,indent):\n    FreeCAD.Console.PrintLog(indent+node.__str__()+\"\\n\")\n    if node.getTypeId().getName().__str__() == \"Coordinate3\":\n        points=node.point\n        for i in range(points.getNum()):\n            FreeCAD.Console.PrintLog(indent+\" \"+str(i)+\": \"+str(points[i].getValue())+\"\\n\")\n    if node.getTypeId().getName().__str__() == \"Coordinate4\":\n        points=node.point\n        for i in range(points.getNum()):\n            FreeCAD.Console.PrintLog(indent+\" \"+str(i)+\": \"+str(points[i].getValue())+\"\\n\")\n    printFields(node,indent+\" \")\n    if node.getChildren().__str__() != \"None\":\n        for i in range(node.getNumChildren()):\n            printTree(node.getChild(i),indent+\" \")\n\nad = FreeCADGui.ActiveDocument\nif ad == None:\n    FreeCAD.Console.PrintLog(\"No active document\\n\")\nelse:\n    QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))\n    printTree(ad.ActiveView.getViewer().getSoEventManager().getSceneGraph(), \"\")\n    QtGui.QApplication.restoreOverrideCursor()",
    "url": "https://wiki.freecad.org/Macro_Print_SceneGraph",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_Print_SceneGraph",
    "version": "00.03",
    "license": "",
    "date": "24/10/2017",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Aleph0",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Print_SceneGraph.png",
    "icon_source": "https://wiki.freecad.org/images/0/0b/Macro_Print_SceneGraph.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Python Assistant Window",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro provides a cut/copy/paste workspace for Python code, it is segmented so different sections can be selected and it is persistent between FreeCAD sessions.<br /><br />Macro version: 1.0<br />Last modified: 2015-01-21<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/4/45/Macro_Python_Assistant_Window.png\">ToolBar Icon</a><br />Author: Piffpoof<br /> ",
    "comment": "This macro provides a cut/copy/paste workspace for Python code, it is segmented so different sections can be selected and it is persistent between FreeCAD sessions.",
    "code": "<html>\r\n<head>\r\n\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf8\">\r\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n\t<title>...</title>\r\n\t<style type=\"text/css\">\r\n\t\t.erisime_engellenmis {\r\n\t\t\tfont-family: Arial, Helvetica, sans-serif;\r\n\t\t\tfont-size: 32px;\r\n\t\t\tfont-weight: bold;\r\n\t\t\tcolor: #0000FF;\r\n\t\t\ttext-decoration: none;\r\n\t\t\ttext-align: center;\r\n\t\t\tborder-right-width: 1px;\r\n\t\t\tborder-left-width: 1px;\r\n\t\t\tborder-right-style: none;\r\n\t\t\tborder-left-style: none;\r\n\t\t\tborder-right-color: #0000FF;\r\n\t\t\tborder-left-color: #0000FF;\r\n\t\t\tborder-top-width: 1px;\r\n\t\t\tborder-top-style: none;\r\n\t\t\tborder-top-color: #0000FF;\r\n\t\t\tborder-bottom-width: 1px;\r\n\t\t\tborder-bottom-style: none;\r\n\t\t\tborder-bottom-color: #0000FF;\r\n\t\t}\r\n\r\n\t\t.yazi1 {\r\n\t\t\tfont-family: Georgia, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 12px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #666666;\r\n\t\t\ttext-decoration: none;\r\n\t\t}\r\n\r\n\t\t.yazi2 {\r\n\t\t\tfont-family: Georgia, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 12px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #6565FF;\r\n\t\t\ttext-decoration: none;\r\n\t\t}\r\n\r\n\t\t.yazi3 {\r\n\t\t\tfont-family: Georgia, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 10px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #BB65FF;\r\n\t\t\ttext-decoration: none;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t}\r\n\r\n\t\t.yazi2_1 {\r\n\t\t\tfont-family: Verdana, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 12px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #6565FF;\r\n\t\t\ttext-decoration: none;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t}\r\n\r\n\t\t.yazi2_2 {\r\n\t\t\tfont-family: Verdana, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 12px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #00005C;\r\n\t\t\ttext-decoration: none;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t}\r\n\r\n\t\t.yazi3_1 {\r\n\t\t\tfont-family: Verdana, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 10px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #BB65FF;\r\n\t\t\ttext-decoration: none;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t}\r\n\r\n\t\t.yazi4_1 {\r\n\t\t\tfont-family: Verdana, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 10px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #444444;\r\n\t\t\ttext-decoration: none;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t}\r\n\r\n\t\t.yazi5_1 {\r\n\t\t\tfont-family: Verdana, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 35px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #FF0000;\r\n\t\t\ttext-decoration: none;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t}\r\n\r\n\t\t.yazi6_1 {\r\n\t\t\tfont-family: Verdana, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 25px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #FF0000;\r\n\t\t\ttext-decoration: none;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t}\r\n\r\n\t\ta.link:link {\r\n\t\t\tfont-family: Georgia, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 11px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #0000FF;\r\n\t\t\ttext-decoration: underline;\r\n\t\t}\r\n\r\n\t\ta.link:active {\r\n\t\t\tfont-family: Georgia, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 11px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #0000FF;\r\n\t\t\ttext-decoration: underline;\r\n\t\t}\r\n\r\n\t\ta.link:visited {\r\n\t\t\tfont-family: Georgia, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 11px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #0000FF;\r\n\t\t\ttext-decoration: underline;\r\n\t\t}\r\n\r\n\t\ta.link:hover {\r\n\t\t\tfont-family: Georgia, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 11px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #BB65FF;\r\n\t\t\ttext-decoration: none;\r\n\t\t}\r\n\r\n\t\t.alticizgili_genisliktd {\r\n\t\t\theight: 100%;\r\n\t\t\twidth: 100%;\r\n\t\t\tpadding-top: 20px;\r\n\t\t\tborder-bottom-width: 1px;\r\n\t\t\tborder-bottom-style: dotted;\r\n\t\t\tborder-bottom-color: #DDCCFE;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t\ttext-align: center;\r\n\t\t}\r\n\r\n\t\t.genisliktd {\r\n\t\t\theight: 100%;\r\n\t\t\twidth: 100%;\r\n\t\t\tpadding-top: 20px;\r\n\t\t\ttext-align: center;\r\n\t\t}\r\n\r\n\t\t.genisliktdbaslik {\r\n\t\t\theight: 100%;\r\n\t\t\twidth: 100%;\r\n\t\t\tpadding-top: 20px;\r\n\t\t\ttext-align: left;\r\n\t\t\tborder-bottom-width: 5px;\r\n\t\t\tborder-bottom-style: solid;\r\n\t\t\tborder-bottom-color: #DDCCFE;\r\n\t\t}\r\n\t</style>\r\n\r\n</head>\r\n\r\n<body onselectstart=\"return false\" bgcolor=\"aliceblue\">\r\n\t<div>\r\n\r\n\t\t<table border=\"0\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\" width=\"1024\" height=\"100%\">\r\n\t\t\t<tr>\r\n\t\t\t\t<td class=\"alticizgili_genisliktd\">\r\n<br><br><br> <span class=\"yazi2_2\">pastebin.com, 08/03/2012 tarihli ve 2012/27976 Say\u0131l\u0131 Ankara CBS karar\u0131yla eri\u015fime engellenmi\u015ftir.</span><br><br><span class=\"yazi3_1\">pastebin.com, 08/03/2012 has been blocked by the decision dated 2012/27976 and numbered 08/03/2012 of Ankara CBS.</span><br><br><br>\n<a class=\"link\" target=\"_blank\" href=\"http://www.ihbarweb.org.tr\">-http://www.ihbarweb.org.tr</a>\r\n</td>\r\n</tr>\r\n\r\n</table>\r\n</div>\r\n</body>\r\n\r\n</html>\r\n",
    "url": "https://wiki.freecad.org/Macro_Python_Assistant_Window",
    "raw_code_url": "http://pastebin.com/raw/2m0u94Z1",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2015-01-21",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Piffpoof",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Python_Assistant_Window.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/4/45/Macro_Python_Assistant_Window.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "ZTest Over 128",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro is only used by programmers.<br />Test characters ASCII over 127.<br /><br />Macro version: 3.0<br />Last modified: 2019-06-14<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/c/c1/Macro_ZTest_Over_128.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "This macro is only used by programmers.",
    "code": "\n\n# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\n#this macro is only used by programmers\n#test caracteres au dessus de 127\n#this is not one macro Not download\n\n__title__   = \"Macro_ZTest_Over_128\"\n__author__  = \"Programmer\"\n__url__     = \"https://www.freecadweb.org/wiki/Main_Page\"\n__Wiki__    = \"https://www.freecadweb.org/wiki/Macro_ZTest_Over_128\"\n__version__ = \"03.00\"\n__date__    = \"2019/06/14\"\n\n\ntry:\n    print()\n    print(\"chr()_____________________________1\")\n    print(chr(176))    #degree\n    print(chr(178))    #exposant 2\n    print(chr(179))    #exposant 3\n    print(chr(181))    #micro\n    print(chr(192))    #capital A accent grave\n    print(chr(193))    #capital A accent aigu\n    print(chr(194))    #capital A circonflex\n    print(chr(196))    #capital A trema\n    print(chr(197))    #capital A ring\nexcept Exception:\n    FreeCAD.Console.PrintError(\"ERROR mode 1\" + \"\\n\")\n\ntry:\n    print()\n    print(\"str(chr(176))_____________________2\")\n    print(str(chr(176)))    #degree\n    print(str(chr(178)))    #exposant 2\n    print(str(chr(179)))    #exposant 3\n    print(str(chr(181)))    #micro\n    print(str(chr(192)))    #capital A accent grave\n    print(str(chr(193)))    #capital A accent aigu\n    print(str(chr(194)))    #capital A circonflex\n    print(str(chr(196)))    #capital A trema\n    print(str(chr(197)))    #capital A ring\nexcept Exception:\n    FreeCAD.Console.PrintError(\"ERROR mode 2\" + \"\\n\")\n\ntry:\n    print()\n    print(\"b'\\xc2\\xb0'.decode('utf-8')_______3\")\n    print(b'\\xc2\\xb0'.decode('utf-8'))    #degree\n    print(b'\\xc2\\xb2'.decode('utf-8'))    #exposant 2\n    print(b'\\xc2\\xb3'.decode('utf-8'))    #exposant 3\n    print(b'\\xc2\\xb5'.decode('utf-8'))    #micro\n    print(b'\\xc3\\x80'.decode('utf-8'))    #capital A accent grave\n    print(b'\\xc3\\x81'.decode('utf-8'))    #capital A accent aigu\n    print(b'\\xc3\\x82'.decode('utf-8'))    #capital A circonflex\n    print(b'\\xc3\\x83'.decode('utf-8'))    #capital A trema\n    print(b'\\xc3\\x85'.decode('utf-8'))    #capital A ring\nexcept Exception:\n    FreeCAD.Console.PrintError(\"ERROR mode 3\" + \"\\n\")\n\ntry:\n    print()\n    print(\"b'\\xb0'.decode('iso8859')_________4\")\n    print(b'\\xb0'.decode('iso8859'))    #degree\n    print(b'\\xb2'.decode('iso8859'))    #exposant 2\n    print(b'\\xb3'.decode('iso8859'))    #exposant 3\n    print(b'\\xb5'.decode('iso8859'))    #micro\n    print(b'\\xc0'.decode('iso8859'))    #capital A accent grave\n    print(b'\\xc1'.decode('iso8859'))    #capital A accent aigu\n    print(b'\\xc2'.decode('iso8859'))    #capital A circonflex\n    print(b'\\xc3'.decode('iso8859'))    #capital A trema\n    print(b'\\xc5'.decode('iso8859'))    #capital A ring\nexcept Exception:\n    FreeCAD.Console.PrintError(\"ERROR mode 4\" + \"\\n\")\n\ntry:\n    print()\n    print(\"car_______________________________5\")\n    print(\"\u00b0\")    #degree\n    print(\"\u00b2\")    #exposant 2\n    print(\"\u00b3\")    #exposant 3\n    print(\"\u00b5\")    #micro\n    print(\"\u00c0\")    #capital A accent grave\n    print(\"\u00c1\")    #capital A accent aigu\n    print(\"\u00c2\")    #capital A circonflex\n    print(\"\u00c3\")    #capital A tilde\n    print(\"\u00c4\")    #capital A trema\n    print(\"\u00c5\")    #capital A ringexcept Exception:\nexcept Exception:\n    FreeCAD.Console.PrintError(\"ERROR mode 5\" + \"\\n\")\n\ntry:\n    print()\n    print(\"u'car'.encode('utf-8')____________6\")\n    print(u\"\u00b0\".encode('utf-8'))    #degree\n    print(u\"\u00b2\".encode('utf-8'))    #exposant 2\n    print(u\"\u00b3\".encode('utf-8'))    #exposant 3\n    print(u\"\u00b5\".encode('utf-8'))    #micro\n    print(u\"\u00c0\".encode('utf-8'))    #capital A accent grave\n    print(u\"\u00c1\".encode('utf-8'))    #capital A accent aigu\n    print(u\"\u00c2\".encode('utf-8'))    #capital A circonflex\n    print(u\"\u00c3\".encode('utf-8'))    #capital A trema\n    print(u\"\u00c5\".encode('utf-8'))    #capital A ring\nexcept Exception:\n    FreeCAD.Console.PrintError(\"ERROR mode 6\" + \"\\n\")\n\nprint(\"End_______________________________\")\n\nimport sys\nimport PySide\nfrom PySide import QtGui, QtCore\nclass fen():\n    label = QtGui.QLabel(\"FreeCAD\")\n    label.setGeometry(500, 300, 100, 100)\n    label.setWindowFlags( QtCore.Qt.WindowStaysOnTopHint |  QtCore.Qt.CustomizeWindowHint | QtCore.Qt.FramelessWindowHint) \n    label.setAlignment(QtCore.Qt.AlignCenter)\n\n#    label.setWindowFlags( QtCore.Qt.CustomizeWindowHint) \n#    label.setWindowFlags( QtCore.Qt.FramelessWindowHint) \n#    label.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint)\n\n    label.show()\n\nprint(\"End__Pipe_________________________\")\n\n\n\n\n",
    "url": "https://wiki.freecad.org/Macro_ZTest_Over_128",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_ZTest_Over_128",
    "version": "03.00",
    "license": "",
    "date": "2019/06/14",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Programmer",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_ZTest_Over_128.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/c/c1/Macro_ZTest_Over_128.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "TNP Solution",
    "on_wiki": true,
    "on_git": false,
    "desc": "This is a solution for Topological Naming Problem.<br /><br />Macro version: 1.0<br />Last modified: 2022-08-16<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/e/e4/TNP_solution.png\">ToolBar Icon</a><br />Author: Dprojects<br /> ",
    "comment": "This is a solution for Topological Naming Problem.",
    "code": "__Title__=\"TNP_solution\"\n__Author__ = \"Dprojects\"\n__Version__ = \"1.0\"\n__Date__    = \"2022-08-16\"\n__Comment__ = \"\"\n__Web__ = \"https://github.com/dprojects/Woodworking\"\n__Wiki__ = \"https://wiki.freecadweb.org/TNP_solution\"\n__Icon__  = \"https://wiki.freecad.org/images/e/e4/TNP_solution.png\"\n__IconW__  = \"https://wiki.freecad.org/images/e/e4/TNP_solution.png\"\n__Help__ = \"solution for Topological Naming Problem\"\n__Status__ = \"stable\"\n__Requires__ = \"\"\n__Communication__ = \"http://www.freecadweb.org/wiki/index.php?title=User:Dprojects\"\n\n# ####################################################################\n#\n# This is solution for Topological Naming Problem described at \n# https://wiki.freecadweb.org/Topological_naming_problem\n#\n# MIT License\n# \n# Copyright (c) 2022 Darek L github.com/dprojects\n# \n# Permission is hereby granted, free of charge, to any \n# person obtaining a copy of this software and associated \n# documentation files (the \"Software\"), to deal in the \n# Software without restriction, including without limitation \n# the rights to use, copy, modify, merge, publish, distribute, \n# sublicense, and/or sell copies of the Software, and to permit \n# persons to whom the Software is furnished to do so, subject \n# to the following conditions:\n# \n# The above copyright notice and this permission notice shall \n# be included in all copies or substantial portions of the Software.\n# \n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, \n# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES \n# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \n# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT \n# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, \n# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n# DEALINGS IN THE SOFTWARE.\n# \n# ####################################################################\n\nimport FreeCAD\n\n# this should be set according \n# FreeCAD user GUI precision settings\nprecision = 5\n\n# global settings\nad = FreeCAD.ActiveDocument\n\n# middle object to be resized\np1 = ad.Pad001\ns1 = p1.Profile[0]\n\n# top object bottom to store key\np2 = ad.Pad002\ns2 = p2.Profile[0]\n\n# ####################################################################\ndef getFaceIndex(iObj, iBB):\n\t\n\tindex = 0\t\n\n\tfor f in iObj.Shape.Faces:\n\n\t\tindex += 1\n\t\tbb = round(f.BoundBox.Center[2], precision)\n\t\t\n\t\tFreeCAD.Console.PrintMessage(\"\\n\")\n\t\tFreeCAD.Console.PrintMessage(index)\n\t\tFreeCAD.Console.PrintMessage(\" \")\n\t\tFreeCAD.Console.PrintMessage(bb)\n\n\t\tif bb == iBB:\n\t\t\tFreeCAD.Console.PrintMessage(\" <=== found\")\n\t\t\treturn index\n\n\treturn -1\n\n# ####################################################################\ndef makeTNP():\n\n\t# set key\n\tkey = round(s2.Shape.BoundBox.Center[2], precision)\n\n\t# resize and cause TNP\n\ts1.setDatum(9, FreeCAD.Units.Quantity('350'))\n\n\t# recompute\n\ts1.recompute()\n\tp1.recompute()\n\tad.recompute()\n\n\tFreeCAD.Console.PrintMessage(\"\\n\\n\")\n\tFreeCAD.Console.PrintMessage(\"Stored key:\"+str(key))\n\tFreeCAD.Console.PrintMessage(\"\\n\")\n\n\t# search all faces for solution\n\tsolutionIndex = getFaceIndex(p1, key)\n\tsolution = \"Face\"+str(solutionIndex)\n\t\n\tFreeCAD.Console.PrintMessage(\"\\n\\n\")\n\tFreeCAD.Console.PrintMessage(\"Solution: \"+solution)\n\t\n\t# set exact face to Sketch\n\ts2.Support = (p1, (solution,))\n\tad.recompute()\n\n# ####################################################################\ndef moveBack():\n\n\ts1.setDatum(9, FreeCAD.Units.Quantity('250'))\n\ts2.Support = (p1, ('Face13',))\n\tad.recompute()\n\n# ####################################################################\n# main\n# ####################################################################\n\n# uncomment what you want\nmakeTNP()\n#moveBack()\n\n# ####################################################################",
    "url": "https://github.com/dprojects/Woodworking",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/TNP_solution",
    "version": "1.0",
    "license": "",
    "date": "2022-08-16",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Dprojects",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\TNP_solution.png",
    "icon_source": "https://wiki.freecad.org/images/e/e4/TNP_solution.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "3DXML import",
    "on_wiki": true,
    "on_git": false,
    "desc": "Imports a 3DXML-ascii file to FreeCAD.<br /><br />Macro version: 0.1<br />Last modified: 2021-10-03<br />FreeCAD version: -<br />Author: heda<br /> ",
    "comment": "Imports a 3DXML-ascii file to FreeCAD",
    "code": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n# ***************************************************************************\n# *   Copyright (c) 2021 heda <heda @ freecad forum>                        *\n# *                                                                         *\n# *   This file is part of the FreeCAD CAx development system.              *\n# *                                                                         *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU Lesser General Public License (LGPL)    *\n# *   as published by the Free Software Foundation; either version 2 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENCE text file.                                 *\n# *                                                                         *\n# *   This program is distributed in the hope that it will be useful,       *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU Library General Public License for more details.                  *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with this program; if not, write to the Free Software   *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\n\n__Name__ = '3DXML_import'\n__Comment__ = 'Imports a 3DXML-ascii file to FreeCAD'\n__Author__ = 'heda @ fc-forum'\n__Version__ = '0.1'\n__Date__ = '2021-10-03'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = ''\n__Wiki__ = 'https://wiki.freecadweb.org/Macro_3DXML_import'\n__Icon__ = ''\n__Help__ = 'Launch macro and select file.'\n__Status__ = 'Stable'\n__Requires__ = 'tested on FreeCAD v0.19'\n__Communication__ = 'forum'\n__Files__ = ''\n\n\n__doc__ = \"\"\"\nThe 3DXML file format allows for multiple types of representations.\nThis macro is limited to human readable content in the files,\ni.e. the ascii tesselated type of geometry definition.\nThis type of geometry definition includes polylines as edges of geometry,\nand meshes (like stl files).\n\nThe macro in current state requires a readable xml-file of type \".3DRep\".\n\nImport of edges is by default off, since that is the operation taking the\nlongest time.\n\nIt is recommended to run a mesh analysis after import to for example\nremove duplicate points or correct flipped normals.\n\nThis macro is created using only one reference file (with only \"strips\" as\nfacets), thus it's applicability on other .3DRep files is currently unknown.\nIf other test files are made available, the macro can be updated.\n\"\"\"\n\nimport FreeCAD as App\nimport Part, Mesh\nfrom PySide import QtGui\nimport xml.etree.ElementTree as ET\n\nIMPORT_EDGES, MERGE_EDGES = False, False\nIMPORT_MESHES, MERGE_MESHES = True, True\n\nfilename, filt = QtGui.QFileDialog.getOpenFileName(filter='*.3DRep')\n\nif not filename:\n    raise UserWarning('Need to select a 3DRep file.')\n\nprint('Importing: {}'.format(filename))\ndoc = App.ActiveDocument\n\ntree = ET.parse(filename)\nroot = tree.getroot()\n\n# get namespaces from xml\nns = dict([node for _, node in\n           ET.iterparse(filename, events=['start-ns'])])\nif ns.get('') != 'http://www.3ds.com/xsd/3DXML':\n    raise UserWarning('did not find expected namespace, file malformed?')\nns.update({'3dx':ns.get('')})\n\n\ndef parse_verts(vertbuffer):\n    def floatify(xyz):\n        return tuple((float(i) for i in xyz.split()))\n    return [floatify(v) for v in vertbuffer.split(',')]\n\ndef parse_strips(strips):\n    return (tuple(int(i) for i in strip.split())\n            for strip in strips.split(','))\n\ndef make_mesh(element):\n    Faces, VertexBuffer, SurfaceAttributes = list(element)\n    Color = Faces.find('.//3dx:Color', ns)\n    RGBA = tuple((float(i) for i in tuple(Color.attrib.values())[1:]))\n    Face = Faces.find('.//3dx:Face', ns)\n    strips = Face.get('strips')\n    facets = list()\n    if strips:\n        Positions, Normals = list(VertexBuffer)\n        facetverts = fv = parse_verts(Positions.text)\n        for strip in parse_strips(strips):\n            facetidx = zip(strip, strip[1:], strip[2:])\n            facets += [tuple(fv[i] for i in pidx) for pidx in facetidx]\n    else:\n        print('face type undefined')\n    return Mesh.Mesh(facets), RGBA\n\n\nfor BagRepType in root.findall('3dx:Root/3dx:Rep', ns):\n    edges, meshes = list(), list()\n    for PolygonalRepType in BagRepType:\n        if PolygonalRepType.find('./3dx:Edges', ns):\n            if not IMPORT_EDGES:\n                continue\n            Edges = PolygonalRepType.find('./3dx:Edges', ns)\n            for polyline in Edges.findall('./3dx:Polyline', ns):\n                verts = parse_verts(polyline.get('vertices'))\n                edges.append(Part.makePolygon(verts))\n                \n        elif PolygonalRepType.find('./3dx:Faces', ns):\n            print('  found face element')\n            if not IMPORT_MESHES:\n                continue\n            mesh = make_mesh(PolygonalRepType)\n            meshes.append(mesh)\n\n    if edges:\n        print('  creating edges')\n        edgegroup = doc.addObject('App::DocumentObjectGroup','Edges')\n        wires = list()\n        if MERGE_EDGES:\n            _edges = list()\n            for _edge in edges:\n                _edges += _edge.Edges\n            for swire in Part.sortEdges(_edges):\n                wire = Part.Wire(swire)\n                obj = doc.addObject('Part::Feature', 'Edge')\n                obj.Shape = wire\n                wires.append(obj)\n        else:\n            for edge in edges:\n                obj = doc.addObject('Part::Feature', 'Edge')\n                obj.Shape = edge\n                wires.append(obj)\n        edgegroup.addObjects(wires)\n\n    if meshes:\n        print('  creating meshes')\n        meshgroup = doc.addObject('App::DocumentObjectGroup','Meshes')\n        meshobjs = list()\n        if MERGE_MESHES:\n            mesh_assembled = Mesh.Mesh()\n            for mesh, RGBA in meshes:\n                mesh_assembled.addMesh(mesh)\n            obj = doc.addObject('Mesh::Feature', 'Mesh')\n            obj.Mesh = mesh_assembled\n            obj.ViewObject.ShapeColor = RGBA\n            meshobjs.append(obj)\n        else:\n            for mesh, RGBA in meshes:\n                obj = doc.addObject('Mesh::Feature', 'Mesh')\n                obj.Mesh = mesh\n                obj.ViewObject.ShapeColor = RGBA\n                meshobjs.append(obj)\n        meshgroup.addObjects(meshobjs)\n\ndoc.recompute()\nprint('... completed import')\n\n# end",
    "url": "https://wiki.freecad.org/Macro_3DXML_import",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_3DXML_import",
    "version": "0.1",
    "license": "",
    "date": "2021-10-03",
    "src_filename": "",
    "filename_from_url": "",
    "author": "heda @ fc-forum",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Batch Export To Mesh",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro helps batch converting to mesh and exporting STL and OBJ files<br /><br />Macro version: 2.16<br />Last modified: 2024-10-11<br />Author: Pablo Gil Fern\u00e1ndez<br /> ",
    "comment": "This macro helps batch converting to mesh and exporting STL and OBJ files",
    "code": "__Title__   = \"Batch export to mesh\"\n__Author__  = \"Pablo Gil Fern\u00e1ndez\"\n__Version__ = \"2.16\"\n__Date__    = \"2024-10-11\"\n__Comment__ = \"This macro helps batch converting to mesh and exporting STL and OBJ files\"\n__Web__ = \"https://github.com/pgilfernandez/FreeCAD_Macro_Batch_Export_To_Mesh\"\n__Wiki__ = \"https://wiki.freecad.org/Macro_Batch_Export_To_Mesh\"\n__Icon__  = \"/usr/lib/freecad/Mod/Mesh/Resources/icons/MeshWorkbench.svg\"\n# __IconW__  = \"C:/Documents and Settings/YourUserName/Application Data/FreeCAD\"\n__Help__ = \"https://forum.freecadweb.org/viewtopic.php?f=22&t=41219\"\n__Status__ = \"stable\"\n__Requires__ = \"FreeCAD 0.17\"\n__Communication__ = \"https://github.com/pgilfernandez/FreeCAD_Macro_Batch_Export_To_Mesh\"\n\nimport FreeCAD, FreeCADGui, Draft, Part, PartGui, math, PartDesignGui, Mesh, MeshPart, Import, os\nfrom FreeCAD import Base\nfrom PySide import QtGui, QtCore\nfrom math import cos, radians\nfrom pivy import coin\nimport sys\nimport subprocess\nimport Mesh\n\nApp = FreeCAD\nGui = FreeCADGui\n\n# If developer mode is True it will show important messages on the Report panel:\ndev_mode = False\n\nclass SavePresetDialog(QtGui.QDialog):\n    def __init__(self, parent=None):\n        super(SavePresetDialog, self).__init__(parent)\n        self.setWindowTitle(\"Save Preset\")\n        self.layout = QtGui.QVBoxLayout()\n\n        self.label = QtGui.QLabel(\"Enter new preset name:\")\n        self.layout.addWidget(self.label)\n\n        self.nameEdit = QtGui.QLineEdit()\n        self.layout.addWidget(self.nameEdit)\n\n        self.buttonBox = QtGui.QDialogButtonBox(QtCore.Qt.Horizontal)\n        self.saveButton = QtGui.QPushButton(\"Save\")\n        self.cancelButton = QtGui.QPushButton(\"Cancel\")\n        self.buttonBox.addButton(self.saveButton, QtGui.QDialogButtonBox.AcceptRole)\n        self.buttonBox.addButton(self.cancelButton, QtGui.QDialogButtonBox.RejectRole)\n        self.layout.addWidget(self.buttonBox)\n\n        self.setLayout(self.layout)\n\n        self.saveButton.clicked.connect(self.accept)\n        self.cancelButton.clicked.connect(self.reject)\n\n    def getName(self):\n        return self.nameEdit.text().strip()\n\nclass BatchExportToMesh(QtGui.QDockWidget):\n    def __init__(self):\n        if dev_mode:\n            self.clear_console()\n\n        existing_instance = Gui.getMainWindow().findChild(QtGui.QWidget, \"BatchETM\")\n        if existing_instance:\n            if dev_mode:\n                self.message(\"Old instance closed!\")\n            existing_instance.close()  # close instance\n\n        super(BatchExportToMesh, self).__init__()\n        self.setWindowTitle(\"Batch export to mesh\")\n        self.setObjectName(\"BatchETM\")\n        self.setWindowIcon(QtGui.QIcon(\":/icons/Mesh_SplitComponents.svg\"))\n        self.resize(420, 500)\n        self.paramGet = App.ParamGet(\"User parameter:BaseApp/BatchETM\")\n        self.initParameters()\n        self.initGui()\n        # self.loadConfigurations()\n        # self.updateConfigDropdown()\n        self.loadActiveConfiguration()  # Cargar la configuraci\u00f3n activa al iniciar\n        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)\n        Gui.getMainWindow().addDockWidget(QtCore.Qt.RightDockWidgetArea, self)\n        self.setFloating(True)\n        self.topLevelChanged.connect(self.on_topLevelChanged) # resize window to defaults when undocking\n        self.setFocusOnInput()\n\n    def setFocusOnInput(self):\n        self.configDropdown.setFocus()\n        \n    def initParameters(self):\n        self.paramGet = App.ParamGet(\"User parameter:BaseApp/BatchETM\")\n        configsGroup = self.paramGet.GetGroup(\"Configurations\")\n        groupNames = configsGroup.GetGroups()  # groupNames es una lista de nombres de grupos (cadenas)\n        if not groupNames:\n            if dev_mode:\n                self.message(\"Creando configuraci\u00f3n por defecto\")\n            # Crear configuraci\u00f3n por defecto\n            self.createDefaultConfiguration()\n\n        # Cargar configuraciones\n        self.loadConfigurations()\n\n    def loadConfigurations(self):\n        self.configurations = []\n        configsGroup = self.paramGet.GetGroup(\"Configurations\")\n        if configsGroup is None:\n            # Crear el grupo 'Configurations' si no existe\n            configsGroup = self.paramGet.GetGroup(\"Configurations\")\n            if dev_mode:\n                self.message(\"Creado el grupo 'Configurations'\")\n        groupNames = configsGroup.GetGroups()  # Ahora groupNames es una lista de nombres de grupos (cadenas)\n\n        if not groupNames:\n            # Si no existen configuraciones, crear una configuraci\u00f3n por defecto\n            self.createDefaultConfiguration()\n        else:\n            for groupName in groupNames:\n                configGroup = configsGroup.GetGroup(groupName)\n                configName = configGroup.GetString(\"ConfigName\")\n                if not configName:\n                    configName = configGroup.GetString(\"Name\")\n                self.configurations.append((groupName, configName))\n\n            if dev_mode:\n                self.message(\"Configuraciones cargadas: \" + str(self.configurations))\n\n    def createDefaultConfiguration(self):\n        configsGroup = self.paramGet.GetGroup(\"Configurations\")\n        defaultConfig = configsGroup.GetGroup(\"config_1\")\n        defaultConfig.SetString(\"ConfigName\", \"Default\")\n        defaultConfig.SetString(\"Name\", \"Default\")\n        defaultConfig.SetFloat(\"SurfaceDeviation\", 0.10)\n        defaultConfig.SetBool(\"Relative\", False)\n        defaultConfig.SetFloat(\"AngularDeviation\", 5.0)\n        defaultConfig.SetString(\"FileNameOption\", \"Label\")\n        defaultConfig.SetBool(\"LocalCoordinates\", True)\n        defaultConfig.SetString(\"FileFormat\", \"Stereolithography (.STL)\")\n        defaultConfig.SetString(\"FileSavingDirectory\", \"./\")\n        # Establecer ActiveConfig solo al crear la configuraci\u00f3n por defecto por primera vez\n        self.paramGet.SetInt(\"ActiveConfig\", 1)\n        # self.configurations.append((\"config_1\", \"Default\"))\n        if dev_mode:\n            self.message(\"Creada configuraci\u00f3n por defecto\")\n\n    def on_topLevelChanged(self, floating):\n        if floating:\n            self.resize(420, 500)\n\n    def initGui(self):\n        infoIcon = [\n            \"16 16 3 1\",\n            \"   c None\",\n            \"+  c #444444\",\n            \".  c #e6e6e6\",\n            \"      ....      \",\n            \"    ........    \",\n            \"   .....++...   \",\n            \"  ......++....  \",\n            \" .............. \",\n            \" ....+++++..... \",\n            \" ...+++++...... \",\n            \".......++.......\",\n            \".......++.......\",\n            \" ......+....... \",\n            \" .....++....... \",\n            \" .....++.+..... \",\n            \"  ....++++....  \",\n            \"   ....++....   \",\n            \"    ........    \",\n            \"      ....      \"\n        ]\n\n        folderIcon = [\n            \"16 16 3 1\",\n            \"   c None\",\n            \"+  c #444444\",\n            \".  c #e6e6e6\",\n            \"                \",\n            \" .....          \",\n            \".......         \",\n            \"........        \",\n            \"..............  \",\n            \"..............  \",\n            \"...             \",\n            \"...             \",\n            \"..  ............\",\n            \"..  ............\",\n            \".  ............ \",\n            \".  ............ \",\n            \"  ............  \",\n            \"  ............  \",\n            \" ............   \",\n            \"                \"\n        ]\n        \n        deleteIcon = [\n            \"16 16 3 1\",\n            \"   c None\",\n            \"+  c #444444\",\n            \".  c #e6e6e6\",\n            \"                \",\n            \"                \",\n            \"                \",\n            \"                \",\n            \"                \",\n            \"                \",\n            \"                \",\n            \"  ............  \",\n            \"  ............  \",\n            \"                \",\n            \"                \",\n            \"                \",\n            \"                \",\n            \"                \",\n            \"                \",\n            \"                \"\n        ]\n        \n        addIcon = [\n            \"16 16 3 1\",\n            \"   c None\",\n            \"+  c #444444\",\n            \".  c #e6e6e6\",\n            \"                \",\n            \"                \",\n            \"       ..       \",\n            \"       ..       \",\n            \"       ..       \",\n            \"       ..       \",\n            \"       ..       \",\n            \"  ............  \",\n            \"  ............  \",\n            \"       ..       \",\n            \"       ..       \",\n            \"       ..       \",\n            \"       ..       \",\n            \"       ..       \",\n            \"                \",\n            \"                \"\n        ]\n\n        # Hide/show \"to column\" label and spinbox based on mode type\n        def disableWidget():\n            if self.d7c.isChecked():\n                self.d7c.setText(\"Custom:\")\n                self.d4.show()\n                self.d4.setEnabled(True)\n                if len(Gui.Selection.getSelection()) == 0:\n                    self.d4.setText(\"mesh001\")\n                else:\n                    self.d4.setText(Gui.Selection.getSelection()[0].Label)\n            else:\n                self.d7c.setText(\"Custom\")\n                self.d4.setEnabled(False)\n                self.d4.setText(\"\")\n                self.d4.hide()\n\n        self.dockWidgetContents = QtGui.QWidget()\n        self.dockWidgetContents.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)\n        self.dockWidgetContents.setObjectName(\"dockWidgetContents\")\n\n        self.grid = QtGui.QGridLayout(self.dockWidgetContents)\n        self.grid.setSpacing(10)\n\n        iN1 = QtGui.QLabel(\"Surface deviation\")\n        iN1.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)\n        self.d1 = QtGui.QDoubleSpinBox()\n        self.d1.setValue(0.10)\n        self.d1.setSingleStep(0.01)\n        self.d1.setToolTip(\"Maximal linear deflection of a mesh section from the surface of the object\")\n        self.d1.setSuffix(\" mm\")\n\n        iN2 = QtGui.QLabel(\"Angular deviation\")\n        iN2.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)\n        self.d2 = QtGui.QDoubleSpinBox()\n        self.d2.setValue(5.0)\n        self.d2.setSingleStep(1.0)\n        self.d2.setToolTip(\"Maximal angular deflection of a mesh section to the next section\")\n        self.d2.setSuffix(\" \u00ba\")\n\n        iN3 = QtGui.QLabel(\"Relative\")\n        iN3.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)\n        self.d3 = QtGui.QCheckBox()\n        self.d3.setToolTip(\"The maximal linear deviation of a mesh segment will be specified\\nSurface deviation multiplied by the length of the current mesh segment (edge)\")\n\n        self.d4 = QtGui.QLineEdit()\n        self.d4.setText(\"\")  # Default value\n        self.d4.setToolTip(\"Name without extension. For batch export multiple objects it is recommended to add '001' to the name so that the rest of files are numbered correctly.\")\n        self.d4.setEnabled(False)  # set initial state as disabled\n        self.d4.hide()\n\n        iN5 = QtGui.QLabel(\"File format\")\n        iN5.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)\n        self.d5 = QtGui.QComboBox()\n        self.d5.addItem(\"Stereolithography (.STL)\")\n        self.d5.addItem(\"Alias mesh (.OBJ)\")\n        self.d5.setToolTip(\"File format to export\")\n        self.d5.setCurrentIndex(0)  # sets default option\n\n        iN6 = QtGui.QLabel(\"File Saving Directory\")\n        iN6.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)\n        self.d6 = QtGui.QLineEdit()\n        self.d6.setText(\"./\")  # Default value\n        self.d6.setToolTip(\"Use any absolute path you want or use relative ones taking in count that:\\n  - start with './' for relative paths from your project directory.\\n  - use '../' to exit a folder.\")\n\n        iN7 = QtGui.QLabel(\"File name:\")\n        iN7.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)\n        self.d7a = QtGui.QRadioButton(\"Label\")\n        self.d7a.setChecked(True)\n        self.d7a.setToolTip(\"if selected, the .STL file will be named with the user defined name\")\n        self.d7a.toggled.connect(disableWidget)\n\n        self.d7b = QtGui.QRadioButton(\"Project\")\n        self.d7b.setChecked(False)\n        self.d7b.setToolTip(\"if selected, the .STL file will be named with the project name, that is, the FreeCAD file name\")\n        self.d7b.toggled.connect(disableWidget)\n\n        self.d7c = QtGui.QRadioButton(\"Custom\")\n        self.d7c.setChecked(False)\n        self.d7c.setToolTip(\"if selected, the .STL file will be named with a custom name set in the next field\")\n        self.d7c.toggled.connect(disableWidget)\n\n        # Agrupar los botones de radio\n        self.radio_group = QtGui.QButtonGroup()\n        self.radio_group.addButton(self.d7a)\n        self.radio_group.addButton(self.d7b)\n        self.radio_group.addButton(self.d7c)\n\n        iN8 = QtGui.QLabel(\"Use local coordinates\")\n        iN8.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)\n        self.d8 = QtGui.QCheckBox()\n        self.d8.setChecked(True)\n        self.d8.setToolTip(\"if TRUE the .STL origin will match with the part one. It's a very useful option when you design multipart files or assemblies\")\n\n        # Presets\n        iN9 = QtGui.QLabel(\"Preset:\")\n        iN9.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)\n        self.configDropdown = QtGui.QComboBox()\n        self.configDropdown.setToolTip(\"Select a saved preset to change all the macro parameters. You can save them as new presets whenever you want with the button to the left.\")\n        self.updateConfigDropdown()\n        self.configDropdown.currentIndexChanged.connect(self.onConfigSelected)\n\n        self.deleteConfigButton = QtGui.QPushButton() # \"Delete\" button\n        deleteSVG = QtGui.QIcon(':/icons/list-remove.svg')\n        if not deleteSVG.isNull():\n            self.deleteConfigButton.setIcon(deleteSVG)\n        else:\n            self.deleteConfigButton.setIcon(QtGui.QIcon(QtGui.QPixmap(deleteIcon)))\n        self.deleteConfigButton.setToolTip(\"Delete active preset.\")\n        self.deleteConfigButton.clicked.connect(self.onDeleteConfig)\n        \n        self.savePresetButton = QtGui.QPushButton() # \"New...\" button\n        addSVG = QtGui.QIcon(':/icons/list-add.svg')\n        if not addSVG.isNull():\n            self.savePresetButton.setIcon(addSVG)\n        else:\n            self.savePresetButton.setIcon(QtGui.QIcon(QtGui.QPixmap(addIcon)))\n        self.savePresetButton.setToolTip(\"Save parameters into a new preset.\")\n        self.savePresetButton.clicked.connect(self.openSavePresetDialog)\n\n        self.SavePath = QtGui.QPushButton()\n        folderSVG = QtGui.QIcon(':/icons/folder.svg')\n        if not folderSVG.isNull():\n            self.SavePath.setIcon(folderSVG)\n        else:\n            self.SavePath.setIcon(QtGui.QIcon(QtGui.QPixmap(folderIcon)))\n        self.SavePath.setObjectName(\"save_path\")\n        self.SavePath.setToolTip(\"Sets a directory to save the converted files. By default it saves the files in the same directory as the FreeCAD project is placed\")\n        self.SavePath.clicked.connect(self.onSavePath)\n\n        self.openPath = QtGui.QPushButton()\n        self.openPath.setText(\"Open folder\")\n        self.openPath.setMinimumHeight(40)\n        self.openPath.setObjectName(\"open_path\")\n        self.openPath.setToolTip(\"Opens the directory written to the left. By default it opens the folder where the FreeCAD project is placed\")\n        self.openPath.clicked.connect(self.onOpenPath)\n\n        self.convertStlButton = QtGui.QPushButton()\n        self.convertStlButton.setText(\"Convert\")\n        self.convertStlButton.setMinimumHeight(40)\n        self.convertStlButton.setObjectName(\"create\")\n        self.convertStlButton.setToolTip(\"Create a new mesh from selected objects inside the FreeCAD project.\")\n        self.convertStlButton.clicked.connect(self.onConvertStl)\n\n        self.saveStl = QtGui.QPushButton()\n        self.saveStl.setText(\"Save to file\")\n        self.saveStl.setMinimumHeight(40)\n        self.saveStl.setObjectName(\"save\")\n        self.saveStl.setToolTip(\"Export selected objects into a mesh file (STL or OBJ).\")\n        self.saveStl.clicked.connect(self.onSaveMesh)\n\n        self.help = QtGui.QPushButton()\n        infoSVG = QtGui.QIcon(':/icons/info.svg')\n        if not infoSVG.isNull():\n            self.help.setIcon(infoSVG)\n        else:\n            self.help.setIcon(QtGui.QIcon(QtGui.QPixmap(infoIcon)))\n        self.help.setFixedWidth(40)\n        self.help.setObjectName(\"help\")\n        self.help.setToolTip(\"More information aboout the macro.\")\n        self.help.clicked.connect(self.onInfo)\n\n        self.noSelection = QtGui.QPushButton()\n        self.noSelection.setText(\"No selection\")\n        self.noSelection.setObjectName(\"noSelection\")\n        self.noSelection.clicked.connect(self.onError)\n        \n        self.infoLabel = QtGui.QLabel(\"\")\n        self.infoLabel.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter)\n\n        spacer1 = QtGui.QSpacerItem(20, 20, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)\n        spacer2 = QtGui.QSpacerItem(20, 20, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)\n        spacer3 = QtGui.QSpacerItem(20, 20, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)\n\n        line_separator1 = QtGui.QFrame()\n        line_separator1.setObjectName(\"separator\")\n        line_separator1.setFrameShape(QtGui.QFrame.HLine)\n        line_separator1.setFrameShadow(QtGui.QFrame.Sunken)\n        line_separator1.setStyleSheet(\"background-color: rgba(0, 0, 0, 0.2);border: 1px solid transparent;border-bottom-color: rgba(255, 255, 255, 0.2);\")\n        \n        line_separator2 = QtGui.QFrame()\n        line_separator2.setObjectName(\"separator\")\n        line_separator2.setFrameShape(QtGui.QFrame.HLine)\n        line_separator2.setFrameShadow(QtGui.QFrame.Sunken)\n        line_separator2.setStyleSheet(\"background-color: rgba(0, 0, 0, 0.2);border: 1px solid transparent;border-bottom-color: rgba(255, 255, 255, 0.2);\")\n\n        info = QtGui.QLabel(\"v\" + __Version__)\n        info.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)\n        # info.setStyleSheet(\"color:#2e2d2d; font-style:italic;\")\n\n        line = QtGui.QLabel(\"------------------------------------------\")\n\n        # addWidget(*Widget, row, column, rowspan, colspan)\n        # Presets management\n        self.grid.addWidget(iN9,                        1, 0, 1, 1)\n        self.grid.addWidget(self.configDropdown,        1, 1, 1, 9)\n        self.grid.addWidget(self.deleteConfigButton,    1, 10, 1, 1)\n        self.grid.addWidget(self.savePresetButton,      1, 11, 1, 1)\n        \n        self.grid.addItem(spacer1,                      2, 0, 1, 12)\n        self.grid.addWidget(line_separator1,            3, 0, 1, 12)\n        \n        # Convert\n        self.grid.addWidget(iN1,                        4, 0, 1, 3)\n        self.grid.addWidget(self.d1,                    4, 3, 1, 6)\n        self.grid.addWidget(iN3,                        4, 9, 1, 2)\n        self.grid.addWidget(self.d3,                    4, 11, 1, 1)\n        self.grid.addWidget(iN2,                        5, 0, 1, 3)\n        self.grid.addWidget(self.d2,                    5, 3, 1, 6)\n        self.grid.addWidget(iN7,                        6, 0, 1, 3)\n        self.grid.addWidget(self.d7a,                   6, 3, 1, 3)\n        self.grid.addWidget(self.d7b,                   7, 3, 1, 3)\n        self.grid.addWidget(self.d7c,                   8, 3, 1, 3)\n        self.grid.addWidget(self.d4,                    8, 6, 1, 6)\n        self.grid.addWidget(iN8,                        9, 0, 1, 3)\n        self.grid.addWidget(self.d8,                    9, 3, 1, 1)\n        self.grid.addWidget(self.convertStlButton,      10, 0, 1, 12)\n        \n        self.grid.addItem(spacer2,                      11, 0, 1, 12)\n        self.grid.addWidget(line_separator2,            12, 0, 1, 12)\n        \n        # Save to file\n        self.grid.addWidget(iN5,                        13, 0, 1, 3)\n        self.grid.addWidget(self.d5,                    13, 3, 1, 9)\n        self.grid.addWidget(iN6,                        14, 0, 1, 3)\n        self.grid.addWidget(self.d6,                    14, 3, 1, 8)\n        self.grid.addWidget(self.SavePath,              14, 11, 1, 1)\n        self.grid.addWidget(self.saveStl,               15, 0, 1, 8)\n        self.grid.addWidget(self.openPath,              15, 8, 1, 4)\n        \n        self.grid.addItem(spacer3,                      16, 0, 1, 12)\n        \n        # Info footer\n        self.grid.addWidget(self.help,                  17, 0, 1, 1)\n        self.grid.addWidget(self.infoLabel,             17, 1, 1, 10)\n        self.grid.addWidget(info,                       17, 11, 1, 1)\n\n        # Fixed label widths\n        iN1.setFixedWidth(140)\n\n        self.setWidget(self.dockWidgetContents)\n        self.dockWidgetContents.setContentsMargins(0, 0, 0, 0)\n\n        # Load the active configuration\n        self.loadActiveConfiguration()\n\n    def updateConfigDropdown(self):\n        self.configDropdown.clear()\n        if dev_mode:\n            print(\"\")\n            print(\"UPDATE START\")\n        for groupName, configName in self.configurations:\n            self.configDropdown.addItem(configName)\n        # Establecer el \u00edndice seleccionado seg\u00fan la configuraci\u00f3n activa\n        activeConfigIndex = self.paramGet.GetInt(\"ActiveConfig\")\n        if dev_mode:\n            if dev_mode:\n                print(\"    UPDATE - ActiveConfig loaded: \" + str(activeConfigIndex))\n        # print(\"len(self.configurations): \" + str(len(self.configurations)))\n        if 1 <= activeConfigIndex <= len(self.configurations):\n            if dev_mode:\n                print(\"    UPDATE - Update ActiveConfig: \" + str(activeConfigIndex))\n            self.configDropdown.setCurrentIndex(activeConfigIndex)\n        else:\n            if dev_mode:\n                print(\"    UPDATE - Reset ActiveConfig to defaults (1)\")\n            self.configDropdown.setCurrentIndex(1)\n        \n        if dev_mode:\n            print(\"UPDATE END\")\n\n\n    def onConfigSelected(self, index):\n        if index >= 0 and index < len(self.configurations):\n            groupName, configName = self.configurations[index]  \n            self.paramGet.SetInt(\"ActiveConfig\", index + 1)  # Actualiza ActiveConfig\n            self.loadConfiguration(groupName)\n            if dev_mode:\n                print(\"\")\n                print(\"SAVE CONFIG - ActiveConfig: \" + str(index + 1))\n\n\n    def loadActiveConfiguration(self):\n        activeConfigIndex = self.paramGet.GetInt(\"ActiveConfig\")\n        if 1 <= activeConfigIndex <= len(self.configurations):\n            if dev_mode:\n                print(\"\")\n                print (\"LOAD ACTIVE - ActiveConfig: \" + str(activeConfigIndex))\n            # Bloquear se\u00f1ales para evitar llamadas redundantes a onConfigSelected\n            self.configDropdown.blockSignals(True)\n            self.configDropdown.setCurrentIndex(activeConfigIndex -1)\n            self.configDropdown.blockSignals(False)\n            # Cargar la configuraci\u00f3n correspondiente\n            groupName, configName = self.configurations[activeConfigIndex - 1]\n            self.loadConfiguration(groupName)\n        else:\n            # Si el \u00edndice no es v\u00e1lido, cargar la configuraci\u00f3n por defecto\n            self.configDropdown.blockSignals(True)\n            self.configDropdown.setCurrentIndex(0)\n            self.configDropdown.blockSignals(False)\n            groupName, configName = self.configurations[0]\n            self.loadConfiguration(groupName)\n\n\n\n    def loadConfiguration(self, groupName):\n        configsGroup = self.paramGet.GetGroup(\"Configurations\")\n        configGroup = configsGroup.GetGroup(groupName)\n        # Set the parameters\n        self.d1.setValue(configGroup.GetFloat(\"SurfaceDeviation\", 0.10))\n        self.d2.setValue(configGroup.GetFloat(\"AngularDeviation\", 5.0))\n        self.d3.setChecked(configGroup.GetBool(\"Relative\", False))\n        fileNameOption = configGroup.GetString(\"FileNameOption\", \"Label\")\n        if fileNameOption == \"Label\":\n            self.d7a.setChecked(True)\n        elif fileNameOption == \"Project\":\n            self.d7b.setChecked(True)\n        else:\n            self.d7c.setChecked(True)\n        self.d8.setChecked(configGroup.GetBool(\"LocalCoordinates\", True))\n        fileFormat = configGroup.GetString(\"FileFormat\", \"Stereolithography (.STL)\")\n        index = self.d5.findText(fileFormat)\n        if index != -1:\n            self.d5.setCurrentIndex(index)\n        self.d6.setText(configGroup.GetString(\"FileSavingDirectory\", \"./\"))\n\n    def onSaveConfig(self, configName):\n        if not configName:\n            self.onError(\"<h2>Empty Preset Name</h2><p style='font-weight:normal;'>Please enter a name for the preset.</p>\")\n            return\n        # Determine the next available configuration number\n        configsGroup = self.paramGet.GetGroup(\"Configurations\")\n        existingConfigs = configsGroup.GetGroups()  # existingConfigs is a list of group names (strings)\n        nextConfigNumber = 1\n        while \"config_\" + str(nextConfigNumber) in existingConfigs:\n            nextConfigNumber += 1\n        # Save the current parameters into the new configuration\n        newConfigGroup = configsGroup.GetGroup(\"config_\" + str(nextConfigNumber))\n        newConfigGroup.SetString(\"ConfigName\", configName)\n        newConfigGroup.SetString(\"Name\", configName)\n        newConfigGroup.SetFloat(\"SurfaceDeviation\", self.d1.value())\n        newConfigGroup.SetFloat(\"AngularDeviation\", self.d2.value())\n        newConfigGroup.SetBool(\"Relative\", self.d3.isChecked())\n        if self.d7a.isChecked():\n            newConfigGroup.SetString(\"FileNameOption\", \"Label\")\n        elif self.d7b.isChecked():\n            newConfigGroup.SetString(\"FileNameOption\", \"Project\")\n        else:\n            newConfigGroup.SetString(\"FileNameOption\", \"Custom\")\n        newConfigGroup.SetBool(\"LocalCoordinates\", self.d8.isChecked())\n        newConfigGroup.SetString(\"FileFormat\", self.d5.currentText())\n        newConfigGroup.SetString(\"FileSavingDirectory\", self.d6.text())\n        # Update the list of configurations\n        self.loadConfigurations()\n        self.updateConfigDropdown()\n        # Set the new configuration as active\n        self.paramGet.SetInt(\"ActiveConfig\", len(self.configurations))\n        self.configDropdown.blockSignals(True)\n        self.configDropdown.setCurrentIndex(len(self.configurations) - 1)\n        self.configDropdown.blockSignals(False)\n        groupName, configName = self.configurations[len(self.configurations) - 1]\n        self.loadConfiguration(groupName)\n\n\n    def onDeleteConfig(self):\n        index = self.configDropdown.currentIndex()\n        if index >= 0 and index < len(self.configurations):\n            groupName, configName = self.configurations[index]\n            if groupName == \"config_1\":\n                self.onError(\"<h2>Default preset can't be deleted</h2><p style='font-weight:normal;'>Select any other preset to be deleted.</p>\")\n                return\n            # Confirmar eliminaci\u00f3n\n            reply = QtGui.QMessageBox.question(None, 'Confirm preset removal', \"<p style='font-weight:normal;'>Are you sure do you want to delete <span style='font-weight:bold'>\" + str(configName) + \"</span>?</p>\", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)\n            if reply == QtGui.QMessageBox.Yes:\n                # Eliminar la configuraci\u00f3n\n                configsGroup = self.paramGet.GetGroup(\"Configurations\")\n                configsGroup.RemGroup(groupName)\n                # Actualizar la lista de configuraciones\n                self.loadConfigurations()\n                self.updateConfigDropdown()\n                # Establecer la configuraci\u00f3n por defecto como activa\n                self.paramGet.SetInt(\"ActiveConfig\", 1)\n                self.configDropdown.blockSignals(True)\n                self.configDropdown.setCurrentIndex(0)\n                self.configDropdown.blockSignals(False)\n                groupName, configName = self.configurations[0]\n                self.loadConfiguration(groupName)\n            self.infoMessages(\"Preset removed!\",\"positive\")\n\n    def openSavePresetDialog(self):\n        dialog = SavePresetDialog(self)\n        if dialog.exec_() == QtGui.QDialog.Accepted:\n            presetName = dialog.getName()\n            if presetName:\n                self.onSaveConfig(presetName)\n                self.infoMessages(\"Preset saved!\",\"positive\")\n            else:\n                self.onError(\"<h2>Empty Configuration Name</h2><p style='font-weight:normal;'>Please enter a name for the configuration.</p>\")\n\n    def onInfo(self):\n        msg=\"\"\"<h2>Batch export to mesh</h2><p style='font-weight:normal;font-style:italic;'>version \"\"\" + __Version__ + \"\"\"</p><p style='font-weight:normal;'>This macro helps Bath converting to mesh and exporting STL and OBJ files. It adds a GUI for speeding up the conversion and file saving of the selected objects</p><p>Features</p><ul><li style='font-weight:normal;'>FreeCAD \"standard\" meshing option</li><li style='font-weight:normal;'>custom names</li><li style='font-weight:normal;'>Converts/exports one or several objects at once</li><li style='font-weight:normal;'>Convert objects into the active FreeCAD project, a user selected folder or</li><li style='font-weight:normal;'>Export objects to .STL or .OBJ files</li><li style='font-weight:normal;'>Absolute or relative paths allowed</li><li style='font-weight:normal;'>Select local or global coordinates</li><li style='font-weight:normal;'>Creates folders if needed</li><li style='font-weight:normal;'>Opens folder in file explorer</li><li style='font-weight:normal;'>Presets loading/saving</li></ul><hr><h2>Licence</h2><p style='font-weight:normal;'>Copyright 2024 Pablo Gil Fern\u00e1ndez</p><p style='font-weight:normal;'>This work is licensed under GNU Lesser General Public License (LGPL). To view a copy of this license, visit:</p><p style='font-weight:normal;'><a href='https://www.gnu.org/licenses/lgpl-3.0.html'>https://www.gnu.org/licenses/lgpl-3.0.html</a></p>\"\"\"\n        # Create a message box\n        res = QtGui.QMessageBox()\n        res.setWindowTitle(\"Information\")\n        res.setText(msg)\n        \n        infoSVG = QtGui.QPixmap(\":/icons/info.svg\")\n        if not infoSVG.isNull():\n            res.setIconPixmap(infoSVG)\n        else:\n            res.setIcon(QtGui.QMessageBox.Information)  # Set a predefined icon: NoIcon, Information, Warning, Critical, Question\n\n        # Show the message box\n        res.exec_()\n\n    # ERROR\n    def onError(self, msg):\n        res = QtGui.QMessageBox.warning(None,\"Error\",msg,QtGui.QMessageBox.Ok)\n\n    # GET SAVING PATH\n    def onSavePath(self):\n        folder_path = QtGui.QFileDialog.getExistingDirectory()\n        if folder_path:\n            if dev_mode:\n                self.message(folder_path)\n            self.d6.setText(folder_path)\n\n    # OPEN PATH IN FILE BROWSER\n    def onOpenPath(self):\n        if dev_mode:\n            print(\"\\nOpen directory\\n===================\")\n        project_filename_path = FreeCAD.ActiveDocument.FileName\n        project_path = os.path.dirname(project_filename_path)\n        length_project_path = len(project_path)\n        final_folder_path = \"\"\n        user_path = self.d6.text()\n        length_user_path = len(user_path)\n        if dev_mode:\n            print(\"\\nproject_path = \" + project_path)\n            print(\"\\nlength_project_path = \" + str(length_project_path))\n            print(\"\\nuser_path = \" + user_path)\n            print(\"\\nlength_user_path = \" + str(length_user_path))\n        if length_project_path == 0:\n            FreeCAD.Console.PrintError(\"\\nProject not saved!\\nIt is not possible to open the file browser. Try again after saving your project somewhere.\")\n            self.onError(\"<h2>Project not saved!</h2><p style='font-weight:normal;'>It is not possible to open the file browser. Try again after saving your project somewhere.</p>\")\n        else:\n            if length_user_path == 0:\n                if dev_mode:\n                    self.message(\"\\n-- Absolute mode (user path) --\")\n                final_folder_path = project_path\n            else:\n                project_filename_path = FreeCAD.ActiveDocument.FileName\n                project_path = os.path.dirname(project_filename_path)\n                length_user_path = len(user_path)\n                if length_user_path == 0:\n                    if dev_mode:\n                        self.message(\"\\n-- Absolute mode (project path) --\")\n                    final_folder_path = project_path\n                else:\n                    if dev_mode:\n                        self.message(\"\\n-- Relative mode --\")\n                    joined_path = os.path.join(project_path, user_path)\n                    final_folder_path = os.path.abspath(joined_path)\n\n            if os.path.exists(final_folder_path):\n                if dev_mode:\n                    self.message(\"\\nThe path exists\")\n                    self.message(\"\\nfinal_folder_path: \" + final_folder_path)\n\n                    if dev_mode:\n                        print(\"\\nOpening...\")\n                        FreeCAD.Console.PrintMessage(\"\\nOpening...\")\n\n                operating_system = sys.platform\n                if operating_system == \"darwin\":\n                    if dev_mode:\n                        print(\"\\nOpening macOS Finder...\")\n                    subprocess.run([\"open\", final_folder_path])\n\n                elif operating_system == \"win32\":\n                    if dev_mode:\n                        print(\"\\nOpening File Explorer...\")\n                    subprocess.run([\"explorer\", final_folder_path], shell=True)\n\n                elif operating_system == \"linux\":\n                    if dev_mode:\n                        print(\"\\nOpening Linux file explorer...\")\n                    subprocess.run([\"xdg-open\", final_folder_path])\n\n                else:\n                    FreeCAD.Console.PrintError(\"\\nUnsupported operating system\")\n                    self.onError(\"<h2>Unsupported operating system</h2><p style='font-weight:normal;'>It is not possible to open your OS file browser.</p>\")\n\n            else:\n                FreeCAD.Console.PrintError(\"\\nThe path doesn't exist, please create it\")\n                self.onError(\"<h2>The path doesn't exist</h2><p style='font-weight:normal;'>Please create it manually.</p>\")\n\n    # CONVERT STL INTO ACTIVE FREECAD PROJECT\n    def onConvertStl(self):\n        if dev_mode:\n            self.clear_console()\n            self.message(\"\\n****** START (convert) ********\")\n\n        # Variables\n        selection = Gui.Selection.getSelection()\n        surface = self.d1.value()\n        angular = self.d2.value() * math.pi / 180\n        if self.d3.isChecked():\n            relative = True\n        else:\n            relative = False\n        name = self.d4.text()\n\n        if len(selection) == 0:\n            if dev_mode:\n                self.message(\"\\n-- No selection --\")\n            FreeCAD.Console.PrintError(\"Export STL error: nothing selected, please, select one or several objects\")\n            self.onError(\"<h2>Nothing selected</h2><p style='font-weight:normal;'>You must select at least one object to convert or export.</p>\")\n\n        elif len(selection) == 1:\n            if dev_mode:\n                self.message(\"\\n-- 1 object selected --\")\n            # Generate Mesh\n            mesh = App.ActiveDocument.addObject(\"Mesh::Feature\",\"Mesh\")\n            part = Gui.Selection.getSelection()[0]\n            shape = part.Shape.copy(False)\n\n            # Set part coordinates (local or global)\n            if self.d8.isChecked():\n                shape.Placement = App.Placement(App.Vector(0,0,0), App.Rotation(App.Vector(0,0,1),0), App.Vector(0,0,0))\n            else:\n                shape.Placement = part.getGlobalPlacement()\n\n            # Create mesh\n            mesh.Mesh = MeshPart.meshFromShape(Shape=shape, LinearDeflection=surface, AngularDeflection=angular, Relative=relative)\n\n            # Name mesh\n            if self.d7a.isChecked():\n                final_name = Gui.Selection.getSelection()[0].Label\n            elif self.d7b.isChecked():\n                final_name = App.ActiveDocument.Name\n            else:\n                final_name = name\n\n            mesh.Label = final_name\n\n            part.Visibility = False\n            Gui.activeDocument().activeObject().DisplayMode=u\"Flat Lines\"\n            if dev_mode:\n                self.message(\"\\n-- 1 object converted to mesh --\")\n            del mesh, part, shape\n            \n            self.infoMessages(\"1 object converted to mesh\",\"positive\")\n\n        else:\n            quantity = len(selection)\n            if dev_mode:\n                self.message(\"\\n-- \" + str(quantity) + \" objects selected --\")\n            i = 0\n            while i < quantity:\n                mesh = App.ActiveDocument.addObject(\"Mesh::Feature\",\"Mesh\")\n                part = Gui.Selection.getSelection()[i]\n                shape = part.Shape.copy(False)\n\n                # Set part coordinates (local or global)\n                if self.d8.isChecked():\n                    shape.Placement = App.Placement(App.Vector(0,0,0), App.Rotation(App.Vector(0,0,1),0), App.Vector(0,0,0))\n                else:\n                    shape.Placement = part.getGlobalPlacement()\n\n                # Create mesh\n                mesh.Mesh = MeshPart.meshFromShape(Shape=shape, LinearDeflection=surface, AngularDeflection=angular, Relative=relative)\n\n                # Name mesh\n                if self.d7a.isChecked():\n                    mesh.Label = Gui.Selection.getSelection()[i].Label\n                elif self.d7b.isChecked():\n                    mesh.Label = App.ActiveDocument.Name + \"_\" + str(i+1)\n                else:\n                    mesh.Label = name + \"_\" + str(i+1)\n\n                part.Visibility = False\n                Gui.activeDocument().activeObject().DisplayMode=u\"Flat Lines\"\n                del mesh, part, shape\n                i += 1\n            if dev_mode:\n                self.message(\"\\n-- \" + str(quantity) + \" objects converted to mesh --\")\n            \n            self.infoMessages(str(quantity) + \" objects converted to mesh\",\"positive\")\n            \n        App.ActiveDocument.recompute()\n        if dev_mode:\n            self.message(\"\\n********* END *********\")\n            FreeCAD.Console.PrintMessage(\"\\nConversion done\")\n\n\n    # SAVE TO .STL OR .OBJ FILE\n    def onSaveMesh(self):\n        if dev_mode:\n            self.clear_console()\n            self.message(\"\\n****** START (save) ********\")\n\n        # Variables\n        selection = Gui.Selection.getSelection()\n        surface = self.d1.value()\n        angular = self.d2.value() * math.pi / 180\n        if self.d3.isChecked():\n            relative = True\n        else:\n            relative = False\n        name = self.d4.text()\n        savePath = self.d6.text()\n        docPath = FreeCAD.ActiveDocument.FileName\n\n        if docPath == \"\":\n            if savePath[0] == \".\":\n                if dev_mode:\n                    self.message(\"\\n-- The project is not saved or the path doesn't correspond to an absolute one --\")\n                    FreeCAD.Console.PrintError(\"Error exporting: The project is not saved or the path doesn't correspond to an absolute one, please, save your project somewhere or add a valid absolute path under '<i>File saving directory</i>' field.\")\n                self.onError(\"<h2>Error exporting</h2><p style='font-weight:normal;'>The project is not saved or the path doesn't correspond to an absolute one, please, save your project somewhere or add a valid absolute path under '<i>File saving directory</i>' field.</p>\")\n                return\n            if os.path.exists(savePath) and os.path.isdir(savePath):\n                if dev_mode:\n                    self.message(\"\\nsavePath is valid, continuing... \")\n            else:\n                if dev_mode:\n                    self.message(\"\\n-- The project is not saved or the path doesn't correspond to an absolute one --\")\n                    FreeCAD.Console.PrintError(\"Error exporting: The project is not saved or the path doesn't correspond to an absolute one, please, save your project somewhere or add a valid absolute path under '<i>File saving directory</i>' field.\")\n                self.onError(\"<h2>Error exporting</h2><p style='font-weight:normal;'>The project is not saved or the path doesn't correspond to an absolute one, please, save your project somewhere or add a valid absolute path under '<i>File saving directory</i>' field.</p>\")\n                return\n\n        if savePath[0] == \".\":\n            if dev_mode:\n                self.message(\"\\n-- Relative mode: --\")\n            absolutePath = os.path.dirname(docPath)\n            relativePath = savePath.replace(\".\",\"\",1)\n            relativePath = relativePath.replace(\"\\\\\",\"\",1)\n            relativePath = relativePath.replace(\"/\",\"\",1)\n            savePath = os.path.join(absolutePath, relativePath)\n\n        if len(selection) == 0:\n            if dev_mode:\n                self.message(\"\\n-- No selection --\")\n                FreeCAD.Console.PrintError(\"Export STL error: nothing selected, please, select one or several objects\")\n            self.onError(\"<h2>Nothing selected</h2><p style='font-weight:normal;'>You must select at least one object to convert or export.</p>\")\n            return\n\n        elif len(selection) == 1:\n            if dev_mode:\n                self.message(\"\\n-- 1 object selected --\")\n            # Generate STL\n            obj=[]\n            part = Gui.Selection.getSelection()[0]\n            shape = part.Shape.copy(False)\n\n            # Set part coordinates (local or global)\n            if self.d8.isChecked():\n                shape.Placement = App.Placement(App.Vector(0,0,0), App.Rotation(App.Vector(0,0,1),0), App.Vector(0,0,0))\n            else:\n                shape.Placement = part.getGlobalPlacement()\n\n            # Create mesh\n            mesh = MeshPart.meshFromShape(Shape=shape, LinearDeflection=surface, AngularDeflection=angular, Relative=relative)\n\n            # Name mesh\n            if self.d7a.isChecked():\n                final_name = Gui.Selection.getSelection()[0].Label\n            elif self.d7b.isChecked():\n                final_name = App.ActiveDocument.Name\n            else:\n                final_name = name\n\n            # Check if the path exists:\n            if not os.path.exists(savePath):\n                if dev_mode:\n                    FreeCAD.Console.PrintWarning(\"\\nThe path doesn't exist, creating it...\")\n                os.makedirs(savePath, exist_ok=True)\n            else:\n                if dev_mode:\n                    print(\"\\nThe path exist, continuing...\")\n\n            if self.d5.currentText() == \"Stereolithography (.STL)\":\n                # export mesh to STL\n                filename = os.path.join(savePath, final_name + \".stl\")\n                mesh.write(filename)\n            if self.d5.currentText() == \"Alias mesh (.OBJ)\":\n                # export mesh to OBJ\n                filename = os.path.join(savePath, final_name + \".obj\")\n                obj = []\n                obj.append(part)\n                Mesh.export(obj, filename)\n\n            if dev_mode:\n                self.message(\"\\n-- 1 mesh exported to file at: \" + filename + \" --\")\n            del mesh, obj, part, shape\n\n            if dev_mode:\n                FreeCAD.Console.PrintMessage(\"\\nSaved\")\n        \n            self.infoMessages(\"1 object exported to file\",\"positive\")\n\n        else:\n            quantity = len(selection)\n            if dev_mode:\n                self.message(\"\\n-- \" + str(quantity) + \" objects selected --\")\n            i = 0\n            namesArray = []\n            labelsArray = []\n            while i < quantity:\n                obj=[]\n                part = Gui.Selection.getSelection()[i]\n                shape = part.Shape.copy(False)\n\n                # Set part coordinates (local or global)\n                if self.d8.isChecked():\n                    shape.Placement = App.Placement(App.Vector(0,0,0), App.Rotation(App.Vector(0,0,1),0), App.Vector(0,0,0))\n                else:\n                    shape.Placement = part.getGlobalPlacement()\n\n                # Create mesh\n                mesh = MeshPart.meshFromShape(Shape=shape, LinearDeflection=surface, AngularDeflection=angular, Relative=relative)\n\n                # Name mesh\n                if self.d7a.isChecked():\n                    final_name = Gui.Selection.getSelection()[i].Label\n                elif self.d7b.isChecked():\n                    final_name = App.ActiveDocument.Name + \"_\" + str(i+1)\n                else:\n                    final_name = name + \"_\" + str(i+1)\n\n                labelsArray.append(final_name)\n\n                # Check if the path exists:\n                if not os.path.exists(savePath):\n                    FreeCAD.Console.PrintWarning(\"\\nThe path doesn't exist, creating it...\")\n                    os.makedirs(savePath, exist_ok=True)\n                else:\n                    if dev_mode:\n                        print(\"\\nThe path exist, continuing...\")\n\n                if self.d5.currentText() == \"Stereolithography (.STL)\":\n                    # export mesh to STL\n                    filename = os.path.join(savePath, labelsArray[i] + \".stl\")\n                    mesh.write(filename)\n                if self.d5.currentText() == \"Alias mesh (.OBJ)\":\n                    # export mesh to OBJ\n                    filename = os.path.join(savePath, labelsArray[i] + \".obj\")\n                    obj = []\n                    obj.append(part)\n                    Mesh.export(obj, filename)\n\n                if dev_mode:\n                    self.message(\"\\n-- 1 mesh exported to file at: \" + filename + \" --\")\n                del mesh, obj, part, shape\n                i += 1\n\n            i = 0\n            while i < quantity:\n                if dev_mode:\n                    self.message(\"\\n-- \" + str(labelsArray[i]) + \" exported --\")\n                i += 1\n\n            if dev_mode:\n                FreeCAD.Console.PrintMessage(\"\\nSaved\")\n            \n            self.infoMessages(str(quantity) + \" objects exported to file\",\"positive\")\n\n        App.ActiveDocument.recompute()\n        if dev_mode:\n            self.message(\"\\n********* END *********\")\n\n    def clear_console(self):\n        #clearing previous messages\n        mw=FreeCADGui.getMainWindow()\n        r=mw.findChild(QtGui.QTextEdit, \"Report view\")\n        r.clear()\n\n    def message(self,msg):\n        FreeCAD.Console.PrintMessage(\"BatchETM: \" + str(msg) + \"\\n\")\n\n    def message_warning(self,msg):\n        FreeCAD.Console.PrintWarning(\"BatchETM: \" + str(msg) + \"\\n\")\n\n    def message_error(self,msg):\n        FreeCAD.Console.PrintError(\"BatchETM: \" + str(msg) + \"\\n\")\n        \n    def infoMessages(self,msg,type):\n        if type == \"positive\":\n            self.infoLabel.setStyleSheet(\"color: rgb(19, 27, 2);background-color: rgba(183, 192, 165, 0.5);border-radius: 8px;\") # positive\n        elif type == \"negative\":\n            self.infoLabel.setStyleSheet(\"color: rgb(20, 0, 0);background-color: rgba(172, 40, 40, 0.5);border-radius: 8px;\") # negative\n        elif type == \"reset\":\n            self.infoLabel.setStyleSheet(\"color: black;background-color: rgba(0, 0, 0, 0);border-radius: 8px;\") # reset\n        else:\n            self.infoLabel.setStyleSheet(\"color: rgb(0, 0, 255);background-color: rgba(183, 192, 165, 0.5);border-radius: 8px;\")\n        self.infoLabel.setText(str(msg))\n\nBatchETM = BatchExportToMesh()\nBatchETM.show()\nBatchETM.destroyed.connect(lambda: FreeCADGui.getMainWindow().findChild(QtGui.QWidget, \"BatchETM\").deleteLater())\n",
    "url": "https://github.com/pgilfernandez/FreeCAD_Macro_Batch_Export_To_Mesh",
    "raw_code_url": "",
    "wiki": "https://wiki.freecad.org/Macro_Batch_Export_To_Mesh",
    "version": "2.16",
    "license": "",
    "date": "2024-10-11",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Pablo Gil Fern\u00e1ndez",
    "icon": "/usr/lib/freecad/Mod/Mesh/Resources/icons/MeshWorkbench.svg",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Compound Plus",
    "on_wiki": true,
    "on_git": false,
    "desc": "Draft command set in a small macro for the 2D wire example: work with the DXF files. The macro detected&#160;: Line, Arc, Circle, Ellipse, BSplineCurve and reproduce the DXF wire in a Draft object. The text is converted in ShapeString.<br /><br />Macro version: 00.05<br />Last modified: 2024-11-11<br />FreeCAD version: 0.21.2 and more<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/f/fd/Macro_Compound_Plus.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Draft command set in a small macro for the 2D wire example: work with the DXF files. The macro detected&#160;: Line, Arc, Circle, Ellipse, BSplineCurve and reproduce the DXF wire in a Draft object. The text is converted in ShapeString.",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2016 2017 2018 1019 2020 2024 <Mario52>                 *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#Macro_Compound_Plus 05/08/2016 /_00 24/01/2018 /.02 2018-01-24/.03 2020/05/12 15-08-2020/ 0.04 forcer\n#\n#OS: Windows 10 (10.0)\n#Word size of OS: 64-bit\n#Word size of FreeCAD: 64-bit\n#Version: 0.19.22209 (Git)\n#Build type: Release\n#Branch: master\n#Hash: 9c3f9b72a82249d5fcf1f543dd69a78740251b26\n#Python version: 3.6.8\n#Qt version: 5.12.1\n#Coin version: 4.0.0a\n#OCC version: 7.3.0\n#Locale: French/Mars (fr_MA)\n#\n#Icon.fromTheme by FreeCAD\n#\n__title__   = \"Macro_Compound_Plus\"\n__author__  = \"Mario52\"\n__url__     = \"https://wiki.freecadweb.org/Macro_Compound_Plus\"\n__version__ = \"0.05\"\n__date__    = \"2024/11/11\"    #YYYYMMDD\n__icon__    = \"https://wiki.freecadweb.org/images/f/fd/Macro_Compound_Plus.png\"\n__gistLoc__ = \"https://gist.github.com/mario52a/7be361a8c489deec918f664fdcfc4394\"\n#\n#try:\nimport PySide\nfrom PySide import (QtWidgets, QtCore, QtGui)\nfrom PySide.QtWidgets import (QWidget, QApplication, QSlider, QGraphicsView, QGraphicsScene, QVBoxLayout, QStyle)\nfrom PySide.QtGui import (QPainter, QColor, QIcon)\nfrom PySide.QtSvg import *\n#import PySide.QtXml\n#except Exception:\n#    import PySide2\n#    from PySide2 import (QtWidgets, QtCore, QtGui)\n#    from PySide2.QtWidgets import (QWidget, QApplication, QSlider, QGraphicsView, QGraphicsScene, QVBoxLayout, QStyle)\n#    from PySide2.QtGui import (QPainter, QColor, QIcon)\n#    from PySide2.QtSvg import *\n#    import PySide2.QtXml\n\nimport Draft, Part, PartGui, FreeCADGui, FreeCAD\nfrom FreeCAD import Base\nfrom FreeCAD import Vector\nimport math\nfrom math import sqrt, pi, sin, cos, asin, degrees, radians\n\nimport re\nimport operator\nfrom operator import itemgetter, attrgetter, methodcaller    # pour sort \nApp = FreeCAD\nGui = FreeCADGui\n\nimport os, time, sys\nimport platform\n\nglobal doc  ; doc = App.activeDocument()\nglobal ui   ; ui         = \"\"\n\ntry:\n    import webbrowser\nexcept Exception:\n    None\n\n#### Detect version macro begin ########################################### #22/03/2021\ntry:\n    import urllib\n    from urllib import request\nexcept Exception:\n    None\n#### Test FreeCAD.Version simple ############################################################################################################\n#if int(FreeCAD.Version()[1]) < 19:      # Version de FreeCAD\n#    rawAddress = \"https://gist.githubusercontent.com/mario52a/7be361a8c489deec918f664fdcfc4394/raw/11ae1a55229c84d9aab4e9a36099d90f52909958/Macro_Compound_Plus.FCMacro\"\n#    FreeCAD.Console.PrintError(\"This version \" + __title__ + \" \" + __version__ + \" rmu  work with the FreeCAD 0.19 or higher.\" + \"\\n\\n\")\n#    FreeCAD.Console.PrintError(\"SOME FUNCTIONS MAY NOT WORK PROPERLY \" + \"\\n\\n\")\n#    FreeCAD.Console.PrintError(\"For the precedent version (00.02) see the page \" + \"\\n\\n\")\n#    FreeCAD.Console.PrintError(rawAddress + \"\\n\\n\")\n#\n#    msg = (\"This version \" + __title__ + \" \" + __version__ + \" rmu  work only with the FreeCAD 0.19 or higher.\" + \"\\n\\n\"\n#           \"SOME FUNCTIONS MAY NOT WORK PROPERLY \" + \"\\n\\n\"\n#           \"For the precedent version click the button \" + \"\\n\\n\")\n#    diag = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Critical, __title__ + \" \" + __version__ , msg) #NoIcon, Information, Warning, Critical, Question\n#    diag.addButton(\" See the raw page Compound Plus version 00.02 \", QtWidgets.QMessageBox.AcceptRole) #0\n#    diag.addButton(\" Quit \", QtWidgets.QMessageBox.RejectRole)             #1\n#    diag.addButton(\" Upgrade FreeCAD \", QtWidgets.QMessageBox.ActionRole)  #2\n#    diag.setWindowModality(QtCore.Qt.ApplicationModal)\n#    button = diag.exec_()\n#    if button == QtWidgets.QMessageBox.AcceptRole:\n#        webbrowser.open(rawAddress)\n#    if button == 2: #ActionRole:\n#        webbrowser.open(\"https://github.com/FreeCAD/FreeCAD-Bundle/releases/tag/weekly-builds\")\n\n#### Test FreeCAD.Version simple ############################################################################################################\nglobal switchVersion; switchVersion = 0\ntry: \n    import draftmake    # only 0.19 for arc3points\n    from draftmake.make_arc_3points import make_arc_3points\nexcept Exception:\n    switchVersion = 1\n\nsetIconTTF = [\n\"16 16 6 1\",\n\" \tc None\",\n\".\tc #204A87\",\n\"+\tc None\",\n\"@\tc #729FCF\",\n\"#\tc #CC0000\",\n\"$\tc #EDD400\",\n\".+++++++++++@@@@\",\n\".++++++++@+@++@@\",\n\".++#####++++@@+@\",\n\".+++$#$$$++@+@+@\",\n\".++++#$+++++++@+\",\n\".++++#$#####++++\",\n\".++++#$+$#$$$+++\",\n\".++++#$++#$+++++\",\n\".@++++$++#$+###+\",\n\".@@++++++#$+#$$$\",\n\"..@@+++++#$+#$++\",\n\"...@@+++++$+###+\",\n\"....@@++++++#$$$\",\n\".....@@+++++#$++\",\n\"......@@+++++$++\",\n\"................\"]\n\nsetIconFON = [\n\"16 16 6 1\",\n\" \tc None\",\n\".\tc #204A87\",\n\"+\tc None\",\n\"@\tc #F57900\",\n\"#\tc #CC0000\",\n\"$\tc #EDD400\",\n\".+++++++++++@@@@\",\n\".++++++++@+@++@@\",\n\".++###++++++@@+@\",\n\".++#$$$++++@+@+@\",\n\".++#$+++++++++@+\",\n\".++###+###++++++\",\n\".++#$$$#$#$+++++\",\n\".++#$++#$#$+++++\",\n\".@++$++#$#$##+#+\",\n\".@@++++#$#$##$#$\",\n\"..@@+++###$#$##$\",\n\"...@@+++$$$#$##$\",\n\"....@@+++++#$+#$\",\n\".....@@++++#$+#$\",\n\"......@@++++$++$\",\n\"................\"]\n\nsetIconOTF = [\n\"16 16 6 1\",\n\" \tc None\",\n\".\tc #204A87\",\n\"+\tc None\",\n\"@\tc #4E9A06\",\n\"#\tc #CC0000\",\n\"$\tc #EDD400\",\n\".+++++++++++@@@@\",\n\".++++++++@+@++@@\",\n\".++###++++++@@+@\",\n\".++#$#$++++@+@+@\",\n\".++#$#$+++++++@+\",\n\".++#$#$###++++++\",\n\".++#$#$+#$$+++++\",\n\".++###$+#$++++++\",\n\".@++$$$+#$+###++\",\n\".@@+++++#$+#$$$+\",\n\"..@@++++#$+#$+++\",\n\"...@@++++$+###++\",\n\"....@@+++++#$$$+\",\n\".....@@++++#$+++\",\n\"......@@++++$+++\",\n\"................\"]\n\nsetIconPOL = [\n\"16 16 12 1\",\n\" \tc None\",\n\".\tc #204A87\",\n\"+\tc None\",\n\"@\tc #06989A\",\n\"#\tc #73D216\",\n\"$\tc #000000\",\n\"%\tc #75507B\",\n\"&\tc #729FCF\",\n\"*\tc #CC0000\",\n\"=\tc #F57900\",\n\"-\tc #EDD400\",\n\";\tc #4E9A06\",\n\".+++++++++++@#$%\",\n\".++++++++$+#++&$\",\n\".++***++++++=@+%\",\n\".++*-*-++++*+&+$\",\n\".++*-*-+++++++*+\",\n\".++***-***++++++\",\n\".++*---*-*-+++++\",\n\".++*-++*-*-+++++\",\n\".$++-++*-*-*++++\",\n\".*@++++*-*-*-+++\",\n\"..#*+++***-*-+++\",\n\"...;#+++---*-+++\",\n\"....%=+++++*-+++\",\n\".....;$++++****+\",\n\"......@%++++----\",\n\"................\"]\n\n#path#################################################################\nglobal path                                                          #\n#path  = FreeCAD.ConfigGet(\"AppHomePath\")                             # path FreeCAD installation\n#path  = FreeCAD.ConfigGet(\"UserAppData\")                             # path FreeCAD User data\n#path  = \"your path\"                                                  # your directory path\nparam = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\") # macro path\npath  = param.GetString(\"MacroPath\",\"\") + \"/\"                        # macro path\npath  = path.replace(\"\\\\\",\"/\")                                       # convert the \"\\\" to \"/\"\n#FreeCAD.Console.PrintMessage( \"Path for the icons : \" + path  + \"\\n\")# \n######################################################################\n\n#### matplotlib #################################################################\n#import glob\n#files_TTF = glob.glob(self.pathFont + \"/*.TTF\") \n\n##################################\nimport matplotlib\nimport matplotlib.font_manager\nimport matplotlib.font_manager as fontman\nimport matplotlib.font_manager as fontconfig\nfrom matplotlib.font_manager import FontProperties\n\n#from matplotlib.ft2font import FT2Font\n##################################\n\nglobal newPolicePath\nglobal PolicePath\nglobal nomPolice\n\nif platform.system()   == \"Windows\" :\n    PolicePath = \"C:/Windows/Fonts/ARIAL.TTF\"\nelif platform.system() == \"Linux\" :\n    PolicePath = \"/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-M.ttf\"\nelif platform.system() == \"Darwin\":\n    PolicePath = \"/Library/Fonts/Arial.ttf\"\nelse:\n    PolicePath = \"C:/Windows/Fonts/ARIAL.TTF\"\n\nnomPolice     = os.path.basename(PolicePath).split('.')[0]\nnewPolicePath = os.path.dirname(PolicePath).split('.')[0]\n\n#### matplotlib #################################################################\n#### Config Begin matplotlib font #######################\n                                                        # # https://en.wikipedia.org/wiki/Web_colors\nglobal setColorTTF       ; setColorTTF       = \"blue\"   # .TTF   color by \"extension name\" or hexa \"#0000FF\" \nglobal setColorFON       ; setColorFON       = \"orange\" # .FON   color by \"extension name\" or hexa \"#FFA500\"\nglobal setColorOTF       ; setColorOTF       = \"green\"  # .OTF   color by \"extension name\" or hexa \"#008000\"\nglobal setColorPOL       ; setColorPOL       = \"black\"  # .OTHER color by \"extension name\" or hexa \"#000000\"\n                                                      #####\nglobal switchModeTextList; switchModeTextList= 1        # 0 = mode text normal (et noir) coupe le switchFontComBox\n                                                        # 1 = permet le switchFontComBox 1 (default)\n                                                      #####\nglobal switchFontComBox  ; switchFontComBox  = 1        # 0 = (et switchModeTextList= 1) mode texte (en couleur) dans liste ComboBox plus rapide\n                                                        # 1 = (et switchModeTextList= 1) fontFamily dans liste ComboBox plus lent mais plus beau! (default)\n                                                      #####\nglobal setSystemFonts    ; setSystemFonts    = 1        # 0 = matplotlib.font_manager.findSystemFonts(\"C:/\", \"ttf\") \n                                                        #     fait toutes les fontes (dans tous les dossiers et sous dossiers du DD) time !!\n                                                        # 1 = fontman.findSystemFonts(self.pathFont)\n                                                        #     fait toutes les fontes du repertoire (et dans tous les sous dossiers) (default)\n                                                      #####\nglobal seTtextAlignement ; seTtextAlignement = 0        # 0 = AlignLeft (default)\n                                                        # 1 = AlignCenter\n                                                        # 2 = AlignRight\n                                                      #####\n#### Config End matplotlib font #########################\n\n#### matplotlib #################################################################\n\ndef createSpace(texte):    # detecte majuscule et ajoute un espace devant la lettre\n    # return createSpace(TexTe) = Tex Te , if createSpace(TEXTE) = TEXTE\n    if texte.isupper():\n        stringSpace = texte\n    else:\n        try:\n            stringSpace = texte[0]\n            for i in texte[1:]:\n                if re.search(r\"[A-Z]\", i): i = \" \" +  i\n                stringSpace += i\n        except Exception:\n            stringSpace = texte\n    return stringSpace\n\ndef family(chaine):\n    # return family(chaine)[1] = Family , family(chaine)[2] = typeCar (form [a, b, c ...]\n    famille = typeCar = \"\"\n    try:\n        if chaine.find('-') != -1:\n            famille = chaine[:chaine.find('-')]\n            typeCar = chaine[chaine.find('-')+1:]\n        else:\n            famille = chaine\n            typeCar = \"\"\n    except Exception:\n        famille = chaine\n        typeCar = \"\"\n    typeCar = str(createSpace(typeCar)).split()\n    return [createSpace(famille), typeCar]\n\nclass MyLabelPatience():        # fenetre image d'attente de chargement\n    global path\n    label = QtWidgets.QLabel()\n    label.setText(\"<img src=\" + path + \"Macro_Compound_Plus.png><b><center>Wait please</center> \\n\\n<center>i search the fonts !\\n\\n</right></b>\")\n    ecran = FreeCADGui.getMainWindow().frameGeometry()\n    xF = 250; yF = 120\n    xW = (ecran.width()/2) - (xF/2)\n    yW = (ecran.height()/2)- (yF/2)\n    label.setGeometry(xW, yW, xF, yF)\n    label.setStyleSheet(\"QLabel {background-color : #F0C300;font: 12pt; }\");\n    label.setWindowFlags(QtCore.Qt.WindowFlags(QtCore.Qt.FramelessWindowHint))        # pas de bords\n    label.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)         # PySide cette fonction met la fenetre en avant\n#### matplotlib #################################################################\n\ndef unsignedDecode(value, mode = 0): # mode 0 = entier, mode 1 = float (a partir de ex: 4283773951)\n                                     # 4283773951 = [255 85 51 255] = [red, green, blue, transparent]\n    value = hex(value)\n#    print(value)\n    a1 = value[0:2]\n    a2 = \"000000000\" + value[2:]\n    a2 = a2[len(a2)-8:]\n    value = a1 + a2\n    if mode == 0:   # for button\n        red         = int(value[2:4 ],16)\n        green       = int(value[4:6 ],16)\n        blue        = int(value[6:8 ],16)\n        transparent = int(value[8:10],16)\n    else:           # for FreeCAD object\n        red         = float(int(value[2:4 ],16) / 255.0)\n        green       = float(int(value[4:6 ],16) / 255.0)\n        blue        = float(int(value[6:8 ],16) / 255.0)\n        transparent = float(int(value[8:10],16) / 255.0)\n    return [red, green, blue, transparent]\n\ndef unsignedEncode(red = 0, green = 0, blue = 0, transparent = 255): # convert red, green, blue, transparence to unique number\n                                                                     #(255 *256*256*256 ) + (85 *256*256) + (51 *256) +(255) = 4283773951\n    value = (red *256*256*256 ) + (green *256*256) + (blue *256) + (transparent)\n    return value\n\n#write parameter\n#FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Mod/FCMmacro/FCTexture\").SetString(\"Path\",pathFile)\n#read parameter\n#pathFile = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Mod/FCMmacro/FCTexture\").GetString(\"Path\")\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\nclass Ui_Compound(object):\n\n    def __init__(self):\n        global path\n        global nomPolice\n\n        self.path          = path\n        self.nameL         = []\n        self.comP          = []\n        del        self.nameL[:]\n        del         self.comP[:]\n\n        self.lineWidth     = 0.0\n        self.TextLabel     = \"\"\n        self.TextLabelText = \"\"\n        self.TextPosition  = \"\"\n        self.TextFontSize  = 8.0\n        self.TextTextColor = \"\"\n        self.fonte         = \"\"\n        self.fontSizeManual= False\n        self.lineSizeManual= False\n\n        ####font textEdit\n        self.nomPolice     = \"Arial\"\n        self.FontTextSize  = 20\n        self.fonteComp     = \"\"\n        self.font          = QtGui.QFont()\n        ####font textEdit\n        self.FontSize      = 0.0\n\n        # for button\n        self.red     = 255   #204.0\n        self.green   = 0     #204.0\n        self.blue    = 0     #204.0\n        self.alpha   = 255   #255 = visibility max (opacity)\n\n        # for object FC\n        self.redFL   = 1.0\n        self.greenFL = 0.0\n        self.blueFL  = 0.0\n        self.alphaFL = 1.0   # 1.0 = visibility max (opacity)\n\n        self.tableau       = [] #Index (), [chemin plus nom fichier (nomPathPolice), nom sans extension (nomSimple), nomSimpleExt (nomSimple + Ext)]\n        self.index         = 0  #Index ()\n\n    #### font ######################\n    def searchFont(self,pathSearch):\n        global setSystemFonts\n        global seTtextAlignement\n        global switchFontComBox\n        global switchModeTextList\n\n        MyLabelPatience.label.show()\n        FreeCADGui.updateGui()                                 # rafraichi l'ecran\n\n        files_All_Fonts = \"\"\n        ##https://matplotlib.org/_modules/matplotlib/font_manager.html\n        if setSystemFonts == 0:\n            files_All_Fonts = matplotlib.font_manager.findSystemFonts(pathSearch, \"ttf\")  # fait toutes les fontes ? ()\n        else:\n            files_All_Fonts = fontman.findSystemFonts(pathSearch)                         # fait toutes les fontes (et dans tous les sous dossiers)\n\n        if len(files_All_Fonts) > 0:           \n            self.tableau = []\n            self.index = 0\n\n            for fonte in files_All_Fonts:\n                ####\n                nomPathPolice = nomFichier = nomSimpleExt = nomSimple = nomExtension = nameName = \"\"\n\n                nomPathPolice = fonte.replace(\"\\\\\",\"/\")     # convert the \"\\\" to \"/\"\n                nomFichier    = nomPathPolice.split(\"/\")    # complet split\n                nomSimpleExt  = nomFichier[-1]              # nom avec extension\n                nomSimple     = nomFichier[-1][:-4]         # nom sans extension\n                nomExtension  = nomSimpleExt[nomSimpleExt.rfind('.')+1:].upper() # extension\n                ####\n                try:\n#                    nameFamily    = matplotlib.font_manager.FontProperties(fname=fonte).get_family()            ##['sans-serif']\n#                    nameStyle     = matplotlib.font_manager.FontProperties(fname=fonte).get_style()              #normal\n#                    nameVariant   = matplotlib.font_manager.FontProperties(fname=fonte).get_variant()            #normal\n#                    nameWeight    = matplotlib.font_manager.FontProperties(fname=fonte).get_weight()             #normal\n#                    nameStretch   = matplotlib.font_manager.FontProperties(fname=fonte).get_stretch()            #normal\n#                    nameFileComp  = matplotlib.font_manager.FontProperties(fname=fonte).get_file()              ##c:\\windows\\fonts\\NotoNaskhArabicUI-Regular.ttf\n#                    nameSize      = matplotlib.font_manager.FontProperties(fname=fonte).get_size()               #10.0\n                    nameName      = matplotlib.font_manager.FontProperties(fname=fonte).get_name()              ##Noto Naskh Arabic UI\n#                    nameSizePoint = matplotlib.font_manager.FontProperties(fname=fonte).get_size_in_points()     #10.0\n#                    nameSlant     = matplotlib.font_manager.FontProperties(fname=fonte).get_slant()              #normal\n#                    namePattern   = matplotlib.font_manager.FontProperties(fname=fonte).get_fontconfig_pattern() #:family=sans-serif:style=normal:variant=normal:weight=normal:stretch=normal:file=c:\\windows\\fonts\\NotoNaskhArabicUI-Regular.ttf:size=10.0\n                except Exception:\n                    nameFamily = nameStyle = nameVariant = nameWeight = nameStretch = nameFileComp = nameSize = nameName = nameSizePoint = nameSlant = namePattern = \"\"\n                ####\n                if nameName == \"\" :\n                    nameName = nomSimple\n                self.tableau.append([0, nomPathPolice, nomSimple, nomSimpleExt.upper(), nomExtension.upper(), nameName])\n                \n            self.tableau = sorted(self.tableau, key=itemgetter(3))          # sorted by nomSimple.upper()\n\n            try:\n                for line in range(len(self.tableau)):                       # enleve les doubles (bon)\n                    if self.tableau[line][2] == self.tableau[line + 1][2]:  # enleve les doubles (bon)\n                        del(self.tableau[line + 1])                         # enleve les doubles (bon)\n            except Exception:\n                None\n\n            self.comboBoxPy.clear()\n            for line in range(len(self.tableau)): \n                try:\n                    self.tableau[line][0] = line                 # ajoute le numero de ligne\n                    if self.tableau[line][2].upper() == \"ARIAL\": # detecte la fonte de base\n                        self.index = line\n    \n                    ####Section common color and font begin ######################\n                    model = self.comboBoxPy.model()\n\n                    if switchModeTextList == 1:\n                        if self.tableau[line][4] == \"TTF\":\n                            item = QtGui.QStandardItem(QtGui.QPixmap(setIconTTF), str(line))\n                            item.setForeground(QtGui.QColor(setColorTTF))\n                        elif self.tableau[line][4] == \"FON\":\n                            item = QtGui.QStandardItem(QtGui.QPixmap(setIconFON), str(line))\n                            item.setForeground(QtGui.QColor(setColorFON))\n                        elif self.tableau[line][4] == \"OTF\":\n                            item = QtGui.QStandardItem(QtGui.QPixmap(setIconOTF), str(line))\n                            item.setForeground(QtGui.QColor(setColorOTF))\n                        else:\n                            item = QtGui.QStandardItem(QtGui.QPixmap(setIconPOL), str(line))\n                            item.setForeground(QtGui.QColor(setColorPOL))\n\n                        if   seTtextAlignement == 0:\n                            item.setTextAlignment(QtCore.Qt.AlignLeft)\n                        elif seTtextAlignement == 1:\n                            item.setTextAlignment(QtCore.Qt.AlignCenter)\n                        elif seTtextAlignement == 2:\n                            item.setTextAlignment(QtCore.Qt.AlignRight)\n                        else:\n                            self.comboBoxPy.addItem(self.tableau[line][2])    \n                        model.appendRow(item)\n                    else:\n                        self.comboBoxPy.addItem(\"\")\n                    self.comboBoxPy.setItemText(line, self.tableau[line][2])\n                    ####Section item color and font end ##########################\n    \n                    ####Section setfont Family switchFontComBox begin#############\n                    if (switchFontComBox == 1) and (switchModeTextList == 1):\n                        typeCar = font = \"\"\n                        font = QtGui.QFont()\n                        #font = item.font()\n        \n                        typeCar   = family(self.tableau[line][2])[1]\n                        font.setBold(False)\n                        font.setItalic(False)\n        \n                        if len(typeCar) > 0:\n                            for option in typeCar:\n                                if option == \"Bold\":\n                                    font.setBold(True)\n                                if (option == \"Italic\") or (option == \"It\") or (option == \"Slanted\"):\n                                    font.setItalic(True)\n                                if option == \"Oblique\":\n                                    font.setItalic(True)\n                        #'Bold''Regular''Slanted''Italic''Medium''Extra''Light''Condensed''Black''It''Semibold'\n                        \n                        font.setFamily(self.tableau[line][5])\n                        font.setPixelSize(15)\n                        if switchModeTextList == 1:\n                            item.setFont(font)\n                        else:\n                            self.comboBoxPy.addItem(\"\")\n                    ####Section setfont Family switchFontComBox end###############\n\n                except Exception:\n                    FreeCAD.Console.PrintMessage(\"searchFont()\" + \"\\n\")\n                    None\n            self.lineEdit_NameFile.setText(\"(\" + str(self.index + 1) + \"/\" + str(len(self.tableau)) + \") \" + self.tableau[self.index][1])\n            #print(len(self.tableau))\n            #for i in self.tableau:\n            #    print(i)\n            self.comboBoxPy.setCurrentIndex(self.index)\n            self.fonteComp = self.tableau[self.index][1]\n            MyLabelPatience.label.close()\n\n    #### font ######################\n\n    def setupUi(self, MainWindow):\n        global PolicePath\n        global setSystemFonts\n        global setColorTTF\n        global setColorFON\n        global setColorOTF\n        global setColorPOL\n        global seTtextAlignement\n        global switchFontComBox\n        global switchModeTextList\n        global ui\n\n        self.window = MainWindow\n\n        Compound.setObjectName(\"Compound\")\n        Compound.resize(250, 440)\n#        MainWindow.setMinimumSize(QtCore.QSize(250, 440))\n#        MainWindow.setMaximumSize(QtCore.QSize(250, 440))\n\n        self.centralwidget = QtWidgets.QWidget(Compound)\n        self.centralwidget.setObjectName(\"centralwidget\")\n\n        self.groupBox = QtWidgets.QGroupBox()\n\n        self.groupBox_Choice = QtWidgets.QGroupBox()\n\n        self.PB_01_Compound_01 = QtWidgets.QPushButton()\n        self.PB_01_Compound_01.setIcon(QtGui.QIcon.fromTheme(\"Part\",QtGui.QIcon(\":/icons/Part_Compound.svg\")))\n        self.PB_01_Compound_01.clicked.connect(self.on_PB_01_Compound_01)                    # \n\n        self.label_02_Type_1 = QtWidgets.QLabel()\n\n        self.PB_02_Compound_02 = QtWidgets.QPushButton()\n        self.PB_02_Compound_02.setIcon(QtGui.QIcon.fromTheme(\"Part\",QtGui.QIcon(\":/icons/Part_Compound.svg\")))\n        self.PB_02_Compound_02.clicked.connect(self.on_PB_02_Compound_02)                    # \n\n        self.label_03_Type_2 = QtWidgets.QLabel()\n        ####\n\n        self.groupBox_00 = QtWidgets.QGroupBox()\n#        self.groupBox_00.setAlignment(QtWidgets.AlignLeft)                    # AlignLeft     AlignCenter      AlignRight\n        self.groupBox_00.setCheckable(True)\n        self.groupBox_00.setChecked(False)\n        self.groupBox_00.clicked.connect(self.on_groupBox_00)                  # \n\n        self.PB_03_Color = QtWidgets.QPushButton()\n        self.PB_03_Color.setIcon(QtGui.QIcon.fromTheme(\"Part\",QtGui.QIcon(\":/icons/colors.svg\")))\n        self.PB_03_Color.clicked.connect(self.on_PB_03_Color)                                # \n        self.PB_03_Color.setStyleSheet(\"background-color: rgb(\"+str(self.red)+\",\"+str(self.green)+\",\"+str(self.blue)+\")\")\n        ####\n\n        self.groupBox_Tools = QtWidgets.QGroupBox()\n\n        self.lineEdit_NameFile = QtWidgets.QLineEdit()\n        self.comboBoxPy = QtWidgets.QComboBox()\n        ####\n        #self.pathFont = PolicePath[:-10]\n        self.pathFont = PolicePath[:len(PolicePath)-(PolicePath[::-1].index(\"/\"))-1]\n        ####\n\n        self.PB_04_Convert_Text = QtWidgets.QPushButton()\n        self.PB_04_Convert_Text.setIcon(QtGui.QIcon.fromTheme(\"Part\",QtGui.QIcon(\":/icons/Draft_Text.svg\")))\n        self.PB_04_Convert_Text.clicked.connect(self.on_PB_04_Convert_Text)                            # \"\"\n\n        ui.searchFont(self.pathFont)\n        QtCore.QObject.connect(self.comboBoxPy, QtCore.SIGNAL(\"currentIndexChanged(int)\"), self.on_fontComboBoxPython)\n\n        self.DS_02_Size_Font = QtWidgets.QDoubleSpinBox()\n        self.DS_02_Size_Font.setValue(0.0)\n        self.DS_02_Size_Font.setSuffix(\" Auto\")\n        self.DS_02_Size_Font.valueChanged.connect(self.on_DS_02_Size_Font_valueChanged)             # \n\n        self.line = QtWidgets.QFrame()\n        self.line.setFrameShape(QtWidgets.QFrame.HLine)\n        self.line.setFrameShadow(QtWidgets.QFrame.Sunken)\n\n        self.PB_04c_Convert_Edge = QtWidgets.QPushButton()\n        self.PB_04c_Convert_Edge.setIcon(QtGui.QIcon.fromTheme(\"Part\",QtGui.QIcon(\":/icons/Draft_Line.svg\")))\n        self.PB_04c_Convert_Edge.clicked.connect(self.on_PB_04c_Convert_Edge)                 # \"\"\n\n        self.DS_01_Width_Line = QtWidgets.QDoubleSpinBox()\n        self.DS_01_Width_Line.setValue(0.0) #self.lineWidth\n        self.DS_01_Width_Line.setSuffix(\" Auto\")\n        self.DS_01_Width_Line.valueChanged.connect(self.on_DS_01_Width_Line_valueChanged)             # \n\n        self.CB_BezierCurve = QtWidgets.QCheckBox()\n        self.CB_BezierCurve.setIcon(QtGui.QIcon.fromTheme(\"Part\",QtGui.QIcon(\":/icons/Draft_BezCurve.svg\")))\n        self.CB_BezierCurve.clicked.connect(self.on_CB_BezierCurve_clicked)\n\n        self.RB_01_FlatLines = QtWidgets.QRadioButton()\n        self.RB_01_FlatLines.setIcon(QtGui.QIcon.fromTheme(\"Vieuw\",QtGui.QIcon(\":/icons/DrawStyleFlatLines.svg\")))\n        self.RB_01_FlatLines.setChecked(True)\n        self.RB_02_Wireframe = QtWidgets.QRadioButton()\n        self.RB_02_Wireframe.setIcon(QtGui.QIcon.fromTheme(\"Vieuw\",QtGui.QIcon(\":/icons/DrawStyleWireFrame.svg\")))\n        self.RB_03_Points = QtWidgets.QRadioButton()\n        self.RB_03_Points.setIcon(QtGui.QIcon.fromTheme(\"Vieuw\",QtGui.QIcon(\":/icons/DrawStylePoints.svg\")))\n        ####\n\n        self.groupBox_Force_LAC = QtWidgets.QGroupBox()\n\n        self.PB_Force_LAC = QtWidgets.QPushButton()\n        self.PB_Force_LAC.setIcon(QtGui.QIcon.fromTheme(\"Vieuw\",QtGui.QIcon(\":/icons/Draft_Line.svg\")))\n        self.PB_Force_LAC.clicked.connect(self.on_PB_Force_LAC)                 # \"\"\n\n        self.RB_Force_01_Line = QtWidgets.QRadioButton()\n        self.RB_Force_01_Line.setIcon(QtGui.QIcon.fromTheme(\"Vieuw\",QtGui.QIcon(\":/icons/Draft_Line.svg\")))\n        self.RB_Force_01_Line.setChecked(True)\n        self.RB_Force_01_Line.clicked.connect(self.on_RB_Force_clicked)\n        self.RB_Force_02_Arc = QtWidgets.QRadioButton()\n        self.RB_Force_02_Arc.setIcon(QtGui.QIcon.fromTheme(\"Vieuw\",QtGui.QIcon(\":/icons/Draft_Arc.svg\")))\n        self.RB_Force_02_Arc.clicked.connect(self.on_RB_Force_clicked)\n        if switchVersion == 1:\n            self.RB_Force_02_Arc.setEnabled(False)\n        self.RB_Force_03_Circle = QtWidgets.QRadioButton()\n        self.RB_Force_03_Circle.setIcon(QtGui.QIcon.fromTheme(\"Vieuw\",QtGui.QIcon(\":/icons/Draft_Circle.svg\")))\n        self.RB_Force_03_Circle.clicked.connect(self.on_RB_Force_clicked)\n       ####\n\n        self.groupBox_01 = QtWidgets.QGroupBox()\n\n        self.RB_01_Default = QtWidgets.QRadioButton()\n        self.RB_01_Default.setChecked(True)\n        self.RB_02_Hidden = QtWidgets.QRadioButton()\n        self.RB_03_Delete = QtWidgets.QRadioButton()\n        self.RB_03_Delete.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogCancelButton))) #\n#        self.RB_03_Delete.setChecked(True)\n\n        self.PB_09_Upgrade = QtWidgets.QPushButton()\n        self.PB_09_Upgrade.setIcon(QtGui.QIcon.fromTheme(\"Part\",QtGui.QIcon(\":/icons/Draft_Upgrade.svg\")))\n        self.PB_09_Upgrade.clicked.connect(self.on_PB_09_Upgrade)                       # \n\n        self.PB_06_Downgrade = QtWidgets.QPushButton()\n        self.PB_06_Downgrade.setIcon(QtGui.QIcon.fromTheme(\"Part\",QtGui.QIcon(\":/icons/Draft_Downgrade.svg\")))\n        self.PB_06_Downgrade.clicked.connect(self.on_PB_06_Downgrade)                       # \n\n        self.groupBox_Command = QtWidgets.QGroupBox()\n\n        self.progressBar = QtWidgets.QProgressBar()\n        self.progressBar.setValue(0)\n        self.progressBar.setAlignment(QtCore.Qt.AlignCenter)\n\n        self.PB_05_Reset = QtWidgets.QPushButton()\n        self.PB_05_Reset.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogResetButton))) #\n        self.PB_05_Reset.clicked.connect(self.on_PB_05_Reset)                               # \n\n        self.PB_07_Quit = QtWidgets.QPushButton()\n        self.PB_07_Quit.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogCloseButton))) #\n        self.PB_07_Quit.clicked.connect(self.on_PB_07_Quit)                                 # \n\n        self.PB_08_Help = QtWidgets.QPushButton()\n        self.PB_08_Help.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_MessageBoxQuestion))) #\n        self.PB_08_Help.clicked.connect(self.on_PB_Help_clicked)                                 # \n\n        #### layout ###################################################\n        self.gridLayoutWidget = QtWidgets.QWidget(self.centralwidget)\n        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)\n        self.gridLayout.setContentsMargins(10, 10, 10, 10)\n\n        self.gridLayout_3 = QtWidgets.QGridLayout(self.groupBox)\n        self.gridLayout_3.setContentsMargins(10, 10, 10, 10)\n\n        self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox_Choice)\n        self.gridLayout_2.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_2.addWidget(self.PB_01_Compound_01, 0, 0, 1, 1)\n        self.gridLayout_2.addWidget(self.label_02_Type_1, 0, 1, 1, 1)\n        self.gridLayout_2.addWidget(self.PB_02_Compound_02, 1, 0, 1, 1)\n        self.gridLayout_2.addWidget(self.label_03_Type_2, 1, 1, 1, 1)\n        self.gridLayout_3.addWidget(self.groupBox_Choice, 0, 0, 1, 1)\n\n        self.gridLayout_4 = QtWidgets.QGridLayout(self.groupBox_00)\n        self.gridLayout_4.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_4.addWidget(self.PB_03_Color, 0, 0, 1, 1)\n        self.gridLayout_3.addWidget(self.groupBox_00, 1, 0, 1, 1)\n\n        self.gridLayout_5 = QtWidgets.QGridLayout(self.groupBox_Tools)\n        self.gridLayout_5.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_5.addWidget(self.lineEdit_NameFile, 0, 0, 1, 3)\n        self.gridLayout_5.addWidget(self.comboBoxPy, 1, 0, 1, 3)\n        self.gridLayout_5.addWidget(self.PB_04_Convert_Text, 2, 0, 1, 2)\n        self.gridLayout_5.addWidget(self.DS_02_Size_Font, 2, 2, 1, 1)\n        self.gridLayout_5.addWidget(self.line, 3, 0, 1, 3)\n        self.gridLayout_5.addWidget(self.PB_04c_Convert_Edge, 4, 0, 1, 2)\n        self.gridLayout_5.addWidget(self.DS_01_Width_Line, 4, 2, 1, 1)\n        self.gridLayout_5.addWidget(self.CB_BezierCurve, 5, 0, 1, 1)\n        self.gridLayout_5.addWidget(self.RB_01_FlatLines, 6, 0, 1, 1)\n        self.gridLayout_5.addWidget(self.RB_02_Wireframe, 6, 1, 1, 1)\n        self.gridLayout_5.addWidget(self.RB_03_Points, 6, 2, 1, 1)\n        self.gridLayout_5.addWidget(self.PB_09_Upgrade, 7, 0, 1, 1)\n        self.gridLayout_5.addWidget(self.PB_06_Downgrade, 7, 1, 1, 1)\n        self.gridLayout_3.addWidget(self.groupBox_Tools, 2, 0, 1, 1)\n\n        self.gridLayout_7 = QtWidgets.QGridLayout(self.groupBox_01)\n        self.gridLayout_7.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_7.addWidget(self.RB_01_Default, 0, 0, 1, 1)\n        self.gridLayout_7.addWidget(self.RB_02_Hidden, 0, 1, 1, 1)\n        self.gridLayout_7.addWidget(self.RB_03_Delete, 1, 0, 1, 1)\n        self.gridLayout_3.addWidget(self.groupBox_01, 3, 0, 1, 1)\n\n        self.gridLayout_8 = QtWidgets.QGridLayout(self.groupBox_Force_LAC)\n        self.gridLayout_8.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_8.addWidget(self.PB_Force_LAC, 0, 0, 1, 3)\n        self.gridLayout_8.addWidget(self.RB_Force_01_Line, 1, 0, 1, 1)\n        self.gridLayout_8.addWidget(self.RB_Force_02_Arc, 1, 1, 1, 1)\n        self.gridLayout_8.addWidget(self.RB_Force_03_Circle, 1, 2, 1, 1)\n        self.gridLayout_3.addWidget(self.groupBox_Force_LAC, 4, 0, 1, 1)\n\n        self.gridLayout_6 = QtWidgets.QGridLayout(self.groupBox_Command)\n        self.gridLayout_6.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_6.addWidget(self.progressBar, 0, 0, 1, 3)\n        self.gridLayout_6.addWidget(self.PB_05_Reset, 1, 0, 1, 1)\n        self.gridLayout_6.addWidget(self.PB_07_Quit, 1, 1, 1, 1)\n        self.gridLayout_6.addWidget(self.PB_08_Help, 1, 2, 1, 1)\n        self.gridLayout_3.addWidget(self.groupBox_Command, 5, 0, 1, 1)\n        self.gridLayout.addWidget(self.groupBox, 0, 0, 1, 1)\n        #### layout ###################################################\n\n        Compound.setCentralWidget(self.centralwidget)\n\n        self.retranslateUi(Compound)\n        QtCore.QMetaObject.connectSlotsByName(Compound)\n\n    def retranslateUi(self, Compound):\n        Compound.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)                    # PySide cette fonction met la fenetre en avant\n        Compound.setWindowIcon(QtGui.QIcon(self.path + 'Macro_Compound_Plus.png'))         # change l'icone de la fenetre principale\n        Compound.setWindowTitle(\"Compound +\")\n\n        self.groupBox.setTitle(\"Version : \" + __date__ + \" : \" + __version__)\n\n        self.groupBox_Choice.setTitle(\"Choice\")\n        self.PB_01_Compound_01.setText(\"Compound I\")\n        self.PB_01_Compound_01.setToolTip(\"Make a compound Block unique\")\n        self.PB_02_Compound_02.setText(\"Compound II\")\n        self.PB_02_Compound_02.setToolTip(\"Make a compound same Part, Menu > Part > Make compound\")\n        self.label_02_Type_1.setText(\"Type I [ 1 + 1 = 1 ]\")\n        self.label_03_Type_2.setText(\"Type II [ 1 + 1 = A (1 + 1) ]\")\n\n        self.groupBox_00.setTitle(\"Option color\")\n        self.groupBox_00.setToolTip(\"If this box is unchecked the colors attributes and width line\\n\"\n                                    \"of the original line(s) are not modified\\n\"\n                                    \"This chekBox work with all objects\\n\")\n        self.PB_03_Color.setText(\"Color\")\n        self.PB_03_Color.setToolTip(\"Change the color of object(s) selected(s) value by defaut rvb 255,0,0\")\n\n        self.groupBox_Tools.setTitle(\"Tools\")\n\n        self.lineEdit_NameFile.setToolTip(\"(Number index / Number Fonts) Complete path and name of Font file\")\n\n        self.comboBoxPy.setToolTip(\"Choice your Font\" + \"\\n\" +\n                                   \"\\n\" +\n                                   \"You must modify the configuration of display\" + \"\\n\" +\n                                   \"See in the beginning of the macro section (line 120):\" + \"\\n\" +\n                                   \"####\" + \"\\n\" +\n                                   \"Config Begin matplotlib font\" + \"\\n\" \n                                   \"switchModeTextList= 1\\t# 0 = mode text normal (the switchFontComBox is enabled)\" + \"\\n\"\n                                   \"\\t\\t\\t# 1 = switchFontComBox authorized (default)\" + \"\\n\"\n                                   \"\\t\\t\\t#####\" + \"\\n\"\n                                   \"switchFontComBox  = 1\\t# 0 = mode text in color .. faster\" + \"\\n\"\n                                   \"\\t\\t\\t# 1 = fontFamily listed ComboBox slower but beautiful (default)\" + \"\\n\"\n                                   \"\\t\\t\\t#####\" + \"\\n\"\n                                   \"setSystemFonts    = 1\\t# 0 = matplotlib.font_manager.findSystemFonts\" + \"\\n\"\n                                   \"\\t\\t\\t#   all fonts in System font\" + \"\\n\"\n                                   \"\\t\\t\\t# 1 = fontman.findSystemFonts(self.pathFont) (default)\" + \"\\n\"\n                                   \"\\t\\t\\t# all fonts in all directory and sub directory\" + \"\\n\"\n                                   \"\\t\\t\\t#####\" + \"\\n\"\n                                   \"seTtextAlignement = 0\\t# 0 = AlignLeft (default)\" + \"\\n\"\n                                   \"\\t\\t\\t# 1 = AlignCenter\" + \"\\n\"\n                                   \"\\t\\t\\t# 2 = AlignRight\" + \"\\n\"\n                                   \"\\t\\t\\t#####\" + \"\\n\"\n                                   \"Config End matplotlib font\" + \"\\n\"\n                                   \"####\" + \"\\n\" +\n                                   \"Read the info\")\n        self.PB_04_Convert_Text.setText(\"Convert Text (A)\")\n        self.PB_04_Convert_Text.setToolTip(\"Convert the selected text in ShapeString\\n\"\n                                           \"By default Convert (A)utomatic use the font preselected and the size of original text\\n\"\n                                           \"If the values or font is modified the button change of Convert (M)anual\\n\"\n                                           \"The label of the texte are modified to SString_original text (max 30 characters)\")\n        self.DS_02_Size_Font.setToolTip(\"Size of the font of the ShapeString\")\n        self.PB_04c_Convert_Edge.setText(\"Convert Wire (A)\")\n        self.PB_04c_Convert_Edge.setToolTip(\"Convert the wire to object Draft\" + \"\\n\"\n                                            \"Select the wire(s) in the 3D view\" + \"\\n\\n\"\n                                            \"Are detected : Line, Circle, Arc, Ellipse, BSplineCurve\" + \"\\n\"\n                                            \"BezierCurve, BezierCurve Cubic (if checked)\" + \"\\n\\n\"\n                                            \"If the Surface or Point or other wire unknown are detected,\" + \"\\n\"\n                                            \"the selection Object is duplicated\" + \"\\n\"\n                                            \"If the values is modified the button change of Convert (M)anual\\n\")\n        self.DS_01_Width_Line.setToolTip(\"Give a new width for the line(s) selected(s)\")\n        self.CB_BezierCurve.setText(\"BezierCurve\")\n        self.CB_BezierCurve.setToolTip(\"If checked the BezierCurve is Cubic\")\n\n        self.RB_01_FlatLines.setText(\"FlatLines\")\n        self.RB_01_FlatLines.setToolTip(\"FlatLines\")\n        self.RB_02_Wireframe.setText(\"Wireframe\")\n        self.RB_02_Wireframe.setToolTip(\"Wireframe\")\n        self.RB_03_Points.setText(\"Points\")\n        self.RB_03_Points.setToolTip(\"Points\")\n\n        self.PB_09_Upgrade.setText(\"UpGrade\")\n        self.PB_09_Upgrade.setToolTip(\"Upgrade the selected object Same Draft > Upgrade\")\n        self.PB_06_Downgrade.setText(\"DownGrade\")\n        self.PB_06_Downgrade.setToolTip(\"Downgrade the selected object Same Draft > Downgrade\")\n\n        self.groupBox_01.setTitle(\"For Compound I and Convert\")\n        self.RB_01_Default.setText(\"None\")\n        self.RB_01_Default.setToolTip(\"The object stay as is\\n\"\n                                      \"For Compound I and Convert text to String\")\n        self.RB_02_Hidden.setText(\"Hidden original object(s) \")\n        self.RB_02_Hidden.setToolTip(\"The original object are hidden after transform\\n\"\n                                     \"For Compound I and Convert text to String\")\n        self.RB_03_Delete.setText(\"Delete original object(s)\")\n        self.RB_03_Delete.setToolTip(\"The original object are deleted after transform\\n\"\n                                     \"For Compound I and Convert text to String\")\n\n        self.groupBox_Force_LAC.setTitle(\"Force on a form : Line\")\n        self.groupBox_Force_LAC.setToolTip(\"This section lets you choose the shape.\\n\"\n                                           \"Force the creation of the object, Line, Arc or Circle\\n\"\n                                           \"(in the case of non-satisfaction of creation in the Tools section)\\n\" \n                                           \"No verification is made on the selection.\\n\"\n                                           \"You have to choose the shape that will be created,\\n\"\n                                           \"only one verification in the possibility of creation of the object is made,\\n\"\n                                           \"according to the detected coordinates\")\n        self.PB_Force_LAC.setText(\"Force on : Line\")\n        self.RB_Force_01_Line.setText(\"Line\")\n        self.RB_Force_01_Line.setToolTip(\"Force on Line if possible\")\n        self.RB_Force_02_Arc.setText(\"Arc\")\n        self.RB_Force_02_Arc.setToolTip(\"Force on Arc if possible\")\n        self.RB_Force_03_Circle.setText(\"Circle\")\n        self.RB_Force_03_Circle.setToolTip(\"Force on Circle if possible\")\n\n        self.groupBox_Command.setTitle(\"Command\")\n        self.PB_05_Reset.setText(\"Reset\")\n        self.PB_05_Reset.setToolTip(\"Reset the values\")\n        self.PB_07_Quit.setText(\"Quit\")\n        self.PB_07_Quit.setToolTip(\"Quit Compound +\")\n        self.PB_08_Help.setText(\"Help\")\n        self.PB_08_Help.setToolTip(\"Quit Compound +\")\n\n    def on_fontComboBoxPython(self,indeX):                                          # 0: for fontComboBoxPython\n        global PolicePath\n\n        self.index = indeX\n        self.lineEdit_NameFile.setText(\"(\" + str(self.index + 1) + \"/\" + str(len(self.tableau)) + \") \" + self.tableau[self.index][1])\n        PolicePath = self.tableau[self.index][1]\n\n        famille = typeCar = self.font = \"\"\n        self.font = QtGui.QFont()\n        typeCar   = family(self.tableau[self.index][2])[1]\n        self.font.setBold(False)\n        self.font.setItalic(False)\n\n        if len(typeCar) > 0:\n            for option in typeCar:\n                if option == \"Bold\":\n                    self.font.setBold(True)\n                if (option == \"Italic\") or (option == \"It\") or (option == \"Slanted\"):\n                    self.font.setItalic(True)\n                if option == \"Oblique\":\n                    self.font.setItalic(True)\n        #'Bold''Regular''Slanted''Italic''Medium''Extra''Light''Condensed''Black''It''Semibold'#+\n        \n        self.font.setFamily(self.tableau[self.index][5])\n        self.font.setPointSize(self.FontTextSize)\n        ####\n        self.fonteComp = self.tableau[self.index][1]\n#        FreeCAD.Console.PrintMessage(str(self.index) + \" , \" + self.tableau[self.index][1] + \" , \" + self.tableau[self.index][2] + \" , ' \" + famille + \"' , ' \" + typeCar + \" ' \\n\")\n\n    def on_PB_newPathFont(self):\n        global ui\n        global newPolicePath\n        global setSystemFonts\n\n        newPolicePath = str(QtWidgets.QFileDialog.getExistingDirectory(None, \"Select new font directory\", newPolicePath, QtWidgets.QFileDialog.ShowDirsOnly))\n        if newPolicePath:\n            MyLabelPatience.label.show()\n            FreeCADGui.updateGui()                             # rafraichi l'ecran\n            ui.searchFont(newPolicePath)\n            setSystemFonts = 1\n            MyLabelPatience.label.close()\n\n    def on_PB_systemPath(self):\n        global ui\n        global setSystemFonts\n\n        MyLabelPatience.label.show()\n        FreeCADGui.updateGui()                                 # rafraichi l'ecran\n        setSystemFonts = 0\n        ui.searchFont(self.pathFont)\n        MyLabelPatience.label.close()\n\n    def on_PB_01_Compound_01(self):\n        global doc\n        \n        self.selectionObjects = FreeCADGui.Selection.getSelection()\n        if len(self.selectionObjects) > 0:\n            try:\n                self.nameL         = []\n                self.comP          = []\n                del        self.nameL[:]\n                del         self.comP[:]\n\n                self.progressBar.setMaximum(len(self.selectionObjects))\n                compteur = 0\n                for i in self.selectionObjects:\n                    self.nameL.append(i.Name)\n                    self.comP.append(i.Shape)\n                    compteur += 1\n                    self.progressBar.setValue(compteur)\n                    Gui.updateGui()\n                    print( \"Object : \",i.Name)\n\n                comp = Part.makeCompound(self.comP)\n                Part.show(comp)\n\n                if self.groupBox_00.isChecked():\n                    FreeCADGui.ActiveDocument.ActiveObject.LineWidth  = self.lineWidth\n                    FreeCADGui.ActiveDocument.ActiveObject.LineColor  = (self.redFL, self.greenFL, self.blueFL)\n                    FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (self.redFL, self.greenFL, self.blueFL)\n                    FreeCADGui.ActiveDocument.ActiveObject.PointColor = (self.redFL, self.greenFL, self.blueFL)\n\n                App.ActiveDocument.ActiveObject.Label = \"reproShape_T_I\"\n        \n                if self.RB_01_Default.isChecked():\n                    None\n                if self.RB_02_Hidden.isChecked():\n                    for i in range(len(self.nameL)):\n                        print( \"Hidden : \",self.nameL[i])\n                        FreeCADGui.ActiveDocument.getObject(self.nameL[i]).Visibility = False\n                try:\n                    if self.RB_03_Delete.isChecked():\n                        for i in range(len(self.nameL)):\n                            print( \"Delete : \",self.nameL[i])\n                            doc.removeObject(self.nameL[i])\n                except Exception:\n                    FreeCAD.Console.PrintError(\"Error Delete : \",self.nameL[i] + \"\\n\")\n                \n            except Exception:\n                FreeCAD.Console.PrintError(\"Error objects \"+\"\\n\")\n            self.progressBar.setValue(0)\n            FreeCAD.ActiveDocument.recompute()\n        else:\n            FreeCAD.Console.PrintError(\"Not objects selected \"+\"\\n\")\n#        FreeCAD.Console.PrintMessage(str(\"on_PB_01_Compound_01 \")+\"\\n\")\n\n    def on_PB_02_Compound_02(self):\n        self.selectionObjects = FreeCADGui.Selection.getSelection()\n        if len(self.selectionObjects) > 0:\n            try:\n                self.nameL         = []\n                self.comP          = []\n                del        self.nameL[:]\n                del         self.comP[:]\n                \n                App.activeDocument().addObject(\"Part::Compound\",\"Compound\")\n                \n                self.progressBar.setMaximum(len(self.selectionObjects))\n                compteur = 0\n                for i in self.selectionObjects:\n                    self.nameL.append(App.ActiveDocument.getObject(i.Name))\n                    compteur += 1\n                    self.progressBar.setValue(compteur)\n                    Gui.updateGui()\n                    print( i.Name)\n                App.activeDocument().Compound.Links = self.nameL\n                App.activeDocument().recompute()\n\n                if self.groupBox_00.isChecked():\n                    FreeCADGui.ActiveDocument.ActiveObject.LineWidth  = self.lineWidth\n                    FreeCADGui.ActiveDocument.ActiveObject.LineColor  = (self.redFL, self.greenFL, self.blueFL)\n                    FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (self.redFL, self.greenFL, self.blueFL)\n                    FreeCADGui.ActiveDocument.ActiveObject.PointColor = (self.redFL, self.greenFL, self.blueFL)\n                # else:\n                    # FreeCADGui.ActiveDocument.ActiveObject.LineWidth  = \n                    # FreeCADGui.ActiveDocument.ActiveObject.LineColor  = \n                    # FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = \n                    # FreeCADGui.ActiveDocument.ActiveObject.PointColor = \n                \n                App.ActiveDocument.ActiveObject.Label = \"reproShape_T_II\"\n        \n            except Exception:\n                FreeCAD.Console.PrintError(\"Error objects \"+\"\\n\")\n            self.progressBar.setValue(0)\n            FreeCAD.ActiveDocument.recompute()\n        else:\n            FreeCAD.Console.PrintError(\"Not objects selected \"+\"\\n\")\n#        FreeCAD.Console.PrintMessage(str(\"on_PB_02_Compound_02 \")+\"\\n\")\n\n    def on_PB_03_Color(self):\n        #p = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/View\")\n        #print( p.GetUnsigned(\"DefaultShapeLineColor\"))\n        self.PB_03_Color.setStyleSheet(\"background-color: QPalette.Base\")        # origin system\n        self.window.hide()                                                       # hide the window open color\n        couleur = QtWidgets.QColorDialog.getColor()\n        \n        if couleur.isValid():\n            self.red   = int(str(couleur.name()[1:3]),16)\n            self.green = int(str(couleur.name()[3:5]),16)\n            self.blue  = int(str(couleur.name()[5:7]),16)\n\n            self.redFL   = float(couleur.redF())\n            self.greenFL = float(couleur.greenF())\n            self.blueFL  = float(couleur.blueF())\n            self.alphaFL = float(couleur.alphaF())\n            self.PB_03_Color.setStyleSheet(\"background-color: rgb(\"+str(self.red)+\",\"+str(self.green)+\",\"+str(self.blue)+\")\")\n\n        self.window.show()                                                        # show the window and close color\n#        FreeCAD.Console.PrintMessage(str(\"PB_03_Color \")+\"\\n\")\n\n    def on_PB_04_Convert_Text(self):        # convert Text to ShapeString\n        global PolicePath\n        global doc\n        \n        self.selectionObjects = FreeCADGui.Selection.getSelection()\n        self.progressBar.setMaximum(len(self.selectionObjects))\n        compteur = 0\n        if len(self.selectionObjects) > 0:\n            #objA = self.selectionObjects[0]\n            for objA in self.selectionObjects:\n\n                try:\n                    self.TextLabel     = objA.Label\n                    self.TextLabelText = objA.Text[0]      #0.19\n                    self.TextPosition  = objA.Placement    #0.19\n                    self.TextFontSize  = objA.ViewObject.FontSize \n\n                    if self.fontSizeManual:\n                        self.TextFontSize = self.FontSize\n\n                    self.TextTextColor = objA.ViewObject.TextColor\n                    texte = self.TextLabelText #0.19\n\n                    ss=Draft.makeShapeString(String = texte, FontFile=PolicePath, Size=float(self.TextFontSize), Tracking=0)\n\n                    if self.RB_01_FlatLines.isChecked():\n                        ss.ViewObject.DisplayMode = u\"Flat Lines\"\n                    if self.RB_02_Wireframe.isChecked():\n                        ss.ViewObject.DisplayMode = u\"Wireframe\"\n                    if self.RB_03_Points.isChecked():\n                        ss.ViewObject.DisplayMode = u\"Points\"\n\n                    plm  = self.TextPosition\n                    ss.Placement=plm\n                    ss.Support=None\n                    ss.Label = \"SString_\"+texte[:30]\n                    if self.groupBox_00.isChecked():\n                        #### imposted colors\n                        FreeCADGui.ActiveDocument.getObject(ss.Name).ShapeColor = (self.redFL, self.greenFL, self.blueFL)\n                        FreeCADGui.ActiveDocument.getObject(ss.Name).LineColor  = (self.redFL, self.greenFL, self.blueFL)\n                        FreeCADGui.ActiveDocument.getObject(ss.Name).PointColor = (self.redFL, self.greenFL, self.blueFL)\n                    else:\n#                        #### preferences colors\n#                        r, b, g, t = unsignedDecode(FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/View\").GetUnsigned(\"DefaultShapeColor\"),1)\n#                        FreeCADGui.ActiveDocument.getObject(ss.Name).ShapeColor = (r, b, g, t)\n#                        r, b, g, t = unsignedDecode(FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/View\").GetUnsigned(\"DefaultShapeLineColor\"),1)\n#                        FreeCADGui.ActiveDocument.getObject(ss.Name).LineColor  = (r, b, g, t)\n#                        r, b, g, t = unsignedDecode(FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/View\").GetUnsigned(\"DefaultShapeVertexColor\"),1)\n#                        FreeCADGui.ActiveDocument.getObject(ss.Name).PointColor = (r, b, g, t)\n\n                        #### original object colors\n                        FreeCADGui.ActiveDocument.getObject(ss.Name).ShapeColor = objA.ViewObject.TextColor\n                        FreeCADGui.ActiveDocument.getObject(ss.Name).LineColor  = objA.ViewObject.LineColor\n                        ##FreeCADGui.ActiveDocument.getObject(ss.Name).LineWidth  = objA.ViewObject.LineWidth\n                        \n                    compteur += 1\n                    self.progressBar.setValue(compteur)\n\n                    if self.RB_01_Default.isChecked():\n                        None\n                    if self.RB_02_Hidden.isChecked():\n                        print( \"Hidden : \",objA.Name)\n                        FreeCADGui.ActiveDocument.getObject(objA.Name).Visibility = False\n                    try:\n                        if self.RB_03_Delete.isChecked():\n                            print( \"Delete : \",objA.Name)\n                            doc.removeObject(objA.Name)\n                    except Exception:\n                        FreeCAD.Console.PrintError(\"Error Delete : \",objA.Name + \"\\n\")\n\n                    Gui.updateGui()\n                except Exception:\n                    FreeCAD.Console.PrintError(\"Not object TEXT or error\" + \"\\n\")\n\n            self.progressBar.setValue(0)\n            FreeCAD.ActiveDocument.recompute()\n        else:\n            FreeCAD.Console.PrintError(\"Select one or more objects TEXT\" + \"\\n\")\n#        FreeCAD.Console.PrintMessage(str(\"on_PB_04_Convert_Text \")+\"\\n\")\n\n    def on_DS_02_Size_Font_valueChanged(self,value):\n                        \n        \n        self.FontSize = value\n        if self.FontSize != 0:\n            self.PB_04_Convert_Text.setText(\"Convert Text (M)\")\n            self.DS_02_Size_Font.setSuffix(\" mm Size\")\n            self.fontSizeManual = True\n        else:\n            self.PB_04_Convert_Text.setText(\"Convert Text (A)\")\n            self.DS_02_Size_Font.setSuffix(\" Auto\")\n            self.fontSizeManual = False\n        #App.Console.PrintMessage(\"New FontSize \" + str(self.FontSize)+\"\\n\")\n\n    def on_PB_04c_Convert_Edge(self):                                                    # Convert Edge to line\n        self.selectionObjects = FreeCADGui.Selection.getSelectionEx()                    # Select an object or sub object\n        self.progressBar.setMaximum(len(self.selectionObjects))\n        compteur = 0\n        for selection in self.selectionObjects:\n            nameObject = selection.Object.Name\n            countSubName = 0\n            for selectedEdge in selection.SubObjects:\n                subName = selection.SubElementNames[countSubName]\n                compteur += 1\n                self.progressBar.setValue(compteur)\n                if (hasattr(selectedEdge,\"Surface\")) or (hasattr(selectedEdge,\"Point\")):\n                    Part.show(selectedEdge.copy())                                       # create repro shape subObject\n                    FreeCAD.Console.PrintMessage(\"Object Point or Surface duplicated !!\" + \"\\n\")\n                    FreeCAD.ActiveDocument.ActiveObject.Label = nameObject + \"_\" + subName + \"_(Copy)\"\n                else:\n                    try:\n                        s = selectedEdge\n                        if str(s.Curve) == \"<Ellipse object>\":                           # Ellipse\n                            FreeCAD.Console.PrintMessage(\"Detected : Ellipse\" + \"\\n\")\n                            pl=FreeCAD.Placement()\n                            pl.Rotation = FreeCAD.Rotation(s.Curve.XAxis, s.Curve.YAxis, s.Curve.Axis, \"ZXY\")\n                            pl.Base     = s.Curve.Center\n                            ellipse = Draft.makeEllipse(s.Curve.MajorRadius, s.Curve.MinorRadius, placement=pl, face=False, support=None)\n                            FreeCAD.ActiveDocument.ActiveObject.Label = nameObject + \"_\" + subName + \"_(Ellipse)\"\n                            edge  = selectedEdge\n                            ellipse.FirstAngle = degrees(edge.FirstParameter)\n                            ellipse.LastAngle  = degrees(edge.LastParameter)\n                            Draft.autogroup(ellipse)\n                \n                        elif str(s.Curve) == \"<Line object>\":                            # Line\n                            FreeCAD.Console.PrintMessage(\"Detected : Line\" + \"\\n\")\n                            points = []\n                            points = selectedEdge.Edges[0].discretize(3)                 # Dicretize\n                            wire   =  Draft.makeLine(points[0],points[-1])\n                            FreeCAD.ActiveDocument.ActiveObject.Label = nameObject + \"_\" + subName + \"_(Line)\"\n                            Draft.autogroup(wire)\n                            points[:]    = []\n                                \n                        elif (hasattr(s.Curve,\"Center\")) and (hasattr(s.Curve,\"Radius\")):# arc or circle\n                            FreeCAD.Console.PrintMessage(\"Detected : Arc or Circle\" + \"\\n\")\n                            ##https://github.com/yorikvanhavre/FreeCAD/blob/master/src/Mod/Draft/Draft.py#L264\n                            pl=FreeCAD.Placement()\n                            pl.Rotation = FreeCAD.Rotation(s.Curve.XAxis, s.Curve.YAxis, s.Curve.Axis, \"ZXY\")\n                            pl.Base     = s.Curve.Center\n                            circle = Draft.makeCircle(radius=s.Curve.Radius, placement=pl, face=False, support=None)\n                            circle.FirstAngle = degrees(selectedEdge.FirstParameter)\n                            circle.LastAngle  = degrees(selectedEdge.LastParameter)-360\n                            FreeCAD.ActiveDocument.ActiveObject.Label = nameObject + \"_\" + subName + \"_(CiOrArc)\"\n                            Draft.autogroup(circle)\n                \n                        elif (str(s.Curve) == \"<BSplineCurve object>\"):\n                            #print(s.Curve.getPoles())\n                            points   = []\n\n                            #try:\n                                #points = s.Curve.getPoles() ?                            # getPoles\n                            #except Exception:\n                            bspline = s.Curve\n                            arcs    = bspline.toBiArcs(0.001)\n                            BsplineNumberElement = len(arcs)\n                            points  = selectedEdge.Edges[0].discretize(BsplineNumberElement * 10)# Dicretize\n                            spline   = Draft.makeBSpline(points, closed=False, face=False, support=None)\n                            \n                            FreeCAD.ActiveDocument.ActiveObject.Label = nameObject + \"_\" + subName + \"_(BSplineC)\"\n                            Draft.autogroup(spline)\n                            points[:]= []\n                            FreeCAD.Console.PrintMessage(\"Detected : BSplineCurve (\" + str(BsplineNumberElement) + \" poles x 10)\" + \"\\n\")\n            \n                        elif (str(s.Curve) == \"<BezierCurve object>\"):                   # BezierCurve\n                            FreeCAD.Console.PrintMessage(\"Detected : BezierCurve\" + \"\\n\")\n                            #print(s.Curve.getPoles())\n                            points = []\n                            \n                            try:\n                                points = s.Curve.getPoles()                              # getPoles\n                            except Exception:\n                                points = selectedEdge.Edges[0].discretize(1000)          # Discretize\n                            try:\n                                if self.CB_BezierCurve.isChecked():\n                                    bezCurve = Draft.makeBezCurve(points, closed=False, support=None, degree=3)     #makeBezCurve3 (cubic) 0.19\n                                    FreeCAD.ActiveDocument.ActiveObject.Label = nameObject + \"_\" + subName + \"_(BezCubic)\"\n                                else:\n                                    bezCurve = Draft.makeBezCurve(points, closed=False, support=None, degree=None)  #makeBezCurve 0.19\n                                    FreeCAD.ActiveDocument.ActiveObject.Label = nameObject + \"_\" + subName + \"_(BezCurve)\"\n                                Draft.autogroup(bezCurve)\n                            except Exception:\n                                bezCurve = Draft.makeBezCurve(points,closed=False,support=None)  #makeBezCurve 0.18\n                                Draft.autogroup(bezCurve)\n                            points[:]= []\n            \n                        else:\n                            FreeCAD.Console.PrintMessage(\"Object duplicated !\" + \"\\n\")\n                            Part.show(selectedEdge.copy())                               # create repro shape subObject\n                            FreeCAD.ActiveDocument.ActiveObject.Label = nameObject + \"_\" + subName + \"_(Dupicate)\"\n            \n                    except Exception:\n                        FreeCAD.Console.PrintMessage(\"Error !!!\" + \"\\n\")\n                        \n                try:\n                    if self.RB_01_FlatLines.isChecked():\n                        FreeCADGui.ActiveDocument.ActiveObject.DisplayMode = u\"Flat Lines\"\n                    if self.RB_02_Wireframe.isChecked():\n                        FreeCADGui.ActiveDocument.ActiveObject.DisplayMode = u\"Wireframe\"\n                    if self.RB_03_Points.isChecked():\n                        FreeCADGui.ActiveDocument.ActiveObject.DisplayMode = u\"Points\"\n                except Exception:\n                    None\n\n                if self.lineWidth != 0.0:\n                    FreeCADGui.ActiveDocument.ActiveObject.LineWidth  = self.lineWidth\n                else:\n                    FreeCADGui.ActiveDocument.ActiveObject.LineWidth  = selection.Object.ViewObject.LineWidth\n                    \n                try:\n                    if self.groupBox_00.isChecked():\n                                                                                          \n                        FreeCADGui.ActiveDocument.ActiveObject.LineColor  = (self.redFL, self.greenFL, self.blueFL)\n                        FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (self.redFL, self.greenFL, self.blueFL)\n                        FreeCADGui.ActiveDocument.ActiveObject.PointColor = (self.redFL, self.greenFL, self.blueFL)\n                    else:\n                                                                                                                 \n                        FreeCADGui.ActiveDocument.ActiveObject.PointSize  = selection.Object.ViewObject.PointSize\n                        FreeCADGui.ActiveDocument.ActiveObject.LineColor  = selection.Object.ViewObject.LineColor\n                        FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = selection.Object.ViewObject.ShapeColor\n                        FreeCADGui.ActiveDocument.ActiveObject.PointColor = selection.Object.ViewObject.PointColor\n                except Exception:\n                    None\n                    \n                countSubName += 1\n                \n            if self.RB_01_Default.isChecked():\n                None\n            if self.RB_02_Hidden.isChecked():\n                print( \"Hidden : \",nameObject)\n                FreeCADGui.ActiveDocument.getObject(nameObject).Visibility = False\n            try:\n                if self.RB_03_Delete.isChecked():\n                    print( \"Delete : \",nameObject)\n                    doc.removeObject(nameObject)\n            except Exception:\n                FreeCAD.Console.PrintError(\"Error Delete : \",str(nameObject) + \"\\n\")\n\n        self.progressBar.setValue(0)\n        FreeCAD.ActiveDocument.recompute()\n#        FreeCAD.Console.PrintMessage(str(\"on_PB_04c_Convert_Edge\")+\"\\n\")\n\n    def on_groupBox_00(self):\n        if self.groupBox_00.isChecked():\n            None\n        else:\n            None\n#        FreeCAD.Console.PrintMessage(str(\"on_groupBox_00\")+\"\\n\")\n\n    def on_RB_Force_clicked(self):\n\n        if self.RB_Force_01_Line.isChecked():\n            self.groupBox_Force_LAC.setTitle(\"Force on a form : Line\")\n            self.PB_Force_LAC.setText(\"Force on : Line\")\n            self.PB_Force_LAC.setIcon(QtGui.QIcon.fromTheme(\"Vieuw\",QtGui.QIcon(\":/icons/Draft_Line.svg\")))\n        elif self.RB_Force_02_Arc.isChecked():\n            self.groupBox_Force_LAC.setTitle(\"Force on a form : Arc\")\n            self.PB_Force_LAC.setText(\"Force on : Arc\")\n            self.PB_Force_LAC.setIcon(QtGui.QIcon.fromTheme(\"Vieuw\",QtGui.QIcon(\":/icons/Draft_Arc.svg\")))\n        elif self.RB_Force_03_Circle.isChecked():\n            self.groupBox_Force_LAC.setTitle(\"Force on a form : Circle\")\n            self.PB_Force_LAC.setText(\"Force on : Circle\")\n            self.PB_Force_LAC.setIcon(QtGui.QIcon.fromTheme(\"Vieuw\",QtGui.QIcon(\":/icons/Draft_Circle.svg\")))\n\n    def on_PB_Force_LAC(self):\n\n        try:\n            selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0]                    # Select an object or sub object\n            selection    = FreeCADGui.Selection.getSelection()[0]\n            nameObject   = selection.Name\n            subName      = FreeCADGui.Selection.getSelectionEx()[0].SubElementNames[0]\n            s            = selectedEdge\n\n            if self.RB_Force_01_Line.isChecked():   # Force create Line\n                points = []\n                points = selectedEdge.Edges[0].discretize(3)                 # Dicretize\n                if (points[0] == points[-1]) :\n                    App.Console.PrintError(\"Bad selection the points are egual\"+\"\\n\")\n                else:\n                    wireLine = Draft.makeLine(points[0],points[-1])\n                    wireLine.ViewObject.LineColor = (1.0,0.0,0.0)         # give color\n                    wireLine.Label = nameObject + \"_\" + subName + \"_(Line)\" \n                    Draft.autogroup(wireLine)\n                points[:] = []\n\n            elif self.RB_Force_02_Arc.isChecked():   # Force create Arc\n\n                #App.Console.PrintError(\"This fonction is only availlable with FreeCAD 0.19 (Arc)\"+\"\\n\")\n                points = []\n                selectedArc = []\n                points = selectedEdge.Edges[0].discretize(3)                 # Dicretize\n                selectedArc = points\n\n                if (selectedArc[0]==selectedArc[1]) or (selectedArc[0]==selectedArc[2]) or selectedArc[1]==selectedArc[2] :\n                    App.Console.PrintError(\"Bad selection the points are egual (Line)\"+\"\\n\")\n                else:\n                    try:\n                        C1 = Part.Arc(FreeCAD.Vector(selectedArc[0]),FreeCAD.Vector(selectedArc[1]),FreeCAD.Vector(selectedArc[2]))\n                        S1 = Part.Shape([C1])                                      # create arc base\n                        Part.show(S1)\n\n                        obj = App.ActiveDocument.ActiveObject                      # select the object created\n                        Gui.Selection.addSelection(obj)\n                        sel = obj.Shape\n\n                        CircleDirection = sel.Curve.Axis                           # decode the datas\n                        CircleRayon     = sel.Curve.Radius\n                        CircleAxis      = sel.Curve.Center\n\n                        App.ActiveDocument.removeObject(obj.Label)                 # remove arc master\n\n                        v = CircleDirection                                        # give direction to circle\n                        r = App.Rotation(App.Vector(0,0,1),v)\n                        pl=FreeCAD.Placement()\n                        pl.Base=FreeCAD.Vector(CircleAxis)\n                        pl.Rotation.Q = r.Q\n                         \n                        arc3Points = make_arc_3points(selectedArc)\n\n                        arc3Points.ViewObject.LineColor = (1.0,0.0,0.0)         # give color\n                        arc3Points.Label =  nameObject + \"_\" + subName + \"_(\" + str(round(CircleRayon,3)) + \"_r)_(Arc)\"\n                    except Exception:\n                        App.Console.PrintError(\"Three points are collinear or bad selection (Arc)\"+\"\\n\"\n                                               \"Tray Force Circle\"+\"\\n\")\n                del selectedArc[:]\n\n            elif self.RB_Force_03_Circle.isChecked():   # Force create Circle\n\n                selectedCircle = []\n                points = selectedEdge.Edges[0].discretize(7)                 # Dicretize\n                selectedCircle = points\n\n                if (selectedCircle[0]==selectedCircle[1]) or (selectedCircle[0]==selectedCircle[2]) or selectedCircle[1]==selectedCircle[2] :\n                    App.Console.PrintError(\"Bad selection the points are egual\"+\"\\n\")\n                else:\n                    try:\n                        C1 = Part.Arc(FreeCAD.Vector(selectedCircle[0]),FreeCAD.Vector(selectedCircle[1]),FreeCAD.Vector(selectedCircle[2]))\n                        S1 = Part.Shape([C1])                                      # create arc base\n                        Part.show(S1)\n\n                        obj = App.ActiveDocument.ActiveObject                      # select the object created\n                        Gui.Selection.addSelection(obj)\n                        sel = obj.Shape\n\n                        CircleDirection = sel.Curve.Axis                           # decode the datas\n                        CircleRayon     = sel.Curve.Radius\n                        CircleAxis      = sel.Curve.Center\n\n                        App.ActiveDocument.removeObject(obj.Label)                 # remove arc master\n\n                        v = CircleDirection                                        # give direction to circle\n                        r = App.Rotation(App.Vector(0,0,1),v)\n                        pl=FreeCAD.Placement()\n                        pl.Base=FreeCAD.Vector(CircleAxis)\n                        pl.Rotation.Q = r.Q\n                        circle3Points = Draft.makeCircle(radius=CircleRayon, placement=pl, face=False, support=None)\n                        circle3Points.ViewObject.LineColor = (1.0,0.0,0.0)         # give color\n                        circle3Points.Label =  nameObject + \"_\" + subName + \"_(\" + str(round(CircleRayon,3)) + \"_r)_(Circle)\"\n                        Draft.autogroup(circle3Points)\n                    except Exception:\n                        App.Console.PrintError(\"Three points are collinear or bad selection (Circle)\"+\"\\n\")\n                del selectedCircle[:]\n\n            FreeCAD.ActiveDocument.recompute()\n        except Exception:\n            App.Console.PrintError(\"Error in Create Forced object\" + \"\\n\")\n\n    def on_DS_01_Width_Line_valueChanged(self,LineWidth):\n        self.lineWidth = LineWidth\n        if self.lineWidth != 0.0:\n            self.DS_01_Width_Line.setSuffix(\" mm Width\")\n            self.PB_04c_Convert_Edge.setText(\"Convert Wire (M)\")\n        else:\n            self.DS_01_Width_Line.setSuffix(\" Auto\")\n            self.PB_04c_Convert_Edge.setText(\"Convert Wire (A)\")\n#        FreeCAD.Console.PrintMessage(str(\"on_DS_01_Width_Line_valueChanged \")+str(self.lineWidth)+\"\\n\")\n\n    def on_CB_BezierCurve_clicked(self):\n        if self.CB_BezierCurve.isChecked():\n            self.CB_BezierCurve.setIcon(QtGui.QIcon.fromTheme(\"Part\",QtGui.QIcon(\":/icons/Draft_CubicBezCurve.svg\")))\n            self.CB_BezierCurve.setText(\"Cubic BezierCurve\")\n        else:\n            self.CB_BezierCurve.setIcon(QtGui.QIcon.fromTheme(\"Part\",QtGui.QIcon(\":/icons/Draft_BezCurve.svg\")))\n            self.CB_BezierCurve.setText(\"BezierCurve\")\n#        FreeCAD.Console.PrintMessage(str(\"on_CB_BezierCurve_clicked \")+\"\\n\")\n\n    def on_PB_05_Reset(self):                     # \n        global ui\n        global setSystemFonts\n        global PolicePath\n        global nomPolice\n \n        #p = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/View\")\n        #print( p.GetUnsigned(\"DefaultShapeLineColor\"))\n        self.red     = 255   #204               # for button\n        self.green   = 0     #204\n        self.blue    = 0     #204\n        self.alpha   = 255   # 255 = visibility max (opacity)\n        self.redFL   = float(255.0 / 255.0)     # for object FC\n        self.greenFL = float(0.0   / 255.0)\n        self.blueFL  = float(0.0   / 255.0)\n        self.alphaFL = float(255.0 / 255.0)     # 1.0 = visibility max (opacity)\n        \n        self.PB_03_Color.setStyleSheet(\"background-color: rgb(\"+str(self.red)+\",\"+str(self.green)+\",\"+str(self.blue)+\")\")\n        self.groupBox_00.setChecked(False)\n        \n        self.RB_01_Default.setChecked(True)\n        self.lineWidth = 0.0\n        self.DS_01_Width_Line.setValue(self.lineWidth)\n        self.DS_02_Size_Font.setValue(0.0)\n\n        self.groupBox_Force_LAC.setTitle(\"Force on a form : Line\")\n        self.PB_Force_LAC.setText(\"Force on : Line\")\n        self.PB_Force_LAC.setIcon(QtGui.QIcon.fromTheme(\"Vieuw\",QtGui.QIcon(\":/icons/Draft_Line.svg\")))\n        self.RB_Force_01_Line.setChecked(True)\n\n        MyLabelPatience.label.show()\n        FreeCADGui.updateGui()                                 # rafraichi l'ecran\n        setSystemFonts = 0\n        ui.searchFont(self.pathFont)\n        MyLabelPatience.label.close()\n\n        self.fontSizeManual    = False\n        self.PB_04_Convert_Text.setText(\"Convert Text (A)\")\n        self.FontSize  = 0.0\n        self.DS_02_Size_Font.setValue(self.FontSize)\n        self.fonte     = PolicePath + \"/\" + nomPolice + \".TTF\"\n        self.CB_BezierCurve.setChecked(False)\n        self.RB_01_FlatLines.setChecked(True)\n\n#        FreeCAD.Console.PrintMessage(str(\"on_PB_05_Reset \")+\"\\n\")\n\n    def on_PB_09_Upgrade(self):                     # \n        try:\n            Draft.upgrade(FreeCADGui.Selection.getSelection(), delete=True)\n            FreeCAD.ActiveDocument.recompute()\n        except Exception:\n            None\n#        FreeCAD.Console.PrintMessage(str(\"on_PB_06_Downgrade \")+\"\\n\")\n\n    def on_PB_06_Downgrade(self):                     # \n        try:\n            Draft.downgrade(FreeCADGui.Selection.getSelection(),delete=True)\n            FreeCAD.ActiveDocument.recompute()\n        except Exception:\n            None\n#        FreeCAD.Console.PrintMessage(str(\"on_PB_06_Downgrade \")+\"\\n\")\n\n    def on_PB_07_Quit(self):                     # \n        FreeCAD.Console.PrintMessage(\"End Compound +\"+\"\\n\")\n        self.window.hide()\n#        FreeCAD.Console.PrintMessage(str(\"on_PB_06_Quit \")+\"\\n\")\n\n    def on_PB_Help_clicked(self):\n        webbrowser.open(\"https://wiki.freecadweb.org/Macro_Compound_Plus\")\n\n        App.Console.PrintMessage(\"https://wiki.freecadweb.org/Macro_Compound_Plus\" + \"\\n\")\n#        FreeCAD.Console.PrintMessage(str(\"Help \")+\"\\n\")\n\n###### Read Configuration begin ####\n#switchModeTextList = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switchModeTextList\")\n#switchFontComBox   = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switchFontComBox\")\n#setSystemFonts     = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"setSystemFonts\")\n#seTtextAlignement  = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"seTtextAlignement\")\n###### Read Configuration end   ####\n\n###### Write Configuration begin ####\n#FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchModeTextList\", True)    # True or False\n#FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchFontComBox\", True)      # True or False\n#FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"setSystemFonts\", True)        # True or False\n#FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"seTtextAlignement\", 0)         # 0, 1, or 2\nFreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"Version\",__version__ + \" (\" + __date__ + \")\")# \n###### Write Configuration end   ####\n\nCompound = QtWidgets.QMainWindow()\nui = Ui_Compound()\nui.setupUi(Compound)\nCompound.show()\n",
    "url": "https://wiki.freecad.org/Macro_Compound_Plus",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/7be361a8c489deec918f664fdcfc4394/raw/2d12268123cbd38a3fba10fff1c7f35837cd3325/Macro_Compound_Plus.FCMacro",
    "wiki": "",
    "version": "0.05",
    "license": "",
    "date": "2024/11/11",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Compound_Plus.png",
    "icon_source": "https://wiki.freecadweb.org/images/f/fd/Macro_Compound_Plus.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Creating faces from a DXF file",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro create face from a DXF file, the \"Layer\" are recognized separate and trained in groups.<br /><br />Macro version: 01.00<br />Last modified: 2014-10-29<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/0/03/Macro_Creating_faces_from_a_DXF_file.png\">ToolBar Icon</a><br />Author: shoogen<br /> ",
    "comment": "This macro create face from a DXF file, the \"Layer\" are recognized separate and trained in groups.",
    "code": "import FreeCAD,Part,OpenSCAD2Dgeom\ndoc = App.ActiveDocument\nfor group in doc.findObjects('App::DocumentObjectGroup'):\n    try:\n        edges=sum((obj.Shape.Edges for obj in group.Group \\\n                if hasattr(obj,'Shape')),[])\n        face = OpenSCAD2Dgeom.edgestofaces(edges)\n        faceobj = doc.addObject('Part::Feature','face_%s' % group.Name)\n        faceobj.Label = 'face_%s' % group.Label\n        faceobj.Shape = face\n    except Part.OCCError: # Exception: # \n        FreeCAD.Console.PrintError('Error in Group %s (%s)' % (group.Name,group.Label)+\"\\n\")",
    "url": "https://wiki.freecad.org/Macro_Creating_faces_from_a_DXF_file",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-10-29",
    "src_filename": "",
    "filename_from_url": "",
    "author": "shoogen",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Creating_faces_from_a_DXF_file.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/0/03/Macro_Creating_faces_from_a_DXF_file.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "DXF to Face and Sketch",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro create face and sketch from a DXF file.<br /><br />Macro version: 02.00<br />Last modified: 2017-10-23<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/6/6d/Macro_DXF_to_Face_and_Sketch.png\">ToolBar Icon</a><br />Author: shoogen,  easyw-fc<br /> ",
    "comment": "This macro create face and sketch from a DXF file.",
    "code": "##    Select the items to be processed\n##    Launch the macro, all selected objects are analyzed and transformed into faces and sketches.\n##    change create_face=True or create_sketch=True to False to generate only one item\n## todo: fix closed curves for bsplines method\n\nimport FreeCAD,Part,Path\nfrom PathScripts import PathUtils\n\nimport sys, os\n#sys.path.append('C:\\Cad\\Progetti_K\\3D-FreeCad-tools/')\n#sys.path.append(os.path.realpath(__file__)) #workaround to test OpenSCAD2DgeomMau\n#import OpenSCAD2DgeomMau #OpenSCAD2Dgeom\n#reload(OpenSCAD2DgeomMau)\nimport OpenSCAD2Dgeom\n\nimport PySide\nfrom PySide import QtGui, QtCore\n\n\nimport DraftGeomUtils\nimport Draft\nfrom DraftGeomUtils import geomType\n\ncreate_face=True\ncreate_sketch=True\ndqd = 0.02 #discretize(QuasiDeflection=d) => gives a list of points with a maximum deflection 'd' to the edge (faster)\n\n\ndef clear_console():\n    #clearing previous messages\n    mw=FreeCADGui.getMainWindow()\n    c=mw.findChild(QtGui.QPlainTextEdit, \"Python console\")\n    c.clear()\n    r=mw.findChild(QtGui.QTextEdit, \"Report view\")\n    r.clear()\n\ndef shape2Sketch(shape):\n    # replace shape.edges with arcs\n    newEdges = PathUtils.cleanedges(shape.Edges,0.1)\n    wire = Part.Wire([Part.Edge(i) for i in newEdges])\n    sketch = Draft.makeSketch(wire,autoconstraints=True,delete=True)\n    return sketch\n\ndef Discretize(shape, addToName=None):\n    ##http://forum.freecadweb.org/viewtopic.php?f=12&t=16336#p129468\n    ##Discretizes the edge and returns a list of points.\n    ##The function accepts keywords as argument:\n    ##discretize(Number=n) => gives a list of 'n' equidistant points\n    ##discretize(QuasiNumber=n) => gives a list of 'n' quasi equidistant points (is faster than the method above)\n    ##discretize(Distance=d) => gives a list of equidistant points with distance 'd'\n    ##discretize(Deflection=d) => gives a list of points with a maximum deflection 'd' to the edge\n    ##discretize(QuasiDeflection=d) => gives a list of points with a maximum deflection 'd' to the edge (faster)\n    ##discretize(Angular=a,Curvature=c,[Minimum=m]) => gives a list of points with an angular deflection of 'a'\n    ##and a curvature deflection of 'c'. Optionally a minimum number of points\n    ##can be set which by default is set to 2. \n\n    global dqd\n\n    # lng=(abs(FreeCAD.ActiveDocument.getObject(skt_name).Shape.BoundBox.XLength)+abs(FreeCAD.ActiveDocument.getObject(skt_name).Shape.BoundBox.YLength))\n    # dv=int(dvm*lng) #discretize auto setting\n    # #dv=int(0.5*lng) #discretize auto setting COARSE for testing\n    # #print( dv)\n    # if dv < 20:\n    #     dv=20\n    #b=FreeCAD.ActiveDocument.getObject(skt_name)\n    #l=b.Shape.copy().discretize(dv)\n    #l=b.Shape.copy().discretize(QuasiDeflection=0.02)\n    l=shape.copy().discretize(QuasiDeflection=dqd)\n    f=Part.makePolygon(l)\n    Part.show(f)\n    sh_name=FreeCAD.ActiveDocument.ActiveObject.Name\n    if addToName is None:\n        Draft.makeSketch(FreeCAD.ActiveDocument.ActiveObject,autoconstraints=True)\n    else:\n        Draft.makeSketch(FreeCAD.ActiveDocument.ActiveObject,autoconstraints=True, addTo=addToName)\n    s_name=FreeCAD.ActiveDocument.ActiveObject.Name\n    FreeCAD.ActiveDocument.removeObject(sh_name)\n    #FreeCAD.ActiveDocument.removeObject(skt_name)\n    FreeCAD.ActiveDocument.recompute() \n    return s_name\n    #stop\n\ndef WireDiscretize(wire):\n    ##http://forum.freecadweb.org/viewtopic.php?f=12&t=16336#p129468\n    ##Discretizes the edge and returns a list of points.\n    ##The function accepts keywords as argument:\n    ##discretize(Number=n) => gives a list of 'n' equidistant points\n    ##discretize(QuasiNumber=n) => gives a list of 'n' quasi equidistant points (is faster than the method above)\n    ##discretize(Distance=d) => gives a list of equidistant points with distance 'd'\n    ##discretize(Deflection=d) => gives a list of points with a maximum deflection 'd' to the edge\n    ##discretize(QuasiDeflection=d) => gives a list of points with a maximum deflection 'd' to the edge (faster)\n    ##discretize(Angular=a,Curvature=c,[Minimum=m]) => gives a list of points with an angular deflection of 'a'\n    ##and a curvature deflection of 'c'. Optionally a minimum number of points\n    ##can be set which by default is set to 2. \n\n    global dqd\n\n    l=wire.copy().discretize(QuasiDeflection=dqd)\n    f=Part.makePolygon(l)\n    Part.show(f)\n    sh_name=FreeCAD.ActiveDocument.ActiveObject.Name\n    FreeCAD.ActiveDocument.recompute() \n    \n    return sh_name\n    #stop\n    \n    \n#creating face from dxf\ndoc = App.ActiveDocument\nclear_console()\n\nif FreeCADGui.Selection.getSelection():\n\n    try:\n        edges=sum((obj.Shape.Edges for obj in \\\n        FreeCADGui.Selection.getSelection() if hasattr(obj,'Shape')),[])\n        for edge in edges:\n            print( \"geomType \",DraftGeomUtils.geomType(edge))\n        face = OpenSCAD2Dgeom.edgestofaces(edges)\n        #face = OpenSCAD2DgeomMau.edgestofaces(edges)\n        face.check() # reports errors\n        face.fix(0,0,0)\n        faceobj = doc.addObject('Part::Feature','face_%s' % \"dxf\")\n        faceobj.Label = 'face_%s' % \"dxf\"\n        faceobj.Shape = face\n        for obj in FreeCADGui.Selection.getSelection():\n            Gui.ActiveDocument.getObject(obj.Name).Visibility=False   \n        #creating sketch from face from dxf\n        #wires,_faces = Draft.downgrade(FreeCADGui.Selection.getSelection(),delete=False)\n        if create_sketch:\n            if create_face:\n                wires,_faces = Draft.downgrade(faceobj,delete=False)\n            else:\n                wires,_faces = Draft.downgrade(faceobj,delete=True)\n            if 0: #try:\n                sketch = Draft.makeSketch(wires[0:1])\n                sketch.Label = \"Sketch_dxf\"\n                for wire in wires[1:]:\n                    Draft.makeSketch([wire],addTo=sketch)\n                for wire in wires:\n                    FreeCAD.ActiveDocument.removeObject(wire.Name)\n            else: #except:\n                FreeCAD.Console.PrintWarning(\"\\nConverting Bezier curves to Arcs\\n\")\n                #FreeCAD.ActiveDocument.removeObject(FreeCAD.ActiveDocument.ActiveObject.Name)\n                \n                #print()\n                sketchesList=[]\n                #for wire in wires:\n                #    for e in wire.Shape.Edges:\n                #        if geomType(e) == \"BSplineCurve\" or geomType(e) == \"BezierCurve\":\n                #        #if 'spline' in e.Curve:\n                #            sk_name = Discretize(e)\n                #            sketchesList.append(sk_name)\n                #        else:\n                #            sketch = Draft.makeSketch(Part.Wire(e))\n                #            sketchesList.append(sketch.Name)\n                #print( sketchesList)\n                \n                newShapeList = []\n                newShapes = []\n                for wire in wires:\n                    for e in wire.Shape.Edges:\n                        if geomType(e) == \"BSplineCurve\" or geomType(e) == \"BezierCurve\":\n                        #if 'spline' in e.Curve:\n                            w = Part.Wire(e)\n                            w_name =WireDiscretize(w)\n                            newShapeList.append(w_name)\n                            wn=FreeCAD.ActiveDocument.getObject(w_name)\n                            newShapes.append(wn)\n                        else:\n                            w = Part.Wire(e)\n                            Part.show(w)\n                            newShapes.append(w)\n                            w_name = FreeCAD.ActiveDocument.ActiveObject.Name\n                            newShapeList.append(w_name)\n                            \n                #print( newShapes)\n                sketch = Draft.makeSketch(newShapes[0])\n                FreeCAD.ActiveDocument.ActiveObject.Label=\"Sketch_dxf\"\n                for w in newShapes[1:]:\n                    Draft.makeSketch([w],addTo=sketch)    \n                for wire in wires:\n                    FreeCAD.ActiveDocument.removeObject(wire.Name)\n                for w_name in newShapeList:\n                    FreeCAD.ActiveDocument.removeObject(w_name)\n                \n                #stop\n                #WireDiscretize(wire)\n                \n                \n                #stop\n                #sk_name=FreeCAD.ActiveDocument.ActiveObject.Name\n                #skObj=FreeCAD.ActiveDocument.getObject(sk_name)\n                #for wire in wires[1:]:\n                #    Discretize(wire.Shape,skObj)\n                    \n                #for wire in wires:\n                #    FreeCAD.ActiveDocument.removeObject(wire.Name)\n                    \n                #for wire in wires[1:]:\n                #    Discretize(wire.Shape,sketch)\n                #for wire in wires:\n                #    FreeCAD.ActiveDocument.removeObject(wire.Name)\n                #for wire in wires:\n                #    FreeCAD.ActiveDocument.removeObject(wire.Name)\n                #sketch = shape2Sketch(face)\n                #sketch = Discretize(FreeCAD.ActiveDocument.getObject(faceobj.Name).Shape)\n                #sketch = Discretize(FreeCAD.ActiveDocument.getObject(f1.Name))\n                \n    except Part.OCCError: # Exception: #\n        FreeCAD.Console.PrintError('Error in dxf %s (%s)' % (faceobj.Name,faceobj.Label)+\"\\n\")\nelse:\n    #FreeCAD.Console.PrintError(\"Select elements from dxf imported file\\n\")\n    FreeCAD.Console.PrintWarning(\"Select elements from dxf imported file\\n\")",
    "url": "https://wiki.freecad.org/Macro_DXF_to_Face_and_Sketch",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2017-10-23",
    "src_filename": "",
    "filename_from_url": "",
    "author": "shoogen,  easyw-fc",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_DXF_to_Face_and_Sketch.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/6/6d/Macro_DXF_to_Face_and_Sketch.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Dxf To Shape",
    "on_wiki": true,
    "on_git": false,
    "desc": "Utility to create a unique wire with many wires<br /><br />Macro version: 00.00<br />Last modified: 2020-09-04<br />FreeCAD version: 0.18, 0.19<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/f/f4/Macro_Dxf_To_Shape.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Still in development and not finished",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2016 2017 2018 2019 2020 <mario52>                      *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#Macro_DXF_to_Shape 01/11/2015 /_00 13/02/2020_00\n#\n#OS: Windows 10\n#Word size of OS: 64-bit\n#Word size of FreeCAD: 64-bit\n#Version: 0.16.6706 (Git)\n#Build type: Release\n#Branch: releases/FreeCAD-0-16\n#Hash: f86a4e411ff7848dea98d7242f43b7774bee8fa0\n#Python version: 2.7.8\n#Qt version: 4.8.7\n#Coin version: 4.0.0a\n#OCC version: 6.8.0.oce-0.17\n#\n__title__   =\"Macro_DXF_to_Shape\"\n__author__  = \"mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__version__ = \" modified 00.00\"\n__date__    = \"2020/09/04\"    #YYYY/MM/DD\n\n__Comment__  = \"Still in development and not finished\"\n__Web__      = \"\"\n__Wiki__     = \"\"\n__IconL__    = \"\"\n__IconW__    = \"\"\n__Help__     = \"\"\n__Status__   = \"prototype Not finished\"\n__Requires__ = \"\"\n__Communication__ = \"\"\n# original modifie Curve : line 1835 28/11/2016 mouse mode 01-02-2017\nimport PySide\nfrom PySide import QtGui ,QtCore\nfrom PySide.QtGui import *\nfrom PySide.QtCore import *\n \nimport Draft, Part, math, PartGui, FreeCADGui\nimport FreeCAD\nApp = FreeCAD\nGui = FreeCADGui\n\nfrom math import sqrt, pi, sin, cos, asin\nfrom FreeCAD import Base\nimport OpenSCAD2Dgeom\nimport os\nimport copy\n\n# reproduire une serie de lignes pour en faire une seule et doit fonctionner avec sweep ici sauver dans le fichier les vecteurs\n\nglobal path        ;\n#path = FreeCAD.ConfigGet(\"AppHomePath\")        # app install\n#path = FreeCAD.ConfigGet(\"UserAppData\")        # user app config\npath  = \"C:/Provisoire400/\"+\"DXF_ASC/\"                        # your path\nApp.Console.PrintMessage(\"Path temporary file : \" + path + \"\\n\")\n\nglobal sel            ; sel            = \"\"        # selection\nglobal nomFichier     ; nomFichier     = \"FCDataTest_XYZ.asc\"# temporary file\nglobal OpenName       ; OpenName       = \"\"\nglobal lecture        ; lecture        = 1         # writeData= 0 readData= 1\nglobal revers         ; revers         = 0         # 0=Reversed 1=Forward 2=Neutral\nglobal createLine     ; createLine     = 1         # 1=Create line 0=not line\nglobal typeLine       ; typeLine       = 0         # 0=makeWire 1=BSpline 2=BSplineCurve\nglobal typeArc        ; typeArc        = 0         # 0=False 1=True\nglobal wireClose      ; wireClose      = 0         # 0=False 1=True\nglobal wireFace       ; wireFace       = 0         # 0=False 1=True\nglobal pointsPerMm    ; pointsPerMm    = 1.0       # precision\nglobal createCloud    ; createCloud    = 0         # 1=create Cloud\nglobal createShell    ; createShell    = 0         # 1=create a Shell with a Cloud\nglobal createPoint    ; createPoint    = 0         # 1=create points\nglobal savedata       ; savedata       = 0         # save datas 0=XYZ 1=XY 2=YZ 3=XZ\nglobal pp             ; pp             = []        # list coordinates XYZ\nglobal objectLabel    ; objectLabel    = \"\"        # object selected\nglobal text           ; text           = \"\"        # text for display\nglobal comptData      ; comptData      = 0         # compteur datas\nglobal comptDataSaved ; comptDataSaved = 0         # compteur datas saved in file\nglobal sautData       ; sautData       = 1         # saut coordonnees        \nglobal lineCreate     ; lineCreate     = \"\"        # create object line\nglobal myCircle       ; myCircle       = \"\"        # test myCircle\nglobal mySweep        ; mySweep        = \"\"        # test mySweep\nglobal mySweepSolid   ; mySweepSolid   = 1         # mySweepSolid  1=yes 0=no\nglobal mySweepFrenet  ; mySweepFrenet  = 1         # mySweepFrenet 1=yes 0=no\nglobal txtBegin       ; txtBegin       = \"\"        # txtBegin Begin line\nglobal txtEnd         ; txtEnd         = \"\"        # txtEnd End Line\nglobal createZero     ; createZero     = 0         # create the zero in the file coordinate \nglobal rgbPoints      ; rgbPoints      = []        # rgb color points cloud\nglobal diamCircle     ; diamCircle     = 0.5       # diameter circle test sweep\nglobal verbose        ; verbose        = 1         # colore the lines\nglobal suppressBegin  ; suppressBegin  = 0         # suppress the x first carachter data loaded (cas:X10.0 Y15.0 Z20.0)\nglobal suppressEnd    ; suppressEnd    = 0         # suppress the x first carachter data loaded (cas:X10.0 Y15.0 Z20.0)\n\nglobal check_To_Mouse ; check_To_Mouse = 0         # check To Mouse\nglobal vecteurSou     ; vecteurSou     = \"\"        # vecteur mode Souris  #FreeCAD.Vector(0,0,0)\nglobal vecteurSou_Comp; vecteurSou_Comp= 0         # compteur de coordonnees\nglobal file_Mouse     ; file_Mouse     = \"\"        # file_Mouse\nglobal pointsRead     ; pointsRead     = []        # \nglobal pointsName     ; pointsName     = []        # \n\nglobal Switch_TE_Zoom ; Switch_TE_Zoom = 0         # switch zoom\n\nglobal s              ; s              = \"\"        # resident\nglobal ui             ; ui             = \"\"\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\n#ajouter affiner la forme\n#App.ActiveDocument.addObject('Part::Feature','Extrude_DWire').Shape=App.ActiveDocument.Extrude_DWire.Shape.removeSplitter()\n#>>> App.ActiveDocument.ActiveObject.Label=App.ActiveDocument.Extrude_DWire.Label\n#>>> Gui.ActiveDocument.Extrude_DWire.hide()\n#>>> \n#>>> Gui.ActiveDocument.ActiveObject.ShapeColor=Gui.ActiveDocument.Extrude_DWire.ShapeColor\n#>>> Gui.ActiveDocument.ActiveObject.LineColor=Gui.ActiveDocument.Extrude_DWire.LineColor\n#>>> Gui.ActiveDocument.ActiveObject.PointColor=Gui.ActiveDocument.Extrude_DWire.PointColor\n#>>> App.ActiveDocument.recompute()\n#>>> \n\n\n####chrono####\nimport time\nglobal depart ; depart  = 0.0\nglobal arrivee; arrivee = 0.0\ndef Chrono(sec):\n#time.strftime('%X %x %Z')#'15:44:07 12/14/19 Paris, Madrid'\n    global depart\n    global arrivee\n    if sec == 0:\n        depart = time.time()#time.clock()\n        App.Console.PrintMessage(\"Chrono begin   : \"+str(time.strftime('%X'))+\"\\n\")\n    else:\n        arrivee = time.time()#time.clock()\n        App.Console.PrintMessage(\"Chrono end     : \"+str(time.strftime('%X'))+\"\\n\")\n        parcouru = ((arrivee - depart)/60.0)\n        App.Console.PrintError(\"Time execution : \"+str(\"%.3f\" % parcouru)+\" min\"+\"\\n\\n\")\n    FreeCADGui.updateGui()    \n####chrono####\n\nglobal objectPlacementAngle ; objectPlacementAngle = \"\"\ndef objectRealPlacement3D(obj):\n    global objectPlacementAngle\n    try:\n        objectPlacement      = obj.Shape.Placement\n        #### \n        objectPlacementBase  = FreeCAD.Vector(objectPlacement.Base)\n        ####\n        objectWorkCenter     = objectPlacementBase\n        ####\n        objectPlacementAngle = objectPlacement.Rotation.toEuler()\n\n        if hasattr(obj, \"getGlobalPlacement\"):\n            globalPlacement       = obj.getGlobalPlacement()\n            globalPlacementBase   = FreeCAD.Vector(globalPlacement.Base)\n            objectRealPlacement3D = globalPlacementBase.add(objectWorkCenter).sub(objectPlacementBase)\n            objectPlacementAngle  = globalPlacement.Rotation.toEuler()\n        else:\n            objectRealPlacement3D = objectWorkCenter\n\n        return objectRealPlacement3D\n    except Exception:\n        return FreeCAD.Vector(0.0, 0.0, 0.0)\n\n\nclass Ui_MainWindow(object):\n    def __init__(self):\n        self.red           = 1.0\n        self.green         = 0.0\n        self.blue          = 0.0\n        self.alpha         = 0.0\n        self.pointFont     = 8.0\n\n    def setupUi(self, MainWindow):\n        global path\n        global pp\n        global pointsPerMm\n        global ui\n\n        self.window = MainWindow\n        \n        self.fontGlobal_08 = QtGui.QFont()            # pour compatibilite Windows Linux pour tous les textes\n        self.fontGlobal_08.setFamily(\"Arial\")         # pour compatibilite Windows Linux pour tous les textes\n        self.fontGlobal_08.setPointSize(self.pointFont)# pour compatibilite Windows Linux pour tous les textes\n        #self.xxxxx.setFont(self.fontGlobal_08)       # Windows Linux\n\n        MainWindow.setObjectName(_fromUtf8(\"MainWindow\"))\n        MainWindow.resize(311, 655)\n        MainWindow.setMinimumSize(QtCore.QSize(311, 655))\n        MainWindow.setMaximumSize(QtCore.QSize(311, 655))\n        MainWindow.move(925, 115)\n\n        self.centralwidget = QtGui.QWidget(MainWindow)\n        self.centralwidget.setObjectName(_fromUtf8(\"centralwidget\"))\n\n        self.GBox_00_Configuration = QtGui.QGroupBox(self.centralwidget)\n        self.GBox_00_Configuration.setGeometry(QtCore.QRect(10, 10, 291, 241))\n        self.GBox_00_Configuration.setFont(self.fontGlobal_08)       # Windows Linux\n        self.GBox_00_Configuration.setFlat(False)\n        self.GBox_00_Configuration.setObjectName(_fromUtf8(\"GBox_00_Configuration\"))\n\n        self.GBox_01_Orientation = QtGui.QGroupBox(self.GBox_00_Configuration)\n        self.GBox_01_Orientation.setGeometry(QtCore.QRect(10, 20, 131, 81))\n        self.GBox_01_Orientation.setFont(self.fontGlobal_08)          # Windows Linux\n        self.GBox_01_Orientation.setObjectName(_fromUtf8(\"GBox_01_Orientation\"))\n\n        self.RB_01_01_Reversed = QtGui.QRadioButton(self.GBox_01_Orientation)\n        self.RB_01_01_Reversed.setGeometry(QtCore.QRect(10, 20, 82, 17))\n        self.RB_01_01_Reversed.setFont(self.fontGlobal_08)          # Windows Linux\n        self.RB_01_01_Reversed.setChecked(True)\n        self.RB_01_01_Reversed.setToolTip(\"Revese the coordinates (If Orientation='Reversed')\")\n        self.RB_01_01_Reversed.setObjectName(_fromUtf8(\"RB_01_01_Reversed\"))\n        self.RB_01_01_Reversed.clicked.connect(self.on_RB_01_01_Reversed_clicked)            # connect radioButton_3 on def \"on_RB_01_01_Reversed_clicked:\"\n\n        self.RB_01_02_Forward = QtGui.QRadioButton(self.GBox_01_Orientation)\n        self.RB_01_02_Forward.setGeometry(QtCore.QRect(10, 40, 82, 17))\n        self.RB_01_02_Forward.setFont(self.fontGlobal_08)          # Windows Linux\n        self.RB_01_02_Forward.setObjectName(_fromUtf8(\"RB_01_02_Forward\"))\n        self.RB_01_02_Forward.setToolTip(\"Revese the coordinates (If Orientation='Forward')\")\n        self.RB_01_02_Forward.clicked.connect(self.on_RB_01_02_Forward_clicked)              # connect on def \"on_RB_01_02_Forward_clicked:\"\n\n        self.RB_01_03_Neutral = QtGui.QRadioButton(self.GBox_01_Orientation)\n        self.RB_01_03_Neutral.setGeometry(QtCore.QRect(10, 60, 82, 17))\n        self.RB_01_03_Neutral.setFont(self.fontGlobal_08)          # Windows Linux\n        self.RB_01_03_Neutral.setObjectName(_fromUtf8(\"RB_01_03_Neutral\"))\n        self.RB_01_03_Neutral.setToolTip(\"Neutral\")\n        self.RB_01_03_Neutral.clicked.connect(self.on_RB_01_03_Neutral_clicked)              # connect on def \"on_RB_01_03_Neutral_clicked:\"\n\n        self.CB_01_01_Reverse = QtGui.QCheckBox(self.GBox_01_Orientation)\n        self.CB_01_01_Reverse.setGeometry(QtCore.QRect(70, 60, 81, 17))\n        self.CB_01_01_Reverse.setFont(self.fontGlobal_08)          # Windows Linux\n        self.CB_01_01_Reverse.setObjectName(_fromUtf8(\"CB_01_01_Reverse\"))\n        self.CB_01_01_Reverse.setEnabled(False)\n        self.CB_01_01_Reverse.setToolTip(\"Force reverse coordinates\") \n        self.CB_01_01_Reverse.clicked.connect(self.on_CB_01_01_Reverse_clicked)              # connect on def \"on_CB_01_01_Reverse_clicked\"\n\n        self.Label_04_01 = QtGui.QLabel(self.GBox_00_Configuration)\n        self.Label_04_01.setGeometry(QtCore.QRect(10, 105, 271, 16))\n        self.Label_04_01.setFont(self.fontGlobal_08)          # Windows Linux\n        self.Label_04_01.setObjectName(_fromUtf8(\"Label_04_01\"))\n        self.Label_04_01.setToolTip(\"Give the perimeter of the selection ronded '0.1'\" + \"\\n\"\n                                    \"Parenthesis Give the number points: perimeter / precision\" + \"\\n\"\n                                    \"  (the wire must be selected)\")\n\n        self.DSB_00_01_Precision = QtGui.QDoubleSpinBox(self.GBox_00_Configuration)\n        self.DSB_00_01_Precision.setGeometry(QtCore.QRect(10, 120, 131, 22))\n        self.DSB_00_01_Precision.setFont(self.fontGlobal_08)          # Windows Linux\n        self.DSB_00_01_Precision.setPrefix(_fromUtf8(\"\"))\n        self.DSB_00_01_Precision.setDecimals(5)\n        self.DSB_00_01_Precision.setMinimum(0.00001)\n        self.DSB_00_01_Precision.setMaximum(99999.99999)\n        self.DSB_00_01_Precision.setValue(1.0)\n        self.DSB_00_01_Precision.setObjectName(_fromUtf8(\"DSB_00_01_Precision\"))\n        self.DSB_00_01_Precision.setToolTip(\"Give the precision desidered\")\n#        self.DSB_00_01_Precision.valueChanged.connect(self.on_DSB_00_01_Precision_valueChanged)        # connect on def \"on_DSB_00_01_Precision_valueChanged\"\n        self.DSB_00_01_Precision.valueChanged[float].connect(self.on_DSB_00_01_Precision_valueChanged) # connect on def \"on_DSB_00_01_Precision_valueChanged\"\n\n        self.GBox_02_Type_Line = QtGui.QGroupBox(self.GBox_00_Configuration)\n        self.GBox_02_Type_Line.setGeometry(QtCore.QRect(150, 20, 131, 121))\n        self.GBox_02_Type_Line.setFont(self.fontGlobal_08)          # Windows Linux\n        self.GBox_02_Type_Line.setCheckable(True)\n        self.GBox_02_Type_Line.setObjectName(_fromUtf8(\"GBox_02_Type_Line\"))\n        self.GBox_02_Type_Line.setToolTip(\"If the checkBox Type Line is unchecked\" + \"\\n\"\n                                          \"you created one point cloud with the coordinates\" + \"\\n\"\n                                          \"Disponible Point cloud and Points\")\n        self.GBox_02_Type_Line.clicked.connect(self.on_GBox_02_Type_Line_clicked)            # connect on def \"on_GBox_02_Type_Line_clicked:\"\n\n        self.RB_02_01_MakeWire = QtGui.QRadioButton(self.GBox_02_Type_Line)\n        self.RB_02_01_MakeWire.setGeometry(QtCore.QRect(10, 20, 82, 17))\n        self.RB_02_01_MakeWire.setFont(self.fontGlobal_08)          # Windows Linux\n        self.RB_02_01_MakeWire.setChecked(True)\n        self.RB_02_01_MakeWire.setObjectName(_fromUtf8(\"RB_02_01_MakeWire\"))\n        self.RB_02_01_MakeWire.setToolTip(\"Create wires\")\n        self.RB_02_01_MakeWire.clicked.connect(self.on_RB_02_01_MakeWire_clicked)            # connect on def \"on_RB_02_01_MakeWire_clicked:\"\n\n        self.RB_02_02_BSpline = QtGui.QRadioButton(self.GBox_02_Type_Line)\n        self.RB_02_02_BSpline.setGeometry(QtCore.QRect(10, 40, 82, 17))\n        self.RB_02_02_BSpline.setFont(self.fontGlobal_08)          # Windows Linux\n        self.RB_02_02_BSpline.setObjectName(_fromUtf8(\"RB_02_02_BSpline\"))\n        self.RB_02_02_BSpline.setToolTip(\"Create BSpline\")\n        self.RB_02_02_BSpline.clicked.connect(self.on_RB_02_02_BSpline_clicked)              # connect on def \"on_RB_02_02_BSpline_clicked:\"\n\n        self.RB_02_03_BSplineCurve = QtGui.QRadioButton(self.GBox_02_Type_Line)\n        self.RB_02_03_BSplineCurve.setGeometry(QtCore.QRect(10, 60, 91, 17))\n        self.RB_02_03_BSplineCurve.setFont(self.fontGlobal_08)          # Windows Linux\n        self.RB_02_03_BSplineCurve.setObjectName(_fromUtf8(\"RB_02_03_BSplineCurve\"))\n        self.RB_02_03_BSplineCurve.setToolTip(\"Create BSplineCurve\")\n        self.RB_02_03_BSplineCurve.clicked.connect(self.on_RB_02_03_BSplineCurve_clicked)    # connect on def \"on_RB_02_03_BSplineCurve_clicked:\"\n\n        self.CB_02_01_Arc = QtGui.QCheckBox(self.GBox_02_Type_Line)\n        self.CB_02_01_Arc.setGeometry(QtCore.QRect(95, 60, 70, 17))\n        self.CB_02_01_Arc.setFont(self.fontGlobal_08)          # Windows Linux\n        self.CB_02_01_Arc.setEnabled(False)\n        self.CB_02_01_Arc.setChecked(False)\n        self.CB_02_01_Arc.setObjectName(_fromUtf8(\"CB_02_01_Arc\"))\n        self.CB_02_01_Arc.setToolTip(\"Create BSplineCurve Arc\")\n        self.CB_02_01_Arc.clicked.connect(self.on_CB_02_01_Arc_clicked)                      # connect on def \"on_CB_02_01_Arc_clicked\"\n\n        self.RB_02_04_MakePolygon = QtGui.QRadioButton(self.GBox_02_Type_Line)\n#        self.RB_02_04_MakePolygon.setEnabled(False)\n        self.RB_02_04_MakePolygon.setGeometry(QtCore.QRect(10, 80, 111, 17))\n        self.RB_02_04_MakePolygon.setFont(self.fontGlobal_08)          # Windows Linux\n        self.RB_02_04_MakePolygon.setObjectName(_fromUtf8(\"RB_02_04_MakePolygon\"))\n        self.RB_02_04_MakePolygon.setToolTip(\"Create Polygon\")\n        self.RB_02_04_MakePolygon.clicked.connect(self.on_RB_02_04_MakePolygon_clicked)      # connect on def \"on_RB_02_04_MakePolygon_clicked:\"\n\n        self.RB_02_05_MakeBezCurve = QtGui.QRadioButton(self.GBox_02_Type_Line)\n        self.RB_02_05_MakeBezCurve.setGeometry(QtCore.QRect(10, 100, 82, 17))\n        self.RB_02_05_MakeBezCurve.setFont(self.fontGlobal_08)          # Windows Linux\n        self.RB_02_05_MakeBezCurve.setObjectName(_fromUtf8(\"RB_02_05_MakeBezCurve\"))\n        self.RB_02_05_MakeBezCurve.setToolTip(\"Create BezCurve\")\n        self.RB_02_05_MakeBezCurve.clicked.connect(self.on_RB_02_05_MakeBezCurve_clicked)    # connect on def \"on_RB_02_05_MakeBezCurve_clicked:\"\n\n\n        self.GBox_03_Options = QtGui.QGroupBox(self.GBox_00_Configuration)\n        self.GBox_03_Options.setGeometry(QtCore.QRect(10, 150, 131, 81))\n        self.GBox_03_Options.setFont(self.fontGlobal_08)          # Windows Linux\n        self.GBox_03_Options.setObjectName(_fromUtf8(\"GBox_03_Options\"))\n\n        self.CB_03_01_Close = QtGui.QCheckBox(self.GBox_03_Options)\n        self.CB_03_01_Close.setGeometry(QtCore.QRect(10, 20, 51, 17))\n        self.CB_03_01_Close.setFont(self.fontGlobal_08)          # Windows Linux\n        self.CB_03_01_Close.setObjectName(_fromUtf8(\"CB_03_01_Close\"))\n        self.CB_03_01_Close.setToolTip(\"Close the wire (if possible)\")\n        self.CB_03_01_Close.clicked.connect(self.on_CB_03_01_Close_clicked)                  # connect on def \"on_CB_03_01_Close_clicked\"\n\n        self.CB_03_01a_To_Mouse = QtGui.QCheckBox(self.GBox_03_Options)\n        self.CB_03_01a_To_Mouse.setGeometry(QtCore.QRect(10, 20, 81, 17))\n        self.CB_03_01a_To_Mouse.setVisible(False)\n        self.CB_03_01a_To_Mouse.setFont(self.fontGlobal_08)          # Windows Linux\n        self.CB_03_01a_To_Mouse.setObjectName(_fromUtf8(\"CB_03_01a_To_Mouse\"))\n        self.CB_03_01a_To_Mouse.setToolTip(\"Save the coordinate to point selected\" + \"\\n\"\n                                          \"The coordinates saved are the coordinates on menu 'Save coordinates'\" + \"\\n\"\n                                          \"The point selected (and saved) is marked hidden\" + \"\\n\"\n                                          \"the points are restitute visible of the end function\")\n        self.CB_03_01a_To_Mouse.clicked.connect(self.on_CB_03_01a_To_Mouse_clicked)            # connect on def \"on_CB_03_01_Close_clicked\"\n\n        self.CB_03_01b_CloseFo = QtGui.QCheckBox(self.GBox_03_Options)\n        self.CB_03_01b_CloseFo.setGeometry(QtCore.QRect(69, 20, 61, 17))\n        self.CB_03_01b_CloseFo.setFont(self.fontGlobal_08)          # Windows Linux\n        self.CB_03_01b_CloseFo.setObjectName(_fromUtf8(\"CB_03_01b_CloseFo\"))\n        self.CB_03_01b_CloseFo.setToolTip(\"Force close wire\" + \"\\n\"\n                                          \"The coordinate [first] is adding in [latest] coordinate\")\n        self.CB_03_01b_CloseFo.clicked.connect(self.on_CB_03_01_Close_clicked)               # connect on def \"on_CB_03_01_Close_clicked\"\n\n        self.CB_03_02_Create_Face = QtGui.QCheckBox(self.GBox_03_Options)\n        self.CB_03_02_Create_Face.setGeometry(QtCore.QRect(10, 40, 101, 17))\n        self.CB_03_02_Create_Face.setFont(self.fontGlobal_08)          # Windows Linux\n        self.CB_03_02_Create_Face.setObjectName(_fromUtf8(\"CB_03_02_Create_Face\"))\n        self.CB_03_02_Create_Face.setToolTip(\"Create face (if possible)\")\n        self.CB_03_02_Create_Face.clicked.connect(self.on_CB_03_02_Create_Face_clicked)      # connect on def \"on_CB_03_02_Create_Face_clicked\"\n\n        self.CB_03_02b_Create_Cloud = QtGui.QCheckBox(self.GBox_03_Options)\n        self.CB_03_02b_Create_Cloud.setVisible(False)\n        self.CB_03_02b_Create_Cloud.setGeometry(QtCore.QRect(10, 40, 111, 17))\n        self.CB_03_02b_Create_Cloud.setFont(self.fontGlobal_08)          # Windows Linux\n        self.CB_03_02b_Create_Cloud.setObjectName(_fromUtf8(\"CB_03_02b_Create_Cloud\"))\n        self.CB_03_02b_Create_Cloud.setToolTip(\"Create cloud\")\n        self.CB_03_02b_Create_Cloud.clicked.connect(self.on_CB_03_02b_Create_Cloud_clicked)  # connect on def \"on_CB_03_02b_Create_Cloud_clicked\"\n\n        self.CB_03_02bb_Create_Shell = QtGui.QCheckBox(self.GBox_03_Options)\n        self.CB_03_02bb_Create_Shell.setVisible(False)\n        self.CB_03_02bb_Create_Shell.setGeometry(QtCore.QRect(85, 40, 46, 17))\n        self.CB_03_02bb_Create_Shell.setFont(self.fontGlobal_08)          # Windows Linux\n        self.CB_03_02bb_Create_Shell.setObjectName(_fromUtf8(\"CB_03_02bb_Create_Shell\"))\n        self.CB_03_02bb_Create_Shell.setToolTip(\"Create shell with the cloud\")\n        self.CB_03_02bb_Create_Shell.clicked.connect(self.on_CB_03_02bb_Create_Shell_clicked)  # connect on def \"on_CB_03_02bb_Create_Shell_clicked\"\n\n        self.CB_03_03_Create_Points = QtGui.QCheckBox(self.GBox_03_Options)\n        self.CB_03_03_Create_Points.setGeometry(QtCore.QRect(10, 60, 101, 17))\n        self.CB_03_03_Create_Points.setFont(self.fontGlobal_08)          # Windows Linux\n        self.CB_03_03_Create_Points.setObjectName(_fromUtf8(\"CB_03_03_Create_Points\"))\n        self.CB_03_03_Create_Points.setToolTip(\"Create coordinates points in the 3D view\")\n        self.CB_03_03_Create_Points.clicked.connect(self.on_CB_03_03_Create_Points_clicked)  # connect on def \"on_CB_03_03_Create_Points_clicked\"\n\n        self.PB_00_Mouse_Mode = QtGui.QPushButton(self.centralwidget)\n        self.PB_00_Mouse_Mode.setGeometry(QtCore.QRect(20, 180, 131, 61))\n        self.PB_00_Mouse_Mode.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_00_Mouse_Mode.setVisible(False)\n        self.PB_00_Mouse_Mode.setStyleSheet(\"color : #008500\")                                # Color text\n        self.PB_00_Mouse_Mode.setObjectName(_fromUtf8(\"PB_00_Mouse_Mode\"))\n        self.PB_00_Mouse_Mode.setToolTip(\"Click to quit the mouse Mode\")\n        self.PB_00_Mouse_Mode.clicked.connect(self.on_PB_00_Mouse_Mode_clicked)               # connect on def \"on_PB_00_Mouse_Mode_clicked\"\n\n        self.GBox_04_Coordinates = QtGui.QGroupBox(self.GBox_00_Configuration)\n        self.GBox_04_Coordinates.setGeometry(QtCore.QRect(149, 150, 131, 81))\n        self.GBox_04_Coordinates.setFont(self.fontGlobal_08)          # Windows Linux\n        self.GBox_04_Coordinates.setObjectName(_fromUtf8(\"GBox_04_Coordinates\"))\n\n        self.RB_04_01_XYZ = QtGui.QRadioButton(self.GBox_04_Coordinates)\n        self.RB_04_01_XYZ.setGeometry(QtCore.QRect(10, 20, 51, 17))\n        self.RB_04_01_XYZ.setFont(self.fontGlobal_08)          # Windows Linux\n        self.RB_04_01_XYZ.setChecked(True)\n        self.RB_04_01_XYZ.setObjectName(_fromUtf8(\"RB_04_01_XYZ\")) \n        self.RB_04_01_XYZ.setToolTip(\"Save the coordinates X Y Z\")\n        self.RB_04_01_XYZ.clicked.connect(self.on_RB_04_01_XYZ_clicked)                       # connect on def \"on_RB_04_01_XYZ_clicked:\"\n\n        self.RB_04_02_XY = QtGui.QRadioButton(self.GBox_04_Coordinates)\n        self.RB_04_02_XY.setGeometry(QtCore.QRect(10, 40, 51, 17))\n        self.RB_04_02_XY.setFont(self.fontGlobal_08)          # Windows Linux\n        self.RB_04_02_XY.setObjectName(_fromUtf8(\"RB_04_02_XY\"))\n        self.RB_04_02_XY.setToolTip(\"Save the coordinates X Y\")\n        self.RB_04_02_XY.clicked.connect(self.on_RB_04_02_XY_clicked)                         # connect on def \"on_RB_04_02_XY_clicked:\"\n\n        self.RB_04_03_YZ = QtGui.QRadioButton(self.GBox_04_Coordinates)\n        self.RB_04_03_YZ.setGeometry(QtCore.QRect(10, 60, 51, 17))\n        self.RB_04_03_YZ.setFont(self.fontGlobal_08)          # Windows Linux\n        self.RB_04_03_YZ.setObjectName(_fromUtf8(\"RB_04_03_YZ\"))\n        self.RB_04_03_YZ.setToolTip(\"Save the coordinates Y Z\")\n        self.RB_04_03_YZ.clicked.connect(self.on_RB_04_03_YZ_clicked)                         # connect on def \"on_RB_04_03_YZ_clicked:\"\n\n        self.RB_04_04_XZ = QtGui.QRadioButton(self.GBox_04_Coordinates)\n        self.RB_04_04_XZ.setGeometry(QtCore.QRect(70, 40, 51, 17))\n        self.RB_04_04_XZ.setFont(self.fontGlobal_08)          # Windows Linux\n        self.RB_04_04_XZ.setObjectName(_fromUtf8(\"RB_04_04_XZ\"))\n        self.RB_04_04_XZ.setToolTip(\"Save the coordinates X Z\")\n        self.RB_04_04_XZ.clicked.connect(self.on_RB_04_04_XZ_clicked)                         # connect on def \"on_RB_04_04_XZ_clicked:\"\n\n        self.CB_04_01_Zero = QtGui.QCheckBox(self.GBox_04_Coordinates)\n        self.CB_04_01_Zero.setGeometry(QtCore.QRect(70, 60, 61, 17))\n        self.CB_04_01_Zero.setFont(self.fontGlobal_08)          # Windows Linux\n        self.CB_04_01_Zero.setChecked(False)\n        self.CB_04_01_Zero.setEnabled(False)\n        self.CB_04_01_Zero.setObjectName(_fromUtf8(\"CB_04_01_Zero\"))\n        self.CB_04_01_Zero.setToolTip(\"Save the coordinates slected for make 3 coordinates\"+\"\\n\"\n                                      \"Example :\"+\"\\n\"\n                                      \"XY = X Y 0.0\"+\"\\n\"\n                                      \"XZ = X 0.0 Z\"+\"\\n\"\n                                      \"YZ = 0.0 Y Z\")\n        self.CB_04_01_Zero.clicked.connect(self.on_CB_04_01_Zero_clicked)                     # connect on def \"on_CB_04_01_Zero_clicked:\"\n\n        self.CB_04_02_Coma = QtGui.QCheckBox(self.GBox_04_Coordinates)\n        self.CB_04_02_Coma.setGeometry(QtCore.QRect(70, 20, 56, 18))\n        self.CB_04_02_Coma.setFont(self.fontGlobal_08)          # Windows Linux\n        self.CB_04_02_Coma.setChecked(False)\n        self.CB_04_02_Coma.setObjectName(_fromUtf8(\"CB_04_01_Zero\"))\n        self.CB_04_02_Coma.setToolTip(\"Save the coordinates with coma separator\" + \"\\n\"\n                                      \"If this option is activated (colored green)\" + \"\\n\"\n                                      \"the data is saved only with the Save button\" + \"\\n\"\n                                      \"If the coma is detected in open file\" + \"\\n\"\n                                      \"the button is automatically colored in green\" + \"\\n\"\n                                      \"Example : X, Y, Z\")\n        self.CB_04_02_Coma.clicked.connect(self.on_CB_04_02_Coma_clicked)                     # connect on def \"on_CB_04_01_Zero_clicked:\"\n\n        self.GBox_05_Data_Wire_Gui = QtGui.QGroupBox(self.centralwidget)\n        self.GBox_05_Data_Wire_Gui.setGeometry(QtCore.QRect(10, 260, 291, 241))\n        self.GBox_05_Data_Wire_Gui.setFont(self.fontGlobal_08)          # Windows Linux\n        self.GBox_05_Data_Wire_Gui.setObjectName(_fromUtf8(\"GBox_05_Data_Wire_Gui\"))\n        self.GBox_05_Data_Wire_Gui.setToolTip(\"This section work with the wire creation\"+\"\\n\"\n                                              \"The idea is : save the coordinates of wires in one temporary file for create a wire unique\"+\"\\n\"\n                                              \"The direction of coordinates can be reversed added and saved in the file\"+\"\\n\"\n                                              \"The read file give one object unique with the selected type line\")\n\n        self.PB_05_01_Wire_For_Test = QtGui.QPushButton(self.GBox_05_Data_Wire_Gui)\n        self.PB_05_01_Wire_For_Test.setGeometry(QtCore.QRect(10, 150, 84, 23))\n        self.PB_05_01_Wire_For_Test.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_05_01_Wire_For_Test.setObjectName(_fromUtf8(\"PB_05_01_Wire_For_Test\"))\n        self.PB_05_01_Wire_For_Test.setToolTip(\"Create the forme with the type line checked   \"+\"\\n\"\n                                               \"The direction of the line is displayed Begin...End   \"+\"\\n\"\n                                               \"The line type is displayed of the button   \"+\"\\n\")\n        self.PB_05_01_Wire_For_Test.clicked.connect(self.on_PB_05_01_Wire_For_Test_clicked)    # connect on def \"on_PB_05_01_Wire_For_Test_clicked\"\n\n        self.Label_05_01_Data = QtGui.QLabel(self.GBox_05_Data_Wire_Gui)\n        self.Label_05_01_Data.setGeometry(QtCore.QRect(10, 110, 271, 16))\n        self.Label_05_01_Data.setFont(self.fontGlobal_08)          # Windows Linux\n        self.Label_05_01_Data.setObjectName(_fromUtf8(\"Label_05_01_Data\"))\n\n        self.PB_05_03_Reuse = QtGui.QPushButton(self.GBox_05_Data_Wire_Gui)\n        self.PB_05_03_Reuse.setGeometry(QtCore.QRect(104, 150, 84, 23))\n        self.PB_05_03_Reuse.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_05_03_Reuse.setObjectName(_fromUtf8(\"PB_05_03_Reuse\"))\n        self.PB_05_03_Reuse.setToolTip(\"Reuse the data in memory\"+\"\\n\"\n                                       \"Reuse work with the type line selected\")\n        self.PB_05_03_Reuse.clicked.connect(self.on_PB_05_03_Reuse_clicked)                    # connect on def \"on_PB_05_03_Reuse_clicked\"\n\n        self.PB_05_02_Reset_Data = QtGui.QPushButton(self.GBox_05_Data_Wire_Gui)\n        self.PB_05_02_Reset_Data.setGeometry(QtCore.QRect(198, 150, 84, 23))\n        self.PB_05_02_Reset_Data.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_05_02_Reset_Data.setObjectName(_fromUtf8(\"PB_05_02_Reset_Data\"))\n        self.PB_05_02_Reset_Data.setToolTip(\"Reset the data in memory\")\n        self.PB_05_02_Reset_Data.clicked.connect(self.on_PB_05_02_Reset_Data_clicked)          # connect on def \"on_PB_05_02_Reset_Data_clicked\"\n\n        self.PB_05_04_ClearTE = QtGui.QPushButton(self.GBox_05_Data_Wire_Gui)\n        self.PB_05_04_ClearTE.setGeometry(QtCore.QRect(10, 210, 61, 23))\n        self.PB_05_04_ClearTE.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_05_04_ClearTE.setObjectName(_fromUtf8(\"PB_05_04_ClearTE\"))\n        self.PB_05_04_ClearTE.setToolTip(\"Clean the window list data textEdit\")\n        self.PB_05_04_ClearTE.clicked.connect(self.on_PB_05_04_ClearTE_clicked)                # connect on def \"on_PB_05_04_ClearTE_clicked\"\n     \n        self.PB_05_04b_Zoom = QtGui.QPushButton(self.GBox_05_Data_Wire_Gui)\n        self.PB_05_04b_Zoom.setGeometry(QtCore.QRect(76, 210, 18, 23))\n        self.PB_05_04b_Zoom.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_05_04b_Zoom.setObjectName(_fromUtf8(\"PB_05_04b_Zoom\"))\n        self.PB_05_04b_Zoom.setToolTip(\"Zoom the window list data textEdit\")\n        self.PB_05_04b_Zoom.clicked.connect(self.on_PB_05_04b_Zoom_clicked)                # connect on def \"on_PB_05_04b_Zoom_clicked\"\n     \n        self.PB_05_05_ClearRView = QtGui.QPushButton(self.GBox_05_Data_Wire_Gui)\n        self.PB_05_05_ClearRView.setGeometry(QtCore.QRect(104, 210, 84, 23))\n        self.PB_05_05_ClearRView.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_05_05_ClearRView.setObjectName(_fromUtf8(\"PB_05_05_ClearRView\"))\n        self.PB_05_05_ClearRView.setToolTip(\"Clean the window Report view\")\n        self.PB_05_05_ClearRView.clicked.connect(self.on_PB_05_05_ClearRView_clicked)          # connect on def \"on_PB_05_05_ClearRView_clicked\"\n\n        self.PB_05_06_Del_Line = QtGui.QPushButton(self.GBox_05_Data_Wire_Gui)\n        self.PB_05_06_Del_Line.setGeometry(QtCore.QRect(198, 180, 84, 23))    #198, 210, 84, 23\n        self.PB_05_06_Del_Line.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_05_06_Del_Line.setObjectName(_fromUtf8(\"PB_05_06_Del_Line\"))\n        self.PB_05_06_Del_Line.setToolTip(\"Delete the last line created (object)\")\n        self.PB_05_06_Del_Line.clicked.connect(self.on_PB_05_06_Del_Line_clicked)              # connect on def \"on_PB_05_03_Reuse_clicked\"\n\n        self.PB_05_07_Test_Sweep = QtGui.QPushButton(self.GBox_05_Data_Wire_Gui)\n        self.PB_05_07_Test_Sweep.setGeometry(QtCore.QRect(10, 180, 71, 23))\n        self.PB_05_07_Test_Sweep.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_05_07_Test_Sweep.setObjectName(_fromUtf8(\"PB_05_07_Test_Sweep\"))\n        self.PB_05_07_Test_Sweep.setToolTip(\"Create sweep for testing\")\n        self.PB_05_07_Test_Sweep.clicked.connect(self.on_PB_05_07_Test_Sweep_clicked)          # connect on def \"on_PB_05_07_Test_Sweep_clicked\"\n\n        self.PB_05_08_Recompute = QtGui.QPushButton(self.GBox_05_Data_Wire_Gui)\n        self.PB_05_08_Recompute.setGeometry(QtCore.QRect(198, 210, 84, 23))    #198, 180, 84, 23\n        self.PB_05_08_Recompute.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_05_08_Recompute.setObjectName(_fromUtf8(\"PB_05_08_Recompute\"))\n        self.PB_05_08_Recompute.setToolTip(\"recompute the 3D view\")\n        self.PB_05_08_Recompute.clicked.connect(self.on_PB_05_08_Recompute_clicked)            # connect on def \"on_PB_05_08_Recompute_clicked\"\n\n        self.TE_05_01_textEdit = QtGui.QTextEdit(self.GBox_05_Data_Wire_Gui)\n        self.TE_05_01_textEdit.setGeometry(QtCore.QRect(10, 20, 271, 81))\n        self.TE_05_01_textEdit.setFont(self.fontGlobal_08)          # Windows Linux\n        self.TE_05_01_textEdit.setToolTip(\"display the last operation\")\n        self.TE_05_01_textEdit.setObjectName(_fromUtf8(\"TE_05_01_textEdit\"))\n\n        self.PBar_05_01_ProgressBar = QtGui.QProgressBar(self.GBox_05_Data_Wire_Gui)\n        self.PBar_05_01_ProgressBar.setGeometry(QtCore.QRect(10, 130, 270, 16))\n        self.PBar_05_01_ProgressBar.setToolTip(_fromUtf8(\"\"))\n#        self.PBar_05_01_ProgressBar.setLayoutDirection(QtCore.Qt.LeftToRight)\n        self.PBar_05_01_ProgressBar.setAlignment(QtCore.Qt.AlignCenter)\n        self.PBar_05_01_ProgressBar.setMinimum(0)\n        self.PBar_05_01_ProgressBar.setValue(0)\n#        self.PBar_05_01_ProgressBar.setTextVisible(True)\n        self.PBar_05_01_ProgressBar.setOrientation(QtCore.Qt.Horizontal)\n        self.PBar_05_01_ProgressBar.setObjectName(_fromUtf8(\"PBar_05_01_ProgressBar\"))\n\n        self.SP_05_01_Dia_Circle = QtGui.QSpinBox(self.GBox_05_Data_Wire_Gui)\n        self.SP_05_01_Dia_Circle.setGeometry(QtCore.QRect(90, 180, 42, 22))\n        self.SP_05_01_Dia_Circle.setFont(self.fontGlobal_08)          # Windows Linux\n        self.SP_05_01_Dia_Circle.setValue(diamCircle)\n        self.SP_05_01_Dia_Circle.setSuffix(\" r\")\n        self.SP_05_01_Dia_Circle.setMinimum(1)\n        self.SP_05_01_Dia_Circle.setMaximum(99999)\n        self.SP_05_01_Dia_Circle.setObjectName(_fromUtf8(\"SP_05_01_Dia_Circle\"))\n        self.SP_05_01_Dia_Circle.valueChanged.connect(self.on_SP_05_01_Dia_Circle_valueChanged)            # connect on def \"on_SP_05_01_Dia_Circle_valueChanged\"\n\n        self.CB_05_01_Solid = QtGui.QCheckBox(self.GBox_05_Data_Wire_Gui)\n        self.CB_05_01_Solid.setGeometry(QtCore.QRect(140, 176, 51, 17))\n        self.CB_05_01_Solid.setFont(self.fontGlobal_08)          # Windows Linux\n        self.CB_05_01_Solid.setChecked(True)\n        self.CB_05_01_Solid.setObjectName(_fromUtf8(\"CB_05_01_Solid\"))\n        self.CB_05_01_Solid.setToolTip(\"Create solid sweep to see if the sweep is rigth\")\n        self.CB_05_01_Solid.clicked.connect(self.on_CB_05_01_Solid_clicked)                    # connect on \"def on_CB_05_01_Solid_clicked:\"\n\n        self.CB_05_02_Frenet = QtGui.QCheckBox(self.GBox_05_Data_Wire_Gui)\n        self.CB_05_02_Frenet.setGeometry(QtCore.QRect(140, 190, 51, 17))\n        self.CB_05_02_Frenet.setFont(self.fontGlobal_08)          # Windows Linux\n        self.CB_05_02_Frenet.setChecked(True)\n        self.CB_05_02_Frenet.setObjectName(_fromUtf8(\"CB_05_02_Frenet\"))\n        self.CB_05_02_Frenet.setToolTip(\"Create frenet sweep\")\n        self.CB_05_02_Frenet.clicked.connect(self.on_CB_05_02_Frenet_clicked)                  # connect on def \"on_CB_05_02_Frenet_clicked:\"\n\n        self.GBox_06_Data_File = QtGui.QGroupBox(self.centralwidget)\n        self.GBox_06_Data_File.setGeometry(QtCore.QRect(10, 510, 291, 51))\n        self.GBox_06_Data_File.setFont(self.fontGlobal_08)          # Windows Linux\n        self.GBox_06_Data_File.setObjectName(_fromUtf8(\"GBox_06_Data_File\"))\n        self.GBox_06_Data_File.setToolTip(\"This section save the coordinate of wire in the temporary file\")\n\n        self.PB_06_01_Save_Data_File = QtGui.QPushButton(self.GBox_06_Data_File)\n        self.PB_06_01_Save_Data_File.setGeometry(QtCore.QRect(10, 20, 51, 23))\n        self.PB_06_01_Save_Data_File.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_06_01_Save_Data_File.setObjectName(_fromUtf8(\"PB_06_01_Save_Data_File\"))\n        self.PB_06_01_Save_Data_File.setToolTip(\"Save the coordinates in the temporary file\")\n        self.PB_06_01_Save_Data_File.clicked.connect(self.on_PB_06_01_Save_Data_File_clicked)      # connect on def \"on_PB_06_01_Save_Data_File_clicked\"\n\n        self.CB_06_01_Contigu_Data = QtGui.QCheckBox(self.GBox_06_Data_File)\n        self.CB_06_01_Contigu_Data.setGeometry(QtCore.QRect(65, 25, 51, 17))\n        self.CB_06_01_Contigu_Data.setFont(self.fontGlobal_08)          # Windows Linux\n        self.CB_06_01_Contigu_Data.setChecked(False)\n        self.CB_06_01_Contigu_Data.setObjectName(_fromUtf8(\"CB_06_01_Contigu_Data\"))\n        self.CB_06_01_Contigu_Data.setToolTip(\"If the second wire selected is contiguous\" + \"\\n\"\n                                              \"check this checkbox for delette the first coordinate\" + \"\\n\"\n                                              \" not create two coordinate with the same value\")\n#        self.CB_06_01_Contigu_Data.clicked.connect(self.on_CB_06_01_Contigu_Data_clicked)                    # connect on \"def on_CB_05_01_Solid_clicked:\"\n\n        self.PB_06_02_Read_Data_File = QtGui.QPushButton(self.GBox_06_Data_File)\n        self.PB_06_02_Read_Data_File.setGeometry(QtCore.QRect(115, 20, 51, 23))\n        self.PB_06_02_Read_Data_File.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_06_02_Read_Data_File.setObjectName(_fromUtf8(\"PB_06_02_Read_Data_File\"))\n        self.PB_06_02_Read_Data_File.setToolTip(\"Read the coordinates saved in the temporary file\")\n        self.PB_06_02_Read_Data_File.clicked.connect(self.on_PB_06_02_Read_Data_File_clicked)  # connect on def \"PB_06_02_Read_Data_File\"\n\n        self.SP_06_01_Step = QtGui.QSpinBox(self.GBox_06_Data_File)\n        self.SP_06_01_Step.setGeometry(QtCore.QRect(174, 20, 51, 22))\n        self.SP_06_01_Step.setFont(self.fontGlobal_08)          # Windows Linux\n        self.SP_06_01_Step.setMinimum(1)\n        self.SP_06_01_Step.setMaximum(9999)\n        self.SP_06_01_Step.setObjectName(_fromUtf8(\"SP_06_01_Step\"))\n        self.SP_06_01_Step.setToolTip(\"Step in read the coordinates\")\n        self.SP_06_01_Step.valueChanged.connect(self.on_SP_06_01_Step_valueChanged)            # connect on def \"on_doubleSpinBox_2_valueChanged\"\n\n        self.PB_06_03_Reset_Data_File = QtGui.QPushButton(self.GBox_06_Data_File)\n        self.PB_06_03_Reset_Data_File.setGeometry(QtCore.QRect(232, 20, 51, 23))\n        self.PB_06_03_Reset_Data_File.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_06_03_Reset_Data_File.setObjectName(_fromUtf8(\"PB_06_03_Reset_Data_File\"))\n        self.PB_06_03_Reset_Data_File.setToolTip(\"Reset the coordinates in the temporary file\")\n        self.PB_06_03_Reset_Data_File.clicked.connect(self.on_PB_06_03_Reset_Data_File_clicked)          # connect on def \"on_PB_06_03_Reset_Data_File_clicked\"\n\n        self.GBox_07_Button = QtGui.QGroupBox(self.centralwidget)\n        self.GBox_07_Button.setGeometry(QtCore.QRect(10, 575, 291, 71))\n        self.GBox_07_Button.setFont(self.fontGlobal_08)          # Windows Linux\n        self.GBox_07_Button.setObjectName(_fromUtf8(\"GBox_07_Button\"))\n\n        self.PB_01_Save = QtGui.QPushButton(self.GBox_07_Button)\n        self.PB_01_Save.setGeometry(QtCore.QRect(10, 10, 40, 23))\n        self.PB_01_Save.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_01_Save.setObjectName(_fromUtf8(\"PB_01_Save\"))\n        self.PB_01_Save.setToolTip(\"Save the coordinates\" + \"\\n\"\n                                   \"(Save the temporary file 'FCDataTest_XYZ' if exist)\" + \"\\n\"\n                                   \"Create Wire, Bspline, Point .... for create coordinate in memory\" + \"\\n\"\n                                   \"and save the coordinate with the 'Save DataT' button\" + \"\\n\"\n                                   \"and now push the Save button\")\n        self.PB_01_Save.clicked.connect(self.on_PB_01_Save_clicked)                           # connect on def \"on_PB_01_Save_clicked\"\n\n        self.PB_02_Read = QtGui.QPushButton(self.GBox_07_Button)\n        self.PB_02_Read.setGeometry(QtCore.QRect(57, 10, 40, 23))\n        self.PB_02_Read.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_02_Read.setObjectName(_fromUtf8(\"PB_02_Read\"))\n        self.PB_02_Read.setToolTip(\"Read the file .asc, .pcd, .txt\")\n        self.PB_02_Read.clicked.connect(self.on_PB_02_Read_clicked)                           # connect on def \"on_PB_02_Read_clicked\"\n\n        self.SP_01_suppressBegin = QtGui.QSpinBox(self.GBox_07_Button)\n        self.SP_01_suppressBegin.setGeometry(QtCore.QRect(105, 10, 42, 22))\n        self.SP_01_suppressBegin.setFont(self.fontGlobal_08)          # Windows Linux\n        self.SP_01_suppressBegin.setValue(suppressBegin)\n        self.SP_01_suppressBegin.setSuffix(\" >\")\n        self.SP_01_suppressBegin.setMinimum(0)\n        self.SP_01_suppressBegin.setMaximum(99999)\n        self.SP_01_suppressBegin.setObjectName(_fromUtf8(\"SP_01_suppressBegin\"))\n        self.SP_01_suppressBegin.setToolTip(\"Cut the string of x characters from the left\" + \"\\n\"\n                                            \"Example :\" + \"\\n\"\n                                            \"X12.042769Z1.390658Y0.0000\" + \"\\n\"\n                                            \"X12.045179Z1.390658Y0.0000\" + \"\\n\"\n                                            \"X12.047590Z1.390658Y0.0000\" + \"\\n\"\n                                            \"X12.050000Z1.390658Y0.0000\") #https://forum.freecadweb.org/viewtopic.php?f=3&t=4217&start=100\n        self.SP_01_suppressBegin.valueChanged.connect(self.on_SP_01_suppressBegin_valueChanged)            # connect on def \"on_SP_05_01_Dia_Circle_valueChanged\"\n\n        self.SP_02_suppressEnd = QtGui.QSpinBox(self.GBox_07_Button)\n        self.SP_02_suppressEnd.setGeometry(QtCore.QRect(155, 10, 42, 22))\n        self.SP_02_suppressEnd.setFont(self.fontGlobal_08)          # Windows Linux\n        self.SP_02_suppressEnd.setValue(suppressEnd)\n        self.SP_02_suppressEnd.setSuffix(\" <\")\n        self.SP_02_suppressEnd.setMinimum(0)\n        self.SP_02_suppressEnd.setMaximum(99999)\n        self.SP_02_suppressEnd.setObjectName(_fromUtf8(\"SP_02_suppressEnd\"))\n        self.SP_02_suppressEnd.setToolTip(\"Cut the string of x characters from the rigth\")\n        self.SP_02_suppressEnd.valueChanged.connect(self.on_SP_02_suppressEnd_valueChanged)            # connect on def \"on_SP_05_01_Dia_Circle_valueChanged\"\n\n        self.PB_05_Dowgrade = QtGui.QPushButton(self.GBox_07_Button)\n        self.PB_05_Dowgrade.setGeometry(QtCore.QRect(205, 10, 40, 23))\n        self.PB_05_Dowgrade.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_05_Dowgrade.setObjectName(_fromUtf8(\"PB_05_Dowgrade\"))\n        self.PB_05_Dowgrade.setToolTip(\"Downgrade the object\")\n        self.PB_05_Dowgrade.clicked.connect(self.on_PB_05_Dowgrade_clicked)                          # connect on def \"on_PB_05_Color_clicked\"\n\n        self.PB_03_Reset = QtGui.QPushButton(self.GBox_07_Button)\n        self.PB_03_Reset.setGeometry(QtCore.QRect(10, 40, 40, 23))\n        self.PB_03_Reset.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_03_Reset.setObjectName(_fromUtf8(\"PB_03_Reset\"))\n        self.PB_03_Reset.setToolTip(\"Reset the macro\")\n        self.PB_03_Reset.clicked.connect(self.on_PB_03_Reset_clicked)                          # connect on def \"on_PB_03_Reset_clicked\"\n\n        self.PB_04_Color = QtGui.QPushButton(self.GBox_07_Button)\n        self.PB_04_Color.setGeometry(QtCore.QRect(57, 40, 40, 23))\n        self.PB_04_Color.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_04_Color.setObjectName(_fromUtf8(\"PB_04_Color\"))\n        self.PB_04_Color.setToolTip(\"Color of object\")\n        self.PB_04_Color.clicked.connect(self.on_PB_04_Color_clicked)                          # connect on def \"on_PB_05_Color_clicked\"\n\n        self.PB_07_Duplicate = QtGui.QPushButton(self.GBox_07_Button)\n        self.PB_07_Duplicate.setGeometry(QtCore.QRect(105, 40, 40, 23))\n        self.PB_07_Duplicate.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_07_Duplicate.setObjectName(_fromUtf8(\"PB_07_Duplicate\"))\n        self.PB_07_Duplicate.setToolTip(\"Duplicate the edge(s)/face(s) selected\")\n        self.PB_07_Duplicate.clicked.connect(self.on_PB_07_Duplicate_clicked)                          # connect on def \"on_PB_05_Color_clicked\"\n\n        self.PB_06_Quit = QtGui.QPushButton(self.GBox_07_Button)\n        self.PB_06_Quit.setGeometry(QtCore.QRect(205, 40, 40, 23))\n        self.PB_06_Quit.setFont(self.fontGlobal_08)          # Windows Linux\n        self.PB_06_Quit.setObjectName(_fromUtf8(\"PB_06_Quit\"))\n        self.PB_06_Quit.setToolTip(\"\\n\"+\"Quit the macro\"+\"\\n\"\n                                   \"A window open and asks if you want to keep the file\" + \"\\n\"\n                                   \"If you wild save the temporary file, give a name and validate\")\n        self.PB_06_Quit.clicked.connect(self.on_PB_06_Quit_clicked)                            # connect on def \"on_PB_04_Quit_clicked\"\n\n        self.CB_00_Verbose = QtGui.QCheckBox(self.GBox_07_Button)\n        self.CB_00_Verbose.setGeometry(QtCore.QRect(260, 10, 13, 17))\n        self.CB_00_Verbose.setFont(self.fontGlobal_08)          # Windows Linux\n        self.CB_00_Verbose.setChecked(True)\n        self.CB_00_Verbose.setObjectName(_fromUtf8(\"CB_00_Verbose\"))\n        self.CB_00_Verbose.setToolTip(\"Create lines with defaut color\")\n        self.CB_00_Verbose.clicked.connect(self.on_CB_00_Verbose_clicked)                      # connect on def \"on_CB_00_Verbose_clicked\"\n\n        MainWindow.setCentralWidget(self.centralwidget)\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n        MainWindow.setWindowTitle(\"FCDxf to Shape\" + __version__)\n        MainWindow.setWindowIcon(QtGui.QIcon(path + \"Macro_Dxf_to_Shape.png\"))  # change l'icone de la fenetre principale\n        MainWindow.setWindowFlags(Qt.WindowFlags(Qt.WindowMinimizeButtonHint))  # - ( max X )\n        MainWindow.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint)        # PySide cette fonction met la fen\u00eatre en avant\n\n        self.GBox_00_Configuration.setTitle(\"Configuration\")\n        self.DSB_00_01_Precision.setSuffix(\" mm\")\n\n        self.GBox_01_Orientation.setTitle(\"Orientation\")\n        self.RB_01_01_Reversed.setText(\"Reversed\")\n        self.RB_01_02_Forward.setText(\"Forward\")\n        self.RB_01_03_Neutral.setText(\"Neutral\")\n        self.CB_01_01_Reverse.setText(\"Reverse\")\n\n        self.GBox_02_Type_Line.setTitle(\"Type Line\")\n        self.RB_02_01_MakeWire.setText(\"MakeWire\")\n        self.RB_02_02_BSpline.setText(\"BSpline\")\n        self.RB_02_03_BSplineCurve.setText(\"BSplineCurve\")\n        self.RB_02_04_MakePolygon.setText(\"Polygon\")\n        self.RB_02_05_MakeBezCurve.setText(\"BezCurve\")\n        self.CB_02_01_Arc.setText(\"Arc\")\n\n        self.GBox_03_Options.setTitle(\"Options\")\n        self.CB_03_01_Close.setText(\"Close\")\n        self.CB_03_01a_To_Mouse.setText(\"To Mouse\")\n        self.CB_03_01b_CloseFo.setText(\"Forced\")\n        self.CB_03_02_Create_Face.setText(\"Create face\")\n        self.CB_03_02b_Create_Cloud.setText(\"Create Cloud\")\n        self.CB_03_02bb_Create_Shell.setText(\"Shell\")\n        self.CB_03_03_Create_Points.setText(\"Create points\")\n\n        self.GBox_04_Coordinates.setTitle(\"Save coordinates\")\n        self.RB_04_01_XYZ.setText(\"X Y Z\")\n        self.RB_04_02_XY.setText(\"X Y\")\n        self.RB_04_03_YZ.setText(\"Y Z\")\n        self.RB_04_04_XZ.setText(\"X Z\")\n        self.CB_04_01_Zero.setText(\"Zero\")\n        self.CB_04_02_Coma.setText(\"Coma\")\n\n        self.GBox_05_Data_Wire_Gui.setTitle(\"Data wire Gui testing\")\n        self.TE_05_01_textEdit.setText(\"List Data object saved in file\")\n        self.Label_05_01_Data.setText(\"Data object : \")\n        self.Label_04_01.setText(\"Perim.(Se) : \"+str(\"-.-\"))\n        self.PB_05_01_Wire_For_Test.setText(\"Ok MakeWire\")\n        self.PB_05_02_Reset_Data.setText(\"Reset data\")\n        self.PB_05_03_Reuse.setText(\"Reuse\")\n        self.PB_05_04_ClearTE.setText(\"Clear TEdit\")\n        self.PB_05_04b_Zoom.setText(\"Z\")\n        self.PB_05_06_Del_Line.setText(\"Del Test\")\n        self.CB_05_01_Solid.setText(\"Solid\")\n        self.CB_05_02_Frenet.setText(\"Frenet\")\n        self.PB_05_05_ClearRView.setText(\"Clear RepV\")\n        self.PB_05_07_Test_Sweep.setText(\"Test Sweep\")\n        self.PB_05_08_Recompute.setText(\"Recompute\")\n\n        self.GBox_06_Data_File.setTitle(\"Data file Temporary\")\n        self.PB_06_01_Save_Data_File.setText(\"Save DT\")\n        self.CB_06_01_Contigu_Data.setText(\"Cont.\")\n        self.PB_06_02_Read_Data_File.setText(\"Read DT\")\n        self.SP_06_01_Step.setSuffix(\" Step\")\n        self.PB_06_03_Reset_Data_File.setText(\"Reset DataT\")\n\n        self.PB_00_Mouse_Mode.setText(\"Click for Quit\\nMouse Mode\\n\")\n        self.PB_01_Save.setText(\"Save\")\n        self.PB_02_Read.setText(\"Read\")\n        self.PB_03_Reset.setText(\"Reset\")\n        self.PB_04_Color.setText(\"Color\")\n        self.PB_05_Dowgrade.setText(\"Explo\")\n        self.PB_07_Duplicate.setText(\"Duplic\")\n        self.PB_06_Quit.setText(\"Quit\")\n\n#Part.sortEdges() \n\n    def on_RB_01_01_Reversed_clicked(self):                                                  # on_RB_01_01_Reversed_clicked\n        global revers\n\n        revers = 0\n        self.CB_01_01_Reverse.setEnabled(False)\n        self.CB_01_01_Reverse.setChecked(False)\n#        print( \"on_RB_01_01_Reversed_clicked \",str(revers))\n\n    def on_RB_01_02_Forward_clicked(self):                                                   # on_RB_01_02_Forward_clicked\n        global revers\n\n        revers = 1\n        self.CB_01_01_Reverse.setEnabled(False)\n        self.CB_01_01_Reverse.setChecked(False)\n#        print( \"on_RB_01_02_Forward_clicked \",str(revers))\n\n    def on_RB_01_03_Neutral_clicked(self):                                                    # on_RB_01_03_Neutral_clicked\n        global revers\n\n        revers = 2\n        self.CB_01_01_Reverse.setEnabled(True)\n        self.CB_01_01_Reverse.setChecked(False)\n#        print( \"on_RB_01_03_Neutral_clicked \",str(revers))\n\n    def on_CB_01_01_Reverse_clicked(self):                                                    # on_CB_01_01_Reverse_clicked\n        global revers\n\n        if self.CB_01_01_Reverse.isChecked():\n            revers = 3\n        else:\n            revers = 2\n#        print( \"on_RB_01_03_Neutral_clicked \",str(revers))\n\n    def on_RB_02_01_MakeWire_clicked(self):                                                   # on_RB_02_01_MakeWire_clicked\n        global typeLine\n        global typeArc\n\n        typeLine = 0\n        self.CB_02_01_Arc.setChecked(False)\n        self.CB_02_01_Arc.setEnabled(False)\n        typeArc = 0\n        self.PB_05_01_Wire_For_Test.setText(\"Ok MakeWire\")\n#        print( \"on_RB_02_01_MakeWire_clicked \",str(typeLine))\n\n    def on_GBox_02_Type_Line_clicked(self):                                                   # on_GBox_02_Type_Line_clicked\n        global createLine\n        global wireClose\n        global wireFace\n        global createCloud\n        global createShell\n\n        wireClose   = 0\n        wireFace    = 0\n        createCloud = 0\n        createShell = 0\n        if self.GBox_02_Type_Line.isChecked():\n            createLine = 1\n#            revers = 3\n#            self.RB_01_01_Reversed.setChecked(False)\n#            self.RB_01_02_Forward.setVisible(True)\n#            self.RB_01_03_Neutral.setVisible(True)\n            self.CB_03_01_Close.setVisible(True)\n            self.CB_03_01a_To_Mouse.setVisible(False)\n            self.PB_00_Mouse_Mode.setVisible(False)\n            self.CB_03_01b_CloseFo.setVisible(True)\n            self.CB_03_02_Create_Face.setVisible(True)\n            self.CB_03_02b_Create_Cloud.setVisible(False)\n            self.CB_03_02bb_Create_Shell.setVisible(False)\n            self.PB_05_01_Wire_For_Test.setText(\"Ok MakeWire\")\n        else:\n            createLine = 0\n#            revers = 0\n#            self.RB_01_01_Reversed.setChecked(True)\n#            self.RB_01_02_Forward.setVisible(False)\n#            self.RB_01_03_Neutral.setVisible(False)\n\n            self.CB_03_01_Close.setChecked(False)\n            self.CB_03_01_Close.setVisible(False)\n\n            self.CB_03_01a_To_Mouse.setChecked(False)\n            self.CB_03_01a_To_Mouse.setVisible(True)\n\n            self.CB_03_01b_CloseFo.setChecked(False)\n            self.CB_03_01b_CloseFo.setVisible(False)\n\n            self.CB_03_02_Create_Face.setChecked(False)\n            self.CB_03_02_Create_Face.setVisible(False)\n\n            self.CB_03_02b_Create_Cloud.setChecked(False)\n            self.CB_03_02b_Create_Cloud.setEnabled(True)\n            self.CB_03_02b_Create_Cloud.setVisible(True)\n\n            if createCloud == 1:\n                self.CB_03_02bb_Create_Shell.setChecked(False)\n                self.CB_03_02bb_Create_Shell.setEnabled(True)\n                self.CB_03_02bb_Create_Shell.setVisible(True)\n\n\n            self.PB_05_01_Wire_For_Test.setText(\"Ok Points\")\n#        print( \"on_GBox_02_Type_Line_clicked \",str(createLine))\n\n    def on_RB_02_02_BSpline_clicked(self):                                                    # on_RB_02_02_BSpline_clicked\n        global typeLine\n        global typeArc\n\n        typeLine = 1\n        self.CB_02_01_Arc.setChecked(False)\n        self.CB_02_01_Arc.setEnabled(False)\n        typeArc = 0\n        self.PB_05_01_Wire_For_Test.setText(\"Ok BSpline\")\n#        print( \"on_RB_02_02_BSpline_clicked \",str(typeLine))\n\n    def on_RB_02_03_BSplineCurve_clicked(self):                                               # on_RB_02_03_BSplineCurve_clicked\n        global typeLine\n        global typeArc\n\n        typeLine = 2\n        self.CB_02_01_Arc.setChecked(False)\n        self.CB_02_01_Arc.setEnabled(True)\n        typeArc = 0\n        self.PB_05_01_Wire_For_Test.setText(\"Ok BSplineCur.\")\n#        print( \"on_RB_02_03_BSplineCurve_clicked \",str(typeLine))\n\n    def on_CB_02_01_Arc_clicked(self):                                                        # on_CB_02_01_Arc_clicked\n        global typeArc\n\n        if self.RB_02_03_BSplineCurve.isChecked():\n            self.CB_02_01_Arc.setEnabled(True)\n            if self.CB_02_01_Arc.isChecked():\n                typeArc = 1\n                self.PB_05_01_Wire_For_Test.setText(\"Ok BSplineCur+\")\n            else:\n                typeArc = 0\n                self.PB_05_01_Wire_For_Test.setText(\"Ok BSplineCur.\")\n        else:\n            self.CB_02_01_Arc.setEnabled(False)\n#        print( \"CB_02_01_Arc KO \",str(typeArc))\n\n    def on_RB_02_04_MakePolygon_clicked(self):                                                # on_RB_02_04_MakePolygon_clicked\n        global typeLine\n        global typeArc\n\n        typeLine = 3\n        self.CB_02_01_Arc.setChecked(False)\n        self.CB_02_01_Arc.setEnabled(False)\n        typeArc = 0\n        self.PB_05_01_Wire_For_Test.setText(\"Ok Polygon\")\n#        print( \"on_RB_02_04_MakePolygon_clicked \",str(typeLine))\n\n    def on_RB_02_05_MakeBezCurve_clicked(self):                                                # on_RB_02_05_MakeBezCurve_clicked\n        global typeLine\n        global typeArc\n\n        typeLine = 4\n        self.CB_02_01_Arc.setChecked(False)\n        self.CB_02_01_Arc.setEnabled(False)\n        typeArc = 0\n        self.PB_05_01_Wire_For_Test.setText(\"Ok BezCurve\")\n#        print( \"on_RB_02_05_MakeBezCurve_clicked \",str(typeLine))\n\n    def mouse_Mode(self):                                                                      # mouse mode\n        global vecteurSou\n        global vecteurSou_Comp\n        global pointsRead\n        global pp\n\n        pointsRead.append(str(vecteurSou[0])+\" \"+ str(vecteurSou[1])+\" \"+ str(vecteurSou[2])+\"\\n\")\n        pp.append(FreeCAD.Vector(float(vecteurSou[0]),float(vecteurSou[1]),float(vecteurSou[2])))\n\n        Gui.ActiveDocument.getObject(pointsName[vecteurSou_Comp]).Visibility=False\n        self.TE_05_01_textEdit.append(str(vecteurSou_Comp) + \": \" + str(vecteurSou))\n#        pp = pointsRead\n#        pp = copy.deepcopy(pointsRead)\n        vecteurSou_Comp += 1\n\n        self.TE_05_01_textEdit.verticalScrollBar().setValue(len(pointsRead)*((self.pointFont * 4)))          # \n        self.TE_05_01_textEdit.verticalScrollBar().setSliderPosition(len(pointsRead)*((self.pointFont * 4))) #\n#        print( \"mouse_Mode \",str(typeLine))\n\n    def on_CB_03_01a_To_Mouse_clicked(self):                                                   # on_CB_03_00_To_Mouse_clicked\n        global createCloud\n        global createPoint\n        global check_To_Mouse\n        global path\n        global nomFichier\n        global pp\n        global Switch_TE_Zoom\n\n#        print( path + nomFichier, \" on_CB_03_01a_To_Mouse_clicked\")\n#        print( pp)\n\n#        file = open(path + nomFichier, \"w\")    # vide the temporary file # verifier\n#        file.close()\n\n        Switch_TE_Zoom = 0\n        ui.on_PB_05_04b_Zoom_clicked()\n\n        check_To_Mouse = 1\n        self.CB_03_02b_Create_Cloud.setChecked(False)\n        createCloud = 0\n        self.CB_03_02bb_Create_Shell.setChecked(False)\n        createShell = 0\n        self.CB_03_03_Create_Points.setChecked(False)\n        createPoint = 0\n        self.GBox_00_Configuration.setEnabled(False)\n        self.GBox_05_Data_Wire_Gui.setEnabled(False)\n        self.GBox_06_Data_File.setEnabled(False)\n        self.PB_00_Mouse_Mode.setVisible(True)\n        self.TE_05_01_textEdit.setText(\"Mode ToMouse\")\n#        print( \"on_CB_03_01a_To_Mouse_clicked \", (check_To_Mouse))\n\n    def on_PB_00_Mouse_Mode_clicked(self):                                                    # quit Mouse_Mode\n        global check_To_Mouse\n        global vecteurSou_Comp\n        global pointsRead\n        global pointsName\n        global path\n        global nomFichier\n        global pp\n        global Switch_TE_Zoom\n#        try:\n#            file = open(path + nomFichier, \"w\")                                               # open the file r=read w=write a=append\n#            for i in pointsRead:\n#                file.write(i)\n#                X, Y, Z = i.split(\" \")\n#                pp.append(FreeCAD.Vector(float(X),float(Y),float(Z)))                         # append the coordinates XYZ\n#            file.close()\n#        except Exception:\n#            App.Console.PrintWarning( \"Error in creation file\" + \"\\n\")\n\n\n#        pp = copy.deepcopy(pointsRead)\n        print( pp)\n#ici\n\n        self.GBox_02_Type_Line.setChecked(True)\n        ui.on_GBox_02_Type_Line_clicked()\n#        ui.on_PB_05_01_Wire_For_Test_clicked()\n        ui.on_PB_06_01_Save_Data_File_clicked()\n#        ui.createWire()\n\n        Switch_TE_Zoom = 1\n        ui.on_PB_05_04b_Zoom_clicked()\n\n\n\n#        try:\n#            for obj in FreeCAD.ActiveDocument.Objects:         # deslectionne tout\n#                FreeCADGui.Selection.removeSelection(obj)\n#        except Exception:\n#            None\n\n        for object in pointsName:\n            print( object)\n            Gui.ActiveDocument.getObject(object).Visibility=True\n#            try:\n            FreeCADGui.Selection.removeSelection(App.ActiveDocument.getObject(object))  # deslectionne\n#            except Exception:\n#                None\n\n        check_To_Mouse  = 0\n        vecteurSou_Comp = 0\n\n        del pointsRead[:]\n        del pointsName[:]\n\n        self.CB_03_01a_To_Mouse.setChecked(False)\n        self.GBox_00_Configuration.setEnabled(True)\n        self.GBox_05_Data_Wire_Gui.setEnabled(True)\n        self.GBox_06_Data_File.setEnabled(True)\n        self.PB_00_Mouse_Mode.setVisible(False)\n#        print( \"on_PB_00_Mouse_Mode_clicked \")\n\n    def on_CB_03_01_Close_clicked(self):                                                      # on_CB_03_01_Close_clicked\n        global wireClose\n\n        wireClose = 0\n        if self.CB_03_01_Close.isChecked():\n            wireClose = 1\n        if self.CB_03_01b_CloseFo.isChecked():\n            wireClose = 2\n#        print( \"CB_01_Close \", str(wireClose))\n\n    def on_CB_03_02_Create_Face_clicked(self):                                                # on_CB_03_02_Create_Face_clicked\n        global wireFace\n\n        if self.CB_03_02_Create_Face.isChecked():\n            wireFace = 1\n        else:\n            wireFace = 0\n#        print( \"CB_02_Create_Face \", str(wireFace))\n\n    def on_CB_03_02b_Create_Cloud_clicked(self):                                              # on_CB_03_02b_Create_Cloud_clicked\n        global createCloud\n        global createShell\n\n        createShell = 0\n        if self.CB_03_02b_Create_Cloud.isChecked():\n            createCloud = 1\n            self.CB_03_02bb_Create_Shell.setVisible(True)\n        else:\n            createCloud = 0\n            self.CB_03_02bb_Create_Shell.setVisible(False)\n            self.CB_03_02bb_Create_Shell.setChecked(False)\n        print( \"on_CB_03_02b_Create_Cloud_clicked Cl Sh \", str(createCloud),\" \", str(createShell))\n\n    def on_CB_03_02bb_Create_Shell_clicked(self):                                              # on_CB_03_02bbCreate_Shell_clicked\n        global createCloud\n        global createShell\n\n        if createCloud == 1:\n            if self.CB_03_02bb_Create_Shell.isChecked():\n                createShell = 1\n            else:\n                createShell = 0\n        print( \"on_CB_03_02bbCreate_Shell_clicked Cl Sh \", str(createCloud),\" \", str(createShell))\n\n    def on_CB_03_03_Create_Points_clicked(self):                                              # on_CB_03_03_Create_Points_clicked\n        global createPoint\n\n        if self.CB_03_03_Create_Points.isChecked():\n            createPoint = 1\n        else:\n            createPoint = 0\n#        print( \"CB_03_Create_Points \", str(createPoint))\n\n    def on_RB_04_01_XYZ_clicked(self):                                                        # on_RB_04_01_XYZ_clicked\n        global savedata\n        global createZero\n\n        self.CB_04_01_Zero.setEnabled(False)\n        self.CB_04_01_Zero.setChecked(False)\n        savedata = 0\n        createZero = 0\n        self.RB_04_02_XY.setText(\"X Y\")\n        self.RB_04_03_YZ.setText(\"Y Z\")\n        self.RB_04_04_XZ.setText(\"X Z\")\n#        print( \"on_RB_04_01_XYZ_clicked \", str(savedata))\n\n    def on_RB_04_02_XY_clicked(self):                                                         # on_RB_04_02_XY_clicked\n        global savedata\n\n        self.CB_04_01_Zero.setEnabled(True)\n        savedata = 1\n#        print( \"on_RB_04_02_XY_clicked \", str(savedata))\n\n    def on_RB_04_03_YZ_clicked(self):                                                         # on_RB_04_03_YZ_clicked\n        global savedata\n\n        self.CB_04_01_Zero.setEnabled(True)\n        savedata = 2\n#        print( \"on_RB_04_03_YZ_clicked \", str(savedata))\n\n    def on_RB_04_04_XZ_clicked(self):                                                         # on_RB_04_04_XZ_clicked\n        global savedata\n\n        self.CB_04_01_Zero.setEnabled(True)\n        savedata = 3\n#        print( \"on_RB_04_04_XZ_clicked \", str(savedata))\n\n    def on_CB_04_01_Zero_clicked(self):\n        global createZero\n\n        if self.CB_04_01_Zero.isChecked():\n            createZero = 1\n            self.RB_04_02_XY.setText(\"X Y 0\")\n            self.RB_04_03_YZ.setText(\"0 Y Z\")\n            self.RB_04_04_XZ.setText(\"X 0 Z\")\n        else:\n            createZero = 0\n            self.RB_04_02_XY.setText(\"X Y\")\n            self.RB_04_03_YZ.setText(\"Y Z\")\n            self.RB_04_04_XZ.setText(\"X Z\")\n#        print( \"on_CB_04_01_Zero_clicked \", str(createZero))\n\n    def on_CB_04_02_Coma_clicked(self):\n\n        if self.CB_04_02_Coma.isChecked():\n            self.CB_04_02_Coma.setStyleSheet(\"background-color: green\")                  # origin system\n        else:\n            self.CB_04_02_Coma.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        print( \"on_CB_04_02_Coma_clicked \", str(\"\"))\n\n    def on_Label_04_01(self):                                                                 # upgrade length ,value\n        global pointsPerMm\n\n        sel = FreeCADGui.Selection.getSelection()   \n        perimetre = 0.0\n        try:\n            for j in enumerate(sel[0].Shape.Edges):\n                perimetre += (sel[0].Shape.Edges[j[0]].Length)\n            self.Label_04_01.setText(\"Perim.(Se) : \"+str(round(perimetre,1))+\" (\"+ str(int((perimetre)/(pointsPerMm))+1) + \")\")\n            self.PB_05_01_Wire_For_Test.setStyleSheet(\"background-color: QPalette.Base\")      # origin system\n        except Exception:\n            None\n#        print( \"on_Label_04_01 \")\n\n    def on_DSB_00_01_Precision_valueChanged(self,value):                                      # on_DSB_00_01_Precision_valueChanged\n        global pointsPerMm\n        global ui\n\n        if value <= 1 :\n            self.DSB_00_01_Precision.setSingleStep(0.1)\n        else:\n            self.DSB_00_01_Precision.setSingleStep(1.0)\n        pointsPerMm = value\n        ff = ui\n        ff.on_Label_04_01()\n#        print( \"on_DSB_00_01_Precision_valueChanged \",str(value))\n\n    def createWire(self):                                                                     # Create wire\n        import FreeCADGui, FreeCAD\n        global OpenName\n        global pp\n        global createLine\n        global typeLine\n        global typeArc\n        global revers                                                                         # 0=Reversed 1=Forward 2=Neutral\n        global wireFace\n        global wireClose\n        global createCloud\n        global createShell\n        global createPoint\n        global objectLabel\n        global pointsPerMm\n        global text\n        global lineCreate\n        global txtBegin\n        global txtEnd\n        global rgbPoints\n\n        def colored(text):                                                                    # colored the line and text\n            import FreeCADGui, FreeCAD\n            global OpenName\n            global createLine\n            global createCloud\n            global createShell\n            global createPoint\n            global objectLabel\n            global pointsPerMm\n            global revers\n            global txtBegin\n            global txtEnd\n            global rgbPoints\n            global verbose\n\n            if revers == 0:\n                text += \"_Reversed\"\n            elif revers == 1:\n                text += \"_Forward\"\n            elif revers == 2:\n                text += \"_Neutral\"\n            elif revers == 3:\n                text += \"_Neutral_Forced\"\n\n            FreeCAD.ActiveDocument.ActiveObject.Label = objectLabel + \" \" + text + \"_Prec(\" + str(pointsPerMm) + \")\"  # give Label\n            self.TE_05_01_textEdit.append(objectLabel + \" \" + text + \"_Prec(\" + str(pointsPerMm) + \")\")\n\n            if verbose == 1:\n                FreeCADGui.activeDocument().activeObject().LineColor  = (self.red, self.green, self.blue)     # give LineColor\n                FreeCADGui.activeDocument().activeObject().PointColor = (self.red, self.green, self.blue)     # give PointColor\n                FreeCADGui.activeDocument().activeObject().ShapeColor = (self.red, self.green, self.blue)     # give ShapeColor\n            try:\n                diagonale = FreeCAD.ActiveDocument.ActiveObject.Shape.BoundBox.DiagonalLength                 # diagonal object for Height text\n            except Exception:\n                diagonale = 60.0\n\n            if pp[1] == pp[len(pp)-2]:\n                txtBegin = Draft.makeText([\"Begin\"],point=FreeCAD.Vector(pp[0]))                  # create text Begin\n            else:\n                txtBegin = Draft.makeText([\"Begin\"],point=FreeCAD.Vector(pp[1]))                  # create text Begin\n            FreeCADGui.activeDocument().getObject(txtBegin.Label).FontSize = diagonale / 6.0\n            if verbose == 1:\n                FreeCADGui.activeDocument().getObject(txtBegin.Label).TextColor = (0.0, 1.0, 0.0)\n            txtBegin.Label = objectLabel + \"_Begin\"\n\n            txtEnd = Draft.makeText([\"End\"],point=FreeCAD.Vector(pp[len(pp)-2]))              # create text End\n            FreeCADGui.activeDocument().getObject(txtEnd.Label).FontSize = diagonale / 6.0\n            if verbose == 1:\n                FreeCADGui.activeDocument().getObject(txtEnd.Label).TextColor = (1.0, 0.0, 0.0)\n            txtEnd.Label = objectLabel + \"_End\"\n\n            Gui.updateGui()                                                                   # rafraichi l'ecran\n\n        self.Label_05_01_Data.setText(\"Number coordinates : \" + str(len(pp)))\n        self.Label_05_01_Data.setStyleSheet(\"color : #008500\")                                # Color text\n        Gui.updateGui()                                                                       # rafraichi l'ecran\n\n        try:\n            if len(pp) != 0:\n                self.PB_05_06_Del_Line.setStyleSheet(\"background-color: green\")                       # green\n                if createCloud != 0:                                                                  # create Cloud\n                    import Points\n                    pnt=Points.Points()\n                    for i in range(len(pp)):\n                        a = FreeCAD.Vector(float(pp[i][0]), float(pp[i][1]), float(pp[i][2]))\n                        pnt.addPoints([a])\n                    Points.show(pnt)\n                    FreeCAD.ActiveDocument.ActiveObject.Label = \"Points_\" +  OpenName                 # give cloud Label\n                    if createShell == 1:\n                        print(\"A faire\")\n#                        https://www.freecadweb.org/wiki/TopoShape_API\n#################### adapter ######################\n                        #https://forum.freecadweb.org/viewtopic.php?f=13&t=40000&start=10\n                        # shape = App.ActiveDocument.Compound001.Shape\n                        # p = shape.Vertexes\n\n                        # h = 72.0 # diesen Wert erh\u00e4lt man aus der Bounding-Box\n                        # w = 142.0\n                        # s = 2.0 # diesen Wert erh\u00e4lt man durch Messen\n\n                        # width = w/s + 1\n                        # height = h/s + 1\n\n                        # # Das erzeugt ein dict mit Index-Wert -> Punkt\n                        # map={}\n                        # for i in p:\n                          # x=i.Point.x\n                          # y=i.Point.y\n                          # xi=x/s\n                          # yi=y/s\n                          # index=int(yi*width + xi)\n                          # map[index]=i.Point\n\n                        # # durch Sortieren kann man das an eine geordnete Punktewolke \u00fcbergeben \n                        # sorted_map={}\n                        # for i in sorted(map.keys()):\n                          # sorted_map[i] = map[i]\n\n                        # import Points\n                        # pts=Points.Points()\n                        # pts.addPoints(list(sorted_map.values()))\n\n                        # sp=App.ActiveDocument.addObject(\"Points::Structured\", \"Cloud\")\n                        # sp.Width=int(width)\n                        # sp.Height=int(height)\n                        # sp.Points=pts\n                        # App.ActiveDocument.recompute()\n\n##########################################        \n                if createPoint != 0:                                                                  # create points\n                    self.PBar_05_01_ProgressBar.setMinimum(0)                                         # ProgressBar\n                    self.PBar_05_01_ProgressBar.setMaximum(len(pp))                                   # ProgressBar\n                    self.TE_05_01_textEdit.append(\"Create \" + str(len(pp)) + \" points \")\n                    for i in range(len(pp)):\n                        Draft.makePoint(pp[i])                                                         # create points\n                        try:\n                            FreeCADGui.activeDocument().activeObject().PointColor = (rgbPoints[i][0],rgbPoints[i][1],rgbPoints[i][2])\n                        except Exception:\n                            FreeCADGui.activeDocument().activeObject().PointColor = (self.red, self.green, self.blue)\n        \n                        self.PBar_05_01_ProgressBar.setValue(i+1)                                     # ProgressBar\n                    self.PBar_05_01_ProgressBar.setValue(0)                                           # ProgressBar\n        #            self.PBar_05_01_ProgressBar.setMinimum(0)                                         # ProgressBar\n        #            self.PBar_05_01_ProgressBar.setMaximum(0)                                         # ProgressBar\n        \n                if createLine == 1:\n    \n                    if typeLine == 1:\n#                        try:\n\n#https://forum.freecadweb.org/viewtopic.php?f=3&t=7827&p=174209#p174209\n#import Draft\n#sels=Gui.Selection.getSelection()\n#for sel in sels:\n#   for w in sel.Shape.Wires:\n#      pts=[v.Point for v in w.Vertexes]\n#      r=Draft.makeWire(pts)\n#      r.Label=\"DW for \" +sel.Label      \n\n#      r=Draft.makeBSpline(pts)\n\n#      r.Label=\"Spline for \" +sel.Label\n#      pts=r.Shape.Edge1.Curve.discretize(500)\n#      r2=Draft.makeBSpline(pts)\n#      r2.Label=\"Spline 500 for \" +sel.Label\n\n                            print( pp)\n                            pts =pp\n                            lineCreate=Draft.makeBSpline(pts)\n#                            lineCreate = Draft.makeBSpline(pp)                               # Ok avec courbes makeBSpline\n                            text = \"_makeBSpline\"\n                            colored(text)\n                            self.RB_02_02_BSpline.setChecked(True)\n#                        except Exception:\n#                            App.Console.PrintWarning(\"Type line makeBSpline abandoned try with BSplineCurve\" + \"\\n\")\n#                            typeLine = 2\n            \n                    if typeLine == 2:\n                        try:\n                            ###https://forum.freecadweb.org/viewtopic.php?f=3&t=22653&p=175919#p175919\n                            ###obj = FreeCAD.ActiveDocument.getObject(\"DWire\")\n                            ###pts = [v.Point for v in obj.Shape.Vertexes]\n                            ###import Part\n                            ###bs = Part.BSplineCurve()\n                            ###bs.interpolate(pts)\n                            ###Part.show(bs.toShape())\n\n                            #lineCreate = Part.BSplineCurve()                                          # OK avec courbes BSplineCurve 1\n                            #lineCreate.interpolate(pp)#,False)                                        # OK avec courbes BSplineCurve 1\n                            #lineCreate = Part.Edge(lineCreate)                                        # OK avec courbes BSplineCurve 1\n                            #Part.show(lineCreate)                                                     # OK avec courbes BSplineCurve 1\n                            #self.RB_02_03_BSplineCurve.setChecked(True)                               # OK avec courbes BSplineCurve 1\n                            #text = \"_BSplineCurve 1\"                                                  # OK avec courbes BSplineCurve 1\n                            #App.Console.PrintMessage(\"_BSplineCurve 1\" + \"\\n\")                        # OK avec courbes BSplineCurve 1\n    \n                            lineCreate = Part.BSplineCurve()                                          # OK avec courbes BSplineCurve 2\n                            lineCreate.buildFromPoles(pp)                                             # OK avec courbes BSplineCurve 2\n                            Part.show(lineCreate.toShape())                                           # OK avec courbes BSplineCurve 2\n                            lineCreate = App.ActiveDocument.ActiveObject                              # OK avec courbes BSplineCurve 2\n                            self.RB_02_03_BSplineCurve.setChecked(True)                               # OK avec courbes BSplineCurve 2\n                            text = \"_BSplineCurve 2\"                                                  # OK avec courbes BSplineCurve 2\n                            App.Console.PrintMessage(\"_BSplineCurve 2\" + \"\\n\")                        # OK avec courbes BSplineCurve 2\n                            colored(text)\n                            if typeArc == 1:                                                          # OK with BSplineCurve toBiArcs version 0.16 !!!\n                                try:\n                                    arcs=lineCreate.toBiArcs(0.01)\n                                    arcs\n                                    lineCreate = App.ActiveDocument.ActiveObject\n                                    text = \"_BSplineCurvetoBiArcs\"\n                                    App.Console.PrintMessage(\"_BSplineCurvetoBiArcs\" + \"\\n\")\n                                    colored(text)\n                                except Exception:\n                                    App.Console.PrintError(\"Error toBiArcs\" + \"\\n\")\n    \n                        except Exception:\n                            App.Console.PrintMessage(\"type line BSplineCurve abandoned try with makePolygon\" + \"\\n\")\n                            typeLine = 3\n            \n                    if typeLine == 3:\n                        try:\n                            lineCreate = Part.makePolygon(pp)                                             # makePolygon\n                            Part.show(lineCreate)\n                            lineCreate = App.ActiveDocument.ActiveObject\n                            self.RB_02_04_MakePolygon.setChecked(True)\n                            text = \"_makePolygon\"\n                            App.Console.PrintMessage(\"_makePolygon\" + \"\\n\")\n                            colored(text)\n                        except Exception:\n                            App.Console.PrintWarning(\"Type line _makePolygon abandoned try with makeBezCurve\" + \"\\n\")\n                            typeLine = 4\n            \n                    if typeLine == 4:\n                        try:\n                            lineCreate = Draft.makeBezCurve(pp,closed=False,support=None)                 # makeBezCurve\n                            text = \"_makeBezCurve\"\n                            App.Console.PrintMessage(\"_makeBezCurve\" + \"\\n\")\n                            colored(text)\n                        except Exception:\n                            App.Console.PrintWarning(\"Type line _makeBezCurve abandoned try with makeWire\" + \"\\n\")\n                            typeLine = 0\n            \n                    if typeLine == 0:\n                        lineCreate = Draft.makeWire(pp,closed=False,face=False,support=None)              # makeWire\n                        self.RB_02_01_MakeWire.setChecked(True)\n                        text = \"_makeWire\"\n                        App.Console.PrintMessage(\"_makeWire\" + \"\\n\")\n                        colored(text)\n            \n                    self.PB_05_01_Wire_For_Test.setStyleSheet(\"background-color: green\")\n                    self.PB_05_02_Reset_Data.setStyleSheet(\"background-color: green\")\n                    self.PB_05_03_Reuse.setStyleSheet(\"background-color: green\")\n                    self.PB_06_01_Save_Data_File.setStyleSheet(\"background-color: green\")                 # green\n            \n                    import FreeCAD, FreeCADGui\n                    doc=App.ActiveDocument.Name\n            \n                    try:                                                                                  # Wire close or open\n                        if wireClose == 0:\n                            FreeCAD.getDocument(doc).getObject(lineCreate.Name).Closed = False\n                        else:\n                            FreeCAD.getDocument(doc).getObject(lineCreate.Name).Closed = True\n                    except Exception:\n                        None\n                    \n                    try:                                                                                  # face or not face\n                        if wireFace == 0:\n                            lineCreate.MakeFace = False\n                        else:\n                            lineCreate.MakeFace = True\n                    except Exception:\n                        try:                                                                              # face Shape\n                            faceShape = Part.Wire(lineCreate.Shape)\n                            faceShape1 = Part.Face(faceShape)\n                            Part.show(faceShape1)\n                            FreeCADGui.activeDocument().activeObject().ShapeColor = (1.00,0.00,0.0)\n                            App.ActiveDocument.ActiveObject.Label   = objectLabel + \"_Face_\" + text\n                            #print( \"Create face shape \")\n                        except Exception:\n                            #print( \"Not face created \")\n                            None\n        \n                    self.PBar_05_01_ProgressBar.setValue(0)                                           # ProgressBar\n#                    self.PBar_05_01_ProgressBar.setMinimum(0)                                         # ProgressBar\n#                    self.PBar_05_01_ProgressBar.setMaximum(0)                                         # ProgressBar\n                FreeCAD.ActiveDocument.recompute()\n            else:\n                App.Console.PrintError(\"Select object\" + \"\\n\")\n        except Exception:\n            self.Label_05_01_Data.setText(\"Standard_ConstructionError try a different type of line \" + str(len(pp)))\n            self.Label_05_01_Data.setStyleSheet(\"color : #FF0000\")                                # Color text\n            App.Console.PrintError(\"Standard_ConstructionError or not document open\" + \"\\n\")\n\n    def on_PB_05_01_Wire_For_Test_clicked(self):\n        global objectLabel\n        global revers\n        global pp\n        global pointsPerMm\n        global wireClose\n\n        sel = FreeCADGui.Selection.getSelection()\n        try:\n            objectLabel = sel[0].Label\n            App.Console.PrintMessage(\"Selection(s) : \" + str(len(sel)) + \"  \" + objectLabel + \" (\"+ str(pointsPerMm) + \")\" + \"\\n\")\n    \n            self.Label_05_01_Data.setText(\"Data object : Wait\")\n            self.Label_05_01_Data.setStyleSheet(\"color : #FF0000\")                                # Color text\n            self.PB_05_01_Wire_For_Test.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n            self.PB_05_02_Reset_Data.setStyleSheet(\"background-color: QPalette.Base\")             # origin system\n            self.PB_05_03_Reuse.setStyleSheet(\"background-color: QPalette.Base\")                  # origin system\n            self.PB_05_06_Del_Line.setStyleSheet(\"background-color: green\")                       # green\n            Gui.updateGui()                                                                       # rafraichi l'ecran\n    \n            c = -1\n            r = 1\n            p  = []\n            if self.CB_03_01a_To_Mouse.isChecked():\n                print( pp)\n                None\n            else:\n                pp = []\n                del pp[:]\n    \n# ori           try:\n            self.PBar_05_01_ProgressBar.setMaximum(len(sel))                     # ProgressBar\n            for w in sel:\n                    c += 1\n                    w =sel[c].Shape\n                    w2=Part.Wire(OpenSCAD2Dgeom.findConnectedEdges(w.Edges)[0])\n                    self.PB_05_01_Wire_For_Test.setStyleSheet(\"background-color: green\")              # green\n                    self.PB_05_02_Reset_Data.setStyleSheet(\"background-color: green\")                 # green\n                    self.PB_05_03_Reuse.setStyleSheet(\"background-color: green\")                      # green\n                    comp0 = 0\n                    for e in w2.Edges:\n                        self.PBar_05_01_ProgressBar.setMinimum(0)                                     # ProgressBar\n                        self.PBar_05_01_ProgressBar.setMaximum(0)                                     # ProgressBar\n                        comp0 += 1\n                        try:\n                            points=e.discretize(Distance=pointsPerMm)\n#                            print(\"1   \",points)\n                        except Exception:\n                            points = [e.Vertexes[0].Point, e.Vertexes[1].Point]\n#                            print(pointsPerMm,\" \",e.Vertexes[0].Point)\n#                            print(\"2    \",points)\n\n        \n        #                if pointsPerMm         \"ici   je ne sais plus pourquoi .. peut etre 0 a travailler \"\n        \n                        if revers == 0:\n                            if (str(e.Curve)[1:5]    == \"Line\") and (e.Orientation==\"Reversed\"):\n                                points.reverse()\n                            elif (str(e.Curve)[0:6]  == \"Circle\") and (e.Orientation==\"Reversed\"):\n                                points.reverse()\n                            elif (str(e.Curve)[1:8]  == \"Ellipse\") and (e.Orientation==\"Reversed\"):\n                                points.reverse()\n                            elif (str(e.Curve)[1:13] == \"BSplineCurve\") and (e.Orientation==\"Reversed\"):\n                                points.reverse()\n                            elif (str(e.Curve)[1:13] == \"BezierCurve\") and (e.Orientation==\"Reversed\"):\n                                points.reverse()\n                                 \n                        elif revers == 1:\n                            if (str(e.Curve)[1:5]    == \"Line\") and (e.Orientation==\"Forward\"):\n                                points.reverse()\n                            elif (str(e.Curve)[0:6]  == \"Circle\") and (e.Orientation==\"Forward\"):\n                                points.reverse()\n                            elif (str(e.Curve)[1:8]  == \"Ellipse\") and (e.Orientation==\"Forward\"):\n                                points.reverse()\n                            elif (str(e.Curve)[1:13] == \"BSplineCurve\") and (e.Orientation==\"Forward\"):\n                                points.reverse()\n                            elif (str(e.Curve)[1:13] == \"BezierCurve\") and (e.Orientation==\"Forward\"):\n                                points.reverse()\n        \n                        elif revers == 2:\n                            None\n        \n                        elif revers == 3:\n                            points.reverse()\n        \n                        self.Label_05_01_Data.setText(\"Number coordinates : \" + str(len(pp)))\n                        self.Label_05_01_Data.setStyleSheet(\"color : #008500\")                                # Color text\n                        self.PBar_05_01_ProgressBar.setValue(c)                                           # affect the value \"val_X\" in PBar_05_01_ProgressBar\n            \n                        p = points\n                        pp += p\n                        del p[:]\n        \n            if revers == 0:\n                pp.reverse()\n            if wireClose == 2:\n#                    pp.append(pp[0])\n                pp += pp[0]\n            ff = ui\n            ff.createWire()\n#            except Exception:\n#                App.Console.PrintError(\"Decoding error or inappropriate object\" + \"\\n\")\n            \n        except Exception:\n            self.PB_05_01_Wire_For_Test.setStyleSheet(\"background-color: QPalette.Base\")      # origin system\n            self.PB_05_02_Reset_Data.setStyleSheet(\"background-color: QPalette.Base\")         # origin system\n            self.PB_05_01_Wire_For_Test.setStyleSheet(\"background-color: white;\\n\"\n                                                      \"border:2px solid rgb(255, 0, 0);\")     # white and red\n            App.Console.PrintError(\"Select one object or error object\" + \"\\n\")\n            \n        self.PBar_05_01_ProgressBar.setMinimum(0)                       # ProgressBar\n        self.PBar_05_01_ProgressBar.setMaximum(100)                     # ProgressBar\n        self.PBar_05_01_ProgressBar.setValue(0)                         # ProgressBar\n#        self.PB_05_06_Del_Line.setStyleSheet(\"background-color: QPalette.Base\")               # origin system\n#        print( \"on_PB_05_01_Wire_For_Test_clicked\"     )\n\n    def on_PB_05_02_Reset_Data_clicked(self):\n        global pp\n\n        del pp[:]\n        self.PBar_05_01_ProgressBar.setValue(0)\n        self.Label_05_01_Data.setText(\"Number coordinates : 0\")\n        self.Label_05_01_Data.setStyleSheet(\"color : #FF0000\")                                # Color text\n        self.PB_05_01_Wire_For_Test.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.PB_05_02_Reset_Data.setStyleSheet(\"background-color: QPalette.Base\")             # origin system\n        self.PB_05_03_Reuse.setStyleSheet(\"background-color: QPalette.Base\")                  # origin system\n        self.PB_06_01_Save_Data_File.setStyleSheet(\"background-color: QPalette.Base\")         # origin system\n        self.PB_05_06_Del_Line.setStyleSheet(\"background-color: QPalette.Base\")               # origin system\n#        print( \"on_PB_05_02_Reset_Data_clicked\")\n\n    def on_PB_05_03_Reuse_clicked(self):\n        global pp\n        global text\n\n        if len(pp) != 0:\n            text = \"\"\n            Gui.updateGui()                                                                   # rafraichi l'ecran\n            self.Label_05_01_Data.setText(\"Number coordinates : \" + str(len(pp)))\n            self.Label_05_01_Data.setStyleSheet(\"color : #008500\")                            # Color text\n            ff = ui\n            ff.createWire()\n        else:\n            self.Label_05_01_Data.setText(\"Number coordinates : Not data\")\n            self.Label_05_01_Data.setStyleSheet(\"color : #FF0000\")                            # Color text\n            App.Console.PrintError(\"Not data\" + \"\\n\")\n            self.PB_05_03_Reuse.setStyleSheet(\"background-color: red\")                        #red\n\n        self.PBar_05_01_ProgressBar.setMinimum(0)                                             # ProgressBar\n        self.PBar_05_01_ProgressBar.setMaximum(100)                                           # ProgressBar\n        self.PBar_05_01_ProgressBar.setValue(0)                                               # ProgressBar\n#        print( \"on_PB_05_03_Reuse_clicked\")\n\n    def on_PB_05_04_ClearTE_clicked(self):\n        self.TE_05_01_textEdit.clear()\n        self.TE_05_01_textEdit.setText(\"List Data object history\")\n#        print( \"on_PB_05_04_ClearTE_clicked\")\n    \n    def on_PB_05_04b_Zoom_clicked(self):\n        global Switch_TE_Zoom\n\n        if Switch_TE_Zoom == 0:\n            self.TE_05_01_textEdit.setGeometry(QtCore.QRect(10, 20, 271, 182))\n            self.CB_05_01_Solid.setVisible(False)\n            self.CB_05_02_Frenet.setVisible(False)\n            self.PBar_05_01_ProgressBar.setVisible(False)\n            self.SP_05_01_Dia_Circle.setVisible(False)\n            Switch_TE_Zoom = 1\n        else:\n            self.TE_05_01_textEdit.setGeometry(QtCore.QRect(10, 20, 271, 81))\n            self.CB_05_01_Solid.setVisible(True)\n            self.CB_05_02_Frenet.setVisible(True)\n            self.PBar_05_01_ProgressBar.setVisible(True)\n            self.SP_05_01_Dia_Circle.setVisible(True)\n            Switch_TE_Zoom = 0\n#        print( \"on_PB_05_04b_Zoom_clicked\")\n\n    def on_PB_05_05_ClearRView_clicked(self):                                                 # on_PB_05_05_ClearRView_clicked\n        try:\n            mw=Gui.getMainWindow()\n            r=mw.findChild(QtGui.QTextEdit, \"Report view\")\n            r.clear()\n        except Exception:\n            None\n#        print( \"on_PB_05_05_ClearRView_clicked\")\n\n    def on_PB_05_06_Del_Line_clicked(self):                                                   # on_PB_05_06_Del_Line_clicked\n        global lineCreate\n        global myCircle\n        global mySweep\n        global txtBegin\n        global txtEnd\n        global text\n\n        try:\n            FreeCAD.ActiveDocument.removeObject(lineCreate.Name)\n            self.TE_05_01_textEdit.append( str(comptDataSaved) + \" : \" + objectLabel + \" \" + text + \"_Prec(\" + str(pointsPerMm) + \") deleted\") # give Label in TE_05_01_textEdit\n            try:\n                FreeCAD.ActiveDocument.removeObject(txtBegin.Name)\n                FreeCAD.ActiveDocument.removeObject(txtEnd.Name)\n            except Exception:\n                None\n            try:\n                FreeCAD.ActiveDocument.removeObject(myCircle.Name)\n                FreeCAD.ActiveDocument.removeObject(mySweep.Name)\n            except Exception:\n                None\n            self.PB_05_06_Del_Line.setStyleSheet(\"background-color: QPalette.Base\")             # origin system\n        except Exception:\n            self.PB_05_06_Del_Line.setStyleSheet(\"background-color: red\")                       # red\n            App.Console.PrintError(\"Error delete object\" + \"\\n\")\n#        print( \"on_PB_05_06_Del_Line_clicked\")\n\n    def on_SP_05_01_Dia_Circle_valueChanged(self,value):\n        global diamCircle\n        diamCircle = value\n#        print( \"on_SP_05_01_Dia_Circle_valueChanged\")\n\n    def on_PB_05_07_Test_Sweep_clicked(self):\n        global pp\n        global lineCreate\n        global objectLabel\n        global myCircle\n        global mySweep\n        global mySweepSolid\n        global mySweepFrenet\n        global diamCircle\n\n        try:\n            Chrono(0)\n            myCircle = Draft.makeCircle(diamCircle)\n            myCircle.MakeFace  = True\n            myCircle.Label     = objectLabel + \"_Circle\"\n    \n            pointsDirection  = []\n            pointsDirection = lineCreate.Shape.discretize(Number=500)\n            #discretize(Number=n)                          => gives a list of 'n' equidistant points\n            #discretize(QuasiNumber=n)                     => gives a list of 'n' quasi equidistant points (is faster than the method above)\n            #discretize(Distance=d)                        => gives a list of equidistant points with distance 'd'\n            #discretize(Deflection=d)                      => gives a list of points with a maximum deflection 'd' to the edge\n            #discretize(QuasiDeflection=d)                 => gives a list of points with a maximum deflection 'd' to the edge (faster)\n            #discretize(Angular=a,Curvature=c,[Minimum=m]) => gives a list of points with an angular deflection of 'a'\n    \n            directionOriginalObject = pointsDirection[0].sub(pointsDirection[1])    # avec vecteurs 1 et 2 (direction debut ligne)\n            v=pointsDirection[0].sub(pointsDirection[1])                            # avec vecteurs 1 et 2 (direction debut ligne)\n            #directionOriginalObject = pointsDirection[0].sub(pointsDirection[-1])   #avec vecteurs extremites (direction objet)\n            #v=pointsDirection[0].sub(pointsDirection[-1])                           #avec vecteurs extremites (direction objet)\n            r=App.Rotation(App.Vector(0,0,1),v)     # original\n            v=directionOriginalObject\n    \n            pl=FreeCAD.Placement()\n            pl.Rotation.Q = r.Q\n            pl.Base = pp[0]\n            myCircle.Placement = pl\n            \n            del pointsDirection[:]\n            text = \"\"\n        except Exception:\n            App.Console.PrintError(\"Error create circle\" + \"\\n\")\n\n        try:\n            mySweep            = App.activeDocument().addObject('Part::Sweep','mySweepTest')\n            mySweep.Sections   = [myCircle]\n            mySweep.Spine      = lineCreate\n            if mySweepSolid   == 1:\n                mySweep.Solid  = True\n                text = \"True\"\n            else:\n                mySweep.Solid  = False\n                text = \"False\"\n    \n            if mySweepFrenet  == 1:\n                mySweep.Frenet = True\n                text += \" - True\"\n            else:\n                mySweep.Frenet = False\n                text += \" - False\"\n            #mySweep.Transition = 1    #1=angle droit   2=courbe\n            mySweep.Label = objectLabel + \"_mySweepTest\"\n    \n            FreeCAD.ActiveDocument.recompute()\n            self.TE_05_01_textEdit.append( objectLabel + \" \" + text + \"_Prec(\" + str(pointsPerMm) + \") Sweep\") # give Label in TE_05_01_textEdit\n        except Exception:\n            try:\n                FreeCADGui.ActiveDocument.removeObject(myCircle.Name)\n            except Exception:\n                None\n            try:\n                FreeCADGui.ActiveDocument.removeObject(mySweep.Name)\n            except Exception:\n                None\n            App.Console.PrintError(\"Error create sweep\" + \"\\n\")\n        Chrono(1)\n#        print( \"on_PB_05_07_Test_Sweep_clicked\")\n\n    def on_CB_05_01_Solid_clicked(self):                                                      # on_CB_05_01_Solid_clicked\n        global mySweepSolid\n\n        if self.CB_05_01_Solid.isChecked():\n            mySweepSolid = 1\n        else:\n            mySweepSolid = 0\n        print( \"on_CB_05_01_Solid_clicked \", str(mySweepSolid))\n\n    def on_CB_05_02_Frenet_clicked(self):                                                     # on_CB_05_02_Frenet_clicked\n        global mySweepFrenet\n\n        if self.CB_05_02_Frenet.isChecked():\n            mySweepFrenet = 1\n        else:\n            mySweepFrenet = 0\n        print( \"on_CB_05_01_Solid_clicked \", str(mySweepFrenet))\n\n    def on_PB_05_08_Recompute_clicked(self):\n        import FreeCAD\n\n        FreeCAD.ActiveDocument.recompute()\n#        print( \"on_PB_05_08_Recompute_clicked \")\n\n    def on_PB_06_01_Save_Data_File_clicked(self):                                             #on_PB_06_01_Save_Data_File_clicked save data Tmp\n        global pp\n        global path\n        global nomFichier\n        global objectLabel\n        global pointsPerMm\n        global text\n        global comptDataSaved\n        global savedata\n        global createZero\n\n        if len(pp) != 0:\n            comptDataSaved += 1\n\n            nomFichier2 = nomFichier.split(\".\")\n            nomFichier2 = nomFichier2[-2][:-3]\n#            nomFichier2 = nomFichier2[:-3]\n\n            if savedata  ==  0: # XYZ\n                    nomFichier2 = nomFichier\n\n            elif savedata == 1: # XY\n                if createZero == 1:\n                    nomFichier2 += \"XY0.asc\"\n                else:\n                    nomFichier2 += \"XY-.asc\"\n\n            elif savedata == 2: # YZ\n                if createZero == 1:\n                    nomFichier2 += \"0YZ.asc\"\n                else:\n                    nomFichier2 += \"-YZ.asc\"\n\n            elif savedata == 3: # XZ\n                if createZero == 1:\n                    nomFichier2 += \"X0Z.asc\"\n                else:\n                    nomFichier2 += \"X-Z.asc\"\n\n            if self.CB_06_01_Contigu_Data.isChecked:\n                del pp[0]\n\n            file = open(path + nomFichier2, \"a\")                                               # open the file r=read w=write a=append\n            App.Console.PrintMessage(nomFichier2 + \" ( \" + str(len(pp)) + \" )\" + \"\\n\")\n#            print( pp)\n            for i in pp:                                                                       # save coordinates in file\n                \n                if savedata  ==  0: # XYZ\n                    file.write(str(i.x)+\" \"+str(i.y)+\" \"+str(i.z)+\"\\n\")\n\n                elif savedata == 1: # XY\n                    if createZero == 1:\n                        file.write(str(i.x)+\" \"+str(i.y)+\" 0.0\"+\"\\n\")\n                    else:\n                        file.write(str(i.x)+\" \"+str(i.y)+\"\"+\"\\n\")\n\n                elif savedata == 2: # YZ\n                    if createZero == 1:\n                        file.write(\"0.0 \"+str(i.y)+\" \"+str(i.z)+\"\\n\")\n                    else:\n                        file.write(\"\"+str(i.y)+\" \"+str(i.z)+\"\\n\")\n\n                elif savedata == 3: # XZ\n                    if createZero == 1:\n                        file.write(str(i.x)+\" 0.0 \"+str(i.z)+\"\\n\")\n                    else:\n                        file.write(str(i.x)+\" \"+str(i.z)+\"\\n\")\n\n            file.close()\n\n            del pp[:]   #a verifier !!!\n            self.Label_05_01_Data.setText(\"Number coordinates : \" + str(len(pp)))\n            self.Label_05_01_Data.setStyleSheet(\"color : #008500\")                            # Color text\n\n            self.PB_05_01_Wire_For_Test.setStyleSheet(\"background-color: QPalette.Base\")      # origin system\n            self.PB_05_02_Reset_Data.setStyleSheet(\"background-color: QPalette.Base\")         # origin system\n            self.PB_05_03_Reuse.setStyleSheet(\"background-color: QPalette.Base\")              # origin system\n\n            self.PB_06_01_Save_Data_File.setStyleSheet(\"background-color: green\")             #green\n            self.PB_06_02_Read_Data_File.setStyleSheet(\"background-color: green\")             #green\n            self.PB_06_03_Reset_Data_File.setStyleSheet(\"background-color: green\")            #green\n            self.PB_01_Save.setStyleSheet(\"background-color: green\")                          #green\n\n            self.TE_05_01_textEdit.append( str(comptDataSaved) + \" : \" + objectLabel + \" \" + text + \"_Prec(\" + str(pointsPerMm) + \") saved_\" + nomFichier2[11:-4]) # give Label in TE_05_01_textEdit\n        else:\n            self.PB_06_01_Save_Data_File.setStyleSheet(\"background-color: red\")                 #red\n            App.Console.PrintError(\"Not data to save\" + \"\\n\")\n#        print( \"on_PB_06_01_Save_Data_File_clicked\")\n\n    def decodeData(self,p):\n        global pp\n        global createCloud\n        global createShell\n        global createPoint\n        global nomFichier\n        global comptData\n        global sautData\n        global rgbPoints\n        global suppressBegin\n        global suppressEnd\n\n        X = Y = Z  = 0.0\n        comptData = 0\n        self.PBar_05_01_ProgressBar.setMinimum(0)\n        self.PBar_05_01_ProgressBar.setMaximum(len(p))\n\n        ###### variables for PCD begin\n        passage = 1                                             # open the passage PCD datas\n        VERSION = FIELDS = SIZE = TYPE = COUNT = WIDTH = HEIGHT = VIEWPOINT = POINTS = DATA = \"\"\n        rgb = WIDTH_X = HEIGHT_Y = 0.0\n        del rgbPoints[:]\n        ###### variables for PCD end\n        longueurExecute = err = 0\n        longueurFichier = len(p)\n        print(\"len file \",len(p))\n\n        for ligne in p:\n\n            longueurExecute += 1\n            print( longueurExecute,\"/\",longueurFichier)\n\n            if (p[0].find(\"PCD\") != -1) and (passage == 1) :    # The PCD configuration datas are not used in the macro\n                                                                # http://pointclouds.org/documentation/tutorials/pcd_file_format.php\n                li2 = ligne.split()\n                try:\n                    if li2[0] == \"VERSION\"   : VERSION   = li2[1] ; print( \"VERSION   \",VERSION )    # VERSION   # .5        # .5              # 0.7           # .7            # .7            #\n                    if li2[0] == \"FIELDS\"    : FIELDS    = li2[1] ; print( \"FIELDS    \",FIELDS )     # FIELDS    # x y z     # x y z intensity # rgba          # x y z         # x y z rgb     #\n                    if li2[0] == \"SIZE\"      : SIZE      = li2[1] ; print( \"SIZE      \",SIZE )       # SIZE      # 4 4 4     # 4 4 4 4         # 4             # 4 4 4         # 4 4 4 4       #\n                    if li2[0] == \"TYPE\"      : TYPE      = li2[1] ; print( \"TYPE      \",TYPE )       # TYPE      # F F F     # F F F F         # U             # F F F         # F F F F       #\n                    if li2[0] == \"COUNT\"     : COUNT     = li2[1] ; print( \"COUNT     \",COUNT )      # COUNT     # 1 1 1     # 1 1 1 1         # 1             # 1 1 1         # 1 1 1 1       #\n                    if li2[0] == \"WIDTH\"     : WIDTH     = li2[1] ; print( \"WIDTH     \",WIDTH )      # WIDTH     # 397       # 167198          # 640           # 10031         # 213           #\n                    if li2[0] == \"HEIGHT\"    : HEIGHT    = li2[1] ; print( \"HEIGHT    \",HEIGHT )     # HEIGHT    # 1         # 1               # 480           # 1             # 1             #\n                    if li2[0] == \"VIEWPOINT\" : VIEWPOINT = li2[1] ; print( \"VIEWPOINT \",VIEWPOINT )  # VIEWPOINT # neant     # neant           # 0 0 0 1 0 0 0 # 0 0 0 1 0 0 0 # 0 0 0 1 0 0 0 #\n                    if li2[0] == \"POINTS\"    : POINTS    = li2[1] ; print( \"POINTS    \",POINTS )     # POINTS    # 397       # 167198          # 307200        # 10031         # 213           #\n                    if li2[0] == \"DATA\"      :                                                     # DATA      # ascii     # ascii           # ascii         # ascii         # ascii         #\n                        DATA      = li2[1]                        ; print( \"DATA      \",DATA )       # DATA      # ascii\n                        passage = 0                                                                # Cutting the passage PCD datas    \n                except Exception:\n                    App.Console.PrintError(\"Error read header PCD\" + \"\\n\")\n\n            else:\n\n                coordinates = ligne.split()\n#                print( coordinates))\n                comptData += 1\n\n                if (comptData % sautData == 0) and (len(coordinates) != 0):\n                    self.PBar_05_01_ProgressBar.setValue(comptData)\n##\n## ici pts = X Y Z Intensity R G B.\n##100140   = longueur \n##0.4042519999999996 -3.476741 -1.634333 53 9 11 6\n##\n##from FreeCAD import Base\n##fichier  = str(\"C:/Provisoire400/DXF_ASC/Autres Points/internet_00.pts\")\n##print( fichier\n##file = open(fichier, \"r\")                                  # open the file read\n##import Points\n##pnt=Points.Points()\n##pp = []\n##long = file.readline()\n##print( long\n##for ligne in file:\n##    X,Y,Z,a,b,c,d = ligne.split()                                 # separate the coordinates pour pct\n##    a = FreeCAD.Vector(float(X), float(Y), float(Z))\n##    pnt.addPoints([a])\n##Points.show(pnt)\n##\n                    try:                                                                          # The PCD configuration ver .7\n                        X, Y, Z, rgb = coordinates      # rgb float('4.2108e+06') = 4210800.0     # separate the coordinates 4 fields\n                        try:\n                            a =  bin(int(float(rgb)))\n                            b = a[a.find(\"b\")+1:]\n                            rP = float((int(b[len(b)-8:],2)) * (1.0/255.0))                       # decode Red    color for FreeCAD\n                            gP = float((int(b[len(b)-16:-8],2)) * (1.0/255.0))                    # decode Ground color for FreeCAD\n                            bP = float((int(b[:-16],2)) * (1.0/255.0))                            # decode Blue   color for FreeCAD\n                            rgbPoints.append([rP, gP, bP])\n                        except Exception:\n                            rgbPoints.append([0.0, 1.0, 0.0])\n                    except Exception:\n                        try:\n                            X, Y, Z = coordinates                                                 # separate the coordinates 3 fields\n                        except Exception:\n                            try:\n                                X, Y = coordinates                                                # separate the coordinates 2 fields\n                                Z    = 0.0\n                            except Exception:\n                                X = WIDTH_X                                                       # points as one photo\n                                Y = HEIGHT_Y\n                                Z = 0.0\n\n                                App.Console.PrintMessage(str(WIDTH_X) +\" \"+ str(HEIGHT_Y) +\" \"+ str(WIDTH) + \"\\n\")\n                                if WIDTH_X == (float(WIDTH) - 1):\n                                    HEIGHT_Y += 1\n                                    WIDTH_X = -1.0\n                                WIDTH_X += 1\n    \n                                a =  bin(int(float(ligne)))\n                                b = a[a.find(\"b\")+1:]\n                                try:\n                                    rP = float((int(b[len(b)-8:],2)) * (1.0/255.0))                   # decode Red color for FreeCAD\n                                except Exception:\n                                    rp = 0.0\n                                try:\n                                    gP = float((int(b[len(b)-16:-8],2)) * (1.0/255.0))                # decode Ground color for FreeCAD\n                                except Exception:\n                                    rp = 0.0\n                                try:\n                                    bP = float((int(b[:-16],2)) * (1.0/255.0))                        # decode Blue   color for FreeCAD\n                                except Exception:\n                                    rp = 0.0\n    \n                                rgbPoints.append([rP, gP, bP])\n\n                    if suppressEnd == 0:\n                        X = X[suppressBegin:]\n                        Y = Y[suppressBegin:]\n                        Z = Z[suppressBegin:]\n                    else:\n                        X = X[suppressBegin:-suppressEnd]\n                        Y = Y[suppressBegin:-suppressEnd]\n                        Z = Z[suppressBegin:-suppressEnd]\n\n                    try:\n                        pp.append(FreeCAD.Vector(float(X),float(Y),float(Z))) # append the coordinates XYZ\n                    except Exception:\n                        print(\"Error coordinates type \", coordinates)\n#                        print( \"ouille\")\n\n#                    print( X,\" \",Y,\" \",Z,\" \",rP,\" \",gP,\" \",bP)\n                \n                    Gui.updateGui()                                                           # rafraichi l'ecran\n\n        self.PBar_05_01_ProgressBar.setValue(0)\n        self.TE_05_01_textEdit.append(\"File : \" + nomFichier + \"\\nNumber coordinates :\" + str(comptData))\n        self.Label_05_01_Data.setText(\"Number coordinates : \" + str(comptData))\n        self.Label_05_01_Data.setStyleSheet(\"color : #008500\")                                # Color text\n#        print( \"decodeData\")\n\n    def on_SP_06_01_Step_valueChanged(self,value):                                            # on_SP_06_01_Step_valueChanged\n        global sautData\n\n        sautData = value\n#        print( \"on_SP_06_01_Step_valueChanged \",str(sautData))\n\n    def on_PB_06_02_Read_Data_File_clicked(self):                                             # on_PB_06_02_Read_Data_File_clicked\n        global path\n        global nomFichier\n        global pp\n\n        try:                                        # ajouter lire les asc avec entete\n            file = open(path+nomFichier, \"r\")                                                 # open the file read imposed\n            del pp[:]\n            p = []\n            del p[:]\n            p = file.readlines()\n            file.close()\n            App.Console.PrintMessage(\"Read : \"+ nomFichier + \"\\n\")\n            self.TE_05_01_textEdit.append(\"File : \" + nomFichier + \"\\nFile length :\" + str(len(p)))\n            self.Label_05_01_Data.setText(\"Data object : \" + str(len(p)))\n            self.Label_05_01_Data.setStyleSheet(\"color : #008500\")                            # Color text\n            ff = ui\n            ff.decodeData(p)\n            del p[:]\n            ff = ui\n            ff.createWire()\n\n            self.PB_05_01_Wire_For_Test.setStyleSheet(\"background-color: QPalette.Base\")      # origin system\n            self.PB_05_02_Reset_Data.setStyleSheet(\"background-color: QPalette.Base\")         # origin system\n            self.PB_05_03_Reuse.setStyleSheet(\"background-color: QPalette.Base\")              # origin system\n        except Exception:\n            self.PB_06_02_Read_Data_File.setStyleSheet(\"background-color: red\")               #red\n            App.Console.PrintError(\"Not file \" + path + nomFichier + \" existant\" + \"\\n\")\n#        print( \"on_PB_06_02_Read_Data_File_clicked\")\n\n\n    def on_SP_01_suppressBegin_valueChanged(self,value):            # connect on def \"on_SP_01_suppressBegin_valueChanged\"\n        global suppressBegin\n\n        suppressBegin = value\n        print(\"on_SP_01_suppressBegin_valueChanged \",str(suppressBegin))\n\n    def on_SP_02_suppressEnd_valueChanged(self,value):            # connect on def \"on_SP_02_suppressEnd_valueChanged\"\n        global suppressEnd\n\n        suppressEnd = value\n        print(\"on_SP_02_suppressEnd_valueChanged \",str(suppressEnd))\n\n    def on_PB_06_03_Reset_Data_File_clicked(self):                                            # on_PB_06_03_Reset_Data_File_clicked\n        global path\n        global nomFichier\n        global text\n        global comptData\n        global comptDataSaved\n\n        try:\n            os.remove(path + nomFichier)                                                      # delete the file\n            App.Console.PrintMessage(\"File : \" + path + nomFichier + \" Deleted\" + \"\\n\")\n            text = \"\"\n            comptData = 0\n            comptDataSaved = 0\n            self.CB_04_02_Coma.setChecked(False)\n            self.Label_05_01_Data.setText(\"Number coordinates : \" + str(comptData))\n            self.Label_05_01_Data.setStyleSheet(\"color : #008500\")                            # Color text\n            self.PB_06_01_Save_Data_File.setStyleSheet(\"background-color: QPalette.Base\")     # origin system\n            self.PB_06_02_Read_Data_File.setStyleSheet(\"background-color: QPalette.Base\")     # origin system\n            self.PB_06_03_Reset_Data_File.setStyleSheet(\"background-color: QPalette.Base\")    # origin system\n            self.PB_01_Save.setStyleSheet(\"background-color: QPalette.Base\")                  # origin system\n        except Exception:\n            self.PB_06_03_Reset_Data_File.setStyleSheet(\"background-color: red\")                   #red\n            App.Console.PrintError(\"The temporary file \" + nomFichier + \" not  present\" + \"\\n\")\n#        print( \"on_PB_06_03_Reset_Data_File_clicked\")\n\n    def on_PB_01_Save_clicked(self):                                                          # on_PB_01_Save_clicked\n        global path\n        global nomFichier\n#        global s\n\n        try:\n            file = open(path + nomFichier, \"r\")                                               # open the file r=read w=write a=append\n            ##########\n            if self.CB_04_02_Coma.isChecked():      # create coma instead space\n                p = []\n                p = file.readlines()\n                for i in range(len(p)):\n                    p[i] = p[i].replace(\" \",\",\")\n            ##########\n            file.close()\n            self.window.hide()                                                                # hide the window open color\n            pathSave = path\n            SaveName, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, \"Save a file asc\", pathSave,             \"*.asc\") # PySide\n\n            if SaveName == \"\":\n                App.Console.PrintMessage(\"Process aborted\" + \"\\n\")\n            else:\n                nomFichierSave = SaveName\n                try:\n                    if self.CB_04_02_Coma.isChecked():\n                        f = open(nomFichierSave, 'w')\n                        for i in p:\n                            f.write(i)\n                        f.close()\n                        del p[:]\n                    else:\n                        import shutil\n                        shutil.copy(path + nomFichier, nomFichierSave)\n                    App.Console.PrintMessage(\"File saved to \" + SaveName + \"\\n\")\n                except Exception:\n                    App.Console.PrintError(\"Not data for save or error I/O file\" + \"\\n\")\n            self.window.show()                                                                   # show the window and close color\n        except Exception:\n            App.Console.PrintError(\"Not file \" + nomFichier + \" for copy\" + \"\\n\")                # detect error ... display the text in red (PrintError)\n##        App.Console.PrintMessage(\"on_PB_01_Save_clicked\" + \"\\n\")\n\n    def on_PB_02_Read_clicked(self):                                                        # on_PB_02_Read_clicked\n        global pp\n        global path\n        global objectLabel\n        global text\n#        global comptData\n        global OpenName\n\n        OpenName = \"\"\n        OpenName, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, \"Read a file FCDataTest\", path, \"*.asc *.pcd *.txt *.pts *.qvd *.dat\")#PySide\n#   retablir     try:\n        if OpenName != \"\":\n#   retablir             try:\n######################################\n#                print( OpenName)\n##                if OpenName[-4:].upper() == \".PCD\":\n#                import Points\n#                print( OpenName)\n#                Points.open(OpenName)\n#                print( OpenName[-4:].upper())\n######################################\n\n                text = \"\"\n                del pp[:]\n                p = []\n                del p[:]\n                file = open(OpenName, \"r\")     # open the file r=read w=write a=append\n                p = file.readlines()\n\n                if \",\" in p[0] != 0:           # detect coma in file\n                    self.CB_04_02_Coma.setChecked(True)\n                    self.CB_04_02_Coma.setStyleSheet(\"background-color: green\")                  # origin system\n                    for i in range(len(p)):\n                        p[i] = p[i].replace(\",\",\" \")                # replace the coma with space conversion for macro data\n\n                file.close()\n                self.Label_05_01_Data.setText(\"Data object : \" + OpenName + \" \" + str(len(p)))\n                self.Label_05_01_Data.setStyleSheet(\"color : #008500\")                                # Color text\n                self.TE_05_01_textEdit.append(\"File : \" + OpenName + \"\\nFile length :\" + str(len(p)))\n\n                objectLabel = OpenName.split(\"/\")\n                objectLabel = objectLabel[-1]\n                ff = ui\n                ff.decodeData(p)\n                del p[:]\n\n                ff = ui\n                ff.createWire()\n#                except Exception:\n#                    App.Console.PrintError(\"Error read file\" + \"\\n\")\n                self.PBar_05_01_ProgressBar.setValue(0)\n#        except Exception:\n#            None\n        else:\n            App.Console.PrintMessage(\"Proces aborded\" + \"\\n\")\n#        print( \"on_PB_02_Read_clicked\")\n\n    def on_PB_03_Reset_clicked(self):\n        global revers\n        global createLine\n        global typeLine\n        global typeArc\n        global wireClose\n        global wireFace\n        global pointsPerMm\n        global createCloud\n        global createShell\n        global createPoint\n        global savedata\n        global pp\n        global comptData\n        global comptDataSaved\n        global sautData\n        global createZero\n        global mySweepSolid\n        global mySweepFrenet\n        global verbose\n        global check_To_Mouse\n        global vecteurSou_Comp\n        global path\n        global nomFichier\n\n\n        self.red       = 1.0\n        self.green     = 0.0\n        self.blue      = 0.0\n\n        self.GBox_00_Configuration.setEnabled(True)\n        self.GBox_05_Data_Wire_Gui.setEnabled(True)\n        self.GBox_06_Data_File.setEnabled(True)\n        check_To_Mouse = 0\n        vecteurSou_Comp = 0\n        self.CB_03_01a_To_Mouse.setChecked(False)\n        self.CB_03_01a_To_Mouse.setVisible(False)\n        self.PB_00_Mouse_Mode.setVisible(False)\n\n        self.CB_01_01_Reverse.setEnabled(False)\n        self.CB_01_01_Reverse.setChecked(False)\n        self.TE_05_01_textEdit.clear()\n        self.TE_05_01_textEdit.setText(\"List Data object saved in file\")\n        self.Label_05_01_Data.setText(\"Reset\")\n        self.Label_05_01_Data.setStyleSheet(\"color : #000000\")                                # Color text\n        revers      = 0\n        self.RB_01_01_Reversed.setChecked(True)\n        self.CB_01_01_Reverse.setChecked(False)\n        self.CB_01_01_Reverse.setEnabled(False)\n\n        self.GBox_02_Type_Line.setChecked(True)\n        createLine  = 1\n        self.RB_02_01_MakeWire.setChecked(True)\n        typeLine    = 0\n        self.PB_05_01_Wire_For_Test.setText(\"Ok MakeWire\")\n        self.CB_02_01_Arc.setChecked(False)\n        typeArc   = 0\n        self.CB_03_01_Close.setChecked(False)\n        self.CB_03_01_Close.setVisible(True)\n        self.CB_03_01b_CloseFo.setChecked(False)\n        self.CB_03_01b_CloseFo.setVisible(True)\n        wireClose   = 0\n        self.CB_03_02_Create_Face.setChecked(False)\n        self.CB_03_02_Create_Face.setVisible(True)\n        wireFace    = 0\n        createCloud    = 0\n        self.CB_03_03_Create_Points.setChecked(False)\n        self.CB_03_02b_Create_Cloud.setVisible(False)\n        createPoint = 0\n        self.CB_03_02bb_Create_Shell.setVisible(False)\n        createShell = 0\n        self.DSB_00_01_Precision.setValue(1)\n        pointsPerMm = 1.0\n        self.RB_04_01_XYZ.setChecked(True)\n        savedata    = 0\n        self.CB_04_01_Zero.setChecked(False)\n        createZero = 0\n        self.CB_04_02_Coma.setChecked(False)\n        self.CB_04_02_Coma.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.RB_04_02_XY.setText(\"X Y\")\n        self.RB_04_03_YZ.setText(\"Y Z\")\n        self.RB_04_04_XZ.setText(\"X Z\")\n        del pp[:]\n        try:\n            os.remove(path + nomFichier)                                                      # efface FCDataTest_XYZ.asc\n        except Exception:\n            None\n        mySweepSolid = 1\n        self.CB_05_01_Solid.setChecked(True)\n        mySweepFrenet = 1\n        self.CB_05_02_Frenet.setChecked(True)\n        comptData   = 0\n        comptDataSaved = 0\n        self.SP_06_01_Step.setValue(1)\n        sautData = 1\n        self.CB_00_Verbose.setChecked(True)\n        verbose = 1\n\n        self.CB_06_01_Contigu_Data.setChecked(False)\n        self.PBar_05_01_ProgressBar.setValue(0)\n        self.PB_04_Color.setStyleSheet(\"background-color: QPalette.Base\")                     # origin system\n        self.PB_05_01_Wire_For_Test.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.PB_05_02_Reset_Data.setStyleSheet(\"background-color: QPalette.Base\")             # origin system\n        self.PB_05_03_Reuse.setStyleSheet(\"background-color: QPalette.Base\")                  # origin system\n        self.PB_05_06_Del_Line.setStyleSheet(\"background-color: QPalette.Base\")               # origin system\n        self.PB_06_01_Save_Data_File.setStyleSheet(\"background-color: QPalette.Base\")         # origin system\n        self.PB_06_02_Read_Data_File.setStyleSheet(\"background-color: QPalette.Base\")         # origin system\n        self.PB_06_03_Reset_Data_File.setStyleSheet(\"background-color: QPalette.Base\")        # origin system\n        self.PB_01_Save.setStyleSheet(\"background-color: QPalette.Base\")                      # origin system\n#        App.Console.PrintMessage(\"on_PB_03_Reset_clicked\" + \"\\n\")\n\n    def on_PB_04_Color_clicked(self):\n        self.PB_04_Color.setStyleSheet(\"background-color: QPalette.Base\")                    # origin system\n        self.window.hide()                                                                   # hide the window open color\n        couleur = QtGui.QColorDialog.getColor()\n        if couleur.isValid():\n            self.red   = couleur.redF()\n            self.green = couleur.greenF()\n            self.blue  = couleur.blueF()\n        self.PB_04_Color.setStyleSheet(\"background-color: rgb(\"+str(self.red*255)+\",\"+str(self.green*255)+\",\"+str(self.blue*255)+\"); color: cmj(\"+str(255)+\",\"+str(255)+\",\"+str(255)+\")\")\n        self.window.show()                                                                    # show the window and close color\n#        App.Console.PrintMessage(\"on_PB_04_Color_clicked\" + \"\\n\")\n\n    def on_PB_05_Dowgrade_clicked(self):                                                      # on_PB_05_Dowgrade_clicked\n        Draft.downgrade(FreeCADGui.Selection.getSelection(),delete=True) #False\n#        App.Console.PrintMessage(\"on_PB_05_Dowgrade_clicked\" + \"\\n\")\n\n    def on_PB_07_Duplicate_clicked(self):                                                          # on_PB_07_Duplicate_clicked\n        try:\n            sel = Gui.Selection.getSelection()\n            s   = Gui.Selection.getSelectionEx()\n            i2 = ii2 = -1 \n            for i in s:\n                i2 += 1\n                ii2 = -1\n                FreeCADGui.Selection.getSelectionEx()[i2].SubObjects[ii2]\n                for ii in i.SubElementNames:\n                    placementOrigine = objectRealPlacement3D(FreeCAD.ActiveDocument.getObject(i.ObjectName))# search the original Placement\n                    ii2 += 1\n                    Part.show(FreeCADGui.Selection.getSelectionEx()[i2].SubObjects[ii2].copy())   # create repro shape subObject\n                    #print( i2+1 ,\"/\", ii2+1 ,\"/\", len(s) ,\" \", i.ObjectName ,\" \", ii)             # display the info SubObject\n                    a = App.ActiveDocument.ActiveObject\n                    a.Placement.Base = placementOrigine\n                    a.Placement.Rotation = App.Rotation(objectPlacementAngle[0], objectPlacementAngle[1], objectPlacementAngle[2])\n                    #    object Name  / original object Name / SubObject Name\n                    a.Label = a.Name + \" \" + i.ObjectName + \" \" + ii                              # Label for the repro shape\n                    try:\n                        FreeCADGui.activeDocument().activeObject().LineColor  = (1.0,0.0,0.0)     # give LineColor\n                        FreeCADGui.activeDocument().activeObject().PointColor = (1.0,0.0,0.0)     # give PointColor\n                        FreeCADGui.activeDocument().activeObject().ShapeColor = (1.0,0.0,0.0)     # give ShapeColor\n                    except Exception:\n                        None\n        except Exception:\n            #print( \"Not SubObject\")\n            None\n        FreeCAD.ActiveDocument.recompute()\n\n    def on_PB_06_Quit_clicked(self):                                                          # on_PB_06_Quit_clicked\n        global path\n        global nomFichier\n        global s\n        FreeCADGui.Selection.removeObserver(s)                                                # desinstalle la fonction residente\n        try:\n            MainWindow.setWindowState(Qt.WindowMinimized)                           # PySide cette WindowMinimized la fenetre avant de quitter\n        except Exception:\n            None\n\n        try:\n            file = open(path + nomFichier, \"r\")                                               # open the file r=read w=write a=append here for test\n            file.close()\n            reply = QtGui.QMessageBox.question(None, \"\", \"Give name for preserve the coordinates file\\n or click Cancel to quit\",\n                     QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)\n            if reply == QtGui.QMessageBox.Yes:\n                ff = ui\n                ff.on_PB_01_Save_clicked()\n        except Exception:\n            None\n\n        if os.path.isfile(path + nomFichier):\n            try:\n                os.remove(path + nomFichier)                                                  # efface FCDataTest_XYZ.asc\n                App.Console.PrintMessage(nomFichier + \" deleted\" + \"\\n\")\n            except Exception:\n                App.Console.PrintError(\"Error delete file\" + \"\\n\")\n\n        App.Console.PrintMessage(\"End FCDXF_to_Shape\" + \"\\n\")\n        self.window.hide()                                                                    # hide the window and close the macro\n#        App.Console.PrintMessage(\"on_PB_06_Quit_clicked\" + \"\\n\")\n\n    def on_CB_00_Verbose_clicked(self):\n        global verbose\n        verbose = 0\n        if self.CB_00_Verbose.isChecked():\n            verbose = 1\n#        FreeCAD.Console.PrintMessage(\"on_CB_00_Verbose_clicked\" + \"\\n\")\n\n#    def on_textEdit_Changed(self):                                                            # on_textEdit_Changed\n#        texte = unicode(self.TE_05_01_textEdit.toPlainText())\n#        print( \"on_textEdit_Changed \",texte)\n\n##################################################################################################\nclass SelObserver:\n    def addSelection(self, document, object, element, position):  # Selection\n        global ui\n        global check_To_Mouse\n        global vecteurSou\n        global pointsName\n        \n        if check_To_Mouse == 1:                    # mouse mode\n            pointsName.append(object)\n            vecteurSou = FreeCAD.Vector(position)\n            ff = ui\n            ff.mouse_Mode()\n\n        try:\n            Object = Gui.Selection.getSelectionEx()[0].SubObjects[0]\n#            try:\n#                print( \"Curve : \",Object.Curve)\n#            except Exception:\n#                print( \"No attribute 'Curve'\")\n            print( vecteurSou)\n        except Exception:\n            None\n        ff = ui\n        ff.on_Label_04_01()\n##################################################################################################\n\ndoc = FreeCAD.ActiveDocument\nif doc == None:\n    doc = FreeCAD.newDocument()\n\ns=SelObserver()\nFreeCADGui.Selection.addObserver(s)               # installe the function in resident mode\n\nMainWindow = QtGui.QMainWindow()\nui = Ui_MainWindow()\nui.setupUi(MainWindow)\nMainWindow.show()\n\n",
    "url": "https://wiki.freecad.org/Macro_Dxf_To_Shape",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/0596ad522b151806d5970586a5051e4b/raw/23fe427f5f00df81c9a7d0a877cf58c052ea5f76/Macro_DXF_to_Shape.FCMacro",
    "wiki": "",
    "version": " modified 00.00",
    "license": "",
    "date": "2020/09/04",
    "src_filename": "",
    "filename_from_url": "",
    "author": "mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Dxf_To_Shape.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/f/f4/Macro_Dxf_To_Shape.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Extract Wires from Mesh",
    "on_wiki": true,
    "on_git": false,
    "desc": "Finds boundary wires in selected mesh objects. Boundary wires are formed from all the edges found in the mesh that are shared by only one face, that is, they are \"border\" edges. The found wires get added to the document (one compound per mesh object), while the mesh itself gets hidden.<br /><br />Macro version: 1<br />Last modified: 2016-12-17<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/2/28/Macro_Extract_Wires_from_Mesh.png\">ToolBar Icon</a><br />Author: Yorik<br /> ",
    "comment": "Finds boundary wires in selected mesh objects. Boundary wires are formed from all the edges found in the mesh that are shared by only one face, that is, they are \"border\" edges. The found wires get added to the document (one compound per mesh object), while the mesh itself gets hidden.",
    "code": "#!/usr/bin/python\n\n# This macro will extract wires from selected meshes\n# The result is a new Part Compound containing wires, one per original mesh object\n# The selected meshes will be hidden but still selected after the operation.\n# Warning, it takes a bit of time...\n\nimport FreeCAD,FreeCADGui,Part,Draft,DraftGeomUtils,Mesh\nfor obj in FreeCADGui.Selection.getSelection():\n    if obj.isDerivedFrom(\"Mesh::Feature\"):\n        shape = Part.Shape()\n        shape.makeShapeFromMesh(obj.Mesh.Topology,0.1)\n        edges = []\n        lut = {}\n        for f in shape.Faces:\n            for e in f.Edges:\n                lut.setdefault(e.hashCode(),[]).append(e)\n        for k,v in lut.items():\n            if len(v) == 1:\n                edges.extend(v)\n        if edges:\n            wires = DraftGeomUtils.findWires(edges)\n            if wires:\n                Part.show(Part.makeCompound(wires))\n                obj.ViewObject.hide()",
    "url": "https://wiki.freecad.org/Macro_Extract_Wires_from_Mesh",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2016-12-17",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Yorik",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Extract_Wires_from_Mesh.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/2/28/Macro_Extract_Wires_from_Mesh.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FaceToSketch",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro breaks down your form with function Draft Downgrade and transforms the face selected in a sketch without constraints, and ready to be modified.<br /><br />Macro version: 1.0<br />Last modified: 2013-12-23<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/6/6e/Macro_FaceToSketch.png\">ToolBar Icon</a><br />Author: Jreinhardt<br /> ",
    "comment": "This macro breaks down your form with function Draft Downgrade and transforms the face selected in a sketch without constraints, and ready to be modified.",
    "code": "import Draft\n  \nwires,_faces = Draft.downgrade(FreeCADGui.Selection.getSelection(),delete=True)\n  \nsketch = Draft.makeSketch(wires[0:1])\nfor wire in wires[1:]:\n    Draft.makeSketch([wire],addTo=sketch)\n  \nfor wire in wires:\n    FreeCAD.ActiveDocument.removeObject(wire.Name)",
    "url": "https://wiki.freecad.org/Macro_FaceToSketch",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2013-12-23",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Jreinhardt",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_FaceToSketch.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/6/6e/Macro_FaceToSketch.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FCBmpImport",
    "on_wiki": true,
    "on_git": false,
    "desc": "Import BMP monochrome and grayscale images into FreeCAD as sketches, solids, wires, faces or lithophane.<br /><br />Macro version: 0.2021.09.23<br />Last modified: 2021-09-23<br />FreeCAD version: 0.18 or later<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/File:FCBmpImportScreenshot.png\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Import BMP monochrome and grayscale images into FreeCAD as sketches, solids, wires, faces or lithophane.",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2018 <TheMarkster>                                      *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License at http://www.gnu.org/licenses     *\n*   for more details.                                                     *\n*                                                                         *\n*   For more information about the GNU Library General Public License     *\n*   write to the Free Software Foundation, Inc., 59 Temple Place,         *\n*   Suite 330, Boston, MA  02111-1307 USA                                 *\n*                                                                         *\n***************************************************************************\n\"\"\"\n\n\n\n__title__ = \"FCBmpImport\"\n__author__ = \"TheMarkster\"\n__url__ = \"https://github.com/mwganson/fcbmpimport\"\n__Wiki__ = \"https://github.com/mwganson/fcbmpimport/blob/master/README.md\"\n__date__ = \"2021.09.23\" #year.month.date and optional a,b,c, etc. subrevision letter, e.g. 2018.10.16a\n__version__ = __date__\n\nVERSION_STRING = __title__ + ' Macro v0.' + __version__\n\nimport FreeCAD\nimport Part\nfrom FreeCAD import Base\nimport struct\nimport math\nimport time\nfrom PySide import QtCore, QtGui\ntry:\n    import shiboken2 as shiboken\nexcept:\n    shiboken = None\nimport sys\nfrom itertools import groupby\nimport PartGui\nimport base64\nimport ast\nimport operator as op\nimport Draft\nimport OpenSCADUtils\nimport locale\nimport re\nimport DraftVecUtils,DraftGeomUtils\n\n\n\n#from QTDesigner via PySide uic.py\nclass Ui_MainWindow(object):\n    def setupUi(self, MainWindow):\n        MainWindow.setObjectName(\"MainWindow\")\n        MainWindow.resize(636, 512)\n        MainWindow.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)\n        MainWindow.setAttribute(QtCore.Qt.WA_WindowPropagation, True) #inherit parent fonts, so comment out font-related below\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Helvetica\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #MainWindow.setFont(font)\n        MainWindow.setDockNestingEnabled(True)\n        self.centralwidget = QtGui.QWidget(MainWindow)\n        self.centralwidget.setObjectName(\"centralwidget\")\n        self.imagePreviewLabel = QtGui.QLabel(self.centralwidget)\n        self.imagePreviewLabel.setGeometry(QtCore.QRect(180, 0, 451, 20))\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.imagePreviewLabel.setFont(font)\n        self.imagePreviewLabel.setObjectName(\"imagePreviewLabel\")\n        self.verticalGroupBox_2 = QtGui.QGroupBox(self.centralwidget)\n        self.verticalGroupBox_2.setGeometry(QtCore.QRect(440, 340, 181, 151))\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.verticalGroupBox_2.setFont(font)\n        self.verticalGroupBox_2.setObjectName(\"verticalGroupBox_2\")\n        self.verticalLayout = QtGui.QVBoxLayout(self.verticalGroupBox_2)\n        self.verticalLayout.setObjectName(\"verticalLayout\")\n        self.previewButton = QtGui.QPushButton(self.verticalGroupBox_2)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.previewButton.setFont(font)\n        self.previewButton.setObjectName(\"previewButton\")\n        self.verticalLayout.addWidget(self.previewButton)\n        self.horizontalLayout_5 = QtGui.QHBoxLayout()\n        self.horizontalLayout_5.setObjectName(\"horizontalLayout_5\")\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n\n        self.verticalLayout.addLayout(self.horizontalLayout_5)\n        self.horizontalLayout_4 = QtGui.QHBoxLayout()\n        self.horizontalLayout_4.setObjectName(\"horizontalLayout_4\")\n        self.importAsSolidButton = QtGui.QPushButton(self.verticalGroupBox_2)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.importAsSolidButton.setFont(font)\n        self.importAsSolidButton.setObjectName(\"importAsSolidButton\")\n        self.horizontalLayout_4.addWidget(self.importAsSolidButton)\n        self.importAsSketchButton = QtGui.QPushButton(self.verticalGroupBox_2)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.importAsSketchButton.setFont(font)\n        self.importAsSketchButton.setObjectName(\"importAsSketchButton\")\n        self.horizontalLayout_4.addWidget(self.importAsSketchButton)\n        self.verticalLayout.addLayout(self.horizontalLayout_4)\n        self.horizontalLayout_2 = QtGui.QHBoxLayout()\n        self.horizontalLayout_2.setObjectName(\"horizontalLayout_2\")\n        self.importAsPointButton = QtGui.QPushButton(self.verticalGroupBox_2)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.importAsPointButton.setFont(font)\n        self.importAsPointButton.setObjectName(\"importAsPointButton\")\n        self.horizontalLayout_2.addWidget(self.importAsPointButton)\n        self.importAsWireButton = QtGui.QPushButton(self.verticalGroupBox_2)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.importAsWireButton.setFont(font)\n        self.importAsWireButton.setObjectName(\"importAsWireButton\")\n        self.horizontalLayout_2.addWidget(self.importAsWireButton)\n        self.verticalLayout.addLayout(self.horizontalLayout_2)\n        self.offsetsGroupBox = QtGui.QGroupBox(self.centralwidget)\n        self.offsetsGroupBox.setGeometry(QtCore.QRect(10, 349, 421, 141))\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.offsetsGroupBox.setFont(font)\n        self.offsetsGroupBox.setTitle(\"\")\n        self.offsetsGroupBox.setObjectName(\"offsetsGroupBox\")\n        self.gridLayout = QtGui.QGridLayout(self.offsetsGroupBox)\n        self.gridLayout.setObjectName(\"gridLayout\")\n        self.horizontalLayout = QtGui.QHBoxLayout()\n        self.horizontalLayout.setObjectName(\"horizontalLayout\")\n        self.verticalLayout_3 = QtGui.QVBoxLayout()\n        self.verticalLayout_3.setObjectName(\"verticalLayout_3\")\n        self.scaleLabel = QtGui.QLabel(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.scaleLabel.setFont(font)\n        self.scaleLabel.setObjectName(\"scaleLabel\")\n        self.verticalLayout_3.addWidget(self.scaleLabel)\n        self.xOffsetLabel = QtGui.QLabel(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.xOffsetLabel.setFont(font)\n        self.xOffsetLabel.setObjectName(\"xOffsetLabel\")\n        self.verticalLayout_3.addWidget(self.xOffsetLabel)\n        self.yOffsetLabel = QtGui.QLabel(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.yOffsetLabel.setFont(font)\n        self.yOffsetLabel.setObjectName(\"yOffsetLabel\")\n        self.verticalLayout_3.addWidget(self.yOffsetLabel)\n        self.zOffsetLabel = QtGui.QLabel(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.zOffsetLabel.setFont(font)\n        self.zOffsetLabel.setObjectName(\"zOffsetLabel\")\n        self.verticalLayout_3.addWidget(self.zOffsetLabel)\n        self.horizontalLayout.addLayout(self.verticalLayout_3)\n        self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)\n        self.verticalLayout_4 = QtGui.QVBoxLayout()\n        self.verticalLayout_4.setObjectName(\"verticalLayout_4\")\n        self.scaleEdit = QtGui.QLineEdit(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.scaleEdit.setFont(font)\n        self.scaleEdit.setObjectName(\"scaleEdit\")\n        self.verticalLayout_4.addWidget(self.scaleEdit)\n        self.xOffsetEdit = QtGui.QLineEdit(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.xOffsetEdit.setFont(font)\n        self.xOffsetEdit.setObjectName(\"xOffsetEdit\")\n        self.verticalLayout_4.addWidget(self.xOffsetEdit)\n        self.yOffsetEdit = QtGui.QLineEdit(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.yOffsetEdit.setFont(font)\n        self.yOffsetEdit.setToolTip(\"\")\n        self.yOffsetEdit.setObjectName(\"yOffsetEdit\")\n        self.verticalLayout_4.addWidget(self.yOffsetEdit)\n        self.zOffsetEdit = QtGui.QLineEdit(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.zOffsetEdit.setFont(font)\n        self.zOffsetEdit.setToolTip(\"\")\n        self.zOffsetEdit.setObjectName(\"zOffsetEdit\")\n        self.verticalLayout_4.addWidget(self.zOffsetEdit)\n        self.gridLayout.addLayout(self.verticalLayout_4, 0, 1, 1, 1)\n        self.verticalLayout_8 = QtGui.QVBoxLayout()\n        self.verticalLayout_8.setObjectName(\"verticalLayout_8\")\n        self.baseNameEdit = QtGui.QLineEdit(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.baseNameEdit.setFont(font)\n        self.baseNameEdit.setObjectName(\"baseNameEdit\")\n        self.verticalLayout_8.addWidget(self.baseNameEdit)\n        self.shapeHeightEdit = QtGui.QLineEdit(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.shapeHeightEdit.setFont(font)\n        self.shapeHeightEdit.setObjectName(\"shapeHeightEdit\")\n        self.verticalLayout_8.addWidget(self.shapeHeightEdit)\n        self.recomputeIntervalEdit = QtGui.QLineEdit(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.recomputeIntervalEdit.setFont(font)\n        self.recomputeIntervalEdit.setToolTip(\"\")\n        self.recomputeIntervalEdit.setObjectName(\"recomputeIntervalEdit\")\n        self.verticalLayout_8.addWidget(self.recomputeIntervalEdit)\n        self.cheatFactorEdit = QtGui.QLineEdit(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.cheatFactorEdit.setFont(font)\n        self.cheatFactorEdit.setObjectName(\"cheatFactorEdit\")\n        self.verticalLayout_8.addWidget(self.cheatFactorEdit)\n        self.gridLayout.addLayout(self.verticalLayout_8, 0, 3, 1, 1)\n        self.verticalLayout_7 = QtGui.QVBoxLayout()\n        self.verticalLayout_7.setObjectName(\"verticalLayout_7\")\n        self.baseNameLabel = QtGui.QLabel(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.baseNameLabel.setFont(font)\n        self.baseNameLabel.setObjectName(\"baseNameLabel\")\n        self.verticalLayout_7.addWidget(self.baseNameLabel)\n        self.shapeHeightLabel = QtGui.QLabel(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.shapeHeightLabel.setFont(font)\n        self.shapeHeightLabel.setObjectName(\"shapeHeightLabel\")\n        self.verticalLayout_7.addWidget(self.shapeHeightLabel)\n        self.recomputeIntervalLabel = QtGui.QLabel(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.recomputeIntervalLabel.setFont(font)\n        self.recomputeIntervalLabel.setObjectName(\"recomputeIntervalLabel\")\n        self.verticalLayout_7.addWidget(self.recomputeIntervalLabel)\n        self.cheatFactorLabel = QtGui.QLabel(self.offsetsGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.cheatFactorLabel.setFont(font)\n        self.cheatFactorLabel.setObjectName(\"cheatFactorLabel\")\n        self.verticalLayout_7.addWidget(self.cheatFactorLabel)\n        self.gridLayout.addLayout(self.verticalLayout_7, 0, 2, 1, 1)\n        self.progressGroupBox = QtGui.QGroupBox(self.centralwidget)\n        self.progressGroupBox.setGeometry(QtCore.QRect(10, 50, 161, 101))\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.progressGroupBox.setFont(font)\n        self.progressGroupBox.setTitle(\"\")\n        self.progressGroupBox.setObjectName(\"progressGroupBox\")\n        self.verticalLayout_6 = QtGui.QVBoxLayout(self.progressGroupBox)\n        self.verticalLayout_6.setObjectName(\"verticalLayout_6\")\n        self.progressLabel = QtGui.QLabel(self.progressGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.progressLabel.setFont(font)\n        self.progressLabel.setObjectName(\"progressLabel\")\n        self.verticalLayout_6.addWidget(self.progressLabel)\n        self.progressBar = QtGui.QProgressBar(self.progressGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.progressBar.setFont(font)\n        self.progressBar.setProperty(\"value\", 0)\n        self.progressBar.setObjectName(\"progressBar\")\n        self.verticalLayout_6.addWidget(self.progressBar)\n        self.horizontalLayout_3 = QtGui.QHBoxLayout()\n        self.horizontalLayout_3.setObjectName(\"horizontalLayout_3\")\n        self.abortButton = QtGui.QPushButton(self.progressGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.abortButton.setFont(font)\n        self.abortButton.setObjectName(\"abortButton\")\n        self.horizontalLayout_3.addWidget(self.abortButton)\n        self.exitButton = QtGui.QPushButton(self.progressGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.exitButton.setFont(font)\n        self.exitButton.setObjectName(\"exitButton\")\n        self.horizontalLayout_3.addWidget(self.exitButton)\n        self.verticalLayout_6.addLayout(self.horizontalLayout_3)\n        self.staysOnTopCheckBox = QtGui.QCheckBox(self.centralwidget)\n        self.staysOnTopCheckBox.setGeometry(QtCore.QRect(10, 10, 151, 17))\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.staysOnTopCheckBox.setFont(font)\n        self.staysOnTopCheckBox.setObjectName(\"staysOnTopCheckBox\")\n        self.wireEditGroupBox = QtGui.QGroupBox(self.centralwidget)\n        self.wireEditGroupBox.setGeometry(QtCore.QRect(10, 179, 160, 101))\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.wireEditGroupBox.setFont(font)\n        self.wireEditGroupBox.setObjectName(\"wireEditGroupBox\")\n        self.verticalLayout_9 = QtGui.QVBoxLayout(self.wireEditGroupBox)\n        self.verticalLayout_9.setObjectName(\"verticalLayout_9\")\n        self.horizontalLayout_7 = QtGui.QHBoxLayout()\n        self.horizontalLayout_7.setObjectName(\"horizontalLayout_7\")\n        self.selectOddPointsButton = QtGui.QPushButton(self.wireEditGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.selectOddPointsButton.setFont(font)\n        self.selectOddPointsButton.setObjectName(\"selectOddPointsButton\")\n        self.horizontalLayout_7.addWidget(self.selectOddPointsButton)\n        self.cutSelectedButton = QtGui.QPushButton(self.wireEditGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.cutSelectedButton.setFont(font)\n        self.cutSelectedButton.setObjectName(\"cutSelectedButton\")\n        self.horizontalLayout_7.addWidget(self.cutSelectedButton)\n        self.verticalLayout_9.addLayout(self.horizontalLayout_7)\n        self.horizontalLayout_8 = QtGui.QHBoxLayout()\n        self.horizontalLayout_8.setObjectName(\"horizontalLayout_8\")\n        self.moveButton = QtGui.QPushButton(self.wireEditGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.moveButton.setFont(font)\n        self.moveButton.setObjectName(\"moveButton\")\n        self.horizontalLayout_8.addWidget(self.moveButton)\n        self.insertButton = QtGui.QPushButton(self.wireEditGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.insertButton.setFont(font)\n        self.insertButton.setObjectName(\"insertButton\")\n        self.horizontalLayout_8.addWidget(self.insertButton)\n        self.verticalLayout_9.addLayout(self.horizontalLayout_8)\n        self.blackForegroundCheckbox = QtGui.QCheckBox(self.centralwidget)\n        self.blackForegroundCheckbox.setGeometry(QtCore.QRect(10, 30, 140, 21))\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.blackForegroundCheckbox.setFont(font)\n        self.blackForegroundCheckbox.setObjectName(\"blackForegroundCheckbox\")\n        self.selectFacesButton = QtGui.QPushButton(self.centralwidget)\n        self.selectFacesButton.setGeometry(QtCore.QRect(10, 150, 161, 23))\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.selectFacesButton.setFont(font)\n        self.selectFacesButton.setObjectName(\"selectFacesButton\")\n        self.graphicsView = QtGui.QGraphicsView(self.centralwidget)\n        self.graphicsView.setGeometry(QtCore.QRect(190, 20, 431, 321))\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.graphicsView.setFont(font)\n        self.graphicsView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)\n        self.graphicsView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)\n        self.graphicsView.setDragMode(QtGui.QGraphicsView.ScrollHandDrag)\n        self.graphicsView.setObjectName(\"graphicsView\")\n        self.horizontalGroupBox = QtGui.QGroupBox(self.centralwidget)\n        self.horizontalGroupBox.setGeometry(QtCore.QRect(10, 280, 171, 61))\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.horizontalGroupBox.setFont(font)\n        self.horizontalGroupBox.setObjectName(\"horizontalGroupBox\")\n        self.horizontalLayout_6 = QtGui.QHBoxLayout(self.horizontalGroupBox)\n        self.horizontalLayout_6.setObjectName(\"horizontalLayout_6\")\n        self.zeroButton = QtGui.QPushButton(self.horizontalGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.zeroButton.setFont(font)\n        self.zeroButton.setObjectName(\"zeroButton\")\n        self.horizontalLayout_6.addWidget(self.zeroButton)\n        self.defaultsButton = QtGui.QPushButton(self.horizontalGroupBox)\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.defaultsButton.setFont(font)\n        self.defaultsButton.setObjectName(\"defaultsButton\")\n        self.horizontalLayout_6.addWidget(self.defaultsButton)\n        self.offsetsGroupBoxLabel = QtGui.QLabel(self.centralwidget)\n        self.offsetsGroupBoxLabel.setGeometry(QtCore.QRect(20, 340, 391, 16))\n       #font  = QtGui.QFont()\n       #font .setFamily(\"Arial\")\n       #font .setPointSize(FONT_POINT_SIZE)\n       #self.offsetsGroupBoxLabel.setFont(font)\n        self.offsetsGroupBoxLabel.setObjectName(\"offsetsGroupBoxLabel\")\n        MainWindow.setCentralWidget(self.centralwidget)\n        self.statusbar = QtGui.QStatusBar(MainWindow)\n        self.statusbar.setObjectName(\"statusbar\")\n        MainWindow.setStatusBar(self.statusbar)\n\n        #self.retranslateUi(MainWindow)\n        QtCore.QObject.connect(self.exitButton, QtCore.SIGNAL(\"clicked()\"), MainWindow.close)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n        MainWindow.setWindowTitle(QtGui.QApplication.translate(\"MainWindow\", \"MainWindow\", None, QtGui.QApplication.UnicodeUTF8))\n        self.imagePreviewLabel.setText(QtGui.QApplication.translate(\"MainWindow\", \"Image Preview:\", None, QtGui.QApplication.UnicodeUTF8))\n        self.verticalGroupBox_2.setTitle(QtGui.QApplication.translate(\"MainWindow\", \"Import Buttons\", None, QtGui.QApplication.UnicodeUTF8))\n        self.previewButton.setText(QtGui.QApplication.translate(\"MainWindow\", \"Open Image\", None, QtGui.QApplication.UnicodeUTF8))\n        self.importAsSolidButton.setText(QtGui.QApplication.translate(\"MainWindow\", \"Solid\", None, QtGui.QApplication.UnicodeUTF8))\n        self.importAsSketchButton.setText(QtGui.QApplication.translate(\"MainWindow\", \"Sketch\", None, QtGui.QApplication.UnicodeUTF8))\n        self.importAsPointButton.setText(QtGui.QApplication.translate(\"MainWindow\", \"Faces\", None, QtGui.QApplication.UnicodeUTF8))\n        self.importAsWireButton.setText(QtGui.QApplication.translate(\"MainWindow\", \"Wires\", None, QtGui.QApplication.UnicodeUTF8))\n        self.scaleLabel.setText(QtGui.QApplication.translate(\"MainWindow\", \"Scale Factor\", None, QtGui.QApplication.UnicodeUTF8))\n        self.xOffsetLabel.setText(QtGui.QApplication.translate(\"MainWindow\", \"X Offset\", None, QtGui.QApplication.UnicodeUTF8))\n        self.yOffsetLabel.setText(QtGui.QApplication.translate(\"MainWindow\", \"Y Offset\", None, QtGui.QApplication.UnicodeUTF8))\n        self.zOffsetLabel.setText(QtGui.QApplication.translate(\"MainWindow\", \"Z Offset\", None, QtGui.QApplication.UnicodeUTF8))\n        self.baseNameEdit.setText(QtGui.QApplication.translate(\"MainWindow\", \"Imported\", None, QtGui.QApplication.UnicodeUTF8))\n        self.baseNameLabel.setText(QtGui.QApplication.translate(\"MainWindow\", \"Base Name\", None, QtGui.QApplication.UnicodeUTF8))\n        self.shapeHeightLabel.setText(QtGui.QApplication.translate(\"MainWindow\", \"Shape Height\", None, QtGui.QApplication.UnicodeUTF8))\n        self.recomputeIntervalLabel.setText(QtGui.QApplication.translate(\"MainWindow\", \"Recompute Interval    \", None, QtGui.QApplication.UnicodeUTF8))\n        self.cheatFactorLabel.setText(QtGui.QApplication.translate(\"MainWindow\", \"Cheat Factor\", None, QtGui.QApplication.UnicodeUTF8))\n        self.progressLabel.setText(QtGui.QApplication.translate(\"MainWindow\", \"Progress Bar\", None, QtGui.QApplication.UnicodeUTF8))\n        self.abortButton.setText(QtGui.QApplication.translate(\"MainWindow\", \"Abort\", None, QtGui.QApplication.UnicodeUTF8))\n        self.exitButton.setText(QtGui.QApplication.translate(\"MainWindow\", \"Exit\", None, QtGui.QApplication.UnicodeUTF8))\n        self.staysOnTopCheckBox.setText(QtGui.QApplication.translate(\"MainWindow\", \"Window Stays on Top\", None, QtGui.QApplication.UnicodeUTF8))\n        self.wireEditGroupBox.setTitle(QtGui.QApplication.translate(\"MainWindow\", \"Wire Editing\", None, QtGui.QApplication.UnicodeUTF8))\n        self.selectOddPointsButton.setText(QtGui.QApplication.translate(\"MainWindow\", \"Select\", None, QtGui.QApplication.UnicodeUTF8))\n        self.cutSelectedButton.setText(QtGui.QApplication.translate(\"MainWindow\", \"Cut\", None, QtGui.QApplication.UnicodeUTF8))\n        self.moveButton.setText(QtGui.QApplication.translate(\"MainWindow\", \"Move\", None, QtGui.QApplication.UnicodeUTF8))\n        self.insertButton.setText(QtGui.QApplication.translate(\"MainWindow\", \"Insert\", None, QtGui.QApplication.UnicodeUTF8))\n        self.blackForegroundCheckbox.setText(QtGui.QApplication.translate(\"MainWindow\", \"Black Foreground\", None, QtGui.QApplication.UnicodeUTF8))\n        self.selectFacesButton.setText(QtGui.QApplication.translate(\"MainWindow\", \"Select Objects\", None, QtGui.QApplication.UnicodeUTF8))\n        self.horizontalGroupBox.setTitle(QtGui.QApplication.translate(\"MainWindow\", \"Defaults\", None, QtGui.QApplication.UnicodeUTF8))\n        self.zeroButton.setText(QtGui.QApplication.translate(\"MainWindow\", \"Zero XYZ\", None, QtGui.QApplication.UnicodeUTF8))\n        self.defaultsButton.setText(QtGui.QApplication.translate(\"MainWindow\", \"Defaults\", None, QtGui.QApplication.UnicodeUTF8))\n        self.offsetsGroupBoxLabel.setText(QtGui.QApplication.translate(\"MainWindow\", \"various options\", None, QtGui.QApplication.UnicodeUTF8))\n\n\n\n\n#end QTDesigner produced code\n\n\n#this was a bad idea that seemed like a good one at the time\n#in case anybody want to translate this all the strings were\n#in one spot.  But this makes the code more difficult to read\n\nimportAsSolidButtonText = u'Solid'\nimportAsSketchButtonText = u'Sketch'\nfaceText = u'FACE'\nwireText = u'WIRE'\npointText = u'POINT'\nsketchSupportText = u'Sketch Support'\nbuildingShapesText = u'building shapes '\nselectFacesButtonText = u'Select Objects'\nselectFacesText = u'Select Axis'\nexitButtonText = u'Exit'\nprogressLabelText = u'Progress Bar'\nabortButtonText = u'Abort'\nimportAsPointButtonTip = u'Imports image as points'\nimportAsWireButtonTip = u'Imports image as DWire objects'\nimportAsWireButtonText = u'Wires'\nimportAsPointButtonText = u'Points'\nblackForegroundCheckboxText = u'Black Foreground'\nimagePreviewLabelText = u'Image Preview'\noffsetsGroupBoxText = u'Various Options (mouse over for tool tip help)'\nscaleLabelText = u'Scale'\nrecomputeIntervalLabelText = u'Recompute Int'\nxOffsetLabelText = u'X Offset'\nyOffsetLabelText = u'Y Offset'\nzOffsetLabelText = u'Z Offset'\nstaysOnTopText = u'Keep Window on Top'\nbaseNameLabelText = u'Base Name Lbl'\nshapeHeightLabelText = u'Part Height'\nsfTip = u'Select all the Part.Faces, Part.Edges, or Part.Vertexes objects that are at the same level relative to selected axis X,Y, or Z as currently selected object.  Useful for selecting faces for creating pocket paths.'\niasbTip = u'Imports image as a solid using Wedge primitives, which can optionaly be combined into a single compound, or fused into a single solid.'\niassbTip = u'Imports image as a sketch using unconstrained line segments.'\nebTip = u'Exits and closes main window.  You should abort any ongoing operations before exiting.'\nseTip = u'Scales created objects.  Invalid values are ignored in favor of 1.  One example usage: if you are setup in mm, but want to use 3/4\\\" equivalent number of mm you could enter 25.4 * 3/4 to convert to 3/4 inch.'\nriTip = u'Shapes are inserted multiple times in between calls to recompute().  This sets the interval.  Should be an int value. \\n\\\nLower values will call recompute() more often, resulting in reduced performance during import.'\nyoeTip = zoeTip = xoeTip = u'Offset image to desired position relative to the origin, also used for wire point editing moves.'\nbneTip = u'Base name applied to labels for most import types, e.g. Imported, Imported1, etc.'\ncheTip = u'Z height for some import types. Scale Factor is NOT applied to part height, so this will be the final height.'\nwirePointEditingText = u'Wire Point Editing'\nselectedObjectNotDWireCandidateErrorText = u'Selected object is not a candidate from which we might create a DWire object.'\nselectErrorMessage = u'You must first select an existing face, edge, or vertex, so we know which x/y/zmin and x/y/zmax to look for'\nabortedText = u'Aborted by user'\nplacingText = u\"Processing \"\npreviewButtonText = u'Open Image'\n\napplyMidpointsStopAllText = u'Do not do this one or any of the remaining, if any.'\n\npreviewButtonTip = u'Loads an image for preview in the preview panel, displays red and green cross to indicate origin (0,0) position'\ngraphicsExceptionText = u'\\nGraphics exception displaying preview image.\\n'\ninvalidFileText = u'File must be a monochrome BMP (black and white, monochrome, 1 bit-per-pixel only).'\nopenMonoFileText = u'Open bmp (monochrome) file'\nparsingBmpText = u\"Parsing image\"\nuserErrorText = u'User error'\naddingText = u'Adding '\nlineSegmentsText = u' line segments'\nexaminingText = u'Examining '\nobjectsText = u' objects'\nselectOddPointsErrorMessage = u'No points selected.  Select a point or points on a DWire object.'\nselectOddPointsErrorMessage2 = u'These methods only work with DWire objects.  (You might be able to convert it to a DWire by right-clicking on Select button with object selected.)'\nscaleFactorErrorText = u'Error setting scale_factor, resetting to 1'\nrecomputeErrorText = u'Error setting recompute_interval, resetting to 10'\nxOffsetErrorText = u'Error setting import_x_offset, resetting to 0'\nyOffsetErrorText = u'Error setting import_y_offset, resetting to 0'\nzOffsetErrorText = u'Error setting import_z_offset, resetting to 0'\nbaseNameErrorText = u'Error setting Shape Base Name, resetting to default Shape'\ncheatFactorErrorText = u'Error setting Cheat Factor, resetting to default 0.0001'\nwedgeHeightErrorText = u'Error setting Shape Height, resetting to 1'\napplyingCheatsText = u'Applying cheats'\ncheatFactorLabelText = u'Cheat Factor'\ncfeTip = u'Should ordinarily be a very small floating point value.  Used for diagonally adjacent pixels in sketches, faces, and wires to fuse them together.  Set this to 0 if you do not want to use the cheating algorithm, but note: wires, and faces require it.'\nprogressCompleteText = u'Process complete'\noffsetsGroupBoxTipText = u'\\\nMath expressions are allowed, and will be converted to floating point values.\\n\\n\\\nConstants supported:\\n\\\ne = math.e = Euler\\'s constant = 2.718...\\n\\\npi = math.pi = 3.14159...\\n\\\nphi = golden ratio, alternatively golden, golden_ratio = 1.618...\\n\\\ninch = 25.4, alternatively inches, thou = .0254\\n\\n\\\nReferences supported:\\n\\\nscale (value in scale factor edit box)\\n\\\nx, y, z (current value in x, y, z offset)\\n\\\npart_height, alternatively: part (value in part height edit box)\\n\\\nrecompute, alternatively: recompute_interval (value in recompute interval edit box)\\n\\\ncheat, alternatively: cheat_factor (value in cheat factor edit box)\\n\\\nzoom (current preview image zoom value, displayed as nnnx where nnn is the zoom factor)\\n\\\nvx, vy (width and height of the image preview panel in pixels)\\n\\\npx, py (number of pixels CAPABLE of being displayed in the preview panel at the current zoom)\\n\\\nwidth, alternatively: w (width, including background pixels, of currently previewed image)\\n\\\nheight, alternatively: h (height, including background pixels, of currently previwed image)\\n\\n\\\nNote: references are TEMPORARY and are to current immediate values only.  Thus when original referenced\\n\\\nvalue changes, the edit box using that reference is NOT updated.\\n\\n\\\nMath functions supported:\\n\\\ncos, acos, sin, asin, tan, atan, log, tlog (Note: neither constants nor references can be used with these.)\\n\\n\\\nExamples:\\n\\n\\\ncos32p5d interpreted as cos(32.5 degrees)\\n\\\ncos32r  interpreted as cos(32 radians)\\n\\\nasin1p interpreted as asin(1 radians) (Note: radians is default if neither d nor r is appended to parameter.)\\n\\\nsinpi (error, must use numbers for parameters)\\n\\\nsin3p1415926r interpreted as sin(pi radians)\\n\\\ncosx (error, must use numbers for parameters to trig functions)\\n\\\nlog7 (natural logarithm using base e, same as math.log(7))\\n\\\ntlog10  (base 10 logarithm using base 10, same as math.log10(10)\\n\\\nlog10 (natural logarithm using base e, same as math.log(10))\\n\\\ntlog23p5 (base 10 logarithm -- math.log10(23.5))\\n\\\n-width/2, alternatively: -w/2 (if used in x offset would center axis cross in currently previewed image)\\n\\\n-height/2, alternatively: -h/2 (if used in y offset box would center axis cross)\\n\\\n250/width, alternatively: 250/w (if used in scale factor box would scale imported object to be 250 mm wide)\\n\\\n25/scale (if used in part height box would ensure final part, for some import types, would be 25 mm in height.\\n\\\n(5+1/2)*inches/w (if used in scale factor box would scale imported object to be 5 1/2 inches wide, presumes you are in mm units)\\n\\\n2**3 (2 to the power of 3 = 8)\\n\\\n2^3 (bitwise exclusive or function, NOT 2 to the power of 3!)\\n\\\n2**(1/2) (square root of 2 = 1.414...)\\n\\\ny**(1/3) (cube root of whatever value is currently in the y offset edit box)\\n\\\n2+3*5 (17, NOT 25, usual algebraic order of operation is applied)\\n\\\n10*phi, alternatively: 10*golden, alternatively 10*golden_ratio (10 * 1.618...)\\n\\\ne**pi (e to the power of pi = 23.14...)\\n\\\n'\nmakeDWireGoText = u'Looks Good, keep going.'\nmakeDWireStopText = u'No, something is not right.'\nmakeDWireTitleText = u'Continue?'\nmakeDWireMessageText = u'Continue replacing existing structure with this line?'\n\napplyMidpointsDoAllText=u'Just do them all without asking.'\nimportAsSketchButtonTip = u'Import image as Sketch made up exclusively of unconstrained line segments.'\ncantImportText = u'Sorry, can\\'t import as this type if Cheat Factor is set to 0'\nsolidObjectText = u'MAKE ONE FUSION'\nmoveButtonText = u'Move'\nmoveButtonWaitingText = u'Waiting...'\nmoveButtonTipText=u'Move currently selected point by x,y,z offset, SHIFT+CLICK to go opposite direction (UNDO), CTRL+CLICK to setup mouse click destination, CLICK again to cancel.'\nselectOddPointsButtonText=u'Select'\nselectOddPointsButtonTipText = u'Select points on a DWire object, CLICK = every other point, SHIFT+CLICK = every point, CTRL+CLICK = smart select, RIGHT-CLICK for context menu.'\n\nshiftSelectActionText = u'Shift-Select (all points)'\nctrlSelectActionText = u'Ctrl-Select (smart select)'\nmakeArcActionText=u'Make Arc from 3 points'\nreorderPointsActionText = u'Reorder Points'\nreversePointsActionText = u'Reverse (Uncross) Points'\nglobalUndoActionText = u'Undo'\nglobalRedoActionText = u'Redo'\nmakeDWireActionText = u'Make DWire from Selected Object'\nmakeLineActionText = u'Make Line, Replace Existing'\nshiftMoveActionText=u'Shift-Move (opposite direction)'\nshiftInsertActionText=u'Shift-Insert (insert from cut buffer)'\nctrlMoveActionText=u'Ctrl-Move (click destination)'\napplyMidpointsActionText=u'Apply Midpoints (average out lines)'\nrefMoveXActionText = u'Reference Move X Axis'\nrefMoveYActionText = u'Reference Move Y Axis'\nrefMoveXYActionText=u'Reference Move XY Axes'\nremoveColinearActionText = u'Remove Colinear Points'\nrefMoveXYActionTip = u'Moves selected point(s) to the XY location of the reference (first selected) point'\nctrlMoveActionTip = u'Select a point first, and then use this operation.  Click anywhere in 3D space to finish the move, or click the Move (Waiting...) button to cancel.'\nrefMoveXActionTip = u'Moves selected point(s) to x position of first selected reference point.'\nrefMoveYActionTip = u'Moves selected point(s) to y position of first selected reference point.'\nreorderPointsActionTip = u'Makes selected point Vertex1.'\nreversePointsActionTip = u'Reverses Vertex index numbers for selected points, can be used to uncross crossed wires.'\nmakeArcActionTip = u'Makes an arc using 3 selected rim points as a reference. All points and edges between and including the 2 outer points gets replaced by the arc.'\nmakeLineActionTip = u'Makes line(s) out of selected points to replace all points and edges between and including the 2 outer points.'\nremoveColinearActionTip = u'Removes extraneous colinear points, reducing size and complexity of DWire object. \\nThis operation usually follows the Apply Midpoints operation.'\napplyMidpointsActionTip = u'Smooths out jagged, pixellated edges by replacing the first point of every set of 2 consecutive points with the midpoint between them.\\n\\\nIt is recommended to import as a Wire object(s), and apply this operation to all imported Wires, followed by the Remove Colinear operation.'\ndeleteButtonText = u'Cut'\ndeleteButtonTipText = u'Cuts previously selected points from DWire object (SHIFT+CLICK to undo last cut operation)'\ninsertButtonText = u'Insert'\ninsertButtonTipText = u'Insert a new point in between 2 previously selected points on a DWire object, SHIFT+CLICK to paste previously cut points.'\nmultipleSolidsText = u'MULTIPLE WEDGES'\nsolidImportText = u'Solid Import Options'\ncompoundSolidText = u'MAKE COMPOUND'\nafcbTip = u'Checked = Use black as foreground, unchecked = use white as foreground color.'\nselect2PointsText=u'Select 2 adjacent points on the wire object.'\nbaseNameText = u'Imported'\nzoomText = u'Zoom'\nzeroText = u'Zero XYZ'\nzeroButtonTipText = u'Zero out XYZ offsets'\ndefaultsButtonText = u'Defaults'\ndefaultsButtonTipText = u'Resets all UI elements to default values (same as closing and restarting macro).  To change defaults you must edit the source code defaults section.'\n\n\n#default constant defines\n#change these for different ui starting values\n\nBLACK_FOREGROUND = True  #foreground color will be black if True, else white\nPART_HEIGHT = 1 #pixel height (z axis) for solid import types \nSHAPE_BASENAME = 'Imported'\nIMPORT_X_OFFSET = 0 \nIMPORT_Y_OFFSET = 0 \nIMPORT_Z_OFFSET = 0 \nSCALE_FACTOR = 1 \nRECOMPUTE_INTERVAL = 100\nCHEAT_FACTOR = 7e-5\nWINDOW_STAYS_ON_TOP = False\nSEPARATOR = locale.localeconv()['decimal_point']\nSEPARATOR_STANDIN = 'p'\nDEGREES_INDICATOR = 'd'\nRADIANS_INDICATOR = 'r'\nDISCRETIZE_NUMBER = 50 #number of discrete points to use when creating DWire from curve (unless AUTO_DISCRETIZE_COUNT = True)\nAUTO_DISCRETIZE_COUNT = True #uses length (in mm) of edge * AUTO_DISCRETIZE_POINTS_PER_MM as DISCRETIZE_NUMBER suggestion\nAUTO_DISCRETIZE_POINTS_PER_MM = 0.5\nAUTO_DISCRETIZE_MINIMUM_SUGGESTED = 12\nFONT_POINT_SIZE=11\n\n\n#some globals\n\nboxes = []\nvlines = [] #will contain list of VLine objects representing vertical lines in sketch\nhlines = [] #horizontal lines\nsketch = None \nraster_lines = 0\npixels_per_line = 0\npreview_width = 0\npreview_height = 0 \nbit_array = None #[[]]\nprogress_abort = False #when user clicks abort button in progressLayout this gets set to True\nlast_update = time.time() #used so we only update progress bar every .5 seconds\npreview_image = None\nimageName = None\nname = None\nzoomFactor = 1.0\nfactor = None #related to preview image zoom level\nactual_zoom = None\nshownX = None #how many pixels currently showing in preview panel at this zoom level?\nshownY = None\nmouseEventCallBack = None\nselPointIndex = None #used to keep track of which point was selected before mouseEventCallBack in move function\nundoPoints=[] #to undo some operations\nundoObject=None\nredoPoints = []\nredoObject=None\nselect_objects_axis = 'Z'\nimport_as_2d = False\none_solid = True \nmake_compound_solid = True\nsketch_external = False #when importing as Points add them as external geometry in a new sketch?\nviewrectHeight = None\nviewrectWidth = None\nmadeFace = None #used in makeDWire()\n#apply default values\nblack_foreground = BLACK_FOREGROUND\nforeground_color = 0 #0 = color 1, 1 = color 2 (gets changed if user changes black foreground checkbox)\nshape_basename = SHAPE_BASENAME\nimport_x_offset = IMPORT_X_OFFSET\nimport_y_offset = IMPORT_Y_OFFSET\nimport_z_offset = IMPORT_Z_OFFSET\nscale_factor = SCALE_FACTOR\nrecompute_interval = RECOMPUTE_INTERVAL\ncheat_factor = CHEAT_FACTOR\nwindow_stays_on_top = WINDOW_STAYS_ON_TOP\npart_height = PART_HEIGHT\nselectPopupMenu = None\nboolMakeDWireSuccess = False #communication between makeArc and makeDWire (whether user canceled)\n# for evaluating math expressions in gui input text fields\n# credit \"jfs\" of stackoverflow for these 2 functions, which I modified for my needs\n# supported operators\n\n\noperators = {ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul,\n             ast.Div: op.truediv, ast.Pow: op.pow, ast.BitXor: op.xor, #ast.BitXor: op.pow would remap ^ to pow()\n             ast.USub: op.neg}\n#add some constants and references that might be useful for users of FCBmpImport\nconstants = {'pi':math.pi,'e':math.e, 'phi':16180339887e-10, 'golden':16180339887e-10,'golden_ratio':16180339887e-10,\n             'inch':254e-1, 'inches':254e-1, 'thou':254e-4}\nreferences= {'width':'preview_width', 'w':'preview_width', 'vx':'viewrectWidth', 'vy':'viewrectHeight', 'px':'shownX','py':'shownY',\n            'height':'preview_height', 'h':'preview_height', 'x':'import_x_offset', 'y':'import_y_offset', 'z':'import_z_offset',\n            'part_height':'part_height', 'part':'part_height', 'cheat':'cheat_factor', 'cheat_factor':'cheat_factor',\n            'scale':'scale_factor', 'scale_factor':'scale_factor',\n            'recompute':'recompute_interval', 'recompute_interval':'recompute_interval', 'zoom':'actual_zoom'}\nmaths = {'cos':'cos','acos':'acos','tan':'tan','atan':'atan','sin':'sin','asin':'asin','log':'log','tlog':'log10'}\ndef eval_expr(expr):\n    \"\"\"\n    >>> eval_expr('2^6')\n    4\n    >>> eval_expr('2**6')\n    64\n    >>> eval_expr('1 + 2*3**(4^5) / (6 + -7)')\n    -5.0\n    \"\"\"\n    return eval_(ast.parse(expr, mode='eval').body)\n\ndef eval_(node):\n    if isinstance(node, ast.Num): # <number>\n        return node.n\n    elif isinstance(node, ast.BinOp): # <left> <operator> <right>\n        return operators[type(node.op)](eval_(node.left), eval_(node.right))\n    elif isinstance(node, ast.UnaryOp): # <operator> <operand> e.g., -1\n        return operators[type(node.op)](eval_(node.operand))\n#provide support for constants and references\n    elif node.id:\n        if node.id in constants:\n            return constants[node.id]\n        elif node.id in references: #e.g. references[node.id] is a string, e.g. 'scale_factor' representing global variable scale_factor\n            return globals()[references[node.id]]\n        elif node.id[:3] in maths:\n            func = getattr(math, maths[node.id[:3]])\n            opstring = node.id[3:].replace(SEPARATOR_STANDIN,SEPARATOR)\n            if opstring[-1:]==DEGREES_INDICATOR:\n                opstring = opstring[:-1]\n                return func(float(opstring)*math.pi/180.0)\n            elif opstring[-1:]==RADIANS_INDICATOR:\n                opstring = opstring[:-1]\n                return func(float(opstring))  \n            else:\n                return func(float(opstring))\n        elif node.id[:4] in maths:\n            func = getattr(math, maths[node.id[:4]])\n            opstring = node.id[4:].replace(SEPARATOR_STANDIN,SEPARATOR)\n            if opstring[-1:]==DEGREES_INDICATOR:\n                opstring = opstring[:-1]\n                return func(float(opstring)*math.pi/180.0)\n            elif opstring[-1:]==RADIANS_INDICATOR:\n                opstring = opstring[:-1]\n                return func(float(opstring)) \n            else:\n                return func(float(opstring))\n        else:\n            App.Console.PrintMessage(u'unsupported token: '+node.id+u'\\n')\n    else:\n        raise TypeError(node)\n\n\ndef on_exit(): #user presses exit button\n    #could add progress_abort = True here to close any currently running process, but have decided not to\n    #in case the user has exited thinking the process was complete and there are still a few things left to do.\n    pass\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    \n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\n\n\n\n\nclass Box(object):\n    __slots__ = ('length', 'width', 'height', 'x', 'y', 'z','boxName')\n\nclass VLine(object):\n    __slots__ = ('top_x', 'top_y', 'bottom_x', 'bottom_y', 'isExtensible')\n\nclass HLine(object):\n    __slots__ = ('left_x', 'left_y', 'right_x', 'right_y','isExtensible')\n\n\nclass GraphicsView(QtGui.QGraphicsView): #subclass so we can handle mouse wheel movements for zooming preview\n    def __init__ (self, parent=None):\n        super(GraphicsView, self).__init__ (parent)\n    def wheelEvent(self, evt):\n        global zoomFactor\n        inFactor = 10.0/9.0\n        outFactor = 9.0/10.0\n        modifiers = QtGui.QApplication.keyboardModifiers()\n\n        if evt.delta() > 0:\n            zoomFactor = zoomFactor * float(inFactor)\n            if modifiers == QtCore.Qt.ShiftModifier or modifiers==QtCore.Qt.ShiftModifier.__or__(QtCore.Qt.ControlModifier): #zoom in until we have one more pixel shown in the preview panel\n                if shownX:\n                    targetX = round(shownX,0)-1\n                    zoomFactor = 1/(targetX/viewrectWidth)/factor\n            elif modifiers == QtCore.Qt.ControlModifier:\n                if shownY:\n                    targetY = round(shownY,0)-1\n                    zoomFactor = 1/(targetY/viewrectHeight)/factor\n        else:\n            zoomFactor = zoomFactor*float(outFactor)\n            if modifiers == QtCore.Qt.ShiftModifier or modifiers==QtCore.Qt.ShiftModifier.__or__(QtCore.Qt.ControlModifier):\n                if shownX:\n                    targetX = round(shownX,0)+1\n                    zoomFactor = 1/(targetX/viewrectWidth)/factor\n            elif modifiers == QtCore.Qt.ControlModifier:\n                if shownY:\n                    targetY = round(shownY,0)+1\n                    zoomFactor = 1/(targetY/viewrectHeight)/factor\n        try:\n            scalePreview(pixmap, self, zoomFactor)\n        except:\n            raise StandardError('Exception in zooming preview, can probably be ignored.')\n            \n\n#for CTRL+MOVE operation in wire point editing tools\nclass ViewObserver:\n    def __init__(self, view):\n       self.view = view\n   \n    def offsetMove(self, info):\n       down = (info[\"State\"] == \"DOWN\")\n       pos = info[\"Position\"]\n       btn = info[\"Button\"]\n       if btn == 'BUTTON2': #right click to cancel operation and remove observer\n           v=Gui.activeDocument().activeView()\n           v.removeEventCallback(\"SoMouseButtonEvent\",mouseEventCallBack)\n           ui.moveButton.setText(moveButtonText)\n           processEvents()\n\n       if (down and btn != 'BUTTON2'):\n           pnt = self.view.getPoint(pos)\n           moveSelected(pnt)\n           info = self.view.getObjectInfo(pos)\n           v=Gui.activeDocument().activeView()\n           v.removeEventCallback(\"SoMouseButtonEvent\",mouseEventCallBack) \n   \n\n#helper function for selecting multiple faces, edges, or points (on the same x, y, or zmin/zmax) of a\n#complex object\n\ndef selectObjects():\n\n    # select one face of the object\n    # all other faces at that same zmin and zmax will be selected by this macro\n    # example, if you have pocketed an imported image for an engraving job\n    # at 1 mm beneath the surface of your stock piece you can select one\n    # of the pockets, and then invoke the macro to select all the other\n    # faces at that same 1 mm zmin/zmax \n\n    #see which face, if any, is already selected\n    #and get zmin/zmax values\n\n    global select_objects_axis\n\n    selectionObject = FreeCADGui.Selection.getSelectionEx()\n    if not selectionObject:\n        msgDialog(selectErrorMessage,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return\n    else:\n        selObj = selectionObject[0]\n\n    items = (u'Z', u'Y', u'X') #put Z first since it is most useful and likely to be most used\n    item, ok = QtGui.QInputDialog.getItem(MainWindow, selectFacesText,selectFacesText, items, 0, False)\n    if ok:\n        select_objects_axis = item\n    else:\n        return\n\n\n\n    documentName = selObj.DocumentName #'Unnamed' etc\n    objectName = selObj.ObjectName #'Cut' 'Fusion001' etc\n    subElementName = selObj.SubElementNames[-1] #(without the [0]) names of selected faces ['Face4','Face5'] etc\n    faceSel = selObj.SubObjects[-1] #current face selected (list of Face objects without the [0])\n    boundBox = faceSel.BoundBox\n    typeId = faceSel.TypeId\n    selectedObjects = []\n\n    #zmin = boundBox.ZMin #if ZMin == ZMain this is a face on the xy plane at z=ZMin\n    #zmax = boundBox.ZMax\n    axismin = None\n    axismax = None\n    if select_objects_axis == 'Z':\n        axismin = boundBox.ZMin\n        axismax = boundBox.ZMax\n    elif select_objects_axis == 'X':\n        axismin = boundBox.XMin\n        axismax = boundBox.XMax\n    elif select_objects_axis == 'Y':\n        axismin = boundBox.YMin\n        axismax = boundBox.YMax\n\n\n    #this might take some time, so add a progress dialog\n    shapes = App.ActiveDocument.findObjects(\"Part::Feature\")\n\n    initProgressBar(examiningText + str(len(shapes)) + objectsText, len(shapes))\n    progress = 0\n    for sh in shapes:\n        if sh.Label != objectName:\n            progress +=1\n            updateProgressBar(progress)\n            continue\n        objects=[]\n        typeName = ''\n        #handle some other types besides just faces\n        if type(faceSel) is Part.Face:\n            objects = [\"Face%d\" % (i + 1) for i in range(len(sh.Shape.Faces))]\n            typeName = 'Faces'\n        elif type(faceSel) is Part.Edge:\n            objects = [\"Edge%d\" % (i + 1) for i in range(len(sh.Shape.Edges))]\n            typeName = 'Edges'\n        elif type(faceSel) is Part.Vertex:\n            objects = [\"Vertex%d\" % (i + 1) for i in range(len(sh.Shape.Vertexes))]\n            typeName = 'Vertexes' #you say vertexes i say vertices\n            \n\n        it = 0\n        for f in objects:\n            attr = getattr(sh.Shape,typeName)\n            bb = attr[it].BoundBox\n\n            \n            if select_objects_axis == 'Z'and bb.ZMax == axismax and bb.ZMin == axismin:\n                Gui.Selection.addSelection(sh, [objects[it]])\n\n                selectedObjects.append((sh,objects[it]))\n            elif select_objects_axis == 'X' and bb.XMax == axismax and bb.XMin == axismin:\n                Gui.Selection.addSelection(sh, [objects[it]]) \n            elif select_objects_axis == 'Y' and bb.YMax == axismax and bb.YMin == axismin:\n                Gui.Selection.addSelection(sh, [objects[it]]) \n            it += 1\n        progress +=1\n        updateProgressBar(progress)\n    postSelObj = FreeCADGui.Selection.getSelectionEx()[0]\n\n#end of selectObjects()\n\n#picked points have been modified by placement\n#allPoints have not been\n\n#WIRE POINT EDITING TOOLS\n\ndef globalUndo():\n    global undoObject\n    global undoPoints\n    global redoObject\n    global redoPoints\n    \n    if undoObject != None and len(undoPoints) != 0:\n        redoObject = undoObject\n        redoPoints = undoObject.Points\n        undoObject.Points = undoPoints\n        undoObject = None\n        undoPoints = []\n        App.ActiveDocument.recompute()\n\n\ndef globalRedo():\n    global undoObject\n    global undoPoints\n    global redoObject\n    global redoPoints\n    if redoObject != None and len(redoPoints) != 0:\n        undoObject = redoObject\n        undoPoints = redoPoints\n        redoObject.Points = redoPoints\n        redoObject = None\n        redoPoints = []\n        App.ActiveDocument.recompute()\n\n\n\ndef doShiftInsert():\n    insertPoint(bShiftKey=True)\n\ndef insertPoint(bShiftKey=False): # add new point on wire in between the 2 selected points\n                # or insert previously cut points if SHIFT+CLICK\n    global undoPoints\n    global undoObject\n    selectionObject = Gui.Selection.getSelectionEx()\n    if selectionObject:\n        selObj = selectionObject[0]\n    else:\n        msgDialog(selectOddPointsErrorMessage,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return\n    subObjs = selObj.SubObjects\n    objectName = selObj.ObjectName #e.g. 'DWire'\n    picked = selObj.SubObjects\n    pickedTmp = [] #convert Edge objects to points\n    for p in picked:\n        if hasattr(p,'ShapeType'):\n            if p.ShapeType == 'Edge':\n                for v in p.Vertexes:\n                   pickedTmp.append(v.Point.sub(v.Placement.Base))\n            elif p.ShapeType == 'Vertex':\n                pickedTmp.append(p.Point.sub(p.Placement.Base))\n    picked = pickedTmp \n    if len(picked) != 2:\n        msgDialog(select2PointsText)\n        return\n    doc = Gui.activeDocument()\n    obj = doc.getObject(selObj.ObjectName)\n    if not hasattr(obj.Object,'Points'):\n        msgDialog(selectOddPointsErrorMessage2,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return\n    \n    allPoints = obj.Object.Points #all the points in the selected wire\n    modifiers = QtGui.QApplication.keyboardModifiers()\n\n\n    outerPoints=[]\n\n    for jj in range(len(allPoints)-1,-1,-1):\n        for ii in range(len(picked)-1,-1,-1):\n            if comparePoints(allPoints[jj],picked[ii]):\n                outerPoints.append(jj)\n\n    start = outerPoints[0]\n    end = outerPoints[1]\n    \n    if start > end:\n        temp = start\n        start = end\n        end = temp    \n\n\n    startPoint = allPoints[start]\n    endPoint = allPoints[end]\n\n    if modifiers == QtCore.Qt.ShiftModifier or bShiftKey: #insert undoPoints if shift-clicked\n        if len(undoPoints)==0:\n            return\n        else:\n            for p in undoPoints:\n                allPoints.insert(end,p)\n            undoPoints = []\n            undoObject=None\n    else:\n\n\n        newPoint = App.Vector(startPoint)\n        newPoint.x = (startPoint.x + endPoint.x)/2.0\n        newPoint.y = (startPoint.y + endPoint.y)/2.0\n        newPoint.z = (startPoint.z + endPoint.z)/2.0\n        idx = None\n        if start == 0 and end == 1:\n            allPoints.insert(1,newPoint)\n            idx = 1\n        elif start == 0 and end == len(allPoints) -1:\n            allPoints.insert(end+1, newPoint)\n            idx = end+1\n        else:\n            allPoints.insert(start+1,newPoint)\n            idx = start+1\n    undoPoints = obj.Object.Points\n    undoObject = obj.Object\n    obj.Object.Points = allPoints\n    App.ActiveDocument.recompute()\n    if modifiers != QtCore.Qt.ShiftModifier and not bShiftKey: \n        selectOddPoints(idx)\n\n\n\ndef cutSelected():\n    global undoPoints\n    global undoObject\n    selectionObject = Gui.Selection.getSelectionEx()\n    if selectionObject:\n        selObj = selectionObject[-1]\n    else:\n        msgDialog(selectOddPointsErrorMessage,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return\n\n    subObjs = selObj.SubObjects\n    picked = selObj.SubObjects\n    pickedTmp = [] #convert Edge objects to points\n    for p in picked:\n        if hasattr(p,'ShapeType'):\n            if p.ShapeType == 'Edge':\n                for v in p.Vertexes:\n                   pickedTmp.append(v)\n            elif p.ShapeType == 'Vertex':\n                pickedTmp.append(p)\n    picked = pickedTmp \n    doc = Gui.activeDocument()\n    obj = doc.getObject(selObj.ObjectName)\n    if not hasattr(obj.Object,'Points'):\n        msgDialog(selectOddPointsErrorMessage2,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return\n    allPoints = obj.Object.Points #all the points in the selected wire\n    modifiers = QtGui.QApplication.keyboardModifiers()\n    if modifiers == QtCore.Qt.ShiftModifier: #undo cut points if shift-clicked\n        globalUndo()\n        return\n\n    toBeRemoved=[]\n    for jj in range(len(allPoints)-1,-1,-1):\n        for ii in range(len(picked)-1,-1,-1):\n            if abs(allPoints[jj].x -picked[ii].X)<cheat_factor and abs(allPoints[jj].y -picked[ii].Y)<cheat_factor and abs(allPoints[jj].z -picked[ii].Z)<cheat_factor:\n                toBeRemoved.append(jj)\n\n    for tbr in toBeRemoved: #because we have these in reverse order from end, larger indices first, this method can work\n        allPoints.pop(tbr)\n    undoPoints = obj.Object.Points\n    undoObject = obj.Object\n    obj.Object.Points = allPoints\n    if len(allPoints) == 0:\n        docName = App.ActiveDocument.Name\n        App.getDocument(docName).removeObject(selObj.ObjectName)\n\n    App.ActiveDocument.recompute()\n\n\ndef comparePoints(p1,p2,precision = cheat_factor/2.0):\n    if math.fabs(p1[0]-p2[0])<precision:\n        if math.fabs(p1[1]-p2[1])<precision:\n            if math.fabs(p1[2]-p2[2])<precision:\n                return True\n\n    return False\n\ndef movePoint(p,bOpposite): #apply offsets and return new point\n    newPoint = App.Vector(p)\n    if not bOpposite:\n        newPoint[0]+=import_x_offset\n        newPoint[1]+=import_y_offset\n        newPoint[2]+=import_z_offset\n    else: #move in opposite direction (helps to undo back moves)\n        newPoint[0]-=import_x_offset\n        newPoint[1]-=import_y_offset\n        newPoint[2]-=import_z_offset\n    return newPoint\n\ndef mergeDWires():\n    selObject = Gui.Selection.getSelectionEx()\n    if len(selObject)<2:\n        msgDialog(u'Select 2 or more DWire objects to merge.')\n        return\n    doc = Gui.activeDocument()\n    dwires=[]\n    objects = []\n    for sel in selObject:\n        dwires.append(doc.getObject(sel.ObjectName))\n        objects.append(doc.getObject(sel.ObjectName))\n\n    pointsArray=[]\n    for dw in dwires:\n        if not hasattr(dw.Object,'Points'):\n            msgDialog(u'Only DWire objects are supported for this operation.  You might be able to convert your objects to DWires by using Make DWire from Selected Objects.')\n            for dw2 in dwires:\n                dw2.Visibility=True\n            return\n        dw.Visibility=False\n\n    newPoints =dwires[0].Object.Points\n    dwires.pop(0)\n    bConnection = True\n    while bConnection:\n        bConnection = False\n        for ii in range(0,len(dwires)):\n            if newPoints[-1] == dwires[ii].Object.Points[0]:\n                bConnection = True\n                newPoints.extend(dwires[ii].Object.Points[1:])\n                dwires.pop(ii)\n                break\n            elif newPoints[-1] == dwires[ii].Object.Points[-1]:\n                bConnection = True\n                newPoints.extend(reversed(dwires[ii].Object.Points[:-1]))\n                dwires.pop(ii)\n                break\n            elif newPoints[0] == dwires[ii].Object.Points[0]:\n                bConnection = True\n                newPoints=dwires[ii].Object.Points[1:]+newPoints\n                dwires.pop(ii)\n                break\n            elif newPoints[0] == dwires[ii].Object.Points[-1]:\n                bConnection = True\n                newPoints=reversed(dwires[ii].Object.Points[:-1])+newPoints\n                dwires.pop(ii)\n                break\n\n    if len(dwires)!=0:\n        msgDialog(u'Unable to merge one or more Dwires.  Ensure all wires are connected and try again.') \n        for o in objects:\n            o.Visibility=True\n        return             \n    Draft.makeWire(newPoints)\n\ndef makeDWire(): #make a DWire object based on the selected object\n    global madeFace\n    global boolMakeDWireSuccess\n    selectionObject = Gui.Selection.getSelectionEx()\n    if selectionObject:\n        selObjs = selectionObject\n    else:\n        msgDialog(selectOddPointsErrorMessage,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return\n    for selObj in selObjs:\n        objectName = selObj.ObjectName #e.g. 'DWire'\n        doc = Gui.activeDocument()\n        obj = doc.getObject(objectName)\n        if not hasattr(obj.Object,'Points') or 'Draft._BSpline' in str(obj.Object.Proxy) or 'Draft._BezCurve' in str(obj.Object.Proxy):\n            shape = obj.Object.Shape\n            if not hasattr(shape,'Wires'):\n                msgDialog(selectedObjectNotDWireCandidateErrorText)\n                continue\n            else:\n                if not hasattr(obj.Object,'Proxy') and len(shape.Wires)!=0:\n                    for w in shape.Wires:\n                        Draft.makeWire(w,closed=False,face=madeFace)\n                        Draft.autogroup(w)\n\n                elif hasattr(obj.Object,'Proxy') and ('Draft._Circle' not in str(obj.Object.Proxy) and 'Draft._Ellipse' not in str(obj.Object.Proxy) and 'Draft._BSpline' not in str(obj.Object.Proxy) and 'Draft._BezCurve' not in str(obj.Object.Proxy)):\n                    if len(shape.Wires)!=0:\n                        for w in shape.Wires:\n                            if hasattr(obj.Proxy.Object,'MakeFace'):\n                                madeFace = obj.Proxy.Object.MakeFace\n                            Draft.makeWire(w,closed=False,face=madeFace)\n                            Draft.autogroup(w)\n                            madeFace = None\n                    else:\n                        msgDialog(u'Wire count is zero for this object.')\n                else: #handle curve objects\n\n\n                    if not hasattr(shape,'discretize'):\n                        madeFace = obj.Proxy.Object.MakeFace\n                        obj.Proxy.Object.MakeFace = False #needs to be false in order to have a discretize() function\n                        App.ActiveDocument.recompute()\n                        makeDWire()\n                        madeFace = None\n                        continue\n                    if AUTO_DISCRETIZE_COUNT == True:\n                        discretePoints = int(obj.Object.Shape.Length * AUTO_DISCRETIZE_POINTS_PER_MM)\n                        if discretePoints < AUTO_DISCRETIZE_MINIMUM_SUGGESTED:\n                            discretePoints = AUTO_DISCRETIZE_MINIMUM_SUGGESTED\n                    else:\n                        discretePoints = DISCRETIZE_NUMBER\n                    num, okPressed = QtGui.QInputDialog.getInt(MainWindow, \"Discretize Number\",\"Vertices for \"+objectName+\":\",discretePoints, 2, 100000, 1)\n                    if not okPressed:\n                        boolMakeDWireSuccess=False #tells makeArc user is canceling\n                        continue\n                    else:\n                        boolMakeDWireSuccess=True \n                    w = shape.discretize(Number=num)\n                    Draft.makeWire(w,closed=False,face=False)\n                    Draft.autogroup(w)\n                    if madeFace:\n                        obj.Proxy.Object.MakeFace = madeFace #set make face back to true again\n\n                obj.Visibility=False\n                App.ActiveDocument.recompute()\n                \n\n\ndef reversePoints(): #reverse the order of all selected points\n    global undoPoints\n    global undoObject\n    selectionObject = Gui.Selection.getSelectionEx()\n    if selectionObject:\n        selObj = selectionObject[-1]\n    else:\n        msgDialog(selectOddPointsErrorMessage,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return\n    subObjs = selObj.SubObjects\n    objectName = selObj.ObjectName #e.g. 'DWire'\n    picked = selObj.SubObjects\n    pickedTmp = [] #convert Edge objects to points\n    for p in picked:\n        if hasattr(p,'ShapeType'):\n            if p.ShapeType == 'Edge':\n                for v in p.Vertexes:\n                   pickedTmp.append(v)\n            elif p.ShapeType == 'Vertex':\n                pickedTmp.append(p)\n    picked = pickedTmp \n    if len(picked)<2:\n        msgDialog(u'Select the points you wish to reverse.')\n        return\n    doc = Gui.activeDocument()\n    obj = doc.getObject(selObj.ObjectName)\n    if not hasattr(obj.Object,'Points'):\n        msgDialog(selectOddPointsErrorMessage2,u'FCBmpImport',QtGui.QMessageBox.Critical)#wrong object type\n        return\n    allPoints = obj.Object.Points #all the points in the selected wire\n\n    outerPoints=[]\n\n    for jj in range(len(allPoints)-1,-1,-1):\n        for ii in range(len(picked)-1,-1,-1):\n            if allPoints[jj].x == picked[ii].X and allPoints[jj].y == picked[ii].Y and allPoints[jj].z == picked[ii].Z:\n                outerPoints.append(jj)\n\n    start = outerPoints[0] #start and end are indices\n    end = outerPoints[-1]\n    if start > end:\n        tmp = start\n        start = end\n        end = tmp\n    allPoints[start:end+1] = allPoints[start:end+1][::-1] #credit flakes and dawg at stackoverflow for this line of code to reverse a sublist\n    undoPoints = obj.Object.Points\n    undoObject = obj.Object\n    obj.Object.Points = allPoints\n    App.ActiveDocument.recompute()\n\n\ndef reorderPoints(): #make the selected point Vertex1\n    global undoPoints\n    global undoObject\n    selectionObject = Gui.Selection.getSelectionEx()\n    if selectionObject:\n        selObj = selectionObject[-1]\n    else:\n        msgDialog(selectOddPointsErrorMessage,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return\n    subObjs = selObj.SubObjects\n    objectName = selObj.ObjectName #e.g. 'DWire'\n    picked = selObj.SubObjects\n    pickedTmp = [] #convert Edge objects to points\n    for p in picked:\n        if hasattr(p,'ShapeType'):\n            if p.ShapeType == 'Edge':\n                for v in p.Vertexes:\n                   pickedTmp.append(v)\n            elif p.ShapeType == 'Vertex':\n                pickedTmp.append(p)\n    picked = pickedTmp \n    if len(picked)!=1:\n        msgDialog(u'Select one point on the DWire object you wish to reorder.  That selected point will become Vertex1.')\n        return\n    doc = Gui.activeDocument()\n    obj = doc.getObject(selObj.ObjectName)\n    if not hasattr(obj.Object,'Points'):\n        msgDialog(selectOddPointsErrorMessage2,u'FCBmpImport',QtGui.QMessageBox.Critical)#wrong object type\n        return\n    allPoints = obj.Object.Points #all the points in the selected wire\n\n    outerPoints=[]\n\n    for jj in range(len(allPoints)-1,-1,-1):\n        for ii in range(len(picked)-1,-1,-1):\n            if allPoints[jj].x == picked[ii].X and allPoints[jj].y == picked[ii].Y and allPoints[jj].z == picked[ii].Z:\n                outerPoints.append(jj)\n\n    newVertex1 = outerPoints[0]\n    newPoints = []\n    for ii in range(newVertex1,len(allPoints)):\n        newPoints.append(allPoints[ii])\n    for ii in range(0,newVertex1):\n        newPoints.append(allPoints[ii])\n\n\n    undoPoints = obj.Object.Points\n    undoObject = obj.Object\n    obj.Object.Points = newPoints\n    App.ActiveDocument.recompute()\n\n\ndef select_context_menu(point):\n    # create context menu\n    global selectPopupMenu\n    selectPopupMenu = QtGui.QMenu(MainWindow)\n\n    shiftSelectAction = QtGui.QAction(shiftSelectActionText, MainWindow)\n    shiftSelectAction.triggered.connect(doShiftSelect)\n    selectPopupMenu.addAction(shiftSelectAction)\n\n    ctrlSelectAction = QtGui.QAction(ctrlSelectActionText, MainWindow)\n    ctrlSelectAction.triggered.connect(doCtrlSelect)\n    selectPopupMenu.addAction(ctrlSelectAction)\n\n    shiftInsertAction = QtGui.QAction(shiftInsertActionText, MainWindow)\n    shiftInsertAction.triggered.connect(doShiftInsert)\n    selectPopupMenu.addAction(shiftInsertAction)\n\n    ctrlMoveAction = QtGui.QAction(ctrlMoveActionText, MainWindow)\n    ctrlMoveAction.triggered.connect(doCtrlMove)\n    ctrlMoveAction.setToolTip(ctrlMoveActionTip)\n    selectPopupMenu.addAction(ctrlMoveAction)\n\n    shiftMoveAction = QtGui.QAction(shiftMoveActionText, MainWindow)\n    shiftMoveAction.triggered.connect(doShiftMove)\n    selectPopupMenu.addAction(shiftMoveAction)\n\n    refMoveXAction = QtGui.QAction(refMoveXActionText, MainWindow)\n    refMoveXAction.triggered.connect(doRefMoveX)\n    refMoveXAction.setToolTip(refMoveXActionTip)\n    selectPopupMenu.addAction(refMoveXAction)\n\n    refMoveYAction = QtGui.QAction(refMoveYActionText, MainWindow)\n    refMoveYAction.triggered.connect(doRefMoveY)\n    refMoveYAction.setToolTip(refMoveYActionTip)\n    selectPopupMenu.addAction(refMoveYAction)\n\n    refMoveXYAction = QtGui.QAction(refMoveXYActionText, MainWindow)\n    refMoveXYAction.triggered.connect(doRefMoveXY)\n    refMoveXYAction.setToolTip(refMoveXYActionTip)\n    selectPopupMenu.addAction(refMoveXYAction)\n\n    selectPopupMenu.addSeparator()\n\n    makeDWireAction = QtGui.QAction(makeDWireActionText, MainWindow)\n    makeDWireAction.triggered.connect(makeDWire)\n    selectPopupMenu.addAction(makeDWireAction)\n\n    mergeDWiresActionText = u'Merge DWires'\n    mergeDWiresActionTip = u'Merges 2 or more selected DWire objects (must already be connected at ends).'\n    mergeDWiresAction = QtGui.QAction(mergeDWiresActionText, MainWindow)\n    mergeDWiresAction.triggered.connect(mergeDWires)\n    mergeDWiresAction.setToolTip(mergeDWiresActionTip)\n    selectPopupMenu.addAction(mergeDWiresAction)\n\n    reorderPointsAction = QtGui.QAction(reorderPointsActionText,MainWindow)\n    reorderPointsAction.triggered.connect(reorderPoints)\n    reorderPointsAction.setToolTip(reorderPointsActionTip)\n    selectPopupMenu.addAction(reorderPointsAction)\n\n    reversePointsAction = QtGui.QAction(reversePointsActionText,MainWindow)\n    reversePointsAction.triggered.connect(reversePoints)\n    reversePointsAction.setToolTip(reversePointsActionTip)\n    selectPopupMenu.addAction(reversePointsAction)\n\n    makeArcAction = QtGui.QAction(makeArcActionText,MainWindow)\n    makeArcAction.triggered.connect(makeArc)\n    makeArcAction.setToolTip(makeArcActionTip)\n    selectPopupMenu.addAction(makeArcAction)\n\n    makeLineAction = QtGui.QAction(makeLineActionText,MainWindow)\n    makeLineAction.triggered.connect(makeLine)\n    makeLineAction.setToolTip(makeLineActionTip)\n    selectPopupMenu.addAction(makeLineAction)\n\n\n    removeColinearAction = QtGui.QAction(removeColinearActionText,MainWindow)\n    removeColinearAction.triggered.connect(removeColinear)\n    removeColinearAction.setToolTip(removeColinearActionTip)\n    selectPopupMenu.addAction(removeColinearAction)\n\n    applyMidpointsAction = QtGui.QAction(applyMidpointsActionText,MainWindow)\n    applyMidpointsAction.triggered.connect(applyMidpoints)\n    applyMidpointsAction.setToolTip(applyMidpointsActionTip)\n    selectPopupMenu.addAction(applyMidpointsAction)\n\n    selectPopupMenu.addSeparator()\n\n    globalUndoAction = QtGui.QAction(globalUndoActionText,MainWindow)\n    globalUndoAction.triggered.connect(globalUndo)\n    selectPopupMenu.addAction(globalUndoAction)\n    if len(undoPoints)==0:\n        globalUndoAction.setEnabled(False)\n    else:\n        globalUndoAction.setEnabled(True)\n\n    globalRedoAction = QtGui.QAction(globalRedoActionText,MainWindow)\n    globalRedoAction.triggered.connect(globalRedo)\n    selectPopupMenu.addAction(globalRedoAction)\n    if len(redoPoints)==0:\n        globalRedoAction.setEnabled(False)\n    else:\n        globalRedoAction.setEnabled(True)\n\n    selectPopupMenu.hovered.connect(handleMenuHovered)\n    selectPopupMenu.toolTipsVisible=True\n\n    selectPopupMenu.exec_(ui.selectOddPointsButton.mapToGlobal(point))\n\ndef handleMenuHovered(action):\n    QtGui.QToolTip.showText(\n    QtGui.QCursor.pos(), action.toolTip(),\n    selectPopupMenu, selectPopupMenu.actionGeometry(action))\n\ndef removeColinear(): #remove extra colinear points along all straight edges\n    global undoPoints\n    global undoObject\n    global redoPoints\n    global redoObject\n    modifiers = QtGui.QApplication.keyboardModifiers()\n    if modifiers == QtCore.Qt.ShiftModifier:\n        bUndo = True\n    else:\n        bUndo = False\n    selectionObject = Gui.Selection.getSelectionEx()\n    if not selectionObject:\n        msgDialog(selectOddPointsErrorMessage,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return\n    bStopAsking=False\n    counter = 1\n    initProgressBar(u'Removing Colinears',len(selectionObject),1)\n    for selObj in selectionObject:\n\n        updateProgressBar(counter)\n        counter += 1\n        subObjs = selObj.SubObjects\n        picked = selObj.SubObjects\n        pickedTmp = [] #convert Edge objects to points\n        for p in picked:\n            if hasattr(p,'ShapeType'):\n                if p.ShapeType == 'Edge':\n                    for v in p.Vertexes:\n                       pickedTmp.append(v)\n                elif p.ShapeType == 'Vertex':\n                    pickedTmp.append(p)\n        picked = pickedTmp \n        doc = Gui.activeDocument()\n        obj = doc.getObject(selObj.ObjectName)\n\n        if not hasattr(obj.Object,'Points'):\n            msgDialog(selectOddPointsErrorMessage2,u'FCBmpImport',QtGui.QMessageBox.Critical)#object not compatible\n            return\n        if len(picked)<=1:\n            picked=obj.Object.Points\n        if bUndo:\n            if len(undoPoints)==0:\n                msgDialog(u'Sorry, undo buffer is empty.')\n                return\n            redoObject = obj.Object\n            redoPoints = obj.Object.Points\n            obj.Object.Points = undoPoints\n            undoPoints = []\n            undoObject = None\n            App.ActiveDocument.recompute()\n            return\n        if not bUndo and len(picked)==0:\n            picked = obj.Object.Points\n        indices = []\n        allPoints = obj.Object.Points\n        undoPoints=obj.Object.Points\n        undoObject = obj.Object\n        for ii in range(0,len(allPoints)):\n            for p in picked:\n                if hasattr(p,'ShapeType'):\n                    if p.ShapeType != 'Vertex':\n                        msgDialog(u'Invalid selection, this tool only works with selected points.')\n                        return\n                if hasattr(p,'Point'):\n                    if comparePoints(allPoints[ii],p.Point):\n                        indices.append(ii)\n                else:\n                    if comparePoints(allPoints[ii],p):\n                        indices.append(ii)\n      \n        lowIdx = indices[0]\n        highIdx = indices[-1]\n        if highIdx < lowIdx:\n            tmp = highIdx\n            highIdx = lowIdx\n            lowIdx = tmp\n\n    #now go from lowIdx to highIdx and get the colinear points to be removed\n        colinearPoints = []\n\n        for ii in range(lowIdx-3,highIdx-2):\n            startPoint = allPoints[ii]\n            midPoint = allPoints[ii+1]\n            endPoint = allPoints[ii+2]\n            if DraftVecUtils.isColinear([startPoint,midPoint,endPoint]):\n                colinearPoints.append(midPoint)\n        \n        if len(colinearPoints)==0:\n            FreeCAD.Console.PrintMessage(\"Found: \"+str(len(colinearPoints))+ \" colinear points to be removed.\\n\")\n            continue\n        else:\n            FreeCAD.Console.PrintMessage(\"Found: \"+str(len(colinearPoints))+ \" colinear points to be removed.\\n\")\n        keptPoints = []\n        for ap in allPoints:\n            if ap not in colinearPoints:\n                keptPoints.append(ap)\n\n\n       \n        allPoints = keptPoints\n        undoObject = obj.Object\n        undoPoints = undoObject.Points\n        obj.Object.Points = allPoints\n        #end of for selObj loop\n    App.ActiveDocument.recompute()\n       \n\n\ndef applyMidpoints():\n\n#make a line (or multiple lines) using midpoints of selected points \n    global undoPoints\n    global undoObject\n    global redoPoints\n    global redoObject\n    modifiers = QtGui.QApplication.keyboardModifiers()\n    if modifiers == QtCore.Qt.ShiftModifier:\n        bUndo = True\n    else:\n        bUndo = False\n    selectionObject = Gui.Selection.getSelectionEx()\n    if not selectionObject:\n        msgDialog(selectOddPointsErrorMessage,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return\n    bStopAsking=False\n    counter = 1\n    initProgressBar(u'Applying Midpoints',len(selectionObject),1)\n    for selObj in selectionObject:\n\n        updateProgressBar(counter)\n        counter += 1\n        subObjs = selObj.SubObjects\n        picked = selObj.SubObjects\n\n        doc = Gui.activeDocument()\n        obj = doc.getObject(selObj.ObjectName)\n\n        if not hasattr(obj.Object,'Points'):\n            msgDialog(selectOddPointsErrorMessage2,u'FCBmpImport',QtGui.QMessageBox.Critical)#object not compatible\n            return\n        if len(picked)<=1:\n            picked=obj.Object.Points\n\n        if bUndo:\n            if len(undoPoints)==0:\n                msgDialog(u'Sorry, undo buffer is empty.')\n                return\n            redoObject = obj.Object\n            redoPoints = obj.Object.Points\n            obj.Object.Points = undoPoints\n            undoPoints = []\n            undoObject = None\n            App.ActiveDocument.recompute()\n            return\n        if not bUndo and len(picked)==0:\n            picked = obj.Object.Points\n        indices = []\n        allPoints = obj.Object.Points\n        undoPoints=obj.Object.Points\n        undoObject = obj.Object\n        for ii in range(0,len(allPoints)):\n            for p in picked:\n                if hasattr(p,'ShapeType'):\n                    if p.ShapeType != 'Vertex':\n                        msgDialog(u'Invalid selection, this tool only works with selected points.')\n                        return\n                if hasattr(p,'Point'):\n                    if comparePoints(allPoints[ii],p.Point):\n                        indices.append(ii)\n                else:\n                    if comparePoints(allPoints[ii],p):\n                        indices.append(ii)\n      \n        lowIdx = indices[0]\n        highIdx = indices[-1]\n        if highIdx < lowIdx:\n            tmp = highIdx\n            highIdx = lowIdx\n            lowIdx = tmp\n\n    #now go from lowIdx to highIdx and get the midpoints\n        midPoints = []\n\n        for ii in range(lowIdx,highIdx-1):\n            startPoint = allPoints[ii]\n            endPoint = allPoints[ii+1]\n            newPoint = App.Vector(startPoint)\n            newPoint.x = (startPoint.x + endPoint.x)/2.0\n            newPoint.y = (startPoint.y + endPoint.y)/2.0\n            newPoint.z = (startPoint.z + endPoint.z)/2.0\n            midPoints.append(newPoint)\n\n        edges=[]\n        for ii in range(0,len(midPoints)-1):\n            edges.append(Part.makeLine(midPoints[ii],midPoints[ii+1]))\n\n        partWire = Part.Wire(edges)\n        Part.show(partWire)\n        App.ActiveDocument.recompute()\n        partWireName = App.ActiveDocument.ActiveObject.Label\n        Draft.select(App.ActiveDocument.ActiveObject)\n \n        makeDWire()\n        dwire = App.ActiveDocument.ActiveObject\n        dwireName = dwire.Label\n        dwPoints = dwire.Points\n        \n\n        if not bStopAsking:\n            items = (makeDWireGoText, makeDWireStopText,applyMidpointsDoAllText,applyMidpointsStopAllText)\n            item, okPressed = QtGui.QInputDialog.getItem(MainWindow, makeDWireTitleText, makeDWireMessageText, items, 0, False)\n            if not okPressed or item== makeDWireStopText: #user canceled\n                App.ActiveDocument.removeObject(partWireName)\n                App.ActiveDocument.removeObject(dwireName)\n                continue\n            elif okPressed and item==applyMidpointsDoAllText:\n                bStopAsking=True\n            elif okPressed and item==applyMidpointsStopAllText:\n                App.ActiveDocument.removeObject(partWireName)\n                App.ActiveDocument.removeObject(dwireName)\n                return\n\n\n        for ii in range(highIdx-1,lowIdx,-1):\n            allPoints.pop(ii) #removes original vertices between new arc endpoints\n\n        if comparePoints(allPoints[lowIdx],dwPoints[0]):\n            dwPoints.reverse()        \n      \n        allPoints = allPoints[:lowIdx] + dwPoints+ allPoints[lowIdx+1:]\n        App.ActiveDocument.removeObject(dwireName)    \n        App.ActiveDocument.removeObject(partWireName)\n        undoObject = obj.Object\n        undoPoints = undoObject.Points\n        obj.Object.Points = allPoints\n        #end of for selObj loop\n    App.ActiveDocument.recompute()\n       \n\n\n\ndef getDistance3d(x1, y1, z1, x2, y2, z2):\n    return math.sqrt((x1 - x2)**2 + (y1 - y2)**2 + (z1 - z2)**2)\n\n#find the center of a circle in 3d space given 3 points on the rim of the circle\n#adapted from java code by Russell Strauss posted on stackoverflow\n#stackoverflow.com/questions/4103405/what-is-the-algorithm-for-finding-the-center-of-a-circle-from-three-points\n#original java code:\n #pt circleCenter(pt A, pt B, pt C) {\n\n #   float yDelta_a = B.y - A.y;\n #   float xDelta_a = B.x - A.x;\n #   float yDelta_b = C.y - B.y;\n #   float xDelta_b = C.x - B.x;\n #   pt center = P(0,0);\n\n #   float aSlope = yDelta_a/xDelta_a;\n #   float bSlope = yDelta_b/xDelta_b;  \n #   center.x = (aSlope*bSlope*(A.y - C.y) + bSlope*(A.x + B.x)\n #       - aSlope*(B.x+C.x) )/(2* (bSlope-aSlope) );\n #   center.y = -1*(center.x - (A.x+B.x)/2)/aSlope +  (A.y+B.y)/2;\n\n #   return center;\n # }\n\ndef getCenter(ax,ay,az,bx,by,bz,cx,cy,cz):\n    if not (math.fabs(az) <= CHEAT_FACTOR/2.0 and math.fabs(bz) <= CHEAT_FACTOR/2.0 and math.fabs(cz) <= CHEAT_FACTOR/2.0):\n        msgDialog(u'Sorry, but this only works for wires on the xy plane with z = 0.  If you feel this is in error, try adjust Cheat Factor to a larger value.')\n        return None\n    avoidDivByZero = CHEAT_FACTOR/2.0 #lazy bit of hackery\n\n    yDelta_a = float(by-ay)\n    xDelta_a = float(bx-ax)\n    yDelta_b = float(cy-by)\n    xDelta_b = float(cx-bx)\n\n    if xDelta_a == 0: \n        xDelta_a = avoidDivByZero\n\n    if xDelta_b == 0:\n        xDelta_b = avoidDivByZero\n       \n\n    aSlope = yDelta_a/xDelta_a\n\n    if aSlope == 0:\n        aSlope = avoidDivByZero\n\n    bSlope = yDelta_b/xDelta_b\n\n    if bSlope == aSlope:\n        bSlope = avoidDivByZero\n  \n    dx = (aSlope*bSlope*(ay-cy) + bSlope*(ax+bx) - aSlope*(bx+cx) )/(2.0* (bSlope-aSlope) )\n    dy = -1.0*(dx - (ax+bx)/2.0)/aSlope +  (ay+by)/2.0\n\n    return dx,dy,0\n\ndef makeLine(boolUndo = False):\n#make a line (or multiple lines) to replace existing structure, similar to makeArc, but with a straight line instead of a curve\n    global undoPoints\n    global undoObject\n    modifiers = QtGui.QApplication.keyboardModifiers()\n    if modifiers == QtCore.Qt.ShiftModifier or boolUndo:\n        bUndo = True\n    else:\n        bUndo = False\n    selectionObject = Gui.Selection.getSelectionEx()\n    if selectionObject:\n        selObj = selectionObject[-1]\n    else:\n        msgDialog(selectOddPointsErrorMessage,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return\n\n    subObjs = selObj.SubObjects\n    picked = selObj.SubObjects\n    pickedTmp = [] #convert Edge objects to points\n    for p in picked:\n        if hasattr(p,'ShapeType'):\n            if p.ShapeType == 'Edge':\n                for v in p.Vertexes:\n                   pickedTmp.append(v)\n            elif p.ShapeType == 'Vertex':\n                pickedTmp.append(p)\n    picked = pickedTmp \n    if not bUndo and len(picked)<=1:\n        msgDialog(u'Select at least 2 points and try again.')\n        return\n\n    doc = Gui.activeDocument()\n    obj = doc.getObject(selObj.ObjectName)\n    if not hasattr(obj.Object,'Points'):\n        msgDialog(selectOddPointsErrorMessage2,u'FCBmpImport',QtGui.QMessageBox.Critical)#object not compatible\n        return\n\n    if bUndo:\n        if len(undoPoints)==0:\n            msgDialog(u'Sorry, undo buffer is empty.')\n            return\n        redoObject = obj.Object\n        redoPoints = obj.Object.Points\n        obj.Object.Points = undoPoints\n        undoPoints = []\n        undoObject = None\n        App.ActiveDocument.recompute()\n        return\n\n    indices = []\n    allPoints = obj.Object.Points\n    undoPoints=obj.Object.Points\n    undoObject = obj.Object\n    for ii in range(0,len(allPoints)):\n        for p in picked:\n            if comparePoints(allPoints[ii],p.Point):\n                indices.append(ii)\n\n\n      \n    lowIdx = indices[0]\n    highIdx = indices[-1]\n    if highIdx < lowIdx:\n        tmp = highIdx\n        highIdx = lowIdx\n        lowIdx = tmp\n\n    edges=[]\n    for ii in range(0,len(picked)-1):\n        edges.append(Part.makeLine(picked[ii].Point,picked[ii+1].Point))\n\n    partWire = Part.Wire(edges)\n    Part.show(partWire)\n    App.ActiveDocument.recompute()\n    partWireName = App.ActiveDocument.ActiveObject.Label\n    Draft.select(App.ActiveDocument.ActiveObject)\n \n    makeDWire()\n    dwire = App.ActiveDocument.ActiveObject\n    dwireName = dwire.Label\n    dwPoints = dwire.Points\n\n    items = (makeDWireGoText, makeDWireStopText)\n    item, okPressed = QtGui.QInputDialog.getItem(MainWindow, makeDWireTitleText, makeDWireMessageText, items, 0, False)\n    if not okPressed or item== makeDWireStopText: #user canceled\n        App.ActiveDocument.removeObject(partWireName)\n        App.ActiveDocument.removeObject(dwireName)\n        return\n\n\n\n    for ii in range(highIdx-1,lowIdx,-1):\n        allPoints.pop(ii) #removes original vertices between new arc endpoints\n\n    if not comparePoints(allPoints[lowIdx],dwPoints[0]):\n        dwPoints.reverse()        \n      \n    allPoints = allPoints[:lowIdx] + dwPoints+ allPoints[lowIdx+1:]\n    App.ActiveDocument.removeObject(dwireName)    \n    App.ActiveDocument.removeObject(partWireName)\n    undoObject = obj.Object\n    undoPoints = undoObject.Points\n    obj.Object.Points = allPoints\n    \n    App.ActiveDocument.recompute()\n\n\n\n\n\n\n\n\ndef makeArc(boolUndo = False):\n    global undoPoints\n    global undoObject\n    global boolMakeDWireSuccess\n    modifiers = QtGui.QApplication.keyboardModifiers()\n    if modifiers == QtCore.Qt.ShiftModifier or boolUndo:\n        bUndo = True\n    else:\n        bUndo = False\n    selectionObject = Gui.Selection.getSelectionEx()\n    if selectionObject:\n        selObj = selectionObject[-1]\n    else:\n        msgDialog(selectOddPointsErrorMessage,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return\n\n    subObjs = selObj.SubObjects\n    picked = selObj.SubObjects\n    pickedTmp = [] #convert Edge objects to points\n    for p in picked:\n        if hasattr(p,'ShapeType'):\n            if p.ShapeType == 'Edge':\n                for v in p.Vertexes:\n                   pickedTmp.append(v)\n            elif p.ShapeType == 'Vertex':\n                pickedTmp.append(p)\n    picked = pickedTmp \n\n    if not bUndo and len(picked)!= 3:\n        msgDialog(u'Select 3 rim points along the arc and try again.')\n        return\n\n    doc = Gui.activeDocument()\n    obj = doc.getObject(selObj.ObjectName)\n    if not hasattr(obj.Object,'Points'):\n        msgDialog(selectOddPointsErrorMessage2,u'FCBmpImport',QtGui.QMessageBox.Critical)#object not compatible\n        return\n\n    if bUndo:\n        if len(undoPoints)==0:\n            msgDialog(u'Sorry, undo buffer is empty.')\n            return\n        redoObject = obj.Object\n        redoPoints = obj.Object.Points\n        obj.Object.Points = undoPoints\n        undoPoints = []\n        undoObject = None\n        App.ActiveDocument.recompute()\n        return\n\n    indices = []\n    allPoints = obj.Object.Points\n    undoPoints=obj.Object.Points\n    undoObject = obj.Object\n    for ii in range(0,len(allPoints)):\n        if comparePoints(allPoints[ii],picked[0].Point):\n            lowIdx = ii\n        elif comparePoints(allPoints[ii],picked[1].Point):\n            midIdx = ii\n        elif comparePoints(allPoints[ii],picked[2].Point):\n            highIdx = ii\n\n    if DraftVecUtils.isColinear([allPoints[lowIdx],allPoints[midIdx],allPoints[highIdx]]):\n        msgDialog(u'Select 3 points that are not colinear.')\n        return\n      \n    if highIdx < lowIdx:\n        tmp = highIdx\n        highIdx = lowIdx\n        lowIdx = tmp\n\n    if lowIdx > midIdx or midIdx > highIdx: #set a new vertex1 so we don't have an overflow issue\n        if lowIdx > midIdx:\n            newVertex1 = lowIdx + 1\n        else:\n            newVertex1 = highIdx -1\n        newPoints = []\n        for ii in range(newVertex1,len(allPoints)):\n            newPoints.append(allPoints[ii])\n        for ii in range(0,newVertex1):\n            newPoints.append(allPoints[ii])\n        obj.Object.Points = newPoints\n\n        indices = []\n        allPoints = obj.Object.Points\n        undoPoints = obj.Object.Points\n        undoObject = obj.Object\n        for ii in range(0,len(allPoints)):\n            if comparePoints(allPoints[ii],picked[0].Point):\n                lowIdx = ii\n            elif comparePoints(allPoints[ii],picked[1].Point):\n                midIdx = ii\n            elif comparePoints(allPoints[ii],picked[2].Point):\n                highIdx = ii\n\n        if highIdx < lowIdx:\n            tmp = highIdx\n            highIdx = lowIdx\n            lowIdx = tmp\n\n\n\n    start = App.Vector(picked[0].X,picked[0].Y,picked[0].Z)\n    mid = App.Vector(picked[1].X,picked[1].Y,picked[1].Z)\n    end = App.Vector(picked[2].X,picked[2].Y,picked[2].Z)\n\n    cx,cy,cz = getCenter(start.x,start.y,start.z,mid.x,mid.y,mid.z,end.x,end.y,end.z)\n    radius = getDistance3d(cx,cy,cz,start.x,start.y,start.z)\n    placement = App.Placement(App.Vector(cx,cy,cz), App.Rotation(App.Vector(0,0,1),0),App.Vector(0,0,0))\n    startAngle = math.atan2(start.y-cy,start.x-cx) *180.0 / math.pi\n    midAngle = math.atan2(mid.y-cy,mid.x-cx)*180.0 / math.pi\n    endAngle = math.atan2(end.y-cy,end.x-cx) * 180.0/ math.pi\n    \n    draftArc = Draft.makeCircle(radius, placement, False, startAngle, endAngle)\n   \n    Draft.select([draftArc])\n    draftArcName = App.ActiveDocument.ActiveObject.Label\n    edge = draftArc.Shape.Edges[0]\n    if not DraftGeomUtils.isPtOnEdge(mid,edge):\n        App.ActiveDocument.removeObject(draftArcName)\n        draftArc = Draft.makeCircle(radius, placement, False, endAngle, startAngle)\n        Draft.select([draftArc])\n        draftArcName = App.ActiveDocument.ActiveObject.Label\n    boolMakeDWireSuccess=False\n    makeDWire()\n    bContinue = boolMakeDWireSuccess\n\n    if not bContinue: #user canceled\n        App.ActiveDocument.removeObject(draftArcName)\n        return\n\n    dwire = App.ActiveDocument.ActiveObject\n    dwireName = dwire.Label\n    dwPoints = dwire.Points\n\n    for ii in range(highIdx-1,lowIdx,-1):\n        allPoints.pop(ii) #removes original vertices between new arc endpoints\n\n    if not comparePoints(allPoints[lowIdx],dwPoints[0]):\n        dwPoints.reverse()        \n      \n    allPoints = allPoints[:lowIdx] + dwPoints+ allPoints[lowIdx+1:]\n    App.ActiveDocument.removeObject(dwireName)    \n    App.ActiveDocument.removeObject(draftArcName)\n    undoObject = obj.Object\n    undoPoints = undoObject.Points\n    obj.Object.Points = allPoints\n    \n    App.ActiveDocument.recompute()\n\n\ndef doShiftSelect(): #reached from select context menu\n    selectOddPoints(bShiftKey=True)\n\ndef doCtrlSelect(): #reached from select context menu\n    selectOddPoints(bCtrlKey=True)\n\ndef selectOddPoints(idx=None,bShiftKey=False,bCtrlKey=False): #user selects 2 points on the same wire, we select the odd points in between\n                                #or if shift+click and 2 points we select all points in between or..\n                        #alternatively, user selects one point and we select all odd points (or even if the user selected even numbered point) or...\n                        #user selects one point and shift+clicks and we select all points on the wire\n\n   #bShiftKey is True when called internally by another method, such as makeArc()\n\n\n    mod = None\n    modifiers = QtGui.QApplication.keyboardModifiers()\n    selectAll = False\n    smartSelect = False\n    if modifiers == QtCore.Qt.ShiftModifier or bShiftKey: #select all points if shift-clicked\n        selectAll = True\n    elif modifiers == QtCore.Qt.ControlModifier or bCtrlKey: #ctrl-clicked, so do smart select\n        smartSelect = True\n        \n    selectionObject = Gui.Selection.getSelectionEx()\n    if selectionObject:\n        selObj = selectionObject[-1]\n    else:\n        msgDialog(selectOddPointsErrorMessage,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return\n    subObjs = selObj.SubObjects\n    picked = selObj.PickedPoints #the point(s) the user selected\n    pickedTmp = [] #convert Edge objects to points\n    for p in picked:\n        if hasattr(p,'ShapeType'):\n            if p.ShapeType == 'Edge':\n                for v in p.Vertexes:\n                   pickedTmp.append(v)\n            elif p.ShapeType == 'Vertex':\n                pickedTmp.append(p)\n    picked = pickedTmp \n    objectName = selObj.ObjectName #e.g. 'DWire'\n    doc = Gui.activeDocument()\n    obj = doc.getObject(objectName)\n\n\n    if not hasattr(obj.Object,'Points'):\n        msgDialog(selectOddPointsErrorMessage2,u'FCBmpImport',QtGui.QMessageBox.Critical)#not a DWire\n        return\n    allPoints = obj.Object.Points #all the points in the selected wire\n\n    \n\n    startEndIndices=[] #should be 2 points in here after the jj and ii loops\n\n    shapes = App.ActiveDocument.findObjects(\"Part::Part2DObject\")\n    names = []\n    ourShape = None\n    for sh in shapes:\n        if sh.Label == objectName:\n            names = [\"Vertex%d\" % (i + 1) for i in range(len(sh.Shape.Vertexes))]\n            ourShape = sh\n\n    for jj in range(len(allPoints)-1,-1,-1):\n        for ii in range(len(picked)-1,-1,-1):\n            if comparePoints(allPoints[jj],picked[ii]):\n                startEndIndices.append(jj)\n\n\n    start = None\n    end = None\n\n    if len(startEndIndices)!=2: #if user selects more than 2 points we select all odd points beginning at 1st (unless shift+click, we select all points between)\n        if len(startEndIndices)!= 0 and startEndIndices[0] % 2 == 0: #select all even or odd points depending on the user's initial selection if he only selected one point\n            start = 0\n        else:\n            start = 1\n        end = len(names)\n    else:\n        start = startEndIndices[0]\n        end = startEndIndices[1]\n    if selectAll and len(startEndIndices)!=2:\n        start = 0\n        end = len(names)\n    step = 1\n    if start > end:\n        step = -1\n    mod = start % 2\n    toBeAdded=[]#will be strings naming the vertices to be additionally selected\n    if idx == None:\n        if not smartSelect:\n            for ii in range(start, end, step):\n                if ii % 2 == mod and not selectAll:\n                   toBeAdded.append(names[ii]) \n                elif selectAll:\n                   toBeAdded.append(names[ii])\n        else: #do smart select\n            comeFromDirection = None #old recently used directions\n            goingToDirection = None\n            toDirection = None #new soon to be used directions\n            fromDirection = None\n            if start > end:\n                tmp = start\n                start = end\n                end = tmp\n\n            comeFromDirection = fixDirection(allPoints[start-1],allPoints[start])\n            goingToDirection = fixDirection(allPoints[start],allPoints[start+1]) \n\n            ii=start                 \n            while ii < end:\n                if ii==start:\n                    fromDirection = comeFromDirection\n                    toDirection = goingToDirection\n                else:\n                    fromDirection = fixDirection(allPoints[ii-1],allPoints[ii])\n                    if ii+1 >= len(allPoints):\n                        break\n                    toDirection = fixDirection(allPoints[ii],allPoints[ii+1])\n\n                if not comparePoints(comeFromDirection,fromDirection) or not comparePoints(goingToDirection,toDirection): #new direction\n                    ii += 1 #skip this point\n                    if ii>=len(allPoints):\n                        break\n                toBeAdded.append(names[ii])\n                comeFromDirection = fixDirection(allPoints[ii-1],allPoints[ii])\n                if ii+1 >= len(allPoints):\n                    break\n                goingToDirection = fixDirection(allPoints[ii],allPoints[ii+1])\n                ii+=2\n        #end smart select\n    else:\n        if len(names)>idx:\n            toBeAdded.append(names[idx])\n        Gui.Selection.clearSelection()\n\n\n    Gui.Selection.addSelection(ourShape, toBeAdded) \n\ndef fixDirection(vec1,vec2):\n    \n    vector2 = vec1-vec2\n    for ii in range(0,3):\n        vector2[ii]=round(vector2[ii]) #otherwise cheat factor would make diagonal directions\n\n    for jj in range(0,3):\n        if vector2[jj]<0: #only interested in the direction, not how far\n            vector2[jj]=-1.0\n        elif vector2[jj]>0:\n            vector2[jj]=1.0\n    return vector2 \n\ndef doCtrlMove():\n    moveSelected(bCtrlKey=True)\n\ndef doShiftMove():\n    moveSelected(bShiftKey=True)\n\ndef moveSelected(newVector = None, bCtrlKey=False,bShiftKey=False):\n    global mouseEventCallBack\n    global selPointIndex #point selected when Ctrl-clicked move button\n    global undoPoints\n    global undoObject\n    processEvents()\n    checkOffsets() #ensure offset values are registered\n\n    if newVector == None and ui.moveButton.text()==moveButtonWaitingText: #cancel move if user clicks move button again while 'waiting...'\n        v=Gui.activeDocument().activeView()\n        v.removeEventCallback(\"SoMouseButtonEvent\",mouseEventCallBack)\n        ui.moveButton.setText(moveButtonText)\n        processEvents()\n        return\n\n        \n\n    modifiers = QtGui.QApplication.keyboardModifiers()\n    moveOpposite = False\n    if modifiers == QtCore.Qt.ShiftModifier or bShiftKey: #move opposite direction if shift-clicked\n        moveOpposite = True\n\n    selectionObject = Gui.Selection.getSelectionEx()\n    if selectionObject:\n        selObj = selectionObject[0]\n    else:\n        msgDialog(selectOddPointsErrorMessage,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return\n\n\n    subObjs = selObj.SubObjects\n    picked = selObj.SubObjects\n    pickedTmp = [] #convert Edge objects to points\n    for p in picked:\n        if hasattr(p,'ShapeType'):\n            if p.ShapeType == 'Edge':\n                for v in p.Vertexes:\n                   pickedTmp.append(v)\n            elif p.ShapeType == 'Vertex':\n                pickedTmp.append(p)\n    picked = pickedTmp \n    doc = Gui.activeDocument()\n    obj = doc.getObject(selObj.ObjectName)\n    if not hasattr(obj.Object,'Points'):\n        msgDialog(selectOddPointsErrorMessage2,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return  \n    allPoints = obj.Object.Points #all the points in the selected wire\n\n\n    toBeMoved=[]\n\n    for jj in range(len(allPoints)-1,-1,-1):\n        for ii in range(len(picked)-1,-1,-1):\n            if allPoints[jj].x == picked[ii].X and allPoints[jj].y == picked[ii].Y and allPoints[jj].z == picked[ii].Z:\n                toBeMoved.append(jj)\n    if modifiers == QtCore.Qt.ControlModifier or bCtrlKey: #if user ctrl-clicks move we setup observer and return, on click the observer calls moveSelected again with newVector set\n        v=Gui.activeDocument().activeView()\n        o = ViewObserver(v)\n        mouseEventCallBack = v.addEventCallback(\"SoMouseButtonEvent\",o.offsetMove)\n        selPointIndex = toBeMoved[0]\n        ui.moveButton.setText(moveButtonWaitingText)\n        return\n\n\n    if len(toBeMoved) > 1 or newVector==None:\n        for tbm in toBeMoved: \n            #allPoints.pop(tbm)\n            allPoints[tbm]=movePoint(allPoints[tbm],moveOpposite)\n    else:\n        #user clicked ctrl-move, and then clicked the destination position (else newVector == None and we don't get here)\n        cur = allPoints[selPointIndex]   #setup an undo operation using shift+move \n        import_x_offset = newVector[0]-cur[0]\n        import_y_offset = newVector[1]-cur[1]\n\n\n        ui.xOffsetEdit.setText(str(import_x_offset))\n        ui.yOffsetEdit.setText(str(import_y_offset))\n\n        ui.moveButton.setText(moveButtonText)\n        Gui.Selection.clearSelection()\n        processEvents()\n        for ii in range(0,2): #make the actual move\n            allPoints[selPointIndex][ii] = newVector[ii]\n        allPoints[selPointIndex][2] = float(import_z_offset) #user must manually set z offset to something other than 0\n\n    undoPoints = obj.Object.Points\n    undoObject = obj.Object\n    obj.Object.Points = allPoints\n    App.ActiveDocument.recompute()\n\ndef doRefMoveX():\n    moveToReference(axis='X')\n\ndef doRefMoveY():\n    moveToReference(axis='Y')\n\ndef doRefMoveXY():\n    moveToReference(axis='XY')\n\n\ndef moveToReference(axis):\n    global mouseEventCallBack\n    global selPointIndex #point selected when Ctrl-clicked move button\n    global undoPoints\n    global undoObject\n    processEvents()\n    checkOffsets() #ensure offset values are registered\n\n\n    selectionObject = Gui.Selection.getSelectionEx()\n    if selectionObject:\n        refObj = selectionObject[0]\n        targObj = selectionObject[-1] #usually the same, but allow user to use the reference point from a different DWire\n    else:\n        msgDialog(selectOddPointsErrorMessage,u'FCBmpImport',QtGui.QMessageBox.Critical)#no object selected\n        return\n\n\n    ref = refObj.SubObjects[0]\n    if hasattr(ref,'ShapeType'):\n        if ref.ShapeType == 'Edge':\n           ref = ref.Vertexes[0]\n\n    doc = Gui.activeDocument()\n    tObj = doc.getObject(targObj.ObjectName) #targObj is the one with the points to be moved\n    picked = targObj.SubObjects\n    if not hasattr(tObj.Object,'Points'):\n        msgDialog(selectOddPointsErrorMessage2,u'FCBmpImport',QtGui.QMessageBox.Critical)#invalid object selected\n        return  \n    pickedTmp = [] #convert Edge objects to points\n    for p in picked:\n        if hasattr(p,'ShapeType'):\n            if p.ShapeType == 'Edge':\n                for v in p.Vertexes:\n                   pickedTmp.append(v.Point)\n            elif p.ShapeType == 'Vertex':\n                pickedTmp.append(p.Point)\n    picked = pickedTmp\n\n    if len(picked)<2 and refObj == targObj:\n        msgDialog(u'Select a point to use as a reference, then any additional points you wish to move to that reference point\\'s X,Y,or Z position.')\n        return\n    \n    newVector = App.Vector(ref.X,ref.Y,ref.Z)\n\n    \n    if axis=='X':\n        newVector.y = 0\n    elif axis=='Y':\n        newVector.x = 0\n\n    allPoints = tObj.Object.Points #all the points in the selected wire\n\n    toBeMoved=[]\n    pickedStart = 0\n    if refObj == targObj:\n        pickedStart = 1\n    for jj in range(0, len(allPoints)):\n        for ii in range(pickedStart, len(picked)):\n            if comparePoints(allPoints[jj],picked[ii]):\n                toBeMoved.append(jj)\n\n    cur = picked[0]   #setup an undo operation using shift+move \n    if targObj == refObj:\n        cur=picked[1]\n    if axis=='X':\n        import_x_offset = newVector[0]-cur.x\n        ui.xOffsetEdit.setText(str(import_x_offset))\n        import_y_offset = 0\n        ui.yOffsetEdit.setText('0')\n    elif axis=='Y':\n        import_y_offset = newVector[1]-cur.y\n        ui.yOffsetEdit.setText(str(import_y_offset))\n        import_x_offset = 0\n        ui.xOffsetEdit.setText('0')\n    elif axis=='XY':\n        import_x_offset = newVector[0]-cur.x\n        ui.xOffsetEdit.setText(str(import_x_offset))\n        import_y_offset = newVector[1]-cur.y\n        ui.yOffsetEdit.setText(str(import_y_offset))\n\n    for tbm in toBeMoved: \n        if axis=='X':\n            allPoints[tbm].x += import_x_offset\n        elif axis=='Y':\n            allPoints[tbm].y += import_y_offset\n        elif axis=='XY':\n            allPoints[tbm].x += import_x_offset\n            allPoints[tbm].y += import_y_offset\n\n    undoPoints = tObj.Object.Points\n    undoObject = tObj.Object\n    tObj.Object.Points = allPoints\n    App.ActiveDocument.recompute()\n\n\n\n#PROGRESS BAR STUFF\n\ndef initProgressBar(label, maxValue, minValue=0, cancel_button_text=abortButtonText, title=\"FCBmpImport Macro\",modal=False):\n        \n        global progress_abort\n        ui.progressLabel.setText(label)\n        ui.progressBar.minimum = minValue\n        ui.progressBar.maximum = maxValue\n        ui.progressBar.setValue(0)\n        ui.abortButton.setEnabled(True)\n        progress_abort = False\n        \n\ndef updateProgressBar(val): #sets new progress value, processes events (to keep UI responsive), and checks\n                            #for user abort\n    global progress_abort\n    if shiboken:\n        if shiboken.isValid(ui.progressBar):\n            ui.progressBar.setValue(val * 100 / ui.progressBar.maximum)\n    else:\n            ui.progressBar.setValue(val * 100 / ui.progressBar.maximum)\n    processEvents()\n    \n    if val == ui.progressBar.maximum:\n        if shiboken:\n            if shiboken.isValid(ui.abortButton):\n                ui.abortButton.setEnabled(False)\n                ui.progressLabel.setText(progressCompleteText)\n        else:\n                ui.abortButton.setEnabled(False)\n                ui.progressLabel.setText(progressCompleteText)\n\n    if progress_abort == True:\n        progress_abort = False\n        if shiboken:\n            if shiboken.isValid(ui.progressBar):\n                ui.progressBar.setValue(0)\n                ui.progressLabel.setText(abortedText)\n        else:\n                ui.progressBar.setValue(0)\n                ui.progressLabel.setText(abortedText)\n        raise Exception(\"Controlled, yet rather ungraceful exit, user aborted.\") \ndef progressAbort():\n    global progress_abort\n    progress_abort = True   \n\ndef processEvents():\n    global last_update\n    now = time.time()\n    if now - last_update >= 0.5:\n        last_update = now\n        if not progress_abort:\n            FreeCADGui.updateGui()\n\n\ndef msgDialog(msg, title='FCBmpImport', icon=QtGui.QMessageBox.Information):\n\n    diag = QtGui.QMessageBox(icon, title, msg)\n    diag.setWindowModality(QtCore.Qt.ApplicationModal)\n    diag.exec_()\n \n\n\n\n#create the objects for solid imports\ndef makeOurPart(l,w,h,x1,y1,z1,last_part=False):\n    SF = scale_factor\n    length = l\n    width = w\n    height = h\n    group = None\n\n    if(last_part == True): #wrap it up, we're done (parameters not valid for new part, just display what\n                           #we have so far)\n        wedges=[]\n        ii = 0\n        total = len(boxes)\n        initProgressBar(placingText + str(len(boxes)) + u' '+ shape_basename+u's', len(boxes))\n        doc = App.ActiveDocument\n        for b in boxes:\n\n            #apply scale factor at the last minute since we're waiting on FreeCAD at this point anyway\n            b.x *= SF\n            b.y *= SF\n            b.z *= SF\n            b.length *= SF\n            b.width *= SF\n            #b.height *= SF #no longer apply scale_factor to part_height as of version 2018.05.16\n\n            obj = None\n            if one_solid:\n                #obj = Part.makeWedge(xmin, ymin, zmin, z2min, x2min, xmax, ymax, zmax, z2max, x2max,[pnt, dir])\n                obj = Part.makeWedge(b.x, b.y, b.z, b.z, b.x, b.x+b.length, b.y+b.width, b.z+b.height, b.z+b.height, b.x+b.length)\n                wedges.append(obj)\n            else:\n                obj = doc.addObject(\"Part::Wedge\", b.boxName)\n                if not group:\n                    group = doc.addObject(\"App::DocumentObjectGroup\",shape_basename)\n                group.addObject(obj)\n                obj.Xmin=str(b.x)\n                obj.Ymin =str(b.y)\n                obj.Zmin = str(b.z)\n                obj.Xmax = str(b.x+b.length)\n                obj.X2max = str(b.x+b.length)\n                obj.X2min = str(b.x)\n                obj.Ymax = str(b.y+b.width)\n                obj.Zmax = str(b.z+b.height)\n                obj.Z2min = str(b.z)\n                obj.Z2max=str(b.z+b.height)\n\n            ii += 1\n            if ii % recompute_interval == 0:\n                App.ActiveDocument.recompute()\n            if ii == 2:\n                Gui.SendMsgToActiveView(\"ViewFit\")\n            updateProgressBar(ii)\n\n        if one_solid and not make_compound_solid:\n            initProgressBar(u'Fusing wedges', len(wedges)-1)\n            wedge = wedges[0]\n            interim = wedge #using an interim object greatly speeds up the process versus fusing each wedge individually to the current full fusion\n            for idx in range(1,len(wedges)):\n                if idx % recompute_interval == 0:\n                    wedge = wedge.fuse(interim)\n                    interim = wedges[idx]\n                    continue\n                interim = interim.fuse(wedges[idx])\n                updateProgressBar(idx)\n            wedge = wedge.fuse(interim)\n        if one_solid and make_compound_solid:\n            wedge = Part.makeCompound(wedges)\n        \n        if one_solid:\n            f = doc.addObject(\"Part::Feature\", shape_basename)\n            f.Shape = wedge.removeSplitter()\n\n        Gui.SendMsgToActiveView(\"ViewFit\")\n        App.ActiveDocument.recompute()\n        return      \n    else: #not last part\n        box = Box()\n        box.width = width\n        box.height = height\n        box.length = length\n        box.x = x1\n        box.y = y1\n        box.z = z1\n\n        box.boxName = shape_basename + str(len(boxes))\n        boxes.append(box)\n\n\n\n#returns True if neighboring pixel is foreground color\ndef hasNeighbor(direction, x,y):\n\n    if direction == 'north':\n        if y >= raster_lines - 1:\n            return False\n        return bit_array[x][y + 1] == foreground_color\n    elif direction == 'south':\n        if y == 0:\n            return False\n        return bit_array[x][y - 1] == foreground_color\n    elif direction == 'east':\n        if x == pixels_per_line - 1: \n            return False\n        return bit_array[x + 1][y] == foreground_color\n    elif direction == 'west':\n        if x == 0:\n            return False\n        return bit_array[x - 1][y] == foreground_color\n\n\n\ndef addHLine(x,y,x2,y2,isExtensible):\n\n    newLine = HLine()\n    newLine.left_x = x\n    newLine.left_y = y\n    newLine.right_x = x2\n    newLine.right_y = y2\n    newLine.isExtensible = isExtensible\n    match = False\n\n    for oldLine in hlines:\n        if oldLine.isExtensible and oldLine.right_x == newLine.left_x and oldLine.right_y == newLine.right_y:\n            hlines.remove(oldLine)\n            oldLine.right_x = newLine.right_x\n            oldLine.right_y = newLine.right_y\n            oldLine.isExtensible = isExtensible\n            hlines.append(oldLine)\n            match = True\n            break\n    if match == False:\n        hlines.append(newLine)\n\ndef addVLine(x,y,x2,y2,isExtensible):\n\n    newLine = VLine()\n    newLine.bottom_x = x\n    newLine.bottom_y = y\n    newLine.top_x = x2\n    newLine.top_y = y2\n    newLine.isExtensible = isExtensible\n    match = False\n    counter = 0\n    for oldLine in vlines:\n        if oldLine.isExtensible and oldLine.top_x == newLine.bottom_x and oldLine.top_y == newLine.bottom_y:\n            match = True\n            vlines.remove(oldLine)            \n            oldLine.top_x = newLine.top_x\n            oldLine.top_y = newLine.top_y\n            oldLine.isExtensible = isExtensible\n            vlines.append(oldLine)\n            break\n    if match == False:\n        vlines.append(newLine)\n\ndef previewMaybe(): #we get here if the user presses enter or leaves after editing various line edits\n    if preview_image == None:\n        checkOffsets() #updates globals based on ui elements\n        return\n    else:\n        update_preview()\n\n\ndef update_preview():\n    global preview_image\n    global pixmap\n\n    checkOffsets()\n    if preview_image == None:\n        preview()\n    else:\n        try:\n            scene.clear()\n            pixmap = preview_image\n            preview_image = pixmap\n\n            scalePreview(pixmap, ui.graphicsView, zoomFactor)\n\n        except:\n            App.Console.PrintMessage(graphicsExceptionText)       \n\ndef preview():\n    global preview_image\n    global pixmap\n    global imageName\n    global name\n    global zoomFactor\n    checkOffsets()\n    zoomFactor = 0.95 #show it bit smaller the first time so the axis cross is visible\n    try:\n\n        #name= QtGui.QFileDialog.getOpenFileName(QtGui.qApp.activeWindow(),openMonoFileText,'*.bmp')[0]\n        name= QtGui.QFileDialog.getOpenFileName(QtGui.QApplication.activeWindow(),openMonoFileText,'*.bmp')[0]\n        if not name:\n            return\n        scene.clear()\n        setToolTip(ui.imagePreviewLabel, name)\n        imageName = name\n        pixmap = QtGui.QPixmap(name)\n        preview_image = pixmap\n\n        scalePreview(pixmap, ui.graphicsView, zoomFactor)\n    except:\n        App.Console.PrintMessage(graphicsExceptionText)\n\ndef doGrayScale():\n    global bit_array #will hold the pixel gray scales in the form of a decimal value between 0 (darker) and 1 (lighter)\n    global raster_lines\n    global pixels_per_line\n    global foreground_color\n    global black_foreground\n    global import_z_offset\n\n    bit_array = [[]]\n    global boxes\n    boxes = []\n    global vlines\n    vlines = []\n    global hlines\n    hlines = []\n    global pixmap\n\n    checkOffsets() #validate and update globals in offsets options group\n    if import_z_offset == 0:\n        setTo1Text = u'Set it to 1'\n        continueAnywayText = u'Continue anyway'\n        cancelText = u'Cancel'\n        needZText = u'Need a Z offset for the back plate height'\n        items=(setTo1Text,continueAnywayText,cancelText)\n        item, okpressed = QtGui.QInputDialog.getItem(MainWindow,needZText,needZText, items, 0, False)\n\n        if not okpressed:\n            return\n        elif item==cancelText:\n            return\n        elif item == setTo1Text:\n            import_z_offset = 1\n            ui.zOffsetEdit.setText('1')\n            processEvents()\n    #display preview image\n    if imageName == None:\n        preview() #sets global name variable to new fileName\n    try:\n        scene.clear()\n        pixmap = QtGui.QPixmap(name)\n        qImage = QtGui.QImage(name)\n        scalePreview(pixmap, ui.graphicsView, 1.0)\n    except:\n        App.Console.PrintMessage(graphicsExceptionText)\n\n    if len(name) > 0:\n        with open(name, \"rb\") as binary_file:\n            data = binary_file.read()\n\n        unpacked = struct.unpack_from(\"B\" * len(data), data)\n        byte0 = unpacked[0] #should be 0x42 'B'\n        byte1 = unpacked[1] #should be 0x4d 'M'\n        byte1c = unpacked[0x1c] #bits per pixel (must be 1)\n        if byte0 != 0x42 or byte1 != 0x4d:# or byte1c != 0x08: #'BM' in first 2 bytes signifies this is a .BMP file, 0x08 at 0x1c means 8 bits per pixel\n            msgDialog(invalidFileText,'FCBmpImport', QtGui.QMessageBox.Critical)\n            return\n            \n        else: #parse the .BMP file\n            #4 bytes (little endian) beginning at 0x0a gives the offset into\n                         #the\n                     #pixel array\n            offset = unpacked[0x0a] + unpacked[0x0b] * 256 + unpacked[0x0c] * 256 * 256 + unpacked[0x0d] * 256 * 256 * 256\n            #horizontal pixel count (pixels per row) provided in 4 bytes\n            #(little\n            #endian) beginning at 0x12\n            pixels_per_line = unpacked[0x12] + unpacked[0x13] * 256 + unpacked[0x14] * 256 * 256 + unpacked[0x15] * 256 * 256 * 256\n            #vertical pixels (rows) at 0x16, again 4 bytes little endian\n            raster_lines = unpacked[0x16] + unpacked[0x17] * 256 + unpacked[0x18] * 256 * 256 + unpacked[0x19] * 256 * 256 * 256\n            bit_array = [[0 for y in range(raster_lines)] for x in range(pixels_per_line) ] #initialize bit_array\n\n            initProgressBar(u'Loading image file', raster_lines)\n            for yy in range(0, raster_lines):\n                updateProgressBar(yy)\n                for xx in range(0, pixels_per_line): #npb = non-padded-byte\n                    pixColor = QtGui.QColor(qImage.pixel(xx,yy))\n                    our_byte= 1-((pixColor.red()+pixColor.green()+pixColor.blue())/3.0/255.0)\n                    bit_array[xx][yy] = our_byte\n    else:\n        return #no file selected\n\n    if not App.ActiveDocument:\n        App.newDocument()\n\n    initProgressBar(parsingBmpText, raster_lines - 1)\n    group = App.ActiveDocument.addObject(\"App::DocumentObjectGroup\",shape_basename)\n    backPlate = Part.makeBox(pixels_per_line,raster_lines, part_height)\n    f = App.ActiveDocument.addObject(\"Part::Feature\",\"BackPlate\")\n    group.addObject(f)\n    f.Shape=backPlate\n    f.Placement = App.Placement(App.Vector(import_x_offset,import_y_offset,0), App.Rotation(App.Vector(0,0,1),0),App.Vector(0,0,0)) #backplate is at z=0, litho starts at z offset\n    fusion = None\n    compounds = []\n    for y in range(0,raster_lines):\n        #time.sleep(0.001)\n        updateProgressBar(y)\n        wedges=[]\n\n        #we'll make rectangular parts to keep part count down for better\n        #performance\n\n        L = []    \n        for x in range(0, pixels_per_line):    \n            L.append(bit_array[x][y])\n\n        grouped_L = [(k, sum(1 for i in g)) for k,g in groupby(L)] #credit: Josh Caswell of stackoverflow for this line of code\n                                                                    #takes a list like [1,1,1,0,0,1,0,1,1,1] and turns it into a\n                                                                    #list of tuples[(1,3),(0,2),(1,1),(0,1),(1,3)]\n                                                                                                                                           \n        current_x = 0 #tracks the x-coordinate for each new contiguous pixel group on this row\n        wedges=[]\n        for g in range(len(grouped_L)-1,-1,-1): #each g is a tuple in the form (pixel, count)\n            #time.sleep(0.001)\n            updateProgressBar(y)\n            pixel = grouped_L[g][0]#pixel gray scale as a percentage of 255,e.g. 0.396215\n            count = grouped_L[g][1]#how many in a row in this group?\n\n            box = Box()\n            box.width = 1\n            box.height = part_height*pixel+import_z_offset\n            box.length = count\n            box.x = current_x+import_x_offset\n            box.y = y+import_y_offset\n            box.z = import_z_offset\n            obj = Part.makeWedge(box.x, box.y, box.z, box.z, box.x, box.x+box.length, box.y+box.width, box.z+box.height, box.z+box.height, box.x+box.length)\n            wedges.append(obj)\n            current_x = current_x + count\n        \n        lineName = \"Line\"+str(y)\n        comp = Part.makeCompound(wedges)\n        lineWedge = App.ActiveDocument.addObject(\"Part::Feature\",lineName)\n        lineWedge.Shape = comp\n        group.addObject(lineWedge)\n\n        shapes=[]\n\n    #makeOurPart(0,0,0,0,0,0,True) #0's just place holders, no new part will be made this final run\n    \n    #compound = Part.makeCompound(compounds)\n    #Part.show(compound,\"Lithophane\")\n    #f = App.ActiveDocument.addObject(\"Part::Feature\", shape_basename)\n    #f.Shape = compound.removeSplitter()\n    #Part.show(compound)\n     \n    App.ActiveDocument.recompute()\n    Gui.SendMsgToActiveView(\"ViewFit\") \n\n\ndef doImport():\n    global bit_array #will hold the bits used to determine pixel color (1's and 0's)\n    global raster_lines\n    global pixels_per_line\n    global foreground_color\n    global black_foreground\n    global sketch_external\n    global import_as_2d\n    global shape_form\n\n    bit_array = [[]]\n    global boxes\n    boxes = []\n    global vlines\n    vlines = []\n    global hlines\n    hlines = []\n    global pixmap\n\n    if ui.blackForegroundCheckbox.isChecked():\n        black_foreground = True\n    else:\n        black_foreground = False\n\n    checkOffsets() #validate and update globals in offsets options group\n    if import_as_2d and cheat_factor == 0:\n        msgDialog(cantImportText)\n        return\n    #display preview image\n    if imageName == None:\n        preview() #sets global name variable to new fileName\n    try:\n        scene.clear()\n        pixmap = QtGui.QPixmap(name)\n        scalePreview(pixmap, ui.graphicsView, 1.0)\n    except:\n        App.Console.PrintMessage(graphicsExceptionText)\n    if len(name) > 0:\n        with open(name, \"rb\") as binary_file:\n            data = binary_file.read()\n        \n        unpacked = struct.unpack_from(\"B\" * len(data), data)\n   \n        byte0 = unpacked[0] #should be 0x42 'B'\n        byte1 = unpacked[1] #should be 0x4d 'M'\n        byte1c = unpacked[0x1c] #bits per pixel (must be 1)\n        if byte0 != 0x42 or byte1 != 0x4d or byte1c != 0x01: #'BM' in first 2 bytes signifies this is a .BMP file\n            msgDialog(invalidFileText,'FCBmpImport', QtGui.QMessageBox.Critical)\n            return\n        else: #parse the .BMP file\n            #4 bytes (little endian) beginning at 0x0a gives the offset into\n                         #the\n                     #pixel array\n            offset = unpacked[0x0a] + unpacked[0x0b] * 256 + unpacked[0x0c] * 256 * 256 + unpacked[0x0d] * 256 * 256 * 256\n            #horizontal pixel count (pixels per row) provided in 4 bytes\n            #(little\n            #endian) beginning at 0x12\n            pixels_per_line = unpacked[0x12] + unpacked[0x13] * 256 + unpacked[0x14] * 256 * 256 + unpacked[0x15] * 256 * 256 * 256\n            #vertical pixels (rows) at 0x16, again 4 bytes little endian\n            raster_lines = unpacked[0x16] + unpacked[0x17] * 256 + unpacked[0x18] * 256 * 256 + unpacked[0x19] * 256 * 256 * 256\n            bit_array = [[0 for y in range(raster_lines)] for x in range(pixels_per_line) ] #initialize bit_array\n            bytes_per_row = int((pixels_per_line + 31) / 32) * 4 #rows get padded out to multiples of 32 bits (4 bytes)\n            non_padded_bytes = math.floor(pixels_per_line / 8)\n            if (pixels_per_line % 8) != 0:\n                non_padded_bytes += 1\n            non_padded_bytes = int(non_padded_bytes)        \n            color_1_Blue = unpacked[0x36] #monochrome images don't necessarily have to be black and white\n            color_1_Green = unpacked[0x37] #could be for example red and white, blue and green, whatever\n            color_1_Red = unpacked[0x38] #but vast majority will be black and white\n            color_2_Blue = unpacked[0x3a] #we assume ours will be black and white\n            color_2_Green = unpacked[0x3b]\n            color_2_Red = unpacked[0x3c]\n            color_1_isBlack = False\n            if color_1_Blue == 0 and color_1_Green == 0 and color_1_Red == 0:\n                color_1_isBlack = True\n\n\n            initProgressBar(u'Loading image file', raster_lines)\n            for rr in range(0, raster_lines):\n                updateProgressBar(rr)\n                for npb in range(0, non_padded_bytes): #npb = non-padded-byte\n                    if int(offset+npb+rr*bytes_per_row)>len(unpacked):\n                        continue\n                    our_byte = unpacked[int(offset + npb + rr * bytes_per_row)]                  \n                    byte_string = bin(our_byte)[2:].rjust(8, '0') #credit Daniel G at stackoverflow for this line of code\n                    whichBit = 0                \n                    for bit in byte_string:\n                        x = npb * 8 + whichBit\n                        y = rr \n                        if x > pixels_per_line - 1:#check to see if this is a padded bit\n                            break                    \n                        bit_array[x][y] = int(bit)\n                        whichBit += 1\n\n            if black_foreground == True:\n                if color_1_isBlack:\n                    foreground_color = 0 #color 1\n                else:\n                    foreground_color = 1 #color 2\n            else: \n                if color_1_isBlack:\n                    foreground_color = 1 #color 2\n                else:\n                    foreground_color = 0 #color 1\n\n\n \n    else:\n        return #no file selected\n\n    if not App.ActiveDocument:\n        App.newDocument()\n\n\n    if import_as_2d and not shape_form:  \n        sketch = App.ActiveDocument.addObject('Sketcher::SketchObject',shape_basename)\n    elif import_as_2d and shape_form and shape_form != pointText:\n        group = App.ActiveDocument.addObject(\"App::DocumentObjectGroup\",shape_basename)\n    elif import_as_2d and shape_form == pointText:\n        point_compounds = []\n \n    initProgressBar(parsingBmpText, raster_lines - 1)\n\n    for y in range(0,raster_lines):\n        #time.sleep(0.001)\n        updateProgressBar(y)\n\n        App.ActiveDocument.recompute()\n\n\n        #we'll make rectangular parts to keep part count down for better\n        #performance\n        if import_as_2d == False:\n\n            L = []    \n            for x in range(0, pixels_per_line):    \n                L.append(bit_array[x][y])\n\n            grouped_L = [(k, sum(1 for i in g)) for k,g in groupby(L)] #credit: Josh Caswell of stackoverflow for this line of code\n                                                                       #takes a list like [1,1,1,0,0,1,0,1,1,1] and turns it into a\n                                                                       #list of tuples[(1,3),(0,2),(1,1),(0,1),(1,3)]\n                                                                                                                                           \n            current_x = 0 #tracks the x-coordinate for each new contiguous pixel group on this row\n            for g in grouped_L: #each g is a tuple in the form (pixel, count)\n                pixel = g[0]#which pixel, black or white?\n                count = g[1]#how many in a row in this group?\n                if pixel == foreground_color:\n                    makeOurPart(count,1, part_height, current_x + import_x_offset, y + import_y_offset, import_z_offset, False) #False = not finished\n                current_x = current_x + count \n\n        else: #sketch import\n\n            for x in range(0, pixels_per_line):            \n                pixel = bit_array[x][y]\n                if pixel != foreground_color:\n                    continue #we're done with this pixel, nothing to see here, move along\n                else:\n                    #this is a pixel containing our target color\n                    #strategy is to surround each pixel with line segments\n                    #we check to see if there are pixels to east, north, etc. to see lines are needed above, below, etc.\n                    #we want to minimize the number of line segments used where possible\n\n                    if hasNeighbor('north',x,y) == False:\n                        addHLine(x,y + 1,x + 1,y + 1,hasNeighbor('east',x,y)) #no neighbor there so add a line over the cell\n \n                    if hasNeighbor('south',x,y) == False:\n                        addHLine(x,y,x + 1,y,hasNeighbor('east',x,y)) #extra call to hasNeighbor determines whether this line is extensible\n               \n                    if hasNeighbor('west',x,y) == False:\n                        addVLine(x,y,x,y + 1,hasNeighbor('north',x,y)) #x,y = top_x, top_y for new vline\n               \n                    if hasNeighbor('east',x,y) == False:\n                        addVLine(x + 1,y,x + 1,y + 1,hasNeighbor('north',x,y)) #addVLine manages the list of vlines\n\n    #outer y loop now complete\n    if import_as_2d == False:\n        makeOurPart(0,0,0,0,0,0,True) #0's just place holders, no new part will be made this final run\n    \n        \n    #stage 2 (adding hlines and vlines to the sketch)\n    if import_as_2d: #sketch unless shape_form is one of \"points\", \"faces\", or \"wires\"\n\n        #where 4 line segments meet is where we need to fix things up if\n        #cheat_factor is enabled\n        #we want the top and left to stay connected and the bottom and right to\n        #stay connected\n        #but we don't want both intersections to be coincidental at the same\n        #point, we want them\n        #cheat_factor distance apart both horizontally and vertically\n        new_hlines = [] #to be added\n        new_vlines = []\n        old_hlines = [] #to be removed\n        old_vlines = []\n        hSub = []\n        vSub = []\n        if cheat_factor != 0:\n            initProgressBar('Analyzing Cheats ', len(hlines) + len(vlines))\n                #optimization reduces size of lists we have to deal with to\n                #only those lines with diagonal adjacencies\n            it = 0\n            for l1 in hlines:\n                it += 1\n                updateProgressBar(it)\n                for l2 in hlines:\n                    if l1.left_x == l2.right_x and l1.left_y == l2.right_y:\n                        hSub.append(l1)\n                        hSub.append(l2)\n                        continue\n\n            hSub = list(set(hSub))\n\n            for l1 in vlines:\n                it+=1\n                updateProgressBar(it)\n                for l2 in vlines:\n\n                    if l1.top_x == l2.bottom_x and l1.top_y == l2.bottom_y:\n                        vSub.append(l1)\n                        vSub.append(l2)\n                        continue\n            vSub = list(set(vSub))\n            it = 0\n            initProgressBar(applyingCheatsText, len(hSub)+len(vSub) )\n            for left in hSub:\n                it += 1\n                updateProgressBar(it)\n                for right in hSub:\n                    if left.right_x != right.left_x or left.right_y != right.left_y:\n                        continue\n                    for top in vSub:\n                        if top.bottom_x != left.right_x or top.bottom_x != right.left_x or top.bottom_y != left.right_y or top.bottom_y != right.left_y:\n                            continue\n                        for bottom in vSub:\n                            if bottom.top_x == top.bottom_x and bottom.top_y == top.bottom_y and left.right_x == right.left_x and left.right_y == right.left_y and bottom.top_x == left.right_x and bottom.top_y == left.right_y:\n                                direction = getCheatDirection(bottom.top_x,bottom.top_y)\n                                #will be 1 if upper quadrant has a pixel,\n                                #meaning pixels are at Upper Right and BL, else -1,\n                                #meaning pixels are at UL and BR\n                                new_top = top\n                                new_bottom = bottom\n                                new_left = left\n                                new_right = right\n                                if direction == 1:\n                                    new_top.bottom_x -= cheat_factor\n                                    new_top.bottom_y += cheat_factor\n                                    new_left.right_x -= cheat_factor\n                                    new_left.right_y += cheat_factor\n                                    new_right.left_x += cheat_factor\n                                    new_right.left_y -= cheat_factor\n                                    new_bottom.top_x += cheat_factor\n                                    new_bottom.top_y -= cheat_factor\n                                else:\n                                    new_top.bottom_x += cheat_factor\n                                    new_top.bottom_y += cheat_factor\n                                    new_left.right_x -= cheat_factor\n                                    new_left.right_y -= cheat_factor\n                                    new_right.left_x += cheat_factor\n                                    new_right.left_y += cheat_factor\n                                    new_bottom.top_x -= cheat_factor\n                                    new_bottom.top_y -= cheat_factor\n\n\n\n                                #out with the old, in with the new\n                                new_vlines.append(new_top)\n                                new_vlines.append(new_bottom)\n                                new_hlines.append(new_left)\n                                new_hlines.append(new_right)\n                                old_vlines.append(top)\n                                old_vlines.append(bottom)\n                                old_hlines.append(left)\n                                old_hlines.append(right)\n                                #break\n        for vl in old_vlines:\n            if vl in vlines:\n                vlines.remove(vl)\n        for vl in new_vlines:\n            if not vl in vlines:\n                vlines.append(vl)\n        for hl in old_hlines:\n            if hl in hlines:                \n                hlines.remove(hl)\n        for hl in new_hlines:\n            if not hl in hlines:\n                hlines.append(hl)\n\n        if not shape_form:\n\n            job = len(hlines) + len(vlines)\n            initProgressBar(addingText + str(job) + lineSegmentsText, job)\n            progress = 0\n    \n            for hl in hlines:\n                SF = scale_factor\n                sketch.addGeometry(Part.LineSegment(App.Vector(SF * (hl.left_x + import_x_offset),SF * (hl.left_y + import_y_offset),SF * (0 + import_z_offset)), App.Vector(SF * (hl.right_x + import_x_offset),SF * (hl.right_y + import_y_offset),SF * (0 + import_z_offset))),False)\n                progress+=1\n                if progress == 10:\n                    Gui.SendMsgToActiveView(\"ViewFit\") \n                updateProgressBar(progress)\n\n            for vl in vlines:    \n                SF = scale_factor\n                sketch.addGeometry(Part.LineSegment(App.Vector(SF * (vl.bottom_x + import_x_offset),SF * (vl.bottom_y + import_y_offset),SF * (0 + import_z_offset)),App.Vector(SF * (vl.top_x + import_x_offset),SF * (vl.top_y+import_y_offset),SF * (0 + import_z_offset))),False)\n                progress+=1\n                updateProgressBar(progress)\n\n        elif shape_form: #Points, Faces, or Wires\n\n\n            #at this point we have 2 lists of VLines and HLines, but they're not linked together\n            #we need to sort them into shapes, then form edges out of those shapes, wires out of those edges, faces out of those wires\n\n            #for every hline there are exactly 2 vlines connected to it, and same for every vline, with 2 hlines connected to it (cheat factor ensures this)\n            #at some point we get back to the original hline with a vline connected back to it.\n            shapes = []\n            attached = []\n            initProgressBar(buildingShapesText, len(hlines)-1)\n            for it in range(0,len(hlines)):\n                updateProgressBar(it)\n                hl = hlines[it]\n                if hl in attached:\n                    continue\n                shape = []\n                shape.append(hl)\n                attached.append(hl)\n                cl = findConnectingLine(hl,hl)\n                cl2 = findConnectingLine(cl,hl)\n                cl3 = findConnectingLine(cl2,cl)\n                if cl not in attached:\n                    shape.append(cl)\n                if cl2 not in attached:\n                    shape.append(cl2)\n                if cl3 not in attached:\n                    shape.append(cl3)\n                attached.append(cl)\n                attached.append(cl2)\n                attached.append(cl3)\n                while compareLines(cl3, hl) == False:\n                    if cl3 not in attached:\n                        shape.append(cl3)\n                        attached.append(cl3)\n                    cl = cl2\n                    cl2 = cl3\n                    cl3 = findConnectingLine(cl2,cl)\n                shapes.append(shape)\n                shape = []\n            part_lines = []\n                \n            edges=[]\n            SF = scale_factor\n            for sh in shapes:\n                for line in sh:\n                    if isinstance(line,HLine):\n                        hl = Part.makeLine((SF * (line.left_x + import_x_offset),SF * (line.left_y + import_y_offset),SF * (0 + import_z_offset)),  (SF * (line.right_x + import_x_offset),SF * (line.right_y + import_y_offset),SF * (0 + import_z_offset)))\n                        part_lines.append(hl)\n                    else:\n                        vl = Part.makeLine((SF * (line.bottom_x + import_x_offset),SF * (line.bottom_y + import_y_offset),SF * (0 + import_z_offset)),(SF * (line.top_x + import_x_offset),SF * (line.top_y+import_y_offset),SF * (0 + import_z_offset)))\n                        part_lines.append(vl)\n                for pl in part_lines:\n                    e = Part.Edge(pl)\n                    edges.append(e)\n                w = Part.Wire(edges)\n                edges=[]\n                part_lines = []\n                vectors=[]\n\n                if shape_form == faceText:\n                    dw = Draft.makeWire(w,closed=True,face=True)\n                    group.addObject(dw)\n                       \n                elif shape_form == wireText:\n                    dw = Draft.makeWire(w, closed=True, face=False)\n                    group.addObject(dw)\n\n                elif shape_form == pointText:\n                    verts = [Part.Vertex(v) for v in w.Vertexes]\n                    point_compounds.extend(verts)\n\n    if import_as_2d and shape_form == pointText:\n        points = App.ActiveDocument.addObject(\"Part::Feature\",shape_basename)\n        points.Shape = Part.makeCompound(point_compounds)\n        if sketch_external:\n            sketch = App.ActiveDocument.addObject(\"Sketcher::SketchObject\",\"Sketch\")\n            initProgressBar(\"Adding external geometry\", len(points.Shape.Vertexes)-1)\n            for ii in range(0,len(points.Shape.Vertexes)):\n                vname = 'Vertex'+str(ii+1)\n                sketch.addExternal(points.Name, vname)\n                updateProgressBar(ii)\n\n\n    App.ActiveDocument.recompute()\n    Gui.SendMsgToActiveView(\"ViewFit\")\n    import_as_2d = False\n    shape_form = None\n    sketch_external = False\n#end of doImport()\ndef getCheatDirection(x,y): #do we cheat to top left/bottom right or top right/bottom left?\n    direction = 1\n    if bit_array[x][y] != foreground_color: #upper right quadrant is not a pixel\n        direction = -1\n\n    return direction\n\n#helper functions for importing as shapes   \ndef findConnectingLine(line,alreadyConnectedLine):\n    #find the other connecting line, can be only one\n    if type(line) is HLine:\n        for v in vlines:\n            if v.bottom_x == line.right_x and v.bottom_y == line.right_y and compareLines(v,alreadyConnectedLine)==False:\n                return v\n            if v.top_x == line.right_x and v.top_y == line.right_y and compareLines(v,alreadyConnectedLine)==False:\n                return v\n            if v.bottom_x == line.left_x and v.bottom_y == line.left_y and compareLines(v,alreadyConnectedLine)==False:\n                return v\n            if v.top_x == line.left_x and v.top_y == line.left_y and compareLines(v,alreadyConnectedLine)==False:\n                return v\n        return None #should never get here unless there is some error in program logic\n    else: #line is a VLine, so check for connecting hline\n        for h in hlines:\n            if h.left_x == line.top_x and h.left_y == line.top_y and compareLines(h,alreadyConnectedLine)==False:\n                return h\n            if h.right_x == line.top_x and h.right_y == line.top_y and compareLines(h,alreadyConnectedLine)==False:\n                return h\n            if h.left_x == line.bottom_x and h.left_y == line.bottom_y and compareLines(h,alreadyConnectedLine)==False:\n                return h\n            if h.right_x == line.bottom_x and h.right_y == line.bottom_y and compareLines(h,alreadyConnectedLine)==False:\n                return h\n        return None\n\ndef compareLines(line1, line2):\n    if isinstance(line1,HLine) and isinstance(line2, HLine):\n        if line1.left_x == line2.left_x and line1.left_y == line2.left_y and line1.right_x == line2.right_x and line1.right_y == line2.right_y:\n            return True\n        else:\n            return False \n    elif isinstance(line1, VLine) and isinstance(line2,VLine): #VLines\n        if line1.top_x == line2.top_x and line1.top_y == line2.top_y and line1.bottom_x == line2.bottom_x and line1.bottom_y == line2.bottom_y:\n            return True\n        else:\n            return False\n    else:\n            return False #2 different line types\n              \n\n\n\ndef scalePreview(pixmap, gView, scaleFactor):\n    global preview_width\n    global preview_height\n    global actual_zoom\n    global viewrectHeight\n    global viewrectWidth\n    global shownX\n    global shownY\n    global factor\n\n    modifiers = QtGui.QApplication.keyboardModifiers()\n\n    rect = QtCore.QRectF(pixmap.rect())\n    if not rect.isNull():\n        w = rect.width()\n        h = rect.height()\n        preview_width = w\n        preview_height = h\n       \n        gView.setSceneRect(rect)\n        unity = gView.transform().mapRect(QtCore.QRectF(0, 0, 1, 1))\n        gView.scale(1 / unity.width(), 1 / unity.height())\n        viewrect = gView.viewport().rect()\n        scenerect = gView.transform().mapRect(rect)\n        viewrectHeight = viewrect.height()\n        viewrectWidth = viewrect.width()\n        factor = min(viewrect.width() / scenerect.width(),\n        viewrect.height() / scenerect.height())\n        \n        y = (h + import_y_offset)\n        x = -1*import_x_offset\n        \n        \n        penRed = QtGui.QPen(QtCore.Qt.red) #axis cross (red and green)\n        penGreen = QtGui.QPen(QtCore.Qt.green)\n        penBlue = QtGui.QPen(QtCore.Qt.blue) #measuring lines\n        penYellow = QtGui.QPen(QtCore.Qt.yellow)\n        penDarkRed = QtGui.QPen(QtCore.Qt.darkRed)\n        penRed.setWidth(1.0/factor)\n        penGreen.setWidth(1.0/factor)\n        penBlue.setWidth(1.0/factor)\n        penYellow.setWidth(1.0/factor)\n        penDarkRed.setWidth(1.0/factor)\n        bkcolor = MainWindow.palette().color(QtGui.QPalette.Background)\n        scene.setBackgroundBrush(bkcolor)\n        scene.addPixmap(pixmap)\n\n        actual_zoom = factor*scaleFactor\n        shownX = 1.0/(actual_zoom/viewrectWidth)\n        shownY = 1.0/(actual_zoom/viewrectHeight)\n        if modifiers == QtCore.Qt.ShiftModifier:\n            for ii in range(0,int(w)):\n                if ii%10==0:\n                    scene.addLine(ii,0,ii,h,penDarkRed)\n                elif ii%5==0:\n                    scene.addLine(ii,0,ii,h,penYellow)\n                else:\n                    scene.addLine(ii,0,ii,h,penBlue)\n        elif modifiers == QtCore.Qt.ControlModifier:\n            for ii in range(0,int(h)):\n                if ii%10==0:\n                    scene.addLine(0,ii,w,ii,penDarkRed)\n                elif ii%5==0:\n                    scene.addLine(0,ii,w,ii,penYellow)\n                else:\n                    scene.addLine(0,ii,w,ii,penBlue)\n\n        scene.addLine(x-10.0/factor,y,x+10.0/factor,y,penRed) #axis cross\n        scene.addLine(x,y-10.0/factor, x,y+10.0/factor,penGreen)\n \n        gView.scale(factor * scaleFactor, factor * scaleFactor)\n        ui.imagePreviewLabel.setText(imagePreviewLabelText + u' ('+str(int(w))+u'x'+str(int(h))+u'),  px,py = '+str(round(shownX,2))+u','+str(round(shownY,2))+u'  '+zoomText+' = '+str(round(factor*scaleFactor,4))+u'x')\n       \n\n\n\n#FCBmpImport logo\nxpm_file = [\"78 16 17 1\",\n\" \tc None\",\n\".\tc #020401\",\n\"+\tc #3E002C\",\n\"@\tc #0D1348\",\n\"#\tc #742423\",\n\"$\tc #BB1518\",\n\"%\tc #913A00\",\n\"&\tc #4C6290\",\n\"*\tc #EA3E26\",\n\"=\tc #8E818B\",\n\"-\tc #5C94D3\",\n\";\tc #AEAE69\",\n\">\tc #86D3FC\",\n\",\tc #FFC06C\",\n\"'\tc #A9D5DA\",\n\")\tc #FDFFCE\",\n\"!\tc #FDFFFC\",\n\"!!!'========!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\",\n\"!!!=*******#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\",\n\"!!!=*******#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\",\n\"!!!=**$#####!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\",\n\"!!!=**#!!!!!='!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\",\n\"!!!=**#!!!!'&&!''!!!!!>@...,!!!!!!!!!!!!!!>@.#)!!!!!!!!!!!!!!!!!!!!!!!!>#)!!!!\",\n\"!!!=*$$###&&-&&&&!!!!!>#)!>#)!!!!!!!!!!!!!!>#)!!!!!!!!!!!!!!!!!!!!!!!!!>#)!!!!\",\n\"!!!=*$$$$#------&!!!!!>#)!-%>#@.,@.,>#@..,!>#)>#@.,@.,>#@..,!>@.#)>#&#)@..,!!!\",\n\"!!!=*$***#-&==&-&'!!!!>@...,>+,-.,-%'+,!-#)>#)>+,-.,-%'+,!-#)@,!-%>@,!!>#)!!!!\",\n\"!!!=*$#=@&-=!!=--&=!!!>#)!>#'#)>#)>#'#)!'@,>#)>#)>#)>#'#)!'@;#)!>+'#)!!>#)!!!!\",\n\"!!!=*$#=&--=!!=-&&'!!!>#)!'+'#)>#)>#'#)!'@,>#)>#)>#)>#'#)!'@;#)!>+'#)!!>#)!!!!\",\n\"!!!=$$#!'&-&==&-&!!!!!>#)!-%'#)>#)>#'#)!-%)>#)>#)>#)>#'#)!-%)@,!-%>#)!!>+)!!!!\",\n\"!!!=$$#!!&---&-&&'!!!!>@..#)>#)>#)>#'@..#)>@.#'#)>#)>#'@..#)!>@.#)>#)!!!&.,!!!\",\n\"!!!=$$#!!&&&&&&&&'!!!!!!!!!!!!!!!!!!>#)!!!!!!!!!!!!!!!>#)!!!!!!!!!!!!!!!!!!!!!\",\n\"!!!=*$#!!''!&&'!!!!!!!!!!!!!!!!!!!!!>#)!!!!!!!!!!!!!!!>#)!!!!!!!!!!!!!!!!!!!!!\",\n\"!!!'===!!!!!'=!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\"]\n\n\n\ndef doSolid():\n    global import_as_2d\n    global one_solid\n    global make_compound_solid\n    import_as_2d = False\n\n    grayScaleLithophaneText=u'GRAY SCALE LITHOPHANE'\n    items = (multipleSolidsText, compoundSolidText, solidObjectText, grayScaleLithophaneText)\n    item, ok = QtGui.QInputDialog.getItem(MainWindow, solidImportText, solidImportText, items, 0, False)\n    if ok:\n        if item==grayScaleLithophaneText:\n            doGrayScale()\n            return\n\n        if item == solidObjectText:\n            one_solid = True\n            make_compound_solid = False\n        elif item == compoundSolidText:\n            one_solid = True\n            make_compound_solid = True\n        else:\n            one_solid = False\n            make_compound_solid = False\n        doImport()\n\n\n\ndef doSketch():\n    global import_as_2d\n    global sketch_support\n    global shape_form\n    import_as_2d = True\n    shape_form = None\n    doImport()\n\n\ndef doWire():\n    global import_as_2d\n    global shape_form\n    items = [\"Wires\",\"Faces\",\"Cancel\"]\n    item,ok = QtGui.QInputDialog.getItem(MainWindow,\"Wire options\",\"Select whether to make faces from wires.\\n\",items,0,False)\n    if ok:\n        if item == items[0]:\n            shape_form = wireText\n        elif item == items[1]:\n            shape_form = faceText\n        else: #cancel\n            return\n    import_as_2d = True\n    doImport()\n\n    \ndef doPoint():\n    global import_as_2d\n    global shape_form\n    global sketch_external\n    items = [\"Points compound\",\"Sketch external\",\"Cancel\"]\n    item,ok = QtGui.QInputDialog.getItem(MainWindow,\"Point options\",\"Select whether to make a sketch and add the points as external geometry.\\n\",items,0,False)\n    if ok:\n        if item == items[0]:\n            sketch_external = False\n        elif item == items[1]:\n            sketch_external = True\n        else: #cancel\n            return\n    import_as_2d = True\n    shape_form = pointText\n    doImport()\n\n\ndef setToolTip(obj,tip):\n    obj.setToolTip(_fromUtf8(tip))\n\ndef zeroOffsets():\n    global import_x_offset\n    global import_y_offset\n    global import_z_offset\n\n    import_x_offset = 0\n    ui.xOffsetEdit.setText('0')\n    import_y_offset = 0\n    ui.yOffsetEdit.setText('0')\n    import_z_offset = 0\n    ui.zOffsetEdit.setText('0')\n    processEvents()\n\ndef reportMsg(elem, msg): #save history of entries into line edits in the associated label as a tool tip\n    if msg not in elem.toolTip(): #but only those entries not already in there\n        setToolTip(elem,elem.toolTip()+msg+'\\n')\n\ndef checkOffsets():\n    #check all the offset, scale, etc.  options and set globals accordingly\n    global import_x_offset\n    global import_y_offset\n    global import_z_offset\n    global scale_factor\n    global recompute_interval\n    global shape_basename\n    global part_height\n    global cheat_factor\n\n    try:\n        se = ui.scaleEdit.text()\n        reportMsg(ui.scaleLabel,se)\n        if(se == ''):\n            scale_factor = 1 #set safe default\n            ui.scaleEdit.setText('1')\n            return\n        scale_factor = eval_expr(ui.scaleEdit.text()) #eval_expr() allows for input such as 25.4 / 2**4\n        ui.scaleEdit.setText(str(scale_factor))\n    except:\n        ui.scaleEdit.setText('1')\n        scale_factor = 1\n        raise StandardError(scaleFactorErrorText)\n    \n    try:\n        ri = ui.recomputeIntervalEdit.text()\n        reportMsg(ui.recomputeIntervalLabel,ri)\n        if(ri == ''):\n            recompute_interval = 10\n            return\n        recompute_interval = eval_expr(ri)\n        ui.recomputeIntervalEdit.setText(str(recompute_interval))\n    except:\n        ui.recomputeIntervalEdit.setText('100')\n        recompute_interval = 10\n        raise StandardError(recomputeErrorText)\n#x\n    try:\n        xo = ui.xOffsetEdit.text()\n        reportMsg(ui.xOffsetLabel,xo)\n       \n        if (xo == \"\"):\n            import_x_offset = 0\n            ui.xOffsetEdit.setText('0')\n            return\n\n        import_x_offset = eval_expr(xo)\n        ui.xOffsetEdit.setText(str(import_x_offset))\n\n\n    except:\n        ui.xOffsetEdit.setText('0')\n        import_x_offset = 0\n        raise StandardError(xOffsetErrorText)\n#y\n    try:\n        yo = ui.yOffsetEdit.text()\n        reportMsg(ui.yOffsetLabel,yo)\n        if (yo == \"\"):\n            import_y_offset = 0\n            ui.yOffsetEdit.setText('0')\n            return\n\n        import_y_offset = eval_expr(yo)\n        ui.yOffsetEdit.setText(str(import_y_offset))\n    except:\n        ui.yOffsetEdit.setText('0')\n        import_y_offset = 0\n        raise StandardError(yOffsetErrorText)\n\n#z\n    try:\n        zo = ui.zOffsetEdit.text()\n        reportMsg(ui.zOffsetLabel,zo)\n        if (zo == \"\"):\n            import_z_offset = 0\n            ui.zOffsetEdit.setText('0')\n            return\n\n        import_z_offset = eval_expr(zo)\n        ui.zOffsetEdit.setText(str(import_z_offset))\n    except:\n        ui.zOffsetEdit.setText('0')\n        import_z_offset = 0\n        raise StandardError(zOffsetErrorText)\n\n    try:\n        cbn = ui.baseNameEdit.text()\n        reportMsg(ui.baseNameLabel,cbn)\n        shape_basename = cbn\n    except:\n        ui.baseNameEdit.setText(baseNameText)\n        shape_basename = baseNameText\n        raise StandardError(baseNameErrorText)\n    \n#shape height\n    try:\n        ch = ui.shapeHeightEdit.text()\n        reportMsg(ui.shapeHeightLabel,ch)\n        if (ch == \"\"):\n            part_height = 1\n            ui.shapeHeightEdit.setText('1')\n            return\n\n        part_height = eval_expr(ch)\n        ui.shapeHeightEdit.setText(str(part_height))\n    except:\n        ui.shapeHeightedit.setText('1')\n        part_height = 1\n        raise StandardError(wedgeHeightErrorText)\n\n#cheat factor\n    try:\n        cf = ui.cheatFactorEdit.text()\n        reportMsg(ui.cheatFactorLabel,cf)\n        if(cf == ''):\n            cheat_factor = eval_expr(CHEAT_FACTOR) #set safe default\n            ui.cheatFactorEdit.setText(str(cheat_factor))\n            return\n        cheat_factor = eval_expr(ui.cheatFactorEdit.text()) #eval_expr() allows for input such as 25.4 / 2**4\n        ui.cheatFactorEdit.setText(str(cheat_factor))\n    except:\n        ui.cheatFactorEdit.setText(str(eval_expr(CHEAT_FACTOR)))\n        cheat_factor = 1\n        raise StandardError(cheatFactorErrorText)\n\ndef stayOnTop(windowHasAlreadyBeenShown = True):\n    global window_stays_on_top\n    bStay = window_stays_on_top\n    if windowHasAlreadyBeenShown:\n        bStay = ui.staysOnTopCheckBox.isChecked()\n    flags = MainWindow.windowFlags()\n    if bStay:\n        MainWindow.setWindowFlags(flags.__or__(QtCore.Qt.WindowStaysOnTopHint).__or__(QtCore.Qt.CustomizeWindowHint))\n        window_stays_on_top = True\n        MainWindow.show()\n    else:\n        MainWindow.setWindowFlags(flags ^ (QtCore.Qt.WindowStaysOnTopHint.__or__(QtCore.Qt.CustomizeWindowHint)))\n        window_stays_on_top = False\n        MainWindow.show()\n\ndef defaults():\n    ui.staysOnTopCheckBox.setChecked(WINDOW_STAYS_ON_TOP)\n    ui.blackForegroundCheckbox.setChecked(BLACK_FOREGROUND)\n    ui.scaleEdit.setText(str(SCALE_FACTOR))\n    ui.recomputeIntervalEdit.setText(str(RECOMPUTE_INTERVAL))\n    ui.cheatFactorEdit.setText(str(eval_expr(str(CHEAT_FACTOR))))\n    ui.shapeHeightEdit.setText(str(PART_HEIGHT))\n    ui.zOffsetEdit.setText(str(IMPORT_Z_OFFSET))\n    ui.yOffsetEdit.setText(str(IMPORT_Y_OFFSET))\n    ui.xOffsetEdit.setText(str(IMPORT_X_OFFSET))\n    ui.baseNameEdit.setText(SHAPE_BASENAME)\n    processEvents()\n\n\n\n\nMainWindow = QtGui.QMainWindow()\n\nui = Ui_MainWindow()\nui.setupUi(MainWindow)\nMainWindow.setWindowTitle(VERSION_STRING)\n\n#override default QGraphicsView with our own reimplemented GraphicsView object (defined above) so we can handle wheel movements for zooming preview image\ngeometry = ui.graphicsView.geometry()\nui.graphicsView = GraphicsView(ui.centralwidget)\nui.graphicsView.setGeometry(geometry)\nui.graphicsView.setDragMode(QtGui.QGraphicsView.ScrollHandDrag)\nui.graphicsView.setObjectName(\"graphicsView\")\nui.graphicsView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)\nui.graphicsView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)\n\n#connect clicked events / setup defaults / apply tooltips\nui.staysOnTopCheckBox.setChecked(window_stays_on_top)\nui.staysOnTopCheckBox.clicked.connect(stayOnTop)\nui.staysOnTopCheckBox.setText(staysOnTopText)\nui.selectFacesButton.clicked.connect(selectObjects)\nsetToolTip(ui.selectFacesButton, sfTip)\n\nui.importAsPointButton.clicked.connect(doPoint)\nui.importAsWireButton.clicked.connect(doWire)\n\nsetToolTip(ui.importAsPointButton,importAsPointButtonTip)\nsetToolTip(ui.importAsWireButton,importAsWireButtonTip)\nui.importAsWireButton.setText(importAsWireButtonText)\nui.importAsPointButton.setText(importAsPointButtonText)\n\nsetToolTip(ui.previewButton, previewButtonTip)\nui.previewButton.clicked.connect(preview)\nui.previewButton.setText(previewButtonText)\n\nui.importAsSolidButton.clicked.connect(doSolid)\nsetToolTip(ui.importAsSolidButton,iasbTip)\n\nui.importAsSketchButton.clicked.connect(doSketch)\nsetToolTip(ui.importAsSketchButton, importAsSketchButtonTip)\nui.exitButton.clicked.connect(on_exit)\n\nui.abortButton.clicked.connect(progressAbort)\nui.moveButton.setText(moveButtonText)\n\nsetToolTip(ui.moveButton, moveButtonTipText)\nui.blackForegroundCheckbox.setChecked(black_foreground)\n\nsetToolTip(ui.blackForegroundCheckbox,afcbTip)\n\nui.scaleEdit.setText(str(scale_factor))\nsetToolTip(ui.scaleEdit,seTip)\nui.scaleEdit.editingFinished.connect(previewMaybe)\n\nui.recomputeIntervalEdit.setText(str(recompute_interval))\nsetToolTip(ui.recomputeIntervalEdit, riTip)\nui.recomputeIntervalEdit.editingFinished.connect(previewMaybe)\n\nui.xOffsetEdit.setText(str(import_x_offset))\nui.xOffsetEdit.editingFinished.connect(previewMaybe)\n\nsetToolTip(ui.xOffsetEdit, xoeTip)\n\nui.yOffsetEdit.setText(str(import_y_offset))\nsetToolTip(ui.yOffsetEdit, yoeTip)\nui.yOffsetEdit.editingFinished.connect(previewMaybe)\n\nui.zOffsetEdit.setText(str(import_z_offset))\nsetToolTip(ui.zOffsetEdit, zoeTip)\nui.zOffsetEdit.editingFinished.connect(previewMaybe)\n\nui.baseNameEdit.setText(shape_basename)\nsetToolTip(ui.baseNameEdit,bneTip)\n\nui.shapeHeightEdit.setText(str(part_height))\nsetToolTip(ui.shapeHeightEdit,cheTip)\nui.shapeHeightEdit.editingFinished.connect(previewMaybe)\nui.cheatFactorLabel.setText(cheatFactorLabelText)\nsetToolTip(ui.cheatFactorEdit,cfeTip)\nui.cheatFactorEdit.setText(str(cheat_factor))\nui.cheatFactorEdit.editingFinished.connect(previewMaybe)\nsetToolTip(ui.offsetsGroupBoxLabel,offsetsGroupBoxTipText)\n\nui.cutSelectedButton.clicked.connect(cutSelected)\nui.selectOddPointsButton.clicked.connect(selectOddPoints)\nui.selectOddPointsButton.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)\nui.selectOddPointsButton.customContextMenuRequested.connect(select_context_menu)\n\nui.moveButton.clicked.connect(moveSelected)\nui.insertButton.clicked.connect(insertPoint)\nui.defaultsButton.clicked.connect(defaults)\nsetToolTip(ui.defaultsButton, defaultsButtonTipText)\nui.defaultsButton.setText(defaultsButtonText)\n\n#end of clicked connections\n\n#apply labels or translations, if any\nui.importAsSolidButton.setText(importAsSolidButtonText)\nui.importAsSketchButton.setText(importAsSketchButtonText)\nui.selectFacesButton.setText(selectFacesButtonText)\nui.exitButton.setText(exitButtonText)\nui.progressLabel.setText(progressLabelText)\nui.abortButton.setText(abortButtonText)\nui.abortButton.setEnabled(False)\nui.blackForegroundCheckbox.setText(blackForegroundCheckboxText)\n\nui.imagePreviewLabel.setText(imagePreviewLabelText)\nui.offsetsGroupBox.setTitle(u'')\nui.scaleLabel.setText(scaleLabelText)\nui.recomputeIntervalLabel.setText(recomputeIntervalLabelText)\nui.xOffsetLabel.setText(xOffsetLabelText)\n\nui.zeroButton.setText(zeroText)\nui.zeroButton.clicked.connect(zeroOffsets)\n\nsetToolTip(ui.zeroButton,zeroButtonTipText)\nui.yOffsetLabel.setText(yOffsetLabelText)\nui.zOffsetLabel.setText(zOffsetLabelText)\nui.baseNameLabel.setText(baseNameLabelText)\nui.shapeHeightLabel.setText(shapeHeightLabelText)\nui.insertButton.setText(insertButtonText)\nsetToolTip(ui.insertButton, insertButtonTipText)\nui.wireEditGroupBox.setTitle(wirePointEditingText)\n\nsetToolTip(ui.cutSelectedButton,deleteButtonTipText)\nsetToolTip(ui.selectOddPointsButton,selectOddPointsButtonTipText)\nui.selectOddPointsButton.setText(selectOddPointsButtonText)\nui.cutSelectedButton.setText(deleteButtonText)\nui.offsetsGroupBoxLabel.setText(offsetsGroupBoxText)\n\nscene = QtGui.QGraphicsScene()\nui.graphicsView.setScene(scene)\npixmap = QtGui.QPixmap(xpm_file)\n\n#scalePreview(pixmap, ui.graphicsView, 1) #current icon looks better unscaled\nscene.addPixmap(pixmap)\n\nstayOnTop(False) #False means window hasn't yet been shown\nstayOnTop() #show it first in previous call, and then call again to set the configuration\n\n\n#MainWindow.show()\n\n\n",
    "url": "https://wiki.freecad.org/Macro_FCBmpImport",
    "raw_code_url": "https://gist.githubusercontent.com/mwganson/ea7aa4dcb79d7492caa24e8970967174/raw/1fe247b5b93e5084866a69754854d9caedca1f09/FCBmpImport.FCMacro",
    "wiki": "https://github.com/mwganson/fcbmpimport/blob/master/README.md",
    "version": "2021.09.23",
    "license": "",
    "date": "2021.09.23",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\120px-FCBmpImportScreenshot.png",
    "icon_source": "https://wiki.freecad.org//images/thumb/0/0b/FCBmpImportScreenshot.png/120px-FCBmpImportScreenshot.png?20210923163201",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FCWire To Volume",
    "on_wiki": true,
    "on_git": false,
    "desc": "Create the boolean operation with the selected wires. Push the 2d button for create the boolean operation to 2D wire.<br /><br />Macro version: 0.02c<br />Last modified: 2020/04/11<br />FreeCAD version: 0.19<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/f/f2/Macro_FCWire_To_Volume.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Create the boolean operation with the selected wires. Push the 2d button for create the boolean operation to 2D wire.",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n#\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2016 2017 2018 2019 2020 <mario52>                      *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#Macro_FCWire_To_Volume 10/10/2016_01, 2020/04/08_02, 2020/04/10_2b, 2020/04/11_2c\n#\n#OS: Windows 10 (10.0)\n#Word size of OS: 64-bit\n#Word size of FreeCAD: 64-bit\n#Version: 0.19.20311 (Git)\n#Build type: Release\n#Branch: master\n#Hash: 915e551bbb7e3614bc804f1ae1f65027b5432b9f\n#Python version: 3.6.8\n#Qt version: 5.12.1\n#Coin version: 4.0.0a\n#OCC version: 7.3.0\n#\n__title__   = \"Macro_FCWire_To_Volume\"\n__author__  = \"Mario52\"\n__url__     = \"https://wiki.freecadweb.org/Macro_FCWire_To_Volume\"\n__version__ = \"00.02c\"\n__date__    = \"2020/04/11\"    #YYYY/MM/DD\n\nif int(FreeCAD.Version()[1]) < 18:      # Version de FreeCAD\n    FreeCAD.Console.PrintMessage(\"This version \" + __title__ + \" rmu  work with the FreeCAD 0.18 or higher. \" + \"\\n\\n\")\n\nimport PySide2\nfrom PySide2 import (QtWidgets, QtCore, QtGui)\nfrom PySide2.QtWidgets import (QWidget, QApplication, QSlider, QGraphicsView, QGraphicsScene, QVBoxLayout, QStyle)\nfrom PySide2.QtGui import (QPainter, QColor, QIcon)\n#from PySide2.QtSvg import *\n#import PySide2.QtXml\nimport WebGui\n\nimport Draft, Part, PartGui, FreeCADGui, FreeCAD\nfrom FreeCAD import Base\nimport math\nfrom math import sqrt, pi, sin, cos, asin\n\nGui = FreeCADGui\nApp = FreeCAD\n\nglobal create2D ; create2D = 0\nglobal ui       ; ui       = \"\"\nglobal doc\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\nclass Ui_MainWindow(object):\n\n    def __init__(self ):\n        self.window = MainWindow\n        #self.path   = FreeCAD.ConfigGet(\"AppHomePath\")\n        self.path   = FreeCAD.ConfigGet(\"UserAppData\")\n        self.path   = self.path.replace(\"\\\\\",\"/\")\n\n        self.thicknessValue  = 0.0\n        self.thicknessX      = 0.0     # extrusion\n        self.thicknessY      = 0.0     # extrusion\n        self.thicknessZ      = 0.0     # extrusion\n        self.thicknessD      = 0.0     # extrusion\n\n    def setupUi(self, MainWindow):\n        self.window = MainWindow\n        MainWindow.setObjectName(_fromUtf8(\"__title__\"))\n        MainWindow.resize(300, 300)\n#        MainWindow.setMinimumSize(QtCore.QSize(300, 200))\n#        MainWindow.setMaximumSize(QtCore.QSize(300, 200))\n        self.centralwidget = QtWidgets.QWidget(MainWindow)\n\n        self.groupBox0 = QtWidgets.QGroupBox()\n        self.groupBox_01 = QtWidgets.QGroupBox()\n\n        self.doubleSpinBox = QtWidgets.QDoubleSpinBox()\n        self.doubleSpinBox.setMinimum(0)\n        self.doubleSpinBox.setMaximum(999999.999999)\n        self.doubleSpinBox.setDecimals(3)\n        self.doubleSpinBox.setValue(0.0)\n        self.doubleSpinBox.setAlignment(PySide2.QtCore.Qt.AlignCenter)\n        self.doubleSpinBox.setSuffix(\" mm\")\n        self.doubleSpinBox.valueChanged.connect(self.on_doubleSpinBox) ###\n        ####\n        self.groupBox_02 = QtWidgets.QGroupBox()\n\n        self.GroupBox_Bool = QtWidgets.QGroupBox()\n        self.RB_Intersection = QtWidgets.QRadioButton()\n        self.RB_Intersection.setIcon(QtGui.QIcon.fromTheme(\"bool\",QtGui.QIcon(\":/icons/Part_Common.svg\")))\n        self.RB_Intersection.setChecked(True)\n        self.RB_Cut = QtWidgets.QRadioButton()\n        self.RB_Cut.setIcon(QtGui.QIcon.fromTheme(\"bool\",QtGui.QIcon(\":/icons/Part_Cut.svg\")))\n        self.RB_Union = QtWidgets.QRadioButton()\n        self.RB_Union.setIcon(QtGui.QIcon.fromTheme(\"bool\",QtGui.QIcon(\":/icons/Part_Fuse.svg\")))\n        self.RB_Xor = QtWidgets.QRadioButton()\n        self.RB_Xor.setIcon(QtGui.QIcon.fromTheme(\"bool\",QtGui.QIcon(\":/icons/Part_XOR.svg\")))\n        ####\n        self.groupBox_Axis = QtWidgets.QGroupBox()\n        self.RB_Axis_X = QtWidgets.QRadioButton()\n        self.RB_Axis_X.setIcon(QtGui.QIcon.fromTheme(\"axis\",QtGui.QIcon(\":/icons/Std_CoordinateSystem.svg\")))\n        self.RB_Axis_Y = QtWidgets.QRadioButton()\n        self.RB_Axis_Y.setIcon(QtGui.QIcon.fromTheme(\"axis\",QtGui.QIcon(\":/icons/Std_CoordinateSystem.svg\")))\n        self.RB_Axis_Z = QtWidgets.QRadioButton()\n        self.RB_Axis_Z.setChecked(True)\n        self.RB_Axis_Z.setIcon(QtGui.QIcon.fromTheme(\"axis\",QtGui.QIcon(\":/icons/Std_CoordinateSystem.svg\")))\n        self.RB_Axis_D = QtWidgets.QRadioButton()\n        self.RB_Axis_D.setEnabled(False)\n        self.RB_Axis_D.setIcon(QtGui.QIcon.fromTheme(\"axis\",QtGui.QIcon(\":/icons/Part_Line_Parametric.svg\")))#Std_CoordinateSystem\n        ####\n        self.groupBox_03 = QtWidgets.QGroupBox()\n        self.checkBox_01 = QtWidgets.QCheckBox()\n        self.checkBox_01.setChecked(True)             #  # False\n        self.checkBox_01.setIcon(QtGui.QIcon.fromTheme(\"part\",QtGui.QIcon(\":/icons/Tree_Part.svg\")))\n        self.checkBox_01.clicked.connect(self.on_checkBox_01) ###\n\n        self.CB_Create_2D_Visible = QtWidgets.QCheckBox()\n        self.CB_Create_2D_Visible.setChecked(True)    #    # False\n        self.CB_Create_2D_Visible.clicked.connect(self.on_CB_Create_2D_Visible) ###\n#        self.CB_Create_2D_Visible.setIcon(QtGui.QIcon.fromTheme(\"draft\",QtGui.QIcon(\":/icons/dagViewVisible.svg\")))#\n\n        self.CB_Colorer = QtWidgets.QCheckBox()\n        self.CB_Colorer.setChecked(False)             # True   # \n        self.CB_Colorer.setIcon(QtGui.QIcon.fromTheme(\"part\",QtGui.QIcon(\":/icons/colors.svg\")))\n        ####\n        self.groupBox_04 = QtWidgets.QGroupBox()\n        self.PB_Create_2D = QtWidgets.QPushButton()\n        self.PB_Create_2D.clicked.connect(self.on_PB_Create_2D) ###\n        self.PB_Create_2D.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogOkButton))) #\n        self.PB_Create = QtWidgets.QPushButton()\n        self.PB_Create.clicked.connect(self.on_PB_Create) ###\n        self.PB_Create.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogOkButton))) #\n        self.PB_Help = QtWidgets.QPushButton()\n        self.PB_Help.clicked.connect(self.on_PB_Help) ###\n        self.PB_Help.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_MessageBoxQuestion))) #\n        self.PB_Quit = QtWidgets.QPushButton()\n        self.PB_Quit.clicked.connect(self.on_PB_Quit) ###\n        self.PB_Quit.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogCloseButton))) #\n\n        ####gridLayout####\n        self.gridLayout0 = QtWidgets.QGridLayout(self.centralwidget)\n        self.gridLayout0.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout0.addWidget(self.groupBox0, 0, 0, 1, 1)\n        ####\n        self.gridLayout = QtWidgets.QGridLayout(self.groupBox0)\n        self.gridLayout.setContentsMargins(10, 10, 10, 10)\n        ####\n        self.gridLayout_02 = QtWidgets.QGridLayout(self.groupBox_01)\n        self.gridLayout_02.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_02.addWidget(self.doubleSpinBox, 0, 0, 1, 1)\n        self.gridLayout.addWidget(self.groupBox_01, 0, 0, 1, 2)\n        ####\n        self.gridLayout_03 = QtWidgets.QGridLayout(self.groupBox_02)\n        self.gridLayout_03.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_03.addWidget(self.groupBox_02, 0, 0, 1, 1)\n        ####\n        self.gridLayout_04 = QtWidgets.QGridLayout(self.GroupBox_Bool)\n        self.gridLayout_04.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_04.addWidget(self.RB_Intersection, 0, 0, 1, 1)\n        self.gridLayout_04.addWidget(self.RB_Cut, 1, 0, 1, 1)\n        self.gridLayout_04.addWidget(self.RB_Union, 2, 0, 1, 1)\n        self.gridLayout_04.addWidget(self.RB_Xor, 3, 0, 1, 1)\n        self.gridLayout_03.addWidget(self.GroupBox_Bool, 0, 0, 1, 1)\n        ####\n        self.gridLayout_05 = QtWidgets.QGridLayout(self.groupBox_Axis)\n        self.gridLayout_05.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_05.addWidget(self.RB_Axis_X, 0, 0, 1, 1)\n        self.gridLayout_05.addWidget(self.RB_Axis_Y, 1, 0, 1, 1)\n        self.gridLayout_05.addWidget(self.RB_Axis_Z, 2, 0, 1, 1)\n        self.gridLayout_05.addWidget(self.RB_Axis_D, 3, 0, 1, 1)\n        self.gridLayout_03.addWidget(self.groupBox_Axis, 0, 1, 1, 1)\n        self.gridLayout.addWidget(self.groupBox_02, 1, 0, 1, 2)\n        ####\n        self.gridLayout_06 = QtWidgets.QGridLayout(self.groupBox_03)\n        self.gridLayout_06.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_06.addWidget(self.checkBox_01, 0, 0, 1, 1)\n        self.gridLayout_06.addWidget(self.CB_Create_2D_Visible, 0, 1, 1, 1)\n        self.gridLayout_06.addWidget(self.CB_Colorer, 0, 2, 1, 1)\n        self.gridLayout.addWidget(self.groupBox_03, 2, 0, 1, 2)\n        ####\n        self.gridLayout_07 = QtWidgets.QGridLayout(self.groupBox_04)\n        self.gridLayout_07.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_07.addWidget(self.PB_Create_2D, 0, 0, 1, 1)\n        self.gridLayout_07.addWidget(self.PB_Create, 0, 1, 1, 1)\n        self.gridLayout_07.addWidget(self.PB_Help, 1, 0, 1, 1)\n        self.gridLayout_07.addWidget(self.PB_Quit, 1, 1, 1, 1)\n        self.gridLayout.addWidget(self.groupBox_04, 3, 0, 1, 2)\n        ####gridLayout####\n\n        MainWindow.setCentralWidget(self.centralwidget)\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n        _translate = QtCore.QCoreApplication.translate\n        MainWindow.setWindowTitle(\"FCWire To Volume\")\n        MainWindow.setWindowFlags(PySide2.QtCore.Qt.WindowStaysOnTopHint)        # PySide2 cette fonction met la fenetre en avant\n\n        self.groupBox0.setTitle(_translate(\"MainWindow\", \"Ver : \" + __version__ + \" : \" + __date__) + \" rmu\") #__title__ + \" \" +\n        self.groupBox_01.setTitle(_translate(\"MainWindow\", \"Thickness Solide\"))\n        self.groupBox_02.setTitle(_translate(\"MainWindow\", \"Choice\"))\n\n        self.GroupBox_Bool.setTitle(_translate(\"MainWindow\", \"Boolean\"))\n        self.RB_Intersection.setText(_translate(\"MainWindow\", \"Intersection\"))\n        self.RB_Cut.setText(_translate(\"MainWindow\", \"Substraction\"))\n        self.RB_Union.setText(_translate(\"MainWindow\", \"Union\"))\n        self.RB_Xor.setText(_translate(\"MainWindow\", \"Xor\"))\n\n        self.groupBox_Axis.setTitle(_translate(\"MainWindow\", \"Axis\"))\n        self.RB_Axis_X.setText(_translate(\"MainWindow\", \"X Axis\"))\n        self.RB_Axis_X.setToolTip(_translate(\"MainWindow\", \"Plane YZ extrude direction X\"))\n        self.RB_Axis_Y.setText(_translate(\"MainWindow\", \"Y Axis\"))\n        self.RB_Axis_Y.setToolTip(_translate(\"MainWindow\", \"Plane XZ extrude direction Y\"))\n        self.RB_Axis_Z.setText(_translate(\"MainWindow\", \"Z Axis\"))\n        self.RB_Axis_Z.setToolTip(_translate(\"MainWindow\", \"Plane XY extrude direction Z\"))\n        self.RB_Axis_D.setText(_translate(\"MainWindow\", \"Direction\"))\n        self.RB_Axis_D.setToolTip(_translate(\"MainWindow\", \"Extrude direction (for later)\"))\n\n        self.groupBox_03.setTitle(_translate(\"MainWindow\", \"Option\"))\n        self.checkBox_01.setText(_translate(\"MainWindow\", \"Single object\"))\n        self.checkBox_01.setToolTip(_translate(\"MainWindow\", \"Check this checkBox\"+\"\\n\"+\n                                               \"for create single object\"))\n        self.CB_Create_2D_Visible.setText(_translate(\"MainWindow\", \"Hidden\"))\n        self.CB_Create_2D_Visible.setToolTip(_translate(\"MainWindow\", \"The object used are Hidden\"))\n        self.CB_Colorer.setText(_translate(\"MainWindow\", \"Color\"))\n        self.CB_Colorer.setToolTip(_translate(\"MainWindow\", \"If is checked the result is colored in red\"))\n        self.groupBox_04.setTitle(_translate(\"MainWindow\", \"Command\"))\n        self.PB_Create_2D.setText(_translate(\"MainWindow\", \"Create 2D\"))\n        self.PB_Create_2D.setToolTip(_translate(\"MainWindow\", \"This button Create 2D object (Draft.makeShape2DView)\" + \"\\n\" +\n                                                \"The projection is make in the Z axis\" + \"\\n\" +\n                                                \"The selection order is decisive for the desired result (Substraction)\"))\n        self.PB_Create.setText(_translate(\"MainWindow\", \"Create 3D\"))\n        self.PB_Create.setToolTip(_translate(\"MainWindow\", \"Create the object 3D\" + \"\\n\" +\n                                             \"The selection order is decisive for the desired result (Substraction)\"))\n        self.PB_Help.setText(_translate(\"MainWindow\", \"Help\"))\n        self.PB_Help.setToolTip(_translate(\"MainWindow\", \"Display the wiki page in the FreeCAD browser\"))\n        self.PB_Quit.setText(_translate(\"MainWindow\", \"Quit\"))\n        self.PB_Quit.setToolTip(_translate(\"MainWindow\", \"Quit Wire to volume, Salut\"))\n\n\n    def on_doubleSpinBox(self,value):\n        self.thicknessValue = value\n        self.doubleSpinBox.setStyleSheet(\"Base\")\n        self.PB_Create_2D.setStyleSheet(\"Base\")\n        self.PB_Create.setStyleSheet(\"Base\")\n\n    def on_checkBox_01(self):\n        if self.checkBox_01.isChecked():\n            self.checkBox_01.setIcon(QtGui.QIcon.fromTheme(\"part\",QtGui.QIcon(\":/icons/Tree_Part.svg\")))\n            self.checkBox_01.setText(u\"Single object\")\n        else:\n            self.checkBox_01.setIcon(QtGui.QIcon.fromTheme(\"part\",QtGui.QIcon(\":/icons/sel-instance.svg\")))\n            self.checkBox_01.setText(u\"Objects\")\n\n    def on_CB_Create_2D_Visible(self):\n        if self.CB_Create_2D_Visible.isChecked():\n#            self.CB_Create_2D_Visible.setIcon(QtGui.QIcon.fromTheme(\"draft\",QtGui.QIcon(\":/icons/dagViewVisible.svg\")))#\n            self.CB_Create_2D_Visible.setIcon(QtGui.QIcon.fromTheme(\"part\",QtGui.QIcon(\"\")))\n            self.CB_Create_2D_Visible.setText(u\"Hidden\")\n        else:\n            self.CB_Create_2D_Visible.setIcon(QtGui.QIcon.fromTheme(\"part\",QtGui.QIcon(\":/icons/dagViewVisible.svg\")))\n            self.CB_Create_2D_Visible.setText(u\"Visible\")\n\n    def on_PB_Create_2D(self):\n        global create2D\n        global ui\n\n        sel = FreeCADGui.Selection.getSelection()\n        self.PB_Create_2D.setStyleSheet(\"Base\")\n        self.PB_Create.setStyleSheet(\"Base\")\n        if len(sel) < 2:\n            create2D = 0\n            self.PB_Create_2D.setStyleSheet(\"background-color: white;\\n\"\n                                            \"border:2px solid rgb(239, 41, 41);\")  # bord white and red\n        else:\n            create2D = 1\n            self.thicknessValue = 1.0\n            self.doubleSpinBox.setValue(self.thicknessValue)\n            self.RB_Axis_Z.setChecked(True)\n            ui.on_PB_Create()\n        \n    def on_PB_Create(self):\n        global create2D\n        global doc\n\n        selectionObjects = FreeCADGui.Selection.getSelection()\n        self.doubleSpinBox.setStyleSheet(\"Base\")\n        self.PB_Create_2D.setStyleSheet(\"Base\")\n        self.PB_Create.setStyleSheet(\"Base\")\n        noface = 0\n        ####\n        if create2D > 0:\n            lab00 = selectionObjects[0].Label\n            lab01 = selectionObjects[1].Label\n            boolChoice = \"\"\n            if self.RB_Intersection.isChecked():\n                boolChoice = \"Comm\"\n            elif self.RB_Cut.isChecked():\n                boolChoice = \"Subs\"\n            elif self.RB_Union.isChecked():\n                boolChoice = \"Unio\"\n            elif self.RB_Xor.isChecked():\n                boolChoice = \"Diff\"\n\n            if self.checkBox_01.isChecked():\n                None\n            else:\n                FCSpring = FreeCAD.ActiveDocument.addObject(\"App::DocumentObjectGroup\",\"Wire2D_\" + lab00 + \"_\" + boolChoice + \"_\" +lab01)\n        ####\n        try:\n            selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0] # select one element SubObjects\n            if str(selectedEdge)[1:5] == \"Face\":\n                noface = 1\n        except Exception:\n            None\n\n        selectionDuplicate  = []\n        del selectionDuplicate[:]\n        p  = []\n        del p[:]\n        \n        try:\n            ###########\n            self.thicknessX = 0.0\n            self.thicknessY = 0.0\n            self.thicknessZ = 0.0\n        #        self.thicknessD = 0.0\n        \n            if self.RB_Axis_X.isChecked():\n                self.thicknessX = self.thicknessValue\n            if self.RB_Axis_Y.isChecked():\n                self.thicknessY = self.thicknessValue\n            if self.RB_Axis_Z.isChecked():\n                self.thicknessZ = self.thicknessValue\n        #        if self.RB_Axis_D.isChecked():\n        #            self.thicknessD = self.thicknessValue\n            ###########\n        \n            if (len(selectionObjects) >= 2) and (noface == 0) and (self.thicknessX + self.thicknessY + self.thicknessZ != 0.0):\n                for i in selectionObjects:            # duplicate object\n                    Part.show(i.Shape.copy())\n                    sD = doc.ActiveObject\n                    sD.Label = i.Name\n                    selectionDuplicate.append(sD)\n            \n                for i in (selectionDuplicate):        # extrude object\n                    a = Draft.extrude(i,Base.Vector(self.thicknessX,self.thicknessY,self.thicknessZ))    # axis extrude X Y Z\n                    a.Solid = True\n                    p.append(a)\n            \n                if self.RB_Intersection.isChecked():\n                    name = \"Common_\" + selectionDuplicate[0].Label         ## create Common_\n                    tx = doc.addObject(\"Part::MultiCommon\",name)\n                    tx.Shapes = p\n                    doc.recompute()\n                    if self.checkBox_01.isChecked():\n                        Part.show(tx.Shape)\n                        singleO = App.ActiveDocument.ActiveObject\n                        singleO.Label = name\n                        doc.removeObject(tx.Name)\n                        for i in range(len(selectionDuplicate)):\n                            doc.removeObject(selectionDuplicate[i].Name)\n                            doc.removeObject(p[i].Name)\n                    if self.CB_Colorer.isChecked():\n                        FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (1.0,0.0,0.0)\n                    App.Console.PrintMessage(\"RB_Intersection \")\n        \n                elif self.RB_Cut.isChecked():\n                    name = str(\"Cut_\" + selectionDuplicate[0].Label)       ## create Cut_\n                    tx = doc.addObject(\"Part::Cut\",name)\n                    tx.Base = p[0]\n                    tx.Tool = p[1]\n                    doc.recompute()\n                    if self.checkBox_01.isChecked():\n                        Part.show(tx.Shape)\n                        singleO = App.ActiveDocument.ActiveObject\n                        singleO.Label = name\n                        doc.removeObject(tx.Name)\n                        for i in range(len(selectionDuplicate)):\n                            doc.removeObject(selectionDuplicate[i].Name)\n                            doc.removeObject(p[i].Name)\n                    if self.CB_Colorer.isChecked():\n                        FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (1.0,0.0,0.0)\n                    App.Console.PrintMessage(\"RB_Cut \")\n            \n                elif self.RB_Union.isChecked():\n                    name = str(\"Fusion_\" + selectionDuplicate[0].Label)    ## create Fusion_\n                    tx = doc.addObject(\"Part::MultiFuse\",name)\n                    tx.Shapes = p\n                    doc.recompute()\n                    if self.checkBox_01.isChecked():\n                        Part.show(tx.Shape)\n                        singleO = App.ActiveDocument.ActiveObject\n                        singleO.Label = name\n                        doc.removeObject(tx.Name)\n                        for i in range(len(selectionDuplicate)):\n                            doc.removeObject(selectionDuplicate[i].Name)\n                            doc.removeObject(p[i].Name)\n                    if self.CB_Colorer.isChecked():\n                        FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (1.0,0.0,0.0)\n                    App.Console.PrintMessage(\"RB_Union\")\n            \n                elif self.RB_Xor.isChecked():\n                    name = \"CommonD_\" + selectionDuplicate[0].Label        ##\n                    commun = doc.addObject(\"Part::MultiCommon\",name)\n                    commun.Shapes = p\n                    name = str(\"FusionD_\" + selectionDuplicate[0].Label)   ##\n                    fusion = doc.addObject(\"Part::MultiFuse\",name)\n                    fusion.Shapes = p\n                    name = str(\"Difference_\" + selectionDuplicate[0].Label)## create Difference_\n                    difference = doc.addObject(\"Part::Cut\",name)\n                    difference.Base = fusion\n                    difference.Tool = commun\n                    doc.recompute()\n                    if self.checkBox_01.isChecked():\n                        Part.show(difference.Shape)\n                        singleO = App.ActiveDocument.ActiveObject\n                        singleO.Label = name\n                        doc.removeObject(commun.Name)\n                        doc.removeObject(fusion.Name)\n                        doc.removeObject(difference.Name)\n                        for i in range(len(selectionDuplicate)):\n                            doc.removeObject(selectionDuplicate[i].Name)\n                            doc.removeObject(p[i].Name)\n                    if self.CB_Colorer.isChecked():\n                        FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (1.0,0.0,0.0)\n                    App.Console.PrintMessage(\"RB_Xor \")\n            \n                doc.recompute()\n                App.Console.PrintMessage(str(self.thicknessX)+\" \"+str(self.thicknessY)+\" \"+str(self.thicknessZ) + \"\\n\")\n            else:\n                if (self.thicknessX + self.thicknessY + self.thicknessZ == 0.0):\n                    App.Console.PrintError(\"Thickness = 0\" + \"\\n\")\n                    self.doubleSpinBox.setStyleSheet(\"background-color: white;\\n\"\n                                                     \"border:2px solid rgb(239, 41, 41);\")  # bord white and red\n                else:\n                    App.Console.PrintError(\"Not for Face\" + \"\\n\")\n        \n            #### section 2D\n            if create2D > 0:\n                objSolid = App.ActiveDocument.getObject(FreeCAD.ActiveDocument.ActiveObject.Name)\n                objSolid.Label = \"objSolid\"\n        \n                object2D = Draft.makeShape2DView(objSolid)\n                object2D.Label = \"object2D\"\n                FreeCAD.ActiveDocument.recompute()\n        \n                Gui.Selection.clearSelection()\n                Gui.Selection.addSelection(object2D)\n        \n                if self.CB_Create_2D_Visible.isChecked():\n                    FreeCADGui.ActiveDocument.getObject(objSolid.Name).Visibility = False\n                else:\n                    FreeCADGui.ActiveDocument.getObject(objSolid.Name).ShapeColor = (1.0,0.0,0.0)\n                    FreeCADGui.ActiveDocument.getObject(objSolid.Name).Transparency = 80\n        \n                if self.CB_Colorer.isChecked():\n                    FreeCADGui.ActiveDocument.getObject(object2D.Name).LineColor = (1.0,0.0,0.0)\n        \n                ##### bon ordre pour effacer\n                if self.checkBox_01.isChecked():\n                    Part.show(object2D.Shape.copy())\n                    if self.CB_Colorer.isChecked():\n                        FreeCADGui.ActiveDocument.ActiveObject.LineColor = (1.0,0.0,0.0)\n                    App.ActiveDocument.ActiveObject.Label = (\"Wire2D_\" + lab00 + \"_\" + boolChoice + \"_\" +lab01)\n                    doc.removeObject(object2D.Name)\n                    doc.removeObject(objSolid.Name)\n                else:\n                    FCSpring.addObject(objSolid)\n                    FCSpring.addObject(object2D)\n        \n            if self.CB_Create_2D_Visible.isChecked():\n                FreeCADGui.ActiveDocument.getObject(selectionObjects[0].Name).Visibility = False\n                FreeCADGui.ActiveDocument.getObject(selectionObjects[1].Name).Visibility = False\n            #### section 2D\n        \n            create2D = 0\n            FreeCAD.ActiveDocument.recompute()\n        except Exception:\n            print( \"Wrong selection or operation\")\n            self.PB_Create.setStyleSheet(\"background-color: white;\\n\"\n                                         \"border:2px solid rgb(239, 41, 41);\")  # bord white and red\n\n    def on_PB_Help(self): # \n        WebGui.openBrowser(\"https://wiki.freecadweb.org/Macro_FCWire_To_Volume\")\n        App.Console.PrintMessage(\"https://wiki.freecadweb.org/Macro_FCWire_To_Volume\" + \"\\n\")\n\n    def on_PB_Quit(self):                        # Quit\n        App.Console.PrintMessage(str(\"Fin FCWire To Volume \")+\"\\n\")\n        self.window.hide()\n\n    ####\n\ndoc = FreeCAD.ActiveDocument\nif doc == None:\n    doc = FreeCAD.newDocument()\n\nMainWindow = QtWidgets.QMainWindow()\nui = Ui_MainWindow()\nui.setupUi(MainWindow)\nMainWindow.show()",
    "url": "https://wiki.freecad.org/Macro_FCWire_To_Volume",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.02c",
    "license": "",
    "date": "2020/04/11",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_FCWire_To_Volume.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/f/f2/Macro_FCWire_To_Volume.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Iges PyImporter",
    "on_wiki": true,
    "on_git": false,
    "desc": "Imports an IGES file with entity 128 into FreeCAD.<br /><br />Macro version: 0.2<br />Last modified: 2022-03-26<br />FreeCAD version: any<br />Author: heda<br /> ",
    "comment": "Imports an iges file with entity 128 to FreeCAD",
    "code": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n# ***************************************************************************\n# *   Copyright (c) 2022 heda <heda @ freecad forum>                        *\n# *                                                                         *\n# *   This file is part of the FreeCAD CAx development system.              *\n# *                                                                         *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU Lesser General Public License (LGPL)    *\n# *   as published by the Free Software Foundation; either version 2 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENSE text file.                                 *\n# *                                                                         *\n# *   This program is distributed in the hope that it will be useful,       *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU Library General Public License for more details.                  *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with this program; if not, write to the Free Software   *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\n\n__Name__ = 'Iges_PyImporter'\n__Comment__ = 'Imports an iges file with entity 128 to FreeCAD'\n__Author__ = 'heda @ fc-forum'\n__Version__ = '0.2'\n__Date__ = '2022-03-26'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = ''\n__Wiki__ = 'https://wiki.freecad.org/Macro_Iges_PyImporter'\n__Icon__ = ''\n__Help__ = 'Launch macro and select file.'\n__Status__ = 'works'\n__Requires__ = 'tested on FreeCAD v0.19'\n__Communication__ = 'forum'\n__Files__ = ''\n\n\n\n__doc__ = \"\"\"\nStandalone import for ascii iges-files with bspline surfaces,\nentity 128, which appears to always be incorrectly handled by occ.\n\noptions:\n- make shell [default on] or individual surfaces\n  if off, the making of shell is enforced for files with more than 50 surfaces\n- apply color [default on] if color is present in the iges-file,\n  the parser naivly takes the first and ignores any following color records\n- progress bar [default on] see note.\n\nRun macro and select the iges file.\nCreation of the surfaces can take a while.\nImport is to current document if available, else a new is created.\n\nThere are no error or consistency checks, the parser either works or fails.\nThe only parsed entity is 128 - rational bspline surface,\nassumed to be freeform. Parsing ability could be expanded,\nspecification used is iges5.3.\n\nThe importer is tested on:\n- one freeship file\n- one libIGES file\n\nv0.1 - first version - handled iges files created by freeship.\nv0.2 - also handles files made with libIGES (on gh).\n\nnote: if the macro has an error, the use of the progress bar makes fc\n      freezes in monumental ways, the application has to be killed\n      with system commands. If so, switch off the progress bar.\n\"\"\"\n\n\nimport FreeCAD as App\nimport FreeCADGui as Gui\nimport Part\nfrom PySide import QtGui\n\nimport re\nfrom pathlib import Path\nfrom collections import namedtuple, Counter\n\n### options\nMakeShell = True\nShellLimit = 50\nApplyColor = True\nProgressBar = True\n\nfilename, filt = QtGui.QFileDialog.getOpenFileName(filter='*.igs')\n\nif not filename:\n    raise UserWarning('Need to select an iges file.')\n\nprint('Importing: {}'.format(filename))\n\nclass Ticker:\n    \"\"\"better than nothing, does not always show though\"\"\"\n    tick_count = 0\n    pbon = ProgressBar\n    if pbon:\n        pb = App.Base.ProgressIndicator() \n        pb.start('importing iges', 100)\n    \n    def tick(self, ticks=1):\n        if self.pbon:\n            for i in range(ticks):\n                self.pb.next()\n                self.tick_count += 1\n\n    def tick_time(self, prog):\n        if isinstance(self.tick_step, int):\n            self.tick(self.tick_step)\n        else:\n            if prog in self.tick_step:\n                self.tick()\n    \n    def set_tick_step(self, number):\n        self.tot_number = number\n        span = 100 - 3 * 4\n        if number >= span:\n            self.tick_step = tuple(range(0, number, int(number / span) + 1))\n        else:\n            self.tick_step = int(span / number)\n        \n    def end(self):\n        if self.pbon:\n            for i in range(101 - self.tick_count):\n                self.tick()\n            self.pb.stop()\n\n\nticker = Ticker()\n\n\niges = Path(filename)\ndata = iges.read_text().splitlines()\n\nsec_def = re.compile('\\W+')\nsections = dict(S='', G='', D=list(), P=dict())\nDES = namedtuple('DES', 'entity linecount label')\noddeven = color = None\n\nfor i, line in enumerate(data):\n    sec_col = line[72:]\n    section, snbr = sec_def.split(sec_col)\n    if section in 'SG':\n        sections[section] += line[:72]\n    elif section == 'D':\n        if oddeven is None:\n            oddeven = bool(i % 2)\n        if isinstance(oddeven, bool):\n            if bool(i % 2) == oddeven:\n                row1 = [line[j:j+8] for j in range(0, 80, 8)]\n                row2 = [data[i+1][j:j+8] for j in range(0, 80, 8)]\n                entitydef = (int(row1[0]), int(row2[3]), row2[-3])\n                sections['D'].append(DES(*entitydef))\n    elif section == 'P':\n        break\n\nlc = i\n\n### header\nfields = ' '.join(('f{}'.format(i+1) for i in range(25)))\nfor oldnew in (('f6 preprocessor', 'f14 unitsflag', 'f23 version')):\n    fields = fields.replace(*oldnew.split())\nHeader = namedtuple('Header', fields)\ncheat = sections.get('G').split(',')\ncheat[0] += ',' # assume that the parameter delimiter is a comma\nif len(cheat) == 26:\n    cheat.pop(1) # the freeship file\n\nheader = Header(*cheat)\n\n### unit\nUnits = dict(u1=(25.4, 'inch'),\n             u2=(1, 'mm'),\n             u3=(1, 'user defined, skip'),\n             u4=(25.4 * 12, 'feet'),\n             u5=(1, 'miles, skipping'),\n             u6=(1000, 'meters'),\n             u7=(10000, 'kilometers'),\n             u8=(25.4 / 1000, 'milli inch'),\n             u9=(1, 'micron, skipping'),\n             u10=(10, 'centimeters'),\n             u11=(1, 'micro inches, skipping'),\n             )\n\nunit, unitname = Units.get('u{}'.format(header.unitsflag))\nmsg = 'file units: {} / preprocessor: {}'\nprint(msg.format(unitname, header.preprocessor))\n\nticker.tick(3)\n\n### color\n# naive assumtion that color is first entry\nmsg = 'color definition found in file'\nif 314 in set((desi.entity for desi in sections['D'])):\n    des = sections['D'].pop(0)\n    code, *rgb, _ = data[lc].split(';')[0].split(',')\n    color = tuple(float(c) / 100 for c in (rgb)) + (0.,)\n    lc += des.linecount\n    print(msg)\nelse:\n    print('no ' + msg)\n\nticker.tick(3)\n\nentities, skipped = list(), list()\nfor des in sections['D']:\n    if des.entity == 128:\n        chunk = ''\n        for line in data[lc:lc+des.linecount]:\n            chunk += line[:64].strip()\n        entities.append(chunk.strip()[:-1])\n    else:\n        skipped.append(des.entity)\n    lc += des.linecount\n\nprint('found {} surfaces'.format(len(entities)))\nif skipped:\n    for entity, count in Counter(skipped).items():\n        print('skipped {} records of entity {}'.format(count, entity))\nelse:\n    print('no records skipped during parsing')\nprint('creating surfaces...')\n\nGui.updateGui() # flushes prints\nticker.tick(3)\nticker.set_tick_step(len(entities))\n\nMakeShell = MakeShell if len(entities) < ShellLimit + 1 else True\ndoc = App.ActiveDocument if App.ActiveDocument else App.newDocument(iges.stem)\n\nsurfs = list()\n\n### parse iges record and create fc surface\nfor j, entity in enumerate(entities):\n    entity = entity.split(',')\n    entity[:10] = [int(i) for i in entity[:10]]\n    entity[10:] = [float(i) for i in entity[10:]]\n    K1, K2, M1, M2, P1, P2, P3, P4, P5 = entity[1:10]\n    N1 = 1 + K1 - M1\n    N2 = 1 + K2 - M2\n    A = N1 + 2 * M1\n    B = N2 + 2 * M2\n    C = (1 + K1) * (1 + K2)\n    # matrix is K1 + 1 x K2 + 1; u,v\n    \n    uknots = entity[10:10+A+1]\n    vknots = entity[11+A:11+A+B+1]\n    weights = entity[12+A+B:11+A+B+C+1]\n    poles = entity[12+A+B+C:11+A+B+4*C+1]\n    \n    if P3 == 0: # rational\n        u0, u1, v0, v1 = entity[12+A+B+4*C:15+A+B+4*C+1]\n    else: # polynomial\n        pass\n    \n    umults = [uknots.count(kn) for kn in sorted(set(uknots))]\n    vmults = [vknots.count(kn) for kn in sorted(set(vknots))]\n    \n    if P3 == 0:\n        pass\n    else:\n        uknots = uknots[M1:-M1]\n        vknots = vknots[M2:-M2]\n    \n    poles = [App.Vector(*pt) * unit\n             for pt in zip(poles[0::3], poles[1::3],poles[2::3])]\n    \n    poles = [poles[i:i+K1+1] for i in range(0, len(poles), K1+1)]\n    weights = [weights[i:i+K1+1] for i in range(0, len(weights), K1+1)]\n    poles = list(zip(*poles))\n    weights = list(zip(*weights))\n    \n    bsurface = Part.BSplineSurface()\n    builder = bsurface.buildFromPolesMultsKnots\n    builder(poles, umults, vmults, uknots, vknots,\n            bool(P4), bool(P5), M1, M2, weights)\n    \n    if MakeShell:\n        surfs.append(bsurface.toShape())\n    else:\n       Part.show(bsurface.toShape(), 'Surface')\n       if color and ApplyColor:\n           doc.ActiveObject.ViewObject.ShapeColor = color\n\n    ticker.tick_time(j)\n    \n\nif MakeShell:\n    shell = Part.makeShell(surfs)\n    Part.show(shell, iges.stem)\n    if color and ApplyColor:\n        doc.ActiveObject.ViewObject.ShapeColor = color\n    doc.ActiveObject.ViewObject.DisplayMode = 'Shaded'\n\nticker.tick(3)\n\ndoc.recompute()\nav = Gui.ActiveDocument.ActiveView\nav.viewIsometric()\nav.fitAll()\nprint('... import iges completed')\nticker.end()\n\n# end",
    "url": "https://wiki.freecad.org/Macro_Iges_PyImporter",
    "raw_code_url": "",
    "wiki": "https://wiki.freecad.org/Macro_Iges_PyImporter",
    "version": "0.2",
    "license": "",
    "date": "2022-03-26",
    "src_filename": "",
    "filename_from_url": "",
    "author": "heda @ fc-forum",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "MeshToPart",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro converts selected meshes to parts. It has a broad tolerance, so use it only with objects that have no curves otherwise you'll get weird results<br /><br />Macro version: 1.0<br />Last modified: 2011-08-01<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/f/fa/Macro_MeshToPart.png\">ToolBar Icon</a><br />Author: Wmayer<br /> ",
    "comment": "This macro converts selected meshes to parts. It has a broad tolerance, so use it only with objects that have no curves otherwise you'll get weird results",
    "code": "import FreeCAD,FreeCADGui,Mesh,Part,MeshPart\n \nfor obj in FreeCADGui.Selection.getSelection():\n    if \"Mesh\" in obj.PropertiesList:\n        faces = []      \n        mesh = obj.Mesh\n        segments = mesh.getPlanarSegments(0.01) # use rather strict tolerance here\n \n        for i in segments:\n          if len(i) > 0:\n             # a segment can have inner holes\n             wires = MeshPart.wireFromSegment(mesh, i)\n             # we assume that the exterior boundary is that one with the biggest bounding box\n             if len(wires) > 0:\n                ext = None\n                max_length = 0\n                for i in wires:     \n                   if i.BoundBox.DiagonalLength > max_length:\n                      max_length = i.BoundBox.DiagonalLength\n                      ext = i\n                wires.remove(ext)\n                # all interior wires mark a hole and must reverse their orientation, otherwise Part.Face fails\n                for i in wires:\n                   i.reverse()\n                # make sure that the exterior wires comes as first in the lsit\n                wires.insert(0, ext)\n                faces.append(Part.Face(wires))\n \n        shell=Part.Compound(faces)\n        solid = Part.Solid(Part.Shell(faces))\n        name = obj.Name\n        FreeCAD.ActiveDocument.removeObject(name)\n        FreeCAD.ActiveDocument.addObject(\"Part::Feature\",name).Shape = solid",
    "url": "https://wiki.freecad.org/Macro_MeshToPart",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2011-08-01",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Wmayer",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_MeshToPart.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/f/fa/Macro_MeshToPart.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "PartToVRML",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro converts selected parts to VRML meshes.<br /><br />Macro version: 1.9.2<br />Last modified: 2016-02-22<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/f/f8/PartToVRML.png\">ToolBar Icon</a><br />Author: Easyw-fc<br /> ",
    "comment": "This macro creates VRML model of selected object(s), with colors (for Kicad and Blender compatibility)",
    "code": "\n\n# -*- coding: utf-8 -*-\n\n# PartToVRML.FCMacro\n# creates VRML model of selected object(s), with colors (for Kicad and Blender compatibility)\n# useful messages on Report view\n#\n\n__title__ = \"PartToVRML\"\n__author__ = \"easyw-fc, hyOzd\"\n__url__     = \"http://www.freecadweb.org/\"\n__version__ = \"1.9.2\"\n__date__    = \"22/02/2016\"\n\n__Comment__ = \"This macro creates VRML model of selected object(s), with colors (for Kicad and Blender compatibility)\"\n__Web__ = \"http://www.freecadweb.org/\"\n__Wiki__ = \"http://www.freecadweb.org/wiki/index.php?title=Macro_PartToVRML\"\n__Icon__  = \"https://wiki.freecad.org/images/f/f8/PartToVRML.png\"\n__IconW__  = \"C:/Users/User Name/AppData/Roaming/FreeCAD/Macro_PartToVRML.png\"\n__Help__ = \"start the macro and follow the instructions\"\n__Status__ = \"stable\"\n__Requires__ = \"Freecad\"\n\n# FreeCAD VRML python exporter is free software: you can redistribute it\n# and/or modify it under the terms of the GNU General Public License\n# as published by the Free Software Foundation, either version 3 of\n# the License, or (at your option) any later version.\n#\n# This sw is distributed in the hope that it will be\n# useful, but WITHOUT ANY WARRANTY; without even the implied warranty\n# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with expVrmlColor.FCMacro.  If not, see\n# <http://www.gnu.org/licenses/>.\n\n## export VRML from FreeCAD is a python macro that will export simplified VRML of \n## a (multi)selected Part or fused Part to VRML optimized to Kicad and compatible with Blender\n## the size of VRML is much smaller compared to the one exported from FC Gui\n## and the loading/rendering time is smaller too\n## change mesh deviation to increase quality of VRML\n\n## to do \n#  export material properties to vrml\n\nimport FreeCAD,FreeCADGui,Part,Mesh\nimport PySide\nfrom PySide import QtGui, QtCore\nfrom collections import namedtuple\nimport sys, os\nfrom os.path import expanduser\n\n#clearing previous messages\nmw=Gui.getMainWindow()\nc=mw.findChild(QtGui.QPlainTextEdit, \"Python console\")\nc.clear()\nr=mw.findChild(QtGui.QTextEdit, \"Report view\")\nr.clear()\n\ndef say(msg):\n    FreeCAD.Console.PrintMessage(msg)\n    FreeCAD.Console.PrintMessage('\\n')\n\n# points: [Vector, Vector, ...]\n# faces: [(pi, pi, pi), ], pi: point index\n# color: (Red, Green, Blue), values range from 0 to 1.0\nMesh = namedtuple('Mesh', ['points', 'faces', 'color', 'transp'])\n\ndef shapeToMesh(shape, color, transp, scale=None):\n    mesh_deviation=0.03 #the smaller the best quality, 1 coarse; 0.03 good compromise :)\n    mesh_data = shape.tessellate(mesh_deviation)\n    points = mesh_data[0]\n    if scale != None:\n        points = map(lambda p: p*scale, points)\n    newMesh= Mesh(points = points,\n                faces = mesh_data[1],\n                color = color, transp=transp)\n    return newMesh\n        \ndef exportVRML(objects, filepath):\n    \"\"\"Export given list of Mesh objects to a VRML file.\n\n    `Mesh` structure is defined at root.\"\"\"\n\n    with open(filepath, 'w') as f:\n        # write the standard VRML header\n        f.write(\"#VRML V2.0 utf8\\n\\n\")\n        for obj in objects:\n            f.write(\"Shape { geometry IndexedFaceSet \\n{ coordIndex [\")\n            # write coordinate indexes for each face\n            f.write(','.join(\"%d,%d,%d,-1\" % f for f in obj.faces))\n            f.write(\"]\\n\") # closes coordIndex\n            f.write(\"coord Coordinate { point [\")\n            # write coordinate points for each vertex\n            #f.write(','.join('%.3f %.3f %.3f' % (p.x, p.y, p.z) for p in obj.points))\n            f.write(','.join('%.3f %.3f %.3f' % (p.x, p.y, p.z) for p in obj.points))\n            f.write(\"]\\n}\") # closes Coordinate\n            #shape_col=(1.0, 0.0, 0.0)#, 0.0)\n            f.write(\"}\\n\") # closes points\n            #say(obj.color)\n            shape_col=obj.color[:-1] #remove last item\n            #say(shape_col)\n            shape_transparency=obj.transp\n            f.write(\"appearance Appearance{material Material{diffuseColor %f %f %f\\n\" % shape_col)\n            f.write(\"transparency %f}}\" % shape_transparency)\n            f.write(\"}\\n\") # closes Shape\n        say(filepath+' written')\n###\n\ndef export(componentObjs, fullfilePathName, scale=None):\n    \"\"\" Exports given ComponentModel object using FreeCAD.\n\n    `componentObjs` : a ComponentObjs list\n    `fullfilePathName` : name of the FC file, extension is important\n    \n    \"\"\"\n    \n    exp_name=componentObjs[0].Label\n    path, fname = os.path.split(fullfilePathName)\n    fname=os.path.splitext(fname)[0]\n    if scale != None:\n        filename=path+os.sep+exp_name+'.wrl'\n    else:\n        filename=path+os.sep+exp_name+'_1_1.wrl'\n    say(filename)    \n    color=[]\n    Diffuse_color=[]\n    transparency=[]\n    for obj in componentObjs:\n        say(obj.Label)\n        color.append(Gui.ActiveDocument.getObject(obj.Name).ShapeColor)\n        transparency.append(Gui.ActiveDocument.getObject(obj.Name).Transparency/100.0)\n        #say(\"color\")\n        #say(Gui.ActiveDocument.getObject(obj.Name).DiffuseColor)\n        Diffuse_color.append(Gui.ActiveDocument.getObject(obj.Name).DiffuseColor)\n    i=0\n    meshes=[]\n    #say(\"diffuse color\")\n    #say(Diffuse_color)\n    indexColor=0;\n    color_vector=[]\n    applyDiffuse=0\n    for obj in componentObjs:\n        shape1=obj.Shape\n        single_color=Diffuse_color[i];\n        #check lenght color\n        #say(\"len color\")\n        #say(len(single_color))\n        #colors less then faces\n        if(len(single_color)!=len(shape1.Faces)):\n            applyDiffuse=0;\n            #copy color to all faces\n        #else copy singolar colors for faces\n        else:\n            applyDiffuse=1;\n            for color in single_color:\n                color_vector.append(color)\n        #say(\"color_vector\")\n        #say(color_vector)\n        for index in range(len(shape1.Faces)):\n            #say(\"color x\")\n            #say(color_vector[indexColor])\n            singleFace=shape1.Faces[index]\n            if(applyDiffuse):\n                #say(color_vector[indexColor])\n                meshes.append(shapeToMesh(singleFace, color_vector[indexColor], transparency[i], scale))\n            else:\n                #say(single_color[0])\n                meshes.append(shapeToMesh(singleFace, single_color[0], transparency[i], scale))\n            indexColor=indexColor+1\n            #meshes.append(shapeToMesh(face, Diffuse_color[i], transparency[i], scale))\n        color_vector=[]\n        indexColor=0;\n        i=i+1            \n    exportVRML(meshes, filename)\n    return\n###\n\ndef go_export():\n    sel = FreeCADGui.Selection.getSelection()\n    if not sel:\n        FreeCAD.Console.PrintWarning(\"Select something first!\\n\\n\")\n        msg=\"export VRML from FreeCAD is a python macro that will export simplified VRML of \"\n        msg+=\"a (multi)selected Part or fused Part to VRML optimized to Kicad and compatible with Blender \"\n        msg+=\"the size of VRML is much smaller compared to the one exported from FC Gui \"\n        msg+=\"and the loading/rendering time is also smaller\\n\"\n        msg+=\"change mesh deviation to increase quality of VRML\"\n        say(msg)\n    else:\n        objs = []\n        for obj in sel:\n                objs.append(obj)\n                #say(obj.Label)\n                #say(obj.Name)\n        say(fullFilePathName)\n        #say(objs)\n        export(objs, fullFilePathName, scale=None)\n        export(objs, fullFilePathName, 0.3937)\n    \ndoc = FreeCAD.ActiveDocument\nif doc!=None:\n    fullFilePathName=doc.FileName\n    if fullFilePathName==\"\":\n        home = expanduser(\"~\")\n        fullFilePathName=home+os.sep+doc.Label+'.FCStd'\n        say('path not found, saving to '+fullFilePathName)\n        #say(fullFilePathName)\n    else:\n        fullFilePathName = os.path.dirname(os.path.abspath(fullFilePathName))\n        fullFilePathName=fullFilePathName+os.sep+doc.Label+'.FCStd'\n        say(fullFilePathName)\n    go_export()\n\n",
    "url": "http://www.freecadweb.org/",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_PartToVRML",
    "version": "1.9.2",
    "license": "",
    "date": "22/02/2016",
    "src_filename": "",
    "filename_from_url": "",
    "author": "easyw-fc, hyOzd",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\PartToVRML.png",
    "icon_source": "https://wiki.freecad.org/images/f/f8/PartToVRML.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Align Camera to Working Plane",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro aligns the camera to the current <a href=\"/Draft_SelectPlane\" title=\"Draft SelectPlane\">Draft Working Plane</a><br /><br />Macro version: 0.1<br />Last modified: 2017-03-16<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/f/fd/Macro_Align_Camera_to_Working_Plane.png\">ToolBar Icon</a><br />Author: yorik<br /> ",
    "comment": "This macro aligns the camera to the current Draft Working Plane",
    "code": "import FreeCAD,FreeCADGui\nc = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()\nr = FreeCAD.DraftWorkingPlane.getRotation().Rotation.Q\nc.orientation.setValue(r)",
    "url": "https://wiki.freecad.org/Macro_Align_Camera_to_Working_Plane",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2017-03-16",
    "src_filename": "",
    "filename_from_url": "",
    "author": "yorik",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Align_Camera_to_Working_Plane.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/f/fd/Macro_Align_Camera_to_Working_Plane.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Align Working Plane to Camera",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro moves the current <a href=\"/Draft_SelectPlane\" title=\"Draft SelectPlane\">Draft Working Plane</a> to the center of the current view<br /><br />Macro version: 1.0<br />Last modified: 2017-05-10<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/0/01/Macro_Align_Working_Plane_to_Camera.png\">ToolBar Icon</a><br />Author: yorik<br /> ",
    "comment": "This macro moves the current Draft Working Plane to the center of the current view",
    "code": "import FreeCAD,FreeCADGui\ncam = FreeCAD.Vector(FreeCADGui.ActiveDocument.ActiveView.getCameraNode().position.getValue().getValue())\npos = FreeCAD.DraftWorkingPlane.projectPoint(cam)\nFreeCAD.DraftWorkingPlane.position = pos\nFreeCADGui.Snapper.setGrid()",
    "url": "https://wiki.freecad.org/Macro_Align_Working_Plane_to_Camera",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2017-05-10",
    "src_filename": "",
    "filename_from_url": "",
    "author": "yorik",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Align_Working_Plane_to_Camera.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/0/01/Macro_Align_Working_Plane_to_Camera.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Draft Circle 3 Points",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro creates a circle on 3 selected points. The points can be objects such as cubes, cylinder, then selected coordinates will be the centre of these forms.<br /><br />Macro version: 01.00<br />Last modified: 2013-03-11<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/c/c7/Macro_Make_Circle_3_Points.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "This macro creates a circle on 3 selected points. The points can be objects such as cubes, cylinder, then selected coordinates will be the centre of these forms.",
    "code": "# -*- coding: utf-8 -*-\n# cr\u00e9er un cercle \u00e0 partir de 3 points s\u00e9l\u00e9ctionn\u00e9s\n# avec comme options le cercle peut \u00eatre construit sur un plans au choix\n# \u00e0 la coordonn\u00e9e d'une des trois formes s\u00e9lectionn\u00e9es au choix\n# et cr\u00e9ation du point central O/N\n# 04/03/2013 , 07/09/2018 replace PyQt4 to PySide\n# la formule provient de\n# http://www-obs.univ-lyon1.fr/labo/fc/Ateliers_archives/ateliers_2005-06/cercle_3pts.pdf\n# lire la note dans le pdf, sur l'ordre de s\u00e9lection des points,\n# si la formule renvoie une erreur (exemple les 3 points dans le m\u00eame alignement)\n#\nimport Draft, Part, FreeCAD, math, PartGui, FreeCADGui\nfrom math import sqrt, pi, sin, cos\nfrom FreeCAD import Base\nfrom PySide import QtCore, QtGui\n\ndef errorDialog(msg):\n    # Create a simple dialog QMessageBox\n    # The first argument indicates the icon used: one of QtGui.QMessageBox.{NoIcon, Information, Warning, Critical, Question} \n\tdiag = QtGui.QMessageBox(QtGui.QMessageBox.Critical,u\"Error Message\",msg)\n\tdiag.setWindowModality(QtCore.Qt.ApplicationModal)\n\tdiag.exec_()\n\ndef affiche(x,y,z,rayon,r,v,b,afficherPoint):\n\tpl.Base=FreeCAD.Vector(x,y,z)\n\tDraft.makeCircle((rayon),placement=pl,face=False,support=None)\n\tFreeCADGui.activeDocument().activeObject().LineColor = (r,v,b)\n\tif afficherPoint==1:\n\t\tDraft.makePoint(x,y,z)\n\tdiag = QtGui.QMessageBox(QtGui.QMessageBox.Information,u\"Coordinates\",u\"Coordinates X : \"+str(x)+\"\\r\\n\"+u\"Coordinates Y : \"+str(y)+\"\\n\"+u\"Coordinates Z : \"+str(z)+\"\\nRayon\\t     : \"+str(rayon))\n\tdiag.setWindowModality(QtCore.Qt.ApplicationModal)\n\tdiag.exec_()\n\n# prendre les objets selectionnes\nsel = FreeCADGui.Selection.getSelection()\ni=0\ncentreX=0;centreY=0;rayon=0\n\n# S'il y a 3 points s\u00e9lectionn\u00e9s alors..\nif len(sel)==3 :\n\ti=0\n\tta=[0,0,0,0,0,0,0,0,0]\n\tfor obj in sel:\n\t\tx=(obj.Shape.BoundBox.Center)\n\t\tta[i+0]=(x.x)\n\t\tta[i+1]=(x.y)\n\t\tta[i+2]=(x.z)\n\t\ti=i+3\n# Change the values here below\n\t\t\t# mode by default vueChoix = 0 and alignerSur = 0\n\tvueChoix=0\t# choice of the top view = 1 XY, view Front = 2 ZX, Right view = 3 ZY\n\talignerSur=0\t# Aligns the circle shaped the choice (1,2 or 3) or Z = 0\n\tafficherPoint=1\t# Displays the center point of the circle\n\n    # Affectation des variables\n\tif vueChoix==3:\t\t# View of right ZY (Red)\n \t  \tz_point_1=ta[0]\n\t\tx_point_1=ta[1]\n\t\ty_point_1=ta[2]\n\t\n\t\tz_point_2=ta[3]\n\t\tx_point_2=ta[4]\n\t\ty_point_2=ta[5]\n\t\n\t\tz_point_3=ta[6]\n\t\tx_point_3=ta[7]\n\t\ty_point_3=ta[8]\n\n\telif vueChoix==2:\t# Front view ZX (Green)\n \t  \ty_point_1=ta[0]\n\t\tz_point_1=ta[1]\n\t\tx_point_1=ta[2]\n\t\n\t\ty_point_2=ta[3]\n\t\tz_point_2=ta[4]\n\t\tx_point_2=ta[5]\n\t\n\t\ty_point_3=ta[6]\n\t\tz_point_3=ta[7]\n\t\tx_point_3=ta[8]\n\n\telse:\t\t\t# Top view XY (blue)\n \t  \tx_point_1=ta[0]\n\t\ty_point_1=ta[1]\n\t\tz_point_1=ta[2]\n\t\n\t\tx_point_2=ta[3]\n\t\ty_point_2=ta[4]\n\t\tz_point_2=ta[5]\n\t\n\t\tx_point_3=ta[6]\n\t\ty_point_3=ta[7]\n\t\tz_point_3=ta[8]\n\n    # Calculation of coordinates of the center of the circle\t\n\ttry:\n\t\tcentreX =((x_point_3**2-x_point_2**2+y_point_3**2-y_point_2**2)/(2*(y_point_3-y_point_2))-(x_point_2**2-x_point_1**2+y_point_2**2-y_point_1**2)/(2*(y_point_2-y_point_1)))/((x_point_3-x_point_2)/(y_point_3-y_point_2)-(x_point_2-x_point_1)/(y_point_2-y_point_1))\n\t\tcentreY =-(x_point_2-x_point_1)/(y_point_2-y_point_1)*centreX+(x_point_2**2-x_point_1**2+y_point_2**2-y_point_1**2)/(2*(y_point_2-y_point_1))\n\t\trayon =sqrt((x_point_1-centreX)**2+(y_point_1-centreY)**2)\n\texcept:\n\t\terrorDialog(u\"Impossible calculation too aligned elements\")\n\telse:\n\t#finally: sera TOUJOURS ex\u00e9cut\u00e9\n\t   # Definition of the coordinate Z\n\t\tcentreZ=0\n\t    # Cr\u00e9ation du cercle\n\t\tpl=FreeCAD.Placement()\n\t\tif vueChoix==1:\t# Plan XY Dessus\n\t\t\tpl.Rotation.Q=(0,0,0,1.0)\n\t\t\tif alignerSur==1:\t\n\t\t\t\taffiche(centreX,centreY,z_point_1,rayon,0.0,0.0,1.0,afficherPoint)\n\t\t\telif alignerSur==2:\n\t\t\t\taffiche(centreX,centreY,z_point_2,rayon,0.0,0.0,1.0,afficherPoint)\n\t\t\telif alignerSur==3:\n\t\t\t\taffiche(centreX,centreY,z_point_3,rayon,0.0,0.0,1.0,afficherPoint)\n\t\telif vueChoix==2: # Plan XZ Face\n\t\t\tpl.Rotation.Q=(1,0,0,1.0)\n\t\t\tif alignerSur==1:\t\n\t\t\t\taffiche(centreY,z_point_1,centreX,rayon,0.0,1.0,0.0,afficherPoint)\n\t\t\telif alignerSur==2:\n\t\t\t\taffiche(centreY,z_point_2,centreX,rayon,0.0,1.0,0.0,afficherPoint)\n\t\t\telif alignerSur==3:\n\t\t\t\taffiche(centreY,z_point_3,centreX,rayon,0.0,1.0,0.0,afficherPoint)\n\t\telif vueChoix==3: # Plan YZ Droite\n\t\t\tpl.Rotation.Q=(0,1,0,1.0)\n\t\t\tif alignerSur==1:\t\n\t\t\t\taffiche(z_point_1,centreX,centreY,rayon,1.0,0.0,0.0,afficherPoint)\n\t\t\telif alignerSur==2:\n\t\t\t\taffiche(z_point_2,centreX,centreY,rayon,1.0,0.0,0.0,afficherPoint)\n\t\t\telif alignerSur==3:\n\t\t\t\taffiche(z_point_3,centreX,centreY,rayon,1.0,0.0,0.0,afficherPoint)\n\t\telse:\t# modifier pour avoir XYZ\n\t\t\t# si les coordonn\u00e9es Z sont \u00e9gales alors le cercle s'aligne \u00e0 Z\n\t\t\tif z_point_1==z_point_2 and z_point_2==z_point_3:\n\t\t\t\tcentreZ=z_point_1\n\t\t\t\taffiche(centreX,centreY,z_point_1,rayon,0.0,0.0,0.0,afficherPoint)\n\t\t\telse:\n\t        \t# Si une coordonn\u00e9e est diff\u00e9rente alors Z=0\n\t\t\t\taffiche(centreX,centreY,0,rayon,0.0,0.0,0.0,afficherPoint)\n\nelse:\n    # Si la condition n'est pas remplie, recommencer\n\terrorDialog(u\"Select 3 points and repeat\")\n\t#FreeCAD.Console.PrintError(\"Select 3 points and repeatr\\n\")",
    "url": "https://wiki.freecad.org/Macro_Draft_Circle_3_Points",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2013-03-11",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Make_Circle_3_Points.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/c/c7/Macro_Make_Circle_3_Points.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Draft Circle 3 Points 3D",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro creates a circle on 3 selected points in the space. The points can be objects such as cubes, cylinder, then selected coordinates will be the centre of these forms.<br /><br />Macro version: 01.00<br />Last modified: 2013-03-16<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/1/10/Macro_Draft_Circle_3_Points.png\">ToolBar Icon</a><br />Author: galou_breizh<br /> ",
    "comment": "This macro creates a circle on 3 selected points in the space. The points can be objects such as cubes, cylinder, then selected coordinates will be the centre of these forms.",
    "code": "# -*- coding: utf-8 -*-\n# Create a circle from 3 points selected on the X, Y, Z map\n# 04/03/2013\n# From https://en.wikipedia.org/wiki/Circumscribed_circle#Cartesian_coordinates_from_cross-_and_dot-products\n# Also see : https://math.stackexchange.com/questions/2658318/how-to-find-the-circumcenter-of-a-triangle-and-the-length-of-the-corresponding-r\n# O=R/2S*(acos\u03b1\u22c5A+bcos\u03b2\u22c5B+ccos\u03b3\u22c5C)  ; R is circumradius, S is area of triangle\n# 08/08/2014 PyQt4 and PySide\n\n#OS: Windows Vista\n#Word size: 32-bit\n#Version: 0.14.3700 (Git)\n#Branch: releases/FreeCAD-0-14\n#Hash: 32f5aae0a64333ec8d5d160dbc46e690510c8fe1\n#Python version: 2.6.2\n#Qt version: 4.5.2\n#Coin version: 3.1.0\n#SoQt version: 1.4.1\n#OCC version: 6.5.1\n\ntry:\n    import PyQt4\n    from PyQt4 import QtCore, QtGui\nexcept Exception:\n    import PySide\n    from PySide import QtCore, QtGui\nfrom math import pi, asin\nimport Draft, FreeCAD, FreeCADGui\nfrom FreeCAD import Base\n\ndef errorDialog(msg):\n    # Create a simple dialog QMessageBox\n    # The first argument indicates the icon used: one of QtGui.QMessageBox.{NoIcon, Information, Warning, Critical, Question} \n    diag = QtGui.QMessageBox(QtGui.QMessageBox.Critical,u\"Error Message\",msg)\n    diag.setWindowModality(QtCore.Qt.ApplicationModal)\n    diag.exec_()\n\ndef affiche(x,y,z,r,angle):\n    diag = QtGui.QMessageBox(QtGui.QMessageBox.Information,u\"Coordinates\",u\"Coordinate X : \"+str(x)+\"\\r\\n\"+u\"Coordinate Y : \"+str(y)+\"\\n\"+u\"Coordinate Z : \"+str(z)+\"\\nRadius\\t   : \"+str(r)+\"\\nAngle\\t   : \"+str(angle))\n    diag.setWindowModality(QtCore.Qt.ApplicationModal)\n    diag.setWindowModality(QtCore.Qt.NonModal)\n    diag.exec_()\n\n# objects selected\nsel = FreeCADGui.Selection.getSelection()\n# If there are 3 selected points so...\nif len(sel)==3 :\n    # Assignment of variables\n    P1 = sel[0].Shape.BoundBox.Center\n    P2 = sel[1].Shape.BoundBox.Center\n    P3 = sel[2].Shape.BoundBox.Center\n\n    P1P2 = (P2 - P1).Length\n    P2P3 = (P3 - P2).Length\n    P3P1 = (P1 - P3).Length\n\n    # Circle radius.\n    l = ((P1 - P2).cross(P2 - P3)).Length\n    try:\n        #if l < 1e-8:\n        #    errorDialog(\"The three points are aligned\")\n        r = P1P2 * P2P3 * P3P1 / 2 / l\n    except:\n        errorDialog(\"The three points are aligned\")\n    else:\n        # Sphere center.\n        a = P2P3**2 * (P1 - P2).dot(P1 - P3) / 2 / l**2\n        b = P3P1**2 * (P2 - P1).dot(P2 - P3) / 2 / l**2\n        c = P1P2**2 * (P3 - P1).dot(P3 - P2) / 2 / l**2\n        P1.multiply(a)\n        P2.multiply(b)\n        P3.multiply(c)\n        PC = P1 + P2 + P3\n\n        # Creation of a circle\n        pl = Base.Placement()\n        v = (P1 - P2).cross(P3 - P2)\n        v.normalize()\n        axis = Base.Vector(0, 0, 1).cross(v)\n        angle = asin(axis.Length) * 180 / pi\n        axis.normalize()\n        pl = Base.Placement(PC, axis, angle)\n        Draft.makeCircle(r, placement=pl, face=False, support=None)\n        # Displays the result in the windows\n        affiche((PC.x),(PC.y),(PC.z),r,angle)\n        # Displays the result in the FreeCAD report view\n        #FreeCAD.Console.PrintMessage(\"Coordinate X : \"+str(PC.x)+\"\\n\")\n        #FreeCAD.Console.PrintMessage(\"Coordinate Y : \"+str(PC.y)+\"\\n\")\n        #FreeCAD.Console.PrintMessage(\"Coordinate Z : \"+str(PC.z)+\"\\n\")\n        #FreeCAD.Console.PrintMessage(\"Radius       : \"+str(r)+\"\\n\")\n        #FreeCAD.Console.PrintMessage(\"Angle        : \"+str(angle)+\"\\n\")\nelse:\n    # If the condition is not met, repeat\n    #FreeCAD.Console.PrintError(\"Select 3 points and repeat\\n\")\n    errorDialog(\"Select 3 points and repeat\\n\")",
    "url": "https://wiki.freecad.org/Macro_Draft_Circle_3_Points_3D",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2013-03-16",
    "src_filename": "",
    "filename_from_url": "",
    "author": "galou_breizh",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Draft_Circle_3_Points.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/1/10/Macro_Draft_Circle_3_Points.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Draft Circle Tangent",
    "on_wiki": true,
    "on_git": false,
    "desc": "Makes tangents to Draft circles.<br /><br />Macro version: 0.2<br />Last modified: 2022-11-27<br />FreeCAD version: -<br />Author: heda<br /> ",
    "comment": "Makes tangents to draft circles.",
    "code": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n# ***************************************************************************\n# *   Copyright (c) 2022 heda <heda @ freecad forum>                        *\n# *                                                                         *\n# *   This file is part of the FreeCAD CAx development system.              *\n# *                                                                         *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU Lesser General Public License (LGPL)    *\n# *   as published by the Free Software Foundation; either version 2 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENCE text file.                                 *\n# *                                                                         *\n# *   This program is distributed in the hope that it will be useful,       *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU Library General Public License for more details.                  *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with this program; if not, write to the Free Software   *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\n\n__Name__ = 'Draft_Circle_Tangent'\n__Comment__ = 'Makes tangents to draft circles.'\n__Author__ = 'heda @ fc-forum'\n__Version__ = '0.2'\n__Date__ = '2022-11-27'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = ''\n__Wiki__ = 'https://wiki.freecadweb.org/Macro_Draft_Circle_Tangent'\n__Icon__ = ''\n__Help__ = 'Select and launch.'\n__Status__ = 'functional'\n__Requires__ = 'tested on FreeCAD v0.20'\n__Communication__ = ''\n__Files__ = ''\n\n\n__doc__ = \"\"\"\nmakes tangents for draft circles and arcs\na) circle and vertex/point\nb) two circles\n\nselect before launching macro\n\nfor circle and point the tangents are constructed,\nas one would do with pen and paper\nfor circle and circle the angles are calculated,\none can also construct the tangents in a similar way to\ncircle/point way, i.e. intersections by additional construction circles\n\nnote: tesselation often makes the true tangent not look like a true tangent\nthis is to not overload rendering for larger projects\none can change the viewsetting deviation for the circle to minimum (0.01)\nif one wants to better view the true tangent, if so, better turn that back\nto default once viewed - it is easy to forget that this has been done,\nand can in larger projects put fc to more or less a complete halt.\n\"\"\"\n\nfrom math import sin, cos, pi, atan2, acos, asin\n\nimport Draft\n\ndoc = App.ActiveDocument\ncgroup = doc.addObject('App::DocumentObjectGroup','Construction')\nVector, Placement = App.Vector, App.Placement\nRotZero = Placement().Rotation\n\ndef get_curve(obj):\n    return obj.Shape.Edge1.Curve\n\ndef point2vector(pt):\n    return pt.toShape().Point\n\ndef get_intersection_points(obj1, obj2):\n    doc.recompute()\n    i1, i2 = get_curve(obj1).intersect(get_curve(obj2))\n    return (point2vector(p) for p in (i1, i2))\n\ndef add_construction(obj):\n    _ = cgroup.addObject(obj)\n\ndef mk_line(v1, v2, construction=True):\n    line = Draft.make_line(v1, v2)\n    if construction:\n        line.ViewObject.DrawStyle = 'Dashdot'\n        add_construction(line)\n    return line\n\ndef mk_circle(centre, radius):\n    circle = Draft.make_circle(radius, Placement(centre, RotZero), False)\n    circle.ViewObject.DrawStyle = 'Dashed'\n    add_construction(circle)\n    return circle\n\n\n## selection logic\nSINGLE = False\nmsg = ('select exactly 2 items, 2 (draft) circles '\n        'or 1 (draft) circle and one vertex or (draft) point')\nselection = Gui.Selection.getSelection()\nif len(selection) == 2:\n    s1, s2 = selection\n    r1, r2 = (hasattr(r, 'Radius') for r in selection)\n    if r1 and r2:\n        c1s, c2s = s1, s2\n    elif not r1 and not r2:\n        raise RunTimeWarning(msg)\n    else:\n        SINGLE = True\n        circle = s1 if r1 else s2\n        sx1, sx2 = Gui.Selection.getSelectionEx()\n        sx = sx2 if r1 else sx1\n        if sx.PickedPoints:\n            point, = sx.PickedPoints\n        else: # it is a draft point selected in tree view\n            point = sx.Object.Shape.Point\n    \nelse:\n    raise RunTimeWarning(msg)\n\nif SINGLE:\n\n    o = circle.Placement.Base\n    op = point - o\n\n    ccircle = mk_circle(o + op/2, op.Length/2)\n\n    v1, v2 = get_intersection_points(circle, ccircle)\n\n    tangent1 = mk_line(point, v1, False)\n    tangent2 = mk_line(point, v2, False)\n\n\nelse:\n\n    # c1 is the larger one\n    if c1s.Radius >= c2s.Radius:\n        c1, c2 = c1s, c2s\n    else:\n        c1, c2 = c2s, c1s\n\n    c1c, c2c = c1.Placement.Base, c2.Placement.Base\n\n    centerline = mk_line(c1c, c2c)\n    cc = c2c - c1c\n\n    # construction circle outer tangent\n    c3 = mk_circle(c1c, c1.Radius - c2.Radius)\n\n    phi1 = atan2(cc.y, cc.x) + acos(c3.Radius / cc.Length)\n    v1 = Vector(cos(phi1), sin(phi1), 0).normalize()\n    line = mk_line(c1c, v1 * c1.Radius + c1c)\n    ot1 = mk_line(c1c + v1 * c1.Radius, c2c + v1 * c2.Radius, False)\n\n    phi2 = atan2(cc.y, cc.x) - acos(c3.Radius / cc.Length)\n    v2 = Vector(cos(phi2), sin(phi2), 0).normalize()\n    line2 = mk_line(c1c, v2 * c1.Radius + c1c)\n    ot2 = mk_line(c1c + v2 * c1.Radius, c2c + v2 * c2.Radius, False)\n\n    # construction circle inner tangent\n    c4 = mk_circle(c2c, c1.Radius + c2.Radius)\n\n    phi1 = atan2(cc.y, cc.x) + asin(c4.Radius / cc.Length) - pi/2\n    v1 = Vector(cos(phi1), sin(phi1), 0).normalize()\n    line = mk_line(c2c, -v1 * c2.Radius + c2c)\n    ot1 = mk_line(c1c + v1 * c1.Radius, c2c - v1 * c2.Radius, False)\n\n    phi2 = atan2(cc.y, cc.x) - asin(c4.Radius / cc.Length) + pi/2\n    v2 = Vector(cos(phi2), sin(phi2), 0).normalize()\n    line2 = mk_line(c2c, - v2 * c2.Radius + c2c)\n    ot2 = mk_line(c1c + v2 * c1.Radius, c2c - v2 * c2.Radius, False)\n\ncgroup.ViewObject.Visibility = False\ndoc.recompute()",
    "url": "https://wiki.freecad.org/Macro_Draft_Circle_Tangent",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_Draft_Circle_Tangent",
    "version": "0.2",
    "license": "",
    "date": "2022-11-27",
    "src_filename": "",
    "filename_from_url": "",
    "author": "heda @ fc-forum",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "EdgesToArc",
    "on_wiki": true,
    "on_git": false,
    "desc": "Replaces the selected Edges by a circular Arc if possible. Useful for restoring discretized arcs.<br /><br />Macro version: 1.0<br />Last modified: 2014-01-02<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/6/65/Macro_EdgesToArc.png\">ToolBar Icon</a><br />Author: Jreinhardt<br /> ",
    "comment": "Replaces the selected Edges by a circular Arc if possible. Useful for restoring discretized arcs.",
    "code": "import Draft\nimport FreeCADGui, FreeCAD\nfrom FreeCAD import Base, Console\nfrom math import atan2, pi, fabs\n\n#This macro replaces a number of edges approximating a circular arc by a proper circular arc.\n#It might be necessary to use the superwire macro to recombine the edges back to a wire, because of small errors in the calculations.\n\nsel = FreeCADGui.Selection.getSelection()\nif len(sel) < 2:\n    Console.PrintError(\"Too few edges are selected\\n\")\nedges = [s.Shape for s in sel]\n\nstart_vertices = []\nend_vertices = []\nfor edge in edges:\n    start_vertices.append(edge.Vertexes[0].Point)\n    end_vertices.append(edge.Vertexes[1].Point)\nvertices = start_vertices + end_vertices\n\nstart,end,middle = None,None,None\n\n#find start and end points\nfor edge in edges:\n    is_start = True\n    is_end = True\n    for point in end_vertices:\n        if edge.Vertexes[0].Point.distanceToPoint(point) < 1e-8:\n            is_start = False\n\n    for point in start_vertices:\n        if edge.Vertexes[1].Point.distanceToPoint(point) < 1e-8:\n            is_end = False\n    if is_start:\n        start = edge.Vertexes[0].Point\n    if is_end:\n        end = edge.Vertexes[1].Point\n\n#find middle point, at least not too far away from the middle\n\nfor v in vertices:\n    ratio = v.distanceToPoint(start)/v.distanceToPoint(end)\n    if ratio > 0.5 and ratio < 2.:\n        middle = v\n        break\n\nif middle is None:\n    Console.PrintError(\"Could not find suitable middle point\\n\")\n\narc = Part.ArcOfCircle(start,middle,end)\n\n#Check circularity\ncircular = True\nfor v in vertices:\n    if fabs(v.distanceToPoint(arc.Center) - arc.Radius) > 1e-6:\n        Console.PrintError(\"Edges do not approximate a circular arc\\n\")\n        circular = False\n        break\n\nif circular:\n        Part.show(arc.toShape())\n        for shape in sel:\n            FreeCAD.ActiveDocument.removeObject(shape.Name)",
    "url": "https://wiki.freecad.org/Macro_EdgesToArc",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-01-02",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Jreinhardt",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_EdgesToArc.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/6/65/Macro_EdgesToArc.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Ellipse-Center+2Points",
    "on_wiki": true,
    "on_git": false,
    "desc": "Makes an ellipse by selecting three points (in this order): centre, major radius and minor radius<br /><br />Macro version: 02.00<br />Last modified: 2019-07-29<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/6/66/Macro_Ellipse-Center%2B2Points.png\">ToolBar Icon</a><br />Author: Eriossoltero<br /> ",
    "comment": "Makes an ellipse by selecting three points (in this order): centre, major radius and minor radius",
    "code": "# Macro Begin: Ellipse-Center+2Points.FCMacro +++++++++++++++++++++++++++++++++++++++++++++++++\n# http://freecad-tutorial.blogspot.com/2011/12/engine-9-poly-v-belt.html\n# https://www.freecadweb.org/wiki/User:Eriossoltero\n# 13/03/2012, 29/07/2019\nimport Part, FreeCAD, math, PartGui, FreeCADGui\nfrom FreeCAD import Base\n\n# get the selected objects, with first selection for the trajectory and second for the section\n# Adapted from:\n# Macro Begin: Ellipse-Center+2Points.FCMacro +++++++++++++++++++++++++++++++++++++++++++++++++\n# http://freecad-tutorial.blogspot.com/2011/12/engine-9-poly-v-belt.html\nimport Part, FreeCAD, math, PartGui, FreeCADGui\nfrom FreeCAD import Base\n\n# get the selected objects, with first selection for the trajectory and second for the section\n# Adapted from:\n# http://freecad-tutorial.blogspot.com/2011/12/engine-9-poly-v-belt.html\ns = FreeCADGui.Selection.getSelection()\ntry:\n    sel1=s[0].Shape\n    sel2=s[1].Shape\n    sel3=s[2].Shape\n    pt_center = sel1.Point\n    pt_radmay = sel2.Point\n    pt_radmen = sel3.Point\n    \n    # create Part object in the current document\n    myObject=App.ActiveDocument.addObject(\"Part::Feature\",\"Ellipse\")\n    \n    # create a shape and assign it to the current document\n    ellipse = Part.Ellipse(pt_radmay, pt_radmen, pt_center)\n    myObject.Shape = ellipse.toShape()\n    # Macro End: Ellipse-Center+2Points.FCMacro +++++++++++++++++++++++++++++++++++++++++++++++++\n\nexcept:\n    print( \"Wrong selection\")\n    print( \"First:centre, Second:major radius and Third:minor radius\")",
    "url": "https://wiki.freecad.org/Macro_Ellipse-Center%2B2Points",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2019-07-29",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Eriossoltero",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Ellipse-Center%2B2Points.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/6/66/Macro_Ellipse-Center%2B2Points.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FCConvertLines",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro convert the object line, wire in line Dash, DashDot or DashDotDot with the dimensions given.<br /><br />Macro version: 00.07b<br />Last modified: 2020-11-09<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/e/e2/Macro_FCConvertLines.png\">ToolBar Icon</a><br />Author: mario52<br /> ",
    "comment": "This macro convert the object line, wire in line Dash, DashDot or DashDotDot with the dimensions given.",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\nfrom __future__ import division\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2014 2015 2016 2017 2018 2019 2020 <mario52>            *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *\n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#Macro_FCConvertLines 03/01/2016 - 18/02/2016 GUI - 05/09/2016 - 11/01/2017 - 20/02/2017 - 13/05/2017 - 09/11/2020\n#\n#OS: Windows 10 (10.0)\n#Word size of OS: 64-bit\n#Word size of FreeCAD: 64-bit\n#Version: 0.19.22894 (Git)\n#Build type: Release\n#Branch: master\n#Hash: 9eb080488d970d313c538473e7272117ea0a7cd1\n#Python version: 3.6.8\n#Qt version: 5.12.1\n#Coin version: 4.0.0a\n#OCC version: 7.3.0\n#Locale: French/Mars (fr_MA)\n#\n__title__   = \"FCConvertLines\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__Wiki__    = \"http://www.freecadweb.org/wiki/index.php?title=Macro_FC_Convert_Lines\"\n__author__  = \"Mario52\"\n__version__ = \"00.07b\"\n__date__    = \"09/11/2020\"\n#\nimport PySide\nfrom PySide import QtGui ,QtCore\nfrom PySide.QtGui import *\nfrom PySide.QtCore import *\n \nimport Draft, Part, math, PartGui\nfrom math import sqrt, pi, sin, cos, asin\nfrom FreeCAD import Base\nimport os, time, sys, platform\n\nimport FreeCAD, FreeCADGui\nApp = FreeCAD\nGui = FreeCADGui\n\nglobal emergency ; emergency = 0\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\ndef errorDialog(msg):\n    diag = QtGui.QMessageBox(QtGui.QMessageBox.Critical,u\"Error Message\",msg )\n    diag.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint) # PySide #cette fonction met la fen\u00eatre en avant\n    diag.exec_()\n\n####################################################################################################################\n\ndef cutLength(cutLength = 10.0,cutLine = 0, red = 0, green = 0, blue = 0, typeColor = 0, createLine = 1, createPoints = 0, lineWidth = 2.0, pSize = 2.0): \n                                                                         #typeColor = 0 (color system) typeColor = 1 (color = red white)\n    global emergency\n    def createLines(numberOfPoints, points, createLine, createPoints): # create lines special cutLength ant cut x lines\n        bicolor = 0\n        for lin in range(numberOfPoints-1):\n\n            if typeColor == 1:                                         # type color 0 (color system),  1 (color = red white)\n                if bicolor == 0:\n                    red2 = 255.0; green2 = 0.0; blue2 = 0.0\n                    bicolor = 1\n                else:\n                    red2 = 255.0; green2 = 255.0; blue2 = 255.0\n                    bicolor = 0\n            else:\n                red2 = red; green2 = green; blue2 = blue\n\n            if createLine == 1:                                        # create line\n                creaLine = [FreeCAD.Vector(points[lin]),FreeCAD.Vector(points[lin+1])]\n                wire =  Draft.makeWire(creaLine,closed=False,face=False,support=None)\n                colorize(red2 = red2, green2 = green2, blue2 = blue2)\n\n            if createPoints == 1:                                      # create points \n                Draft.makePoint( FreeCAD.Vector(points[lin]))\n                colorize(red2 = red2, green2 = green2, blue2 = blue2)\n\n                if (lin == numberOfPoints-2):\n                    Draft.makePoint( FreeCAD.Vector(points[lin+1]))\n                    colorize(red2 = red2, green2 = green2, blue2 = blue2)\n\n    def colorize(red2 = 0, green2 = 0, blue2 = 0):\n        FreeCADGui.activeDocument().activeObject().LineColor  = (float(red2)/255,float(green2)/255,float(blue2)/255) # cutToLength\n        FreeCADGui.activeDocument().activeObject().PointColor = (float(red2)/255,float(green2)/255,float(blue2)/255) # cutToLength\n        FreeCADGui.activeDocument().activeObject().ShapeColor = (float(red2)/255,float(green2)/255,float(blue2)/255) # cutToLength\n        FreeCADGui.activeDocument().activeObject().LineWidth  = lineWidth\n        FreeCADGui.activeDocument().activeObject().PointSize  = pSize\n\n    if (cutLength + cutLine) != 0:\n        points    = []; points[:]  = []\n        points2   = []; points2[:] = []\n    \n        precision = 10000.0                                                      # permet 4 decimales = 0.0001\n        cutLength    = cutLength  * precision\n    \n        try:\n    #######Selectionne un ou des objets vue 3D ou vue combinnee (subObjects complete) getSelection()############################\n    #            compt_Oject = -1                                                                                              #\n    #            selectionObjects = FreeCADGui.Selection.getSelection()                                                        # Select an object or primitive getSelection()\n    #            for selection in enumerate(selectionObjects):                                                                 #\n    #                compt_Oject += 1                                                                                          #\n    #                compt_Edges = -1                                                                                          #\n    #                for selectedEdge in enumerate(selectionObjects[compt_Oject].Shape.Edges):                                 # Search the \"Edges\" and their lengths\n    #                    compt_Edges += 1                                                                                      #\n    #                    longueur = (selectionObjects[compt_Oject].Shape.Edges[compt_Edges].Length) * precision                #\n    #                    numberOfPoints = (longueur + 1)                                                                       #\n    #                    points = selectionObjects[compt_Oject].Shape.Edges[compt_Edges].discretize(int(numberOfPoints))       # Dicretize\n    ############################################################################################################################\n    #####selection 1 objet ou sous objet a la fois dans la vue 3D getSelectionEx()#############################################\n            selectionObjects = FreeCADGui.Selection.getSelectionEx()                                                          # Select an object or sub object getSelectionEx\n            for selection in selectionObjects:                                                                                #\n                for selectedEdge in selection.SubObjects:                                                                     #\n                    if cutLine != 0:                                                                                          # cut line to x parts\n                        points = selectedEdge.Edges[0].discretize(int(cutLine+1))                                             # Dicretize\n                        createLines(len(points), points, createLine, createPoints)\n                    else:                                                                                                     # cut line to x length\n                        longueur = (selectedEdge.Length) * precision\n                        numberOfPoints = (longueur + 1)\n                        points = selectedEdge.Edges[0].discretize(int(numberOfPoints))                                        # Dicretize\n                        compt = 0\n                        points2 += [points[0]]\n                        for ii2 in range(len(points)):\n                            try:\n                                compt += int(cutLength)\n                                points2 += [points[compt]]\n                            except Exception:\n                                points2 += [points[-1]]\n                                points2[-1] = points[-1]\n                                break\n                        createLines(len(points2), points2, createLine, createPoints)\n\n                    points[:]  = []\n                    points2[:] = []\n   \n            points[:]  = []\n            points2[:] = []\n    \n            #App.ActiveDocument.ActiveObject.recompute()\n            App.ActiveDocument.recompute()\n\n        except Exception:\n            FreeCAD.Console.PrintError(\"can not create\"+\"\\n\")\n            emergency = 1\n    else:\n        FreeCAD.Console.PrintError(\"Zero not permitted\"+\"\\n\")\n        emergency = 1\n\n########################################################################################################################\n \n########################################################################################################################\n\ndef handLine(LengthA = 150, HeightB = 2.0, WaveC = 40.0, compLine = 0, red = 0, green = 0, blue = 0, plane = 1, lineWidth = 2.0, pSize = 2.0):\n\n    global emergency\n    def colorize():\n        FreeCADGui.activeDocument().activeObject().LineColor  = (float(red)/255,float(green)/255,float(blue)/255)\n        FreeCADGui.activeDocument().activeObject().PointColor = (float(red)/255,float(green)/255,float(blue)/255)\n        FreeCADGui.activeDocument().activeObject().ShapeColor = (float(red)/255,float(green)/255,float(blue)/255)\n        FreeCADGui.activeDocument().activeObject().LineWidth  = lineWidth\n        FreeCADGui.activeDocument().activeObject().PointSize  = pSize\n\n    if LengthA and HeightB and WaveC != 0:\n        try:    \n            points    = []; points[:]  = []\n            \n            coor_X   = 0.0\n            coor_Y   = 0.0\n            coor_Z   = 0.0\n            \n            X = 0.0\n            Y = 0.0\n            precision  = 10.0\n            \n            while X <= LengthA :\n                points += [FreeCAD.Vector(coor_X,coor_Y,coor_Z)]\n                X += (WaveC  / precision)\n                Y = sin(X * WaveC )\n                coor_X = X\n                coor_Y = Y * (HeightB /2)\n\n            zz = Draft.makeBSpline(points,closed=False)\n            colorize()\n            if plane == 1:                                                                                  # \"XY\"\n                zz.Placement = App.Placement(App.Vector(0,0,0), App.Rotation(0,0,0), App.Vector(0,0,0))\n                zz.Label = \" Hand_XY\" #zz.Name + \" Hand_XY\"\n                Gui.activeDocument().activeView().viewTop()\n            if plane == 2:                                                                                  # \"YZ\"\n                zz.Placement = App.Placement(App.Vector(0,0,0), App.Rotation(90,0,90), App.Vector(0,0,0))\n                zz.Label = \" Hand_YZ\" #zz.Name + \" Hand_YZ\"\n                Gui.activeDocument().activeView().viewRight()\n            if plane == 3:                                                                                  # \"XZ\"\n                zz.Placement = App.Placement(App.Vector(0,0,0), App.Rotation(0,0,90), App.Vector(0,0,0))\n                zz.Label = \" Hand_XZ\" #zz.Name + \" Hand_XZ\"\n                Gui.activeDocument().activeView().viewFront()\n            points[:]  = []\n\n            #App.ActiveDocument.ActiveObject.recompute()\n            App.ActiveDocument.recompute()\n\n        except Exception:\n            FreeCAD.Console.PrintError(\"can not create\"+\"\\n\")\n            emergency = 1\n    else:\n        FreeCAD.Console.PrintError(\"Zero not permitted\"+\"\\n\")\n        emergency = 1\n\n########################################################################################################################\n \n####################################################################################################################\n\ndef zigzagLine(NumberX = 10, BeginA = 2.0, DimensionB = 4.0, GapC = 10.0, HeightD = 2.0, NumberE = 1, compLine = 0, red = 0, green = 0, blue = 0, plane = 1, lineWidth = 2.0, pSize = 2.0):\n\n    global emergency\n    def colorize():\n        FreeCADGui.activeDocument().activeObject().LineColor  = (float(red)/255,float(green)/255,float(blue)/255)\n        FreeCADGui.activeDocument().activeObject().PointColor = (float(red)/255,float(green)/255,float(blue)/255)\n        FreeCADGui.activeDocument().activeObject().ShapeColor = (float(red)/255,float(green)/255,float(blue)/255)\n        FreeCADGui.activeDocument().activeObject().LineWidth  = lineWidth\n        FreeCADGui.activeDocument().activeObject().PointSize  = pSize\n\n    if DimensionB and GapC and HeightD and NumberE != 0:\n        points2   = []; points2[:] = []\n        points    = []; points[:]  = []\n\n        Longueur = (BeginA * 2) + ((NumberX * (DimensionB + (GapC * NumberE))) - DimensionB)\n        ZigZag = Draft.makeWire([FreeCAD.Vector(0.0,0.0,0.0),FreeCAD.Vector(Longueur,0.0,0.0)],closed=False,face=False,support=None)\n        App.ActiveDocument.ActiveObject.recompute()\n    \n        precision  = 100.0                                                      # permet 2 decimales = 0.01\n        BeginA     = BeginA     * precision\n        DimensionB = DimensionB * precision\n        GapC       = GapC       * precision\n\n        try:\n            Longueur *=  precision\n            points = ZigZag.Shape.copy().discretize(int(Longueur))            # Dicretize points base\n            App.ActiveDocument.removeObject(ZigZag.Name)                      # remove line to base directrice\n    \n            compt = 0                                                         # compt points\n            points2 += [points[compt]]                                        # \n            compt = int(BeginA)\n            points2 += [points[compt]]\n    \n            for ii2 in range(int(NumberX)):\n                try:\n                    for i in range(NumberE):\n                        x0 = points[compt][0]+((GapC/precision)*0.25)\n                        y0 = points[compt][1]+HeightD\n                        z0 = 0.0\n                        points2 += [FreeCAD.Vector(x0,y0,z0)]\n    \n                        x0 = points[compt][0]+((GapC/precision)*0.75)\n                        y0 = points[compt][1]-HeightD\n                        z0 = 0.0\n                        points2 += [FreeCAD.Vector(x0,y0,z0)]\n                        compt += int(GapC)\n    \n                    points2 += [points[compt]]\n                    compt   += int(DimensionB)\n                    points2 += [points[compt]]\n                except Exception:\n                    None\n            points2 += [points[-1]]\n            zz = Draft.makeWire(points2,closed=False,face=False,support=None)\n            colorize()\n    \n            if plane == 1:                                                                                  # Placement \"XY\"\n                zz.Placement = App.Placement(App.Vector(0,0,0), App.Rotation(0,0,0), App.Vector(0,0,0))\n                zz.Label = \" ZigZag_XY\" #zz.Name + \" ZigZag_XY\"\n                Gui.activeDocument().activeView().viewTop()\n            if plane == 2:                                                                                  # Placement \"YZ\"\n                zz.Placement = App.Placement(App.Vector(0,0,0), App.Rotation(90,0,90), App.Vector(0,0,0))\n                zz.Label = \" ZigZag_YZ\" #zz.Name + \" ZigZag_YZ\"\n                Gui.activeDocument().activeView().viewRight()\n            if plane == 3:                                                                                  # Placement \"XZ\"\n                zz.Placement = App.Placement(App.Vector(0,0,0), App.Rotation(0,0,90), App.Vector(0,0,0))\n                zz.Label = \" ZigZag_XZ\" #zz.Name + \" ZigZag_XZ\"\n                Gui.activeDocument().activeView().viewFront()\n            points[:]  = []\n            points2[:] = []\n    \n            #App.ActiveDocument.ActiveObject.recompute()\n            App.ActiveDocument.recompute()\n\n        except Exception:\n            FreeCAD.Console.PrintError(\"Can not create\"+\"\\n\")\n            emergency = 1\n    else:\n        FreeCAD.Console.PrintError(\"Zero not permitted\"+\"\\n\")\n        emergency = 1\n\n########################################################################################################################\n\n####################################################################################################################\ndef dashLine(dash001 = 2.0, space001 = 1.0, dash002 = 1.0, space002 = 1.0, compLine = 0, red = 0, green = 0, blue = 0, typeLine = 1, lineWidth = 2.0, pSize = 2.0):\n                                                                                              # typeLine = 1 \"_ _ _ _ _ _ _ _ _ \"  dash         (dash001, space001)\n                                                                                              # typeLine = 2 \"___ _ ___ _ ___ _ \"  dash dot     (dash001, space001, dash002, space002)\n                                                                                              # typeLine = 3 \"___ _ _ ___ _ _ ___\" dash dot dot (dash001, space001, dash002, space002)\n    global emergency\n    def createLines(numberOfPoints, points):\n        space = 0\n        for lin in range(numberOfPoints-1):\n            if space == 0:\n                creaLine = [FreeCAD.Vector(points[lin]),FreeCAD.Vector(points[lin+1])]\n                if str(creaLine[0]) != str(creaLine[1]):\n                    wire = Draft.makeWire(creaLine,closed=False,face=False,support=None)# lines\n                else:\n                    wire = Draft.makePoint(FreeCAD.Vector(points[lin+1]))               # end line = point\n                App.ActiveDocument.ActiveObject.recompute()\n                space = 1\n                ligne.append(wire.Shape)                                      # for compount \n                nom.append(wire.Name)                                         # for compount\n            else:\n                space = 0\n            # si pas possible affiche cette ligne (ajoute recompute() pour corriger)# Cannot compute Inventor representation for the shape of Shape. \n\n    def colorize():\n        FreeCADGui.activeDocument().activeObject().LineColor  = (float(red)/255,float(green)/255,float(blue)/255)\n        FreeCADGui.activeDocument().activeObject().PointColor = (float(red)/255,float(green)/255,float(blue)/255)\n        FreeCADGui.activeDocument().activeObject().ShapeColor = (float(red)/255,float(green)/255,float(blue)/255)\n        FreeCADGui.activeDocument().activeObject().LineWidth  = lineWidth\n        FreeCADGui.activeDocument().activeObject().PointSize  = pSize\n\n    if dash001 and space001 and dash002 and space002 != 0:\n        nom       = []; nom[:]     = []\n        ligne     = []; ligne[:]   = []\n        comp2     = []; comp2[:]   = []\n        points    = []; points[:]  = []\n        points2   = []; points2[:] = []\n    \n        precision = 1000.0                                                      # permet 3 decimales = 0.001\n        dash001    = dash001  * precision\n        space001   = space001 * precision\n        dash002    = dash002  * precision\n        space002   = space002 * precision\n    \n        try:\n    #######Selectionne un ou des objets vue 3D ou vue combinnee (subObjects complete) getSelection()############################\n    #            compt_Oject = -1                                                                                              #\n    #            selectionObjects = FreeCADGui.Selection.getSelection()                                                        # Select an object or primitive getSelection()\n    #            for selection in enumerate(selectionObjects):                                                                 #\n    #                compt_Oject += 1                                                                                          #\n    #                compt_Edges = -1                                                                                          #\n    #                for selectedEdge in enumerate(selectionObjects[compt_Oject].Shape.Edges):                                 # Search the \"Edges\" and their lengths\n    #                    dash01 = dash001; space01 = space001; dash02 = dash002; space02 = space002                            #\n    #                    compt_Edges += 1                                                                                      #\n    #                    longueur = (selectionObjects[compt_Oject].Shape.Edges[compt_Edges].Length) * precision                #\n    #                    if (dash01 + space01 + dash02 + space02) >= longueur:                                                 #\n    #                        dash01    = int(longueur / 6)                                                                     # altenate solution\n    #                        space01   = int(longueur / 6)                                                                     # altenate solution\n    #                        dash02    = int(longueur / 6)                                                                     # altenate solution\n    #                        space02   = int(longueur / 6)                                                                     # altenate solution\n    #                        FreeCAD.Console.PrintError(\"Alernate Dash\"+\"\\n\")                                                  # altenate solution\n    #                    numberOfPoints = (longueur + 1)                                                                       #\n    #                    points = selectionObjects[compt_Oject].Shape.Edges[compt_Edges].discretize(int(numberOfPoints))       # Dicretize\n    ############################################################################################################################\n    #####selection 1 objet ou sous objet a la fois dans la vue 3D getSelectionEx()#############################################\n            selectionObjects = FreeCADGui.Selection.getSelectionEx()                                                      # Select an object or sub object getSelectionEx\n            for selection in selectionObjects:                                                                            #\n    #            compEdge = 0                                                                                              # compt affichage nom\n                for selectedEdge in selection.SubObjects:                                                                 #\n                    dash01 = dash001; space01 = space001; dash02 = dash002; space02 = space002                            #\n                    longueur = (selectedEdge.Length) * precision                                                          #\n                    if (dash01 + space01 + dash02 + space02) >= longueur:                                                 # altenate solution\n                        dash01    = int(longueur / 6)                                                                     # altenate solution\n                        space01   = int(longueur / 6)                                                                     # altenate solution\n                        dash02    = int(longueur / 6)                                                                     # altenate solution\n                        space02   = int(longueur / 6)                                                                     # altenate solution\n                        FreeCAD.Console.PrintError(\"Alernate Dash\"+\"\\n\")                                                  # altenate solution\n    #                    print selection.SubElementNames[compEdge]                                                         #\n    #                compEdge += 1                                                                                         #\n                    numberOfPoints = (longueur + 1)                                                                       #\n                    points = selectedEdge.Edges[0].discretize(int(numberOfPoints))                                        # Dicretize\n    ###########################################################################################################################\n            #######cut line in dashDot coordinates#########################################################################\n                    compt = 0\n                    points2 += [points[0]]\n\n                    for ii2 in range(len(points)):\n                        try:\n                            compt += int(dash01)                              # typeLine = 1 \"_ _ _ _ _ _ _ _ _ \"  dash   \n                            points2 += [points[compt]]\n                            compt += int(space01)\n                            points2 += [points[compt]]\n                            if typeLine > 1:                                  # typeLine = 2 \"___ _ ___ _ ___ _ \"  dash dot\n                                compt += int(dash02)                          #              \"___ _  ___ _  ___ \"\n                                points2 += [points[compt]]\n                                if typeLine == 2:\n                                    compt += int(space02)\n                                else:\n                                    compt += int(space01)\n                                points2 += [points[compt]]\n                                if typeLine > 2:                              # typeLine = 3 \"___ _ _ ___ _ _ ___\" dash dot dot\n                                    compt += int(dash02)\n                                    points2 += [points[compt]]\n                                    compt += int(space01)\n                                    points2 += [points[compt]]\n                        except Exception:\n                            points2 += [points[-1]]\n                            points2[-1] = points[-1]\n                            break\n    \n                    createLines(len(points2), points2)\n            #######cut line in dash coordinates##############################################################################\n        \n                    if compLine == 0:\n                        comp = Part.makeCompound(ligne)                       # si compount ligne separee\n                        Part.show(comp)                                       # si compount ligne separee\n                    else:\n                        comp2 += ligne\n\n                    if typeLine == 1:\n                        App.ActiveDocument.ActiveObject.Label = \"Line_Dash\"\n                    elif typeLine == 2:\n                        App.ActiveDocument.ActiveObject.Label = \"Line_Dash_D\"\n                    elif typeLine == 3:\n                        App.ActiveDocument.ActiveObject.Label = \"Line_Dash_DD\"\n\n                    colorize()\n                    ligne[:]  = []                                            # si compount ligne separee\n    \n                    points[:]  = []\n                    points2[:] = []\n        \n            for i in nom:\n                FreeCAD.ActiveDocument.removeObject(i)\n        \n            if compLine != 0:                                                 # 1 = toutes les selections en un compount\n                comp = Part.makeCompound(comp2)                               # si compount ensemble complet\n                Part.show(comp)                                               # si compount ensemble complet\n                colorize()\n\n                if typeLine == 1:\n                    App.ActiveDocument.ActiveObject.Label = \"Line_Dash_C\"\n                elif typeLine == 2:\n                    App.ActiveDocument.ActiveObject.Label = \"Line_Dash_D_C\"\n                elif typeLine == 3:\n                    App.ActiveDocument.ActiveObject.Label = \"Line_Dash_DD_C\"\n    \n            nom[:]     = []\n            ligne[:]   = []\n            comp2[:]   = []\n            points[:]  = []\n            points2[:] = []\n    \n            #App.ActiveDocument.ActiveObject.recompute()\n            App.ActiveDocument.recompute()\n\n        except Exception:\n            FreeCAD.Console.PrintError(\"can not create\"+\"\\n\")\n            emergency = 1\n    else:\n        FreeCAD.Console.PrintError(\"Zero not permitted\"+\"\\n\")\n        emergency = 1\n\n#####################################################################################################################\n        \nclass Ui_MainWindow(object):\n\n    def __init__(self):\n        #self.path = FreeCAD.ConfigGet(\"AppHomePath\")\n        #self.path = FreeCAD.ConfigGet(\"UserAppData\")\n        #self.path = \"your path\"\n        param = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")# macro path\n        self.path = param.GetString(\"MacroPath\",\"\") + \"/\"                   # macro path\n        self.path = self.path.replace(\"\\\\\",\"/\")\n\n        global emergency\n\n        self.NumberCut  = 2.0\n        self.LineA      = 2.0\n        self.SpaceB     = 0.5\n        self.Line2C     = 0.2\n        self.Space2D    = self.SpaceB\n        self.red        = 0\n        self.green      = 0\n        self.blue       = 0\n        self.NHeadsX    = 20\n        self.BeginA     = 2.0\n        self.DimensionB = 4.0\n        self.GapC       = 3.0\n        self.HeightD    = 2.0\n        self.NumberE    = 1\n        self.Compound   = 0\n        self.lineWidth  = 2.0\n        self.pointSize  = 2.0\n        self.Plan       = 1\n        self.LengthA    = 150\n        self.HeightB    = 2.0\n        self.WaveC      = 40.0\n        self.NameType   = \"Name of type\"\n        self.fontGlobal_08 = \"\"                       # pour compatibilite Windows Linux pour tous les textes\n\n    def setupUi(self, MainWindow):\n        self.window = MainWindow\n\n        MainWindow.setObjectName(_fromUtf8(\"MainWindow\"))\n        MainWindow.resize(363, 621)\n        MainWindow.setMinimumSize(QtCore.QSize(363, 621))\n        MainWindow.setMaximumSize(QtCore.QSize(363, 621))\n        MainWindow.setToolTip(_fromUtf8(\"\"))\n        self.centralwidget = QtGui.QWidget(MainWindow)\n        self.centralwidget.setObjectName(_fromUtf8(\"centralwidget\"))\n\n        self.fontGlobal_08 = QtGui.QFont()            # pour compatibilite Windows Linux pour tous les textes\n        self.fontGlobal_08.setFamily(\"Arial\")         # pour compatibilite Windows Linux pour tous les textes\n        self.fontGlobal_08.setPointSize(8.0)          # pour compatibilite Windows Linux pour tous les textes\n\n        self.PB_01_Save = QtGui.QPushButton(self.centralwidget)\n        self.PB_01_Save.setGeometry(QtCore.QRect(10, 560, 73, 23))\n        self.PB_01_Save.setFont(self.fontGlobal_08)\n        self.PB_01_Save.setToolTip(_fromUtf8(\"Save the configuration in file with extension .FCConvert\"))\n        self.PB_01_Save.setObjectName(_fromUtf8(\"PB_01_Save\"))\n        self.PB_01_Save.clicked.connect(self.on_PB_01_Save)                    # \n\n        self.PB_02_Load = QtGui.QPushButton(self.centralwidget)\n        self.PB_02_Load.setGeometry(QtCore.QRect(100, 560, 73, 23))\n        self.PB_02_Load.setFont(self.fontGlobal_08)\n        self.PB_02_Load.setToolTip(_fromUtf8(\"Load the file configuration\"))\n        self.PB_02_Load.setObjectName(_fromUtf8(\"PB_02_Load\"))\n        self.PB_02_Load.clicked.connect(self.on_PB_02_Load)                    # \n\n        self.LE_01_LineType = QtGui.QLineEdit(self.centralwidget)\n        self.LE_01_LineType.setGeometry(QtCore.QRect(190, 560, 161, 23))\n        self.LE_01_LineType.setFont(self.fontGlobal_08)\n        self.LE_01_LineType.setObjectName(_fromUtf8(\"LE_01_LineType\"))\n        self.LE_01_LineType.setToolTip(\"Give the name of type line created\"+\"\\n\"+\n                                       \"This information is saved in the file\")\n#        self.LE_01_LineType.setText(QtGui.QApplication.translate(\"Form\", \"Name type line\", None, QtGui.QApplication.UnicodeUTF8))\n        #self.LE_01_LineType.returnPressed.connect(self.on_lineEdit_1_Pressed)                  # connect on def \"on_lineEdit_1_Pressed\" for execute actionn   # for validate the data with press on return touch\n        self.LE_01_LineType.textChanged.connect(self.on_LE_01_LineType_Pressed)                 # connect on def \"on_lineEdit_1_Pressed\" for execute actionn   # with tips key char by char\n\n        self.PB_04_CreateComp = QtGui.QPushButton(self.centralwidget)\n        self.PB_04_CreateComp.setGeometry(QtCore.QRect(100, 590, 73, 23))\n        self.PB_04_CreateComp.setFont(self.fontGlobal_08)\n        self.PB_04_CreateComp.setToolTip(_fromUtf8(\"Create the lines and create the compound.\"+\"\\n\"+\n                                                   \"Not for Cut Lines, Ziqzag and Hand\"))\n        self.PB_04_CreateComp.setEnabled(False)\n        self.PB_04_CreateComp.setObjectName(_fromUtf8(\"PB_04_CreateComp\"))\n        self.PB_04_CreateComp.clicked.connect(self.on_PB_04_CreateComp)        # \n     \n        self.PB_05_Create = QtGui.QPushButton(self.centralwidget)\n        self.PB_05_Create.setGeometry(QtCore.QRect(190, 590, 73, 23))\n        self.PB_05_Create.setFont(self.fontGlobal_08)\n        self.PB_05_Create.setToolTip(_fromUtf8(\"Create the lines\"))\n        self.PB_05_Create.setObjectName(_fromUtf8(\"PB_05_Create\"))\n        self.PB_05_Create.clicked.connect(self.on_PB_05_Create)                # \n\n        self.PB_03_Reset = QtGui.QPushButton(self.centralwidget)\n        self.PB_03_Reset.setGeometry(QtCore.QRect(10, 590, 73, 23))\n        self.PB_03_Reset.setFont(self.fontGlobal_08)\n        self.PB_03_Reset.setToolTip(_fromUtf8(\"Reset the macro in the defaut values\"))\n        self.PB_03_Reset.setObjectName(_fromUtf8(\"PB_03_Reset\"))\n        self.PB_03_Reset.clicked.connect(self.on_PB_03_Reset)                  # \n\n        self.PB_06_Quit = QtGui.QPushButton(self.centralwidget)\n        self.PB_06_Quit.setGeometry(QtCore.QRect(280, 590, 73, 23))\n        self.PB_06_Quit.setFont(self.fontGlobal_08)\n        self.PB_06_Quit.setToolTip(_fromUtf8(\"Quit the macro and goodbye\"))\n        self.PB_06_Quit.setObjectName(_fromUtf8(\"PB_06_Quit\"))\n        self.PB_06_Quit.clicked.connect(self.on_PB_06_Quit)                    # \n\n        self.groupBox_00_CutLine = QtGui.QGroupBox(self.centralwidget)\n        self.groupBox_00_CutLine.setGeometry(QtCore.QRect(10, 30, 341, 51))\n        self.groupBox_00_CutLine.setFont(self.fontGlobal_08)\n        self.groupBox_00_CutLine.setCheckable(True)\n        self.groupBox_00_CutLine.setToolTip(_fromUtf8(\"Cut line in x parts if this checkBox is checked five types of lines can be selected\"))\n        self.groupBox_00_CutLine.setObjectName(_fromUtf8(\"groupBox_00_CutLine\"))\n        self.groupBox_00_CutLine.clicked.connect(self.on_groupBox_00_CutLine)                  #connection checkBox\n\n        self.DS_01_NumberCut = QtGui.QDoubleSpinBox(self.centralwidget)\n        self.DS_01_NumberCut.setGeometry(QtCore.QRect(20, 49, 81, 22))\n        self.DS_01_NumberCut.setFont(self.fontGlobal_08)\n        self.DS_01_NumberCut.setObjectName(_fromUtf8(\"DS_01_NumberCut\"))\n        self.DS_01_NumberCut.setSingleStep(1)\n        self.DS_01_NumberCut.setMaximum(9999999)\n        self.DS_01_NumberCut.setMinimum(1)\n        self.DS_01_NumberCut.setDecimals(0)\n        self.DS_01_NumberCut.setSuffix(_fromUtf8(\" Cut\"))\n        self.DS_01_NumberCut.setValue(self.NumberCut)\n        self.DS_01_NumberCut.setToolTip(_fromUtf8(\"Select one or more line(s) in the 3D view enter the desired number of cut (The suffix is Cut)\"+\"\\n\"+\n                                                  \"If Dimension is checked one length is input (The suffix is Dim)\"))\n        self.DS_01_NumberCut.valueChanged.connect(self.on_DS_01_NumberCut_valueChanged)        #connect on def \"on_DS_00_01_NumberCut_valueChanged\"\n\n        self.label_00_01 = QtGui.QLabel(self.groupBox_00_CutLine)\n        self.label_00_01.setGeometry(QtCore.QRect(70, 20, 61, 16))\n        self.label_00_01.setFont(self.fontGlobal_08)\n        self.label_00_01.setToolTip(_fromUtf8(\"\"))\n        self.label_00_01.setObjectName(_fromUtf8(\"label_00_01\"))\n\n        self.CB_00_02_BiColor = QtGui.QCheckBox(self.groupBox_00_CutLine)\n        self.CB_00_02_BiColor.setGeometry(QtCore.QRect(231, 23, 61, 17))\n        self.CB_00_02_BiColor.setFont(self.fontGlobal_08)\n        self.CB_00_02_BiColor.setToolTip(_fromUtf8(\"If Bicolor is checked the line Cut or Dimension are colored in Red and White.\"+\"\\n\"+\n                                                   \"If this checkBox is not checked the color is the color selected in the button Color\"))\n        self.CB_00_02_BiColor.setChecked(True)\n        self.CB_00_02_BiColor.setObjectName(_fromUtf8(\"CB_00_02_BiColor\"))\n        self.CB_00_02_BiColor.clicked.connect(self.on_CB_00_02_BiColor_clicked)                # connect on def \"CB_00_01_Dimension\"\n\n        self.CB_00_03_CreatePoints = QtGui.QCheckBox(self.groupBox_00_CutLine)\n        self.CB_00_03_CreatePoints.setGeometry(QtCore.QRect(290, 23, 51, 17))\n        self.CB_00_03_CreatePoints.setFont(self.fontGlobal_08)\n        self.CB_00_03_CreatePoints.setToolTip(_fromUtf8(\"If Points is checked on point is created to the Cut or Dimension (Checked by defaut)\"))\n        self.CB_00_03_CreatePoints.setObjectName(_fromUtf8(\"CB_00_03_CreatePoints\"))\n        self.CB_00_03_CreatePoints.clicked.connect(self.on_CB_00_03_CreatePoints_clicked)      # connect on def \"CB_00_01_Dimension\"\n\n        self.CB_00_01_Dimension = QtGui.QCheckBox(self.groupBox_00_CutLine)\n        self.CB_00_01_Dimension.setGeometry(QtCore.QRect(164, 23, 71, 17))\n        self.CB_00_01_Dimension.setFont(self.fontGlobal_08)\n        self.CB_00_01_Dimension.setToolTip(_fromUtf8(\"If Dimension is not checked the number entered is the number of cut\"+\"\\n\"+\n                                                     \"If Dimension is checked the number entered is a length\"+\"\\n\"+\n                                                     \"The line is cut into given length.\"+\"\\n\"+\n                                                     \"If the dimension greater than the line the line is duplicated\"+\"\\n\"+\n                                                     \"If the line is greater than the Dimension a line will be created with the remaining length\"))\n        self.CB_00_01_Dimension.setObjectName(_fromUtf8(\"CB_00_01_Dimension\"))\n        self.CB_00_01_Dimension.clicked.connect(self.on_CB_00_01_Dimension_clicked)            # connect on def \"CB_00_01_Dimension\"\n\n        self.CB_00_00_CreateLine = QtGui.QCheckBox(self.groupBox_00_CutLine)\n        self.CB_00_00_CreateLine.setGeometry(QtCore.QRect(100, 23, 71, 17))\n        self.CB_00_00_CreateLine.setFont(self.fontGlobal_08)\n        self.CB_00_00_CreateLine.setToolTip(_fromUtf8(\"If Create line is checked the lines are created (Checked by defaut)\"))\n        self.CB_00_00_CreateLine.setChecked(True)\n        self.CB_00_00_CreateLine.setObjectName(_fromUtf8(\"CB_00_00_CreateLine\"))\n        self.CB_00_00_CreateLine.clicked.connect(self.on_CB_00_CB_00_00_CreateLine_clicked)    # connect on def \"CB_00_01_Dimension\"\n\n        self.groupBox_01_TypeLine = QtGui.QGroupBox(self.centralwidget)\n        self.groupBox_01_TypeLine.setEnabled(False)\n        self.groupBox_01_TypeLine.setGeometry(QtCore.QRect(10, 90, 341, 461))\n        self.groupBox_01_TypeLine.setFont(self.fontGlobal_08)\n        self.groupBox_01_TypeLine.setToolTip(_fromUtf8(\"\"))\n        self.groupBox_01_TypeLine.setTitle(_fromUtf8(\"Type line\"))\n        self.groupBox_01_TypeLine.setCheckable(False)\n        self.groupBox_01_TypeLine.setChecked(False)\n        self.groupBox_01_TypeLine.setObjectName(_fromUtf8(\"groupBox_01_TypeLine\"))\n\n        self.RB_01_01_Dash = QtGui.QRadioButton(self.groupBox_01_TypeLine)\n        self.RB_01_01_Dash.setGeometry(QtCore.QRect(10, 20, 51, 17))\n        self.RB_01_01_Dash.setFont(self.fontGlobal_08)\n        self.RB_01_01_Dash.setToolTip(_fromUtf8(\"The type line is Dash. Select one or more line(s) in the 3D view and create\"))\n        self.RB_01_01_Dash.setChecked(True)\n        self.RB_01_01_Dash.setObjectName(_fromUtf8(\"RB_01_01_Dash\"))\n        self.RB_01_01_Dash.clicked.connect(self.on_RB_01_01_Dash)                              #connection radioButton\n\n        self.RB_01_02_DashDot = QtGui.QRadioButton(self.groupBox_01_TypeLine)\n        self.RB_01_02_DashDot.setGeometry(QtCore.QRect(70, 20, 61, 17))\n        self.RB_01_02_DashDot.setFont(self.fontGlobal_08)\n        self.RB_01_02_DashDot.setToolTip(_fromUtf8(\"The type line is Dash Dot. Select one or more line(s) in the 3D view and create\"))\n        self.RB_01_02_DashDot.setObjectName(_fromUtf8(\"RB_01_02_DashDot\"))\n        self.RB_01_02_DashDot.clicked.connect(self.on_RB_01_02_DashDot)                        #connection radioButton\n\n        self.RB_01_03_DashDotDot = QtGui.QRadioButton(self.groupBox_01_TypeLine)\n        self.RB_01_03_DashDotDot.setGeometry(QtCore.QRect(140, 20, 81, 17))\n        self.RB_01_03_DashDotDot.setFont(self.fontGlobal_08)\n        self.RB_01_03_DashDotDot.setToolTip(_fromUtf8(\"The type line is Dash Dot Dot. Select one or more line(s) in the 3D view and create\"))\n        self.RB_01_03_DashDotDot.setObjectName(_fromUtf8(\"RB_01_03_DashDotDot\"))\n        self.RB_01_03_DashDotDot.clicked.connect(self.on_RB_01_03_DashDotDot)                  #connection radioButton\n\n        self.RB_01_04_ZigZag = QtGui.QRadioButton(self.groupBox_01_TypeLine)\n        self.RB_01_04_ZigZag.setGeometry(QtCore.QRect(220, 20, 61, 17))\n        self.RB_01_04_ZigZag.setFont(self.fontGlobal_08)\n        self.RB_01_04_ZigZag.setToolTip(_fromUtf8(\"The type line is ZigZag one line are created\"+\"\\n\"+\n                                                  \"Select the plane XY, YZ or ZX the length is calculate in real time\"))\n        self.RB_01_04_ZigZag.setObjectName(_fromUtf8(\"RB_01_04_ZigZag\"))\n        self.RB_01_04_ZigZag.clicked.connect(self.on_RB_01_04_ZigZag)                          #connection radioButton\n\n        self.RB_01_05_Hand = QtGui.QRadioButton(self.groupBox_01_TypeLine)\n        self.RB_01_05_Hand.setGeometry(QtCore.QRect(290, 20, 51, 17))\n        self.RB_01_05_Hand.setFont(self.fontGlobal_08)\n        self.RB_01_05_Hand.setToolTip(_fromUtf8(\"The type line is Hand one line aleatory are created\"+\"\\n\"+\n                                                \"Select the plane XY, YZ or ZX\"))\n        self.RB_01_05_Hand.setObjectName(_fromUtf8(\"RB_01_05_Hand\"))\n        self.RB_01_05_Hand.clicked.connect(self.on_RB_01_05_Hand)                              #connection radioButton\n\n        self.groupBox_02_01_DashDot = QtGui.QGroupBox(self.groupBox_01_TypeLine)\n        self.groupBox_02_01_DashDot.setGeometry(QtCore.QRect(10, 40, 321, 61))\n        self.groupBox_02_01_DashDot.setFont(self.fontGlobal_08)\n        self.groupBox_02_01_DashDot.setObjectName(_fromUtf8(\"groupBox_02_01_DashDot\"))\n\n        self.label_02_01_01_A = QtGui.QLabel(self.groupBox_02_01_DashDot)\n        self.label_02_01_01_A.setGeometry(QtCore.QRect(10, 10, 61, 16))\n        self.label_02_01_01_A.setFont(self.fontGlobal_08)\n        self.label_02_01_01_A.setToolTip(_fromUtf8(\"First line set\"))\n        self.label_02_01_01_A.setObjectName(_fromUtf8(\"label_02_01_01_A\"))\n\n        self.label_02_01_02_B = QtGui.QLabel(self.groupBox_02_01_DashDot)\n        self.label_02_01_02_B.setGeometry(QtCore.QRect(90, 10, 61, 16))\n        self.label_02_01_02_B.setFont(self.fontGlobal_08)\n        self.label_02_01_02_B.setToolTip(_fromUtf8(\"First space set\"))\n        self.label_02_01_02_B.setObjectName(_fromUtf8(\"label_02_01_02_B\"))\n\n        self.label_02_01_03_C = QtGui.QLabel(self.groupBox_02_01_DashDot)\n        self.label_02_01_03_C.setGeometry(QtCore.QRect(170, 10, 61, 16))\n        self.label_02_01_03_C.setFont(self.fontGlobal_08)\n        self.label_02_01_03_C.setToolTip(_fromUtf8(\"Second line set\"))\n        self.label_02_01_03_C.setObjectName(_fromUtf8(\"label_02_01_03_C\"))\n\n        self.label_02_01_04_D = QtGui.QLabel(self.groupBox_02_01_DashDot)\n        self.label_02_01_04_D.setGeometry(QtCore.QRect(250, 10, 61, 16))\n        self.label_02_01_04_D.setFont(self.fontGlobal_08)\n        self.label_02_01_04_D.setToolTip(_fromUtf8(\"Second space set\"))\n        self.label_02_01_04_D.setObjectName(_fromUtf8(\"label_02_01_04_D\"))\n\n        self.DS_02_01_01_LineA = QtGui.QDoubleSpinBox(self.groupBox_02_01_DashDot)\n        self.DS_02_01_01_LineA.setGeometry(QtCore.QRect(10, 30, 62, 22))\n        self.DS_02_01_01_LineA.setFont(self.fontGlobal_08)\n        self.DS_02_01_01_LineA.setToolTip(_fromUtf8(\"First line set\"))\n        self.DS_02_01_01_LineA.setMaximum(999999.999999)\n        self.DS_02_01_01_LineA.setValue(self.LineA)\n        self.DS_02_01_01_LineA.setObjectName(_fromUtf8(\"DS_02_01_01_LineA\"))\n        self.DS_02_01_01_LineA.valueChanged.connect(self.on_DS_02_01_01_LineA_valueChanged)     # connect on def \"on_DS_02_01_01_LineA_valueChanged\"\n\n        self.DS_02_01_02_SpaceB = QtGui.QDoubleSpinBox(self.groupBox_02_01_DashDot)\n        self.DS_02_01_02_SpaceB.setGeometry(QtCore.QRect(90, 30, 62, 22))\n        self.DS_02_01_02_SpaceB.setFont(self.fontGlobal_08)\n        self.DS_02_01_02_SpaceB.setToolTip(_fromUtf8(\"First space set\"))\n        self.DS_02_01_02_SpaceB.setMaximum(999999.999999)\n        self.DS_02_01_02_SpaceB.setValue(self.SpaceB)\n        self.DS_02_01_02_SpaceB.setObjectName(_fromUtf8(\"DS_02_01_02_SpaceB\"))\n        self.DS_02_01_02_SpaceB.valueChanged.connect(self.on_DS_02_01_02_SpaceB_valueChanged)   # connect on def \"on_DS_02_01_02_SpaceB_valueChanged\"\n\n        self.DS_02_01_03_Line2C = QtGui.QDoubleSpinBox(self.groupBox_02_01_DashDot)\n        self.DS_02_01_03_Line2C.setGeometry(QtCore.QRect(170, 30, 62, 22))\n        self.DS_02_01_03_Line2C.setFont(self.fontGlobal_08)\n        self.DS_02_01_03_Line2C.setToolTip(_fromUtf8(\"Second line set\"))\n        self.DS_02_01_03_Line2C.setMaximum(999999.999999)\n        self.DS_02_01_03_Line2C.setValue(self.Line2C)\n        self.DS_02_01_03_Line2C.setObjectName(_fromUtf8(\"DS_02_01_03_Line2C\"))\n        self.DS_02_01_03_Line2C.valueChanged.connect(self.on_DS_02_01_03_Line2C_valueChanged)   # connect on def \"on_DS_02_01_03_Line2C_valueChanged\"\n\n        self.DS_02_01_04_Space2D = QtGui.QDoubleSpinBox(self.groupBox_02_01_DashDot)\n        self.DS_02_01_04_Space2D.setGeometry(QtCore.QRect(250, 30, 62, 22))\n        self.DS_02_01_04_Space2D.setFont(self.fontGlobal_08)\n        self.DS_02_01_04_Space2D.setToolTip(_fromUtf8(\"Second space set\"))\n        self.DS_02_01_04_Space2D.setMaximum(999999.999999)\n        self.DS_02_01_04_Space2D.setValue(self.Space2D)\n        self.DS_02_01_04_Space2D.setObjectName(_fromUtf8(\"DS_02_01_04_Space2D\"))\n        self.DS_02_01_04_Space2D.valueChanged.connect(self.on_DS_02_01_04_Space2D_valueChanged) # connect on def \"on_DS_02_01_04_Space2D_valueChanged\"\n\n        self.groupBox_02_02_ZigZag = QtGui.QGroupBox(self.groupBox_01_TypeLine)\n        self.groupBox_02_02_ZigZag.setGeometry(QtCore.QRect(10, 110, 321, 101))\n        self.groupBox_02_02_ZigZag.setFont(self.fontGlobal_08)\n        self.groupBox_02_02_ZigZag.setObjectName(_fromUtf8(\"groupBox_02_02_ZigZag\"))\n\n        self.label_02_02_Length = QtGui.QLabel(self.groupBox_02_02_ZigZag)\n        self.label_02_02_Length.setGeometry(QtCore.QRect(200, 20, 110, 20))\n        self.label_02_02_Length.setFont(self.fontGlobal_08)\n        self.label_02_02_Length.setFrameShape(QtGui.QFrame.Box)\n        self.label_02_02_Length.setLineWidth(2)\n        self.label_02_02_Length.setAlignment(QtCore.Qt.AlignCenter)\n        self.label_02_02_Length.setToolTip(_fromUtf8(\"For the ZigZag the length is calculate in real time\"+\"\\n\"+\n                                                     \"and displayed in this window\"))\n        self.label_02_02_Length.setIndent(0)\n        self.label_02_02_Length.setObjectName(_fromUtf8(\"label_02_02_Length\"))\n        self.label_02_02_Length.setText(str((self.BeginA * 2) + ((self.NHeadsX * (self.DimensionB + (self.GapC * self.NumberE))) - self.DimensionB)))\n\n        self.label_02_02_0X = QtGui.QLabel(self.groupBox_02_02_ZigZag)\n        self.label_02_02_0X.setGeometry(QtCore.QRect(70, 20, 91, 16))\n        self.label_02_02_0X.setFont(self.fontGlobal_08)\n        self.label_02_02_0X.setToolTip(_fromUtf8(\"Number of heads in the line (a head is a crown)\"))\n        self.label_02_02_0X.setObjectName(_fromUtf8(\"label_02_02_0X\"))\n\n        self.label_02_02_01_A = QtGui.QLabel(self.groupBox_02_02_ZigZag)\n        self.label_02_02_01_A.setGeometry(QtCore.QRect(10, 50, 46, 13))\n        self.label_02_02_01_A.setFont(self.fontGlobal_08)\n        self.label_02_02_01_A.setToolTip(_fromUtf8(\"First and latest section of the line\"))\n        self.label_02_02_01_A.setObjectName(_fromUtf8(\"label_02_02_01_A\"))\n\n        self.label_02_02_02_B = QtGui.QLabel(self.groupBox_02_02_ZigZag)\n        self.label_02_02_02_B.setGeometry(QtCore.QRect(70, 50, 61, 16))\n        self.label_02_02_02_B.setFont(self.fontGlobal_08)\n        self.label_02_02_02_B.setToolTip(_fromUtf8(\"Dimension betwen two heads\"))\n        self.label_02_02_02_B.setObjectName(_fromUtf8(\"label_02_02_02_B\"))\n\n        self.label_02_02_03_C = QtGui.QLabel(self.groupBox_02_02_ZigZag)\n        self.label_02_02_03_C.setGeometry(QtCore.QRect(140, 50, 61, 16))\n        self.label_02_02_03_C.setFont(self.fontGlobal_08)\n        self.label_02_02_03_C.setToolTip(_fromUtf8(\"Gap of the head\"))\n        self.label_02_02_03_C.setObjectName(_fromUtf8(\"label_02_02_03_C\"))\n\n        self.label_02_02_04_D = QtGui.QLabel(self.groupBox_02_02_ZigZag)\n        self.label_02_02_04_D.setGeometry(QtCore.QRect(200, 50, 61, 16))\n        self.label_02_02_04_D.setFont(self.fontGlobal_08)\n        self.label_02_02_04_D.setToolTip(_fromUtf8(\"Head height\"))\n        self.label_02_02_04_D.setObjectName(_fromUtf8(\"label_02_02_04_D\"))\n\n        self.label_02_02_05_E = QtGui.QLabel(self.groupBox_02_02_ZigZag)\n        self.label_02_02_05_E.setGeometry(QtCore.QRect(260, 50, 61, 16))\n        self.label_02_02_05_E.setFont(self.fontGlobal_08)\n        self.label_02_02_05_E.setToolTip(_fromUtf8(\"Number of contiguous heads\"))\n        self.label_02_02_05_E.setObjectName(_fromUtf8(\"label_02_02_05_E\"))\n\n        self.SP_02_02_01_NHeadsX = QtGui.QSpinBox(self.groupBox_02_02_ZigZag)\n        self.SP_02_02_01_NHeadsX.setGeometry(QtCore.QRect(10, 20, 51, 22))\n        self.SP_02_02_01_NHeadsX.setFont(self.fontGlobal_08)\n        self.SP_02_02_01_NHeadsX.setToolTip(_fromUtf8(\"Number of heads in the line (a head is a crown)\"))\n        self.SP_02_02_01_NHeadsX.setMaximum(999999.999999)\n        self.SP_02_02_01_NHeadsX.setValue(self.NHeadsX)\n        self.SP_02_02_01_NHeadsX.setObjectName(_fromUtf8(\"SP_02_02_01_NHeadsX\"))\n        self.SP_02_02_01_NHeadsX.valueChanged.connect(self.on_SP_02_02_01_NHeadsX_valueChanged)     # connect on def \"SP_02_02_01_NHeadsX\"\n\n        self.DS_02_02_01_BeginA = QtGui.QDoubleSpinBox(self.groupBox_02_02_ZigZag)\n        self.DS_02_02_01_BeginA.setGeometry(QtCore.QRect(10, 70, 51, 22))\n        self.DS_02_02_01_BeginA.setFont(self.fontGlobal_08)\n        self.DS_02_02_01_BeginA.setToolTip(_fromUtf8(\"First and latest section of the line\"))\n        self.DS_02_02_01_BeginA.setMaximum(999999.999999)\n        self.DS_02_02_01_BeginA.setValue(self.BeginA)\n        self.DS_02_02_01_BeginA.setObjectName(_fromUtf8(\"DS_02_02_01_BeginA\"))\n        self.DS_02_02_01_BeginA.valueChanged.connect(self.on_DS_02_02_01_BeginA_valueChanged)       # connect on def \"DS_02_02_01_DimensionA\"\n\n        self.DS_02_02_02_DimensionB = QtGui.QDoubleSpinBox(self.groupBox_02_02_ZigZag)\n        self.DS_02_02_02_DimensionB.setGeometry(QtCore.QRect(70, 70, 61, 22))\n        self.DS_02_02_02_DimensionB.setFont(self.fontGlobal_08)\n        self.DS_02_02_02_DimensionB.setToolTip(_fromUtf8(\"Dimension betwen two heads\"))\n        self.DS_02_02_02_DimensionB.setMaximum(999999.999999)\n        self.DS_02_02_02_DimensionB.setValue(self.DimensionB)\n        self.DS_02_02_02_DimensionB.setObjectName(_fromUtf8(\"DS_02_02_02_DimensionB\"))\n        self.DS_02_02_02_DimensionB.valueChanged.connect(self.on_DS_02_02_02_DimensionB_valueChanged)     # connect on def \"DS_02_02_02_DimensionB\"\n\n        self.DS_02_02_03_GapC = QtGui.QDoubleSpinBox(self.groupBox_02_02_ZigZag)\n        self.DS_02_02_03_GapC.setGeometry(QtCore.QRect(140, 70, 51, 22))\n        self.DS_02_02_03_GapC.setFont(self.fontGlobal_08)\n        self.DS_02_02_03_GapC.setToolTip(_fromUtf8(\"Gap of the head\"))\n        self.DS_02_02_03_GapC.setMaximum(999999.999999)\n        self.DS_02_02_03_GapC.setValue(self.GapC)\n        self.DS_02_02_03_GapC.setObjectName(_fromUtf8(\"DS_02_02_03_GapC\"))\n        self.DS_02_02_03_GapC.valueChanged.connect(self.on_DS_02_02_03_GapC_valueChanged)      # connect on def \"on_DS_02_02_03_GapB_valueChanged\"\n\n        self.DS_02_02_04_HeightD = QtGui.QDoubleSpinBox(self.groupBox_02_02_ZigZag)\n        self.DS_02_02_04_HeightD.setGeometry(QtCore.QRect(200, 70, 51, 22))\n        self.DS_02_02_04_HeightD.setFont(self.fontGlobal_08)\n        self.DS_02_02_04_HeightD.setToolTip(_fromUtf8(\"Head height\"))\n        self.DS_02_02_04_HeightD.setMaximum(999999.999999)\n        self.DS_02_02_04_HeightD.setValue(self.HeightD)\n        self.DS_02_02_04_HeightD.setObjectName(_fromUtf8(\"DS_02_02_04_HeightD\"))\n        self.DS_02_02_04_HeightD.valueChanged.connect(self.on_DS_02_02_04_HeightD_valueChanged)# connect on def \"on_DS_02_02_02_HeightC_valueChanged\"\n\n        self.SP_02_02_05_NumberE = QtGui.QSpinBox(self.groupBox_02_02_ZigZag)\n        self.SP_02_02_05_NumberE.setGeometry(QtCore.QRect(260, 70, 51, 22))\n        self.SP_02_02_05_NumberE.setFont(self.fontGlobal_08)\n        self.SP_02_02_05_NumberE.setToolTip(_fromUtf8(\"Number of contiguous heads\"))\n        self.SP_02_02_05_NumberE.setMaximum(999999.999999)\n        self.SP_02_02_05_NumberE.setValue(self.NumberE)\n        self.SP_02_02_05_NumberE.setObjectName(_fromUtf8(\"SP_02_02_05_NumberE\"))\n        self.SP_02_02_05_NumberE.valueChanged.connect(self.on_SP_02_02_05_NumberE_valueChanged)# connect on def \"on_SP_02_02_04_NumberD_valueChanged\"\n\n        self.groupBox_02_03_Hand = QtGui.QGroupBox(self.groupBox_01_TypeLine)\n        self.groupBox_02_03_Hand.setGeometry(QtCore.QRect(10, 220, 211, 71))\n        self.groupBox_02_03_Hand.setFont(self.fontGlobal_08)\n        self.groupBox_02_03_Hand.setObjectName(_fromUtf8(\"groupBox_02_03_Hand\"))\n\n        self.label_02_03_01_A = QtGui.QLabel(self.groupBox_02_03_Hand)\n        self.label_02_03_01_A.setGeometry(QtCore.QRect(10, 20, 61, 16))\n        self.label_02_03_01_A.setFont(self.fontGlobal_08)\n        self.label_02_03_01_A.setToolTip(_fromUtf8(\"Length of complete line\"))\n        self.label_02_03_01_A.setObjectName(_fromUtf8(\"label_02_03_01_A\"))\n\n        self.label_02_03_02_B = QtGui.QLabel(self.groupBox_02_03_Hand)\n        self.label_02_03_02_B.setGeometry(QtCore.QRect(90, 20, 51, 16))\n        self.label_02_03_02_B.setFont(self.fontGlobal_08)\n        self.label_02_03_02_B.setToolTip(_fromUtf8(\"Heigth of the wave\"))\n        self.label_02_03_02_B.setObjectName(_fromUtf8(\"label_02_03_02_H\"))\n\n        self.label_02_03_03_C = QtGui.QLabel(self.groupBox_02_03_Hand)\n        self.label_02_03_03_C.setGeometry(QtCore.QRect(150, 20, 51, 16))\n        self.label_02_03_03_C.setFont(self.fontGlobal_08)\n        self.label_02_03_03_C.setToolTip(_fromUtf8(\"Length betwen two crown\"))\n        self.label_02_03_03_C.setObjectName(_fromUtf8(\"label_02_03_03_P\"))\n\n        self.DS_02_03_01_LengthA = QtGui.QDoubleSpinBox(self.groupBox_02_03_Hand)\n        self.DS_02_03_01_LengthA.setGeometry(QtCore.QRect(10, 40, 71, 22))\n        self.DS_02_03_01_LengthA.setFont(self.fontGlobal_08)\n        self.DS_02_03_01_LengthA.setToolTip(_fromUtf8(\"Length of complete line\"))\n        self.DS_02_03_01_LengthA.setMaximum(999999.999999)\n        self.DS_02_03_01_LengthA.setValue(self.LengthA)\n        self.DS_02_03_01_LengthA.setObjectName(_fromUtf8(\"DS_02_03_01_LengthA\"))\n        self.DS_02_03_01_LengthA.valueChanged.connect(self.on_DS_02_03_01_LengthA_valueChanged)# connect on def \"on_DS_02_03_01_LengthA_valueChanged\"\n\n        self.DS_02_03_02_HeightB = QtGui.QDoubleSpinBox(self.groupBox_02_03_Hand)\n        self.DS_02_03_02_HeightB.setGeometry(QtCore.QRect(90, 40, 51, 22))\n        self.DS_02_03_02_HeightB.setFont(self.fontGlobal_08)\n        self.DS_02_03_02_HeightB.setToolTip(_fromUtf8(\"Heigth of the wave\"))\n        self.DS_02_03_02_HeightB.setMaximum(999999.999999)\n        self.DS_02_03_02_HeightB.setValue(self.HeightB)\n        self.DS_02_03_02_HeightB.setObjectName(_fromUtf8(\"DS_02_03_02_HeightB\"))\n        self.DS_02_03_02_HeightB.valueChanged.connect(self.on_DS_02_03_02_HeightB_valueChanged)# connect on def \"on_DS_02_03_02_HeightB_valueChanged\"\n\n        self.DS_02_03_03_WaveC = QtGui.QDoubleSpinBox(self.groupBox_02_03_Hand)\n        self.DS_02_03_03_WaveC.setGeometry(QtCore.QRect(150, 40, 51, 22))\n        self.DS_02_03_03_WaveC.setFont(self.fontGlobal_08)\n        self.DS_02_03_03_WaveC.setToolTip(_fromUtf8(\"Length betwen two crown\"))\n        self.DS_02_03_03_WaveC.setMaximum(999999.999999)\n        self.DS_02_03_03_WaveC.setValue(self.WaveC)\n        self.DS_02_03_03_WaveC.setObjectName(_fromUtf8(\"DS_02_03_03_WaveC\"))\n        self.DS_02_03_03_WaveC.valueChanged.connect(self.on_DS_02_03_03_WaveC_valueChanged)     # connect on def \"on_DS_02_03_03_WaveC_valueChanged\"\n\n        self.groupBox_02_04_OptionsL = QtGui.QGroupBox(self.centralwidget)\n        self.groupBox_02_04_OptionsL.setGeometry(QtCore.QRect(240, 310, 101, 131))\n        self.groupBox_02_04_OptionsL.setFont(self.fontGlobal_08)\n        self.groupBox_02_04_OptionsL.setFlat(False)\n        self.groupBox_02_04_OptionsL.setObjectName(_fromUtf8(\"groupBox_02_04_OptionsL\"))\n\n        self.label_02_04_01 = QtGui.QLabel(self.groupBox_02_04_OptionsL)\n        self.label_02_04_01.setGeometry(QtCore.QRect(10, 20, 71, 16))\n        self.label_02_04_01.setFont(self.fontGlobal_08)\n        self.label_02_04_01.setToolTip(_fromUtf8(\"Line width\"))\n        self.label_02_04_01.setObjectName(_fromUtf8(\"label_02_04_01\"))\n\n        self.label_02_04_02 = QtGui.QLabel(self.groupBox_02_04_OptionsL)\n        self.label_02_04_02.setGeometry(QtCore.QRect(90, 20, 46, 13))\n        self.label_02_04_02.setFont(self.fontGlobal_08)\n        self.label_02_04_02.setToolTip(_fromUtf8(\"Points of line\"))\n        self.label_02_04_02.setObjectName(_fromUtf8(\"label_02_04_02\"))\n\n        self.DS_02_04_01_LineWidth = QtGui.QDoubleSpinBox(self.groupBox_02_04_OptionsL)\n        self.DS_02_04_01_LineWidth.setGeometry(QtCore.QRect(10, 20, 81, 22))\n        self.DS_02_04_01_LineWidth.setFont(self.fontGlobal_08)\n        self.DS_02_04_01_LineWidth.setToolTip(_fromUtf8(\"Line Width\"))\n        self.DS_02_04_01_LineWidth.setMaximum(999999.999999)\n        self.DS_02_04_01_LineWidth.setSingleStep(self.lineWidth)\n        self.DS_02_04_01_LineWidth.setValue(self.lineWidth)\n        self.DS_02_04_01_LineWidth.setSingleStep(1)\n        self.DS_02_04_01_LineWidth.setObjectName(_fromUtf8(\"DS_02_04_01_LineWidth\"))\n        self.DS_02_04_01_LineWidth.valueChanged.connect(self.on_DS_02_04_01_LineWidth)         # connect on def \"on_DS_02_04_01_LineWidth_valueChanged\"\n\n        self.DS_02_04_02_PSize = QtGui.QDoubleSpinBox(self.groupBox_02_04_OptionsL)\n        self.DS_02_04_02_PSize.setGeometry(QtCore.QRect(10, 50, 81, 22))\n        self.DS_02_04_02_PSize.setFont(self.fontGlobal_08)\n        self.DS_02_04_02_PSize.setToolTip(_fromUtf8(\"Points of line\"))\n        self.DS_02_04_02_PSize.setMaximum(999999.999999)\n        self.DS_02_04_02_PSize.setSingleStep(self.pointSize)\n        self.DS_02_04_02_PSize.setValue(self.pointSize)\n        self.DS_02_04_02_PSize.setSingleStep(1)\n        self.DS_02_04_02_PSize.setObjectName(_fromUtf8(\"DS_02_04_02_PSize\"))\n        self.DS_02_04_02_PSize.valueChanged.connect(self.on_DS_02_04_02_PSize)                 # connect on def \"on_DS_02_04_02_PSize\"\n\n        self.PB_02_04_03_Color = QtGui.QPushButton(self.groupBox_02_04_OptionsL)\n        self.PB_02_04_03_Color.setGeometry(QtCore.QRect(10, 90, 81, 31))\n        self.PB_02_04_03_Color.setFont(self.fontGlobal_08)\n        self.PB_02_04_03_Color.setToolTip(_fromUtf8(\"Color of line\"))\n        self.PB_02_04_03_Color.setObjectName(_fromUtf8(\"PB_02_04_03_Color\"))\n        self.PB_02_04_03_Color.clicked.connect(self.on_PB_02_04_03_Color)          # \n\n        self.groupBox_02_05_Plane = QtGui.QGroupBox(self.groupBox_01_TypeLine)\n        self.groupBox_02_05_Plane.setGeometry(QtCore.QRect(10, 300, 211, 51))\n        self.groupBox_02_05_Plane.setFont(self.fontGlobal_08)\n        self.groupBox_02_05_Plane.setEnabled(False)\n        self.groupBox_02_05_Plane.setObjectName(_fromUtf8(\"groupBox_02_05_Plane\"))\n\n        self.RB_02_05_01_XY = QtGui.QRadioButton(self.groupBox_02_05_Plane)\n        self.RB_02_05_01_XY.setGeometry(QtCore.QRect(10, 20, 41, 17))\n        self.RB_02_05_01_XY.setFont(self.fontGlobal_08)\n        self.RB_02_05_01_XY.setToolTip(_fromUtf8(\"Plans XY this function is used by ZigZag and Hand\"))\n        self.RB_02_05_01_XY.setChecked(True)\n        self.RB_02_05_01_XY.setObjectName(_fromUtf8(\"RB_02_05_01_XY\"))\n        self.RB_02_05_01_XY.clicked.connect(self.on_RB_02_05_01_XY)                            #connection radioButton\n\n        self.RB_02_05_02_YZ = QtGui.QRadioButton(self.groupBox_02_05_Plane)\n        self.RB_02_05_02_YZ.setGeometry(QtCore.QRect(60, 20, 41, 17))\n        self.RB_02_05_02_YZ.setFont(self.fontGlobal_08)\n        self.RB_02_05_02_YZ.setToolTip(_fromUtf8(\"Plans YZ this function is used by ZigZag and Hand\"))\n        self.RB_02_05_02_YZ.setObjectName(_fromUtf8(\"RB_02_05_02_YZ\"))\n        self.RB_02_05_02_YZ.clicked.connect(self.on_RB_02_05_02_YZ)                            #connection radioButton\n\n        self.RB_02_05_03_XY = QtGui.QRadioButton(self.groupBox_02_05_Plane)\n        self.RB_02_05_03_XY.setGeometry(QtCore.QRect(110, 20, 41, 17))\n        self.RB_02_05_03_XY.setFont(self.fontGlobal_08)\n        self.RB_02_05_03_XY.setToolTip(_fromUtf8(\"Plans XY this function is used by ZigZag and Hand\"))\n        self.RB_02_05_03_XY.setObjectName(_fromUtf8(\"RB_02_05_03_XY\"))\n        self.RB_02_05_03_XY.clicked.connect(self.on_RB_02_05_03_XY)                            #connection radioButton\n\n        ### ---graphicsView---02_View\n        self.graphicsView_2 = QtGui.QGraphicsView(self.groupBox_02_05_Plane)                   #Plane type view\n        if platform.system() == \"Windows\" :\n            self.graphicsView_2.setGeometry(QtCore.QRect(170, 12, 31, 31))                     # image = setGeometry - 2px\n        else:\n            self.graphicsView_2.setGeometry(QtCore.QRect(170, 12, 33, 33))                     # image = setGeometry\n        self.graphicsView_2.setFont(self.fontGlobal_08)\n        self.graphicsView_2.setObjectName(_fromUtf8(\"graphicsView_2\"))\n        pic = QtGui.QPixmap(self.path + \"Macro_FCConvrtLines_View-top.png\")\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView_2.setScene(ui.scene)\n        ### ---graphicsView---02_View\n\n        ### ---graphicsView---01_tableau\n        self.graphicsView = QtGui.QGraphicsView(self.groupBox_01_TypeLine)                     #Line type\n        if platform.system() == \"Windows\" :\n            self.graphicsView.setGeometry(QtCore.QRect(10, 360, 321, 91))                      # image = setGeometry - 2px\n        else:\n            self.graphicsView.setGeometry(QtCore.QRect(10, 360, 323, 93))                      # image = setGeometry\n        self.graphicsView.setFont(self.fontGlobal_08)\n        self.graphicsView.setFrameShape(QtGui.QFrame.StyledPanel)\n        self.graphicsView.setObjectName(_fromUtf8(\"graphicsView\"))\n        pic = QtGui.QPixmap(self.path + \"Macro_FCConvertLines_Title.png\")\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(ui.scene)\n        ### ---graphicsView---01_tableau\n\n        self.label_Title = QtGui.QLabel(self.centralwidget)\n        self.label_Title.setGeometry(QtCore.QRect(110, 10, 161, 20))\n        font = QtGui.QFont()\n        font.setPointSize(16)\n        font.setUnderline(True)\n        self.label_Title.setFont(font)\n        self.label_Title.setObjectName(_fromUtf8(\"label_Title\"))\n\n        MainWindow.setCentralWidget(self.centralwidget)\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n        MainWindow.setWindowTitle(__title__ + \" (\" + __version__ + \" : \" + __date__ + \")\")\n\n        self.PB_01_Save.setText(\"Save Type\")\n        self.PB_02_Load.setText(\"Load type\")\n        self.PB_03_Reset.setText(\"Reset\")\n        self.PB_04_CreateComp.setText(\"Create Comp\")\n        self.PB_05_Create.setText(\"Create\")\n        self.LE_01_LineType.setText(\"Name type line\")\n        self.PB_06_Quit.setText(\"Quit\")\n\n        self.RB_01_01_Dash.setText(\"Dash\")\n        self.RB_01_02_DashDot.setText(\"DashDot\")\n        self.RB_01_03_DashDotDot.setText(\"DashDotDot\")\n        self.RB_01_04_ZigZag.setText(\"Zigzags\")\n        self.RB_01_05_Hand.setText(\"Hand\")\n\n        self.groupBox_02_01_DashDot.setTitle(\"Dash ... ...\")\n        self.label_02_01_01_A.setText(\"Line  A\")\n        self.label_02_01_02_B.setText(\"Space  B\")\n        self.label_02_01_03_C.setText(\"Line 2  C\")\n        self.label_02_01_04_D.setText(\"Space 2  D\")\n\n        self.groupBox_02_02_ZigZag.setTitle(\"ZigZag\")\n        self.label_02_02_0X.setText(\"Number heads\")\n        self.label_02_02_01_A.setText(\"Begin  A\")\n        self.label_02_02_02_B.setText(\"Dimension B\")\n        self.label_02_02_03_C.setText(\"Gap C\")\n        self.label_02_02_04_D.setText(\"Height  D\")\n        self.label_02_02_05_E.setText(\"Number  E\")\n        self.label_02_02_Length.setText(str((self.BeginA * 2) + ((self.NHeadsX * (self.DimensionB + (self.GapC * self.NumberE))) - self.DimensionB)))\n\n        self.groupBox_02_03_Hand.setTitle(\"Hand\")\n        self.label_02_03_01_A.setText(\"Length  A\")\n        self.label_02_03_02_B.setText(\"Height  B\")\n        self.label_02_03_03_C.setText(\"Wave\")\n\n        self.groupBox_02_04_OptionsL.setTitle(\"Options line\")\n        self.DS_02_04_01_LineWidth.setSuffix(\"  Width\")\n        self.DS_02_04_02_PSize.setSuffix(\"  Point Size\")\n        self.PB_02_04_03_Color.setText(\"Color\")\n\n        self.label_Title.setText(\"FCConvert Lines\")\n\n        self.groupBox_02_05_Plane.setTitle(\"Plane\")\n        self.RB_02_05_01_XY.setText(\"XY\")\n        self.RB_02_05_02_YZ.setText(\"YZ\")\n        self.RB_02_05_03_XY.setText(\"XZ\")\n\n        self.groupBox_00_CutLine.setTitle(\"Cut Line\")\n        self.CB_00_00_CreateLine.setText(\"Create L.\")\n        self.CB_00_01_Dimension.setText(\"Dimension\")\n        self.CB_00_02_BiColor.setText(\"BiColor\")\n        self.CB_00_03_CreatePoints.setText(\"Points\")\n\n        MainWindow.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint)            # PySide cette fonction met la fen\u00eatre en avant\n\n    def on_groupBox_00_CutLine(self):                                               # \n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        if self.groupBox_00_CutLine.isChecked():\n            self.groupBox_01_TypeLine.setEnabled(False)\n            self.groupBox_02_05_Plane.setEnabled(False)\n\n            self.DS_01_NumberCut.setEnabled(True)\n            self.RB_01_01_Dash.setChecked(True)\n            self.PB_04_CreateComp.setEnabled(False)\n\n            pic = QtGui.QPixmap(self.path+\"Macro_FCConvertLines_Title.png\") \n            self.scene = QtGui.QGraphicsScene()\n            self.scene.addPixmap(QtGui.QPixmap(pic)) \n            self.graphicsView.setScene(ui.scene)\n        else:\n            self.groupBox_01_TypeLine.setEnabled(True)\n            self.groupBox_02_01_DashDot.setEnabled(True)\n\n            self.DS_01_NumberCut.setEnabled(False)\n            self.PB_04_CreateComp.setEnabled(True)\n            self.DS_02_01_03_Line2C.setEnabled(False)\n            self.DS_02_01_04_Space2D.setEnabled(False)\n            self.groupBox_02_02_ZigZag.setEnabled(False)\n            self.groupBox_02_03_Hand.setEnabled(False)\n\n            pic = QtGui.QPixmap(self.path+\"Macro_FCConvertLines_Dash.png\")\n            self.scene = QtGui.QGraphicsScene()\n            self.scene.addPixmap(QtGui.QPixmap(pic)) \n            self.graphicsView.setScene(ui.scene)\n#        FreeCAD.Console.PrintMessage(str(\"on_groupBox_00_CutLine \")+\"\\n\")\n\n    def on_DS_01_NumberCut_valueChanged(self,Value):\n        self.NumberCut = Value\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n#        FreeCAD.Console.PrintMessage(str(\"SP_01_NumberCut \")+str(self.NumberCut)+\"\\n\")\n\n    def on_CB_00_CB_00_00_CreateLine_clicked(self):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n#        FreeCAD.Console.PrintMessage(str(\"on_CB_00_CB_00_00_CreateLine_clicked\"+\"\\n\")\n\n    def on_CB_00_01_Dimension_clicked(self):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        if self.CB_00_01_Dimension.isChecked():            # Dimension\n            self.DS_01_NumberCut.setSingleStep(1)\n            self.DS_01_NumberCut.setMaximum(9999999.9999999)\n            self.DS_01_NumberCut.setMinimum(-9999999)\n            self.DS_01_NumberCut.setDecimals(3)\n            self.DS_01_NumberCut.setSuffix(_fromUtf8(\" Dim\"))\n            self.DS_01_NumberCut.setValue(self.NumberCut)\n            self.DS_01_NumberCut.setToolTip(_fromUtf8(\"Cut the line to length\"))\n        else:\n            self.DS_01_NumberCut.setSingleStep(1)          # Cut line\n            self.DS_01_NumberCut.setMaximum(9999999)\n            self.DS_01_NumberCut.setMinimum(1)\n            self.DS_01_NumberCut.setDecimals(0)\n            self.DS_01_NumberCut.setSuffix(_fromUtf8(\" Cut\"))\n            self.DS_01_NumberCut.setValue(self.NumberCut)\n            self.DS_01_NumberCut.setToolTip(_fromUtf8(\"Cut in x parts the selected line\"))\n#        FreeCAD.Console.PrintMessage(str(\"on_CB_00_01_Dimension_clicked \")+\"\\n\")\n\n    def on_CB_00_02_BiColor_clicked(self):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n#        FreeCAD.Console.PrintMessage(str(\"on_CB_00_03_CreatePoints_clicked \")+\"\\n\")\n\n    def on_CB_00_03_CreatePoints_clicked(self):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n#        FreeCAD.Console.PrintMessage(str(\"on_CB_00_03_CreatePoints_clicked \")+\"\\n\")\n\n    def on_RB_01_01_Dash(self):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.groupBox_02_01_DashDot.setEnabled(True)\n        self.groupBox_02_02_ZigZag.setEnabled(False)\n        self.groupBox_02_03_Hand.setEnabled(False)\n        self.DS_02_01_01_LineA.setEnabled(True)\n        self.DS_02_01_02_SpaceB.setEnabled(True)\n        self.DS_02_01_03_Line2C.setEnabled(False)\n        self.DS_02_01_04_Space2D.setEnabled(False)\n        self.groupBox_02_05_Plane.setEnabled(False)\n        self.PB_04_CreateComp.setEnabled(True)\n#        FreeCAD.Console.PrintMessage(str(\"on_RB_01_01_Dash \")+\"\\n\")\n\n        pic = QtGui.QPixmap(self.path+\"Macro_FCConvertLines_Dash.png\")\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic)) \n        self.graphicsView.setScene(ui.scene)\n\n    def on_RB_01_02_DashDot(self):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.groupBox_02_01_DashDot.setEnabled(True)\n        self.groupBox_02_02_ZigZag.setEnabled(False)\n        self.groupBox_02_03_Hand.setEnabled(False)\n        self.DS_02_01_01_LineA.setEnabled(True)\n        self.DS_02_01_02_SpaceB.setEnabled(True)\n        self.DS_02_01_03_Line2C.setEnabled(True)\n        self.DS_02_01_04_Space2D.setEnabled(True)\n        self.groupBox_02_05_Plane.setEnabled(False)\n        self.PB_04_CreateComp.setEnabled(True)\n#        FreeCAD.Console.PrintMessage(str(\"on_RB_01_02_DashDot \")+\"\\n\")\n\n        pic = QtGui.QPixmap(self.path+\"Macro_FCConvertLines_DashDot.png\")\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic)) \n        self.graphicsView.setScene(ui.scene)\n\n    def on_RB_01_03_DashDotDot(self):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.groupBox_02_01_DashDot.setEnabled(True)\n        self.groupBox_02_02_ZigZag.setEnabled(False)\n        self.groupBox_02_03_Hand.setEnabled(False)\n        self.DS_02_01_01_LineA.setEnabled(True)\n        self.DS_02_01_02_SpaceB.setEnabled(True)\n        self.DS_02_01_03_Line2C.setEnabled(True)\n        self.DS_02_01_04_Space2D.setEnabled(True)\n        self.groupBox_02_05_Plane.setEnabled(False)\n        self.PB_04_CreateComp.setEnabled(True)\n#        FreeCAD.Console.PrintMessage(str(\"on_RB_01_03_DashDotDot \")+\"\\n\")\n\n        pic = QtGui.QPixmap(self.path+\"Macro_FCConvertLines_DashDotDot.png\")\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic)) \n        self.graphicsView.setScene(ui.scene)\n\n    def on_RB_01_04_ZigZag(self):                               # \n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.groupBox_02_01_DashDot.setEnabled(False)\n        self.groupBox_02_02_ZigZag.setEnabled(True)\n        self.groupBox_02_03_Hand.setEnabled(False)\n        self.groupBox_02_05_Plane.setEnabled(True)\n        self.PB_04_CreateComp.setEnabled(False)\n#        FreeCAD.Console.PrintMessage(str(\"on_RB_01_04_ZigZag \")+\"\\n\")\n\n        pic = QtGui.QPixmap(self.path+\"Macro_FCConvertLines_ZigZag.png\")\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic)) \n        self.graphicsView.setScene(ui.scene)\n\n    def on_RB_01_05_Hand(self):                                   # \n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.groupBox_02_01_DashDot.setEnabled(False)\n        self.groupBox_02_02_ZigZag.setEnabled(False)\n        self.groupBox_02_03_Hand.setEnabled(True)\n        self.groupBox_02_05_Plane.setEnabled(True)\n        self.PB_04_CreateComp.setEnabled(False)\n#        FreeCAD.Console.PrintMessage(str(\"on_RB_01_05_Hand \")+\"\\n\")\n\n        pic = QtGui.QPixmap(self.path+\"Macro_FCConvertLines_Hand.png\")\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic)) \n        self.graphicsView.setScene(ui.scene)\n\n    def on_RB_02_05_01_XY(self):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.Plan = 1\n\n        pic = QtGui.QPixmap(self.path+\"Macro_FCConvrtLines_View-top.png\")\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic)) \n        self.graphicsView_2.setScene(ui.scene)\n#        FreeCAD.Console.PrintMessage(str(\"on_RB_02_05_01_XY \")+str(self.Plan)+\"\\n\")\n\n    def on_RB_02_05_02_YZ(self):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.Plan = 2\n\n        pic = QtGui.QPixmap(self.path+\"Macro_FCConvrtLines_View-right.png\")\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic)) \n        self.graphicsView_2.setScene(ui.scene)\n#        FreeCAD.Console.PrintMessage(str(\"on_RB_02_05_02_YZ \")+str(self.Plan)+\"\\n\")\n\n    def on_RB_02_05_03_XY(self):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.Plan = 3\n\n        pic = QtGui.QPixmap(self.path+\"Macro_FCConvrtLines_View-front.png\")\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic)) \n        self.graphicsView_2.setScene(ui.scene)\n#        FreeCAD.Console.PrintMessage(str(\"on_RB_02_05_03_XY \")+str(self.Plan)+\"\\n\")\n\n    ### DS ##########################################################################\n\n    def on_DS_02_01_01_LineA_valueChanged(self,value):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.LineA = value\n#        FreeCAD.Console.PrintMessage(str(\"DS_02_01_01_LineA \")+str(self.LineA)+\"\\n\")\n    def on_DS_02_01_02_SpaceB_valueChanged(self,value):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.SpaceB = value\n        self.DS_02_01_04_Space2D.setValue(self.SpaceB)\n        self.Space2D = self.SpaceB\n#        FreeCAD.Console.PrintMessage(str(\"DS_02_01_02_SpaceB \")+str(self.SpaceB)+\"\\n\")\n    def on_DS_02_01_03_Line2C_valueChanged(self,value):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.Line2C = value\n#        FreeCAD.Console.PrintMessage(str(\"DS_02_01_03_Line2C \")+str(self.Line2C)+\"\\n\")\n    def on_DS_02_01_04_Space2D_valueChanged(self,value):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.Space2D = value\n#        FreeCAD.Console.PrintMessage(str(\"DS_02_01_04_Space2D \")+str(self.Space2D)+\"\\n\")\n\n    def on_SP_02_02_01_NHeadsX_valueChanged(self,value):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.NHeadsX = value\n        self.label_02_02_Length.setText(str((self.BeginA * 2) + ((self.NHeadsX * (self.DimensionB + (self.GapC * self.NumberE))) - self.DimensionB)))\n#        FreeCAD.Console.PrintMessage(str(\"DS_02_02_01_NHeadsX \")+str(self.NHeadsX)+\"\\n\")\n    def on_DS_02_02_01_BeginA_valueChanged(self,value):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.BeginA = value\n        self.label_02_02_Length.setText(str((self.BeginA * 2) + ((self.NHeadsX * (self.DimensionB + (self.GapC * self.NumberE))) - self.DimensionB)))\n#        FreeCAD.Console.PrintMessage(str(\"DS_02_02_01_BeginA \")+str(self.BeginA)+\"\\n\")\n    def on_DS_02_02_02_DimensionB_valueChanged(self,value):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.DimensionB = value\n        self.label_02_02_Length.setText(str((self.BeginA * 2) + ((self.NHeadsX * (self.DimensionB + (self.GapC * self.NumberE))) - self.DimensionB)))\n#        FreeCAD.Console.PrintMessage(str(\"DS_02_02_02_DimensionB \")+str(self.DimensionB)+\"\\n\")\n    def on_DS_02_02_03_GapC_valueChanged(self,value):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.GapC = value\n        self.label_02_02_Length.setText(str((self.BeginA * 2) + ((self.NHeadsX * (self.DimensionB + (self.GapC * self.NumberE))) - self.DimensionB)))\n#        FreeCAD.Console.PrintMessage(str(\"DS_02_02_03_GapC \")+str(self.GapC)+\"\\n\")\n    def on_DS_02_02_04_HeightD_valueChanged(self,value):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.HeightD = value\n        self.label_02_02_Length.setText(str((self.BeginA * 2) + ((self.NHeadsX * (self.DimensionB + (self.GapC * self.NumberE))) - self.DimensionB)))\n#        FreeCAD.Console.PrintMessage(str(\"DS_02_02_04_HeightD \")+str(self.HeightD)+\"\\n\")\n    def on_SP_02_02_05_NumberE_valueChanged(self,value):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.NumberE = value\n        self.label_02_02_Length.setText(str((self.BeginA * 2) + ((self.NHeadsX * (self.DimensionB + (self.GapC * self.NumberE))) - self.DimensionB)))\n#        FreeCAD.Console.PrintMessage(str(\"SP_02_02_05_NumberD \")+str(self.NumberE)+\"\\n\")\n\n    def on_DS_02_03_01_LengthA_valueChanged(self,value):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.LengthA = value\n#        FreeCAD.Console.PrintMessage(str(\"DS_02_03_01_LengthA \")+str(self.LengthA)+\"\\n\")\n    def on_DS_02_03_02_HeightB_valueChanged(self,value):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.HeightB = value\n#        FreeCAD.Console.PrintMessage(str(\"DS_02_03_02_HeightB \")+str(self.HeightB)+\"\\n\")\n    def on_DS_02_03_03_WaveC_valueChanged(self,value):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        self.WaveC = value\n#        FreeCAD.Console.PrintMessage(str(\"DS_02_03_03_WaveC \")+str(self.WaveC)+\"\\n\")\n\n    ### PB ############################################################################\n    def on_PB_01_Save(self):                     # \n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n        SaveName  = \"\"\n        preDefini = \"\"\n\n        if self.groupBox_00_CutLine.isChecked():                        # 2 \n            preDefini = \"CutLine_\"\n        elif self.RB_01_01_Dash.isChecked():                            # 8\n            preDefini = \"Dash_\"\n        elif self.RB_01_02_DashDot.isChecked():                         # 9\n            preDefini = \"DashDot_\"\n        elif self.RB_01_03_DashDotDot.isChecked():                      # 10\n            preDefini = \"DashDotDot_\"\n        elif self.RB_01_04_ZigZag.isChecked():                          # 11\n            preDefini = \"ZigZag_\"\n        elif self.RB_01_05_Hand.isChecked():                            # 12\n            preDefini = \"Hand_\"\n\n        try:\n            SaveName = QFileDialog.getSaveFileName(None,QString.fromLocal8Bit(\"Save a file FCConvertL\"),self.path + preDefini, \"*.FCConvertL\")   # PyQt4\n        except Exception:\n            SaveName, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, \"Save a file FCConvertL\", self.path + preDefini, \"*.FCConvertL\")   # PySide\n\n        if SaveName == \"\":\n            FreeCAD.Console.PrintMessage(\"Process aborted\"+\"\\n\")\n            errorDialog(\"Process aborted\")\n        else:\n\n            FreeCAD.Console.PrintMessage(\"Registration of \"+SaveName+\"\\n\")\n            try:\n                import codecs\n                file = codecs.open(SaveName, encoding='utf-8', mode='w')# r=read a=append w=write accepte les accents\n                try:\n                    file.write(\"FCConvert_01\"+\",\")                      # 0 # header version \n                    if self.NameType == \"\":\n                        self.NameType = \"FCConvertLines\"\n                    file.write(self.NameType +\",\")                      # 1 # nom venant de la boite de dialogue\n                    #####\n                    if self.groupBox_00_CutLine.isChecked():            # 2 \n                        file.write(str(\"1\")+\",\")\n                    else:\n                        file.write(str(\"0\")+\",\")\n                    file.write(str(self.NumberCut)+\",\")                 # 3\n                    if self.CB_00_00_CreateLine.isChecked():            # 4\n                        file.write(str(\"1\")+\",\")\n                    else:\n                        file.write(str(\"0\")+\",\")\n                    if self.CB_00_01_Dimension.isChecked():             # 5\n                        file.write(str(\"1\")+\",\")\n                    else:\n                        file.write(str(\"0\")+\",\")\n                    if self.CB_00_02_BiColor.isChecked():               # 6\n                        file.write(str(\"1\")+\",\")\n                    else:\n                        file.write(str(\"0\")+\",\")\n                    if self.CB_00_03_CreatePoints.isChecked():          # 7\n                        file.write(str(\"1\")+\",\")\n                    else:\n                        file.write(str(\"0\")+\",\")\n                    #####\n                    if self.RB_01_01_Dash.isChecked():                  # 8\n                        file.write(str(\"1\")+\",\")\n                    else:\n                        file.write(str(\"0\")+\",\")\n                    if self.RB_01_02_DashDot.isChecked():               # 9\n                        file.write(str(\"1\")+\",\")\n                    else:\n                        file.write(str(\"0\")+\",\")\n                    if self.RB_01_03_DashDotDot.isChecked():            # 10\n                        file.write(str(\"1\")+\",\")\n                    else:\n                        file.write(str(\"0\")+\",\")\n                    if self.RB_01_04_ZigZag.isChecked():                # 11\n                        file.write(str(\"1\")+\",\")\n                    else:\n                        file.write(str(\"0\")+\",\")\n                    if self.RB_01_05_Hand.isChecked():                  # 12\n                        file.write(str(\"1\")+\",\")\n                    else:\n                        file.write(str(\"0\")+\",\")\n                    #####\n                    file.write(str(self.LineA)+\",\")                     # 13\n                    file.write(str(self.SpaceB)+\",\")                    # 14\n                    file.write(str(self.Line2C)+\",\")                    # 15\n                    file.write(str(self.Space2D)+\",\")                   # 16\n                    #####\n                    file.write(str(self.NHeadsX)+\",\")                   # 17\n                    file.write(str(self.BeginA)+\",\")                    # 18\n                    file.write(str(self.DimensionB)+\",\")                # 19\n                    file.write(str(self.GapC)+\",\")                      # 20\n                    file.write(str(self.HeightD)+\",\")                   # 21\n                    file.write(str(self.NumberE)+\",\")                   # 22\n                    #####\n                    file.write(str(self.LengthA)+\",\")                   # 23\n                    file.write(str(self.HeightB)+\",\")                   # 24\n                    file.write(str(self.WaveC)+\",\")                     # 25\n                    #####\n                    file.write(str(self.lineWidth)+\",\")                 # 26\n                    file.write(str(self.pointSize)+\",\")                 # 27\n                    file.write(str(self.red)+\",\")                       # 28\n                    file.write(str(self.green)+\",\")                     # 29\n                    file.write(str(self.blue)+\",\")                      # 30\n                    #####\n                    if self.RB_02_05_01_XY.isChecked():                 # 31\n                        file.write(str(\"1\")+\",\")\n                    else:\n                        file.write(str(\"0\")+\",\")\n                    if self.RB_02_05_02_YZ.isChecked():                 # 32\n                        file.write(str(\"1\")+\",\")\n                    else:\n                        file.write(str(\"0\")+\",\")\n                    if self.RB_02_05_03_XY.isChecked():                 # 33\n                        file.write(str(\"1\")+\",\")\n                    else:\n                        file.write(str(\"0\")+\",\")\n                    #####\n                    file.write(str(\"00\")+\",\")                           # 34\n                    file.write(str(\"00\")+\",\")                           # 35\n                    file.write(str(\"00\")+\",\")                           # 36\n                    file.write(str(\"00\")+\",\")                           # 37\n                    file.write(str(\"00\")+\",\")                           # 38\n                    file.write(str(\"00\")+\",\")                           # 39\n                    file.write(str(\"00\")+\",\")                           # 40\n                    file.write(str(\"00\")+\",\")                           # 41\n                    file.write(str(\"00\")+\",\")                           # 42\n                    file.write(str(\"00\")+\",\")                           # 43\n                    file.write(str(\"00\")+\",\")                           # 44\n                    file.write(str(\"00\")+\"\\n\")                          # 45 last data with line feed [ENTER]\n\n                finally:\n                    file.close()\n\n            except Exception:\n                FreeCAD.Console.PrintError(\"Error Registration file \"+SaveName+\"\\n\")\n                errorDialog(\"Error Registration file \"+SaveName)\n#        FreeCAD.Console.PrintMessage(str(\"on_PB_01_Save \")+\"\\n\")\n\n    def on_PB_02_Load(self):                     # \n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n\n        OpenName = \"\"\n        try:\n            OpenName = QFileDialog.getOpenFileName(None,QString.fromLocal8Bit(\"Read a file FCConvertL\"),self.path,\"*.FCConvertL\") # PyQt4\n        except Exception:\n            OpenName, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, \"Read a file FCConvertL\", self.path, \"*.FCConvertL\")#PySide\n        try:\n            if OpenName != \"\":\n                try:\n                    import codecs\n                    file = codecs.open(OpenName, encoding='utf-8', mode='r')     # r=read a=append w=write accepte les accents\n                    codeFile = file.readline().split(\",\")      \n\n                    if (str(codeFile[0]) == \"FCConvert_01\"):                     # 0 # header version\n                        a = ui\n                        a.on_PB_03_Reset()\n                        self.LE_01_LineType.setText(codeFile[1])                 # 1 # nom venant de la boite de dialogue\n                        #####\n                        if int(codeFile[2]) == 1:                                # 2 \n                            self.groupBox_00_CutLine.setChecked(True)\n                        else:\n                            self.groupBox_00_CutLine.setChecked(False)\n                        a = ui\n                        a.on_groupBox_00_CutLine()\n\n                        self.NumberCut = float(codeFile[3])                      # 3\n                        self.DS_01_NumberCut.setValue(self.NumberCut)\n\n                        if int(codeFile[4]) == 1:                                # 4 \n                            self.CB_00_00_CreateLine.setChecked(True)\n                        else:\n                            self.CB_00_00_CreateLine.setChecked(False)\n\n                        if int(codeFile[5]) == 1:                                # 5\n                            self.CB_00_01_Dimension.setChecked(True)\n                        else:\n                            self.CB_00_01_Dimension.setChecked(False)\n                        a = ui\n                        a.on_CB_00_01_Dimension_clicked()\n\n                        if int(codeFile[6]) == 1:                                # 6\n                            self.CB_00_02_BiColor.setChecked(True)\n                        else:\n                            self.CB_00_02_BiColor.setChecked(False)\n\n                        if int(codeFile[7]) == 1:                                # 7\n                            self.CB_00_03_CreatePoints.setChecked(True)\n                        else:\n                            self.CB_00_03_CreatePoints.setChecked(False)\n                        #####\n\n                        if int(codeFile[8]) == 1:                                # 8\n                            self.RB_01_01_Dash.setChecked(True)\n                            a = ui\n                            a.on_RB_01_01_Dash()\n#                        else:\n#                            self.RB_01_01_Dash.setChecked(False)\n#                        a = ui\n#                        a.on_RB_01_01_Dash()\n\n                        if int(codeFile[9]) == 1:                                # 9\n                            self.RB_01_02_DashDot.setChecked(True)\n                            a = ui\n                            a.on_RB_01_02_DashDot()\n#                        else:\n#                            self.RB_01_02_DashDot.setChecked(False)\n#                        a = ui\n#                        a.on_RB_01_02_DashDot()\n\n                        if int(codeFile[10]) == 1:                               # 10\n                            self.RB_01_03_DashDotDot.setChecked(True)\n                            a = ui\n                            a.on_RB_01_03_DashDotDot()\n#                        else:\n#                            self.RB_01_03_DashDotDot.setChecked(False)\n#                        a = ui\n#                        a.on_RB_01_03_DashDotDot()\n\n                        if int(codeFile[11]) == 1:                               # 11\n                            self.RB_01_04_ZigZag.setChecked(True)\n                            a = ui\n                            a.on_RB_01_04_ZigZag()\n#                        else:\n#                            self.RB_01_04_ZigZag.setChecked(False)\n#                        a = ui\n#                        a.on_RB_01_04_ZigZag()\n\n                        if int(codeFile[12]) == 1:                               # 12\n                            self.RB_01_05_Hand.setChecked(True)\n                            a = ui\n                            a.on_RB_01_05_Hand()\n#                        else:\n#                            self.RB_01_05_Hand.setChecked(False)\n#                        a = ui\n#                        a.on_RB_01_05_Hand()\n                        #####\n\n                        self.LineA = float(codeFile[13])                         # 13\n                        self.DS_02_01_01_LineA.setValue(self.LineA)\n\n                        self.SpaceB = float(codeFile[14])                        # 14\n                        self.DS_02_01_02_SpaceB.setValue(self.SpaceB)\n\n                        self.Line2C = float(codeFile[15])                        # 15\n                        self.DS_02_01_03_Line2C.setValue(self.Line2C)\n\n                        self.Space2D = float(codeFile[16])                       # 16\n                        self.DS_02_01_04_Space2D.setValue(self.Space2D)\n                        #####\n\n                        self.NHeadsX = float(codeFile[17])                       # 17\n                        self.SP_02_02_01_NHeadsX.setValue(self.NHeadsX)\n\n                        self.BeginA = float(codeFile[18])                        # 18\n                        self.DS_02_02_01_BeginA.setValue(self.BeginA)\n\n                        self.DimensionB = float(codeFile[19])                    # 19\n                        self.DS_02_02_02_DimensionB.setValue(self.DimensionB)\n\n                        self.GapC = float(codeFile[20])                          # 20\n                        self.DS_02_02_03_GapC.setValue(self.GapC)\n\n                        self.HeightD = float(codeFile[21])                       # 21\n                        self.DS_02_02_04_HeightD.setValue(self.HeightD)\n\n                        self.NumberE = float(codeFile[22])                       # 22\n                        self.SP_02_02_05_NumberE.setValue(self.NumberE)\n                        self.label_02_02_Length.setText(str((self.BeginA * 2) + ((self.NHeadsX * (self.DimensionB + (self.GapC * self.NumberE))) - self.DimensionB)))\n                        #####\n\n                        self.LengthA = float(codeFile[23])                       # 23\n                        self.DS_02_03_01_LengthA.setValue(self.LengthA)\n\n                        self.HeightB = float(codeFile[24])                       # 24\n                        self.DS_02_03_02_HeightB.setValue(self.HeightB)\n\n                        self.WaveC = float(codeFile[25])                         # 25\n                        self.DS_02_03_03_WaveC.setValue(self.WaveC)\n                        #####\n\n                        self.lineWidth = float(codeFile[26])                     # 26\n                        self.DS_02_04_01_LineWidth.setValue(self.lineWidth)\n\n                        self.pointSize = float(codeFile[27])                     # 27\n                        self.DS_02_04_02_PSize.setValue(self.pointSize)\n\n                        self.red = float(codeFile[28])                           # 28\n                        self.green = float(codeFile[29])                         # 29\n                        self.blue = float(codeFile[30])                          # 30\n                        self.PB_02_04_03_Color.setStyleSheet(\"background-color: rgb(\"+str(self.red)+\",\"+str(self.green)+\",\"+str(self.blue)+\"); color: cmj(\"+str(255)+\",\"+str(255)+\",\"+str(255)+\")\")\n                        #####\n\n                        if int(codeFile[31]) == 1:                               # 31\n                            self.RB_02_05_01_XY.setChecked(True)\n#                        else:\n#                            self.RB_02_05_01_XY.setChecked(False)\n\n                        if int(codeFile[32]) == 1:                               # 32\n                            self.RB_02_05_02_YZ.setChecked(True)\n#                        else:\n#                            self.RB_02_05_02_YZ.setChecked(False)\n\n                        if int(codeFile[33]) == 1:                               # 33\n                            self.RB_02_05_03_XY.setChecked(True)\n#                        else:\n#                            self.RB_02_05_03_XY.setChecked(False)\n                        #####\n\n                        forFuture = int(codeFile[34])                            # 34\n                        forFuture = int(codeFile[35])                            # 35\n                        forFuture = int(codeFile[36])                            # 36\n                        forFuture = int(codeFile[37])                            # 37\n                        forFuture = int(codeFile[38])                            # 38\n                        forFuture = int(codeFile[39])                            # 39\n                        forFuture = int(codeFile[40])                            # 40\n                        forFuture = int(codeFile[41])                            # 41\n                        forFuture = int(codeFile[42])                            # 42\n                        forFuture = int(codeFile[43])                            # 43\n                        forFuture = int(codeFile[44])                            # 44\n                        forFuture = int(codeFile[45])                            # 45 last data with line feed [ENTER]\n#                        FreeCAD.Console.PrintMessage(\"____________________\"+\"\\n\")\n                finally:\n                    file.close()\n        except Exception:\n            FreeCAD.Console.PrintError(\"Error in reading the file \"+OpenName+\"\\n\")\n            errorDialog(\"Error in reading the file \"+OpenName)\n\n#        FreeCAD.Console.PrintMessage(str(\"on_PB_02_Load \")+\"\\n\")\n\n    def on_PB_04_CreateComp(self):                     # \n        global ui\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")       # origin system\n        self.Compound = 1\n        ff = ui\n        ff.on_PB_05_Create()\n        self.Compound = 0\n#        FreeCAD.Console.PrintMessage(str(\"on_PB_04_CreateComp \")+\"\\n\")\n\n    def on_PB_02_04_03_Color(self):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")       # origin system\n        self.window.hide()                                                       # hide the window open color\n        couleur = QtGui.QColorDialog.getColor()\n        if couleur.isValid():\n            self.red   = int(str(couleur.name()[1:3]),16)\n            self.green = int(str(couleur.name()[3:5]),16)\n            self.blue  = int(str(couleur.name()[5:7]),16)\n            self.PB_02_04_03_Color.setStyleSheet(\"background-color: rgb(\"+str(self.red)+\",\"+str(self.green)+\",\"+str(self.blue)+\"); color: cmj(\"+str(255)+\",\"+str(255)+\",\"+str(255)+\")\")\n        self.window.show()                                                                    # show the window and close color\n#        FreeCAD.Console.PrintMessage(str(\"PB_02_04_03_Color \")+\"\\n\")\n\n    def on_LE_01_LineType_Pressed(self):\n        self.NameType = self.LE_01_LineType.text()                                                      # extract the string in the lineEdit\n#        FreeCAD.Console.PrintMessage(str(\"on_LE_01_LineType_Pressed \")+self.NameType+\"\\n\")\n\n\n    def on_PB_05_Create(self):                                                                # OK create the line\n        selectionObjects = FreeCADGui.Selection.getSelection()\n        global emergency\n        if (len(selectionObjects) != 0) or (self.RB_01_04_ZigZag.isChecked()) or (self.RB_01_05_Hand.isChecked()):\n            emergency = 0\n\n            try:\n                doc = FreeCAD.ActiveDocument    \n                if doc == None:\n                    doc = FreeCAD.newDocument()\n            except Exception:\n                FreeCAD.Console.PrintMessage(\"Error document\"+\"\\n\")\n                None\n\n            #### Chrono begin########################################################################### chrono begin\n            #depart = time.clock()                                                                      # chrono begin\n            ############################################################################################ chrono begin\n            self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n\n            if self.groupBox_00_CutLine.isChecked():                                    # Cut and Dimension lines\n                if self.CB_00_00_CreateLine.isChecked():\n                    createLine = 1\n                else:\n                    createLine = 0\n                if self.CB_00_02_BiColor.isChecked():\n                    biColor = 1\n                else:\n                    biColor = 0\n                if self.CB_00_03_CreatePoints.isChecked():\n                    createPoint = 1\n                else:\n                    createPoint = 0\n                if self.CB_00_01_Dimension.isChecked():\n                    cutLength(cutLength = self.NumberCut, cutLine = 00, red = self.red, green = self.green, blue = self.blue, typeColor = biColor, createLine = createLine, createPoints = createPoint, lineWidth = self.lineWidth, pSize = self.pointSize)\n                else:\n                    cutLength(cutLength = 00, cutLine = self.NumberCut, red = self.red, green = self.green, blue = self.blue, typeColor = biColor, createLine = createLine, createPoints = createPoint, lineWidth = self.lineWidth, pSize = self.pointSize)\n\n            else:\n                if self.RB_01_01_Dash.isChecked():\n                    dashLine(self.LineA, self.SpaceB, compLine = self.Compound, red = self.red, green = self.green, blue = self.blue, typeLine = 1, lineWidth = self.lineWidth, pSize = self.pointSize)\n\n                if self.RB_01_02_DashDot.isChecked():\n                    dashLine(self.LineA, self.SpaceB, self.Line2C, self.Space2D, compLine = self.Compound,  red = self.red, green = self.green, blue = self.blue, typeLine = 2, lineWidth = self.lineWidth, pSize = self.pointSize)\n\n                if self.RB_01_03_DashDotDot.isChecked():\n                    dashLine(self.LineA, self.SpaceB, self.Line2C, self.Space2D, compLine = self.Compound,  red = self.red, green = self.green, blue = self.blue, typeLine = 3, lineWidth = self.lineWidth, pSize = self.pointSize)\n\n                if self.RB_01_04_ZigZag.isChecked():\n                    zigzagLine(NumberX = self.NHeadsX, BeginA = self.BeginA, DimensionB = self.DimensionB, GapC = self.GapC, HeightD = self.HeightD, NumberE = self.NumberE, compLine = self.Compound,  red = self.red, green = self.green, blue = self.blue, plane = self.Plan, lineWidth = self.lineWidth, pSize = self.pointSize)\n\n                if self.RB_01_05_Hand.isChecked():\n                    handLine(LengthA = self.LengthA, HeightB = self.HeightB, WaveC = self.WaveC, red = self.red, green = self.green, blue = self.blue, plane = self.Plan, lineWidth = self.lineWidth, pSize = self.pointSize)\n\n            if emergency == 0:\n                self.PB_05_Create.setStyleSheet(\"background-color: green\") # This function gives a color button\n            else:\n                self.PB_05_Create.setStyleSheet(\"background-color: red\")   # This function gives a color button\n\n            #### Chrono end ########################################################################### chrono end\n            #arrivee = time.clock()                                                                    # chrono end\n            #FreeCAD.Console.PrintMessage(\"Time : \"+str(\"%.2f\" % ((arrivee - depart)/60))+\" min\"+\"\\n\\n\")   # chrono end\n            ########################################################################################### chrono end\n        else:\n            FreeCAD.Console.PrintError(str(\"Select one object \")+\"\\n\")\n            self.PB_05_Create.setStyleSheet(\"background-color: red\")           # This function gives a color button\n#        FreeCAD.Console.PrintMessage(str(\"on_PB_05_Create \")+\"\\n\")\n\n    def on_DS_02_04_01_LineWidth(self,LineWidth):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")     # origin system\n        self.lineWidth = LineWidth\n#        FreeCAD.Console.PrintMessage(str(\"on_DS_02_04_01_LineWidth \")+str(self.lineWidth)+\"\\n\")\n\n    def on_DS_02_04_02_PSize(self,PointSize):\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")      # origin system\n        self.pointSize = PointSize\n#        FreeCAD.Console.PrintMessage(str(\"on_DS_02_04_02_PSize \")+str(self.pointSize)+\"\\n\")\n\n    def on_PB_03_Reset(self):                     # \n        global emergency\n        emergency       = 0\n        self.NumberCut  = 2.0\n        self.LineA      = 2.0\n        self.SpaceB     = 0.5\n        self.Line2C     = 0.2\n        self.Space2D    = self.SpaceB\n        self.red        = 0\n        self.green      = 0\n        self.blue       = 0\n        self.NHeadsX    = 20\n        self.BeginA     = 2.0\n        self.DimensionB = 4.0\n        self.GapC       = 3.0\n        self.HeightD    = 2.0\n        self.NumberE    = 1\n        self.Compound   = 0\n        self.lineWidth  = 2.0\n        self.pointSize  = 2.0\n        self.Plan       = 1\n        self.LengthA    = 150\n        self.HeightB    = 2.0\n        self.WaveC      = 40.0\n        self.groupBox_00_CutLine.setCheckable(True)\n        self.PB_04_CreateComp.setEnabled(False)\n        self.LE_01_LineType.setText(\"Name type line\")\n        self.DS_01_NumberCut.setValue(self.NumberCut)\n        self.CB_00_02_BiColor.setChecked(True)\n        self.CB_00_03_CreatePoints.setChecked(False)\n        self.CB_00_01_Dimension.setChecked(False)\n        self.CB_00_00_CreateLine.setChecked(True)\n        self.RB_01_01_Dash.setChecked(True)\n        self.DS_02_01_01_LineA.setValue(self.LineA)\n        self.DS_02_01_02_SpaceB.setValue(self.SpaceB)\n        self.DS_02_01_03_Line2C.setValue(self.Line2C)\n        self.DS_02_01_04_Space2D.setValue(self.Space2D)\n        self.label_02_02_Length.setText(str((self.BeginA * 2) + ((self.NHeadsX * (self.DimensionB + (self.GapC * self.NumberE))) - self.DimensionB)))\n        self.SP_02_02_01_NHeadsX.setValue(self.NHeadsX)\n        self.DS_02_02_01_BeginA.setValue(self.BeginA)\n        self.DS_02_02_02_DimensionB.setValue(self.DimensionB)\n        self.DS_02_02_03_GapC.setValue(self.GapC)\n        self.DS_02_02_04_HeightD.setValue(self.HeightD)\n        self.SP_02_02_05_NumberE.setValue(self.NumberE)\n        self.DS_02_03_01_LengthA.setValue(self.LengthA)\n        self.DS_02_03_02_HeightB.setValue(self.HeightB)\n        self.DS_02_03_03_WaveC.setValue(self.WaveC)\n        self.DS_02_04_01_LineWidth.setValue(self.lineWidth)\n        self.DS_02_04_02_PSize.setValue(self.pointSize)\n        self.red   = 0\n        self.green = 0\n        self.blue  = 0\n        self.DS_01_NumberCut.setSingleStep(1)                                          # Cut line\n        self.DS_01_NumberCut.setMaximum(9999999)\n        self.DS_01_NumberCut.setMinimum(1)\n        self.DS_01_NumberCut.setDecimals(0)\n        self.DS_01_NumberCut.setSuffix(_fromUtf8(\" Cut\"))\n        self.DS_01_NumberCut.setValue(self.NumberCut)\n        self.DS_01_NumberCut.setToolTip(_fromUtf8(\"Cut in x parts the selected line\"))\n        self.PB_02_04_03_Color.setStyleSheet(\"background-color: QPalette.Base\")        # origin system\n        self.RB_02_05_01_XY.setChecked(True)\n        self.groupBox_01_TypeLine.setEnabled(False)\n        self.groupBox_02_05_Plane.setEnabled(False)\n        self.DS_01_NumberCut.setEnabled(True)\n        pic = QtGui.QPixmap(self.path+\"Macro_FCConvertLines_Title.png\") \n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic)) \n        self.graphicsView.setScene(ui.scene)\n        self.PB_05_Create.setStyleSheet(\"background-color: QPalette.Base\")              # origin system\n        pic = QtGui.QPixmap(self.path+\"Macro_FCConvrtLines_View-top.png\")\n        self.scene = QtGui.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic)) \n        self.graphicsView_2.setScene(ui.scene)\n#        FreeCAD.Console.PrintMessage(str(\"on_PB_03_Reset \")+\"\\n\")\n\n    def on_PB_06_Quit(self):                     # \n        FreeCAD.Console.PrintMessage(\"Fin FCConvertLines\"+\"\\n\")\n        self.window.hide()\n#        FreeCAD.Console.PrintMessage(str(\"on_PB_06_Quit \")+\"\\n\")\n\n#________________________________________________________________________________________\nMainWindow = QtGui.QMainWindow()\nui = Ui_MainWindow()\nui.setupUi(MainWindow)\nMainWindow.show()\n",
    "url": "https://wiki.freecad.org/Macro_FCConvertLines",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/3d719574089a5f9044ec/raw/812769b6b296a1da2e9c8cd8153ad7266fe80f8d/Macro_FCConvertLines.FCMacro",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_FC_Convert_Lines",
    "version": "00.07b",
    "license": "",
    "date": "09/11/2020",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_FCConvertLines.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/e/e2/Macro_FCConvertLines.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Make Arc 3 Points",
    "on_wiki": true,
    "on_git": false,
    "desc": "Creates a arc from 3 selected points.<br /><br />Macro version: 02.00<br />Last modified: 2019-07-29<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/9/92/Macro_Make_Arc_3_Points.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Creates a arc from 3 selected points.",
    "code": "# -*- coding: utf-8 -*-\nfrom FreeCAD import Base\n\n__title__   = \"Macro_Make_Arc_3_points\"\n__author__  = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__version__ = \"00.02\"\n__date__    = \"29/07/2019\"\n\nglobal selected; selected = []\nApp = FreeCAD\n\nclass SelObserver:\n    print( \"Create Arc to 3 points ...\")\n    def addSelection(self,doc,obj,sub,pnt):  # Selection \n        global selected\n        selected.append(pnt)\n        if len(selected) == 1:\n            print( \"Point 1 : \",FreeCAD.Vector(selected[0]))\n        elif len(selected) == 2:\n            print( \"Point 2 : \",FreeCAD.Vector(selected[1]))\n        elif len(selected) == 3:\n            print( \"Point 3 : \",FreeCAD.Vector(selected[2]))\n            try:\n                C1 = Part.Arc(FreeCAD.Vector(selected[0]),FreeCAD.Vector(selected[1]),FreeCAD.Vector(selected[2]))\n                S1 = Part.Shape([C1])\n                W = Part.Wire(S1.Edges)\n                Part.show(W)\n                App.ActiveDocument.ActiveObject.Label   = \"Arc_3_Points\"\n                print( \"Length  : \",W.Length)\n            except Exception:\n                print( \"Three points are collinear or bad selection\")\n            del selected[:]\n            FreeCADGui.Selection.removeObserver(s)\n            print( \"End Make_Arc_3_Points\")\n            print( \"_____________________\")\n\ns=SelObserver()\nFreeCADGui.Selection.addObserver(s)",
    "url": "https://wiki.freecad.org/Macro_Make_Arc_3_Points",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.02",
    "license": "",
    "date": "29/07/2019",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Make_Arc_3_Points.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/9/92/Macro_Make_Arc_3_Points.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Make Circle 3 Points",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro creates a circle circumscribed on 3 selected points, orthogonal manner or in 3D at the option space. Points can be objects such as cubes, cylinders,... then selected coordinates will be the centre of these forms.<br /><br />Macro version: 1.0<br />Last modified: 2014-08-08<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/c/c7/Macro_Make_Circle_3_Points.png\">ToolBar Icon</a><br /><a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/f/fb/View-Top.png\">Icon View-Top</a><br /><a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/c/ca/View-Left.png\">Icon View-Left</a><br /><a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/6/64/View-Front.png\">Icon View-Front</a><br /><a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/1/19/View-C3P.png\">Icon View-C3P</a><br />Author: Mario52<br /> ",
    "comment": "This macro creates a circle circumscribed on 3 selected points, orthogonal manner or in 3D at the option space. Points can be objects such as cubes, cylinders,... then selected coordinates will be the centre of these forms.",
    "code": "# -*- coding: utf-8 -*-\n# Cercle sur 3 points.py\n# create a circle from 3 points selected\n# combination of the two programs 'create a circle from 3 points selected'\n# with as options (orthogonal) circle can be built on a choice plans\n# to coordinate one of the three selected choice shapes\n# mode by default, creates the circle in 3D space\n# the options create the circle of orthogonal way on the map and view the choice\n# with the creation of a central color related to the axes Y/N Y/N\n# 04/03/2013 # 24/03/2013 # 08/08/2014 by mario52\n# the formula adapted (with permission of its author) by \"mario52\" for orthogonal circles comes from\n# http://www-obs.univ-lyon1.fr/labo/fc/Ateliers_archives/ateliers_2005-06/cercle_3pts.pdf\n# read the note in pdf, on the order of selection points,\n# If the formula returns an error (example the 3 points in the same alignment)\n# the formula adapted by \"galou_breizh\" for the cecle in 3D space comes from\n# http://en.wikipedia.org/wiki/Circumscribed_circle\n# the window is always visible and allows you to work on other programs\n# as for example to select other items in FreeCAD\n\n#08/08/2014 PyQt4 and PySide\n\n#OS: Windows Vista\n#Word size: 32-bit\n#Version: 0.14.3700 (Git)\n#Branch: releases/FreeCAD-0-14\n#Hash: 32f5aae0a64333ec8d5d160dbc46e690510c8fe1\n#Python version: 2.6.2\n#Qt version: 4.5.2\n#Coin version: 3.1.0\n#SoQt version: 1.4.1\n#OCC version: 6.5.1\n\ntry:\n    import PyQt4\n    from PyQt4 import QtCore, QtGui\nexcept Exception:\n    import PySide\n    from PySide import QtCore, QtGui\n\nimport Draft, Part, FreeCAD, math, PartGui, FreeCADGui\nfrom math import sqrt, pi, sin, cos, asin\nfrom FreeCAD import Base\n \n                    # vueChoix = 0 et alignerSur = 0 , mode par d\u00e9faut\nglobal vueChoix\t\t# choix de la vue Dessus=1 XY, vue Face=2 ZX, vue Droite=3 ZY (Orthogonal)\nglobal alignerSur   # aligne le cercle sur une forme au choix (1,2 ou 3) ou sur Z=0 (Orthogonal)\nglobal afficherPoint# affiche le point central du cercle\nglobal colorer     \t# colorer suivant l'axe 1=Ok 0=Couleur courante uniquement Orthogonal !\nvueChoix = 0\nalignerSur = 0\nafficherPoint = 1\ncolorer = 1\n \ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n \ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n \nclass Ui_MainWindow(object):\n \n    def __init__(self, MainWindow):\n        self.window = MainWindow\n        path = FreeCAD.ConfigGet(\"AppHomePath\") # chemin \n \n        MainWindow.setObjectName(_fromUtf8(\"MainWindow\"))\n        MainWindow.resize(490, 302)\n        MainWindow.setWindowIcon(QtGui.QIcon(path+'View-C3P.png'))\n        self.centralWidget = QtGui.QWidget(MainWindow)\n        self.centralWidget.setObjectName(_fromUtf8(\"centralWidget\"))\n \n        self.groupBox = QtGui.QGroupBox(self.centralWidget)\n        self.groupBox.setGeometry(QtCore.QRect(20, 10, 130, 161))\n        self.groupBox.setObjectName(_fromUtf8(\"groupBox_1\"))\n \n        self.radioButton_1 = QtGui.QRadioButton(self.groupBox)\n        self.radioButton_1.setGeometry(QtCore.QRect(10, 30, 130, 20))\n        self.radioButton_1.setChecked(True)\n        self.radioButton_1.setObjectName(_fromUtf8(\"radioButton_1\"))\n        self.radioButton_1.clicked.connect(self.on_radioButton_1_clicked) #connection radioButton_1\n        self.radioButton_1.setToolTip(_translate(\"MainWindow\", \"Cercle sur 3 points dans l'espace\", None))\n \n        self.radioButton_2 = QtGui.QRadioButton(self.groupBox)\n        self.radioButton_2.setGeometry(QtCore.QRect(10, 60, 130, 20))\n        self.radioButton_2.setObjectName(_fromUtf8(\"radioButton_2\"))\n        self.radioButton_2.clicked.connect(self.on_radioButton_2_clicked) #connection radioButton_2\n        self.radioButton_2.setToolTip(_translate(\"MainWindow\", \"Cercle orthogonal sur la vue de face\", None))\n        #self.image_01 = \"C:\\Program Files\\FreeCAD0.13\\View-Front.png\"\n        self.image_01 = path+\"View-Front.png\"\n        icon01 = QtGui.QIcon() \n        icon01.addPixmap(QtGui.QPixmap(self.image_01),QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.radioButton_2.setIcon(icon01) \n \n        self.radioButton_3 = QtGui.QRadioButton(self.groupBox)\n        self.radioButton_3.setGeometry(QtCore.QRect(10, 90, 130, 20))\n        self.radioButton_3.setObjectName(_fromUtf8(\"radioButton_3\"))\n        self.radioButton_3.clicked.connect(self.on_radioButton_3_clicked) #connection radioButton_3\n        self.radioButton_3.setToolTip(_translate(\"MainWindow\", \"Cercle orthogonal sur la vue de dessus\", None))\n        #self.image_02 = \"C:\\Program Files\\FreeCAD0.13\\View-Top.png\"\n        self.image_02 = path+\"View-Top.png\"\n        icon02 = QtGui.QIcon() \n        icon02.addPixmap(QtGui.QPixmap(self.image_02),QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.radioButton_3.setIcon(icon02) \n \n        self.radioButton_4 = QtGui.QRadioButton(self.groupBox)\n        self.radioButton_4.setGeometry(QtCore.QRect(10, 120, 130, 20))\n        self.radioButton_4.setObjectName(_fromUtf8(\"radioButton_4\"))\n        self.radioButton_4.clicked.connect(self.on_radioButton_4_clicked) #connection radioButton_4\n        self.radioButton_4.setToolTip(_translate(\"MainWindow\", \"Cercle orthogonal sur la vue de droite\", None))\n        #self.image_03 = \"C:\\Program Files\\FreeCAD0.13\\View-Left.png\"\n        self.image_03 = path+\"View-Left.png\"\n        icon03 = QtGui.QIcon() \n        icon03.addPixmap(QtGui.QPixmap(self.image_03),QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.radioButton_4.setIcon(icon03) \n \n        self.groupBox_2 = QtGui.QGroupBox(self.centralWidget)\n        self.groupBox_2.setGeometry(QtCore.QRect(170, 10, 120, 161))\n        self.groupBox_2.setObjectName(_fromUtf8(\"groupBox_2\"))\n \n        self.radioButton_5 = QtGui.QRadioButton(self.groupBox_2)\n        self.radioButton_5.setGeometry(QtCore.QRect(10, 30, 95, 20))\n        self.radioButton_5.setChecked(True)\n        self.radioButton_5.setObjectName(_fromUtf8(\"radioButton_5\"))\n        self.radioButton_5.clicked.connect(self.on_radioButton_5_clicked) #connection radioButton_5\n        self.radioButton_5.setToolTip(_translate(\"MainWindow\", \"Cercle sur 3 points dans l'espace\", None))\n \n        self.radioButton_6 = QtGui.QRadioButton(self.groupBox_2)\n        self.radioButton_6.setGeometry(QtCore.QRect(10, 60, 95, 20))\n        self.radioButton_6.setObjectName(_fromUtf8(\"radioButton_6\"))\n        self.radioButton_6.clicked.connect(self.on_radioButton_6_clicked) #connection radioButton_6\n        self.radioButton_6.setToolTip(_translate(\"MainWindow\", \"Cercle orthogonal sur la forme 1\", None))\n \n        self.radioButton_7 = QtGui.QRadioButton(self.groupBox_2)\n        self.radioButton_7.setGeometry(QtCore.QRect(10, 90, 95, 20))\n        self.radioButton_7.setObjectName(_fromUtf8(\"radioButton_7\"))\n        self.radioButton_7.clicked.connect(self.on_radioButton_7_clicked) #connection radioButton_7\n        self.radioButton_7.setToolTip(_translate(\"MainWindow\", \"Cercle orthogonal sur la forme 2\", None))\n \n        self.radioButton_8 = QtGui.QRadioButton(self.groupBox_2)\n        self.radioButton_8.setGeometry(QtCore.QRect(10, 120, 95, 20))\n        self.radioButton_8.setObjectName(_fromUtf8(\"radioButton_8\"))\n        self.radioButton_8.clicked.connect(self.on_radioButton_8_clicked) #connection radioButton_8\n        self.radioButton_8.setToolTip(_translate(\"MainWindow\", \"Cercle orthogonal sur la forme 3\", None))\n \n        self.checkBox_1 = QtGui.QCheckBox(self.centralWidget)\n        self.checkBox_1.setGeometry(QtCore.QRect(20, 190, 140, 20))\n        self.checkBox_1.setChecked(True)\n        self.checkBox_1.setObjectName(_fromUtf8(\"checkBox_1\"))\n        self.checkBox_1.setToolTip(_translate(\"MainWindow\", \"Affiche un point sur le centre du cercle\", None))\n#        self.checkBox_1.clicked.connect(self.on_checkBox_1_clicked) #connection checkBox_1\n \n        self.checkBox_2 = QtGui.QCheckBox(self.centralWidget)\n        self.checkBox_2.setGeometry(QtCore.QRect(170, 190, 150, 20))\n        self.checkBox_2.setChecked(True)\n        self.checkBox_2.setObjectName(_fromUtf8(\"checkBox_2\"))\n        self.checkBox_2.setToolTip(_translate(\"MainWindow\", \"Associe la couleur du cercle \u00e0 la couleur des axes X,Y,Z (Orthogonal)\", None))\n#        self.checkBox_2.clicked.connect(self.on_checkBox_2_clicked) #connection checkBox_1\n \n        self.lineEdit_1 = QtGui.QLineEdit(self.centralWidget)\n        self.lineEdit_1.setGeometry(QtCore.QRect(320, 30, 151, 22))\n        self.lineEdit_1.setObjectName(_fromUtf8(\"lineEdit_1\"))\n        self.lineEdit_1.setReadOnly(True)\n \n        self.lineEdit_2 = QtGui.QLineEdit(self.centralWidget)\n        self.lineEdit_2.setGeometry(QtCore.QRect(320, 80, 151, 22))\n        self.lineEdit_2.setObjectName(_fromUtf8(\"lineEdit_2\"))\n        self.lineEdit_2.setReadOnly(True)\n \n        self.lineEdit_3 = QtGui.QLineEdit(self.centralWidget)\n        self.lineEdit_3.setGeometry(QtCore.QRect(320, 130, 151, 22))\n        self.lineEdit_3.setObjectName(_fromUtf8(\"lineEdit_3\"))\n        self.lineEdit_3.setReadOnly(True)\n \n        self.lineEdit_4 = QtGui.QLineEdit(self.centralWidget)\n        self.lineEdit_4.setGeometry(QtCore.QRect(320, 180, 151, 22))\n        self.lineEdit_4.setObjectName(_fromUtf8(\"lineEdit_4\"))\n        self.lineEdit_4.setReadOnly(True)\n \n        self.lineEdit_5 = QtGui.QLineEdit(self.centralWidget)\n        self.lineEdit_5.setGeometry(QtCore.QRect(320, 230, 151, 22))\n        self.lineEdit_5.setObjectName(_fromUtf8(\"lineEdit_5\"))\n        self.lineEdit_5.setReadOnly(True)\n \n        self.label_1 = QtGui.QLabel(self.centralWidget)\n        self.label_1.setGeometry(QtCore.QRect(320, 10, 91, 16))\n        self.label_1.setObjectName(_fromUtf8(\"label_1\"))\n \n        self.label_2 = QtGui.QLabel(self.centralWidget)\n        self.label_2.setGeometry(QtCore.QRect(320, 60, 91, 16))\n        self.label_2.setObjectName(_fromUtf8(\"label_2\"))\n \n        self.label_3 = QtGui.QLabel(self.centralWidget)\n        self.label_3.setGeometry(QtCore.QRect(320, 110, 91, 16))\n        self.label_3.setObjectName(_fromUtf8(\"label_3\"))\n \n        self.label_4 = QtGui.QLabel(self.centralWidget)\n        self.label_4.setGeometry(QtCore.QRect(320, 160, 53, 16))\n        self.label_4.setObjectName(_fromUtf8(\"label_4\"))\n \n        self.label_5 = QtGui.QLabel(self.centralWidget)\n        self.label_5.setGeometry(QtCore.QRect(320, 210, 81, 16))\n        self.label_5.setObjectName(_fromUtf8(\"label_5\"))\n \n        self.pushButton_1 = QtGui.QPushButton(self.centralWidget)\n        self.pushButton_1.setGeometry(QtCore.QRect(20, 230, 90, 28))\n        self.pushButton_1.setObjectName(_fromUtf8(\"pushButton_1\"))\n        self.pushButton_1.clicked.connect(self.on_pushButton_1_clicked) #connection pushButton_1\n        self.pushButton_1.setToolTip(_translate(\"MainWindow\", \"Quitte la fonction\", None))\n \n        self.pushButton_2 = QtGui.QPushButton(self.centralWidget)\n        self.pushButton_2.setGeometry(QtCore.QRect(110, 230, 90, 28))\n        self.pushButton_2.setObjectName(_fromUtf8(\"pushButton_2\"))\n        self.pushButton_2.clicked.connect(self.on_pushButton_2_clicked) #connection pushButton_2\n        self.pushButton_2.setToolTip(_translate(\"MainWindow\", \"Applique la fonction sans quitter\", None))\n        #self.pushButton_2.setStyleSheet(\"background-color: red\") #cette fonction donne une couleur au bouton\n        #self.pushButton_2.setStyleSheet(\"color : #ff0000\") #cette fonction donne une couleur au texte du bouton\n        #self.pushButton_2.setStyleSheet(\"color : #ff0000; background-color : #0000ff;\" ) #combinaison des deux\n \n        self.pushButton_3 = QtGui.QPushButton(self.centralWidget)\n        self.pushButton_3.setGeometry(QtCore.QRect(200, 230, 90, 28))\n        self.pushButton_3.setObjectName(_fromUtf8(\"pushButton_3\"))\n        self.pushButton_3.clicked.connect(self.on_pushButton_3_clicked) #connection pushButton_3\n        self.pushButton_3.setToolTip(_translate(\"MainWindow\", \"D\u00e9finit le mode par d\u00e9faut (Cercle sur 3 points dans l'espace)\", None))\n \n        MainWindow.setCentralWidget(self.centralWidget)\n        self.statusBar = QtGui.QStatusBar(MainWindow)\n        self.statusBar.setObjectName(_fromUtf8(\"statusBar\"))\n        MainWindow.setStatusBar(self.statusBar)\n \n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n \n    def retranslateUi(self, MainWindow):\n        try:\n            MainWindow.setWindowFlags(PyQt4.QtCore.Qt.WindowStaysOnTopHint) # PyQt4 cette fonction met la fen\u00eatre en avant\n        except Exception:\n            MainWindow.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint) # PySide cette fonction met la fen\u00eatre en avant\n        #MainWindow.setStyleSheet(\"background-color: red\") #cette fonction donne une couleur \u00e0 la fen\u00eatre\n        #MainWindow.setWindowOpacity(0.5)    #cette fonction donne une transparence \u00e0 la fen\u00eatre\n        MainWindow.setWindowTitle(_translate(\"MainWindow\", \"Cercle sur 3 points\", None))\n        self.groupBox.setTitle(_translate(\"MainWindow\", \"Mode\", None))\n        self.radioButton_1.setText(_translate(\"MainWindow\", \"D\u00e9faut\", None))\n        self.radioButton_2.setText(_translate(\"MainWindow\", \"Vue  Face\", None))\n        self.radioButton_3.setText(_translate(\"MainWindow\", \"Vue Dessus\", None))\n        self.radioButton_4.setText(_translate(\"MainWindow\", \"Vue Droite\", None))\n        self.groupBox_2.setTitle(_translate(\"MainWindow\", \"Alignement sur\", None))\n        self.radioButton_5.setText(_translate(\"MainWindow\", \"D\u00e9faut\", None))\n        self.radioButton_6.setText(_translate(\"MainWindow\", \"Forme 1\", None))\n        self.radioButton_7.setText(_translate(\"MainWindow\", \"Forme 2\", None))\n        self.radioButton_8.setText(_translate(\"MainWindow\", \"Forme 3\", None))\n        self.checkBox_1.setText(_translate(\"MainWindow\", \"Afficher le centre\", None))\n        self.checkBox_2.setText(_translate(\"MainWindow\", \"Associer les couleurs\", None))\n        self.label_1.setText(_translate(\"MainWindow\", \"Coordonn\u00e9e X\", None))\n        self.label_2.setText(_translate(\"MainWindow\", \"Coordonn\u00e9e Y\", None))\n        self.label_3.setText(_translate(\"MainWindow\", \"Coordonn\u00e9e Z\", None))\n        self.label_4.setText(_translate(\"MainWindow\", \"Rayon\", None))\n        self.label_5.setText(_translate(\"MainWindow\", \"Angle\", None))\n        self.pushButton_1.setText(_translate(\"MainWindow\", \"Quitter\", None))\n        self.pushButton_2.setText(_translate(\"MainWindow\", \"Appliquer\", None))\n        self.pushButton_3.setText(_translate(\"MainWindow\", \"D\u00e9faut\", None))\n    # premi\u00e8re s\u00e9rie de radioboutons\n    def on_radioButton_1_clicked(self):\n        if self.radioButton_1.isChecked():\n            self.radioButton_5.setChecked(True)\n    def on_radioButton_2_clicked(self):\n        if self.radioButton_5.isChecked():\n            self.radioButton_6.setChecked(True)\n    def on_radioButton_3_clicked(self):\n        if self.radioButton_5.isChecked():\n            self.radioButton_6.setChecked(True)\n    def on_radioButton_4_clicked(self):\n        if self.radioButton_5.isChecked():\n            self.radioButton_6.setChecked(True)\n    # deuxi\u00e8me s\u00e9rie de radioboutons\n    def on_radioButton_5_clicked(self):\n        if self.radioButton_5.isChecked():\n            self.radioButton_1.setChecked(True)\n    def on_radioButton_6_clicked(self):\n        if self.radioButton_1.isChecked():\n            self.radioButton_2.setChecked(True)\n    def on_radioButton_7_clicked(self):\n        if self.radioButton_1.isChecked():\n            self.radioButton_2.setChecked(True)\n    def on_radioButton_8_clicked(self):\n        if self.radioButton_1.isChecked():\n            self.radioButton_2.setChecked(True)\n    # Boutons\n    def on_pushButton_1_clicked(self):    # Bouton Quitte la fonction\n        App.Console.PrintMessage(\"Termin\u00e9\\r\\n\")\n        self.window.hide()\n \n    def on_pushButton_2_clicked(self):    # Bouton Appliquer\n        if self.radioButton_1.isChecked():\n            vueChoix=0\n        if self.radioButton_2.isChecked():\n            vueChoix=1\n        if self.radioButton_3.isChecked():\n            vueChoix=2\n        if self.radioButton_4.isChecked():\n            vueChoix=3\n \n        if self.radioButton_5.isChecked():\n            alignerSur=0\n        if self.radioButton_6.isChecked():\n            alignerSur=1\n        if self.radioButton_7.isChecked():\n            alignerSur=2\n        if self.radioButton_8.isChecked():\n            alignerSur=3\n \n        if self.checkBox_1.checkState()==0:\n            afficherPoint=0\n        else:\n            afficherPoint=1\n        if self.checkBox_2.checkState()==0:\n            colorer=0\n        else:\n            colorer=1\n \n        # App.Console.PrintMessage(\"Appliquer\\r\\n\")\n        # App.Console.PrintMessage(str(vueChoix)+\" \\t\")\n        # App.Console.PrintMessage(str(alignerSur)+\" \\t\")\n        # App.Console.PrintMessage(str(afficherPoint)+\" \\t\")\n        # App.Console.PrintMessage(str(colorer)+\" \\r\\n\")\n \n        def errorDialog(msg):\n            # Create a simple dialog QMessageBox\n            # The first argument indicates the icon used: one of QtGui.QMessageBox.{NoIcon, Information, Warning, Critical, Question} \n            diag = QtGui.QMessageBox(QtGui.QMessageBox.Critical,u\"Error Message\",msg)\n            try:\n                diag.setWindowFlags(PyQt4.QtCore.Qt.WindowStaysOnTopHint) # PyQt4 cette fonction met la fen\u00eatre en avant\n            except Exception:\n                diag.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint) # PySide cette fonction met la fen\u00eatre en avant\n            #diag.setWindowModality(QtCore.Qt.ApplicationModal) # la fonction a \u00e9t\u00e9 d\u00e9sactiv\u00e9e pour favoriser \"WindowStaysOnTopHint\"\n            diag.exec_()\n \n        def affiche(x,y,z,rayon,r,v,b,afficherPoint,angle):\n            pl.Base=FreeCAD.Vector(x,y,z)\n            Draft.makeCircle((rayon),placement=pl,face=False,support=None)\n            if colorer==1:    \n                FreeCADGui.activeDocument().activeObject().LineColor = (r,v,b)\n            if afficherPoint==1:\n                Draft.makePoint(x,y,z)\n                if colorer==1:\n                    FreeCADGui.activeDocument().activeObject().PointColor = (r,v,b)\n            str(self.lineEdit_1.setText(str(x)))\n            str(self.lineEdit_2.setText(str(y)))\n            str(self.lineEdit_3.setText(str(z)))\n            str(self.lineEdit_4.setText(str(rayon)))\n            str(self.lineEdit_5.setText(str(angle)))\n \n        # prendre les objets selectionnes\n        sel = FreeCADGui.Selection.getSelection()           \n        i=0\n        centreX=0;centreY=0;rayon=0\n \n        # S'il y a 3 points s\u00e9lectionn\u00e9s alors..\n        if len(sel)==3 :\n            i=0\n            ta=[0,0,0,0,0,0,0,0,0]\n            for obj in sel:\n                x=(obj.Shape.BoundBox.Center)\n                ta[i+0]=(x.x)\n                ta[i+1]=(x.y)\n                ta[i+2]=(x.z)\n                i=i+3\n \n            if vueChoix==3:        # Vue de droite ZY (Rouge)\n                z_point_1=ta[0]\n                x_point_1=ta[1]\n                y_point_1=ta[2]\n \n                z_point_2=ta[3]\n                x_point_2=ta[4]\n                y_point_2=ta[5]\n \n                z_point_3=ta[6]\n                x_point_3=ta[7]\n                y_point_3=ta[8]\n \n            elif vueChoix==2:    # Vue de face ZX (Vert)\n                y_point_1=ta[0]\n                z_point_1=ta[1]\n                x_point_1=ta[2]\n \n                y_point_2=ta[3]\n                z_point_2=ta[4]\n                x_point_2=ta[5]\n \n                y_point_3=ta[6]\n                z_point_3=ta[7]\n                x_point_3=ta[8]\n \n            else:                # Vue de dessus XY (Bleu)\n                x_point_1=ta[0]\n                y_point_1=ta[1]\n                z_point_1=ta[2]\n \n                x_point_2=ta[3]\n                y_point_2=ta[4]\n                z_point_2=ta[5]\n \n                x_point_3=ta[6]\n                y_point_3=ta[7]\n                z_point_3=ta[8]\n \n            # Calcul des coordonn\u00e9es du centre du cercle    \n            try:\n                centreX =((x_point_3**2-x_point_2**2+y_point_3**2-y_point_2**2)/(2*(y_point_3-y_point_2))-(x_point_2**2-x_point_1**2+y_point_2**2-y_point_1**2)/(2*(y_point_2-y_point_1)))/((x_point_3-x_point_2)/(y_point_3-y_point_2)-(x_point_2-x_point_1)/(y_point_2-y_point_1))\n                centreY =-(x_point_2-x_point_1)/(y_point_2-y_point_1)*centreX+(x_point_2**2-x_point_1**2+y_point_2**2-y_point_1**2)/(2*(y_point_2-y_point_1))\n                rayon =sqrt((x_point_1-centreX)**2+(y_point_1-centreY)**2)\n            except:\n                errorDialog(u\"Calcul impossible trop d'\u00e9lements align\u00e9s\")\n            else:\n            #finally: # si finally est pr\u00e9sent, il sera TOUJOURS ex\u00e9cut\u00e9\n               # D\u00e9finition de la coordonn\u00e9e Z\n                centreZ=0\n                # Cr\u00e9ation du cercle\n                pl=FreeCAD.Placement()\n                if vueChoix==1:    # Plan XY Dessus\n                    pl.Rotation.Q=(0,0,0,1.0)\n                    if alignerSur==1:    \n                        affiche(centreX,centreY,z_point_1,rayon,0.0,0.0,1.0,afficherPoint,0)\n                    elif alignerSur==2:\n                        affiche(centreX,centreY,z_point_2,rayon,0.0,0.0,1.0,afficherPoint,0)\n                    elif alignerSur==3:\n                        affiche(centreX,centreY,z_point_3,rayon,0.0,0.0,1.0,afficherPoint,0)\n                elif vueChoix==2:    # Plan XZ Face\n                    pl.Rotation.Q=(1,0,0,1.0)\n                    if alignerSur==1:    \n                        affiche(centreY,z_point_1,centreX,rayon,0.0,1.0,0.0,afficherPoint,0)\n                    elif alignerSur==2:\n                        affiche(centreY,z_point_2,centreX,rayon,0.0,1.0,0.0,afficherPoint,0)\n                    elif alignerSur==3:\n                        affiche(centreY,z_point_3,centreX,rayon,0.0,1.0,0.0,afficherPoint,0)\n                elif vueChoix==3:    # Plan YZ Droite\n                    pl.Rotation.Q=(0,1,0,1.0)\n                    if alignerSur==1:    \n                        affiche(z_point_1,centreX,centreY,rayon,1.0,0.0,0.0,afficherPoint,0)\n                    elif alignerSur==2:\n                        affiche(z_point_2,centreX,centreY,rayon,1.0,0.0,0.0,afficherPoint,0)\n                    elif alignerSur==3:\n                        affiche(z_point_3,centreX,centreY,rayon,1.0,0.0,0.0,afficherPoint,0)\n                else:    # 3D XYZ\n                    P1 = sel[0].Shape.BoundBox.Center\n                    P2 = sel[1].Shape.BoundBox.Center\n                    P3 = sel[2].Shape.BoundBox.Center\n \n                    P1P2 = (P2 - P1).Length\n                    P2P3 = (P3 - P2).Length\n                    P3P1 = (P1 - P3).Length\n \n                    # Circle radius.\n                    l = ((P1 - P2).cross(P2 - P3)).Length\n                    try:\n                    #if l < 1e-8:\n                    #    errorDialog(\"The three points are aligned\")\n                        r = P1P2 * P2P3 * P3P1 / 2 / l\n                    except:\n                        errorDialog(\"The three points are aligned\")\n                    else:\n                        # Sphere center.\n                        a = P2P3**2 * (P1 - P2).dot(P1 - P3) / 2 / l**2\n                        b = P3P1**2 * (P2 - P1).dot(P2 - P3) / 2 / l**2\n                        c = P1P2**2 * (P3 - P1).dot(P3 - P2) / 2 / l**2\n                        P1.multiply(a)\n                        P2.multiply(b)\n                        P3.multiply(c)\n                        PC = P1 + P2 + P3\n \n                        # Creation of a circle\n                        pl = Base.Placement()\n                        v = (P1 - P2).cross(P3 - P2)\n                        v.normalize()\n                        axis = Base.Vector(0, 0, 1).cross(v)\n                        angle = asin(axis.Length) * 180 / pi\n                        axis.normalize()\n                        pl = Base.Placement(PC, axis, angle)\n                        affiche((PC.x),(PC.y),(PC.z),r,0.0,0.0,0.0,afficherPoint,angle)\n \n        else:\n            # Si la condition n'est pas remplie, recommencer\n            errorDialog(u\"S\u00e9lectionnez 3 points et recommencez\")\n            #FreeCAD.Console.PrintError(\"S\u00e9lectionnez 3 points et recommencez\\r\\n\")\n#________________________________________________________________________________\n    def on_pushButton_3_clicked(self):    # Valeurs d'origine\n        App.Console.PrintMessage(\"D\u00e9faut\\r\\n\")\n        vueChoix=0\t\t# choix de la vue Dessus=1 XY, vue Face=2 ZX, vue Droite=3 ZY\n        self.radioButton_1.setChecked(True)\n        alignerSur=0\t# aligne le cercle sur une forme au choix (1,2 ou 3) ou sur Z=0\n        self.radioButton_5.setChecked(True)\n        afficherPoint=1\t# affiche le point central du cercle\n        self.checkBox_1.setChecked(True)\n        colorer=1\t\t# colorer suivant l'axe 1=Ok 0=Couleur courante uniquement Orthogonal !\n        self.checkBox_2.setChecked(True)\n \n#______________________________________________________________________________________\n \nMainWindow = QtGui.QMainWindow()\nui = Ui_MainWindow(MainWindow)\nMainWindow.show()",
    "url": "https://wiki.freecad.org/Macro_Make_Circle_3_Points",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-08-08",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Make_Circle_3_Points.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/c/c7/Macro_Make_Circle_3_Points.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "export transient FEM results",
    "on_wiki": true,
    "on_git": false,
    "desc": "Export multiple FEM results from a transient analysis for post-processing in ParaView.<br /><br />Macro version: 0.1<br />Last modified: 2019-08-30<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://drive.google.com/file/d/1MSBxLPlQ-TwzF-sFkgOeFb48zij5_scp/view?usp=sharing\">Macro file (3 kB)</a><br /><a rel=\"nofollow\" class=\"external text\" href=\"https://drive.google.com/file/d/1m3RiJ-JM7QSJ6YDhZnafHIbyL92V6sYU/view?usp=sharing\">Example file without results (200 kB)</a><br /><a rel=\"nofollow\" class=\"external text\" href=\"https://drive.google.com/file/d/157aIdVpIyfpVW9WxL-ReGz0FIsQebH_q/view?usp=sharing\">Example file with results (10 MB)</a><br /><a rel=\"nofollow\" class=\"external text\" href=\"https://drive.google.com/file/d/1g-QOJtl3G5KaY2bSrw03NNQ8mnfBi03T/view?usp=sharing\">All example files, including the vtk-export folder (21 MB)</a><br />Author: Luftschraube<br /> ",
    "comment": "Export multiple FEM results from a transient analysis for post-processing in ParaView.",
    "code": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n#\n# Macro to export multiple FEM results objects from a transient analysis for\n# post-processing in ParaView.\n#\n# Created by <Luftschraube> under the GNU Lesser General Public License (LGPL)\n#\n# Version 0.1 (30.08.2019)\n#\n\nimport FreeCAD\nimport Fem\nimport feminout.importVTKResults\nimport os\nfrom sys import exit\n\nFreeCAD.Console.PrintMessage(\">>>---------Macro started\\n\")\n\n#Get the file path and name of the active document \np = FreeCAD.ActiveDocument.FileName\nFilePath = \"/\".join(p.split(\"/\")[:-1])\nFileName = p.split(\"/\")[-1].split(\".\")[0]\nFreeCAD.Console.PrintMessage(\"File path:\" + FilePath + \"\\n\")\nFreeCAD.Console.PrintMessage(\"File name:\" + FileName + \"\\n\")\nFreeCAD.Console.PrintMessage(\"\\n<<<----------Macro finished with errors\\n\")\n\n#Get FEM result objects into a list\nFreeCAD.Console.PrintMessage(\"Looking for result objects...\")\nFEMResultObjects = []\n\nfor obj in App.ActiveDocument.Objects:\n\tif obj.TypeId == \"Fem::FemResultObjectPython\":\t\n\t\tFEMResultObjects.append(obj.Label)\n\t\t#FreeCAD.Console.PrintMessage(obj.Label + '\\n')\n\nNumberOfResultObjects = len(FEMResultObjects)\nFreeCAD.Console.PrintMessage(str(NumberOfResultObjects) + \" found\\n\")\n\nif NumberOfResultObjects > 0:\n\t\n\t#Export result objects as .vtu file and generate .pvu file\n\tExportFolderName = \"vtk-export\"\n\tExportOutputPath = FilePath + \"/\" + ExportFolderName\n\tif not os.path.exists(ExportOutputPath):\n\t\tos.makedirs(ExportOutputPath)\n\t\tFreeCAD.Console.PrintMessage(ExportOutputPath + \" has been created\\n\")\n\telse:\n\t\tFreeCAD.Console.PrintMessage(ExportOutputPath + \" already exists\\n\")\n\t\n\tPVUFile = open(ExportOutputPath + \"/\" + FileName + \".pvd\",\"w\")\n\tPVUFile.write(\"<VTKFile type=\\\"Collection\\\" version=\\\"1.0\\\" byte_order=\\\"LittleEndian\\\" header_type=\\\"UInt64\\\">\\n\\t<Collection>\\n\")\n\t\n\tn = 0\n\tfor ExportObject in sorted(FEMResultObjects):\n\t\tn = n + 1\n\t\t\n\t\t#Read and format time stamp (e.g., 12.37 s = 0001237)\n\t\tFreeCADResultLabelParts = ExportObject.split(\"_\")\n\t\tPreDecimal = FreeCADResultLabelParts[-3]\n\t\tPostDecimal = FreeCADResultLabelParts[-2]\n\n\t\tif len(PostDecimal) == 1:\n\t\t\tPostDecimal = PostDecimal + str(0)\n\t\tTimeValue = float(PreDecimal) + float(PostDecimal)/100\n\t\tTimeString = str(int(round(TimeValue*100,0))).zfill(7)\n\t\n\t\t#For some reason, the VTK exporter expects a list (although only one object is processed at once...) - so build a list with the current object\n\t\tExportObjectList = []\n\t\tExportObjectList.append(FreeCAD.ActiveDocument.getObject(ExportObject))\n\t\tFileNameOUT = FileName + \"_\" + TimeString + \".vtu\"\n\t\tFilePath = ExportOutputPath + \"/\" + FileNameOUT\n\t\tFreeCAD.Console.PrintMessage(FilePath + \" is to be created\\n\")\n\t\tfeminout.importVTKResults.export(ExportObjectList,FilePath)\n\t\n\t\tPVUFile.write(\"\\t\\t<DataSet timestep=\\\"\" + str(TimeValue) + \"\\\" file=\\\"\" + FileNameOUT + \"\\\"/>\\n\")\n\t\n\t#Close the .pvu file\n\tPVUFile.write(\"\\t</Collection>\\n</VTKFile>\")\n\tPVUFile.close()\nelse:\n\tFreeCAD.Console.PrintMessage(\"Nothing to export!\")\n\nFreeCAD.Console.PrintMessage('\\n<<<----------Macro finished\\n')",
    "url": "https://wiki.freecad.org/Macro_export_transient_FEM_results",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2019-08-30",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Luftschraube",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "MacroMenu",
    "on_wiki": true,
    "on_git": false,
    "desc": "Adds the macros found in the macros folder to the FreeCAD Macros menu<br /><br />Macro version: 1.0<br />Last modified: 2014-08-07<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/1/1e/Macro_MacroMenu.png\">ToolBar Icon</a><br />Author: Yorik<br /> ",
    "comment": "Adds the macros found in the macros folder to the FreeCAD Macros menu",
    "code": "import os,FreeCAD,FreeCADGui\n \nmacrosList = []\nmacroPath = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\").GetString(\"MacroPath\") \n \nclass MacroCommand():\n    \"A template for macro commands\"\n    def __init__(self,macroname):\n        self.macroname = macroname\n \n    def GetResources(self):\n        return {'Pixmap'  : 'Draft_Macro',\n                'MenuText': self.macroname,\n                'ToolTip': 'Executes the '+self.macroname+' macro'}\n \n    def Activated(self):\n        target = macroPath+os.sep+self.macroname+'.FCMacro'\n        if os.path.exists(target): execfile(target)\n            \nif macroPath and os.path.isdir(macroPath):\n    macros = []\n    for f in os.listdir(macroPath):\n        if \".FCMacro\" in f:\n            macros.append(f[:-8])\n    for m in macros:\n        cmd = 'Macro_'+m\n        FreeCADGui.addCommand(cmd,MacroCommand(m))\n        macrosList.append(cmd)",
    "url": "https://wiki.freecad.org/Macro_MacroMenu",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-08-07",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Yorik",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_MacroMenu.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/1/1e/Macro_MacroMenu.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Toggle Panels Visibility",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro toggles the visibility of various supporting views in FreeCAD, allowing the main window to be viewed with all available screen space.<br /><br />Macro version: 1.0<br />Last modified: 2015-01-17<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/d/d0/Macro_Toggle_Views_Visibility.png\">ToolBar Icon</a><br />Author: Piffpoof<br /> ",
    "comment": "This macro toggles the visibility of various supporting views in FreeCAD, allowing the main window to be viewed with all available screen space.",
    "code": "# -*- coding: utf-8 -*-\n# macro to toggle visibility of Report view, Python console, Combo view\nfrom PySide import QtCore, QtGui\nmainWindow = FreeCADGui.getMainWindow()\ndockWidgets = mainWindow.findChildren(QtGui.QDockWidget)\nfor dw in dockWidgets:\n    if dw.objectName() == \"Python console\":\n        pcWidget = dw\n    if dw.objectName() == \"Combo View\":\n        cvWidget = dw\n    if dw.objectName() == \"Report view\":\n        rvWidget = dw\n     \nif pcWidget.isVisible():\n    pcWidget.hide()\n    cvWidget.hide()\n    rvWidget.hide()\nelse:\n    pcWidget.show()\n    cvWidget.show()\n    rvWidget.show()",
    "url": "https://wiki.freecad.org/Macro_Toggle_Panels_Visibility",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2015-01-17",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Piffpoof",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Toggle_Views_Visibility.png",
    "icon_source": "https://wiki.freecad.org/images/d/d0/Macro_Toggle_Views_Visibility.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "MacroToolbarManager",
    "on_wiki": true,
    "on_git": false,
    "desc": "Easily manage custom macro toolbars<br /><br />Macro version: 0.2023.10.27<br />Last modified: 2023-10-27<br />FreeCAD version: Python 3 versions<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/File:MacroToolbarManager_icon.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Easily manage custom macro toolbars",
    "code": "\n\n# This code is copied instead of the original macro code\n# to guide the user to the online download page.\n# Use it if the code of the macro is larger than 64 KB and cannot be included in the wiki\n# or if the RAW code URL is somewhere else in the wiki.\n\nfrom PySide import QtGui, QtCore\n\ndiag = QtGui.QMessageBox(QtGui.QMessageBox.Information,\n    \"Information\",\n    \"This macro must be downloaded from this link\\n\"\n    \"\\n\"\n    \"https://gist.github.com/mwganson/3464e2d54e859ee94ec8d7ce20c75660/raw/5bcd7bff7b451709ff300e3ee1269ff379c9b087/MacroToolbarManager.FCMacro\" + \"\\n\"\n    \"\\n\"\n    \"Quit this window to access the download page\")\n\ndiag.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)\ndiag.setWindowModality(QtCore.Qt.ApplicationModal)\ndiag.exec_()\n\nimport webbrowser \nwebbrowser.open(\"https://gist.github.com/mwganson/3464e2d54e859ee94ec8d7ce20c75660/raw/5bcd7bff7b451709ff300e3ee1269ff379c9b087/MacroToolbarManager.FCMacro\")\n",
    "url": "https://wiki.freecad.org/Macro_MacroToolbarManager",
    "raw_code_url": "https://gist.github.com/mwganson/3464e2d54e859ee94ec8d7ce20c75660/raw/5bcd7bff7b451709ff300e3ee1269ff379c9b087/MacroToolbarManager.FCMacro",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2023-10-27",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\MacroToolbarManager_icon.svg",
    "icon_source": "https://wiki.freecad.org//images/5/56/MacroToolbarManager_icon.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "BoundingBox Tracing",
    "on_wiki": true,
    "on_git": false,
    "desc": "Creates a red outline of the BoundingBox (6 Faces with 6 rectangles) of an object, display the dimension of the rectangle, create volume of boundBox.<br /><br />Macro version: 0.12<br />Last modified: 2021/07/10<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/6/60/BoundBoxTracing.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Creates a red outline of the BoundingBox (6 Faces with 6 rectangles) of an object, display the dimension of the rectangle, create volume of boundBox.",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\n# cette macro trace en rouge (modifiable) le tour du boundingbox avec 6 rectangles\n# si \"createVol\" = 1 il sera cree un volume (rouge) de la dimension du BoundBox\n# this macro red trace (editable) around the BoundingBox with 6 rectangles\n# if \"createVol\" = 1 on volume (red) is created \n# Macro_BoundingBox_Tracing\n#\n#OS: Windows Vista     #OS: Windows 8.1                                #OS: Windows 10                                 #OS: Windows 10\n#Platform: 32-bit      #Word size of OS: 64-bit                        #Word size of OS: 64-bit                        #Word size of OS: 64-bit\n#Version: 0.14.3389    #Word size of FreeCAD: 64-bit                   #Word size of FreeCAD: 64-bit                   #Word size of FreeCAD: 64-bit\n#Python version: 2.6.2 #Version: 0.15.4671 (Git)                       #Version: 0.16.6700 (Git)                       #Version: 0.17.13528 (Git)\n#Qt version: 4.5.2     #Branch: releases/FreeCAD-0-15                  #Build type: Release                            #Build type: Release\n#Coin version: 3.1.0   #Hash: 244b3aef360841646cbfe80a1b225c8b39c8380c #Branch: releases/FreeCAD-0-16                  #Branch: releases/FreeCAD-0-17\n#SoQt version: 1.4.1   #Python version: 2.7.8                          #Hash: 7b925d11aa69ac405b423635adb1e2833f18a817 #Hash: 5c3f7bf8ec51e2c7187789f7edba71a7aa82a88b\n#OCC version: 6.5.1    #Qt version: 4.8.6                              #Python version: 2.7.8                          #Python version: 2.7.14\n#                      #Coin version: 4.0.0a                           #Qt version: 4.8.6                              #Qt version: 4.8.7\n#                      #OCC version: 6.8.0.oce-0.17                    #Coin version: 4.0.0a                           #Coin version: 4.0.0a\n#                                                                      #OCC version: 6.8.0.oce-0.17                    #OCC version: 7.2.0\n###############################################################################################################################################\n#OS: Windows 10 (10.0)                                #OS: Windows 10 (10.0)\n#Word size of OS: 64-bit                              #Word size of FreeCAD: 64-bit\n#Word size of FreeCAD: 64-bit                         #Version: 0.20.25131 (Git)\n#Version: 0.19.16624 (Git)                            #Build type: Release\n#Build type: Release                                  #Branch: master\n#Branch: master                                       #Hash: 7c519689f0d5ea78fb3292be36a857d283c05507\n#Hash: 222ae7305fdf1097e4ef3d050f69dff47dbd8786       #Python version: 3.8.10\n#Python version: 3.6.8                                #Qt version: 5.12.9\n#Qt version: 5.12.1                                   #Coin version: 4.0.0\n#Coin version: 4.0.0a                                 #OCC version: 7.5.2\n#OCC version: 7.3.0                                   #Locale: French/Mars (fr_MA)\n###############################################################################################################################################\n#\n#2021/07/10 modified by edwilliams16 to handle objects in nested part containers\n#https://forum.freecadweb.org/viewtopic.php?f=22&t=59852\n#\n__title__   = \"BoundingBox_Tracing\"\n__author__  = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__Wiki__    = \"https://www.freecadweb.org/wiki/Macro_BoundingBox_Tracing\"\n__version__ = \"0.12\"\n__date__    = \"2021/07/10\" #  YYYY/MM/DD\n\n\nimport PySide\nimport FreeCAD, FreeCADGui, Draft, Part\nApp = FreeCAD\nimport sys\n\ndebug = False\nif debug:\n    from sys import path\n    sys.path.append('/Users/ed/opt/anaconda3/lib/python3.7/site-packages')\n    import ptvsd\n    print(\"Waiting for debugger attach\")\n    # 5678 is the default attach port in the VS Code debug configurations\n    ptvsd.enable_attach(address=('localhost', 5678), redirect_output=True)\n    ptvsd.wait_for_attach()\n\n##### Section configuration begin ##################\n##### for volume begin ###################\ncreateVol         = 1           # give 1 for create Volume # mettre a 1 pour creer un volume\ncreateDimVol      = 1           # 1 = create dimension info : 0 = not dimension info\n##### for volume end   ###################\n\n##### for dimensions info begin ##########\ncreateDim         = 1           # 1 = create dimension info : 0 = not create dimension info\n\nif int(FreeCAD.Version()[1]) > 17:      # Version de FreeCAD\n    DisplayModeText   = str(u\"3D text\") # available : u\"2D text\" or u\"3D text\" \nelse:\n    DisplayModeText   = str(u\"Screen\")  # available : u\"Screen\" or u\"World\" \n\nJustificationText = str(u\"Center\")    # available : \"Center\" or \"Left\" or \"Right\"\nFontSizeText      = 3.0         # text info dimension\nTextColorText_R   = 0.0         # text color info red      1 = 255\nTextColorText_G   = 0.0         # text color info green    1 = 255\nTextColorText_B   = 0.0         # text color info blue     1 = 255\narondi            = 3           # round the info ex: 3 = 3 decimals\n\n##### for dimensions info end   ##########\n##### Section configuration end ####################\n\n\ndef adjustedGlobalPlacement(obj, locVector):\n    '''find global placement to make locVector the local origin with the correct orientation'''\n    try:\n        objectPlacement = obj.Shape.Placement\n        objectGlobalPlacement = obj.getGlobalPlacement()\n        locPlacement = App.Placement(locVector, App.Rotation(App.Vector(1,0,0),0))\n        return objectGlobalPlacement.multiply(objectPlacement.inverse()).multiply(locPlacement)\n    except Exception:\n        locPlacement = App.Placement(App.Vector(0,0,0), App.Rotation(0,0,0), App.Vector(0,0,0))\n        return locPlacement\n\n\nsel   = FreeCADGui.Selection.getSelection()\nselEx = FreeCADGui.Selection.getSelectionEx()\nobjs  = [selobj.Object for selobj in selEx]\n    \nif len(objs) >= 1:\n    if hasattr(objs[0], \"Shape\"):\n        s = objs[0].Shape\n    elif hasattr(objs[0], \"Mesh\"):      # upgrade with wmayer thanks #http://forum.freecadweb.org/viewtopic.php?f=13&t=22331\n        s = objs[0].Mesh\n    elif hasattr(objs[0], \"Points\"):\n        s = objs[0].Points\n\n    try:\n        # LineColor\n        red   = 1.0  # 1 = 255\n        green = 0.0  #\n        blue  = 0.0  #\n    \n        # boundBox\n        boundBox_    = s.BoundBox\n        boundBoxLX   = boundBox_.XLength\n        boundBoxLY   = boundBox_.YLength\n        boundBoxLZ   = boundBox_.ZLength\n        boundBoxXMin = boundBox_.XMin\n        boundBoxYMin = boundBox_.YMin\n        boundBoxZMin = boundBox_.ZMin\n        boundBoxLocation = App.Vector(boundBox_.XMin,boundBox_.YMin,boundBox_.ZMin)\n        nameLabel  = sel[0].Label\n\n        try:\n            import unicodedata    \n            nameLabel = str(unicodedata.normalize('NFKD', nameLabel).encode('ascii','ignore'))[2:]\n        except Exception:\n            None\n\n        App.Console.PrintMessage(str(boundBox_)+\"\\r\\n\")\n        App.Console.PrintMessage(\"Rectangle      : \"+str(boundBoxLX)+\" x \"+str(boundBoxLY)+\" x \"+str(boundBoxLZ)+\"\\r\\n\")\n        \n        if (createVol == 1) and (boundBoxLX > 0) and (boundBoxLY > 0) and (boundBoxLZ > 0):  # Create Volume\n            BDvol = App.ActiveDocument.addObject(\"Part::Box\",nameLabel + \"_BoundBoxVolume\")\n            #BDvol.Label = \"BoundBoxVolume\"\n            BDvol.Length.Value = boundBoxLX\n            BDvol.Width.Value  = boundBoxLY\n            BDvol.Height.Value = boundBoxLZ\n            BDvol.Placement = adjustedGlobalPlacement(objs[0], boundBoxLocation)\n            BDPl = BDvol.Placement\n            oripl_X=BDvol.Placement.Base.x\n            oripl_Y=BDvol.Placement.Base.y\n            oripl_Z=BDvol.Placement.Base.z\n            #if debug: print(f'global {globalObjectPlacement}\\n local {localObjectPlacement} BB {BBlocPlacement}')\n            FreeCADGui.ActiveDocument.getObject(BDvol.Name).LineColor  = (red, green, blue)\n            FreeCADGui.ActiveDocument.getObject(BDvol.Name).PointColor = (red, green, blue)\n            FreeCADGui.ActiveDocument.getObject(BDvol.Name).ShapeColor = (red, green, blue)\n            FreeCADGui.ActiveDocument.getObject(BDvol.Name).Transparency = 80\n            App.Console.PrintMessage(nameLabel + \"_BoundBoxVolume : \" + str(BDvol.Shape.Volume)+\"\\r\\n\")\n    \n            if createDimVol == 1:    # section create dimension info for volume\n                conteneurVol = []\n                del conteneurVol[:]\n                conteneurVol = App.activeDocument().addObject(\"App::DocumentObjectGroup\",nameLabel + \"_BoundBoxVolume_Info\")\n    \n                #pl_0C1 = Draft.make_text([str(round(boundBoxLX,arondi))],point=FreeCAD.Vector(oripl_X + (boundBoxLX/2), oripl_Y, oripl_Z))\n                pl_0C1 = Draft.make_text([str(round(boundBoxLX,arondi))],placement = BDPl.multVec(App.Vector(boundBoxLX/2,0,0)))\n                pl_0C1.ViewObject.DisplayMode   = DisplayModeText\n                pl_0C1.ViewObject.Justification = JustificationText\n                pl_0C1.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                pl_0C1.ViewObject.FontSize      = FontSizeText\n                pl_0C1.Label      = nameLabel + \"_Volume_X_\" + str(round(boundBoxLX,arondi))\n                conteneurVol.addObject(pl_0C1)\n    \n                #pl_0C2 = Draft.make_text([str(round(boundBoxLY,arondi))],point=FreeCAD.Vector(oripl_X, oripl_Y + (boundBoxLY/2), oripl_Z))\n                pl_0C2 = Draft.make_text([str(round(boundBoxLY,arondi))],placement = BDPl.multVec(App.Vector(0, boundBoxLY/2, 0)))\n                pl_0C2.ViewObject.DisplayMode   = DisplayModeText\n                pl_0C2.ViewObject.Justification = JustificationText\n                pl_0C2.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                pl_0C2.ViewObject.FontSize      = FontSizeText\n                pl_0C2.Label      = nameLabel + \"_Volume_Y_\" + str(round(boundBoxLY,arondi))\n                conteneurVol.addObject(pl_0C2)\n        \n                #pl_0C3 = Draft.make_text([str(round(boundBoxLZ,arondi))],placement=FreeCAD.Vector(oripl_X, oripl_Y, oripl_Z + (boundBoxLZ/2)))\n                pl_0C3 = Draft.make_text([str(round(boundBoxLZ,arondi))],placement = BDPl.multVec(App.Vector(0, 0, boundBoxLZ/2)))\n                pl_0C3.ViewObject.DisplayMode   = DisplayModeText\n                pl_0C3.ViewObject.Justification = JustificationText\n                pl_0C3.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                pl_0C3.ViewObject.FontSize      = FontSizeText\n                pl_0C3.Label      = nameLabel + \"_Volume_Z_\" + str(round(boundBoxLZ,arondi))\n                conteneurVol.addObject(pl_0C3)\n    \n    #    else:\n    #        App.Console.PrintMessage(\"Not Volume BoundBox possible\"+\"\\r\\n\")\n        App.Console.PrintMessage(\"_____________________\"+\"\\r\\n\")\n\n    \n        #####\n        conteneurRectangle = []\n        del conteneurRectangle[:]\n        conteneurRectangle = App.activeDocument().addObject(\"App::DocumentObjectGroup\",nameLabel + \"_BoundBoxRectangle\")\n    \n        if createDim == 1:    # conteneur dimension info\n            conteneurInfo = []\n            del conteneurInfo[:]\n            conteneurInfo = App.activeDocument().addObject(\"App::DocumentObjectGroup\",nameLabel + \"_BoundBoxRectangle_Info\")\n        try:\n            if (boundBoxLX and boundBoxLY) > 0.0:\n                #pl_0 = App.Placement(App.Vector(oripl_X,oripl_Y,oripl_Z), App.Rotation(0.0,0.0,0.0))\n                pl_0 = adjustedGlobalPlacement(objs[0], boundBoxLocation)\n                double = Draft.makeRectangle(length=boundBoxLX,height=boundBoxLY,placement=pl_0,face=False,support=None) #OK\n                double.Label = nameLabel + \"_BoundBoxRectangle_Bo\"\n                FreeCADGui.activeDocument().activeObject().LineColor = (red, green, blue)\n                conteneurRectangle.addObject(double)\n    #        else:\n    #            App.Console.PrintError(\"not value 0\"+\"\\n\")\n    \n            if createDim == 1:    # section create dimension info\n                #pl_0C1 = Draft.make_text([str(round(boundBoxLX,arondi))],placement=FreeCAD.Vector(pl_0.Base.x + (boundBoxLX/2), pl_0.Base.y, pl_0.Base.z))\n                # XY -> XY\n                pl_0C1 = Draft.make_text([str(round(boundBoxLX,arondi))],placement=pl_0.multVec(App.Vector(boundBoxLX/2, 0, 0)))\n                pl_0C1.ViewObject.DisplayMode   = DisplayModeText\n                pl_0C1.ViewObject.Justification = JustificationText\n                pl_0C1.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                pl_0C1.ViewObject.FontSize      = FontSizeText\n                pl_0C1.Label      = nameLabel + \"_Rectangle_Bo_0X_\" + str(round(boundBoxLX,arondi))\n                conteneurInfo.addObject(pl_0C1)\n        \n                #pl_0C2 = Draft.make_text([str(round(boundBoxLY,arondi))],placement=FreeCAD.Vector(pl_0.Base.x, pl_0.Base.y + (boundBoxLY/2), pl_0.Base.z))\n                pl_0C2 = Draft.make_text([str(round(boundBoxLY,arondi))],placement=pl_0.multVec(App.Vector(0., boundBoxLY/2, 0.)))\n                pl_0C2.ViewObject.DisplayMode   = DisplayModeText\n                pl_0C2.ViewObject.Justification = JustificationText\n                pl_0C2.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                pl_0C2.ViewObject.FontSize      = FontSizeText\n                pl_0C2.Label      = nameLabel + \"_Rectangle_Bo_0Y_\" + str(round(boundBoxLY,arondi))\n                conteneurInfo.addObject(pl_0C2)\n    \n        except:\n            App.Console.PrintError(\"not done 0\"+\"\\n\")\n\n        try:\n            if (boundBoxLX and boundBoxLY) > 0.0:\n                #pl_1 = App.Placement(App.Vector(oripl_X,oripl_Y,oripl_Z+boundBoxLZ), App.Rotation(0.0,0.0,0.0))\n                pl_1 =adjustedGlobalPlacement(objs[0], boundBoxLocation + App.Vector(0,0,boundBoxLZ))\n                double = Draft.makeRectangle(length=boundBoxLX,height=boundBoxLY,placement=pl_1,face=False,support=None) #Ok\n                double.Label = nameLabel + \"_BoundBoxRectangle_To\"\n                FreeCADGui.activeDocument().activeObject().LineColor = (red, green, blue)\n                conteneurRectangle.addObject(double)\n    #        else:\n    #            App.Console.PrintError(\"not value 1\"+\"\\n\")\n    \n            if createDim == 1:    # section create dimension info\n                #pl_0C1 = Draft.make_text([str(round(boundBoxLX,arondi))],placement=FreeCAD.Vector(pl_1.Base.x + (boundBoxLX/2), pl_1.Base.y, pl_1.Base.z))\n                #XY -> XY\n                pl_0C1 = Draft.make_text([str(round(boundBoxLX,arondi))],placement=pl_1.multVec(App.Vector(boundBoxLX/2, 0, 0)))\n                pl_0C1.ViewObject.DisplayMode   = DisplayModeText\n                pl_0C1.ViewObject.Justification = JustificationText\n                pl_0C1.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                pl_0C1.ViewObject.FontSize      = FontSizeText\n                pl_0C1.Label      = nameLabel + \"_Rectangle_To_1X_\" + str(round(boundBoxLX,arondi))\n                conteneurInfo.addObject(pl_0C1)\n        \n                #pl_0C2 = Draft.make_text([str(round(boundBoxLY,arondi))],placement=FreeCAD.Vector(pl_1.Base.x, pl_1.Base.y + (boundBoxLY/2), pl_1.Base.z))\n                pl_0C2 = Draft.make_text([str(round(boundBoxLY,arondi))],placement=pl_1.multVec(App.Vector(0., boundBoxLY/2, 0)))\n\n                pl_0C2.ViewObject.DisplayMode   = DisplayModeText\n                pl_0C2.ViewObject.Justification = JustificationText\n                pl_0C2.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                pl_0C2.ViewObject.FontSize      = FontSizeText\n                pl_0C2.Label      = nameLabel + \"_Rectangle_To_1Y_\" + str(round(boundBoxLY,arondi))\n                conteneurInfo.addObject(pl_0C2)\n    \n        except:\n            App.Console.PrintError(\"not done 1\"+\"\\n\")\n\n        try:\n            if (boundBoxLX and boundBoxLZ) > 0.0:\n                #pl_2 = App.Placement(App.Vector(oripl_X,oripl_Y,oripl_Z), App.Rotation(0.0,0.0,90))\n                pl_2 = pl_0.multiply(App.Placement(App.Vector(0.,0.,0.),App.Rotation(0.0,0.0,90)))\n                double = Draft.makeRectangle(length=boundBoxLX,height=boundBoxLZ,placement=pl_2,face=False,support=None) #Ok\n                double.Label = nameLabel + \"_BoundBoxRectangle_Fr\"\n                FreeCADGui.activeDocument().activeObject().LineColor = (red, green, blue)\n                conteneurRectangle.addObject(double)\n    #        else:\n    #            App.Console.PrintError(\"not value 2\"+\"\\n\")\n    \n            if createDim == 1:    # section create dimension info\n                #pl_0C1 = Draft.make_text([str(round(boundBoxLX,arondi))],placement=FreeCAD.Vector(pl_2.Base.x + (boundBoxLX/2), pl_2.Base.y, pl_2.Base.z))\n                #XZ -> XY\n                pl_0C1 = Draft.make_text([str(round(boundBoxLX,arondi))],placement=pl_2.multVec(App.Vector(boundBoxLX/2, 0, 0)))\n                pl_0C1.ViewObject.DisplayMode   = DisplayModeText\n                pl_0C1.ViewObject.Justification = JustificationText\n                pl_0C1.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                pl_0C1.ViewObject.FontSize      = FontSizeText\n                pl_0C1.Label      = nameLabel + \"_Rectangle_Fr_2X_\" + str(round(boundBoxLX,arondi))\n                conteneurInfo.addObject(pl_0C1)\n       \n                #pl_0C2 = Draft.make_text([str(round(boundBoxLZ,arondi))],placement=FreeCAD.Vector(pl_2.Base.x, pl_2.Base.y, pl_2.Base.z + (boundBoxLZ/2)))\n                pl_0C2 = Draft.make_text([str(round(boundBoxLZ,arondi))],placement=pl_2.multVec(App.Vector(0, boundBoxLZ/2, 0)))\n                pl_0C2.ViewObject.DisplayMode   = DisplayModeText\n                pl_0C2.ViewObject.Justification = JustificationText\n                pl_0C2.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                pl_0C2.ViewObject.FontSize      = FontSizeText\n                pl_0C2.Label      = nameLabel + \"_Rectangle_Fr_2Z_\" + str(round(boundBoxLZ,arondi))\n                conteneurInfo.addObject(pl_0C2)\n    \n        except:\n            App.Console.PrintError(\"not done 2\"+\"\\n\")\n\n        try:\n            if (boundBoxLX and boundBoxLZ) > 0.0:\n                #pl_3 = App.Placement(App.Vector(oripl_X,oripl_Y+boundBoxLY,oripl_Z), App.Rotation(0.0,0.0,90))\n                pl_3 = adjustedGlobalPlacement(objs[0], boundBoxLocation+App.Vector(0, boundBoxLY, 0)).multiply(App.Placement(App.Vector(0.,0.,0.),App.Rotation(0.0,0.0,90)))\n                double = Draft.makeRectangle(length=boundBoxLX,height=boundBoxLZ,placement=pl_3,face=False,support=None) #Ok\n                double.Label = nameLabel + \"_BoundBoxRectangle_Re\"\n                FreeCADGui.activeDocument().activeObject().LineColor = (red, green, blue)\n                conteneurRectangle.addObject(double)\n    #        else:\n    #            App.Console.PrintError(\"not value 3\"+\"\\n\")\n    \n            if createDim == 1:    # section create dimension info\n                #XZ -> XY\n                pl_0C1 = Draft.make_text([str(round(boundBoxLX,arondi))],placement=pl_3.multVec(App.Vector(boundBoxLX/2, 0, 0)))\n                pl_0C1.ViewObject.DisplayMode   = DisplayModeText\n                pl_0C1.ViewObject.Justification = JustificationText\n                pl_0C1.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                pl_0C1.ViewObject.FontSize      = FontSizeText\n                pl_0C1.Label      = nameLabel + \"_Rectangle_Re_3X_\" + str(round(boundBoxLX,arondi))\n                conteneurInfo.addObject(pl_0C1)\n        \n                pl_0C2 = Draft.make_text([str(round(boundBoxLZ,arondi))],placement=pl_3.multVec(App.Vector(0, boundBoxLZ/2, 0)))\n                pl_0C2.ViewObject.DisplayMode   = DisplayModeText\n                pl_0C2.ViewObject.Justification = JustificationText\n                pl_0C2.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                pl_0C2.ViewObject.FontSize      = FontSizeText\n                pl_0C2.Label      = nameLabel + \"_Rectangle_Re_3Z_\" + str(round(boundBoxLZ,arondi))\n                conteneurInfo.addObject(pl_0C2)\n    \n        except:\n            App.Console.PrintError(\"not done 3\"+\"\\n\")\n\n        try:\n            if (boundBoxLY and boundBoxLZ) > 0.0:\n                #pl_4 = App.Placement(App.Vector(oripl_X,oripl_Y,oripl_Z), App.Rotation(90,0.0,90))\n                pl_4 = pl_0.multiply(App.Placement(App.Vector(0.,0.,0.),App.Rotation(90,0,90)))\n                double = Draft.makeRectangle(length=boundBoxLY,height=boundBoxLZ,placement=pl_4,face=False,support=None) #Ok\n                double.Label = nameLabel + \"_BoundBoxRectangle_Le\"\n                FreeCADGui.activeDocument().activeObject().LineColor = (red, green, blue)\n                conteneurRectangle.addObject(double)\n    #        else:\n    #            App.Console.PrintError(\"not value 4\"+\"\\n\")\n    \n            if createDim == 1:    # section create dimension info\n                #pl_0C1 = Draft.make_text([str(round(boundBoxLY,arondi))],placement=FreeCAD.Vector(pl_4.Base.x, pl_4.Base.y + (boundBoxLY/2), pl_4.Base.z))\n                #YZ ->XY\n                pl_0C1 = Draft.make_text([str(round(boundBoxLY,arondi))],placement=pl_4.multVec(App.Vector(boundBoxLY/2, 0., 0.)))\n                pl_0C1.ViewObject.DisplayMode   = DisplayModeText\n                pl_0C1.ViewObject.Justification = JustificationText\n                pl_0C1.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                pl_0C1.ViewObject.FontSize      = FontSizeText\n                pl_0C1.Label      = nameLabel + \"_Rectangle_Le_4Y_\" + str(round(boundBoxLY,arondi))\n                conteneurInfo.addObject(pl_0C1)\n        \n                #pl_0C2 = Draft.make_text([str(round(boundBoxLZ,arondi))],placement=FreeCAD.Vector(pl_4.Base.x, pl_4.Base.y, pl_4.Base.z + (boundBoxLZ/2)))\n                pl_0C2 = Draft.make_text([str(round(boundBoxLZ,arondi))],placement=pl_4.multVec(App.Vector(0., boundBoxLZ/2, 0)))\n                pl_0C2.ViewObject.DisplayMode   = DisplayModeText\n                pl_0C2.ViewObject.Justification = JustificationText\n                pl_0C2.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                pl_0C2.ViewObject.FontSize      = FontSizeText\n                pl_0C2.Label      = nameLabel + \"_Rectangle_Le_4Z_\" + str(round(boundBoxLZ,arondi))\n                conteneurInfo.addObject(pl_0C2)\n    \n        except:\n            App.Console.PrintError(\"not done 4\"+\"\\n\")\n\n        try:\n            if (boundBoxLY and boundBoxLZ) > 0.0:\n                #pl_5 = App.Placement(App.Vector(oripl_X+boundBoxLX,oripl_Y,oripl_Z), App.Rotation(90,0.0,90))\n                pl_5 = adjustedGlobalPlacement(objs[0], boundBoxLocation+App.Vector(boundBoxLX,0,0)).multiply(App.Placement(App.Vector(0.,0.,0.),App.Rotation(90,0.0,90)))\n                double = Draft.makeRectangle(length=boundBoxLY,height=boundBoxLZ,placement=pl_5,face=False,support=None) #Ok\n                double.Label = nameLabel + \"_BoundBoxRectangle_Ri\"\n                FreeCADGui.activeDocument().activeObject().LineColor = (red, green, blue)\n                conteneurRectangle.addObject(double)\n    #            else:\n    #                App.Console.PrintError(\"not value 5\"+\"\\n\")\n    \n            if createDim == 1:    # section create dimension info\n                #YZ-> XY\n                pl_0C1 = Draft.make_text([str(round(boundBoxLY,arondi))],placement=pl_5.multVec(App.Vector(boundBoxLY/2, 0, 0)))\n                pl_0C1.ViewObject.Justification = JustificationText\n                pl_0C1.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                pl_0C1.ViewObject.FontSize      = FontSizeText\n                pl_0C1.Label      = nameLabel + \"_Rectangle_Ri_5Y_\" + str(round(boundBoxLY,arondi))\n                conteneurInfo.addObject(pl_0C1)\n        \n                pl_0C2 = Draft.make_text([str(round(boundBoxLZ,arondi))],placement=pl_5.multVec(App.Vector(0, boundBoxLZ/2, 0 )))\n                pl_0C2.ViewObject.DisplayMode   = DisplayModeText\n                pl_0C2.ViewObject.Justification = JustificationText\n                pl_0C2.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                pl_0C2.ViewObject.FontSize      = FontSizeText\n                pl_0C2.Label      = nameLabel + \"_Rectangle_Ri_5Z_\" + str(round(boundBoxLZ,arondi))\n                conteneurInfo.addObject(pl_0C2)\n    \n        except:\n            App.Console.PrintError(\"not done 5\"+\"\\n\")\n    \n        #####\n        App.ActiveDocument.recompute()\n    except Exception:\n        App.Console.PrintError(\"Bad selection\"+\"\\n\")\nelse:\n    App.Console.PrintMessage(\"Select an object !\"+\"\\n\")",
    "url": "https://wiki.freecad.org/Macro_BoundingBox_Tracing",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_BoundingBox_Tracing",
    "version": "0.12",
    "license": "",
    "date": "2021/07/10",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\BoundBoxTracing.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/6/60/BoundBoxTracing.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "CenterFace",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro red trace (editable) the center face (mass) with 1 point and print the coordinates.<br /><br />Macro version: 0.2<br />Last modified: 2018-10-07<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/1/16/CenterFace.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "select a face launch and list the center coordinate XYZ of face",
    "code": "# -*- coding: utf-8 -*-\n\n#OS: Windows Vista     #OS: Windows 10\n#Platform: 32-bit      #Word size of OS: 64-bit\n#Version: 0.14.3389    #Word size of FreeCAD: 64-bit\n#Python version: 2.6.2 #Version: 0.17.13528 (Git)\n#Qt version: 4.5.2     #Build type: Release\n#Coin version: 3.1.0   #Branch: releases/FreeCAD-0-17\n#SoQt version: 1.4.1   #Hash: 5c3f7bf8ec51e2c7187789f7edba71a7aa82a88b\n#OCC version: 6.5.1    #Python version: 2.7.14\n                       #Qt version: 4.8.7\n                       #Coin version: 4.0.0a\n                       #OCC version: 7.2.0\n\n# 29/04/2014, 07/10/2018\n__title__   = \"Macro_CenterFace\"\n__author__  = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__Wiki__    = \"https://www.freecadweb.org/wiki/Macro_CenterFace\"\n__version__ = \"00.02\"\n__date__    = \"07/10/2018\"\n__Comment__ = \"select a face launch and list the center coordinate XYZ of face\"\n\nimport FreeCAD, FreeCADGui, Draft, Part\n\ndef objectRealPlacement3D(obj):    # search the real Placement\n    try:\n        objectPlacement      = obj.Shape.Placement\n        objectPlacementBase  = FreeCAD.Vector(objectPlacement.Base)\n\n        #### \n        objectWorkCenter     = objectPlacementBase\n        ####\n        \n        if hasattr(obj, \"getGlobalPlacement\"):\n            globalPlacement       = obj.getGlobalPlacement()\n            globalPlacementBase   = FreeCAD.Vector(globalPlacement.Base)\n            ####\n            objectRealPlacement3D = globalPlacementBase.sub(objectWorkCenter)#mode=0 adapte pour BBox + Centerpoints\n            ####\n        else:\n            objectRealPlacement3D = objectWorkCenter\n        \n        return objectRealPlacement3D\n    except Exception:\n        return FreeCAD.Vector(0.0, 0.0, 0.0)\n\n\ntry:\n    sel = FreeCADGui.Selection.getSelection()       # get the selection\n    sh = sel[0]                                     # seletion of the first element\n    \n    App.Console.PrintMessage( \"__Begin__________\"+\"\\n\")\n    import unicodedata    \n    nameLabel  = unicodedata.normalize('NFKD', sh.Label).encode('ascii','ignore')\n    App.Console.PrintMessage(\"Label : \"+ str(nameLabel)+\"\\n\")        # extract the Label\n    App.Console.PrintMessage(\"Name  : \"+ str(sel[0].Name) +\"\\n\")     # extract the Name\nexcept:\n    App.Console.PrintError( \"Select a face\"+\"\\n\")\n\ntry:\n    SubElement = FreeCADGui.Selection.getSelectionEx()# \"getSelectionEx\" Used for selecting subobjects\n    element_ = SubElement[0].SubElementNames[0]       # seletion of the first element\n    \n    #print element_\n    #print sh.Faces\n    # LineColor\n    red   = 1.0  # 1 = 255\n    green = 0.0  #\n    blue  = 0.0  #\n\n    for i in range(len(sh.Shape.Faces)):                    # list and extract the data\n\n        oripl_X = sh.Shape.Faces[i].CenterOfMass.x\n        oripl_Y = sh.Shape.Faces[i].CenterOfMass.y\n        oripl_Z = sh.Shape.Faces[i].CenterOfMass.z\n        placementOrigine = objectRealPlacement3D( sh )\n        oripl_X += placementOrigine[0]\n        oripl_Y += placementOrigine[1]\n        oripl_Z += placementOrigine[2]\n\n        App.Console.PrintMessage( \"Center Face \"+str(i)+\"    : \"+str(sh.Shape.Faces[i].CenterOfMass)+\"\\n\") # Vector center mass to face\n        App.Console.PrintMessage( \"GlobalPlacement  : \"+str(placementOrigine)+\"\\n\") # Vector center mass to face\n        Draft.makePoint(oripl_X, oripl_Y, oripl_Z) # create a point\n        FreeCADGui.activeDocument().activeObject().PointColor = (red, green, blue)\n    \n        App.Console.PrintMessage( \"       Surface   : \"+str(sel[0].Shape.Faces[i-1].Area)+\"\\n\")\n        fco = 0\n        for f0 in sel[0].Shape.Faces[i].Vertexes:      # Vertexes faces\n            fco += 1\n            App.Console.PrintMessage(\"       Vertexe X\"+str(fco)+\": \"+str(f0.Point.x)+\" Y\"+str(fco)+\": \"+str(f0.Point.y)+\" Z\"+str(fco)+\": \"+str(f0.Point.z)+\"\\n\")\n\nexcept:\n    App.Console.PrintError( \"Select a face *\"+\"\\n\")\nApp.Console.PrintMessage( \"__End____________\"+\"\\n\")",
    "url": "https://wiki.freecad.org/Macro_CenterFace",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_CenterFace",
    "version": "00.02",
    "license": "",
    "date": "07/10/2018",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\CenterFace.png",
    "icon_source": "https://wiki.freecad.org/images/1/16/CenterFace.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "cross section",
    "on_wiki": true,
    "on_git": false,
    "desc": "Macro to display a cross-section of the objects in the scene: the cross-section plane can be moved by a slider bar.<br /><br />Macro version: 0.10<br />Last modified: 2020-12-19<br />FreeCAD version: 0.15 and above<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/f/f5/Macro_cross_section.png\">ToolBar Icon</a><br />Author: aleph0<br /> ",
    "comment": "Dynamic cross section viewer",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"\n***************************************************************************\n*                                                                         *\n*   This widget makes an interactively moveable cross-section of the      *\n*   currently visible objects in the currently active document. The       *\n*   cross-sectioning plane is specified by its normal, and the cross-     *\n*   section can be moved along that normal using a slider bar. It can     *\n*   show the cross-section either as an outline or a view of the sliced   *\n*   objects. To run the macro, first download it from this site and       *\n*   install it in your macros directory, then use the menu to call up     *\n*   your list of macros and double-click on this one. It will display     *\n*   a default cross-section and pop up a window to enable you to set      *\n*   the cross-sectioning parameters. Closing the pop-up window will       *\n*   restore the scene to its previous state before the macro was          *\n*   started.                                                              *\n*                                                                         *\n***************************************************************************\n*   Copyright (c) 2016 Richard P. Parkins, M. A.                          *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n\"\"\"\n__title__   = \"Cross-Section\"\n__author__  = \"Aleph0\"\n__version__ = \"00.10\"\n__date__    = \"19/12/2020\"\n\n# \"29/01/2016\" \"10/06/2016\" \"29/09/2016 * 2\" \"17/08/2017\" \"06/09/2017\" \"17/09/2017\" \"04/07/2019\" \"31/08/2019\" \"19/12/2020\"\n\n# Upgrade:\n# 17/08/2017 by Sam             #https://forum.freecadweb.org/viewtopic.php?f=28&t=15084&start=10#p187030\n# 06/09/2017 17/09/2017 by Gift #https://www.forum.freecadweb.org/viewtopic.php?f=13&t=24130\n# 04/07/2019 by duke24 replace tab to space #https://forum.freecadweb.org/viewtopic.php?f=13&t=37449\n# 31/08/2019 by g.becu adding line 334 #https://forum.freecadweb.org/viewtopic.php?f=28&t=15084&start=20#p330351\n# 19/12/2020 by Chris_G : exlude App.Part from the list of input objects + many code style fixes (PEP8)\n#                         See forum : https://forum.freecadweb.org/viewtopic.php?f=22&t=53423\n\n__Comment__ = \"Dynamic cross section viewer\"\n__Wiki__ = \"http://www.freecadweb.org/wiki/index.php?title=Macro_cross_section\"\n__Help__ = \"see first few lines of macro text\"\n__Status__ = \"stable\"\n__Requires__ = \"freecad 0.15\"\n\n# OS: Ubuntu 14.04.3 LTS                        # OS: Windows 10\n# Word size of OS: 64-bit                       # Word size of OS: 64-bit\n# Word size of FreeCAD: 64-bit                  # Word size of FreeCAD: 64-bit\n# Version: 0.15.4671 (Git)                      # Version: 0.19.17171 (Git)\n# Branch: releases/FreeCAD-0-15                 # Build type: Release\n# Hash: 244b3aef360841646cbfe80a1b225c8b39c8380c# Branch: master\n# Python version: 2.7.6                         # Hash: d19470a9711ea604f3ca6c93e46afadf64d5bb87\n# Qt version: 4.8.6                             # Python version: 3.6.6\n# Coin version: 4.0.0a                          # Qt version: 5.6.2\n# OCC version: 6.8.0.oce-0.17                   # Coin version: 4.0.0a\n#                                               # OCC version: 7.3.0\n\nimport PySide\nfrom PySide import QtCore, QtGui\nimport FreeCAD as App\nimport FreeCADGui\nimport Part\nimport Draft\nfrom FreeCAD import Base\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\n\nwidth = 350  # width of our window\nheight = 310  # height of our window\nglobal FreeCADRootWindow  # main window before we start\n\n\n# This is the interactive window that the macro creates\n# Its main function is to have a close box and tidy up when closed\nclass CrossSectionWindow(PySide.QtGui.QMainWindow):\n    # automagically called when the window is created\n    def __init__(self):\n        super(CrossSectionWindow, self).__init__()\n        self.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint)\n        self.setWindowTitle(_translate(\n            \"MainWindow\", \"Cross-section\", None))\n\n        # Create and set the window's widget, which does all the work\n        self.child = CrossSection(self)\n        self.setCentralWidget(self.child)\n        self.child.initUI(self)\n        if self.child.startup_failed:\n            self.destroy()\n        else:\n            # Position our window relative to the FreeCAD root\n            self.setPosition(FreeCADRootWindow)\n            self.child.show()\n            self.show()\n\n    # User closed the window, tidy up\n    def closeEvent(self, event):\n        self.child.restoreObjects()\n\n    # Set a sensible default position for the window\n    # With FreeCAD's default layout, this will be over the docking area\n    # so it will not obscure the 3D view\n    def setPosition(self, parent):\n        geom = parent.geometry()\n        xpos = geom.left() + 50\n        ypos = geom.center().y() - height / 2\n        self.setGeometry(xpos, ypos, width, height)\n        self.setFixedSize(width, height)\n\n\n# This is the widget which does almost all of the work\n# Widgets don't have close boxes, so closing is dealt with in CrossSectionWindow\nclass CrossSection(PySide.QtGui.QWidget):\n    # Lay out the interactive elements\n    def initUI(self, parent):\n        self.parent = parent\n        font = QtGui.QFont()\n        font.setFamily(\"Times New Roman\")\n        font.setPointSize(10)\n        font.setWeight(10)\n        font.setBold(True)\n        self.hideObjects()\n\n        margin = 10\n        alw = 20  # axis label width\n        sbp = margin + alw + margin  # spin boxes to right of axis labels\n        slw = width - 2 * margin  # width of slider and progress bar\n        ypos = margin\n\n        self.setObjectName(_fromUtf8(\"CrossSection\"))\n\n        # The cross-section plane is defined by its normal\n        # The length of the normal is immaterial as long as it is nonzero\n        self.label_1 = QtGui.QLabel(self)\n        self.label_1.setGeometry(QtCore.QRect(margin, ypos, slw, 22))\n        self.label_1.setObjectName(_fromUtf8(\"label_1\"))\n        self.label_1.setText(_translate(\n            \"MainWindow\", \"Sliding axis direction\", None))\n        self.label_1.setToolTip(_translate(\n            \"MainWindow\",\n            \"Cross-section is taken perpendicular to this axis\", None))\n        ypos = ypos + 30\n\n        self.label_2 = QtGui.QLabel(self)\n        self.label_2.setGeometry(QtCore.QRect(margin, ypos, alw, 25))\n        self.label_2.setObjectName(_fromUtf8(\"label_2\"))\n        self.label_2.setText(_translate(\"MainWindow\", \"X\", None))\n\n        self.doubleSpinBox_X = QtGui.QDoubleSpinBox(self)\n        self.doubleSpinBox_X.setGeometry(QtCore.QRect(sbp, ypos, 62, 25))\n        self.doubleSpinBox_X.setMinimum(-10000.0)\n        self.doubleSpinBox_X.setMaximum(10000.0)\n        self.doubleSpinBox_X.setValue(0.0)\n        self.doubleSpinBox_X.setSingleStep(1)\n        self.doubleSpinBox_X.setObjectName(_fromUtf8(\"doubleSpinBox_X\"))\n        self.doubleSpinBox_X.valueChanged.connect(\n            self.on_doubleSpinBox_X_valueChanged)\n        self.doubleSpinBox_X.setToolTip(_translate(\n            \"MainWindow\", \"Sliding axis X\", None))\n        ypos = ypos + 30\n\n        self.label_3 = QtGui.QLabel(self)\n        self.label_3.setGeometry(QtCore.QRect(margin, ypos, alw, 25))\n        self.label_3.setObjectName(_fromUtf8(\"label_3\"))\n        self.label_3.setText(_translate(\"MainWindow\", \"Y\", None))\n\n        self.doubleSpinBox_Y = QtGui.QDoubleSpinBox(self)\n        self.doubleSpinBox_Y.setGeometry(QtCore.QRect(sbp, ypos, 62, 25))\n        self.doubleSpinBox_Y.setMinimum(-10000.0)\n        self.doubleSpinBox_Y.setMaximum(10000.0)\n        self.doubleSpinBox_Y.setValue(0.0)\n        self.doubleSpinBox_Y.setSingleStep(1)\n        self.doubleSpinBox_Y.setObjectName(_fromUtf8(\"doubleSpinBox_Y\"))\n        self.doubleSpinBox_Y.valueChanged.connect(\n            self.on_doubleSpinBox_Y_valueChanged)\n        self.doubleSpinBox_Y.setToolTip(_translate(\n            \"MainWindow\", \"Sliding axis Y\", None))\n        ypos = ypos + 30\n\n        self.label_4 = QtGui.QLabel(self)\n        self.label_4.setGeometry(QtCore.QRect(margin, ypos, alw, 25))\n        self.label_4.setObjectName(_fromUtf8(\"label_4\"))\n        self.label_4.setText(_translate(\"MainWindow\", \"Z\", None))\n\n        self.doubleSpinBox_Z = QtGui.QDoubleSpinBox(self)\n        self.doubleSpinBox_Z.setGeometry(QtCore.QRect(sbp, ypos, 62, 25))\n        self.doubleSpinBox_Z.setMinimum(-10000.0)\n        self.doubleSpinBox_Z.setMaximum(10000.0)\n        self.doubleSpinBox_Z.setValue(1.0)\n        self.doubleSpinBox_Z.setSingleStep(1)\n        self.doubleSpinBox_Z.setObjectName(_fromUtf8(\"doubleSpinBox_Z\"))\n        self.doubleSpinBox_Z.valueChanged.connect(\n            self.on_doubleSpinBox_Z_valueChanged)\n        self.doubleSpinBox_Z.setToolTip(\n            _translate(\"MainWindow\", \"Sliding axis Z\", None))\n        ypos = ypos + 40\n        # Make the interactive slider control\n        # As you move this slider with the mouse, the cross-section slides\n        # through the model\n        self.label_5 = QtGui.QLabel(self)\n        self.label_5.setGeometry(QtCore.QRect(margin, ypos, slw, 22))\n        self.label_5.setObjectName(_fromUtf8(\"label_5\"))\n        self.label_5.setText(_translate(\n            \"MainWindow\", \"Position along axis\", None))\n        ypos = ypos + 30\n\n        self.horizontalSlider = QtGui.QSlider(self)\n        self.horizontalSlider.setGeometry(QtCore.QRect(margin, ypos, slw - 50, 20))\n        self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal)\n        self.horizontalSlider.setInvertedAppearance(False)\n        self.horizontalSlider.setObjectName(_fromUtf8(\"horizontalSlider\"))\n        self.horizontalSlider.setRange(0, 100)\n        self.horizontalSlider.setValue(int(self.fraction * 100.0))\n        self.horizontalSlider.setToolTip(_translate(\n            \"MainWindow\", \"Slide to move cross-section along axis\", None))\n\n        # must be called after setValue()\n        self.horizontalSlider.valueChanged.connect(self.on_horizontal_slider)\n        ypos = ypos + 30\n\n        self.progressBar_1 = QtGui.QProgressBar(self)\n        self.progressBar_1.setGeometry(QtCore.QRect(margin, ypos, slw - 50, 23))\n        self.progressBar_1.setValue(int(self.fraction * 100.0))\n        self.progressBar_1.setOrientation(QtCore.Qt.Horizontal)\n        self.progressBar_1.setAlignment(QtCore.Qt.AlignCenter)\n        self.progressBar_1.setObjectName(_fromUtf8(\"progressBar_1\"))\n        self.progressBar_1.setToolTip(_translate(\n            \"MainWindow\", \"Percent position of cross-section\", None))\n        ypos = ypos + 40\n\n##################################    add\n        self.SpinBox_PBar = QtGui.QSpinBox(self)\n        self.SpinBox_PBar.setGeometry(QtCore.QRect(sbp+255, ypos - 40, 45, 23))\n        self.SpinBox_PBar.setMinimum(0.0)\n        self.SpinBox_PBar.setMaximum(100.0)\n        self.SpinBox_PBar.setValue(int(self.fraction * 100.0))\n        self.SpinBox_PBar.setSingleStep(1)\n        self.SpinBox_PBar.setObjectName(_fromUtf8(\"SpinBox_PBar\"))\n        self.SpinBox_PBar.valueChanged.connect(self.on_SpinBox_PBar_valueChanged)\n        self.SpinBox_PBar.setToolTip(_translate(\n            \"MainWindow\", \"Sliding percent\", None))\n#################################    add\n\n        # Select the display format for the cross-section\n        # This button shows a wire line in the cross-section plane\n        self.radioButton_1 = QtGui.QRadioButton(self)\n        self.radioButton_1.setGeometry(QtCore.QRect(margin, ypos, slw, 20))\n        self.radioButton_1.setText(_fromUtf8(\"Outline\"))\n        self.radioButton_1.setChecked(True)\n        self.radioButton_1.toggled.connect(self.onRadioButton)\n        self.radioButton_1.setObjectName(_fromUtf8(\"radioButton_1\"))\n        self.radioButton_1.setToolTip(_translate(\n            \"MainWindow\", \"Make cross-section as wire outline\", None))\n        ypos = ypos + 30\n\n        # Select the display format for the cross-section\n        # This button shows a normal 3D display with everything above the\n        # cross-section plane cut away\n        self.radioButton_2 = QtGui.QRadioButton(self)\n        self.radioButton_2.setGeometry(QtCore.QRect(margin, ypos, slw, 20))\n        self.radioButton_2.setText(_fromUtf8(\"Cut objects\"))\n        self.radioButton_2.setChecked(False)\n        self.radioButton_2.toggled.connect(self.onRadioButton)\n        self.radioButton_2.setObjectName(_fromUtf8(\"radioButton_2\"))\n        self.radioButton_2.setToolTip(_translate(\n            \"MainWindow\", \"Make cross-section as cut objects\", None))\n\n##################################\n        # Keep the sectional view\n        self.CB_00 = QtGui.QCheckBox(self)\n        self.CB_00.setText(_fromUtf8(\"Keep the sectional view\"))\n        self.CB_00.setGeometry(QtCore.QRect(margin+168, ypos-30, slw, 20))\n        self.CB_00.setObjectName(_fromUtf8(\"CB_00\"))\n        self.CB_00.setChecked(False)\n        self.CB_00.setToolTip(_translate(\n            \"MainWindow\", \"Keep the sectional view or erase\", None))\n##################################\n\n    # Called at macro start up by initUI()\n    def hideObjects(self):\n        # Initialise the cross-section state variables\n        self.startup_failed = False\n        self.fraction = 0.5\n        self.axisX = 0.0\n        self.axisY = 0.0\n        self.axisZ = 1.0\n        self.cross_section_type = 1\n\n        # We must have something to do a cross-section on\n        if App.ActiveDocument is None:\n            QtGui.QMessageBox.warning(None, _translate(\"MainWindow\",\n                \"Cross-section\", None),\n                _translate(\"MainWindow\", \"There is no Active Document\\n\" +\n                    \"Create one and run this macro again.\", None),\n                QtGui.QMessageBox.Cancel,\n                QtGui.QMessageBox.Cancel)\n            self.startup_failed = True\n            self.parent.destroy()  # This will close the window\n        else:\n\n            # Make a list of the user's objects\n            # WARNING!!\n            # This list is persistent. We'll get confused if the user deletes or\n            # adds objects while the macro is active\n            self.oblist = []  # App.ActiveDocument.Objects\n            for obj in App.ActiveDocument.Objects:\n                try:\n                    obj.getPropertyByName(\"Shape\")\n                    self.oblist.append(obj)\n                except AttributeError:\n                    pass\n            # self.oblist = [obj for obj in self.oblist if hasattr(obj,\"Shape\")]\n            # Create the cross-section object\n            self.cs = App.ActiveDocument.addObject(\"Part::Feature\", \"Generated__cross-section\")\n            self.OriginalVisibilities = list()\n            self.xmin = 1000.0\n            self.xmax = -1000.0\n            self.ymin = 1000.0\n            self.ymax = -1000.0\n            self.zmin = 1000.0\n            self.zmax = -1000.0\n#            n = 0\n#            for p in self.oblist: # stupid Python list has no length function\n#                n = n + 1\n############################# Skip the <group object> ########################\n            b0 = []\n            for x0 in self.oblist:\n                if str(x0) != \"<group object>\":\n                    b0.append(x0)\n            self.oblist = b0\n            n = len(self.oblist)\n###############################################################################\n            # Make a list of the visible objects and make them invisible while\n            # the macro is active\n            # Also we compute the bounding box of the model\n            for i in range(n):\n                vis = self.oblist[i].ViewObject.Visibility\n                self.OriginalVisibilities.append(vis)\n                if vis:\n                    if self.oblist[i].TypeId != str(\"Drawing::FeatureViewPython\"):   # add\n                        self.oblist[i].ViewObject.Visibility = False\n                        b = self.oblist[i].Shape.BoundBox\n                        if b.XMin < self.xmin:\n                            self.xmin = b.XMin\n                        if b.XMax > self.xmax:\n                            self.xmax = b.XMax\n                        if b.YMin < self.ymin:\n                            self.ymin = b.YMin\n                        if b.YMax > self.ymax:\n                            self.ymax = b.YMax\n                        if b.ZMin < self.zmin:\n                            self.zmin = b.ZMin\n                        if b.ZMax > self.zmax:\n                            self.zmax = b.ZMax\n            # Moan and give up if there is nothing to cross-section\n            if self.xmax <= self.xmin \\\n                or self.ymax <= self.ymin \\\n                    or self.zmax <= self.zmin:\n                QtGui.QMessageBox.warning(None, _translate(\"MainWindow\",\n                    \"Cross-section\", None),\n                    _translate(\"MainWindow\",\n                    \"There are no visible solid objects\\n\" +\n                    \"Create some and run this macro again.\", None),\n                    QtGui.QMessageBox.Cancel,\n                    QtGui.QMessageBox.Cancel)\n                self.restoreObjects()\n                self.startup_failed = True\n                App.ActiveDocument.removeObject(\"Generated__cross_section\")\n                self.parent.destroy()  # This will close the window\n            else:\n                # Trigger initial display\n                self.updateAxis()\n\n    # Called when macro is closed\n    # Restore the original visibility of the user's objects\n    # and destroy our cross-section object\n    def restoreObjects(self):\n\n        n = 0\n        for p in self.oblist:  # stupid Python list has no length function\n            n = n + 1\n        for i in range(n):\n            self.oblist[i].ViewObject.Visibility = self.OriginalVisibilities[i]\n        try:\n            if self.CB_00.isChecked() is False:\n                App.ActiveDocument.removeObject(\"Generated__cross_section\")\n        except Exception:\n            None\n\n    # Something has changed, recalculate the cross-section\n    def updateGui(self):\n        # default to no visible cross-ection\n        self.cs.ViewObject.Visibility = False\n\n        # check if the sliding axis is invalid\n        if self.xdir == 0.0 and self.ydir == 0.0 and self.zdir == 0.0 :\n            QtGui.QMessageBox.warning(None, _translate(\"MainWindow\",\n                \"Cross-section\", None),\n                _translate(\"MainWindow\", \"The sliding axis has zero length\\n\" +\n                    \"Please set a valid axis.\", None),\n                QtGui.QMessageBox.Ok,\n                QtGui.QMessageBox.Ok)\n        else:\n\n            # First we compute the 0% and 100% positions on the sliding axis\n            if self.xdir < 0.0:\n                x = self.xmax + self.fraction * self.xdir\n            else:\n                x = self.xmin + self.fraction * self.xdir\n            if self.ydir < 0.0:\n                y = self.ymax + self.fraction * self.ydir\n            else:\n                y = self.ymin + self.fraction * self.ydir\n            if self.zdir < 0.0:\n                z = self.zmax + self.fraction * self.zdir\n            else:\n                z = self.zmin + self.fraction * self.zdir\n\n            r = 2 * max(self.xmax - self.xmin, self.ymax - self.ymin,\n                        self.zmax - self.xmin)\n\n            # Display the dimensions\n            dimDep = \"X \" + str(x) + \" mm , Y \" + str(y) + \" mm , Z \" + str(z) + \" mm\"\n            App.Console.PrintMessage(dimDep + \"\\n\")\n\n            # Create a big enough disc in the cross-section plane\n            c = Part.makeCircle(r, Base.Vector(x, y, z),\n                                Base.Vector(self.xdir, self.ydir, self.zdir))\n            f = Part.Face(Part.Wire(c))\n            part_list = list()  # list for cross-section parts\n            n = 0\n            for p in self.oblist:  # stupid Python list has no length function\n                n = n + 1\n            something = 0\n            if self.cross_section_type == 1:\n                # wire line cross-section\n                for i in range(n):\n                    if self.oblist[i].TypeId != str(\"Drawing::FeatureViewPython\"):  # add\n                        if self.OriginalVisibilities[i]:\n                            ob = self.oblist[i].Shape.section(f)\n                            # check for valid section part\n                            if ob.BoundBox.XMin <= ob.BoundBox.XMax:\n                                part_list.append(ob)\n                                something = 1\n            else:\n                # cut shape cross-section\n                # extrude our cross-ection disc into a cylinder\n                cyl = f.extrude(Base.Vector(self.xdir, self.ydir, self.zdir))\n                doc = App.ActiveDocument\n                for i in range(n):\n                    if self.oblist[i].TypeId != str(\"Drawing::FeatureViewPython\"):  # add\n                        if self.OriginalVisibilities[i]:\n                            if (self.oblist[i].Shape.Volume <= 0.0):\n                                continue\n                            acut = doc.addObject(\"Part::Cut\", \"Cut\")\n                            abase = Draft.clone(self.oblist[i])\n                            abase.ViewObject.DiffuseColor = self.oblist[i].ViewObject.DiffuseColor\n                            abase.ViewObject.Transparency = self.oblist[i].ViewObject.Transparency\n                            doc.recompute()\n                            atool = doc.addObject(\"Part::Feature\")\n                            atool.Shape = cyl\n                            atool.ViewObject.ShapeColor = self.oblist[i].ViewObject.ShapeColor  # (0.25,0.57,0.35)\n                            atool.ViewObject.Transparency = self.oblist[i].ViewObject.Transparency\n                            doc.recompute()\n                            acut.Base = abase\n                            acut.Tool = atool\n                            acut.ViewObject.DiffuseColor = abase.ViewObject.DiffuseColor\n                            doc.recompute()\n                            if acut.Shape.isValid() and acut.Shape.Volume > 0.0:\n                                ob = doc.addObject(\"Part::Feature\")\n                                ob.Shape = acut.Shape\n                                ob.ViewObject.DiffuseColor = acut.ViewObject.DiffuseColor\n                                doc.recompute()\n                                part_list.append(ob)\n                                something = 2\n                            doc.removeObject(acut.Name)\n                            doc.recompute()\n                            doc.removeObject(abase.Name)\n                            doc.recompute()\n                            doc.removeObject(atool.Name)\n                            doc.recompute()\n\n            if something == 1:\n                s = Part.makeCompound(part_list)\n                if s.isValid():\n                    self.cs.Shape = s\n                    self.cs.ViewObject.Visibility = True\n            if something == 2:\n                feature = App.ActiveDocument.addObject(\"Part::Compound\", \"Compound\")\n                feature.Links = part_list\n                App.ActiveDocument.recompute()\n                if feature.Shape.isValid():\n                    self.cs.Shape = feature.Shape.copy()\n                    self.cs.ViewObject.DiffuseColor = feature.ViewObject.DiffuseColor\n                    self.cs.ViewObject.Visibility = True\n                    App.ActiveDocument.recompute()\n                for od in part_list:\n                    App.ActiveDocument.removeObject(od.Name)\n                    App.ActiveDocument.recompute()\n                App.ActiveDocument.removeObject(feature.Name)\n            FreeCADGui.updateGui()\n\n    # User changed axis vector\n    # Compute a new axis vector whose length just covers the model\n    def updateAxis(self):\n        ldir = 0.0\n        if self.axisX != 0.0:\n            ldir = (self.xmax - self.xmin) / abs(self.axisX)\n        if self.axisY != 0.0:\n            ldir = max(ldir, (self.ymax - self.ymin) / abs(self.axisY))\n        if self.axisZ != 0.0:\n            ldir = max(ldir, (self.zmax - self.zmin) / abs(self.axisZ))\n        self.xdir = self.axisX * ldir\n        self.ydir = self.axisY * ldir\n        self.zdir = self.axisZ * ldir\n        self.updateGui()  # recalculate the cross-section\n\n    def on_horizontal_slider(self, val):\n        self.fraction = val / 100.0\n        self.progressBar_1.setValue(val)\n        self.SpinBox_PBar.setValue(val)\n        self.updateGui()\n\n    def on_doubleSpinBox_X_valueChanged(self, val):\n        self.axisX = val\n        self.updateAxis()\n\n    def on_doubleSpinBox_Y_valueChanged(self, val):\n        self.axisY = val\n        self.updateAxis()\n\n    def on_doubleSpinBox_Z_valueChanged(self, val):\n        self.axisZ = val\n        self.updateAxis()\n\n    def on_SpinBox_PBar_valueChanged(self, val):\n        self.progressBar_1.setValue(val)\n        self.horizontalSlider.setValue(int(val))\n        self.updateGui()\n\n    def onRadioButton(self, wasChecked):\n        if self.radioButton_1.isChecked():\n            self.cross_section_type = 1\n        else:\n            self.cross_section_type = 2\n        self.updateGui()\n\n#######################################\n\n\n# Find FreeCAD's root window\nFreeCADRootWindow = FreeCADGui.getMainWindow()\n\n# Create the window and start it\nmyWidget = CrossSectionWindow()\n\n# The CrossSectionWindow will do all the work",
    "url": "https://wiki.freecad.org/Macro_cross_section",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_cross_section",
    "version": "00.10",
    "license": "",
    "date": "19/12/2020",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Aleph0",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_cross_section.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/f/f5/Macro_cross_section.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Delta xyz",
    "on_wiki": true,
    "on_git": false,
    "desc": "Gives the Delta values and distance between 2 points.<br />Start the macro<br />Select the first point in 3D view<br />Select the second point in 3D view<br />If the \"SHIFT\" key is pressed, the Delta value begin on coordinate 0,0,0 to point clicked  (the coordinate 0,0,0 is displayed in red).<br />One option is possible for the macro stay resident (continuous) then push \"Q\" key to quit the macro, and option for impose the number of decimals or use the decimal in the preference option.<br /><br />Macro version: 0.2<br />Last modified: 2020-10-23<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/f/f4/Macro_Delta_xyz.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Gives the Delta values and distance between 2 points.",
    "code": "# -*- coding: utf-8 -*-\n#Delta x y z Click Q to quit\n#\n#OS: Windows 10 (10.0)\n#Word size of OS: 64-bit\n#Word size of FreeCAD: 64-bit\n#Version: 0.19.22808 (Git)\n#Build type: Release\n#Branch: master\n#Hash: 72eb41b24f12b572d55081042160954b93f4614c\n#Python version: 3.6.8\n#Qt version: 5.12.1\n#Coin version: 4.0.0a\n#OCC version: 7.3.0\n#Locale: French/Mars(fr_Ma)\n#\n__title__   = \"Delta_XYZ\"\n__author__  = \"Mario52\"\n__url__     = \"https://www.freecadweb.org/wiki/Main_Page\"\n__Wiki__    = \"https://wiki.freecadweb.org/Macro_Delta_xyz\"\n__version__ = \"00.02\"\n__date__    = \"2020/10/23\"    #YYYY/MM/DD\n\nimport Draft, Part\nimport math\nfrom FreeCAD import Base\nimport FreeCAD, FreeCADGui\nApp = FreeCAD\nGui = FreeCADGui\n\nglobal positionX1 ;positionX1 = 0.0\nglobal positionY1 ;positionY1 = 0.0\nglobal positionZ1 ;positionZ1 = 0.0\nglobal positionX2 ;positionX2 = 0.0\nglobal positionY2 ;positionY2 = 0.0\nglobal positionZ2 ;positionZ2 = 0.0\nglobal pas        ;pas        = 0\n\nglobal setArrondi                    # round value\nglobal switchResident                # switch resident 0=not resident, 1=stay resident\nglobal switchDecimalsPref            # switch unit preference or not\n\n#### Configuration begin      #### \n#### NOT MODIFY THE CODE HERE ####\n#### for modify : go to : FreeCAD >Menu >Tools >Edit parameters... >BaseApp/Preferences/Macros/FCMmacros/Delta_XYZ ####\n##\nFreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"Version\", __version__ + \" (\" + __date__ + \")\")\n##\nswitchResident = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switchResident\")   # switch Resident or not\nif switchResident == False:\n    FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchResident\", switchResident)# switch Resident or not : 0 = Not Resident 1 = Resident\n##\nswitchDecimalsPref = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switchDecimalsPref\")   # switch unit preference or not\nif switchDecimalsPref == True:\n    setArrondi = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Units\").GetInt(\"Decimals\")    # unit in preferences\nelse:\n    FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchDecimalsPref\", switchDecimalsPref)# \n    setArrondi = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"setArrondi\")\n    if setArrondi < 1:\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"setArrondi\", 3) # setArrondi\n        setArrondi = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"setArrondi\")\n\n##\n####Configuration###################################################################################################################\n\n## Tool Draft def : sub, length, dist\ndef sub(first, other): \n\t\"sub(Vector,Vector) - subtracts second vector from first one\"\n\tif isinstance(first,FreeCAD.Vector) and isinstance(other,FreeCAD.Vector):\n\t\treturn FreeCAD.Vector(first.x-other.x, first.y-other.y, first.z-other.z)\ndef length(first):\n\t\"lengh(Vector) - gives vector length\"\n\tif isinstance(first,FreeCAD.Vector):\n\t\treturn math.sqrt(first.x*first.x + first.y*first.y + first.z*first.z)\ndef dist(first, other):\n\t\"dist(Vector,Vector) - returns the distance between both points/vectors\"\n\tif isinstance(first,FreeCAD.Vector) and isinstance(other,FreeCAD.Vector):\n\t\treturn length(sub(first,other))\n\nimport FreeCAD, FreeCADGui \n\n#########\ndoc = FreeCAD.ActiveDocument\nif doc == None:\n    doc = FreeCAD.newDocument(\"Delta x y z\")\n#########\n\n##key\nglobal i     ; i = 0   \nglobal c     ; c = \"\"\nglobal d     ; d = \"\"\nglobal v     ; v = Gui.activeDocument().activeView()\nglobal o     ; o = \"\"\nglobal s     ; s = \"\"\nglobal SHIFT ; SHIFT = \"\"\nglobal DOWN  ; DOWN = \"\"\n##\n\nclass ViewObserver:\n    def keyPosition(self, info):\n#        global i\n#        global c\n        global SHIFT\n        global DOWN\n        global s \n        global d \n        global v\n        global o\n\n        SHIFT = \"\"\n        key = info[\"Key\"]\n\n        if (key.upper() == \"SHIFT\") and (info[\"ShiftDown\"] == False):  #\n            SHIFT = \"SHIFT\"\n            DOWN  = \"DOWN\"\n            key   = \"\"\n\n        if key.upper() == \"Q\":\n            FreeCADGui.Selection.removeObserver(s)                     # Uninstalls the resident function\n            v.removeEventCallback(\"SoKeyboardEvent\",d)\n            App.Console.PrintMessage(\"____End Delta_XYZ____\" + \"\\n\")\n        xx = info[\"Key\"]\n\nclass SelObserver:\n    def addSelection(self,document, object, element, position):  # Selection\n        global pas\n        global positionX1\n        global positionY1\n        global positionZ1\n        global positionX2\n        global positionY2\n        global positionZ2\n        global SHIFT\n        global DOWN\n        global s \n        global d \n        global v\n\n        pas+=1\n        if (SHIFT == \"SHIFT\") and (DOWN == \"DOWN\"):\n            positionX1 = 0.0\n            positionY1 = 0.0\n            positionZ1 = 0.0\n            App.Console.PrintError(\"Begin    : X1 \"+str(positionX1)+\" Y1: \"+str(positionY1)+\" Z1: \"+str(positionZ1)+\"\\n\")    \n            pas = 2\n            SHIFT = DOWN  = \"\"\n\n        if pas==1:\n            positionX1 = round(position[0],setArrondi)\n            positionY1 = round(position[1],setArrondi)\n            positionZ1 = round(position[2],setArrondi)\n            App.Console.PrintMessage(\"Begin    : X1 \"+str(positionX1)+\" Y1: \"+str(positionY1)+\" Z1: \"+str(positionZ1)+\"\\n\")    \n        else:\n            positionX2 = round(position[0],setArrondi)\n            positionY2 = round(position[1],setArrondi)\n            positionZ2 = round(position[2],setArrondi)\n            App.Console.PrintMessage(\"End      : X2 \"+str(positionX2)+\" Y2: \"+str(positionY2)+\" Z2: \"+str(positionZ2)+\"\\n\")    \n            App.Console.PrintMessage(\"Delta X  : \"+str(round(abs(positionX1-positionX2),setArrondi))+\"\\n\")    \n            App.Console.PrintMessage(\"Delta Y  : \"+str(round(abs(positionY1-positionY2),setArrondi))+\"\\n\")    \n            App.Console.PrintMessage(\"Delta Z  : \"+str(round(abs(positionZ1-positionZ2),setArrondi))+\"\\n\")    \n            v1=FreeCAD.Vector(positionX1,positionY1,positionZ1)\n            v2=FreeCAD.Vector(positionX2,positionY2,positionZ2)\n            distance = dist(v1,v2)\n            App.Console.PrintMessage(\"Distance : \"+ str(round(distance,setArrondi))+\"\\n\")\n            App.Console.PrintMessage(\"__________________________________\"+\"\\n\")\n            pas=0\n            if switchResident == False:\n                FreeCADGui.Selection.removeObserver(s)                     # Uninstalls the resident function\n                v.removeEventCallback(\"SoKeyboardEvent\",d)                 # Uninstalls the resident function\n\n\npas = 0\ns=SelObserver()\nFreeCADGui.Selection.addObserver(s)          # install the function mode resident \n## key\no = ViewObserver()                           # install the function mode resident \nd = v.addEventCallback(\"SoKeyboardEvent\",o.keyPosition)\nApp.Console.PrintMessage(\"____Begin Delta_XYZ____\" + \"\\n\")\n##\nFreeCAD.Console.PrintMessage(\"\\n\"+\"####Configure################################################################################################\" + \"\\n\\n\")\nFreeCAD.Console.PrintMessage(\"For modify the value : go to : FreeCAD >Menu >Tools >Edit parameters... >BaseApp/Preferences/Macros/FCMmacros/Delta_XYZ\"+\"\\n\\n\")\nFreeCAD.Console.PrintMessage(\"_____switchDecimalsPref_____  \")\nFreeCAD.Console.PrintError(\"Actual \" + str(switchDecimalsPref)+\"\\n\")\nFreeCAD.Console.PrintMessage(\"switchDecimalsPref : True  1 : the round value takes the global preferences value \"+\"\\n\")\nFreeCAD.Console.PrintMessage(\"                   : False 0 : the round value takes your choice \"+\"\\n\\n\")\nFreeCAD.Console.PrintMessage(\"_____setArrondi_____  \")\nFreeCAD.Console.PrintError(\"Actual \" + str(setArrondi)+\"\\n\")\nFreeCAD.Console.PrintMessage(\"setArrondi         : set your choice round value\"+\"\\n\")\nFreeCAD.Console.PrintMessage(\"                   : if your choice = 0 : the round value is 3 by default \"+\"\\n\\n\")\nFreeCAD.Console.PrintMessage(\"_____switchResident_____  \")\nFreeCAD.Console.PrintError(\"Actual \" + str(switchResident)+\"\\n\")\nFreeCAD.Console.PrintMessage(\"switchResident     : True  1 : the macro stay resident (Type Q to quit)\"+\"\\n\")\nFreeCAD.Console.PrintMessage(\"                   : False 0 : the macro is used on run and quit after use\"+\"\\n\")\nFreeCAD.Console.PrintMessage(\"\\n\"+\"####Configure end############################################################################################\" + \"\\n\")\nFreeCAD.Console.PrintMessage(\"\\n\"+\"####Use######################################################################################################\" + \"\\n\")\nFreeCAD.Console.PrintMessage(\"Use : click the first point, click the second point, the data is diplayed\"+\"\\n\")\nFreeCAD.Console.PrintMessage(\"    : press the SHIFT button click the point, the Delta is displayed with the coordinate X=0,Y=0,Z=0 to point clicked X, Y, Z\"+\"\\n\")\nFreeCAD.Console.PrintMessage(\"    : the first coordinate X=0, Y=0, Z=0 is displayed in red\"+\"\\n\")\nFreeCAD.Console.PrintMessage(\"####Use end#######################################################################################################\" + \"\\n\\n\")\n##",
    "url": "https://wiki.freecad.org/Macro_Delta_xyz",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_Delta_xyz",
    "version": "00.02",
    "license": "",
    "date": "2020/10/23",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Delta_xyz.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/f/f4/Macro_Delta_xyz.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Dump Objects",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro generates a listing of all objects in the current document - the list can be in a window or on the Report view.<br /><br />Macro version: 0.3<br />Last modified: 2023-01-14<br />FreeCAD version: 0.20<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/2/2e/Macro_Dump_Objects.png\">ToolBar Icon</a><br />Author: Piffpoof<br /> ",
    "comment": "This macro generates a listing of all objects in the current document - the list can be in a window or on the Report view.",
    "code": "#\n#                       Dump Object\n#                       v 0.3 - 14/01/2023 conversion to PySide2\n#                       v 0.2 - added report to CSV file\n#                       v 0.1 - added report to window\n#                       v 0.0 - report to Report view\n#\n#***********************************************************************************\n# routine to dump object space for Geometric model in the currently active file\n#\n__title__   = \"Dump_Objects\"\n__author__  = \"Piffpoof\"\n__url__     = \"https://wiki.freecadweb.org/Macro_Dump_Objects\"\n__version__ = \"0.3\"\n__date__    = \"2023/01/14\"    #YYYY/MM/DD\n#\n\n# import statements\nfrom PySide2 import QtWidgets, QtGui, QtCore\nfrom PySide2.QtWidgets import * #QDialog , QLineEdit, QPushButton, QApplication\nfrom datetime import datetime       # datestamp on output window\nfrom os.path import expanduser      # output directory for CSV\nimport math\n# UI Class definitions\n\nclass configureMacro(QtWidgets.QDialog):\n    \"\"\"\"\"\"\n    def __init__(self):\n        super(configureMacro, self).__init__()\n        self.initUI()\n    def initUI(self):\n        self.result         = None\n        # set up display only field for selected path type\n        self.cbss           = QtWidgets.QCheckBox(\"Show Sketcher Segments?\", self)\n        self.cbss.move(20,20)\n        self.cbp            = QtWidgets.QCheckBox(\"Show Positions?\", self)\n        self.cbp.move(220,20)\n        self.pathTypeLbl    = QtWidgets.QLabel(\"Select Report Destination:\", self)\n        self.pathTypeLbl.move(20, 70)\n        # cancel button\n        cancelButton = QtWidgets.QPushButton('Cancel', self)\n        cancelButton.clicked.connect(self.onCancel)\n        cancelButton.move(10, 100)\n        # button #1\n        button1 = QtWidgets.QPushButton(choice1, self)\n        button1.clicked.connect(self.onBtn1)\n        button1.move(120, 100)\n        # button #2\n        button2 = QtWidgets.QPushButton(choice2, self)\n        button2.clicked.connect(self.onBtn2)\n        button2.move(235, 100)\n        # button #3\n        button3 = QtWidgets.QPushButton(choice3, self)\n        button3.clicked.connect(self.onBtn3)\n        button3.move(327, 100)\n        # define window     xLoc,yLoc,xDim,yDim\n        self.setGeometry(   250, 250, 435, 150)\n        self.setWindowTitle(\"Select a Report Destination\")\n        self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)\n        self.show()\n    def onCancel(self):\n        self.result = \"cancelled\"\n        self.close()\n    def onBtn1(self):\n        self.result = choice1\n        self.close()\n    def onBtn2(self):\n        self.result = choice2\n        self.close()\n    def onBtn3(self):\n        self.result = choice3\n        self.close()\n\nclass DisplayText(QtWidgets.QWidget):\n    \"\"\"\"\"\"\n    def __init__(self, textToDisplay):\n        self.text = textToDisplay\n        super(DisplayText, self).__init__()\n        self.initUI(textToDisplay)\n    def initUI(self, textToDisplay):\n        \"\"\"Constructor\"\"\"\n        self.textToDisplay = textToDisplay\n        # some window dimensions\n        self.windowHome = screenWidth * 0.05\n        self.windowWidth = screenWidth * 0.9\n        self.windowHeight = 400\n        self.fieldMargin = 40\n        # some column titles\n        columnLabels = QtWidgets.QLabel(formatPrintLine(\"Type / WB\",\"Shape\",\"User Supplied Label\",\"Name\"))\n        columnLabels.setFont('Courier')\n        # set up text editing widget\n        text_editor = QtWidgets.QTextEdit(self)\n        #self.setCentralWidget(self.text_editor)\n        text_editor.setFont('Courier')\n        text_editor.setLineWrapMode(QtWidgets.QTextEdit.NoWrap)\n        text_editor.move(self.fieldMargin,self.fieldMargin)\n        text_editor.move(0,self.fieldMargin)\n        text_editor.resize(self.windowWidth-(2*self.fieldMargin),self.windowHeight-(2*self.fieldMargin))\n        text_editor.resize(self.windowWidth,self.windowHeight-(2*self.fieldMargin))\n        text_editor.append(self.textToDisplay)\n        # set up the layout\n        vBox = QtWidgets.QVBoxLayout()\n        vBox.addWidget(columnLabels)\n        vBox.addWidget(text_editor)\n        self.setLayout(vBox)\n        # define window     xLoc,yLoc,xDim,yDim\n        self.setGeometry(   self.windowHome, self.windowHome, self.windowWidth, self.windowHeight)\n        self.setWindowTitle(\"Object Dump of '\" + FreeCADGui.ActiveDocument.Document.Label + \"' at \" + str(datetime.now()))\n        self.show()\n    #----------------------------------------------------------------------\n    def onOk(self):\n        self.close()\n\n# Class definitions\n\n# Function Definitions\n\ndef countObjects():\n    printList = list()\n    objectTypeTable = {}\n    # build up dictionary of different classes and keep a count\n    for obj in FreeCAD.ActiveDocument.Objects:\n        if objectTypeTable.__contains__(obj.TypeId):\n            objectTypeTable[obj.TypeId] = objectTypeTable[obj.TypeId]+1\n        else:\n            objectTypeTable[obj.TypeId] = 1\n        wb = obj.TypeId[0:obj.TypeId.find(\"::\")]\n        shape = obj.TypeId[obj.TypeId.find(\"::\")+2:]\n        #print wb + \"---\" + shape\n        placementString = \"\"\n        if obj.TypeId == \"Sketcher::SketchObject\":\n            printList.append(formatPrintLine(\"Sketch\", \"\", str(obj.Label)))\n            if showSketcherSegmentsFlag:\n                for i in obj.Geometry:\n                    printList.append(formatPrintLine(\"\", \" -segment\", str(i)))\n        elif wb == \"Part\":\n            if showPlacementFlag:\n                placementString = str(obj.Placement)\n            if shape in (\"Cylinder\", \"Cut\", \"Box\", \"Fuse\", \"Loft\", \"Feature\", \"FeaturePython\", \"Part2DObjectPython\"):\n                printList.append(formatPrintLine(wb, shape, str(obj.Label), str(obj.Name)))\n            else: # print shapes not in list above\n                printList.append(formatPrintLine(str(obj.TypeId), \"\", str(obj.Label), str(obj.Name)))\n        elif wb == \"PartDesign\":\n            if showPlacementFlag:\n                placementString = str(obj.Placement)\n            if shape in (\"Pad\", \"Feature\", \"Fillet\", \"Part2DObjectPython\"):\n                printList.append(formatPrintLine(wb, shape, str(obj.Label), str(obj.Name)))\n            else: # print shapes not in list above\n                printList.append(formatPrintLine(str(obj.TypeId), \"\", str(obj.Label), str(obj.Name)))\n        elif obj.TypeId == \"App::DocumentObjectGroup\":\n            printList.append(formatPrintLine(\"Group\", \"\", str(obj.Label)))\n        elif obj.TypeId == \"Image::ImagePlane\":\n            printList.append(formatPrintLine(wb, shape, str(obj.Label), str(obj.Name)))     \n        else: # print workbench shapes not in lists above\n            printList.append(formatPrintLine(str(obj.TypeId), str(obj.Label), str(obj.Name)))\n        if showPlacementFlag and len(placementString)!=0:\n            printList.append(formatPrintLineMax(\"\", \" -placement\", placementString))\n\n    printList.append(\"\")\n    printList.append(summarySeparator)\n    from collections import OrderedDict\n    sortedByTags = OrderedDict(sorted(objectTypeTable.items(), key=lambda x: x[1], reverse=True))\n    for k, v in sortedByTags.items():\n        printList.append(formatPrintLineSum(k,v))\n    printList.append(\"\")\n    objectClassCount = 0; objectTotalCount = 0\n    for i in objectTypeTable:\n        objectTotalCount = objectTotalCount + objectTypeTable[i]\n    objectCLassCount = len(objectTypeTable)\n    printList.append(formatPrintLineSum(\"Object Class Total is \", str(objectCLassCount)))\n    printList.append(formatPrintLineSum(\"Object Total is \", str(objectTotalCount)))\n    printList.append(summarySeparator)\n    return printList\n\ndef formatPrintLineSum(a,b):\n    return printLineFormatter(2, a, str(b), \"\", \"\")\n\ndef formatPrintLineMax(a,b,c):\n    return printLineFormatter(1, a, b, \"\", \"\")\n\ndef formatPrintLine(a,b,c, *args):\n    d = \"\"\n    if len(args)==1:\n        d = args[0]\n    return printLineFormatter(0, a, b, c, d)\n\ndef printLineFormatter(flag,a,b,c,d):\n    # flag = 0  standard print, spread values over 4 columns\n    # flag = 1  printing verbose things like Sketch details or Placements, combine columns 3 & 4\n    # flag = 2  printing the summary lines, combine columns 1 & 2\n    suffix = \"\"\n    if csvFlag:\n        pfs2 = printFormatString2csv\n        pfs3 = printFormatString3csv\n        pfs4 = printFormatString4csv\n    else:\n        pfs2 = printFormatString2\n        pfs3 = printFormatString3\n        pfs4 = printFormatString4\n    if flag==0:\n        aa = a[:f1]\n        bb = b[:f2]\n        cc = c[:f3]\n        dd = d[:f4]\n        return pfs4.format(aa,bb,cc,dd)\n    elif flag==1:\n        aa = a[:f1]\n        bb = b[:f2]\n        cc = c[:f3+f4]\n        dd = d[:f4]\n        return pfs3.format(aa,bb,cc)\n    else:\n        print(a)\n        aa = a[:f1+f2]\n        bb = b[:f3+f4]\n        return pfs2.format(aa,bb)\n\n# Constant definitions\n# set some field widths\nscreenWidth = QtWidgets.QDesktopWidget().screenGeometry().width()\nglobal f1, f2, f3, f4\n# f1 = 15; f2 = 25; f3 = 45; f4 = 25 # 110 columns in 1000 pixels\nf1 = math.floor(15*screenWidth/1000); f2 = math.floor(25*screenWidth/1000); f3 = math.floor(45*screenWidth/1000); f4 = math.floor(25*screenWidth/1000)\n# and some print format strings\nglobal printFormatString2, printFormatString3, printFormatString4\nglobal printFormatString2csv, printFormatString3csv, printFormatString4csv\nprintFormatString2 = \"{0:<\"+str(f1+f2)+\"} {1:<\"+str(f3)+\"}\"\nprintFormatString2csv = \"{0}, {1}\"\nprintFormatString3 = \"{0:<\"+str(f1)+\"} {1:<\"+str(f2)+\"} {2:<\"+str(f3+f4)+\"}\"\nprintFormatString3csv = \"{0}, {1}, {2}\"\nprintFormatString4 = \"{0:<\"+str(f1)+\"} {1:<\"+str(f2)+\"} {2:<\"+str(f3)+\"} {3:<\"+str(f4)+\"}\"\nprintFormatString4csv = \"{0}, {1}, {2}, {3}\"\n# some button labels that are checked in the code\nglobal choice1, choice2, choice3, csvFlag\nchoice1 = \"Report View\"; choice2 = \"CSV File\"; choice3 = \"Window\"\ncsvFlag = False\nsummarySeparator = \"=======================================================\"\nsummarySeparatorCsv = \"-------------------------------------------------------\"\n# code ***********************************************************************************\nif FreeCAD.ActiveDocument != None:\n    # ask if to window or to Report View...\n    form = configureMacro()\n    form.exec_()\n    showSketcherSegmentsFlag = False\n    if form.cbss.isChecked():\n        showSketcherSegmentsFlag = True\n    showPlacementFlag = False\n    if form.cbp.isChecked():\n        showPlacementFlag = True\n    if form.result == choice2:\n        csvFlag = True\n        showSketcherSegmentsFlag = False\n        showPlacementFlag = False\n        summarySeparator = summarySeparatorCsv\n    printList = countObjects()\n    if form.result == choice1: # report to Report View\n        mainWindow = FreeCADGui.getMainWindow()\n        dockWidgets = mainWindow.findChildren(QtWidgets.QDockWidget)\n        reportViewFlag = False\n        for dw in dockWidgets:\n            if dw.objectName() == \"Report view\":\n                reportViewFlag = True\n        if reportViewFlag:\n            print( printFormatString4.format(   \"\", \"\", \"(User Supplied)\", \"\"))\n            print( printFormatString4.format(   \"Type\", \"Shape\", \"Label\", \"Name\"))\n            print( \"\")\n            for line in printList:\n                print( line + \"\\n\")\n        else:\n            QtWidgets.QMessageBox.information(None,\"\",\"Please use 'Menu->View->Views->Report view' to open the 'Report view'\")\n    if form.result == choice2: # report to CSV file\n        filePath = QtWidgets.QFileDialog.getSaveFileName(parent=None,caption=\"Save CSV file as\",dir=expanduser(\"~\"),filter=\"*.csv\")\n        file = open(filePath[0],\"w\")\n        for line in printList:\n            file.write(line + \"\\n\")\n        file.close()\n    if form.result == choice3: # report to window\n        #----------------------------------------------------------------------\n        longPrintLine = \"\"\n        for line in printList:\n            longPrintLine = longPrintLine + line + \"\\n\"\n        form = DisplayText(longPrintLine)\n#\n#OS: Windows 10 Version 2009\n#Word size of FreeCAD: 64-bit\n#Version: 0.21.0.31513 (Git)\n#Build type: Release\n#Branch: master\n#Hash: b2ab8edba4bfd71681e639f8c3f1105066bed4c7\n#Python 3.10.8, Qt 5.15.4, Coin 4.0.0, Vtk 9.1.0, OCC 7.6.3\n#\n#thus ends the macro...",
    "url": "https://wiki.freecad.org/Macro_Dump_Objects",
    "raw_code_url": "",
    "wiki": "",
    "version": "0.3",
    "license": "",
    "date": "2023/01/14",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Piffpoof",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Dump_Objects.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/2/2e/Macro_Dump_Objects.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FC element selector",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro displays all elements below the cursor (all elements covered by other elements will also be displayed).<br /><br />Macro version: 01.00<br />Last modified: 2016-12-26<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/0/07/Macro_FC_element_selector.png\">ToolBar Icon</a><br />Author: HoWil<br /> ",
    "comment": "This macro displays all elements below the cursor (all elements covered by other elements will also be displayed).",
    "code": "#!/usr/bin/env python2\n# -*- coding: utf-8 -*-\n\"\"\"\nCreated on Mon Dec 26 22:29:29 2016\n\n@author: HoWil\nLicense: LGPL v 2.1\n\nConcept:\n After starting the process by clicking on \"Start here...\" one can click into the 3D view to get all elements below the the cursor click.\n The found elements are then listed in a pulldown-menu.\n\nHint:\n  Does not work with Part-Design-Next 'Part'-elements and childs of them in the tree.\n\"\"\"\n\n#==============================================================================\n#\n#==============================================================================\nfrom PySide import QtGui, QtCore\nimport FreeCADGui\nimport FreeCAD\nfrom pivy.coin import SoMouseButtonEvent\n\n\nclass element_selector():\n\n# ========================================================\n#  GUI\n# ========================================================\n    def __init__(self):\n\n        self.dialog = None\n        self.dialog = QtGui.QDialog()\n        self.dialog.resize(500,150)\n        self.dialog.setWindowTitle(\"Find all components and related objects below cursor click.\")\n \n        self.view = None\n        self.root = None\n        self.hm = None\n\n        self.elements_list = []\n        self.objects_list = []\n        self.components_list = []\n        self.element_selection_data = []\n\n        self.element_selection = QtGui.QComboBox()\n        self.element_selection.setToolTip(\"Lists all found components\")\n        self.element_selection.currentIndexChanged.connect(self.selection_manager)\n        self.element_selection.setMinimumContentsLength = 40\n        self.element_selection.setMinimumSize(300,30)\n        self.element_selection.addItems(['Found elements will be listed here.'])\n        self.element_selection.setEditable(False) # Set the combo-box not-editalbe\n        \n        self.get_click = QtGui.QPushButton(\"Start here before clicking on an object in the draw window.\")\n        self.get_click.clicked.connect(self.start_mouse_over_cb)\n        \n        cancle_button = QtGui.QDialogButtonBox(self.dialog)\n        cancle_button.setOrientation(QtCore.Qt.Horizontal)\n        cancle_button.setStandardButtons(QtGui.QDialogButtonBox.Close)\n\n        \n        grid = QtGui.QGridLayout()             #    rot, column, alignment\n        grid.setSpacing(10)\n\n        # Run\n        grid.addWidget(self.get_click,              0, 0, 1, 1)\n        # Elements\n        grid.addWidget(self.element_selection,      1, 0, 1, 1)\n        # Cancel\n        grid.addWidget(cancle_button,                       2, 0, 1, 1)\n\n        self.dialog.setLayout(grid)\n\n        QtCore.QObject.connect(cancle_button, QtCore.SIGNAL(\"rejected()\"), self.close)\n\n        QtCore.QMetaObject.connectSlotsByName(self.dialog)\n        self.dialog.show()\n        self.dialog.exec_()\n        \n    def start_mouse_over_cb(self):\n        self.element_selection.clear() # Clear all elements in the combo-box\n        self.element_selection.setEditable(True) # Set the combo-box editalbe\n        self.view = FreeCADGui.ActiveDocument.ActiveView\n\n        view = FreeCADGui.ActiveDocument.ActiveView.getViewer()\n        root = view.getSceneGraph()\n        hm = root.highlightMode.getValue() # store the original highlightMode\n        root.highlightMode.setValue(2) # switch highlightMode off\n        self.root = root\n        self.hm = hm\n        \n        self.callback = self.view.addEventCallbackPivy(SoMouseButtonEvent.getClassTypeId(), self.mouse_over_cb)\n        \n        \n    def mouse_over_cb(self, event_callback):\n        event = event_callback.getEvent()\n        \n        if event.getState() == SoMouseButtonEvent.DOWN:\n            pos = event.getPosition().getValue()\n\n            element_list = FreeCADGui.ActiveDocument.ActiveView.getObjectsInfo((int(pos[0]), int(pos[1])))\n            FreeCADGui.Selection.clearSelection()\n            \n            self.element_selection.clear() # clear pull down dialog\n            self.element_selection_data = []\n        \n            self.elements_list = element_list # store all elements found\n            \n            self.objects_list = [] # reset objects_list\n            self.components_list = [] # restet components_list\n            \n            if element_list: # if there were elements found\n            \n                FreeCAD.Console.PrintMessage(\"\\n *** Elements found under mouse pointer (Part-Desing-Next- 'Parts' do not work yet!) ***\\n\")\n                \n                for e in element_list:\n                    label_object = str(e[\"Object\"])\n                    label_component = str(e[\"Component\"])\n                    label_object_plus_component = label_object + ' - ' + label_component\n\n                    if label_object not in self.element_selection_data:\n                        self.objects_list.append(e[\"Object\"])\n                        self.components_list.append(None)\n                        \n                        FreeCAD.Console.PrintMessage(\" \" + str(label_object) + \"\\n\")\n                        \n                        self.element_selection.addItem(label_object)\n                        self.element_selection_data.append(label_object)\n                    \n                    if label_object_plus_component not in self.element_selection_data:\n                        self.objects_list.append(e[\"Object\"])\n                        self.components_list.append(e[\"Component\"])\n                            \n                        FreeCAD.Console.PrintMessage(\" \" + str(label_object_plus_component) + \"\\n\")\n        \n                        self.element_selection.addItem(label_object_plus_component)\n                        self.element_selection_data.append(label_object_plus_component)\n                        \n        \n        self.view.removeEventCallbackPivy(SoMouseButtonEvent.getClassTypeId(), self.callback)    \n        \n        self.root.highlightMode.setValue(self.hm) # restore the original highlightMode\n        FreeCADGui.Selection.clearSelection()\n\n        self.element_selection.removeItem(self.element_selection.findText('tmp'))\n\n#==============================================================================\n# Highligthing the choice from GUI\n#==============================================================================\n    def selection_manager(self):\n        try:\n            FreeCADGui.Selection.clearSelection()\n            if self.element_selection.isEditable():\n                sel_index = self.element_selection.currentIndex()\n                \n                if self.components_list[sel_index] == None :\n                    # An object was selected in combobox\n                    FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(self.objects_list[sel_index]))\n                else:\n                    # An element of an object was selected in combobox\n                    FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(self.objects_list[sel_index]), self.components_list[sel_index])\n\n        except:\n            FreeCAD.Console.PrintError(\"Unable to complete the element selection/highlighting.\\n\")\n            self.close()\n\n    def close(self):\n        self.dialog.hide()\n\nelement_selector()",
    "url": "https://wiki.freecad.org/Macro_FC_element_selector",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2016-12-26",
    "src_filename": "",
    "filename_from_url": "",
    "author": "HoWil",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_FC_element_selector.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/0/07/Macro_FC_element_selector.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FCInfo",
    "on_wiki": true,
    "on_git": false,
    "desc": "Gives information about the selected shape and can display a conversion of length, inclination (degrees, radians, grades, percent), area, volume and weight in different units (metric and imperial). The macro now also works for the elements of a sketch in edit mode. <p><br />French Version <a rel=\"nofollow\" class=\"external text\" href=\"https://gist.github.com/mario52a/6afc64081c4eb8be3b93\">Version Fran\u00e7aise</a><br /><br />Macro version: 1.30c<br />Last modified: 2025/01/28<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/5/53/FCInfo.png\">ToolBar Icon</a><br />Author: Mario52<br /> </p> ",
    "comment": "gives different information about the selected object with the possibility of saving information",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\"\"\"\n***************************************************************************\n*   Copyright (c) <mario52> 2014 2015 2016 2017 2018 2019 2020 2021 2022  *\n*                           2023 2024 2025                                *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *\n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n# FCInfo.FCMacro    en\n#       https://fr.wikipedia.org/wiki/Kilogramme\n# Select an object or launch the application and select an object, and a series of information appear.\n# Calculations FreeCAD unit, which is the mm on each new selection, the unit of length-based his return still on mm and decimal degrees angle.\n# Always leave by the \"Exit\" button if it exits the program without going through the button \"Exit\" the program remains in memory and continues to run.\n# Should leave FreeCAD to erase memory.\n# Only the first 200 objects are visible in the table if there are more than 200 items in the object a signal will be displayed by '(!+ 200),\n# The complete list of data is visible in the backup file\n#\n# 05_01 01/14 Docked PyQt4 + PySide 19/12/2015 suppression de PyQt4 21/06/2017 ajout style 8 points et nouveau path\n# 12/12/2017 upgrade de la section Matrix of inertia de \"pinq\" voir \"https://forum.freecadweb.org/viewtopic.php?f=22&t=23888\"\n#            other: Momentof Interia - FCInfo macro: https://forum.freecad.org/viewtopic.php?t=64653\n# ajout de Plans, Axes, Points et optimisation\n# 16/04/2019 upgrade pour 0.17.13541 (Git), 0.18.16093 (Git), 0.19.16474 (Git)Qt: 5.6.2 Python: 3.6.6 OCC: 7.3.0\n# 30/05/2019 ver \"01.21-rmu\" rmu change fixed positions to qt layouts grid.addWidget() by rmu75 see the rmu75 fork \"https://gist.github.com/rmu75/b165147bd1c2f2659c014103793ae1d8\"\n# 07/11/2019 ver \"01.21-3-rmu\" replace character micro = \"U\", square = \"2\", cube = \"3\", degrees = \" deg\" see \"https://forum.freecadweb.org/viewtopic.php?f=3&t=6005&start=70#p345819\"\n# 12/11/2020 ver \"01.22-rmu\" replace self window(hide) by \"self.window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)\"\n# 18/11/2021 ver \"01.23 rmu\" ajout icones, RB clipBoard, Decimal, Hauteur texte, compatible Sketcher editeur ouvert \n# 25/11/2021 ver \"01.23cb rmu\" delete \"import Sketcher * \" create conflict with open(OpenName, \"r\") ??\n# 02/12/2021 ver \"01.24 rmu\" add adjustedGlobalPlacement(,), boundbox tracing\n# 10/12/2021 ver \"01.25 rmu\" PySide2 and add comboBox materials\n# 11/12/2021 ver \"01.25b, 12/12/2021 ver \"01.25c, 13/12/2021 ver \"01.25d, 2021/12/27 ver \"1.25e\"\n# 2022/02/06 ver \"1.26\" Mesh, Points, Couleurs, 2022/02/20 ver 1.26b upgrade BSPline, 2022/04/19 ver 1.26c upgrade BSpline error with Gear Bspline=Line\n# 2023/06/24 ver \"1.27\" optimize styleSheet and litle bug\n# 2023/09/01 ver \"1.28\" modify variable name, possibility hidden each sector, save data spreadSheet in document, surface radius, add button webWiki and webForum\n# 2024/05/06 ver \"1.29\" port to PySide6 by sylvainbx https://gist.github.com/sylvainbx/af09a30be3e1427de56305825331fb29\n# 2024/05/10 ver \"1.29b\" PySide2 modify Inertia \" MatrixX1*uniteM to (MatrixX1*uniteM) \" and adding spinBox inertia\n            #https://forum.freecad.org/viewtopic.php?p=713935#p713935 # Moment of inertias calculation\n            #https://forum.freecad.org/viewtopic.php?t=64653    # Momentof Interia - FCInfo macro\n# 2025/01/02 ver 1.30 delette all reference to PySide PySide2 and QtWidgets modify the (Qt) Save file, 2025/01/25 1.30b replace slash Windows by slash Python \"/\" , 2025/01/28 comboBox ArchLinux \n#\n#OS: Windows 10 build 19045\n#Word size of FreeCAD: 64-bit\n#Version: 0.22.0dev.37100 (Git)\n#Build type: Release\n#Branch: main\n#Hash: ede6c811fd39d68a44949601f2eb7ecc8a67fdb7\n#Python 3.11.9, Qt 5.15.13, Coin 4.0.2, Vtk 9.2.6, OCC 7.7.2\n#Locale: French/Mars (fr_MA)\n#\n__Title__    = \"FCInfo\"\n__Author__   = \"Mario52\"\n__Url__      = \"https://gist.github.com/mario52a/8d40ab6c018c2bde678f\"\n__Version__  = \"1.30c\"\n__Date__     = \"2025/01/28\"\n__Comment__  = \"gives different information about the selected object with the possibility of saving information\"\n__Forum1__   = \"http://forum.freecadweb.org/viewtopic.php?f=10&t=3185\"\n__Forum2__   = \"https://forum.freecadweb.org/viewtopic.php?f=3&t=6005\"\n__Wiki__     = \"https://www.freecadweb.org/wiki/Macro_FCInfo\"\n__Gist__     = \"https://gist.github.com/mario52a/6afc64081c4eb8be3b93\"\n__IconL__    = \"\"\n__IconW__    = \"\"\n__Help__     = \"Start the macro select an object and read the info displayed\"\n__Status__   = \"stable\"\n__Requires__ = \"freecad 0.19 and more\"\n__Communication__ = \"http://forum.freecadweb.org/viewtopic.php?f=10&t=3185\"\n#\nimport PySide\ntry:\n    from PySide import QtWidgets\n    from PySide.QtWidgets import *\nexcept Exception:\n    None\nfrom PySide import QtGui , QtCore\nfrom PySide.QtGui import *\nfrom PySide.QtCore import *\n\n#import PySide.QtXml\nimport os\nimport platform\nimport warnings\nwarnings.simplefilter(\"ignore\")\n\nimport Draft, Part, FreeCAD, PartGui, FreeCADGui\nimport FreeCAD as App\nimport FreeCADGui as Gui\nfrom FreeCAD import Base\nimport Sketcher\nimport Points\nimport Mesh\nimport pivy\nfrom pivy import coin\nimport Spreadsheet\n\nimport math\nimport decimal\nfrom math import sqrt, pi, sin, cos, asin, acos, atan, atan2, degrees, radians, tan\n\nimport csv\nimport codecs\nimport sys\nimport copy                                                  # pour copier 2 tableaux\nimport re\n\n####path#########################################################################\nglobal path          ; path          = \"\"                            #\n#path  = FreeCAD.ConfigGet(u\"AppHomePath\")                           # path FreeCAD installation\n#path  = FreeCAD.ConfigGet(u\"UserAppData\")                           # path FreeCAD User data\n#path  = \"your path\"                                                 # your directory path\nparam = FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macro\")# macro path\npath = param.GetString(u\"MacroPath\",\"\") + \"/\"                        # macro path\npath = path.replace(u\"\\\\\",\"/\")                                       # convert the \"\\\" to \"/\"\n#print( u\"Path for the icons : \" , path )                            #\n#################################################################################\n\ntry:\n    import webbrowser\nexcept Exception:\n    None\n\n#### Detect version macro ########################################### #22/03/2021\ntry:\n    import urllib\n    from urllib import request\nexcept Exception:\n    None\n#### Detect version macro ########################################### #22/03/2021\ndef versionSearch():\n    try:\n        contentPage = request.urlopen(u\"https://wiki.freecadweb.org/Macro_\" + __Title__).readlines()\n        versionDetect = dateDetect = \"\"\n        effacer = 0\n        for i in contentPage:\n            if \"ctEven macro-version\" in str(i):\n                versionDetect = str((str(i).split(\">\")[1]))\n                versionDetect = versionDetect.split(\"\\\\\")[0]\n            if \"ctEven macro-date\" in str(i):\n                dateDetect = str((str(i).split(\">\")[1]))\n                dateDetect = dateDetect.split(\"\\\\\")[0]\n            if (versionDetect != \"\") and (dateDetect != \"\"):\n                break\n        try:\n            if (versionDetect == __Version__) and (dateDetect == __Date__):\n                None\n            else:\n                msg = (u\"New version availlable : \" + \"\\n\" + \n                      str(versionDetect) + \":\" + str(dateDetect) + \"\\n\" + \n                      \"You can install with AddonManager\" + \"\\n\" + \n                      \"For desactivate this Info window go to \" + \"\\n\" +\n                      \"parameter:BaseApp/Preferences/Macros/FCMmacros/FCInfo \" + \"\\n\" +\n                      \"set the [ switchVersionSearch ] parameter to False\")\n                App.Console.PrintMessage(u\"your actual version    : \" + str(__Version__) + \" : \" + str(__Date__) + \"\\n\")\n                App.Console.PrintMessage(u\"new version availlable : \" + str(versionDetect) + \" : \" + str(dateDetect) + \"\\n\")\n                diag = QMessageBox(QMessageBox.Information, 'New Version', msg)\n                diag.setWindowModality(QtCore.Qt.ApplicationModal)\n                diag.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)  # PySide cette fonction met la fenetre en avant\n                diag.exec_()\n        except Exception:\n            None\n        return versionDetect, dateDetect\n    except Exception:\n        App_Console_PrintError(u\"Not search version not connected for testing or internal error\" + \"\\n\")\n\nglobal FreeCAD_ParamGetSet ; FreeCAD_ParamGetSet = FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__)    # FreeCAD_ParamGetSet\nglobal switchVersionSearch; switchVersionSearch = 0  # Search version switchable in \n                                                     # Tools/Edit parameter/BaseApp/Preferences/Macros/FCMmacros/FCCircularText\nswitchVersionSearch = FreeCAD_ParamGetSet.GetBool(u\"switchVersionSearch\")\nFreeCAD_ParamGetSet.SetBool(u\"switchVersionSearch\", switchVersionSearch)            #*True or False\nif switchVersionSearch == 1:\n    versionSearch()\n#### Detect version macro ###########################################\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QApplication.translate(context, text, disambig)\n\n####################################################################################\n\ndef iso8859(encoder):\n# ori 0.18 Py 27   return unicode(encoder).encode('iso-8859-1')\n    verPython = sys.version_info\n    if int(verPython.major) < 3:\n        return unicode(encoder).encode('iso-8859-1')\n    else:\n        encoder = str(encoder)\n        return encoder\n\ndef utf8(unio):\n    return unicode(unio).encode('UTF8')\n\ndef heure():\n    return QtCore.QTime().currentTime().toString('hh:mm:ss')\ndef dateEu():\n    return QtCore.QDate().currentDate().toString('dd/MM/yyyy')       # forme euro\ndef dateUs():\n    return QtCore.QDate().currentDate().toString('MM/dd/yyyy')       # forme us\ndef dateUk():\n    return QtCore.QDate().currentDate().toString('yyyy/MM/dd')       # forme Uk\ndef dateComp():\n    return QtCore.QDate().currentDate().toString('dddd d MMMM yyyy') # Return \"dimanche 20 Juillet 2013\"\n\ndef Around(a) :\n    global seTDecimalValue\n\n    if seTDecimalValue == -1:\n        seTDecimalValue = 1000\n    ard = round(a, seTDecimalValue)\n    return ard\n\nglobal uniteAs       ; uniteAs       = \" deg\" #  HTML: &deg\ndef degMinSec(angle0):\n    # give the angle in degrees\n    global uniteAs\n    try:\n        deg = int(angle0)\n        min = int((angle0 - deg)*60)\n        sec = Around((((angle0 - deg)*60)-min)*60)\n        angle = str(deg)+\" deg\"+\" \"+str(min)+u\"' \"+str(sec)+u\"''\"\n        uniteAs = \"\"\n        return angle\n    except Exception:\n        return 0\n\ndef angleGrade(angle0):\n    # give the angle in degrees\n    global uniteAs\n    try:\n        angle = float(angle0)\n        angle = (200.0 * angle) / 180.0\n        uniteAs = \" gon\"\n        #return round(angle,6)\n        return angle\n    except Exception:\n        return 0\n\ndef anglePourcent(angle0):\n    # give the angle in degrees\n    global uniteAs\n    #angle0 = round(abs(angle0))\n    angle0 = abs(angle0)\n    if (angle0 == 90):\n        return 0.0\n    else:\n        try:\n            if angle0 in range(90 ,181): angle0 = 180 - angle0\n            if angle0 in range(180,271): angle0 = angle0 - 180\n            if angle0 in range(270,361): angle0 = 360 - angle0\n            #angle = abs(round((tan(radians(angle0))*100),2))\n            angle = abs(tan(radians(angle0))*100)\n            uniteAs = u\"%\"\n            #return round(angle,6)\n            return angle\n            \n        except Exception:\n            return 0.0\n\ndef angle2(vecteur_x1, vecteur_y1, vecteur_x2, vecteur_y2, modeTypeAngle):\n# calculation of the slope of a line using two vectors\n# If 'modeTypeAngle' = 1 then display in degrees else in radians\n    global uniteAs\n    try:\n        deltaX = vecteur_x2 - vecteur_x1\n        deltaY = vecteur_y2 - vecteur_y1\n        if modeTypeAngle == 1:\n            angle = degrees(atan2(float(deltaY),float(deltaX))) # degrees\n            uniteAs = \" deg\"\n        else:\n            angle = atan2(float(deltaY),float(deltaX))          # radian\n            uniteAs = \" rad\"\n        #return round(angle,6)\n        return angle\n    except Exception:\n        return 0\n\n#### Configuration begin ################################################\n#### NOT MODIFY THE CODE HERE ####\n#### for modify : go to : FreeCAD >Menu >Tools >Edit parameters... >BaseApp/Preferences/Macros/FCMmacros/FCInfo ####\n##\nFreeCAD_ParamGetSet.SetString(u\"Version\", __Version__ + \" (\" + __Date__ + \")\")\n##\nglobal switchNotInfoOnBeginning # switchNotInfoOnBeginnin   = 0   # display or not the inf on beginning run macro False\nswitchNotInfoOnBeginning = FreeCAD_ParamGetSet.GetBool(u\"switchNotInfoOnBeginning\")\nFreeCAD_ParamGetSet.SetBool(u\"switchNotInfoOnBeginning\", switchNotInfoOnBeginning)  #*True or False\n##\nglobal switchWarning            # display or not the little window \"Warning Error Selection\"\nswitchWarning = FreeCAD_ParamGetSet.GetBool(u\"switchWarning\")\nFreeCAD_ParamGetSet.SetBool(u\"switchWarning\", switchWarning)                        #*True or False\n#Config\nglobal switchCreatePoint        #; switchCreatePoint        = 0   # for point False\nswitchCreatePoint = FreeCAD_ParamGetSet.GetBool(u\"switchCreatePoint\")\n##\nglobal switchCreateAxis         #; switchCreateAxis         = 1   # for axis  True\nswitchCreateAxis = FreeCAD_ParamGetSet.GetBool(u\"switchCreateAxis\")\n##\nglobal switchCreatePlane        #; switchCreatePlane        = 1   # for plane True\nswitchCreatePlane = FreeCAD_ParamGetSet.GetBool(u\"switchCreatePlane\")\n##\nglobal switchDisplayInfoObject  #; switchDisplayInfoObject  = 0   # \nswitchDisplayInfoObject = FreeCAD_ParamGetSet.GetBool(u\"switchDisplayInfoObject\")\nFreeCAD_ParamGetSet.SetBool(u\"switchDisplayInfoObject\", switchDisplayInfoObject)    #*True or False\n##\nglobal switchDisplayErrorInfo  #; switchDisplayErrorInfo  = 0   # \nswitchDisplayErrorInfo = FreeCAD_ParamGetSet.GetBool(u\"switchDisplayErrorInfo\")\nFreeCAD_ParamGetSet.SetBool(u\"switchDisplayErrorInfo\", switchDisplayErrorInfo)      #*True or False\n##\nglobal switchClearDisplayReportView #; switchClearDisplayReportView  = 0   # \nswitchClearDisplayReportView = FreeCAD_ParamGetSet.GetBool(u\"switchClearDisplayReportView\")\nFreeCAD_ParamGetSet.SetBool(u\"switchClearDisplayReportView\", switchClearDisplayReportView) #*True or False\n##\nglobal seTWidgetPosition        #; seTWidgetPosition        = 0   # position the widget Left or Right\nseTWidgetPosition = FreeCAD_ParamGetSet.GetBool(u\"seTWidgetPosition\")               # True or False\nFreeCAD_ParamGetSet.SetBool(u\"seTWidgetPosition\", seTWidgetPosition)   \n##\nglobal switchBoundBoxCreateText #; switchBoundBoxCreateText = 0   # \nswitchBoundBoxCreateText = FreeCAD_ParamGetSet.GetBool(u\"switchBoundBoxCreateText\")\n##\nglobal seTBoundBoxTextHeigth    #; seTBoundBoxTextHeigth    = 3.0 # \nseTBoundBoxTextHeigth = FreeCAD_ParamGetSet.GetFloat(u\"seTBoundBoxTextHeigth\")\nif seTBoundBoxTextHeigth == 0: seTBoundBoxTextHeigth = 3.0\n##\nglobal seTBoundBoxTextArround   #; seTBoundBoxTextArround   = 3   # \nseTBoundBoxTextArround = FreeCAD_ParamGetSet.GetInt(u\"seTBoundBoxTextArround\")\nif seTBoundBoxTextArround == 0: seTBoundBoxTextArround = 3\nFreeCAD_ParamGetSet.SetInt(u\"seTBoundBoxTextArround\", seTBoundBoxTextArround)       # 3\n##\nglobal seTBoundBoxDisplayModeText   #; seTBoundBoxDisplayModeText = str(u\"Screen\")   # available : u\"Screen\" or u\"World\" \nseTBoundBoxDisplayModeText = FreeCAD_ParamGetSet.GetString(u\"seTBoundBoxDisplayModeText\")\nif seTBoundBoxDisplayModeText == \"\": seTBoundBoxDisplayModeText = str(u\"Screen\")\nFreeCAD_ParamGetSet.SetString(u\"seTBoundBoxDisplayModeText\", seTBoundBoxDisplayModeText)\n##\nglobal seTBoundBoxJustificationText #; seTBoundBoxJustificationText = str(u\"Center\") # available : \"Center\" or \"Left\" or \"Right\"\nseTBoundBoxJustificationText = FreeCAD_ParamGetSet.GetString(u\"seTBoundBoxJustificationText\")\nif seTBoundBoxJustificationText == \"\": seTBoundBoxJustificationText = str(u\"Center\")\nFreeCAD_ParamGetSet.SetString(u\"seTBoundBoxJustificationText\", seTBoundBoxJustificationText)\n##\nglobal seTMemoClipBoard         #; seTMemoClipBoard         = 0   # seT format du memo 0=None ou 1=F...CAD(1,1,1) ou 2=1,1,1 ou 3=1 1 1 \nseTMemoClipBoard = FreeCAD_ParamGetSet.GetInt(u\"seTMemoClipBoard\")\n##\nglobal seTTextHeigthValue       #; seTTextHeigthValue       = 11  # heigth Text value\nseTTextHeigthValue = FreeCAD_ParamGetSet.GetInt(u\"seTTextHeigthValue\")\nif seTTextHeigthValue == 0: seTTextHeigthValue = 11\n##\nglobal seTDecimalValue          #; seTDecimalValue          = 4   # number of decimal value\nseTDecimalValue = FreeCAD_ParamGetSet.GetInt(u\"seTDecimalValue\")\nif seTDecimalValue == 0: seTDecimalValue = 4\n##\nglobal seTMaterialCurrentIndex  #; seTMaterialCurrentIndex  = ?   # index materiel\nseTMaterialCurrentIndex = FreeCAD_ParamGetSet.GetInt(u\"seTMaterialCurrentIndex\")\n##\nglobal seTMaterialFileName      #; seTMaterialFileName      = u\"FCInfo_material.txt\" or other\nseTMaterialFileName = FreeCAD_ParamGetSet.GetString(u\"seTMaterialFileName\")\nif seTMaterialFileName == \"\": seTMaterialFileName =  u\"FCInfo_material.txt\"\nFreeCAD_ParamGetSet.SetString(u\"seTMaterialFileName\", seTMaterialFileName)          #*\"FCInfo_material.txt\"\n##\n#### new version since 1.25f separate path and name of file more logic 28/01/2022 the parameter/Preferences is not compatible \"you must delete the name file and extension in preferences\"\nglobal seTMaterialReadPathName  #; seTMaterialReadPathName  = path\nglobal seTMaterialSavePathName  #; seTMaterialSavePathName  = path\nseTMaterialSavePathName = FreeCAD_ParamGetSet.GetString(u\"seTMaterialSavePathName\")\nif seTMaterialSavePathName == \"\": seTMaterialSavePathName = path\nseTMaterialSavePathName = os.path.dirname(seTMaterialSavePathName) + \"/\"  # = C:/Provisoire400/\nseTMaterialReadPathName = seTMaterialSavePathName\nFreeCAD_ParamGetSet.SetString(u\"seTMaterialSavePathName\", seTMaterialSavePathName)  #*\"C:/.../Macro/\"\n##\nglobal seTMaterialPrice         #; seTMaterialPrice         = 1.0  # price\nseTMaterialPrice = FreeCAD_ParamGetSet.GetFloat(u\"seTMaterialPrice\")\nif seTMaterialPrice == 0: seTMaterialPrice = 0.0\n##\nglobal seTMaterialSuffixDevise  #; seTMaterialSuffixDevise  = \" Eu # Suffix Devise\nseTMaterialSuffixDevise = FreeCAD_ParamGetSet.GetString(u\"seTMaterialSuffixDevise\")\nif seTMaterialSuffixDevise == \"\": seTMaterialSuffixDevise = \" Eu (by Kg)\"\n##\nglobal seTMaterialSuffixCost    #; seTMaterialSuffixCost    = \" Eu # Suffix Cost\nseTMaterialSuffixCost = FreeCAD_ParamGetSet.GetString(u\"seTMaterialSuffixCost\")\nif seTMaterialSuffixCost == \"\": seTMaterialSuffixCost  = \" Eu\"\n##\nglobal seTMaterialCost          #; seTMaterialCost          = 1.0  # (by Kg)\nseTMaterialCost = FreeCAD_ParamGetSet.GetFloat(u\"seTMaterialCost\")\nif seTMaterialCost == 0: seTMaterialCost = 1.0\n##\nglobal seTDensiteValue          #; seTDensiteValue          = 1.0  # (steel = 7,32 to 7,86 kg by dm3)\nseTDensiteValue = FreeCAD_ParamGetSet.GetFloat(u\"seTDensiteValue\")\nif seTDensiteValue == 0: seTDensiteValue = 1.0\nFreeCAD_ParamGetSet.SetFloat(u\"seTDensiteValue\", seTDensiteValue)\n##\nglobal seTDensiteDecimalNumber  #; seTDensiteDecimalNumber  = 4    # number of decimal value\nseTDensiteDecimalNumber = FreeCAD_ParamGetSet.GetInt(u\"seTDensiteDecimalNumber\")\nif seTDensiteDecimalNumber == 0: seTDensiteDecimalNumber = 4\nFreeCAD_ParamGetSet.SetInt(u\"seTDensiteDecimalNumber\", seTDensiteDecimalNumber)     #*4\n##\nglobal seTDensiteSingleStep     #; seTDensiteSingleStep     = 1.0  # increse step \nseTDensiteSingleStep = FreeCAD_ParamGetSet.GetFloat(u\"seTDensiteSingleStep\")\nif seTDensiteSingleStep == 0: seTDensiteSingleStep = 1.0\nFreeCAD_ParamGetSet.SetFloat(u\"seTDensiteSingleStep\", seTDensiteSingleStep)         #*1.0\n##\nglobal seTIndexUnitWeight       ; seTIndexUnitWeight = 0           # item Poids\n#seTIndexUnitWeight = FreeCAD_ParamGetSet.GetInt(u\"seTIndexUnitWeight\")\n##\nglobal seTIndexUnitLength       ; seTIndexUnitLength = 0           # item Longueur\n#seTIndexUnitLength = FreeCAD_ParamGetSet.GetInt(u\"seTIndexUnitLength\")\n##\nglobal seTPositionFlyRightLeft  #; seTPositionFlyRightLeft  = 2    # 1 = fly, 2 = RightDock other= LeftDock\nseTPositionFlyRightLeft = FreeCAD_ParamGetSet.GetInt(u\"seTPositionFlyRightLeft\")\nif seTPositionFlyRightLeft == 0: seTPositionFlyRightLeft = 2       # 1 , 2, other\n##\nglobal seTUnitSymbolMicro       #; seTUnitSymbolMicro       = u\"U\" # micro  hex=\"\\xB5\", html=<span>&#181;</span>\nseTUnitSymbolMicro = FreeCAD_ParamGetSet.GetString(u\"seTUnitSymbolMicro\")\nif seTUnitSymbolMicro == \"\": seTUnitSymbolMicro = \"U\"\nFreeCAD_ParamGetSet.SetString(u\"seTUnitSymbolMicro\", seTUnitSymbolMicro)            #*\"U\"\n##\nglobal seTUnitSymbolCube        #; seTUnitSymbolCube        = u\"3\" # cube   hex=\"\\xb3\", html=<span>&#179;</span>\nseTUnitSymbolCube = FreeCAD_ParamGetSet.GetString(u\"seTUnitSymbolCube\")\nif seTUnitSymbolCube == \"\": seTUnitSymbolCube = \"3\"\nFreeCAD_ParamGetSet.SetString(u\"seTUnitSymbolCube\", seTUnitSymbolCube)              #*\"3\"\n##\nglobal seTDensiteSuffixChain    #; seTDensiteSuffixChain    = kg   # Suffix (by dm3)\nseTDensiteSuffixChain = FreeCAD_ParamGetSet.GetString(u\"seTDensiteSuffixChain\")\nif seTDensiteSuffixChain == \"\": seTDensiteSuffixChain = \" kg (by dm)\" + seTUnitSymbolCube\nFreeCAD_ParamGetSet.SetString(u\"seTDensiteSuffixChain\", seTDensiteSuffixChain)      #*\" kg (by dm3)\"\n##\nglobal seTUnitSymbolCarre       #; seTUnitSymbolCarre       = u\"2\" # carre  hex=\"\\xb2\", html=<span>&#178;</span>\nseTUnitSymbolCarre = FreeCAD_ParamGetSet.GetString(u\"seTUnitSymbolCarre\")\nif seTUnitSymbolCarre == \"\": seTUnitSymbolCarre = \"2\"\nFreeCAD_ParamGetSet.SetString(u\"seTUnitSymbolCarre\", seTUnitSymbolCarre)            #*\"2\"\n##\nglobal setPathLatestDirectory   #; setPathLatestDirectory   = \"C:/ ???\"\nsetPathLatestDirectory = FreeCAD_ParamGetSet.GetString(u\"setPathLatestDirectory\")\nif setPathLatestDirectory == \"\": setPathLatestDirectory = path\nFreeCAD_ParamGetSet.SetString(u\"setPathLatestDirectory\", setPathLatestDirectory)    #*\"C:/ ???\"\n##\nglobal setBSplineToByArcValue   #; setBSplineToByArcValue   = 0.00001\nsetBSplineToByArcValue = FreeCAD_ParamGetSet.GetFloat(u\"setBSplineToByArcValue\")\nif setBSplineToByArcValue == 0.0: setBSplineToByArcValue = 0.00001\nFreeCAD_ParamGetSet.SetFloat(u\"setBSplineToByArcValue\", setBSplineToByArcValue)     #*0.00001\nglobal BSplinetoByArcValeurS    # string pour afficher en \"0.00001\" pas en 1.e5\nBSplinetoByArcValeurS = str(\"%.12f\" % setBSplineToByArcValue)\nBSplinetoByArcValeurS = str(BSplinetoByArcValeurS.rstrip('0'))\n##\nglobal setMeshTopologyValue   #; setMeshTopologyValue   = 0.1\nsetMeshTopologyValue = FreeCAD_ParamGetSet.GetFloat(u\"setMeshTopologyValue\")\nif setMeshTopologyValue == 0.0: setMeshTopologyValue = 0.1\nFreeCAD_ParamGetSet.SetFloat(u\"setMeshTopologyValue\", setMeshTopologyValue)         #*0.1\n##\nglobal switchBSplineCreateCircleConstructorAxis#; switchBSplineCreateCircleConstructorAxis = 0                 # for create points with toByArcs()\nswitchBSplineCreateCircleConstructorAxis = FreeCAD_ParamGetSet.GetBool(u\"switchBSplineCreateCircleConstructorAxis\")\nFreeCAD_ParamGetSet.SetBool(u\"switchBSplineCreateCircleConstructorAxis\", switchBSplineCreateCircleConstructorAxis)#*True or False\n##\nglobal switchBSplineCreateCircleConstructor    #; switchBSplineCreateCircleConstructor = 0      # for create circles with toByArcs()\nswitchBSplineCreateCircleConstructor = FreeCAD_ParamGetSet.GetBool(u\"switchBSplineCreateCircleConstructor\")\nFreeCAD_ParamGetSet.SetBool(u\"switchBSplineCreateCircleConstructor\", switchBSplineCreateCircleConstructor)        #*True or False\n##\nglobal switchCreateLineDiVatNatOnClick    #; switchCreateLineDiVatNatOnClick = 0      # for position line on click mouse\nswitchCreateLineDiVatNatOnClick = FreeCAD_ParamGetSet.GetBool(u\"switchCreateLineDiVatNatOnClick\")\nFreeCAD_ParamGetSet.SetBool(u\"switchCreateLineDiVatNatOnClick\", switchCreateLineDiVatNatOnClick)                  #*True or False\n##\nglobal setMomentOfInertia_16    #; setMomentOfInertia_16 = 1\nsetMomentOfInertia_16 = FreeCAD_ParamGetSet.GetInt(u\"setMomentOfInertia_16\")\nif setMomentOfInertia_16 == 0: setMomentOfInertia_16 = 1\nFreeCAD_ParamGetSet.SetInt(u\"setMomentOfInertia_16\", setMomentOfInertia_16)\n##\nglobal setMomentOfInertiaMassique_17    #; setMomentOfInertiaMassique_17 = 1 \nsetMomentOfInertiaMassique_17 = FreeCAD_ParamGetSet.GetInt(u\"setMomentOfInertiaMassique_17\")\nif setMomentOfInertiaMassique_17 == 0: setMomentOfInertiaMassique_17 = 1\nFreeCAD_ParamGetSet.SetInt(u\"setMomentOfInertiaMassique_17\", setMomentOfInertiaMassique_17)\n####\n#### section GroupBox begin\nglobal switch_setVisible_GBox_001_Document             # switch_setVisible_GBox_001_Document = True (1)\nswitch_setVisible_GBox_001_Document = FreeCAD_ParamGetSet.GetBool(u\"switch_setVisible_GBox_001_Document\", True)\nFreeCAD_ParamGetSet.SetBool(u\"switch_setVisible_GBox_001_Document\", switch_setVisible_GBox_001_Document)           # *True or False\nglobal switch_setVisible_GBox_002_Coordinate_Mouse     # switch_setVisible_GBox_002_Coordinate_Mouse = True (1)\nswitch_setVisible_GBox_002_Coordinate_Mouse = FreeCAD_ParamGetSet.GetBool(u\"switch_setVisible_GBox_002_Coordinate_Mouse\", True)\nFreeCAD_ParamGetSet.SetBool(u\"switch_setVisible_GBox_002_Coordinate_Mouse\", switch_setVisible_GBox_002_Coordinate_Mouse) # *True or False\nglobal switch_setVisible_GBox_003_Color                # switch_setVisible_GBox_003_Color = True (1)\nswitch_setVisible_GBox_003_Color = FreeCAD_ParamGetSet.GetBool(u\"switch_setVisible_GBox_003_Color\", True)\nFreeCAD_ParamGetSet.SetBool(u\"switch_setVisible_GBox_003_Color\", switch_setVisible_GBox_003_Color)                 # *True or False\nglobal switch_setVisible_GBox_004_Object_Mesh          # switch_setVisible_GBox_004_Object_Mesh = True (1)\nswitch_setVisible_GBox_004_Object_Mesh = FreeCAD_ParamGetSet.GetBool(u\"switch_setVisible_GBox_004_Object_Mesh\", True)\nFreeCAD_ParamGetSet.SetBool(u\"switch_setVisible_GBox_004_Object_Mesh\", switch_setVisible_GBox_004_Object_Mesh)     # *True or False\nglobal switch_setVisible_GBox_005_Value_Unit           # switch_setVisible_GBox_005_Value_Unit = True (1)\nswitch_setVisible_GBox_005_Value_Unit = FreeCAD_ParamGetSet.GetBool(u\"switch_setVisible_GBox_005_Value_Unit\", True)\nFreeCAD_ParamGetSet.SetBool(u\"switch_setVisible_GBox_005_Value_Unit\", switch_setVisible_GBox_005_Value_Unit)       # *True or False\nglobal switch_setVisible_GBox_006_Inclination          # switch_setVisible_GBox_006_Inclination = True (1)\nswitch_setVisible_GBox_006_Inclination = FreeCAD_ParamGetSet.GetBool(u\"switch_setVisible_GBox_006_Inclination\", True)\nFreeCAD_ParamGetSet.SetBool(u\"switch_setVisible_GBox_006_Inclination\", switch_setVisible_GBox_006_Inclination)     # *True or False\nglobal switch_setVisible_GBox_007_Surface_and_Volume   # switch_setVisible_GBox_007_Surface_and_Volume = True (1)\nswitch_setVisible_GBox_007_Surface_and_Volume = FreeCAD_ParamGetSet.GetBool(u\"switch_setVisible_GBox_007_Surface_and_Volume\", True)\nFreeCAD_ParamGetSet.SetBool(u\"switch_setVisible_GBox_007_Surface_and_Volume\", switch_setVisible_GBox_007_Surface_and_Volume) # *True or False\nglobal switch_setVisible_GBox_008_Cost_And_Price       # switch_setVisible_GBox_008_Cost_And_Price = True (1)\nswitch_setVisible_GBox_008_Cost_And_Price = FreeCAD_ParamGetSet.GetBool(u\"switch_setVisible_GBox_008_Cost_And_Price\", True)\nFreeCAD_ParamGetSet.SetBool(u\"switch_setVisible_GBox_008_Cost_And_Price\", switch_setVisible_GBox_008_Cost_And_Price) # *True or False\nglobal switch_setVisible_GBox_009_BoundBox             # switch_setVisible_GBox_009_BoundBox = True (1)\nswitch_setVisible_GBox_009_BoundBox = FreeCAD_ParamGetSet.GetBool(u\"switch_setVisible_GBox_009_BoundBox\", True)\nFreeCAD_ParamGetSet.SetBool(u\"switch_setVisible_GBox_009_BoundBox\", switch_setVisible_GBox_009_BoundBox)            # *True or False\nglobal switch_setVisible_GBox_010_Center_Mass          # switch_setVisible_GBox_010_Center_Mass = True (1)\nswitch_setVisible_GBox_010_Center_Mass = FreeCAD_ParamGetSet.GetBool(u\"switch_setVisible_GBox_010_Center_Mass\", True)\nFreeCAD_ParamGetSet.SetBool(u\"switch_setVisible_GBox_010_Center_Mass\", switch_setVisible_GBox_010_Center_Mass)      # *True or False\nglobal switch_setVisible_GBox_011_Inertia              # switch_setVisible_GBox_011_Inertia = True (1)\nswitch_setVisible_GBox_011_Inertia = FreeCAD_ParamGetSet.GetBool(u\"switch_setVisible_GBox_011_Inertia\", True)\nFreeCAD_ParamGetSet.SetBool(u\"switch_setVisible_GBox_011_Inertia\", switch_setVisible_GBox_011_Inertia)              # *True or False\nglobal switch_setVisible_GBox_012_SpreadSheet          # switch_setVisible_GBox_012_SpreadSheet = True (1)\nswitch_setVisible_GBox_012_SpreadSheet = FreeCAD_ParamGetSet.GetBool(u\"switch_setVisible_GBox_012_SpreadSheet\", True)\nFreeCAD_ParamGetSet.SetBool(u\"switch_setVisible_GBox_012_SpreadSheet\", switch_setVisible_GBox_012_SpreadSheet)      # *True or False\nglobal switch_setVisible_GBox_013_SpreadSheet_Creation # switch_setVisible_GBox_013_SpreadSheet_Creation = True (1)\nswitch_setVisible_GBox_013_SpreadSheet_Creation = FreeCAD_ParamGetSet.GetBool(u\"switch_setVisible_GBox_013_SpreadSheet_Creation\", True)\nFreeCAD_ParamGetSet.SetBool(u\"switch_setVisible_GBox_013_SpreadSheet_Creation\", switch_setVisible_GBox_013_SpreadSheet_Creation) # *True or False\nglobal switch_setVisible_GBox_014_Main_Tools           # switch_setVisible_GBox_014_Main_Tools = True (1)\nswitch_setVisible_GBox_014_Main_Tools = FreeCAD_ParamGetSet.GetBool(u\"switch_setVisible_GBox_014_Main_Tools\", True)\nFreeCAD_ParamGetSet.SetBool(u\"switch_setVisible_GBox_014_Main_Tools\", switch_setVisible_GBox_014_Main_Tools)        # *True or False\n#### section GroupBox end\n####\nglobal switch_Set_Placeholder_Text                        # switch_Set_Placeholder_Text = True (1)\nswitch_Set_Placeholder_Text = FreeCAD_ParamGetSet.GetBool(u\"switch_Set_Placeholder_Text\", True)\nFreeCAD_ParamGetSet.SetBool(u\"switch_Set_Placeholder_Text\", switch_Set_Placeholder_Text)                  # *True or False\n#### Configuration end ################################################\n##\n####tools after in FreeCAD.ParamGet###########################################################\n##\nglobal ui            ; ui            = \"\"   # QMainWindow()\nglobal FCmw          ; FCmw          = \"\"   # Docked RightDock LeftDock\nglobal myNewFreeCADWidget; myNewFreeCADWidget = \"\"\n##\n####tools after in FreeCAD.ParamGet###########################################################\n#\ndef App_Console_PrintMessage(textInfo):\n    global switchDisplayInfoObject\n\n    if switchDisplayInfoObject == 1 :\n        App.Console.PrintMessage(textInfo)\n\ndef App_Console_PrintError(textInfo):\n    global switchDisplayErrorInfo\n\n    if switchDisplayErrorInfo == 1 :\n        App.Console.PrintMessage(textInfo)\n\ndef errorDialog(msg):\n    global switchWarning\n\n    if switchWarning == 0:\n        None\n    else:\n        diag = QMessageBox(QMessageBox.Critical,\"Error Message\",msg )\n        diag.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) # PySide #cette fonction met la fenetre en avant\n        #diag.setWindowModality(QtCore.Qt.ApplicationModal)       # la fonction a ete desactivee pour favoriser \"WindowStaysOnTopHint\"\n        diag.exec_()\n\nglobal sel           ; sel           = u\"\"\nglobal document_     ; document_     = u\"FCInfo\"\nglobal object_Label  ; object_Label  = u\"\"\nglobal object_Name   ; object_Name   = u\"\"\nglobal typeObject    ; typeObject    = u\"\"  # ShapeType : Compound\nglobal object_Type   ; object_Type   = u\"\"  # Part::Feature\n\nglobal subElemName   ; subElemName   = u\"\"\nglobal RotationToEuler; RotationToEuler = u\"\"\nglobal position0     ; position0     = 0.0\nglobal position1     ; position1     = 0.0\nglobal position2     ; position2     = 0.0\n\nglobal diffuseColorRF     ; diffuseColorRF   = 0.0   # color face Red Float         0.0 a 1.0\nglobal diffuseColorVF     ; diffuseColorVF   = 0.0   # color face Vert/Green Float  0.0 a 1.0\nglobal diffuseColorBF     ; diffuseColorBF   = 0.0   # color face Blue Float        0.0 a 1.0\nglobal diffuseColorTF     ; diffuseColorTF   = 0.0   # color face Transparent Float 0.0 a 1.0\nglobal transparenceFace   ; transparenceFace = 0     # taux de transparence de fa face 0 a 100 Int\nglobal unsignedEncodeColor; unsignedEncodeColor = \"\" # resultat format 25144423565 unsigned FC\nglobal cols               ; cols             = []\nglobal colorShapeFace     ; colorShapeFace   = []\nglobal colorShapeLine     ; colorShapeLine   = []\nglobal colorShapePoint    ; colorShapePoint  = []\nglobal colorShapeFaceDiffuseColor; colorShapeFaceDiffuseColor  = []\n\nglobal longueurObjet ; longueurObjet = 0.0\nglobal rayonObjet    ; rayonObjet    = 0.0\nglobal perimetre     ; perimetre     = 0.0\nglobal numberEdges   ; numberEdges   = 0\nglobal typeLongueur  ; typeLongueur  = u\"Length of object \"\nglobal nombreArretesMesh; nombreArretesMesh = 0\nglobal nombreFacesMesh  ; nombreFacesMesh   = 0\nglobal nombrePointsMesh ; nombrePointsMesh  = 0\n\nglobal Plan_xy       ; Plan_xy       = 0.0\nglobal Plan_xy_V     ; Plan_xy_V     = u\"\"\nglobal Plan_yz       ; Plan_yz       = 0.0\nglobal Plan_yz_V     ; Plan_yz_V     = u\"\"\nglobal Plan_zx       ; Plan_zx       = 0.0\nglobal Plan_zx_V     ; Plan_zx_V     = u\"\"\n\nglobal surface       ; surface       = 0.0\nglobal surfaceFace   ; surfaceFace   = 0.0\nglobal volume_       ; volume_       = 0.0\nglobal poids         ; poids         = 0.0\nglobal uniteM        ; uniteM        = 1.0   # unit of measurement length\nglobal uniteMs       ; uniteMs       = u\"mm\" # micro  hex=\"\\xB5\", html=<span>&#181;</span>\nglobal uniteS        ; uniteS        = 1.0   # unit of measurement surface\nglobal uniteSs       ; uniteSs       = u\"mm\"+seTUnitSymbolCarre    # carre  hex=\"\\xb2\", html=<span>&#178;</span>\nglobal uniteV        ; uniteV        = 1.0   # unit of measurement volume\nglobal uniteVs       ; uniteVs       = u\"mm\"+seTUnitSymbolCube    # cube   hex=\"\\xb3\", html=<span>&#179;</span>\nglobal uniteP        ; uniteP        = 1.0   # unit of measure Mass\nglobal unitePs       ; unitePs       = u\"g\"\n#global uniteAs       ; uniteAs       = \" deg\" #place plus haut\n\nglobal boundBox_     ; boundBox_     = 0.0\nglobal boundBoxLX    ; boundBoxLX    = 0.0\nglobal boundBoxLY    ; boundBoxLY    = 0.0\nglobal boundBoxLZ    ; boundBoxLZ    = 0.0\nglobal boundBox_S    ; boundBox_S    = u\"\"\nglobal BDvol         ; BDvol = FreeCAD.Placement()\nglobal switchBoundBoxCreateVolume ; switchBoundBoxCreateVolume = 0 # 1 = create Volume\nglobal massOrGravity ; massOrGravity = \" Mass \"\n\nglobal adaptWithBody   ; adaptWithBody   = 1    # 1 = adaptWithBody passe par adjustedGlobalPlacement() / 0 = mode normal\n                                                ## Verify this section by person knowing the inertia position       ##\n                                                ##      ONLY IF THE OBJECT IS PRESENT IN ONE BODY                   ##\n                                                ## and post your knowledges in the forum tread if it is not correct ##\n                                                ## http://forum.freecadweb.org/viewtopic.php?f=10&t=3185            ##\nglobal boundBoxCenterX ; boundBoxCenterX = 0.0\nglobal boundBoxCenterY ; boundBoxCenterY = 0.0\nglobal boundBoxCenterZ ; boundBoxCenterZ = 0.0\nglobal boundBoxXMin    ; boundBoxXMin    = 0.0\nglobal boundBoxYMin    ; boundBoxYMin    = 0.0\nglobal boundBoxZMin    ; boundBoxZMin    = 0.0\n\nglobal boundBoxCenter; boundBoxCenter= 0.0\nglobal boundBoxDiag  ; boundBoxDiag  = 0.0\n\nglobal CenterOfMassX ; CenterOfMassX = 0.0\nglobal CenterOfMassY ; CenterOfMassY = 0.0\nglobal CenterOfMassZ ; CenterOfMassZ = 0.0\n\nglobal MatrixX1      ; MatrixX1      = 0.0\nglobal MatrixY1      ; MatrixY1      = 0.0\nglobal MatrixZ1      ; MatrixZ1      = 0.0\nglobal Matrix_1      ; Matrix_1      = 0.0\n\nglobal MatrixX2      ; MatrixX2      = 0.0\nglobal MatrixY2      ; MatrixY2      = 0.0\nglobal MatrixZ2      ; MatrixZ2      = 0.0\nglobal Matrix_2      ; Matrix_2      = 0.0\n\nglobal MatrixX3      ; MatrixX3      = 0.0\nglobal MatrixY3      ; MatrixY3      = 0.0\nglobal MatrixZ3      ; MatrixZ3      = 0.0\nglobal Matrix_3      ; Matrix_3      = 0.0\n\nglobal Matrix12      ; Matrix12      = 0.0\nglobal Matrix13      ; Matrix13      = 0.0\nglobal Matrix14      ; Matrix14      = 0.0\nglobal Matrix15      ; Matrix15      = 0.0\n\nglobal MatrixOfInertiaRaw; MatrixOfInertiaRaw = \"\"\nglobal MatrixX1_16   ; MatrixX1_16   = 0.0\nglobal MatrixY1_16   ; MatrixY1_16   = 0.0\nglobal MatrixZ1_16   ; MatrixZ1_16   = 0.0\nglobal MatrixX2_16   ; MatrixX2_16   = 0.0\nglobal MatrixY2_16   ; MatrixY2_16   = 0.0\nglobal MatrixZ2_16   ; MatrixZ2_16   = 0.0\nglobal MatrixX3_16   ; MatrixX3_16   = 0.0\nglobal MatrixY3_16   ; MatrixY3_16   = 0.0\nglobal MatrixZ3_16   ; MatrixZ3_16   = 0.0\n\nglobal MatrixX1_17   ; MatrixX1_17   = 0.0\nglobal MatrixY1_17   ; MatrixY1_17   = 0.0\nglobal MatrixZ1_17   ; MatrixZ1_17   = 0.0\nglobal MatrixX2_17   ; MatrixX2_17   = 0.0\nglobal MatrixY2_17   ; MatrixY2_17   = 0.0\nglobal MatrixZ2_17   ; MatrixZ2_17   = 0.0\nglobal MatrixX3_17   ; MatrixX3_17   = 0.0\nglobal MatrixY3_17   ; MatrixY3_17   = 0.0\nglobal MatrixZ3_17   ; MatrixZ3_17   = 0.0\nglobal DeterminantM  ; DeterminantM  = 0.0\nglobal refreshMatrix ; refreshMatrix = 1\n\nglobal Vertx         ; Vertx         = u\"\"\nglobal Edges         ; Edges         = u\"\"\nglobal ReperEdge     ; ReperEdge     = 0\nglobal EdgesLong     ; EdgesLong     = 0.0\nglobal Faces         ; Faces         = u\"\"\nglobal FacesSurf     ; FacesSurf     = 0.0\nglobal FacesCoor     ; FacesCoor     = 0.0\nglobal compt_E       ; compt_E       = 0\nglobal compt_F       ; compt_F       = 0\nglobal compt_VF      ; compt_VF      = 0\n\nglobal placement_    ; placement_    = u\"\"\nglobal RowCount      ; RowCount      = 200\nglobal RowCountTest  ; RowCountTest  = 0\nglobal SaveName      ; SaveName      = u\"\"\nglobal ESCAPE        ; ESCAPE        = u\"\\t\" # tabulation SpreadSheet separation\n\nglobal angleX1       ; angleX1       = 0.0\nglobal angleY1       ; angleY1       = 0.0\nglobal angleZ1       ; angleZ1       = 0.0\nglobal angleX2       ; angleX2       = 0.0\nglobal angleY2       ; angleY2       = 0.0\nglobal angleZ2       ; angleZ2       = 0.0\n\nglobal directionObj  ; directionObj  = \"[]\"\nglobal direcValueAt  ; direcValueAt  = \"[]\"\nglobal direcNormalAt ; direcNormalAt = \"[]\"\nglobal typeNormalAt  ; \nif switchCreateLineDiVatNatOnClick == 0:\n    typeNormalAt  = u\"NormalAt(0,0)\"\nelse:\n    typeNormalAt  = u\"*NormalAt(0,0)\"\n\nglobal switchInertia ; switchInertia = 0   # 0 = pass / 1 = stop for create plane without refresh\n\nglobal BsplineDetect           ; BsplineDetect            = u\"\"\nglobal BsplinePointsCoor       ; BsplinePointsCoor        = []\nglobal BsplineNombreDeNoeuds   ; BsplineNombreDeNoeuds    = 0\nglobal BsplineArcsRadius       ; BsplineArcsRadius        = []\nglobal BsplineArcsLocation     ; BsplineArcsLocation      = []\nglobal BsplineRayonApproximatif; BsplineRayonApproximatif = u\"\"\nglobal BsplineCercleToolTip    ; BsplineCercleToolTip     = u\"Bspline d\u00e9tect\u00e9 \"\nglobal BsplineNumberElement    ; BsplineNumberElement     = 0\nglobal BsplineCutLength        ; BsplineCutLength         = 0.0\n\nglobal detected                ; detected                 = u\"\"\nglobal newSpreadSheetName     ; newSpreadSheetName = \"FCSpreadSheet\"\n\nglobal TextColorText_R        ; TextColorText_R   = 0.627451  # color red   1 = 255\nglobal TextColorText_G        ; TextColorText_G   = 0.627451  # color green 1 = 255\nglobal TextColorText_B        ; TextColorText_B   = 0.643137  # color blue  1 = 255\nglobal TextColorText_L        ; TextColorText_L   = 1.000000  # transparency 1 = 255\n\n##################################################################################\n\nMacro_FCInfo_01 = [\n\" 24  24  8  1\",\n\"` c #a90d0e\",\n\". c #a39697\",\n\"# c #875e5e\",\n\"  c None\",\n\"b c #e10c0d\",\n\"c c #ed5f60\",\n\"d c #e1a1a1\",\n\"e c #8d3130\",\n\"                        \",\n\"        d.ccccdd        \",\n\"      .ebbccccce#d      \",\n\"     #bbbcd  dcbb`.     \",\n\"    ebbbbc    cbbbb#    \",\n\"   #bbbbbd    ccbbbb.   \",\n\"  .bbbccbd    cddcbbe   \",\n\"  ebbc  cc    d  dbbb#  \",\n\" d`bbd  cc    cd  cbbe  \",\n\" .bbbd dbc    cc  dbb`d \",\n\" cbbc  cbc    bbd dbbbd \",\n\" ebbc  cbbd  cbbd dbbbd \",\n\" ebbc  cbbbccbbbd dbbbd \",\n\" #bbbd dbbbbbbbbd cbb`d \",\n\" .bbbd  cbbbbbbd  cbb`  \",\n\" d`bbc  dcbbbbd  dbbb#  \",\n\"  #bbbc   dddd  dcbb`.  \",\n\"  d`bbbcd     ddcbbb#   \",\n\"   .`b`bbcddddcbbbbed   \",\n\"    #`b```bbbb``bbe.    \",\n\"     .ebbbbbbbbb`#d     \",\n\"      d#e`````e#.       \",\n\"         ddddd          \",\n\"                        \"]\n\nMacro_FCInfo_02 = [\n\"  24  23  8  1\",\n\"` c #4478b4\",\n\". c #a4c0de\",\n\"# c #7b9ac1\",\n\"  c None\",\n\"b c #c8d0db\",\n\"c c #6391c5\",\n\"d c #89aad1\",\n\"e c #5b80ad\",\n\"      bdd##ddb          \",\n\"     ddbbbbb.d#d    b#  \",\n\"    d.bbbbb...b.#. bcd  \",\n\"   ..b..dd.bb....dc#.d  \",\n\"   #bc``dbbd#..ddddddd  \",\n\"   #e``      dcdd###dd  \",\n\"  .ecd#        ddd##dd  \",\n\"  b`b..        ddd##dd  \",\n\"  bd          bdddddd.  \",\n\"   b         b`#c###c.  \",\n\"   cd###ded          b  \",\n\"   .b...bd           d  \",\n\"   d.d..c           b#  \",\n\"   d....c        b  #c  \",\n\"   d.dd..cdb     . d`.  \",\n\"   d...d###ee##ce#ee`   \",\n\"  ...cddccc###cceecce   \",\n\"  d.#b#cd#ccccccccceb   \",\n\"  #ebbb.ec##cccccce.    \",\n\"  bb bbbb.#eeeeee#b b   \",\n\"     bbbbbbbbb.bb b     \",\n\"         bbbbb          \",\n\"                        \"]\n\nMacro_FCInfo_03 = [\n\"  24  24  8  1\",\n\"` c #293444\",\n\". c #619ee5\",\n\"# c #366ab3\",\n\"a c #6f7885\",\n\"b c #b7b8b8\",\n\"c c #ecedec\",\n\"d c #344861\",\n\"e c #919aa2\",\n\"bccbccbcbbaaecccbccbcbcc\",\n\"ecbebbebd#aaaddcbcbebeec\",\n\"bcbbbbbd.#.b..aabcbbbbbc\",\n\"ebcacbda.a#a...adbbaceec\",\n\"ccccce`abce#a..e#bcccccc\",\n\"bccbcaacbcced...#ecbcbcc\",\n\"aaadaaaadaad`a.#.ddaaecc\",\n\"aabbbbeaaaaa`#.#.ddadacc\",\n\"aecbbcbaa``#d.##..#d`acc\",\n\"beccccb`ead..#####.adbcc\",\n\"e```````da#d#ddd`d#`dacc\",\n\"aacbbbedabbd##``##deeacc\",\n\"aacebbedabba`##d#dabbacc\",\n\"aebebbedabbee`#.dabeeabc\",\n\"b`ddddd``````d`````d`ecc\",\n\"aaeaeea`deeabaadaeeaaacc\",\n\"aabbbcedebbecbbbeeebeacc\",\n\"aabeebedeebebbbeeeeeeabc\",\n\"e````d````d`d`d``````abc\",\n\"baeeeea`aeeeeeeeeeeeaecc\",\n\"aecbcbbdacbecbbcebbbbacc\",\n\"aacbccedacbbbbbbbbcbbacc\",\n\"aaaaaaaddaaaaaaaaaaaaabc\",\n\"bccbccbcbccbccccbccbcbbc\"]\n\nMacro_FCInfo_04 = [\n\"  24  24  8  1\",\n\"` c #2e383f\",\n\". c #7a9abf\",\n\"# c #4870a2\",\n\"a c #7a8592\",\n\"  c None\",\n\"c c #adb0b1\",\n\"d c #425264\",\n\"e c #5b89c3\",\n\"                 ca     \",\n\"               .dacc    \",\n\"            cad.c  .    \",\n\"          adac   ca`    \",\n\"       cd`c    cddacc   \",\n\"     adacdc caddac  .   \",\n\"  ccac   adddac   cadc  \",\n\"  caac cad`a    .ddaca  \",\n\"  caadddac#. cadd.   c  \",\n\"  caada   .`ddac   cada \",\n\"  .aa#a cad`a   c.ddac. \",\n\"  c#dd`d`d.ddcca``#.c cc\",\n\"  cd#.....e..eee...aaac \",\n\"  .de.eeee.e.eeeee...   \",\n\"  ad..eeeeeeeeeeeeeec   \",\n\"  .d......e.....eeeec   \",\n\"  ad............eeeec   \",\n\"  ad.....eeeeeeeeeeec   \",\n\"  #deeeee#########ee.   \",\n\"  #d################.   \",\n\"  dd##############e#c   \",\n\"  #deeeeeeeeeeeeeeedc   \",\n\"  d`ddddddddddddddd#c   \",\n\"  aaaaaaaaaaaaaaaaaac   \"]\n\nMacro_FCInfo_05 = [\n\"    24  24  8  1\",\n\"` c None\",\n\". c #280000\",\n\"# c #8ae234\",\n\"a c #729fcf\",\n\"b c #2a1018\",\n\"c c #c8a9a7\",\n\"d c #ef2929\",\n\"e c #000000\",\n\"                    .   \",\n\"                   ...  \",\n\"                   .#.  \",\n\"      ...          .#.  \",\n\"      .aa.        ..#.. \",\n\"      .aaa...     .###. \",\n\"       .aaaa..    .###. \",\n\"        .aaaa.    ..#.. \",\n\"        .aaaa.     .#.  \",\n\"        ..aaaa.    .#.  \",\n\"         ...aaa.   .#.  \",\n\"            .aab....#...\",\n\"             .bacccc#ccc\",\n\"              .acccc#ccc\",\n\"              .caccc#ccc\",\n\"              .ccacc#ccc\",\n\"              .ccacc#ccc\",\n\"              .cccac#ccc\",\n\"    ....      .cccca#ccc\",\n\" ....dd........cccca#ccc\",\n\"..ddddddddddddddddddaddd\",\n\" ....dd........ccccc#acc\",\n\"    ....      .ccccc#acc\",\n\"              .ccccc#cac\"]\n\nMacro_FCInfo_06 = [\n\" 24 24 8 1\",\n\"` c #2c0204\",\n\". c #749ecc\",\n\"# c #ccaaa4\",\n\"a c #0dfa0d\",\n\"b c #8ce234\",\n\"c c #ec2a2c\",\n\"  c None\",\n\"e c #fcfefc\",\n\"                    `   \",\n\"       ``````      ```  \",\n\"     ```aaaa```    `b`  \",\n\"   ```aaaaaaaa```  `b`  \",\n\"   `aaaaaaaaaaaa` ``b`` \",\n\"  ``aaaaaaaaaaaa```bbb` \",\n\"  `aaaaaaaaaaaaea``bbb` \",\n\" ``aaaaaaaaaaaeea```b`` \",\n\" `aaaaaaaaaaaeeeaa``b`  \",\n\" `aaaeeaaaaaeeeeaa``b`  \",\n\" `aaaeeeaaaeeeeaaa``b`  \",\n\" `aaaeeeeaeeeeaaaa``b```\",\n\" ``aaaeeeeeeeaaaa``#b###\",\n\"  `aaaaeeeeeaaaaa`##b###\",\n\"  ``aaaaeeeaaaaa``##b###\",\n\"   `aaaaaeaaaaaa`.##b###\",\n\"   ```aaaaaaaa```.##b###\",\n\"     ```aaaa```###.#b###\",\n\"    ````````` `####.b###\",\n\" ````cc````````####.b###\",\n\"``cccccccccccccccccc.ccc\",\n\" ````cc````````#####b.##\",\n\"    ````      `#####b.##\",\n\"              `#####b#.#\"]\n\nMacro_FCInfo_07 = [\n\" 24 24 8 1\",\n\"  c None\",\n\". c #280000\",\n\"# c #ef2929\",\n\"a c #8ae234\",\n\"b c #ffffff\",\n\"c c #c8a9a7\",\n\"d c #729fcf\",\n\"e c #000000\",\n\"                    .   \",\n\"     .........     ...  \",\n\"    ..#######..    .a.  \",\n\"   ..#########..   .a.  \",\n\"  ..###########.. ..a.. \",\n\" ..##bb#####bb##...aaa. \",\n\" .###bbb###bbb###..aaa. \",\n\" .####bbb#bbb####...a.. \",\n\" .#####bbbbb#####. .a.  \",\n\" .######bbb######. .a.  \",\n\" .#####bbbbb#####. .a.  \",\n\" .####bbb#bbb####...a...\",\n\" .###bbb###bbb###.ccaccc\",\n\" ..##bb#####bb##..ccaccc\",\n\"  ..###########..cccaccc\",\n\"   ..#########..cdccaccc\",\n\"    ..#######..ccdccaccc\",\n\"     ..........cccdcaccc\",\n\"    ....      .ccccdaccc\",\n\" ....##........ccccdaccc\",\n\"..##################d###\",\n\" ....##........cccccadcc\",\n\"    ....      .cccccadcc\",\n\"              .cccccacdc\"]\n\n\nMacro_FCInfo_08 = [\n\"21 24 8 1\",\n\"` c #fc0507\",\n\". c #fc9494\",\n\"# c #fc4c4b\",\n\"a c #fcd1d0\",\n\"  c None\",\n\"c c #fcb9b9\",\n\"d c #fc3433\",\n\"e c #fc6f6f\",\n\"       a````e.a      \",\n\"      c```dd````d.aa \",\n\"     e`dd`   a.#````d\",\n\"    d`# e`       c```\",\n\"  a``e  e`       c```\",\n\" .``a   e`      a`d``\",\n\"e``e    e`     a`` #`\",\n\"``````e.#`    a``  d`\",\n\"`da.ed`````#.a#`a  #`\",\n\"`#     ad`d````c   #`\",\n\"`#      e`  a`d    #`\",\n\"`#      e`   d`    #`\",\n\"`#      e`c  d`    #`\",\n\"`#     e```````    #`\",\n\"`#    #`#ac#````#c #`\",\n\"`#   ``e     d`d`````\",\n\"`# a``c      d`  ce``\",\n\"`#c``a       d`   a``\",\n\"```d         d`  a`` \",\n\"```c         d` a``  \",\n\"c````ea      dda``   \",\n\"  ce````dc   #```a   \",\n\"     a.d```d.d``a    \",\n\"         .`````a     \"]\n\nMacro_FCInfo_09 = [\n\" 24 24 8 1\",\n\"` c #b7201c\",\n\". c #cba938\",\n\"# c #e1cb42\",\n\"a c #d6d1bd\",\n\"b c #f4e256\",\n\"c c #b7752b\",\n\"d c #c7b295\",\n\"  c None\",\n\"   dda                  \",\n\"  a.c.a                 \",\n\"  dcdcd                 \",\n\"  a.cc.                 \",\n\"   dccca                \",\n\"   a.ccc a              \",\n\"    accc##              \",\n\"     d.bbbca            \",\n\"    b#bbac``            \",\n\"    a#.c`c`.a           \",\n\"     d```cbbb.          \",\n\"     d``.bbbb##         \",\n\"      d#bbbb####a       \",\n\"       #bbbb####b#      \",\n\"       ##bbb###.#ab     \",\n\"       .b#####.####ab   \",\n\"       a##########.ba   \",\n\"       a#.#####.####a   \",\n\"     aaadb.###.b.#daaa  \",\n\"    a aaa#.#.#b..ddaaaa \",\n\"     aaaddb###ddddaaaa  \",\n\"       aaadadadaaaaa    \",\n\"          a aa a a      \",\n\"                        \"]\n\nMacro_FCInfo_10 = [\n\"  24 24 8 1\",\n\"` c #486ea4\",\n\". c #b8babd\",\n\"# c #868e98\",\n\"a c #dfdfe1\",\n\"b c #9da5b1\",\n\"c c #6687b4\",\n\"d c #d0d2d2\",\n\"  c None\",\n\"       aaa              \",\n\"     .bcc#bb            \",\n\"    .cbbbbbcc           \",\n\"   accccbbbbcb          \",\n\"   cc.adccbcbca         \",\n\"  aca    cbcbcb         \",\n\"  d.b####ccccb`####.    \",\n\"  aa.a...bcccb`b....a   \",\n\"   dda#ccbbcccbbc`d.d   \",\n\"   #aaacccccc``cc.aa#   \",\n\"  d.aa dcc````cc.aaabd  \",\n\"  #a aaad`c``c`bddadd#  \",\n\" ab daada.`c`ccdddaaa#a \",\n\" .aaaaadddbccc.ddddddd. \",\n\" .aadadaaddb`..dddddddb \",\n\"a.a adaddadaddadddda d.a\",\n\"a.aaaaaaadadadadadadddba\",\n\"a.d...........b.b.bbb.#a\",\n\"a...##bbb.bbbb.b..bb.b#a\",\n\"a...##bbbb.b.b.bb.bb.b#a\",\n\"a.....bb.bb.bb.bb.bb.b#a\",\n\"abddddd.d........bbbbb#a\",\n\" .b###################. \",\n\"   addddddaddddddddaaa  \"]\n\nMacro_FCInfo_11 = [\n\" 24 24 8 1\",\n\"` c #040204\",\n\". c #749ecc\",\n\"# c #ec2a2c\",\n\"a c #244a84\",\n\"b c #fcea4c\",\n\"  c None\",\n\"d c #040234\",\n\"e c #040644\",\n\"                        \",\n\"                        \",\n\"        ````````        \",\n\"      ```.....````````  \",\n\"    ```...........````  \",\n\"   ````````.....de`aa`  \",\n\"   `.....````````aaaa`  \",\n\"   `............`aaaa`  \",\n\"   `....bbb.....`aaaa`  \",\n\"   `...bbbbb....`aaaa`  \",\n\"   `...b``bb....`aaa``  \",\n\"  ``...```bb...``aaa``  \",\n\"  ``..``#`b....``aaa`   \",\n\"  `..``##`.....`aaaa`   \",\n\"  `.``###`.....`aaaa`   \",\n\"  ```####`.....`aaaa`   \",\n\"  ``#####`.....`aaaa`   \",\n\" ``######`.....`aaa``   \",\n\" ```#####`.....`a```    \",\n\"   `#####````..```      \",\n\"   `###`#`  `````       \",\n\"   `##````              \",\n\"   ````                 \",\n\"                        \"]\n\nMacro_FCInfo_12 = [\n\" 24 24 8 1\",\n\"` c #060407\",\n\". c #049a9c\",\n\"# c #c5a107\",\n\"a c #ec2a2c\",\n\"  c None\",\n\"c c #34e2e4\",\n\"d c #342a34\",\n\"e c #fcae3c\",\n\"  `ccccccccccc`...`     \",\n\" `cccccccccccc`...`     \",\n\" `ccccccccccc`.....`    \",\n\" ````cccccccc`.....`    \",\n\" `###````ccc`.....`     \",\n\" `#######```......`     \",\n\" `###`#####`.....`      \",\n\"  `#`a`####`.....`      \",\n\"  ``aaa`####`...`       \",\n\"  `aaaa`#````````d``d```\",\n\"  `aaa`##`eeeeeeeeeeeee`\",\n\"  `aaa``#``eeeeeeeeeeee`\",\n\"  `aaa` ``a`eeeeeeeeeee`\",\n\"  `aaa`  `aa`eeeeeeeeee`\",\n\"  `aaaa` `aaa`eeeeeeeee`\",\n\"   `aaaa`aaaaa`eeeeeeee`\",\n\"    `aaaaaaaaaa`eeeeeee`\",\n\"     `aaaaaaaaa`eeeeeee`\",\n\"      ``aaaaaa`eeeeeeee`\",\n\"        `aaaa`eeeeeeeee`\",\n\"         `aa`eeeeeeeeee`\",\n\"         `a`eeeeeeeeeee`\",\n\"         ``eeeeeeeeeeee`\",\n\"         ```````````````\"]\n\nMacro_FCInfo_13J = [\n\"24 24 4 1\",\n\" \tc None\",\n\".\tc #280000\",\n\"+\tc #EF2929\",\n\"@\tc #FBE852\",\n\"...                     \",\n\".++...        ++        \",\n\".+++++..     ++++       \",\n\" .+++++..   +++  +      \",\n\" .++@@.    +++   +      \",\n\" .++@@@.   ++    +   +  \",\n\"  .+.@@@.   +   +       \",\n\"  .. .@@@.   +++   +    \",\n\"   .  .@@@.       +     \",\n\"       .@@@.     +  ++  \",\n\"        .@@@.   +  ++++ \",\n\"         .@@@.    ++ +  \",\n\"          .@@@.   +     \",\n\"           .@@@.        \",\n\"            .@@@.       \",\n\"             .@@@.      \",\n\"              .@@@.     \",\n\"               .@@@.    \",\n\"                .@@@.   \",\n\"                 .@@@.  \",\n\"                  .@@@. \",\n\"                   .@@@.\",\n\"                    .@++\",\n\"                     .++\"]\n\nMacro_FCInfo_13M = [\n\"24 24 5 1\",\n\" \tc None\",\n\".\tc #280000\",\n\"+\tc #EE292B\",\n\"@\tc #EF2929\",\n\"#\tc #FE19FF\",\n\"...                     \",\n\".@@...        ++        \",\n\".@@@@@..      ++        \",\n\" .@@@@@..    ++         \",\n\" .@@##.      ++         \",\n\" .@@###.    ++   +++    \",\n\"  .@.###.   ++++++      \",\n\"  .. .###.  ++    +++   \",\n\"   .  .###.    ++++++   \",\n\"       .###.  ++ + +   +\",\n\"        .###.    +++  ++\",\n\"         .###.    +  ++ \",\n\"          .###.   + ++  \",\n\"           .###.   ++   \",\n\"            .###.  +    \",\n\"             .###.  +   \",\n\"              .###.     \",\n\"               .###.    \",\n\"                .###.   \",\n\"                 .###.  \",\n\"                  .###. \",\n\"                   .###.\",\n\"                    .#@@\",\n\"                     .@@\"\n]\n\nMacro_FCInfo_13C = [\n\"24 24 5 1\",\n\" \tc None\",\n\".\tc #280000\",\n\"+\tc #EE292B\",\n\"@\tc #EF2929\",\n\"#\tc #19FEFF\",\n\"...                     \",\n\".@@...       ++         \",\n\".@@@@@..    +++         \",\n\" .@@@@@..  +++          \",\n\" .@@##.   ++ + ++       \",\n\" .@@###.  +  +++  +     \",\n\"  .@.###.    ++  +++    \",\n\"  .. .###.  ++  ++ ++   \",\n\"   .  .###.    ++ ++    \",\n\"       .###.  ++ ++  ++ \",\n\"        .###.  +++  ++++\",\n\"         .###.  +  ++  +\",\n\"          .###.   ++ + +\",\n\"           .###.  +  +++\",\n\"            .###.   +   \",\n\"             .###.  +   \",\n\"              .###.     \",\n\"               .###.    \",\n\"                .###.   \",\n\"                 .###.  \",\n\"                  .###. \",\n\"                   .###.\",\n\"                    .#@@\",\n\"                     .@@\"\n\n]\n\nMacro_FCInfo_Point = [\n\"24 24 8 1\",\n\" \tc None\",\n\".\tc #000100\",\n\"+\tc #B0A22C\",\n\"@\tc #E9D235\",\n\"#\tc #6B6014\",\n\"$\tc #F7E66C\",\n\"%\tc #FBF4BC\",\n\"&\tc #D5B716\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"         ......         \",\n\"       ..+@@@@+..       \",\n\"      .#$$$@@@@@#.      \",\n\"     .#$%%$@@@@@@#.     \",\n\"     .$%%%$@@@@@@@.     \",\n\"    .+$%%$@@@@@@@@+.    \",\n\"    .@$$$@@@@@&&&&&.    \",\n\"    .@@@@@@@&&&&&&&.    \",\n\"    .@@@@@&&&&&&&&&.    \",\n\"    .@@@@&&&&&&&&&&.    \",\n\"    .+@@&&&&&&&&&&+.    \",\n\"     .@&&&&&&&&&&&.     \",\n\"     .#&&&&&&&&&&#.     \",\n\"      .#&&&&&&&&#.      \",\n\"       ..+&&&&+..       \",\n\"         ......         \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\nMacro_FCInfo_Plane = [\n\"24 24 8 1\",\n\" \tc None\",\n\".\tc #A40000\",\n\"+\tc #204A87\",\n\"@\tc #208020\",\n\"#\tc #EF2929\",\n\"$\tc #729FCF\",\n\"%\tc #8AE234\",\n\"&\tc #729ECE\",\n\"     .                  \",\n\"     ..    +     @      \",\n\"     .#.  +$+   @@      \",\n\"     .##.+$$$+ @%@      \",\n\"     .###.$$$$@%%@      \",\n\"     .####.$$@%%%@      \",\n\"     ..####.@%%%%@      \",\n\"     ++.##.@.%%%@+      \",\n\"    +&$+..@@#.%@+$+     \",\n\"   +&$&&+@%@##.+$$$+    \",\n\"  +&$&&&@%%@###.$$$$+   \",\n\" +&$&&&@%%%@####.$$$$+  \",\n\"  +$&&@%%%%@#####.$$$$+ \",\n\"   +$&@%%%@+.#####.$$$+ \",\n\"    +&@%%@+$+.####.$$+  \",\n\"     +@%@+$$$+.###.$+   \",\n\"      @@+$$$$$+.##.+    \",\n\"      @+$$$$$$$+.#.     \",\n\"      @%+$$$$$$$+..     \",\n\"      @%%+$$$$$$+#.     \",\n\"      @%@ +$&$$+##.     \",\n\"      @@   +$$+ .#.     \",\n\"      @     ++   ..     \",\n\"                  .     \"\n]\n\nMacro_FCInfo_Axis = [\n\"24 24 6 1\",\n\" \tc None\",\n\".\tc #204B86\",\n\"+\tc #247F23\",\n\"@\tc #A30701\",\n\"#\tc #204A87\",\n\"$\tc #208023\",\n\"                        \",\n\"                        \",\n\"            ..          \",\n\"            ..          \",\n\"            ..          \",\n\"            .           \",\n\"            .           \",\n\"  ++       ..           \",\n\"   +++     ..       @   \",\n\"     +++   ..    @@@@   \",\n\"       +++ .# @@@@      \",\n\"         +$#@@@@        \",\n\"      @@@@##@           \",\n\"   @@@@@  ..+++         \",\n\"  @@      ..  +++       \",\n\"          ..    +++     \",\n\"          ..      ++    \",\n\"          ..            \",\n\"          .             \",\n\"          .             \",\n\"         ..             \",\n\"         ..             \",\n\"         ..             \",\n\"                        \"\n]\n\nMacro_FCInfo_Info = [\n\"24 24 10 1\",\n\" \tc None\",\n\".\tc #F57900\",\n\"+\tc #BCBCB3\",\n\"@\tc #555755\",\n\"#\tc #ECEEEB\",\n\"$\tc #D8DAD7\",\n\"%\tc #DBDDDA\",\n\"&\tc #E6E9E5\",\n\"*\tc #F2F4F1\",\n\"=\tc #EFF1EE\",\n\"                        \",\n\"                        \",\n\"        .  .  .  .      \",\n\"      +..+..+..+..++    \",\n\"     @@..@..@..@..@+    \",\n\"     @#.##.##.##.#@+    \",\n\"     @############@+    \",\n\"     @#$$$$$$$$$$#@+    \",\n\"     @#++++++++++#@+    \",\n\"     @#$%%%%%$$$##@+    \",\n\"     @#++++++++++#@+    \",\n\"     @#$%%%$$$$%#&@+    \",\n\"     @#++++++++%##@+    \",\n\"     @#$%$$$$$$$%#@+    \",\n\"     @#+++++++++%#@+    \",\n\"     @#$$$$$$$$$$*@+    \",\n\"     @#++++$######@+    \",\n\"     @#$$$$$####@@@+    \",\n\"     @####&=*##@@@++    \",\n\"     @###&#***#@@++     \",\n\"     @@@@@@@@@@@++      \",\n\"      +++++++++++       \",\n\"                        \",\n\"                        \"\n]\n\nMacro_FCInfo_Radian = [\n\"24 24 6 1\",\n\" \tc None\",\n\".\tc #0C0000\",\n\"+\tc #171018\",\n\"@\tc #EE2C29\",\n\"#\tc #749FCE\",\n\"$\tc #FFFFFF\",\n\"                        \",\n\"                        \",\n\"        .......     +++ \",\n\"      ...#####...   + + \",\n\"     ..#########@@  ++  \",\n\"    ..##########$@@ + + \",\n\"   ..##########$##@@    \",\n\"   .##########$####@    \",\n\"  ..##########$####@@   \",\n\"  .##########$######@   \",\n\"  .#########$#######@   \",\n\"  .########$$$$$$$$$$   \",\n\"  .#################.   \",\n\"  .##########+++####.   \",\n\"  ..#########+#+###..   \",\n\"   .#########++####.    \",\n\"   ..########+#+##..    \",\n\"    ..###########..     \",\n\"     ..#########..      \",\n\"      ...#####...       \",\n\"        .......         \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\nMacro_FCInfo_Pourcent = [\n\"24 24 4 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"+\tc #A40000\",\n\"@\tc #FFFFFF\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"           +            \",\n\"          +++           \",\n\"          +@+           \",\n\"         ++@++          \",\n\"        ++@@@++         \",\n\"        +@@@@@+         \",\n\"       ++@.@.@++        \",\n\"      ++@@.@..@++       \",\n\"      +@@@.@@.@@+       \",\n\"     ++@.@@@@@@@++      \",\n\"    ++@....@@@@@@++     \",\n\"    +@.......@@@@@+     \",\n\"   ++@.........@@@++    \",\n\"  ++@............@@++   \",\n\"  +@...............@+   \",\n\" ++@@@@@@@@@@@@@@@@@++  \",\n\" +++++++++++++++++++++  \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\nMacro_FCInfo_Degrees = [\n\"24 24 5 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"+\tc #EE2C29\",\n\"@\tc #3965A3\",\n\"#\tc #FFFFFF\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                      ..\",\n\"              .   ... ..\",\n\"              . . . .   \",\n\"              ... . .   \",\n\"                . . .   \",\n\"             #+ . ...   \",\n\"            ##++        \",\n\"           ##@@++       \",\n\"          ##@@@@+       \",\n\"         ##@@@@@++      \",\n\"       ###@@@@@@@++     \",\n\"      ###@@@@@@@@@++    \",\n\"     ##@@@@@@@@@@@@+    \",\n\"    ##@@@@@@@@@@@@@++   \",\n\"   ##@@@@@@@@@@@@@@@+   \",\n\"  ##@@@@@@@@@@@@@@@@+   \",\n\"  ###################   \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\nMacro_FCInfo_DegreesMinSec = [\n\"24 24 6 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"+\tc #A40000\",\n\"@\tc #204A87\",\n\"#\tc #4E9A06\",\n\"$\tc #FCAF3E\",\n\"                        \",\n\"                        \",\n\"        +++++++         \",\n\"      +++$@$@$+++       \",\n\"     ++$$$@.@$$$++      \",\n\"    ++$@$$$$$$.@$++     \",\n\"   ++$.$@$$$$$$$$$++    \",\n\"   +$@..$$$$$$$$$$$+    \",\n\"  ++$$@..$$$$$.$$.@++   \",\n\"  +$$$$$..$$$..$$$$$+   \",\n\"  +$$$$$$..$..$$$$$$+   \",\n\"  +@@.$$$$...$$$$.@@+   \",\n\"  +$$$$$$$$.$$$$$$$$+   \",\n\"  +$$$$$$$$$$$$$$$$$+   \",\n\"  ++$$.$$$###$$$$.$++   \",\n\"   +$@$$$$$#$$$$$$@+    \",\n\"   ++$$$$$$$$$.$$$++    \",\n\"    ++$$.$$$$$$@$++     \",\n\"     ++@$$$.$$$$++      \",\n\"      +++$$@$$+++       \",\n\"        +++++++         \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\nMacro_FCInfo_Grade = [\n\"24 24 5 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"+\tc #A40000\",\n\"@\tc #C4A000\",\n\"#\tc #FFFFFF\",\n\"                        \",\n\"                        \",\n\"  #   #                 \",\n\"  #...#...  #           \",\n\"  #+++#++..#.           \",\n\"  #@@@@@@+#+...  #      \",\n\"  #@@@@@@@@@++..#       \",\n\"  #@@#@@@@@@@@+#.       \",\n\"  #@@#@@@#@@@@@+..      \",\n\"  #@@#@@#@@@@@@@+..     \",\n\"  #@@#@@#@@@#@@@@+..#   \",\n\"  #@#@@#@@@#@@@@@@+#    \",\n\"  #@#@@#@@#@@@@@@@#.    \",\n\"  #@#@#@@#@@@@@#@@+..   \",\n\"  #@#@#@#@@@@##@@@@+.   \",\n\"  #@##@#@@@##@@@@@@+.   \",\n\"  #@###@@##@@@@@@@@+.   \",\n\"  ####@##@@@@@@@@@@#### \",\n\"  #####@@@@######@@+.   \",\n\"  #########@@@@@@@@+.   \",\n\"  +#################### \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\nMacro_FCInfo_ClipBoard_None = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #A30500\",\n\"+\tc #555755\",\n\"@\tc #BCBCB3\",\n\"#\tc #D7DAD6\",\n\"$\tc #DBDDDA\",\n\"%\tc #E7E9E6\",\n\"&\tc #EBEEEA\",\n\"*\tc #F1F4F0\",\n\"                        \",\n\"   @...@@@@@@@@@@@ ...  \",\n\"  ++....+++++++++@....  \",\n\"  +$....$$$$$$$$+.....  \",\n\"  +$$....$$$$$$$.....   \",\n\"  +$$.....$$$$......@@@ \",\n\"  +$$@....+++......+++@ \",\n\"  +$$$$....&......&&&+@ \",\n\"  +$$@@.........&&&&&+@ \",\n\"  +$$$$$.......&&&&&&+@ \",\n\"  +$$@@@+.....@@@@@@&+@ \",\n\"  +$$$$$......$$###&&+@ \",\n\"  +$$@@........@@@@@&+@ \",\n\"  +$$..........###$&%+@ \",\n\"  +$......&@....@@$&&+@ \",\n\"  +......&&$.....##$&+@ \",\n\"  .....$+&&@@....@@$&+@ \",\n\" .....$$+&&&&&....&&*+@ \",\n\" ....++++&&&&&.....&&+@ \",\n\" ...    +&&&&&&....+++@ \",\n\"        +&&&&%**....+@@ \",\n\"        +&&&%&**....@@  \",\n\"        +++++++++...@   \",\n\"         @@@@@@@@@@@    \"\n]\n\nMacro_FCInfo_ClipBoard_FC = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #A30500\",\n\"+\tc #154A89\",\n\"@\tc #555755\",\n\"#\tc #BCBCB3\",\n\"$\tc #DADDDA\",\n\"%\tc #E7E9E6\",\n\"&\tc #EBEEEA\",\n\"*\tc #F1F4F0\",\n\"                        \",\n\"   ###############      \",\n\"  @@@@@@@@@@@@@@@#      \",\n\"  @$$$$$$$$$$$$$@#      \",\n\"  @$$$$$$$$$$$$$@#      \",\n\"  @$$$$$$$$$$$$$@###### \",\n\"  @$$###@@@@@@@@@@+@@@# \",\n\"  @$$$.......+&&&++&&@# \",\n\"  @$$#.......++&++&&&@# \",\n\"  @$$$.......++++&&&&@# \",\n\"  @$$#...&+++++++###&@# \",\n\"  @$$$.....+$%$++++&&@# \",\n\"  @$$#......%%%+++++&@# \",\n\"  @$$$.....+$%$++++&%@# \",\n\"  @$$$...&+++++++#$&&@# \",\n\"  @$$$...++$+++$++$$&@# \",\n\"  @$$$..++&#+++##++$&@# \",\n\"  @$$$..+&&&&+&&&&+&*@# \",\n\"  @@@@@@@&&&&&&&&&&&&@# \",\n\"        @&&&&&&&&&&@@@# \",\n\"        @&&&&%**&&@@@## \",\n\"        @&&&%&***&@@##  \",\n\"        @@@@@@@@@@@##   \",\n\"         ###########    \"\n]\n\nMacro_FCInfo_ClipBoard_Comma = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"+\tc #A30500\",\n\"@\tc #2C4A85\",\n\"#\tc #555755\",\n\"$\tc #52990C\",\n\"%\tc #BCBCB3\",\n\"&\tc #DADDD9\",\n\"*\tc #ECEEEB\",\n\"                        \",\n\"   %%%%%%%%%%%%%%%      \",\n\"  ###############%      \",\n\"  #&&&&&&&&&&&&&#%      \",\n\"  #&&&&&&&&&&&&&#%      \",\n\"  #&&&&&&&&&&&&&#%%%%%% \",\n\"  #&&%%%##############% \",\n\" ++&&&&++*$$**$$*@@@@@@ \",\n\" +++&%+++*$$$&$$&@@@@@@ \",\n\"  ++&&++#**$$*$$****@@% \",\n\"  #++++%#**$$%$$%%%%@@% \",\n\"  #&++&&#**&$$$$&&&@@#% \",\n\"  #&++%%#**%$$$$%%%@@#% \",\n\"  #++++&#**&&$$&&&&@@#% \",\n\"  ++&&++#**%%$$%%%@@*#% \",\n\"  +&&&&+#**&$$$&&&@@*#% \",\n\" ++&&&&++..%$$..%@@@@@@ \",\n\" +#&&&&&+..*$$..*@@@@@@ \",\n\"  #######*.****.*****#% \",\n\"        #..***..***###% \",\n\"        ..***..***###%% \",\n\"        #*********##%%  \",\n\"        ###########%%   \",\n\"         %%%%%%%%%%%    \"\n]\n\nMacro_FCInfo_ClipBoard_Raw = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"+\tc #A30500\",\n\"@\tc #2C4A85\",\n\"#\tc #555755\",\n\"$\tc #52990C\",\n\"%\tc #BCBCB3\",\n\"&\tc #DADDD9\",\n\"*\tc #ECEEEB\",\n\"                        \",\n\"   %%%%%%%%%%%%%%%      \",\n\"  ###############%      \",\n\"  #&&&&&&&&&&&&&#%      \",\n\"  #&&&&&&&&&&&&&#%      \",\n\"  #&&&&&&&&&&&&&#%%%%%% \",\n\"  #&&%%%##############% \",\n\" ++&&&&++*$$**$$*@@@@@@ \",\n\" +++&%+++*$$$&$$&@@@@@@ \",\n\"  ++&&++#**$$*$$****@@% \",\n\"  #++++%#**$$%$$%%%%@@% \",\n\"  #&++&&#**&$$$$&&&@@#% \",\n\"  #&++%%#**%$$$$%%%@@#% \",\n\"  #++++&#**&&$$&&&&@@#% \",\n\"  ++&&++#**%%$$%%%@@*#% \",\n\"  +&&&&+#**&$$$&&&@@*#% \",\n\" ++&&&&++**%$$%%%@@@@@@ \",\n\" +#&&&&&+***$$***@@@@@@ \",\n\"  #######************#% \",\n\"        #**********###% \",\n\"        #*********###%% \",\n\"        #*********##%%  \",\n\"        ###########%%   \",\n\"         %%%%%%%%%%%    \"\n]\n\nMacro_FCInfo_BoundBoxTracing = [\n\"24 24 8 1\",\n\" \tc None\",\n\".\tc #A30500\",\n\"+\tc #ED2928\",\n\"@\tc #69678E\",\n\"#\tc #6B6990\",\n\"$\tc #6D6B92\",\n\"%\tc #706E95\",\n\"&\tc #746F91\",\n\"                        \",\n\"                        \",\n\"               +++.     \",\n\"           ++++..++.    \",\n\"       ++++....  ++.    \",\n\"    +++....      +.+.   \",\n\"    ++.          +.+.   \",\n\"    +.+.       +++. +.  \",\n\"    +. +.  ++++..+. +.  \",\n\"    +. ++++...   +. +.  \",\n\"    +.  +..    +++. +.  \",\n\"    +.  +. ++++...+.+.  \",\n\"    +. ++++....    ++.  \",\n\"    +++.+..         +.  \",\n\"     +..+.          +.  \",\n\"      +.+.         ++.  \",\n\"      +.+.     ++++..   \",\n\"       ++. ++++....     \",\n\"        +++....         \",\n\"        ...             \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\nMacro_FCInfo_BoundBoxVolume = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"+\tc #140300\",\n\"@\tc #A40709\",\n\"#\tc #CE000B\",\n\"$\tc #ED2928\",\n\"%\tc #F02C30\",\n\"&\tc #6A698F\",\n\"*\tc #706E95\",\n\"                        \",\n\"               ++++     \",\n\"           ++++$$$+     \",\n\"       ++++$$$$%%%$+    \",\n\"    +++$$$$%%%%%%%$+    \",\n\"   ..$$%%%%%%%%%%%%$+   \",\n\"   .$.%%%%%%%%%%%%..+   \",\n\"   .#$.%%%%%%%%...@@$+  \",\n\"   .##$.%%%....@@@@@$+  \",\n\"   .###$...@@@@@@@@@$+  \",\n\"   .###$.@@@@@@@@@@@$+  \",\n\"   .###$.@@@@@@@@@@@$+  \",\n\"   .###$.@@@@@@@@@@@$+  \",\n\"   .$##$.@@@@@@@@@@@$+  \",\n\"    .$#$.@@@@@@@@@@@$+  \",\n\"     .$$.@@@@@@@@@@$$+  \",\n\"     .$$.@@@@@@$$$$+++  \",\n\"      .$.@@$$$$++++     \",\n\"       ..$$++++         \",\n\"        +++             \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\nMacro_FCInfo_DeleteLineMaterial = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #A30500\",\n\"+\tc #555755\",\n\"@\tc #F67904\",\n\"#\tc #BCBCB3\",\n\"$\tc #D8DAD7\",\n\"%\tc #E7E9E6\",\n\"&\tc #EBEEEA\",\n\"*\tc #F1F4F0\",\n\"                        \",\n\"                        \",\n\"        @  @  @  @      \",\n\"      #@@#@@#@@#@@##    \",\n\".    ++@@+@@+@@+@@+#   .\",\n\"...  +&@&&@&&@&&@&+# ...\",\n\".....+&&&&&&&&&&&&+.....\",\n\".......$$$$$$$$$$.......\",\n\" ........######........ \",\n\"   ........$$........   \",\n\"     ..............#    \",\n\"     +&..........%+#    \",\n\"     +&..........&+#    \",\n\"     ..............#    \",\n\"   ........##........   \",\n\" ........$$$$$$........ \",\n\".......####$&&&&&.......\",\n\".....+&$$$$$&&&&+++.....\",\n\"...  +&&&&%**&&+++## ...\",\n\".    +&&&%&***&++##    .\",\n\"     +++++++++++##      \",\n\"      ###########       \",\n\"                        \",\n\"                        \"\n]\n\nMacro_FCInfo_Beer = [\n\"25 25 7 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"+\tc #C17D11\",\n\"@\tc #BABDB6\",\n\"#\tc #BDBDBA\",\n\"$\tc #D7D9D6\",\n\"%\tc #EEEEEC\",\n\"                         \",\n\"                         \",\n\"       %  %              \",\n\"      %%%% %%  %         \",\n\"     %   %%  %% %%       \",\n\"   % %%%%  %%% %  %      \",\n\"   %%%@%%@%%%@%@%%%      \",\n\"  %%%%%@%%@%%%%%%% %     \",\n\"   %%%%@@%%%@%%@%.       \",\n\"  %%@%@%%@%%@%@%#...     \",\n\"  %%%$%%%%%%%%%%####..   \",\n\"   %.$$%%@%%@%%%##.##.   \",\n\"    ..$.%%%%%%@.#. .#.   \",\n\"     .#%@.@.@.%%#. .#.   \",\n\"     .#+%%+@%%%+#. .#.   \",\n\"     .#+++++++++#. .#.   \",\n\"     .#+++++++++#. .#.   \",\n\"     .##++++++++#. .#.   \",\n\"     ..#++++++++#..##.   \",\n\"      .#++++++++#.##.    \",\n\"      .###+++++##...     \",\n\"       ...#####...       \",\n\"         .......         \",\n\"                         \",\n\"                         \"\n]\n\nMacro_FCInfo_Save_Material = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"+\tc #A30500\",\n\"@\tc #555755\",\n\"#\tc #CD5D01\",\n\"$\tc #F67904\",\n\"%\tc #BCBCB3\",\n\"&\tc #EBEEEA\",\n\"*\tc #F1F3F0\",\n\"                        \",\n\"                        \",\n\"        $  $  $  $      \",\n\"      %$$%$$%$$%$$%%    \",\n\"     @@$$@$$@$$@$$@%    \",\n\"     @&$&&$&&$&&$&@%    \",\n\"     @&&&&&&&&&&&&@%    \",\n\"     @&&&&&&&&&&&&@%    \",\n\"     @&&%%%%%%%%&&@%    \",\n\"     @&&&&&&&&&&&&@%    \",\n\"     @&&%%..%&&&&&@%    \",\n\"     @&&&&.@@&&&&&@%    \",\n\"     @&&%%%@@@&&&&@%    \",\n\"     @&&&&&&@++&&&@%    \",\n\"     @&&%%%%++++&&@%    \",\n\"     @&&&&&&&++++&@%    \",\n\"     @&&%%%&&&++++@%    \",\n\"     @&&&&&&&&&++++%    \",\n\"     @&&&&&**&&@+++#    \",\n\"     @&&&&&***&@@+##$   \",\n\"     @@@@@@@@@@@%%#$$$  \",\n\"      %%%%%%%%%%%  $$$$ \",\n\"                    $$  \",\n\"                        \"\n]\n\nMacro_FCInfo_Work = [\n\"24 24 8 1\",\n\" \tc None\",\n\".\tc #C17D11\",\n\"+\tc #8F5902\",\n\"@\tc #BABDB6\",\n\"#\tc #EDD400\",\n\"$\tc #A40000\",\n\"%\tc #CE5C00\",\n\"&\tc #171018\",\n\"                        \",\n\"         .....          \",\n\"      ++........        \",\n\"     +...++++++...      \",\n\"    +..@@@@#@@@++..     \",\n\"   +..#@@@@#@@@@#+..    \",\n\"  +..@@#@@@#@@$#@@+..   \",\n\"  +.#@@@%@@%@@$@@@#+.   \",\n\" +..@#@@@@@#@$@@@#@+..  \",\n\" +.@@@%@@@@@$$@@%@@@+.  \",\n\" +.@@@@@@@@@$$@@@@@@+.  \",\n\" +.@@@@@@@@&&@@@@@@@+.  \",\n\" +.###%@@@@&&@@@%###+.  \",\n\" +.@@@@@@@@$$@@@@@@@+.  \",\n\" +.@@@%@@@@@$$@@%@@@+.  \",\n\" +..@#@@@@@#$$$@@#@+..  \",\n\"  +.#@@@%@@%@$$@@@#+.   \",\n\"   ..@@#@@@#@@$$@@+..   \",\n\"   +..#@@@@#@@@$#+..    \",\n\"    +..@@@@#@@@++..     \",\n\"     +...++++++...      \",\n\"      ++........        \",\n\"         ......         \",\n\"                        \"\n]\n\nMacro_FCInfo_Color = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #16D0D2\",\n\"+\tc #D3D7CF\",\n\"@\tc #C17D11\",\n\"#\tc #EDD400\",\n\"$\tc #73D216\",\n\"%\tc #F57900\",\n\"&\tc #3465A4\",\n\"*\tc #CC0000\",\n\"         ....           \",\n\" +++     ....      @@@@ \",\n\" ++####  ....  $$$ @@@@ \",\n\" ++####%%%...&&$$$ @@@@ \",\n\"   ####%%% &&&&$$$ @@@@ \",\n\"   ####%%%+&&&&**       \",\n\"    $$$$ ++&&&&**##%%%  \",\n\"@@@@$$$$ ++++ ***##%%%  \",\n\"@@@@$$$$ ++++  ####%%%  \",\n\"@@@@      &&&$$$$##     \",\n\"@@@$$$$ %%&&&$$$$ %%%%  \",\n\"   $$$$ %%&***$$$ %%%%  \",\n\"...$$$$ %%%***$$$ %%%%  \",\n\"...$$$$*** ***&&&+%%%%  \",\n\"....%%%***### &&&+++@@@@\",\n\"....%%%***### &&&+++@@@@\",\n\"  +++%%   ### ....  @@@@\",\n\"  +++ &&&  $$$..####@@@@\",\n\"  +++ &&****$$..####    \",\n\" #### &&****$&&&###**** \",\n\" ####+++**...&&&###**** \",\n\" ####+++**...&&&&  **** \",\n\" ####+++  ...&&&&  **** \",\n\"          ....          \"\n]\n\nMacro_FCInfo_Face = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #A30500\",\n\"+\tc #9C0C04\",\n\"@\tc #9C0D0C\",\n\"#\tc #EF2B29\",\n\"$\tc #5468F8\",\n\"%\tc #A9B0CB\",\n\"&\tc #98B5D8\",\n\"*\tc #9EB7D5\",\n\"                        \",\n\"                        \",\n\"           ##           \",\n\"         ##++##         \",\n\"       ##++++++##       \",\n\"     ##++++++++++##     \",\n\"      ##@+++++++##      \",\n\"  ## $$*#++++++#**$     \",\n\"    ##***##++##***$$ #  \",\n\"  ##**##***##***$$*$##  \",\n\"  #.#***##*****$*&*# #  \",\n\"  #..##***#$*$$**##$ #  \",\n\"  #....#***%$**##**$ #  \",\n\"  #.....##%%$*#****$ #  \",\n\"  #......#%%$#*****$ #  \",\n\"  #......#%%$#*****$ #  \",\n\"  #......#%%$#***&*$ #  \",\n\"  #......#%%$#***$$  #  \",\n\"  ##.....#%%$#*$$  ##   \",\n\"    ##...#$%$#$   #     \",\n\"      ##.# $$#  ##      \",\n\"        ##   ###        \",\n\"         #   #          \",\n\"                        \"\n]\n\nMacro_FCInfo_WebForum = [\n\"24 24 4 1\",\n\" \tc None\",\n\".\tc #1E4C89\",\n\"+\tc #EBF0F3\",\n\"@\tc #FFFFFF\",\n\"                        \",\n\"       ..........       \",\n\"      ..@@@@@@@@..      \",\n\"     ..@@......@@..     \",\n\"    ..@@........@+..    \",\n\"   ..@@...@@@@...@@..   \",\n\"  ..@@...@@@@@@...@@..  \",\n\" ..@@...@@@..@@@...@@.. \",\n\" .@@....@@....@@....@@. \",\n\" .@...........@@.....@. \",\n\" .@..........@@@.....@. \",\n\" .@.........@@@......@. \",\n\" .@........@@@.......@. \",\n\" .@........@@........@. \",\n\" .@........@@........@. \",\n\" .@@.......@@.......@@. \",\n\" ..@@..............@@.. \",\n\"  ..@@............@@..  \",\n\"   ..@@....@@....@@..   \",\n\"    ..@@...@@...@@..    \",\n\"     ..@@......@@..     \",\n\"      ..@@@@@@@@..      \",\n\"       ..........       \",\n\"                        \"\n]\n\nMacro_FCInfo_WebWiki = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #091756\",\n\"+\tc #194C8B\",\n\"@\tc #214B97\",\n\"#\tc #50627D\",\n\"$\tc #BC727C\",\n\"%\tc #9DAAC0\",\n\"&\tc #C7D0DF\",\n\"*\tc #FFFFFF\",\n\"                        \",\n\"       ++++++++++       \",\n\"      ++********++      \",\n\"     ++**++++++**++     \",\n\"    ++**++++++++**++    \",\n\"   ++**+++****+++**++   \",\n\"  ++**+++******+++**++  \",\n\" ++**+++***++***+++**++ \",\n\" +**++++**++++**++++**+ \",\n\" +*+++++++++++**+++++*+ \",\n\" +*+++++++++............\",\n\" +*+++++++++.**@@@@****.\",\n\" +*++++++++*.*@%&%%@***.\",\n\" +*++++++++*.@%%%*%%@**.\",\n\" +*++++++++*.@&%**$%@**.\",\n\" +**+++++++*.@%**$$%@**.\",\n\" ++**+++++++.@%%$$$%@**.\",\n\"  ++**++++++.*@%%%%@***.\",\n\"   ++**++++*.**@@@@%#**.\",\n\"    ++**+++*.******#%#*.\",\n\"     ++**+++.*....**#%#.\",\n\"      ++****.**%%%***#%.\",\n\"       +++++.*********#.\",\n\"            ............\"\n]\n\nMacro_FCInfo_SpreadSheet = [\n\"27 24 8 1\",\n\" \tc #383C3E\",\n\".\tc #4D5153\",\n\"+\tc #6C6F70\",\n\"@\tc #868A8C\",\n\"#\tc #9DA1A1\",\n\"$\tc #BFC1BE\",\n\"%\tc #D6D9D5\",\n\"&\tc #EFF1EE\",\n\"&&&&&&&&&&&&&&&&&&&&&&&&&&&\",\n\"&$@@@@@@@@@@@@@@@@@@@@@@@@&\",\n\"&$######@ ###############@&\",\n\"&$%&&&&&@ %&&&&&&&&&&&&&%@&\",\n\"&$%&&&&&@ %&&&&&&&&&&&&&%@&\",\n\"&$%$$$$$@ %&&&&&&&&&&&&&%@&\",\n\"&$                       @&\",\n\"&$######@ ###############@&\",\n\"&$%&&&&&@ %&&&&&&&&&&&&&%@&\",\n\"&$%&&&&&@ %&&&&&&&&&&&&&%@&\",\n\"&$%$$$$$@ %&&&&&&&&&&&&&%@&\",\n\"&$                       @&\",\n\"&$######@ ###############@&\",\n\"&$%&&&&&@ %&&&&&&&&&&&&&%@&\",\n\"&$%&&&&&@ %&&&&&&&&&&&&&%@&\",\n\"&$%$$$$$@ %&&&&&&&&&&&&&%@&\",\n\"&$                       @&\",\n\"&$######@ ###############@&\",\n\"&$%&&&&&@ %&&&&&&&&&&&&&%@&\",\n\"&$%&&&&&@ %&&&&&&&&&&&&&%@&\",\n\"&$%$$$$$@ %&&&&&&&&&&&&&%@&\",\n\"&$#######################@&\",\n\"&$$$$$$$$$$$$$$$$$$$$$$$$$&\",\n\"&&&&&&&&&&&&&&&&&&&&&&&&&&&\"\n]\n\n#### Material, Gravity By Default Begin\nglobal materialAssociated ;   materialAssociated = []   # material associate\n\nmaterialAssociated = [\n(u\"Liquid Water (H2o),1,10.0,adapt Price\"),\n(u\"Mater Beton,2.4,10.0,adapt Price\"),\n(u\"Metal Aluminium (Al),2.7,10.0,adapt Price\"),\n(u\"Metal Copper (Cu),8.96,10.0,adapt Price\"),\n(u\"Metal Gold (Au),19.3,10.0,Gratis\"),\n(u\"Metal Iron (Fe),7.87,10.0,adapt Price\"),\n(u\"Metal Lead (Pb),11.35,10.0,adapt Price\"),\n(u\"Metal Magnesium (Mg),1.43,10.0,adapt Price\"),\n(u\"Metal Nickel (Ni),8.27,10.0,adapt Price\"),\n(u\"Metal Pewter (Sn),7.29,10.0,adapt Price\"),\n(u\"Metal Platinum (Pt),21.45,10.0,adapt Price\"),\n(u\"Metal Silver (Ag),10.5,10.0,adapt Price\"),\n(u\"Metal Sodium (Na),0.97,10.0,adapt Price\"),\n(u\"Metal Titanium (Ti),4.4,10.0,adapt Price\"),\n(u\"Metal Zinc (Zn),7.1,10.0,adapt Price\"),\n(u\"Wood Beechwood,0.8,10.0,adapt Price\"),\n(u\"Wood MDF,0.75,10.0,adapt Price\"),\n(u\"Wood Mahogany,0.6,10.0,adapt Price\"),\n(u\"Wood Oak,0.7,10.0,adapt Price\"),\n(u\"Wood White pine,0.4,10.0,adapt Price\")\n]\n\nif os.path.exists(path):\n    #App.Console.PrintMessage(str(os.path.exists(path)) + \"\\n\")\n    #App.Console.PrintMessage(str(os.path.isfile(path + \"FCInfo_material.txt\")) + \"\\n\")\n    #\n    #if not file one file (data default in macro) is created in the Macro location or in the seTMaterialSavePathName path\n    if (os.path.isfile(seTMaterialSavePathName + seTMaterialFileName) == False) or (os.path.getsize(seTMaterialSavePathName + seTMaterialFileName) == 0):   # default \"FCInfo_material.txt\"\n\n        App.Console.PrintMessage(u\"Save \" + str(seTMaterialSavePathName) + str(seTMaterialFileName) + \"\\n\")\n        materialAssociated.sort()\n        App_Console_PrintMessage(u\"Number material : \" + str(len(materialAssociated)) + \"\\n\")\n        try:\n            f = open(seTMaterialSavePathName + seTMaterialFileName, 'w') # write\n            for i in materialAssociated:\n                f.write(i + \"\\n\")\n            f.close()\n            App_Console_PrintMessage(u\"Create/Save file : \" + seTMaterialFileName + \"\\n\")\n        except Exception:\n            App_Console_PrintError(u\"Not file \" + seTMaterialFileName + \"\\n\")\n        seTMaterialCurrentIndex = 0\n        seTDensiteValue = float(materialAssociated[0].split(\",\")[1])\n    else:\n        try:\n            App_Console_PrintMessage(u\"Read the file \" + str(seTMaterialReadPathName) + str(seTMaterialFileName) + \"\\n\")\n            f = open(seTMaterialReadPathName + seTMaterialFileName, 'r')  # read    # read the file\n            materialAssociated = []\n            for i in f:\n                i2 = i.rstrip()      # .lstrip(), .rstrip(), .split(\",\")\n                materialAssociated.append(i2)\n            f.close()\n            seTDensiteValue = float(materialAssociated[0].split(\",\")[1])\n            App_Console_PrintMessage(u\"Load the file : \" + seTMaterialFileName + \"\\n\")\n        except Exception:\n            App_Console_PrintError(u\"Not read file \" + seTMaterialFileName + \" saved\" + \"\\n\")\n#### Material, Gravity End\n\nglobal infoFaceMesh; \nglobal indexFaceMesh  ; indexFaceMesh  = 0\nglobal coordPointsMesh; coordPointsMesh = \"\"\n#import warnings\n#warnings.simplefilter(\"ignore\")\ndef getNormal(cb):\n    #https://wiki.freecadweb.org/Code_snippets#Get_the_normal_vector_of_a_surface_from_a_STL_file\n    global infoFaceMesh;\n    global indexFaceMesh\n\n    try:\n        pp = cb.getPickedPoint()\n        indexFaceMesh  = coin.cast(pp.getDetail(), \"SoFaceDetail\").getFaceIndex()\n    except Exception:\n        None\n\ndef Around(a) :\n    global seTDecimalValue\n\n    if seTDecimalValue == -1:\n        seTDecimalValue = 1000\n    ard = round(a, seTDecimalValue)\n    return ard\n\n#### BoundBox Tracing ####\ndef adjustedGlobalPlacement(obj, locVector):\n    '''find global placement to make locVector the local origin with the correct orientation'''\n    # extract BoundingBox_Tracing\n    #2021/07/10 modified by edwilliams16 to handle objects in nested part containers\n    #https://forum.freecadweb.org/viewtopic.php?f=22&t=59852\n    #\n    try:\n        objectPlacement = obj.Placement\n        objectGlobalPlacement = obj.getGlobalPlacement()\n        locPlacement = App.Placement(locVector, App.Rotation(App.Vector(1,0,0),0))\n        return objectGlobalPlacement.multiply(objectPlacement.inverse()).multiply(locPlacement)\n    except Exception:\n        locPlacement = App.Placement(App.Vector(0,0,0), App.Rotation(0,0,0), App.Vector(0,0,0))\n        App_Console_PrintError(u\"Error adjustedGlobalPlacement\")\n        return locPlacement\n\ndef bounBoxTracing():\n    #import PySide\n    global BDvol\n    global switchBoundBoxCreateVolume   # 1 = create Volume\n    global switchBoundBoxCreateText     # 1 = create dimension info : 0 = not dimension info\n    global seTBoundBoxTextHeigth        # text heigth\n    global seTBoundBoxTextArround       # arrondi text dimensions\n    global seTBoundBoxDisplayModeText   # u\"Screen\" or u\"World\"\n    global seTBoundBoxJustificationText # u\"Center\" or u\"Left\" or u\"Right\"\n\n    ##### Section configuration begin ##################\n    FontSizeText      = seTBoundBoxTextHeigth# text info dimension\n    ####\n    TextColorText_R   = 0.0 # text color info red   1 = 255\n    TextColorText_G   = 0.0 # text color info green 1 = 255\n    TextColorText_B   = 0.0 # text color info blue  1 = 255\n    LineColor_red     = 1.0 # Line Color rectangle  1 = 255\n    LineColor_green   = 0.0 # Line Color rectangle  1 = 255\n    LineColor_blue    = 0.0 # Line Color rectangle  1 = 255\n    arrondi           = seTBoundBoxTextArround  # round the info ex: 3 = 3 decimals\n    ##### Section configuration end ####################\n\n    sel   = FreeCADGui.Selection.getSelection()\n    selEx = FreeCADGui.Selection.getSelectionEx()\n    objs  = [selobj.Object for selobj in selEx]\n\n    if len(objs) >= 1:\n        if hasattr(objs[0], \"Shape\"):\n            s = objs[0].Shape\n        elif hasattr(objs[0], \"Mesh\"):      # upgrade with wmayer thanks #http://forum.freecadweb.org/viewtopic.php?f=13&t=22331\n            s = objs[0].Mesh\n        elif hasattr(objs[0], \"Points\"):\n            s = objs[0].Points\n        FreeCAD.ActiveDocument.openTransaction(u\"FCInfo BBox\")    # memorise les actions (avec annuler restore)\n        #FreeCAD.ActiveDocument.commitTransaction()         # restore les actions  (avec annuler restore)\n        #FreeCAD.ActiveDocument.abortTransaction()          # abandonne les actions(avec annuler restore)\n\n        # boundBox\n        if sel[0].isDerivedFrom(\"Fem::FemPostWarpVectorFilter\"):\n            boundBox_ = sel[0].ViewObject.getBoundingBox()\n        else:\n            boundBox_ = s.BoundBox\n\n        boundBoxLX   = boundBox_.XLength\n        boundBoxLY   = boundBox_.YLength\n        boundBoxLZ   = boundBox_.ZLength\n        boundBoxXMin = boundBox_.XMin\n        boundBoxYMin = boundBox_.YMin\n        boundBoxZMin = boundBox_.ZMin\n        boundBoxLocation = App.Vector(boundBox_.XMin,boundBox_.YMin,boundBox_.ZMin)\n        nameLabel  = sel[0].Label\n\n        try:\n            try:\n                import unicodedata    \n                nameLabel = str(unicodedata.normalize('NFKD', nameLabel).encode('ascii','ignore'))[2:]\n            except Exception:\n                None\n\n            boundBoxLocation = App.Vector(boundBoxXMin,boundBoxYMin,boundBoxZMin)\n            nameLabel  = sel[0].Label\n\n            # create Volume\n            if (switchBoundBoxCreateVolume == 1):\n                if (boundBoxLX > 0) and (boundBoxLY > 0) and (boundBoxLZ > 0):  # Create Volume\n                    BDvol = App.ActiveDocument.addObject(\"Part::Box\",nameLabel + \"_BoundBoxVolume\")\n                    #BDvol.Label = \"BoundBoxVolume\"\n                    BDvol.Length.Value = boundBoxLX\n                    BDvol.Width.Value  = boundBoxLY\n                    BDvol.Height.Value = boundBoxLZ\n                    BDvol.Placement = adjustedGlobalPlacement(objs[0], boundBoxLocation)\n                    BDPl = BDvol.Placement\n                    oripl_X=BDvol.Placement.Base.x\n                    oripl_Y=BDvol.Placement.Base.y\n                    oripl_Z=BDvol.Placement.Base.z\n                    #if debug: print(f'global {globalObjectPlacement}\\n local {localObjectPlacement} BB {BBlocPlacement}')\n                    FreeCADGui.ActiveDocument.getObject(BDvol.Name).LineColor  = (LineColor_red, LineColor_green, LineColor_blue)\n                    FreeCADGui.ActiveDocument.getObject(BDvol.Name).PointColor = (LineColor_red, LineColor_green, LineColor_blue)\n                    FreeCADGui.ActiveDocument.getObject(BDvol.Name).ShapeColor = (LineColor_red, LineColor_green, LineColor_blue)\n                    FreeCADGui.ActiveDocument.getObject(BDvol.Name).Transparency = 80\n                    switchBoundBoxCreateVolume = 0\n                    #App_Console_PrintMessage(nameLabel + \"_BoundBoxVolume : \" + str(BDvol.Shape.Volume)+\"\\r\\n\")\n\n                    # create Text for volume\n                    if switchBoundBoxCreateText == 1:    # section create dimension info\n                        conteneurVol = []\n                        del conteneurVol[:]\n                        conteneurVol = App.activeDocument().addObject(\"App::DocumentObjectGroup\",nameLabel + \"_BoundBoxVolume_Info\")\n                        BDtext = FreeCAD.Placement()\n                        BDtext = adjustedGlobalPlacement(objs[0], boundBoxLocation)\n                        BDPl = BDtext\n\n                        #pl_0C1 = Draft.make_text([str(round(boundBoxLX,arrondi))],point=FreeCAD.Vector(oripl_X + (boundBoxLX/2), oripl_Y, oripl_Z))\n                        pl_0C1 = Draft.make_text([str(round(boundBoxLX,arrondi))],placement = BDPl.multVec(App.Vector(boundBoxLX/2,0,0)))\n                        pl_0C1.ViewObject.DisplayMode   = seTBoundBoxDisplayModeText\n                        pl_0C1.ViewObject.Justification = seTBoundBoxJustificationText\n                        pl_0C1.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                        pl_0C1.ViewObject.FontSize      = FontSizeText\n                        pl_0C1.Label      = nameLabel + \"_Volume_X_\" + str(round(boundBoxLX,arrondi))\n                        conteneurVol.addObject(pl_0C1)\n\n                        #pl_0C2 = Draft.make_text([str(round(boundBoxLY,arrondi))],point=FreeCAD.Vector(oripl_X, oripl_Y + (boundBoxLY/2), oripl_Z))\n                        pl_0C2 = Draft.make_text([str(round(boundBoxLY,arrondi))],placement = BDPl.multVec(App.Vector(0, boundBoxLY/2, 0)))\n                        pl_0C2.ViewObject.DisplayMode   = seTBoundBoxDisplayModeText\n                        pl_0C2.ViewObject.Justification = seTBoundBoxJustificationText\n                        pl_0C2.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                        pl_0C2.ViewObject.FontSize      = FontSizeText\n                        pl_0C2.Label      = nameLabel + \"_Volume_Y_\" + str(round(boundBoxLY,arrondi))\n                        conteneurVol.addObject(pl_0C2)\n\n                        #pl_0C3 = Draft.make_text([str(round(boundBoxLZ,arrondi))],placement=FreeCAD.Vector(oripl_X, oripl_Y, oripl_Z + (boundBoxLZ/2)))\n                        pl_0C3 = Draft.make_text([str(round(boundBoxLZ,arrondi))],placement = BDPl.multVec(App.Vector(0, 0, boundBoxLZ/2)))\n                        pl_0C3.ViewObject.DisplayMode   = seTBoundBoxDisplayModeText\n                        pl_0C3.ViewObject.Justification = seTBoundBoxJustificationText\n                        pl_0C3.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                        pl_0C3.ViewObject.FontSize      = FontSizeText\n                        pl_0C3.Label      = nameLabel + \"_Volume_Z_\" + str(round(boundBoxLZ,arrondi))\n                        conteneurVol.addObject(pl_0C3)\n                        App.ActiveDocument.recompute()\n\n            else: #create rectangles\n                conteneurRectangle = []\n                del conteneurRectangle[:]\n                conteneurRectangle = App.activeDocument().addObject(\"App::DocumentObjectGroup\",nameLabel + \"_BoundBoxRectangle\")\n\n                if switchBoundBoxCreateText == 1:    # conteneur dimension info\n                    conteneurInfo = []\n                    del conteneurInfo[:]\n                    conteneurInfo = App.activeDocument().addObject(\"App::DocumentObjectGroup\",nameLabel + \"_BoundBoxRectangle_Info\")\n                try:\n                    if (boundBoxLX and boundBoxLY) > 0.0:\n                        #pl_0 = App.Placement(App.Vector(oripl_X,oripl_Y,oripl_Z), App.Rotation(0.0,0.0,0.0))\n                        pl_0 = adjustedGlobalPlacement(objs[0], boundBoxLocation)\n                        double = Draft.makeRectangle(length=boundBoxLX,height=boundBoxLY,placement=pl_0,face=False,support=None) #OK\n                        double.Label = nameLabel + \"_BoundBoxRectangle_Bo\"\n                        FreeCADGui.activeDocument().activeObject().LineColor = (LineColor_red, LineColor_green, LineColor_blue)\n                        conteneurRectangle.addObject(double)\n\n                    if switchBoundBoxCreateText == 1:    # section create dimension info\n                        #pl_0C1 = Draft.make_text([str(round(boundBoxLX,arrondi))],placement=FreeCAD.Vector(pl_0.Base.x + (boundBoxLX/2), pl_0.Base.y, pl_0.Base.z))\n                        # XY -> XY\n                        pl_0C1 = Draft.make_text([str(round(boundBoxLX,arrondi))],placement=pl_0.multVec(App.Vector(boundBoxLX/2, 0, 0)))\n                        pl_0C1.ViewObject.DisplayMode   = seTBoundBoxDisplayModeText\n                        pl_0C1.ViewObject.Justification = seTBoundBoxJustificationText\n                        pl_0C1.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                        pl_0C1.ViewObject.FontSize      = FontSizeText\n                        pl_0C1.Label      = nameLabel + \"_Rectangle_Bo_0X_\" + str(round(boundBoxLX,arrondi))\n                        conteneurInfo.addObject(pl_0C1)\n\n                        #pl_0C2 = Draft.make_text([str(round(boundBoxLY,arrondi))],placement=FreeCAD.Vector(pl_0.Base.x, pl_0.Base.y + (boundBoxLY/2), pl_0.Base.z))\n                        pl_0C2 = Draft.make_text([str(round(boundBoxLY,arrondi))],placement=pl_0.multVec(App.Vector(0., boundBoxLY/2, 0.)))\n                        pl_0C2.ViewObject.DisplayMode   = seTBoundBoxDisplayModeText\n                        pl_0C2.ViewObject.Justification = seTBoundBoxJustificationText\n                        pl_0C2.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                        pl_0C2.ViewObject.FontSize      = FontSizeText\n                        pl_0C2.Label      = nameLabel + \"_Rectangle_Bo_0Y_\" + str(round(boundBoxLY,arrondi))\n                        conteneurInfo.addObject(pl_0C2)\n                except:\n                    App_Console_PrintError(u\"not done 0\"+\"\\n\")\n\n                try:\n                    if (boundBoxLX and boundBoxLY) > 0.0:\n                        #pl_1 = App.Placement(App.Vector(oripl_X,oripl_Y,oripl_Z+boundBoxLZ), App.Rotation(0.0,0.0,0.0))\n                        pl_1 =adjustedGlobalPlacement(objs[0], boundBoxLocation + App.Vector(0,0,boundBoxLZ))\n                        double = Draft.makeRectangle(length=boundBoxLX,height=boundBoxLY,placement=pl_1,face=False,support=None) #Ok\n                        double.Label = nameLabel + \"_BoundBoxRectangle_To\"\n                        FreeCADGui.activeDocument().activeObject().LineColor = (LineColor_red, LineColor_green, LineColor_blue)\n                        conteneurRectangle.addObject(double)\n\n                    if switchBoundBoxCreateText == 1:    # section create dimension info\n                        #pl_0C1 = Draft.make_text([str(round(boundBoxLX,arrondi))],placement=FreeCAD.Vector(pl_1.Base.x + (boundBoxLX/2), pl_1.Base.y, pl_1.Base.z))\n                        #XY -> XY\n                        pl_0C1 = Draft.make_text([str(round(boundBoxLX,arrondi))],placement=pl_1.multVec(App.Vector(boundBoxLX/2, 0, 0)))\n                        pl_0C1.ViewObject.DisplayMode   = seTBoundBoxDisplayModeText\n                        pl_0C1.ViewObject.Justification = seTBoundBoxJustificationText\n                        pl_0C1.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                        pl_0C1.ViewObject.FontSize      = FontSizeText\n                        pl_0C1.Label      = nameLabel + \"_Rectangle_To_1X_\" + str(round(boundBoxLX,arrondi))\n                        conteneurInfo.addObject(pl_0C1)\n\n                        #pl_0C2 = Draft.make_text([str(round(boundBoxLY,arrondi))],placement=FreeCAD.Vector(pl_1.Base.x, pl_1.Base.y + (boundBoxLY/2), pl_1.Base.z))\n                        pl_0C2 = Draft.make_text([str(round(boundBoxLY,arrondi))],placement=pl_1.multVec(App.Vector(0., boundBoxLY/2, 0)))\n\n                        pl_0C2.ViewObject.DisplayMode   = seTBoundBoxDisplayModeText\n                        pl_0C2.ViewObject.Justification = seTBoundBoxJustificationText\n                        pl_0C2.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                        pl_0C2.ViewObject.FontSize      = FontSizeText\n                        pl_0C2.Label      = nameLabel + \"_Rectangle_To_1Y_\" + str(round(boundBoxLY,arrondi))\n                        conteneurInfo.addObject(pl_0C2)\n                except:\n                    App_Console_PrintError(u\"not done 1\"+\"\\n\")\n\n                try:\n                    if (boundBoxLX and boundBoxLZ) > 0.0:\n                        #pl_2 = App.Placement(App.Vector(oripl_X,oripl_Y,oripl_Z), App.Rotation(0.0,0.0,90))\n                        pl_2 = pl_0.multiply(App.Placement(App.Vector(0.,0.,0.),App.Rotation(0.0,0.0,90)))\n                        double = Draft.makeRectangle(length=boundBoxLX,height=boundBoxLZ,placement=pl_2,face=False,support=None) #Ok\n                        double.Label = nameLabel + \"_BoundBoxRectangle_Fr\"\n                        FreeCADGui.activeDocument().activeObject().LineColor = (LineColor_red, LineColor_green, LineColor_blue)\n                        conteneurRectangle.addObject(double)\n\n                    if switchBoundBoxCreateText == 1:    # section create dimension info\n                        #pl_0C1 = Draft.make_text([str(round(boundBoxLX,arrondi))],placement=FreeCAD.Vector(pl_2.Base.x + (boundBoxLX/2), pl_2.Base.y, pl_2.Base.z))\n                        #XZ -> XY\n                        pl_0C1 = Draft.make_text([str(round(boundBoxLX,arrondi))],placement=pl_2.multVec(App.Vector(boundBoxLX/2, 0, 0)))\n                        pl_0C1.ViewObject.DisplayMode   = seTBoundBoxDisplayModeText\n                        pl_0C1.ViewObject.Justification = seTBoundBoxJustificationText\n                        pl_0C1.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                        pl_0C1.ViewObject.FontSize      = FontSizeText\n                        pl_0C1.Label      = nameLabel + \"_Rectangle_Fr_2X_\" + str(round(boundBoxLX,arrondi))\n                        conteneurInfo.addObject(pl_0C1)\n\n                        #pl_0C2 = Draft.make_text([str(round(boundBoxLZ,arrondi))],placement=FreeCAD.Vector(pl_2.Base.x, pl_2.Base.y, pl_2.Base.z + (boundBoxLZ/2)))\n                        pl_0C2 = Draft.make_text([str(round(boundBoxLZ,arrondi))],placement=pl_2.multVec(App.Vector(0, boundBoxLZ/2, 0)))\n                        pl_0C2.ViewObject.DisplayMode   = seTBoundBoxDisplayModeText\n                        pl_0C2.ViewObject.Justification = seTBoundBoxJustificationText\n                        pl_0C2.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                        pl_0C2.ViewObject.FontSize      = FontSizeText\n                        pl_0C2.Label      = nameLabel + \"_Rectangle_Fr_2Z_\" + str(round(boundBoxLZ,arrondi))\n                        conteneurInfo.addObject(pl_0C2)\n                except:\n                    App_Console_PrintError(u\"not done 2\"+\"\\n\")\n\n                try:\n                    if (boundBoxLX and boundBoxLZ) > 0.0:\n                        #pl_3 = App.Placement(App.Vector(oripl_X,oripl_Y+boundBoxLY,oripl_Z), App.Rotation(0.0,0.0,90))\n                        pl_3 = adjustedGlobalPlacement(objs[0], boundBoxLocation+App.Vector(0, boundBoxLY, 0)).multiply(App.Placement(App.Vector(0.,0.,0.),App.Rotation(0.0,0.0,90)))\n                        double = Draft.makeRectangle(length=boundBoxLX,height=boundBoxLZ,placement=pl_3,face=False,support=None) #Ok\n                        double.Label = nameLabel + \"_BoundBoxRectangle_Re\"\n                        FreeCADGui.activeDocument().activeObject().LineColor = (LineColor_red, LineColor_green, LineColor_blue)\n                        conteneurRectangle.addObject(double)\n\n                    if switchBoundBoxCreateText == 1:    # section create dimension info\n                        #XZ -> XY\n                        pl_0C1 = Draft.make_text([str(round(boundBoxLX,arrondi))],placement=pl_3.multVec(App.Vector(boundBoxLX/2, 0, 0)))\n                        pl_0C1.ViewObject.DisplayMode   = seTBoundBoxDisplayModeText\n                        pl_0C1.ViewObject.Justification = seTBoundBoxJustificationText\n                        pl_0C1.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                        pl_0C1.ViewObject.FontSize      = FontSizeText\n                        pl_0C1.Label      = nameLabel + \"_Rectangle_Re_3X_\" + str(round(boundBoxLX,arrondi))\n                        conteneurInfo.addObject(pl_0C1)\n                \n                        pl_0C2 = Draft.make_text([str(round(boundBoxLZ,arrondi))],placement=pl_3.multVec(App.Vector(0, boundBoxLZ/2, 0)))\n                        pl_0C2.ViewObject.DisplayMode   = seTBoundBoxDisplayModeText\n                        pl_0C2.ViewObject.Justification = seTBoundBoxJustificationText\n                        pl_0C2.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                        pl_0C2.ViewObject.FontSize      = FontSizeText\n                        pl_0C2.Label      = nameLabel + \"_Rectangle_Re_3Z_\" + str(round(boundBoxLZ,arrondi))\n                        conteneurInfo.addObject(pl_0C2)\n                except:\n                    App_Console_PrintError(u\"not done 3\"+\"\\n\")\n\n                try:\n                    if (boundBoxLY and boundBoxLZ) > 0.0:\n                        #pl_4 = App.Placement(App.Vector(oripl_X,oripl_Y,oripl_Z), App.Rotation(90,0.0,90))\n                        pl_4 = pl_0.multiply(App.Placement(App.Vector(0.,0.,0.),App.Rotation(90,0,90)))\n                        double = Draft.makeRectangle(length=boundBoxLY,height=boundBoxLZ,placement=pl_4,face=False,support=None) #Ok\n                        double.Label = nameLabel + \"_BoundBoxRectangle_Le\"\n                        FreeCADGui.activeDocument().activeObject().LineColor = (LineColor_red, LineColor_green, LineColor_blue)\n                        conteneurRectangle.addObject(double)\n\n                    if switchBoundBoxCreateText == 1:    # section create dimension info\n                        #pl_0C1 = Draft.make_text([str(round(boundBoxLY,arrondi))],placement=FreeCAD.Vector(pl_4.Base.x, pl_4.Base.y + (boundBoxLY/2), pl_4.Base.z))\n                        #YZ ->XY\n                        pl_0C1 = Draft.make_text([str(round(boundBoxLY,arrondi))],placement=pl_4.multVec(App.Vector(boundBoxLY/2, 0., 0.)))\n                        pl_0C1.ViewObject.DisplayMode   = seTBoundBoxDisplayModeText\n                        pl_0C1.ViewObject.Justification = seTBoundBoxJustificationText\n                        pl_0C1.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                        pl_0C1.ViewObject.FontSize      = FontSizeText\n                        pl_0C1.Label      = nameLabel + \"_Rectangle_Le_4Y_\" + str(round(boundBoxLY,arrondi))\n                        conteneurInfo.addObject(pl_0C1)\n\n                        #pl_0C2 = Draft.make_text([str(round(boundBoxLZ,arrondi))],placement=FreeCAD.Vector(pl_4.Base.x, pl_4.Base.y, pl_4.Base.z + (boundBoxLZ/2)))\n                        pl_0C2 = Draft.make_text([str(round(boundBoxLZ,arrondi))],placement=pl_4.multVec(App.Vector(0., boundBoxLZ/2, 0)))\n                        pl_0C2.ViewObject.DisplayMode   = seTBoundBoxDisplayModeText\n                        pl_0C2.ViewObject.Justification = seTBoundBoxJustificationText\n                        pl_0C2.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                        pl_0C2.ViewObject.FontSize      = FontSizeText\n                        pl_0C2.Label      = nameLabel + \"_Rectangle_Le_4Z_\" + str(round(boundBoxLZ,arrondi))\n                        conteneurInfo.addObject(pl_0C2)\n                except:\n                    App_Console_PrintError(u\"not done 4\"+\"\\n\")\n\n                try:\n                    if (boundBoxLY and boundBoxLZ) > 0.0:\n                        #pl_5 = App.Placement(App.Vector(oripl_X+boundBoxLX,oripl_Y,oripl_Z), App.Rotation(90,0.0,90))\n                        pl_5 = adjustedGlobalPlacement(objs[0], boundBoxLocation+App.Vector(boundBoxLX,0,0)).multiply(App.Placement(App.Vector(0.,0.,0.),App.Rotation(90,0.0,90)))\n                        double = Draft.makeRectangle(length=boundBoxLY,height=boundBoxLZ,placement=pl_5,face=False,support=None) #Ok\n                        double.Label = nameLabel + \"_BoundBoxRectangle_Ri\"\n                        FreeCADGui.activeDocument().activeObject().LineColor = (LineColor_red, LineColor_green, LineColor_blue)\n                        conteneurRectangle.addObject(double)\n\n                    if switchBoundBoxCreateText == 1:    # section create dimension info\n                        #YZ-> XY\n                        pl_0C1 = Draft.make_text([str(round(boundBoxLY,arrondi))],placement=pl_5.multVec(App.Vector(boundBoxLY/2, 0, 0)))\n                        pl_0C1.ViewObject.DisplayMode   = seTBoundBoxDisplayModeText\n                        pl_0C1.ViewObject.Justification = seTBoundBoxJustificationText\n                        pl_0C1.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                        pl_0C1.ViewObject.FontSize      = FontSizeText\n                        pl_0C1.Label      = nameLabel + \"_Rectangle_Ri_5Y_\" + str(round(boundBoxLY,arrondi))\n                        conteneurInfo.addObject(pl_0C1)\n\n                        pl_0C2 = Draft.make_text([str(round(boundBoxLZ,arrondi))],placement=pl_5.multVec(App.Vector(0, boundBoxLZ/2, 0 )))\n                        pl_0C2.ViewObject.DisplayMode   = seTBoundBoxDisplayModeText\n                        pl_0C2.ViewObject.Justification = seTBoundBoxJustificationText\n                        pl_0C2.ViewObject.TextColor     = (TextColorText_R, TextColorText_G, TextColorText_B)\n                        pl_0C2.ViewObject.FontSize      = FontSizeText\n                        pl_0C2.Label      = nameLabel + \"_Rectangle_Ri_5Z_\" + str(round(boundBoxLZ,arrondi))\n                        conteneurInfo.addObject(pl_0C2)\n                except:\n                    App_Console_PrintError(u\"not done 5\"+\"\\n\")\n                #####\n                App.ActiveDocument.recompute()\n        except Exception:\n            App_Console_PrintError(u\"Bad selection\"+\"\\n\")\n    else:\n        App_Console_PrintMessage(u\"Select an object !\"+\"\\n\")\n##############################################################################################################\n\ndef axisPlane( posX = 0.0, posY = 0.0, posZ = 0.0, namePlane = \"FCPlane\"):    # plane creation\n    global sel\n    global document_\n    global object_Name\n    global boundBoxDiag\n    global switchInertia\n    global seTMemoClipBoard\n    global switchCreatePoint\n    global switchCreateAxis\n    global switchCreatePlane\n    global directionObj\n\n    FreeCAD.ActiveDocument.openTransaction(u\"FCInfo Plane\")    # memorise les actions (avec annuler restore)\n    #FreeCAD.ActiveDocument.commitTransaction()         # restore les actions  (avec annuler restore)\n    #FreeCAD.ActiveDocument.abortTransaction()          # abandonne les actions(avec annuler restore)\n\n    sel = FreeCADGui.Selection.getSelection()\n    retour =  Macro_FCInfo_05 # icone dans une variable (ok / ko)\n\n    switchInertia = 1\n    if seTMemoClipBoard >= 1:                # memo clipBoard\n        memo = QApplication.clipboard()\n        memo.clear(mode=memo.Clipboard )\n        if seTMemoClipBoard == 1:\n            memo.setText(u\"FreeCAD.Vector(\"+str(Around(posX))+\", \"+str(Around(posY))+\", \"+str(Around(posZ))+\")\", mode = memo.Clipboard) # format : FreeCAD.Vector(x, y, z)\n        elif seTMemoClipBoard == 2:\n            memo.setText(str(Around(posX))+\", \"+str(Around(posY))+\", \"+str(Around(posZ)), mode = memo.Clipboard)                        # format : x, y, z\n        elif seTMemoClipBoard == 3:\n            memo.setText(str(Around(posX))+\" \"+str(Around(posY))+\" \"+str(Around(posZ)), mode = memo.Clipboard)                          # format : x y z\n\n    if switchCreatePoint == 1:\n        try:                                # create point\n            point = Draft.makePoint( posX, posY, posZ)\n            point.ViewObject.PointColor = (1.0,0.0,0.0)\n            point.Label = u\"FCPoint\" + namePlane\n            retour = Macro_FCInfo_06\n            FreeCADGui.updateGui()          # updateGui\n            App.ActiveDocument.recompute()\n        except Exception:\n            retour = Macro_FCInfo_07\n\n    if switchCreatePlane == 1:\n        try:                                # create plane\n            doc = App.activeDocument()\n            if boundBoxDiag == 0.0:\n                boundBoxDiag = 10.0\n            boundBoxLX  = boundBoxLY  = boundBoxLZ  = boundBoxDiag\n            FCSpring = doc.addObject(u\"App::DocumentObjectGroup\", \"FCPlane\" + namePlane)\n            plr = FreeCAD.Placement()\n            plr.Base = FreeCAD.Vector( posX, posY, posZ)\n\n            ### PlaneX-R\n            plan = App.ActiveDocument.addObject(\"Part::Plane\",\"PlaneX-R\")\n            plan.Length=boundBoxLZ\n            plan.Width=boundBoxLX\n            plan.Placement = plr\n            plan.Placement.Rotation = plan.Placement.Rotation.multiply(App.Rotation(0.0,-90.0,0.0))\n            plan.Placement = plan.Placement.multiply(App.Placement(App.Vector(-float(plan.Length)/2.0,-float(plan.Width)/2.0,0.0), App.Rotation(App.Vector(0.0,0.0,0.0),0.0), App.Vector(0.0,0.0,0.0)))\n\n            plan.ViewObject.LineColor = (1.0,0.66667,0.0)\n            plan.ViewObject.ShapeColor = (0.6, 0.0, 0.0)\n            plan.ViewObject.Transparency = 90\n            plan.ViewObject.LineWidth = 1.0\n            FCSpring.addObject(plan)\n\n            ### PlaneY-V\n            plan = App.ActiveDocument.addObject(\"Part::Plane\",\"PlaneY-V\")\n            plan.Length=boundBoxLY\n            plan.Width=boundBoxLZ\n            plan.Placement = plr\n            plan.Placement.Rotation = plan.Placement.Rotation.multiply(App.Rotation(0.0,0.0,90.0))\n            plan.Placement = plan.Placement.multiply(App.Placement(App.Vector(-float(plan.Length)/2.0,-float(plan.Width)/2.0,0.0), App.Rotation(App.Vector(0.0,0.0,0.0),0.0), App.Vector(0.0,0.0,0.0)))\n\n            plan.ViewObject.LineColor = (1.0, 0.66667, 0.0)\n            plan.ViewObject.ShapeColor = (0.0, 0.6, 0.0)\n            plan.ViewObject.Transparency = 90\n            plan.ViewObject.LineWidth = 1.0\n            FCSpring.addObject(plan)\n\n            ### PlaneZ-B\n            plan = App.ActiveDocument.addObject(\"Part::Plane\",\"PlaneZ-B\")\n            plan.Length=boundBoxLX\n            plan.Width=boundBoxLY\n            plan.Placement = plr\n            plan.Placement = plan.Placement.multiply(App.Placement(App.Vector(-float(plan.Length)/2.0,-float(plan.Width)/2.0,0.0), App.Rotation(App.Vector(0.0,0.0,0.0),0.0), App.Vector(0.0,0.0,0.0)))\n\n            plan.ViewObject.LineColor = (1.0,1.0,1.0)\n            plan.ViewObject.ShapeColor = (0.0,0.0,0.6)\n            plan.ViewObject.Transparency = 90\n            plan.ViewObject.LineWidth = 1.0\n            FCSpring.addObject(plan)\n\n            FreeCADGui.updateGui()          # updateGui\n            App.ActiveDocument.recompute()\n            retour = Macro_FCInfo_06\n        except Exception:\n            retour = Macro_FCInfo_07\n\n    if switchCreateAxis == 1:               # create axis\n        try:\n            doc = App.activeDocument()\n            if boundBoxDiag == 0.0:\n                boundBoxDiag = 10.0\n            boundBoxLX  = boundBoxLY  = boundBoxLZ  = boundBoxDiag\n            FCSpring = doc.addObject(\"App::DocumentObjectGroup\", \"FCAxis\" + namePlane)\n            plr = FreeCAD.Placement()\n            plr.Base = FreeCAD.Vector( posX, posY, posZ)\n\n            #create axis\n            points=[FreeCAD.Vector(0.0,0.0,0.0),FreeCAD.Vector(0.0,0.0,boundBoxLX)]\n            centerX = Draft.makeWire(points,closed=False,face=False,support=None)\n            centerX.Placement = plr\n            centerX.Placement.Rotation = centerX.Placement.Rotation.multiply(App.Rotation(0.0,90.0,0.0))\n            centerX.Placement = centerX.Placement.multiply(App.Placement(App.Vector(0.0,0.0,-float(boundBoxLX)/2.0), App.Rotation(App.Vector(0.0,0.0,0.0),0.0), App.Vector(0.0,0.0,0.0)))\n            centerX.ViewObject.LineColor = (1.0,1.0,1.0)\n            centerX.ViewObject.LineWidth = 1.0\n            centerX.ViewObject.DrawStyle = str(u\"Dashdot\")\n            centerX.Label = str(u\"Axis White PlaneX\")\n            FCSpring.addObject(centerX)\n\n            points=[FreeCAD.Vector(0.0,0.0,0.0),FreeCAD.Vector(0.0,0.0,boundBoxLX)]\n            centerY = Draft.makeWire(points,closed=False,face=False,support=None)\n            centerY.Placement = plr\n            centerY.Placement.Rotation = centerY.Placement.Rotation.multiply(App.Rotation(0.0,90.0,90.0))\n            centerY.Placement = centerY.Placement.multiply(App.Placement(App.Vector(0.0,0.0,-float(boundBoxLX)/2.0), App.Rotation(App.Vector(0.0,0.0,0.0),0.0), App.Vector(0.0,0.0,0.0)))\n            centerY.ViewObject.LineColor = (1.0,1.0,1.0)\n            centerY.ViewObject.LineWidth = 1.0\n            centerY.ViewObject.DrawStyle = str(u\"Dashdot\")\n            centerY.Label = str(u\"Axis White PlaneY\")\n            FCSpring.addObject(centerY)\n\n            points=[FreeCAD.Vector(0.0,0.0,0.0),FreeCAD.Vector(0.0,0.0,boundBoxLX)]\n            centerZ = Draft.makeWire(points,closed=False,face=False,support=None)\n            centerZ.Placement = plr\n            centerZ.Placement.Rotation = centerZ.Placement.Rotation.multiply(App.Rotation(0,0,0))\n            centerZ.Placement = centerZ.Placement.multiply(App.Placement(App.Vector(0.0,0.0,-float(boundBoxLX)/2.0), App.Rotation(App.Vector(0.0,0.0,0.0),0.0), App.Vector(0.0,0.0,0.0)))\n            centerZ.ViewObject.LineColor = (1.0,1.0,1.0)\n            centerZ.ViewObject.LineWidth = 1.0\n            centerZ.ViewObject.DrawStyle = str(u\"Dashdot\")\n            centerZ.Label = str(u\"Axis White PlaneZ\")\n            FCSpring.addObject(centerZ)\n\n            FreeCADGui.updateGui()          # updateGui\n            App.ActiveDocument.recompute()\n            retour = Macro_FCInfo_06\n        except Exception:\n            retour = Macro_FCInfo_07\n\n    try:\n        Gui.Selection.addSelection(App.ActiveDocument.getObject(object_Name))\n    except Exception:\n        None\n\n    #FreeCAD.ActiveDocument.commitTransaction()         # restore les actions  (avec annuler restore)\n    #FreeCAD.ActiveDocument.abortTransaction()          # abandonne les actions(avec annuler restore)\n    FreeCADGui.updateGui()          # updateGui\n    switchInertia = 0\n    return retour\n\ndef tableau():\n    global sel\n    global subElemName\n    global perimetre\n    global numberEdges\n    global Vertx\n    global Edges\n    global EdgesLong\n    global Faces\n    global FacesSurf\n    global FacesCoor\n    global compt_E\n    global compt_F\n    global compt_VF\n    global RowCountTest\n\n    global angleX1\n    global angleY1\n    global angleZ1\n    global angleX2\n    global angleY2\n    global angleZ2\n\n    if len(sel) != 0:\n        Vertx=[]\n        Edges=[]\n        Faces=[]\n        compt_E   = 0\n        compt_F   = 0\n        compt_VF  = 0\n        perimetre = 0.0\n        EdgesLong = []\n        angleX1   = 0.0\n        angleY1   = 0.0\n        angleZ1   = 0.0\n        angleX2   = 0.0\n        angleY2   = 0.0\n        angleZ2   = 0.0\n\n        numberEdges = len(sel[0].Shape.Edges)\n        for j in enumerate(sel[0].Shape.Edges):                         # search Edges\n            compt_E+=1\n            Edges.append(\"Edge%d\" % (j[0]+1))\n            EdgesLong.append(str(sel[0].Shape.Edges[compt_E-1].Length))\n            perimetre += (sel[0].Shape.Edges[compt_E-1].Length)\n            a = sel[0].Shape.Edges[compt_E-1].Vertexes[0]\n            Vertx.append(u\"X1: \"+str(a.Point.x))\n            Vertx.append(u\"Y1: \"+str(a.Point.y))\n            Vertx.append(u\"Z1: \"+str(a.Point.z))\n            try:\n                a = sel[0].Shape.Edges[compt_E-1].Vertexes[1]           # search Vertexes Edges\n                Vertx.append(u\"X2: \"+str(a.Point.x))\n                Vertx.append(u\"Y2: \"+str(a.Point.y))\n                Vertx.append(u\"Z2: \"+str(a.Point.z))\n            except Exception:\n                Vertx.append(u\"-\")\n                Vertx.append(u\"-\")\n                Vertx.append(u\"-\")\n\n        FacesSurf = []\n        FacesCoor = []\n        for j in enumerate(sel[0].Shape.Faces):                         # search Faces\n            compt_F+=1\n            Faces.append(u\"Face%d\" % (j[0]+1))\n            FacesSurf.append(str(sel[0].Shape.Faces[compt_F-1].Area))\n            fco = 0\n            for f0 in sel[0].Shape.Faces[compt_F-1].Vertexes:           # search Vertexes face\n                fco += 1\n                FacesCoor.append(u\"X\"+str(fco)+\": \"+str(f0.Point.x))\n                FacesCoor.append(u\"Y\"+str(fco)+\": \"+str(f0.Point.y))\n                FacesCoor.append(u\"Z\"+str(fco)+\": \"+str(f0.Point.z))\n                compt_VF += 1\n            FacesCoor += (u\"T\",)\n\n        RowCountTest = compt_E + compt_F + compt_VF\n\n# encoder 3 couleurs et transparence renvoye la valeur (unsigned pour Preferences FC)\ndef unsignedEncode(red = 0, green = 0, blue = 0, transparent = 1): # \n    #(255 *256*256*256 ) + (85 *256*256) + (51 *256) +(1*255) = 4283773951\n    red   = int(red*255)\n    green = int(green*255)\n    blue  = int(blue*255)\n    transparent = int(transparent*255)\n    value = int((red*pow(256,3)) + (green*pow(256,2)) + (blue*pow(256,1)) + (transparent*pow(256,0)))\n    return value\n\n# converti decimal en hexadecimal\ndef decimalTohexa(decimal = 0):\n    # 5 = \"05\"\n    hexa = str(hex(int(decimal)))[2:4]\n    if len(hexa) == 1:\n        hexa = \"0\" + hexa\n    return hexa\n\ndef affect(passTableau):\n        global ui\n        global sel\n        global document_\n        global object_Label\n        global object_Name\n        global typeObject\n        global object_Type\n        global subElemName\n        global RotationToEuler \n        global position0\n        global position1\n        global position2\n\n        global diffuseColorRF\n        global diffuseColorVF\n        global diffuseColorBF\n        global diffuseColorTF\n        global transparenceFace\n        global unsignedEncodeColor\n        global cols\n        global colorShapeFace\n        global colorShapeLine\n        global colorShapePoint\n        global BsplineRayonApproximatif\n\n        global longueurObjet\n        global rayonObjet\n        global perimetre\n        global numberEdges\n        global nombreArretesMesh\n        global nombreFacesMesh\n        global nombrePointsMesh\n\n        global Plan_xy\n        global Plan_xy_V\n        global Plan_yz\n        global Plan_yz_V\n        global Plan_zx\n        global Plan_zx_V\n\n        global surface\n        global surfaceFace\n        global volume_\n        global seTDensiteValue\n        global poids\n        global uniteM\n        global uniteMs\n        global uniteS\n        global uniteSs\n        global uniteV\n        global uniteVs\n        global uniteP\n        global unitePs\n        global uniteAs\n\n        global boundBox_\n        global boundBoxLX\n        global boundBoxLY\n        global boundBoxLZ\n        global boundBox_S\n        global BDvol\n\n        global adaptWithBody\n        global boundBoxCenterX\n        global boundBoxCenterY\n        global boundBoxCenterZ\n        global boundBoxDiag\n        global boundBoxXMin\n        global boundBoxYMin\n        global boundBoxZMin\n\n        global CenterOfMassX\n        global CenterOfMassY\n        global CenterOfMassZ\n        global massOrGravity\n\n        global MatrixX1\n        global MatrixY1\n        global MatrixZ1\n        global Matrix_1\n\n        global MatrixX2\n        global MatrixY2\n        global MatrixZ2\n        global Matrix_2\n\n        global MatrixX3\n        global MatrixY3\n        global MatrixZ3\n        global Matrix_3\n\n        global Matrix12\n        global Matrix13\n        global Matrix14\n        global Matrix15\n        global DeterminantM\n\n        global FacesSurf\n        global EdgesLong\n        global FacesCoor\n\n        global angleX1\n        global angleY1\n        global angleZ1\n        global angleX2\n        global angleY2\n        global angleZ2\n        global directionObj\n        global direcValueAt\n        global direcNormalAt\n        global typeNormalAt\n\n        global switchDisplayInfoObject\n\n        global MatrixOfInertiaRaw\n        global MatrixX1_16\n        global MatrixY1_16\n        global MatrixZ1_16\n        global MatrixX2_16\n        global MatrixY2_16\n        global MatrixZ2_16\n        global MatrixX3_16\n        global MatrixY3_16\n        global MatrixZ3_16\n\n        global MatrixX1_17\n        global MatrixY1_17\n        global MatrixZ1_17\n        global MatrixX2_17\n        global MatrixY2_17\n        global MatrixZ2_17\n        global MatrixX3_17\n        global MatrixY3_17\n        global MatrixZ3_17\n        global refreshMatrix\n\n        global typeLongueur\n        global BsplineDetect\n        global BsplineNombreDeNoeuds\n        global BsplinePointsCoor\n        global BsplineArcsRadius\n        global BsplineArcsLocation\n        global switchBSplineCreateCircleConstructorAxis\n        global switchBSplineCreateCircleConstructor\n        global setBSplineToByArcValue\n        global BsplineCercleToolTip\n        global BsplineNumberElement\n        global BsplineCutLength\n        global BSplinetoByArcValeurS\n        global colorShapeFaceDiffuseColor\n        global detected\n        global indexFaceMesh\n        global coordPointsMesh\n\n        detected = \"\"\n        try:\n            atest = sel[0].Shape.Vertexes\n        except Exception:\n            ####################\n            selEx = FreeCADGui.Selection.getSelectionEx()\n            objs  = [selobj.Object for selobj in selEx]\n\n            if len(objs) >= 1:\n                ui.on_ZeroInfo()    # zero 25-07-2023\n\n                if hasattr(objs[0],    \"Shape\"):\n                    colorShapeFace = colorShapeLine = colorShapePoint = colorShapeFaceDiffuseColor = []\n                    s = objs[0].Shape\n\n                elif hasattr(objs[0],   \"Mesh\"):\n                    ##https://wiki.freecadweb.org/Mesh_API\n                    originalObject = objs[0]\n                    s = objs[0].Mesh                    # object mesh\n                    sel = Gui.Selection.getSelection()  # object\n                    originalObject  = sel[0]            # object\n                    colorShapeFace = colorShapeLine = colorShapePoint = colorShapeFaceDiffuseColor = []\n                    colorShapeFace = sel[0].ViewObject.ShapeColor\n                    colorShapeLine = sel[0].ViewObject.LineColor\n                    ##colorShapePoint = sel[0].ViewObject.PointColor\n                    detected = str(s)\n                    cols = colors = []\n                    cols = sel[0].ViewObject.ShapeColor\n                    diffuseColorRF = cols[0]\n                    diffuseColorVF = cols[1]\n                    diffuseColorBF = cols[2]\n                    diffuseColorTF = float(transparenceFace) / 100.0\n                    transparenceFace = FreeCAD.ActiveDocument.getObject(sel[0].Name).ViewObject.Transparency\n                    # unsignedEncodeColor decimal pour FC\n                    unsignedEncodeColor = '\"' + str(unsignedEncode((diffuseColorRF), (diffuseColorVF), (diffuseColorBF), 0.0)) + '\"'\n                    diffuseColorHexa    = '\"' + \"#\"  + decimalTohexa(int(diffuseColorRF*255.0)) + decimalTohexa(int(diffuseColorVF*255.0)) + decimalTohexa(int(diffuseColorBF*255.0)) + '\"'\n                    diffuseColorHexaPy  = '\"' + \"0x\" + decimalTohexa(int(diffuseColorRF*255.0)) + decimalTohexa(int(diffuseColorVF*255.0)) + decimalTohexa(int(diffuseColorBF*255.0)) + '\"'\n                    diffuseColorRVB     = '\"' + str(int(diffuseColorRF*255.0)) + \",\" + str(int(diffuseColorVF*255.0)) + \",\" + str(int(diffuseColorBF*255.0)) + '\"'\n                    diffuseColorFloat   = '\"' + \"(\" + str(Around(diffuseColorRF)) + \",\" + str(Around(diffuseColorVF)) + \",\" + str(Around(diffuseColorBF)) + \")\" + '\"'\n                    #\n                    unsignedEncodeColor = unsignedEncodeColor + \" , \" + diffuseColorHexa + \" , \" + diffuseColorHexaPy + \" , \" + diffuseColorRVB + \" , \" + diffuseColorFloat\n\n                    object_Label = sel[0].Label\n                    object_Name  = sel[0].Name\n                    object_Type  = sel[0].TypeId\n                    typeObject   = sel[0].Module\n\n                    boundBox_ = s.BoundBox\n                    boundBoxLX = boundBox_.XLength\n                    boundBoxLY = boundBox_.YLength\n                    boundBoxLZ = boundBox_.ZLength\n                    boundBoxDiag = boundBox_.DiagonalLength\n                    boundBox_S = \"[X: \"+str(Around(boundBoxLX * uniteM))+\" \"+uniteMs+\"] x [Y: \"+str(Around(boundBoxLY * uniteM))+\" \"+uniteMs+\"] x [Z: \"+str(Around(boundBoxLZ * uniteM))+\" \"+uniteMs+\"] Diagonal: \" + str(Around(boundBoxDiag * uniteM))+\" \"+uniteMs\n                    ####\n                    boundBoxLocation = App.Vector(boundBox_.Center[0], boundBox_.Center[1], boundBox_.Center[2])\n                    BDvol = adjustedGlobalPlacement(sel[0], boundBoxLocation)\n                    boundBoxCenterX = BDvol.Base[0] \n                    boundBoxCenterY = BDvol.Base[1] \n                    boundBoxCenterZ = BDvol.Base[2] \n                    ####\n                    surface = s.Area\n                    surfaceFace = s.Facets[indexFaceMesh].Area\n                    coordPointsMesh = s.Facets[indexFaceMesh].Points\n\n###################################### mesh later\n#                    x=0\n#                    for i in s.Facets:\n#                        print(str(Around(i.Area * uniteM )) + uniteMs)\n#                        print(str((i.getEdge(0) )))\n#                        print(str((i.getEdge(0).Points)))\n#                        print(str(i.Points))\n#                        print(\"____________________________________________\")\n#                        x += 1\n#                        if x >= 10 : break\n######################################\n\n                    try:                                # no in version 018\n                        length0 = s.Facets[indexFaceMesh].getEdge(0).Length\n                        length1 = s.Facets[indexFaceMesh].getEdge(1).Length\n                        length2 = s.Facets[indexFaceMesh].getEdge(2).Length\n                    except Exception:\n                        length0 = length1 = length2 = 0.0\n\n                    longueurObjet = length0 + length1 + length2\n                    typeLongueur = u\"Perimeter of face\"\n\n                    if switchCreateLineDiVatNatOnClick == 0:\n                        typeNormalAt = u\"Normal_____\"\n                    else:\n                        typeNormalAt = u\"*Normal_____\"\n\n                    direcNormalAt = s.Facets[indexFaceMesh].Normal\n                    volume_ = s.Volume\n                    # poids\n                    poids = ((volume_ * seTDensiteValue) * uniteP) / 1000.0   # mm3   (mm base  FreeCAD)\n\n                    CenterOfMassX = s.CenterOfGravity[0]\n                    CenterOfMassY = s.CenterOfGravity[1]\n                    CenterOfMassZ = s.CenterOfGravity[2]\n\n                    subElemName = \"Face\" + str(indexFaceMesh)\n                    DeterminantM = 0.0\n\n                    nombreFacesMesh   = s.CountFacets\n                    nombrePointsMesh  = s.CountPoints\n                    try:                                # no in version 018\n                        nombreArretesMesh = s.CountEdges\n                    except Exception:\n                        nombreArretesMesh = 0\n\n                    #print(s.Topology)\n                    \n                elif hasattr(objs[0], \"Points\"):\n                    s = objs[0].Points\n                    #sel = Gui.Selection.getSelection()\n                    detected = str(s)\n                    sel = Gui.Selection.getSelection()\n                    cols = colors = []\n                    colorShapeFace = colorShapeLine = colorShapePoint = colorShapeFaceDiffuseColor = []\n                    cols = FreeCAD.ActiveDocument.getObject(sel[0].Name).ViewObject.ShapeColor\n                    diffuseColorRF = cols[0]\n                    diffuseColorVF = cols[1]\n                    diffuseColorBF = cols[2]\n                    diffuseColorTF = float(transparenceFace) / 100.0\n                    transparenceFace = FreeCAD.ActiveDocument.getObject(sel[0].Name).ViewObject.Transparency\n                    # unsignedEncodeColor decimal pour FC\n                    unsignedEncodeColor = '\"' + str(unsignedEncode((diffuseColorRF), (diffuseColorVF), (diffuseColorBF), 0.0)) + '\"'\n                    diffuseColorHexa    = '\"' + \"#\"  + decimalTohexa(int(diffuseColorRF*255.0)) + decimalTohexa(int(diffuseColorVF*255.0)) + decimalTohexa(int(diffuseColorBF*255.0)) + '\"'\n                    diffuseColorHexaPy  = '\"' + \"0x\" + decimalTohexa(int(diffuseColorRF*255.0)) + decimalTohexa(int(diffuseColorVF*255.0)) + decimalTohexa(int(diffuseColorBF*255.0)) + '\"'\n                    diffuseColorRVB     = '\"' + str(int(diffuseColorRF*255.0)) + \",\" + str(int(diffuseColorVF*255.0)) + \",\" + str(int(diffuseColorBF*255.0)) + '\"'\n                    diffuseColorFloat   = '\"' + \"(\" + str(Around(diffuseColorRF)) + \",\" + str(Around(diffuseColorVF)) + \",\" + str(Around(diffuseColorBF)) + \")\" + '\"'\n                    #\n                    unsignedEncodeColor = unsignedEncodeColor + \" , \" + diffuseColorHexa + \" , \" + diffuseColorHexaPy + \" , \" + diffuseColorRVB + \" , \" + diffuseColorFloat\n\n                    object_Label = sel[0].Label\n                    object_Name  = sel[0].Name\n                    object_Type  = sel[0].TypeId\n                    typeObject   = sel[0].Module\n\n                    nombrePointsMesh  = s.CountPoints\n\n                    boundBox_ = s.BoundBox\n                    boundBoxLX = boundBox_.XLength\n                    boundBoxLY = boundBox_.YLength\n                    boundBoxLZ = boundBox_.ZLength\n                    try:\n                        boundBoxDiag = boundBox_.DiagonalLength\n                    except Exception:\n                        boundBoxDiag = 0.0\n                    boundBox_S = \"[X: \"+str(Around(boundBoxLX * uniteM))+\" \"+uniteMs+\"] x [Y: \"+str(Around(boundBoxLY * uniteM))+\" \"+uniteMs+\"] x [Z: \"+str(Around(boundBoxLZ * uniteM))+\" \"+uniteMs+\"] Diagonal: \" + str(Around(boundBoxDiag * uniteM))+\" \"+uniteMs\n                    #### correction\n                    boundBoxLocation = App.Vector(boundBox_.Center[0], boundBox_.Center[1], boundBox_.Center[2])\n                    BDvol = adjustedGlobalPlacement(sel[0], boundBoxLocation)\n                    ####\n                    boundBoxCenterX = BDvol.Base[0] \n                    boundBoxCenterY = BDvol.Base[1] \n                    boundBoxCenterZ = BDvol.Base[2] \n                    CenterOfMassX = CenterOfMassY = CenterOfMassZ = 0.0\n\n                #### Fem debut\n                elif sel[0].isDerivedFrom(\"Fem::FemPostWarpVectorFilter\"):      # same sel[0].TypeId\n                    detected = \"FemPostWarpVectorFilter\"\n                    object_Label = sel[0].Label\n                    object_Name  = sel[0].Name\n                    object_Type  = sel[0].TypeId\n                    typeObject   = sel[0].Module\n                    boundBox_ = sel[0].ViewObject.getBoundingBox()\n                    boundBoxLX = boundBox_.XLength\n                    boundBoxLY = boundBox_.YLength\n                    boundBoxLZ = boundBox_.ZLength\n                    try:\n                        boundBoxDiag = boundBox_.DiagonalLength\n                    except Exception:\n                        boundBoxDiag = 0.0\n                    boundBox_S = \"[X: \"+str(Around(boundBoxLX * uniteM))+\" \"+uniteMs+\"] x [Y: \"+str(Around(boundBoxLY * uniteM))+\" \"+uniteMs+\"] x [Z: \"+str(Around(boundBoxLZ * uniteM))+\" \"+uniteMs+\"] Diagonal: \" + str(Around(boundBoxDiag * uniteM))+\" \"+uniteMs\n                    #### correction\n                    boundBoxLocation = App.Vector(boundBox_.Center[0], boundBox_.Center[1], boundBox_.Center[2])\n                    BDvol = adjustedGlobalPlacement(sel[0], boundBoxLocation)\n                    ####\n                    boundBoxCenterX = BDvol.Base[0] \n                    boundBoxCenterY = BDvol.Base[1] \n                    boundBoxCenterZ = BDvol.Base[2] \n                    CenterOfMassX = CenterOfMassY = CenterOfMassZ = 0.0\n                #### Fem fin ##################\n\n            else:\n                App_Console_PrintMessage(u\"Invalid selection \" + \"\\n\")\n                errorDialog(u\"Invalid selection \" + \"\\n\" + detected )\n                sel = selEx = \"\"\n\n        else:\n            sel = FreeCADGui.Selection.getSelection()\n            mydoc = FreeCAD.activeDocument().Name\n            document_ = mydoc\n\n            try:\n                object_Type += \" / \" + sel[0].TypeId\n                object_Type = sel[0].Shape.TypeId\n            except Exception:\n                object_Type = \"?\"\n\n            try:\n                object_Label = sel[0].Label\n                object_Name  = sel[0].Name\n            except Exception:\n                object_Label = \"\"\n                object_Name  = \"\"\n\n            try:\n                SubElement  = FreeCADGui.Selection.getSelectionEx()\n                subElemName = SubElement[0].SubElementNames[0]\n            except Exception:\n                subElemName = \"\"\n\n            #### sketcher begin ####\n            ##\n            ##https://forum.freecadweb.org/viewtopic.php?f=22&t=53127\n            ##How to select edges inside of Sketcher?\n            ##\n            sketch  = Gui.Selection.getSelection()[0]\n            App.ActiveDocument.recompute()\n            if (Gui.ActiveDocument.getInEdit() and (sketch.TypeId == \"Sketcher::SketchObject\")) and (\"Constraint\" not in subElemName): # sketcher open\n                try:\n                    longueurObjet = rayonObjet = points1 = points2 = 0.0\n                    directionObj = direcValueAt = direcNormalAt = \"\"\n                    typeLongueur = RotationToEuler = \"\"\n\n                    nameSketch = sketch.Name\n                    sketch0    = Gui.Selection.getSelectionEx()[0]\n                    subElemName     = sketch0.SubElementNames[0]\n                    RotationToEuler = sketch.Placement.Rotation.toEuler()  # Plan (Direction)\n                    indexSubObject  = int(subElemName[4:]) - 1             # index\n                    sObject = App.ActiveDocument.getObject(nameSketch).Geometry[indexSubObject]\n                    typeObject = sketch.TypeId\n\n                    if isinstance(sObject,(Part.LineSegment)):\n                        #print(\"Part.LineSegment\")\n                        points1 = sObject.StartPoint\n                        points2 = sObject.EndPoint\n                        longueurObjet = sObject.length()\n                        typeLongueur = u\"Length (Sk) \"\n                        directionObj = points2.sub(points1)\n\n                    elif isinstance(sObject,(Part.BSplineCurve)):\n                        #print(\"Part.BSplineCurve\")\n                        points1 = sObject.StartPoint\n                        points2 = sObject.EndPoint\n                        longueurObjet = sObject.length()\n                        typeLongueur = u\"Length (Sk) \"\n                        directionObj = points2.sub(points1)\n\n                    elif isinstance(sObject,(Part.Circle)):\n                        #print(\"Part.Circle\")\n                        longueurObjet = sObject.length()\n                        typeLongueur = u\"Length (Sk) \"\n                        rayonObjet = sObject.Radius\n\n                    elif isinstance(sObject,(Part.ArcOfCircle)):\n                        #print(\"Part.ArcOfCircle\")\n                        points1 = sObject.StartPoint\n                        points2 = sObject.EndPoint\n                        longueurObjet = sObject.length()\n                        typeLongueur = u\"Length (Sk) \"\n                        rayonObjet = sObject.Radius\n                        directionObj = points2.sub(points1)\n                    else:\n                        None\n                    ####\n                    # angles\n                    if isinstance(sObject,(Part.Circle)) == False:\n                        try:\n                            angleX1 = points1.x; angleY1 = points1.y; angleZ1 = points1.z\n                            angleX2 = points2.x; angleY2 = points2.y; angleZ2 = points2.z\n                        except Exception:\n                            angleX1 = angleY1 = angleZ1 = 0.0\n                            angleX2 = angleY2 = angleZ2 = 0.0\n\n                        modeTypeAngle = 1    # 1 = degrees other = radians\n                        try:\n                            Plan_xy   = Around(angle2(angleX1, angleY1, angleX2, angleY2, modeTypeAngle))\n                            Plan_xy_V = \"[,\"+str(Around(angleX1))+\" , \"+str(Around(angleY1))+\",]  [,\"+str(Around(angleX2))+\" , \"+str(Around(angleY2))+\",]\"\n                        except Exception:\n                            Plan_xy = 0.0; Plan_xy_V = \"\"\n                        try:\n                            Plan_yz   = Around(angle2(angleY1, angleZ1, angleY2, angleZ2, modeTypeAngle))\n                            Plan_yz_V = \"[,\"+str(Around(angleY1))+\" , \"+str(Around(angleZ1))+\",]  [,\"+str(Around(angleY2))+\" , \"+str(Around(angleZ2))+\",]\"\n                        except Exception:\n                            Plan_yz   = 0.0; Plan_yz_V   = \"\"\n                        try:\n                            Plan_zx   = Around(angle2(angleZ1, angleX1, angleZ2, angleX2, modeTypeAngle))\n                            Plan_zx_V = \"[,\"+str(Around(angleZ1))+\" , \"+str(Around(angleX1))+\",]  [,\"+str(Around(angleZ2))+\" , \"+str(Around(angleX2))+\",]\"\n                        except Exception:\n                            Plan_zx   = 0.0; Plan_zx_V = \"\"\n                except Exception:\n                    None\n            ##\n            #### sketcher end  ####\n\n            else:\n                # colors (DiffuseColor)\n                try:\n                    #### search color face selected\n                    a = FreeCADGui.Selection.getSelectionEx()    # selection sous objet\n                    aa = FreeCADGui.Selection.getSelection()     # selection objet\n                    colorShapeFace = colorShapeLine = colorShapePoint = colorShapeFaceDiffuseColor = []\n                    colorShapeFace  = aa[0].ViewObject.ShapeColor\n                    colorShapeLine  = aa[0].ViewObject.LineColor\n                    colorShapePoint = aa[0].ViewObject.PointColor\n\n                    diffuseColorRF  = diffuseColorVF = diffuseColorBF = diffuseColorTF = 0.0\n                    transparenceFace = 0\n                    cols = colors = []\n\n                    if str(Gui.Selection.getSelectionEx()[0].SubObjects[0])[1:5] == \"Face\":\n                        cols = colors = []\n                        cols = FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.DiffuseColor\n                        if len(cols) == 1:\n                            for i in aa[0].Shape.Faces:\n                                colors += [(cols[0])]\n                            cols = colors\n                        else:\n                            colors = cols\n                        fce = int(a[0].SubElementNames[0][4:])-1\n                        indexFaceMesh  = fce\n                        colorShapeFaceDiffuseColor = colors #[fce]\n                        diffuseColorRF = colors[fce][0]\n                        diffuseColorVF = colors[fce][1]\n                        diffuseColorBF = colors[fce][2]\n                        diffuseColorTF = colors[fce][3]\n                        transparenceFace = math.ceil(round(cols[fce][3]*100, 12))\n                        # unsignedEncodeColor decimal pour FC\n                        unsignedEncodeColor = '\"' + str(unsignedEncode((diffuseColorRF), (diffuseColorVF), (diffuseColorBF), 1.0)) + '\"'\n                        diffuseColorHexa    = '\"' + \"#\"  + decimalTohexa(int(diffuseColorRF*255.0)) + decimalTohexa(int(diffuseColorVF*255.0)) + decimalTohexa(int(diffuseColorBF*255.0)) + '\"'\n                        diffuseColorHexaPy  = '\"' + \"0x\" + decimalTohexa(int(diffuseColorRF*255.0)) + decimalTohexa(int(diffuseColorVF*255.0)) + decimalTohexa(int(diffuseColorBF*255.0)) + '\"'\n                        diffuseColorRVB     = '\"' + str(int(diffuseColorRF*255.0)) + \",\" + str(int(diffuseColorVF*255.0)) + \",\" + str(int(diffuseColorBF*255.0)) + '\"'\n                        diffuseColorFloat   = '\"' + \"(\" + str(Around(diffuseColorRF)) + \",\" + str(Around(diffuseColorVF)) + \",\" + str(Around(diffuseColorBF)) + \")\" + '\"'\n                        #\n                        unsignedEncodeColor = unsignedEncodeColor + \" , \" + diffuseColorHexa + \" , \" + diffuseColorHexaPy + \" , \" + diffuseColorRVB + \" , \" + diffuseColorFloat\n                    elif str(Gui.Selection.getSelectionEx()[0].SubObjects[0])[1:5] == \"Edge\":\n                        cols = FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.LineColor\n                        diffuseColorRF = cols[0]\n                        diffuseColorVF = cols[1]\n                        diffuseColorBF = cols[2]\n                        diffuseColorTF = 0.0\n                        transparenceFace =  FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.Transparency\n                        # unsignedEncodeColor decimal pour FC\n                        unsignedEncodeColor = '\"' + str(unsignedEncode((diffuseColorRF), (diffuseColorVF), (diffuseColorBF), 0.0)) + '\"'\n                        diffuseColorHexa    = '\"' + \"#\"  + decimalTohexa(int(diffuseColorRF*255.0)) + decimalTohexa(int(diffuseColorVF*255.0)) + decimalTohexa(int(diffuseColorBF*255.0)) + '\"'\n                        diffuseColorHexaPy  = '\"' + \"0x\" + decimalTohexa(int(diffuseColorRF*255.0)) + decimalTohexa(int(diffuseColorVF*255.0)) + decimalTohexa(int(diffuseColorBF*255.0)) + '\"'\n                        diffuseColorRVB     = '\"' + str(int(diffuseColorRF*255.0)) + \",\" + str(int(diffuseColorVF*255.0)) + \",\" + str(int(diffuseColorBF*255.0)) + '\"'\n                        diffuseColorFloat   = '\"' + \"(\" + str(Around(diffuseColorRF)) + \",\" + str(Around(diffuseColorVF)) + \",\" + str(Around(diffuseColorBF)) + \")\" + '\"'\n                        #\n                        unsignedEncodeColor = unsignedEncodeColor + \" , \" + diffuseColorHexa + \" , \" + diffuseColorHexaPy + \" , \" + diffuseColorRVB + \" , \" + diffuseColorFloat\n                    elif str(Gui.Selection.getSelectionEx()[0].SubObjects[0])[1:7] == \"Vertex\":\n                        cols = FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.PointColor\n                        diffuseColorRF = cols[0]\n                        diffuseColorVF = cols[1]\n                        diffuseColorBF = cols[2]\n                        diffuseColorTF = 0.0\n                        transparenceFace = FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.Transparency\n                        # unsignedEncodeColor decimal pour FC\n                        unsignedEncodeColor = '\"' + str(unsignedEncode((diffuseColorRF), (diffuseColorVF), (diffuseColorBF), 0.0)) + '\"'\n                        diffuseColorHexa    = '\"' + \"#\"  + decimalTohexa(int(diffuseColorRF*255.0)) + decimalTohexa(int(diffuseColorVF*255.0)) + decimalTohexa(int(diffuseColorBF*255.0)) + '\"'\n                        diffuseColorHexaPy  = '\"' + \"0x\" + decimalTohexa(int(diffuseColorRF*255.0)) + decimalTohexa(int(diffuseColorVF*255.0)) + decimalTohexa(int(diffuseColorBF*255.0)) + '\"'\n                        diffuseColorRVB     = '\"' + str(int(diffuseColorRF*255.0)) + \",\" + str(int(diffuseColorVF*255.0)) + \",\" + str(int(diffuseColorBF*255.0)) + '\"'\n                        diffuseColorFloat   = '\"' + \"(\" + str(Around(diffuseColorRF)) + \",\" + str(Around(diffuseColorVF)) + \",\" + str(Around(diffuseColorBF)) + \")\" + '\"'\n                        #\n                        unsignedEncodeColor = unsignedEncodeColor + \" , \" + diffuseColorHexa + \" , \" + diffuseColorHexaPy + \" , \" + diffuseColorRVB + \" , \" + diffuseColorFloat\n                    else:\n                        unsignedEncodeColor = unsignedEncodeColor = diffuseColorHexa = diffuseColorHexaPy = diffuseColorRVB = \"\"\n                        diffuseColorRF = 0.0; diffuseColorVF = 0.0; diffuseColorBF = 0.0; diffuseColorTF = 0.0; unsignedEncodeColor = \"\"\n                except Exception:\n                    if str(aa) == \"[<Part::Part2DObject>]\": # (triangle) une Face du Mesh\n                        colorShapeFace = colorShapeLine = colorShapePoint = colorShapeFaceDiffuseColor = []\n                        colorShapeFace  = FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.ShapeColor\n                        cols = FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.LineColor\n                        diffuseColorRF = cols[0]\n                        diffuseColorVF = cols[1]\n                        diffuseColorBF = cols[2]\n                        diffuseColorTF = 0.0\n                        transparenceFace =  FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.Transparency\n                        # unsignedEncodeColor decimal pour FC\n                        unsignedEncodeColor = '\"' + str(unsignedEncode((diffuseColorRF), (diffuseColorVF), (diffuseColorBF), 0.0)) + '\"'\n                        diffuseColorHexa    = '\"' + \"#\"  + decimalTohexa(int(diffuseColorRF*255.0)) + decimalTohexa(int(diffuseColorVF*255.0)) + decimalTohexa(int(diffuseColorBF*255.0)) + '\"'\n                        diffuseColorHexaPy  = '\"' + \"0x\" + decimalTohexa(int(diffuseColorRF*255.0)) + decimalTohexa(int(diffuseColorVF*255.0)) + decimalTohexa(int(diffuseColorBF*255.0)) + '\"'\n                        diffuseColorRVB     = '\"' + str(int(diffuseColorRF*255.0)) + \",\" + str(int(diffuseColorVF*255.0)) + \",\" + str(int(diffuseColorBF*255.0)) + '\"'\n                        diffuseColorFloat   = '\"' + \"(\" + str(Around(diffuseColorRF)) + \",\" + str(Around(diffuseColorVF)) + \",\" + str(Around(diffuseColorBF)) + \")\" + '\"'\n                        #\n                        unsignedEncodeColor = unsignedEncodeColor + \" , \" + diffuseColorHexa + \" , \" + diffuseColorHexaPy + \" , \" + diffuseColorRVB + \" , \" + diffuseColorFloat\n                    else:\n                        unsignedEncodeColor = unsignedEncodeColor = diffuseColorHexa = diffuseColorHexaPy = diffuseColorRVB = \"\"\n                        diffuseColorRF = 0.0; diffuseColorVF = 0.0; diffuseColorBF = 0.0; diffuseColorTF = 0.0; unsignedEncodeColor = \"\"\n\n                # Shape\n                # longueur Objet\n                try:\n                    longueurObjet = Gui.Selection.getSelectionEx()[0].SubObjects[0].Length\n                    if str(Gui.Selection.getSelectionEx()[0].SubObjects[0])[1:5] == \"Face\":\n                        typeLongueur = u\"Perimeter of the face\"\n                    else:\n                        typeLongueur = u\"Length of the object\"\n                except Exception:\n                    longueurObjet = 0.0\n                    typeLongueur = u\"Length of the object\"\n\n########################\n#\n#        if (str(s.Curve)[1:5]) == \"Line\" :\n#                FreeCAD.Console.PrintMessage( \"4The Object is a Line!\\n\")\n#\n############################\n                # rayon Objet cas cercle et Bspline Begin\n                BsplineDetect = \"\"\n                BsplinePointsCoor = []\n                rayonObjet = 0.0\n\n                try:\n                    BsplineDetect = str(Gui.Selection.getSelectionEx()[0].SubObjects[0].Curve) #\"<BSplineCurve object>\"\n                except Exception: BsplineDetect = \"\"\n\n                # surface Face Radius (surveiller la position !!)\n                try:\n                    rayonObjet = Gui.Selection.getSelectionEx()[0].SubObjects[0].Surface.Radius\n                except Exception:\n                    rayonObjet = 0.0\n                    try:\n                        rayonObjet = Gui.Selection.getSelectionEx()[0].SubObjects[0].Curve.Radius\n                        BsplineDetect = \"\"\n                        BsplineArcsRadius = []\n                    except Exception:\n#                    try:\n                        if str(BsplineDetect) == \"<BSplineCurve object>\" :\n                            BsplineDetect = Gui.Selection.getSelectionEx()[0].SubObjects[0].Curve\n                            BsplineNombreDeNoeuds = BsplineDetect.NbKnots\n                            #### toBiArcs\n                            BsplineArcsToBiArcs  = BsplineDetect.toBiArcs(setBSplineToByArcValue)\n                            BsplineNumberElement = len(BsplineArcsToBiArcs)\n                            BsplineArcsRadius    = []\n\n                            for i in BsplineArcsToBiArcs:              # radius on point \"toBiArcs(0.00001)\"\n                                try:\n                                    BsplineArcsRadius.append(i.Radius) # .Axis  , Vector (-0.7265381966759821, 0.49597386656536946, -0.4755545946103446)\n                                                           # .Location (center) , Vector (47.192438328074296, -12.532928959782193, -85.17027221104478)\n                                                           # .Circle            , Circle (Radius : 390.516, Position : (47.1924, -12.5329, -85.1703), Direction : (-0.726538, 0.495974, -0.475555))\n                                                           # .Radius            , 390.51645180669107\n                                                           #ArcOfCircle (Radius : 90.2998, Position : (-123.212, -33.0236, 153.798), Direction : (-0.726538, 0.495974, -0.475555), Parameter : (3.37639, 3.38484))\n                                    rayonObjet = BsplineArcsRadius[0]\n                                except Exception:\n                                    BsplineArcsRadius = []\n                                    rayonObjet = 0.0\n\n                            #### for create points and circle creators of the BSpline\n                            if (switchBSplineCreateCircleConstructorAxis == 1) or ( switchBSplineCreateCircleConstructor == 1):\n                                try:\n                                    BsplineArcsLocation  = []\n                                    for i in BsplineArcsToBiArcs:\n                                        BsplineArcsLocation.append(i)  # .Location (center), Vector (47.192438328074296, -12.532928959782193, -85.17027221104478)\n                                except Exception:\n                                    BsplineArcsLocation  = []\n                                    None\n                            ####\n                            BsplineNumberToBiArcs = len(BsplineArcsToBiArcs)\n\n                            #### toBiArcs\n                            try:\n                                BsplineRayonApproximatif = str(Around(BsplineArcsRadius[0] * float(uniteM))) + \" \" + uniteMs\n                            except Exception :\n                                BsplineRayonApproximatif = u\"\"\n\n                            try:\n                                #### distance between 2 points Shape\n                                bsplineL = Gui.Selection.getSelection()[0]\n                                BsplineLength = float(bsplineL.Shape.Length)\n                                BsplineCutLength = BsplineLength / float(BsplineNumberElement)\n                                #### points noeuds\n                                for i in bsplineL.Points:     # nombre de points (noeuds)\n                                    BsplinePointsCoor.append(i)\n                                #### points Shape\n                            except Exception:  #    None\n                                #### distance between 2 points Curve.getPoles()\n                                bsplineL = Gui.Selection.getSelectionEx()[0].SubObjects[0] #.Curve\n                                BsplineLength = float(bsplineL.Length)\n                                BsplineCutLength = BsplineLength / float(BsplineNumberElement)\n                                #### points a.Curve.NbKnots\n                                for i in Gui.Selection.getSelectionEx()[0].SubObjects[0].Curve.getPoles():     # nombre de poles (noeuds)\n                                    BsplinePointsCoor.append(i)\n                                #### points a.Curve.NbKnots\n                            typeLongueur = \"Length BSpline\"\n#                    except Exception:\n#                        rayonObjet = 0.0\n                # rayon Objet cas cercle et Bspline End\n\n                # tableau\n                if passTableau == 1:\n                    tableau()\n\n                # surface\n                try:    # object\n                    surface = sel[0].Shape.Area\n                except Exception:\n                    surface = 0.0\n\n                try:    # face\n                    surfaceFace = Gui.Selection.getSelectionEx()[0].SubObjects[0].Area\n                except Exception:\n                    surfaceFace = 0.0\n\n                # volume\n                try:\n                    volume_ = sel[0].Shape.Volume\n                except Exception:\n                    volume_ = 0.0\n\n                # poids\n                poids = ((volume_ * seTDensiteValue) * uniteP) / 1000.0   # mm3   (mm base  FreeCAD)\n\n                # boundinbox (dimensions hors tout)\n                try:\n                    boundBox_ = sel[0].Shape.BoundBox\n                    boundBoxLX = boundBox_.XLength\n                    boundBoxLY = boundBox_.YLength\n                    boundBoxLZ = boundBox_.ZLength\n                    boundBoxDiag = boundBox_.DiagonalLength\n                    boundBox_S = \"[X: \"+str(Around(boundBoxLX * uniteM))+\" \"+uniteMs+\"] x [Y: \"+str(Around(boundBoxLY * uniteM))+\" \"+uniteMs+\"] x [Z: \"+str(Around(boundBoxLZ * uniteM))+\" \"+uniteMs+\"] Diagonal: \" + str(Around(boundBoxDiag * uniteM))+\" \"+uniteMs\n\n                    boundBoxXMin = boundBox_.XMin   # BB tracing\n                    boundBoxYMin = boundBox_.YMin\n                    boundBoxZMin = boundBox_.ZMin\n                except Exception:\n                    boundBox_  = boundBoxLX = boundBoxLY = boundBoxLZ = boundBoxDiag = 0.0\n                    boundBox_S = \"\"\n\n                if adaptWithBody == 0:\n                    # centre de la forme (boundBox) mode sans Body (normal)\n                    try:\n                        boundBoxCenterX = boundBox_.Center[0]\n                        boundBoxCenterY = boundBox_.Center[1]\n                        boundBoxCenterZ = boundBox_.Center[2]\n                    except Exception:\n                        boundBoxCenterX = boundBoxCenterY = boundBoxCenterZ = 0.0\n                else:\n                    # centre de la forme (boundBox) mode avec correction Body GetGlobalPlacement\n                    try:\n                        #### correction\n                        boundBoxLocation = App.Vector(boundBox_.Center[0], boundBox_.Center[1], boundBox_.Center[2])\n                        BDvol = adjustedGlobalPlacement(sel[0], boundBoxLocation)\n                        ####\n                        boundBoxCenterX = BDvol.Base[0] \n                        boundBoxCenterY = BDvol.Base[1] \n                        boundBoxCenterZ = BDvol.Base[2] \n                    except Exception:\n                        boundBoxCenterX = boundBoxCenterY = boundBoxCenterZ = 0.0\n\n                # Perimetre tous les bords\n                select  = FreeCADGui.Selection.getSelection()\n                numberEdges = len(select[0].Shape.Edges)\n                perimetre   = 0.0\n                try:\n                    for i in select[0].Shape.Edges:\n                        perimetre += i.Length\n                except Exception:\n                    perimetre = 0.0\n\n                # vertexes pour les angles\n                try:\n                    selectionObjects = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0]\n                    if str(selectionObjects)[1:5] == \"Edge\":\n                        points = selectionObjects.Edges[0].Vertexes[0].Point\n                        angleX1 = points.x\n                        angleY1 = points.y\n                        angleZ1 = points.z\n                        points = selectionObjects.Edges[0].Vertexes[1].Point\n                        angleX2 = points.x\n                        angleY2 = points.y\n                        angleZ2 = points.z\n                except Exception:\n                    angleX1 = angleY1 = angleZ1 = 0.0\n                    angleX2 = angleY2 = angleZ2 = 0.0\n\n                modeTypeAngle = 1\n                try:\n                    Plan_xy   = Around(angle2(angleX1,angleY1,angleX2,angleY2,modeTypeAngle))\n                    Plan_xy_V = \"[,\"+str(Around(angleX1))+\" , \"+str(Around(angleY1))+\",]  [,\"+str(Around(angleX2))+\" , \"+str(Around(angleY2))+\",]\"\n                except Exception:\n                    Plan_xy = 0.0\n                    Plan_xy_V = \"\"\n                try:\n                    Plan_yz   = Around(angle2(angleY1,angleZ1,angleY2,angleZ2,modeTypeAngle))\n                    Plan_yz_V = \"[,\"+str(Around(angleY1))+\" , \"+str(Around(angleZ1))+\",]  [,\"+str(Around(angleY2))+\" , \"+str(Around(angleZ2))+\",]\"\n                except Exception:\n                    Plan_yz   = 0.0\n                    Plan_yz_V   = \"\"\n                try:\n                    Plan_zx   = Around(angle2(angleZ1,angleX1,angleZ2,angleX2,modeTypeAngle))\n                    Plan_zx_V = \"[,\"+str(Around(angleZ1))+\" , \"+str(Around(angleX1))+\",]  [,\"+str(Around(angleZ2))+\" , \"+str(Around(angleX2))+\",]\"\n                except Exception:\n                    Plan_zx   = 0.0\n                    Plan_zx_V = \"\"\n                # angle Placement\n\n                try:\n                    typeObject = sel[0].Shape.ShapeType\n                except Exception:\n                    typeObject = \"\"\n\n                # center of mass or gravity\n                try:\n                    c = FreeCADGui.Selection.getSelection()[0].Shape.CenterOfMass\n                    massOrGravity = \" Mass \"\n                except Exception:\n                    try:\n                        c = FreeCADGui.Selection.getSelection()[0].Shape.CenterOfGravity\n                        massOrGravity = \" Gravity \"\n                    except Exception:\n                        try:\n                            ###https://forum.freecad.org/viewtopic.php?p=664655#p664655\n                            ##shp = App.ActiveDocument.Shape059.Shape\n                            ##cog = (shp.Face1.CenterOfGravity + shp.Face2.CenterOfGravity) / 2\n                            ##Part.show(Part.Vertex(cog))\n                            selEx = FreeCADGui.Selection.getSelectionEx()\n                            objs = [selobj.Object for selobj in selEx]\n                            s = objs[0].Shape\n                            c = s.Solids[0].CenterOfMass\n                            massOrGravity = \" Mass \"\n                        except Exception:\n                            c = \"\"\n                            massOrGravity = \" Mass \"\n                if adaptWithBody == 0:\n                    # centre de la forme (CenterOfMass) mode sans Body (normal)\n                    try:\n                        CenterOfMassX = c.x\n                        CenterOfMassY = c.y\n                        CenterOfMassZ = c.z\n                        massOrGravity = \" Mass \"\n                    except Exception:\n                        try:\n                            c = FreeCADGui.Selection.getSelection()[0].Shape.CenterOfGravity\n                            CenterOfMassX = c.x\n                            CenterOfMassY = c.y\n                            CenterOfMassZ = c.z\n                            massOrGravity = \" Gravity \"\n                        except:\n                            CenterOfMassX = CenterOfMassY = CenterOfMassZ = 0.0\n                            massOrGravity = \" Mass \"\n                else:\n                    # centre de la forme (CenterOfMass) mode avec correction Body GetGlobalPlacement\n                    try:\n                        #### correction\n                        boundBoxLocation = App.Vector(c[0], c[1], c[2])\n                        BDvol = adjustedGlobalPlacement(sel[0], boundBoxLocation)\n                        ####\n                        CenterOfMassX = BDvol.Base[0] \n                        CenterOfMassY = BDvol.Base[1] \n                        CenterOfMassZ = BDvol.Base[2] \n                    except Exception:\n                        CenterOfMassX = CenterOfMassY = CenterOfMassZ = 0.0\n\n                # inertia DeterminantM\n                try:    # inertia DeterminantM\n                    DeterminantM = FreeCADGui.Selection.getSelection()[0].Shape.MatrixOfInertia.determinant()\n                except Exception:\n                    try:\n                        selEx = FreeCADGui.Selection.getSelectionEx()\n                        objs = [selobj.Object for selobj in selEx]\n                        s = objs[0].Shape\n                        DeterminantM = s.Solids[0].MatrixOfInertia.determinant()\n                    except Exception:\n                        DeterminantM = 0.0\n    \n                try:    # inertia\n                    matrixOfInertia = FreeCADGui.Selection.getSelection()[0].Shape.MatrixOfInertia\n                except Exception:\n                    try:\n                        selEx = FreeCADGui.Selection.getSelectionEx()\n                        objs = [selobj.Object for selobj in selEx]\n                        s = objs[0].Shape\n                        matrixOfInertia = s.Solids[0].MatrixOfInertia\n                    except Exception:\n                        matrixOfInertia = \"\"\n                MatrixOfInertiaRaw = str(matrixOfInertia)\n\n                # Matrix of inertia\n                ## Verify this section by person knowing the inertia position       ##\n                ##      ONLY IF THE OBJECT IS PRESENT IN ONE BODY                   ##\n                ## and post your knowledges in the forum tread if it is not correct ##\n                ## http://forum.freecadweb.org/viewtopic.php?f=10&t=3185            ##\n                try:    # Matrix of inertia\n                    MatrixX1_16 = MatrixX1 = (matrixOfInertia.A[0])\n                    MatrixY1_16 = MatrixY1 = (matrixOfInertia.A[1])\n                    MatrixZ1_16 = MatrixZ1 = (matrixOfInertia.A[2])\n                    Matrix_1    = (matrixOfInertia.A[3])\n\n                    MatrixX2_16 = MatrixX2 = (matrixOfInertia.A[4])\n                    MatrixY2_16 = MatrixY2 = (matrixOfInertia.A[5])\n                    MatrixZ2_16 = MatrixZ2 = (matrixOfInertia.A[6])\n                    Matrix_2    = (matrixOfInertia.A[7])\n\n                    MatrixX3_16 = MatrixX3 = (matrixOfInertia.A[8])\n                    MatrixY3_16 = MatrixY3 = (matrixOfInertia.A[9])\n                    MatrixZ3_16 = MatrixZ3 = (matrixOfInertia.A[10])\n                    Matrix_3    = (matrixOfInertia.A[11])\n\n                    Matrix12 = (matrixOfInertia.A[12])\n                    Matrix13 = (matrixOfInertia.A[13])\n                    Matrix14 = (matrixOfInertia.A[14])\n                    Matrix15 = (matrixOfInertia.A[15])\n                    refreshMatrix = 1\n\n                except Exception:\n                    MatrixX1_16 = MatrixX1 = 0.0\n                    MatrixY1_16 = MatrixY1 = 0.0\n                    MatrixZ1_16 = MatrixZ1 = 0.0\n                    Matrix_1    = 0.0\n\n                    MatrixX2_16 = MatrixX2 = 0.0\n                    MatrixY2_16 = MatrixY2 = 0.0\n                    MatrixZ2_16 = MatrixZ2 = 0.0\n                    Matrix_2    = 0.0\n\n                    MatrixX3_16 = MatrixX3 = 0.0\n                    MatrixY3_16 = MatrixY3 = 0.0\n                    MatrixZ3_16 = MatrixZ3 = 0.0\n                    Matrix_3    = 0.0\n\n                    Matrix12 = 0.0\n                    Matrix13 = 0.0\n                    Matrix14 = 0.0\n                    Matrix15 = 0.0\n                    refreshMatrix = 0\n\n                try:    # Direction verifier choix objet ou sub objet\n#                    edgeObject = Gui.Selection.getSelection()[0].Shape.Edges[0]          # first edge of Shape\n                    edgeObject = Gui.Selection.getSelectionEx()[0].SubObjects[0].Edges[0] # sub object selcted\n                    directionObj = edgeObject.Vertexes[1].Point.sub(edgeObject.Vertexes[0].Point)\n                except Exception:\n                    directionObj = \"[]\"\n\n                try:    # valueAt(0)\n                    direcValueAt = Gui.Selection.getSelectionEx()[0].SubObjects[0].Edges[0].valueAt(0)\n                except Exception:\n                    direcValueAt = \"[]\"\n\n                try:    # normalAt(0,0)\n                    if switchCreateLineDiVatNatOnClick == 0:\n                        typeNormalAt = u\"NormalAt(0,0)\"\n                    else:\n                        typeNormalAt = u\"*NormalAt(0,0)\"\n                    direcNormalAt  = Gui.Selection.getSelectionEx()[0].SubObjects[0].Faces[0].normalAt(0,0)\n                except Exception:\n                    direcNormalAt = \"[]\"\n\n        #### Display info\n        if switchDisplayInfoObject == 1 :\n\n            if switchClearDisplayReportView == 1:\n                ##################### effacer la vue rapport ############################\n                try:                                                                 ####\n                    mw=Gui.getMainWindow()                                           ####\n                    r=mw.findChild(QTextEdit, \"Report view\")               ####\n                    r.clear()                                                        ####\n                except Exception:                                                    ####\n                    None                                                             ####\n                #########################################################################\n\n            App_Console_PrintMessage(u\"\\n\")\n            App_Console_PrintMessage(u\"FCInfo_Beginning_\"+str(subElemName) +\"______________________________________________________\"+\"\\n\")\n            App_Console_PrintMessage(u\"Document name            : \"+document_+\"\\n\")\n            App_Console_PrintMessage(u\"Label of the object      : \"+object_Label+\"\\n\")\n            App_Console_PrintMessage(u\"Internal name            : \"+object_Name+\"\\n\")\n            App_Console_PrintMessage(u\"Element name             : \"+str(subElemName)+\"\\n\")\n            App_Console_PrintMessage(u\"Object type              : \"+typeObject+\"\\n\")\n            App_Console_PrintMessage(u\"Object type              : \"+object_Type+\"\\n\")\n            App_Console_PrintMessage(u\"Mouse coordinates        : X: \"+str(Around(position0 * uniteM)) + \" \" + uniteMs + \"  Y:\" + str(Around(position1 * uniteM)) + \" \" + uniteMs + \"  Z:\" + str(Around(position2 * uniteM)) + \" \" + uniteMs + \"\\n\")\n            App_Console_PrintMessage(typeLongueur + \"     : \"+str(Around(longueurObjet * uniteM))+\", \"+uniteMs+\"\\n\\n\")\n\n            App_Console_PrintMessage(u\"Color on selection\" + \"\\n\")\n            App_Console_PrintMessage(u\"Red\" + \", \" + str(int(diffuseColorRF*255.0)) + \", \" + \n                                     u\"Green\" + \", \" + str(int(diffuseColorVF*255.0)) + \", \" + \n                                     u\"Blue\" + \", \" + str(int(diffuseColorBF*255.0)) + \", \" + \n                                     u\"Transparency\" + \", \" + str(int(diffuseColorTF*255.0)) + \"\\n\\n\")\n\n            #### couleurs\n            if len(colorShapeFace) != 0:\n                App_Console_PrintMessage(u\"Color Object (float) \" + str(colorShapeFace[0])+\", \"+str(colorShapeFace[1])+\", \"+str(colorShapeFace[2])+\", \"+str(colorShapeFace[3])+\")\" + \"\\n\")\n                App_Console_PrintMessage(u\"Color Object (int  )(\" + str(int(colorShapeFace[0]*255.0))+\", \"+str(int(colorShapeFace[1]*255.0))+\", \"+str(int(colorShapeFace[2]*255.0))+\", \"+str(int(colorShapeFace[3]*255.0))+\")\" + \"\\n\\n\")\n\n            if len(colorShapeLine) != 0:\n                App_Console_PrintMessage(u\"Color Line(s) (float) \" + str(colorShapeLine[0])+\", \"+str(colorShapeLine[1])+\", \"+str(colorShapeLine[2])+\", \"+str(colorShapeLine[3])+\")\" + \"\\n\")\n                App_Console_PrintMessage(u\"Color Line(s) (int  )(\" + str(int(colorShapeLine[0]*255.0))+\", \"+str(int(colorShapeLine[1]*255.0))+\", \"+str(int(colorShapeLine[2]*255.0))+\", \"+str(int(colorShapeLine[3]*255.0))+\")\" + \"\\n\\n\")\n\n            if len(colorShapePoint) != 0:\n                try:\n                    App_Console_PrintMessage(u\"Color Point(s) (float) \" + str(colorShapePoint[0])+\", \"+str(colorShapePoint[1])+\", \"+str(colorShapePoint[2])+\", \"+str(colorShapePoint[3])+\")\" + \"\\n\")\n                    App_Console_PrintMessage(u\"Color Point(s) (int  )(\" + str(int(colorShapePoint[0]*255.0))+\", \"+str(int(colorShapePoint[1]*255.0))+\", \"+str(int(colorShapePoint[2]*255.0))+\", \"+str(int(colorShapePoint[3]*255.0))+\")\" + \"\\n\\n\")\n                except Exception:\n                    None\n\n            if detected[0:4] == \"Mesh\":\n                App_Console_PrintMessage(u\"Number of Edges          : \"+str(nombreArretesMesh)+\"\\n\")\n                App_Console_PrintMessage(u\"Number of Faces          : \"+str(nombreFacesMesh)+\"\\n\")\n                App_Console_PrintMessage(u\"Number of Points         : \"+str(nombrePointsMesh)+\"\\n\\n\")\n\n            if detected == \"<PointKernel object>\":\n                App_Console_PrintMessage(u\"Number of Points         : \"+str(nombrePointsMesh)+\"\\n\\n\")\n\n            ############### detail of Cercle BSpline begin\n            if (rayonObjet != 0.0) or (str(BsplineDetect) == \"<BSplineCurve object>\"):\n                if (str(BsplineDetect) == \"<BSplineCurve object>\"):\n                    App_Console_PrintMessage(u\"Number of nodes          : \"+str(BsplineNombreDeNoeuds) +\"\\n\")\n                    for i in enumerate(BsplinePointsCoor):     # nombre de points\n                        App_Console_PrintMessage(\"\\t\" + u\"X\" + str(i[0]+1) + \": \" + str(Around(float(BsplinePointsCoor[i[0]][0]))) + \" \" + \"\\t\" + \n                                                        u\"Y\" + str(i[0]+1) + \": \" + str(Around(float(BsplinePointsCoor[i[0]][1]))) + \" \" + \"\\t\" +  \n                                                        u\"Z\" + str(i[0]+1) + \": \" + str(Around(float(BsplinePointsCoor[i[0]][2]))) + \"\\n\")\n                    App_Console_PrintMessage(u\"\\n\")\n                else:\n                    App_Console_PrintMessage(u\"Radius of the object     : \"+str(Around(rayonObjet * uniteM))+\", \"+uniteMs +\"\\n\")\n                    App_Console_PrintMessage(u\"Diameter of the object   : \"+str(Around((rayonObjet * uniteM) * 2.0))+\", \"+uniteMs +\"\\n\")\n            ############### detail of Cercle BSpline end\n\n            App_Console_PrintMessage(u\"Perimeter of the shape   : \"+str(Around(perimetre * uniteM))+\", \"+uniteMs+\"\\n\\n\")\n\n            ############### detail of object begin \n            if passTableau == 1:    #\n                App_Console_PrintMessage(u\"Vertexes and details     : (\"+ str(compt_E) +\") (\"+ str(compt_F)+\") (\"+ str(compt_VF)+\") (\"+str(RowCountTest)+\")\\n\")\n                co = 0\n                aa = 0\n                for j in enumerate(Edges):\n                    App_Console_PrintMessage(u\"Length \"+str(j[1])+\" = \"+str(Around(float(EdgesLong[co]) * float(uniteM)))+\" \"+uniteMs+\"\\n\")\n                    try:\n                        for a in range(aa,aa+6):\n                            chaine = str(Vertx[a]).split(\":\")\n                            App_Console_PrintMessage(chaine[0] + \": \" + str(Around(float(chaine[1]) * float(uniteM)))+\" \"+uniteMs+\"\\n\")\n\n                    except Exception:\n                        None\n                    co += 1\n                    aa += 6\n                    App_Console_PrintMessage(u\"\\n\")\n                co=0\n                cco=0\n                for j in enumerate(Faces):\n                    App_Console_PrintMessage(u\"Area \"+str(j[1])+\" = \"+str(Around(float(FacesSurf[co]) * float(uniteS)))+\" \"+uniteSs+\"\\n\")\n                    if len(colorShapeFaceDiffuseColor) != 0:\n                        App_Console_PrintMessage(u\"Color float Face\" + str(j[0]+1) + \" \" + \n                                                 u\"R: \" + str(colorShapeFaceDiffuseColor[j[0]][0]) + \", \"+\n                                                 u\"G: \" + str(colorShapeFaceDiffuseColor[j[0]][1]) + \", \"+\n                                                 u\"B: \" + str(colorShapeFaceDiffuseColor[j[0]][2]) + \", \"+\n                                                 u\"T: \" + str(colorShapeFaceDiffuseColor[j[0]][3]) + \"\\n\")\n                        App_Console_PrintMessage(u\"Color integer Face\" + str(j[0]+1) + \" \" +\n                                                 u\"R: \" + str(int(colorShapeFaceDiffuseColor[j[0]][0]*255.0))+\", \"+\n                                                 u\"G: \" + str(int(colorShapeFaceDiffuseColor[j[0]][1]*255.0))+\", \"+\n                                                 u\"B: \" + str(int(colorShapeFaceDiffuseColor[j[0]][2]*255.0))+\", \"+\n                                                 u\"T: \" + str(int(colorShapeFaceDiffuseColor[j[0]][3]*255.0))+ \"\\n\")\n\n                    for jj in range(cco,len(FacesCoor)):\n                        cco+=1\n                        if FacesCoor[jj] == \"T\":\n                            break\n                        else:\n                            chaine = str(FacesCoor[jj]).split(\":\")\n                            App_Console_PrintMessage(chaine[0] + \": \" + str(Around(float(chaine[1]) * float(uniteM)))+\" \"+uniteMs+\"\\n\")\n\n                    App_Console_PrintMessage(u\"\\n\")\n                    co += 1\n                cco=0\n            else:\n                App_Console_PrintMessage(u\"\\n\")\n            ############### detail of object end\n\n            #### Display info Begin\n            App_Console_PrintMessage(u\"Plane                    : XY: \" + str(Around(Plan_xy))+uniteAs+\" coordinates: \" + str(Plan_xy_V)+\"\\n\")\n            App_Console_PrintMessage(u\"Plane                    : YZ: \" + str(Around(Plan_yz))+uniteAs+\" coordinates: \" + str(Plan_yz_V)+\"\\n\")\n            App_Console_PrintMessage(u\"Plane                    : ZX: \" + str(Around(Plan_zx))+uniteAs+\" coordinates: \" + str(Plan_zx_V)+\"\\n\\n\")\n            App_Console_PrintMessage(u\"The form surface         : \"+str(Around(surface * uniteS))+\"  \"+uniteSs+\"\\n\")\n            App_Console_PrintMessage(u\"The face surface         : \"+str(Around(surfaceFace * uniteS))+\"  \"+uniteSs+\"\\n\\n\")\n            App_Console_PrintMessage(u\"Volume of the form       : \"+str(Around(volume_ * uniteV))+\"  \"+uniteVs+\"\\n\")\n            App_Console_PrintMessage(u\"Mass                     : \"+str(Around(poids))+ \" \" +unitePs+u\" (Densit\u00e9 : \"+str(seTDensiteValue)+\")\\n\\n\")\n            App_Console_PrintMessage(u\"Center of the shape      : X: \"+str(Around(boundBoxCenterX * uniteM))+ \" \" +uniteMs+\"  Y: \"+str(Around(boundBoxCenterY * uniteM))+ \" \" +uniteMs+\"  Z: \"+str(Around(boundBoxCenterZ * uniteM))+ \" \" +uniteMs+\"\\n\")\n            App_Console_PrintMessage(u\"Center of mass           : X: \"+str(Around(CenterOfMassX * uniteM))+ \" \" +uniteMs  +\"  Y: \"+str(Around(CenterOfMassY * uniteM))+ \" \" +uniteMs  +\"  Z: \"+str(Around(CenterOfMassZ * uniteM))+ \" \" +uniteMs+\"\\n\")\n            App_Console_PrintMessage(u\"Overall dimensions       : \"+boundBox_S+\"\\n\\n\")\n\n            if directionObj != \"[]\":\n                App_Console_PrintMessage(u\"Direction                : \"+str(directionObj)+\"\\n\")\n            if direcValueAt != \"[]\":\n                App_Console_PrintMessage(u\"ValueAt                  : \"+str(direcValueAt)+\"\\n\")\n            if direcNormalAt != \"[]\":\n                App_Console_PrintMessage(u\"NormalAt                 : \"+str(direcNormalAt)+\"\\n\")\n            App_Console_PrintMessage(u\"\\n\")\n\n            if detected[0:4] == \"Mesh\":\n                None\n            else:\n                App_Console_PrintMessage(u\"Matrix of inertia        : Raw: \"+str(MatrixOfInertiaRaw)+\"\\n\")\n                App_Console_PrintMessage(u\"                         : \" + uniteMs + \"^\" + str(setMomentOfInertia_16) + \"\\n\")\n                App_Console_PrintMessage(u\"                         : X: \"+str(Around(MatrixX1_16))+\"  Y: \"+str(Around(MatrixY1_16))+\"  Z: \"+str(Around(MatrixZ1_16))+\"  : \"+str(Around(Matrix_1))+\"\\n\")\n                App_Console_PrintMessage(u\"                         : X: \"+str(Around(MatrixX2_16))+\"  Y: \"+str(Around(MatrixY2_16))+\"  Z: \"+str(Around(MatrixZ2_16))+\"  : \"+str(Around(Matrix_2))+\"\\n\")\n                App_Console_PrintMessage(u\"                         : X: \"+str(Around(MatrixX3_16))+\"  Y: \"+str(Around(MatrixY3_16))+\"  Z: \"+str(Around(MatrixZ3_16))+\"  : \"+str(Around(Matrix_3))+\"\\n\")\n                App_Console_PrintMessage(u\"                         : X: \"+str(Around(Matrix12))+\"  Y: \"+str(Around(Matrix13))+\"  Z: \"+str(Around(Matrix14))+\"  : \"+str(Around(Matrix15))+\"\\n\\n\")\n\n                App_Console_PrintMessage(u\"Matrix inertia with mass : \" +unitePs + uniteSs + \"^\" + str(setMomentOfInertiaMassique_17) + \"\\n\")\n                App_Console_PrintMessage(u\"                         : X: \"+str(Around(MatrixX1_17))+\"  Y: \"+str(Around(MatrixY1_17))+\"  Z: \"+str(Around(MatrixZ1_17))+\"\\n\")\n                App_Console_PrintMessage(u\"                         : X: \"+str(Around(MatrixX2_17))+\"  Y: \"+str(Around(MatrixY2_17))+\"  Z: \"+str(Around(MatrixZ2_17))+\"\\n\")\n                App_Console_PrintMessage(u\"                         : X: \"+str(Around(MatrixX3_17))+\"  Y: \"+str(Around(MatrixY3_17))+\"  Z: \"+str(Around(MatrixZ3_17))+\"\\n\\n\")\n                App_Console_PrintMessage(u\"Determinant              : \" +  str(DeterminantM)+\"\\n\")\n                App_Console_PrintMessage(u\"Determinant decimal      : \" +  str(decimal.Decimal(DeterminantM))+\"\\n\")\n            App_Console_PrintMessage(u\"FCInfo_End_\"+str(subElemName)+ \"____________________________________________________________\"+\"\\n\\n\")\n            #### Display info end\n\nclass Ui_MainWindow(object):\n\n    def setupUi(self, MainWindow):\n        global sel\n        global document_\n        global object_Label\n        global object_Name\n        global typeObject\n        global object_Type\n        global subElemName\n        global position0\n        global position1\n        global position2\n\n        global diffuseColorRF\n        global diffuseColorVF\n        global diffuseColorBF\n        global diffuseColorTF\n        global transparenceFace\n        global unsignedEncodeColor\n\n        global longueurObjet\n        global rayonObjet\n        global perimetre\n        global Plan_xy\n        global Plan_xy_V\n        global Plan_yz\n        global Plan_yz_V\n        global Plan_zx\n        global Plan_zx_V\n        global surface\n        global surfaceFace\n        global volume_\n        global poids\n        global materialAssociated\n        global seTMaterialCurrentIndex\n        global uniteM\n        global uniteMs\n        global uniteS\n        global uniteSs\n        global uniteV\n        global uniteVs\n        global uniteP\n        global unitePs\n        global directionObj\n        global direcValueAt\n        global direcNormalAt\n        global uniteAs\n        global boundBoxCenterX\n        global boundBoxCenterY\n        global boundBoxCenterZ\n        global CenterOfMassX\n        global CenterOfMassY\n        global CenterOfMassZ\n        global boundBoxLX\n        global boundBoxLY\n        global boundBoxLZ\n        global boundBoxDiag\n        global MatrixX1\n        global MatrixY1\n        global MatrixZ1\n        global Matrix_1\n\n        global MatrixX2\n        global MatrixY2\n        global MatrixZ2\n        global Matrix_2\n\n        global MatrixX3\n        global MatrixY3\n        global MatrixZ3\n        global Matrix_3\n\n        global Matrix12\n        global Matrix13\n        global Matrix14\n        global Matrix15\n        global DeterminantM\n\n        global compt_E\n        global compt_F\n        global compt_VF\n        global placement_\n                              \n        global RowCount\n        global RowCountTest\n\n        global seTMemoClipBoard\n        global switchCreatePoint\n        global switchCreateAxis\n        global switchCreatePlane\n        global switchDisplayInfoObject\n        global seTWidgetPosition\n        global switchBoundBoxCreateText\n        global seTBoundBoxTextHeigth\n        global seTDecimalValue\n        global seTTextHeigthValue\n        global seTDensiteDecimalNumber\n        global seTDensiteValue\n        global seTDensiteSingleStep\n        global seTDensiteSuffixChain\n        global seTPositionFlyRightLeft\n        global seTMaterialPrice\n        global seTMaterialSuffixDevise\n        global seTMaterialSuffixCost\n        global seTIndexUnitLength\n        global seTIndexUnitWeight\n        global setMomentOfInertia_16\n        global setMomentOfInertiaMassique_17\n\n        global BsplineDetect\n        global BsplineRayonApproximatif\n        global BsplineArcsRadius\n\n        global switch_setVisible_GBox_001_Document\n        global switch_setVisible_GBox_002_Coordinate_Mouse\n        global switch_setVisible_GBox_003_Color\n        global switch_setVisible_GBox_004_Object_Mesh\n        global switch_setVisible_GBox_005_Value_Unit\n        global switch_setVisible_GBox_006_Inclination\n        global switch_setVisible_GBox_007_Surface_and_Volume\n        global switch_setVisible_GBox_008_Cost_And_Price\n        global switch_setVisible_GBox_009_BoundBox\n        global switch_setVisible_GBox_010_Center_Mass\n        global switch_setVisible_GBox_011_Inertia\n        global switch_setVisible_GBox_012_SpreadSheet\n        global switch_setVisible_GBox_013_SpreadSheet_Creation\n        global switch_setVisible_GBox_014_Main_Tools\n\n        self.window = MainWindow\n        ####\n        if seTPositionFlyRightLeft == 1:\n            MainWindow.setObjectName(_fromUtf8(u\"MainWindow\"))    # volant\n            MainWindow.resize(500, 515)\n            MainWindow.setMinimumSize(QtCore.QSize(500, 515))\n            #MainWindow.setMaximumSize(QtCore.QSize(380, 515))\n            #MainWindow.move(1300, 120)                           # deplace la fenetre\n\n        ####\n        self.fontGlobal_08 = QtGui.QFont()\n        self.fontGlobal_08.setFamily(u\"Arial\")\n#        self.fontGlobal_08.setPointSize(seTTextHeigthValue)\n        self.fontGlobal_08.setPixelSize(seTTextHeigthValue)\n        #self.xxxx.setFont(self.fontGlobal_08)\n        #self.xxxx.setStyleSheet(u\"color : #ff0000; font: bold\")     # couleur du texte et gras#\n        ####\n\n        self.centralWidget = QWidget(MainWindow)\n        #self.centralWidget.setMinimumSize(QtCore.QSize(500, 500))\n\n        ####\n        grid = QGridLayout()\n        self.centralWidget.setLayout(grid)\n        ####\n        self.scrollArea = QScrollArea(self.centralWidget)    # cadre scrollarea contenant le widget GUI\n        self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)\n        self.scrollArea.setWidgetResizable(True)\n        grid.addWidget(self.scrollArea, 0, 0)\n        vbox = QVBoxLayout()\n        self.scrollArea.setLayout(vbox)\n\n        self.scrollAreaWidgetContents_2 = QWidget()          #widget contenant le GUI\n\n        vbox.addWidget(self.scrollAreaWidgetContents_2)\n\n        sel = FreeCADGui.Selection.getSelection()\n        if len(sel)==0:\n            App_Console_PrintMessage(u\"Select an object\"+\"\\n\")\n            errorDialog(u\"Select an object\")\n        else:\n            affect(0)\n\n        vbox = QVBoxLayout()\n        self.scrollAreaWidgetContents_2.setLayout(vbox)\n\n        #### Document\n        grid = QGridLayout()\n        self.GBox_001_Document = QGroupBox()\n        if switch_setVisible_GBox_001_Document == False:\n            self.GBox_001_Document.setVisible(switch_setVisible_GBox_001_Document)                        # visibility\n        self.GBox_001_Document.setLayout(grid)\n        vbox.addWidget(self.GBox_001_Document)\n\n        self.LA_1 = QLabel()\n        self.LE_1 = QLineEdit()\n\n        grid.addWidget(self.LA_1, 0, 0)\n        grid.addWidget(self.LE_1, 0, 1, 1, 2)\n\n        self.LA_2 = QLabel()\n        self.LE_2 = QLineEdit()\n        self.LE_2a = QLineEdit()\n\n        grid.addWidget(self.LA_2, 1, 0)\n        grid.addWidget(self.LE_2, 1, 1)\n        grid.addWidget(self.LE_2a, 1, 2)\n\n        self.LA_3 = QLabel()\n        self.LA_4 = QLabel()\n        self.LE_3 = QLineEdit()\n        self.LE_3a = QLineEdit()\n        self.LE_4 = QLineEdit()\n\n        grid.addWidget(self.LA_3, 2, 0)\n        grid.addWidget(self.LE_3, 2, 1)\n        grid.addWidget(self.LE_3a, 2, 2)\n        grid.addWidget(self.LA_4, 3, 0)\n        grid.addWidget(self.LE_4, 3, 1, 1, 2)\n\n        #### Coordinate click mouse\n        grid = QGridLayout()\n        self.GBox_002_Coordinate_Mouse = QGroupBox()\n        if switch_setVisible_GBox_002_Coordinate_Mouse == False:\n            self.GBox_002_Coordinate_Mouse.setVisible(switch_setVisible_GBox_002_Coordinate_Mouse)        # visibility\n        self.GBox_002_Coordinate_Mouse.setLayout(grid)\n        vbox.addWidget(self.GBox_002_Coordinate_Mouse)\n\n        self.LA_4x = QLabel()\n        self.LA_4x.setStyleSheet(u\"QLabel {color : #ff0000; font: bold}\")       # couleur du texte et gras\n        self.LE_4x = QLineEdit()\n\n        grid.addWidget(self.LA_4x, 0, 0)\n        grid.addWidget(self.LE_4x, 1, 0)\n\n        self.LA_4y = QLabel()\n        self.LA_4y.setStyleSheet(u\"QLabel {color : #008500; font: bold}\")       # couleur du texte et gras\n        self.LE_4y = QLineEdit()\n\n        grid.addWidget(self.LA_4y, 0, 1)\n        grid.addWidget(self.LE_4y, 1, 1)\n\n        self.LA_4z = QLabel()\n        self.LA_4z.setStyleSheet(u\"QLabel {color : #0000ff; font: bold}\")       # couleur du texte et gras\n        self.LE_4z = QLineEdit()\n\n        grid.addWidget(self.LA_4z, 0, 2)\n        grid.addWidget(self.LE_4z, 1, 2)\n\n        self.PB_Axis_01 = QPushButton()\n        self.PB_Axis_01.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_05))) # icone dans une variable \n        self.PB_Axis_01.clicked.connect(self.on_PB_Axis_Mouse)\n        grid.addWidget(self.PB_Axis_01, 1, 3)\n\n        #### couleur point clique\n        grid = QGridLayout()\n        self.GBox_003_Color = QGroupBox()\n        if switch_setVisible_GBox_003_Color == False:\n            self.GBox_003_Color.setVisible(switch_setVisible_GBox_003_Color)        # visibility\n        self.GBox_003_Color.setLayout(grid)\n        vbox.addWidget(self.GBox_003_Color)\n\n        self.LA_1_Red = QLabel()\n        self.LA_1_Red.setStyleSheet(u\"QLabel {color : #ff0000; font: bold}\")         # couleur du texte et gras\n        grid.addWidget(self.LA_1_Red, 0, 0)\n\n        self.LA_2_Green = QLabel()\n        self.LA_2_Green.setStyleSheet(u\"QLabel {color : #008500; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_2_Green, 0, 1)\n\n        self.LA_3_Blue = QLabel()\n        self.LA_3_Blue.setStyleSheet(u\"QLabel {color : #0000ff; font: bold}\")        # couleur du texte et gras\n        grid.addWidget(self.LA_3_Blue, 0, 2)\n\n        self.LA_4_Transparent = QLabel()\n        self.LA_4_Transparent.setStyleSheet(u\"QLabel {color : #000000; font: bold}\") # couleur du texte et gras\n        grid.addWidget(self.LA_4_Transparent, 0, 3)\n\n        self.LE_CRed = QLineEdit()\n        grid.addWidget(self.LE_CRed, 1, 0)\n        self.LE_CGreen = QLineEdit()\n        grid.addWidget(self.LE_CGreen, 1, 1)\n        self.LE_CBlue = QLineEdit()\n        grid.addWidget(self.LE_CBlue, 1, 2)\n        self.LE_Transparent = QLineEdit()\n        grid.addWidget(self.LE_Transparent, 1, 3)\n\n        self.LE_ConversionUnsigned = QLineEdit()\n        grid.addWidget(self.LE_ConversionUnsigned, 2, 0, 1, 4)\n\n        self.CBox_Color_FaceObject = QCheckBox()\n        #self.CBox_Color_FaceObject.setChecked(False)\n        self.CBox_Color_FaceObject.clicked.connect(self.SIGNAL_CBox_Color_FaceObject)\n        grid.addWidget(self.CBox_Color_FaceObject, 3, 0)\n\n        self.PB_ChangeColor = QPushButton()\n        self.PB_ChangeColor.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Color))) # icone dans une variable \n        self.PB_ChangeColor.clicked.connect(self.on_PB_ChangeColor)\n        grid.addWidget(self.PB_ChangeColor, 3, 1)\n\n        self.PB_CreateFace = QPushButton()\n        self.PB_CreateFace.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Face))) # icone dans une variable \n        self.PB_CreateFace.clicked.connect(self.on_PB_CreateFace)\n        grid.addWidget(self.PB_CreateFace, 3, 2)\n\n        self.SBox_Transparence = QSpinBox()\n        #self.SBox_Transparence.setEnabled(False)\n        self.SBox_Transparence.setMinimum(0)\n        self.SBox_Transparence.setMaximum(100)\n        self.SBox_Transparence.setValue(transparenceFace)\n        self.SBox_Transparence.valueChanged.connect(self.on_SBox_Transparence_valueChanged)\n        grid.addWidget(self.SBox_Transparence, 3, 3)\n\n        #### Composantes Object Mesh\n        grid = QGridLayout()\n        self.GBox_004_Object_Mesh = QGroupBox()\n        if switch_setVisible_GBox_004_Object_Mesh == False:\n            self.GBox_004_Object_Mesh.setVisible(switch_setVisible_GBox_004_Object_Mesh) # visibility\n        self.GBox_004_Object_Mesh.setVisible(False)\n\n        self.GBox_004_Object_Mesh.setLayout(grid)\n        vbox.addWidget(self.GBox_004_Object_Mesh)\n\n        self.LA_N_Edges = QLabel()\n        self.LE_N_Edges = QLineEdit()\n\n        grid.addWidget(self.LA_N_Edges, 0, 0)\n        grid.addWidget(self.LE_N_Edges, 1, 0)\n\n        self.LA_N_Facets = QLabel()\n        self.LE_N_Facets = QLineEdit()\n\n        grid.addWidget(self.LA_N_Facets, 0, 1)\n        grid.addWidget(self.LE_N_Facets, 1, 1)\n\n        self.LA_N_Points = QLabel()\n        self.LE_N_Points = QLineEdit()\n\n        grid.addWidget(self.LA_N_Points, 0, 2)\n        grid.addWidget(self.LE_N_Points, 1, 2)\n\n        #### Unit\n        grid = QGridLayout()\n        self.GBox_005_Value_Unit = QGroupBox()\n        if switch_setVisible_GBox_005_Value_Unit == False:\n            self.GBox_005_Value_Unit.setVisible(switch_setVisible_GBox_005_Value_Unit)   # visibility\n        self.GBox_005_Value_Unit.setLayout(grid)\n        vbox.addWidget(self.GBox_005_Value_Unit)\n\n        self.LA_5a = QLabel()\n        grid.addWidget(self.LA_5a, 0, 0)\n\n        self.comboBox = QComboBox()\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        self.comboBox.addItem(_fromUtf8(u\"\"))\n        #self.comboBox.setCurrentIndex(seTIndexUnitLength)\n                                                                                                                            \n        self.comboBox.currentTextChanged.connect(self.SIGNAL_comboBox_Changed)\n        grid.addWidget(self.comboBox, 0, 1)#, 1, 2\n\n        #### Line Cercle et BSpline\n        self.LA_5 = QLabel()\n        grid.addWidget(self.LA_5, 1, 0)#, 1, 2\n\n        self.LE_5 = QLineEdit()\n        grid.addWidget(self.LE_5, 1, 1)#, 1, 2\n\n        self.LA_5b = QLabel()\n        grid.addWidget(self.LA_5b, 2, 0)#, 1, 2\n\n        self.LE_5b = QLineEdit()\n        grid.addWidget(self.LE_5b, 2, 1)#, 1, 2\n\n        self.SB_Arc_ToByArcs = QSpinBox()\n        self.SB_Arc_ToByArcs.setMinimum(1)\n        self.SB_Arc_ToByArcs.setMaximum(99999999)\n        self.SB_Arc_ToByArcs.setPrefix(u\"arc \")\n#        try:\n#            self.SB_Arc_ToByArcs.setSuffix(u\" / \" + str(len(BsplineArcsRadius)))\n#            BsplineRayonApproximatif = str(Around(BsplineArcsRadius[0] * float(uniteM))) + \" \" + uniteMs\n#        except Exception:\n#            BsplineRayonApproximatif = u\"\"\n        self.SB_Arc_ToByArcs.valueChanged.connect(self.on_SB_Arc_ToByArcs_valueChanged)\n        grid.addWidget(self.SB_Arc_ToByArcs, 2, 2)\n\n        self.LA_6 = QLabel()\n        grid.addWidget(self.LA_6, 3, 0)#, 1, 1\n\n        self.LE_6 = QLineEdit()\n        grid.addWidget(self.LE_6, 3, 1)\n\n        self.PB_BSplineCreateNodes = QPushButton()\n        self.PB_BSplineCreateNodes.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Point))) # icone dans une variable \n        self.PB_BSplineCreateNodes.clicked.connect(self.on_PB_BSplineCreateNodes)\n        grid.addWidget(self.PB_BSplineCreateNodes, 3, 2)\n\n#        if (rayonObjet != 0) or (str(BsplineDetect) == \"<BSplineCurve object>\")::\n#            if (str(BsplineDetect) == \"<BSplineCurve object>\"):\n#                self.SB_Arc_ToByArcs.setVisible(True)\n#                self.PB_BSplineCreateNodes.setVisible(True)\n#            self.LA_5b.setVisible(True)\n#            self.LE_5b.setVisible(True)\n#        else:\n#            self.SB_Arc_ToByArcs.setVisible(False)\n#            self.PB_BSplineCreateNodes.setVisible(False)\n#            self.LA_5b.setVisible(False)\n#            self.LE_5b.setVisible(False)\n#            rayonObjet = 0.0\n\n        #### Inclination\n        grid = QGridLayout()\n        self.GBox_006_Inclination = QGroupBox()\n        if switch_setVisible_GBox_006_Inclination == False:\n            self.GBox_006_Inclination.setVisible(switch_setVisible_GBox_006_Inclination)                  # visibility\n        self.GBox_006_Inclination.setLayout(grid)\n        vbox.addWidget(self.GBox_006_Inclination)\n\n        self.LA_8a = QLabel(self.GBox_006_Inclination)\n        grid.addWidget(self.LA_8a, 0, 0)\n\n        self.PB_Ra = QPushButton()\n        self.PB_Ra.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Degrees))) # icone dans une variable \n        self.PB_Ra.clicked.connect(self.on_PB_Ra_clicked) # \"Radian\"\n        grid.addWidget(self.PB_Ra, 0, 1)\n\n        self.LA_8a_2 = QLabel()\n        grid.addWidget(self.LA_8a_2, 0, 2, 1, 3)\n\n        self.LA_8xy = QLabel()\n        self.LA_8xy.setStyleSheet(u\"QLabel {color : #ff0000; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_8xy, 1, 0)\n\n        self.LE_8xy = QLineEdit()\n        grid.addWidget(self.LE_8xy, 1, 1)\n\n        self.LE_8xya = QLineEdit()\n        grid.addWidget(self.LE_8xya, 1, 2)\n\n        self.LA_8yz = QLabel()\n        self.LA_8yz.setStyleSheet(u\"QLabel {color : #008500; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_8yz, 2, 0)\n\n        self.LE_8yz = QLineEdit()\n        grid.addWidget(self.LE_8yz, 2, 1)\n\n        self.LE_8yza = QLineEdit()\n        grid.addWidget(self.LE_8yza, 2, 2)\n\n        self.LA_8zx = QLabel()\n        self.LA_8zx.setStyleSheet(u\"QLabel {color : #0000ff; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_8zx, 3, 0)\n\n        self.LE_8zx = QLineEdit()\n        grid.addWidget(self.LE_8zx, 3, 1)\n\n        self.LE_8zxa = QLineEdit()\n        grid.addWidget(self.LE_8zxa, 3, 2)\n\n        self.PB_Line_Direction = QPushButton()\n        self.PB_Line_Direction.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_13J))) # icone dans une variable \n        self.PB_Line_Direction.clicked.connect(self.on_PB_Line_Direction)\n        grid.addWidget(self.PB_Line_Direction, 4, 0)\n\n        self.LE_9_Direction = QLineEdit()\n        grid.addWidget(self.LE_9_Direction, 4, 1, 1, 2)\n\n        self.PB_Line_ValueAT = QPushButton()\n        self.PB_Line_ValueAT.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_13M))) # icone dans une variable \n        self.PB_Line_ValueAT.clicked.connect(self.on_PB_Line_ValueAT)\n        grid.addWidget(self.PB_Line_ValueAT, 5, 0)\n\n        self.LE_10_ValueAt = QLineEdit()\n        grid.addWidget(self.LE_10_ValueAt, 5, 1, 1, 2)\n\n        self.PB_Line_NormalAT = QPushButton()\n        self.PB_Line_NormalAT.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_13C))) # icone dans une variable \n        self.PB_Line_NormalAT.clicked.connect(self.on_PB_Line_NormalAT)\n        grid.addWidget(self.PB_Line_NormalAT, 6, 0)\n\n        self.LE_10b_NormalAt = QLineEdit()\n        grid.addWidget(self.LE_10b_NormalAt, 6, 1, 1, 2)\n\n        ##### Surface and Volume\n        grid = QGridLayout()\n        self.GBox_007_Surface_and_Volume = QGroupBox()\n        if switch_setVisible_GBox_007_Surface_and_Volume == False:\n            self.GBox_007_Surface_and_Volume.setVisible(switch_setVisible_GBox_007_Surface_and_Volume)    # visibility\n        self.GBox_007_Surface_and_Volume.setLayout(grid)\n        vbox.addWidget(self.GBox_007_Surface_and_Volume)\n\n        self.LA_9 = QLabel()\n        grid.addWidget(self.LA_9, 0, 0)\n\n        self.LE_9a = QLineEdit()\n        grid.addWidget(self.LE_9a, 0, 1)\n\n        self.LA_10 = QLabel()\n        grid.addWidget(self.LA_10, 1, 0)\n\n        self.LE_10a = QLineEdit()\n        grid.addWidget(self.LE_10a, 1, 1)\n\n        self.LA_11 = QLabel()\n        grid.addWidget(self.LA_11, 2, 0)\n\n        self.LE_11a = QLineEdit()\n        grid.addWidget(self.LE_11a, 2, 1)\n\n        self.LA_Unit = QLabel()\n        grid.addWidget(self.LA_Unit, 3, 0)\n\n        self.comboBox_Unit = QComboBox()\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        self.comboBox_Unit.addItem(_fromUtf8(u\"\"))\n        #self.comboBox_Unit.setCurrentIndex(seTIndexUnitWeight)\n                                                                                                                                   \n        self.comboBox_Unit.currentTextChanged.connect(self.SIGNAL_comboPoids_Changed)\n        grid.addWidget(self.comboBox_Unit, 3, 1)\n\n        self.LA_Weight = QLabel()\n        grid.addWidget(self.LA_Weight, 4, 0)\n\n        self.LA_Density = QLabel()\n        grid.addWidget(self.LA_Density, 4, 1)\n\n        self.LE_12a = QLineEdit()\n        self.LE_12a.setText(str(Around(poids))+\" \"+unitePs)\n        grid.addWidget(self.LE_12a, 5, 0)\n\n        self.DS_Density = QDoubleSpinBox()\n        seTDensiteValue = float(materialAssociated[seTMaterialCurrentIndex].split(\",\")[1])\n        self.DS_Density.setDecimals(seTDensiteDecimalNumber)\n        self.DS_Density.setMinimum(-0.00000001)\n        self.DS_Density.setMaximum(99999999.0)\n        #self.DS_Density.setProperty(u\"value\", seTDensiteValue)\n        self.DS_Density.setValue(seTDensiteValue)\n        self.DS_Density.setSuffix(seTDensiteSuffixChain)\n        self.DS_Density.setSingleStep(seTDensiteSingleStep)\n        self.DS_Density.valueChanged.connect(self.on_DS_Density_valueChanged)\n        grid.addWidget(self.DS_Density, 5, 1)\n\n        self.LA_Material = QLabel()\n        grid.addWidget(self.LA_Material, 6, 0)\n\n        self.CBox_Materiel = QComboBox()\n        for ligneMat in materialAssociated:\n            self.CBox_Materiel.addItem(_fromUtf8(ligneMat))\n        self.CBox_Materiel.setCurrentIndex(seTMaterialCurrentIndex)\n                                                                                                                                      \n        self.CBox_Materiel.currentTextChanged.connect(self.SIGNAL_CBox_Materiel_Changed)\n        grid.addWidget(self.CBox_Materiel,7, 0, 1, 2)\n\n        self.LA_NewMaterial = QLabel()\n        grid.addWidget(self.LA_NewMaterial, 8, 0)\n\n        self.LE_Materiel = QLineEdit()\n        self.LE_Materiel.setText(materialAssociated[seTMaterialCurrentIndex])\n        self.LE_Materiel.returnPressed.connect(self.on_LE_Materiel_Pressed)   # connect \"on_LE_Materiel_Pressed\"   # for validate the data with press on return touch\n        #self.LE_Materiel.textChanged.connect(self.on_LE_Materiel_Pressed)     # connect \"on_LE_Materiel_Pressed\"   # with tips key char by char\n        grid.addWidget(self.LE_Materiel, 9, 0, 1, 2)\n\n        self.PB_Del_Material = QPushButton()\n        self.PB_Del_Material.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_DeleteLineMaterial))) # icone dans une variable \n        self.PB_Del_Material.clicked.connect(self.on_PB_Del_Material_clicked)\n        grid.addWidget(self.PB_Del_Material, 10, 0)\n\n        self.PB_Save_Material = QPushButton()\n        self.PB_Save_Material.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Save_Material))) # icone dans une variable \n        self.PB_Save_Material.clicked.connect(self.on_PB_Save_Material_clicked)\n        grid.addWidget(self.PB_Save_Material, 10, 1)\n\n        #### Cost\n        grid = QGridLayout()\n        self.GBox_008_Cost_And_Price = QGroupBox()\n        if switch_setVisible_GBox_008_Cost_And_Price == False:\n            self.GBox_008_Cost_And_Price.setVisible(switch_setVisible_GBox_008_Cost_And_Price)  # visibility\n        self.GBox_008_Cost_And_Price.setLayout(grid)\n        vbox.addWidget(self.GBox_008_Cost_And_Price)\n\n        self.LA_Cost = QLabel()\n        grid.addWidget(self.LA_Cost, 0, 0)\n\n        self.LA_Price = QLabel()\n        grid.addWidget(self.LA_Price, 0, 1)\n\n        self.LE_Cost = QLineEdit()\n        seTMaterialCost = ((volume_ * seTDensiteValue * seTMaterialPrice) / 1000000.0)\n        self.LE_Cost.setText(str(Around(seTMaterialCost)) + seTMaterialSuffixCost) #CostMaterial\n        grid.addWidget(self.LE_Cost, 1, 0)\n\n        self.DS_Price = QDoubleSpinBox()\n        self.DS_Price.setDecimals(seTDensiteDecimalNumber)\n        self.DS_Price.setMinimum(-0.00000001)\n        self.DS_Price.setMaximum(99999999.0)\n        #self.DS_Price.setProperty(u\"value\", seTMaterialPrice)\n        self.DS_Price.setValue(seTMaterialPrice)\n        self.DS_Price.setSuffix(seTMaterialSuffixDevise)\n        self.DS_Price.setSingleStep(1)\n        self.DS_Price.valueChanged.connect(self.on_DS_Price_valueChanged)\n        grid.addWidget(self.DS_Price, 1, 1)\n\n        ##### BoundBox\n        grid = QGridLayout()\n        self.GBox_009_BoundBox = QGroupBox()\n        if switch_setVisible_GBox_009_BoundBox == False:\n            self.GBox_009_BoundBox.setVisible(switch_setVisible_GBox_009_BoundBox)          # visibility\n        self.GBox_009_BoundBox.setLayout(grid)\n        vbox.addWidget(self.GBox_009_BoundBox)\n\n        self.LA_007_01_Xlength = QLabel()\n        self.LA_007_01_Xlength.setStyleSheet(u\"QLabel {color : #ff0000; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_007_01_Xlength, 0, 0)\n\n        self.LA_007_02_Ylength = QLabel()\n        self.LA_007_02_Ylength.setStyleSheet(u\"QLabel {color : #008500; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_007_02_Ylength, 0, 1)\n\n        self.LA_007_03_Zlength = QLabel()\n        self.LA_007_03_Zlength.setStyleSheet(u\"QLabel {color : #0000ff; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_007_03_Zlength, 0, 2)\n\n        self.LA_007_04_Diagonallength = QLabel()\n        grid.addWidget(self.LA_007_04_Diagonallength, 0, 3)\n\n        self.LE_007_BB_01_XLength = QLineEdit()\n        grid.addWidget(self.LE_007_BB_01_XLength, 1, 0)\n\n        self.LE_007_BB_02_YLength = QLineEdit()\n        grid.addWidget(self.LE_007_BB_02_YLength, 1, 1)\n\n        self.LE_007_BB_03_ZLength = QLineEdit()\n        grid.addWidget(self.LE_007_BB_03_ZLength, 1, 2)\n\n        self.LE_007_BB_04_Diagonal = QLineEdit()\n        grid.addWidget(self.LE_007_BB_04_Diagonal, 1, 3)\n\n        self.PB_BoundBox_Tracing = QPushButton()\n        self.PB_BoundBox_Tracing.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_BoundBoxTracing))) # icone dans une variable \n        self.PB_BoundBox_Tracing.clicked.connect(self.on_PB_BoundBox_Tracing)\n        grid.addWidget(self.PB_BoundBox_Tracing, 2, 0)\n\n        self.PB_00_BoundBox_Volume = QPushButton()\n        self.PB_00_BoundBox_Volume.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_BoundBoxVolume))) # icone dans une variable \n        self.PB_00_BoundBox_Volume.clicked.connect(self.On_PB_00_BoundBox_Volume)\n        grid.addWidget(self.PB_00_BoundBox_Volume, 2, 1)\n\n        self.CB_01_BoundBox_Text = QCheckBox()\n        self.CB_01_BoundBox_Text.setChecked(switchBoundBoxCreateText)\n        self.CB_01_BoundBox_Text.clicked.connect(self.On_CB_01_BoundBox_Text)\n        grid.addWidget(self.CB_01_BoundBox_Text, 2, 2)\n\n        self.DS_BoundBoxTextHeigth = QDoubleSpinBox()\n        self.DS_BoundBoxTextHeigth.setMinimum(-0.00000001)\n        self.DS_BoundBoxTextHeigth.setMaximum(99999999.0)\n        #self.DS_BoundBoxTextHeigth.setProperty(u\"value\", seTBoundBoxTextHeigth)\n        self.DS_BoundBoxTextHeigth.setValue(seTBoundBoxTextHeigth)\n        self.DS_BoundBoxTextHeigth.setDecimals(seTDensiteDecimalNumber)\n        self.DS_BoundBoxTextHeigth.setSingleStep(1)\n        self.DS_BoundBoxTextHeigth.setEnabled(switchBoundBoxCreateText)\n        self.DS_BoundBoxTextHeigth.valueChanged.connect(self.on_DS_BoundBoxTextHeigth_valueChanged)\n        grid.addWidget(self.DS_BoundBoxTextHeigth, 2, 3)\n\n        ##### Center of:\n        grid = QGridLayout()\n        self.GBox_010_Center_Mass = QGroupBox()\n        if switch_setVisible_GBox_010_Center_Mass == False:\n            self.GBox_010_Center_Mass.setVisible(switch_setVisible_GBox_010_Center_Mass)  # visibility\n        self.GBox_010_Center_Mass.setLayout(grid)\n        vbox.addWidget(self.GBox_010_Center_Mass)\n\n        self.LA_13x = QLabel()\n        self.LA_13x.setStyleSheet(u\"QLabel {color : #ff0000; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_13x, 1, 0)\n\n        self.LA_13y = QLabel()\n        self.LA_13y.setStyleSheet(u\"QLabel {color : #008500; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_13y, 1, 1)\n\n        self.LA_13z = QLabel()\n        self.LA_13z.setStyleSheet(u\"QLabel {color : #0000ff; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_13z, 1, 2)\n\n        self.LE_13x = QLineEdit()\n        grid.addWidget(self.LE_13x, 2, 0)\n\n        self.LE_13y = QLineEdit()\n        grid.addWidget(self.LE_13y, 2, 1)\n\n        self.LE_13z = QLineEdit()\n        grid.addWidget(self.LE_13z, 2, 2)\n\n        self.PB_Axis_02 = QPushButton()\n        self.PB_Axis_02.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_05))) # icone dans une variable \n        self.PB_Axis_02.clicked.connect(self.on_PB_Axis_Center_Shape)\n        grid.addWidget(self.PB_Axis_02, 2, 3)\n\n        self.LA_14x = QLabel()\n        self.LA_14x.setStyleSheet(u\"QLabel {color : #ff0000; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_14x, 4, 0)\n\n        self.LA_14y = QLabel()\n        self.LA_14y.setStyleSheet(u\"QLabel {color : #008500; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_14y, 4, 1)\n\n        self.LA_14z = QLabel()\n        self.LA_14z.setStyleSheet(u\"QLabel {color : #0000ff; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_14z, 4, 2)\n\n        self.LE_14x = QLineEdit()\n        grid.addWidget(self.LE_14x, 5, 0)\n\n        self.LE_14y = QLineEdit()\n        grid.addWidget(self.LE_14y, 5, 1)\n\n        self.LE_14z = QLineEdit()\n        grid.addWidget(self.LE_14z, 5, 2)\n\n        self.PB_Axis_03 = QPushButton()\n        self.PB_Axis_03.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_05))) # icone dans une variable \n        self.PB_Axis_03.clicked.connect(self.on_PB_Axis_Center_Mass)\n        grid.addWidget(self.PB_Axis_03, 5, 3)\n\n        ##### Inertia\n        grid = QGridLayout()\n        self.GBox_011_Inertia = QGroupBox()\n        if switch_setVisible_GBox_011_Inertia == False:\n            self.GBox_011_Inertia.setVisible(switch_setVisible_GBox_011_Inertia) # visibility\n        self.GBox_011_Inertia.setLayout(grid)\n        vbox.addWidget(self.GBox_011_Inertia)\n\n        self.LA_16 = QLabel()\n        grid.addWidget(self.LA_16, 0, 0, 1, 3)\n\n        self.LE_16_Raw = QLineEdit()  # mode RAW\n        grid.addWidget(self.LE_16_Raw, 1, 0, 1, 5)\n\n        ##oriself.LE_16_M = QLineEdit() # change en spinBox\n        self.SB_16_M = QSpinBox()\n        #self.SB_16_M.setEnabled(False)\n        self.SB_16_M.setMinimum(0)\n        self.SB_16_M.setMaximum(999999)\n        self.SB_16_M.setPrefix(u\"mm^\")\n        self.SB_16_M.setAlignment(QtCore.Qt.AlignCenter)\n        self.SB_16_M.setValue(setMomentOfInertia_16)\n        self.SB_16_M.valueChanged.connect(self.on_SB_16_M_valueChanged)\n        self.SB_16_M.setStyleSheet(u\"QLineEdit {color: #000000; font: bold}\")   # couleur du texte et gras\n        grid.addWidget(self.SB_16_M, 2, 3, 1, 2)\n\n        self.LA_16x = QLabel()\n        self.LA_16x.setStyleSheet(u\"QLabel {color: #ff0000; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_16x, 2, 0)\n\n        self.LA_16y = QLabel()\n        self.LA_16y.setStyleSheet(u\"QLabel {color: #008500; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_16y, 2, 1)\n\n        self.LA_16z = QLabel()\n        self.LA_16z.setStyleSheet(u\"QLabel {color: #0000ff; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_16z, 2, 2)\n\n        self.LE_16_1x = QLineEdit()\n        self.LE_16_1x.setAlignment(QtCore.Qt.AlignLeft)\n        self.LE_16_1x.cursorPosition()\n        self.LE_16_1x.setCursorPosition(1)\n        grid.addWidget(self.LE_16_1x, 3, 0)\n\n        self.LE_16_1y = QLineEdit()\n        self.LE_16_1y.setAlignment(QtCore.Qt.AlignLeft)\n        self.LE_16_1y.cursorPosition()\n        self.LE_16_1y.setCursorPosition(1)\n        grid.addWidget(self.LE_16_1y, 3, 1)\n\n        self.LE_16_1z = QLineEdit()\n        self.LE_16_1z.setAlignment(QtCore.Qt.AlignLeft)\n        self.LE_16_1z.cursorPosition()\n        self.LE_16_1z.setCursorPosition(1)\n        grid.addWidget(self.LE_16_1z, 3, 2)\n\n        self.LE_16_01 = QLineEdit()\n        self.LE_16_01.setEnabled(False)\n        grid.addWidget(self.LE_16_01, 3, 3)\n\n        self.PB_Axis_04_16_1 = QPushButton()\n        self.PB_Axis_04_16_1.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_05))) # icone dans une variable \n        self.PB_Axis_04_16_1.clicked.connect(self.on_PB_Axis_04_16_1)\n        grid.addWidget(self.PB_Axis_04_16_1, 3, 4)\n\n        self.LE_16_2x = QLineEdit()\n        grid.addWidget(self.LE_16_2x, 4, 0)\n\n        self.LE_16_2y = QLineEdit()\n        grid.addWidget(self.LE_16_2y, 4, 1)\n\n        self.LE_16_2z = QLineEdit()\n        grid.addWidget(self.LE_16_2z, 4, 2)\n\n        self.LE_16_02 = QLineEdit()\n        self.LE_16_02.setEnabled(False)\n        grid.addWidget(self.LE_16_02, 4, 3)\n\n        self.PB_Axis_05_16_2 = QPushButton()\n        self.PB_Axis_05_16_2.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_05))) # icone dans une variable \n        self.PB_Axis_05_16_2.clicked.connect(self.on_PB_Axis_05_16_2)\n        grid.addWidget(self.PB_Axis_05_16_2, 4, 4)\n\n        self.LE_16_3x = QLineEdit()\n        grid.addWidget(self.LE_16_3x, 5, 0)\n\n        self.LE_16_3y = QLineEdit()\n        grid.addWidget(self.LE_16_3y, 5, 1)\n\n        self.LE_16_3z = QLineEdit()\n        grid.addWidget(self.LE_16_3z, 5, 2)\n\n        self.LE_16_03 = QLineEdit()\n        self.LE_16_03.setEnabled(False)\n        grid.addWidget(self.LE_16_03, 5, 3)\n\n        self.PB_Axis_06_16_3 = QPushButton()\n        self.PB_Axis_06_16_3.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_05))) # icone dans une variable \n        self.PB_Axis_06_16_3.clicked.connect(self.on_PB_Axis_06_16_3)\n        grid.addWidget(self.PB_Axis_06_16_3, 5, 4)\n\n        self.LE_16_4x = QLineEdit()\n        self.LE_16_4x.setEnabled(False)\n        grid.addWidget(self.LE_16_4x, 6, 0)\n\n        self.LE_16_4y = QLineEdit()\n        self.LE_16_4y.setEnabled(False)\n        grid.addWidget(self.LE_16_4y, 6, 1)\n\n        self.LE_16_4z = QLineEdit()\n        self.LE_16_4z.setEnabled(False)\n        grid.addWidget(self.LE_16_4z, 6, 2)\n\n        self.LE_16_04 = QLineEdit()\n        self.LE_16_04.setEnabled(False)\n        grid.addWidget(self.LE_16_04, 6, 3)\n\n        self.PB_Axis_07_16_4 = QPushButton()\n        self.PB_Axis_07_16_4.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_05))) # icone dans une variable \n        self.PB_Axis_07_16_4.clicked.connect(self.on_PB_Axis_07_16_4)\n        grid.addWidget(self.PB_Axis_07_16_4, 6, 4)\n\n        self.LA_17 = QLabel()\n        grid.addWidget(self.LA_17, 7, 0, 1, 3)\n\n        ##self.LE_17_M = QLineEdit() # change en spinBox\n        self.SB_17_M = QSpinBox()\n        #self.SB_17_M.setEnabled(False)\n        self.SB_17_M.setMinimum(0)\n        self.SB_17_M.setMaximum(999999)\n        self.SB_17_M.setPrefix(u\"mm2^\")\n        self.SB_17_M.setAlignment(QtCore.Qt.AlignCenter)\n        self.SB_17_M.setValue(setMomentOfInertiaMassique_17)\n        self.SB_17_M.valueChanged.connect(self.on_SB_17_M_valueChanged)\n        self.SB_17_M.setAlignment(QtCore.Qt.AlignCenter)\n        self.SB_17_M.setStyleSheet(u\"QLineEdit {color: #000000; font: bold}\")   # couleur du texte et gras\n        grid.addWidget(self.SB_17_M, 8, 3, 1, 2)\n\n        self.LA_17x = QLabel()\n        self.LA_17x.setStyleSheet(u\"QLabel {color: #ff0000; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_17x, 8, 0)\n\n        self.LA_17y = QLabel()\n        self.LA_17y.setStyleSheet(u\"QLabel {color: #008500; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_17y, 8, 1)\n\n        self.LA_17z = QLabel()\n        self.LA_17z.setStyleSheet(u\"QLabel {color: #0000ff; font: bold}\")       # couleur du texte et gras\n        grid.addWidget(self.LA_17z, 8, 2)\n\n        self.LE_17_1x = QLineEdit()\n        grid.addWidget(self.LE_17_1x, 9, 0)\n\n        self.LE_17_1y = QLineEdit()\n        grid.addWidget(self.LE_17_1y, 9, 1)\n\n        self.LE_17_1z = QLineEdit()\n        grid.addWidget(self.LE_17_1z, 9, 2)\n\n        self.PB_Axis_08_17_1 = QPushButton()\n        self.PB_Axis_08_17_1.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_05))) # icone dans une variable \n        self.PB_Axis_08_17_1.clicked.connect(self.on_PB_Axis_08_17_1)\n        grid.addWidget(self.PB_Axis_08_17_1, 9, 4)\n\n        self.LE_17_2x = QLineEdit()\n        grid.addWidget(self.LE_17_2x, 10, 0)\n\n        self.LE_17_2y = QLineEdit()\n        grid.addWidget(self.LE_17_2y, 10, 1)\n\n        self.LE_17_2z = QLineEdit()\n        grid.addWidget(self.LE_17_2z, 10, 2)\n\n        self.PB_Axis_09_17_2 = QPushButton()\n        self.PB_Axis_09_17_2.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_05))) # icone dans une variable \n        self.PB_Axis_09_17_2.clicked.connect(self.on_PB_Axis_09_17_2)\n        grid.addWidget(self.PB_Axis_09_17_2, 10, 4)\n\n        self.LE_17_3x = QLineEdit()\n        grid.addWidget(self.LE_17_3x, 11, 0)\n\n        self.LE_17_3y = QLineEdit()\n        grid.addWidget(self.LE_17_3y, 11, 1)\n\n        self.LE_17_3z = QLineEdit()\n        grid.addWidget(self.LE_17_3z, 11, 2)\n\n        self.PB_Axis_10_17_3 = QPushButton()\n        self.PB_Axis_10_17_3.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_05))) # icone dans une variable \n        self.PB_Axis_10_17_3.clicked.connect(self.on_PB_Axis_10_17_3)\n        grid.addWidget(self.PB_Axis_10_17_3, 11, 4)\n\n        self.PB_Axis_11_17_4 = QPushButton()\n        self.PB_Axis_11_17_4.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_05))) # icone dans une variable \n        self.PB_Axis_11_17_4.clicked.connect(self.on_PB_Axis_11_17_4)\n        grid.addWidget(self.PB_Axis_11_17_4, 12, 4)\n\n        self.LA_determinant = QLabel()\n        grid.addWidget(self.LA_determinant, 13, 0, 1, 1)\n\n        self.LE_18_determinant = QLineEdit()\n        grid.addWidget(self.LE_18_determinant, 13, 1, 1, 4)\n\n        self.LA_determinantDecimal = QLabel()\n        grid.addWidget(self.LA_determinantDecimal, 14, 0, 1, 1)\n\n        self.LE_18_determinantDecim = QLineEdit()\n        grid.addWidget(self.LE_18_determinantDecim, 14, 1, 1, 4)\n                            \n        #### Disabled Module (SpreadSheet)\n        grid = QGridLayout()\n        self.GBox_012_SpreadSheet = QGroupBox()\n        if switch_setVisible_GBox_012_SpreadSheet == False:\n            self.GBox_012_SpreadSheet.setVisible(switch_setVisible_GBox_012_SpreadSheet) # visibility\n        self.GBox_012_SpreadSheet.setCheckable(True)\n        self.GBox_012_SpreadSheet.setChecked(False)\n        self.GBox_012_SpreadSheet.setStyleSheet(u\"QGroupBox {color : #ff0000}\")\n        self.GBox_012_SpreadSheet.clicked.connect(self.on_GBox_012_SpreadSheet)\n        self.GBox_012_SpreadSheet.setLayout(grid)\n        vbox.addWidget(self.GBox_012_SpreadSheet)\n\n        self.tableWidget = QTableWidget() # self.GBox_012_SpreadSheet\n        self.tableWidget.setIconSize(QtCore.QSize(15, 15))\n        self.tableWidget.setRowCount(RowCount)\n        self.tableWidget.setColumnCount(8)          # number of columns\n        self.tableWidget.horizontalHeader().setVisible(False)\n        self.tableWidget.horizontalHeader().setDefaultSectionSize(100)\n        self.tableWidget.horizontalHeader().setMinimumSectionSize(15)\n        self.tableWidget.verticalHeader().setVisible(True)\n        self.tableWidget.verticalHeader().setCascadingSectionResizes(False)\n        self.tableWidget.verticalHeader().setDefaultSectionSize(20)\n        self.tableWidget.verticalHeader().setMinimumSectionSize(20)\n        grid.addWidget(self.tableWidget, 0, 0, 4, 4)\n\n        #### SpreadSheet (options CSV debut)\n        grid = QGridLayout()\n        self.GBox_013_SpreadSheet_Creation = QGroupBox()\n        if switch_setVisible_GBox_013_SpreadSheet_Creation == False:\n            self.GBox_013_SpreadSheet_Creation.setVisible(switch_setVisible_GBox_013_SpreadSheet_Creation) # visibility\n        self.GBox_013_SpreadSheet_Creation.setLayout(grid)\n        vbox.addWidget(self.GBox_013_SpreadSheet_Creation)\n\n        #### SpreadSheet dans le document\n        self.PB_03_Create_SpreadSheet = QPushButton()\n        self.PB_03_Create_SpreadSheet.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_SpreadSheet))) # icone dans une variable \n        self.PB_03_Create_SpreadSheet.clicked.connect(self.on_PB_03_Create_SpreadSheet_clicked)\n        grid.addWidget(self.PB_03_Create_SpreadSheet, 0, 0, 1, 2)\n\n        self.LE_SpreadSheet = QLineEdit()\n        self.LE_SpreadSheet.setText(newSpreadSheetName)\n        self.LE_SpreadSheet.textChanged.connect(self.on_LE_SpreadSheet_Pressed)\n        grid.addWidget(self.LE_SpreadSheet, 0, 2, 1, 2)\n\n        self.PB_SpreadSheet_Refresh = QPushButton()\n        self.PB_SpreadSheet_Refresh.clicked.connect(self.on_PB_SpreadSheet_clicked)\n        grid.addWidget(self.PB_SpreadSheet_Refresh, 1, 0, 1, 2)\n\n        self.ComboB_SpreadSheet = QComboBox()\n                                                                                                                                   \n        self.ComboB_SpreadSheet.currentTextChanged.connect(self.On_ComboB_SpreadSheet)\n        grid.addWidget(self.ComboB_SpreadSheet, 1, 2, 1, 2)\n\n        #### SpreadSheet sur disque\n        self.PB_01_Read_SpreadSheet = QPushButton()\n        self.PB_01_Read_SpreadSheet.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_04))) # icone dans une variable \n        self.PB_01_Read_SpreadSheet.clicked.connect(self.on_PB_01_Read_SpreadSheet_clicked)\n        grid.addWidget(self.PB_01_Read_SpreadSheet, 2, 0, 1, 1)\n\n        self.PB_02_Save_SreadSheet = QPushButton()\n        self.PB_02_Save_SreadSheet.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_03))) # icone dans une variable \n        self.PB_02_Save_SreadSheet.clicked.connect(self.on_PB_02_Save_SreadSheet_clicked)\n        grid.addWidget(self.PB_02_Save_SreadSheet, 2, 1, 1, 1)\n\n        self.RB_01_Tabulation = QRadioButton()\n        self.RB_01_Tabulation.setChecked(True)\n\n        self.RB_01_Tabulation.clicked.connect(self.on_RB_Separation)\n        grid.addWidget(self.RB_01_Tabulation, 3, 0)\n\n        self.RB_02_Virgule = QRadioButton()\n        self.RB_02_Virgule.clicked.connect(self.on_RB_Separation)\n        grid.addWidget(self.RB_02_Virgule, 3, 1)\n\n        self.RB_03_Point_Virgule = QRadioButton()\n        self.RB_03_Point_Virgule.clicked.connect(self.on_RB_Separation)\n        grid.addWidget(self.RB_03_Point_Virgule, 3, 2)\n\n        self.RB_04_Espace = QRadioButton()\n        self.RB_04_Espace.clicked.connect(self.on_RB_Separation)\n        grid.addWidget(self.RB_04_Espace, 3, 3)\n        #options CSV fin\n\n        #### Main\n        grid = QGridLayout()\n        self.GBox_014_Main_Tools = QGroupBox()\n        if switch_setVisible_GBox_014_Main_Tools == False:\n            self.GBox_014_Main_Tools.setVisible(switch_setVisible_GBox_014_Main_Tools)     # visibility\n        self.GBox_014_Main_Tools.setLayout(grid)\n        vbox.addWidget(self.GBox_014_Main_Tools)\n\n        self.CB_01_Info = QCheckBox()\n        self.CB_01_Info.setChecked(switchDisplayInfoObject)\n        self.CB_01_Info.clicked.connect(self.on_CB_01_Info)\n        grid.addWidget(self.CB_01_Info, 0, 0, 1, 2)\n\n        self.CB_02_Point = QCheckBox()\n        self.CB_02_Point.setChecked(switchCreatePoint)\n        self.CB_02_Point.clicked.connect(self.on_CB_02_Point)\n        grid.addWidget(self.CB_02_Point, 0, 1)\n\n        self.CB_03_Axis = QCheckBox()\n        self.CB_03_Axis.setChecked(switchCreateAxis) #False\n        self.CB_03_Axis.clicked.connect(self.on_CB_03_Axis)\n        grid.addWidget(self.CB_03_Axis, 0, 2)\n\n        self.CB_04_Plane = QCheckBox()\n        self.CB_04_Plane.setChecked(switchCreatePlane) #False\n        self.CB_04_Plane.clicked.connect(self.on_CB_04_Plane)\n        grid.addWidget(self.CB_04_Plane, 0, 3)\n\n        self.RB_00_ClipBoard = QRadioButton()\n        if seTMemoClipBoard == 0:\n            self.RB_00_ClipBoard.setChecked(True)\n        self.RB_00_ClipBoard.clicked.connect(self.on_RB_00_ClipBoard)\n        grid.addWidget(self.RB_00_ClipBoard, 1, 0)\n\n        self.RB_01_ClipBoard = QRadioButton()\n        if seTMemoClipBoard == 1:\n            self.RB_01_ClipBoard.setChecked(True)\n        self.RB_01_ClipBoard.clicked.connect(self.on_RB_01_ClipBoard)\n        grid.addWidget(self.RB_01_ClipBoard, 1, 1)\n\n        self.RB_02_ClipBoard = QRadioButton()\n        if seTMemoClipBoard == 2:\n            self.RB_02_ClipBoard.setChecked(True)\n        self.RB_02_ClipBoard.clicked.connect(self.on_RB_02_ClipBoard)\n        grid.addWidget(self.RB_02_ClipBoard, 1, 2)\n\n        self.RB_03_ClipBoard = QRadioButton()\n        if seTMemoClipBoard == 3:\n            self.RB_03_ClipBoard.setChecked(True)\n        self.RB_03_ClipBoard.clicked.connect(self.on_RB_03_ClipBoard)\n        grid.addWidget(self.RB_03_ClipBoard, 1, 3)\n\n        self.CB_05_Position = QCheckBox()\n        self.CB_05_Position.setChecked(False)\n        if seTPositionFlyRightLeft == 1:\n            self.CB_05_Position.setVisible(False)\n        elif seTPositionFlyRightLeft == 2:\n            self.CB_05_Position.setChecked(False)\n        else:\n            self.CB_05_Position.setChecked(True)\n        self.CB_05_Position.clicked.connect(self.on_CB_05_Position)\n        grid.addWidget(self.CB_05_Position, 2, 0)\n\n        self.SPBox_arrondi = QSpinBox()\n        self.SPBox_arrondi.setMinimum(-1)\n        self.SPBox_arrondi.setMaximum(1000)\n        #self.SPBox_arrondi.setProperty(u\"value\", seTDecimalValue)\n        self.SPBox_arrondi.setValue(seTDecimalValue)\n        self.SPBox_arrondi.setSuffix(u\" (Decimals)\")\n        self.SPBox_arrondi.valueChanged.connect(self.on_SPBox_arrondi_valueChanged)\n        grid.addWidget(self.SPBox_arrondi, 3, 0, 1, 2)\n\n        self.SP_012_01_Text = QSpinBox()\n        self.SP_012_01_Text.setMinimum(0)\n        self.SP_012_01_Text.setMaximum(99999999)\n        self.SP_012_01_Text.setValue(seTTextHeigthValue)\n        self.SP_012_01_Text.setSuffix(u\" (Text Height)\")\n        self.SP_012_01_Text.valueChanged.connect(self.on_SP_012_01_Text_valueChanged)\n        grid.addWidget(self.SP_012_01_Text, 3, 2, 1, 2)\n\n        self.PB_05_Help_Forum = QPushButton()\n        self.PB_05_Help_Forum.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_WebForum))) # icone dans une variable \n        self.PB_05_Help_Forum.clicked.connect(self.on_PB_05_Help_Forum_clicked)\n        grid.addWidget(self.PB_05_Help_Forum, 4, 0, 1, 2)\n\n        self.PB_06_Help_Wiki = QPushButton()\n        self.PB_06_Help_Wiki.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_WebWiki))) # icone dans une variable \n        self.PB_06_Help_Wiki.clicked.connect(self.on_PB_06_Help_Wiki)\n        grid.addWidget(self.PB_06_Help_Wiki, 4, 2, 1, 2)\n\n        self.PB_01_Refrech = QPushButton()\n        self.PB_01_Refrech.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_02))) # icone dans une variable \n        self.PB_01_Refrech.clicked.connect(self.on_PB_01_Refrech_clicked)\n        grid.addWidget(self.PB_01_Refrech, 5, 0, 1, 2)\n\n        self.PB_04_Quit = QPushButton()\n        self.PB_04_Quit.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_01))) # icone dans une variable \n        self.PB_04_Quit.clicked.connect(self.on_PB_04_Quit)\n        grid.addWidget(self.PB_04_Quit, 5, 2, 1, 2)\n\n        ###########################################################scrollArea\n        self.scrollArea.setWidget(self.scrollAreaWidgetContents_2)\n        ###########################################################scrollArea\n\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n        if seTPositionFlyRightLeft == 1:                                                 # 1=MainWindow separate\n            #MainWindow.setWindowTitle(__Title__  + u\" rmu (\" + __Version__ + \") (\" + __Date__ + \")\")\n            MainWindow.setCentralWidget(self.centralWidget)\n            MainWindow.move(1000, 120)                           # deplace la fenetre\n        else:\n            #MainWindow.setWindowTitle(__Title__  + u\" rmu (\" + __Version__ + \") (\" + __Date__ + \")\")\n            MainWindow.setWidget(self.centralWidget)\n\n        platform_node = \"\" #platform.node()\n        platform_system = platform.system()\n        MainWindow.setWindowTitle(__Title__  + u\" rmu (\" + __Version__ + \") (\" + __Date__ + \") (\" + platform_system + \") (\" + platform_node + \")\")\n\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n\n        global diffuseColorRF\n        global diffuseColorVF\n        global diffuseColorBF\n        global diffuseColorTF\n        global unsignedEncodeColor\n\n        global typeLongueur\n        global path\n        global volume_ \n        global longueurObjet\n        global rayonObjet\n        global perimetre\n        global seTDensiteValue\n        global seTIndexUnitWeight\n        global seTIndexUnitLength\n        global materialAssociated\n        global seTMaterialFileName\n        global seTMaterialSavePathName\n        global seTMaterialSuffixCost\n        global seTMaterialPrice\n        global seTMaterialCost\n        global seTTextHeigthValue\n        global directionObj\n        global direcValueAt\n        global direcNormalAt\n        global poids\n        global unitePs\n        global numberEdges\n        global nombreArretesMesh\n        global nombreFacesMesh\n        global nombrePointsMesh\n        global seTUnitSymbolMicro\n        global BsplineDetect\n        global BsplineNombreDeNoeuds\n        global BsplineRayonApproximatif\n        global BsplineCercleToolTip\n        global BsplineNumberElement\n        global BsplineCutLength\n        global BsplinePointsCoor\n        global setBSplineToByArcValue\n        global BSplinetoByArcValeurS\n        global switchCreateLineDiVatNatOnClick\n        global switchSetPlaceholderText\n        global typeNormalAt\n\n        #self.LA_determinantDecimal = QLabel()\n        #grid.addWidget(self.LA_determinantDecimal, 14, 0, 1, 1)\n\n        self.on_SP_012_01_Text_valueChanged(seTTextHeigthValue)    # actualise text\n\n        MainWindow.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)        # PySide cette fonction met la fenetre en avant\n        ##https://doc.qt.io/qt-5/qtwidgets-widgets-windowflags-example.html\n        #MainWindow.setWindowFlags(QtCore.Qt.WindowTitleHint)            # 2 absents X grise (fonctionne pas dans ComboView et desactive WindowStaysOnTopHint)\n        #MainWindow.setWindowFlags(QtCore.Qt.WindowContextHelpButtonHint)# WindowCloseButtonHint , setCancelButton(None)\n        MainWindow.setWindowIcon(QtGui.QIcon(path+'FCInfo.png'))                 # icone dans fichier\n\n        pointPlanAxesTexte = (\n        u\"Create Point or Axis or Plane or Clipboard\" + \"\\n\" +\n        u\"Mouse coordinates\" + \"\\n\\n\" +\n        u\"The coordinates are cliped to this form\" + \"\\n\" +\n        u\"FreeCAD.Vector(-24.0, 240.0, 7.0)\" + \"\\n\" +\n        u\"X, Y, Z (separated by comma)\" + \"\\n\" +\n        u\"X Y Z  (separated by space)\" + \"\\n\" +\n        u\"depend option on choice\" + \"\\n\"\n        )\n\n        ####\n        self.GBox_001_Document.setTitle(u\"Document\")\n        self.LE_1.setText(document_)\n        self.LE_1.setToolTip(u\"Name of the active document.\")\n        self.LE_2.setText(object_Label)\n        self.LE_2.setToolTip(u\"Label of the selected object.\")\n        self.LE_2a.setText(object_Name)\n        self.LE_2a.setToolTip(u\"Internal name of the element.\")\n        self.LE_3.setText(str(subElemName))\n        self.LE_3.setToolTip(u\"Name of the selected SubObject.\")\n        self.LE_3a.setText(str(typeObject))\n        self.LE_3a.setToolTip(u\"Type of the selected (Shape) object.\")\n        self.LE_4.setText(str(object_Type))\n        self.LE_4.setToolTip(u\"TypeID of the selected Object.\")\n#        self.LE_Curve.setText(str(curveObject))\n#        self.LE_Curve.setToolTip(u\"Curve.\")\n\n        self.LA_1.setText(u\"Document name\")\n        self.LA_2.setText(u\"Label / Internal-Name\")\n        self.LA_3.setText(u\"Sub.Shape / Type\")\n        self.LA_4.setText(u\"Shape.TypeID / TypeID\")\n#        self.LA_Curve.setText(u\"Curve\")\n\n        ####\n        self.GBox_002_Coordinate_Mouse.setTitle(u\"Coordinate click mouse\")\n        self.LA_4x.setText(u\"X\")\n        self.LA_4y.setText(u\"Y\")\n        self.LA_4z.setText(u\"Z\")\n        self.LE_4x.setText(str(Around(position0)))\n        self.LE_4x.setToolTip(u\"X coordinate of the click of the mouse.\")\n        self.LE_4y.setText(str(Around(position1)))\n        self.LE_4y.setToolTip(u\"Y coordinate of the click of the mouse.\")\n        self.LE_4z.setText(str(Around(position2)))\n        self.LE_4z.setToolTip(u\"Z coordinate of the click of the mouse.\")\n        self.PB_Axis_01.setToolTip(pointPlanAxesTexte)\n\n        ####\n        self.GBox_003_Color.setTitle(u\"Color on point\")\n        self.LA_1_Red.setText(u\"Red\")\n        self.LA_2_Green.setText(u\"Green\")\n        self.LA_3_Blue.setText(u\"Blue\")\n        self.LA_4_Transparent.setText(u\"Transparency\")\n        self.LE_CRed.setText(str(Around(diffuseColorRF)))\n        self.LE_CRed.setToolTip(u\"Color Red on clicked point (format FreeCAD)\" + \"\\n\" +\n                                u\"The frame is colored with the percent of red displayed\")\n        self.LE_CRed.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: rgb(\"+str(int(diffuseColorRF*255.0))+\", 0, 0)}\") # white and red\n        self.LE_CGreen.setText(str(Around(diffuseColorVF)))\n        self.LE_CGreen.setToolTip(u\"Color Green on clicked point (format FreeCAD)\" + \"\\n\" +\n                                  u\"The frame is colored with the percent of green displayed\")\n        self.LE_CGreen.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: rgb(0, \"+str(int(diffuseColorVF*255.0))+\", 0)}\") # white and green\n        self.LE_CBlue.setText(str(Around(diffuseColorBF)))\n        self.LE_CBlue.setToolTip(u\"Color Blue on clicked point (format FreeCAD)\" + \"\\n\" +\n                                 u\"The frame is colored with the percent of blue displayed\")\n        self.LE_CBlue.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: rgb(0, 0, \"+str(int(diffuseColorBF*255.0))+\")}\") # white and blue\n        self.LE_Transparent.setText(str(Around(diffuseColorTF)))\n        self.LE_Transparent.setToolTip(u\"Transparency on clicked point  (format FreeCAD)\")\n        self.LE_ConversionUnsigned.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: rgb(\"+str(int(diffuseColorRF*255.0))+\",\"+str(int(diffuseColorVF*255.0))+\",\"+str(int(diffuseColorBF*255.0))+\")}\") # white\n        self.LE_ConversionUnsigned.setText(str(unsignedEncodeColor))\n        self.LE_ConversionUnsigned.setToolTip(u'Give different mode codification of colors' + '\\n'\n                                              u'The frame is colored with the same color on point clicked' + '\\n\\n' +\n                                              u'Example displayed :' + '\\n\\n'\n                                              u'1:\\t\\t2:\\t\\t3:\\t\\t4:\\t\\t5:' + '\\n'\n                                              u'\"86057986\"\\t, \"#052123\"\\t, \"0x52123\"\\t, \"5,33,35\"\\t, \"0.0196,0.1294,0.1373\"' + '\\n\\n'\n                                              u'1: 86057986\\t: Mode RVBA Int unsigned (format in FreeCAD preferences) Alpha = 255' + '\\n'\n                                              u'2: #052123\\t: Mode RVB  Hexadecimal  (Qt setStyleSheet(\"color : #052123\")' + '\\n'\n                                              u'3: 0x052123\\t: Mode RVB  Hexadecimal  (Python: hex(336163)' + '\\n'\n                                              u'4: RVB decim\\t: Mode RVB  (Qt setStyleSheet(\"background-color: rgb(5, 33, 36)\"))' + '\\n'\n                                              u'5: RVB float\\t: Mode RVB format float de 0.0 to 1.0' + '\\n'\n                                              u'\\t\\t(The number of decimals depend of the option \"x (Decimals)\") (seTDecimalValue)' + '\\n\\n')\n        self.CBox_Color_FaceObject.setText(u\"Sub.Objet\")\n        self.CBox_Color_FaceObject.setToolTip(u\"Change the color of the selected object or subobject\" + \"\\n\" +\n                                              u\"If this box is activated the face or sub Object selected is modified or duplicated\" + \"\\n\" +\n                                              u\"If it is not activated (default) the object is modified (color) or duplicated\")\n        self.PB_ChangeColor.setText(u\"Coul. Obj\")\n        self.PB_ChangeColor.setToolTip(u\"Change the color of the shape or the face depend of the choice\" + \"\\n\"\n                                       u\"In case object Mesh or Points the complete object is colored\" + \"\\n\\n\")\n                                       #u\"If a point or an edge is selected, the complete object is colored\")\n        self.PB_CreateFace.setText(u\"Dupl. Obj\")\n        self.PB_CreateFace.setToolTip(u\"Duplicates the face or the object depend to the chosen option\" + \"\\n\" +\n                                      u\"In the case of a Mesh object or Points the complete object is colored\" + \"\\n\" +\n                                      u\"Duplicate a Mesh object keeps the original and creates a solid shape\" + \"\\n\" +\n                                      u\"Duplicate a Points object keeps the original and creates a copy\")\n        self.SBox_Transparence.setToolTip(u\"Degree of transparency of the selected face or object\" + \"\\n\" +\n                                          u\"depend on the option chosen\" + \"\\n\" +\n                                          u\"0 = opaque / 100 = transparent\")\n\n        ####\n        self.GBox_004_Object_Mesh.setTitle(u\"Components\")  # Mesh or Points\n        self.LA_N_Edges.setText(u\"Edges\")\n        self.LE_N_Edges.setText(str(nombreArretesMesh))\n        self.LE_N_Edges.setToolTip(u\"Number of Edges in object Mesh\")\n        #self.PB_Axis_01.setText(u\"Axis\")\n        self.LA_N_Facets.setText(u\"Faces\")\n        self.LE_N_Facets.setText(str(nombreFacesMesh))\n        self.LE_N_Facets.setToolTip(u\"Number of Faces in object objet Mesh\")\n        self.LA_N_Points.setText(u\"Points\")\n        self.LE_N_Points.setText(str(nombrePointsMesh))\n        self.LE_N_Points.setToolTip(u\"Number of Points in object\")   # mesh and Points\n\n        ####\n        self.GBox_005_Value_Unit.setTitle(u\"Units\")\n        self.LA_5a.setText(u\"Units\")\n        #http://fr.wikipedia.org/wiki/Unit%C3%A9s_de_mesure_anglo-saxonnes\n        self.comboBox.setToolTip(u\"Selects a unit of length.\")\n#        self.comboBox.setCurrentIndex(seTIndexUnitLength)\n        self.comboBox.setCurrentIndex(6)\n        self.comboBox.setItemText(0, u\"km\")         #km #        = 1000000\n        self.comboBox.setItemText(1, u\"hm\")         #hm #        = 100000\n        self.comboBox.setItemText(2, u\"dam\")        #dam#        = 10000\n        self.comboBox.setItemText(3, u\"m\")          #m  #        = 1000\n        self.comboBox.setItemText(4, u\"dm\")         #dm #        = 100\n        self.comboBox.setItemText(5, u\"cm\")         #cm #        = 10\n        self.comboBox.setItemText(6, u\"mm\")         #mm #        = 1\n        self.comboBox.setItemText(7, seTUnitSymbolMicro + u\"m\")#Um#= 0.001    micro  hex=\"\\xB5\", html=<span>&#181;</span>\n        self.comboBox.setItemText(8, u\"nm\")         #nm # *      = 0.000001         nano\n        self.comboBox.setItemText(9, u\"pm\")         #pm #        = 0.000000001      pico\n        self.comboBox.setItemText(10, u\"fm\")        #fm #        = 0.000000000001   femto\n        self.comboBox.setItemText(11, u\"inch\")      #in # inch  pouce    = 25.400\n        self.comboBox.setItemText(12, u\"link\")      #lk # link  chainon  = 201.168\n        self.comboBox.setItemText(13, u\"foot\")      #ft # foot  pied     = 304.800\n        self.comboBox.setItemText(14, u\"yard\")      #yd # yard  verge    = 914.400\n        self.comboBox.setItemText(15, u\"perch\")     #rd # rod ou perch   perche   = 5029.200\n        self.comboBox.setItemText(16, u\"chain\")     #ch # chain chaine   = 20116.800\n        self.comboBox.setItemText(17, u\"furlong\")   #fur# furlong        = 201168\n        self.comboBox.setItemText(18, u\"mile\")      #mi # mile           = 1609344\n        self.comboBox.setItemText(19, u\"league\")    #lea# league lieue   = 4828032\n        self.comboBox.setItemText(20, u\"nautique\")  #nmi# mile nautique  = 1852000\n#        self.LA_6.setText(u\"Perim. shape\")\n\n        self.LA_5.setText(typeLongueur)\n        try:\n            self.LE_5.setText(str(Around(float(longueurObjet) * float(uniteM)))+ \" \" +uniteMs)\n        except Exception:\n            self.LE_5.setText(u\"\")\n        self.LE_5.setToolTip(u\"Length of the object.\" + \"\\n\"\n                             u\"If the face is selected, the perimeter of the face is displayed.\")\n\n        if (rayonObjet != 0.0) or (str(BsplineDetect) == \"<BSplineCurve object>\"):\n            self.LE_5b.setVisible(True)\n            self.LA_5b.setVisible(True)\n            if (str(BsplineDetect) == \"<BSplineCurve object>\"):\n                self.SB_Arc_ToByArcs.setVisible(True)\n                                                     \n                self.SB_Arc_ToByArcs.setToolTip(u\"Bspline detected \" + \"\\n\"\n                                        u\"Number of element = \" + str(BsplineNumberElement) + \"\\n\" +\n                                        u\"Calcul with distance between points \" + str(Around(BsplineCutLength * uniteM)) + \" \" + uniteMs + \"\\n\\n\" +\n                                        u\"toBiArcs(\" + BSplinetoByArcValeurS + \")\" + \"\\n\"\n                                        u\"This value can be modified in the preferences variable : setBSplineToByArcValue\" + \"\\n\")\n                self.PB_BSplineCreateNodes.setText(u\"Points(\" + str(len(BsplinePointsCoor)) + \")\") # Node\n                self.PB_BSplineCreateNodes.setToolTip(u\"Create on point on Poles (\" + str(len(BsplinePointsCoor)) + \") of the BSpline\" + \"\\n\\n\"\n                                                      u\"Command for Shape  : Gui.Selection.getSelection()[0].Points\" + \"\\n\"\n                                                      u\"Command for SubObj : Gui.Selection.getSelectionEx()[0].SubObjects[0].Curve.getPoles()\" + \"\\n\\n\"\n                                                      u\"Hidden Options : \" + \"\\n\\n\"\n                                                      u\"The variables \" + \"\\n\\n\"\n                                                      u\"switchBSplineCreateCircleConstructorAxis\" + \"\\n\"\n                                                      u\"switchBSplineCreateCircleConstructor\" + \"\\n\\n\"\n                                                      u\"accessible in : User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__ + \"\\n\"\n                                                      u\"allow to create the circles and the point axes construction of the BSpline\" + \"\\n\"\n                                                      u\"their number (precision) depends on the value toBiArcs(BSplinetoByArcValeurS)\" + \"\\n\"\n                                                      u\"actual toBiArcs(\" + BSplinetoByArcValeurS + \")\" + \"\\n\")\n                self.PB_BSplineCreateNodes.setVisible(True)\n                self.LA_5b.setText(u\"Radius BSpline.\")\n                self.LE_5b.setText(BsplineRayonApproximatif)\n                self.LE_5b.setToolTip(u\"BSpline Radius on point : \" + self.SB_Arc_ToByArcs.text())\n                self.LA_6.setText(u\"BSpline Nodes\")\n                self.LE_6.setText(str(BsplineNombreDeNoeuds))\n                self.LE_6.setToolTip(u\"Number of nodes of the BSpline.\")\n            else:\n                self.SB_Arc_ToByArcs.setVisible(False)\n                self.PB_BSplineCreateNodes.setVisible(False)\n                self.LA_5b.setText(u\"Radius\")\n                self.LE_5b.setText(str(Around(rayonObjet * float(uniteM))) + \" \" + uniteMs + (\" (dia. \" + str(Around(rayonObjet * float(uniteM) * 2.0)) + \" \" + uniteMs + \")\"))\n                self.LE_5b.setToolTip(u\"Radius detected and displayed in radius and diameter.\"\n                                      u\"If one radius of face is detected, it is also displayed\")\n                if numberEdges == 1:\n                    self.LA_6.setText(u\"Circumference (\" + str(numberEdges) + \")\")\n                else:\n                    self.LA_6.setText(u\"Perimetre of shape (\" + str(numberEdges) + \")\")\n                self.LE_6.setText(str(Around(float(perimetre) * float(uniteM))) + \" \" +uniteMs)\n        else:\n            self.LA_6.setText(u\"Perimetre of shape (\" + str(numberEdges) + \")\")\n            self.SB_Arc_ToByArcs.setVisible(False)\n            self.PB_BSplineCreateNodes.setVisible(False)\n            self.LE_5b.setVisible(False)\n            self.LA_5b.setVisible(False)\n            rayonObjet = 0.0\n            try:\n                self.LE_6.setText(str(Around(float(perimetre) * float(uniteM))) + \" \" +uniteMs)\n            except Exception:\n                perimetre = 0.0\n                self.LE_6.setText(str(Around(perimetre)))\n                self.LE_6.setToolTip(u\"Perimeter total of the form.\" + \"\\n\"\n                                     u\"Display the total result of the edges\")\n\n        self.PB_BSplineCreateNodes.setText(u\"Points(\" + str(len(BsplinePointsCoor)) + \")\") # Node\n        self.PB_BSplineCreateNodes.setToolTip(u\"Create on point on Poles (\" + str(len(BsplinePointsCoor)) + \") of the BSpline\" + \"\\n\\n\"\n                                              u\"Hidden feature : \" + \"\\n\\n\"\n                                              u\"Command for Shape  : Gui.Selection.getSelection()[0].Points\" + \"\\n\"\n                                              u\"Command for SubObj : Gui.Selection.getSelectionEx()[0].SubObjects[0].Curve.getPoles()\" + \"\\n\\n\"\n                                              u\"Hidden Options : \" + \"\\n\\n\"\n                                              u\"The variables \" + \"\\n\\n\"\n                                              u\"switchBSplineCreateCircleConstructorAxis\" + \"\\n\"\n                                              u\"switchBSplineCreateCircleConstructor\" + \"\\n\\n\"\n                                              u\"accessible in : User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__ + \"\\n\"\n                                              u\"allow to create the circles and the point axes construction of the BSpline\" + \"\\n\"\n                                              u\"their number (precision) depends on the value toBiArcs(BSplinetoByArcValeurS)\" + \"\\n\"\n                                              u\"actual toBiArcs(\" + BSplinetoByArcValeurS + \")\" + \"\\n\")\n\n        ####\n        self.GBox_006_Inclination.setTitle(u\"Inclination\")\n        self.GBox_006_Inclination.setToolTip(u\"Inclination compared XY, YZ, XZ\")\n        self.LA_8a.setText(u\"Plane\")\n        self.PB_Ra.setText(u\"Degrees\")\n        self.PB_Ra.setToolTip(u\"Toggles between decimal degrees, degrees minutes second\" + \"\\n\"\n                              u\"Radian, Grade, Percent.\")\n        self.LA_8a_2.setText(u\"Coordinates\")\n        self.LA_8xy.setText(u\"XY\")\n        self.LE_8xy.setText(str(Plan_xy) + \" \" + uniteAs)\n        self.LE_8xy.setToolTip(u\"Angle in the XY plane.\")\n        self.LE_8xya.setText(str(Plan_xy_V))\n        self.LA_8yz.setText(u\"YZ\")\n        self.LE_8yz.setText(str(Plan_yz) + \" \" + uniteAs)\n        self.LE_8yz.setToolTip(u\"Angle in the YZ plane.\")\n        self.LE_8yza.setText(str(Plan_yz_V))\n        self.LA_8zx.setText(u\"ZX\")\n        self.LE_8zx.setText(str(Plan_zx) + \" \" + uniteAs)\n        self.LE_8zx.setToolTip(u\"Angle in the ZX plane.\")\n        self.LE_8zxa.setText(str(Plan_zx_V))\n        ##\n        if switchCreateLineDiVatNatOnClick == 0:\n            self.PB_Line_Direction.setText(u\"Direction\")\n            self.PB_Line_ValueAT.setText(u\"ValueAt(0)\")\n            self.PB_Line_NormalAT.setText(typeNormalAt)\n        else:\n            self.PB_Line_Direction.setText(u\"*Direction\")\n            self.PB_Line_ValueAT.setText(u\"*ValueAt(0)\")\n            self.PB_Line_NormalAT.setText(typeNormalAt)\n\n        self.PB_Line_Direction.setToolTip(u\"Create a line (Yellow) in the displayed direction\" + \"\\n\"\n                                          u\"Line is created at point 0,0,0 to Direction (switchCreateLineDiVatNatOnClick = FALSE)\" + \"\\n\"\n                                          u\"If switchCreateLineDiVatNatOnClick = True, the line starts at the point clicked by the mouse\" + \"\\n\"\n                                          u\"The button is displayed with an asterisk *Direction\" + \"\\n\")\n        self.LE_9_Direction.setText(str(directionObj))\n        self.LE_9_Direction.setToolTip(u\"Direction of object\" + \"\\n\"\n                                       u\"Direction du point(x1,y1,z1) \u00e0 point(x2,y2,z2)\" + \"\\n\"\n                                       u\"Commande :\" + \"\\n\\n\"\n                                       u\"edgeObject = Gui.Selection.getSelection()[0].Shape.Edges[0]\" + \"\\n\"\n                                       u\"directionObj = edgeObject.Vertexes[1].Point.sub(edgeObject.Vertexes[0].Point)\" + \"\\n\\n\")\n\n        self.PB_Line_ValueAT.setToolTip(u\"Create a line (Magenta) in the direction ValueAt(0)\" + \"\\n\"\n                                        u\"The line is created at point 0,0,0 in the direction ValueAt(0) (switchCreateLineDiVatNatOnClick = FALSE)\" + \"\\n\"\n                                        u\"If switchCreateLineDiVatNatOnClick = True, the line starts at the point clicked by the mouse\" + \"\\n\"\n                                        u\"The button is displayed with an asterisk *ValueAt(0)\" + \"\\n\")\n        self.LE_10_ValueAt.setText(str(direcValueAt))\n        self.LE_10_ValueAt.setToolTip(u\"Returns the value of the vector corresponding to the 3D parameter. \" + \"\\n\"\n                                      u\"Command :\" + \"\\n\\n\"\n                                      u\"Gui.Selection.getSelectionEx()[0].SubObjects[0].Edges[0].valueAt(0)\" + \"\\n\\n\")\n\n        self.PB_Line_NormalAT.setToolTip(u\"Create a line (Cyan) in the direction NormalAt(0,0)\" + \"\\n\" \n                                         u\"The line is created at point 0,0,0 in the NormalAt(0,0) direction (switchCreateLineDiVatNatOnClick = FALSE)\" + \"\\n\"\n                                         u\"If switchCreateLineDiVatNatOnClick = True, the line starts at the point clicked by the mouse\" + \"\\n\"\n                                         u\"The button is displayed with an asterisk *NormalAt(0,0)\" + \"\\n\")\n        self.LE_10b_NormalAt.setText(str(direcNormalAt))\n        self.LE_10b_NormalAt.setToolTip(u\"Returns the value of the parameters of the normal of the selected face\" + \"\\n\" \n                                        u\"Command :\" + \"\\n\\n\"\n                                        u\"Gui.Selection.getSelectionEx()[0].SubObjects[0].Faces[0].normalAt(0,0)\" + \"\\n\\n\")\n        ##\n        ####\n        self.GBox_012_SpreadSheet.setTitle(u\"Details of the form\")\n                                                                                                                            \n        self.tableWidget.setToolTip(u\"Details of the form :\" + \"\\n\"\n                                    u\"If the checkBox is checked, a complete scan of the selected form is done\" + \"\\n\"\n                                    u\"(Using this option may take a long time for a large object\" + \"\\n\"\n                                    u\"a full scan is done with each mouse click (Unchecked by default coloured re))\" + \"\\n\\n\"\n                                    u\"If not checked the principal data are displayed\" + \"\\n\" + \"\\n\"\n                                    u\"Vertexes and details : (Edges) (Faces) (Vertex Faces) ...(Total)\" + \"\\n\"\n                                    u\"Scoreboard only the first 200 details of the form are displayed.\" + \"\\n\"\n                                    u\"All the elements will be visible in the file after saving it.\")\n\n        ####\n        self.GBox_007_Surface_and_Volume.setTitle(u\"Area and Volume\")\n        self.LA_9.setText(u\"Area of the form\")\n\n        self.LE_9a.setText(str(Around(surface)) + \" \" + uniteSs)\n        self.LE_9a.setToolTip(u\"Total area of the form.\")\n        self.LA_10.setText(u\"Area of the face\")\n        self.LE_10a.setText(str(Around(surfaceFace)) + \" \" + uniteSs)\n        self.LE_10a.setToolTip(u\"Area of the face.\")\n        self.LA_11.setText(u\"Volume of the form\")\n        self.LE_11a.setText(str(Around(volume_)) + \" \" + uniteVs)\n        self.LE_11a.setToolTip(u\"Total volume of the form.\")\n\n        self.LA_Unit.setText(u\"Unit\")\n        self.comboBox_Unit.setCurrentIndex(5)\n        self.comboBox_Unit.setItemText(0, u\"tonne\")          #t    #   = 1000000\n        self.comboBox_Unit.setItemText(1, u\"quintal\")        #q    #   = 100000\n        self.comboBox_Unit.setItemText(2, u\"kilo gram\")      #kg   #   = 1000\n        self.comboBox_Unit.setItemText(3, u\"hecto gram\")     #hg   #   = 100\n        self.comboBox_Unit.setItemText(4, u\"decagram\")       #dag  #   = 10\n        self.comboBox_Unit.setItemText(5, u\"gram\")           #g    #   = 1\n        self.comboBox_Unit.setItemText(6, u\"decigram\")       #dg   #   = 0.1\n        self.comboBox_Unit.setItemText(7, u\"centigram\")      #cg   #   = 0.01\n        self.comboBox_Unit.setItemText(8, u\"milligram\")      #mg   #   = 0.001\n        self.comboBox_Unit.setItemText(9, u\"microgram\")      #Ug   #   = 0.000001            micro  hex=\"\\xB5\", html=<span>&#181;</span>\n        self.comboBox_Unit.setItemText(10, u\"nanogram\")      #ng   #   = 0.000000001\n        self.comboBox_Unit.setItemText(11, u\"picogram\")      #pg   #   = 0.000000000001\n        self.comboBox_Unit.setItemText(12, u\"femtogram\")     #fg   #   = 0.000000000000001   femtogram\n        self.comboBox_Unit.setItemText(13, u\"grain\")         #gr   #   = 0.06479891 g\n        self.comboBox_Unit.setItemText(14, u\"drachm\")        #dr   #   = 1.7718451953125 g\n        self.comboBox_Unit.setItemText(15, u\"once\")          #oz   #   = 28.3495231250 g\n        self.comboBox_Unit.setItemText(16, u\"once troy\")     #oz t #   = 31.1034768 g  once troy\n        self.comboBox_Unit.setItemText(17, u\"livre troy\")    #lb t #   = 373.2417216 g  livre de troy\n        self.comboBox_Unit.setItemText(18, u\"livre av\")      #lb   #   = 453.59237 g  livre avoirdupois pound\n        self.comboBox_Unit.setItemText(19, u\"stone\")         #st   #   = 6350.29318 g\n        self.comboBox_Unit.setItemText(20, u\"quarter\")       #qtr  #   = 12700.58636 g\n        self.comboBox_Unit.setItemText(21, u\"hundredweight\") #cwt  #   = 50802.34544 g\n        self.comboBox_Unit.setItemText(22, u\"tonneau fr\")    #     #   = 0.00000102145045965 g\n        self.comboBox_Unit.setItemText(23, u\"carat\")         #ct   #   = 0.2 g\n        self.comboBox_Unit.setToolTip(u\"Select a unit of mass.\")\n\n        self.LA_Weight.setText(u\"Mass\")\n        self.LA_Density.setText(u\"Density\")\n\n        self.LE_12a.setText(str(Around(poids)) + \" \" + unitePs)\n        self.LE_12a.setToolTip(u\"Mass of the form in the selected unit.\")\n\n        seTMaterialCost = ((volume_ * seTDensiteValue * seTMaterialPrice) / 1000000.0)\n        self.LE_Cost.setText(str(Around(seTMaterialCost)) + seTMaterialSuffixCost) #CostMaterial\n\n        self.DS_Density.setToolTip(u\"Give the volume density in Kg by dm3.\")\n\n        self.GBox_008_Cost_And_Price.setTitle(u\"Cost\")\n        self.LA_Cost.setText(u\"Cost total\")\n        self.LA_Price.setText(u\"Price (kg/dm3)\")\n\n        self.PB_Del_Material.setText(u\"Delete (\" + str(self.CBox_Materiel.currentIndex() + 1) + \"/\" + str(len(materialAssociated)) + \")\")\n        self.PB_Del_Material.setToolTip(u\"Delete the curent material \")\n\n        self.PB_Save_Material.setText(u\"Save\")\n        self.PB_Save_Material.setToolTip(u\"Save the curent material\" + \"\\n\"\n                                         u\"The material is also saved with the Exit button\")\n\n        self.LA_Material.setText(u\"Material\")\n        self.CBox_Materiel.setToolTip(u\"The material data is saved in the macro location (by default)\" + \"\\n\\n\"\n                                      u\"First run one Material file is created with 20 components\" + \"\\n\"\n                                      u\"(You can adding all components material you want)\" + \"\\n\"\n                                      u\"Location : \" + seTMaterialSavePathName + \" file name : \" + seTMaterialFileName + \"\\n\"\n                                      u\"Actual   : \" + str(len(materialAssociated)) + \" materials listed\" + \"\\n\"\n                                      u\"If the file is deleted or empity one new file of material is created\" + \"\\n\"\n                                      u\"with the basic material include in the macro\")\n\n        self.LA_NewMaterial.setText(u\"New material or editing\")\n        self.LE_Materiel.setToolTip(u\"Enter your new material and press enter for validate\" + \"\\n\\n\"\n                                    u\"Format : newNameMaterial, Density, Price (by kg), Info\" + \"\\n\\n\"\n                                    u\"newNameMaterial : the material name\" + \"\\n\"\n                                    u\"Density \\t : density of the material in Kg by dm3\" + \"\\n\"\n                                    u\"Price \\t : price of the material\" + \"\\n\"\n                                    u\"Info \\t : info of the material of other\" + \"\\n\\n\"\n                                    u\"Each field is separated by a comma\" + \"\\n\\n\"\n                                    u\"Other format is not accepted and the background is coloured in red\" + \"\\n\"\n                                    u\"The current material is displayed you can change or complete the data material\" + \"\\n\"\n                                    u\"If the name is changed, on new material is created\" + \"\\n\")\n\n        ####\n        self.GBox_009_BoundBox.setTitle(u\"BoundBox\")\n        self.LA_007_01_Xlength.setText(u\"X Length\")\n        self.LA_007_02_Ylength.setText(u\"Y Length\")\n        self.LA_007_03_Zlength.setText(u\"Z Length\")\n        self.LA_007_04_Diagonallength.setText(u\"Diagonal Length\")\n        self.LE_007_BB_01_XLength.setText(str(Around(boundBoxLX * uniteM)) + \" \" + uniteMs)\n        self.LE_007_BB_01_XLength.setToolTip(u\"Dimensions of the form:\" + \"\\n\"\n                                             u\"Direction X\")\n        self.LE_007_BB_02_YLength.setText(str(Around(boundBoxLY * uniteM)) + \" \" + uniteMs)\n        self.LE_007_BB_02_YLength.setToolTip(u\"Dimensions of the form:\" + \"\\n\"\n                                             u\"Direction Y\")\n        self.LE_007_BB_03_ZLength.setText(str(Around(boundBoxLZ * uniteM)) + \" \" + uniteMs)\n        self.LE_007_BB_03_ZLength.setToolTip(u\"Dimensions of the form:\" + \"\\n\"\n                                             u\"Direction Z\")\n        self.LE_007_BB_04_Diagonal.setText(str(Around(boundBoxDiag * uniteM)) + \" \" + uniteMs)\n        self.LE_007_BB_04_Diagonal.setToolTip(u\"Dimensions diagonal boundBox of the form.\")\n\n        self.PB_BoundBox_Tracing.setText(u\"Tracing\")\n        self.PB_BoundBox_Tracing.setToolTip(u\"Trace the boundBox edge of the shape.\")\n        self.PB_00_BoundBox_Volume.setText(u\"Volume\")\n        self.PB_00_BoundBox_Volume.setToolTip(u\"Create BoundBox Volume  of the shape.\")\n        self.CB_01_BoundBox_Text.setText(u\"Text Dim.\")\n        self.CB_01_BoundBox_Text.setToolTip(u\"Create Dimension on BoundBox\")\n\n        ####\n        self.GBox_010_Center_Mass.setTitle(u\"Centre of :\")\n        self.LA_13x.setText(u\"BoundBox X\")\n        self.LA_13y.setText(u\"BoundBox Y\")\n        self.LA_13z.setText(u\"BoundBox Z\")\n        self.LE_13x.setText(str(Around(boundBoxCenterX * uniteM)) + \" \" + uniteMs)\n        self.LE_13x.setToolTip(u\"X coordinate of the center of the shape.\")\n        self.LE_13y.setText(str(Around(boundBoxCenterY * uniteM)) + \" \" + uniteMs)\n        self.LE_13y.setToolTip(u\"Y coordinate of the center of the shape.\")\n        self.LE_13z.setText(str(Around(boundBoxCenterZ * uniteM)) + \" \" + uniteMs)\n        self.LE_13z.setToolTip(u\"Z coordinate of the center of the shape.\")\n        #self.PB_Axis_02.setText(u\"Axis\")\n        self.PB_Axis_02.setToolTip(pointPlanAxesTexte)\n        self.LA_14x.setText(massOrGravity + u\" X\")\n        self.LA_14y.setText(massOrGravity + u\" Y\")\n        self.LA_14z.setText(massOrGravity + u\" Z\")\n        self.LE_14x.setText(str(Around(CenterOfMassX * uniteM)) + \" \" + uniteMs)\n        self.LE_14x.setToolTip(u\"X coordinate of the center of \" + massOrGravity)\n        self.LE_14y.setText(str(Around(CenterOfMassY * uniteM)) + \" \" + uniteMs)\n        self.LE_14y.setToolTip(u\"Y coordinate of the center of \" + massOrGravity)\n        self.LE_14z.setText(str(Around(CenterOfMassZ * uniteM)) + \" \" + uniteMs)\n        self.LE_14z.setToolTip(u\"Z coordinate of the center of \" + massOrGravity)\n        #self.PB_Axis_03.setText(u\"Axis\")\n        self.PB_Axis_03.setToolTip(pointPlanAxesTexte)\n        ####\n        self.GBox_011_Inertia.setTitle(u\"Inertia\")\n        self.GBox_011_Inertia.setStyleSheet(u\"QToolTip { color: #ffffff; font: bold 14px; background-color: #ff0000; border: 2px solid white; }\")\n        self.GBox_011_Inertia.setToolTip(u\"<html> <body>\"\n                                         u\"############################################################################################################\" + \"<br/>\"\n                                         u\"                                 INFORMATION\" + \"<br/>\"\n                                         u\"             VERIFY THIS SECTION BY PERSON KNOWING THE INERTIA\" + \"<br/>\"\n                                         u\"   and thanks post your knowledges in the forum tread if it is not correct\" + \"<br/>\"\n                                         u\"           http://forum.freecadweb.org/viewtopic.php?f=10&t=3185 \" + \"<br/>\"\n                                         u\"                                 ###########\"\n                                         u\"<p style=color:Yellow >\"\n                                         u\"  *   Use at your own risk. The author assumes no liability for data loss.  *\"\n                                         u\"</p>\"\n                                         u\"                                 ###########\" + \"<br/>\"\n                                         u\"The exposant value 1 (Raw) correspond mode base of FreeCAD\" + \"<br/>\"\n                                         u\"Code used :\"\n                                         u\"<p style=color:DarkBlue >\"\n                                         u\"####\" + \"<br/>\"\n                                         u\"Matrix = Gui.Selection.getSelection()[0].Shape.MatrixOfInertia  # (complete data .A[0] to .A[11])\" + \"<br/>\"\n                                         u\"MatrixX1 = Gui.Selection.getSelection()[0].Shape.MatrixOfInertia.A[0]  # (first field, first data)\" + \"<br/>\"\n                                         u\"#volume = Gui.Selection.getSelection()[0].Shape.Volume\" + \"<br/>\"\n                                         u\"uniteV = 1.0 # mm3 base FreeCAD ## (kilo = 0.000000000000000001)\" + \"<br/>\"\n                                         u\"uniteS = 1.0 # mm2 base FreeCAD ## (kilo = 0.000000000001)\" + \"<br/>\"\n                                         u\"uniteM = 1.0 # mm  base FreeCAD ## (kilo = 0.000001)\" + \"<br/>\"\n                                         u\"uniteP = 1.0 # gram base FreeCAD## (kilo = 0.001)\" + \"<br/>\"\n                                         u\"setMomentOfInertia_16 = 2 # exposant Moment of inertia value \" + \"<br/>\"\n                                         u\"setMomentOfInertiaMassique_17 = 2 # exposant Moment of inertia massique value\" + \"<br/>\"\n                                         u\"seTDensiteValue = 7.8700 # kg by dm3 (iron)\" + \"<br/>\"\n                                         u\"MatrixX1_16 = (MatrixX1*uniteS)**setMomentOfInertia_16\" + \"<br/>\"\n                                         u\"MatrixX1_17 = (MatrixX1*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\" + \"<br/>\"\n                                         u\"####\"\n                                         u\"</p>\"\n                                         u\"                                 ###########\" + \"<br/>\"\n                                         u\"The moment of inertia, otherwise known as the angular mass or\" + \"<br/>\"\n                                         u\"rotational inertia, of a rigid body is a tensor that determines\" + \"<br/>\"\n                                         u\"the torque needed for a desired angular acceleration about a rotational axis.\" + \"<br/>\"\n                                         u\"It depends on the body's mass distribution and the axis chosen,\" + \"<br/>\"\n                                         u\"with larger moments requiring more torque to change the body's rotation.\" + \"<br/>\"\n                                         u\"see https://en.wikipedia.org/wiki/Moment_of_inertia \" + \"<br/>\"\n                                         u\"############################################################################################################\"\n                                         u\"</html> </body>\")\n\n        self.LA_16.setText(u\"Moment of inertia\")\n        self.LE_16_Raw.setText(\"Raw : \" + MatrixOfInertiaRaw)\n        self.LE_16_Raw.setCursorPosition(0)\n        self.LA_16x.setText(u\"X\")\n        self.LA_16y.setText(u\"Y\")\n        self.LA_16z.setText(u\"Z\")\n\n        #self.SB_16_M.setText(uniteMs + \"^5\")\n        self.SB_16_M.setPrefix(uniteMs + \"^\")\n\n        self.SB_16_M.setValue(setMomentOfInertia_16)\n\n        self.LE_16_1x.setText(str(Around(MatrixX1)))\n        self.LE_16_1y.setText(str(Around(MatrixY1)))\n        self.LE_16_1z.setText(str(Around(MatrixZ1)))\n        self.LE_16_01.setText(str(Around(Matrix_1)))\n        self.PB_Axis_04_16_1.setToolTip(pointPlanAxesTexte)\n        self.LE_16_2x.setText(str(Around(MatrixX2)))\n        self.LE_16_2y.setText(str(Around(MatrixY2)))\n        self.LE_16_2z.setText(str(Around(MatrixZ2)))\n        self.LE_16_02.setText(str(Around(Matrix_2)))\n        self.LE_16_3x.setText(str(Around(MatrixX3)))\n        self.LE_16_3y.setText(str(Around(MatrixY3)))\n        self.LE_16_3z.setText(str(Around(MatrixZ3)))\n        self.LE_16_03.setText(str(Around(Matrix_3)))\n        self.PB_Axis_05_16_2.setToolTip(pointPlanAxesTexte)\n        self.PB_Axis_06_16_3.setToolTip(pointPlanAxesTexte)\n        self.LE_16_4x.setText(str(Around(Matrix12)))\n        self.LE_16_4y.setText(str(Around(Matrix13)))\n        self.LE_16_4z.setText(str(Around(Matrix14)))\n        self.LE_16_04.setText(str(Around(Matrix15)))\n        self.PB_Axis_07_16_4.setToolTip(pointPlanAxesTexte)\n        ##\n        self.LA_17.setText(u\"Moment of inertia massique\")\n        self.LA_17x.setText(u\"X\")\n        self.LA_17y.setText(u\"Y\")\n        self.LA_17z.setText(u\"Z\")\n        self.LA_determinant.setText(u\"Determinant\")\n        self.LA_determinantDecimal.setText(u\"Determinant Dec.\")\n\n        #self.LE_17_M.setText(unitePs+uniteSs)\n        self.SB_17_M.setPrefix(unitePs + uniteSs + \"^\")\n        self.SB_17_M.setValue(setMomentOfInertiaMassique_17)\n\n        self.LE_17_1x.setText(str(Around(MatrixX1*seTDensiteValue)))\n        self.LE_17_1y.setText(str(Around(MatrixY1*seTDensiteValue*uniteP)))\n        self.LE_17_1z.setText(str(Around(MatrixZ1*seTDensiteValue)))\n        self.PB_Axis_08_17_1.setToolTip(pointPlanAxesTexte)\n        self.LE_17_2x.setText(str(Around(MatrixX2*seTDensiteValue)))\n        self.LE_17_2y.setText(str(Around(MatrixY2*seTDensiteValue)))\n        self.LE_17_2z.setText(str(Around(MatrixZ2*seTDensiteValue)))\n        self.PB_Axis_09_17_2.setToolTip(pointPlanAxesTexte)\n        self.LE_17_3x.setText(str(Around(MatrixX3*seTDensiteValue)))\n        self.LE_17_3y.setText(str(Around(MatrixY3*seTDensiteValue)))\n        self.LE_17_3z.setText(str(Around(MatrixZ3*seTDensiteValue)))\n        self.PB_Axis_10_17_3.setToolTip(pointPlanAxesTexte)\n        self.PB_Axis_11_17_4.setToolTip(pointPlanAxesTexte)\n\n        self.LE_18_determinant.setText(str(DeterminantM))\n        self.LE_18_determinant.setToolTip(u\"Determinant of Matrix.\" + \"\\n\"\n                                          u\"In linear algebra, the determinant is a useful value that can be computed\" + \"\\n\"\n                                          u\"from the elements of a square matrix.\" + \"\\n\"\n                                          u\"The determinant of a matrix A is denoted det(A), det A, or \" + chr(124) + \"A\"+ chr(124)+ \".\" + \"\\n\"\n                                          u\"It can be viewed as the scaling factor of the transformation described by the matrix.\" + \"\\n\"\n                                          u\"see https://en.wikipedia.org/wiki/Determinant\")\n        self.LE_18_determinantDecim.setText(str(decimal.Decimal(DeterminantM)))\n        self.LE_18_determinantDecim.setToolTip(u\"Determinant Decimal.\")\n        if switch_Set_Placeholder_Text == True:\n            self.LE_1.setPlaceholderText(u\"Document name\")\n            self.LE_2.setPlaceholderText(u\"Label\")\n            self.LE_2a.setPlaceholderText(u\"Internal name\")\n            self.LE_3.setPlaceholderText(u\"Sub objet\")\n            self.LE_3a.setPlaceholderText(u\"Type\")\n            self.LE_4.setPlaceholderText(u\"TypeID\")\n            self.LE_4x.setPlaceholderText(u\"X Mouse\")\n            self.LE_4y.setPlaceholderText(u\"Y Mouse\")\n            self.LE_4z.setPlaceholderText(u\"Z Mouse\")\n            self.LE_N_Edges.setPlaceholderText(u\"Number of Edge(s)\")\n            self.LE_N_Facets.setPlaceholderText(u\"Number of Face(s)\")\n            self.LE_N_Points.setPlaceholderText(u\"Number of Points\")\n            self.LE_CRed.setPlaceholderText(u\"Red\")\n            self.LE_CGreen.setPlaceholderText(u\"Green\")\n            self.LE_CBlue.setPlaceholderText(u\"Blue\")\n            self.LE_Transparent.setPlaceholderText(u\"Transparency\")\n            self.LE_ConversionUnsigned.setPlaceholderText(u\"Codage of colors\")\n            self.LE_5.setPlaceholderText(u\"Length\")\n            self.LE_5b.setPlaceholderText(u\"Radius\")\n            self.LE_6.setPlaceholderText(u\"Perimeter\")\n            self.LE_8xy.setPlaceholderText(u\"Degrees\")\n            self.LE_8yz.setPlaceholderText(u\"Degrees\")\n            self.LE_8zx.setPlaceholderText(u\"Degrees\")\n            self.LE_8xya.setPlaceholderText(u\"XY Angle\")\n            self.LE_8yza.setPlaceholderText(u\"YZ Angle\")\n            self.LE_8zxa.setPlaceholderText(u\"ZX Angle\")\n            self.LE_9_Direction.setPlaceholderText(u\"Direction\")\n            self.LE_10_ValueAt.setPlaceholderText(u\"Vector\")\n            self.LE_10b_NormalAt.setPlaceholderText(u\"NormalAt\")\n            self.LE_9a.setPlaceholderText(u\"Total Area\")\n            self.LE_10a.setPlaceholderText(u\"Face Area\")\n            self.LE_11a.setPlaceholderText(u\"Volume\")\n            self.LE_12a.setPlaceholderText(u\"Mass\")\n            self.LE_Cost.setPlaceholderText(u\"Price\")\n            self.LE_Materiel.setPlaceholderText(u\"Material\")\n            self.LE_007_BB_01_XLength.setPlaceholderText(u\"X Length\")\n            self.LE_007_BB_02_YLength.setPlaceholderText(u\"Y Length\")\n            self.LE_007_BB_03_ZLength.setPlaceholderText(u\"Z Length\")\n            self.LE_007_BB_04_Diagonal.setPlaceholderText(u\"Diagonal Length\")\n            self.LE_13x.setPlaceholderText(u\"X Coordinate\")\n            self.LE_13y.setPlaceholderText(u\"Y Coordinate\")\n            self.LE_13z.setPlaceholderText(u\"Z Coordinate\")\n            self.LE_14x.setPlaceholderText(u\"X Coordinate\")\n            self.LE_14y.setPlaceholderText(u\"Y Coordinate\")\n            self.LE_14z.setPlaceholderText(u\"Z Coordinate\")\n            self.LE_18_determinant.setPlaceholderText(u\"Determinant\")\n            self.LE_18_determinantDecim.setPlaceholderText(u\"Decimal Determinant\")\n\n        ####\n        self.GBox_013_SpreadSheet_Creation.setTitle(u\"SpreadSheet\")\n        self.GBox_013_SpreadSheet_Creation.setToolTip(u\"Option for save or read the data in spreadSheet\" + \"\\n\"\n                                                u\"with different separator\" + \"\\n\"\n                                                u\"Tabulation, Comma, Semicolon, Space\" + \"\\n\"\n                                                u\"Tabulation are the separator for the FreeCAD spreadSheet module\" + \"\\n\"\n                                                u\"The number of this four separator are calculate for help if unknown\" + \"\\n\\n\"\n                                                u\"The COMMA are the old (01.16 and before) separator of the FCInfo macro\" + \"\\n\"\n                                                u\"Now for compatibility with the FreeCAD spreadSheet and since 01.17 version\" + \"\\n\"\n                                                u\"the TABULATION is the separator by default\" + \"\\n\\n\"\n                                                u\"If you want to convert your old FCInfo spreadsheet :\" + \"\\n\"\n                                                u\"Open it in FCInfo and save it with the Tabulation option checked\")\n        self.PB_01_Read_SpreadSheet.setText(u\"Read\")\n        self.PB_01_Read_SpreadSheet.setToolTip(u\"Read the file from disk.\")\n        self.PB_02_Save_SreadSheet.setText(u\"Save\")\n        self.PB_02_Save_SreadSheet.setToolTip(u\"Save the file to disk.\")\n\n        self.RB_01_Tabulation.setText(u\"Tabulation\")\n        self.RB_02_Virgule.setText(u\"Comma\")\n        self.RB_03_Point_Virgule.setText(u\"Semicolon\")\n        self.RB_04_Espace.setText(u\"Space\")\n\n        self.ComboB_SpreadSheet.setToolTip(u\"List of spreadSeet available\")\n        self.PB_SpreadSheet_Refresh.setText(u\"Refresh\")\n        self.PB_SpreadSheet_Refresh.setToolTip(u\"Refresh and Search Spreadsheet\")\n        self.LE_SpreadSheet.setToolTip(u\"Current worksheet (first displayed)\" + \"\\n\" +\n                                       u\"If there is no worksheet in the document,\" + \"\\n\" +\n                                       u\"a spreadsheet named FCSpreadSheet is created\" + \"\\n\" +\n                                       u\"or the displayed spreadsheet is updated\" + \"\\n\" +\n                                       u\"or type the name of your spreadsheet\")\n        self.PB_03_Create_SpreadSheet.setText(u\"SpreadSheet\")\n        self.PB_03_Create_SpreadSheet.setToolTip(u\"Creates a spreadsheet with all the information in the current document.\")\n\n        ####\n        self.GBox_014_Main_Tools.setTitle(u\"Main menu\")\n\n        self.CB_01_Info.setText(u\"Info\")\n        self.CB_01_Info.setToolTip(u\"If checked Display Infos in Rapport View\")\n        self.CB_01_Info.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Info))) # icone dans une variable \n\n        self.CB_02_Point.setText(u\"Point\")\n        self.CB_02_Point.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Point))) # icone dans une variable \n        self.CB_02_Point.setToolTip(u\"<img src=  />\" + \"\\n\" +\n                                    u\"If checked Create point\")\n        self.CB_03_Axis.setText(u\"Axis\")\n        self.CB_03_Axis.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Axis))) # icone dans une variable \n        self.CB_03_Axis.setToolTip(u\"<img src=  />\" + \"\\n\" +\n                                   u\"If checked Create 3 axis in XYZ direction\")\n        self.CB_04_Plane.setText(u\"Plane\")\n        self.CB_04_Plane.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Plane))) # icone dans une variable \n        self.CB_04_Plane.setToolTip(u\"<img src=   />\" + \"\\n\" +\n                                    u\"If checked Create 3 Plane in XYZ direction\")\n        ####\n        self.RB_00_ClipBoard.setText(u\"Clip-B0\") #Board\n        self.RB_00_ClipBoard.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_ClipBoard_None))) # icone dans une variable \n        self.RB_00_ClipBoard.setToolTip(u\"<img src=  />\" + \"\\n\" +\n                                        u\"None clipBoard\")\n        self.RB_01_ClipBoard.setText(u\"Clip-B1\")\n        self.RB_01_ClipBoard.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_ClipBoard_FC))) # icone dans une variable \n        self.RB_01_ClipBoard.setToolTip(u\"<img src=  />\" + \"\\n\"\n                                        u\"If checked the coordinate are copy in the clipBoard\" + \"\\n\" +\n                                        u\"Form : FreeCAD.Vector(X.0, Y.0, Z.0)\" + \"\\n\" +\n                                        u\"FreeCAD model\")\n        self.RB_02_ClipBoard.setText(u\"Clip-B2\")\n        self.RB_02_ClipBoard.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_ClipBoard_Comma))) # icone dans une variable \n        self.RB_02_ClipBoard.setToolTip(u\"<img src=  />\" + \"\\n\" +\n                                        u\"If checked the coordinate are copy in the clipBoard\" + \"\\n\" +\n                                        u\"Form : X, Y, Z\" + \"\\n\" +\n                                        u\"with Comma separator\")\n        self.RB_03_ClipBoard.setText(u\"Clip-B3\")\n        self.RB_03_ClipBoard.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_ClipBoard_Raw))) # icone dans une variable \n        self.RB_03_ClipBoard.setToolTip(u\"<img src=  />\" + \"\\n\" +\n                                        u\"If checked the coordinate are copy in the clipBoard\" + \"\\n\" +\n                                        u\"Form : X Y Z\" + \"\\n\" +\n                                        u\"As is with Space separator\")\n        ##\n        self.CB_05_Position.setText(u\"Left/Right\")\n        self.CB_05_Position.setToolTip(u\"Change the window macro position Right of Left\")\n        ##\n        self.SPBox_arrondi.setSuffix(u\" (Decimals)\")\n        self.SPBox_arrondi.setToolTip(u\"Select the number of decimal places behind the comma.\" + \"\\n\"\n                                      u\"If the value is -1, the rounding is set to 1000\" + \"\\n\"\n                                      u\"(infinity)\")\n        self.SP_012_01_Text.setSuffix(u\" (Text Height)\")\n        ##\n        self.PB_05_Help_Forum.setText(u\"Forum\")\n        self.PB_05_Help_Forum.setToolTip(u\"Open your explorer in the FCInfo Forum page \")\n        self.PB_06_Help_Wiki.setText(u\"Wiki\")\n        self.PB_06_Help_Wiki.setToolTip(u\"Open your explorer in the FCInfo Wiki page\")\n        ##\n        self.PB_01_Refrech.setText(u\"Ref\")\n        self.PB_01_Refrech.setToolTip(u\"Refrech the rapport view.\")\n        self.PB_04_Quit.setText(u\"Exit\")\n        self.PB_04_Quit.setToolTip(u\"Exit FCInfo.\" + \"\\n\"\n                                   u\"The material is saved also on quit the macro\" + \"\\n\"\n                                   u\"All parameters are saved with this action\")\n        self.SPBox_arrondi.setToolTip(u\"seTDecimalValue the value displayed in the window.\" + \"\\n\"\n                                      u\"If the value is -1 the arrond is called to 1000\" + \"\\n\"\n                                      u\"(infini)\")\n        ##\n\n    def displayMatrixMomentOfInertia(self):\n        global setMomentOfInertia_16\n        global setMomentOfInertiaMassique_17\n        global MatrixOfInertiaRaw\n        global MatrixX1_16\n        global MatrixY1_16\n        global MatrixZ1_16\n        global MatrixX2_16\n        global MatrixY2_16\n        global MatrixZ2_16\n        global MatrixX3_16\n        global MatrixY3_16\n        global MatrixZ3_16\n\n        global MatrixX1_17\n        global MatrixY1_17\n        global MatrixZ1_17\n        global MatrixX2_17\n        global MatrixY2_17\n        global MatrixZ2_17\n        global MatrixX3_17\n        global MatrixY3_17\n        global MatrixZ3_17\n        global DeterminantM\n\n        self.LE_16_Raw.setText(\"Raw : \" + MatrixOfInertiaRaw)\n        self.LE_16_Raw.setCursorPosition(0)\n        self.SB_16_M.setValue(setMomentOfInertia_16)\n        self.SB_16_M.setPrefix(uniteMs + \"^\")\n        ##\n        self.LE_16_1x.setText(str(Around(MatrixX1_16)))\n        self.LE_16_1x.setCursorPosition(0)\n        self.LE_16_1y.setText(str(Around(MatrixY1_16)))\n        self.LE_16_1y.setCursorPosition(0)\n        self.LE_16_1z.setText(str(Around(MatrixZ1_16)))\n        self.LE_16_1z.setCursorPosition(0)\n        self.LE_16_01.setText(str(Around(Matrix_1)))\n        self.LE_16_01.setCursorPosition(0)\n        ##\n        self.LE_16_2x.setText(str(Around(MatrixX2_16)))\n        self.LE_16_2x.setCursorPosition(0)\n        self.LE_16_2y.setText(str(Around(MatrixY2_16)))\n        self.LE_16_2y.setCursorPosition(0)\n        self.LE_16_2z.setText(str(Around(MatrixZ2_16)))\n        self.LE_16_2z.setCursorPosition(0)\n        self.LE_16_02.setText(str(Around(Matrix_2)))\n        self.LE_16_02.setCursorPosition(0)\n        ##\n        self.LE_16_3x.setText(str(Around(MatrixX3_16)))\n        self.LE_16_3x.setCursorPosition(0)\n        self.LE_16_3y.setText(str(Around(MatrixY3_16)))\n        self.LE_16_3y.setCursorPosition(0)\n        self.LE_16_3z.setText(str(Around(MatrixZ3_16)))\n        self.LE_16_3z.setCursorPosition(0)\n        self.LE_16_03.setText(str(Around(Matrix_3)))\n        self.LE_16_03.setCursorPosition(0)\n        ##\n        self.LE_16_4x.setText(str(Around(Matrix12)))\n        self.LE_16_4x.setCursorPosition(0)\n        self.LE_16_4y.setText(str(Around(Matrix13)))\n        self.LE_16_4y.setCursorPosition(0)\n        self.LE_16_4z.setText(str(Around(Matrix14)))\n        self.LE_16_4z.setCursorPosition(0)\n        self.LE_16_04.setText(str(Around(Matrix15)))\n        self.LE_16_04.setCursorPosition(0)\n        ##\n        ####\n        self.SB_17_M.setValue(setMomentOfInertiaMassique_17)\n        self.SB_17_M.setPrefix(unitePs + uniteSs + \"^\")\n        self.LE_17_1x.setText(str(Around(MatrixX1_17)))\n        self.LE_17_1x.setCursorPosition(0)\n        self.LE_17_1y.setText(str(Around(MatrixY1_17)))\n        self.LE_17_1y.setCursorPosition(0)\n        self.LE_17_1z.setText(str(Around(MatrixZ1_17)))\n        self.LE_17_1z.setCursorPosition(0)\n        self.LE_17_2x.setText(str(Around(MatrixX2_17)))\n        self.LE_17_2x.setCursorPosition(0)\n        self.LE_17_2y.setText(str(Around(MatrixY2_17)))\n        self.LE_17_2y.setCursorPosition(0)\n        self.LE_17_2z.setText(str(Around(MatrixZ2_17)))\n        self.LE_17_2z.setCursorPosition(0)\n        self.LE_17_3x.setText(str(Around(MatrixX3_17)))\n        self.LE_17_3x.setCursorPosition(0)\n        self.LE_17_3y.setText(str(Around(MatrixY3_17)))\n        self.LE_17_3y.setCursorPosition(0)\n        self.LE_17_3z.setText(str(Around(MatrixZ3_17)))\n        self.LE_17_3z.setCursorPosition(0)\n\n        self.LE_18_determinant.setText(str(DeterminantM))\n        self.LE_18_determinantDecim.setText(str(decimal.Decimal(DeterminantM)))\n\n    def on_SP_012_01_Text_valueChanged(self, value):\n        global seTTextHeigthValue\n        global FreeCAD_ParamGetSet\n\n        seTTextHeigthValue = value\n        FreeCAD_ParamGetSet.SetInt(u\"seTTextHeigthValue\", seTTextHeigthValue)               # 11\n        self.fontGlobal_08.setPixelSize(seTTextHeigthValue)          # pour compatibilite Windows Linux pour tous les textes\n\n        self.scrollArea.setFont(self.fontGlobal_08)\n        ######GBox_001_Document\n        self.GBox_001_Document.setFont(self.fontGlobal_08)\n        self.LA_1.setFont(self.fontGlobal_08)\n        self.LE_1.setFont(self.fontGlobal_08)\n        self.LA_2.setFont(self.fontGlobal_08)\n        self.LE_2.setFont(self.fontGlobal_08)\n        self.LE_2a.setFont(self.fontGlobal_08)\n        self.LA_3.setFont(self.fontGlobal_08)\n        self.LA_4.setFont(self.fontGlobal_08)\n        self.LE_3.setFont(self.fontGlobal_08)\n        self.LE_3a.setFont(self.fontGlobal_08)\n\n        ######GBox_002_Coordinate_Mouse\n        self.GBox_002_Coordinate_Mouse.setFont(self.fontGlobal_08)\n        self.LA_4x.setFont(self.fontGlobal_08)\n        self.LA_4y.setFont(self.fontGlobal_08)\n        self.LA_4z.setFont(self.fontGlobal_08)\n        self.LE_4x.setFont(self.fontGlobal_08)\n        self.LE_4y.setFont(self.fontGlobal_08)\n        self.LE_4z.setFont(self.fontGlobal_08)\n        self.PB_Axis_01.setFont(self.fontGlobal_08)\n\n        ######GBox_003_Color\n        self.GBox_003_Color.setFont(self.fontGlobal_08)\n        self.LA_1_Red.setFont(self.fontGlobal_08)\n        self.LA_2_Green.setFont(self.fontGlobal_08)\n        self.LA_3_Blue.setFont(self.fontGlobal_08)\n        self.LA_4_Transparent.setFont(self.fontGlobal_08)\n        self.LE_CRed.setFont(self.fontGlobal_08)\n        self.LE_CGreen.setFont(self.fontGlobal_08)\n        self.LE_CBlue.setFont(self.fontGlobal_08)\n        self.LE_Transparent.setFont(self.fontGlobal_08)\n        self.LE_ConversionUnsigned.setFont(self.fontGlobal_08)\n        self.PB_ChangeColor.setFont(self.fontGlobal_08)\n        self.CBox_Color_FaceObject.setFont(self.fontGlobal_08)\n        self.PB_CreateFace.setFont(self.fontGlobal_08)\n        self.SBox_Transparence.setFont(self.fontGlobal_08)\n\n        ######GBox_004_Object_Mesh\n        self.GBox_004_Object_Mesh.setFont(self.fontGlobal_08)\n        self.LA_N_Edges.setFont(self.fontGlobal_08)\n        self.LE_N_Edges.setFont(self.fontGlobal_08)\n        self.LA_N_Facets.setFont(self.fontGlobal_08)\n        self.LE_N_Facets.setFont(self.fontGlobal_08)\n        self.LA_N_Points.setFont(self.fontGlobal_08)\n        self.LE_N_Points.setFont(self.fontGlobal_08)\n\n        ######GBox_005_Value_Unit\n        self.GBox_005_Value_Unit.setFont(self.fontGlobal_08)\n        #self.ComboB_Grandeur.setFont(self.fontGlobal_08)\n        self.LA_5.setFont(self.fontGlobal_08)\n        self.LA_5b.setFont(self.fontGlobal_08)\n        self.LE_5.setFont(self.fontGlobal_08)\n        self.LE_5b.setFont(self.fontGlobal_08)\n        self.SB_Arc_ToByArcs.setFont(self.fontGlobal_08)\n        self.PB_BSplineCreateNodes.setFont(self.fontGlobal_08)\n        self.LA_6.setFont(self.fontGlobal_08)\n        self.LE_6.setFont(self.fontGlobal_08)\n        \n        ######GBox_012_SpreadSheet\n        self.GBox_012_SpreadSheet.setFont(self.fontGlobal_08)\n        self.tableWidget.setFont(self.fontGlobal_08)\n        \n        ######GBox_006_Inclination\n        self.GBox_006_Inclination.setFont(self.fontGlobal_08)\n        self.LA_8a.setFont(self.fontGlobal_08)\n        self.PB_Ra.setFont(self.fontGlobal_08)\n        self.LA_8a_2.setFont(self.fontGlobal_08)\n        self.LE_8xy.setFont(self.fontGlobal_08)\n        self.LA_8xy.setFont(self.fontGlobal_08)\n        self.LE_8xya.setFont(self.fontGlobal_08)\n        self.LA_8yz.setFont(self.fontGlobal_08)\n        self.LE_8yz.setFont(self.fontGlobal_08)\n        self.LE_8yza.setFont(self.fontGlobal_08)\n        self.LA_8zx.setFont(self.fontGlobal_08)\n        self.LE_8zx.setFont(self.fontGlobal_08)\n        self.LE_8zxa.setFont(self.fontGlobal_08)\n        self.PB_Line_Direction.setFont(self.fontGlobal_08)\n        self.PB_Line_ValueAT.setFont(self.fontGlobal_08)\n        self.PB_Line_NormalAT.setFont(self.fontGlobal_08)\n        self.LE_9_Direction.setFont(self.fontGlobal_08)\n        self.LE_10_ValueAt.setFont(self.fontGlobal_08)\n        self.LE_10b_NormalAt.setFont(self.fontGlobal_08)\n\n        ######GBox_007_Surface_and_Volume\n        self.GBox_007_Surface_and_Volume.setFont(self.fontGlobal_08)\n        self.LA_9.setFont(self.fontGlobal_08)\n        self.LE_9a.setFont(self.fontGlobal_08)\n        self.LA_10.setFont(self.fontGlobal_08)\n        self.LE_10a.setFont(self.fontGlobal_08)\n        self.LA_11.setFont(self.fontGlobal_08)\n        self.LE_11a.setFont(self.fontGlobal_08)\n        self.LA_Unit.setFont(self.fontGlobal_08)\n        self.comboBox_Unit.setFont(self.fontGlobal_08)\n        self.LA_Weight.setFont(self.fontGlobal_08)\n        self.LE_12a.setFont(self.fontGlobal_08)\n        self.LA_Density.setFont(self.fontGlobal_08)\n        self.DS_Density.setFont(self.fontGlobal_08)\n        self.LA_Cost.setFont(self.fontGlobal_08)\n        self.LA_Price.setFont(self.fontGlobal_08)\n        self.LE_Cost.setFont(self.fontGlobal_08)\n        self.DS_Price.setFont(self.fontGlobal_08)\n        self.PB_Del_Material.setFont(self.fontGlobal_08)\n        self.CBox_Materiel.setFont(self.fontGlobal_08)\n        self.LE_Materiel.setFont(self.fontGlobal_08)\n\n        ######GBox_009_BoundBox\n        self.GBox_009_BoundBox.setFont(self.fontGlobal_08)\n        self.LA_007_01_Xlength.setFont(self.fontGlobal_08)\n        self.LA_007_02_Ylength.setFont(self.fontGlobal_08)\n        self.LA_007_03_Zlength.setFont(self.fontGlobal_08)\n        self.LA_007_04_Diagonallength.setFont(self.fontGlobal_08)\n        self.LE_007_BB_01_XLength.setFont(self.fontGlobal_08)\n        self.LE_007_BB_02_YLength.setFont(self.fontGlobal_08)\n        self.LE_007_BB_03_ZLength.setFont(self.fontGlobal_08)\n        self.LE_007_BB_04_Diagonal.setFont(self.fontGlobal_08)\n        self.PB_BoundBox_Tracing.setFont(self.fontGlobal_08)\n        self.PB_00_BoundBox_Volume.setFont(self.fontGlobal_08)\n        self.CB_01_BoundBox_Text.setFont(self.fontGlobal_08)\n        self.DS_BoundBoxTextHeigth.setFont(self.fontGlobal_08)\n\n        ######GBox_010_Center_Mass\n        self.GBox_010_Center_Mass.setFont(self.fontGlobal_08)\n        self.PB_BoundBox_Tracing.setFont(self.fontGlobal_08)\n        self.LA_13x.setFont(self.fontGlobal_08)\n        self.LA_13y.setFont(self.fontGlobal_08)\n        self.LA_13z.setFont(self.fontGlobal_08)\n        self.LE_13x.setFont(self.fontGlobal_08)\n        self.LE_13y.setFont(self.fontGlobal_08)\n        self.LE_13z.setFont(self.fontGlobal_08)\n        self.PB_Axis_02.setFont(self.fontGlobal_08)\n        self.LA_14x.setFont(self.fontGlobal_08)\n        self.LA_14y.setFont(self.fontGlobal_08)\n        self.LA_14z.setFont(self.fontGlobal_08)\n        self.LE_14x.setFont(self.fontGlobal_08)\n        self.LE_14y.setFont(self.fontGlobal_08)\n        self.LE_14z.setFont(self.fontGlobal_08)\n        self.PB_Axis_03.setFont(self.fontGlobal_08)\n        \n        ######GBox_011_Inertia\n        self.GBox_011_Inertia.setFont(self.fontGlobal_08)\n        self.LE_16_Raw.setFont(self.fontGlobal_08)\n        self.LA_16.setFont(self.fontGlobal_08)\n        self.SB_16_M.setFont(self.fontGlobal_08)\n        self.LA_16x.setFont(self.fontGlobal_08)\n        self.LA_16y.setFont(self.fontGlobal_08)\n        self.LA_16z.setFont(self.fontGlobal_08)\n        self.LE_16_1x.setFont(self.fontGlobal_08)\n        self.LE_16_1y.setFont(self.fontGlobal_08)\n        self.LE_16_1z.setFont(self.fontGlobal_08)\n        self.LE_16_01.setFont(self.fontGlobal_08)\n        self.PB_Axis_04_16_1.setFont(self.fontGlobal_08)\n        self.LE_16_2x.setFont(self.fontGlobal_08)\n        self.LE_16_2y.setFont(self.fontGlobal_08)\n        self.LE_16_2z.setFont(self.fontGlobal_08)\n        self.LE_16_02.setFont(self.fontGlobal_08)\n        self.PB_Axis_05_16_2.setFont(self.fontGlobal_08)\n        self.LE_16_3x.setFont(self.fontGlobal_08)\n        self.LE_16_3y.setFont(self.fontGlobal_08)\n        self.LE_16_3z.setFont(self.fontGlobal_08)\n        self.LE_16_03.setFont(self.fontGlobal_08)\n        self.PB_Axis_06_16_3.setFont(self.fontGlobal_08)\n        self.LE_16_4x.setFont(self.fontGlobal_08)\n        self.LE_16_4y.setFont(self.fontGlobal_08)\n        self.LE_16_4z.setFont(self.fontGlobal_08)\n        self.LE_16_04.setFont(self.fontGlobal_08)\n        self.PB_Axis_07_16_4.setFont(self.fontGlobal_08)\n        self.LA_17.setFont(self.fontGlobal_08)\n        self.SB_17_M.setFont(self.fontGlobal_08)\n        self.LA_17x.setFont(self.fontGlobal_08)\n        self.LA_17y.setFont(self.fontGlobal_08)\n        self.LA_17z.setFont(self.fontGlobal_08)\n        self.LE_17_1x.setFont(self.fontGlobal_08)\n        self.LE_17_1y.setFont(self.fontGlobal_08)\n        self.LE_17_1z.setFont(self.fontGlobal_08)\n        self.PB_Axis_08_17_1.setFont(self.fontGlobal_08)\n        self.LE_17_2x.setFont(self.fontGlobal_08)\n        self.LE_17_2y.setFont(self.fontGlobal_08)\n        self.LE_17_2z.setFont(self.fontGlobal_08)\n        self.PB_Axis_09_17_2.setFont(self.fontGlobal_08)\n        self.LE_17_3x.setFont(self.fontGlobal_08)\n        self.LE_17_3y.setFont(self.fontGlobal_08)\n        self.LE_17_3z.setFont(self.fontGlobal_08)\n        self.PB_Axis_10_17_3.setFont(self.fontGlobal_08)\n        self.PB_Axis_11_17_4.setFont(self.fontGlobal_08)\n        self.LA_determinant.setFont(self.fontGlobal_08)\n        self.LA_determinantDecimal.setFont(self.fontGlobal_08)\n        self.LE_18_determinant.setFont(self.fontGlobal_08)\n        self.LE_18_determinantDecim.setFont(self.fontGlobal_08)\n        \n        ######GBox_013_SpreadSheet_Creation\n        self.GBox_013_SpreadSheet_Creation.setFont(self.fontGlobal_08)\n        self.PB_01_Read_SpreadSheet.setFont(self.fontGlobal_08)\n        self.PB_02_Save_SreadSheet.setFont(self.fontGlobal_08)\n        self.PB_03_Create_SpreadSheet.setFont(self.fontGlobal_08)\n        self.RB_01_Tabulation.setFont(self.fontGlobal_08)\n        self.RB_02_Virgule.setFont(self.fontGlobal_08)\n        self.RB_03_Point_Virgule.setFont(self.fontGlobal_08)\n        self.RB_04_Espace.setFont(self.fontGlobal_08)\n        \n        ######GBox_014_Main_Tools\n        self.GBox_014_Main_Tools.setFont(self.fontGlobal_08)\n        self.RB_01_ClipBoard.setFont(self.fontGlobal_08)\n        self.CB_02_Point.setFont(self.fontGlobal_08)\n        self.CB_03_Axis.setFont(self.fontGlobal_08)\n        self.CB_04_Plane.setFont(self.fontGlobal_08)\n        self.CB_01_Info.setFont(self.fontGlobal_08)\n        self.CB_05_Position.setFont(self.fontGlobal_08)\n        self.SPBox_arrondi.setFont(self.fontGlobal_08)\n        self.SPBox_arrondi.setFont(self.fontGlobal_08)\n        self.SP_012_01_Text.setFont(self.fontGlobal_08)\n        self.PB_05_Help_Forum.setFont(self.fontGlobal_08)\n        self.PB_06_Help_Wiki.setFont(self.fontGlobal_08)\n        self.PB_01_Refrech.setFont(self.fontGlobal_08)\n        self.PB_04_Quit.setFont(self.fontGlobal_08)\n\n    def on_SPBox_arrondi_valueChanged(self, value):\n        global seTDecimalValue\n        global FreeCAD_ParamGetSet\n\n        seTDecimalValue = value\n        FreeCAD_ParamGetSet.SetInt(u\"seTDecimalValue\", seTDecimalValue)       # *4\n        self.on_PB_01_Refrech_clicked()\n\n    def on_PB_Line_Direction(self):\n        global object_Label\n        global directionObj\n        global direcValueAt\n        global direcNormalAt\n        global switchInertia\n        global RotationToEuler\n        global switchCreateLineDiVatNatOnClick\n        global position0\n        global position1\n        global position2\n\n        if (directionObj != \"[]\"):\n            switchInertia = 1\n            try:\n                FreeCAD.ActiveDocument.openTransaction(u\"FCInfo Direction\")    # memorise les actions (avec annuler restore)\n                if switchCreateLineDiVatNatOnClick == 0:\n                    points=[FreeCAD.Vector(0.0,0.0,0.0),FreeCAD.Vector(directionObj)]\n                else:\n                    points=[FreeCAD.Vector(position0,position1,position2),FreeCAD.Vector(directionObj[0]+position0,directionObj[1]+position1,directionObj[2]+position2)]\n                line0 = Draft.makeWire(points,closed=False,face=False,support=None)\n                App.ActiveDocument.ActiveObject.recompute()\n                line0.Label = u\"Direction_(Yellow)_\" + object_Label\n                line0.ViewObject.LineColor = (1.0,1.0,0.0)\n                line0.Length = 100.0\n                if RotationToEuler != \"\":\n                    line0.Placement.Rotation = FreeCAD.Rotation(RotationToEuler[0] ,RotationToEuler[1], RotationToEuler[2])\n                    RotationToEuler = \"\"\n                App.ActiveDocument.recompute()\n            except Exception:\n                None\n            switchInertia = 0\n\n    def on_PB_Line_ValueAT(self):\n        global object_Label\n        global direcValueAt\n        global switchInertia\n        global RotationToEuler\n        global switchCreateLineDiVatNatOnClick\n        global position0\n        global position1\n        global position2\n\n        if (direcValueAt != \"[]\"):\n            switchInertia = 1\n            try:\n                FreeCAD.ActiveDocument.openTransaction(u\"FCInfo ValueAt\")    # memorise les actions (avec annuler restore)\n                if switchCreateLineDiVatNatOnClick == 0:\n                    points=[FreeCAD.Vector(0.0,0.0,0.0),FreeCAD.Vector(direcValueAt)]\n                else:\n                    points=[FreeCAD.Vector(position0,position1,position2),FreeCAD.Vector(direcValueAt[0]+position0,direcValueAt[1]+position1,direcValueAt[2]+position2)]\n                line0 = Draft.makeWire(points,closed=False,face=False,support=None)\n                App.ActiveDocument.ActiveObject.recompute()\n                line0.Label = u\"ValueAt_(Magenta)_\" + object_Label\n                line0.ViewObject.LineColor = (1.0,0.0,1.0)\n                line0.Length = 100.0\n                if RotationToEuler != \"\":\n                    line0.Placement.Rotation = FreeCAD.Rotation(RotationToEuler[0] ,RotationToEuler[1], RotationToEuler[2])\n                    RotationToEuler = \"\"\n                App.activeDocument().recompute()\n\n            except Exception:\n                None\n            switchInertia = 0\n\n    def on_PB_Line_NormalAT(self):\n        global object_Label\n        global direcNormalAt\n        global switchInertia\n        global RotationToEuler\n        global switchCreateLineDiVatNatOnClick\n        global position0\n        global position1\n        global position2\n\n        if (direcNormalAt != \"[]\"):\n            switchInertia = 1\n            try:\n                FreeCAD.ActiveDocument.openTransaction(u\"FCInfo NormalAt\")    # memorise les actions (avec annuler restore)\n                if switchCreateLineDiVatNatOnClick == 0:\n                    points=[FreeCAD.Vector(0.0,0.0,0.0),FreeCAD.Vector(direcNormalAt)]\n                else:\n                    points=[FreeCAD.Vector(position0,position1,position2),FreeCAD.Vector(direcNormalAt[0]+position0,direcNormalAt[1]+position1,direcNormalAt[2]+position2)]\n                line0 = Draft.makeWire(points,closed=False,face=False,support=None)\n                App.ActiveDocument.ActiveObject.recompute()\n                line0.Label = u\"NormalAt_(Cyan)_\" + object_Label\n                line0.ViewObject.LineColor = (0.0,1.0,1.0)\n                line0.Length = 100.0\n                if RotationToEuler != \"\":\n                    line0.Placement.Rotation = FreeCAD.Rotation(RotationToEuler[0] ,RotationToEuler[1], RotationToEuler[2])\n                    RotationToEuler = \"\"\n                App.ActiveDocument.recompute()\n            except Exception:\n                None\n            switchInertia = 0\n\n    def paletteBase(self):\n        qpBase = \"QLineEdit {background-color: QPalette.Base}\"\n        qpIcon = QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_05)) # icone dans une variable \n\n        self.LE_4x.setStyleSheet(qpBase)\n        self.LE_4y.setStyleSheet(qpBase)\n        self.LE_4z.setStyleSheet(qpBase)\n        self.PB_Axis_01.setIcon(qpIcon)      # icon dans une variable \n        self.LE_13x.setStyleSheet(qpBase)\n        self.LE_13y.setStyleSheet(qpBase)\n        self.LE_13z.setStyleSheet(qpBase)\n        self.PB_Axis_02.setIcon(qpIcon)      # icon dans une variable \n        self.LE_14x.setStyleSheet(qpBase)\n        self.LE_14y.setStyleSheet(qpBase)\n        self.LE_14z.setStyleSheet(qpBase)\n\n        self.PB_Axis_03.setIcon(qpIcon)      # icon dans une variable \n        self.LE_16_1x.setStyleSheet(qpBase)\n        self.LE_16_1y.setStyleSheet(qpBase)\n        self.LE_16_1z.setStyleSheet(qpBase)\n        self.PB_Axis_04_16_1.setIcon(qpIcon) # icone dans une variable \n        self.LE_16_2x.setStyleSheet(qpBase)\n        self.LE_16_2y.setStyleSheet(qpBase)\n        self.LE_16_2z.setStyleSheet(qpBase)\n        self.PB_Axis_05_16_2.setIcon(qpIcon) # icone dans une variable \n        self.LE_16_3x.setStyleSheet(qpBase)\n        self.LE_16_3y.setStyleSheet(qpBase)\n        self.LE_16_3z.setStyleSheet(qpBase)\n        self.PB_Axis_06_16_3.setIcon(qpIcon) # icone dans une variable \n        self.PB_Axis_07_16_4.setIcon(qpIcon) # icone dans une variable \n        self.LE_17_1x.setStyleSheet(qpBase)\n        self.LE_17_1y.setStyleSheet(qpBase)\n        self.LE_17_1z.setStyleSheet(qpBase)\n        self.PB_Axis_08_17_1.setIcon(qpIcon) # icone dans une variable \n        self.LE_17_2x.setStyleSheet(qpBase)\n        self.LE_17_2y.setStyleSheet(qpBase)\n        self.LE_17_2z.setStyleSheet(qpBase)\n        self.PB_Axis_09_17_2.setIcon(qpIcon) # icone dans une variable \n        self.LE_17_3x.setStyleSheet(qpBase)\n        self.LE_17_3y.setStyleSheet(qpBase)\n        self.LE_17_3z.setStyleSheet(qpBase)\n        self.PB_Axis_10_17_3.setIcon(qpIcon) # icone dans une variable \n        self.PB_Axis_11_17_4.setIcon(qpIcon) # icone dans une variable \n        self.PB_05_Help_Forum.setStyleSheet(qpBase)\n        self.PB_06_Help_Wiki.setStyleSheet(qpBase)\n\n    def on_GBox_012_SpreadSheet(self):\n        if self.GBox_012_SpreadSheet.isChecked():\n            self.GBox_012_SpreadSheet.setStyleSheet(u\"QGroupBox {color : QPalette.Base;}\")    # origin system\n            self.on_PB_01_Refrech_clicked()\n        else:\n            self.GBox_012_SpreadSheet.setStyleSheet(u\"QGroupBox {color : #ff0000;}\")\n            self.GBox_012_SpreadSheet.setTitle(u\"Details of the form\")\n            self.GBox_012_SpreadSheet.setToolTip(u\"The module is Disabled by default for rapidity\")\n            self.tableWidget.clear()\n\n    def on_PB_Axis_Mouse(self):\n        global position0\n        global position1\n        global position2\n\n        self.paletteBase()\n        self.LE_4x.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: red}\") #red\n        self.LE_4y.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: green}\")\n        self.LE_4z.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: blue}\")\n        self.PB_Axis_01.setIcon(QtGui.QIcon(QtGui.QPixmap(axisPlane(position0, position1, position2, \"Mouse\"))))\n\n    def on_PB_ChangeColor(self):\n        global seTPositionFlyRightLeft\n        global transparenceFace\n\n        if len(FreeCADGui.Selection.getSelection()) != 0:\n            if seTPositionFlyRightLeft == 1: self.window.hide()  # 1=MainWindow separate\n            couleur = QColorDialog.getColor()\n            if couleur.isValid():\n                FreeCAD.ActiveDocument.openTransaction(u\"FCInfo Color\")    # memorise les actions (avec annuler restore)\n                r = int(str(couleur.name()[1:3]),16)\n                v = int(str(couleur.name()[3:5]),16)\n                b = int(str(couleur.name()[5:7]),16)\n                t = transparenceFace                         # transparence de 0 a 100\n                a = FreeCADGui.Selection.getSelectionEx()    # selection sous objet\n                aa = FreeCADGui.Selection.getSelection()     # selection objet\n                try:\n                    if str(Gui.Selection.getSelectionEx()[0].SubObjects[0])[1:5] == \"Face\":\n                        if self.CBox_Color_FaceObject.isChecked():       # checked = face if not = object\n                            try:\n                                cols = colors = []\n                                cols = FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.DiffuseColor\n                                if len(cols) == 1:\n                                    for i in aa[0].Shape.Faces:\n                                        colors += [(cols[0])]\n                                else:\n                                    colors = cols\n                                for i in range(len(aa)):\n                                    fce = int(a[0].SubElementNames[i][4:])-1\n                                    colors[fce] = (float(r)/255.0, float(v)/255.0, float(b)/255.0, float(t)/100.0)                         \n                                    aa[i].ViewObject.DiffuseColor = colors \n                            except Exception:\n                                None\n                        else:\n                            try:\n                                aa = FreeCADGui.Selection.getSelection()     # selection objet\n                                FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.ShapeColor = (float(r)/255.0, float(v)/255.0, float(b)/255.0)\n                                FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.Transparency = transparenceFace\n                            except Exception:\n                                None\n                    elif str(Gui.Selection.getSelectionEx()[0].SubObjects[0])[1:5] == \"Edge\":\n                        FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.LineColor = (float(r)/255.0, float(v)/255.0, float(b)/255.0)\n\n                    elif str(Gui.Selection.getSelectionEx()[0].SubObjects[0])[1:7] == \"Vertex\":\n                        FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.PointColor = (float(r)/255.0, float(v)/255.0, float(b)/255.0)\n\n                except Exception:\n                    aa = FreeCADGui.Selection.getSelection()             # selection objet\n                    FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.ShapeColor = (float(r)/255.0, float(v)/255.0, float(b)/255.0)\n                    try: \n                        FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.LineColor = (float(r)/255.0, float(v)/255.0, float(b)/255.0)\n                    except Exception: None\n                    try:\n                        FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.PointColor = (float(r)/255.0, float(v)/255.0, float(b)/255.0)\n                    except Exception: None\n                    FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.Transparency = transparenceFace\n\n                ####\n                transparenceFace = FreeCAD.ActiveDocument.getObject(aa[0].Name).ViewObject.Transparency\n                # unsignedEncodeColor decimal pour FC\n                unsignedEncodeColor = '\"' + str(unsignedEncode((r), (v), (b), 0.0)) + '\"'\n                diffuseColorHexa    = '\"' + \"#\"  + decimalTohexa(int(r/255.0)) + decimalTohexa(int(v/255.0)) + decimalTohexa(int(b/255.0)) + '\"'\n                diffuseColorHexaPy  = '\"' + \"0x\" + decimalTohexa(int(r/255.0)) + decimalTohexa(int(v/255.0)) + decimalTohexa(int(b/255.0)) + '\"'\n                diffuseColorRVB     = '\"' + str(int(r/255.0)) + \",\" + str(int(v/255.0)) + \",\" + str(int(b/255.0)) + '\"'\n                #\n                self.on_PB_01_Refrech_clicked()\n                ####\n\n            if seTPositionFlyRightLeft == 1: self.window.show()  # 1=MainWindow separate\n\n    def SIGNAL_CBox_Color_FaceObject(self):\n\n        if self.CBox_Color_FaceObject.isChecked():   # checked = face if not = object\n            self.PB_ChangeColor.setText(u\"Color.S.Obj\")\n            self.PB_CreateFace.setText(u\"Dupl.S.Obj\")\n            self.CBox_Color_FaceObject.setText(u\"Object\")\n        else:\n            self.PB_ChangeColor.setText(u\"Color.Objet\")\n            self.PB_CreateFace.setText(u\"Dupl.Objet\")\n            self.CBox_Color_FaceObject.setText(u\"Sub.Objet\")\n\n    def on_PB_CreateFace(self):\n        global sel\n        global indexFaceMesh\n        global coordPointsMesh\n        global detected\n        global cols\n        global colorShapeFace\n        global colorShapeLine\n        global colorShapePoint\n        global setMeshTopologyValue\n\n        if self.CBox_Color_FaceObject.isChecked():  #  repro face / subOject\n            FreeCAD.ActiveDocument.openTransaction(u\"FCInfo Copy Element\")    # memorise les actions (avec annuler restore)\n            if detected[0:4] == \"Mesh\":\n                labelObject = sel[0].Label\n                points = [FreeCAD.Vector(coordPointsMesh[0][0], coordPointsMesh[0][1], coordPointsMesh[0][2]), \n                          FreeCAD.Vector(coordPointsMesh[1][0], coordPointsMesh[1][1], coordPointsMesh[1][2]), \n                          FreeCAD.Vector(coordPointsMesh[2][0], coordPointsMesh[2][1], coordPointsMesh[2][2])]\n                dummy = cols    # save cols before changing []\n                lineTriangle = Draft.makeWire(points,  closed=True, face=True, support=None)\n                cols = dummy    # restitue the cols deleted\n                actifObjet = App.ActiveDocument.ActiveObject\n                FreeCAD.ActiveDocument.getObject(lineTriangle.Name).Label = \"Face_\" + str(indexFaceMesh) + \"_\" + labelObject\n                Gui.Selection.clearSelection(sel[0].Name)\n            elif detected == \"<PointKernel object>\":\n                Gui.runCommand(u'Std_Copy',0)\n                Gui.runCommand(u'Std_Paste',0)\n                actifObjet = App.ActiveDocument.ActiveObject\n            else:\n                try:\n                    try:\n                        placementOrigine = sel[0].getGlobalPlacement()\n                    except Exception:\n                        placementOrigine = sel[0].Placement()\n                    Part.show(FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0].copy())   # create repro shape subObject\n                    actifObjet = App.ActiveDocument.ActiveObject\n                    actifObjet.Placement = placementOrigine\n                except Exception:\n                    None\n        else: # repro object\n            FreeCAD.ActiveDocument.openTransaction(u\"FCInfo Copy Object\")    # memorise les actions (avec annuler restore)\n            if detected[0:4] == u\"Mesh\":\n                ### Begin command Part_ShapeFromMesh\n                _Shape = App.ActiveDocument.addObject('Part::Feature', str(sel[0].Name) + \"_Shape\")\n                __shape__ = Part.Shape()\n                __shape__.makeShapeFromMesh(App.ActiveDocument.getObject(sel[0].Name).Mesh.Topology, setMeshTopologyValue, False)   # 0.10000\n                App.ActiveDocument.ActiveObject.Shape = __shape__\n                App.ActiveDocument.ActiveObject.purgeTouched()\n                ### End command Part_ShapeFromMesh\n                ### Begin command Part_MakeSolid\n                __s__=App.ActiveDocument.getObject(_Shape.Name).Shape.Faces\n                __s__=Part.Solid(Part.Shell(__s__))\n                __o__=App.ActiveDocument.addObject(\"Part::Feature\",str(sel[0].Name + \"_solid\"))\n                __o__.Label=sel[0].Name + u\"_(Solid)\"\n                __o__.Shape=__s__\n                App.ActiveDocument.removeObject(_Shape.Name)\n                ### End command Part_MakeSolid\n                actifObjet = App.ActiveDocument.ActiveObject\n                App.ActiveDocument.getObject(sel[0].Name).Visibility = False\n            elif detected == \"<PointKernel object>\":\n                Gui.runCommand('Std_Copy',0)\n                Gui.runCommand('Std_Paste',0)\n                actifObjet = App.ActiveDocument.ActiveObject\n                actifObjet.Label = App.ActiveDocument.getObject(sel[0].Name).Label + \"_Points\"\n                App.ActiveDocument.getObject(sel[0].Name).Visibility = False\n            else:\n                try:\n                    placementOrigine = sel[0].getGlobalPlacement()\n                except Exception:\n                    placementOrigine = sel[0].Placement()\n                try:\n                    Part.show(sel[0].Shape)\n                except Exception:\n                    None\n                actifObjet = App.ActiveDocument.ActiveObject\n                actifObjet.Placement = placementOrigine\n\n        try:\n            actifObjet.ViewObject.ShapeColor = colorShapeFace\n        except Exception:\n            None\n        try:\n            actifObjet.ViewObject.LineColor  = colorShapeLine\n        except Exception:\n            None\n        try:\n            actifObjet.ViewObject.PointColor = colorShapePoint\n        except Exception:\n            None\n        try:\n            transPar = math.ceil(round(cols[indexFaceMesh][3]*100, 12))   # face\n        except Exception:\n            try:\n                transPar = math.ceil(round(cols[indexFaceMesh]*100, 12))  # edge\n            except Exception:\n                try:\n                    transPar = math.ceil(round(cols[0]*100, 12))          # if indexFaceMesh-1 = -1\n                except Exception:\n                    transPar = 0\n        try:\n            if self.CBox_Color_FaceObject.isChecked():\n                actifObjet.ViewObject.Transparency = transPar\n                if (self.SBox_Transparence.value()) != transPar:\n                    actifObjet.ViewObject.Transparency = self.SBox_Transparence.value()\n            else:\n                try:\n                    actifObjet.ViewObject.DiffuseColor = cols\n                except Exception: None\n                if (self.CBox_Color_FaceObject.isChecked()) or (len(cols) == 1):\n                    actifObjet.ViewObject.Transparency = transPar\n                if (self.SBox_Transparence.value()) != transPar:\n                    actifObjet.ViewObject.Transparency = self.SBox_Transparence.value()\n        except Exception:\n            None\n        App.activeDocument().recompute(None,True,True)\n\n    def on_SBox_Transparence_valueChanged(self, value):\n        global transparenceFace\n\n        transparenceFace = value\n    def on_SB_16_M_valueChanged(self, value):\n        global FreeCAD_ParamGetSet\n        global setMomentOfInertia_16\n\n        setMomentOfInertia_16 = value\n        FreeCAD_ParamGetSet.SetInt(u\"setMomentOfInertia_16\", setMomentOfInertia_16)\n        self.on_PB_01_Refrech_clicked()\n\n    def on_SB_17_M_valueChanged(self, value):\n        global FreeCAD_ParamGetSet\n        global setMomentOfInertiaMassique_17\n\n        setMomentOfInertiaMassique_17 = value\n        FreeCAD_ParamGetSet.SetInt(u\"setMomentOfInertiaMassique_17\", setMomentOfInertiaMassique_17)\n        self.on_PB_01_Refrech_clicked()\n\n    def on_PB_Axis_Center_Shape(self):\n        global boundBoxCenterX\n        global boundBoxCenterY\n        global boundBoxCenterZ\n\n        self.paletteBase()\n        self.LE_13x.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: red}\") #red\n        self.LE_13y.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: green}\")\n        self.LE_13z.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: blue}\")\n        self.PB_Axis_02.setIcon(QtGui.QIcon(QtGui.QPixmap(axisPlane(boundBoxCenterX, boundBoxCenterY, boundBoxCenterZ, \"BBCenter\")))) # icone dans une variable \n\n    def on_PB_Axis_Center_Mass(self):\n        global CenterOfMassX\n        global CenterOfMassY\n        global CenterOfMassZ\n\n        self.paletteBase()\n        self.LE_14x.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: red}\") #red\n        self.LE_14y.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: green}\")\n        self.LE_14z.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: blue}\")\n        self.PB_Axis_03.setIcon(QtGui.QIcon(QtGui.QPixmap(axisPlane(CenterOfMassX, CenterOfMassY, CenterOfMassZ, \"CenterOfMass\")))) # icone dans une variable \n\n    def on_PB_Axis_04_16_1(self):\n        global MatrixX1_16\n        global MatrixY1_16\n        global MatrixZ1_16\n\n        self.paletteBase()\n        self.LE_16_1x.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: red}\") #red\n        self.LE_16_1y.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: green}\")\n        self.LE_16_1z.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: blue}\")\n        self.PB_Axis_04_16_1.setIcon(QtGui.QIcon(QtGui.QPixmap(axisPlane(MatrixX1_16, MatrixY1_16, MatrixZ1_16, \"Matrix1\")))) # icone dans une variable \n\n    def on_PB_Axis_05_16_2(self):\n        global MatrixX2_16\n        global MatrixY2_16\n        global MatrixZ2_16\n\n        self.paletteBase()\n        self.LE_16_2x.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: red}\") #red\n        self.LE_16_2y.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: green}\")\n        self.LE_16_2z.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: blue}\")\n        self.PB_Axis_05_16_2.setIcon(QtGui.QIcon(QtGui.QPixmap(axisPlane(MatrixX2_16, MatrixY2_16, MatrixZ2_16, \"Matrix2\")))) # icone dans une variable \n\n    def on_PB_Axis_06_16_3(self):\n        global MatrixX3_16\n        global MatrixY3_16\n        global MatrixZ3_16\n\n        self.paletteBase()\n        self.LE_16_3x.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: red}\") #red\n        self.LE_16_3y.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: green}\")\n        self.LE_16_3z.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: blue}\")\n        self.PB_Axis_06_16_3.setIcon(QtGui.QIcon(QtGui.QPixmap(axisPlane(MatrixX3_16, MatrixY3_16, MatrixZ3_16, \"Matrix3\")))) # icone dans une variable \n\n    def on_PB_Axis_07_16_4(self):\n        global MatrixX1_16\n        global MatrixY2_16\n        global MatrixZ3_16\n\n        self.paletteBase()\n        self.LE_16_1x.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: red}\") #red\n        self.LE_16_2y.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: green}\")\n        self.LE_16_3z.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: blue}\")\n        self.PB_Axis_07_16_4.setIcon(QtGui.QIcon(QtGui.QPixmap(axisPlane(MatrixX1_16, MatrixY2_16, MatrixZ3_16, \"Matrix123\")))) # icone dans une variable \n\n    def on_PB_Axis_08_17_1(self):\n        global MatrixX1_17\n        global MatrixY1_17\n        global MatrixZ1_17\n\n        self.paletteBase()\n        self.LE_17_1x.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: red}\") #red\n        self.LE_17_1y.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: green}\")\n        self.LE_17_1z.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: blue}\")\n        self.PB_Axis_08_17_1.setIcon(QtGui.QIcon(QtGui.QPixmap(axisPlane(MatrixX1_17, MatrixY1_17, MatrixZ1_17, \"MatrixW1\")))) # icone dans une variable \n\n    def on_PB_Axis_09_17_2(self):\n        global MatrixX2_17\n        global MatrixY2_17\n        global MatrixZ2_17\n\n        self.paletteBase()\n        self.LE_17_2x.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: red}\") #red\n        self.LE_17_2y.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: green}\")\n        self.LE_17_2z.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: blue}\")\n        self.PB_Axis_09_17_2.setIcon(QtGui.QIcon(QtGui.QPixmap(axisPlane(MatrixX2_17, MatrixY2_17, MatrixZ2_17, \"MatrixW2\")))) # icone dans une variable \n\n    def on_PB_Axis_10_17_3(self):\n        global MatrixX3_17\n        global MatrixY3_17\n        global MatrixZ3_17\n\n        self.paletteBase()\n        self.LE_17_3x.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: red}\") #red\n        self.LE_17_3y.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: green}\")\n        self.LE_17_3z.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: blue}\")\n        self.PB_Axis_10_17_3.setIcon(QtGui.QIcon(QtGui.QPixmap(axisPlane(MatrixX3_17, MatrixY3_17, MatrixZ3_17, \"MatrixW3\")))) # icone dans une variable \n\n    def on_PB_Axis_11_17_4(self):\n        global MatrixX1_17\n        global MatrixY2_17\n        global MatrixZ3_17\n\n        self.paletteBase()\n        self.LE_17_1x.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: red}\") #red\n        self.LE_17_2y.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: green}\")\n        self.LE_17_3z.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: blue}\")\n        self.PB_Axis_11_17_4.setIcon(QtGui.QIcon(QtGui.QPixmap(axisPlane(MatrixX1_17, MatrixY2_17, MatrixZ3_17, \"MatrixW123\")))) # icone dans une variable \n\n    def on_PB_BoundBox_Tracing(self):\n        bounBoxTracing()\n\n    def On_PB_00_BoundBox_Volume(self):\n        global switchBoundBoxCreateVolume\n\n        switchBoundBoxCreateVolume = 1\n        bounBoxTracing()\n\n    def On_CB_01_BoundBox_Text(self):\n        global switchBoundBoxCreateText\n        global FreeCAD_ParamGetSet\n\n        if self.CB_01_BoundBox_Text.isChecked():\n            switchBoundBoxCreateText = 1\n            self.DS_BoundBoxTextHeigth.setEnabled(True)\n            FreeCAD_ParamGetSet.SetBool(u\"switchBoundBoxCreateText\", True)  # True or False\n        else:\n            switchBoundBoxCreateText = 0\n            self.DS_BoundBoxTextHeigth.setEnabled(False)\n            FreeCAD_ParamGetSet.SetBool(u\"switchBoundBoxCreateText\", False) # True or False\n\n    def on_DS_BoundBoxTextHeigth_valueChanged(self, value):\n        global seTBoundBoxTextHeigth\n        global FreeCAD_ParamGetSet\n\n        seTBoundBoxTextHeigth = value\n        FreeCAD_ParamGetSet.SetFloat(u\"seTBoundBoxTextHeigth\", seTBoundBoxTextHeigth)       # 3.0\n\n    def SIGNAL_comboPoids_Changed(self,text):\n        global volume_\n        global seTDensiteValue\n        global poids\n        global uniteM\n        global uniteS\n        global uniteSs\n        global uniteV\n        global uniteP\n        global unitePs\n        global massOrGravity\n        global setMomentOfInertia_16\n        global setMomentOfInertiaMassique_17\n        global MatrixX1_17\n        global MatrixY1_17\n        global MatrixZ1_17\n        global MatrixX2_17\n        global MatrixY2_17\n        global MatrixZ2_17\n        global MatrixX3_17\n        global MatrixY3_17\n        global MatrixZ3_17\n        global seTMaterialPrice\n        global seTMaterialCost\n        global seTMaterialSuffixCost\n        global seTIndexUnitWeight\n        global seTUnitSymbolMicro\n\n        if text == u\"tonne\":          #t    #0.00001 = 1000000\n            uniteP = 0.000001\n            unitePs= u\"t\"\n        elif text == u\"quintal\":      #q    #0.00001 = 100000\n            uniteP = 0.00001\n            unitePs= u\"q\"\n        elif text == u\"kilo gram\":    #kg   # 0.001  = 1000\n            uniteP = 0.001\n            unitePs= u\"kg\"\n        elif text == u\"hecto gram\":   #hg   # 0.01   = 100\n            uniteP = 0.01\n            unitePs= u\"hg\"\n        elif text == u\"decagram\":     #dag  # 0.1   = 10\n            uniteP = 0.1\n            unitePs= u\"dag\"\n        elif text == u\"gram\":         #g    # = 1    Base\n            uniteP = 1.00\n            unitePs= u\"g\"\n        elif text == u\"decigram\":     #dg   # = 0.1\n            uniteP = 10.0\n            unitePs= u\"dg\"\n        elif text == u\"centigram\":    #cg   # = 0.01\n            uniteP = 100.0\n            unitePs= u\"cg\"\n        elif text == u\"milligram\":    #mg   # = 0.001\n            uniteP = 1000.0\n            unitePs= u\"mg\"\n        elif text == u\"microgram\":    #Ug   # = 0.000001    # micro    hex=\"\\xB5\", html=<span>&#181;</span>\n            uniteP = 1000000.0\n            unitePs= seTUnitSymbolMicro+\"g\"\n        elif text == u\"nanogram\":     #ng   # = 0.000000001\n            uniteP = 1000000000.0\n            unitePs= u\"ng\"\n        elif text == u\"picogram\":     #pg   # = 0.000000000001\n            uniteP = 1000000000000.0\n            unitePs= u\"pg\"\n        elif text == u\"femtogram\":    #fg   # = 0.000000000000001\n            uniteP = 1000000000000000.0\n            unitePs= u\"fg\"\n        elif text == u\"grain\":        #gr   # = 0.06479891\n            uniteP = 0.06479891\n            unitePs= u\"gr\"\n        elif text == u\"drachm\":       #dr   # = 1.7718451953125\n            uniteP = 0.56438339189006794681850148894339\n            unitePs= u\"dr\"\n        elif text == u\"once\":         #oz   # = 28.3495231250\n            uniteP = 0.035273961949580412915675808215204\n            unitePs= u\"oz\"\n        elif text == u\"once troy\":    #oz t # = once troy   = 31.1034768\n            uniteP = 0.032150746568627980522100346029483\n            unitePs= u\"oz t\"\n        elif text == u\"livre troy\":   #lb t # = 373.2417216 livre de troy (pound)\n            uniteP = 0.0026792288807189983768416955024569\n            unitePs= u\"lb t\"\n        elif text == u\"livre av\":     #lb   # = 453.59237   livre avoirdupois (pound)\n            uniteP = 0.0022046226218487758072297380134503\n            unitePs= u\"lb\"\n        elif text == u\"stone\":        #st   # = 6350.29318  1 stone     = 14 livres\n            uniteP = 0.00015747304441776970051640985810359\n            unitePs= u\"st\"\n        elif text == u\"quarter\":      #qtr  # = 12700.58636\n            uniteP = 0.000078736522208884850258204929051795\n            unitePs= u\"qtr\"\n        elif text == u\"hundredweight\":#cwt  # = 50802.34544\n            uniteP = 0.000019684130552221212564551232262949\n            unitePs= u\"cwt\"\n        elif text == u\"tonneau fr\":   #     # tonneau fr = 0.00000102145045965\n            uniteP = 0.00000102145045965\n            unitePs= u\"tonneau fr\"\n        elif text == u\"carat\":        #ct   # = 0.2\n            uniteP = 5.0\n            unitePs= u\"ct\"\n        seTIndexUnitWeight = self.comboBox_Unit.currentIndex()\n\n        self.LA_14x.setText(massOrGravity + u\" X\")\n        self.LA_14y.setText(massOrGravity + u\" Y\")\n        self.LA_14z.setText(massOrGravity + u\" Z\")\n        try:\n            poids = ((volume_ * seTDensiteValue) * uniteP) / 1000.0\n            self.LE_12a.setText(str(Around(poids))+ \" \" +unitePs)\n\n            seTMaterialCost = ((volume_ * seTDensiteValue * seTMaterialPrice) / 1000000.0)\n            self.LE_Cost.setText(str(Around(seTMaterialCost)) + seTMaterialSuffixCost) #CostMaterial\n        except Exception:\n            self.LE_12a.setText(u\"\")\n            self.LE_Cost.setText(u\"-\" + seTMaterialSuffixCost) #CostMaterial\n\n        self.SB_17_M.setPrefix(unitePs + uniteSs + \"^\")\n        self.SB_17_M.setValue(setMomentOfInertiaMassique_17)\n        try:\n            ## MatrixX1_17 = MatrixX1*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0)) ## original without parenthesis and modified 17/03/2024\n            MatrixX1_17 = (MatrixX1*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixY1_17 = (MatrixY1*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixZ1_17 = (MatrixZ1*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixX2_17 = (MatrixX2*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixY2_17 = (MatrixY2*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixZ2_17 = (MatrixZ2*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixX3_17 = (MatrixX3*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixY3_17 = (MatrixY3*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixZ3_17 = (MatrixZ3*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n        except Exception:\n            MatrixX1_17 = MatrixY1_17 = MatrixZ1_17 = 0.0\n            MatrixX2_17 = MatrixY2_17 = MatrixZ2_17 = 0.0\n            MatrixX3_17 = MatrixY3_17 = MatrixZ3_17 = 0.0\n\n        self.displayMatrixMomentOfInertia()\n\n    def SIGNAL_comboBox_Changed(self,text):\n        global position0\n        global position1\n        global position2\n        global longueurObjet\n        global rayonObjet\n        global perimetre\n        global numberEdges\n        global surface\n        global surfaceFace\n        global volume_\n        global seTDensiteValue\n        global uniteM\n        global uniteMs\n        global uniteS\n        global uniteSs\n        global uniteV\n        global uniteVs\n        global uniteP\n        global unitePs\n\n        global boundBoxCenterX\n        global boundBoxCenterY\n        global boundBoxCenterZ\n\n        global CenterOfMassX\n        global CenterOfMassY\n        global CenterOfMassZ\n        global massOrGravity\n        global boundBoxLX\n        global boundBoxLY\n        global boundBoxLZ\n        global boundBoxDiag\n        global boundBox_S\n\n        global MatrixX1\n        global MatrixY1\n        global MatrixZ1\n        global Matrix_1\n\n        global MatrixX2\n        global MatrixY2\n        global MatrixZ2\n        global Matrix_2\n\n        global MatrixX3\n        global MatrixY3\n        global MatrixZ3\n        global Matrix_3\n\n        global Matrix12\n        global Matrix13\n        global Matrix14\n        global Matrix15\n\n        global Vertx\n        global Edges\n        global EdgesLong\n        global Faces\n        global FacesSurf\n        global FacesCoor\n        global RowCount\n\n        global setMomentOfInertia_16\n        global setMomentOfInertiaMassique_17\n        global MatrixOfInertiaRaw\n        global MatrixX1_16\n        global MatrixY1_16\n        global MatrixZ1_16\n        global MatrixX2_16\n        global MatrixY2_16\n        global MatrixZ2_16\n        global MatrixX3_16\n        global MatrixY3_16\n\n        global MatrixX1_17\n        global MatrixY1_17\n        global MatrixZ1_17\n        global MatrixX2_17\n        global MatrixY2_17\n        global MatrixZ2_17\n        global MatrixX3_17\n        global MatrixY3_17\n        global MatrixZ3_17\n\n        global seTIndexUnitLength\n        global seTUnitSymbolMicro\n        global seTUnitSymbolCube\n        global seTUnitSymbolCarre\n        global BsplineDetect\n        global BsplineNombreDeNoeuds\n        global BsplineRayonApproximatif\n        global BsplineNumberElement\n        global BsplineCutLength\n        global setBSplineToByArcValue\n        global BSplinetoByArcValeurS\n\n        if text == u\"km\":         #        = 1000000\n            uniteM = 0.000001\n            uniteMs= u\"km\"\n            uniteS = 0.000000000001\n            uniteSs= u\"km\"+seTUnitSymbolCarre\n            uniteV = 0.000000000000000001\n            uniteVs= u\"km\"+seTUnitSymbolCube\n        elif text == u\"hm\":       #        = 100000\n            uniteM = 0.00001\n            uniteMs= u\"hm\"\n            uniteS = 0.0000000001\n            uniteSs= u\"hm\"+seTUnitSymbolCarre\n            uniteV = 0.000000000000001\n            uniteVs= u\"hm\"+seTUnitSymbolCube\n        elif text == u\"dam\":      #        = 10000\n            uniteM = 0.0001\n            uniteMs= u\"dam\"\n            uniteS = 0.00000001\n            uniteSs= u\"dam\"+seTUnitSymbolCarre\n            uniteV = 0.000000000001\n            uniteVs= u\"dam\"+seTUnitSymbolCube\n        elif text == u\"m\":        #        = 1000\n            uniteM = 0.001\n            uniteMs= u\"m\"\n            uniteS = 0.000001\n            uniteSs= u\"m\"+seTUnitSymbolCarre\n            uniteV = 0.000000001\n            uniteVs= u\"m\"+seTUnitSymbolCube\n        elif text == u\"dm\":       #        = 100\n            uniteM = 0.01\n            uniteMs= u\"dm\"\n            uniteS = 0.0001\n            uniteSs= u\"dm\"+seTUnitSymbolCarre\n            uniteV = 0.000001\n            uniteVs= u\"dm\"+seTUnitSymbolCube\n        elif text == u\"cm\":       #        = 10\n            uniteM = 0.1\n            uniteMs= u\"cm\"\n            uniteS = 0.01\n            uniteSs= u\"cm\"+seTUnitSymbolCarre\n            uniteV = 0.001\n            uniteVs= u\"cm\"+seTUnitSymbolCube\n        elif text == u\"mm\":       #        = 1 ###############################\n            uniteM = 1.0\n            uniteMs= u\"mm\"\n            uniteS = 1.0\n            uniteSs= u\"mm\"+seTUnitSymbolCarre\n            uniteV = 1.0\n            uniteVs= u\"mm\"+seTUnitSymbolCube\n        elif text == seTUnitSymbolMicro+\"m\":    #        = 1000 #http://fr.wiktionary.org/wiki/%CE%BCm#conv\n            uniteM = 1000.0\n            uniteMs= seTUnitSymbolMicro+\"m\"\n            uniteS = 1000.0**2\n            uniteSs= seTUnitSymbolMicro+\"m\"+seTUnitSymbolCarre\n            uniteV = 1000.0**3\n            uniteVs= seTUnitSymbolMicro+\"m\"+seTUnitSymbolCube\n        elif text == u\"nm\":       #        = 1000000\n            uniteM = 1000000.0\n            uniteMs= u\"nm\"\n            uniteS = 1000000.0**2\n            uniteSs= u\"nm\"+seTUnitSymbolCarre\n            uniteV = 1000000.0**3\n            uniteVs= u\"nm\"+seTUnitSymbolCube\n        elif text == u\"pm\":       #        = 1000000000\n            uniteM = 1000000000.0\n            uniteMs= u\"pm\"\n            uniteS = 1000000000.0**2\n            uniteSs= u\"pm\"+seTUnitSymbolCarre\n            uniteV = 1000000000.0**3\n            uniteVs= u\"pm\"+seTUnitSymbolCube\n        elif text == u\"fm\":       #        = 1000000000000\n            uniteM = 1000000000000.0\n            uniteMs= u\"fm\"\n            uniteS = 1000000000000.0**2\n            uniteSs= u\"fm\"+seTUnitSymbolCarre\n            uniteV = 1000000000000.0**3\n            uniteVs= u\"fm\"+seTUnitSymbolCube\n        elif text == u\"inch\":     # inch   = 25.400\n            uniteM = 1.0/25.400\n            uniteMs= u\"in\"\n            uniteS = uniteM**2\n            uniteSs= u\"in\"+seTUnitSymbolCarre\n            uniteV = uniteM**3\n            uniteVs= u\"in\"+seTUnitSymbolCube\n        elif text == u\"link\":     # link   = 201.168\n            uniteM = 1.0/201.168\n            uniteMs= u\"lk\"\n            uniteS = uniteM**2\n            uniteSs= u\"lk\"+seTUnitSymbolCarre\n            uniteV = uniteM**3\n            uniteVs= u\"lk\"+seTUnitSymbolCube\n        elif text == u\"foot\":     # foot   = 304.800\n            uniteM = 1.0/304.800\n            uniteMs= u\"ft\"\n            uniteS = uniteM**2\n            uniteSs= u\"ft\"+seTUnitSymbolCarre\n            uniteV = uniteM**3\n            uniteVs= u\"ft\"+seTUnitSymbolCube\n        elif text == u\"yard\":     # yard   = 914.400\n            uniteM = 1.0/914.400\n            uniteMs= u\"yd\"\n            uniteS = uniteM**2\n            uniteSs= u\"yd\"+seTUnitSymbolCarre\n            uniteV = uniteM**3\n            uniteVs= u\"yd\"+seTUnitSymbolCube\n        elif text == u\"perch\":    #rd # rod   perche    = 5029.200\n            uniteM = 1.0/5029.200\n            uniteMs= u\"rd\"\n            uniteS = uniteM**2\n            uniteSs= u\"rd\"+seTUnitSymbolCarre\n            uniteV = uniteM**3\n            uniteVs= u\"rd\"+seTUnitSymbolCube\n        elif text == u\"chain\":    # chain  = 20116.800\n            uniteM = 1.0/20116.800\n            uniteMs= u\"ch\"\n            uniteS = uniteM**2\n            uniteSs= u\"ch\"+seTUnitSymbolCarre\n            uniteV = uniteM**3\n            uniteVs= u\"ch\"+seTUnitSymbolCube\n        elif text == u\"furlong\":  # furlong= 201168\n            uniteM = 1.0/201168\n            uniteMs= u\"fur\"\n            uniteS = uniteM**2\n            uniteSs= u\"fur\"+seTUnitSymbolCarre\n            uniteV = uniteM**3\n            uniteVs= u\"fur\"+seTUnitSymbolCube\n        elif text == u\"mile\":     # mile   = 1609344\n            uniteM = 1.0/1609344\n            uniteMs= u\"mi\"\n            uniteS = uniteM**2\n            uniteSs= u\"mi\"+seTUnitSymbolCarre\n            uniteV = uniteM**3\n            uniteVs= u\"mi\"+seTUnitSymbolCube\n        elif text == u\"league\":   # league = 4828032\n            uniteM = 1.0/4828032\n            uniteMs= u\"lea\"\n            uniteS = uniteM**2\n            uniteSs= u\"lea\"+seTUnitSymbolCarre\n            uniteV = uniteM**3\n            uniteVs= u\"lea\"+seTUnitSymbolCube\n        elif text == u\"nautique\": # nautique = 1852000\n            uniteM = 1.0/1852000\n            uniteMs= u\"nmi\"\n            uniteS = uniteM**2\n            uniteSs= u\"nmi\"+seTUnitSymbolCarre\n            uniteV = uniteM**3\n            uniteVs= u\"nmi\"+seTUnitSymbolCube\n        seTIndexUnitLength = self.comboBox.currentIndex()\n\n        self.LA_14x.setText(massOrGravity + u\" X\")\n        self.LA_14y.setText(massOrGravity + u\" Y\")\n        self.LA_14z.setText(massOrGravity + u\" Z\")\n\n        try:\n            self.LE_4x.setText(str(Around(position0 * uniteM)) + \" \" + uniteMs)\n            self.LE_4y.setText(str(Around(position1 * uniteM)) + \" \" + uniteMs)\n            self.LE_4z.setText(str(Around(position2 * uniteM)) + \" \" + uniteMs)\n        except Exception:\n            position0 = position1 = position2 = 0.0\n            self.LE_4x.setText(str(position0) + \" \" + uniteMs)\n            self.LE_4y.setText(str(position1) + \" \" + uniteMs)\n            self.LE_4z.setText(str(position2) + \" \" + uniteMs)\n\n        try:\n            self.LE_13x.setText(str(Around(boundBoxCenterX * uniteM)) + \" \" + uniteMs)\n            self.LE_13y.setText(str(Around(boundBoxCenterY * uniteM)) + \" \" + uniteMs)\n            self.LE_13z.setText(str(Around(boundBoxCenterZ * uniteM)) + \" \" + uniteMs)\n        except Exception:\n            boundBoxCenterX = boundBoxCenterY = boundBoxCenterZ = 0.0\n            self.LE_13x.setText(str(boundBoxCenterX) + \" \" + uniteMs)\n            self.LE_13y.setText(str(boundBoxCenterY) + \" \" + uniteMs)\n            self.LE_13z.setText(str(boundBoxCenterZ) + \" \" + uniteMs)\n\n        try:\n            self.LE_14x.setText(str(Around(CenterOfMassX * uniteM)) + \" \" + uniteMs)\n            self.LE_14y.setText(str(Around(CenterOfMassY * uniteM)) + \" \" + uniteMs)\n            self.LE_14z.setText(str(Around(CenterOfMassZ * uniteM)) + \" \" + uniteMs)\n        except Exception:\n            CenterOfMassX = CenterOfMassY = CenterOfMassZ = 0.0\n            self.LE_14x.setText(str(CenterOfMassX) + \" \" + uniteMs)\n            self.LE_14y.setText(str(CenterOfMassY) + \" \" + uniteMs)\n            self.LE_14z.setText(str(CenterOfMassZ) + \" \" + uniteMs)\n\n        try:\n            self.LE_007_BB_01_XLength.setText(str(Around(boundBoxLX * uniteM)) + \" \" + uniteMs)\n            self.LE_007_BB_02_YLength.setText(str(Around(boundBoxLY * uniteM)) + \" \" + uniteMs)\n            self.LE_007_BB_03_ZLength.setText(str(Around(boundBoxLZ * uniteM)) + \" \" + uniteMs)\n            self.LE_007_BB_04_Diagonal.setText(str(Around(boundBoxDiag * uniteM)) + \" \" + uniteMs)\n        except Exception:\n            boundBoxLX = boundBoxLY = boundBoxLZ = 0.0\n            self.LE_007_BB_01_XLength.setText(str(boundBoxLX) + \" \" + uniteMs)\n            self.LE_007_BB_02_YLength.setText(str(boundBoxLY) + \" \" + uniteMs)\n            self.LE_007_BB_03_ZLength.setText(str(boundBoxLZ) + \" \" + uniteMs)\n            self.LE_007_BB_04_Diagonal.setText(str(boundBoxDiag) + \" \" + uniteMs)\n\n        try:\n            self.LE_5.setText(str(Around(float(longueurObjet) * float(uniteM)))+ \" \" +uniteMs)\n        except Exception:\n            self.LE_5.setText(u\"\")\n\n        if (rayonObjet != 0.0) or (str(BsplineDetect) == \"<BSplineCurve object>\"):\n            self.LE_5b.setVisible(True)\n            self.LA_5b.setVisible(True)\n            if (str(BsplineDetect) == \"<BSplineCurve object>\"):\n                self.SB_Arc_ToByArcs.setVisible(True)\n                self.on_SB_Arc_ToByArcs_valueChanged(1)\n                self.SB_Arc_ToByArcs.setToolTip(u\"Bspline detected \" + \"\\n\"\n                                        u\"Number of element = \" + str(BsplineNumberElement) + \"\\n\" +\n                                        u\"Calcul with distance between points \" + str(Around((BsplineCutLength) * uniteM)) + \" \" + uniteMs + \"\\n\\n\" +\n                                        u\"toBiArcs(\" + BSplinetoByArcValeurS + \")\" + \"\\n\"\n                                        u\"This value can be modified in the preferences variable : setBSplineToByArcValue\" + \"\\n\")\n                self.PB_BSplineCreateNodes.setText(u\"Points (\" + str(len(BsplinePointsCoor)) + \")\") # Node\n                self.PB_BSplineCreateNodes.setToolTip(u\"Create on point on Poles (\" + str(len(BsplinePointsCoor)) + \") of the BSpline\" + \"\\n\\n\"\n                                                      u\"Command for Shape  : Gui.Selection.getSelection()[0].Points\" + \"\\n\"\n                                                      u\"Command for SubObj : Gui.Selection.getSelectionEx()[0].SubObjects[0].Curve.getPoles()\" + \"\\n\\n\"\n                                                      u\"Hidden Options : \" + \"\\n\\n\"\n                                                      u\"The variables \" + \"\\n\\n\"\n                                                      u\"switchBSplineCreateCircleConstructorAxis\" + \"\\n\"\n                                                      u\"switchBSplineCreateCircleConstructor\" + \"\\n\\n\"\n                                                      u\"accessible in : User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__ + \"\\n\"\n                                                      u\"allow to create the circles and the point axes construction of the BSpline\" + \"\\n\"\n                                                      u\"their number (precision) depends on the value toBiArcs(BSplinetoByArcValeurS)\" + \"\\n\"\n                                                      u\"actual toBiArcs(\" + BSplinetoByArcValeurS + \")\" + \"\\n\")\n                self.PB_BSplineCreateNodes.setVisible(True)\n                self.LA_5b.setText(u\"Radius Appr.\")\n                try:\n                    BsplineRayonApproximatif = str(Around(BsplineArcsRadius[0] * float(uniteM))) + \" \" + uniteMs    # calcul\n                except Exception:\n                    BsplineRayonApproximatif = u\"\"\n                self.LE_5b.setText(BsplineRayonApproximatif)\n                self.LE_5b.setToolTip(u\"BSpline Radius on point : \" + self.SB_Arc_ToByArcs.text())\n                self.LA_6.setText(u\"BSpline nodes\")\n                self.LE_6.setText(str(BsplineNombreDeNoeuds))\n                self.LE_6.setToolTip(u\"Number of nodes of the BSpline.\")\n            else:\n                self.SB_Arc_ToByArcs.setVisible(False)\n                self.PB_BSplineCreateNodes.setVisible(False)\n                self.LA_5b.setText(u\"Radius\")\n                #self.LE_5b.setText(str(Around(rayonObjet * float(uniteM))) + \" \" + uniteMs)\n                self.LE_5b.setText(str(Around(rayonObjet * float(uniteM))) + \" \" + uniteMs + (\" (dia. \" + str(Around(rayonObjet * float(uniteM) * 2.0)) + \" \" + uniteMs + \")\"))\n                self.LE_5b.setToolTip(u\"Radius detected.\")\n                if numberEdges == 1:       \n                    self.LA_6.setText(u\"Circonference (\" + str(numberEdges) + \")\")\n                else:\n                    self.LA_6.setText(u\"Perimetre of shape (\" + str(numberEdges) + \")\")\n                self.LE_6.setText(str(Around(float(perimetre) * float(uniteM))) + \" \" +uniteMs)\n        else:\n            self.LA_6.setText(u\"Perimetre of shape (\" + str(numberEdges) + \")\")\n            self.SB_Arc_ToByArcs.setVisible(False)\n            self.PB_BSplineCreateNodes.setVisible(False)\n            self.LE_5b.setVisible(False)\n            self.LA_5b.setVisible(False)\n            rayonObjet = 0.0\n            try:\n                self.LE_6.setText(str(Around(float(perimetre) * float(uniteM))) + \" \" +uniteMs)\n            except Exception:\n                perimetre = 0.0\n                self.LE_6.setText(str(Around(perimetre)))\n                self.LE_6.setToolTip(u\"Perimeter total of the form.\" + \"\\n\"\n                                     u\"Display the total result of the edges\")\n        try:\n            self.LE_9a.setText(str(Around(float(surface) * float(uniteS))) + \" \" + uniteSs)\n        except Exception:\n            self.LE_9a.setText(u\"\")\n        try:\n            self.LE_10a.setText(str(Around(float(surfaceFace) * float(uniteS))) + \" \" + uniteSs)\n        except Exception:\n            self.LE_10a.setText(u\"\")\n        try:\n            self.LE_11a.setText(str(Around(float(volume_) * float(uniteV))) + \" \" + uniteVs)\n        except Exception:\n            self.LE_11a.setText(u\"\")\n\n        self.SB_16_M.setPrefix(uniteMs + \"^\")\n        self.SB_16_M.setValue(setMomentOfInertia_16)\n        self.LE_16_Raw.setText(\"Raw : \" + MatrixOfInertiaRaw)\n        self.LE_16_Raw.setCursorPosition(0)\n\n        try:\n            ## MatrixX1_16 = MatrixX1*uniteM**setMomentOfInertia_16 ## original without parenthesis and modified 17/03/2024\n            MatrixX1_16 = (MatrixX1*uniteM)**setMomentOfInertia_16\n            MatrixY1_16 = (MatrixY1*uniteM)**setMomentOfInertia_16\n            MatrixZ1_16 = (MatrixZ1*uniteM)**setMomentOfInertia_16\n            MatrixX2_16 = (MatrixX2*uniteM)**setMomentOfInertia_16\n            MatrixY2_16 = (MatrixY2*uniteM)**setMomentOfInertia_16\n            MatrixZ2_16 = (MatrixZ2*uniteM)**setMomentOfInertia_16\n            MatrixX3_16 = (MatrixX3*uniteM)**setMomentOfInertia_16\n            MatrixY3_16 = (MatrixY3*uniteM)**setMomentOfInertia_16\n            MatrixZ3_16 = (MatrixZ3*uniteM)**setMomentOfInertia_16\n        except Exception:\n            MatrixX1_16 = MatrixY1_16 = MatrixZ1_16 = 0.0\n            MatrixX2_16 = MatrixY2_16 = MatrixZ2_16 = 0.0\n            MatrixX3_16 = MatrixY3_16 = MatrixZ3_16 = 0.0\n            #self.SB_16_M.setText(u\"\")\n\n        try:\n            ## MatrixX1_17 = MatrixX1*uniteM**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0)) ## original without parenthesis and modified 17/03/2024\n            MatrixX1_17 = (MatrixX1*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixY1_17 = (MatrixY1*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixZ1_17 = (MatrixZ1*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixX2_17 = (MatrixX2*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixY2_17 = (MatrixY2*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixZ2_17 = (MatrixZ2*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixX3_17 = (MatrixX3*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixY3_17 = (MatrixY3*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixZ3_17 = (MatrixZ3*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n        except Exception:\n            MatrixX1_17 = MatrixY1_17 = MatrixZ1_17 = 0.0\n            MatrixX2_17 = MatrixY2_17 = MatrixZ2_17 = 0.0\n            MatrixX3_17 = MatrixY3_17 = MatrixZ3_17 = 0.0\n\n        self.displayMatrixMomentOfInertia()\n        try:\n            self.LE_007_BB_01_XLength.setText(str(Around(boundBoxLX * uniteM)) + \" \" + uniteMs)\n            self.LE_007_BB_02_YLength.setText(str(Around(boundBoxLY * uniteM)) + \" \" + uniteMs)\n            self.LE_007_BB_03_ZLength.setText(str(Around(boundBoxLZ * uniteM)) + \" \" + uniteMs)\n            self.LE_007_BB_04_Diagonal.setText(str(Around(boundBoxDiag * uniteM)) + \" \" + uniteMs)\n            boundBox_S = (u\"[X: \" + str(Around(boundBoxLX * uniteM)) + \" \" + uniteMs + \n                          u\"] x [Y: \" + str(Around(boundBoxLY * uniteM)) + \" \" + uniteMs + \n                          u\"] x [Z: \" + str(Around(boundBoxLZ * uniteM)) + \" \" + uniteMs + \n                          u\"] Diagonal: \" + str(Around(boundBoxDiag * uniteM)) + \" \" + uniteMs)\n        except Exception:\n            self.LE_007_BB_01_XLength.setText(u\"\")\n            self.LE_007_BB_02_YLength.setText(u\"\")\n            self.LE_007_BB_03_ZLength.setText(u\"\")\n            self.LE_007_BB_04_Diagonal.setText(u\"\")\n            boundBox_S = \"\"\n\n        if self.GBox_012_SpreadSheet.isChecked():\n            co = 0\n            li = 0\n            for li in range(RowCount):       # Zero\n                for co in range(10):\n                    newitem = QTableWidgetItem(u\"\")\n                    self.tableWidget.setItem( li,co, newitem)\n\n            co = 0\n            li = 0\n            aa = 0\n            for j in enumerate(Edges):       # Edges\n                newitem = QTableWidgetItem(str(j[1]))\n                self.tableWidget.setItem( li,0, newitem)\n                newitem = QTableWidgetItem(str(float(EdgesLong[li]) * float(uniteM)) + \" \" + uniteMs)\n                self.tableWidget.setItem( li,1, newitem)\n                co+=1\n                try:\n                    for a in range(aa,aa+6): # Vertexes\n                        co += 1\n                        #newitem = QTableWidgetItem(str(Vertx[a]))\n                        chaine = str(Vertx[a]).split(u\":\")\n                        newitem = QTableWidgetItem(chaine[0]+\":\" + str(float(chaine[1]) * float(uniteM)) + \" \" + uniteMs)\n                        self.tableWidget.setItem( li,co, newitem)\n                except Exception:\n                    None\n                aa += 6\n                co = 0\n                li+= 1\n            li += 1\n            co  = 0\n            cco = 0\n            co2 = 0\n            for j in enumerate(Faces):\n                newitem = QTableWidgetItem(str(j[1]))\n                self.tableWidget.setItem( li,0, newitem)\n                newitem = QTableWidgetItem(str(float(FacesSurf[co]) * float(uniteS)) + \" \" + uniteSs)\n                self.tableWidget.setItem( li,1, newitem)\n                li+= 1\n                for jj in range(cco,len(FacesCoor)):# Faces coordinates\n                    cco+=1\n                    if FacesCoor[jj] == \"T\":\n                        break\n                    else:\n                        #newitem = QTableWidgetItem(FacesCoor[jj])\n                        chaine = str(FacesCoor[jj]).split(\":\")\n                        newitem = QTableWidgetItem(chaine[0]+\":\" + str(float(chaine[1]) * float(uniteM)) + \" \" + uniteMs)\n                        self.tableWidget.setItem( li,co2, newitem)\n                        co2 += 1\n                        if co2 == 3:\n                            li += 1\n                            co2 = 0\n                co += 1\n                li += 1\n\n    def on_SB_Arc_ToByArcs_valueChanged(self, val):\n        global uniteM\n        global uniteMs\n        global BsplineArcsRadius\n        global BsplineRayonApproximatif\n        global BsplineNumberElement\n\n        if (val >=1) and (val <= BsplineNumberElement):\n            self.SB_Arc_ToByArcs.setSuffix(u\" / \" + str(BsplineNumberElement))\n            self.SB_Arc_ToByArcs.setPrefix(u\"arc \")\n            try:\n                BsplineRayonApproximatif = str(Around(BsplineArcsRadius[val - 1] * float(uniteM))) + \" \" + uniteMs\n            except Exception:\n                BsplineRayonApproximatif = str(Around(0 * float(uniteM))) + \" \" + uniteMs\n            self.LE_5b.setText(BsplineRayonApproximatif)\n        else:\n            self.SB_Arc_ToByArcs.setValue(0)\n\n    def on_PB_BSplineCreateNodes(self):\n        global subElemName\n        global BsplinePointsCoor\n        global switchInertia\n        global switchBSplineCreateCircleConstructorAxis\n        global switchBSplineCreateCircleConstructor\n\n        FreeCAD.ActiveDocument.openTransaction(u\"FCInfo Points BS\")   # memorise les actions (avec annuler restore)\n        switchInertia = 1                       # for create points without refresh\n\n        self.PB_BSplineCreateNodes.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Work))) # icone dans une variable \n        try:                                    # create point on node\n            conteneurBSpline = App.activeDocument().addObject(u\"App::DocumentObjectGroup\", \"BSpline_Points(\" + str(len(BsplinePointsCoor)) + \")\")\n            for i in BsplinePointsCoor:\n                point = Draft.makePoint( i[0], i[1], i[2])\n                conteneurBSpline.addObject(point)\n                point.ViewObject.PointColor = (1.0,0.0,0.0)\n                point.Label = u\"FCPoint_BSPline_\" + subElemName\n                FreeCADGui.updateGui()          # updateGui\n            App.ActiveDocument.recompute()\n        except Exception:\n            None\n\n        FreeCAD.ActiveDocument.openTransaction(u\"FCInfo Axis BS\")   # memorise les actions (avec annuler restore)\n        if (switchBSplineCreateCircleConstructorAxis == 1) and (len(BsplineArcsLocation) != 0):\n            try:                                # create point axis toByArcs()\n                conteneurBSplineP = App.activeDocument().addObject(u\"App::DocumentObjectGroup\", \"BSpline_Center(\" + str(len(BsplineArcsLocation)) + \")\")\n                for i in BsplineArcsLocation:\n                    point = Draft.makePoint(i.Location.x, i.Location.y, i.Location.z)\n                    point.ViewObject.PointColor = (0.0,1.0,0.0)\n                    point.Label = u\"FCPoint_BSPline_toByArcs_\" + subElemName\n                    conteneurBSplineP.addObject(point)\n                App.ActiveDocument.recompute()\n            except Exception:\n                None\n\n        FreeCAD.ActiveDocument.openTransaction(u\"FCInfo Circles BS\")   # memorise les actions (avec annuler restore)\n        if (switchBSplineCreateCircleConstructor == 1) and (len(BsplineArcsLocation) != 0):\n            try:                                # create circle toByArcs()\n                conteneurBSplineC = App.activeDocument().addObject(u\"App::DocumentObjectGroup\", \"BSpline_Circles(\" + str(len(BsplineArcsLocation)) + \")\")\n                pl=FreeCAD.Placement()\n                for i in BsplineArcsLocation:\n                    ##\n                    pl.Base = FreeCAD.Vector(i.Location.x, i.Location.y, i.Location.z)\n                    pl.Rotation.Q = i.Circle.Rotation.Q\n                    circle = Draft.makeCircle(radius = i.Radius, placement = pl, face = False, support = None)\n                    circle.ViewObject.LineColor = (0.0,0.0,1.0)\n                    circle.Label = u\"FCCircle_BSPline_toByArcs\" + subElemName\n                    conteneurBSplineC.addObject(circle)\n                App.ActiveDocument.recompute()\n            except Exception:\n                None\n\n        self.PB_BSplineCreateNodes.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Point))) # icone dans une variable \n        switchInertia = 0\n\n    def SIGNAL_CBox_Materiel_Changed(self,text):\n        global seTDensiteValue\n        global seTMaterialCurrentIndex\n        global seTMaterialPrice\n        global materialAssociated\n        global FreeCAD_ParamGetSet\n\n        self.PB_Del_Material.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_DeleteLineMaterial))) # icone dans une variable \n        self.LE_Materiel.setStyleSheet(u\"QLineEdit {background-color: QPalette.Base}\") # origin system\n        if text != \"\":\n            self.LE_Materiel.setText(materialAssociated[self.CBox_Materiel.currentIndex()]) # affiche la chaine pour completion ou info\n            self.PB_Del_Material.setText(u\"Delete (\" + str(self.CBox_Materiel.currentIndex() + 1) + \"/\" + str(len(materialAssociated)) + \")\")\n            chaineMat = text.rstrip().split(\",\")\n            seTDensiteValue = float(chaineMat[1])\n            FreeCAD_ParamGetSet.SetFloat(u\"seTDensiteValue\", seTDensiteValue)                   #*1.0\n            try:\n                seTMaterialPrice = float(chaineMat[2])\n            except Exception:\n                seTMaterialPrice = 0.0\n            #self.DS_Density.setProperty(u\"value\", seTDensiteValue)\n            self.DS_Density.setValue(seTDensiteValue)\n            self.DS_Price.setValue(seTMaterialPrice)\n            seTMaterialCurrentIndex = self.CBox_Materiel.currentIndex()\n\n        if self.CBox_Materiel.currentIndex() == -1:\n            self.PB_Del_Material.setText(u\"Delete (0\\0)\")\n            self.PB_Del_Material.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Beer))) # icone dans une variable \n        FreeCAD_ParamGetSet.SetInt(u\"seTMaterialCurrentIndex\", seTMaterialCurrentIndex)     #*0\n\n    def on_PB_Del_Material_clicked(self):   # efface le materiel en cours\n        global materialAssociated\n\n        index = self.CBox_Materiel.currentIndex()\n        if self.CBox_Materiel.currentIndex() != -1:\n            try:\n                materialAssociated.remove(materialAssociated[index])\n                self.CBox_Materiel.clear()\n                for ligneMat in materialAssociated:\n                    self.CBox_Materiel.addItem(_fromUtf8(ligneMat))\n                self.CBox_Materiel.setCurrentIndex(0)\n                self.LE_Materiel.setText(materialAssociated[0])\n                self.PB_Save_Material.setText(u\"Save (*)\")\n            except Exception:\n                self.LE_Materiel.clear()\n                None\n\n    def on_PB_Save_Material_clicked(self):   # sauve le materiel en cours\n        global materialAssociated\n        global seTMaterialSavePathName\n        global seTMaterialFileName\n        global FreeCAD_ParamGetSet\n\n        #### save the material begin ####\n        materialAssociated.sort()\n        App_Console_PrintMessage(u\"Number material : \" + str(len(materialAssociated)) + \"\\n\")\n        try:\n            seTMaterialSavePathName = path #+ seTMaterialFileName # u\"FCInfo_material.txt\"\n            f = open(seTMaterialSavePathName + seTMaterialFileName, 'w') # write\n            for i in materialAssociated:\n                f.write(i + \"\\n\")\n            f.close()\n            self.PB_Save_Material.setText(u\"Save\")\n            App_Console_PrintMessage(u\"Create file : \" + seTMaterialFileName + \"\\n\")\n            FreeCAD_ParamGetSet.SetString(u\"seTMaterialFileName\", seTMaterialFileName)          #*\"FCInfo_material.txt\"\n            FreeCAD_ParamGetSet.SetString(u\"seTMaterialSavePathName\", seTMaterialSavePathName)  #*\"C:/.../Macro/ #FCInfo_material.txt\"\n        except Exception:\n            App_Console_PrintError(u\"Not file \" + seTMaterialFileName + \" saved\" + \"\\n\")\n        #### save the material end ####\n\n    def on_LE_Materiel_Pressed(self):   # LEdit Materiel , tableau des materiaux : [ materiel, poids, prix, info ]\n        global materialAssociated\n\n        newMateriel = self.LE_Materiel.text()                       # extract the string in the LE_Materiel\n        self.LE_Materiel.setStyleSheet(u\"QLineEdit {background-color: QPalette.Base}\") # origin system\n\n        if (len(newMateriel.split(\",\")) >= 2):\n            try:\n                if (newMateriel.split(\",\")[1].isdecimal()) or ((float(newMateriel.split(\",\")[1])!= 0.0)):   # test si alphaNumerique\n\n                    ##nomMat   = newMateriel.split(\",\")[0].capitalize()  # Metal copper (cu),8.96,10.0\n                    ##nomMat   = newMateriel.split(\",\")[0].title()       # Metal Copper (Cu),8.96,10.0\n                    ##nomMat   = newMateriel.split(\",\")[0].upper()       # METAL COPPER (CU),8.96,10.0\n                    nomMat   = newMateriel.split(\",\")[0][0].upper() + newMateriel.split(\",\")[0][1:] # Metal Copper (Cu),8.96,10.0\n\n                    try:\n                        poidsMat = str(float(newMateriel.split(\",\")[1]))    # teste si float\n                    except Exception:\n                        poidsMat = \"0.0\"\n                    try:\n                        coutMat = str(float(newMateriel.split(\",\")[2]))     # teste si float (facultatif)\n                    except Exception:\n                        coutMat = \"0.0\"\n                    try:\n                        infoMat = newMateriel.split(\",\")[3]                 # info (facultatif)\n                    except Exception:\n                        infoMat = \" !\"\n                    newMateriel = nomMat + \",\" + poidsMat + \",\" + coutMat + \",\" + infoMat\n\n                    self.LE_Materiel.setStyleSheet(u\"QLineEdit {color : QPalette.Base}\") # origin system\n                    index = self.CBox_Materiel.currentIndex()\n                    if index == -1:\n                        index = 0\n                    try:\n                        if nomMat.upper() == materialAssociated[index].split(\",\")[0].upper():  # remplace (efface)si c'est le meme nom\n                            materialAssociated.remove(materialAssociated[index])\n                    except Exception:\n                        None\n\n                    #materialAssociated.append(newMateriel.capitalize())                # ajout la nouvelle entree\n                    materialAssociated.append(newMateriel)                             # ajout la nouvelle entree\n\n                    materialAssociated.sort()\n                    self.CBox_Materiel.clear()\n                    comptIndex = 0\n                    for ligneMat in materialAssociated:\n                        self.CBox_Materiel.addItem(_fromUtf8(ligneMat))\n                        #if ligneMat.rstrip().split(\",\")[0] == newMateriel.capitalize().split(\",\")[0]:\n                        if ligneMat.rstrip().split(\",\")[0] == newMateriel.split(\",\")[0][0].upper() + newMateriel.split(\",\")[0][1:]:\n                            index = comptIndex\n                        comptIndex += 1\n                    self.CBox_Materiel.setCurrentIndex(index)\n                    self.LE_Materiel.clear()\n                    self.PB_Save_Material.setText(u\"Save (*)\")\n                else:\n                    self.LE_Materiel.setStyleSheet(u\"QLineEdit {background-color: #efef29}\")\n            except Exception:\n                self.LE_Materiel.setStyleSheet(u\"QLineEdit {background-color: #ef2929}\")\n        else:\n            self.LE_Materiel.setStyleSheet(u\"QLineEdit {background-color: #ef2929}\")\n\n    def on_DS_Density_valueChanged(self,densiteSB):    # SpinBox    # DS_Density_1 poids\n        global volume_\n        global uniteM\n        global uniteP\n        global unitePs\n        global uniteV # uniteV not in Global ?, add it 05/12/21\n        global seTDensiteValue\n        global poids\n        global setMomentOfInertia_16\n        global setMomentOfInertiaMassique_17\n        global MatrixX1\n        global MatrixY1\n        global MatrixZ1\n        global MatrixX2\n        global MatrixY2\n        global MatrixZ2\n        global MatrixX3\n        global MatrixY3\n        global MatrixZ3\n        global MatrixX1_17\n        global MatrixY1_17\n        global MatrixZ1_17\n        global MatrixX2_17\n        global MatrixY2_17\n        global MatrixZ2_17\n        global MatrixX3_17\n        global MatrixY3_17\n        global MatrixZ3_17\n        global seTMaterialPrice\n        global seTMaterialCost\n        global seTMaterialSuffixCost\n        global FreeCAD_ParamGetSet\n\n        seTDensiteValue = densiteSB\n        FreeCAD_ParamGetSet.SetFloat(u\"seTDensiteValue\", seTDensiteValue)\n        poids = ((volume_ * seTDensiteValue) * uniteP) / 1000.0 # base FreeCAD = mm\n        self.LE_12a.setText(str(Around(poids))  + \" \" +  unitePs)\n        seTMaterialCost = ((volume_ * seTDensiteValue * seTMaterialPrice) / 1000000.0)\n        self.LE_Cost.setText(str(Around(seTMaterialCost)) + seTMaterialSuffixCost) #CostMaterial\n\n        self.SB_17_M.setPrefix(unitePs + uniteSs + \"^\")\n        self.SB_17_M.setValue(setMomentOfInertiaMassique_17)\n        try:\n            ## MatrixX1_17 = MatrixX1*uniteM**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0)) ## original without parenthesis and modified 17/03/2024\n            MatrixX1_17 = (MatrixX1*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixY1_17 = (MatrixY1*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixZ1_17 = (MatrixZ1*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixX2_17 = (MatrixX2*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixY2_17 = (MatrixY2*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixZ2_17 = (MatrixZ2*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixX3_17 = (MatrixX3*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixY3_17 = (MatrixY3*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            MatrixZ3_17 = (MatrixZ3*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n        except Exception:\n            MatrixX1_17 = MatrixY1_17 = MatrixZ1_17 = 0.0\n            MatrixX2_17 = MatrixY2_17 = MatrixZ2_17 = 0.0\n            MatrixX3_17 = MatrixY3_17 = MatrixZ3_17 = 0.0\n\n        self.displayMatrixMomentOfInertia()\n\n    def on_DS_Price_valueChanged(self, price):    # DSpinBox\n        global volume_\n        global seTDensiteValue\n        global seTMaterialPrice\n        global seTMaterialCost\n        global seTMaterialSuffixCost\n\n        seTMaterialPrice = price\n        seTMaterialCost = ((volume_ * seTDensiteValue * seTMaterialPrice) / 1000000.0)\n        self.LE_Cost.setText(str(Around(seTMaterialCost)) + seTMaterialSuffixCost) #CostMaterial\n        FreeCAD_ParamGetSet.SetFloat(u\"seTMaterialPrice\", seTMaterialPrice)        # *x\n        FreeCAD_ParamGetSet.SetFloat(u\"seTMaterialCost\", seTMaterialCost)          # *x\n\n    def on_PB_01_Refrech_clicked(self):  # refresh\n        global sel\n        global document_\n        global object_Label\n        global object_Name\n        global typeObject\n        global object_Type\n        global subElemName\n        global position0\n        global position1\n        global position2\n\n        global diffuseColorRF\n        global diffuseColorVF\n        global diffuseColorBF\n        global diffuseColorTF\n        global unsignedEncodeColor\n\n        global longueurObjet\n        global rayonObjet\n        global perimetre\n        global typeLongueur\n        global numberEdges\n        global nombreArretesMesh\n        global nombreFacesMesh\n        global nombrePointsMesh\n\n        global Plan_xy\n        global Plan_xy_V\n        global Plan_yz\n        global Plan_yz_V\n        global Plan_zx\n        global Plan_zx_V\n\n        global surface\n        global surfaceFace\n        global volume_\n        global seTDensiteValue\n        global poids\n        global uniteM\n        global uniteMs\n        global uniteS\n        global uniteSs\n        global uniteV\n        global uniteVs\n        global uniteP\n        global unitePs\n        global uniteAs\n\n        global boundBoxCenterX\n        global boundBoxCenterY\n        global boundBoxCenterZ\n\n        global CenterOfMassX\n        global CenterOfMassY\n        global CenterOfMassZ\n        global massOrGravity\n        global boundBoxLX\n        global boundBoxLY\n        global boundBoxLZ\n        global boundBox_S\n\n        global MatrixX1\n        global MatrixY1\n        global MatrixZ1\n        global Matrix_1\n\n        global MatrixX2\n        global MatrixY2\n        global MatrixZ2\n        global Matrix_2\n\n        global MatrixX3\n        global MatrixY3\n        global MatrixZ3\n        global Matrix_3\n\n        global Matrix12\n        global Matrix13\n        global Matrix14\n        global Matrix15\n\n        global Vertx\n        global Edges\n        global EdgesLong\n        global Faces\n        global FacesSurf\n        global FacesCoor\n        global compt_E\n        global compt_F\n        global compt_VF\n        global RowCount\n        global RowCountTest\n        global ESCAPE\n        global directionObj\n        global direcValueAt\n        global direcNormalAt\n        global typeNormalAt\n        global switchCreateLineDiVatNatOnClick\n\n        global setMomentOfInertia_16\n        global setMomentOfInertiaMassique_17\n        global MatrixOfInertiaRaw\n        global MatrixX1_16\n        global MatrixY1_16\n        global MatrixZ1_16\n        global MatrixX2_16\n        global MatrixY2_16\n        global MatrixZ2_16\n        global MatrixX3_16\n        global MatrixY3_16\n        global MatrixZ3_16\n\n        global MatrixX1_17\n        global MatrixY1_17\n        global MatrixZ1_17\n        global MatrixX2_17\n        global MatrixY2_17\n        global MatrixZ2_17\n        global MatrixX3_17\n        global MatrixY3_17\n        global MatrixZ3_17\n        global DeterminantM\n        global seTMaterialPrice\n        global seTMaterialCost\n        global seTMaterialSuffixCost\n        global seTIndexUnitLength\n\n        global BsplineDetect\n        global BsplineNombreDeNoeuds\n        global BsplinePointsCoor\n        global BsplineRayonApproximatif\n        global BsplineNumberElement\n        global BsplineCutLength\n        global setBSplineToByArcValue\n        global BSplinetoByArcValeurS\n        global BsplineArcsRadius\n        global FreeCAD_ParamGetSet\n\n        sel = FreeCADGui.Selection.getSelection()\n        if len(sel)==0:\n            App_Console_PrintMessage(u\"Select an object\" + \"\\n\")\n            errorDialog(u\"Select an object\")\n        else:\n            if self.GBox_012_SpreadSheet.isChecked():\n                affect(1)\n            else:\n                affect(0)\n                self.GBox_012_SpreadSheet.setTitle(u\"Details of the form\")\n\n            self.LE_1.setText(document_)\n            self.LE_2.setText(object_Label)\n            self.LE_2a.setText(object_Name)\n            self.LE_3.setText(str(subElemName))\n            self.LE_3a.setText(str(typeObject))\n            self.LE_4.setText(str(object_Type))\n\n            self.LA_14x.setText(massOrGravity + u\" X\")\n            self.LA_14y.setText(massOrGravity + u\" Y\")\n            self.LA_14z.setText(massOrGravity + u\" Z\")\n\n            self.LE_4x.setText(str(Around(position0 * uniteM)) + \" \" + uniteMs)\n            self.LE_4y.setText(str(Around(position1 * uniteM)) + \" \" + uniteMs)\n            self.LE_4z.setText(str(Around(position2 * uniteM)) + \" \" + uniteMs)\n\n            self.LE_N_Edges.setText(str(nombreArretesMesh))\n            self.LE_N_Facets.setText(str(nombreFacesMesh))\n            self.LE_N_Points.setText(str(nombrePointsMesh))\n\n            self.LE_CRed.setText(str(Around(diffuseColorRF)))\n            self.LE_CRed.setToolTip(u\"Red color at clicked point (format FreeCAD)\")\n            self.LE_CRed.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: rgb(\"+str(int(diffuseColorRF*255.0))+\", 0, 0)}\") # white and red\n            self.LE_CGreen.setText(str(Around(diffuseColorVF)))\n            self.LE_CGreen.setToolTip(u\"Green color at the clicked point (format FreeCAD)\")\n            self.LE_CGreen.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: rgb(0, \"+str(int(diffuseColorVF*255.0))+\", 0)}\") # white and green\n            self.LE_CBlue.setText(str(Around(diffuseColorBF)))\n            self.LE_CBlue.setToolTip(u\"Blue color at the clicked point (format FreeCAD)\")\n            self.LE_CBlue.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: rgb(0, 0, \"+str(int(diffuseColorBF*255.0))+\")}\") # white and blue\n            self.LE_Transparent.setText(str(Around(diffuseColorTF)))\n            self.LE_Transparent.setToolTip(u\"Transparency at the clicked point\")\n            self.LE_ConversionUnsigned.setText(str(unsignedEncodeColor))\n            self.LE_ConversionUnsigned.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: rgb(\"+str(int(diffuseColorRF*255.0))+\",\"+str(int(diffuseColorVF*255.0))+\",\"+str(int(diffuseColorBF*255.0))+\")}\") # white\n\n            switchCreateLineDiVatNatOnClick = FreeCAD_ParamGetSet.GetBool(u\"switchCreateLineDiVatNatOnClick\")\n            if switchCreateLineDiVatNatOnClick == 0:\n                self.PB_Line_Direction.setText(u\"Direction\")\n                self.PB_Line_ValueAT.setText(u\"ValueAt(0)\")\n                self.PB_Line_NormalAT.setText(typeNormalAt)\n            else:\n                self.PB_Line_Direction.setText(u\"*Direction\")\n                self.PB_Line_ValueAT.setText(u\"*ValueAt(0)\")\n                self.PB_Line_NormalAT.setText(typeNormalAt)\n\n            self.LE_9_Direction.setText(str(directionObj))\n            self.LE_10_ValueAt.setText(str(direcValueAt))\n            self.LE_10b_NormalAt.setText(str(direcNormalAt))\n            self.PB_Line_NormalAT.setText(typeNormalAt)\n            self.SBox_Transparence.setValue(transparenceFace)\n\n            try:\n                self.LE_007_BB_01_XLength.setText(str(Around(boundBoxLX * uniteM)) + \" \" + uniteMs)\n                self.LE_007_BB_02_YLength.setText(str(Around(boundBoxLY * uniteM)) + \" \" + uniteMs)\n                self.LE_007_BB_03_ZLength.setText(str(Around(boundBoxLZ * uniteM)) + \" \" + uniteMs)\n                self.LE_007_BB_04_Diagonal.setText(str(Around(boundBoxDiag * uniteM)) + \" \" + uniteMs)\n                boundBox_S = \"[X: \"+str(Around(boundBoxLX * uniteM)) + \" \" + uniteMs+\"] x [Y: \"+str(Around(boundBoxLY * uniteM)) + \" \" + uniteMs+\"] x [Z: \"+str(Around(boundBoxLZ * uniteM)) + \" \" + uniteMs+\"] Diagonal: \" + str(Around(boundBoxDiag * uniteM)) + \" \" + uniteMs\n            except Exception:\n                self.LE_007_BB_01_XLength.setText(u\"\")\n                self.LE_007_BB_02_YLength.setText(u\"\")\n                self.LE_007_BB_03_ZLength.setText(u\"\")\n                self.LE_007_BB_04_Diagonal.setText(u\"\")\n                boundBox_S = u\"\"\n\n            self.LA_5.setText(typeLongueur)\n            try:\n                self.LE_5.setText(str(Around(float(longueurObjet) * float(uniteM)))+ \" \" +uniteMs)\n            except Exception:\n                self.LE_5.setText(u\"\")\n\n            # Circle Bspline\n            if (rayonObjet != 0.0) or (str(BsplineDetect) == \"<BSplineCurve object>\"):\n                self.LE_5b.setVisible(True)\n                self.LA_5b.setVisible(True)\n                if str(BsplineDetect) == \"<BSplineCurve object>\":\n#                    BsplineArcsRadius = []\n                    self.on_SB_Arc_ToByArcs_valueChanged(1)\n                    self.SB_Arc_ToByArcs.setVisible(True)\n                    self.SB_Arc_ToByArcs.setToolTip(u\"Bspline detected \" + \"\\n\"\n                                            u\"Number of element = \" + str(BsplineNumberElement) + \"\\n\" +\n                                            u\"Calcul with difference between points \" + str(Around(BsplineCutLength * uniteM)) + \" \" + uniteMs + \"\\n\\n\" +\n                                            u\"toBiArcs(\" + BSplinetoByArcValeurS + \")\" + \"\\n\"\n                                            u\"This value can be changed in the variable preferences : setBSplineToByArcValue\" + \"\\n\")\n                    self.PB_BSplineCreateNodes.setText(u\"Points(\" + str(len(BsplinePointsCoor)) + \")\") # Node\n                    self.PB_BSplineCreateNodes.setToolTip(u\"Create on point on Poles (\" + str(len(BsplinePointsCoor)) + \") of the BSpline\" + \"\\n\\n\"\n                                                          u\"Command for Shape  : Gui.Selection.getSelection()[0].Points\" + \"\\n\"\n                                                          u\"Command for SubObj : Gui.Selection.getSelectionEx()[0].SubObjects[0].Curve.getPoles()\" + \"\\n\\n\"\n                                                          u\"Hidden Options : \" + \"\\n\\n\"\n                                                          u\"The variables \" + \"\\n\\n\"\n                                                          u\"switchBSplineCreateCircleConstructorAxis\" + \"\\n\"\n                                                          u\"switchBSplineCreateCircleConstructor\" + \"\\n\\n\"\n                                                          u\"accessible in : User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__ + \"\\n\"\n                                                          u\"allow to create the circles and the point axes construction of the BSpline\" + \"\\n\"\n                                                          u\"their number (precision) depends on the value toBiArcs(BSplinetoByArcValeurS)\" + \"\\n\"\n                                                          u\"actual toBiArcs(\" + BSplinetoByArcValeurS + \")\" + \"\\n\")\n\n                    self.PB_BSplineCreateNodes.setVisible(True)\n                    self.LA_5b.setText(u\"Radius Appr.\")\n                    self.LE_5b.setText(BsplineRayonApproximatif)\n                    self.LE_5b.setToolTip(u\"BSpline Radius on point : \")# + self.SB_Arc_ToByArcs.text()\n                    self.LA_6.setText(u\"BSpline Nodes\")\n                    self.LE_6.setText(str(BsplineNombreDeNoeuds))\n                    self.LE_6.setToolTip(u\"Number of nodes of the BSpline.\")\n                else:\n                    self.SB_Arc_ToByArcs.setVisible(False)\n                    self.PB_BSplineCreateNodes.setVisible(False)\n                    self.LA_5b.setText(u\"Radius\")\n                    #self.LE_5b.setText(str(Around(rayonObjet * float(uniteM))) + \" \" + uniteMs)\n                    self.LE_5b.setText(str(Around(rayonObjet * float(uniteM))) + \" \" + uniteMs + (u\" (dia. \" + str(Around(rayonObjet * float(uniteM) * 2.0)) + \" \" + uniteMs + \")\"))\n                    self.LE_5b.setToolTip(u\"Radius detected.\")\n                    if numberEdges == 1:\n                        self.LA_6.setText(u\"Circumference (\" + str(numberEdges) + \")\")\n                    else:\n                        self.LA_6.setText(u\"Perimeter of shape (\" + str(numberEdges) + \")\")\n                    self.LE_6.setText(str(Around(float(perimetre) * float(uniteM))) + \" \" +uniteMs)\n            else:\n                self.LA_6.setText(u\"Perimeter of shape (\" + str(numberEdges) + \")\")\n                self.SB_Arc_ToByArcs.setVisible(False)\n                self.PB_BSplineCreateNodes.setVisible(False)\n                self.LE_5b.setVisible(False)\n                self.LA_5b.setVisible(False)\n                rayonObjet = 0.0\n                try:\n                    self.LE_6.setText(str(Around(float(perimetre) * float(uniteM))) + \" \" +uniteMs)\n                except Exception:\n                    perimetre = 0.0\n                    self.LE_6.setText(str(Around(perimetre)))\n                    self.LE_6.setToolTip(u\"Perimeter total of the form.\" + \"\\n\"\n                                         u\"Display the total edges of theform\")\n\n            if self.GBox_012_SpreadSheet.isChecked():\n                self.tableWidget.clear()  # Zero\n                co = 0\n                li = 1\n                aa = 0\n                #### detail of Cercle BSpline begin\n                if (str(BsplineDetect) == \"<BSplineCurve object>\"):\n                    newitem = QTableWidgetItem(u\"Number of nodes\")\n                    self.tableWidget.setItem( li,0, newitem)\n                    newitem = QTableWidgetItem(str(len(BsplinePointsCoor)))\n                    self.tableWidget.setItem( li,1, newitem)\n                    li += 1\n                    for i in enumerate(BsplinePointsCoor):        # Edges\n                        newitem = QTableWidgetItem(u\"Node\" + str(i[0]+1))\n                        self.tableWidget.setItem( li,0, newitem)\n                        for a in range(3):  # Vertexes\n                            co += 1\n                            chaine = str(Around(BsplinePointsCoor[i[0]][a]))\n                            newitem = QTableWidgetItem(chaine)\n                            self.tableWidget.setItem( li,co, newitem)\n                        aa += 6\n                        co = 0\n                        li += 1\n                #### detail of Cercle BSpline end\n\n                if RowCountTest > RowCount:\n                    self.GBox_012_SpreadSheet.setTitle(u\"Details (\"+ str(compt_E) +\") (\"+ str(compt_F)+\") (\"+ str(compt_VF)+\")  (!+ \"+str(RowCount)+\") \"+str(RowCountTest))\n                else:\n                    self.GBox_012_SpreadSheet.setTitle(u\"Vertexes and details (\"+ str(compt_E) +\") (\"+ str(compt_F)+\") (\"+ str(compt_VF)+\")\")#str(RowCount)\n\n                co = 0\n                li = 0\n                aa = 0\n                for j in enumerate(Edges):        # Edges\n                    newitem = QTableWidgetItem(str(j[1]))\n                    self.tableWidget.setItem( li,0, newitem)\n                    newitem = QTableWidgetItem(str(float(EdgesLong[li]) * float(uniteM))+\" \"+uniteMs)\n                    self.tableWidget.setItem( li,1, newitem)\n                    co+=1\n                    try:\n                        for a in range(aa,aa+6):  # Vertexes\n                            co += 1\n                            #newitem = QTableWidgetItem(str(Vertx[a]))\n                            chaine = str(Vertx[a]).split(\":\")\n                            newitem = QTableWidgetItem(chaine[0]+\":\" + str(float(chaine[1]) * float(uniteM))+\" \"+uniteMs)\n                            self.tableWidget.setItem( li,co, newitem)\n                    except Exception:\n                        None\n                    aa += 6\n                    co = 0\n                    li += 1\n\n                li += 1\n                co  = 0\n                cco = 0\n                co2 = 0\n                for j in enumerate(Faces):             # Faces\n                    newitem = QTableWidgetItem(str(j[1]))\n                    self.tableWidget.setItem( li,0, newitem)\n                    newitem = QTableWidgetItem(str(float(FacesSurf[co]) * float(uniteS))+\" \"+uniteSs)\n                    self.tableWidget.setItem( li,1, newitem)\n                    li += 1\n                    for jj in range(cco,len(FacesCoor)):# Faces coordinates\n                        cco+=1\n                        if FacesCoor[jj] == \"T\":\n                            break\n                        else:\n    #                        newitem = QTableWidgetItem(FacesCoor[jj])\n                            chaine = str(FacesCoor[jj]).split(\":\")\n                            newitem = QTableWidgetItem(chaine[0]+\":\" + str(float(chaine[1]) * float(uniteM)) + \" \" + uniteMs)\n                            self.tableWidget.setItem( li,co2, newitem)\n                            co2 += 1\n                            if co2 == 3:\n                                li += 1\n                                co2 = 0\n                    co += 1\n                    li += 1\n\n            self.LE_8xy.setText(str(Around(Plan_xy))+uniteAs)\n            self.LE_8xya.setText(str(Plan_xy_V))\n            self.LE_8yz.setText(str(Around(Plan_yz))+uniteAs)\n            self.LE_8yza.setText(str(Plan_yz_V))\n            self.LE_8zx.setText(str(Around(Plan_zx))+uniteAs)\n            self.LE_8zxa.setText(str(Plan_zx_V))\n\n            self.LE_9a.setText(str(Around(surface * uniteS)) + \" \" + uniteSs)\n            self.LE_10a.setText(str(Around(surfaceFace * uniteS)) + \" \" + uniteSs)\n            self.LE_11a.setText(str(Around(volume_ * uniteV)) + \" \" + uniteVs)\n            self.LE_12a.setText(str(Around(poids)) + \" \" + unitePs)\n\n            seTMaterialCost = ((volume_ * seTDensiteValue * seTMaterialPrice) / 1000000.0)\n            self.LE_Cost.setText(str(Around(seTMaterialCost)) + seTMaterialSuffixCost) #CostMaterial\n\n            self.LE_13x.setText(str(Around(boundBoxCenterX * uniteM)) + \" \" + uniteMs)\n            self.LE_13y.setText(str(Around(boundBoxCenterY * uniteM)) + \" \" + uniteMs)\n            self.LE_13z.setText(str(Around(boundBoxCenterZ * uniteM)) + \" \" + uniteMs)\n            self.LE_14x.setText(str(Around(CenterOfMassX * uniteM)) + \" \" + uniteMs)\n            self.LE_14y.setText(str(Around(CenterOfMassY * uniteM)) + \" \" + uniteMs)\n            self.LE_14z.setText(str(Around(CenterOfMassZ * uniteM)) + \" \" + uniteMs)\n\n            self.LE_007_BB_01_XLength.setText(str(Around(boundBoxLX * uniteM)) + \" \" + uniteMs)\n            self.LE_007_BB_02_YLength.setText(str(Around(boundBoxLY * uniteM)) + \" \" + uniteMs)\n            self.LE_007_BB_03_ZLength.setText(str(Around(boundBoxLZ * uniteM)) + \" \" + uniteMs)\n            self.LE_007_BB_04_Diagonal.setText(str(Around(boundBoxDiag * uniteM)) + \" \" + uniteMs)\n\n            self.SB_16_M.setPrefix(uniteMs + \"^\")\n            self.SB_16_M.setValue(setMomentOfInertia_16)\n            self.LE_16_Raw.setText(\"Raw : \" + MatrixOfInertiaRaw)\n            self.LE_16_Raw.setCursorPosition(0)\n\n            try:\n                ## MatrixX1_16 = MatrixX1*uniteM**setMomentOfInertia_16 ## original without parenthesis and modified 17/03/2024\n                MatrixX1_16 = (MatrixX1*uniteS)**setMomentOfInertia_16\n                MatrixY1_16 = (MatrixY1*uniteS)**setMomentOfInertia_16\n                MatrixZ1_16 = (MatrixZ1*uniteS)**setMomentOfInertia_16\n                MatrixX2_16 = (MatrixX2*uniteS)**setMomentOfInertia_16\n                MatrixY2_16 = (MatrixY2*uniteS)**setMomentOfInertia_16\n                MatrixZ2_16 = (MatrixZ2*uniteS)**setMomentOfInertia_16\n                MatrixX3_16 = (MatrixX3*uniteS)**setMomentOfInertia_16\n                MatrixY3_16 = (MatrixY3*uniteS)**setMomentOfInertia_16\n                MatrixZ3_16 = (MatrixZ3*uniteS)**setMomentOfInertia_16\n            except Exception:\n                MatrixX1_16 = MatrixY1_16 = MatrixZ1_16 = 0.0\n                MatrixX2_16 = MatrixY2_16 = MatrixZ2_16 = 0.0\n                MatrixX3_16 = MatrixY3_16 = MatrixZ3_16 = 0.0\n                #self.SB_16_M.setText(u\"\")\n\n            try:\n                ## MatrixX1_17 = MatrixX1*uniteM**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0)) ## original without parenthesis and modified 17/03/2024\n                MatrixX1_17 = (MatrixX1*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n                MatrixY1_17 = (MatrixY1*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n                MatrixZ1_17 = (MatrixZ1*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n                MatrixX2_17 = (MatrixX2*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n                MatrixY2_17 = (MatrixY2*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n                MatrixZ2_17 = (MatrixZ2*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n                MatrixX3_17 = (MatrixX3*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n                MatrixY3_17 = (MatrixY3*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n                MatrixZ3_17 = (MatrixZ3*uniteM)**setMomentOfInertiaMassique_17*seTDensiteValue*uniteP*(1.0/(uniteV*1000.0))\n            except Exception:\n                MatrixX1_17 = MatrixY1_17 = MatrixZ1_17 = 0.0\n                MatrixX2_17 = MatrixY2_17 = MatrixZ2_17 = 0.0\n                MatrixX3_17 = MatrixY3_17 = MatrixZ3_17 = 0.0\n\n        self.displayMatrixMomentOfInertia()\n\n        self.RB_01_Tabulation.setText(u\"Tabulation\")\n        self.RB_02_Virgule.setText(u\"Comma\")\n        self.RB_03_Point_Virgule.setText(u\"Semicolon\")\n        self.RB_04_Espace.setText(u\"Space\")\n\n#        self.RB_01_Tabulation.setChecked(True)\n#        ESCAPE = \"\\t\"\n        self.paletteBase()\n\n    def on_RB_Separation(self):          # option ESCAPE for  spreadSheet\n        global ESCAPE\n\n        if self.RB_01_Tabulation.isChecked():          #tabulation    #compatible FC\n            ESCAPE = \"\\t\"\n        elif self.RB_02_Virgule.isChecked():           #virgule       #compatible FCInfo\n            ESCAPE = \",\"\n        elif self.RB_03_Point_Virgule.isChecked():     #point virgule #option\n            ESCAPE = \";\"\n        elif self.RB_04_Espace.isChecked():            #espace        #option\n            ESCAPE = \" \"\n\n    def on_PB_01_Read_SpreadSheet_clicked(self):       # lecture\n        global ESCAPE\n        global setPathLatestDirectory\n        global FreeCAD_ParamGetSet\n\n        OpenName = \"\"\n        ####  mint\n        if platform.node() == \"mint\":   # Mint\n            OpenName, Filter = QFileDialog.getOpenFileName(None, u\"Read a txt file\", setPathLatestDirectory, \"(FCInfo *.FCInfo);;(Cvs *.csv);;(Ascii *.asc);;(TXT *.txt);;(*.*);;(*)\")#PySide Mint\n        ####  mint\n        else:\n            OpenName, Filter = QFileDialog.getOpenFileName(None, u\"Read a txt file\", setPathLatestDirectory, \"*.FCInfo *.csv *.asc *.txt;;FCInfo (*.FCInfo);;Cvs (*.csv);;Ascii (*.asc);;TXT (*.txt);;(*.*);;(*)\")#PySide\n\n        try:\n            if OpenName != \"\":\n                ####new2\n                pathFile      = os.path.dirname(OpenName) + \"/\"  #1# = C:/Provisoire400/\n                setPathLatestDirectory = pathFile\n                FreeCAD_ParamGetSet.SetString(u\"setPathLatestDirectory\", setPathLatestDirectory)    #*\"C:/ ???\"\n                #racineDrive   = os.path.splitdrive(OpenName)[0]  #2# = C:\n                #formatFichier = os.path.splitext(OpenName)[1]    #4# = .png\n                #OpenName      = os.path.splitext(OpenName)[0]    #5# = /home/kubuntu/.FreeCAD/Macro/Texture_007_H #= C:/Provisoire400/image3D\n                #nomFichier    = os.path.basename(OpenName)       #3# = image3D\n                #SaveNameformatFichier = OpenName + formatFichier #6# = C:/Provisoire400/image3D.png\n                #pathFileSaveNameformatFichier = pathFile + nomFichier + formatFichier #7# = C:/Provisoire400/image3D.png\n                ####new2\n\n                ####detection separator###################\n                file = open(OpenName, \"r\")                   # open file for counter separator\n                separateur1 = separateur2 = separateur3 = separateur4 = 0\n                for separator in file:\n                    separateur1 += separator.count(u\"\\t\")\n                    separateur2 += separator.count(u\",\")\n                    separateur3 += separator.count(u\";\")\n                    separateur4 += separator.count(u\" \")\n\n                self.RB_01_Tabulation.setText(u\"Tabulation \"+str(separateur1))\n                self.RB_02_Virgule.setText(u\"Comma \"+str(separateur2))\n                self.RB_03_Point_Virgule.setText(u\"Semicolon \"+str(separateur3))\n                self.RB_04_Espace.setText(u\"Space \"+\"(\" + str(separateur4) + \")\")\n\n                file.close()\n                ####detection separator###################\n                     \n                ####counter line and colonne###################\n                file = open(OpenName, \"r\")                   # open file for counter line and colonne\n\n                reader = csv.reader(file, delimiter = ESCAPE) #, quotechar=';'\n                Count0  = 0\n                ligne   = 0\n                colonne = 0\n                try:                         #\n                    for row in reader:\n                        ligne += 1           #\n                        for field in row:\n                           Count0 += 1       #\n                        if Count0 > colonne:\n                            colonne = Count0\n                        Count0 = 0\n                finally:\n                    file.close()\n\n                self.table = QTableWidget( ligne , colonne)   # prepare le tableau\n                self.table.setWindowTitle(u\"FCInfo Patience reading the file\")\n#                self.table.resize(700, 500)\n                self.table.resize(500, 700)\n                self.table.setWindowModality(QtCore.Qt.NonModal)\n                self.table.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)     # PySide\n                self.table.setWindowIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_04))) # icone dans une variable \n                self.table.show()\n                ####counter line and colonne###################\n                                                                                      \n                ####csv.reader###################\n                file = open(OpenName, \"r\")                    # open file for read\n                reader = csv.reader(file, delimiter = ESCAPE) #, quotechar=';'\n                lignes = ligne\n                colonne = 0\n                ligne   = 0\n                try:\n                    for row in reader:\n                        for field in row:\n                           newitem = QTableWidgetItem(str(field))\n                           self.table.setItem(ligne, colonne, newitem)\n                           colonne += 1\n                        ligne += 1\n                        colonne = 0\n                        self.table.setWindowTitle(u\"FCInfo Patience reading the file \"+str(ligne)+\"/\"+str(lignes))\n                finally:\n                    file.close()\n\n                self.table.setWindowTitle(u\"FCInfo Tableau \" + OpenName)\n                ####csv.reader###################\n\n        except Exception:\n            App_Console_PrintMessage(u\"Error in reading the file \" + OpenName + \"\\n\")\n            errorDialog(u\"Error in reading the file \" + OpenName)\n\n    def on_PB_02_Save_SreadSheet_clicked(self):      # registration\n        global document_\n        global object_Label\n        global object_Name\n        global typeObject\n        global object_Type\n        global subElemName\n        global position0\n        global position1\n        global position2\n        global longueurObjet\n        global rayonObjet\n        global detected\n        global perimetre\n        global massOrGravity\n        global diffuseColorRF\n        global diffuseColorVF\n        global diffuseColorBF\n        global diffuseColorTF\n\n        global Plan_xy_V\n        global Plan_yz_V\n        global Plan_zx_V\n\n        global surface\n        global surfaceFace\n        global volume_\n        global seTDensiteValue\n        global poids\n        global uniteM\n        global uniteMs\n        global uniteS\n        global uniteSs\n        global uniteV\n        global uniteVs\n        global unitePs\n\n        global boundBoxCenterX\n        global boundBoxCenterY\n        global boundBoxCenterZ\n\n        global CenterOfMassX\n        global CenterOfMassY\n        global CenterOfMassZ\n\n        global boundBoxLX\n        global boundBoxLY\n        global boundBoxLZ\n\n        global Vertx\n        global Edges\n        global EdgesLong\n        global Faces\n        global FacesSurf\n        global FacesCoor\n        global compt_E\n        global compt_F\n        global compt_VF\n        global RowCountTest\n        global path\n        global SaveName\n        global ESCAPE\n        global directionObj\n        global direcValueAt\n        global direcNormalAt\n\n        global Matrix_1\n        global Matrix_2\n        global Matrix_3\n\n        global Matrix12\n        global Matrix13\n        global Matrix14\n        global Matrix15\n        global DeterminantM\n\n        global setMomentOfInertia_16\n        global setMomentOfInertiaMassique_17\n        global MatrixOfInertiaRaw\n        global MatrixX1_16\n        global MatrixY1_16\n        global MatrixZ1_16\n        global MatrixX2_16\n        global MatrixY2_16\n        global MatrixZ2_16\n        global MatrixX3_16\n        global MatrixY3_16\n        global MatrixZ3_16\n\n        global MatrixX1_17\n        global MatrixY1_17\n        global MatrixZ1_17\n        global MatrixX2_17\n        global MatrixY2_17\n        global MatrixZ2_17\n        global MatrixX3_17\n        global MatrixY3_17\n        global MatrixZ3_17\n        global typeLongueur\n\n        global nombreArretesMesh\n        global nombreFacesMesh\n        global nombrePointsMesh\n        global colorShapeFaceDiffuseColor\n\n        global BsplineDetect\n        global BsplineNombreDeNoeuds\n        global BsplinePointsCoor\n\n        global seTMaterialCost\n        global seTMaterialPrice\n        global seTMaterialSuffixCost\n        global materialAssociated\n        global seTMaterialCurrentIndex\n        global setPathLatestDirectory\n        global FreeCAD_ParamGetSet\n\n        SaveName = \"\"\n        ####  mint\n        if platform.node() == \"mint\":   # Mint\n            SaveName, Filter = QFileDialog.getSaveFileName(None, \"Save a txt file\", setPathLatestDirectory, \" (FCInfo *.FCInfo);; (Cvs *.csv);; (Ascii *.asc);; (TXT *.txt);;(*.*);;(*)\")#PySide Mint\n            Filter = Filter[Filter.find(\".\"):Filter.find(\")\")]\n            if Filter[-2:] == \".*\":\n                 Filter = Filter[:-2]\n            if SaveName.count(\".\") == 1:    # supposed extension free\n                None\n            else:\n                SaveName = SaveName + Filter\n        ####  Windows\n        elif platform.system() == \"Windows\":\n            SaveName, Filter = QFileDialog.getSaveFileName(None, \"Save a txt file\", setPathLatestDirectory, \"*.FCInfo *.csv *.asc *.txt;;FCInfo (*.FCInfo);;Cvs (*.csv);;Ascii (*.asc);;TXT (*.txt);;(*.*);;(*)\")#PySide\n        #### other Kubuntu\n        else:\n            SaveName, Filter = QFileDialog.getSaveFileName(None, \"Save a txt file\", setPathLatestDirectory, \" (FCInfo *.FCInfo);; (Cvs *.csv);; (Ascii *.asc);; (TXT *.txt);;(*.*);;(*)\")#PySide ubuntu\n            Filter = Filter[Filter.find(\".\"):Filter.find(\")\")]\n            if (Filter == \"*.*\") or (Filter == \".*\") or (Filter == \"*\") or (Filter == \".\") or (Filter == \"\"):\n                    Filter = \".FCInfo\"\n            if SaveName.count(\".\") == 1:    # supposed extension free\n                None\n            else:\n                SaveName = SaveName + Filter\n        ####\n        if SaveName == \"\":\n            App_Console_PrintMessage(u\"Process aborted\" + \"\\n\")\n            errorDialog(u\"Process aborted\")\n        else:\n            App_Console_PrintMessage(u\"Registration of \" + SaveName + \"\\n\")\n            ####new2\n            pathFile      = os.path.dirname(SaveName) + \"/\"  #1# = C:/Provisoire400/\n            setPathLatestDirectory = pathFile\n            FreeCAD_ParamGetSet.SetString(u\"setPathLatestDirectory\", setPathLatestDirectory)    #*\"C:/ ???\"\n            #racineDrive   = os.path.splitdrive(SaveName)[0]  #2# = C:\n            #formatFichier = os.path.splitext(SaveName)[1]    #4# = .png\n            #SaveName      = os.path.splitext(SaveName)[0]    #5# = /home/kubuntu/.FreeCAD/Macro/Texture_007_H #= C:/Provisoire400/image3D\n            #nomFichier    = os.path.basename(SaveName)       #3# = image3D\n            #SaveNameformatFichier = SaveName + formatFichier #6# = C:/Provisoire400/image3D.png\n            #pathFileSaveNameformatFichier = pathFile + nomFichier + formatFichier #7# = C:/Provisoire400/image3D.png\n            ####new2\n\n            try:\n                f = open(SaveName, 'w') # write\n                f.write(iso8859(u\"Info of the element\\n\"))\n                f.write(iso8859(u\"___________________\\n\"))\n                f.write(iso8859(dateUs() + \" \"+ heure() + \"\\n\\n\"))\n                f.write(iso8859(u\"Name of the document\" + ESCAPE + document_ + \"\\n\"))\n                f.write(iso8859(u\"Label Name\" + ESCAPE + object_Label + \"\\n\"))\n                f.write(iso8859(u\"Internal Name\" + ESCAPE + object_Name + \"\\n\"))\n                f.write(iso8859(u\"Name of the element\" + ESCAPE + str(subElemName) + \"\\n\"))\n                f.write(iso8859(u\"Object type (Shape)\" + ESCAPE + typeObject + \"\\n\"))\n                f.write(iso8859(u\"Object type\" + ESCAPE + object_Type + \"\\n\\n\"))\n\n                f.write(iso8859(u\"Mouse coordinates\" + ESCAPE + \"X\" + ESCAPE + str(Around(position0 * uniteM)) + ESCAPE + uniteMs + ESCAPE + \n                                                                       \"Y\" + ESCAPE + str(Around(position1 * uniteM)) + ESCAPE + uniteMs + ESCAPE + \n                                                                       \"Z\" + ESCAPE + str(Around(position2 * uniteM)) + ESCAPE + uniteMs + \"\\n\\n\"))\n\n                #### couleurs\n                f.write(iso8859(u\"Color of the selection\" + \"\\n\"))\n                f.write(iso8859(u\"Red\" + ESCAPE + str(int(diffuseColorRF*255.0)) + ESCAPE + \n                                u\"Green\" + ESCAPE + str(int(diffuseColorVF*255.0)) + ESCAPE + \n                                u\"Blue\" + ESCAPE + str(int(diffuseColorBF*255.0)) + ESCAPE + \n                                u\"Transparency\" + ESCAPE + str(int(diffuseColorTF*255.0)) + \"\\n\\n\"))\n\n                if len(colorShapeFace) != 0:\n                    f.write(iso8859(u\"Color Objet (float) \" + ESCAPE + u\"Red\" + ESCAPE + str(colorShapeFace[0]) + ESCAPE + \n                                                                       u\"Green\"  + ESCAPE + str(colorShapeFace[1]) + ESCAPE + \n                                                                       u\"Blue\" + ESCAPE + str(colorShapeFace[2]) + ESCAPE + \n                                                                       u\"Transparency\" + ESCAPE + str(colorShapeFace[3]) + \"\\n\"))\n                    f.write(iso8859(u\"Color Objet (int  ) \" + ESCAPE + u\"Red\" + ESCAPE + str(int(colorShapeFace[0]*255.0)) + ESCAPE + \n                                                                       u\"Green\"  + ESCAPE + str(int(colorShapeFace[1]*255.0)) + ESCAPE + \n                                                                       u\"Blue\" + ESCAPE + str(int(colorShapeFace[2]*255.0)) + ESCAPE + \n                                                                       u\"Transparency\" + ESCAPE + str(int(colorShapeFace[3]*255.0)) + \"\\n\\n\"))\n\n                if len(colorShapeLine) != 0:\n                    f.write(iso8859(u\"Color Line(s) (float) \" + ESCAPE + u\"Red\" + ESCAPE + str(colorShapeLine[0]) + ESCAPE + \n                                                                         u\"Green\"  + ESCAPE + str(colorShapeLine[1]) + ESCAPE + \n                                                                         u\"Blue\" + ESCAPE + str(colorShapeLine[2]) + ESCAPE + \n                                                                         u\"Transparency\" + ESCAPE + str(colorShapeLine[3]) + \"\\n\"))\n                    f.write(iso8859(u\"Color Line(s) (int  ) \" + ESCAPE + u\"Red\" + ESCAPE + str(int(colorShapeLine[0]*255.0)) + ESCAPE + \n                                                                         u\"Green\"  + ESCAPE + str(int(colorShapeLine[1]*255.0)) + ESCAPE + \n                                                                         u\"Blue\" + ESCAPE + str(int(colorShapeLine[2]*255.0)) + ESCAPE + \n                                                                         u\"Transparency\" + ESCAPE + str(int(colorShapeLine[3]*255.0)) + \"\\n\\n\"))\n\n                if len(colorShapePoint) != 0:\n                    try:\n                        f.write(iso8859(u\"Color Point(s) (float) \" + ESCAPE + u\"Red\" + ESCAPE + str(colorShapePoint[0]) + ESCAPE + \n                                                                              u\"Green\"  + ESCAPE + str(colorShapePoint[1]) + ESCAPE + \n                                                                              u\"Blue\" + ESCAPE + str(colorShapePoint[2]) + ESCAPE + \n                                                                              u\"Transparency\" + ESCAPE + str(colorShapePoint[3]) + \"\\n\"))\n                        f.write(iso8859(u\"Color Point(s) (int  ) \" + ESCAPE + u\"Red\" + ESCAPE + str(int(colorShapePoint[0]*255.0)) + ESCAPE + \n                                                                              u\"Green\"  + ESCAPE + str(int(colorShapePoint[1]*255.0)) + ESCAPE + \n                                                                              u\"Blue\" + ESCAPE + str(int(colorShapePoint[2]*255.0)) + ESCAPE + \n                                                                              u\"Transparency\" + ESCAPE + str(int(colorShapePoint[3]*255.0)) + \"\\n\\n\"))\n                    except Exception:\n                        None\n\n                f.write(iso8859(typeLongueur + ESCAPE + str(Around(longueurObjet * uniteM)) + ESCAPE + uniteMs + \"\\n\"))\n\n                if detected[0:4] == \"Mesh\":\n                    f.write(iso8859(u\"Components Mesh\" + \"\\n\"))\n                    f.write(iso8859(u\"_______________\\n\"))\n                    f.write(iso8859(u\"Number Edges\" + ESCAPE + str(nombreArretesMesh) + \"\\n\"))\n                    f.write(iso8859(u\"Number Faces\" + ESCAPE + str(nombreFacesMesh) + \"\\n\"))\n                    f.write(iso8859(u\"Number Points\" + ESCAPE + str(nombrePointsMesh) + \"\\n\\n\"))\n\n                if detected == \"<PointKernel object>\":\n                    f.write(iso8859(u\"Components Points\" + \"\\n\"))\n                    f.write(iso8859(u\"_________________\\n\"))\n                    f.write(iso8859(u\"Number Points\" + ESCAPE + str(nombrePointsMesh) + \"\\n\\n\"))\n\n               #### detail of Cercle\n                if rayonObjet != 0.0:\n                    f.write(iso8859(u\"Radius\" + ESCAPE + str(Around(rayonObjet * uniteM)) + ESCAPE + uniteMs + \"\\n\\n\"))\n\n                f.write(iso8859(u\"Perimeter of the shape\" + ESCAPE + str(Around(perimetre * uniteM)) + ESCAPE + uniteMs + \"\\n\\n\"))\n\n                if self.GBox_012_SpreadSheet.isChecked():\n                    #### detail of Cercle BSpline begin\n                    if (str(BsplineDetect) == \"<BSplineCurve object>\"):\n                        f.write(iso8859(u\"Number of nodes\" + ESCAPE + str(BsplineNombreDeNoeuds) + \"\\n\"))\n                        for i in enumerate(BsplinePointsCoor):     # nombre de points noeuds\n                            f.write(iso8859(u\"Nodes\" + str(i[0]) + ESCAPE + u\"X\" + str(i[0] + 1) + ESCAPE + str(Around(i[1][0])) + ESCAPE + \n                                                                            u\"Y\" + str(i[0] + 1) + ESCAPE + str(Around(i[1][1])) + ESCAPE + \n                                                                            u\"Z\" + str(i[0] + 1) + ESCAPE + str(Around(i[1][2])) + ESCAPE + \"\\n\"))\n                        f.write(iso8859(\"\\n\"))\n                    #### detail of Cercle BSpline end\n\n                    f.write(iso8859(u\"Vertexes and details\" + ESCAPE + u\" Number Edges\" + ESCAPE + str(compt_E) + ESCAPE + u\" Number Faces\" + ESCAPE + str(compt_F) + ESCAPE + u\" Number Vertexes faces\" + ESCAPE + str(compt_VF) + ESCAPE + u\" Detail Total\" + ESCAPE + str(RowCountTest) + \"\\n\\n\"))\n                    co = 0\n                    aa = 0\n                    for j in enumerate(Edges):\n                        f.write(str(j[1]) + ESCAPE +iso8859(str(Around(float(EdgesLong[co]) * float(uniteM))) + ESCAPE + uniteMs + ESCAPE))#\"\\n\"\n                        co+=1\n                        for a in range(aa,aa+6):\n                            try:\n                                chaine = str(Vertx[a]).split(\":\")\n                                f.write(chaine[0] + ESCAPE + iso8859(str(Around(float(chaine[1]) * float(uniteM)))) + ESCAPE + uniteMs + ESCAPE)\n                            except Exception:\n                                None\n                        aa += 6\n                        f.write(\"\\n\")\n                    f.write(\"\\n\")\n                    co  = 0\n                    cco = 0\n                    co2 = 0\n                    for j in enumerate(Faces):\n                        f.write(str(j[1]) + ESCAPE + iso8859(str(Around(float(FacesSurf[co]) * float(uniteS))) + ESCAPE + uniteSs + \"\\n\"))\n                        co += 1\n                        if len(colorShapeFaceDiffuseColor) != 0:\n                            f.write(iso8859(u\"Color float   Face\" + str(j[0]+1) + ESCAPE + \n                                            u\"Red\" + ESCAPE + str(colorShapeFaceDiffuseColor[j[0]][0]) + ESCAPE + \n                                            u\"Green \" + ESCAPE + str(colorShapeFaceDiffuseColor[j[0]][1]) + ESCAPE + \n                                            u\"Blue \" + ESCAPE + str(colorShapeFaceDiffuseColor[j[0]][2]) + ESCAPE + \n                                            u\"Transparency\" + ESCAPE + str(colorShapeFaceDiffuseColor[j[0]][3]) + ESCAPE + \"\\n\"))\n                            f.write(iso8859(u\"Couleur integer Face\" + str(j[0]+1) + ESCAPE + \n                                            u\"Red\" + ESCAPE + str(int(colorShapeFaceDiffuseColor[j[0]][0]*255.0)) + ESCAPE + \n                                            u\"Green \" + ESCAPE + str(int(colorShapeFaceDiffuseColor[j[0]][1]*255.0)) + ESCAPE + \n                                            u\"Blue \" + ESCAPE + str(int(colorShapeFaceDiffuseColor[j[0]][2]*255.0)) + ESCAPE + \n                                            u\"Transparency\" + ESCAPE + str(int(colorShapeFaceDiffuseColor[j[0]][3]*255.0)) + ESCAPE + \"\\n\"))\n\n                        for jj in range(cco,len(FacesCoor)):# Faces coordinates\n                            cco+=1\n                            if FacesCoor[jj] == \"T\":\n                                f.write(\"\\n\")\n                                break\n                            else:\n                                chaine = str(FacesCoor[jj]).split(\":\")\n                                f.write(iso8859(chaine[0] + ESCAPE + str(Around(float(chaine[1]) * float(uniteM))) + ESCAPE + uniteMs + ESCAPE))\n                                co2 += 1\n                                if co2 == 3:\n                                    f.write(\"\\n\")\n                                    co2 = 0\n\n                f.write(u\"\\n\")\n                f.write(iso8859(u\"Plane\" + ESCAPE + u\" XY:\" + ESCAPE + self.LE_8xy.text() + ESCAPE + u\" coordinates:\" + ESCAPE + str(Plan_xy_V) + \"\\n\"))\n                f.write(iso8859(u\"Plane\" + ESCAPE + u\" YZ:\" + ESCAPE + self.LE_8yz.text() + ESCAPE + u\" coordinates:\" + ESCAPE + str(Plan_yz_V) + \"\\n\"))\n                f.write(iso8859(u\"Plane\" + ESCAPE + u\" ZX:\" + ESCAPE + self.LE_8zx.text() + ESCAPE + u\" coordinates:\" + ESCAPE + str(Plan_zx_V) + \"\\n\\n\"))\n                f.write(iso8859(u\"The form area\" + ESCAPE + str(Around(surface * uniteS)) + ESCAPE + uniteSs + \"\\n\"))\n                f.write(iso8859(u\"Area of the face\" + ESCAPE + str(Around(surfaceFace * uniteS)) + ESCAPE + uniteSs + \"\\n\\n\"))\n                f.write(iso8859(u\"Volume of the form\" + ESCAPE + str(Around(volume_ * uniteV)) + ESCAPE + uniteVs + \"\\n\"))\n                f.write(iso8859(u\"Mass\" + ESCAPE + str(Around(poids)) + ESCAPE + unitePs + ESCAPE + u\" Density:\" + ESCAPE + str(Around(seTDensiteValue)) + \"\\n\\n\"))\n                f.write(iso8859(u\"Center of the shape\" + ESCAPE + u\" X:\" + ESCAPE + str(Around(boundBoxCenterX * uniteM)) + ESCAPE + uniteMs + ESCAPE + \n                                                                  u\" Y:\" + ESCAPE + str(Around(boundBoxCenterY * uniteM)) + ESCAPE + uniteMs + ESCAPE + \n                                                                  u\" Z:\" + ESCAPE + str(Around(boundBoxCenterZ * uniteM)) + ESCAPE + uniteMs + \"\\n\"))\n                f.write(iso8859(u\"Center of \" + massOrGravity + ESCAPE + u\" X:\" + ESCAPE + str(Around(CenterOfMassX   * uniteM)) + ESCAPE + uniteMs + ESCAPE + \n                                                             u\" Y:\" + ESCAPE + str(Around(CenterOfMassY   * uniteM)) + ESCAPE + uniteMs + ESCAPE + \n                                                             u\" Z:\" + ESCAPE + str(Around(CenterOfMassZ   * uniteM)) + ESCAPE + uniteMs + \"\\n\"))\n                f.write(iso8859(u\"BoundBox\" + ESCAPE + u\" X:\" + ESCAPE + str(Around(boundBoxLX      * uniteM)) + ESCAPE + uniteMs + ESCAPE + \n                                                       u\" Y:\" + ESCAPE + str(Around(boundBoxLY      * uniteM)) + ESCAPE + uniteMs + ESCAPE + \n                                                       u\" Z:\" + ESCAPE + str(Around(boundBoxLZ      * uniteM)) + ESCAPE + uniteMs + \"\\n\"))\n                f.write(iso8859(u\"BoundBox Diagonal\" + ESCAPE + str(Around(boundBoxDiag * uniteM)) + ESCAPE + uniteMs + \"\\n\\n\"))\n\n                if directionObj != \"[]\":\n                    f.write(iso8859(u\"Direction\" + ESCAPE + u\" X:\" + ESCAPE + str(Around(directionObj[0])) + ESCAPE + u\" Y:\" + ESCAPE + str(Around(directionObj[1])) + ESCAPE + u\" Z:\" + ESCAPE + str(Around(directionObj[2])) + \"\\n\"))\n                if direcValueAt != \"[]\":\n                    f.write(iso8859(u\"ValueAt\" + ESCAPE + u\" X:\" + ESCAPE + str(Around(direcValueAt[0])) + ESCAPE + u\" Y:\" + ESCAPE + str(Around(direcValueAt[1])) + ESCAPE + u\" Z:\" + ESCAPE + str(Around(direcValueAt[2])) + \"\\n\"))\n                if direcNormalAt != \"[]\":\n                    f.write(iso8859(u\"NormalAt\" + ESCAPE + u\" X:\" + ESCAPE + str(Around(direcNormalAt[0])) + ESCAPE + u\" Y:\" + ESCAPE + str(Around(direcNormalAt[1])) + ESCAPE + u\" Z:\" + ESCAPE + str(Around(direcNormalAt[2])) + \"\\n\"))\n                f.write(iso8859(u\"\\n\"))\n\n                if detected[0:4] == \"Mesh\":\n                    None\n                else:\n                    f.write(iso8859(u\"Matrix of inertia Raw\" + ESCAPE + str(MatrixOfInertiaRaw)) + \"\\n\")\n                    f.write(iso8859(u\"Matrix of inertia\" + ESCAPE +  uniteMs + \"^\" + str(setMomentOfInertia_16)) + \"\\n\")\n                    f.write(iso8859(ESCAPE + u\" X:\" + ESCAPE + str(Around(MatrixX1_16)) + ESCAPE + \n                                             u\" Y:\" + ESCAPE + str(Around(MatrixY1_16)) + ESCAPE + \n                                             u\" Z:\" + ESCAPE + str(Around(MatrixZ1_16)) + ESCAPE + \n                                             u\" :\" + ESCAPE + str(Around(Matrix_1)) + \"\\n\"))\n                    f.write(iso8859(ESCAPE + u\" X:\" + ESCAPE + str(Around(MatrixX2_16)) + ESCAPE + \n                                             u\" Y:\" + ESCAPE + str(Around(MatrixY2_16)) + ESCAPE + \n                                             u\" Z:\" + ESCAPE + str(Around(MatrixZ2_16)) + ESCAPE + \n                                             u\" :\" + ESCAPE + str(Around(Matrix_2)) + \"\\n\"))\n                    f.write(iso8859(ESCAPE + u\" X:\" + ESCAPE + str(Around(MatrixX3_16)) + ESCAPE + \n                                             u\" Y:\" + ESCAPE + str(Around(MatrixY3_16)) + ESCAPE + \n                                             u\" Z:\" + ESCAPE + str(Around(MatrixZ3_16)) + ESCAPE + \n                                             u\" :\" + ESCAPE + str(Around(Matrix_3)) + \"\\n\"))\n                    f.write(iso8859(ESCAPE + u\" X:\" + ESCAPE + str(Around(Matrix12)) + ESCAPE + \n                                             u\" Y:\" + ESCAPE + str(Around(Matrix13))    + ESCAPE + \n                                             u\" Z:\" + ESCAPE + str(Around(Matrix14))    + ESCAPE + \n                                             u\" :\" + ESCAPE + str(Around(Matrix15)) + \"\\n\\n\"))\n\n                    f.write(iso8859(u\"Matrix inertia with mass\" + ESCAPE + unitePs + uniteSs + \"^\" + str(setMomentOfInertiaMassique_17)) + \"\\n\")\n                    f.write(iso8859(ESCAPE + u\" X:\" + ESCAPE + str(Around(MatrixX1_17)) + ESCAPE + \n                                             u\" Y:\" + ESCAPE + str(Around(MatrixY1_17)) + ESCAPE + \n                                             u\" Z:\" + ESCAPE + str(Around(MatrixZ1_17)) + \"\\n\"))\n                    f.write(iso8859(ESCAPE + u\" X:\" + ESCAPE + str(Around(MatrixX2_17)) + ESCAPE + \n                                             u\" Y:\" + ESCAPE + str(Around(MatrixY2_17)) + ESCAPE + \n                                             u\" Z:\" + ESCAPE + str(Around(MatrixZ2_17)) + \"\\n\"))\n                    f.write(iso8859(ESCAPE + u\" X:\" + ESCAPE + str(Around(MatrixX3_17)) + ESCAPE + \n                                             u\" Y:\" + ESCAPE + str(Around(MatrixY3_17)) + ESCAPE + \n                                             u\" Z:\" + ESCAPE + str(Around(MatrixZ3_17)) + \"\\n\\n\"))\n\n                    f.write(iso8859(u\"Matrix Determinant\" + ESCAPE + str(DeterminantM) + \"\\n\"))\n                    f.write(iso8859(u\"Determinant decimal\" + ESCAPE + str(decimal.Decimal(DeterminantM)) + \"\\n\\n\"))\n\n                materiel = materialAssociated[seTMaterialCurrentIndex].rstrip().split(\",\")\n                nomMateriel     = materiel[0]\n                densitexMateriel= str(Around(float(materiel[1])))\n                prixMateriel    = str(Around(float(materiel[2])))\n                infoMateriel    = materiel[3]\n\n                f.write(iso8859(u\"Material\" + ESCAPE + \"\\n\"))\n                f.write(iso8859(u\"Name\" + ESCAPE + u\"Density\" + ESCAPE + u\"Volume\" + ESCAPE + u\"Unit\" + ESCAPE + u\"Price (kg/dm3)\"+ ESCAPE + \n                                                   u\"Cost total\" + ESCAPE + u\"Devise\" + ESCAPE + u\"Info\" + \"\\n\"))\n                f.write(iso8859(nomMateriel + ESCAPE + densitexMateriel + ESCAPE + str(Around(volume_ * uniteV)) + ESCAPE + uniteVs + ESCAPE + \n                                prixMateriel + ESCAPE + str(Around(seTMaterialCost)) + ESCAPE + seTMaterialSuffixCost + ESCAPE + infoMateriel + \"\\n\\n\"))\n\n                f.write(iso8859(u\"End \" + ESCAPE + document_ + \"\\n\"))\n                f.close()\n            except Exception:\n                App_Console_PrintMessage(u\"Error writing file \" + SaveName + \"\\n\")\n                errorDialog(u\"Error writing file \" + SaveName)\n\n    def on_PB_Ra_clicked(self):    # clicked() pressed(), released() Bouton radian/degrees\n        global uniteAs\n        global Plan_xy\n        global Plan_yz\n        global Plan_zx\n\n        Plan_xy2 = 0.0\n        Plan_yz2 = 0.0\n        Plan_zx2 = 0.0\n        choice = self.PB_Ra.text()\n\n        if choice == \"Degrees\":    # ne pas traduire\n            uniteAs = \"\"\n            self.PB_Ra.setText(u\"DegMinSec\")  # ne pas traduire\n            self.PB_Ra.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_DegreesMinSec))) # icone dans une variable \n            self.LE_8xy.setText(str(degMinSec(Plan_xy))) #angle degesMinutesSecondes\n            self.LE_8yz.setText(str(degMinSec(Plan_yz)))\n            self.LE_8zx.setText(str(degMinSec(Plan_zx)))\n        elif choice == \"DegMinSec\":# ne pas traduire\n            uniteAs = \" rad\"\n            self.PB_Ra.setText(u\"Radian\")  # ne pas traduire\n            self.PB_Ra.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Radian))) # icone dans une variable \n            Plan_xy2 = radians(Plan_xy)\n            self.LE_8xy.setText(str(Around(Plan_xy2))+uniteAs) # angleRadian\n            Plan_yz2 = radians(Plan_yz)\n            self.LE_8yz.setText(str(Around(Plan_yz2))+uniteAs)\n            Plan_zx2 = radians(Plan_zx)\n            self.LE_8zx.setText(str(Around(Plan_zx2))+uniteAs)\n        elif choice == \"Radian\":   # ne pas traduire\n            uniteAs = \" gon\"\n            self.PB_Ra.setText(u\"Grade\")  # ne pas traduire\n            self.PB_Ra.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Grade))) # icone dans une variable \n            Plan_xy2 = angleGrade(Plan_xy)\n            self.LE_8xy.setText(str(Around(Plan_xy2))+uniteAs) #angleGrade\n            Plan_yz2 = angleGrade(Plan_yz)\n            self.LE_8yz.setText(str(Around(Plan_yz2))+uniteAs)\n            Plan_zx2 = angleGrade(Plan_zx)\n            self.LE_8zx.setText(str(Around(Plan_zx2))+uniteAs)\n        elif choice == \"Grade\":    # ne pas traduire\n            uniteAs = u\"%\"\n            self.PB_Ra.setText(u\"Percent\")  # ne pas traduire\n            self.PB_Ra.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Pourcent))) # icone dans une variable \n            Plan_xy2 = anglePourcent(Plan_xy)\n            self.LE_8xy.setText(str(Around(Plan_xy2))+uniteAs) #anglePourcent\n            Plan_yz2 = anglePourcent(Plan_yz)\n            self.LE_8yz.setText(str(Around(Plan_yz2))+uniteAs)\n            Plan_zx2 = anglePourcent(Plan_zx)\n            self.LE_8zx.setText(str(Around(Plan_zx2))+uniteAs)\n        elif choice == \"Percent\":  # ne pas traduire\n            uniteAs = \" deg\"\n            try:\n                self.PB_Ra.setText(u\"Degrees\")  # ne pas traduire\n                self.PB_Ra.setIcon(QtGui.QIcon(QtGui.QPixmap(Macro_FCInfo_Degrees))) # icone dans une variable \n                self.LE_8xy.setText(str(Around(Plan_xy))+uniteAs) # angleDegree\n                self.LE_8yz.setText(str(Around(Plan_yz))+uniteAs)\n                self.LE_8zx.setText(str(Around(Plan_zx))+uniteAs)\n        \n            except Exception:\n                None\n\n    def on_CB_01_Info(self):\n        global switchDisplayInfoObject\n        global FreeCAD_ParamGetSet\n\n        if self.CB_01_Info.isChecked():\n            switchDisplayInfoObject = 1\n        else:\n            switchDisplayInfoObject = 0\n        FreeCAD_ParamGetSet.SetBool(u\"switchDisplayInfoObject\", switchDisplayInfoObject)    # True or False\n\n    def on_CB_02_Point(self):\n        global switchCreatePoint\n        global FreeCAD_ParamGetSet\n\n        if switchCreatePoint == 0:\n            switchCreatePoint = 1\n        else:\n            switchCreatePoint = 0\n        FreeCAD_ParamGetSet.SetBool(u\"switchCreatePoint\", switchCreatePoint)                # True or False\n\n    def on_CB_03_Axis(self):\n        global switchCreateAxis\n        global FreeCAD_ParamGetSet\n\n        if switchCreateAxis == 0:\n            switchCreateAxis = 1\n        else:\n            switchCreateAxis = 0\n        FreeCAD_ParamGetSet.SetBool(u\"switchCreateAxis\", switchCreateAxis)                  #*True or False\n\n    def on_CB_04_Plane(self):\n        global switchCreatePlane\n        global FreeCAD_ParamGetSet\n\n        if switchCreatePlane == 0:\n            switchCreatePlane = 1\n        else:\n            switchCreatePlane = 0\n        FreeCAD_ParamGetSet.SetBool(u\"switchCreatePlane\", switchCreatePlane)                #*True or False\n\n    def on_RB_00_ClipBoard(self):\n        global seTMemoClipBoard\n        global FreeCAD_ParamGetSet\n\n        #self.RB_00_ClipBoard.setChecked(True)\n        seTMemoClipBoard = 0\n        FreeCAD_ParamGetSet.SetInt(u\"seTMemoClipBoard\", seTMemoClipBoard)                   # 0, 1, 2\n\n    def on_RB_01_ClipBoard(self):\n        global seTMemoClipBoard\n        global FreeCAD_ParamGetSet\n\n        #self.RB_01_ClipBoard.setChecked(True)\n        seTMemoClipBoard = 1\n        FreeCAD_ParamGetSet.SetInt(u\"seTMemoClipBoard\", seTMemoClipBoard)                   # 0, 1, 2\n\n    def on_RB_02_ClipBoard(self):\n        global seTMemoClipBoard\n        global FreeCAD_ParamGetSet\n\n        #self.RB_02_ClipBoard.setChecked(True)\n        seTMemoClipBoard = 2\n        FreeCAD_ParamGetSet.SetInt(u\"seTMemoClipBoard\", seTMemoClipBoard)                   # 0, 1, 2\n\n    def on_RB_03_ClipBoard(self):\n        global seTMemoClipBoard\n        global FreeCAD_ParamGetSet\n\n        #self.RB_03_ClipBoard.setChecked(True)\n        seTMemoClipBoard = 3\n        FreeCAD_ParamGetSet.SetInt(u\"seTMemoClipBoard\", seTMemoClipBoard)                   # 0, 1, 2\n\n    def on_CB_05_Position(self):\n        global FCmw\n        global seTPositionFlyRightLeft\n        global seTWidgetPosition\n        global FreeCAD_ParamGetSet\n\n        if seTPositionFlyRightLeft != 1:\n            if self.CB_05_Position.isChecked():\n                FCmw.addDockWidget(QtCore.Qt.LeftDockWidgetArea,myNewFreeCADWidget) # add the widget to the main window Left\n                FreeCAD_ParamGetSet.SetInt(u\"seTPositionFlyRightLeft\", 3)     #*1, 2, other\n                FreeCAD_ParamGetSet.SetBool(u\"seTWidgetPosition\", True)       # True or False\n                seTPositionFlyRightLeft = 3\n                seTWidgetPosition = True\n            else:\n                FCmw.addDockWidget(QtCore.Qt.RightDockWidgetArea,myNewFreeCADWidget)# add the widget to the main window Right\n                FreeCAD_ParamGetSet.SetInt(u\"seTPositionFlyRightLeft\", 2)     #*1, 2, other\n                FreeCAD_ParamGetSet.SetBool(u\"seTWidgetPosition\", False)      # True or False\n                seTPositionFlyRightLeft = 2\n                seTWidgetPosition = False\n\n    def on_ZeroInfo(self):  # reset to 0\n        global typeObject\n        global diffuseColorRF, diffuseColorVF, diffuseColorBF, diffuseColorTF, unsignedEncodeColor\n        global longueurObjet, rayonObjet, perimetre, typeLongueur, numberEdges\n        global Plan_xy, Plan_xy_V, Plan_yz, Plan_yz_V, Plan_zx, Plan_zx_V\n        global surface,surfaceFace,volume_,seTDensiteValue,poids,uniteM, uniteMs, uniteS, uniteSs, uniteV, uniteVs, uniteP, unitePs, uniteAs\n        global boundBoxCenterX, boundBoxCenterY, boundBoxCenterZ, CenterOfMassX, CenterOfMassY, CenterOfMassZ\n        global boundBoxLX, boundBoxLY, boundBoxLZ, boundBox_S, massOrGravity\n        global MatrixX1, MatrixY1, MatrixZ1, Matrix_1\n        global MatrixX2, MatrixY2, MatrixZ2, Matrix_2\n        global MatrixX3, MatrixY3, MatrixZ3, Matrix_3\n        global Matrix12, Matrix13, Matrix14, Matrix15\n        global Vertx, Edges, EdgesLong, Faces, FacesSurf, FacesCoor, compt_E, compt_F, compt_VF, RowCountTest, ESCAPE, directionObj, direcValueAt, direcNormalAt\n        global setMomentOfInertia_16\n        global setMomentOfInertiaMassique_17\n        global MatrixOfInertiaRaw\n        global MatrixX1_16, MatrixY1_16, MatrixZ1_16, MatrixX2_16, MatrixY2_16, MatrixZ2_16, MatrixX3_16, MatrixY3_16, MatrixZ3_16\n        global MatrixX1_17, MatrixY1_17, MatrixZ1_17, MatrixX2_17, MatrixY2_17, MatrixZ2_17, MatrixX3_17, MatrixY3_17, MatrixZ3_17\n        global DeterminantM\n        global seTMaterialPrice, seTMaterialCost, seTMaterialSuffixCost\n        global seTIndexUnitLength\n        global BsplineNombreDeNoeuds, BsplineRayonApproximatif, BsplineNumberElement, BsplineCutLength, setBSplineToByArcValue, BSplinetoByArcValeurS\n        global transparenceFace\n        global typeNormalAt\n\n        global nombreArretesMesh\n        global nombreFacesMesh\n        global nombrePointsMesh\n\n        ####\n        transparenceFace = 0\n        longueurObjet = rayonObjet = perimetre = 0.0\n        numberEdges = 0\n        nombreArretesMesh = nombreFacesMesh = nombrePointsMesh = 0\n        diffuseColorRF = diffuseColorVF = diffuseColorBF = diffuseColorTF = unsignedEncodeColor = 0.0\n\n        surface = surfaceFace = volume_ = poids = 0.0\n        Plan_xy = Plan_yz = Plan_zx = 0.0\n        Plan_xy_V = Plan_yz_V = Plan_zx_V = \"\"\n        MatrixX1 = MatrixY1 = MatrixZ1 = Matrix_1 = 0.0\n        MatrixX2 = MatrixY2 = MatrixZ2 = Matrix_2 = 0.0\n        MatrixX3 = MatrixY3 = MatrixZ3 = Matrix_3 = 0.0\n        Matrix12 = Matrix13 = Matrix14 = Matrix15 = 0.0\n        directionObj = direcValueAt = direcNormalAt = \"[]\"\n        setMomentOfInertia_16 = 1\n        setMomentOfInertiaMassique_17 = 1\n        MatrixOfInertiaRaw = \"Raw : \"\n        MatrixX1_16 = MatrixY1_16 = MatrixZ1_16 = MatrixX2_16 = MatrixY2_16 = MatrixZ2_16 = MatrixX3_16 = MatrixY3_16 = MatrixZ3_16 = 0.0\n        MatrixX1_17 = MatrixY1_17 = MatrixZ1_17 = MatrixX2_17 = MatrixY2_17 = MatrixZ2_17 = MatrixX3_17 = MatrixY3_17 = MatrixZ3_17 = 0.0\n        DeterminantM = 0.0\n        ####\n\n        self.LE_N_Edges.setText(str(nombreArretesMesh))\n        self.LE_N_Facets.setText(str(nombreFacesMesh))\n        self.LE_N_Points.setText(str(nombrePointsMesh))\n\n        self.LE_CRed.setText(str(Around(diffuseColorRF)))\n        self.LE_CGreen.setText(str(Around(diffuseColorVF)))\n        self.LE_CBlue.setText(str(Around(diffuseColorBF)))\n        self.LE_Transparent.setText(str(Around(diffuseColorTF)))\n        self.LE_ConversionUnsigned.setText(str(unsignedEncodeColor))\n        self.LE_9_Direction.setText(str(directionObj))\n        self.LE_10_ValueAt.setText(str(direcValueAt))\n        self.LE_10b_NormalAt.setText(str(direcNormalAt))\n        self.PB_Line_NormalAT.setText(typeNormalAt)\n\n        self.SBox_Transparence.setValue(transparenceFace)\n\n        self.LA_14x.setText(massOrGravity + u\" X\")\n        self.LA_14y.setText(massOrGravity + u\" Y\")\n        self.LA_14z.setText(massOrGravity + u\" Z\")\n\n        self.LE_007_BB_01_XLength.setText(str(Around(boundBoxLX * uniteM)) + \" \" + uniteMs)\n        self.LE_007_BB_02_YLength.setText(str(Around(boundBoxLY * uniteM)) + \" \" + uniteMs)\n        self.LE_007_BB_03_ZLength.setText(str(Around(boundBoxLZ * uniteM)) + \" \" + uniteMs)\n        self.LE_007_BB_04_Diagonal.setText(str(Around(boundBoxDiag * uniteM)) + \" \" + uniteMs)\n        boundBox_S = \"[X: \"+str(Around(boundBoxLX * uniteM)) + \" \" + uniteMs+\"] x [Y: \"+str(Around(boundBoxLY * uniteM)) + \" \" + uniteMs+\"] x [Z: \"+str(Around(boundBoxLZ * uniteM)) + \" \" + uniteMs+\"] Diagonal: \" + str(Around(boundBoxDiag * uniteM)) + \" \" + uniteMs\n\n        self.LE_6.setText(str(Around(float(perimetre) * float(uniteM))) + \" \" +uniteMs)\n\n        self.LE_8xy.setText(str(Around(Plan_xy))+uniteAs)\n        self.LE_8xya.setText(str(Plan_xy_V))\n        self.LE_8yz.setText(str(Around(Plan_yz))+uniteAs)\n        self.LE_8yza.setText(str(Plan_yz_V))\n        self.LE_8zx.setText(str(Around(Plan_zx))+uniteAs)\n        self.LE_8zxa.setText(str(Plan_zx_V))\n\n        self.LE_9a.setText(str(Around(surface * uniteS)) + \" \" + uniteSs)\n        self.LE_10a.setText(str(Around(surfaceFace * uniteS)) + \" \" + uniteSs)\n        self.LE_11a.setText(str(Around(volume_ * uniteV)) + \" \" + uniteVs)\n        self.LE_12a.setText(str(Around(poids)) + \" \" + unitePs)\n\n        self.LE_Cost.setText(str(Around(seTMaterialCost)) + seTMaterialSuffixCost) #CostMaterial\n\n        self.LE_13x.setText(str(Around(boundBoxCenterX * uniteM)) + \" \" + uniteMs)\n        self.LE_13y.setText(str(Around(boundBoxCenterY * uniteM)) + \" \" + uniteMs)\n        self.LE_13z.setText(str(Around(boundBoxCenterZ * uniteM)) + \" \" + uniteMs)\n        self.LE_14x.setText(str(Around(CenterOfMassX * uniteM)) + \" \" + uniteMs)\n        self.LE_14y.setText(str(Around(CenterOfMassY * uniteM)) + \" \" + uniteMs)\n        self.LE_14z.setText(str(Around(CenterOfMassZ * uniteM)) + \" \" + uniteMs)\n\n        self.LE_007_BB_01_XLength.setText(str(Around(boundBoxLX * uniteM)) + \" \" + uniteMs)\n        self.LE_007_BB_02_YLength.setText(str(Around(boundBoxLY * uniteM)) + \" \" + uniteMs)\n        self.LE_007_BB_03_ZLength.setText(str(Around(boundBoxLZ * uniteM)) + \" \" + uniteMs)\n        self.LE_007_BB_04_Diagonal.setText(str(Around(boundBoxDiag * uniteM)) + \" \" + uniteMs)\n\n        self.displayMatrixMomentOfInertia()\n\n        self.paletteBase()\n\n    def on_PB_05_Help_Forum_clicked(self):# Help Forum\n        self.PB_05_Help_Forum.setStyleSheet(u\"QPushButton {background-color: QPalette.Base}\") #red\n        try:\n            webbrowser.open(__Forum2__)\n        except Exception:\n            self.PB_05_Help_Forum.setStyleSheet(u\"QPushButton {border-width: 2px; border-style: solid; border-color: red}\") #red\n            self.PB_05_Help_Forum.setText(u\"Not access\")\n\n    def on_PB_06_Help_Wiki(self):         # Help Wiki\n        self.PB_06_Help_Wiki.setStyleSheet(u\"QPushButton {background-color: QPalette.Base}\") #red\n        try:\n            webbrowser.open(__Wiki__)\n        except Exception:\n            self.PB_06_Help_Wiki.setStyleSheet(u\"QPushButton {border-width: 2px; border-style: solid; border-color: red}\") #red\n            self.PB_06_Help_Wiki.setText(u\"Not access\")\n\n    #### Spreadsheet debut ################################################################################################\n    def decodeColonne(self, colonne = \"A\"):                                  # converti la chaine A ... ZZ en numero de colonne ex: A = 1; AA = 27\n        colonne  = re.split('[0-9]+', colonne, flags=re.IGNORECASE)[0] # supp the alphanumeric number ex: A2 = A; A12 = A (1A return 0)\n        try:\n            if len(colonne) > 1:\n                return ((ord(colonne[0].upper()) - 64) * 26 ) + (ord(colonne[1].upper()) - 64) # max 2 car (AAAA return 27)\n            else:\n                return (ord(colonne.upper()) - 64 )\n        except Exception:\n            return 0\n\n    def decodeOccupation(self, dataTableau = \"\"):  # decode the max occupation Colonnes, Lines and give the cell occupation\n        #\n        #lineMax, colonneMax, cellsOccupation = decodeOccupation(FreeCAD.ActiveDocument.getObject(str(Sheet.Name)))\n        #\n#        try:\n            tyty = dataTableau.cells.Content\n            tyty = tyty.split(\">\")\n            ####\n            cellsOccupation = [] \n            cellsSorted     = []                                                 # search the \"A1\" definition\n\n            for i in tyty[1:-2]:     \n                i = i[i.find('\"')+1:]                                            # split les cases dans la chaine XML\n                i = i[:i.find('\"')]\n                if (i[0] >= \"A\") and (i[0]<=\"Z\"):                                # doit etre une lettre A a Z ( >= 0.18)\n                    cellsOccupation.append(i)\n            cellsSorted = copy.deepcopy(cellsOccupation)\n            cellsSorted.sort()\n            ####\n            linesMax = 0\n            for i in cellsSorted:                                                # recherche le max (ligne et colonne)\n                colonnesMax = re.split('[0-9]+', i, flags=re.IGNORECASE)         # colonne max (AA)\n                dummy   = int(re.split('[A-Z]+', i, flags=re.IGNORECASE)[1])     # line\n                if dummy > linesMax:\n                    linesMax = dummy                                             # lines max\n            del cellsSorted[:]\n            ####\n            return linesMax, self.decodeColonne(colonnesMax[0]), cellsOccupation      # return linesMax , colonnesMax, cellsOccupation\n#        except Exception:\n#            App_Console_PrintError(\"Error data, Enter object <Sheet object> ex:\")\n#            App_Console_PrintError(\"lineMax, colonneMax, cellsOccupation = decodeOccupation(FreeCAD.ActiveDocument.getObject(str(Sheet.Name)))\")\n#            return 0, 0, []\n\n    def caseTableau(self, ligne = 1, colonne = 1):              # calcule et code la case du tableur ex caseTableau(1, 2) return B1\n        if ligne < 1: ligne = 1\n        if ligne > 16384: ligne = 16384\n        if colonne < 1: colonne = 1\n        if colonne > 702: colonne = 702\n        if (colonne > 26):\n            if abs(colonne % 26) == 0:\n                return chr(64 + (abs(int(colonne / 26)) -1)) + chr(90) + str(ligne)\n            else:\n                return chr(64 + (abs(int(colonne / 26)))) + chr(64 + (abs(colonne % 26))) + str(ligne)\n        else:\n            return chr(colonne + 64) + str(ligne)\n\n    def on_PB_SpreadSheet_clicked(self):\n        global newSpreadSheetName     #; newSpreadSheetName = \"FCSpreadSheet\"\n\n        self.ComboB_SpreadSheet.clear()\n        for i in FreeCAD.ActiveDocument.Objects:    # reload for search all SpreadSheet\n            obj = FreeCAD.ActiveDocument.getObject(i.Name).TypeId.split(\"::\")[0]\n            if obj == \"Spreadsheet\":\n                self.ComboB_SpreadSheet.addItem(_fromUtf8(str(i.Name)))\n        App.activeDocument().recompute(None,True,True)#\n\n    def On_ComboB_SpreadSheet(self, text):\n        global newSpreadSheetName\n\n        newSpreadSheetName = text\n        self.LE_SpreadSheet.setText(newSpreadSheetName)\n\n    def on_LE_SpreadSheet_Pressed(self, text):\n        global newSpreadSheetName\n\n        newSpreadSheetName = text\n        App.activeDocument().recompute(None,True,True)#\n\n    def on_PB_03_Create_SpreadSheet_clicked(self):    # create spreadSheet project\n        global document_\n        global object_Label\n        global object_Name\n        global typeObject\n        global object_Type\n        global subElemName\n        global position0\n        global position1\n        global position2\n        global longueurObjet\n        global rayonObjet\n        global detected\n        global perimetre\n\n        global diffuseColorRF\n        global diffuseColorVF\n        global diffuseColorBF\n        global diffuseColorTF\n\n        global Plan_xy_V\n        global Plan_yz_V\n        global Plan_zx_V\n\n        global surface\n        global surfaceFace\n        global volume_\n        global seTDensiteValue\n        global poids\n        global uniteM\n        global uniteMs\n        global uniteS\n        global uniteSs\n        global uniteV\n        global uniteVs\n        global unitePs\n\n        global boundBoxCenterX\n        global boundBoxCenterY\n        global boundBoxCenterZ\n\n        global CenterOfMassX\n        global CenterOfMassY\n        global CenterOfMassZ\n\n        global boundBoxLX\n        global boundBoxLY\n        global boundBoxLZ\n\n        global Vertx\n        global Edges\n        global EdgesLong\n        global Faces\n        global FacesSurf\n        global FacesCoor\n        global compt_E\n        global compt_F\n        global compt_VF\n        global RowCountTest\n        global path\n        global SaveName\n        global directionObj\n        global direcValueAt\n        global direcNormalAt\n\n        global Matrix_1\n        global Matrix_2\n        global Matrix_3\n\n        global Matrix12\n        global Matrix13\n        global Matrix14\n        global Matrix15\n        global DeterminantM\n\n        global setMomentOfInertia_16\n        global setMomentOfInertiaMassique_17\n        global MatrixOfInertiaRaw\n        global MatrixX1_16\n        global MatrixY1_16\n        global MatrixZ1_16\n        global MatrixX2_16\n        global MatrixY2_16\n        global MatrixZ2_16\n        global MatrixX3_16\n        global MatrixY3_16\n        global MatrixZ3_16\n\n        global MatrixX1_17\n        global MatrixY1_17\n        global MatrixZ1_17\n        global MatrixX2_17\n        global MatrixY2_17\n        global MatrixZ2_17\n        global MatrixX3_17\n        global MatrixY3_17\n        global MatrixZ3_17\n        global typeLongueur\n\n        global nombreArretesMesh\n        global nombreFacesMesh\n        global nombrePointsMesh\n        global colorShapeFaceDiffuseColor\n\n        global BsplineDetect\n        global BsplineNombreDeNoeuds\n        global BsplinePointsCoor\n\n        global seTMaterialCost\n        global seTMaterialPrice\n        global seTMaterialSuffixCost\n        global materialAssociated\n        global seTMaterialCurrentIndex\n        global setPathLatestDirectory\n\n        global newSpreadSheetName\n\n        global TextColorText_R        ; TextColorText_R   = 0.627451  # color red   1 = 255\n        global TextColorText_G        ; TextColorText_G   = 0.627451  # color green 1 = 255\n        global TextColorText_B        ; TextColorText_B   = 0.643137  # color blue  1 = 255\n        global TextColorText_L        ; TextColorText_L   = 1.000000  # color blue  1 = 255\n\n        ligne   = 1\n        colonne = 1\n        tableau = \"\"\n\n        try:\n            tableau = FreeCAD.ActiveDocument.getObjectsByLabel(newSpreadSheetName)[0]        # for append in existant SpreadSheet\n            ligne  = self.decodeOccupation(tableau)[0] + 1\n        except Exception:\n            tableau = App.activeDocument().addObject('Spreadsheet::Sheet',newSpreadSheetName)# for create SpreadSheet\n        self.on_PB_SpreadSheet_clicked()\n\n#        try:\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Information of element\"))\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        tableau.setBackground(self.caseTableau(ligne,colonne+1), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        tableau.setBackground(self.caseTableau(ligne,colonne+2), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"________________________\"))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (dateEu() + \" \"+ heure()))\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Document name\")); tableau.set(self.caseTableau(ligne,colonne+1), document_)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Label of the object\")); tableau.set(self.caseTableau(ligne,colonne+1), object_Label)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Internal name of the object\")); tableau.set(self.caseTableau(ligne,colonne+1), object_Name)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Element name\")); tableau.set(self.caseTableau(ligne,colonne+1), str(subElemName))\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Object Type (Shape)\")); tableau.set(self.caseTableau(ligne,colonne+1), typeObject)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Object Type\")); tableau.set(self.caseTableau(ligne,colonne+1), object_Type)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Mouse coordinates\")); tableau.set(self.caseTableau(ligne,colonne+1), u\"X\"); tableau.set(self.caseTableau(ligne,colonne+2), str(Around(position0 * uniteM))); tableau.set(self.caseTableau(ligne,colonne+3), uniteMs); tableau.set(self.caseTableau(ligne,colonne+4),u\"Y\"); tableau.set(self.caseTableau(ligne,colonne+5), str(Around(position1 * uniteM))); tableau.set(self.caseTableau(ligne,colonne+6), uniteMs); tableau.set(self.caseTableau(ligne,colonne+7), u\"Z\"); tableau.set(self.caseTableau(ligne,colonne+8), str(Around(position2 * uniteM))); tableau.set(self.caseTableau(ligne,colonne+9), uniteMs)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n\n        #### couleurs\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Color on selection\"))\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Red\")); tableau.set(self.caseTableau(ligne,colonne+1), str(int(diffuseColorRF*255.0))); tableau.set(self.caseTableau(ligne,colonne+2),u\"Green\"); tableau.set(self.caseTableau(ligne,colonne+3), str(int(diffuseColorVF*255.0))); tableau.set(self.caseTableau(ligne,colonne+4),u\"Blue\"); tableau.set(self.caseTableau(ligne,colonne+5), str(int(diffuseColorBF*255.0))); tableau.set(self.caseTableau(ligne,colonne+6), u\"Transparency\"); tableau.set(self.caseTableau(ligne,colonne+7), str(int(diffuseColorTF*255.0)))\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n\n        if len(colorShapeFace) != 0:\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Object Color (float) \")); tableau.set(self.caseTableau(ligne,colonne+1), u\"Red\"); tableau.set(self.caseTableau(ligne,colonne+2), str(colorShapeFace[0])); tableau.set(self.caseTableau(ligne,colonne+3), u\"Green\" ); tableau.set(self.caseTableau(ligne,colonne+4), str(colorShapeFace[1])); tableau.set(self.caseTableau(ligne,colonne+5), u\"Blue\"); tableau.set(self.caseTableau(ligne,colonne+6), str(colorShapeFace[2])); tableau.set(self.caseTableau(ligne,colonne+7), u\"Transparency\"); tableau.set(self.caseTableau(ligne,colonne+8), str(colorShapeFace[3]))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Object Color (int  ) \")); tableau.set(self.caseTableau(ligne,colonne+1), u\"Red\"); tableau.set(self.caseTableau(ligne,colonne+2), str(int(colorShapeFace[0]*255.0))); tableau.set(self.caseTableau(ligne,colonne+3), u\"Green\" ); tableau.set(self.caseTableau(ligne,colonne+4), str(int(colorShapeFace[1]*255.0))); tableau.set(self.caseTableau(ligne,colonne+5), u\"Blue\"); tableau.set(self.caseTableau(ligne,colonne+6), str(int(colorShapeFace[2]*255.0))); tableau.set(self.caseTableau(ligne,colonne+7), u\"Transparency\"); tableau.set(self.caseTableau(ligne,colonne+8), str(int(colorShapeFace[3]*255.0)))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n\n        if len(colorShapeLine) != 0:\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Object Color (float) \")); tableau.set(self.caseTableau(ligne,colonne+1), u\"Red\"); tableau.set(self.caseTableau(ligne,colonne+2), str(colorShapeLine[0])); tableau.set(self.caseTableau(ligne,colonne+3), u\"Green\" ); tableau.set(self.caseTableau(ligne,colonne+4), str(colorShapeLine[1])); tableau.set(self.caseTableau(ligne,colonne+5), u\"Blue\"); tableau.set(self.caseTableau(ligne,colonne+6), str(colorShapeLine[2])); tableau.set(self.caseTableau(ligne,colonne+7), u\"Transparency\"); tableau.set(self.caseTableau(ligne,colonne+8), str(colorShapeLine[3]))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Color Line(s) (int  ) \")); tableau.set(self.caseTableau(ligne,colonne+1), u\"Red\"); tableau.set(self.caseTableau(ligne,colonne+2), str(int(colorShapeLine[0]*255.0))); tableau.set(self.caseTableau(ligne,colonne+3), u\"Green\" ); tableau.set(self.caseTableau(ligne,colonne+4), str(int(colorShapeLine[1]*255.0))); tableau.set(self.caseTableau(ligne,colonne+5), u\"Blue\"); tableau.set(self.caseTableau(ligne,colonne+6), str(int(colorShapeLine[2]*255.0))); tableau.set(self.caseTableau(ligne,colonne+7), u\"Transparency\"); tableau.set(self.caseTableau(ligne,colonne+8), str(int(colorShapeLine[3]*255.0)))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n\n        if len(colorShapePoint) != 0:\n            try:\n                tableau.set(self.caseTableau(ligne,colonne), (u\"Color Point(s) (float) \")); tableau.set(self.caseTableau(ligne,colonne+1), u\"Red\"); tableau.set(self.caseTableau(ligne,colonne+2), str(colorShapePoint[0])); tableau.set(self.caseTableau(ligne,colonne+3), u\"Green\" ); tableau.set(self.caseTableau(ligne,colonne+4), str(colorShapePoint[1])); tableau.set(self.caseTableau(ligne,colonne+5), u\"Blue\"); tableau.set(self.caseTableau(ligne,colonne+6), str(colorShapePoint[2])); tableau.set(self.caseTableau(ligne,colonne+7), u\"Transparency\"); tableau.set(self.caseTableau(ligne,colonne+8), str(colorShapePoint[3]))\n                tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                ligne += 1\n                tableau.set(self.caseTableau(ligne,colonne), (u\"Color Point(s) (int  ) \")); tableau.set(self.caseTableau(ligne,colonne+1), u\"Red\"); tableau.set(self.caseTableau(ligne,colonne+2), str(int(colorShapePoint[0]*255.0))); tableau.set(self.caseTableau(ligne,colonne+3), u\"Green\" ); tableau.set(self.caseTableau(ligne,colonne+4), str(int(colorShapePoint[1]*255.0))); tableau.set(self.caseTableau(ligne,colonne+5), u\"Blue\"); tableau.set(self.caseTableau(ligne,colonne+6), str(int(colorShapePoint[2]*255.0))); tableau.set(self.caseTableau(ligne,colonne+7), u\"Transparency\"); tableau.set(self.caseTableau(ligne,colonne+8), str(int(colorShapePoint[3]*255.0)))\n                tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                ligne += 1\n            except Exception:\n                None\n\n        tableau.set(self.caseTableau(ligne,colonne), (typeLongueur)); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(longueurObjet * uniteM))); tableau.set(self.caseTableau(ligne,colonne+2), uniteMs)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n\n        if detected[0:4] == \"Mesh\":\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Components Mesh\"))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\"_______________\"))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Number of Edges\")); tableau.set(self.caseTableau(ligne,colonne+1), str(nombreArretesMesh))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Number of Sides\")); tableau.set(self.caseTableau(ligne,colonne+1), str(nombreFacesMesh))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Number of points\")); tableau.set(self.caseTableau(ligne,colonne+1), str(nombrePointsMesh))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n\n        if detected == \"<PointKernel object>\":\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Components Points\"))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\"_________________\"))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Number of points\")); tableau.set(self.caseTableau(ligne,colonne+1), str(nombrePointsMesh))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n\n       #### detail of Cercle\n        if rayonObjet != 0.0:\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Object radius\")); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(rayonObjet * uniteM))); tableau.set(self.caseTableau(ligne,colonne+2), uniteMs)\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Shape Perimeter\")); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(perimetre * uniteM))); tableau.set(self.caseTableau(ligne,colonne+2), uniteMs)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n\n        if self.GBox_012_SpreadSheet.isChecked():\n            #### detail of Cercle BSpline begin\n            if (str(BsplineDetect) == \"<BSplineCurve object>\"):\n                tableau.set(self.caseTableau(ligne,colonne), (u\"Number of nodes\")); tableau.set(self.caseTableau(ligne,colonne+1), str(BsplineNombreDeNoeuds))\n                tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                ligne += 1\n                for i in enumerate(BsplinePointsCoor):     # nombre de points noeuds\n                    tableau.set(self.caseTableau(ligne,colonne), (u\"Nodes\" + str(i[0]))); tableau.set(self.caseTableau(ligne,colonne+1), u\"X\" + str(i[0] + 1)); tableau.set(self.caseTableau(ligne,colonne+2), str(Around(i[1][0]))); tableau.set(self.caseTableau(ligne,colonne+3), u\"Y\" + str(i[0] + 1)); tableau.set(self.caseTableau(ligne,colonne+4), str(Around(i[1][1]))); tableau.set(self.caseTableau(ligne,colonne+5), u\"Z\" + str(i[0] + 1)); tableau.set(self.caseTableau(ligne,colonne+6), str(Around(i[1][2])))\n                    tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                    ligne += 1\n                ligne += 1\n            #### detail of Cercle BSpline end\n\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Vertexes and details\")); tableau.set(self.caseTableau(ligne,colonne+1), u\" Number of Edges\"); tableau.set(self.caseTableau(ligne,colonne+2), str(compt_E)); tableau.set(self.caseTableau(ligne,colonne+3), u\" Number of Faces\"); tableau.set(self.caseTableau(ligne,colonne+4), str(compt_F)); tableau.set(self.caseTableau(ligne,colonne+5), u\" Number Vertexes faces\"); tableau.set(self.caseTableau(ligne,colonne+6), str(compt_VF)); tableau.set(self.caseTableau(ligne,colonne+7), u\" D\u00e9tail Total\"); tableau.set(self.caseTableau(ligne,colonne+8), str(RowCountTest))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n            co = 0\n            aa = 0\n            for j in enumerate(Edges):\n                tableau.set(self.caseTableau(ligne,colonne), (str(j[1]))); tableau.set(self.caseTableau(ligne,colonne+1), (str(Around(float(EdgesLong[co]) * float(uniteM))))); tableau.set(self.caseTableau(ligne,colonne+2), uniteMs)\n                tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                ligne += 1\n                co+=1\n                for a in range(aa,aa+6):\n                    try:\n                        chaine = str(Vertx[a]).split(\":\")\n                        tableau.set(self.caseTableau(ligne,colonne), (chaine[0])); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(float(chaine[1]) * float(uniteM)))); tableau.set(self.caseTableau(ligne,colonne+2), uniteMs)\n                        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                        ligne += 1\n                    except Exception:\n                        None\n                aa += 6\n                ligne += 1\n            ligne += 1\n            co  = 0\n            cco = 0\n            co2 = 0\n            for j in enumerate(Faces):\n                tableau.set(self.caseTableau(ligne,colonne), str(j[1])); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(float(FacesSurf[co]) * float(uniteS)))); tableau.set(self.caseTableau(ligne,colonne+2), uniteSs)\n                tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                ligne += 1\n                co += 1\n                if len(colorShapeFaceDiffuseColor) != 0:\n                    tableau.set(self.caseTableau(ligne,colonne), (u\"Float color Face\" + str(j[0]+1))); tableau.set(self.caseTableau(ligne,colonne+1), u\"Red\"); tableau.set(self.caseTableau(ligne,colonne+2), str(colorShapeFaceDiffuseColor[j[0]][0])); tableau.set(self.caseTableau(ligne,colonne+3), u\"Green \"); tableau.set(self.caseTableau(ligne,colonne+4), str(colorShapeFaceDiffuseColor[j[0]][1])); tableau.set(self.caseTableau(ligne,colonne+5), u\"Blue \"); tableau.set(self.caseTableau(ligne,colonne+6), str(colorShapeFaceDiffuseColor[j[0]][2])); tableau.set(self.caseTableau(ligne,colonne+7), u\"Transparency\"); tableau.set(self.caseTableau(ligne,colonne+8), str(colorShapeFaceDiffuseColor[j[0]][3]))\n                    tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                    ligne += 1\n                    tableau.set(self.caseTableau(ligne,colonne), (u\"Integer color Face\" + str(j[0]+1))); tableau.set(self.caseTableau(ligne,colonne+1), u\"Red\"); tableau.set(self.caseTableau(ligne,colonne+2), str(int(colorShapeFaceDiffuseColor[j[0]][0]*255.0))); tableau.set(self.caseTableau(ligne,colonne+3), u\"Green \"); tableau.set(self.caseTableau(ligne,colonne+4), str(int(colorShapeFaceDiffuseColor[j[0]][1]*255.0))); tableau.set(self.caseTableau(ligne,colonne+5), u\"Blue \"); tableau.set(self.caseTableau(ligne,colonne+6), str(int(colorShapeFaceDiffuseColor[j[0]][2]*255.0))); tableau.set(self.caseTableau(ligne,colonne+7), u\"Transparency\"); tableau.set(self.caseTableau(ligne,colonne+8), str(int(colorShapeFaceDiffuseColor[j[0]][3]*255.0)))\n                    tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                    ligne += 1\n\n                for jj in range(cco,len(FacesCoor)):# Faces coordinates\n                    cco+=1\n                    if FacesCoor[jj] == \"T\":\n                        ligne += 1\n                        break\n                    else:\n                        chaine = str(FacesCoor[jj]).split(\":\")\n                        tableau.set(self.caseTableau(ligne,colonne), (chaine[0])); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(float(chaine[1]) * float(uniteM)))); tableau.set(self.caseTableau(ligne,colonne+2), uniteMs)\n                        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                        ligne += 1\n                        co2 += 1\n                        if co2 == 3:\n                            ligne += 1\n                            co2 = 0\n\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Plane\")); tableau.set(self.caseTableau(ligne,colonne+1), u\" XY:\"); tableau.set(self.caseTableau(ligne,colonne+2), self.LE_8xy.text()); tableau.set(self.caseTableau(ligne,colonne+3), u\" coordinates:\"); tableau.set(self.caseTableau(ligne,colonne+4), str(Plan_xy_V))\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Plane\")); tableau.set(self.caseTableau(ligne,colonne+1), u\" YZ:\"); tableau.set(self.caseTableau(ligne,colonne+2), self.LE_8yz.text()); tableau.set(self.caseTableau(ligne,colonne+3), u\" coordinates:\"); tableau.set(self.caseTableau(ligne,colonne+4), str(Plan_yz_V))\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Plane\")); tableau.set(self.caseTableau(ligne,colonne+1), u\" ZX:\"); tableau.set(self.caseTableau(ligne,colonne+2), self.LE_8zx.text()); tableau.set(self.caseTableau(ligne,colonne+3), u\" coordinates:\"); tableau.set(self.caseTableau(ligne,colonne+4), str(Plan_zx_V))\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Shape area\")); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(surface * uniteS))); tableau.set(self.caseTableau(ligne,colonne+2), uniteSs)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Face area\")); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(surfaceFace * uniteS))); tableau.set(self.caseTableau(ligne,colonne+2), uniteSs)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Volume of the form\")); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(volume_ * uniteV))); tableau.set(self.caseTableau(ligne,colonne+2), uniteVs)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Mass\")); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(poids))); tableau.set(self.caseTableau(ligne,colonne+2), unitePs); tableau.set(self.caseTableau(ligne,colonne+3), u\" Density:\"); tableau.set(self.caseTableau(ligne,colonne+4), str(Around(seTDensiteValue)))\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Shape center\")); tableau.set(self.caseTableau(ligne,colonne+1), u\" X:\"); tableau.set(self.caseTableau(ligne,colonne+2), str(Around(boundBoxCenterX * uniteM))); tableau.set(self.caseTableau(ligne,colonne+3), uniteMs); tableau.set(self.caseTableau(ligne,colonne+4), u\" Y:\"); tableau.set(self.caseTableau(ligne,colonne+5), str(Around(boundBoxCenterY * uniteM))); tableau.set(self.caseTableau(ligne,colonne+6), uniteMs); tableau.set(self.caseTableau(ligne,colonne+7), u\" Z:\"); tableau.set(self.caseTableau(ligne,colonne+8), str(Around(boundBoxCenterZ * uniteM))); tableau.set(self.caseTableau(ligne,colonne+9), uniteMs)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Center of mass\")); tableau.set(self.caseTableau(ligne,colonne+1), u\" X:\"); tableau.set(self.caseTableau(ligne,colonne+2), str(Around(CenterOfMassX   * uniteM))); tableau.set(self.caseTableau(ligne,colonne+3), uniteMs); tableau.set(self.caseTableau(ligne,colonne+4), u\" Y:\"); tableau.set(self.caseTableau(ligne,colonne+5), str(Around(CenterOfMassY * uniteM))); tableau.set(self.caseTableau(ligne,colonne+6), uniteMs); tableau.set(self.caseTableau(ligne,colonne+7), u\" Z:\"); tableau.set(self.caseTableau(ligne,colonne+8), str(Around(CenterOfMassZ   * uniteM))); tableau.set(self.caseTableau(ligne,colonne+9), uniteMs)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Overall dimensions\")); tableau.set(self.caseTableau(ligne,colonne+1), u\" X:\"); tableau.set(self.caseTableau(ligne,colonne+2), str(Around(boundBoxLX      * uniteM))); tableau.set(self.caseTableau(ligne,colonne+3), uniteMs); tableau.set(self.caseTableau(ligne,colonne+4), u\" Y:\"); tableau.set(self.caseTableau(ligne,colonne+5), str(Around(boundBoxLY      * uniteM))); tableau.set(self.caseTableau(ligne,colonne+6), uniteMs); tableau.set(self.caseTableau(ligne,colonne+7), u\" Z:\"); tableau.set(self.caseTableau(ligne,colonne+8), str(Around(boundBoxLZ      * uniteM))); tableau.set(self.caseTableau(ligne,colonne+9), uniteMs)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Diagonal dimensions\")); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(boundBoxDiag * uniteM))); tableau.set(self.caseTableau(ligne,colonne+2), uniteMs)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n\n        if directionObj != \"[]\":\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Direction\")); tableau.set(self.caseTableau(ligne,colonne+1), u\" X:\"); tableau.set(self.caseTableau(ligne,colonne+2), str(Around(directionObj[0]))); tableau.set(self.caseTableau(ligne,colonne+3), u\" Y:\"); tableau.set(self.caseTableau(ligne,colonne+4), str(Around(directionObj[1]))); tableau.set(self.caseTableau(ligne,colonne+5), u\" Z:\"); tableau.set(self.caseTableau(ligne,colonne+6), str(Around(directionObj[2])))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n        if direcValueAt != \"[]\":\n            tableau.set(self.caseTableau(ligne,colonne), (u\"ValueAt\")); tableau.set(self.caseTableau(ligne,colonne+1), u\" X:\"); tableau.set(self.caseTableau(ligne,colonne+2), str(Around(direcValueAt[0]))); tableau.set(self.caseTableau(ligne,colonne+3), u\" Y:\"); tableau.set(self.caseTableau(ligne,colonne+4), str(Around(direcValueAt[1]))); tableau.set(self.caseTableau(ligne,colonne+5), u\" Z:\"); tableau.set(self.caseTableau(ligne,colonne+6), str(Around(direcValueAt[2])))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n        if direcNormalAt != \"[]\":\n            tableau.set(self.caseTableau(ligne,colonne), (u\"NormalAt\")); tableau.set(self.caseTableau(ligne,colonne+1), u\" X:\"); tableau.set(self.caseTableau(ligne,colonne+2), str(Around(direcNormalAt[0]))); tableau.set(self.caseTableau(ligne,colonne+3), u\" Y:\"); tableau.set(self.caseTableau(ligne,colonne+4), str(Around(direcNormalAt[1]))); tableau.set(self.caseTableau(ligne,colonne+5), u\" Z:\"); tableau.set(self.caseTableau(ligne,colonne+6), str(Around(direcNormalAt[2])))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n        ligne += 1\n\n        if detected[0:4] == \"Mesh\":\n            None\n        else:\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Matrix of inertia\")); tableau.set(self.caseTableau(ligne,colonne+1),  uniteMs + \"^\" + str(setMomentOfInertia_16))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\" Raw:\")); tableau.set(self.caseTableau(ligne,colonne+1), str(MatrixOfInertiaRaw))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\" X:\")); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(MatrixX1_16))); tableau.set(self.caseTableau(ligne,colonne+2), u\" Y:\"); tableau.set(self.caseTableau(ligne,colonne+3), str(Around(MatrixY1_16))); tableau.set(self.caseTableau(ligne,colonne+4), u\" Z:\"); tableau.set(self.caseTableau(ligne,colonne+5), str(Around(MatrixZ1_16))); tableau.set(self.caseTableau(ligne,colonne+6), u\" :\"); tableau.set(self.caseTableau(ligne,colonne+7), str(Around(Matrix_1)))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\" X:\")); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(MatrixX2_16))); tableau.set(self.caseTableau(ligne,colonne+2), u\" Y:\"); tableau.set(self.caseTableau(ligne,colonne+3), str(Around(MatrixY2_16))); tableau.set(self.caseTableau(ligne,colonne+4), u\" Z:\"); tableau.set(self.caseTableau(ligne,colonne+5), str(Around(MatrixZ2_16))); tableau.set(self.caseTableau(ligne,colonne+6), u\" :\"); tableau.set(self.caseTableau(ligne,colonne+7), str(Around(Matrix_2)))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\" X:\")); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(MatrixX3_16))); tableau.set(self.caseTableau(ligne,colonne+2), u\" Y:\"); tableau.set(self.caseTableau(ligne,colonne+3), str(Around(MatrixY3_16))); tableau.set(self.caseTableau(ligne,colonne+4), u\" Z:\"); tableau.set(self.caseTableau(ligne,colonne+5), str(Around(MatrixZ3_16))); tableau.set(self.caseTableau(ligne,colonne+6), u\" :\"); tableau.set(self.caseTableau(ligne,colonne+7), str(Around(Matrix_3)))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\" X:\")); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(Matrix12))); tableau.set(self.caseTableau(ligne,colonne+2), u\" Y:\"); tableau.set(self.caseTableau(ligne,colonne+3), str(Around(Matrix13))); tableau.set(self.caseTableau(ligne,colonne+4), u\" Z:\"); tableau.set(self.caseTableau(ligne,colonne+5), str(Around(Matrix14))); tableau.set(self.caseTableau(ligne,colonne+6), u\" :\"); tableau.set(self.caseTableau(ligne,colonne+7), str(Around(Matrix15)))\n            ligne += 1\n\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Matrix inertia massique\")); tableau.set(self.caseTableau(ligne,colonne+1), unitePs + uniteSs + \"^\" + str(setMomentOfInertiaMassique_17))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\" X:\")); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(MatrixX1_17))); tableau.set(self.caseTableau(ligne,colonne+2), u\" Y:\"); tableau.set(self.caseTableau(ligne,colonne+3), str(Around(MatrixY1_17))); tableau.set(self.caseTableau(ligne,colonne+4), u\" Z:\"); tableau.set(self.caseTableau(ligne,colonne+5), str(Around(MatrixZ1_17)))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\" X:\")); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(MatrixX2_17))); tableau.set(self.caseTableau(ligne,colonne+2), u\" Y:\"); tableau.set(self.caseTableau(ligne,colonne+3), str(Around(MatrixY2_17))); tableau.set(self.caseTableau(ligne,colonne+4), u\" Z:\"); tableau.set(self.caseTableau(ligne,colonne+5), str(Around(MatrixZ2_17)))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\" X:\")); tableau.set(self.caseTableau(ligne,colonne+1), str(Around(MatrixX3_17))); tableau.set(self.caseTableau(ligne,colonne+2), u\" Y:\"); tableau.set(self.caseTableau(ligne,colonne+3), str(Around(MatrixY3_17))); tableau.set(self.caseTableau(ligne,colonne+4), u\" Z:\"); tableau.set(self.caseTableau(ligne,colonne+5), str(Around(MatrixZ3_17)))\n            ligne += 1\n\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Matrix Determinant\")); tableau.set(self.caseTableau(ligne,colonne+1), str(DeterminantM))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n            tableau.set(self.caseTableau(ligne,colonne), (u\"Decimal Determinant\")); tableau.set(self.caseTableau(ligne,colonne+1), str(decimal.Decimal(DeterminantM)))\n            tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n            ligne += 1\n\n        materiel = materialAssociated[seTMaterialCurrentIndex].rstrip().split(\",\")\n        nomMateriel     = materiel[0]\n        densitexMateriel= str(Around(float(materiel[1])))\n        prixMateriel    = str(Around(float(materiel[2])))\n        infoMateriel    = materiel[3]\n\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Material\"))\n        tableau.setBackground(self.caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (u\"Name\")); tableau.set(self.caseTableau(ligne,colonne+1), u\"Density\"); tableau.set(self.caseTableau(ligne,colonne+2), u\"Volume\"); tableau.set(self.caseTableau(ligne,colonne+3), u\"Unit\"); tableau.set(self.caseTableau(ligne,colonne+4), u\"Price (kg/dm3)\"); tableau.set(self.caseTableau(ligne,colonne+5), u\"Total cost\"); tableau.set(self.caseTableau(ligne,colonne+6), u\"Devise\"); tableau.set(self.caseTableau(ligne,colonne+7), u\"Info\")\n        tableau.setBackground(self.caseTableau(ligne,colonne)  , (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        tableau.setBackground(self.caseTableau(ligne,colonne+1), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        tableau.setBackground(self.caseTableau(ligne,colonne+2), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        tableau.setBackground(self.caseTableau(ligne,colonne+3), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        tableau.setBackground(self.caseTableau(ligne,colonne+4), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        tableau.setBackground(self.caseTableau(ligne,colonne+5), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        tableau.setBackground(self.caseTableau(ligne,colonne+6), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        tableau.setBackground(self.caseTableau(ligne,colonne+7), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n        ligne += 1\n        tableau.set(self.caseTableau(ligne,colonne), (nomMateriel)); tableau.set(self.caseTableau(ligne,colonne+1), densitexMateriel); tableau.set(self.caseTableau(ligne,colonne+2), str(Around(volume_ * uniteV))); tableau.set(self.caseTableau(ligne,colonne+3), uniteVs); tableau.set(self.caseTableau(ligne,colonne+4), prixMateriel); tableau.set(self.caseTableau(ligne,colonne+5), str(Around(seTMaterialCost))); tableau.set(self.caseTableau(ligne,colonne+6), seTMaterialSuffixCost); tableau.set(self.caseTableau(ligne,colonne+7), infoMateriel)\n        ligne += 1\n\n        tableau.set(self.caseTableau(ligne,colonne), (u\"End \")); tableau.set(self.caseTableau(ligne,colonne+1), document_); tableau.set(self.caseTableau(ligne,colonne+2), object_Label)\n        tableau.setBackground(self.caseTableau(ligne,colonne), (0.9372549019607843, 0.1607843137254902, 0.1607843137254902, TextColorText_L))\n        tableau.setBackground(self.caseTableau(ligne,colonne+1), (0.9372549019607843, 0.1607843137254902, 0.1607843137254902, TextColorText_L))\n        tableau.setBackground(self.caseTableau(ligne,colonne+2), (0.9372549019607843, 0.1607843137254902, 0.1607843137254902, TextColorText_L))\n        ligne += 1\n        tableau.recompute()\n\n#         except Exception:\n#             App_Console_PrintMessage(u\"Erreur d'enregistrement du fichier \" + SaveName)\n#             errorDialog(u\"Erreur d'enregistrement du fichier \" + SaveName)\n    #### Spreadsheet Fin ################################################################################################\n\n    def on_PB_04_Quit(self):              # Exit button\n        global path\n        global infoFaceMesh\n        global switchNotInfoOnBeginning\n        global switchVersionSearch\n        global switchWarning\n        global switchCreatePoint\n        global switchCreateAxis\n        global switchCreatePlane\n        global switchDisplayInfoObject\n        global switchClearDisplayReportView\n        global seTWidgetPosition\n        global switchBoundBoxCreateText\n        global seTBoundBoxTextHeigth\n        global seTBoundBoxTextArround\n        global seTMemoClipBoard\n        global seTTextHeigthValue\n        global seTDecimalValue\n        global seTMaterialCurrentIndex\n        global seTMaterialFileName\n        global seTMaterialSavePathName\n        global seTDensiteValue\n        global seTDensiteDecimalNumber\n        global seTDensiteSingleStep\n        global seTDensiteSuffixChain\n        global seTPositionFlyRightLeft\n        global materialAssociated\n        global seTMaterialPrice\n        global seTMaterialSuffixDevise\n        global seTMaterialSuffixCost\n        global seTMaterialCost\n        global seTIndexUnitWeight\n        global seTIndexUnitLength\n        global seTUnitSymbolMicro\n        global seTUnitSymbolCube\n        global seTUnitSymbolCarre\n        global setPathLatestDirectory\n        global setMeshTopologyValue\n        global setBSplineToByArcValue\n        global switchBSplineCreateCircleConstructorAxis\n        global switchBSplineCreateCircleConstructor\n        global switchCreateLineDiVatNatOnClick\n        global FreeCAD_ParamGetSet\n\n        #### Write Configuration begin ####\n        FreeCAD_ParamGetSet.SetBool(u\"switchNotInfoOnBeginning\", switchNotInfoOnBeginning)  # True or False\n        FreeCAD_ParamGetSet.SetBool(u\"switchVersionSearch\", switchVersionSearch)            # True or False\n        FreeCAD_ParamGetSet.SetBool(u\"switchWarning\", switchWarning)                        # True or False\n        FreeCAD_ParamGetSet.SetBool(u\"switchCreatePoint\", switchCreatePoint)                # True or False\n        FreeCAD_ParamGetSet.SetBool(u\"switchCreateAxis\", switchCreateAxis)                  # True or False\n        FreeCAD_ParamGetSet.SetBool(u\"switchCreatePlane\", switchCreatePlane)                # True or False\n        FreeCAD_ParamGetSet.SetBool(u\"switchDisplayInfoObject\", switchDisplayInfoObject)    # True or False\n        FreeCAD_ParamGetSet.SetBool(u\"switchClearDisplayReportView\", switchClearDisplayReportView)#*True or False\n        FreeCAD_ParamGetSet.SetBool(u\"seTWidgetPosition\", seTWidgetPosition)                # True or False\n        FreeCAD_ParamGetSet.SetBool(u\"switchBoundBoxCreateText\", switchBoundBoxCreateText)  # True or False\n        FreeCAD_ParamGetSet.SetFloat(u\"seTBoundBoxTextHeigth\", seTBoundBoxTextHeigth)       # 3.0\n        FreeCAD_ParamGetSet.SetInt(u\"seTBoundBoxTextArround\", seTBoundBoxTextArround)       # 3\n        FreeCAD_ParamGetSet.SetInt(u\"seTMemoClipBoard\", seTMemoClipBoard)                   # 0, 1, 2\n        FreeCAD_ParamGetSet.SetInt(u\"seTTextHeigthValue\", seTTextHeigthValue)               # 11\n        FreeCAD_ParamGetSet.SetInt(u\"seTDecimalValue\", seTDecimalValue)                     # 4\n        FreeCAD_ParamGetSet.SetInt(u\"seTMaterialCurrentIndex\", seTMaterialCurrentIndex)     # 0\n        FreeCAD_ParamGetSet.SetString(u\"seTMaterialFileName\", seTMaterialFileName)          # \"FCInfo_material.txt\"\n        FreeCAD_ParamGetSet.SetString(u\"seTMaterialSavePathName\", seTMaterialSavePathName)  # \"C:/.../Macro/FCInfo_material.txt\"\n        FreeCAD_ParamGetSet.SetFloat(u\"seTMaterialPrice\", seTMaterialPrice)                 # x\n        FreeCAD_ParamGetSet.SetString(u\"seTMaterialSuffixDevise\", seTMaterialSuffixDevise)  # \" Eu (By Kg)# Suffix device\n        FreeCAD_ParamGetSet.SetString(u\"seTMaterialSuffixCost\", seTMaterialSuffixCost)      # \" Eu # Suffix cost\n        FreeCAD_ParamGetSet.SetFloat(u\"seTMaterialCost\", seTMaterialCost)                   # x\n        FreeCAD_ParamGetSet.SetFloat(u\"seTDensiteValue\", seTDensiteValue)                   # 1.0\n        FreeCAD_ParamGetSet.SetInt(u\"seTDensiteDecimalNumber\", seTDensiteDecimalNumber)     # 4\n        FreeCAD_ParamGetSet.SetFloat(u\"seTDensiteSingleStep\", seTDensiteSingleStep)         # 1.0\n        FreeCAD_ParamGetSet.SetString(u\"seTDensiteSuffixChain\", seTDensiteSuffixChain)      # \" kg (by dm3)\"\n        FreeCAD_ParamGetSet.SetInt(u\"seTPositionFlyRightLeft\", seTPositionFlyRightLeft)     # 1, 2, other\n        #FreeCAD_ParamGetSet.SetInt(u\"seTIndexUnitWeight\", seTIndexUnitWeight)               # x\n        #FreeCAD_ParamGetSet.SetInt(u\"seTIndexUnitLength\", seTIndexUnitLength)               # x\n        FreeCAD_ParamGetSet.SetString(u\"seTUnitSymbolMicro\", seTUnitSymbolMicro)            # \"U\"\n        FreeCAD_ParamGetSet.SetString(u\"seTUnitSymbolCube\", seTUnitSymbolCube)              # \"3\"\n        FreeCAD_ParamGetSet.SetString(u\"seTUnitSymbolCarre\", seTUnitSymbolCarre)            # \"2\"\n        FreeCAD_ParamGetSet.SetFloat(u\"setBSplineToByArcValue\", setBSplineToByArcValue)     # 0.00001\n        FreeCAD_ParamGetSet.SetFloat(u\"setMeshTopologyValue\", setMeshTopologyValue)         # 0.1\n        FreeCAD_ParamGetSet.SetBool(u\"switchBSplineCreateCircleConstructorAxis\", switchBSplineCreateCircleConstructorAxis)# True or False\n        FreeCAD_ParamGetSet.SetBool(u\"switchBSplineCreateCircleConstructor\", switchBSplineCreateCircleConstructor)        # True or False\n        FreeCAD_ParamGetSet.SetBool(u\"switchCreateLineDiVatNatOnClick\", switchCreateLineDiVatNatOnClick)                  # True or False\n        #### Write Configuration end ####\n\n        #### save the material begin ####\n        self.on_PB_Save_Material_clicked()    # save material\n        #### save the material end ####\n\n        App_Console_PrintMessage(u\"End FCInfo\\r\\n\")\n        try:\n            Gui.ActiveDocument.ActiveView.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), infoFaceMesh)\n        except Exception:\n            None\n        FreeCADGui.Selection.removeObserver(s)   # Uninstalls resident function (desactivated for read after LeftDock RightDock)\n\n        try:\n            self.window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)    # destroy\n            self.window.deleteLater()                                     # destroy\n            self.window.destroy()                                         # destroy\n        except Exception:\n            self.window.hide()\n            None\n\n#########################################################################################################################\n\nclass SelObserver:\n    def addSelection(self,document, object, element, position):  # Selection\n        global ui\n        global sel\n        global document_\n        global object_Label\n        global subElemName\n        global position0\n        global position1\n        global position2\n        global switchInertia\n        global infoFaceMesh\n        global switch_setVisible_GBox_001_Document          #\n        global switch_setVisible_GBox_002_Coordinate_Mouse  #\n        global switch_setVisible_GBox_003_Color\n        global switch_setVisible_GBox_004_Object_Mesh\n        global switch_setVisible_GBox_005_Value_Unit\n        global switch_setVisible_GBox_006_Inclination\n        global switch_setVisible_GBox_007_Surface_and_Volume\n        global switch_setVisible_GBox_008_Cost_And_Price\n        global switch_setVisible_GBox_009_BoundBox\n        global switch_setVisible_GBox_010_Center_Mass\n        global switch_setVisible_GBox_011_Inertia\n        global switch_setVisible_GBox_012_SpreadSheet\n        global switch_setVisible_GBox_013_SpreadSheet_Creation\n        global switch_setVisible_GBox_014_Main_Tools        #\n\n        if switchInertia == 0:    # for create plane without refresh\n            sel = FreeCADGui.Selection.getSelection()\n            document_    = document\n            object_Label = object\n            subElemName  = element\n\n            position0 = (position[0])\n            position1 = (position[1])\n            position2 = (position[2])\n\n            if len(sel)==0:\n                App_Console_PrintMessage(u\"Select an object\" + \"\\n\")\n                errorDialog(u\"Select an object\")\n            else:\n#                ui.on_PB_01_Refrech_clicked()\n\n                ####Special_Sketcher\n                try:\n                    sketch  = Gui.Selection.getSelection()[0]\n                except Exception: None \n                #print(sketch.TypeId)\n                App.ActiveDocument.recompute()\n                if (Gui.ActiveDocument.getInEdit() and (sketch.TypeId == \"Sketcher::SketchObject\")): # sketcher open\n                    ui.LE_5.setStyleSheet(u\"QLineEdit {color : QPalette.Base}\")    # origin system\n                    nameSketch = sketch.Name\n                    ui.GBox_004_Object_Mesh.setVisible(False)\n                    ui.GBox_003_Color.setEnabled(False)\n                    ui.GBox_012_SpreadSheet.setEnabled(False)\n                    ui.GBox_007_Surface_and_Volume.setEnabled(False)\n                    ui.GBox_008_Cost_And_Price.setEnabled(False)\n                    ui.GBox_009_BoundBox.setEnabled(False)\n                    ui.GBox_010_Center_Mass.setEnabled(False)\n                    ui.GBox_011_Inertia.setEnabled(False)\n                    ui.GBox_013_SpreadSheet_Creation.setEnabled(False)\n                    if \"Constraint\" in subElemName:\n                        ui.LE_5.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: red}\")  # constraint\n                    else:\n                        try:\n                            indexSubObject = int(subElemName[4:]) - 1        # index\n                            if App.ActiveDocument.getObject(nameSketch).getConstruction(indexSubObject):\n                                ui.LE_5.setStyleSheet(u\"QLineEdit {border-width: 2px; border-style: solid; border-color: blue}\") # construction\n                        except Exception:\n                            None\n\n                elif sketch.TypeId == \"Mesh::Feature\":              # Mesh\n                    #infoFaceMesh = Gui.ActiveDocument.ActiveView.addEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), getNormal)\n#                    ui.on_ZeroInfo()\n                    if switch_setVisible_GBox_004_Object_Mesh == True:\n                        ui.GBox_004_Object_Mesh.setVisible(True)\n                        ui.LA_N_Edges.setEnabled(True)\n                        ui.LA_N_Facets.setEnabled(True)\n                        ui.LE_N_Edges.setEnabled(True)\n                        ui.LE_N_Facets.setEnabled(True)\n\n                    if switch_setVisible_GBox_005_Value_Unit == True:\n                        ui.GBox_005_Value_Unit.setVisible(True)\n                    if switch_setVisible_GBox_006_Inclination == True:\n                        ui.GBox_006_Inclination.setVisible(True)\n                    if switch_setVisible_GBox_007_Surface_and_Volume == True:\n                        ui.GBox_007_Surface_and_Volume.setVisible(True)\n                    if switch_setVisible_GBox_008_Cost_And_Price == True:\n                        ui.GBox_008_Cost_And_Price.setVisible(True)\n                    if switch_setVisible_GBox_009_BoundBox == True:\n                        ui.GBox_009_BoundBox.setVisible(True)\n                    if switch_setVisible_GBox_010_Center_Mass == True:\n                        ui.GBox_010_Center_Mass.setVisible(True)\n                        ui.LE_14x.setEnabled(True)\n                        ui.LE_14y.setEnabled(True)\n                        ui.LE_14z.setEnabled(True)\n                    if switch_setVisible_GBox_011_Inertia == True:\n                        ui.GBox_011_Inertia.setVisible(False)\n                    if switch_setVisible_GBox_012_SpreadSheet == True:\n                        ui.GBox_012_SpreadSheet.setVisible(False)\n                    #ui.GBox_013_SpreadSheet_Creation.setEnabled(False)\n                    ui.on_ZeroInfo()\n                elif sketch.TypeId == \"Points::FeatureCustom\":      # Points\n                    if switch_setVisible_GBox_004_Object_Mesh == True:\n                        ui.GBox_004_Object_Mesh.setVisible(True)\n                    ui.LA_N_Edges.setEnabled(False)\n                    ui.LA_N_Facets.setEnabled(False)\n                    ui.LE_N_Edges.setEnabled(False)\n                    ui.LE_N_Facets.setEnabled(False)\n\n                    ui.GBox_005_Value_Unit.setVisible(False)\n                    ui.GBox_006_Inclination.setVisible(False)\n                    ui.GBox_007_Surface_and_Volume.setVisible(False)\n                    ui.GBox_008_Cost_And_Price.setVisible(False)\n                    ui.GBox_011_Inertia.setVisible(False)\n                    ui.GBox_012_SpreadSheet.setVisible(False)\n                    ui.GBox_013_SpreadSheet_Creation.setVisible(False)\n\n                    ui.LE_14x.setEnabled(False)\n                    ui.LE_14y.setEnabled(False)\n                    ui.LE_14z.setEnabled(False)\n                    ui.on_ZeroInfo()\n                else:\n                    if switch_setVisible_GBox_003_Color == True:\n                        ui.GBox_003_Color.setVisible(True)\n                        ui.GBox_003_Color.setEnabled(True)\n                    ui.GBox_004_Object_Mesh.setVisible(False)\n                    if switch_setVisible_GBox_005_Value_Unit == True:\n                        ui.GBox_005_Value_Unit.setVisible(True)\n                        ui.GBox_005_Value_Unit.setEnabled(True)\n                        ui.LE_5.setStyleSheet(u\"QLineEdit {color : QPalette.Base}\")    # origin system\n                    if switch_setVisible_GBox_006_Inclination == True:\n                        ui.GBox_006_Inclination.setVisible(True)\n                        ui.GBox_006_Inclination.setEnabled(True)\n                    if switch_setVisible_GBox_007_Surface_and_Volume == True:\n                        ui.GBox_007_Surface_and_Volume.setVisible(True)\n                        ui.GBox_007_Surface_and_Volume.setEnabled(True)\n                    if switch_setVisible_GBox_008_Cost_And_Price == True:\n                        ui.GBox_008_Cost_And_Price.setVisible(True)\n                        ui.GBox_008_Cost_And_Price.setEnabled(True)\n                    if switch_setVisible_GBox_009_BoundBox == True:\n                        ui.GBox_009_BoundBox.setVisible(True)\n                        ui.GBox_009_BoundBox.setEnabled(True)\n                    if switch_setVisible_GBox_010_Center_Mass == True:\n                        ui.GBox_010_Center_Mass.setVisible(True)\n                        ui.GBox_010_Center_Mass.setEnabled(True)\n                        ui.LE_14x.setEnabled(True)\n                        ui.LE_14x.setEnabled(True)\n                        ui.LE_14y.setEnabled(True)\n                        ui.LE_14y.setEnabled(True)\n                        ui.LE_14z.setEnabled(True)\n                        ui.LE_14z.setEnabled(True)\n                    if switch_setVisible_GBox_011_Inertia == True:\n                        ui.GBox_011_Inertia.setVisible(True)\n                        ui.GBox_011_Inertia.setEnabled(True)\n                    if switch_setVisible_GBox_012_SpreadSheet == True:\n                        try:\n                            ui.GBox_012_SpreadSheet.setVisible(True)\n                            ui.GBox_012_SpreadSheet.setEnabled(True)\n                        except Exception:\n                            None\n                    if switch_setVisible_GBox_013_SpreadSheet_Creation == True:\n                        ui.GBox_013_SpreadSheet_Creation.setVisible(True)\n                        ui.GBox_013_SpreadSheet_Creation.setEnabled(True)\n                ####SpecialSketcher\n                ui.on_PB_01_Refrech_clicked()\n        else:\n            ui.GBox_012_SpreadSheet\n            ui.GBox_012_SpreadSheet.setTitle(u\"Details of the form\")\n            ####SpecialSketcher\n\n##########################################################################################################################\nif switchNotInfoOnBeginning == 0: # 0 =display the info\n    App_Console_PrintMessage(u\"____________________________________\" + \"\\n\")\n    App_Console_PrintMessage(u\"#### FCInfo Configuration begin ####\" + \"\\n\")\n    App_Console_PrintMessage(u\"####\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"**** Location ****\" + \"\\n\")\n    App_Console_PrintMessage(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/FCInfo/\" + \"\\n\")\n    App_Console_PrintMessage(u\"####\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"switchNotInfoOnBeginning   # SetBool True or [False]\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Display or not this text information on run macro\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\\t\" + \"[False] = display this information\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\\t\" + \" True   = this Information is Not displayed On Beginning\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"switchVersionSearch        # SetBool True or [False]\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Search if one new version exist on run macro\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"switchWarning              # SetBool True or [False]\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Display or not display the window warning in case not good selection\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"switchCreatePoint          # SetBool True or [False]\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Check the Create point checkBox\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"switchCreateAxis           # SetBool True or [False]\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Check the Create axis checkBox\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"switchCreatePlane          # SetBool True or [False]\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Check the Create plane checkBox\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"switchDisplayInfoObject    # SetBool True or [False]\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Check the info checkBox\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"switchClearDisplayReportView# SetBool True or [False]\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"if switchClearDisplayReportView is TRUE the ReportView is cleared\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTWidgetPosition          # SetBool True or [False]\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Check the Widget Position Left/Right checkBox\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"if seTWidgetPosition [False] : if seTPositionFlyRightLeft = 2 = docked to Right\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"if seTWidgetPosition  True   : if seTPositionFlyRightLeft = 3 = docked to Left\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"if it is 1 the window macro is not docked\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"switchBoundBoxCreateText   # SetBool True or [False]\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Create the text dimension of the BoundBox\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTBoundBoxTextHeigth      # seTBoundBoxTextHeigth      = 3.0\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Give the Heigth of the text dimension (independent of the seTTextHeigthValue)\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTBoundBoxTextArround     # seTBoundBoxTextArround     = 3\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Give the arround of the text dimensions (independent of the seTDecimalValue)\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTMemoClipBoard           # SetInt [0], 1, 2, 3\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Give one value [0], 1, 2, 3 clipBoard\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\\t\" + \"[0] = desactivate the clipBoard\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\\t\" + \" 1 = the data string is memorised to : FreeCAD.Vector( X, Y, Z )\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\\t\" + \" 2 = the data string is memorised to : X, Y, Z\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\\t\" + \" 3 = the data string is memorised to : X Y Z\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTTextHeigthValue         # SetInt 11\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Give one text heigth value of the macro\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTDecimalValue            # SetInt 4\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Give the number of decimal displayed\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"If the number is -1 the total decimal value is displayed)\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTMaterialCurrentIndex    # SetInt 0\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Set the index of the ComboBox\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTMaterialFileName        # SetString FCInfo_material.txt\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Name of the material file\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTMaterialSavePathName    # SetString C:/.../Macro/FCInfo_material.txt\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Path name of the material file\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTMaterialPrice           # SetFloat\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Material price by Kg \" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTMaterialSuffixDevise    # SetString\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Devise money\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTMaterialSuffixCost      # seTMaterialSuffixCost\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Suffix Devise cost\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTMaterialCost            # SetFloat\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Material cost\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTDensiteValue            # SetFloat 1.0\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Give the densite value\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTDensiteDecimalNumber    # SetInt 4\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Give the number of decimal for the densite value\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTDensiteSingleStep       # SetFloat 1.0\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Give the step for one click, by default 1.0 (possible 0.01 or ...)\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTDensiteSuffixChain      # SetString  kg (by dm3)\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Choice your suffix string\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTPositionFlyRightLeft    # SetInt 2\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Choice your position, Fly, [Right], Left\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\\t\" + \" 1  = the macro window is fly (not docked)\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\\t\" + \"[2] = the macro window is positionned to Right\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\\t\" + \" 3 or other = the macro window is positionned to Left\" + \"\\n\")\n    App_Console_PrintMessage(u\"seTIndexUnitWeight         # SetInt\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Set unit Mass index\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTUnitSymbolMicro         # U\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Set Symbol Micro\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTUnitSymbolCube          # 3\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Set Symbol Cube\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTUnitSymbolCarre         # 2\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Set Symbol Square\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"seTIndexUnitLength         # SetInt\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Set unit Length index\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"setBSplineToByArcValue     # SetFloat 0.00001\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Set unit for cut the BSpline for seack the radius on point given\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"setMeshTopologyValue       # SetFloat 0.1\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Set unit for create the Mesh to Shape\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"switchBSplineCreateCircleConstructorAxis  #SetBool  True or [False]\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Display the axis of the circles (arcs) for create the BSpline\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"switchBSplineCreateCircleConstructor      #SetBool  True or [False]\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Display the circles cretors for create the BSpline\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"switchCreateLineDiVatNatOnClick           #SetBool  True or [False]\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"Create the Line info on point (0,0,0) or on point mouse clicked (x,y,z) if it is True\" + \"\\n\")\n    App_Console_PrintMessage(u\"\\t\" + \"If it is True one '*' is displayed in front of text. EX: '*Direction'\" + \"\\n\\n\")\n    ####\n    App_Console_PrintMessage(u\"#### section GroupBox begin\" + \"\\n\")\n    App_Console_PrintMessage(u\"This switch hidde or display the GroupBox concerned \" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"All operation of research info and calcul not change only the cosmetic hidden/display is visual\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"switch_setVisible_GBox_001_Document             # [True] or False \" + \"\\n\")\n    App_Console_PrintMessage(u\"switch_setVisible_GBox_002_Coordinate_Mouse     # [True] or False \" + \"\\n\")\n    App_Console_PrintMessage(u\"switch_setVisible_GBox_003_Color                # [True] or False \" + \"\\n\")\n    App_Console_PrintMessage(u\"switch_setVisible_GBox_004_Object_Mesh          # [True] or False \" + \"\\n\")\n    App_Console_PrintMessage(u\"switch_setVisible_GBox_005_Value_Unit           # [True] or False \" + \"\\n\")\n    App_Console_PrintMessage(u\"switch_setVisible_GBox_006_Inclination          # [True] or False \" + \"\\n\")\n    App_Console_PrintMessage(u\"switch_setVisible_GBox_007_Surface_and_Volume   # [True] or False \" + \"\\n\")\n    App_Console_PrintMessage(u\"switch_setVisible_GBox_008_Cost_And_Price       # [True] or False \" + \"\\n\")\n    App_Console_PrintMessage(u\"switch_setVisible_GBox_009_BoundBox             # [True] or False \" + \"\\n\")\n    App_Console_PrintMessage(u\"switch_setVisible_GBox_010_Center_Mass          # [True] or False \" + \"\\n\")\n    App_Console_PrintMessage(u\"switch_setVisible_GBox_011_Inertia              # [True] or False \" + \"\\n\")\n    App_Console_PrintMessage(u\"switch_setVisible_GBox_012_SpreadSheet          # [True] or False \" + \"\\n\")\n    App_Console_PrintMessage(u\"switch_setVisible_GBox_013_SpreadSheet_Creation # [True] or False \" + \"\\n\")\n    App_Console_PrintMessage(u\"switch_setVisible_GBox_014_Main_Tools           # [True] or False \" + \"\\n\")\n    App_Console_PrintMessage(u\"#### section GroupBox end\" + \"\\n\\n\")\n    ####\n    App_Console_PrintError(u\"####FCinfo Warning####################################################\" + \"\\n\")\n    App_Console_PrintError(u\"## Matrix of inertia                                                ##\" + \"\\n\")\n    App_Console_PrintError(u\"## Verify this section by person knowing the inertia position       ##\" + \"\\n\")\n    App_Console_PrintError(u\"##          ONLY IF THE OBJECT IS PRESENT IN ONE BODY               ##\" + \"\\n\")\n    App_Console_PrintError(u\"## and post your knowledges in the forum tread if it is not correct ##\" + \"\\n\")\n    App_Console_PrintError(u\"## http://forum.freecadweb.org/viewtopic.php?f=10&t=3185            ##\" + \"\\n\")\n    App_Console_PrintError(u\"######################################################################\" + \"\\n\\n\")\n    App_Console_PrintError(u\"###########################################################################\" + \"\\n\")\n    App_Console_PrintError(u\"**                                                                       **\" + \"\\n\")\n    App_Console_PrintError(u\"*   Use at your own risk. The author assumes no liability for data loss.  *\" + \"\\n\")\n    App_Console_PrintError(u\"*              It is advised to backup your data frequently.              *\" + \"\\n\")\n    App_Console_PrintError(u\"*             If you do not trust the software do not use it.             *\" + \"\\n\")\n    App_Console_PrintError(u\"**                                                                       **\" + \"\\n\")\n    App_Console_PrintError(u\"###########################################################################\" + \"\\n\\n\")\n    App_Console_PrintMessage(u\"#### FCInfo Configuration end ####\" + \"\\n\")\n    App_Console_PrintMessage(u\"__________________________________\" + \"\\n\\n\")\n    ####\n\ndoc = FreeCAD.activeDocument()\nif doc == None:\n    doc = FreeCAD.newDocument(u\"FCInfo\")\n\nGui.Selection.clearSelection()\n#sel = FreeCADGui.Selection.getSelection()\ntry:\n    infoFaceMesh = Gui.ActiveDocument.ActiveView.addEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), getNormal)\nexcept Exception:\n    None\ns=SelObserver()\nFreeCADGui.Selection.addObserver(s)                          # install the function resident mode\n\nmw = FreeCADGui.getMainWindow()\ndw=mw.findChildren(QDockWidget)\n\nfor i in dw:\n    if str(i.objectName()) == __Title__:\n        if i.isVisible():\n            i.setVisible(False)\n        else:\n            if seTPositionFlyRightLeft == 1:                 # MainWindow\n                None\n            else:\n                myNewFreeCADWidget = QDockWidget() # create (restore) a new dockwidget\n                myNewFreeCADWidget.setObjectName(__Title__)\n                ui = Ui_MainWindow()\n                ui.setupUi(myNewFreeCADWidget)\n                FCmw = FreeCADGui.getMainWindow()\n                i.setVisible(True)\n        break\n\nif i.objectName() != __Title__:                              # macro internal Name\n    #\n    #####MainWindow################################################################################\n    if seTPositionFlyRightLeft == 1:                 # MainWindow\n        MainWindow = QMainWindow()         # create a new window volant\n        MainWindow.setObjectName(__Title__)          # macro internal Name\n        ui = Ui_MainWindow()\n        ui.setupUi(MainWindow)\n        MainWindow.show()\n    #####DockWidget################################################################################\n    #\n    else:\n        myNewFreeCADWidget = QDockWidget() # create a new dockwidget\n        myNewFreeCADWidget.setObjectName(__Title__)\n        ui = Ui_MainWindow()\n        ui.setupUi(myNewFreeCADWidget)\n        FCmw = FreeCADGui.getMainWindow()\n        if seTPositionFlyRightLeft == 2:             # RightDock\n            FCmw.addDockWidget(QtCore.Qt.RightDockWidgetArea,myNewFreeCADWidget) # add the widget to the main window Right\n        else:                                        # LeftDock\n            FCmw.addDockWidget(QtCore.Qt.LeftDockWidgetArea,myNewFreeCADWidget)  # add the widget to the main window Left\n\n    ui.on_PB_SpreadSheet_clicked()  # cherche les SpreadSheet\n\n",
    "url": "https://wiki.freecad.org/Macro_FCInfo",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/8d40ab6c018c2bde678f/raw/2ba412bef3a9a5a0c6da4f3be18513a585f3a301/FCInfo_en_Ver_1-30c-rmu_Docked.FCMacro",
    "wiki": "https://www.freecadweb.org/wiki/Macro_FCInfo",
    "version": "1.30c",
    "license": "",
    "date": "2025/01/28",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\FCInfo.png",
    "icon_source": "https://wiki.freecad.org/images/5/53/FCInfo.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FCInfo ToolBar",
    "on_wiki": true,
    "on_git": false,
    "desc": "Gives information about the selected shape and can display a conversion of radius, diameter, length, area, volume ... in different units (metric and imperial) in a toolBar. The information to be displayed in real time is parametrizable in the Parameter of FreeCAD.<br /><br />Macro version: 00.05b<br />Last modified: 2023/09/06<br />FreeCAD version: 0.18 and more<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/9/9d/FCInfoToolBar.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Gives information about the selected shape and can display a conversion of radius, diameter, length, area, volume ... in different units (metric and imperial) in a toolBar. The information to be displayed in real time is parametrizable in the Parameter of FreeCAD.",
    "code": "\"\"\"\n***************************************************************************\n*   Copyright (c) 2022 2023 <mario52>                                     *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#\n#2022/02/16, 2022/03/14 ajout preselection size toolbar, 29/03/2022 ajout somme tous les edges\n#2023/09/06 et radius Surface\n__title__   = \"FCInfo_ToolBar\" # on ToolBar\n__author__  = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__Wiki__    = \"https://wiki.freecadweb.org/Macro_FCInfo_ToolBar\"\n__version__ = \"00.05b\"\n__date__    = \"2023/09/06\"     #YYYY/MM/DD\n\nimport FreeCAD, FreeCADGui\nApp = FreeCAD\nGui = FreeCADGui\n\nimport PySide2\nfrom PySide2 import (QtWidgets, QtCore, QtGui)\nfrom PySide2.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QStyle, QDockWidget, QToolBar, QDialog)\nfrom PySide2.QtGui import (QColor, QIcon)\nfrom PySide2.QtCore import QSize\nimport Draft, Part, Sketcher\n\nimport pivy\nfrom pivy import coin\n\nglobal uniteM  ; uniteM  = 0.0\nglobal uniteMs ; uniteMs = \"\"\nglobal uniteS  ; uniteS  = 0.0\nglobal uniteSs ; uniteSs = \"\"\nglobal uniteV  ; uniteV  = 0.0\nglobal uniteVs ; uniteVs = \"\"\n\nglobal switch_User_ToolbarIconSize\nglobal seT_User_sizeIconX               # size X icon\nglobal seT_User_sizeIconY               # size Y icon\nglobal seT_User_StyleSheetColorToolBar  # 0 = not setStyleSheet\n                                        # color in HTML format ex: \"#F8E6E0\" ( 0 by default)\nglobal FreeCAD_Paramter ; FreeCAD_Paramter = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__)\n\n##\nglobal toolbar1         ; toolbar1         = QtWidgets.QToolBar()  # tool bar\nglobal lineEdit_ToolBar ; lineEdit_ToolBar = QtWidgets.QLineEdit() # lineEdit\nglobal fontGlobal_08    ; fontGlobal_08    = QtGui.QFont()\n##\nglobal objectName       ; objectName     = \"\"\nglobal SubElementName   ; SubElementName = \"\"\nglobal position\nglobal pos2D              ; pos2D            = \"\"\n\nglobal switch_User_NotInfoOnBeginning\nglobal seT_User_DecimalValue\nglobal seT_User_TextHeigthValue\nglobal seT_User_setFixed_Tool_Bar_Width\nglobal seT_User_setFixed_Tool_Bar_Height\nglobal seT_User_StyleSheetColorToolBar\nglobal switch_User_Work_With_Preselection\nglobal switch_User_Work_With_PreselectionAsterix\nglobal switch_User_Display_objectName\nglobal switch_User_Display_SubElementName\nglobal switch_User_Display_ShapeType\nglobal switch_User_Display_TypeId\nglobal switch_User_Display_RadiusObject\nglobal switch_User_Display_RadiusSurface\nglobal switch_User_Display_BsplineObject\nglobal switch_User_Display_CentreObject\nglobal switch_User_Display_CentreBoundBoxObject\nglobal switch_User_Display_LengthObject\nglobal switch_User_Display_SommeAllEdgesObject    #sommeEdges total edges\nglobal switch_User_Display_AreaObject\nglobal switch_User_Display_AreaSubObject\nglobal switch_User_Display_Position\nglobal switch_User_Display_VolumeObject\nglobal switch_User_Display_Position_2D_CAD\nglobal switch_User_Display_Position_2D_BMP\nglobal seT_User_UnitSymbolSquare\nglobal seT_User_UnitSymbolCube\nglobal seT_User_UnitSymbolMicro\nglobal seT_System_IndexUnitLength\nglobal seT_System_IndexUnitText\nglobal comboBox_ToolBar\n\n\ndoc = FreeCAD.ActiveDocument\nif doc == None:\n    doc = FreeCAD.newDocument()\n    doc = FreeCAD.activeDocument()\n    FreeCAD.setActiveDocument(doc.Name)\n    \n#### Configuration begin      #### \n#### NOT MODIFY THE CODE HERE ####\n#### for modify : go to : FreeCAD >Menu >Tools >Edit parameters... >BaseApp/Preferences/Macros/FCMmacros/FCInfo_ToolBar ####\n##\nFreeCAD_Paramter.SetString(\"Version\", __version__ + \" (\" + __date__ + \")\")\n##\nswitch_User_ToolbarIconSize = FreeCAD_Paramter.GetBool(\"switch_User_ToolbarIconSize\")\nif switch_User_ToolbarIconSize == 0:\n    FreeCAD_Paramter.SetBool(\"switch_User_ToolbarIconSize\", switch_User_ToolbarIconSize)# switch impost or choice \n    seT_User_sizeIconX = seT_User_sizeIconY = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/General\").GetInt(\"ToolbarIconSize\") # FC preference\nelse:\n    seT_User_sizeIconX = FreeCAD_Paramter.GetInt(\"seT_User_sizeIconX\")     # seT_User_sizeIconX X\n    seT_User_sizeIconY = FreeCAD_Paramter.GetInt(\"seT_User_sizeIconY\")     # seT_User_sizeIconY Y\nFreeCAD_Paramter.SetBool(\"switch_User_ToolbarIconSize\", switch_User_ToolbarIconSize)# switch impost or choice \nif seT_User_sizeIconX == 0: seT_User_sizeIconX = 24\nif seT_User_sizeIconY == 0: seT_User_sizeIconY = 24\nFreeCAD_Paramter.SetInt(\"seT_User_sizeIconX\", seT_User_sizeIconX)          # seT_User_sizeIconX X\nFreeCAD_Paramter.SetInt(\"seT_User_sizeIconY\", seT_User_sizeIconY)          # seT_User_sizeIconY Y\n##\nseT_User_setFixed_Tool_Bar_Width = FreeCAD_Paramter.GetInt(\"seT_User_setFixed_Tool_Bar_Width\")\nFreeCAD_Paramter.SetInt(\"seT_User_setFixed_Tool_Bar_Width\", seT_User_setFixed_Tool_Bar_Width)# seT_User_setFixed_Tool_Bar_Width\n##2\nseT_User_setFixed_Tool_Bar_Height = FreeCAD_Paramter.GetInt(\"seT_User_setFixed_Tool_Bar_Height\")\nFreeCAD_Paramter.SetInt(\"seT_User_setFixed_Tool_Bar_Height\", seT_User_setFixed_Tool_Bar_Height)# seT_User_setFixed_Tool_Bar_Height\n##\nseT_User_StyleSheetColorToolBar = FreeCAD_Paramter.GetString(\"seT_User_StyleSheetColorToolBar\")\nif seT_User_StyleSheetColorToolBar == \"\":\n    FreeCAD_Paramter.SetString(\"seT_User_StyleSheetColorToolBar\", \"0\") #F8E6E0\n    seT_User_StyleSheetColorToolBar = \"0\"\n##\nseT_User_DecimalValue = FreeCAD_Paramter.GetInt(\"seT_User_DecimalValue\")   # seT_User_DecimalValue\nif seT_User_DecimalValue == 0:\n    seT_User_DecimalValue = 2\nFreeCAD_Paramter.SetInt(\"seT_User_DecimalValue\", seT_User_DecimalValue)# seT_User_DecimalValue\n##\nseT_User_TextHeigthValue = FreeCAD_Paramter.GetInt(\"seT_User_TextHeigthValue\")# seT_User_TextHeigthValue\nif seT_User_TextHeigthValue == 0:\n    seT_User_TextHeigthValue = 10\nFreeCAD_Paramter.SetInt(\"seT_User_TextHeigthValue\", seT_User_TextHeigthValue)# LineEdit seT_User_TextHeigthValue\n##\nswitch_User_Work_With_Preselection = FreeCAD_Paramter.GetBool(\"switch_User_Work_With_Preselection\")# switch yes / no Name\nFreeCAD_Paramter.SetBool(\"switch_User_Work_With_Preselection\", switch_User_Work_With_Preselection) # switch yes / no Name\nif switch_User_Work_With_Preselection == 1:\n    switch_User_Work_With_PreselectionAsterix = \" *\"\nelse:\n    switch_User_Work_With_PreselectionAsterix= \"\"\n##\nswitch_User_Display_objectName = FreeCAD_Paramter.GetBool(\"switch_User_Display_objectName\")# switch yes / no Name\nFreeCAD_Paramter.SetBool(\"switch_User_Display_objectName\", switch_User_Display_objectName) # switch yes / no Name\n##\nswitch_User_Display_SubElementName = FreeCAD_Paramter.GetBool(\"switch_User_Display_SubElementName\")# switch yes / no Element\nFreeCAD_Paramter.SetBool(\"switch_User_Display_SubElementName\", switch_User_Display_SubElementName) # switch yes / no Element\n##\nswitch_User_Display_ShapeType = FreeCAD_Paramter.GetBool(\"switch_User_Display_ShapeType\")# switch yes / no ShapeType\nFreeCAD_Paramter.SetBool(\"switch_User_Display_ShapeType\", switch_User_Display_ShapeType) # switch yes / no ShapeType\n##\nswitch_User_Display_TypeId = FreeCAD_Paramter.GetBool(\"switch_User_Display_TypeId\")# switch yes / no TypeId\nFreeCAD_Paramter.SetBool(\"switch_User_Display_TypeId\", switch_User_Display_TypeId) # switch yes / no TypeId\n##\nswitch_User_Display_RadiusObject = FreeCAD_Paramter.GetBool(\"switch_User_Display_RadiusObject\")# switch yes / no Radius\nFreeCAD_Paramter.SetBool(\"switch_User_Display_RadiusObject\", switch_User_Display_RadiusObject) # switch yes / no Radius\n##\nswitch_User_Display_RadiusSurface = FreeCAD_Paramter.GetBool(\"switch_User_Display_RadiusSurface\")# switch yes / no Radius\nFreeCAD_Paramter.SetBool(\"switch_User_Display_RadiusSurface\", switch_User_Display_RadiusSurface) # switch yes / no Radius\n##\nswitch_User_Display_LengthObject = FreeCAD_Paramter.GetBool(\"switch_User_Display_LengthObject\")# switch yes / no Length\nFreeCAD_Paramter.SetBool(\"switch_User_Display_LengthObject\", switch_User_Display_LengthObject) # switch yes / no Length\n##\nswitch_User_Display_SommeAllEdgesObject = FreeCAD_Paramter.GetBool(\"switch_User_Display_SommeAllEdgesObject\")# switch yes / no Length\nFreeCAD_Paramter.SetBool(\"switch_User_Display_SommeAllEdgesObject\", switch_User_Display_SommeAllEdgesObject) # switch yes / no Length\n##\nswitch_User_Display_NumberFacesMesh = FreeCAD_Paramter.GetBool(\"switch_User_Display_NumberFacesMesh\")# switch yes / no info\nFreeCAD_Paramter.SetBool(\"switch_User_Display_NumberFacesMesh\", switch_User_Display_NumberFacesMesh) # switch yes / no Radius\n##\nswitch_User_Display_NumberPointsMeshPoints = FreeCAD_Paramter.GetBool(\"switch_User_Display_NumberPointsMeshPoints\")# switch yes / no info\nFreeCAD_Paramter.SetBool(\"switch_User_Display_NumberPointsMeshPoints\", switch_User_Display_NumberPointsMeshPoints) # switch yes / no Radius\n##\nswitch_User_Display_NumberEdgesMesh = FreeCAD_Paramter.GetBool(\"switch_User_Display_NumberEdgesMesh\")# switch yes / no info\nFreeCAD_Paramter.SetBool(\"switch_User_Display_NumberEdgesMesh\", switch_User_Display_NumberEdgesMesh) # switch yes / no Radius\n##\nswitch_User_Display_AreaObject = FreeCAD_Paramter.GetBool(\"switch_User_Display_AreaObject\")# switch yes / no Area\nFreeCAD_Paramter.SetBool(\"switch_User_Display_AreaObject\", switch_User_Display_AreaObject) # switch yes / no Area\n##\nswitch_User_Display_AreaSubObject = FreeCAD_Paramter.GetBool(\"switch_User_Display_AreaSubObject\")# switch yes / no Area\nFreeCAD_Paramter.SetBool(\"switch_User_Display_AreaSubObject\", switch_User_Display_AreaSubObject) # switch yes / no Area\n##\nswitch_User_Display_VolumeObject = FreeCAD_Paramter.GetBool(\"switch_User_Display_VolumeObject\")# switch yes / no Volume\nFreeCAD_Paramter.SetBool(\"switch_User_Display_VolumeObject\", switch_User_Display_VolumeObject) # switch yes / no Volume\n##\nswitch_User_Display_BsplineObject = FreeCAD_Paramter.GetBool(\"switch_User_Display_BsplineObject\")# switch yes / no Bspline\nFreeCAD_Paramter.SetBool(\"switch_User_Display_BsplineObject\", switch_User_Display_BsplineObject) # switch yes / no Bspline\n##\nswitch_User_Display_CentreObject = FreeCAD_Paramter.GetBool(\"switch_User_Display_CentreObject\")# switch yes / no Centre\nFreeCAD_Paramter.SetBool(\"switch_User_Display_CentreObject\", switch_User_Display_CentreObject) # switch yes / no Centre\n##\nswitch_User_Display_CentreBoundBoxObject = FreeCAD_Paramter.GetBool(\"switch_User_Display_CentreBoundBoxObject\")# switch yes / no Centre BoundBox\nFreeCAD_Paramter.SetBool(\"switch_User_Display_CentreBoundBoxObject\", switch_User_Display_CentreBoundBoxObject) # switch yes / no Centre BoundBox\n##\nswitch_User_Display_Position = FreeCAD_Paramter.GetBool(\"switch_User_Display_Position\")# switch yes / no Position\nFreeCAD_Paramter.SetBool(\"switch_User_Display_Position\", switch_User_Display_Position) # switch yes / no Position\n##\nswitch_User_Display_Position_2D_CAD = FreeCAD_Paramter.GetBool(\"switch_User_Display_Position_2D_CAD\")# switch yes / no Position 2D CAD\nFreeCAD_Paramter.SetBool(\"switch_User_Display_Position_2D_CAD\", switch_User_Display_Position_2D_CAD) # switch yes / no Position 2D CAD\n##\nswitch_User_Display_Position_2D_BMP = FreeCAD_Paramter.GetBool(\"switch_User_Display_Position_2D_BMP\")# switch yes / no Position 2D BMP Reverse Y\nFreeCAD_Paramter.SetBool(\"switch_User_Display_Position_2D_BMP\", switch_User_Display_Position_2D_BMP) # switch yes / no Position 2D BMP Reverse Y\n##\nswitch_User_NotInfoOnBeginning = FreeCAD_Paramter.GetBool(\"switch_User_NotInfoOnBeginning\")# switch yes / no Info\nFreeCAD_Paramter.SetBool(\"switch_User_NotInfoOnBeginning\", switch_User_NotInfoOnBeginning) # switch yes / no Info\n##\nseT_User_UnitSymbolSquare = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetString(\"seT_User_UnitSymbolSquare\")\nif seT_User_UnitSymbolSquare == \"\":\n    seT_User_UnitSymbolSquare = \"2\"\nFreeCAD_Paramter.SetString(\"seT_User_UnitSymbolSquare\", seT_User_UnitSymbolSquare) # \n##\nseT_User_UnitSymbolCube = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetString(\"seT_User_UnitSymbolCube\")\nif seT_User_UnitSymbolCube == \"\":\n    seT_User_UnitSymbolCube = \"3\"\nFreeCAD_Paramter.SetString(\"seT_User_UnitSymbolCube\", seT_User_UnitSymbolCube) # \n##\nseT_User_UnitSymbolMicro = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetString(\"seT_User_UnitSymbolMicro\")\nif seT_User_UnitSymbolMicro == \"\":\n    seT_User_UnitSymbolMicro = \"\"\nFreeCAD_Paramter.SetString(\"seT_User_UnitSymbolMicro\", seT_User_UnitSymbolMicro) # \n##\n#### pour demarrage\nseT_System_IndexUnitLength = FreeCAD_Paramter.GetInt(\"seT_System_IndexUnitLength\")    # seT_System_IndexUnitLength\nif seT_System_IndexUnitLength == 0:\n    seT_System_IndexUnitLength = 0\nFreeCAD_Paramter.SetInt(\"seT_System_IndexUnitLength\", seT_System_IndexUnitLength)     # seT_System_IndexUnitLength\n#### pour demarrage\nseT_System_IndexUnitText = FreeCAD_Paramter.GetString(\"seT_System_IndexUnitText\")     # seT_System_IndexUnitText\nif seT_System_IndexUnitText == \"\":\n    seT_System_IndexUnitText = \"km\"\nFreeCAD_Paramter.SetString(\"seT_System_IndexUnitText\", seT_System_IndexUnitText)      # seT_System_IndexUnitText\n##\nuniteM = FreeCAD_Paramter.GetFloat(\"seT_System_uniteM\")\nif uniteM == 0:\n    uniteM = 0.000001\nFreeCAD_Paramter.SetFloat(\"seT_System_uniteM\", uniteM)\n##\nuniteMs = FreeCAD_Paramter.GetString(\"seT_System_uniteMs\")\nif uniteMs == \"\":\n    uniteMs= \"km\"\nFreeCAD_Paramter.SetString(\"seT_System_uniteMs\", uniteMs)\n##\nuniteS = FreeCAD_Paramter.GetFloat(\"seT_System_uniteS\")\nif uniteS == 0:\n    uniteS = 0.000000000001\nFreeCAD_Paramter.SetFloat(\"seT_System_uniteS\", uniteS)\n##\nuniteSs = FreeCAD_Paramter.GetString(\"seT_System_uniteSs\")\nif uniteSs == \"\":\n    uniteSs= \"km\"+seT_User_UnitSymbolSquare\nFreeCAD_Paramter.SetString(\"seT_System_uniteSs\", uniteSs)\n##\nuniteV = FreeCAD_Paramter.GetFloat(\"seT_System_uniteV\")\nif uniteV == 0:\n    uniteV = 0.000000000000000001\nFreeCAD_Paramter.SetFloat(\"seT_System_uniteV\", uniteV)\n##\nuniteVs = FreeCAD_Paramter.GetString(\"seT_System_uniteVs\")\nif uniteVs == \"\":\n    uniteVs= \"km\"+seT_User_UnitSymbolCube\nFreeCAD_Paramter.SetString(\"seT_System_uniteVs\", uniteVs)\n#### Configuration end ################################################\n\n\nRefresh_Icon = [\n\"64 64 9 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"+\tc #1D4376\",\n\"@\tc #5B5E5D\",\n\"#\tc #3C6BA7\",\n\"$\tc #6A93C2\",\n\"%\tc #9DA2A4\",\n\"&\tc #C6CACB\",\n\"*\tc #FFFFFF\",\n\"                                                                \",\n\"    +++++++++++++++++++++++++++++++++++++++++++++++++++++       \",\n\"    +$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$##+       \",\n\"    +$*&&&&&&&&&*&&&&&&&&*&&&&&&&&*********************#+       \",\n\"    +$*%%%%%%%%%*%%%%%%%%*%%%%%%%%*********************#+       \",\n\"    +$*&&&&&&&&&*&&&&&&&&*&&&&&&&&*********************#+       \",\n\"    +$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#+       \",\n\"    +$+++++++++++++++++++++++++++++++++++++++++++++++++#+       \",\n\"    +$#+++++++++++++++++++++++++++++++++++++++++++++++##+       \",\n\"    +$################################################$$+       \",\n\"    +$################################################$$+       \",\n\"    +$###+++++++++++++++++++++++######################$$+       \",\n\"    +$###+#*******************$+######################$$+       \",\n\"    +$$##+$*$$$$$$$$$$$$$$$$$*%+######################$$+       \",\n\"    +$$##+$*+++++++++++++++++&%+######################$$+       \",\n\"    +$$##+$*#++++++++++++++++&%+######################$$+       \",\n\"    +$$##+$*******************%+######################$$+       \",\n\"    +$$##+$*******************%+######################$$+       \",\n\"    +$$##+$*******************%+######################$$+       \",\n\"    +$$##+$*******************%+######################$$+       \",\n\"    +$$##+$*******************%+######################$$+       \",\n\"    +$$##+$*******************%+######################$$+       \",\n\"    +$$##+$*******************%+$$$$$$$$$$++##########$$+       \",\n\"    +$$##+$*******************%+**********&+##########$$+       \",\n\"    +$$##+$*******************%++++++++++&&+##########$$+       \",\n\"    +$$$$+$*******************%++++++++++&&+$$$$$$$$$$$$+       \",\n\"    +$$$$+$*******************%+$$$$$$$$$*&+$$$$$$$$$$$$+       \",\n\"    +$$$$+$*******************%+**********&+$$$$$$$$$$$$+       \",\n\"    +$$$$+$&&&&&&&&&&&&&&&&&&&%+**********&+$$$$$$$$$$$$+       \",\n\"    +$$$$+$&&&&&&&&&&&&&&&&&&&%+**********&+$$$$$$$$$$$$+       \",\n\"    +$$$$+$&&&&&&&&&&&&&&&&&&&%+**********&+$$$$$$$$$$$$+       \",\n\"    +$$$$+#&&&&&&&&&&&&&&&&&&&%+**********&+$$$$$$$$$$$$+       \",\n\"    +$$$$+++++++++++++++++++++++****&&%%@@@@@@@@@@@@@@@@+       \",\n\"    +$$$$$$$##########$&&&&&&&*****%@@@@@@%%%%%%@@@@@@@@+       \",\n\"    +$$$$$$$$$$$$$$$$#$***********@@&**********%@@%%%%@@@       \",\n\"    +$$$$$$$$$$$$$$$$#$**********%@***********%@%%%%%%%@@       \",\n\"    +$$$$$$$$$$$$$$$$#$%@@@@@@@@@@&**********%@@@@@@@@@@@@      \",\n\"    +$$$$$$$$$$$$$$$$#$*%@@%&&&&&&**********&@@@@@@@@@@@%@      \",\n\"    +$$$$$$$$$$$$$$$$#$**&@@***********************%@@%%%@@     \",\n\"    +$$$$$$$$$$$$$$$$#$&&&&%@%*******************%@@%%%%%%@     \",\n\"    +$$$$$$$$$$$$$$$$#$&&&&&&@@****************%@@%%%%%%%%@     \",\n\"    +$$$$$$$$$$$$$$$$#$&&&&&&&@@&***&&&&&****%@@%%%%%%%%%%@@    \",\n\"    +$$$$$$$$$$$$$$$$#+$$$$$$$$@@%***&&****%@@$@%%%%%%%%%%%@    \",\n\"    +$$$$$$$$$$$$$$$$############@@&*****%@@$$$@%%%%%%%%%%%@    \",\n\"    +$$$$$$$$$$$$$$$$$$$$$$$$$$$$$@@%**%@@$$$$$@%&%%%%%%%%%@    \",\n\"    +$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$@@@@$$$$$$$@%&%%%%%%%%%@    \",\n\"    +$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$@$$$$$$$$$@%&&%%%%%%&&@    \",\n\"    +$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$@%&&&%%%%%&%@    \",\n\"    +$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$@%&&&&&&&&&%@    \",\n\"    +$$$$$$$$$$$$$$$$$$$$$$$$$@@@@@@@@@@@@@@@@$@&&&&&&&&&&%@    \",\n\"    +$$$$$$$$$$$$$$$$$$$$$$$$$@%************%@%@&&&&&&&&&&%@    \",\n\"     +$$$$$$$$$$$$$$$$$$$$$$$$@%************&@@@&&&&&&&&&&@@    \",\n\"     +++++++++++++++++++++++++@@************&@@%&&&&&&&&&&@     \",\n\"                              @@************&@@&&&&&&&&&&%@     \",\n\"                              @@%&&&&&&&&&&&&@@&&&&&&&&&&@@     \",\n\"                               @@&&&&&&&&&&&&%@&&&&&&&&&%@      \",\n\"                                @@&&&&&&&&&&&%@%&&&&&&&&@@      \",\n\"                                 @@%%%%%%%%%%%@@&*****&@@       \",\n\"                                  @@@%%%%%%%%%%@@@%%%%@@        \",\n\"                                   @@@@@@@@@@@@@@@@@@@@@        \",\n\"                                    @@@@@@@@@@@@@@@@@@@         \",\n\"                                                                \",\n\"                                                                \",\n\"                                                                \"]\n\n####\n\nglobal infoFaceMesh; \nglobal indexFaceMeshSTR ; indexFaceMeshSTR = \"X\"\nglobal coordPointsMesh  ; coordPointsMesh  = \"\"\nimport warnings\nwarnings.simplefilter(\"ignore\")\n\ndef adjustedGlobalPlacement(obj, locVector):\n    '''find global placement to make locVector the local origin with the correct orientation'''\n    # extract BoundingBox_Tracing\n    #2021/07/10 modified by edwilliams16 to handle objects in nested part containers\n    #https://forum.freecadweb.org/viewtopic.php?f=22&t=59852\n    #\n    try:\n        objectPlacement = obj.Placement\n        objectGlobalPlacement = obj.getGlobalPlacement()\n        locPlacement = App.Placement(locVector, App.Rotation(App.Vector(1,0,0),0))\n        return objectGlobalPlacement.multiply(objectPlacement.inverse()).multiply(locPlacement)\n    except Exception:\n        locPlacement = App.Placement(App.Vector(0,0,0), App.Rotation(0,0,0), App.Vector(0,0,0))\n        #App.Console.PrintError(\"Error adjustedGlobalPlacement\")\n        return locPlacement\n\ndef getNormal(cb):\n    #https://wiki.freecadweb.org/Code_snippets#Get_the_normal_vector_of_a_surface_from_a_STL_file\n    global indexFaceMeshSTR\n    global objs\n\n    try:\n        indexFaceMeshSTR = \"X\"\n        if (hasattr(objs[0], \"Mesh\")):\n            pp = cb.getPickedPoint()\n            indexFaceMeshSTR  = str(coin.cast(pp.getDetail(), \"SoFaceDetail\").getFaceIndex())\n    except Exception:\n        None\n\ndef Refresh_Preference():### Begin command Std_Refresh_Preference\n        global seT_User_DecimalValue\n        global seT_User_TextHeigthValue\n        global switch_User_NotInfoOnBeginning\n        global fontGlobal_08\n        global lineEdit_ToolBar\n        global switch_User_ToolbarIconSize\n        global seT_User_sizeIconX\n        global seT_User_sizeIconY\n        global toolbar1\n        global seT_User_setFixed_Tool_Bar_Width\n        global seT_User_setFixed_Tool_Bar_Height\n        global seT_User_StyleSheetColorToolBar\n        global switch_User_Work_With_Preselection\n        global switch_User_Work_With_PreselectionAsterix\n        global switch_User_Display_objectName\n        global switch_User_Display_SubElementName\n        global switch_User_Display_ShapeType\n        global switch_User_Display_TypeId\n        global switch_User_Display_NumberFacesMesh\n        global switch_User_Display_NumberPointsMeshPoints\n        global switch_User_Display_NumberEdgesMesh\n        global switch_User_Display_RadiusObject\n        global switch_User_Display_RadiusSurface\n        global switch_User_Display_BsplineObject\n        global switch_User_Display_CentreObject\n        global switch_User_Display_CentreBoundBoxObject\n        global switch_User_Display_LengthObject\n        global switch_User_Display_SommeAllEdgesObject\n        global switch_User_Display_AreaObject\n        global switch_User_Display_AreaSubObject\n        global switch_User_Display_Position\n        global switch_User_Display_VolumeObject\n        global switch_User_Display_Position_2D_CAD\n        global switch_User_Display_Position_2D_BMP\n        global seT_User_UnitSymbolSquare\n        global seT_User_UnitSymbolCube\n        global seT_User_UnitSymbolMicro\n        global seT_System_IndexUnitLength\n        global seT_System_IndexUnitText\n        global FreeCAD_Paramter\n        global uniteM\n        global uniteMs\n        global uniteS\n        global uniteSs\n        global uniteV\n        global uniteVs\n\n    #try:\n        seT_User_setFixed_Tool_Bar_Width = FreeCAD_Paramter.GetInt(\"seT_User_setFixed_Tool_Bar_Width\")\n        if seT_User_setFixed_Tool_Bar_Width != 0:\n            toolbar1.setFixedWidth(seT_User_setFixed_Tool_Bar_Width)\n\n        seT_User_setFixed_Tool_Bar_Height = FreeCAD_Paramter.GetInt(\"seT_User_setFixed_Tool_Bar_Height\")\n        if seT_User_setFixed_Tool_Bar_Height != 0:\n            toolbar1.setFixedHeight(seT_User_setFixed_Tool_Bar_Height)\n\n        #### color StyleSheet\n        seT_User_StyleSheetColorToolBar = FreeCAD_Paramter.GetString(\"seT_User_StyleSheetColorToolBar\")\n        if seT_User_StyleSheetColorToolBar == \"\":\n            FreeCAD_Paramter.SetString(\"seT_User_StyleSheetColorToolBar\", \"0\")\n            seT_User_StyleSheetColorToolBar = \"0\"\n        if seT_User_StyleSheetColorToolBar != \"0\":\n            toolbar1.setStyleSheet(\"QToolBar {background-color:\" + seT_User_StyleSheetColorToolBar + \";}\") #F8E6E0\n        else:\n            toolbar1.setStyleSheet(\"QToolBar {QPalette.Base}\")\n\n        switch_User_Work_With_Preselection     = FreeCAD_Paramter.GetBool(\"switch_User_Work_With_Preselection\")      # switch yes / no preselection\n        if switch_User_Work_With_Preselection == 1:\n            switch_User_Work_With_PreselectionAsterix= \" *\"\n            #toolbar1.setStyleSheet(\"QToolBar {QPalette.Base}\")\n            #toolbar1.setStyleSheet(\"QToolBar {color: black; background-color: #F8E6E0}\") # html code  #F8E6E0\n        else:\n            switch_User_Work_With_PreselectionAsterix= \"\"\n        #### color\n\n        ## Icon\n        switch_User_ToolbarIconSize = FreeCAD_Paramter.GetBool(\"switch_User_ToolbarIconSize\")\n        if switch_User_ToolbarIconSize == 0:\n            FreeCAD_Paramter.SetBool(\"switch_User_ToolbarIconSize\", switch_User_ToolbarIconSize)# switch impost or choice \n            seT_User_sizeIconX = seT_User_sizeIconY = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/General\").GetInt(\"ToolbarIconSize\") # FC preference\n        else:\n            seT_User_sizeIconX = FreeCAD_Paramter.GetInt(\"seT_User_sizeIconX\")     # seT_User_sizeIconX X\n            seT_User_sizeIconY = FreeCAD_Paramter.GetInt(\"seT_User_sizeIconY\")     # seT_User_sizeIconY Y\n        FreeCAD_Paramter.SetBool(\"switch_User_ToolbarIconSize\", switch_User_ToolbarIconSize)# switch impost or choice \n        if seT_User_sizeIconX == 0: seT_User_sizeIconX = 24\n        if seT_User_sizeIconY == 0: seT_User_sizeIconY = 24\n        FreeCAD_Paramter.SetInt(\"seT_User_sizeIconX\", seT_User_sizeIconX)          # seT_User_sizeIconX X\n        FreeCAD_Paramter.SetInt(\"seT_User_sizeIconY\", seT_User_sizeIconY)          # seT_User_sizeIconY Y\n        toolbar1.setIconSize(QSize(seT_User_sizeIconX, seT_User_sizeIconY))        # affect size\n\n        #### variables LineEdit debut\n        ##\n        seT_User_DecimalValue    = FreeCAD_Paramter.GetInt(\"seT_User_DecimalValue\")   # seT_User_DecimalValue\n        seT_User_TextHeigthValue = FreeCAD_Paramter.GetInt(\"seT_User_TextHeigthValue\")# LineEdit seT_User_TextHeigthValue\n        ##\n        switch_User_NotInfoOnBeginning           = FreeCAD_Paramter.GetBool(\"switch_User_NotInfoOnBeginning\")          # switch yes / no info\n        switch_User_Display_objectName           = FreeCAD_Paramter.GetBool(\"switch_User_Display_objectName\")          # switch yes / no Object Name\n        switch_User_Display_SubElementName       = FreeCAD_Paramter.GetBool(\"switch_User_Display_SubElementName\")      # switch yes / no Element\n        switch_User_Display_ShapeType            = FreeCAD_Paramter.GetBool(\"switch_User_Display_ShapeType\")           # switch yes / no Shape Type\n        switch_User_Display_TypeId               = FreeCAD_Paramter.GetBool(\"switch_User_Display_TypeId\")              # switch yes / no TypeId\n        switch_User_Display_NumberFacesMesh      = FreeCAD_Paramter.GetBool(\"switch_User_Display_NumberFacesMesh\")     # switch yes / no Face Mesh\n        switch_User_Display_NumberPointsMeshPoints= FreeCAD_Paramter.GetBool(\"switch_User_Display_NumberPointsMeshPoints\")# switch yes / no Points Mesh\n        switch_User_Display_NumberEdgesMesh      = FreeCAD_Paramter.GetBool(\"switch_User_Display_NumberEdgesMesh\")     # switch yes / no Edge Mesh\n        switch_User_Display_RadiusObject         = FreeCAD_Paramter.GetBool(\"switch_User_Display_RadiusObject\")        # switch yes / no Radius\n        switch_User_Display_RadiusSurface        = FreeCAD_Paramter.GetBool(\"switch_User_Display_RadiusSurface\")       # switch yes / no Radius\n        switch_User_Display_BsplineObject        = FreeCAD_Paramter.GetBool(\"switch_User_Display_BsplineObject\")       # switch yes / no Bspline\n        switch_User_Display_CentreObject         = FreeCAD_Paramter.GetBool(\"switch_User_Display_CentreObject\")        # switch yes / no Centre\n        switch_User_Display_CentreBoundBoxObject = FreeCAD_Paramter.GetBool(\"switch_User_Display_CentreBoundBoxObject\")# switch yes / no Centre BoundBox\n        switch_User_Display_LengthObject         = FreeCAD_Paramter.GetBool(\"switch_User_Display_LengthObject\")        # switch yes / no Length\n        switch_User_Display_SommeAllEdgesObject  = FreeCAD_Paramter.GetBool(\"switch_User_Display_SommeAllEdgesObject\") # switch yes / no sommeEdges total edges\n        switch_User_Display_AreaObject           = FreeCAD_Paramter.GetBool(\"switch_User_Display_AreaObject\")          # switch yes / no Area Object\n        switch_User_Display_AreaSubObject        = FreeCAD_Paramter.GetBool(\"switch_User_Display_AreaSubObject\")       # switch yes / no Area SubObject\n        switch_User_Display_Position             = FreeCAD_Paramter.GetBool(\"switch_User_Display_Position\")            # switch yes / no Position\n        switch_User_Display_VolumeObject         = FreeCAD_Paramter.GetBool(\"switch_User_Display_VolumeObject\")        # switch yes / no Volume\n        switch_User_Display_Position_2D_CAD      = FreeCAD_Paramter.GetBool(\"switch_User_Display_Position_2D_CAD\")     # switch yes / no Position 2D CAD Y left bottom\n        switch_User_Display_Position_2D_BMP      = FreeCAD_Paramter.GetBool(\"switch_User_Display_Position_2D_BMP\")     # switch yes / no Position 2D BMP Reverse Y 0,0 left Top\n        ##\n        seT_User_UnitSymbolSquare = FreeCAD_Paramter.GetString(\"seT_User_UnitSymbolSquare\")\n        seT_User_UnitSymbolCube = FreeCAD_Paramter.GetString(\"seT_User_UnitSymbolCube\")\n        seT_User_UnitSymbolMicro = FreeCAD_Paramter.GetString(\"seT_User_UnitSymbolMicro\")\n        ##\n        seT_System_IndexUnitLength = FreeCAD_Paramter.GetInt(\"seT_System_IndexUnitLength\")   # \n        seT_System_IndexUnitText = FreeCAD_Paramter.GetString(\"seT_System_IndexUnitText\" )   # seT_System_IndexUnitText\n        ##\n        uniteM = FreeCAD_Paramter.GetFloat(\"seT_System_uniteM\")\n        uniteMs = FreeCAD_Paramter.GetString(\"seT_System_uniteMs\")\n        uniteS = FreeCAD_Paramter.GetFloat(\"seT_System_uniteS\")\n        uniteSs = FreeCAD_Paramter.GetString(\"seT_System_uniteSs\")\n        uniteV = FreeCAD_Paramter.GetFloat(\"seT_System_uniteV\")\n        uniteVs = FreeCAD_Paramter.GetString(\"seT_System_uniteVs\")\n\n        activeInfo()\n#    except Exception:\n#        None\n\ndef activeInfo():\n    global SubElementName\n    global objectName\n    global position\n    global pos2D\n\n    global sel\n    global selEx\n    global objs\n    global sObj\n    global fontGlobal_08\n    global sketch0selEx\n\n    global lineEdit_ToolBar\n    global seT_User_DecimalValue\n    global seT_User_TextHeigthValue\n    global FreeCAD_Paramter\n    global switch_User_Work_With_PreselectionAsterix\n    global switch_User_Display_objectName\n    global switch_User_Display_SubElementName\n    global switch_User_Display_ShapeType\n    global switch_User_Display_TypeId\n    global switch_User_Display_NumberFacesMesh\n    global switch_User_Display_NumberPointsMeshPoints\n    global switch_User_Display_NumberEdgesMesh\n    global switch_User_Display_RadiusObject\n    global switch_User_Display_RadiusSurface\n    global switch_User_Display_BsplineObject\n    global switch_User_Display_CentreObject\n    global switch_User_Display_CentreBoundBoxObject\n    global switch_User_Display_LengthObject\n    global switch_User_Display_SommeAllEdgesObject\n    global switch_User_Display_AreaObject\n    global switch_User_Display_AreaSubObject\n    global switch_User_Display_Position\n    global switch_User_Display_VolumeObject\n    global switch_User_Display_Position_2D_CAD\n    global switch_User_Display_Position_2D_BMP\n    global seT_User_StyleSheetColorToolBar\n    global switch_User_Work_With_Preselection\n    global uniteM\n    global uniteMs\n    global uniteS\n    global uniteSs\n    global uniteV\n    global uniteVs\n    global infoFaceMesh\n    global indexFaceMeshSTR\n\n    doc = FreeCAD.activeDocument()\n    if doc == None:\n        FreeCAD.Console.PrintError(\"Not activeView or ...\" + \"\\n\")\n        doc = FreeCAD.newDocument(\"FCInfo Tools\")\n        None\n    else:\n        try:\n            rayonObjet  = rayonSurface = longueurObjet = sommeEdges = surfaceObj = surfaceFace = volumeObject = 0.0\n            nombreFacesMesh = nombrePointsMesh = nombreArretesMesh = BsplineNombreDeNoeuds = indexSubObject = 0\n\n            ## Asterix and Obelix\n            objectNameAsterix = SubElementNameAsterix = typeObjectShapeTypeSTRAsterix = typeObjectTypeIdSTRAsterix = nombreFacesMeshSTRAsterix = nombrePointsMeshSTRAsterix = \"\"\n            nombreArretesMeshSTRAsterix = rayonObjetSTRAsterix = rayonSurfaceSTRAsterix = longueurSTRAsterix = sommeEdgesSTRAsterix = surfaceObjSTRAsterix = surfaceFaceSTRAsterix = \"\"\n            volumeObjectSTRAsterix = bsplineSTRAsterix = centreObjetSTRAsterix = centreBBSTRAsterix = positionSTRAsterix = Position2DSTRAsterix = \"\"\n            bsplineNoeudsSTR = bsplineRayonObjetAppSTR = bsplinePointsCoorSoSTR = bsplinePointsCoorShapeSTR = \"\"\n\n            rayonObjetSTR = diametreObjetSTR = rayonSurfaceSTR = diametreSurfaceSTR = longueurSTR = surfaceObjSTR = surfaceFaceSTR = volumeObjectSTR = bsplineSTR = centreObjetSTR = centreBBSTR = positionSTR = pos2DSTR = \"\"\n            nombreFacesMeshSTR = nombrePointsMeshSTR = nombreArretesMeshSTR = typeObjectShapeTypeSTR = typeObjectTypeIdSTR = sketchObjectTypeSTR = centreObjet = \"\"\n\n            BsplineArcsRadius    = []\n            BsplinePointsCoorS   = []\n            BsplinePointsCoorSo  = []\n\n            lineEdit = \"\"\n            lineEdit_ToolBar.clear()\n\n            if switch_User_Display_objectName == 1:                 # objectName\n                try:\n                    objectNameAsterix = \" *\"\n                    lineEdit += \" (\" + str(objectName) + \") \"\n                except Exception:\n                    objectName = \"\"\n                    lineEdit += \" (\" + str(objectName) + \") \"\n\n            if switch_User_Display_SubElementName == 1:             # SubElementName\n                try:\n                    SubElementNameAsterix = \" *\"\n                    try:\n                        if hasattr(objs[0], \"Mesh\"):\n                            SubElementName = \"\"\n                            SubElementName = \"Face\" + indexFaceMeshSTR\n                    except Exception: None\n                    lineEdit += \" (\" + str(SubElementName) + \") \"\n                except Exception:\n                    SubElementName = \"\"\n                    lineEdit += \" (\" + str(SubElementName) + \") \"\n\n            #### sketcher begin ####\n            ##\n            ##https://forum.freecadweb.org/viewtopic.php?f=22&t=53127\n            ##How to select edges inside of Sketcher?\n            ##\n            sketch  = sel[0]    #sketch0    = Gui.Selection.getSelectionEx()[0]\n            App.ActiveDocument.recompute()\n            sketchObjectTypeSTR = indexSubObjectSTR = \"\"\n\n            if (Gui.ActiveDocument.getInEdit() and (sketch.TypeId == \"Sketcher::SketchObject\")): # sketcher open\n\n                if (\"H_Axis\" in SubElementName) or (\"V_Axis\" in SubElementName) or (\"Constraint\" in SubElementName) or (\"Vertex\" in SubElementName):\n                    None\n                else:\n                    try:\n                        longueurSTR = rayonObjetSTR = diametreObjetSTR = rayonSurfaceSTR = diametreSurfaceSTR = CentreObjet = MajorRadiusObjet = MajorRadiusObjet = \"\"\n\n                        nameSketch = sketch.Name\n\n                        try:\n                            indexSubObject  = int(SubElementName[4:]) - 1             # index Edge10\n                            sObject = App.ActiveDocument.getObject(nameSketch).Geometry[indexSubObject]\n\n                            sketchObjectTypeSTR = sketch.TypeId\n                            lineEdit += \" (TyO:\" + str(sketchObjectTypeSTR) + \") \"\n\n                            indexSubObjectSTR = \" (I:\" + str(indexSubObject) + \") \"\n                            lineEdit += indexSubObjectSTR\n                        except Exception: None\n\n                        if isinstance(sObject,(Part.LineSegment)):\n                            longueurObjet = sObject.length()\n\n                        elif isinstance(sObject,(Part.BSplineCurve)):\n                            longueurObjet = sObject.length()\n\n                        elif isinstance(sObject,(Part.Circle)):\n                            longueurObjet = sObject.length()\n                            rayonObjet = sObject.Radius\n                            CentreObjet = sObject.Center\n\n                        elif isinstance(sObject,(Part.ArcOfCircle)):\n                            longueurObjet = sObject.length()\n                            rayonObjet = sObject.Radius\n                            CentreObjet = sObject.Center\n\n                        elif isinstance(sObject,(Part.Ellipse)):\n                            longueurObjet = sObject.length()\n                            CentreObjet = sObject.Center\n                            MajorRadiusObjet = sObject.MajorRadius\n                            MinorRadiusObjet = sObject.MinorRadius\n\n                        elif isinstance(sObject,(Part.ArcOfEllipse)):\n                            longueurObjet = sObject.length()\n                            CentreObjet = sObject.Center\n                            MajorRadiusObjet = sObject.MajorRadius\n                            MinorRadiusObjet = sObject.MinorRadius\n\n                        elif isinstance(sObject,(Part.ArcOfParabola)):\n                            longueurObjet = sObject.length()\n                            CentreObjet = sObject.Center\n        \n                        elif isinstance(sObject,(Part.ArcOfHyperbola)):\n                            longueurObjet = sObject.length()\n                            CentreObjet = sObject.Center\n                            MajorRadiusObjet = sObject.MajorRadius\n                            MinorRadiusObjet = sObject.MinorRadius\n\n                        else:\n                            None\n\n                        if switch_User_Display_LengthObject == 1:              # longueurObjet \n                            try:\n                                if longueurObjet != 0.0:\n                                    longueurSTR = \" (L:\" + str(round(longueurObjet * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs  + \") \"\n                                    lineEdit += longueurSTR\n                            except Exception: None\n\n                        if switch_User_Display_RadiusObject == 1:              # rayon objet\n                            try:\n                                if rayonObjet != 0.0:\n                                    rayonObjetSTR = (\"(r:\" + str(round(rayonObjet * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs + \") \")\n                                    diametreObjetSTR = (\" [D:\" + str(round(rayonObjet * 2.0, seT_User_DecimalValue)) + \" \" + uniteMs + \"] \")\n                                    lineEdit += rayonObjetSTR + diametreObjetSTR\n                            except Exception: None\n\n                        if switch_User_Display_RadiusSurface == 1:             # rayon d'une surface\n                            try:\n                                if rayonSurface != 0.0:\n                                    rayonSurfaceSTR = (\"(rS:\" + str(round(rayonSurface * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs + \") \")\n                                    diametreSurfaceSTR = (\" [DS:\" + str(round(rayonSurface * 2.0, seT_User_DecimalValue)) + \" \" + uniteMs + \"] \")\n                                    lineEdit += rayonSurfaceSTR + diametreSurfaceSTR\n                            except Exception: None\n\n                        if switch_User_Display_CentreObject == 1:              # centre cercle et autres\n                            try:\n                                if CentreObjet != \"\":\n                                    CentreObjetSTR = (\" (Ce:\" + \"X:\" + str(round(float(CentreObjet[0] * uniteM), seT_User_DecimalValue)) + \" \" + uniteMs + \",\" + \n                                                                \"Y:\" + str(round(float(CentreObjet[1] * uniteM), seT_User_DecimalValue)) + \" \" + uniteMs + \",\" + \n                                                                \"Z:\" + str(round(float(CentreObjet[2] * uniteM), seT_User_DecimalValue)) + \" \" + uniteMs + \") \")\n                                    lineEdit += CentreObjetSTR\n                            except Exception: None\n\n                        #try:\n                        #    radiusObjectSTR = (\" (r:\" + \"Min:\" + str(round(float(MajorRadiusObjet * uniteM), seT_User_DecimalValue)) + \" \" + uniteMs + \", \" + \n                        #                                \"Maj:\" + str(round(float(MinorRadiusObjet * uniteM), seT_User_DecimalValue)) + \" \" + uniteMs + \") \")\n                        #    lineEdit += radiusObjectSTR\n                        #except Exception: None\n\n                    except Exception:\n                        App.Console.PrintError(\"Error read Sketcher\")\n            #### sketcher end  ####\n\n            else:\n                #### Shape Mesh Points Begin ####\n                try:\n                    if hasattr(objs[0],   \"Shape\"):  # object Shape\n                        sObj = objs[0].Shape\n                    elif hasattr(objs[0], \"Mesh\"):   # object mesh      # upgrade with wmayer thanks #http://forum.freecadweb.org/viewtopic.php?f=13&t=22331\n                        sObj = objs[0].Mesh\n                        ######## appel 2 fois sinon le premier appel donne 0 ? meme comme ca !!\n                        try:\n                            Gui.ActiveDocument.ActiveView.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), infoFaceMesh)\n                        except Exception: None\n                        try:\n                            infoFaceMesh2 = infoFaceMesh = Gui.ActiveDocument.ActiveView.addEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), getNormal)\n                            infoFaceMesh2 = infoFaceMesh = Gui.ActiveDocument.ActiveView.addEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), getNormal)\n                            Gui.ActiveDocument.ActiveView.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), infoFaceMesh)\n                        except Exception: None\n                        ########\n                    elif hasattr(objs[0], \"Points\"): # object Points\n                        sObj = objs[0].Points\n                    else:\n                        sObj = \"x\"\n                except Exception:\n                    sObj = \"x\"\n\n                if switch_User_Display_ShapeType == 1:                  # Shape Type\n                    try:\n                        typeObjectShapeTypeSTRAsterix = \" *\"\n                        typeObjectShapeTypeSTR = sObj.ShapeType\n                        lineEdit += \" (TyS:\" + str(typeObjectShapeTypeSTR) + \") \"\n                    except Exception:\n                        try:\n                            if hasattr(objs[0], \"Mesh\"):\n                                lineEdit += \" (Ty:\" + \"Mesh\" + \") \"\n                            if hasattr(objs[0], \"Points\"):\n                                lineEdit += \" (Ty:\" + \"Point\" + \") \"\n                            else:\n                                None\n                        except Exception: None\n\n#                if switch_User_Display_SommeAllEdgesObject == 1:       # sommeEdges total edges\n#                    try:\n#                        sommeEdgesSTRAsterix = \" *\"\n#                        for j in sObj.Edges:\n#                            sommeEdges += j.Length\n#                        sommeEdgesSTR = str(sommeEdges)\n#                        lineEdit += \" (Se:\" + sommeEdgesSTR + \") \"\n#                    except Exception: None\n\n                if switch_User_Display_TypeId == 1:                     # Shape TypeId\n                    try:\n                        typeObjectTypeIdSTRAsterix = \" *\"\n                        typeObjectTypeIdSTR = str(sel[0].Shape.TypeId)\n                        lineEdit += \" (TyI:\" + typeObjectTypeIdSTR + \") \"\n                    except Exception: None\n\n                if switch_User_Display_NumberFacesMesh == 1:            # Nombre Faces Mesh\n                    try:\n                        nombreFacesMeshSTRAsterix = \" *\"\n                        if hasattr(objs[0], \"Mesh\"):\n                            nombreFacesMesh   = sObj.CountFacets\n                            nombreFacesMeshSTR = str(nombreFacesMesh)\n                            lineEdit += \" (Nf:\" + nombreFacesMeshSTR + \") \"\n                    except Exception: None\n\n                if switch_User_Display_NumberPointsMeshPoints == 1:     # Nombre Points Mesh\n                    try:\n                        nombrePointsMeshSTRAsterix = \" *\"\n                        if (hasattr(objs[0], \"Mesh\")) or (hasattr(objs[0], \"Points\")):\n                            nombrePointsMesh  = sObj.CountPoints\n                            nombrePointsMeshSTR = str(nombrePointsMesh)\n                            lineEdit += \" (Np:\" + nombrePointsMeshSTR + \") \"\n                    except Exception: None\n\n                if switch_User_Display_NumberEdgesMesh == 1:             # Nombre Edges Mesh\n                    try:\n                        nombreArretesMeshSTRAsterix = \" *\"\n                        if hasattr(objs[0], \"Mesh\"):\n                            try:                                # no in version 018\n                                nombreArretesMesh = sObj.CountEdges\n                            except Exception:\n                                nombreArretesMesh = 0\n                            nombreArretesMeshSTR = str(nombreArretesMesh)\n                            lineEdit += \" (Ne:\" + nombreArretesMeshSTR + \") \"\n                    except Exception: None\n\n                if switch_User_Display_RadiusObject == 1:                # radius object\n                    try:\n                        rayonObjetSTRAsterix = \" *\"\n                        rayonObjet    = selEx.Curve.Radius\n                        rayonObjetSTR = (\"(r:\" + str(round(rayonObjet * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs + \") \")\n                        diametreObjetSTR = (\" [D:\" + str(round(rayonObjet * 2.0, seT_User_DecimalValue)) + \" \" + uniteMs + \"] \")\n                        lineEdit += rayonObjetSTR + diametreObjetSTR\n                    except Exception: None\n\n                if switch_User_Display_RadiusSurface == 1:               # radius surface\n                    try:\n                        rayonSurfaceSTRAsterix = \" *\"\n                        rayonSurface =  selEx.Surface.Radius\n                        rayonSurfaceSTR = (\"(rS:\" + str(round(rayonSurface * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs + \") \")\n                        diametreSurfaceSTR = (\" [DS:\" + str(round(rayonSurface * 2.0, seT_User_DecimalValue)) + \" \" + uniteMs + \"] \")\n                        lineEdit += rayonSurfaceSTR + diametreSurfaceSTR\n                    except Exception: None\n\n                if switch_User_Display_LengthObject == 1:                # longueurObjet \n                    try:\n                        longueurSTRAsterix = \" *\"\n                        if hasattr(objs[0], \"Mesh\"):\n                            try:\n                                length0 = sObj.Facets[int(indexFaceMeshSTR)].getEdge(0).Length # getEdge no in version 018\n                                length1 = sObj.Facets[int(indexFaceMeshSTR)].getEdge(1).Length\n                                length2 = sObj.Facets[int(indexFaceMeshSTR)].getEdge(2).Length\n                                longueurObjet = length0 + length1 + length2  # perimetre triangle\n                            except Exception:\n                                longueurObjet = length0 = length1 = length2 = 0.0\n                            if longueurObjet != 0.0:\n                                longueurSTR = \" (P:\" + str(round(longueurObjet * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs  + \") \"\n                                lineEdit += longueurSTR\n                        else:\n                            longueurObjet    = selEx.Length\n                            if longueurObjet != 0.0:\n                                if \"Face\" in str(selEx):\n                                    longueurSTR = \" (P:\" + str(round(longueurObjet * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs  + \") \"\n                                else:\n                                    longueurSTR = \" (L:\" + str(round(longueurObjet * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs  + \") \"\n                                lineEdit += longueurSTR\n                    except Exception: None\n\n                if switch_User_Display_SommeAllEdgesObject == 1:       # sommeEdges total edges\n                    try:\n                        sommeEdgesSTRAsterix = \" *\"\n                        for j in sObj.Edges:\n                            sommeEdges += j.Length\n                        sommeEdgesSTR = str(round(sommeEdges * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs\n                        lineEdit += \" (Se:\" + sommeEdgesSTR + \") \"\n                    except Exception: None\n\n                if switch_User_Display_AreaObject == 1:                # surface\n                    try:\n                        surfaceObjSTRAsterix = \" *\"\n                        if hasattr(objs[0], \"Mesh\"):\n                            surfaceObj = sObj.Area\n                        else:\n                            surfaceObj = sel[0].Shape.Area\n                        if surfaceObj != 0.0:\n                            surfaceObjSTR = str(round(surfaceObj * uniteS, seT_User_DecimalValue)) +\" \"+ uniteSs\n                            lineEdit += \" (Ao:\" + surfaceObjSTR + \") \"\n                    except Exception: None\n\n                if switch_User_Display_AreaSubObject == 1:             # surface face\n                    try:\n                        surfaceFaceSTRAsterix = \" *\"\n                        if hasattr(objs[0], \"Mesh\"):\n                            surfaceFace = sObj.Facets[int(indexFaceMeshSTR)].Area\n                        else:\n                            surfaceFace = selEx.Area\n                        if surfaceFace != 0.0:\n                            surfaceFaceSTR = str(round(surfaceFace * uniteS, seT_User_DecimalValue)) +\" \"+ uniteSs\n                            lineEdit += \" (Af:\" + surfaceFaceSTR + \") \"\n                    except Exception: None\n\n                if switch_User_Display_VolumeObject == 1:              # Volume \n                    try:\n                        volumeObjectSTRAsterix = \" *\"\n                        if hasattr(objs[0], \"Mesh\"):\n                            volumeObject = sObj.Volume\n                        else:\n                            volumeObject = sel[0].Shape.Volume\n                        if volumeObject != 0.0:\n                            volumeObjectSTR = str(round(volumeObject * uniteV, seT_User_DecimalValue)) + \" \" + uniteVs\n                            lineEdit += \" (V:\" + volumeObjectSTR + \") \"\n                    except Exception: None\n\n                if switch_User_Display_BsplineObject == 1:             # Bspline\n                    try:\n                        bsplineSTRAsterix = \" *\"\n                        BsplineDetect = selEx.Curve\n                        BsplineNombreDeNoeuds = BsplineDetect.NbKnots\n                        bsplineNoeudsSTR = \" (BSKnots:\" + str(BsplineNombreDeNoeuds) + \" n) \"\n\n                        #### toBiArcs\n                        setBSplineToByArcValue = 0.00001\n                        BsplineArcsToBiArcs  = BsplineDetect.toBiArcs(setBSplineToByArcValue)\n                        BsplineNumberElement = len(BsplineArcsToBiArcs)\n\n                        for i in BsplineArcsToBiArcs:              # radius on point \"toBiArcs(0.00001)\"\n                            try:\n                                BsplineArcsRadius.append(i.Radius) # .Axis  , Vector (-0.72, 0.495, -0.47)\n                                rayonObjet = BsplineArcsRadius[0]\n                            except Exception:\n                                BsplineArcsRadius = []\n                                rayonObjet = 0.0  # rayon approximatif \n                        BsplineNumberToBiArcs = len(BsplineArcsToBiArcs)\n\n                        #### toBiArcs\n                        BsplineRayonApproximatif = str(round(BsplineArcsRadius[0] * float(uniteM))) + \" \" + uniteMs\n                        try:\n                            #### distance between 2 points Shape\n                            bsplineL = sel[0]\n                            BsplineLength = float(bsplineL.Shape.Length)\n                            BsplineCutLength = BsplineLength / float(BsplineNumberElement)\n                            #### points noeuds\n                            for i in bsplineL.Points:     # nombre de points (noeuds)\n                                BsplinePointsCoorS.append(i)\n                            #### points Shape\n                            bsplinePointsCoorShapeSTR = \" (BSS:\" + str(len(BsplinePointsCoorS)) + \" p) \" #BSpline Shape\n                        except Exception:  #    None\n                            #### distance between 2 points Curve.getPoles()                     #BSpline SubObject\n                            bsplineL = selEx #.Curve\n                            BsplineLength = float(bsplineL.Length)\n                            BsplineCutLength = BsplineLength / float(BsplineNumberElement)\n                            #### points a.Curve.NbKnots\n                            for i in selEx.Curve.getPoles():          # nombre de poles (noeuds)\n                                BsplinePointsCoorSo.append(i)\n                            bsplinePointsCoorSoSTR = \" (BSc:\" + str(len(BsplinePointsCoorSo)) + \" p) \"\n                            #### points a.Curve.NbKnots\n\n                        bsplineRayonObjetAppSTR = \" (BSrA:\" + str(round(rayonObjet * float(uniteM),seT_User_DecimalValue)) + \" \" + uniteMs +\") \"\n                        lineEdit += bsplineNoeudsSTR + bsplineRayonObjetAppSTR + bsplinePointsCoorSoSTR + bsplinePointsCoorShapeSTR\n                    except Exception: None\n\n                if switch_User_Display_CentreObject == 1:              # centre cercle\n                    try:\n                        centreObjetSTRAsterix = \" *\"\n                        if hasattr(objs[0], \"Mesh\"):\n                            CenterOfMassX = sObj.CenterOfGravity[0]\n                            CenterOfMassY = sObj.CenterOfGravity[1]\n                            CenterOfMassZ = sObj.CenterOfGravity[2]\n                            boundBoxLocation = App.Vector(CenterOfMassX, CenterOfMassY, CenterOfMassZ)\n                        else:\n                            try:\n                                boundBoxLocation = selEx.Curve.Center\n                            except Exception:\n                                #boundBoxLocation = selEx.CenterOfMass\n                                boundBoxLocation = selEx.BoundBox.Center\n                        #### correction\n                        BDvol = adjustedGlobalPlacement(objs[0], boundBoxLocation)\n                        ####\n                        boundBoxCenterX = BDvol.Base[0] \n                        boundBoxCenterY = BDvol.Base[1] \n                        boundBoxCenterZ = BDvol.Base[2] \n                        centreObjet = App.Vector(boundBoxCenterX, boundBoxCenterY, boundBoxCenterZ)\n                        if centreObjet != \"\":\n                            centreObjetSTR = (\" (Ce:\" + \"X:\" + str(round(float(boundBoxCenterX * uniteM), seT_User_DecimalValue)) + \" \" + uniteMs + \",\" + \n                                                        \"Y:\" + str(round(float(boundBoxCenterY * uniteM), seT_User_DecimalValue)) + \" \" + uniteMs + \",\" + \n                                                        \"Z:\" + str(round(float(boundBoxCenterZ * uniteM), seT_User_DecimalValue)) + \" \" + uniteMs + \") \")\n                            lineEdit += centreObjetSTR\n                    except Exception: None\n\n                if switch_User_Display_CentreBoundBoxObject == 1:      # centre BoundBox objet\n                    try:\n                        centreBBSTRAsterix = \" *\"\n                        boundBox_ = sObj.BoundBox\n                        boundBoxLX = boundBox_.XLength\n                        boundBoxLY = boundBox_.YLength\n                        boundBoxLZ = boundBox_.ZLength\n                        try:\n                            boundBoxDiag = boundBox_.DiagonalLength\n                        except Exception:\n                            boundBoxDiag = 0.0\n                        #### correction\n                        boundBoxLocation = App.Vector(boundBox_.Center[0], boundBox_.Center[1], boundBox_.Center[2])\n                        BDvol = adjustedGlobalPlacement(objs[0], boundBoxLocation)\n                        ####\n                        boundBoxCenterX = BDvol.Base[0] \n                        boundBoxCenterY = BDvol.Base[1] \n                        boundBoxCenterZ = BDvol.Base[2] \n                        centreBBSTR = (\" (BBCe:\" + \"X:\" + str(round(float(boundBoxCenterX * uniteM), seT_User_DecimalValue)) + \" \" + uniteMs + \",\" + \n                                                   \"Y:\" + str(round(float(boundBoxCenterY * uniteM), seT_User_DecimalValue)) + \" \" + uniteMs + \",\" + \n                                                   \"Z:\" + str(round(float(boundBoxCenterZ * uniteM), seT_User_DecimalValue)) + \" \" + uniteMs + \") \")\n                        lineEdit += centreBBSTR\n                    except Exception: None\n                #### Shape Mesh Points End ####\n\n                if switch_User_Display_Position == 1:                  # position pour Normal\n                    try:\n                        positionSTRAsterix = \" *\"\n                        position0STR = position1STR = position2STR = \"\"\n                        position0STR = str(round(position[0] * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs\n                        position1STR = str(round(position[1] * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs\n                        position2STR = str(round(position[2] * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs\n                        positionSTR = \" (Pos: X:\" + position0STR + \" Y:\" + position1STR + \" Z:\" + position2STR + \") \"\n                        lineEdit += positionSTR\n                    except Exception: None\n\n            if (switch_User_Display_Position_2D_CAD == 1) or (switch_User_Display_Position_2D_BMP == 1): # position pour 2D \n                try:\n                    Position2DSTRAsterix =  \" *\"\n                    pos2D0STR = str(pos2D[0])\n                    pos2D1STR = str(pos2D[1])                             # CAD Y : Y0 = coin Inferieur Gauche\n                    try:\n                        if switch_User_Display_Position_2D_BMP == True:   # BMP Y : Y0 = coin Superieur Gauche\n                             pos2D1STR = str(Gui.activeDocument().activeView().getSize()[1] - pos2D[1] )  # reverse Y : Y0 = coin Superieur Gauche\n                    except Exception:\n                        None\n                    pos2DSTR = \" (Pos: X2D:\" + pos2D0STR + \"px Y2D:\" + pos2D1STR + \"px) \"\n                    lineEdit += pos2DSTR\n                except Exception: None\n\n            seT_User_TextHeigthValue = FreeCAD_Paramter.GetInt(\"seT_User_TextHeigthValue\")\n            fontGlobal_08.setPixelSize(seT_User_TextHeigthValue)\n            lineEdit_ToolBar.setFont(fontGlobal_08)\n            lineEdit_ToolBar.setText(lineEdit)\n\n            lineEdit_ToolBar.setToolTip(\"\\n\" +\n                                        \"*****\" + \"\\n\" +\n                                        \"Preselection\" + \"\\t\\t\" +      \":\" + switch_User_Work_With_PreselectionAsterix + \"\\t\\t\\t\" + \":\" + \"\\t\" + str(switch_User_Work_With_Preselection) + \"\\n\" +\n                                        \"*****\" + \"\\n\" +\n                                        \"Element Name\" + \"\\t\\t\" +      \":\" + objectNameAsterix + \"\\t\" + \"( )\" + \"\\t\\t\" + \":\" + \"\\t\" + str(objectName) + \"\\n\" +\n                                        \"Sub element Name\" + \"\\t\" +    \":\" + SubElementNameAsterix + \"\\t\" + \"( )\" + \"\\t\\t\" + \":\" + \"\\t\" + str(SubElementName) + \"\\n\" +\n                                        \"Shape Type\" + \"\\t\\t\" +        \":\" + typeObjectShapeTypeSTRAsterix + \"\\t\" + \"(TyS)\" + \"\\t\\t\" + \":\" + \"\\t\" + typeObjectShapeTypeSTR + \"\\n\" +\n                                        \"Shape TypeId\" + \"\\t\\t\" +      \":\" + typeObjectTypeIdSTRAsterix + \"\\t\" + \"(TyI)\" + \"\\t\\t\" + \":\" + \"\\t\" + typeObjectTypeIdSTR + \"\\n\" +\n                                        \"*****\" + \"\\n\" +\n                                        \"Sketcher TypeObject\" + \"\\t\" + \":\" + typeObjectTypeIdSTRAsterix + \"\\t\" + \"(TyO)\" + \"\\t\\t\" + \":\" + \"\\t\" + sketchObjectTypeSTR + \"\\n\" +\n                                        \"Sketcher Index\" + \"\\t\\t\" +    \":\" + \" *\" + \"\\t\" + \"(I)\" + \"\\t\\t\" + \":\" + \"\\t\" + str(indexSubObject) + \"\\n\" +\n                                        \"*****\" + \"\\n\" +\n                                        \"Radius\" + \"\\t\\t\\t\" +          \":\" + rayonObjetSTRAsterix + \"\\t\" + \"(r)\" + \"\\t\\t\" + \":\" + \"\\t\" + str(round(rayonObjet * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs + \"\\n\" +\n                                        \"Diameter\" + \"\\t\\t\" +          \":\" + rayonObjetSTRAsterix + \"\\t\" + \"[D]\" + \"\\t\\t\" + \":\" + \"\\t\" + str(round(rayonObjet * 2.0 * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs + \"\\n\" +\n                                        \"RadiusSurface\" + \"\\t\\t\" +     \":\" + rayonSurfaceSTRAsterix + \"\\t\" + \"(rS)\" + \"\\t\\t\" + \":\" + \"\\t\" + str(round(rayonSurface * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs + \"\\n\" +\n                                        \"DiameterSurface\" + \"\\t\\t\" +   \":\" + rayonSurfaceSTRAsterix + \"\\t\" + \"[DS]\" + \"\\t\\t\" + \":\" + \"\\t\" + str(round(rayonSurface * 2.0 * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs + \"\\n\" +\n                                        \"Length or Perimeter\" + \"\\t\" + \":\" + longueurSTRAsterix + \"\\t\" + \"(L) or (P)\" + \"\\t\\t\" + \":\" + \"\\t\" + str(round(longueurObjet * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs + \"\\n\" +\n                                        \"Somme Edges\" + \"\\t\\t\" +       \":\" + sommeEdgesSTRAsterix + \"\\t\" + \"(Se)\" + \"\\t\\t\" + \":\" + \"\\t\" + str(round(sommeEdges * uniteM, seT_User_DecimalValue)) + \" \" + uniteMs + \"\\n\" +\n                                        \"*****\" + \"\\n\" +\n                                        \"Number Faces Mesh\" + \"\\t\" +   \":\" + nombreFacesMeshSTRAsterix + \"\\t\" + \"(Nf)\" + \"\\t\\t\" + \":\" + \"\\t\" + nombreFacesMeshSTR + \" faces\" + \"\\n\" +\n                                        \"Num. Points Mesh/Points\" + \"\\t\"+ \":\" + nombrePointsMeshSTRAsterix + \"\\t\" + \"(Np)\" + \"\\t\\t\" + \":\" + \"\\t\" + nombrePointsMeshSTR + \" points\" + \"\\n\" +\n                                        \"Number Edges Mesh\" + \"\\t\" +   \":\" + nombreArretesMeshSTRAsterix + \"\\t\" + \"(Ne)\" + \"\\t\\t\" + \":\" + \"\\t\" + nombreArretesMeshSTR + \" edges\" + \"\\n\" +\n                                        \"*****\" + \"\\n\" +\n                                        \"Area Object\" + \"\\t\\t\" +       \":\" + surfaceObjSTRAsterix + \"\\t\" + \"(Ao)\" + \"\\t\\t\" + \":\" + \"\\t\" + str(round(surfaceObj * uniteS, seT_User_DecimalValue)) +\" \"+ uniteSs + \"\\n\" +\n                                        \"Area Face\" + \"\\t\\t\" +         \":\" + surfaceFaceSTRAsterix + \"\\t\" + \"(Af)\" + \"\\t\\t\" + \":\" + \"\\t\" + str(round(surfaceFace * uniteS, seT_User_DecimalValue)) +\" \"+ uniteSs + \"\\n\" +\n                                        \"Volume\" + \"\\t\\t\\t\" +          \":\" + volumeObjectSTRAsterix + \"\\t\" + \"(V)\" + \"\\t\\t\" + \":\" + \"\\t\" + str(round(volumeObject * uniteV, seT_User_DecimalValue)) + \" \" + uniteVs + \"\\n\" +\n                                        \"*****\" + \"\\n\" +\n                                        \"BSPline Node\" + \"\\t\\t\" +      \":\" + bsplineSTRAsterix + \"\\t\" + \"(BSpline)\" + \"\\t\\t\" + \":\" + \"\\t\" + str(BsplineNombreDeNoeuds) + \" \" + \"nodes\" + \"\\n\" +\n                                        \"BSPline radius\" + \"\\t\\t\" +    \":\" + bsplineSTRAsterix + \"\\t\" + \"(BSrA)\" + \"\\t\\t\" + \":\" + \"\\t\" + str(round(rayonObjet * float(uniteM),seT_User_DecimalValue)) + \" \" + uniteMs + \"\\n\" +\n                                        \"BSPline Points Shape\" + \"\\t\"+ \":\" + bsplineSTRAsterix + \"\\t\" + \"(BSS)\" + \"\\t\\t\" + \":\" + \"\\t\" + str(len(BsplinePointsCoorS)) + \" \" + \"points\" + \"\\n\" +\n                                        \"BSPline Points SubObj\" +\"\\t\"+ \":\" + bsplineSTRAsterix + \"\\t\" + \"(BSc)\" + \"\\t\\t\" + \":\" + \"\\t\" + str(len(BsplinePointsCoorSo)) + \" \" + \"points\" + \"\\n\" +\n                                        \"*****\" + \"\\n\" +\n                                        \"Center Circle or Mesh\"+\"\\t\" + \":\" + centreObjetSTRAsterix + \"\\t\" + \"(Ce)\" + \"\\t\\t\" + \":\" + \"\\t\" + centreObjetSTR + \"\\n\" +\n                                        \"BoundBox center\" + \"\\t\\t\" +   \":\" + centreBBSTRAsterix + \"\\t\" + \"(BBCe)\" + \"\\t\\t\" + \":\" + \"\\t\" + centreBBSTR + \"\\n\" +\n                                        \"Mouse position\" + \"\\t\\t\" +    \":\" + positionSTRAsterix + \"\\t\" + \"(Pos)\" + \"\\t\\t\" + \":\" + \"\\t\" + positionSTR + \"\\n\" +\n                                        \"*****\" + \"\\n\" +\n                                        \"Mouse position screen 2D\" + \"\\t\"+ \":\" + Position2DSTRAsterix + \"\\t\" + \"(Pos: X2D)\" + \"\\t\" + \":\" + \"\\t\" + pos2DSTR + \"\\n\" +\n                                        \"*****\" + \"\\n\" +\n                                        __title__ + \"\\t\" + \"Version : \" + __version__ + \"\\t\" + \"Date : \" + __date__ + \"\\n\" +\n                                        \"*****\" + \"\\n\")\n\n            if lineEdit == \" ()  () \" or lineEdit == \"\":\n                lineEdit_ToolBar.setText(\"Go to [Tools Edit paramater : User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__ + \"]\" + \"\\n\" +\n                                         \" check your choice(s) to display and click the Refresh button, choice your Unit Enjoy.\")\n                lineEdit_ToolBar.setToolTip(\"Go to [Tools Edit paramater : User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__ + \"]\" + \"\\n\" +\n                                         \" check your choice(s) to display and click the Refresh button, choice your Unit Enjoy.\")\n                lineEdit_ToolBar.setStyleSheet(\"QLineEdit {color: black; background-color: red}\")\n            else:\n                lineEdit_ToolBar.setStyleSheet(\"QLineEdit {color: QPalette.Base; background-color: QPalette.Base}\")\n            lineEdit_ToolBar.setCursorPosition(0)\n        except Exception:\n            lineEdit_ToolBar.setText(\"Error or Go to [Tools Edit paramater : User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__ + \"]\" + \"\\n\" +\n                                     \" check your choice(s) to display and click the Refresh button, choice your Unit Enjoy.\")\n            lineEdit_ToolBar.setToolTip(\"Error or Go to [Tools Edit paramater : User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__ + \"]\" + \"\\n\" +\n                                     \" check your choice(s) to display and click the Refresh button, choice your Unit Enjoy.\")\n            lineEdit_ToolBar.setStyleSheet(\"QLineEdit {color: black; background-color: red}\")\n#            lineEdit = \"-\"\n#            lineEdit_ToolBar.setText(lineEdit)\n\ndef SIGNAL_comboBox_Changed(text):\n        global uniteM\n        global uniteMs\n        global uniteS\n        global uniteSs\n        global uniteV\n        global uniteVs\n        global seT_User_UnitSymbolSquare\n        global seT_User_UnitSymbolCube\n        global seT_User_UnitSymbolMicro\n        global seT_System_IndexUnitLength\n        global seT_System_IndexUnitText\n        global comboBox_ToolBar\n        global FreeCAD_Paramter\n\n        if text == \"km\":         #        = 1000000\n            uniteM = 0.000001\n            uniteMs= \"km\"\n            uniteS = 0.000000000001\n            uniteSs= \"km\"+seT_User_UnitSymbolSquare\n            uniteV = 0.000000000000000001\n            uniteVs= \"km\"+seT_User_UnitSymbolCube\n        elif text == \"hm\":       #        = 100000\n            uniteM = 0.00001\n            uniteMs= \"hm\"\n            uniteS = 0.0000000001\n            uniteSs= \"hm\"+seT_User_UnitSymbolSquare\n            uniteV = 0.000000000000001\n            uniteVs= \"hm\"+seT_User_UnitSymbolCube\n        elif text == \"dam\":      #        = 10000\n            uniteM = 0.0001\n            uniteMs= \"dam\"\n            uniteS = 0.00000001\n            uniteSs= \"dam\"+seT_User_UnitSymbolSquare\n            uniteV = 0.000000000001\n            uniteVs= \"dam\"+seT_User_UnitSymbolCube\n        elif text == \"m\":        #        = 1000\n            uniteM = 0.001\n            uniteMs= \"m\"\n            uniteS = 0.000001\n            uniteSs= \"m\"+seT_User_UnitSymbolSquare\n            uniteV = 0.000000001\n            uniteVs= \"m\"+seT_User_UnitSymbolCube\n        elif text == \"dm\":       #        = 100\n            uniteM = 0.01\n            uniteMs= \"dm\"\n            uniteS = 0.0001\n            uniteSs= \"dm\"+seT_User_UnitSymbolSquare\n            uniteV = 0.000001\n            uniteVs= \"dm\"+seT_User_UnitSymbolCube\n        elif text == \"cm\":       #        = 10\n            uniteM = 0.1\n            uniteMs= \"cm\"\n            uniteS = 0.01\n            uniteSs= \"cm\"+seT_User_UnitSymbolSquare\n            uniteV = 0.001\n            uniteVs= \"cm\"+seT_User_UnitSymbolCube\n        elif text == \"mm\":       #        = 1 ###############################\n            uniteM = 1.0\n            uniteMs= \"mm\"\n            uniteS = 1.0\n            uniteSs= \"mm\"+seT_User_UnitSymbolSquare\n            uniteV = 1.0\n            uniteVs= \"mm\"+seT_User_UnitSymbolCube\n        elif text == seT_User_UnitSymbolMicro+\"m\":  # = 1000 #http://fr.wiktionary.org/wiki/%CE%BCm#conv\n            uniteM = 1000.0\n            uniteMs= seT_User_UnitSymbolMicro+\"m\"\n            uniteS = 1000.0**2\n            uniteSs= seT_User_UnitSymbolMicro+\"m\"+seT_User_UnitSymbolSquare\n            uniteV = 1000.0**3\n            uniteVs= seT_User_UnitSymbolMicro+\"m\"+seT_User_UnitSymbolCube\n        elif text == \"nm\":       #        = 1000000\n            uniteM = 1000000.0\n            uniteMs= \"nm\"\n            uniteS = 1000000.0**2\n            uniteSs= \"nm\"+seT_User_UnitSymbolSquare\n            uniteV = 1000000.0**3\n            uniteVs= \"nm\"+seT_User_UnitSymbolCube\n        elif text == \"pm\":       #        = 1000000000\n            uniteM = 1000000000.0\n            uniteMs= \"pm\"\n            uniteS = 1000000000.0**2\n            uniteSs= \"pm\"+seT_User_UnitSymbolSquare\n            uniteV = 1000000000.0**3\n            uniteVs= \"pm\"+seT_User_UnitSymbolCube\n        elif text == \"fm\":       #        = 1000000000000\n            uniteM = 1000000000000.0\n            uniteMs= \"fm\"\n            uniteS = 1000000000000.0**2\n            uniteSs= \"fm\"+seT_User_UnitSymbolSquare\n            uniteV = 1000000000000.0**3\n            uniteVs= \"fm\"+seT_User_UnitSymbolCube\n        elif text == \"inch\":     # inch   = 25.400\n            uniteM = 1.0/25.400\n            uniteMs= \"in\"\n            uniteS = uniteM**2\n            uniteSs= \"in\"+seT_User_UnitSymbolSquare\n            uniteV = uniteM**3\n            uniteVs= \"in\"+seT_User_UnitSymbolCube\n        elif text == \"link\":     # link   = 201.168\n            uniteM = 1.0/201.168\n            uniteMs= \"lk\"\n            uniteS = uniteM**2\n            uniteSs= \"lk\"+seT_User_UnitSymbolSquare\n            uniteV = uniteM**3\n            uniteVs= \"lk\"+seT_User_UnitSymbolCube\n        elif text == \"foot\":     # foot   = 304.800\n            uniteM = 1.0/304.800\n            uniteMs= \"ft\"\n            uniteS = uniteM**2\n            uniteSs= \"ft\"+seT_User_UnitSymbolSquare\n            uniteV = uniteM**3\n            uniteVs= \"ft\"+seT_User_UnitSymbolCube\n        elif text == \"yard\":     # yard   = 914.400\n            uniteM = 1.0/914.400\n            uniteMs= \"yd\"\n            uniteS = uniteM**2\n            uniteSs= \"yd\"+seT_User_UnitSymbolSquare\n            uniteV = uniteM**3\n            uniteVs= \"yd\"+seT_User_UnitSymbolCube\n        elif text == \"perch\":    #rd # rod   perche    = 5029.200\n            uniteM = 1.0/5029.200\n            uniteMs= \"rd\"\n            uniteS = uniteM**2\n            uniteSs= \"rd\"+seT_User_UnitSymbolSquare\n            uniteV = uniteM**3\n            uniteVs= \"rd\"+seT_User_UnitSymbolCube\n        elif text == \"chain\":    # chain  = 20116.800\n            uniteM = 1.0/20116.800\n            uniteMs= \"ch\"\n            uniteS = uniteM**2\n            uniteSs= \"ch\"+seT_User_UnitSymbolSquare\n            uniteV = uniteM**3\n            uniteVs= \"ch\"+seT_User_UnitSymbolCube\n        elif text == \"furlong\":  # furlong= 201168\n            uniteM = 1.0/201168\n            uniteMs= \"fur\"\n            uniteS = uniteM**2\n            uniteSs= \"fur\"+seT_User_UnitSymbolSquare\n            uniteV = uniteM**3\n            uniteVs= \"fur\"+seT_User_UnitSymbolCube\n        elif text == \"mile\":     # mile   = 1609344\n            uniteM = 1.0/1609344\n            uniteMs= \"mi\"\n            uniteS = uniteM**2\n            uniteSs= \"mi\"+seT_User_UnitSymbolSquare\n            uniteV = uniteM**3\n            uniteVs= \"mi\"+seT_User_UnitSymbolCube\n        elif text == \"league\":   # league = 4828032\n            uniteM = 1.0/4828032\n            uniteMs= \"lea\"\n            uniteS = uniteM**2\n            uniteSs= \"lea\"+seT_User_UnitSymbolSquare\n            uniteV = uniteM**3\n            uniteVs= \"lea\"+seT_User_UnitSymbolCube\n        elif text == \"nautique\": # nautique = 1852000\n            uniteM = 1.0/1852000\n            uniteMs= \"nmi\"\n            uniteS = uniteM**2\n            uniteSs= \"nmi\"+seT_User_UnitSymbolSquare\n            uniteV = uniteM**3\n            uniteVs= \"nmi\"+seT_User_UnitSymbolCube\n\n        seT_System_IndexUnitLength = comboBox_ToolBar.currentIndex()\n        seT_System_IndexUnitText = text\n\n        FreeCAD_Paramter.SetFloat(\"seT_System_uniteM\", uniteM)\n        FreeCAD_Paramter.SetString(\"seT_System_uniteMs\", uniteMs)\n        FreeCAD_Paramter.SetFloat(\"seT_System_uniteS\", uniteS)\n        FreeCAD_Paramter.SetString(\"seT_System_uniteSs\", uniteSs)\n        FreeCAD_Paramter.SetFloat(\"seT_System_uniteV\", uniteV)\n        FreeCAD_Paramter.SetString(\"seT_System_uniteVs\", uniteVs)\n\n        ## demarrage\n        FreeCAD_Paramter.SetInt(\"seT_System_IndexUnitLength\", seT_System_IndexUnitLength)   # seT_System_IndexUnitLength\n        FreeCAD_Paramter.SetString(\"seT_System_IndexUnitText\", seT_System_IndexUnitText)    # seT_System_IndexUnitText\n        activeInfo()\n\n##def displayDView():\n##    global toolbar1\n##    global lineEdit\n##    global lineEdit_ToolBar\n##    global switch_User_Display_ViewDirection\n##    global directionViewAsterix\n##    #global directionView\n##    global directionViewSTR\n##\n##    directionViewAsterix = \"\" \n##    lineEdit_ToolBar.setStyleSheet(\"QLineEdit {QPalette.Base}\")\n##\n##    if switch_User_Display_ViewDirection == 1:       # ViewDirection\n##        directionViewAsterix = \" *\"\n##        directionViewSTR = \"\"\n##        viewBase = FreeCADGui.ActiveDocument.ActiveView.viewPosition().Base\n##        vBx = str(round(viewBase.x, seT_User_DecimalValue))\n##        vBy = str(round(viewBase.y, seT_User_DecimalValue))\n##        vBz = str(round(viewBase.z, seT_User_DecimalValue))\n##\n##        viewRotation = FreeCADGui.ActiveDocument.ActiveView.viewPosition().Rotation.getYawPitchRoll()\n##        vRx = str(round(viewRotation[0], seT_User_DecimalValue))\n##        vRy = str(round(viewRotation[1], seT_User_DecimalValue))\n##        vRz = str(round(viewRotation[2], seT_User_DecimalValue))\n##\n##        vDBase = \"Bx : \" + vBx + \", By : \" + vBy + \", Bz : \" + vBz\n##        vDRota = \"Yaw : \" + vRx + \", Pitch : \" + vRy + \", Roll : \" + vRz\n##        directionViewSTR = \"( \" + vDBase + \" ) ; ( \" + vDRota + \" )\"\n##\n##        lineEdit = \"\"\n##        lineEdit = \"(DView: \" + directionViewSTR + \")\"\n##        lineEdit_ToolBar.setText(lineEdit)\n\n##def decodePointColor2DView(x2DView = 0, y2DView = 0):\n##    # fonctionne mais empeche toute selection\n##    ##https://forum.freecad.org/viewtopic.php?p=696969#p696969\n##    view = Gui.ActiveDocument.ActiveView\n##    vp = view.getViewer().getSoRenderManager().getViewportRegion() # FC ver 0.22\n##    width = vp.getViewportSizePixels()[0]\n##    height = vp.getViewportSizePixels()[1]\n##    ####\n##    #view.saveImage(\"C:/Temp/test01.png\", width, height, \"Current\")\n##    Gui.Selection.clearSelection()\n##    Gui.Selection.clearPreselection()\n##    viewGrab = Gui.ActiveDocument.ActiveView.getViewer()           # FC ver 0.22\n##    img = viewGrab.grabFramebuffer()\n##    #### Clipboard\n##    #data = PySide2.QtCore.QMimeData()\n##    #data.setImageData(img)\n##    #cb=QtGui.QClipboard()\n##    #cb.setMimeData(data, mode=PySide2.QtGui.QClipboard.Clipboard)\n##    #### Clipboard\n##    #### point color #######\n##    point = PySide2.QtGui.QPixmap(img)\n##    ptn2DView = point.toImage()\n\n#### section Observer begin ######################\nclass SelObserver:                                  # selection Observer\n    def addSelection(self, document, objet, element, positionx):  # Selection\n        global SubElementName\n        global objectName\n        global sel\n        global selEx\n        global objs\n        global sObj\n        global sketch0selEx\n\n        SubElementName = element\n        objectName = objet\n\n        sel   = Gui.Selection.getSelection()        # object\n        objs  = [selobj.Object for selobj in FreeCADGui.Selection.getSelectionEx()]\n        if objs == []:\n            objs = [\"x\"]\n        try:\n            sketch0selEx = FreeCADGui.Selection.getSelectionEx()[0]         # unique objet pour sketch\n            selEx = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0]  # unique objet\n        except Exception:\n            selEx = \"\"\n        activeInfo()\n\n    def setPreselection(self,doc,obj,sub):          # preselection\n        global switch_User_Work_With_Preselection\n\n        if switch_User_Work_With_Preselection == 1:\n            global SubElementName\n            global objectName\n            global sel\n            global selEx\n            global objs\n            global lineEdit_ToolBar\n            global sketch0selEx\n\n            objs = sel = []\n            SubElementName = selEx = objectName = \"\"\n            SubElementName = sub\n            objectName = obj\n\n            sel = [FreeCAD.ActiveDocument.getObject(objectName)] + [\",x\"]\n            objs  = sel\n\n            sketch0selEx = App.ActiveDocument.getObject(objectName)\n            selEx = App.ActiveDocument.getObject(objectName).getSubObject(SubElementName)\n\n            if objs == []:\n                objs = [\"x\"]\n\n            activeInfo()\n\n##    def removeSelection(self,doc,obj,sub):             # Effacer l'objet selectionne\n##        print( \"removeSelection\")\n##    def setSelection(self,doc):                        # Selection dans ComboView\n##        print( \"SelObserver quit macro\")\n##    def clearSelection(self,doc):                      # Si clic sur l'ecran, effacer la selection\n##        print( \"clearSelection\")                       # Si clic sur un autre objet, efface le precedent\n\nsTB=SelObserver()\nFreeCADGui.Selection.addObserver(sTB)                    # install the function resident mode\n#FreeCADGui.Selection.removeObserver(sTB)                 # desinstalle la fonction residente\n\n####\n\n#https://forum.freecadweb.org/viewtopic.php?f=22&t=37030&start=20#p315576\nglobal cTB\nglobal oTB\nglobal vTB; vTB=Gui.activeDocument().activeView()\n\nclass DocObserver:                      # document Observer\n    def slotActivateDocument(self,doc):\n        global cTB\n        global oTB\n        global vTB\n\n        try:\n            vTB.removeEventCallback(\"SoEvent\",cTB)                                            # close event observation\n        except Exception: None\n        try: # ajout de ty ... except\n            vTB=Gui.activeDocument().activeView()\n            oTB = ViewObserver(vTB)\n            cTB = vTB.addEventCallback(\"SoEvent\",oTB.logPosition)\n        except Exception: None\n\nobs=DocObserver()\nApp.addDocumentObserver(obs)\nFreeCADGui.Selection.removeObserver(obs)                 # desinstalle la fonction residente\n####\nvTB=Gui.activeDocument().activeView()\nclass ViewObserver:                     # vue souris Observer\n\n    def __init__(self, view):\n        self.view = view\n    def logPosition(self, info):\n        global cTB\n        global oTB\n        global vTB\n        global position\n        global pos2D\n        try:\n            vTB=Gui.activeDocument().activeView()\n            objectSurvol = vTB.getObjectInfo(vTB.getCursorPos())                               # here for objectSurvol preselected\n            position = FreeCAD.Vector(float(objectSurvol[\"x\"]),float(objectSurvol[\"y\"]),float(objectSurvol[\"z\"]))# vector on position mouse to objectSurvol\n            pos2D = info[\"Position\"]  # 2D X,Y \n            activeInfo()\n        except Exception:\n            #pos2D = info[\"Position\"]                                                        # if mouse in 3D view\n            #position = self.view.getPoint(pos2D)                                            # vector detect on mouse position 3D view\n            None\noTB = ViewObserver(vTB)\ncTB = vTB.addEventCallback(\"SoEvent\",oTB.logPosition)\n#vTB.removeEventCallback(\"SoEvent\",cTB)                                            # close event observation\n### section Observer end ######################\n\n#############################################################################\n####\n#try:\nmw = FreeCADGui.getMainWindow()\ntb = mw.findChildren(QtWidgets.QToolBar)\n\nswitchtbar = 0\n\nfor i in tb:\n    if str(i.objectName()) == __title__:\n        FreeCAD.Console.PrintError(__title__ + \" is already open\" + \"\\n\")\n        switchtbar = 1\n#        if i.isVisible():\n#            i.setVisible(False)               # visible False\n#        else:\n#            i.setVisible(True)                # visible True\n        i.setVisible(True)                     # visible True\n        break\n\nif switchtbar == 0:\n    #toolbar1 = QtWidgets.QToolBar()      # place plus haut\n    mw.addToolBar(toolbar1)\n    toolbar1.setObjectName(__title__)\n    toolbar1.setWindowTitle(__title__)\n    #toolbar1.setFloatable(True)\n\n    if seT_User_setFixed_Tool_Bar_Width != 0:\n        toolbar1.setFixedWidth(seT_User_setFixed_Tool_Bar_Width)\n    if seT_User_setFixed_Tool_Bar_Height != 0:\n        toolbar1.setFixedHeight(seT_User_setFixed_Tool_Bar_Height)\n    toolbar1.setIconSize(QSize(seT_User_sizeIconX, seT_User_sizeIconY))\n\n    #### color StyleSheet\n    seT_User_StyleSheetColorToolBar = FreeCAD_Paramter.GetString(\"seT_User_StyleSheetColorToolBar\")\n    if seT_User_StyleSheetColorToolBar == \"\":\n        FreeCAD_Paramter.SetString(\"seT_User_StyleSheetColorToolBar\", \"0\")\n        seT_User_StyleSheetColorToolBar = \"0\"\n    if seT_User_StyleSheetColorToolBar != \"0\":\n        toolbar1.setStyleSheet(\"QToolBar {background-color:\" + seT_User_StyleSheetColorToolBar + \";}\") #F8E6E0\n    else:\n        toolbar1.setStyleSheet(\"QToolBar {QPalette.Base}\")\n\n#    switch_User_Work_With_Preselection     = FreeCAD_Paramter.GetBool(\"switch_User_Work_With_Preselection\")      # switch yes / no preselection\n#    if switch_User_Work_With_Preselection == 1:\n#        switch_User_Work_With_PreselectionAsterix= \" *\"\n#        toolbar1.setStyleSheet(\"QToolBar {QPalette.Base}\")\n#        toolbar1.setStyleSheet(\"QToolBar {color: black; background-color: #F8E6E0}\") # html code  #F8E6E0\n#    else:\n#        switch_User_Work_With_PreselectionAsterix= \"\"\n    #### color\n\n    toolbar1.addAction(QtGui.QIcon(QtGui.QPixmap(Refresh_Icon)), \"Refresh after change in Preference\"+\"\\n\"+\"and activate the modifications\", Refresh_Preference)# icone, ToolTip, vers def:\n\n    #fontGlobal_08 = QtGui.QFont()      # place plus haut\n    fontGlobal_08.setFamily(\"Arial\")\n    #fontGlobal_08.setPointSize(seT_User_TextHeigthValue)\n    fontGlobal_08.setPixelSize(seT_User_TextHeigthValue)\n\n    comboBox_ToolBar = QtWidgets.QComboBox()\n    comboBox_ToolBar.addItem(\"km\")\n    comboBox_ToolBar.addItem(\"hm\")\n    comboBox_ToolBar.addItem(\"dam\")\n    comboBox_ToolBar.addItem(\"m\")\n    comboBox_ToolBar.addItem(\"dm\")\n    comboBox_ToolBar.addItem(\"cm\")\n    comboBox_ToolBar.addItem(\"mm\")  # 1\n    comboBox_ToolBar.addItem(\"um\")\n    comboBox_ToolBar.addItem(\"nm\")\n    comboBox_ToolBar.addItem(\"pm\")\n    comboBox_ToolBar.addItem(\"fm\")\n    comboBox_ToolBar.addItem(\"inch\")\n    comboBox_ToolBar.addItem(\"link\")\n    comboBox_ToolBar.addItem(\"foot\")\n    comboBox_ToolBar.addItem(\"yard\")\n    comboBox_ToolBar.addItem(\"perch\")\n    comboBox_ToolBar.addItem(\"chain\")\n    comboBox_ToolBar.addItem(\"furlong\")\n    comboBox_ToolBar.addItem(\"mile\")\n    comboBox_ToolBar.addItem(\"league\")\n    comboBox_ToolBar.addItem(\"nautique\")\n    comboBox_ToolBar.setCurrentIndex(seT_System_IndexUnitLength)\n    QtCore.QObject.connect(comboBox_ToolBar, QtCore.SIGNAL(\"currentIndexChanged(QString)\"), SIGNAL_comboBox_Changed)\n    ##comboBox_ToolBar.setItemIcon(0, QIcon('C:/Users/Mario/AppData/Roaming/FreeCAD/Macro/Qt.png'))\n\n    toolbar1.addWidget(comboBox_ToolBar)\n    #lineEdit_ToolBar = QtWidgets.QLineEdit()   # place plus haut\n    lineEdit_ToolBar.setFont(fontGlobal_08)\n    toolbar1.addWidget(lineEdit_ToolBar)\n    ####\n#except Exception:\n#    FreeCAD.Console.PrintError(\"Not activeView or ...\" + \"\\n\")\n\nif switch_User_NotInfoOnBeginning == True:\n    ##\n    FreeCAD.Console.PrintMessage(\"\\n\"+\"####Configure FCInfo_ToolBar Begin####################################################################\" + \"\\n\\n\")\n    FreeCAD.Console.PrintMessage(\"_____Help for configure FCInfo_ToolBar_____\" + \"\\n\\n\")\n    FreeCAD.Console.PrintMessage(\"Go to : Menu > Tools > Edit parameters ... :BaseApp/Preferences/Macros/FCMmacros/FCInfo_ToolBar\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____seT_User_StyleSheetColorToolBar_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(seT_User_StyleSheetColorToolBar) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"seT_User_StyleSheetColorToolBar          # False (Default: system) 1 = the size icon user is availlable\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_ToolbarIconSize_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_ToolbarIconSize) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_ToolbarIconSize              # 0 = not setStyleSheet (Default)\" + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"                                         # color in HTML format ex: #F8E6E0\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____seT_User_sizeIconX_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(seT_User_sizeIconX) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"seT_User_sizeIconX                       # size X of the icon (Default: system)\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____seT_User_sizeIconY_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(seT_User_sizeIconY) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"seT_User_sizeIconY                       # size Y of the icon (Default system)\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____seT_User_DecimalValue_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(seT_User_DecimalValue) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"seT_User_DecimalValue                    # number of decimal value (Default 2)\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____seT_User_setFixed_Tool_Bar_Width_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(seT_User_setFixed_Tool_Bar_Width) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"seT_User_setFixed_Tool_Bar_Width         # Width of the ToolBar\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____seT_User_setFixed_Tool_Bar_Height_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(seT_User_setFixed_Tool_Bar_Height) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"seT_User_setFixed_Tool_Bar_Height        # heigth of the ToolBar\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____seT_User_TextHeigthValue_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(seT_User_TextHeigthValue) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"seT_User_TextHeigthValue                 # heigth of the text in the LineEdit\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Work_With_Preselection_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Work_With_Preselection) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Work_With_Preselection       # True  1 = ()  Work With the Preselectiond \" + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"                                         # with this option the selection ins not availlable !\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_objectName_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_objectName) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_objectName           # True  1 = ()  display the Object name selected \" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_SubElementName_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_SubElementName) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_SubElementName       # True  1 = ()  display the subElement name selected \" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_ShapeType_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_ShapeType) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_ShapeType            # True  1 = (TyS:)  display the Shape Type of the object\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_TypeId_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_TypeId) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_TypeId               # True  1 = (TyI:)  display the Shape TypeId of the object\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_RadiusObject_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_RadiusObject) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_RadiusObject         # True  1 = (r:) [D:] display the radius and the diameter (if circle detected) \" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_RadiusSurface_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_RadiusSurface) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_RadiusSurface        # True  1 = (rS:) [DS:] display the radius and the diameter of surface (if surface detected) \" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_NumberFacesMesh_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_NumberFacesMesh) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_NumberFacesMesh      # True  1 = (Nf:) display the number of faces of the Mesh\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_NumberPointsMeshPoints_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_NumberPointsMeshPoints) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_NumberPointsMeshPoints# True  1 = (Np:) display the number of points of the Mesh or Points\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_NumberEdgesMesh_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_NumberEdgesMesh) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_NumberEdgesMesh      # True  1 = (Ne:) display the number of Edges of the Mesh\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_BsplineObject_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_BsplineObject) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_BsplineObject        # True  1 = (BSpline) display the number of node of the BSpline\" + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"                                                   = (BSrA) BSPline radius approximative first radius of the BSpline\" + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"                                                   = (BSS) BSPline Points Shape number points of the Bspline (case Shape)\" + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"                                                   = (BSc) BSPline Points Sub Object number points of sub object selected (case Edge)\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_CentreObject_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_CentreObject) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_CentreObject         # True  1 = (Ce:)display the center of circle (if detected), face, edge ...\" + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"                                                   = or BBoxCenter of face, edge ... Sub selection\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_CentreBoundBoxObject_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_CentreBoundBoxObject) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_CentreBoundBoxObject # True  1 = (BBCe:) display the center of BoundBox of the object \" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_LengthObject_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_LengthObject) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_LengthObject         # True  1 = (L:) display the Length of the wire, edge, line selected\" + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"                                         #           (P:) if one face is selected, the Perimeter of the face is displayed\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_SommeAllEdgesObject_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_SommeAllEdgesObject) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_SommeAllEdgesObject  # True  1 = (Se:) display the Total Length of the edges\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_AreaObject_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_AreaObject) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_AreaObject           # True  1 = (A:) display the Area of the object selected \" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_AreaSubObject_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_AreaSubObject) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_AreaSubObject        # True  1 = (Af:) display the Area of the face selected \" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_VolumeObject_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_VolumeObject) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_VolumeObject         # True  1 = (V:) display the Volume of the object selected\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_Position_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_Position) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_Position             # True  1 = (Pos:) display the coordinate of the click mouse \" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_Position_2D_CAD_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_Position_2D_CAD) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_Position_2D_CAD      # True  1 = (Pos: X2D:) display the position XY 2D 0,0 = corner Inferior left (CAD)\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____switch_User_Display_Position_2D_BMP_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(switch_User_Display_Position_2D_BMP) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"switch_User_Display_Position_2D_BMP      # True  1 = (Pos: X2D:) display the position XY 2D 0,0 = corner Superior left (BitMap BMP)\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____seT_User_UnitSymbolSquare_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(seT_User_UnitSymbolSquare) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"seT_User_UnitSymbolSquare                # give the Square character '2' by default\" + \"\\n\\n\")\n    ##\n    FreeCAD.Console.PrintMessage(\"_____seT_User_UnitSymbolCube_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(seT_User_UnitSymbolCube) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"seT_User_UnitSymbolCube                  # give the Cube character '3' by default\" + \"\\n\\n\") \n    ##\n    FreeCAD.Console.PrintMessage(\"_____seT_User_UnitSymbolMicro_____ \" + \" \")\n    FreeCAD.Console.PrintError(\"Actual \" + str(seT_User_UnitSymbolMicro) + \"\\n\")\n    FreeCAD.Console.PrintMessage(\"seT_User_UnitSymbolMicro                 # give the Micro character 'u' by default\" + \"\\n\\n\") \n    ##\n    FreeCAD.Console.PrintMessage(\"####Configure FCInfo_ToolBar End######################################################################\" + \"\\n\\n\")\n",
    "url": "https://wiki.freecad.org/Macro_FCInfo_ToolBar",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/e382adbe41747788ad15a18eb206a872/raw/c825afd430d9124a77f9688824d12a78b2219348/FCInfo_ToolBar.FCMacro",
    "wiki": "https://wiki.freecadweb.org/Macro_FCInfo_ToolBar",
    "version": "00.05b",
    "license": "",
    "date": "2023/09/06",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\FCInfoToolBar.png",
    "icon_source": "https://wiki.freecad.org/images/9/9d/FCInfoToolBar.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FCInfoGlass",
    "on_wiki": true,
    "on_git": false,
    "desc": "Gives a series of information on the form display in the 3D view.<br /><br />Macro version: 00.05<br />Last modified: 2016-08-28<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/6/6b/Macro_FCInfoGlass.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "displays various informations on the 3DView",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2015 2016 <mario52>                                     *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#30/07/2015 04/08/2015 31/08/2015 25/11/2015 28/08/2016\n#\n#OS: Windows 8\n#Word size of OS: 64-bit\n#Word size of FreeCAD: 64-bit\n#Version: 0.15.4671 (Git)\n#Branch: releases/FreeCAD-0-15\n#Hash: 244b3aef360841646cbfe80a1b225c8b39c8380c\n#Python version: 2.7.8\n#Qt version: 4.8.6\n#Coin version: 4.0.0a\n#OCC version: 6.8.0.oce-0.17\n#\n__title__         = \"FCInfoGlass\"\n__author__        = \"Mario52\"\n__url__           = \"http://www.freecadweb.org/index-fr.html\"\n__version__       = \"00.05\"\n__date__          = \"28/08/2016\" \n\n__Comment__       = \"displays various informations on the 3DView\"\n__Web__           = \"\"\n__Wiki__          = \"http://www.freecadweb.org/wiki/index.php?title=Macro_FCInfoGlass\"\n__Icon__          = \"/usr/lib/freecad/Mod/plugins/icons/.png\"\n__IconW__         = \"C:/Users/xxxxx/AppData/Roaming/FreeCAD/\"    # with : path = FreeCAD.ConfigGet(\"UserAppData\")\n__Help__          = \"\"\n__Status__        = \"finished\"\n__Requires__      = \"FreeCAD 0.14.3706\"\n__Communication__ = \"http://www.freecadweb.org/wiki/index.php?title=User:Mario52\"\n \ntry:\n    import PyQt4\n    from PyQt4 import QtGui ,QtCore\n    from PyQt4.QtGui import *\n    from PyQt4.QtCore import *\nexcept Exception:\n    import PySide\n    from PySide import QtGui ,QtCore\n    from PySide.QtGui import *\n    from PySide.QtCore import *\n \nimport Draft, Part, FreeCAD, math, PartGui, FreeCADGui, FreeCAD\nfrom math import degrees, radians, atan2, sqrt, pi, sin, cos, asin, acos, atan\nfrom FreeCAD import Base\nimport time\n \nglobal path\n#path = \"YourPath\"\n#path = FreeCAD.ConfigGet(\"AppHomePath\")\npath = FreeCAD.ConfigGet(\"UserAppData\")\n\n#######################################################################\nglobal visualiserWindow      ; visualiserWindow                = 0    # si visualiserWindow = 1 la fenetre est visible (pour test)  \"defaut  = 0\"\n                                                                      # if visualiserWindow = 1 the windows is visible (for test)   \"default = 0\"\n###Section Configuration ##############################################\n# Placement window hidden                                             #\nglobal posiX                 ; posiX                           = 900  # position window coordinate X                   \"defaut  = 900\"\nglobal posiY                 ; posiY                           = 190  # position window coordinate Y                   \"defaut  = 190\"\n#######################################################################\nglobal SizeX                 ; SizeX                           = 600  # size window length  (do not modify)            \"defaut  = 600\"\nglobal SizeY                 ; SizeY                           = 600  # size window heigth  (do not modify)            \"defaut  = 600\"\n\n#######################################################################\n# Section color                                                       #\nglobal colorize              ; colorize                      =\"black\" # colorize the text choice                       \"defaut  = \"black\"\n                                                                      # \"black\" \"white\" \"red\" \"green\" \"blue\" \"yellow\" \"magenta\" \"cyan\"\n\n#######################################################################\n# Section inter                                                       #\nglobal mode                  ; mode                            = 1    # mode 1=degrees mode 0=radians                  \"defaut  = 1\"\nglobal arondi                ; arondi                          = 4    # many numbers after the decimal point           \"defaut  = 4\" \nglobal chaineRemplacement    ; chaineRemplacement              = \"_\"  # replacement string (1 character)               \"defaut  = \"_\"\n\n#######################################################################\n# section switch \n# if switch = 1 then actif (True Displayed) else inactif (False not Displayed)\nglobal PrintReportView       ;PrintReportView                  = 1    # Affichage dans la vue rapport                  #0  Displayed ReportView\n## \nglobal DocumentName          ;DocumentName                     = 1    # Nom du document                                #1  Document Name\nglobal InternalName          ;InternalName                     = 1    # Nom interne de l'objet                         #2  Internal Name\nglobal LabelObject           ;LabelObject                      = 1    # Label                                          #3  Label Object\nglobal ElementName           ;ElementName                      = 1    # Nom de l'element                               #4  Element Name\nglobal ObjectType            ;ObjectType                       = 1    # Type d'objet                                   #5  Object Type\nglobal LineSeparateTitle     ;LineSeparateTitle                = 1    # ligne de separation des titres ____________    #6  Line Separate of Title\n\n## Object subObject \nglobal ObjectLength          ;ObjectLength                     = 1    # longueur Objet ou perimetre si c est une face  #7  Object Length or perimetre if are a face\nglobal ObjectCurveRadius     ;ObjectCurveRadius                = 1    # rayon du subObject si arc ou cerle             #8  radius subObject if arc or cirle\nglobal ObjectCurveCenter     ;ObjectCurveCenter                = 1    # coordonnees centrale subObject si arc ou cerle #9  coordinates center subObject if arc or cirle\n\n## Draft\nglobal LineDimension         ;LineDimension                    = 1    # Dimensions Line                                #10  Line Dimension\nglobal DWireDimension        ;DWireDimension                   = 1    # Dimensions DWire                               #11  DWire Dimension\nglobal CircleDimension       ;CircleDimension                  = 1    # Dimensions Circle                              #12 Circle Dimension\nglobal CirclePartDimension   ;CirclePartDimension              = 1    # Dimensions Circle Part                         #13 Circle Part Dimension\n\nglobal ArcDimension          ;ArcDimension                     = 1    # Dimensions Arc                                 #14 Arc Dimension\nglobal EllipseDimension      ;EllipseDimension                 = 1    # Dimensions Ellipse                             #15 Ellipse Dimension\nglobal EllipsePartDimension  ;EllipsePartDimension             = 1    # Dimensions Ellipse Part                        #16 Ellipse Part Dimension\nglobal PolygonDimension      ;PolygonDimension                 = 1    # Dimensions Polygon                             #17 Polygon Dimension\nglobal RectangleDimension    ;RectangleDimension               = 1    # Dimensions Rectangle                           #18 Rectangle Dimension\nglobal BSplineDimension      ;BSplineDimension                 = 1    # Dimensions BSpline                             #19 BSpline Dimension\nglobal PointDimension        ;PointDimension                   = 1    # Dimensions Point                               #20 Point Dimension\nglobal BezCurveDimension     ;BezCurveDimension                = 1    # Dimensions BezCurve                            #21 BezCurve Dimension\n\n## Solid\nglobal CylinderDimension     ;CylinderDimension                = 1    # Dimensions du Cylindre Rayon Hauteur Angle     #22 Cylinder Dimension\nglobal BoxDimension          ;BoxDimension                     = 1    # Dimensions du Box Length Width Height          #23 Box Dimension\nglobal SphereDimension       ;SphereDimension                  = 1    # Dimensions de la Sphere                        #24 Sphere Dimension\nglobal EllipsoidDimension    ;EllipsoidDimension               = 1    # Dimensions Ellipsoid                           #25 Ellipsoid Dimension\nglobal ConeDimension         ;ConeDimension                    = 1    # Dimensions du Cone                             #26 Cone Dimension\nglobal TorusDimension        ;TorusDimension                   = 1    # Dimensions du Tore                             #27 Torus Dimension\n\n## Part\nglobal PlanePartDimension    ;PlanePartDimension               = 1    # Dimensions Plan Part                           #28 Plane Part Dimension\nglobal PrismPartDimension    ;PrismPartDimension               = 1    # Dimensions Prisme Part                         #29 Prism Part Dimension   \nglobal WedgePartDimension    ;WedgePartDimension               = 1    # Dimensions Wedge Part                          #30 Wedge Part Dimension\nglobal HelixPartDimension    ;HelixPartDimension               = 1    # Dimensions Helix Part                          #31 Helix Part Dimension\nglobal SpiralPartDimension   ;SpiralPartDimension              = 1    # Dimensions Spirale Part                        #32 Spiral Part Dimension\nglobal VertexPartDimensio    ;VertexPartDimension              = 1    # Dimensions Vertex Part                         #33 Vertex Part Dimension\nglobal LinePartDimension     ;LinePartDimension                = 1    # Dimensions Line Part                           #34 Line Part Dimension\nglobal RegularPolygonPartDimension;RegularPolygonPartDimension = 1    # Dimensions RegularPolygon Part                 #35 Regular Polygon Part Dimension\n\n## Face\nglobal FaceSurface           ;FaceSurface                      = 1    # Surface de la face                             #36 Face Surface\nglobal NormalAt              ;NormalAt                         = 1    # Donne la normale (inclinaison)                 #37 normalAt(0,0) Face and edges normalAt(0)\nglobal FaceCenter            ;FaceCenter                       = 1    # Center Face (mass)                             #38 Face Center\nglobal BoundBoxFaceVol       ;BoundBoxFaceVol                  = 1    # BoundBoxFace Volume                            #39 BoundBox Face Volume\nglobal BoundBoxFaceCent      ;BoundBoxFaceCent                 = 1    # BoundBoxFaceCenter                             #40 BoundBox Face Center\nglobal BoundBoxFaceCoor      ;BoundBoxFaceCoor                 = 1    # BoundBoxFace coordinates                       #41 BoundBox Face Coordinates\n\n## Volume\nglobal BounBoxVolumeVol      ;BounBoxVolumeVol                 = 1    # rectangle du BoundBox                          #42 BounBox Volume Volume\nglobal BounBoxVolumeCent     ;BounBoxVolumeCent                = 1    # centre de la forme                             #43 BounBox Volume Center\nglobal BounBoxVolumeCoor     ;BounBoxVolumeCoor                = 1    # boundinbox (dimensions hors tout)              #44 BounBox Volume Coordinates\nglobal VolumeObject          ;VolumeObject                     = 1    # volume                                         #45 Volume Object\nglobal CenterMass            ;CenterMass                       = 1    # centre de la masse                             #46 Center Mass object\nglobal PlacementForme        ;PlacementForme                   = 1    # placement de la forme                          #47 Placement Forme\nglobal LineInclination       ;LineInclination                  = 1    # search inclination XY YZ ZX uniquement lignes  #48 Line Inclination\nglobal VertexesObject        ;VertexesObject                   = 1    # Vertexes de l'objet selectionne                #49 Vertexes Object\nglobal VertexesForme         ;VertexesForme                    = 0    # Vertexes complet de la forme                   #50 Vertexes Forme\n                                                                      # peut prendre du temps, depasser la fenetre et donner des donnees incompletes\n                                                                      # can take time and exceed the window and give data's incompletes\n### End Section Switch #######################################################################################################################\n\n# do not modify\nglobal compteur              ; compteur                        = 0    # compteur objets\nglobal texteInfo             ; texteInfo                       = \"\"   # texte\nglobal dummy3                ; dummy3                          = \"\"   #\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n \ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\n##########\n\ndef Around(a) :\n    global arondi\n    return round(a,arondi)\n\ndef decodeSplit(code,titre):\n    global dummy3\n    a = str(code)\n    dummy = a.split(titre)[1]\n    dummy2 = dummy.split(\")\")\n    dummy3 = dummy2[0].split(\",\")\n\ndef angle2(vecteur_x1,vecteur_y1,vecteur_x2,vecteur_y2,mode):\n# calcul de l'inclinaison d'une ligne a partir de deux Vecteurs\n# si \"mode\" = 1 alors affichage en degres sinon en radian\n    try:\n        deltaX = vecteur_x2 - vecteur_x1\n        deltaY = vecteur_y2 - vecteur_y1\n        if mode ==1:\n            angle = degrees(atan2(float(deltaY),float(deltaX)))         # degrees\n        else:\n            angle = atan2(float(deltaY),float(deltaX))                  # radian\n#        return round(angle,6)\n        return angle\n    except Exception:\n        return 0\n\ndef longChaine(ligne):                                                  # longueur de la chaine convertie en points\n    global chaineRemplacement\n    # pas au point     Not finished\n#### new formule ##########################################\n#    font = QFont(\"\", 0)                                                 # a regler chercher les valeurs \"times\" et \"10\"\n#    fm = QFontMetrics(font)\n#    car = chaineRemplacement[0]                                         # caractere de remplissage\n#    car *= 200                                                          # nombre de caracteres a ajouter\n#    ligne += car\n#    longChaine = fm.elidedText(ligne,Qt.ElideRight,200) + \" : \"         # ElideRight ElideLeft ElideMiddle (coupe a x points et met \"...\")\n#\n#### new formule ##########################################\n#    font = QFont(\"times\", 10)                                            # a regler chercher les valeurs \"times\" et \"10\"\n    font = QFont(\"\", 0)                                                  # a regler chercher les valeurs \"times\" et \"10\"\n\n    fm = QFontMetrics(font)\n    newLine = fm.width(ligne)                                            # largeur nouvelle ligne a traiter\n    \n    car = chaineRemplacement[0]                                          # caractere de remplissage\n    esp = car                                                            # un caractere pour tester nombre de pixels\n    car *= 50\n\n    basepixel = fm.width(esp)                                            # largeur de un espace\n    gabariL = \" : RegularPolygon Circumradius\"                           # texte a respecter (longueur de la chaine la plus longue)\n    gabariLine = fm.width(gabariL)                                       # largeur gabari de la chaine\n\n    space = int((gabariLine - newLine) / basepixel)\n    longChaine = ligne + car[:space] + \" : \"\n\n#    ligne += \"______________________________\"\n#    longChaine = ligne[:24] + \" : \"\n\n    return longChaine\n\ndef afficherVR(titre,texte):                                                 # affiche le texte dans la Vue rapport\n    titre += (\" \"*30)                                                        # \" \" = chaine a inclure\n    App.Console.PrintMessage(titre[:25] + \" : \"+unicode(texte) + \"\\n\")                # 25 = longueur de la chaine\n\nclass Ui_MainWindow(object):\n \n    global path\n    global texteInfo\n    def setupUi(self, MainWindow):\n        self.window = MainWindow\n        global path\n        global texteInfo\n        global SizeX\n        global SizeY\n        global posiX\n        global posiY\n        global red\n        global green\n        global blue\n        global visualiserWindow\n\n        MainWindow.setObjectName(\"MainWindow\")\n        MainWindow.setWindowTitle(\"FCInfoGlass \")\n        MainWindow.resize(SizeX, SizeY)                                       # dimensions exterieures de la fenetre\n        MainWindow.setMinimumSize(QtCore.QSize(SizeX, SizeY))                 # \n        MainWindow.setMaximumSize(QtCore.QSize(SizeX, SizeY))                 # \n\n        MainWindow.setGeometry(posiX, posiY, SizeX, SizeY)                    # coin superieur X,Y coin inferieur X,Y positionne la fenetre dans l'ecran\n                                                                              # modify this line for posionned the window\n        ##### if visualiserWindow = 1 then tranparent window\n        if visualiserWindow == 0:\n            MainWindow.setWindowOpacity(1)                                    # rend la fenetre +/- opaque \n            MainWindow.setWindowFlags(QtCore.Qt.FramelessWindowHint)          # rend la fen\u00eatre transparente et cache le cadre\n            MainWindow.setAttribute(QtCore.Qt.WA_TranslucentBackground, True) # ne pas bouger ,True\n            MainWindow.setStyleSheet(\"background:transparent;\")               # rend le fond transparent\n            self.istransparent = True\n        #####\n#############################################\n#\n#        ################ test bouton\n#        self.frame = QtGui.QFrame(MainWindow)\n#        self.frame.setGeometry(QtCore.QRect(10, 370, 381, 24))\n#        self.frame.setFrameShape(QtGui.QFrame.StyledPanel)\n#        self.frame.setFrameShadow(QtGui.QFrame.Raised)\n#        self.frame.setObjectName(_fromUtf8(\"frame\"))\n#        self.PBQuit = QtGui.QPushButton(self.frame)\n#        self.PBQuit.setGeometry(QtCore.QRect(10, 10, 101, 23))\n#        self.PBQuit.setObjectName(_fromUtf8(\"PBQuit\"))\n#        self.PBQuit.clicked.connect(self.on_PBQuit) ###\n#        ###################\n#\n#        self.frame.setWindowOpacity(1)                                       # rend la fenetre +/- opaque \n#        self.frame.setWindowFlags(QtCore.Qt.FramelessWindowHint)             # rend la fen\u00eatre transparente et cache le cadre\n#        self.frame.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)    # ne pas bouger ,True\n#        self.frame.setStyleSheet(\"background:transparent;\")                  # rend le fond transparent\n#        self.istransparent = True\n# \n##########################################\n#        #cree un cadre aux dimensions   MainWindow.resize(400, 400) mais cache la fenetre textEdit  OK\n#        self.centralWidget = QtGui.QWidget(MainWindow)\n#        self.centralWidget.setObjectName(_fromUtf8(\"centralWidget\"))\n#        self.tableWidget = QtGui.QTableWidget(self.centralWidget)\n#        self.tableWidget.setGeometry(QtCore.QRect(0, 0, 400, 400))\n##########################################\n \n        MainWindow.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint) # met la fenetre en avant\n \n        self.centralWidget = QtGui.QWidget(MainWindow)\n        self.centralWidget.setObjectName(_fromUtf8(\"centralWidget\"))\n        self.label = QtGui.QLabel(self.centralWidget)\n        self.label.setGeometry(QtCore.QRect(10, 20, SizeX, SizeY))           # positionne le label (texte) et donne son occupation (surface cadre)abscisse, ordonnee, largeur, hauteur\n        self.label.setObjectName(_fromUtf8(\"label\"))\n\n        MainWindow.setCentralWidget(self.centralWidget)\n        self.retranslateUi(MainWindow)\n#        self.PBQuit.setText(\"Quit\")\n \n    def retranslateUi(self, MainWindow):\n        MainWindow.setWindowTitle(\"Dialog\")\n#        self.PBQuit.setText(\"Quit\")\n        self.label.setText(\"\")\n \n    def on_pushButton_Raf_clicked(self):                                     # affiche le texte concatene dans la fenetre\n        global texteInfo\n        global colorize\n        self.label.setStyleSheet(\"color:\"+colorize)\n        self.label.setText(unicode(texteInfo) + \"\\n\")\n        \n    def on_PBQuit(self):\n        App.Console.PrintMessage(str(\"Fin FCInfoGlass \")+\"\\n\")\n        FreeCADGui.Selection.removeObserver(s)                              # d\u00e9sinstalle la fonction r\u00e9sidente\n        self.window.hide()\n \nclass SelObserver:\n    afficherVR(\"\",\"\")\n    def addSelection(self,document, object, element, position):              # Selection\n            global texteInfo\n            global compteur\n            global dummy3\n\n            global PrintReportView\n            global DocumentName    \n            global InternalName    \n            global LabelObject     \n            global ElementName     \n            global ObjectType      \n            global LineSeparateTitle\n\n            global ObjectLength    \n            global ObjectCurveRadius\n            global ObjectCurveCenter\n\n            global LineDimension\n            global DWireDimension\n            global CircleDimension\n            global CirclePartDimension\n            global ArcDimension\n            global EllipseDimension\n            global EllipsePartDimension\n            global PolygonDimension\n            global RectangleDimension\n            global BSplineDimension\n            global PointDimension\n            global BezCurveDimension\n\n            global CylinderDimension\n            global BoxDimension\n            global SphereDimension\n            global EllipsoidDimension\n            global ConeDimension\n            global TorusDimension\n\n            global PlanePartDimension\n            global PrismPartDimension\n            global WedgePartDimension\n            global HelixPartDimension\n            global SpiralPartDimension\n            global VertexPartDimension\n            global LinePartDimension\n            global RegularPolygonPartDimension\n\n            global FaceSurface     \n            global NormalAt\n            global FaceCenter     \n            global BoundBoxFaceVol\n            global BoundBoxFaceCent\n            global BoundBoxFaceCoor \n            global BounBoxVolumeVol\n            global BounBoxVolumeCent   \n            global BounBoxVolumeCoor    \n            global VolumeObject    \n            global CenterMass   \n            global PlacementForme   \n            global LineInclination \n            global VertexesObject  \n            global VertexesForme   \n\n            texteInfo = \"\"\n            compteur  = 0\n\n            sel = FreeCADGui.Selection.getSelection()   \n \n            try:\n                Object = Gui.Selection.getSelectionEx()[0].SubObjects[0]\n            except Exception:\n                None\n \n                # Nom du document                                                          #1\n            if DocumentName == 1:\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Document name\" , str(FreeCAD.activeDocument().Name))\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Document name\")+str(FreeCAD.activeDocument().Name)+\"\\n\"\n                except Exception:\n                    None\n     \n                # Nom interne de l'objet                                                   #2\n            if InternalName == 1:\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Object name\" , str(sel[0].Name))\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Object name\")+str(sel[0].Name)+\"\\n\"\n                except Exception:\n                    None\n     \n                # Label                                                                    #3\n            if LabelObject == 1:\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Label name\" , str(unicode(sel[0].Label)))\n#                    texteInfo += longChaine(str(compteur)+\" : Label name\")+str(sel[0].Label)+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Label name\")+str(unicode(sel[0].Label))+\"\\n\"\n                    compteur += 1\n                except Exception:\n                    None\n     \n                # Nom de l'element                                                         #4\n            if ElementName == 1:\n                try:\n                    SubElement = FreeCADGui.Selection.getSelectionEx()   \n                    element_ = SubElement[0].SubElementNames[0]\n                    if PrintReportView == 1:\n                        afficherVR(\"Element name\" , str(element_))\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Element name\")+str(element_)+\"\\n\"\n                except Exception:\n                    None\n     \n                # Type d'objet                                                             #5\n            if ObjectType == 1:\n                try:\n                    typeObject = sel[0].Shape.ShapeType\n                    if PrintReportView == 1:\n                        afficherVR(\"Object type\" , typeObject)\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Object type\")+typeObject+\"\\n\"\n                except Exception:\n                    None\n\n                # ligne de separation                                                      #6\n            if LineSeparateTitle == 1:\n                    if PrintReportView == 1:\n                        afficherVR(\"________________________\",\"\")\n                    texteInfo += \"________________________\"+\"\\n\"\n     \n##### Object or SubObject\n                # longueur Objet ou perimetre                                              #7\n            if ObjectLength == 1:\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Object lenght (or per.)\" , str(Gui.Selection.getSelectionEx()[0].SubObjects[0].Length))\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Object lenght (or per.)\")+str(Around(Gui.Selection.getSelectionEx()[0].SubObjects[0].Length))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"ObjectLength\"+\"\\n\")\n                    None\n\n                # Radius subOject curve                                                    #8\n            if ObjectCurveRadius == 1:\n                try:\n                    r = Gui.Selection.getSelectionEx()[0].SubObjects[0].Curve\n                    if PrintReportView == 1:\n                        afficherVR(\"Object radius\" , str(r.Radius))\n                    texteInfo +=  longChaine(str(compteur)+\" : Object radius\")+str(Around(r.Radius))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"r.Radius\"+\"\\n\")\n                    None\n                # Center subOject curve                                                    #9\n            if ObjectCurveCenter == 1:\n                try:\n                    r = Gui.Selection.getSelectionEx()[0].SubObjects[0].Curve\n                    if PrintReportView == 1:\n                        afficherVR(\"Object center\" , str(r.Center))\n                    texteInfo +=  longChaine(str(compteur)+\" : Object center\")+\"X: \"+str(Around(r.Center.x))+\" Y: \"+str(Around(r.Center.y))+\" Z: \"+str(Around(r.Center.z))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"r.Center\"+\"\\n\")\n                    None\n\n                # ligne de separation                                                      #6\n            if LineSeparateTitle == 1:\n                    if PrintReportView == 1:\n                        afficherVR(\"________________________\",\"\")\n                    texteInfo += \"________________________\"+\"\\n\"\n\n##### Dimensions Draft\n                # Line Draft                                                               #10\n            if (LineDimension == 1) and (str(sel[0].Name[:4]) == \"Line\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Line Start\" , str(sel[0].Start))                       # Line Start\n                        afficherVR(\"Line End\" , str(sel[0].End))                           # Line End\n                        afficherVR(\"Line Length\" , str(sel[0].Length))                     # Line Length\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Line Start\")+ \"X1: \"+ str(Around(sel[0].Start[0]))+ \" Y1: \"+ str(Around(sel[0].Start[1]))+ \" Z1: \"+ str(Around(sel[0].Start[2]))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Line End\") + \"X2: \" + str(Around(sel[0].End[0])) + \" Y2: \"+ str(Around(sel[0].End[1])) + \" Z2: \"+ str(Around(sel[0].End[2]))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Line Length\")+str(Around(sel[0].Length))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"LineDimension\"+\"\\n\")\n                        # Line Part                                                        #11\n                    if (LinePartDimension == 1) and (str(sel[0].Name[:4]) == \"Line\"):\n                        try:\n                            if PrintReportView == 1:\n                                afficherVR(\"Line\" , \"X1: \"+str(sel[0].X1)+\" Y1: \"+str(sel[0].Y1)+\" Z1: \"+str(sel[0].Z1))  # X1 Y1 Z1\n                                afficherVR(\"Line\" , \"X2: \"+str(sel[0].X2)+\" Y2: \"+str(sel[0].Y2)+\" Z2: \"+str(sel[0].Z2))  # X2 Y2 Z2\n                            compteur += 1\n                            texteInfo += longChaine(str(compteur)+\" : Line\")+\"X1: \"+str(Around(sel[0].X1))+\" Y1: \"+str(Around(sel[0].Y1))+\" Z1: \"+str(Around(sel[0].Z1))+\"\\n\"\n                            texteInfo += longChaine(str(compteur)+\" : Line\")+ \"X2: \"+str(Around(sel[0].X2))+\" Y2: \"+str(Around(sel[0].Y2))+\" Z2: \"+str(Around(sel[0].Z2))+\"\\n\"\n                        except Exception:\n                            #App.Console.PrintError(\"LinePartDimension\"+\"\\n\")\n                            None\n\n                # DWire                                                                    #12\n            elif (DWireDimension == 1) and (str(sel[0].Name[:5]) == \"DWire\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"DWire Start\" , str(sel[0].Start))                      # Line Start\n                        afficherVR(\"DWire End\" , str(sel[0].End))                          # Line End\n                        afficherVR(\"DWire Length\" , str(sel[0].Length))                    # Line Length\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : DWire Start\")+ \"X1: \"+ str(Around(sel[0].Start[0]))+ \" Y1: \"+ str(Around(sel[0].Start[1]))+ \" Z1: \"+ str(Around(sel[0].Start[2]))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : DWire End\")+ \"X2: \"  + str(Around(sel[0].End[0]))+ \" Y2: \"+  str(Around(sel[0].End[1]))+ \" Z2: \"+  str(Around(sel[0].End[2]))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : DWire Length\")+str(Around(sel[0].Length))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"DWireDimension\"+\"\\n\")\n                    None\n\n                # Circle Draft                                                             #13\n            elif (CircleDimension == 1) and (str(sel[0].Name[:6]) == \"Circle\"):\n                try:\n                    test = sel[0].FirstAngle    # test error\n                    if PrintReportView == 1:\n                        afficherVR(\"Circle Radius\" ,     str(sel[0].Radius))               # Circle Radius\n                        afficherVR(\"Circle FirstAngle\" , str(sel[0].FirstAngle))           # Circle FirstAngle\n                        afficherVR(\"Circle LastAngle\" ,  str(sel[0].LastAngle))            # Circle LastAngle\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Circle Radius\") +   str(Around(sel[0].Radius))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Circle FirstAngle\")+str(Around(sel[0].FirstAngle))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Circle LastAngle\")+ str(Around(sel[0].LastAngle))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"CircleDimension\"+\"\\n\")\n                        # Circle Part                                                      #14\n                    if (CirclePartDimension == 1) and (str(sel[0].Name[:6]) == \"Circle\"):\n                        try:\n                            if PrintReportView == 1:\n                                afficherVR(\"Circle Radius\" , str(sel[0].Radius))           # Radius\n                                afficherVR(\"Circle Angle0\" , str(sel[0].Angle0))           # Angle0\n                                afficherVR(\"Circle Angle1\" , str(sel[0].Angle1))           # Angle1\n                            compteur += 1\n                            texteInfo += longChaine(str(compteur)+\" : Circle Radius\")+str(Around(sel[0].Radius))+\"\\n\"\n                            texteInfo += longChaine(str(compteur)+\" : Circle Angle0\")+str(Around(sel[0].Angle0))+\"\\n\"\n                            texteInfo += longChaine(str(compteur)+\" : Circle Angle1\")+str(Around(sel[0].Angle1))+\"\\n\"\n                        except Exception:\n                            #App.Console.PrintError(\"CirclePartDimension\"+\"\\n\")\n                            None\n    \n                # Arc                                                                      #15\n            elif (ArcDimension == 1) and (str(sel[0].Name[:3]) == \"Arc\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Arc Radius\" ,     str(sel[0].Radius))                  # Arc Radius\n                        afficherVR(\"Arc FirstAngle\" , str(sel[0].FirstAngle))              # Arc FirstAngle\n                        afficherVR(\"Arc LastAngle\" ,  str(sel[0].LastAngle))               # Arc LastAngle\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Arc Radius\") +   str(Around(sel[0].Radius))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Arc FirstAngle\")+str(Around(sel[0].FirstAngle))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Arc LastAngle\")+ str(Around(sel[0].LastAngle))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"ArcDimension\"+\"\\n\")\n                    None\n\n                # Ellipse Draft                                                            #16\n            elif (EllipseDimension == 1) and (str(sel[0].Name[:7]) == \"Ellipse\"):\n                try:\n                    test = sel[0].FirstAngle    # test error\n                    if PrintReportView == 1:\n                        afficherVR(\"Ellipse MajorRadius\" , str(sel[0].MajorRadius))        # Ellipse MajorRadius\n                        afficherVR(\"Ellipse MinorRadius\" , str(sel[0].MinorRadius))        # Ellipse MinorRadius\n                        afficherVR(\"Ellipse FirstAngle\" , str(sel[0].FirstAngle))          # Ellipse FirstAngle\n                        afficherVR(\"Ellipse LastAngle\" , str(sel[0].LastAngle))            # Ellipse LastAngle\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Ellipse MajorRadius\")+str(Around(sel[0].MajorRadius))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Ellipse MinorRadius\")+str(Around(sel[0].MinorRadius))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Ellipse FirstAngle\") +str(Around(sel[0].FirstAngle))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Ellipse LastAngle\") + str(Around(sel[0].LastAngle))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"EllipseDimension 1\"+\"\\n\")\n                        # Ellipse Part                                                     #17\n                    if (EllipsePartDimension == 1) and (str(sel[0].Name[:7]) == \"Ellipse\"):\n                        try:\n                            if PrintReportView == 1:\n                                afficherVR(\"Ellipse MajorRadius\" , str(sel[0].MajorRadius))# MajorRadius\n                                afficherVR(\"Ellipse MinorRadius\" , str(sel[0].MinorRadius))# MinorRadius\n                                afficherVR(\"Ellipse Angle0\" , str(sel[0].Angle0))          # Angle0\n                                afficherVR(\"Ellipse Angle1\" , str(sel[0].Angle1))          # Angle1\n                            compteur += 1\n                            texteInfo += longChaine(str(compteur)+\" : Ellipse MajorRadius\")+str(Around(sel[0].MajorRadius))+\"\\n\"\n                            texteInfo += longChaine(str(compteur)+\" : Ellipse MinorRadius\")+str(Around(sel[0].MinorRadius))+\"\\n\"\n                            texteInfo += longChaine(str(compteur)+\" : Ellipse Angle0\") +    str(Around(sel[0].Angle0))+\"\\n\"\n                            texteInfo += longChaine(str(compteur)+\" : Ellipse Angle1\") +    str(Around(sel[0].Angle1))+\"\\n\"\n                        except Exception:\n                            #App.Console.PrintError(\"EllipsePartDimension 2\"+\"\\n\")\n                            None\n\n                # Polygon                                                                  #18\n            elif (PolygonDimension == 1) and (str(sel[0].Name[:7]) == \"Polygon\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Polygon Radius\" , str(sel[0].Radius))                  # Polygon Radius\n                        afficherVR(\"Polygon FacesNumber\" , str(sel[0].FacesNumber))        # Polygon FacesNumber\n                        afficherVR(\"Polygon FilletRadius\" , str(sel[0].FilletRadius))      # Polygon FilletRadius\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Polygon Radius\")     + str(Around(sel[0].Radius))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Polygon FacesNumber\")+ str(Around(sel[0].FacesNumber))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Polygon FilletRadius\")+str(Around(sel[0].FilletRadius))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"PolygonDimension\"+\"\\n\")\n                    None\n\n                # Rectangle                                                                #19\n            elif (RectangleDimension == 1) and (str(sel[0].Name[:9]) == \"Rectangle\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Rectangle Length\" , str(sel[0].Length))                # Rectangle Length\n                        afficherVR(\"Rectangle Height\" , str(sel[0].Height))                # Rectangle Height\n                        afficherVR(\"Rectangle ChamferSize\" , str(sel[0].ChamferSize))      # Rectangle ChamferSize\n                        afficherVR(\"Rectangle FilletRadius\" , str(sel[0].FilletRadius))    # Rectangle FilletRadius\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Rectangle Length\") +     str(Around(sel[0].Length))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Rectangle Height\") +     str(Around(sel[0].Height))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Rectangle ChamferSize\")+ str(Around(sel[0].ChamferSize))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Rectangle FilletRadius\")+str(Around(sel[0].FilletRadius))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"RectangleDimension\"+\"\\n\")\n                    None\n                \n                # BSpline                                                                  #20\n            elif (BSplineDimension == 1) and (str(sel[0].Name[:7]) == \"BSpline\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"BSpline MakeFace\" , str(sel[0].MakeFace))              # BSpline Length\n                        afficherVR(\"BSpline Closed\" , str(sel[0].Closed))                  # BSpline Height\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : BSpline MakeFace\")+str((sel[0].MakeFace))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : BSpline Closed\") + str((sel[0].Closed))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"BSplineDimension\"+\"\\n\")\n                    None\n\n                # Point                                                                    #21\n            elif (PointDimension == 1) and (str(sel[0].Name[:5]) == \"Point\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Point\" , \"X: \"+str(sel[0].X)+\" Y: \" + str(sel[0].Y) +\" Z: \"+str(sel[0].Z)) # Point X Y Z\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Point\")+\"X: \"+str(Around(sel[0].X))+\" Y: \"+str(Around(sel[0].Y))+\" Z: \"+str(Around(sel[0].Z))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"PointDimension\"+\"\\n\")\n                    None\n\n                # BezCurve                                                                 #22\n            elif (BezCurveDimension == 1) and (str(sel[0].Name[:8]) == \"BezCurve\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"BezCurve Degree\" , str(sel[0].Degree))                 # BezCurve Degree\n                        afficherVR(\"BezCurve Continuity\" , str(sel[0].Continuity))         # BezCurve Continuity\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : BezCurve Degree\") +   str(Around(sel[0].Degree))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : BezCurve Continuity\")+str(Around(sel[0].Continuity))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"BezCurveDimension\"+\"\\n\")\n                    None\n\n##### Dimensions Volumes\n                # Cylinder                                                                 #23\n            elif (CylinderDimension == 1) and (str(sel[0].Name[:8]) == \"Cylinder\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Cylinder Radius\" , str(sel[0].Radius))                 # Cylinder Radius\n                        afficherVR(\"Cylinder Height\" , str(sel[0].Height))                 # Cylinder Height\n                        afficherVR(\"Cylinder Angle\" , str(sel[0].Angle))                   # Cylinder Angle\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Cylinder Radius\")+str(Around(sel[0].Radius))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Cylinder Height\")+str(Around(sel[0].Height))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Cylinder Angle\")+ str(Around(sel[0].Angle))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"CylinderDimension\"+\"\\n\")\n                    None\n\n                # Box                                                                      #24\n            elif (BoxDimension == 1) and (str(sel[0].Name[:3]) == \"Box\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Box Length\" , str(sel[0].Length))                      # Length\n                        afficherVR(\"Box Width\" , str(sel[0].Width))                        # Width\n                        afficherVR(\"Box Height\" , str(sel[0].Height))                      # Height\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Box Length\")+str(Around(sel[0].Length))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Box Width\") +str(Around(sel[0].Width))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Box Height\")+str(Around(sel[0].Height))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"BoxDimension\"+\"\\n\")\n                    None\n\n                # Sphere                                                                   #25\n            elif (SphereDimension == 1) and (str(sel[0].Name[:6]) == \"Sphere\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Sphere Radius\" , str(sel[0].Radius))                   # Radius\n                        afficherVR(\"Sphere Angle1\" , str(sel[0].Angle1))                   # Angle1\n                        afficherVR(\"Sphere Angle2\" , str(sel[0].Angle2))                   # Angle2\n                        afficherVR(\"Sphere Angle3\" , str(sel[0].Angle3))                   # Angle3\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Sphere Radius\")+str(Around(sel[0].Radius))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Sphere Angle1\")+str(Around(sel[0].Angle1))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Sphere Angle2\")+str(Around(sel[0].Angle2))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Sphere Angle3\")+str(Around(sel[0].Angle3))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"SphereDimension\"+\"\\n\")\n                    None\n\n                # Ellipsoid                                                                #26\n            elif (EllipsoidDimension == 1) and (str(sel[0].Name[:9]) == \"Ellipsoid\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Ellipsoid Radius1\" , str(sel[0].Radius1))              # Radius1\n                        afficherVR(\"Ellipsoid Radius2\" , str(sel[0].Radius2))              # Radius2\n                        afficherVR(\"Ellipsoid Radius3\" , str(sel[0].Radius3))              # Radius3\n                        afficherVR(\"Ellipsoid Angle1\" , str(sel[0].Angle1))                # Angle1\n                        afficherVR(\"Ellipsoid Angle2\" , str(sel[0].Angle2))                # Angle2\n                        afficherVR(\"Ellipsoid Angle3\" , str(sel[0].Angle3))                # Angle3\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Ellipsoid Radius1\")+str(Around(sel[0].Radius1))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Ellipsoid Radius2\")+str(Around(sel[0].Radius2))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Ellipsoid Radius3\")+str(Around(sel[0].Radius3))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Ellipsoid Angle1\")+ str(Around(sel[0].Angle1))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Ellipsoid Angle2\")+ str(Around(sel[0].Angle2))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Ellipsoid Angle3\")+ str(Around(sel[0].Angle3))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"EllipsoidDimension\"+\"\\n\")\n                    None\n\n                # Cone                                                                     #27\n            elif (ConeDimension == 1) and (str(sel[0].Name[:4]) == \"Cone\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Cone Radius1\" , str(sel[0].Radius1))                   # Radius1\n                        afficherVR(\"Cone Radius2\" , str(sel[0].Radius2))                   # Radius2\n                        afficherVR(\"Cone Height\" , str(sel[0].Height))                     # Height\n                        afficherVR(\"Cone Angle\" , str(sel[0].Angle))                       # Angle\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Cone Radius1\")+str(Around(sel[0].Radius1))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Cone Radius2\")+str(Around(sel[0].Radius2))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Cone Height\") +str(Around(sel[0].Height))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Cone Angle\") + str(Around(sel[0].Angle))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"ConeDimension\"+\"\\n\")\n                    None\n\n                # Torus                                                                    #28\n            elif (TorusDimension == 1) and (str(sel[0].Name[:5]) == \"Torus\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Torus Radius1\" , str(sel[0].Radius1))                  # Radius1\n                        afficherVR(\"Torus Radius2\" , str(sel[0].Radius2))                  # Radius2\n                        afficherVR(\"Torus Angle1\" , str(sel[0].Angle1))                    # Angle1\n                        afficherVR(\"Torus Angle2\" , str(sel[0].Angle2))                    # Angle2\n                        afficherVR(\"Torus Angle3\" , str(sel[0].Angle3))                    # Angle3\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Torus Radius1\")+str(Around(sel[0].Radius1))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Torus Radius2\")+str(Around(sel[0].Radius2))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Torus Angle1\") +str(Around(sel[0].Angle1))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Torus Angle2\") +str(Around(sel[0].Angle2))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Torus Angle3\") +str(Around(sel[0].Angle3))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"TorusDimension\"+\"\\n\")\n                    None\n\n                # Plane Part                                                               #29\n            elif (PlanePartDimension == 1) and (str(sel[0].Name[:5]) == \"Plane\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Plane Length\" , str(sel[0].Length))                    # Length\n                        afficherVR(\"Plane Width\" , str(sel[0].Width))                      # Width\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Plane Length\")+str(Around(sel[0].Length))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Plane Width\") +str(Around(sel[0].Width))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"PlanePartDimension\"+\"\\n\")\n                    None\n\n                # Prism Part                                                               #30\n            elif (PrismPartDimension == 1) and (str(sel[0].Name[:5]) == \"Prism\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Prism Polygon\" , str(sel[0].Polygon))                  # Polygon\n                        afficherVR(\"Prism Circumradius\" , str(sel[0].Circumradius))        # Circumradius\n                        afficherVR(\"Prism Height\" , str(sel[0].Height))                    # Height\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Prism Polygon\") +    str(Around(sel[0].Polygon))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Prism Circumradius\")+str(Around(sel[0].Circumradius))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Prism Height\") +     str(Around(sel[0].Height))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"PrismPartDimension\"+\"\\n\")\n                    None\n\n                # Wedge Part                                                               #31\n            elif (WedgePartDimension == 1) and (str(sel[0].Name[:5]) == \"Wedge\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Wedge Xmin\" , str(sel[0].Xmin))                        # Xmin\n                        afficherVR(\"Wedge Ymin\" , str(sel[0].Ymin))                        # Ymin\n                        afficherVR(\"Wedge Zmin\" , str(sel[0].Zmin))                        # Zmin\n\n\n                        afficherVR(\"Wedge X2min\" , str(sel[0].X2min))                      # X2min\n                        afficherVR(\"Wedge Z2min\" , str(sel[0].Z2min))                      # Z2min\n                        afficherVR(\"Wedge Xmax\" , str(sel[0].Xmax))                        # Xmax\n\n                        afficherVR(\"Wedge Ymax\" , str(sel[0].Ymax))                        # Ymax\n                        afficherVR(\"Wedge Zmax\" , str(sel[0].Zmax))                        # Zmax\n                        afficherVR(\"Wedge X2max\" , str(sel[0].X2max))                      # X2max\n\n                        afficherVR(\"Wedge Z2max\" , str(sel[0].Z2max))                      # Z2max\n\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Wedge Xmin\") +str(Around(sel[0].Xmin))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Wedge Ymin\") +str(Around(sel[0].Ymin))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Wedge Zmin\") +str(Around(sel[0].Zmin))+\"\\n\"\n\n                    texteInfo += longChaine(str(compteur)+\" : Wedge X2min\")+str(Around(sel[0].X2min))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Wedge Z2min\")+str(Around(sel[0].Z2min))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Wedge Xmax\") +str(Around(sel[0].Xmax))+\"\\n\"\n\n                    texteInfo += longChaine(str(compteur)+\" : Wedge Ymax\") +str(Around(sel[0].Ymax))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Wedge Zmax\") +str(Around(sel[0].Zmax))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Wedge X2max\")+str(Around(sel[0].X2max))+\"\\n\"\n\n                    texteInfo += longChaine(str(compteur)+\" : Wedge Z2max\")+str(Around(sel[0].Z2max))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"WedgePartDimension\"+\"\\n\")\n                    None\n\n                # Helix Part                                                               #32\n            elif (HelixPartDimension == 1) and (str(sel[0].Name[:5]) == \"Helix\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Helix Pitch\" , str(sel[0].Pitch))                      # Pitch\n                        afficherVR(\"Helix Height\" , str(sel[0].Height))                    # Height\n                        afficherVR(\"Helix Radius\" , str(sel[0].Radius))                    # Radius\n                        afficherVR(\"Helix Angle\" , str(sel[0].Angle))                      # Angle\n                        afficherVR(\"Helix LocalCoord\" , str(sel[0].LocalCoord))            # LocalCoord\n                        afficherVR(\"Helix Style\" , str(sel[0].Style))                      # Style\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Helix Pitch\") +    str(Around(sel[0].Pitch))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Helix Height\") +   str(Around(sel[0].Height))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Helix Radius\") +   str(Around(sel[0].Radius))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Helix Angle\") +    str(Around(sel[0].Angle))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Helix LocalCoord\")+str(Around(sel[0].LocalCoord))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Helix Style\") +    str(Around(sel[0].Style))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"HelixPartDimension\"+\"\\n\")\n                    None\n\n                # Spiral Part                                                              #33\n            elif (SpiralPartDimension == 1) and (str(sel[0].Name[:6]) == \"Spiral\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Spiral Growth\" , str(sel[0].Growth))                   # Growth\n                        afficherVR(\"Spiral Rotations\" , str(sel[0].Rotations))             # Rotations\n                        afficherVR(\"Spiral Radius\" , str(sel[0].Radius))                   # Radius\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Spiral Growth\") +  str(Around(sel[0].Growth))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Spiral Rotations\")+str(Around(sel[0].Rotations))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Spiral Radius\") +  str(Around(sel[0].Radius))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"SpiralPartDimension\"+\"\\n\")\n                    None\n\n                # Vertex Part (Point)                                                      #34\n            elif (VertexPartDimension == 1) and (str(sel[0].Name[:6]) == \"Vertex\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Vertex\" , \"X: \"+str(sel[0].X)+\" Y: \"+str(sel[0].Y)+\" Z: \" , str(sel[0].Z))  # X Y Z\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Vertex\")+\" X: \"+str(Around(sel[0].X))+\" Y: \"+str(Around(sel[0].Y))+\" Z: \"+str(Around(sel[0].Z))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"VertexPartDimension\"+\"\\n\")\n                    None\n\n                # RegularPolygon Part                                                      #35\n            elif (RegularPolygonPartDimension == 1) and (str(sel[0].Name[:14]) == \"RegularPolygon\"):\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"RegularPolygon Polygon\" , str(sel[0].Polygon))          # Polygon\n                        afficherVR(\"RegularPolygon Circumradius\" , str(sel[0].Circumradius))# Circumradius\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : RegularPolygon\") +    str(Around(sel[0].Polygon))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : RegularPolygon Radius\")+str(Around(sel[0].Circumradius))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"RegularPolygonPartDimension\"+\"\\n\")\n                    None\n\n                # Surface de la face                                                       #36\n            if FaceSurface == 1:\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Face area\" , str(Gui.Selection.getSelectionEx()[0].SubObjects[0].Area))\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Face area\")+str(Around(Gui.Selection.getSelectionEx()[0].SubObjects[0].Area))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"FaceSurface\"+\"\\n\")\n                    None\n\n                #NormalAt                                                                 #37\n            if NormalAt == 1:\n                try:\n                    SubElement = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0]   # subobject\n                    a = SubElement.normalAt(0,0)                                          # ok Vector normalAt pour face\n                    compteur += 1\n                    if PrintReportView == 1:\n                        afficherVR(\"NormalAt Face\" , \"X:\"+str(Around(a[0]))+\" Y:\"+str(Around(a[1]))+\" Z:\"+str(Around(a[2])))\n                    texteInfo += longChaine(str(compteur)+\" : NormalAt Face\")+\"X:\"+str(Around(a[0]))+\" Y:\"+str(Around(a[1]))+\" Z:\"+str(Around(a[2]))+\"\\n\"\n                except Exception:\n                    try:\n                        sel = FreeCADGui.Selection.getSelection()[0]                      # object\n                        a = sel.Shape.Edges[0].normalAt(0)                                # ok pour Edges\n                        compteur += 1\n                        if PrintReportView == 1:\n                            afficherVR(\"NormalAt Edges\" , \"X:\"+str(Around(a[0]))+\" Y:\"+str(Around(a[1]))+\" Z:\"+str(Around(a[2])))\n                        texteInfo += longChaine(str(compteur)+\" : NormalAt Edges\")+\"X:\"+str(Around(a[0]))+\" Y:\"+str(Around(a[1]))+\" Z:\"+str(Around(a[2]))+\"\\n\"\n                    except Exception:\n                        #App.Console.PrintError(\"NormalAt\"+\"\\n\")\n                        None\n\n                # Center Face (mass)                                                       #38\n            if FaceCenter == 1:\n                try:\n                    det = Gui.Selection.getSelectionEx()[0].SubObjects[0].CenterOfMass\n                    if PrintReportView == 1:\n                        afficherVR(\"Face center\" , \"X: \"+str(det[0])+\" Y: \"+str(det[1])+\" Z: \"+str(det[2])) # Vector center mass to face\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Face center\")+\"X: \"+str(Around(det[0]))+\" Y: \"+str(Around(det[1]))+\" Z: \"+str(Around(det[2]))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"FaceCenter\"+\"\\n\")\n                    None\n\n                # BoudBox Face Volume                                                      #39\n            if BoundBoxFaceVol == 1:\n                try:\n                    det = Gui.Selection.getSelectionEx()[0].SubObjects[0]\n                    if PrintReportView == 1:\n                        afficherVR(\"Face BoundBox Volume\" , str(det.BoundBox.XLength)+\" x \"+str(det.BoundBox.YLength)+\" x \"+str(det.BoundBox.ZLength)) # BoundBoxFace face volume\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Face BBox Volume\")+str(Around(det.BoundBox.XLength))+\" x \"+str(Around(det.BoundBox.YLength))+\" x \"+str(Around(det.BoundBox.ZLength))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"BoundBoxFaceVol\"+\"\\n\")\n                    None\n     \n                # BoudBox Face Center                                                      #40\n            if BoundBoxFaceCent == 1:\n                try:\n                    det = Gui.Selection.getSelectionEx()[0].SubObjects[0].BoundBox.Center\n                    if PrintReportView == 1:\n                        afficherVR(\"Face BoundBox Center\" , \"X: \"+str(det[0])+\" Y: \"+str(det[1])+\" Z: \"+str(det[2]))             # BoundBoxFace face center\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Face BBox Center\")+\"X: \"+str(Around(det[0]))+\" Y: \"+str(Around(det[1]))+\" Z: \"+str(Around(det[2]))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"BoundBoxFaceCent\"+\"\\n\")\n                    None\n\n                # BoudBox Face Coordinates                                                 #41\n            if BoundBoxFaceCoor == 1:\n                try:\n                    det = Gui.Selection.getSelectionEx()[0].SubObjects[0].BoundBox\n                    decodeSplit(det,\"BoundBox (\")\n                    if PrintReportView == 1:\n                        afficherVR(\"Face BoundBox Coor\" , \"X1: \"+str(dummy3[0])+\" Y1: \"+str(dummy3[1])+\" Z1: \"+str(dummy3[2])) # BoundBoxFace face coordinates\n                        afficherVR(\"\" , \"X2: \"+str(dummy3[3])+\" Y2: \"+str(dummy3[4])+\" Z2: \"+str(dummy3[5]))                 # BoundBoxFace face coordinates\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Face BBox Coor\")+\"X1: \"+str(Around(float(dummy3[0])))+\" Y1: \"+str(Around(float(dummy3[1])))+\" Z1:\"+str(Around(float(dummy3[2])))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : \")+\"X2: \"+str(Around(float(dummy3[3])))+\" Y2: \"+str(Around(float(dummy3[4])))+\" Z2: \"+str(Around(float(dummy3[5])))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"BoundBoxFaceCoor\"+\"\\n\")\n                    None\n     \n            ######Cas d'une forme############################################################\n\n                     # rectangle du BoundBox                                               #42\n            if BounBoxVolumeVol == 1:\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Volume BoundBox Volume\" , str(sel[0].Shape.BoundBox.XLength)+\" x \"+str(sel[0].Shape.BoundBox.YLength)+\" x \"+str(sel[0].Shape.BoundBox.ZLength))\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Volume BBox Volume\")+str(Around(sel[0].Shape.BoundBox.XLength))+\" x \"+str(Around(sel[0].Shape.BoundBox.YLength))+\" x \"+str(Around(sel[0].Shape.BoundBox.ZLength))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"BounBoxVolumeVol\"+\"\\n\")\n                    None\n     \n                 # centre de la forme                                                      #43\n            if BounBoxVolumeCent == 1:\n                try:\n                    det = sel[0].Shape.BoundBox.Center\n                    if PrintReportView == 1:\n                        afficherVR(\"Volume BoundBox Center\" , \"X: \"+str(det[0])+\" Y: \"+str(det[1])+\" Z: \"+str(det[2]))\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Volume BBox Center\")+\"X: \"+str(Around(det[0]))+\" Y: \"+str(Around(det[1]))+\" Z: \"+str(Around(det[2]))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"BounBoxVolumeCent\"+\"\\n\")\n                    None\n\n                 # boundinbox (dimensions hors tout)                                       #44\n            if BounBoxVolumeCoor == 1:\n                try:\n                    det = sel[0].Shape.BoundBox\n                    decodeSplit(det,\"BoundBox (\")\n                    if PrintReportView == 1:\n                        afficherVR(\"Volume BoundBox Coor\" , \"X1: \"+str(dummy3[0])+\" Y1: \"+str(dummy3[1])+\" Z1: \"+str(dummy3[2])) # BoundBox object coordinates\n                        afficherVR(\"\" , \"X2: \"+str(dummy3[3])+\" Y2: \"+str(dummy3[4])+\" Z2: \"+str(dummy3[5]))                     # BoundBox object coordinates\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Volume BBox Coor\")+\"X1: \"+str(Around(float(dummy3[0])))+\" Y1: \"+str(Around(float(dummy3[1])))+\" Z1:\"+str(Around(float(dummy3[2])))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : \")+\"X2: \"+str(Around(float(dummy3[3])))+\" Y2: \"+str(Around(float(dummy3[4])))+\" Z2: \"+str(Around(float(dummy3[5])))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"BounBoxVolumeCoor\"+\"\\n\")\n                    None\n     \n                 # volume                                                                  #45\n            if VolumeObject == 1:\n                try:\n                    if PrintReportView == 1:\n                        afficherVR(\"Volume\" , str(sel[0].Shape.Volume))\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : Volume\")+str(Around(sel[0].Shape.Volume))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"VolumeObject\"+\"\\n\")\n                    None\n     \n                 # centre de la masse                                                      #46\n            if CenterMass == 1:\n                try:\n                    det = sel[0].Shape\n                    c = det.Solids[0].CenterOfMass \n                    if PrintReportView == 1:\n                        afficherVR(\"CenterMass\" , \"X: \"+str(c.x)+\" Y: \"+str(c.y)+\" Z: \"+str(c.z))\n                    compteur += 1\n                    texteInfo += longChaine(str(compteur)+\" : CenterMass\")+\"X: \"+str(Around(c.x))+\" Y: \"+str(Around(c.y))+\" Z: \"+str(Around(c.z))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"CenterMass\"+\"\\n\")\n                    None\n     \n                 # position de la piece Placement                                          #47\n            if PlacementForme == 1:\n                try:\n                    det = sel[0].Placement\n                    compteur += 1\n                    if PrintReportView == 1:\n                        afficherVR(\"Placement\" , \"X: \"+str(det.Base[0])+\" Y: \"+str(det.Base[1])+\" Z: \"+str(det.Base[2]))\n                    texteInfo += longChaine(str(compteur)+\" : Placement\")+str(Around(det.Base[0]))+\" Y: \"+str(Around(det.Base[1]))+\" Z: \"+str(Around(det.Base[2]))+\"\\n\"\n                    decodeSplit(det,\"Yaw-Pitch-Roll=(\") # decode \n                    if PrintReportView == 1:\n                        afficherVR(\"Rotation\" , \"Yaw: \"+str(dummy3[0])+\" Pitch: \"+str(dummy3[1])+\" Roll: \"+str(dummy3[2]))\n                        afficherVR(\"Rotation Q\" , \"X: \"+str(det.Rotation.Q[0])+\" Y: \"+str(det.Rotation.Q[1])+\" Z: \"+str(det.Rotation.Q[2])+\" Q: \"+str(det.Rotation.Q[3]))\n                    texteInfo += longChaine(str(compteur)+\" : Rotation\")+\"Yaw: \"+str(Around(float(dummy3[0])))+\" Pitch: \"+str(Around(float(dummy3[1])))+\" Roll: \"+str(Around(float(dummy3[2])))+\"\\n\"\n                    texteInfo += longChaine(str(compteur)+\" : Rotation Q\")+\"X: \"+str(Around(float(det.Rotation.Q[0])))+\" Y: \"+str(Around(float(det.Rotation.Q[1])))+\" Z: \"+str(Around(float(det.Rotation.Q[2])))+\" Q: \"+str(Around(float(det.Rotation.Q[3])))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"PlacementForme\"+\"\\n\")\n                    None\n     \n                # search inclination XY YZ ZX uniquement lignes                            #48\n            if LineInclination == 1:\n                try:\n                    angleX1 = angleY1 = angleZ1 = 0.0\n                    angleX2 = angleY2 = angleZ2 = 0.0\n                    sel = FreeCADGui.Selection.getSelection()   \n                    SubElement = FreeCADGui.Selection.getSelectionEx()   \n                    element_ = SubElement[0].SubElementNames[0]\n                    if element_[:4] == \"Edge\":\n                        try:\n                            element_ = element_[4:]\n                            a = sel[0].Shape.Edges[int(element_)-1].Vertexes[0]\n                            angleX1 = a.Point.x\n                            angleY1 = a.Point.y\n                            angleZ1 = a.Point.z\n                            try:\n                                a = sel[0].Shape.Edges[int(element_)-1].Vertexes[1]\n                                angleX2 = a.Point.x\n                                angleY2 = a.Point.y\n                                angleZ2 = a.Point.z\n                            except Exception:\n                                Vertx.append(\"-\")\n                                Vertx.append(\"-\")\n                                Vertx.append(\"-\")\n                        except Exception:\n                            None\n                        try:\n                            Plan_xy = angle2(angleX1,angleY1,angleX2,angleY2,mode)\n                        except Exception:\n                            Plan_xy = 0.0\n                        try:\n                            Plan_yz   = angle2(angleY1,angleZ1,angleY2,angleZ2,mode)\n                        except Exception:\n                            Plan_yz = 0.0\n                        try:\n                            Plan_zx = angle2(angleZ1,angleX1,angleZ2,angleX2,mode)\n                        except Exception:\n                            Plan_zx = 0.0\n                        \n                        if PrintReportView == 1:\n                            afficherVR(\"Inclination Obj\" , \"XY: \"+str(Plan_xy)+\" YZ: \"+str(Plan_yz)+\" ZX: \"+str(Plan_zx))\n                        compteur += 1\n                        texteInfo += longChaine(str(compteur)+\" : Inclination Obj\")+\"XY: \"+str(Around(Plan_xy))+\" YZ: \"+str(Around(Plan_yz))+\" ZX: \"+str(Around(Plan_zx))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"LineInclination\"+\"\\n\")\n                    None\n    \n                # Vertexes de l'objet selectionne                                          #49\n            if VertexesObject == 1:\n                try:\n                    a = Gui.Selection.getSelectionEx()[0].SubObjects[0].Vertexes\n                    aa = 0\n                    compteur += 1\n                    for a0 in range(len(a)):\n                        aa += 1\n                        if aa % 2 > 0:\n                            if aa == 1:\n                                if PrintReportView == 1:\n                                    afficherVR(\"Vertexes Obj\" , \"X\"+str(aa)+\": \"+str(a[a0].Point.x)+\" Y\"+str(aa)+ \": \"+str(a[a0].Point.y)+\" Z\"+str(aa)+ \": \"+str(a[a0].Point.z))\n                                texteInfo += longChaine(str(compteur)+\" : Vertexes Obj\")+\"X\"+str(aa)+\": \"+str(Around(a[a0].Point.x))+\" Y\"+str(aa)+ \": \"+str(Around(a[a0].Point.y))+\" Z\"+str(aa)+ \": \"+str(Around(a[a0].Point.z))+\"\\n\"\n                            else:\n                                if PrintReportView == 1:\n                                    afficherVR(\"\" , \"X\"+str(aa)+\": \"+str(a[a0].Point.x)+\" Y\"+str(aa)+ \": \"+str(a[a0].Point.y)+\" Z\"+str(aa)+ \": \"+str(a[a0].Point.z))\n                                texteInfo += longChaine(str(compteur)+\" : \")+\"X\"+str(aa)+\": \"+str(Around(a[a0].Point.x))+\" Y\"+str(aa)+ \": \"+str(Around(a[a0].Point.y))+\" Z\"+str(aa)+ \": \"+str(Around(a[a0].Point.z))+\"\\n\"\n                        else :\n                            if PrintReportView == 1:\n                                afficherVR(\"\" , \"X\"+str(aa)+\": \"+str(a[a0].Point.x)+\" Y\"+str(aa)+ \": \"+str(a[a0].Point.y)+\" Z\"+str(aa)+ \": \"+str(a[a0].Point.z))\n                            texteInfo += longChaine(str(compteur)+\" : \")+\"X\"+str(aa)+\": \"+str(Around(a[a0].Point.x))+\" Y\"+str(aa)+ \": \"+str(Around(a[a0].Point.y))+\" Z\"+str(aa)+ \": \"+str(Around(a[a0].Point.z))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"VertexesObject\"+\"\\n\")\n                    None\n\n                # Vertexes complet de la forme                                             #50\n            if VertexesForme == 1:\n                try:\n                    compt_E   = 0\n                    perimetre = 0.0\n                    for j in enumerate(sel[0].Shape.Edges):\n                        compt_E+=1\n                        perimetre += (sel[0].Shape.Edges[compt_E-1].Length)\n                        a = sel[0].Shape.Edges[compt_E-1].Vertexes[0]\n                        if PrintReportView == 1:\n                            afficherVR(\"Vertexes Form\" , \"X1: \"+str(a.Point.x)+\" Y1: \"+str(a.Point.y)+\" Z1: \"+str(a.Point.z))\n                        compteur += 1\n                        texteInfo += longChaine(str(compteur)+\" : Vertexes Form\")+\"X1: \"+str(Around(a.Point.x))+\" Y1: \"+str(Around(a.Point.y))+\" Z1: \"+str(Around(a.Point.z))+\"\\n\"\n                        a = sel[0].Shape.Edges[compt_E-1].Vertexes[1]\n                        if PrintReportView == 1:\n                            afficherVR(\"\" , \"X2: \" + str(a.Point.x)+\" Y2: \"+str(a.Point.y)+\" Z2: \"+str(a.Point.z))\n                        texteInfo += longChaine(str(compteur)+\" : \")+\"X2: \"+str(Around(a.Point.x))+\" Y2: \"+str(Around(a.Point.y))+\" Z2: \"+str(Around(a.Point.z))+\"\\n\"\n                    if PrintReportView == 1:\n                        afficherVR(\"Perimeter\" , str(perimetre))\n                        compteur += 1\n                        texteInfo += longChaine(str(compteur)+\" : Perimeter\")+str(Around(perimetre))+\"\\n\"\n                except Exception:\n                    #App.Console.PrintError(\"VertexesForme\"+\"\\n\")\n                    None\n\n            ff = ui\n            ff.on_pushButton_Raf_clicked()\n \n            if PrintReportView == 1:\n#                App.Console.PrintMessage(\"*****\"+Counter +str(compteur)+\"*****\"+\"\\n\")\n                App.Console.PrintMessage(\"____End_FCInfoGlass_____________________________________________\"+\"\\n\\n\")\n\ns=SelObserver()                                   # for selection\nFreeCADGui.Selection.addObserver(s)               # installe the function in resident mode\n \nMainWindow = QtGui.QMainWindow()\nui = Ui_MainWindow()\nui.setupUi(MainWindow)\n \nMainWindow.show()\n\n",
    "url": "https://wiki.freecad.org/Macro_FCInfoGlass",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/553b1fc7a8ca5bfa44c6/raw/fc57ec0869a8f68ce396acbaed5e87f396426186/Macro_FCInfoGlass.FCMacro",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_FCInfoGlass",
    "version": "00.05",
    "license": "",
    "date": "28/08/2016",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "/usr/lib/freecad/Mod/plugins/icons/.png",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FCInfoToMouse",
    "on_wiki": true,
    "on_git": false,
    "desc": "Provides info about coordinates, length, and angles in real-time next to the mouse pointer.<br /><br />Macro version: 00.04<br />Last modified: 2018-03-27<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/1/10/FCInfoToMouse.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Provides info about coordinates, length, and angles in real-time next to the mouse pointer.",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2016 <mario52>                                          *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n# http://forum.freecadweb.org/viewtopic.php?f=22&t=9215\n# FCInfoToMouse\n\n__title__   = \"FCInfoToMouse\"\n__author__  = \"Mario52\"\n__url__     = \"https://www.freecadweb.org/wiki/Macro_FCInfoToMouse\"\n__version__ = \"00.04\"\n__date__    = \"27/03/2018\"\n#\nimport Draft, Part\nimport math,FreeCAD\nfrom FreeCAD import Base\nimport time\nApp = FreeCAD\n\nglobal arrondi    ; arrondi    = 4\n\nglobal objectAnn  ; objectAnn  = \"\" \nglobal positionX1 ; positionX1 = 0.0\nglobal positionY1 ; positionY1 = 0.0\nglobal positionZ1 ; positionZ1 = 0.0\nglobal force      ; force      = 0\nglobal hidden     ; hidden     = 0\nglobal coorBegin  ; coorBegin  = \"\"\nglobal pas        ; pas        = 0\n\nglobal spreadSheet; spreadSheet= 0\nglobal compteur   ; compteur   = 0 \nglobal spread     ; spread     = \"\"\n\nfrom math import sqrt, pi, sin, cos, asin, acos, atan, atan2, degrees\n\ndef angle2(vecteur_x1,vecteur_y1,vecteur_x2,vecteur_y2,mode):   #tester getAngle ( Vector )\n# calcul de l'inclinaison d'une ligne a partir de deux Vecteurs\n# si \"mode\" = 1 alors affichage en degres sinon en radian\n    try:\n        deltaX = vecteur_x2 - vecteur_x1\n        deltaY = vecteur_y2 - vecteur_y1\n        if mode ==1:\n            angle = degrees(atan2(float(deltaY),float(deltaX))) # degres  (mode = 1)\n        else:\n            angle = atan2(float(deltaY),float(deltaX))          # radian  (mode = 0)\n        return round(angle,arrondi)\n    except Exception:\n        None\n\ndef sub(first, other): \n\t\"sub(Vector,Vector) - subtracts second vector from first one\"\n\tif isinstance(first,FreeCAD.Vector) and isinstance(other,FreeCAD.Vector):\n\t\treturn FreeCAD.Vector(first.x-other.x, first.y-other.y, first.z-other.z)\n\ndef length(first):\n\t\"lengh(Vector) - gives vector length\"\n\tif isinstance(first,FreeCAD.Vector):\n\t\treturn math.sqrt(first.x*first.x + first.y*first.y + first.z*first.z)\n\ndef dist(first, other):\n\t\"dist(Vector,Vector) - returns the distance between both points/vectors\"\n\tif isinstance(first,FreeCAD.Vector) and isinstance(other,FreeCAD.Vector):\n\t\treturn length(sub(first,other))\n\ndef codeColor(color):\n    try:\n        rgb = float((float(color)/255.0))\n    except Exception:\n        rgb = 0.0\n    return rgb\n\n\ndoc = FreeCAD.ActiveDocument    \nif doc == None:\n    doc = FreeCAD.newDocument()\n\n# for modify the configuration : line 104 to 122\n# PS: if DisplayMode = \"Line\" and Frame = False the annotation is transparent\n#\n##### Configuration  Modify here # Begin #######################################\n                                                                               #\n#BackgroundColor :                                                             #\nred_B           = 0.0                # 0.0 to 255.0                            #\ngreen_B         = 84.0               # 0.0 to 255.0                            #\nblue_B          = 255.0              # 0.0 to 255.0                            #\n                                                                               #\ndisplayMode     = \"Line\"             # \"Line\" or \"Object\"                      #\nfontName        = \"MS Shell Dlg 2\"   # \"MS Shell Dlg 2\" for Windows            #\nfontSize        = 8.0                # Font size                               #\nframe           = False              # \"False\" or \"True\"                       #\njustification   = \"Left\"             # \"Left\", \"Right\", \"Center\"               #\n                                                                               #\n#TextColor       :                                                             #\nred_T           = 255.0              # 0.0 to 255.0                            #\ngreen_T         = 255.0              # 0.0 to 255.0                            #\nblue_T          = 255.0              # 0.0 to 255.0                            #\n                                                                               #\n##### Configuration  End End ###################################################\n\nv=Gui.activeDocument().activeView()\nobjectAnn = App.ActiveDocument.addObject(\"App::AnnotationLabel\",\"FCInfoToMouse\")# create work annotation\nobjectAnn.LabelText=[\"Hello FreeCAD World\"]\n\nFreeCADGui.getDocument(doc.Name).getObject(objectAnn.Label).BackgroundColor = (codeColor(red_B),codeColor(green_B),codeColor(blue_B))   #\nFreeCADGui.getDocument(doc.Name).getObject(objectAnn.Label).DisplayMode     = displayMode                                               #\nFreeCADGui.getDocument(doc.Name).getObject(objectAnn.Label).FontName        = fontName                                                  #\nFreeCADGui.getDocument(doc.Name).getObject(objectAnn.Label).FontSize        = fontSize                                                  #\nFreeCADGui.getDocument(doc.Name).getObject(objectAnn.Label).Frame           = frame                                                     #\nFreeCADGui.getDocument(doc.Name).getObject(objectAnn.Label).Justification   = justification                                             #\nFreeCADGui.getDocument(doc.Name).getObject(objectAnn.Label).TextColor       = (codeColor(red_T),codeColor(green_T),codeColor(blue_T))   #\n\nimport os, sys, platform\nglobal PolicePath;    PolicePath = \"\"\n\n#if platform.system() == \"Windows\" :\n#    PolicePath = \"C:/Windows/Fonts/ARIAL.TTF\"\n#elif platform.system() == \"Linux\" :\n#    PolicePath = \"/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-M.ttf\"\n#elif platform.system() == \"Darwin\":\n#    PolicePath = \"/Library/Fonts/Arial.ttf\"\n#else:\n#    PolicePath = \"C:/Windows/Fonts/ARIAL.TTF\"\n\np=FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Mod/Draft\")\nPolicePath = p.GetString(\"FontFile\")\n\nclass ViewObserver:\n    def __init__(self, view):\n       self.view = view\n\n    def logPosition(self, info):\n        global objectAnn\n        global positionX1, positionY1, positionZ1\n        global pas, arrondi\n        global coorBegin\n        global force\n        global hidden\n        global PolicePath\n        global spreadSheet\n        global compteur\n        global spread\n\n######## for testing key ############\n#        try:                       #\n#            print info[\"Key\"]      #\n#            print info[\"State\"]    #\n##            print ord(info[\"Key\"]) #\n#        except Exception:          #\n#            None                   #\n#####################################\n\n        Button1 = 0\n\n        try:\n            if (info[\"Key\"] == \"Q\") and (info[\"State\"] == \"DOWN\"):                        # SHIFT + Q for quit\n                v.removeEventCallback(\"SoEvent\",c)                                        # close event observation\n                FreeCAD.Console.PrintMessage( \"End FCInfoToMouse\" + \"\\n\")\n        except Exception:\n            None\n\n        try:\n            if (info[\"Key\"] == \"M\") and (info[\"State\"] == \"DOWN\"):                        # SHIFT + M for force display\n                if force == 0:\n                    force = 1\n                    FreeCAD.Console.PrintMessage( \"Forced \" + \"\\n\")\n                elif force == 1:\n                    force = 2\n                    FreeCAD.Console.PrintMessage( \"Single \" + \"\\n\")\n                elif force == 2:\n                    force = 0\n                    FreeCAD.Console.PrintMessage( \"Normal \" + \"\\n\")\n        except Exception:\n            None\n\n        try:\n            if (info[\"Key\"] == \"C\") and (info[\"State\"] == \"DOWN\"):                        # SHIFT + C for hidden / visible annotation OK\n                if hidden == 0:\n                    hidden = 1\n                    FreeCADGui.getDocument(doc.Name).getObject(objectAnn.Label).Visibility = False\n                    FreeCAD.Console.PrintMessage( \"concealed \" + \"\\n\")\n                else:\n                    hidden = 0\n                    FreeCADGui.getDocument(doc.Name).getObject(objectAnn.Label).Visibility = True\n                    FreeCAD.Console.PrintMessage( \"visible \" + \"\\n\")\n        except Exception:\n            None\n\n        try:\n            if (info[\"Key\"] == \"D\") and (info[\"State\"] == \"DOWN\"):                        # SHIFT + S for Open spreadSheet\n                if spreadSheet == 0:\n                    #spread = FreeCAD.ActiveDocument.getObjectsByLabel(spread.Name)[0]    # for append in existant SpreadSheet\n                    spread = App.activeDocument().addObject('Spreadsheet::Sheet','MySpreedSheett')\n                    spreadSheet = 1\n                    FreeCAD.Console.PrintMessage(\"SpreadSheet open : \" + spread.Name + \"\\n\")\n                else:\n                    spreadSheet = 0\n                    FreeCAD.Console.PrintMessage(\"SpreadSheet closed\" + \"\\n\")\n                compteur    = 0\n        except Exception:\n            None\n\n        try:\n            object2 = \"\"\n            object = v.getObjectInfo(v.getCursorPos())                                    # here for object preselected\n            object2 = object[\"Object\"] + \".\" + object[\"Component\"]                        # object + component\n            pnt = FreeCAD.Vector(float(object[\"x\"]),float(object[\"y\"]),float(object[\"z\"]))# vector on position mouse to object\n#            print \"pnt \",pnt\n        except Exception:\n            pos = info[\"Position\"]                                                        # if mouse in 3D view\n            pnt = self.view.getPoint(pos)                                                 # vector detect on mouse position 3D view\n#            print \"pnt \",pnt\n\n        try:\n            if (info[\"Button\"] == \"BUTTON1\") and (info[\"State\"] == \"DOWN\"):               # coordinates clic to mouse\n                positionX1 = round(pnt[0],arrondi)\n                positionY1 = round(pnt[1],arrondi)\n                positionZ1 = round(pnt[2],arrondi)\n                \n                coorBegin = \"\"\n                coorBegin = \"X1: \"+str(positionX1)+\"  Y1: \"+str(positionY1)+\"  Z1: \"+str(positionZ1)\n                if pas == 0:\n                    pas = 1\n                else:\n                    pas = 0\n\n                try:                                                   # spreadSheet\n                    if spreadSheet == 1:\n                        compteur += 1\n                        spread.set(\"A\"+str(compteur) ,  str(positionX1) + \", \" + str(positionY1) + \", \" + str(positionZ1))\n                        spread.set(\"B\"+str(compteur) ,  str(positionX1))\n                        spread.set(\"C\"+str(compteur) ,  str(positionY1))\n                        spread.set(\"D\"+str(compteur) ,  str(positionZ1))\n                        App.ActiveDocument.recompute()\n                        FreeCAD.Console.PrintMessage(str(compteur) + \" : \" +  str(positionX1) + \", \" + str(positionY1) + \", \" + str(positionZ1) + \"\\n\")\n                except Exception:\n                    None\n                \n        except Exception:\n            None\n\n        try:\n            objectAnn.BasePosition = (pnt[0], pnt[1], pnt[2])\n            if force == 2:\n                objectAnn.LabelText = [\"X: \" + str(round(pnt[0],arrondi)) + \" Y: \" + str(round(pnt[1],arrondi)) + \" Z: \" + str(round(pnt[2],arrondi))]\n            else:\n                if ((pas == 1) or (force == 1)):\n                    coorEnd = longueur = angles = \"\"\n                    coorEnd = \"X2: \" + str(round(pnt[0],arrondi)) + \"  Y2: \" + str(round(pnt[1],arrondi)) + \"  Z2: \" + str(round(pnt[2],arrondi))\n                    longueur = \"L: \" + str(round(dist(FreeCAD.Vector(positionX1,positionY1,positionZ1), FreeCAD.Vector(pnt[0], pnt[1], pnt[2])),12)) # around to 12 decimales\n                    alphaXY = alphaXY = alphaXZ = 0.0\n                    alphaXY = str(round(angle2(positionX1,positionY1,pnt[0],pnt[1],1),arrondi))\n                    alphaYZ = str(round(angle2(positionY1,positionZ1,pnt[1],pnt[2],1),arrondi))\n                    alphaXZ = str(round(angle2(positionX1,positionZ1,pnt[0],pnt[2],1),arrondi))\n        \n                    angles = \"XY: \" + alphaXY + unichr(176) + \"  YZ: \" + alphaYZ + unichr(176) + \"  XZ: \" + alphaXZ + unichr(176)    # unichr(176) = degrees character\n        \n                    if object2 == \"\":\n                        objectAnn.LabelText = [coorBegin, coorEnd, longueur, angles,]\n                    else:\n                        objectAnn.LabelText = [object2, coorBegin, coorEnd, longueur, angles,]\n                else:\n                    if object2 == \"\":\n                        objectAnn.LabelText = [\"X: \" + str(round(pnt[0],arrondi)) + \" Y: \" + str(round(pnt[1],arrondi)) + \" Z: \" + str(round(pnt[2],arrondi)),]\n                    else:\n                        objectAnn.LabelText = [object2, \"X: \" + str(round(pnt[0],arrondi)) + \" Y: \" + str(round(pnt[1],arrondi)) + \" Z: \" + str(round(pnt[2],arrondi))]\n\n        except Exception:\n            FreeCAD.Console.PrintError(\"End FCInfoToMouse by an error\" + \"\\n\")\n            v.removeEventCallback(\"SoEvent\",c)                                            # close event observation\n\n##### Begin ######\nFreeCAD.Console.PrintMessage(\"__Welcome to FCInfoToMouse__\" + \"\\n\")\nFreeCAD.Console.PrintMessage(\"SHIFT + Q : for quit\" + \"\\n\")\nFreeCAD.Console.PrintMessage(\"SHIFT + M : for force display, mode single, mode normal\" + \"\\n\")\nFreeCAD.Console.PrintMessage(\"SHIFT + C : for concealed / visible\" + \"\\n\")\nFreeCAD.Console.PrintMessage(\"SHIFT + D : for create spreadSheet / close spreadSheet\" + \"\\n\")\nFreeCAD.Console.PrintMessage(\"____________________________\" + \"\\n\")\n\npas = 0\no = ViewObserver(v)\ntry:\n    c = v.addEventCallback(\"SoEvent\",o.logPosition)\nexcept Exception:\n    App.ActiveDocument.removeObject(objectAnn.Label)\n    FreeCAD.Console.PrintMessage( \"Not GUI End FCInfoToMouse\" + \"\\n\")\n\n",
    "url": "https://wiki.freecad.org/Macro_FCInfoToMouse",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/974214c4b83beaa41495/raw/7789c1995dba2af74a14d549638267f7740c036c/Macro_FCInfoToMouse.FCMacro",
    "wiki": "",
    "version": "00.04",
    "license": "",
    "date": "27/03/2018",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\FCInfoToMouse.png",
    "icon_source": "https://wiki.freecad.org/images/1/10/FCInfoToMouse.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FCTreeView",
    "on_wiki": true,
    "on_git": false,
    "desc": "<span style=\"background-color:#ff0000; color:#ffffff;\">New version GUI modifyed for the HD dpi (QGridLayout) run only FC version 0.18 and more (PySide2 Qt5)</span> <br /> <br />Macro for list all objects in the project in one list without hierarchy, options sort by name, label, visibility, group, by length option search by name, label .... without case sensitive or with case sensitive and select all objects displayed in the macro window. <br /> <br /><a rel=\"nofollow\" class=\"external text\" href=\"https://forum.freecadweb.org/download/file.php?id=70498\">Macro FCTreeView Icon package</a> unzip the .zip file and copy the icon in your macro directory. <br /> <br />For the precedent version see <a rel=\"nofollow\" class=\"external text\" href=\"https://gist.githubusercontent.com/mario52a/67517ef758ff20005d0a6adcfd8c9190/raw/0a92d7f591a0a179f84b2fc417046723b4d7b0e6/Macro_FCTreeView.FCMacro\">Macro_FCTreeView.FCMacro</a> and install it manually.<br /><br />Macro version: 00.09<br />Last modified: 2020-09-24<br />FreeCAD version: 0.18 and below<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/6/64/Macro_FCTreeView.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "New version GUI modifyed for the HD dpi (QGridLayout) run only FC version 0.18 and more (PySide2 Qt5) ",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n#\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2017 2018 2019 2020 <mario52>                           *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#Macro_ 08/09/2017 11/09/2017 23/09/2017 29/09/2017 27/11/2017 13/12/2017 06/05/2018 2020/02/25 rmu 24/09/2020\n#\n#OS: Windows 10 (10.0)\n#Word size of OS: 64-bit\n#Word size of FreeCAD: 64-bit\n#Version: 0.19.22474 (Git)\n#Build type: Release\n#Branch: master\n#Hash: a44f8ffd427fa9b23b1f00dbf62d66cd152cd774\n#Python version: 3.6.8\n#Qt version: 5.12.1\n#Coin version: 4.0.0a\n#OCC version: 7.3.0\n#Locale: French/Mars (fr_MA)\n#\n#\n__title__   = \"FCTreeView\"\n__author__  = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__Wiki__    = \"http://www.freecadweb.org/wiki/index.php?title=Macro_FCTreeView\"\n__version__ = \"00.09\"\n__date__    = \"2020/09/24\" #YYYY/MM/DD\n\nimport WebGui\n\nimport PySide2\nfrom PySide2 import (QtWidgets, QtCore, QtGui)\nfrom PySide2.QtWidgets import (QWidget, QApplication, QSlider, QGraphicsView, QGraphicsScene, QVBoxLayout, QStyle)\nfrom PySide2.QtGui import (QPainter, QColor, QIcon)\nfrom PySide2.QtSvg import *\nimport PySide2.QtXml\n\nimport math\nimport time\nfrom pivy import coin\n\nimport copy                                                  # pour copier 2 tableaux\nimport re\nimport time\nimport operator\nfrom operator import itemgetter, attrgetter, methodcaller    # pour sort \n\n\n####\n#from PySide import QtCore\n#global langue \n#s=QtCore.QLocale()\n#s.countryToString(s.country())\n#s.name()\n#langue = s.languageToString(s.language())\n#print s.name()   # fr\n#print langue     # French\n####\n\nGui = FreeCADGui\nApp = FreeCAD\n\nglobal ui                     ; ui             = \"\"\nglobal doc                    ; doc            = \"\"\nglobal sourisPass             ; sourisPass     = 0\nglobal listeObjetsOriginal    ; listeObjetsOriginal = [[]]    # objName, objLabel, \"False\", objGroupe, objLName, objLLabel, objLGroupe, objSignal, objTypeSolid, objTypeTypeID, objTypeShape, [objNumeric]]\nglobal listeSorted            ; listeSorted         = [[]]    # objName, objLabel, \"False\", objGroupe, objLName, objLLabel, objLGroupe, objSignal, objTypeSolid, objTypeTypeID, objTypeShape, [objNumeric]]\nglobal listeByStringSear      ; listeByStringSear   = []      # object searched\nglobal titre                  ; titre          = \" Original\"\nglobal derouler               ; derouler       = 0\nglobal visibilite             ; visibilite     = 0\nglobal group                  ; group          = 0\nglobal searchString           ; searchString   = \"\"\nglobal SplitNameLabel         ; SplitNameLabel = 0\nglobal selections             ; selections     = 0\n\nglobal reverse_00             ; reverse_00     = 0\nglobal reverse_01             ; reverse_01     = 0\nglobal reverse_02             ; reverse_02     = 0\nglobal reverse_03             ; reverse_03     = 0\n\nglobal impost                 ; impost = [\"Angle\",\"Angle0\",\"Angle1\",\"Angle2\",\"Angle3\",\"ChamferSize\",\"Circumradius\",\"Columns\",\"Degree\",\n                                          \"FilletRadius\",\"FirstAngle\",\"Growth\",\"Height\",\"LastAngle\",\"Length\",\"Length2\",\"MajorRadius\",\n                                          \"MinorRadius\",\"Pitch\",\"Polygon\",\"Radius\",\"Radius1\",\"Radius2\",\"Radius3\",\"Rows\",\"Size\",\"Width\",\n                                          \"X\",\"X1\",\"X2\",\"Xmax\",\"Xmin\",\"X2max\",\"X2min\",\n                                          \"Y\",\"Y1\",\"Y2\",\"Ymax\",\"Ymin\",\"Y2max\",\"Y2min\",\n                                          \"Z\",\"Z1\",\"Z2\",\"Zmax\",\"Zmin\",\"Z2max\",\"Z2min\"]\n\n#### variables global spreadSheet\nglobal densite                ; densite        = 1.00 # densite / 1d3 (steel) (7.50 kg for 1 dm cube(dm3))\nglobal uniteP                 ; uniteP         = 1.00\nglobal unitePs                ; unitePs        = \"g\"\nglobal uniteM                 ; uniteM         = 1.0\nglobal uniteMs                ; uniteMs        = \"mm\"\nglobal uniteS                 ; uniteS         = 1.0\nglobal uniteSs                ; uniteSs        = \"mm2\"\nglobal uniteV                 ; uniteV         = 1.0\nglobal uniteVs                ; uniteVs        = \"mm3\"\n\nglobal arrondi                ; arrondi        = 3\nglobal grandeur               ; grandeur       = \"\"\n\nglobal TextColorText_R        ; TextColorText_R   = 0.627451  # color red   1 = 255\nglobal TextColorText_G        ; TextColorText_G   = 0.627451  # color green 1 = 255\nglobal TextColorText_B        ; TextColorText_B   = 0.643137  # color blue  1 = 255\nglobal TextColorText_L        ; TextColorText_L   = 1.000000  # color blue  1 = 255\n\nglobal newSpreadSheetName     ; newSpreadSheetName = \"FCSpreadSheet\"\nglobal selectAllCB            ; selectAllCB    = 0\n#### variables global spreadSheet\n\n####################################################################################################\nglobal testing                ; testing        = 2    # if testing == 1 MainWindow separate\n                                                      # if testing == 2 RightDock\n                                                      # else       == other LeftDock\n####################################################################################################\n\ndef decodeColonne(colonne = \"A\"):                                  # converti la chaine A ... ZZ en numero de colonne ex: A = 1; AA = 27\n    colonne  = re.split('[0-9]+', colonne, flags=re.IGNORECASE)[0] # supp the alphanumeric number ex: A2 = A; A12 = A (1A return 0)\n    try:\n        if len(colonne) > 1:\n            return ((ord(colonne[0].upper()) - 64) * 26 ) + (ord(colonne[1].upper()) - 64) # max 2 car (AAAA return 27)\n        else:\n            return (ord(colonne.upper()) - 64 )\n    except Exception:\n        return 0\n\ndef decodeOccupation(dataTableau = \"\"):  # decode the max occupation Colonnes, Lines and give the cell occupation\n    #\n    #lineMax, colonneMax, cellsOccupation = decodeOccupation(FreeCAD.ActiveDocument.getObject(str(Sheet.Name)))\n    #\n    try:\n        tyty = dataTableau.cells.Content\n        tyty = tyty.split(\">\")\n        \n        ####\n        cellsOccupation = [] \n        cellsSorted     = []                                                 # search the \"A1\" definition\n\n        for i in tyty[1:-2]:     \n            i = i[i.find('\"')+1:]                                            # split les cases dans la chaine XML\n            i = i[:i.find('\"')]\n            if (i[0] >= \"A\") and (i[0]<=\"Z\"):                                # doit etre une lettre A a Z ( >= 0.18)\n                cellsOccupation.append(i)\n        cellsSorted = copy.deepcopy(cellsOccupation)\n        cellsSorted.sort()\n        ####\n        linesMax = 0\n        for i in cellsSorted:                                                # recherche le max (ligne et colonne)\n            colonnesMax = re.split('[0-9]+', i, flags=re.IGNORECASE)         # colonne max (AA)\n            dummy   = int(re.split('[A-Z]+', i, flags=re.IGNORECASE)[1])     # line\n            if dummy > linesMax:\n                linesMax = dummy                                             # lines max\n        del cellsSorted[:]\n        ####\n        return linesMax, decodeColonne(colonnesMax[0]), cellsOccupation      # return linesMax , colonnesMax, cellsOccupation\n\n    except Exception:\n        FreeCAD.Console.PrintError(\"Error data, Enter object <Sheet object> ex:\" + \"\\n\")\n        FreeCAD.Console.PrintError(\"lineMax, colonneMax, cellsOccupation = decodeOccupation(FreeCAD.ActiveDocument.getObject(str(Sheet.Name)))\" + \"\\n\")\n        return 0, 0, []\n\ndef caseTableau(ligne = 1, colonne = 1):              # calcule et code la case du tableur ex caseTableau(1, 2) return B1\n    if ligne < 1: ligne = 1\n    if ligne > 16384: ligne = 16384\n    if colonne < 1: colonne = 1\n    if colonne > 702: colonne = 702\n    if (colonne > 26):\n        if abs(colonne % 26) == 0:\n            return chr(64 + (abs(int(colonne / 26)) -1)) + chr(90) + str(ligne)\n        else:\n            return chr(64 + (abs(int(colonne / 26)))) + chr(64 + (abs(colonne % 26))) + str(ligne)\n    else:\n        return chr(colonne + 64) + str(ligne)\n\ndef arround( x):\n    global arrondi\n\n    return round(x, arrondi)\n\ndef affDim(obj, model):\n    global grandeur\n\n    objMm    = 0.0\n    grandeur = \"\"\n\n    try:\n        if model   == \"Angle\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Angle\n        elif model == \"Angle0\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Angle0\n        elif model == \"Angle1\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Angle1\n        elif model == \"Angle2\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Angle2\n        elif model == \"Angle3\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Angle3\n        elif model == \"ChamferSize\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).ChamferSize\n        elif model == \"Circumradius\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Circumradius\n        elif model == \"Columns\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Columns\n        elif model == \"Degree\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Degree\n        elif model == \"FilletRadius\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).FilletRadius\n        elif model == \"FirstAngle\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).FirstAngle\n        elif model == \"Growth\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Growth\n        elif model == \"Height\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Height\n        elif model == \"LastAngle\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).LastAngle\n        elif model == \"Length\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Length\n        elif model == \"Length2\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Length2\n        elif model == \"MajorRadius\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).MajorRadius\n        elif model == \"MinorRadius\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).MinorRadius\n        elif model == \"Pitch\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Pitch\n        elif model == \"Polygon\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Polygon\n        elif model == \"Radius\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Radius\n        elif model == \"Radius1\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Radius1\n        elif model == \"Radius2\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Radius2\n        elif model == \"Radius3\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Radius3\n        elif model == \"Rotations\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Rotations\n        elif model == \"Rows\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Rows\n        elif model == \"Size\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Size\n        elif model == \"Width\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Width\n        elif model == \"X\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).X\n        elif model == \"X1\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).X1\n        elif model == \"X2\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).X2\n        elif model == \"X2max\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).X2max\n        elif model == \"X2min\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).X2min\n        elif model == \"Xmax\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Xmax\n        elif model == \"Xmin\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Xmin\n        elif model == \"Y\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Y\n        elif model == \"Y1\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Y1\n        elif model == \"Y2\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Y2\n        elif model == \"Ymax\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Ymax\n        elif model == \"Ymin\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Ymin\n        elif model == \"Z\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Z\n        elif model == \"Z1\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Z1\n        elif model == \"Z2\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Z2\n        elif model == \"Z2max\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Z2max\n        elif model == \"Z2min\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Z2min\n        elif model == \"Zmax\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Zmax\n        elif model == \"Zmin\":\n            objMm = FreeCAD.ActiveDocument.getObject(obj).Zmin\n\n        try:\n            grandeur = str(objMm).split(\" \")\n            grandeur = grandeur[1]\n        except:\n            grandeur = \"\"\n\n        try:\n            objMm = objMm.Value\n        except:\n            objMm = 0.0\n\n    except:\n        objMm = 0.0\n    return objMm\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\nclass Ui_MainWindow(object):\n\n    def __init__(self, MainWindow):\n\n        self.window = MainWindow\n        #############\n        #self.path  = FreeCAD.ConfigGet(\"AppHomePath\")\n        #self.path  = FreeCAD.ConfigGet(\"UserAppData\")\n        #self.path  = \"your path\"\n        param = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")     # macro path\n        self.path = param.GetString(\"MacroPath\",\"\") + \"/\"                        # macro path\n        self.path = self.path.replace(\"\\\\\",\"/\")\n#        print \"Path for the icons : \" , self.path\n        #############\n\n        self.iconName     = QtGui.QIcon(self.path + \"Macro_FCTreeView_00.png\")\n        self.iconTrue     = QtGui.QIcon(self.path + \"Macro_FCTreeView_01.png\")\n        self.iconFalse    = QtGui.QIcon(self.path + \"Macro_FCTreeView_02.png\")\n        self.iconChain    = QtGui.QIcon(self.path + \"Macro_FCTreeView_03.png\")\n        self.iconChainCut = QtGui.QIcon(self.path + \"Macro_FCTreeView_04.png\")\n        self.iconLabel    = QtGui.QIcon(self.path + \"Macro_FCTreeView_05.png\")\n        self.iconVisible  = QtGui.QIcon(self.path + \"Macro_FCTreeView_06.png\")\n        self.iconPaChain  = QtGui.QIcon(self.path + \"Macro_FCTreeView_07.png\")\n        self.iconFolder   = QtGui.QIcon(self.path + \"Macro_FCTreeView_17.png\")\n\n#        self.vueActive = FreeCADGui.ActiveDocument.ActiveView\n#        self.click = self.vueActive.addEventCallback(\"SoMouseButtonEvent\",self.souris)\n        \n#    def souris(self,info):\n#        global sourisPass\n#        #print \"ok2\"\n#        ##{'ShiftDown': False, 'Button': 'BUTTON1', 'CtrlDown': False, 'State': 'UP', 'Time': 'Sunday, July 23, 2017 21:43:39', 'Position': (479, 354), 'AltDown': False, 'Type': 'SoMouseButtonEvent'}\n#        if (info[\"Button\"] == \"BUTTON1\") and (info[\"State\"] == \"DOWN\"):\n#            sourisPass = 0\n#            #print \"ok3\"\n#\n\n    def setupUi(self, MainWindow):\n        global testing\n        global densite\n\n        self.window = MainWindow\n        \n        if testing == 1:\n            MainWindow.setObjectName(_fromUtf8(\"MainWindow\"))    # volant\n            MainWindow.resize(340, 600)\n#            MainWindow.setMinimumSize(QtCore.QSize(341,619))\n#            MainWindow.setMaximumSize(QtCore.QSize(341,619))\n#            MainWindow.move(1300, 120)                           # deplace la fenetre\n\n        self.centralwidget = QtWidgets.QWidget(MainWindow)\n        self.centralwidget.setMinimumSize(QtCore.QSize(340,400))\n\n######### Layout Header ########################################################################\n        self.gridLayoutWidget = QtWidgets.QWidget(self.centralwidget)\n        self.gridLayoutWidget.setObjectName(\"gridLayoutWidget\")\n\n        self.grid_Principal = QtWidgets.QGridLayout(self.centralwidget)\n        self.grid_Principal.setContentsMargins(0, 0, 0, 0)\n        self.grid_Principal.setObjectName(\"grid_Principal\")\n\n        self.horizontal_Fenetre = QtWidgets.QHBoxLayout()\n######### Layout Header ########################################################################\n\n        self.treeWidget = QtWidgets.QTreeWidget(self.centralwidget)\n        #self.treeWidget.setGeometry(QtCore.QRect(10, 10, 321, 400))     # volant\n#        self.treeWidget.setGeometry(QtCore.QRect(10, 25, 321, 361))     # normal\n        #self.treeWidget.setSortingEnabled(True)                         #sort by clicked title\n        #__sortingEnabled = self.treeWidget.isSortingEnabled()           #sort by clicked title\n        #self.treeWidget.setSortingEnabled(__sortingEnabled)             #sort by clicked title\n        #self.treeWidget.header().setSortIndicatorShown(True)            #sort by clicked title\n\n        self.treeWidget.setLineWidth(6)\n        self.treeWidget.setDefaultDropAction(QtCore.Qt.CopyAction)\n        self.treeWidget.setAlternatingRowColors(True)\n        self.treeWidget.setIconSize(QtCore.QSize(12, 12))                # icon dimensions\n        self.treeWidget.setAnimated(True)\n        self.treeWidget.header().sectionSize(1200)\n        self.treeWidget.header().setDefaultSectionSize(1200)\n        self.treeWidget.header().setMinimumSectionSize(1200)             # dimension fenetre interne\n        self.treeWidget.header().setCascadingSectionResizes(True)\n        self.treeWidget.header().setHighlightSections(True)\n        self.treeWidget.header().setStretchLastSection(True)\n#        self.treeWidget.header().setMovable(True)\n        self.treeWidget.clicked.connect(self.on_treeWidget_clicked)      # connect on_treeWidget_clicked\n\n        #self.groupBox_Sort = QtWidgets.QGroupBox()\n\n        self.PB_Sort_00 = QtWidgets.QPushButton()\n        self.PB_Sort_00.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_10.png\"))\n        self.PB_Sort_00.clicked.connect(self.on_PB_Sort_00_clicked)\n\n        self.PB_Sort_01 = QtWidgets.QPushButton()\n        self.PB_Sort_01.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_11.png\"))\n        self.PB_Sort_01.clicked.connect(self.on_PB_Sort_01_clicked)\n\n        self.PB_Sort_02 = QtWidgets.QPushButton()\n        self.PB_Sort_02.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_12.png\"))\n        self.PB_Sort_02.clicked.connect(self.on_PB_Sort_02_clicked)\n\n        self.PB_Sort_03 = QtWidgets.QPushButton()\n        self.PB_Sort_03.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_13.png\"))\n        self.PB_Sort_03.clicked.connect(self.on_PB_Sort_03_clicked)\n\n        self.CB_Length = QtWidgets.QCheckBox()\n        self.CB_Length.setChecked(False)\n        self.CB_Length.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_19.png\"))\n\n        #self.groupBox_Global = QtWidgets.QGroupBox()\n\n#        self.PB_Reverse = QtWidgets.QPushButton()\n#        self.PB_Reverse.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_08.png\"))\n#        self.PB_Reverse.clicked.connect(self.on_PB_Reverse_clicked)\n\n        self.PB_SplitName = QtWidgets.QPushButton()\n        self.PB_SplitName.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_22.png\"))\n        self.PB_SplitName.clicked.connect(self.on_PB_SplitName_clicked)\n\n        self.PB_Expend = QtWidgets.QPushButton()\n        self.PB_Expend.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_15.png\"))\n        self.PB_Expend.clicked.connect(self.on_PB_Expend_clicked)\n\n        self.PB_Visibility = QtWidgets.QPushButton()\n        self.PB_Visibility.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_06.png\"))\n        self.PB_Visibility.clicked.connect(self.on_PB_Visibility_clicked)\n\n        self.PB_Group = QtWidgets.QPushButton()\n        self.PB_Group.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_07.png\"))\n        self.PB_Group.clicked.connect(self.on_PB_Group_clicked)\n\n        self.PB_Reload = QtWidgets.QPushButton()\n        self.PB_Reload.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_16.png\"))\n        self.PB_Reload.clicked.connect(self.on_PB_Reload_clicked)\n\n        self.PB_Original = QtWidgets.QPushButton()\n        self.PB_Original.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_18.png\"))\n        self.PB_Original.clicked.connect(self.on_PB_Original_clicked)\n\n        self.PB_All_Visible = QtWidgets.QPushButton()\n        self.PB_All_Visible.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_01.png\"))\n        self.PB_All_Visible.clicked.connect(self.on_PB_All_Visible_clicked)\n\n        self.PB_All_Hidden = QtWidgets.QPushButton()\n        self.PB_All_Hidden.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_02.png\"))\n        self.PB_All_Hidden.clicked.connect(self.on_PB_All_Hidden_clicked)\n\n\n        #self.groupBox_Search = QtWidgets.QGroupBox()\n\n        self.lineEdit_Search = QtWidgets.QLineEdit()\n#        self.lineEdit_Search.returnPressed.connect(self.on_lineEdit_Search_Pressed)      # for validate the data with press on return touch\n        self.lineEdit_Search.textChanged.connect(self.on_lineEdit_Search_Pressed)         # with tips key char by char\n\n        self.PB_ClearLEdit = QtWidgets.QPushButton()\n        self.PB_ClearLEdit.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_20.png\"))\n        self.PB_ClearLEdit.clicked.connect(self.on_PB_ClearLEdit_clicked)\n\n        self.frame_Options = QtWidgets.QFrame()\n        self.frame_Options.setFrameShape(QtWidgets.QFrame.StyledPanel)\n        self.frame_Options.setFrameShadow(QtWidgets.QFrame.Plain)\n\n        self.RB_01_NameLabel = QtWidgets.QRadioButton()\n        self.RB_01_NameLabel.setChecked(True)\n        self.RB_01_NameLabel.clicked.connect(self.on_RB_Pressed)\n\n        self.RB_02_Name_CS = QtWidgets.QRadioButton()\n        self.RB_02_Name_CS.clicked.connect(self.on_RB_Pressed)\n\n        self.RB_03_Label_NC = QtWidgets.QRadioButton()\n        self.RB_03_Label_NC.clicked.connect(self.on_RB_Pressed)\n\n        self.RB_04_NamLabel_CS = QtWidgets.QRadioButton()\n        self.RB_04_NamLabel_CS.clicked.connect(self.on_RB_Pressed)\n\n        self.RB_05_NameLabel_AL = QtWidgets.QRadioButton()\n        self.RB_05_NameLabel_AL.clicked.connect(self.on_RB_Pressed)\n\n        self.RB_06_Numeric_Num = QtWidgets.QRadioButton()\n        self.RB_06_Numeric_Num.clicked.connect(self.on_RB_Pressed)\n\n        self.PB_Select = QtWidgets.QPushButton()\n        self.PB_Select.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_23.png\"))\n        self.PB_Select.clicked.connect(self.on_PB_Select_clicked)\n\n        self.ComboB_Type = QtWidgets.QComboBox()\n        self.ComboB_Type.addItem(_fromUtf8(\"\"))\n#        self.ComboB_Type.currentIndexChanged.connect(self.SIGNAL_ComboB_Type_Changed)\n        self.ComboB_Type.activated.connect(self.SIGNAL_ComboB_Type_Changed)\n\n        self.label_Ver = QtWidgets.QLabel()\n\n        self.PB_SpreadSheet = QtWidgets.QPushButton()\n        self.PB_SpreadSheet.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_25.png\"))\n        self.PB_SpreadSheet.clicked.connect(self.on_PB_SpreadSheet_clicked)\n\n        self.PB_Quit = QtWidgets.QPushButton()\n        self.PB_Quit.setVisible(False)\n\n        if testing == 1:                                                 # 1=MainWindow separate\n            MainWindow.setCentralWidget(self.centralwidget)\n            MainWindow.setWindowTitle(__title__  + u\" (\" + __version__ + \" rmu (\" + __date__ + \"))\")\n\n            self.PB_Quit.setVisible(True)\n            self.PB_Quit.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_09.png\"))\n            self.PB_Quit.setText(\"Quit\")\n            self.PB_Quit.setToolTip(\"Quit FCTreeView <img src=\" + self.path + \"Macro_FCTreeView_09.png\" + \" />\")\n            self.PB_Quit.clicked.connect(self.on_PB_Quit_clicked)\n        else:\n            MainWindow.setWidget(self.centralwidget)\n            MainWindow.setWindowTitle(__title__ + u\" (\" + __version__ + \" rmu)\")\n            #MainWindow.setWindowTitle(__title__ + u\" (\" + __version__ + \" rmu) modified\")\n\n####SpreadSheet begin#######\n\n        self.Frame_Contener_SpreadSheet = QtWidgets.QGroupBox()\n        self.Frame_Contener_SpreadSheet.setVisible(False)\n\n        self.Frame_01_SpreadSheet = QtWidgets.QFrame()\n        self.Frame_01_SpreadSheet.setFrameShape(QtWidgets.QFrame.StyledPanel)\n        self.Frame_01_SpreadSheet.setFrameShadow(QtWidgets.QFrame.Raised)\n\n        self.CB_01_Title = QtWidgets.QCheckBox()\n        self.CB_01_Title.setChecked(True)\n        self.CB_01_Title.clicked.connect(self.on_CB_01_Title_clicked)\n\n        self.CB_02_Color = QtWidgets.QCheckBox()\n        self.CB_02_Color.setChecked(True)\n        self.CB_02_Color.clicked.connect(self.on_CB_02_Color_clicked)\n\n        self.CB_03_Colonne = QtWidgets.QCheckBox()\n        self.CB_03_Colonne.setChecked(True)\n\n        self.CB_04_Name = QtWidgets.QCheckBox()\n\n        self.CB_05_Label = QtWidgets.QCheckBox()\n        self.CB_05_Label.setChecked(True)\n\n        self.CB_06_Nomenclature = QtWidgets.QCheckBox()\n        self.CB_06_Nomenclature.clicked.connect(self.on_CB_06_Nomenclature_clicked)\n\n        self.CB_07_Solid = QtWidgets.QCheckBox()\n\n        self.CB_08_Volume = QtWidgets.QCheckBox()\n\n        self.CB_09_Weight = QtWidgets.QCheckBox()\n\n        self.CB_10_Weight_Total = QtWidgets.QCheckBox()\n        self.CB_10_Weight_Total.setEnabled(False)\n\n        self.CB_11_Surface = QtWidgets.QCheckBox()\n\n        self.CB_12_BBox = QtWidgets.QCheckBox()\n\n        self.CB_13_Translate = QtWidgets.QCheckBox()\n\n        self.CB_14_Rotation = QtWidgets.QCheckBox()\n\n        self.CB_15_Dimension = QtWidgets.QCheckBox()\n        self.CB_15_Dimension.setChecked(True)\n\n        #self.LA_Wait = QtWidgets.QLabel()\n\n        self.progressBar_01 = QtWidgets.QProgressBar()\n        self.progressBar_01.setMaximum(100)\n        self.progressBar_01.setMinimum(0)\n        self.progressBar_01.setValue(0)\n        self.progressBar_01.setOrientation(QtCore.Qt.Horizontal)\n        self.progressBar_01.setAlignment(QtCore.Qt.AlignCenter)\n        #self.progressBar_01.setToolTip(_translate(\"MainWindow\", \"progressBar_01\", None))\n\n        self.Frame_02_SpreadSheet = QtWidgets.QFrame()\n        self.Frame_02_SpreadSheet.setFrameShape(QtWidgets.QFrame.StyledPanel)\n        self.Frame_02_SpreadSheet.setFrameShadow(QtWidgets.QFrame.Plain)\n\n        self.RB_01_Value = QtWidgets.QRadioButton()\n        self.RB_01_Value.setChecked(True)\n\n        self.RB_02_Val_Gr = QtWidgets.QRadioButton()\n\n        self.RB_03_Val_Gr_Ph = QtWidgets.QRadioButton()\n\n        self.CB_08_Split = QtWidgets.QCheckBox()\n\n        self.Frame_03_Config = QtWidgets.QFrame()\n        self.Frame_03_Config.setFrameShape(QtWidgets.QFrame.StyledPanel)\n        self.Frame_03_Config.setFrameShadow(QtWidgets.QFrame.Plain)\n\n        self.CBox_01_Longueur = QtWidgets.QComboBox()\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        self.CBox_01_Longueur.addItem(_fromUtf8(\"\"))\n        #self.CBox_01_Longueur.currentIndexChanged.connect(self.On_ComboB_SpreadSheet)    # donne le num de ligne\n        self.CBox_01_Longueur.currentIndexChanged[str].connect(self.On_CBox_01_Longueur_SpreadSheet)# [str] or [int]\n\n        self.CBox_02_Poids = QtWidgets.QComboBox()\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        self.CBox_02_Poids.addItem(_fromUtf8(\"\"))\n        #self.CBox_02_Poids.currentIndexChanged.connect(self.On_ComboB_SpreadSheet)    # donne le num de ligne\n        self.CBox_02_Poids.activated[str].connect(self.On_CBox_02_Poids_SpreadSheet)   # [str] or [int]\n\n        self.DS_01_Densite = QtWidgets.QDoubleSpinBox()\n        self.DS_01_Densite.setSuffix(\" Density\")\n        self.DS_01_Densite.setMinimum(-9999999999.999)\n        self.DS_01_Densite.setMaximum(999.999)\n        self.DS_01_Densite.setDecimals(4)\n        self.DS_01_Densite.setValue(densite)\n        self.DS_01_Densite.setSingleStep(1)\n        self.DS_01_Densite.valueChanged.connect(self.on_DS_01_Densite_valueChanged)\n\n        self.DS_02_Round = QtWidgets.QSpinBox()\n        self.DS_02_Round.setMinimum(0)\n        self.DS_02_Round.setMaximum(40)\n        self.DS_02_Round.setValue(3)\n        self.DS_02_Round.setSingleStep(1)\n        self.DS_02_Round.valueChanged.connect(self.on_DS_02_Round_valueChanged)\n\n        self.ComboB_SpreadSheet = QtWidgets.QComboBox()\n        #self.ComboB_SpreadSheet.addItem(_fromUtf8(\"\"))\n        #self.ComboB_SpreadSheet.currentIndexChanged.connect(self.On_ComboB_SpreadSheet)    # donne le num de ligne\n        self.ComboB_SpreadSheet.currentIndexChanged[str].connect(self.On_ComboB_SpreadSheet)# [str] or [int]\n\n        self.LE_SpreadSheet = QtWidgets.QLineEdit()\n        self.LE_SpreadSheet.setText(newSpreadSheetName)\n        self.LE_SpreadSheet.textChanged.connect(self.on_LE_SpreadSheet_Pressed)      # connect on \"on_LE_SpreadSheet_Pressed\n\n        self.PB_01_SpreadSheet_Select_All = QtWidgets.QPushButton()\n        self.PB_01_SpreadSheet_Select_All.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_28.png\"))\n        self.PB_01_SpreadSheet_Select_All.clicked.connect(self.on_PB_01_SpreadSheet_Select_All_clicked)\n\n        self.PB_03_SpreadSheet_Save = QtWidgets.QPushButton()\n        self.PB_03_SpreadSheet_Save.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_27.png\"))\n        self.PB_03_SpreadSheet_Save.clicked.connect(self.on_PB_03_SpreadSheet_Save_clicked)\n\n        self.PB_04_SpreadSheet_Quit = QtWidgets.QPushButton()\n        self.PB_04_SpreadSheet_Quit.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_26.png\"))\n        self.PB_04_SpreadSheet_Quit.clicked.connect(self.on_PB_04_SpreadSheet_Quit_clicked)\n\n####SpreadSheet end######\n######### Layout Begin ########################################################################\n        self.horizontal_Fenetre.addWidget(self.treeWidget)\n        self.horizontal_Fenetre.setContentsMargins(10, 5, 10, 0)\n        self.grid_Principal.addLayout(self.horizontal_Fenetre, 1, 0, 1, 1)\n        self.horizontal_Group_Sort_By = QtWidgets.QHBoxLayout()\n#### Sort\n        ####\n        self.groupBox_Sort = QtWidgets.QGroupBox(self.gridLayoutWidget)\n        self.gridLayoutWidget_2 = QtWidgets.QWidget(self.groupBox_Sort)\n        self.grid_Bouton_SortBy = QtWidgets.QGridLayout(self.groupBox_Sort)\n        self.grid_Bouton_SortBy.setContentsMargins(10, 10, 10, 10)\n        self.grid_Bouton_SortBy.addWidget(self.PB_Sort_00, 0, 0, 1, 1)\n        self.grid_Bouton_SortBy.addWidget(self.PB_Sort_01, 0, 1, 1, 1)\n        self.grid_Bouton_SortBy.addWidget(self.PB_Sort_02, 0, 2, 1, 1)\n        self.grid_Bouton_SortBy.addWidget(self.PB_Sort_03, 0, 3, 1, 1)\n        self.grid_Bouton_SortBy.addWidget(self.CB_Length, 0, 4, 1, 1)\n        \n        self.horizontal_Group_Sort_By.addWidget(self.groupBox_Sort)\n        self.grid_Principal.addLayout(self.horizontal_Group_Sort_By, 2, 0, 1, 1)\n        self.horizontal_Group_Sort_By.setContentsMargins(10, 5, 10, 0)        #marge\n        self.horizontal_Group_Global = QtWidgets.QHBoxLayout()\n        ####\n####\n#### Global\n        ####\n        self.groupBox_Global = QtWidgets.QGroupBox(self.gridLayoutWidget)\n        self.gridLayoutWidget_3 = QtWidgets.QWidget(self.groupBox_Global)\n        self.gridLayoutWidget_3.setContentsMargins(10, 5, 10, 10)\n\n        self.grid_Global_Boutons = QtWidgets.QGridLayout(self.groupBox_Global)\n\n        self.horizontal_Group_Global.addWidget(self.groupBox_Global)\n        self.horizontal_Group_Global.setContentsMargins(10, 5, 10, 0)\n#        self.grid_Global_Boutons.setContentsMargins(10, 10, 10, 10)\n        self.grid_Global_Boutons.addWidget(self.PB_SplitName, 0, 0, 1, 1)\n        self.grid_Global_Boutons.addWidget(self.PB_Expend, 0, 1, 1, 1)\n        self.grid_Global_Boutons.addWidget(self.PB_Visibility, 0, 2, 1, 1)\n        self.grid_Global_Boutons.addWidget(self.PB_Group, 0, 3, 1, 1)\n        self.grid_Global_Boutons.addWidget(self.PB_Reload, 1, 0, 1, 1)\n        self.grid_Global_Boutons.addWidget(self.PB_Original, 1, 1, 1, 1)\n        self.grid_Global_Boutons.addWidget(self.PB_All_Visible, 1, 2, 1, 1)\n        self.grid_Global_Boutons.addWidget(self.PB_All_Hidden, 1, 3, 1, 1)\n\n        self.grid_Principal.addLayout(self.horizontal_Group_Global, 3, 0, 1, 1)\n        ####\n####\n#### Search\n        ####\n        self.horizontal_GroupBox_Search = QtWidgets.QHBoxLayout()\n        self.horizontal_GroupBox_Search.setContentsMargins(10, 0, 10, 10)\n        self.groupBox_Search = QtWidgets.QGroupBox(self.gridLayoutWidget)\n        self.groupBox_Search.setContentsMargins(10, 5, 10, 10)\n        self.grid_Boutons_Search = QtWidgets.QGridLayout(self.groupBox_Search)\n        self.grid_Boutons_Search.setContentsMargins(10, 10, 10, 10)\n\n        self.grid_Boutons_Search.addWidget(self.lineEdit_Search, 0, 0, 1, 2)\n        self.grid_Boutons_Search.addWidget(self.PB_ClearLEdit, 0, 2, 1, 1)\n        self.grid_Boutons_Search.addWidget(self.ComboB_Type, 2, 0, 1, 1)\n        #self.grid_Boutons_Search.addWidget(self.PB_Select, 1, 2, 1, 1)\n        self.grid_Boutons_Search.addWidget(self.PB_SpreadSheet, 2, 1, 1, 1)\n        self.frame_Options = QtWidgets.QFrame(self.groupBox_Search)\n        self.frame_Options.setFrameShape(QtWidgets.QFrame.StyledPanel)\n        self.frame_Options.setFrameShadow(QtWidgets.QFrame.Plain)\n        self.grid_Search_Radio_Bouton = QtWidgets.QGridLayout(self.frame_Options)\n        self.gridLayoutWidget_5 = QtWidgets.QWidget(self.frame_Options)\n        self.grid_Search_Radio_Bouton.addWidget(self.RB_01_NameLabel, 0, 0, 1, 1)\n        self.grid_Search_Radio_Bouton.addWidget(self.RB_02_Name_CS, 0, 1, 1, 1)\n        self.grid_Search_Radio_Bouton.addWidget(self.RB_03_Label_NC, 0, 2, 1, 1)\n        self.grid_Search_Radio_Bouton.addWidget(self.RB_04_NamLabel_CS, 0, 3, 1, 1)\n        self.grid_Search_Radio_Bouton.addWidget(self.RB_05_NameLabel_AL, 0, 4, 1, 1)\n        self.grid_Search_Radio_Bouton.addWidget(self.RB_06_Numeric_Num, 0, 5, 1, 1)\n        if testing == 1:\n            self.grid_Boutons_Search.addWidget(self.PB_Select, 1, 2, 1, 1)\n            self.grid_Boutons_Search.addWidget(self.PB_Quit, 2, 2, 1, 1)\n            self.grid_Boutons_Search.addWidget(self.frame_Options, 1, 0, 1, 2)\n        else:\n            self.grid_Boutons_Search.addWidget(self.PB_Select, 2, 2, 1, 1)\n            self.grid_Boutons_Search.addWidget(self.frame_Options, 1, 0, 1, 3)\n\n        self.horizontal_GroupBox_Search.addWidget(self.groupBox_Search)\n        self.grid_Principal.addLayout(self.horizontal_GroupBox_Search, 4, 0, 1, 1)\n        ####\n####\n#### SpreedSheet\n        ####\n        self.gridLayout = QtWidgets.QGridLayout()\n        self.gridLayout.setContentsMargins(10, 5, 10, 0)\n        self.Frame_Contener_SpreadSheet = QtWidgets.QGroupBox(self.gridLayoutWidget)\n        self.Frame_Contener_SpreadSheet.setVisible(False)\n\n        self.gridLayoutWidget_6 = QtWidgets.QWidget(self.Frame_Contener_SpreadSheet)\n        ####\n        self.gridLayout_23 = QtWidgets.QGridLayout(self.Frame_Contener_SpreadSheet)\n        self.gridLayout_23.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_20 = QtWidgets.QGridLayout()\n\n        ####\n        self.gridLayout_20.addWidget(self.CB_01_Title, 0, 0, 1, 1)\n        self.gridLayout_20.addWidget(self.CB_02_Color, 0, 1, 1, 1)\n        self.gridLayout_20.addWidget(self.CB_03_Colonne, 0, 2, 1, 1)\n        self.gridLayout_20.addWidget(self.CB_04_Name, 0, 3, 1, 1)\n        self.gridLayout_20.addWidget(self.CB_05_Label, 0, 4, 1, 1)\n        self.gridLayout_20.addWidget(self.CB_06_Nomenclature, 1, 0, 1, 1)\n        self.gridLayout_20.addWidget(self.CB_07_Solid, 1, 1, 1, 1)\n        self.gridLayout_20.addWidget(self.CB_08_Volume, 1, 2, 1, 1)\n        self.gridLayout_20.addWidget(self.CB_09_Weight, 1, 3, 1, 1)\n        self.gridLayout_20.addWidget(self.CB_10_Weight_Total, 1, 4, 1, 1)\n        self.gridLayout_20.addWidget(self.CB_11_Surface, 2, 0, 1, 1)\n        self.gridLayout_20.addWidget(self.CB_12_BBox, 2, 1, 1, 1)\n        self.gridLayout_20.addWidget(self.CB_13_Translate, 2, 2, 1, 1)\n        self.gridLayout_20.addWidget(self.CB_14_Rotation, 2, 3, 1, 1)\n        self.gridLayout_20.addWidget(self.CB_15_Dimension, 2, 4, 1, 1)\n        #self.gridLayout_20.addWidget(self.LA_Wait, x, x, 1, 1)\n\n        ####\n        self.Frame_02_SpreadSheet = QtWidgets.QFrame(self.gridLayoutWidget_6)\n        self.Frame_02_SpreadSheet.setFrameShape(QtWidgets.QFrame.StyledPanel)\n        self.Frame_02_SpreadSheet.setFrameShadow(QtWidgets.QFrame.Plain)\n\n        ####\n        self.gridLayout_21 = QtWidgets.QGridLayout(self.Frame_02_SpreadSheet)\n        self.gridLayout_21.setContentsMargins(5, 5, 5, 5)\n        self.gridLayout_21.addWidget(self.RB_01_Value, 0, 0, 1, 1)\n        self.gridLayout_21.addWidget(self.RB_02_Val_Gr, 0, 1, 1, 1)\n        self.gridLayout_21.addWidget(self.RB_03_Val_Gr_Ph, 0, 2, 1, 1)\n        self.gridLayout_21.addWidget(self.CB_08_Split, 0, 3, 1, 1)\n        ####\n\n        self.gridLayout_20.addWidget(self.Frame_02_SpreadSheet, 7, 0, 1, 5)\n\n        self.gridLayout_20.addWidget(self.CBox_01_Longueur, 8, 0, 1, 1)\n        self.gridLayout_20.addWidget(self.CBox_02_Poids, 8, 1, 1, 2)\n        self.gridLayout_20.addWidget(self.DS_01_Densite, 8, 3, 1, 1)\n        self.gridLayout_20.addWidget(self.DS_02_Round, 8, 4, 1, 1)\n\n        self.gridLayout_20.addWidget(self.ComboB_SpreadSheet, 9, 0, 1, 3)\n        self.gridLayout_20.addWidget(self.LE_SpreadSheet, 9, 3, 1, 2)\n\n        self.gridLayout_20.addWidget(self.progressBar_01, 6, 0, 1, 5)\n        self.gridLayout_23.addLayout(self.gridLayout_20, 0, 0, 1, 1)\n        ####\n\n        self.Frame_03_Config = QtWidgets.QFrame(self.gridLayoutWidget_6)\n        self.Frame_03_Config.setFrameShape(QtWidgets.QFrame.StyledPanel)\n        self.Frame_03_Config.setFrameShadow(QtWidgets.QFrame.Plain)\n        \n        ####\n        self.gridLayoutWidget_8 = QtWidgets.QWidget(self.Frame_03_Config)\n        \n        self.gridLayout_22 = QtWidgets.QGridLayout(self.Frame_03_Config)\n        self.gridLayout_22.setContentsMargins(5, 5, 5, 5)\n\n        self.gridLayout_22.addWidget(self.PB_01_SpreadSheet_Select_All, 0, 0, 1, 1)\n        self.gridLayout_22.addWidget(self.PB_03_SpreadSheet_Save, 0, 1, 1, 1)\n        self.gridLayout_22.addWidget(self.PB_04_SpreadSheet_Quit, 0, 2, 1, 1)\n        \n        self.gridLayout_23.addWidget(self.Frame_03_Config, 1, 0, 1, 1)\n\n        self.gridLayout.addWidget(self.Frame_Contener_SpreadSheet, 0, 0, 1, 1)\n        self.grid_Principal.addLayout(self.gridLayout, 3, 0, 1, 1)\n        ####\n####\n######### Layout End ########################################################################\n\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n        if testing == 1:\n            MainWindow.setCentralWidget(self.centralwidget)\n\n    def retranslateUi(self, MainWindow):\n        global newSpreadSheetName\n\n        MainWindow.setWindowIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_18.png\"))   # change l'icone de la fenetre principale\n        MainWindow.setWindowFlags(PySide2.QtCore.Qt.WindowStaysOnTopHint)               # PySide cette fonction met la fenetre en avant\n\n        self.treeWidget.setToolTip(\"The title display the option, number and type object(s) displayed\" + \"\\n\" + \"\\n\" + \n                                   \"O = Objects\" + \"\\n\" + \n                                   \"N = Name\" + \"\\n\" + \n                                   \"L = Label\" + \"\\n\" + \n                                   \"Nu= Numeric\" + \"\\n\" + \n                                   \"T = Total\" + \"\\n\" + \n                                   \"G = Group\" + \"\\n\" + \n                                   \"S = Single\" + \"\\n\" + \n                                   \"V = Visible\" + \"\\n\" + \n                                   \"H = Hidden\" + \"\\n\\n\" +\n                                   \"If one object are selected :\" + \"\\n\" + \n                                   \"the Placement Base, Rotation and Center of mass is displayed\" + \"\\n\" + \n                                   \"if available !\")\n\n        self.groupBox_Sort.setTitle(\"Sort by:\")\n        self.PB_Sort_00.setText(\"Name\")\n        self.PB_Sort_00.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_10.png\" + \" />\" + \"\\n\" + \n                                   \"Sort by <b>Name</b>\")\n        self.PB_Sort_01.setText(\"Label\")\n        self.PB_Sort_01.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_11.png\" + \" />\" + \"\\n\" + \n                                   \"Sort by <b>Label</b>\")\n        self.PB_Sort_02.setText(\"Visible\")\n        self.PB_Sort_02.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_12.png\" + \" />\" + \"\\n\" + \n                                   \"Sort by <b>Visibility</b>\")\n        self.PB_Sort_03.setText(\"Group\")\n        self.PB_Sort_03.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_13.png\" + \" />\" + \"\\n\" + \n                                   \"Sort by <b>Group</b>\")\n        self.CB_Length.setText(\"Length\")\n        self.CB_Length.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_19.png\" + \" />\" + \"\\n\" + \n                                  \"If Checked sort by string length\")\n\n        self.groupBox_Global.setTitle(\"Global\")\n#        self.PB_Reverse.setText(\"Reverse\")\n#        self.PB_Reverse.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_08.png\" + \" />\" + \"\\n\" + \n#                                   \"Reverse the data listing\")\n        self.PB_SplitName.setText(\"Split\")\n        self.PB_SplitName.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_22.png\" + \" />\" + \"\\n\" + \n                                     \"Split name and label\")\n        self.PB_Expend.setText(\"Expend\")\n        self.PB_Expend.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_15.png\" + \" />\" + \"\\n\" + \n                                  \"Expend the listing objects\")\n        self.PB_Visibility.setText(\"Visibility\")\n        self.PB_Visibility.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_06.png\" + \" />\" + \"\\n\" + \n                                      \"The first icon display the visibility or not\")\n        self.PB_Group.setText(\"Group\")\n        self.PB_Group.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_07.png\" + \" />\" + \"\\n\" + \n                                 \"The first icon display the group or not\")\n        self.PB_Reload.setText(\"Reload\")\n        self.PB_Reload.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_16.png\" + \" />\" + \"\\n\" + \n                                  \"Reload the <b>ACTUAL VIEW</b> on 3D Screen\")\n        self.PB_Original.setText(\"Original\")\n        self.PB_Original.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_18.png\" + \" />\" + \"\\n\" + \n                                    \"Return to original objects organisation and visibility\")\n        self.PB_All_Visible.setText(\"All Visible\")\n        self.PB_All_Visible.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_01.png\" + \" />\" + \"\\n\" + \n                                       \"All objects Visible\" + \"\\n\" + \n                                       \"For restitute the original organisation click to <b>Original</b> button\" + \"\\n\" + \n                                       \" <img src=\" + self.path + \"Macro_FCTreeView_18.png\" + \" />\")\n        self.PB_All_Hidden.setText(\"All Hidden\")\n        self.PB_All_Hidden.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_02.png\" + \" />\" + \"\\n\" +\n                                      \"All objects Hidden\" + \"\\n\" +\n                                      \"For restitute the original organisation click to <b>Original</b> button\" + \"\\n\" +\n                                      \"<img src=\" + self.path + \"Macro_FCTreeView_18.png\" + \" />\")\n                                 \n        self.groupBox_Search.setTitle(\"Search\")\n        self.PB_ClearLEdit.setText(\"Clear\")\n        self.PB_ClearLEdit.setToolTip(\"Clear the Line Search same lineEdit emptied <img src=\" + self.path + \"Macro_FCTreeView_20.png\" + \" />\")\n\n        self.RB_01_NameLabel.setText(\"NLwc\")\n        self.RB_01_NameLabel.setToolTip(\"Search by Name and Label Without respecting the sensitive Case\")\n        self.RB_02_Name_CS.setText(\"Nsc\")\n        self.RB_02_Name_CS.setToolTip(\"Search by Name and respecting the Sensitive Case\")\n        self.RB_03_Label_NC.setText(\"Lwc\")\n        self.RB_03_Label_NC.setToolTip(\"Search by Label Without respecting the sensitive Case\")\n        self.RB_04_NamLabel_CS.setText(\"NLsc\")\n        self.RB_04_NamLabel_CS.setToolTip(\"Search by Name and Label and respecting the Sensitive Case\")\n        self.RB_05_NameLabel_AL.setText(\"NLwsc\")\n        self.RB_05_NameLabel_AL.setToolTip(\"Search by Name and Label in Word and respecting the Sensitive Case\" + \"\\n\" + \n                                           \"(same panel selection of FreeCAD)\")\n        self.RB_06_Numeric_Num.setText(\"Num\")\n        self.RB_06_Numeric_Num.setToolTip(\"Search by Numeric value\" + \"\\n\" + \n                                          \"The value searched is the absolute value\" + \"\\n\" + \n                                          \" ex: entry 10\" + \"\\n\" + \n                                          \" result: 10, 10.5, 10.2154...\")\n        self.ComboB_Type.setToolTip(\"Search the object by type\")\n\n        self.PB_SpreadSheet.setText(\"S Sheet\")\n        self.PB_SpreadSheet.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_25.png\" + \" />\" + \"\\n\" + \n                                 \"SpreadSheet options\")\n\n        if testing == 1:\n            self.PB_Quit.setText(\"Quit\")\n            self.PB_Quit.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_09.png\" + \" />\" + \"\\n\" + \n                                 \"Quit FCTreeView\")\n            self.label_Ver.setText(\"FCTreeView (\" + __version__ + \" (\" + __date__ + \"))\")\n\n        self.PB_Select.setText(\"Select\")\n        self.PB_Select.setToolTip(\"Select all object(s) displayed <img src=\" + self.path + \"Macro_FCTreeView_23.png\" + \" />\")\n\n        self.ComboB_Type.setItemText(0, \"Choice your type\")\n\n        ########SpreadSheet##\n        self.Frame_Contener_SpreadSheet.setTitle(\"SpreadSheet\")\n\n        self.Frame_01_SpreadSheet.setToolTip(\"options to save in a spreadSheet\")\n\n        self.CB_01_Title.setText(\"Title\")\n        self.CB_01_Title.setToolTip(\"Create title align Centered and Bold\")\n        self.CB_02_Color.setText(\"Color cell\")\n        self.CB_02_Color.setToolTip(\"Colored the complete title in Grey\" + \"\\n\" +\n                                    \"(Background)\")\n        self.CB_03_Colonne.setText(\"Column\")\n        self.CB_03_Colonne.setToolTip(\"Colored the column Value of object in Grey\" + \"\\n\" + \n                                      \"If Color is checked\")\n        self.CB_04_Name.setText(\"Name\")\n        self.CB_04_Name.setToolTip(\"Real name of the object\")\n        self.CB_05_Label.setText(\"Label\")\n        self.CB_05_Label.setToolTip(\"Label of object\")\n\n        self.CB_06_Nomenclature.setText(\"Nomenclature\")\n        self.CB_06_Nomenclature.setToolTip(\"Nomenclature of object create a listing\" + \"\\n\" +\n                                     \"and display number part(s)\" + \"\\n\" +\n                                     \"in case of same Label the test is done on the volume\" + \"\\n\" +\n                                     \"to detect if the objects are identical\" + \"\\n\" +\n                                     \"(option available : W.Total)\")\n        self.CB_07_Solid.setText(\"Solid\")\n        self.CB_07_Solid.setToolTip(\"Type object Solid\")\n        self.CB_08_Volume.setText(\"Volume\")\n        self.CB_08_Volume.setToolTip(\"Calculate the Volume object\" + \"\\n\" +\n                                     \"(single object)\")\n        self.CB_09_Weight.setText(\"Weight\")\n        self.CB_09_Weight.setToolTip(\"Calculate the Weight object\" + \"\\n\" +\n                                     \"The weigth object is convert in the unit selected\" + \"\\n\" +\n                                     \"(single object)\")\n        self.CB_10_Weight_Total.setText(\"W.Total\")\n        self.CB_10_Weight_Total.setToolTip(\"Calculate the Weight total of object(s)\" + \"\\n\" +\n                                           \"This option is available if the Nomenclature is checked\" + \"\\n\" +\n                                           \"The weigth object(s) is convert in the unit selected\")\n\n        self.CB_11_Surface.setText(\"Surface\")\n        self.CB_11_Surface.setToolTip(\"Calculate the Surface of object\" + \"\\n\" +\n                                      \"The Surface object is convert in the unit selected\" + \"\\n\" +\n                                      \"(single object)\")\n        self.CB_12_BBox.setText(\"BBox\")\n        self.CB_12_BBox.setToolTip(\"Calculate the BoundBox of object\" + \"\\n\" +\n                                   \"The BoundBox value is convert in the unit selected\")\n        self.CB_13_Translate.setText(\"Translat.\")\n        self.CB_13_Translate.setToolTip(\"Display the Placement Translation values of object\" + \"\\n\" +\n                                        \"The Translation value is convert in the unit selected\")\n        self.CB_14_Rotation.setText(\"Rotation\")\n        self.CB_14_Rotation.setToolTip(\"Display the Placement Rotation values of object\" + \"\\n\" +\n                                       \"The Rotation value is convert in Degrees\")\n        self.CB_15_Dimension.setText(\"Dim.\")\n        self.CB_15_Dimension.setToolTip(\"Display the other Dimensions... values of object\" + \"\\n\" +\n                                        \"The Dimensions value is convert :\" + \"\\n\" +\n                                        \"in unit selected, in Degrees\" + \"\\n\" +\n                                        \"or none if the value is numerical value (ex:number face)\" + \"\\n\" +\n                                        \"The number of value depend of the object\")\n\n        self.Frame_02_SpreadSheet.setToolTip(\"Frame SpreadSheet Values\" + \"\\n\" +\n                                             \"Value     = value of object\" + \"\\n\" +\n                                             \"Val Gr    = value + unit detected (in same cell)\" + \"\\n\" +\n                                             \"Val Gr Ph = value + unit + type detected (in same cell)\" + \"\\n\" +\n                                             \"Split     = split the value group in cell separate\")\n\n        self.RB_01_Value.setText(\"Value\")\n        self.RB_01_Value.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_30.png\" + \" />\" + \"\\n\" +\n                                    \"Value = value of object\" + \"\\n\" +\n                                    \" ( Ex: 10.50 )\")\n        self.RB_02_Val_Gr.setText(\"Val Gr\")\n        self.RB_02_Val_Gr.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_31.png\" + \" />\" + \"\\n\" +\n                                     \"Val Gr = value + unit detected (in same cell)\" + \"\\n\" +\n                                     \" ( Ex: 10.50 mm )\")\n        self.RB_03_Val_Gr_Ph.setText(\"Val Gr Ph\")\n        self.RB_03_Val_Gr_Ph.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_32.png\" + \" />\" + \"\\n\" +\n                                        \"Val Gr Ph = value + unit + type detected (in same cell)\" + \"\\n\" +\n                                        \" ( Ex: 10.50 mm Length )\")\n        self.CB_08_Split.setText(\"Split\")\n        self.CB_08_Split.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_33.png\" + \" />\" + \"\\n\" +\n                                    \"Split = split the value group in cell separate\" + \"\\n\" +\n                                    \" ( Ex: 10.50 , mm , Length )\")\n\n        #http://fr.wikipedia.org/wiki/Unit%C3%A9s_de_mesure_anglo-saxonnes\n        self.CBox_01_Longueur.setToolTip(\"Unit on choice\" + \"\\n\" + \"Unit by default = mm\")\n        self.CBox_01_Longueur.setCurrentIndex(6)\n        self.CBox_01_Longueur.setItemText(0, \"km\")         #km #        = 1000000\n        self.CBox_01_Longueur.setItemText(1, \"hm\")         #hm #        = 100000\n        self.CBox_01_Longueur.setItemText(2, \"dam\")        #dam#        = 10000\n        self.CBox_01_Longueur.setItemText(3, \"m\")          #m  #        = 1000\n        self.CBox_01_Longueur.setItemText(4, \"dm\")         #dm #        = 100\n        self.CBox_01_Longueur.setItemText(5, \"cm\")         #cm #        = 10\n        self.CBox_01_Longueur.setItemText(6, \"mm\")         #mm #        = 1\n        self.CBox_01_Longueur.setItemText(7, \"um\")         #um #        = 0.001            micro\n        self.CBox_01_Longueur.setItemText(8, \"nm\")         #nm # *      = 0.000001         nano\n        self.CBox_01_Longueur.setItemText(9, \"pm\")         #pm #        = 0.000000001      pico\n        self.CBox_01_Longueur.setItemText(10, \"fm\")        #fm #        = 0.000000000001   femto\n        self.CBox_01_Longueur.setItemText(11, \"inch\")      #in # inch  pouce    = 25.400\n        self.CBox_01_Longueur.setItemText(12, \"link\")      #lk # link  chainon  = 201.168\n        self.CBox_01_Longueur.setItemText(13, \"foot\")      #ft # foot  pied     = 304.800\n        self.CBox_01_Longueur.setItemText(14, \"yard\")      #yd # yard  verge    = 914.400\n        self.CBox_01_Longueur.setItemText(15, \"perch\")     #rd # rod ou perch   perche   = 5029.200\n        self.CBox_01_Longueur.setItemText(16, \"chain\")     #ch # chain chaine   = 20116.800\n        self.CBox_01_Longueur.setItemText(17, \"furlong\")   #fur# furlong        = 201168\n        self.CBox_01_Longueur.setItemText(18, \"mile\")      #mi # mile           = 1609344\n        self.CBox_01_Longueur.setItemText(19, \"league\")    #lea# league lieue   = 4828032\n        self.CBox_01_Longueur.setItemText(20, \"nautique\")  #nmi# mile nautique  = 1852000\n\n        self.CBox_02_Poids.setToolTip(\"Unit on choice for Density on dm3\" + \"\\n\" + \"Unit by default = g\")\n        self.CBox_02_Poids.setCurrentIndex(5)\n        self.CBox_02_Poids.setItemText(0, \"tonne\")          #t    #   = 1000000\n        self.CBox_02_Poids.setItemText(1, \"quintal\")        #q    #   = 100000\n        self.CBox_02_Poids.setItemText(2, \"kilo gram\")      #kg   #   = 1000\n        self.CBox_02_Poids.setItemText(3, \"hecto gram\")     #hg   #   = 100\n        self.CBox_02_Poids.setItemText(4, \"decagram\")       #dag  #   = 10\n        self.CBox_02_Poids.setItemText(5, \"gram\")           #g    #   = 1\n        self.CBox_02_Poids.setItemText(6, \"decigram\")       #dg   #   = 0.1\n        self.CBox_02_Poids.setItemText(7, \"centigram\")      #cg   #   = 0.01\n        self.CBox_02_Poids.setItemText(8, \"milligram\")      #mg   #   = 0.001\n        self.CBox_02_Poids.setItemText(9, \"microgram\")      #\u00b5g   #   = 0.000001\n        self.CBox_02_Poids.setItemText(10, \"nanogram\")      #ng   #   = 0.000000001\n        self.CBox_02_Poids.setItemText(11, \"picogram\")      #pg   #   = 0.000000000001\n        self.CBox_02_Poids.setItemText(12, \"femtogram\")     #fg   #   = 0.000000000000001   femtogram\n        self.CBox_02_Poids.setItemText(13, \"grain\")         #gr   #   = 0.06479891 g\n        self.CBox_02_Poids.setItemText(14, \"drachm\")        #dr   #   = 1.7718451953125 g\n        self.CBox_02_Poids.setItemText(15, \"once\")          #oz   #   = 28.3495231250 g\n        self.CBox_02_Poids.setItemText(16, \"once troy\")     #oz t #   = 31.1034768 g  once troy\n        self.CBox_02_Poids.setItemText(17, \"livre troy\")    #lb t #   = 373.2417216 g  livre de troy\n        self.CBox_02_Poids.setItemText(18, \"livre av\")      #lb   #   = 453.59237 g  livre avoirdupois pound\n        self.CBox_02_Poids.setItemText(19, \"stone\")         #st   #   = 6350.29318 g\n        self.CBox_02_Poids.setItemText(20, \"quarter\")       #qtr  #   = 12700.58636 g\n        self.CBox_02_Poids.setItemText(21, \"hundredweight\") #cwt  #   = 50802.34544 g\n        self.CBox_02_Poids.setItemText(22, \"tonneau fr\")    #     #   = 0.00000102145045965 g\n        self.CBox_02_Poids.setItemText(23, \"carat\")         #ct   #   = 0.2 g\n\n        self.DS_01_Densite.setToolTip(\"Density of material used\" + \"\\n\" + \n                                      \"By default = 1.0 kg by dm3\")\n        self.DS_02_Round.setToolTip(\"Number of decimal value used\" + \"\\n\" + \n                                    \"By default = 3\")\n        self.ComboB_SpreadSheet.setToolTip(\"List the spreadSheet available\")\n        self.LE_SpreadSheet.setToolTip(\"SpreadSheet current (first displayed)\" + \"\\n\" + \n                                       \"If there is no spreadSheet in the document,\" + \"\\n\" + \n                                       \"one spreadSheet named FCSpreadSheet is created\" + \"\\n\" + \n                                       \"or the spreadSheet displayed is updated\" + \"\\n\" + \n                                       \"or enter your spreadSheet name\")\n        self.PB_01_SpreadSheet_Select_All.setText(\"Select\")\n        self.PB_01_SpreadSheet_Select_All.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_28.png\" + \" />\" + \"\\n\" + \n                                                     \"Select all checkBox options\")\n        self.PB_03_SpreadSheet_Save.setText(\"Save\")\n        self.PB_03_SpreadSheet_Save.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_27.png\" + \" />\" + \"\\n\" + \n                                               \"Save the data in SpreadSheet\" + \"\\n\" + \n                                               \"( actual = \" + \"<b>\" + newSpreadSheetName + \"</b>\" + \" )\")\n        self.PB_04_SpreadSheet_Quit.setText(\"Quit\")\n        self.PB_04_SpreadSheet_Quit.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_26.png\" + \" />\" + \"\\n\" + \n                                               \"Quit the SpreadSheet module\")\n        ########SpreadSheet##\n\n    def details(self,  type, name ):        #details object\n        if type == 0:\n            Fdoc = FreeCAD.ActiveDocument.getObject(name)\n        else:\n            Fdoc = FreeCAD.ActiveDocument.getObjectsByLabel(name)[0]\n        try:\n            Bx = (\"Base\\nX : \"+str(round(Fdoc.Placement.Base[0],3))+\"\\n\")\n            By = (\"Y : \"+str(round(Fdoc.Placement.Base[1],3))+\"\\n\")\n            Bz = (\"Z : \"+str(round(Fdoc.Placement.Base[2],3))+\"\\n\\n\")\n            base = Bx + By + Bz\n        except Exception:\n            base = \"\"\n        try:\n            Rx = (\"Rotation\\nX : \"+str(round(Fdoc.Placement.Rotation.toEuler()[0],3))+\"\\n\")\n            Ry = (\"Y : \"+str(round(Fdoc.Placement.Rotation.toEuler()[1],3))+\"\\n\")\n            Rz = (\"Z : \"+str(round(Fdoc.Placement.Rotation.toEuler()[2],3))+\"\\n\\n\")\n            rotation = Rx + Ry + Rz\n        except Exception:\n            rotation = \"\"\n        try:\n            Cx = (\"CenterOfMass\\nX : \"+str(round(Fdoc.Shape.CenterOfMass[0],3))+\"\\n\")\n            Cy = (\"Y : \"+str(round(Fdoc.Shape.CenterOfMass[1],3))+\"\\n\")\n            Cz = (\"Z : \"+str(round(Fdoc.Shape.CenterOfMass[2],3))+\"\\n\\n\")\n            centerOfMass = Cx + Cy + Cz\n        except Exception:\n            centerOfMass = \"\"\n        return  name[:20] + \"\\n\\n\" + base + rotation + centerOfMass\n\n    def on_treeWidget_clicked(self, item):\n        global listeObjetsOriginal\n        global titre\n        global ui\n        global doc\n        global searchString\n\n        ligne         = item.row()          # index dans la liste\n        colonne       = item.column()       # index dans la liste\n        nomObjetListe = item.data()         # donne le nom clique\n        nomParentBase = item.parent().data()# donne le nom du maitre\n        \n        try:\n            if (nomObjetListe == \"False\") or (nomObjetListe == \"True\"):\n                if nomObjetListe == \"False\":\n                    try:\n                        FreeCAD.ActiveDocument.getObject(nomParentBase).ViewObject.Visibility = True\n                    except Exception:\n                        App.ActiveDocument.getObjectsByLabel(nomParentBase)[0].ViewObject.Visibility = True\n                else:\n                    try:\n                        FreeCAD.ActiveDocument.getObject(nomParentBase).ViewObject.Visibility = False\n                    except Exception:\n                        App.ActiveDocument.getObjectsByLabel(nomParentBase)[0].ViewObject.Visibility = False\n    \n                if searchString == \" Searched\":\n                    ui.loadObjects()\n                    ui.on_lineEdit_Search_Pressed()\n                else:\n                    ui.on_PB_Reload_clicked()\n    \n            FreeCADGui.Selection.clearSelection()\n            if nomParentBase == doc:\n                try:\n                    FreeCADGui.Selection.addSelection(App.ActiveDocument.getObject(nomObjetListe))\n                    self.treeWidget.setToolTip( ui.details(0, nomObjetListe))\n                except Exception:\n                    FreeCADGui.Selection.addSelection(App.ActiveDocument.getObjectsByLabel(nomObjetListe)[0])\n                    self.treeWidget.setToolTip( ui.details(1, nomObjetListe))\n            else:\n                try:\n                    FreeCADGui.Selection.addSelection(App.ActiveDocument.getObject(nomParentBase))\n                    self.treeWidget.setToolTip( ui.details(0, nomParentBase))\n                except Exception:\n                    # ver 0.19 Gui.Selection.addSelection(App.ActiveDocument.Name,selection.Name,vertex, x, y, z)\n                    print( nomParentBase)\n                    FreeCADGui.Selection.addSelection(App.ActiveDocument.getObjectsByLabel(nomParentBase)[0])\n                    self.treeWidget.setToolTip( ui.details(1, nomParentBase))\n    \n            #zoom_selection # https://forum.freecadweb.org/viewtopic.php?f=8&t=15132\n            Gui.SendMsgToActiveView(\"ViewSelection\")\n            Gui.runCommand(\"Std_TreeSelection\")\n\n        except Exception:\n            self.treeWidget.setToolTip(\"The title display the option, number and type object(s) displayed\" + \"\\n\" + \"\\n\" + \n                                       \"O = Objects\" + \"\\n\" + \n                                       \"N = Name\" + \"\\n\" + \n                                       \"L = Label\" + \"\\n\" + \n                                       \"T = Total\" + \"\\n\" + \n                                       \"G = Group\" + \"\\n\" + \n                                       \"S = Single\" + \"\\n\" + \n                                       \"V = Visible\" + \"\\n\" + \n                                       \"H = Hidden\" + \"\\n\\n\" +\n                                       \"If one object are selected :\" + \"\\n\" + \n                                       \"the Placement Base, Rotation and Center of mass is displayed\" + \"\\n\" + \n                                       \"if available !\")\n            FreeCAD.Console.PrintError(\"Error clicked\" + \"\\n\")\n\n    def sorted_List(self, option):                # listing after sorted\n        global doc\n        global listeSorted\n        global titre\n        global derouler\n        global visibilite\n        global group\n        global SplitNameLabel\n\n        enteteTitres  = QtWidgets.QTreeWidgetItem([\" Sorted\" + option,])       # titres entete des colonnes\n        self.treeWidget.setHeaderItem(enteteTitres)                        # affichage des titres #Another alternative is setHeaderLabels([\"Tree\",\"First\",...])\n        documentActif = QtWidgets.QTreeWidgetItem(self.treeWidget, [str(doc)]) # titre du document\n        documentActif.setExpanded(True)                                    # expent tous les enfants\n\n#       #[objName, objLabel, \"False\", objGroupe, objLName, objLLabel, objLGroupe, objSignal, objTypeSolid, objTypeTypeID, objTypeShape, [objNumeric]]\n        for obj in listeSorted:\n\n            if (SplitNameLabel == 0) or (SplitNameLabel == 1):\n                A = QtWidgets.QTreeWidgetItem(documentActif, [obj[0]])             # premier objet dans l'arbre du document\n                if obj[3] == \"-\":\n                    A.setIcon(0,self.iconName)                                 # premiere rangee titre\n                else:\n                    A.setIcon(0,self.iconFolder)                               # premiere rangee titre\n    \n                if derouler == 1:\n                    A.setExpanded(True)                                        # expent tous les enfants\n    \n                etat = QtWidgets.QTreeWidgetItem(A)\n                if obj[-1] == 1:                                               # convert firt char lower original\n                    objL = obj[1][0].lower() + obj[1][1:]\n                    etat.setText(0,objL)                                       # label\n                else:\n                    etat.setText(0,obj[1])                                     # label\n                etat.setIcon(0,self.iconLabel)\n    \n                etat2 = QtWidgets.QTreeWidgetItem(A)\n                if obj[2] == \"True\":\n                    etat2.setText(0,\"True\")                                     # premiere rangee\n                    etat2.setIcon(0,self.iconTrue)                              # premiere rangee\n                    if visibilite == 1:\n                        A.setIcon(0,self.iconTrue)                              # premiere rangee titre\n                else:\n                    etat2.setText(0,\"False\")                                    # premiere rangee\n                    etat2.setIcon(0,self.iconFalse)                             # premiere rangee\n                    if visibilite == 1:\n                        A.setIcon(0,self.iconFalse)                             # premiere rangee titre\n    \n                etat3 = QtWidgets.QTreeWidgetItem(A)\n                if obj[3] == \"-\":\n                    if group == 1:\n                        A.setIcon(0,self.iconChainCut)                          # premiere rangee titre\n                    None\n                else:\n                    etat3.setText(0,obj[3])\n                    etat3.setIcon(0,self.iconChain)                             # premiere rangee\n                    if group == 1:\n                        A.setIcon(0,self.iconChain)                             # premiere rangee titre\n\n            if (SplitNameLabel == 1) or (SplitNameLabel == 2):\n                A = QtWidgets.QTreeWidgetItem(documentActif, [obj[1]])          # premier objet dans l'arbre du document\n                if obj[-1] == 1:                                            # convert firt char lower original\n                    objL = obj[1][0].lower() + obj[1][1:]\n                    A.setText(0,objL)                                       # label\n                else:\n                    A.setText(0,obj[1])                                     # label\n                A.setIcon(0,self.iconLabel)                                 # premiere rangee titre\n\n                if derouler == 1:\n                    A.setExpanded(True)                                     # expent tous les enfants\n\n                B = QtWidgets.QTreeWidgetItem(A)\n                if obj[3] == \"-\":\n                    B.setIcon(0,self.iconName)                              # premiere rangee titre\n                else:\n                    B.setIcon(0,self.iconFolder)                            # premiere rangee titre\n                B.setText(0,obj[0])                                         # name\n\n                C = QtWidgets.QTreeWidgetItem(A)\n                if obj[2] == \"True\":\n                    C.setText(0,\"True\")                                     # premiere rangee\n                    C.setIcon(0,self.iconTrue)                              # premiere rangee\n                    if visibilite == 1:\n                        A.setIcon(0,self.iconTrue)                          # premiere rangee titre\n                else:\n                    C.setText(0,\"False\")                                    # premiere rangee\n                    C.setIcon(0,self.iconFalse)                             # premiere rangee\n                    if visibilite == 1:\n                        A.setIcon(0,self.iconFalse)                         # premiere rangee titre\n    \n                D = QtWidgets.QTreeWidgetItem(A)\n                if obj[3] == \"-\":\n                    if group == 1:\n                        A.setIcon(0,self.iconChainCut)                      # premiere rangee titre\n                    None\n                else:\n                    D.setText(0,obj[3])\n                    D.setIcon(0,self.iconChain)                             # premiere rangee\n                    if group == 1:\n                        A.setIcon(0,self.iconChain)                         # premiere rangee titre\n\n    def on_PB_Sort_00_clicked(self):    # tableau 0 Nom\n        global listeSorted\n        global ui\n        global titre\n        global reverse_00\n        global reverse_01\n        global reverse_02\n        global reverse_03\n\n#       #[objName, objLabel, \"False\", objGroupe, objLName, objLLabel, objLGroupe, objSignal, objTypeSolid, objTypeTypeID, objTypeShape, [objNumeric]]\n        if self.CB_Length.isChecked():\n            listeSorted = sorted(listeSorted, key=itemgetter(4))\n            titre = \" by Length Name\"\n        else:\n            listeSorted = sorted(listeSorted, key=itemgetter(0))\n            titre = \" by Name\"\n        self.treeWidget.clear()\n        ui.sorted_List(titre + \" (O \" + str(len(listeSorted)) + \")\")\n\n        if reverse_00 == 1:\n            ui.on_PB_Reverse_clicked()\n            reverse_00 = 0\n        else:\n            reverse_00 = 1\n        reverse_01 = reverse_02 = reverse_03 = 0\n        self.treeWidget.verticalScrollBar().setStyleSheet(\"background-color: #0000ce;\")\n\n    def on_PB_Sort_01_clicked(self):    # tableau 1 Label\n        global listeSorted\n        global ui\n        global titre\n        global reverse_00\n        global reverse_01\n        global reverse_02\n        global reverse_03\n\n#       #[objName, objLabel, \"False\", objGroupe, objLName, objLLabel, objLGroupe, objSignal, objTypeSolid, objTypeTypeID, objTypeShape, [objNumeric]]\n\n        if self.CB_Length.isChecked():\n            listeSorted = sorted(listeSorted, key=itemgetter(5))\n            titre = \" by Length Label\"\n        else:\n            listeSorted = sorted(listeSorted, key=itemgetter(1))\n            titre = \" by Label\"\n        self.treeWidget.clear()\n        ui.sorted_List(titre + \" (O \" + str(len(listeSorted)) + \")\")\n\n        if reverse_01 == 1:\n            ui.on_PB_Reverse_clicked()\n            reverse_01 = 0\n        else:\n            reverse_01 = 1\n        reverse_00 = reverse_02 = reverse_03 = 0\n        self.treeWidget.verticalScrollBar().setStyleSheet(\"background-color: #0073cc;\")\n\n    def on_PB_Sort_02_clicked(self):    # tableau 2 False True\n        global listeSorted\n        global ui\n        global titre\n        global reverse_00\n        global reverse_01\n        global reverse_02\n        global reverse_03\n\n        self.treeWidget.clear()\n        listeSorted = sorted(listeSorted, key=itemgetter(2))\n        titre = \" by Visibility\"\n        ui.sorted_List(titre + \" (O \" + str(len(listeSorted)) + \")\")\n\n        if reverse_02 == 1:\n            ui.on_PB_Reverse_clicked()\n            reverse_02 = 0\n            self.treeWidget.verticalScrollBar().setStyleSheet(\"background-color: #007000;\")\n        else:\n            reverse_02 = 1\n            self.treeWidget.verticalScrollBar().setStyleSheet(\"background-color: #cc0000;\")\n        reverse_00 = reverse_01 = reverse_03 = 0\n\n    def on_PB_Sort_03_clicked(self):    # tableau 3 False Groupe premier niveau\n        global listeSorted\n        global ui\n        global titre\n        global reverse_00\n        global reverse_01\n        global reverse_02\n        global reverse_03\n\n        if self.CB_Length.isChecked():\n            listeSorted = sorted(listeSorted, key=itemgetter(6))\n            titre = \" by Length Group\"\n        else:\n            listeSorted = sorted(listeSorted, key=itemgetter(3))\n            titre = \" by Group\"\n        self.treeWidget.clear()\n        ui.sorted_List(titre + \" (O \" + str(len(listeSorted)) + \")\")\n\n        if reverse_03 == 1:\n            ui.on_PB_Reverse_clicked()\n            reverse_03 = 0\n        else:\n            reverse_03 = 1\n        reverse_00 = reverse_01 = reverse_02 = 0\n        self.treeWidget.verticalScrollBar().setStyleSheet(\"background-color: #ff5555;\")\n\n    def on_PB_Reverse_clicked(self):    # reverse tableau\n        global listeSorted\n        global ui\n        global titre\n        \n        listeSorted.reverse()\n        self.treeWidget.clear()\n        if titre[-9:] == \" reverse>\":\n            titre = titre.replace(\">\",\"<\")\n        elif titre[-9:] == \" reverse<\":\n            titre = titre.replace(\"<\",\">\")\n        else:\n            titre += \" reverse<\"\n        ui.sorted_List(titre + \" (O \" + str(len(listeSorted)) + \")\")\n\n    def on_PB_SplitName_clicked(self):  # Split Name and Label\n        global ui\n        global titre\n        global SplitNameLabel\n        global listeSorted\n\n        if SplitNameLabel == 0:\n            self.PB_SplitName.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_05.png\"))\n            self.PB_SplitName.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_05.png\" + \" />\" + \"\\n\" + \n                                         \"Display by Label\")\n            SplitNameLabel = 1\n        elif SplitNameLabel == 1:\n            self.PB_SplitName.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_17.png\"))\n            self.PB_SplitName.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_17.png\" + \" />\" + \"\\n\" + \n                                         \"Display by Name\")\n            SplitNameLabel = 2\n        else :\n            self.PB_SplitName.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_22.png\"))\n            self.PB_SplitName.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_22.png\" + \" />\" + \"\\n\" + \n                                         \"Display by Name and Label\")\n            SplitNameLabel = 0\n\n        self.treeWidget.clear()\n        ui.sorted_List(titre + \" (O \" + str(len(listeSorted)) + \")\")\n        \n    def on_PB_Expend_clicked(self):\n        global ui\n        global titre\n        global derouler\n        global listeSorted\n\n        if derouler == 1:\n            derouler = 0\n            self.PB_Expend.setText(\"Develop\")\n            self.PB_Expend.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_15.png\"))\n            self.PB_Expend.setToolTip(\"Click for Develop the listing objects <img src=\" + self.path + \"Macro_FCTreeView_15.png\" + \" />\")\n        else:\n            derouler = 1\n            self.PB_Expend.setText(\"Fold\")\n            self.PB_Expend.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_14.png\"))\n            self.PB_Expend.setToolTip(\"Click for Fold the listing objects <img src=\" + self.path + \"Macro_FCTreeView_14.png\" + \" />\")\n\n        self.treeWidget.clear()\n        ui.sorted_List(titre + \" (O \" + str(len(listeSorted)) + \")\")\n\n########SpreadSheet section debut #####################################################################################################\n    def On_CBox_01_Longueur_SpreadSheet(self,text):\n        global uniteM\n        global uniteMs\n        global uniteS\n        global uniteSs\n        global uniteV\n        global uniteVs\n\n#        text = text.encode('utf-8')                         # PySide\n        if text == \"km\":        #        = 1000000\n            uniteM = 0.000001\n            uniteMs= \"km\"\n            uniteS = 0.000000000001\n            uniteSs= \"km2\"\n            uniteV = 0.000000000000000001\n            uniteVs= \"km3\"\n        elif text == \"hm\":      #        = 100000\n            uniteM = 0.00001\n            uniteMs= \"hm\"\n            uniteS = 0.0000000001\n            uniteSs= \"hm2\"\n            uniteV = 0.000000000000001\n            uniteVs= \"hm3\"\n        elif text == \"dam\":     #        = 10000\n            uniteM = 0.0001\n            uniteMs= \"dam\"\n            uniteS = 0.00000001\n            uniteSs= \"dam2\"\n            uniteV = 0.000000000001\n            uniteVs= \"dam3\"\n        elif text == \"m\":       #        = 1000\n            uniteM = 0.001\n            uniteMs= \"m\"\n            uniteS = 0.000001\n            uniteSs= \"m2\"\n            uniteV = 0.000000001\n            uniteVs= \"m3\"\n        elif text == \"dm\":      #        = 100\n            uniteM = 0.01\n            uniteMs= \"dm\"\n            uniteS = 0.0001\n            uniteSs= \"dm2\"\n            uniteV = 0.000001\n            uniteVs= \"dm3\"\n        elif text == \"cm\":      #        = 10\n            uniteM = 0.1\n            uniteMs= \"cm\"\n            uniteS = 0.01\n            uniteSs= \"cm2\"\n            uniteV = 0.001\n            uniteVs= \"cm3\"\n        elif text == \"mm\":      #        = 1 ###############################\n            uniteM = 1.0\n            uniteMs= \"mm\"\n            uniteS = 1.0\n            uniteSs= \"mm2\"\n            uniteV = 1.0\n            uniteVs= \"mm3\"\n        elif text == \"um\":      #        = 1000 #http://fr.wiktionary.org/wiki/%CE%BCm#conv\n            uniteM = 1000.0\n            uniteMs= \"um\"\n            uniteS = 1000.0**2\n            uniteSs= \"um2\"\n            uniteV = 1000.0**3\n            uniteVs= \"um3\"\n        elif text == \"nm\":      #        = 1000000\n            uniteM = 1000000.0\n            uniteMs= \"nm\"\n            uniteS = 1000000.0**2\n            uniteSs= \"nm2\"\n            uniteV = 1000000.0**3\n            uniteVs= \"nm3\"\n        elif text == \"pm\":      #        = 1000000000\n            uniteM = 1000000000.0\n            uniteMs= \"pm\"\n            uniteS = 1000000000.0**2\n            uniteSs= \"pm2\"\n            uniteV = 1000000000.0**3\n            uniteVs= \"pm3\"\n        elif text == \"fm\":      #        = 1000000000000\n            uniteM = 1000000000000.0\n            uniteMs= \"fm\"\n            uniteS = 1000000000000.0**2\n            uniteSs= \"fm2\"\n            uniteV = 1000000000000.0**3\n            uniteVs= \"fm3\"\n        elif text == \"inch\":    # inch   = 25.400\n            uniteM = 1.0/25.400\n            uniteMs= \"in\"\n            uniteS = uniteM**2\n            uniteSs= \"sq in\"\n            uniteV = uniteM**3\n            uniteVs= \"in3\"\n        elif text == \"link\":    # link   = 201.168\n            uniteM = 1.0/201.168\n            uniteMs= \"lk\"\n            uniteS = uniteM**2\n            uniteSs= \"sq lk\"\n            uniteV = uniteM**3\n            uniteVs= \"lk3\"\n        elif text == \"foot\":    # foot   = 304.800\n            uniteM = 1.0/304.800\n            uniteMs= \"ft\"\n            uniteS = uniteM**2\n            uniteSs= \"sq ft\"\n            uniteV = uniteM**3\n            uniteVs= \"ft3\"\n        elif text == \"yard\":    # yard   = 914.400\n            uniteM = 1.0/914.400\n            uniteMs= \"yd\"\n            uniteS = uniteM**2\n            uniteSs= \"sq yd\"\n            uniteV = uniteM**3\n            uniteVs= \"yd3\"\n        elif text == \"perch\":   #rd # rod   perche    = 5029.200\n            uniteM = 1.0/5029.200\n            uniteMs= \"rd\"\n            uniteS = uniteM**2\n            uniteSs= \"sq rd\"\n            uniteV = uniteM**3\n            uniteVs= \"rd3\"\n        elif text == \"chain\":   # chain  = 20116.800\n            uniteM = 1.0/20116.800\n            uniteMs= \"ch\"\n            uniteS = uniteM**2\n            uniteSs= \"sq ch\"\n            uniteV = uniteM**3\n            uniteVs= \"ch3\"\n        elif text == \"furlong\": # furlong= 201168\n            uniteM = 1.0/201168\n            uniteMs= \"fur\"\n            uniteS = uniteM**2\n            uniteSs= \"sq fur\"\n            uniteV = uniteM**3\n            uniteVs= \"fur3\"\n        elif text == \"mile\":     # mile   = 1609344\n            uniteM = 1.0/1609344\n            uniteMs= \"mi\"\n            uniteS = uniteM**2\n            uniteSs= \"sq mi\"\n            uniteV = uniteM**3\n            uniteVs= \"mi3\"\n        elif text == \"league\":   # league = 4828032\n            uniteM = 1.0/4828032\n            uniteMs= \"lea\"\n            uniteS = uniteM**2\n            uniteSs= \"sq lea\"\n            uniteV = uniteM**3\n            uniteVs= \"lea3\"\n        elif text == \"nautique\": # nautique = 1852000\n            uniteM = 1.0/1852000\n            uniteMs= \"nmi\"\n            uniteS = uniteM**2\n            uniteSs= \"sq nmi\"\n            uniteV = uniteM**3\n            uniteVs= \"nmi3\"\n\n    def On_CBox_02_Poids_SpreadSheet(self,text):\n        global uniteP\n        global unitePs\n\n        #poids = ((volume_ * densite) * uniteP) / 1000)\n#        text = text.encode('utf-8')  # PySide\n        if text == \"tonne\":          #t  #0.000001  = 1000000\n            uniteP = 0.000001\n            unitePs= \"t\"\n        elif text == \"quintal\":      #q  #0.00001   = 100000\n            uniteP = 0.00001\n            unitePs= \"q\"\n        elif text == \"kilo gram\":    #kg # 0.001    = 1000\n            uniteP = 0.001\n            unitePs= \"kg\"\n        elif text == \"hecto gram\":   #hg #  0.01    = 100\n            uniteP = 0.01\n            unitePs= \"hg\"\n        elif text == \"decagram\":     #dag#   0.1    = 10\n            uniteP = 0.1\n            unitePs= \"dag\"\n        elif text == \"gram\":         #g  #  1       = 1\n            uniteP = 1.00\n            unitePs= \"g\"\n        elif text == \"decigram\":     #dg   # = 0.1\n            uniteP = 10\n            unitePs= \"dg\"\n        elif text == \"centigram\":    #cg   # = 0.01\n            uniteP = 100\n            unitePs= \"cg\"\n        elif text == \"milligram\":    #mg   # = 0.001\n            uniteP = 1000\n            unitePs= \"mg\"\n        elif text == \"microgram\":    #\u00b5g   # = 0.000001\n            uniteP = 1000000\n            unitePs= \"ug\"\n        elif text == \"nanogram\":     #ng   # = 0.000000001\n            uniteP = 1000000000\n            unitePs= \"ng\"\n        elif text == \"picogram\":     #pg   # = 0.000000000001\n            uniteP = 1000000000000\n            unitePs= \"pg\"\n        elif text == \"femtogram\":    #fg   # = 0.000000000000001\n            uniteP = 1000000000000000\n            unitePs= \"fg\"\n        elif text == \"grain\":        #gr   # = 0.06479891\n            uniteP = 0.06479891\n            unitePs= \"gr\"\n        elif text == \"drachm\":       #dr   # = 1.7718451953125\n            uniteP = 0.56438339189006794681850148894339\n            unitePs= \"dr\"\n        elif text == \"once\":         #oz   # = 28.3495231250\n            uniteP = 0.035273961949580412915675808215204\n            unitePs= \"oz\"\n        elif text == \"once troy\":    #oz t # = once troy   = 31.1034768\n            uniteP = 0.032150746568627980522100346029483\n            unitePs= \"oz t\"\n        elif text == \"livre troy\":   #lb t # = 373.2417216 livre de troy (pound)\n            uniteP = 0.0026792288807189983768416955024569\n            unitePs= \"lb t\"\n        elif text == \"livre av\":     #lb   # = 453.59237   livre avoirdupois (pound)\n            uniteP = 0.0022046226218487758072297380134503\n            unitePs= \"lb\"\n        elif text == \"stone\":        #st   # = 6350.29318  1 stone     = 14 livres\n            uniteP = 0.00015747304441776970051640985810359\n            unitePs= \"st\"\n        elif text == \"quarter\":      #qtr  # = 12700.58636\n            uniteP = 0.000078736522208884850258204929051795\n            unitePs= \"qtr\"\n        elif text == \"hundredweight\":#cwt  # = 50802.34544\n            uniteP = 0.000019684130552221212564551232262949\n            unitePs= \"cwt\"\n        elif text == \"tonneau fr\":   #     # tonneau fr = 0.00000102145045965\n            uniteP = 0.00000102145045965\n            unitePs= \"tonneau fr\"\n        elif text == \"carat\":        #ct   # = 0.2\n            uniteP = 5\n            unitePs= \"ct\"\n\n    def on_DS_01_Densite_valueChanged(self, value):\n        global densite\n\n        densite = value\n\n    def on_DS_02_Round_valueChanged(self, value):\n        global arrondi\n\n        arrondi = value\n        \n    def on_CB_01_Title_clicked(self):\n        if self.CB_01_Title.isChecked():\n            self.CB_02_Color.setEnabled(True)\n        else:\n            self.CB_02_Color.setEnabled(False)\n            self.CB_03_Colonne.setEnabled(False)\n        self.CB_02_Color.setChecked(False)\n        self.CB_03_Colonne.setChecked(False)\n\n    def on_CB_02_Color_clicked(self):\n        if self.CB_02_Color.isChecked():\n            self.CB_03_Colonne.setEnabled(True)\n        else:\n            self.CB_03_Colonne.setEnabled(False)\n            self.CB_03_Colonne.setChecked(False)\n\n    def on_CB_06_Nomenclature_clicked(self):\n        if self.CB_06_Nomenclature.isChecked():\n            self.CB_06_Nomenclature.setStyleSheet(\"background-color: white;\\n\"\n                                                  \"border:2px solid rgb(115, 210, 22);\")  # bord white and green\n            self.CB_10_Weight_Total.setStyleSheet(\"background-color: white;\\n\"\n                                                  \"border:2px solid rgb(115, 210, 22);\")  # bord white and green\n            self.CB_10_Weight_Total.setEnabled(True)\n        else:\n            self.CB_06_Nomenclature.setStyleSheet(\"Base\")\n            self.CB_10_Weight_Total.setStyleSheet(\"Base\")\n            self.CB_10_Weight_Total.setEnabled(False)\n            self.CB_10_Weight_Total.setChecked(False)\n\n    def on_LE_SpreadSheet_Pressed(self, text):\n        global newSpreadSheetName\n\n        newSpreadSheetName = text\n        self.PB_03_SpreadSheet_Save.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_27.png\" + \" />\" + \"\\n\" + \n                                 \"Save the data in SpreadSheet\" + \"\\n\" +\n                                 \"( actual = \" + \"<b>\" + newSpreadSheetName + \"</b>\" + \" )\")\n\n    def On_ComboB_SpreadSheet(self, text):\n        global newSpreadSheetName\n\n        newSpreadSheetName = text\n        self.LE_SpreadSheet.setText(newSpreadSheetName)\n\n    def on_PB_04_SpreadSheet_Quit_clicked(self):\n        global ui\n\n        self.Frame_Contener_SpreadSheet.setVisible(False)\n        self.groupBox_Sort.setVisible(True)\n        self.groupBox_Search.setVisible(True)\n        self.groupBox_Global.setVisible(True)\n        #ui.on_PB_Reload_clicked()    # reload the total objects after spreadSheet but lose the sort\n\n    def on_PB_03_SpreadSheet_Save_clicked(self):\n        global ui\n\n        ui.tableauSpreadsheet()\n        ui.on_PB_SpreadSheet_clicked()\n\n    def on_PB_01_SpreadSheet_Select_All_clicked(self):\n        global selectAllCB\n\n        if selectAllCB == 1:\n            self.CB_01_Title.setChecked(False)\n            self.CB_02_Color.setChecked(False)\n            self.CB_02_Color.setEnabled(False)\n            self.CB_03_Colonne.setChecked(False)\n            self.CB_03_Colonne.setEnabled(False)\n            self.CB_04_Name.setChecked(False)\n            self.CB_05_Label.setChecked(False)\n            self.CB_06_Nomenclature.setChecked(False)\n            self.CB_06_Nomenclature.setStyleSheet(\"Base\")\n            self.CB_07_Solid.setChecked(False)\n            self.CB_08_Volume.setChecked(False)\n            self.CB_09_Weight.setChecked(False)\n            self.CB_10_Weight_Total.setChecked(False)\n            self.CB_10_Weight_Total.setEnabled(False)\n            self.CB_10_Weight_Total.setStyleSheet(\"Base\")\n            self.CB_11_Surface.setChecked(False)\n            self.CB_12_BBox.setChecked(False)\n            self.CB_13_Translate.setChecked(False)\n            self.CB_14_Rotation.setChecked(False)\n            self.CB_15_Dimension.setChecked(False)\n            selectAllCB = 0\n            self.PB_01_SpreadSheet_Select_All.setText(\"Select\")\n            self.PB_01_SpreadSheet_Select_All.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_28.png\"))\n            self.PB_01_SpreadSheet_Select_All.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_28.png\" + \" />\" + \"\\n\" + \n                                     \"Select all checkBox options\")\n        else:\n            self.CB_01_Title.setChecked(True)\n            self.CB_02_Color.setChecked(True)\n            self.CB_02_Color.setEnabled(True)\n            self.CB_03_Colonne.setChecked(True)\n            self.CB_03_Colonne.setEnabled(True)\n            self.CB_04_Name.setChecked(True)\n            self.CB_05_Label.setChecked(True)\n            self.CB_06_Nomenclature.setChecked(True)\n            self.CB_06_Nomenclature.setStyleSheet(\"background-color: white;\\n\"\n                                                  \"border:2px solid rgb(115, 210, 22);\")  # bord white and green\n            self.CB_07_Solid.setChecked(True)\n            self.CB_08_Volume.setChecked(True)\n            self.CB_09_Weight.setChecked(True)\n            self.CB_10_Weight_Total.setChecked(True)\n            self.CB_10_Weight_Total.setEnabled(True)\n            self.CB_10_Weight_Total.setStyleSheet(\"background-color: white;\\n\"\n                                                  \"border:2px solid rgb(115, 210, 22);\")  # bord white and green\n            self.CB_11_Surface.setChecked(True)\n            self.CB_12_BBox.setChecked(True)\n            self.CB_13_Translate.setChecked(True)\n            self.CB_14_Rotation.setChecked(True)\n            self.CB_15_Dimension.setChecked(True)\n            selectAllCB = 1\n            self.PB_01_SpreadSheet_Select_All.setText(\"Unselect\")\n            self.PB_01_SpreadSheet_Select_All.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_29.png\"))\n            self.PB_01_SpreadSheet_Select_All.setToolTip(\"<img src=\" + self.path + \"Macro_FCTreeView_29.png\" + \" />\" + \"\\n\" + \n                                     \"UnSelect all checkBox options\")\n\n    def on_PB_SpreadSheet_clicked(self):\n        global listeSorted\n\n        if len(listeSorted) != 0:\n            self.groupBox_Sort.setVisible(False)\n            self.groupBox_Search.setVisible(False)\n            self.groupBox_Global.setVisible(False)\n            self.Frame_Contener_SpreadSheet.setVisible(True)\n    \n            self.ComboB_SpreadSheet.clear()\n            for i in FreeCAD.ActiveDocument.Objects:    # reload for search all SpreadSheet\n                obj = FreeCAD.ActiveDocument.getObject(i.Name).TypeId.split(\"::\")[0]\n                if obj == \"Spreadsheet\":\n                    self.ComboB_SpreadSheet.addItem(_fromUtf8(str(i.Name)))\n        else:\n            self.PB_SpreadSheet.setStyleSheet(\"background-color: #ef2929; color: rgb(255, 255, 255)\")\n            \n    def tableauSpreadsheet(self):                # create the SpreadSheet\n        global listeSorted\n        global ui\n        global newSpreadSheetName\n        global densite\n        global uniteP\n        global unitePs\n        global uniteM\n        global uniteMs\n        global uniteS\n        global uniteSs\n        global uniteV\n        global uniteVs\n        global grandeur\n        global TextColorText_R\n        global TextColorText_G\n        global TextColorText_B\n        global TextColorText_L\n\n        #### section nomenclature avec test sur volume ####\n        self.progressBar_01.setMinimum(0)\n        self.progressBar_01.setMaximum(len(listeSorted))\n        self.progressBar_01.setStyleSheet(\"QProgressBar {color:black; }\"\n                                          \"QProgressBar:chunk {background-color: #FFA500;}\") # modify the progressBar color \n        #self.LA_Wait.setText(\"Wait sort in progress\")\n\n        listeSortedBis = []\n        listeSortedBis = copy.deepcopy(listeSorted)\n        listeSortedBis = sorted(listeSortedBis, key=itemgetter(1))                           # sorted by Label\n\n        if self.CB_06_Nomenclature.isChecked():\n\n            compteurPB = 0\n            for doublon in range( len(listeSorted) ):\n                try:\n                    volumeShape1 = str(FreeCAD.ActiveDocument.getObject(listeSortedBis[doublon  ][0]).Shape.Volume) #Volume Shape\n                except Exception:\n                    volumeShape1 = \"0.0\"\n                listeSortedBis[doublon][2] = \"1\"\n                listeSortedBis[doublon][3] = volumeShape1\n                compteurPB += 1\n                self.progressBar_01.setValue(compteurPB)\n            listeSortedBis = sorted(listeSortedBis, key=itemgetter(1, 3))                    # sorted by Label and Volume\n\n            try:\n                compteurPB = 0\n                doublon = 1\n                while doublon < len(listeSorted):\n                    #if (listeSortedBis[doublon][1] == listeSortedBis[doublon-1][1]): # same Name\n                    if (listeSortedBis[doublon][1] == listeSortedBis[doublon-1][1]) and (listeSortedBis[doublon][3] == listeSortedBis[doublon-1][3]): # same Name and Volume\n                        listeSortedBis[doublon-1][2] = str(int(listeSortedBis[doublon-1][2]) + 1)\n                        del listeSortedBis[doublon]\n                        doublon -= 1\n                    doublon += 1\n                    compteurPB += 1\n                    self.progressBar_01.setValue(compteurPB)\n            except Exception:\n                None\n\n            doublon = 0\n        #self.LA_Wait.setText(\"\")\n        self.progressBar_01.reset()\n        self.progressBar_01.setStyleSheet(\"background-color: QPalette.Base\")\n        #### section nomenclature avec test sur volume ####\n\n        ####title creation begin ###################################\n\n        newSpreadSheetName = newSpreadSheetName\n        ligne      = 1\n        colonne    = 1\n\n        try:\n            tableau = FreeCAD.ActiveDocument.getObjectsByLabel(newSpreadSheetName)[0]        # for append in existant SpreadSheet\n            ligne  = decodeOccupation(tableau)[0] + 1\n        except Exception:\n            tableau = App.activeDocument().addObject('Spreadsheet::Sheet',newSpreadSheetName)# for create SpreadSheet\n\n        self.LE_SpreadSheet.setText(newSpreadSheetName)\n#       #[objName, objLabel, \"False\", objGroupe, objLName, objLLabel, objLGroupe, objSignal, objTypeSolid, objTypeTypeID, objTypeShape, [objNumeric]]\n\n        objetdetail = \"\"                                         #variable for title\n\n        if self.CB_01_Title.isChecked():                         #Create title\n            if self.CB_04_Name.isChecked():\n                objetdetail = objetdetail + \"Name object,\"       #objName title\n\n            if self.CB_05_Label.isChecked():\n                objetdetail = objetdetail + \"Label object,\"      #objLabel title\n\n            if self.CB_06_Nomenclature.isChecked():\n                objetdetail = objetdetail + \"Number,\"            #Number title\n\n            if self.CB_07_Solid.isChecked():\n                objetdetail = objetdetail + \"Type Solid,\"        #objTypeSolid title\n\n            if self.CB_08_Volume.isChecked():\n                if self.CB_08_Split.isChecked():                 #Volume title\n                    if self.RB_01_Value.isChecked():\n                        objetdetail = objetdetail + \"Volume,\"\n                    if self.RB_02_Val_Gr.isChecked():\n                        objetdetail = objetdetail + \"Volume,v,\"\n                    if self.RB_03_Val_Gr_Ph.isChecked():\n                        objetdetail = objetdetail + \"Volume,v,v,\"\n                else:\n                    objetdetail = objetdetail + \"Volume,\"\n\n            if self.CB_09_Weight.isChecked():\n                if self.CB_08_Split.isChecked():                 #Weight title\n                    if self.RB_01_Value.isChecked():\n                        objetdetail = objetdetail + \"Weight,\"\n                    if self.RB_02_Val_Gr.isChecked():\n                        objetdetail = objetdetail + \"Weight,w,\"\n                    if self.RB_03_Val_Gr_Ph.isChecked():\n                        objetdetail = objetdetail + \"Weight,w,w,\"\n                else:\n                    objetdetail = objetdetail + \"Weight,\"\n\n            if self.CB_10_Weight_Total.isChecked():\n                if self.CB_08_Split.isChecked():                 #Weight Total title\n                    if self.RB_01_Value.isChecked():\n                        objetdetail = objetdetail + \"W_Total,\"\n                    if self.RB_02_Val_Gr.isChecked():\n                        objetdetail = objetdetail + \"W_Totalt,wt,\"\n                    if self.RB_03_Val_Gr_Ph.isChecked():\n                        objetdetail = objetdetail + \"W_Total,wt,wt,\"\n                else:\n                    objetdetail = objetdetail + \"W_Total,\"\n\n            if self.CB_11_Surface.isChecked():\n                if self.CB_08_Split.isChecked():                 #Surface title\n                    if self.RB_01_Value.isChecked():\n                        objetdetail = objetdetail + \"Surface,\"\n                    if self.RB_02_Val_Gr.isChecked():\n                        objetdetail = objetdetail + \"Surface,s,\"\n                    if self.RB_03_Val_Gr_Ph.isChecked():\n                        objetdetail = objetdetail + \"Surface,s,s,\"\n                else:\n                    objetdetail = objetdetail + \"Surface,\"\n\n            if self.CB_12_BBox.isChecked():\n                if self.CB_08_Split.isChecked():                 #BBox title\n                    if self.RB_01_Value.isChecked():\n                        objetdetail = objetdetail + \"BBox XL,BBox YL,BBox ZL,BBox Diag,\"\n                    if self.RB_02_Val_Gr.isChecked():\n                        objetdetail = objetdetail + \"BBox XL,b,BBox YL,b,BBox ZL,b,BBox Diag,b,\"\n                    if self.RB_03_Val_Gr_Ph.isChecked():\n                        objetdetail = objetdetail + \"BBox XL,b,b,BBox YL,b,b,BBox ZL,b,b,BBox Diag,b,b,\"\n                else:\n                    objetdetail = objetdetail + \"BBox XL,BBox YL,BBox ZL,BBox Diag,\"\n\n            if self.CB_13_Translate.isChecked():                 #Translate title\n                if self.CB_08_Split.isChecked():\n                    if self.RB_01_Value.isChecked():\n                        objetdetail = objetdetail  + \"Translate X,Translate Y,Translate Z,\"\n                    if self.RB_02_Val_Gr.isChecked():\n                        objetdetail = objetdetail  + \"Translate X,t,Translate Y,t,Translate Z,t,\"\n                    if self.RB_03_Val_Gr_Ph.isChecked():\n                        objetdetail = objetdetail + \"Translate X,t,t,Translate Y,t,t,Translate Z,t,t,\"\n                else:\n                    objetdetail = objetdetail + \"Translate X,Translate Y,Translate Z,\"\n\n            if self.CB_14_Rotation.isChecked():                  #Rotation  Yaw (Z) # Pitch (Y) # Roll (X) title\n                if self.CB_08_Split.isChecked():\n                    if self.RB_01_Value.isChecked():\n                        objetdetail = objetdetail  + \"Rotation X,Rotation Y,Rotation Z,\"\n                    if self.RB_02_Val_Gr.isChecked():\n                        objetdetail = objetdetail  + \"Rotation X,r,Rotation Y,r,Rotation Z,r,\"\n                    if self.RB_03_Val_Gr_Ph.isChecked():\n                        objetdetail = objetdetail + \"Rotation X,r,r,Rotation Y,r,r,Rotation Z,r,r,\"\n                else:\n                    objetdetail = objetdetail + \"Rotation X,Rotation Y,Rotation Z,\"\n\n            if self.CB_15_Dimension.isChecked():\n                objetdetail = objetdetail + \"Dimension ...,\"     #Dimension title\n\n            # options title color\n            objetdetail = objetdetail[:len(objetdetail)-1]\n            objetdetail = objetdetail.split(\",\")\n\n            if self.CB_01_Title.isChecked():                                             #Title\n                for titleWrite in objetdetail:\n                    titleWrite = titleWrite\n                    tableau.setAlignment( caseTableau(ligne,colonne), str(\"center\"))\n                    tableau.setStyle(     caseTableau(ligne,colonne), str(\"bold\"))\n                    if self.CB_02_Color.isChecked():                                     #Title color\n                        tableau.setBackground(caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                    tableau.set(caseTableau(ligne,colonne), str(titleWrite))\n                    colonne += 1\n        else: \n            ligne -= 1\n\n        ####title creation end ##################################\n\n        objetdetail = unitSymbol = \"\"\n\n        self.progressBar_01.setMaximum(len(listeSortedBis))\n        compteurPB = 0\n\n        ligne += 1\n        for objListe in listeSortedBis:\n            colonne = 1\n\n            if self.CB_04_Name.isChecked():\n                objetdetail = objListe[ 0]        #objName\n                tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n                tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                colonne += 1\n\n            if self.CB_05_Label.isChecked():\n                objetdetail = objListe[ 1]        #objLabel\n                tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n                tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                colonne += 1\n\n            if self.CB_06_Nomenclature.isChecked():\n                objetdetail = objListe[ 2]        #nomenclature\n                tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n                tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                colonne += 1\n\n            if self.CB_07_Solid.isChecked():\n                objetdetail = objListe[ 8]        #Solid\n                tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n                tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                colonne += 1\n\n            if self.CB_08_Volume.isChecked():\n                try:\n                    volumeShape = FreeCAD.ActiveDocument.getObject(objListe[ 0]).Shape.Volume #Volume\n                    objetdetail = str(arround(volumeShape * uniteV))\n\n                    if self.RB_01_Value.isChecked():\n                        None                                                        # 10.0\n                    if self.RB_02_Val_Gr.isChecked():\n                        objetdetail = objetdetail + \" \" + uniteVs                   # 10 mm^3\n                    if self.RB_03_Val_Gr_Ph.isChecked():\n                        objetdetail = objetdetail + \" \" + uniteVs + \" \" + \"Volume\"  # 10 mm^3 Volume\n\n                    tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                    tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n\n                    if self.CB_08_Split.isChecked():\n                        if self.CB_03_Colonne.isChecked():                          #Title colonne color\n                            tableau.setBackground(caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                        objectNumeric = objetdetail.split(\" \")\n                        for spl in objectNumeric:\n                            objetdetail = spl\n                            tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                            tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n                            tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                            colonne += 1\n                        colonne -= 1\n                    else:\n                        try:\n                            if self.RB_01_Value.isChecked():\n                                None\n                            else:\n                                tableau.setDisplayUnit(caseTableau(ligne,colonne), uniteVs)\n                        except Exception:\n                            None\n                        tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                except Exception:\n                    None #objetdetail = \".\"\n                colonne += 1\n\n            if self.CB_09_Weight.isChecked():    # poids\n                try:\n                    volumeShape = FreeCAD.ActiveDocument.getObject(objListe[ 0]).Shape.Volume #Volume\n                    objetdetail = str(arround(((volumeShape * densite) * uniteP) / 1000.0))\n\n                    if self.RB_01_Value.isChecked():\n                        None                                                        # 10.0\n                    if self.RB_02_Val_Gr.isChecked():\n                        objetdetail = objetdetail + \" \" + unitePs                   # 10 kg\n                    if self.RB_03_Val_Gr_Ph.isChecked():\n                        objetdetail = objetdetail + \" \" + unitePs + \" \" + \"Weight\"  # 10 kg Weight\n\n                    tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                    tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n\n                    if self.CB_08_Split.isChecked():\n                        objectNumeric = objetdetail.split(\" \")\n                        if self.CB_03_Colonne.isChecked():                          #Title colonne color\n                            tableau.setBackground(caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                        for spl in objectNumeric:\n                            objetdetail = spl\n                            tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                            tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n                            tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                            colonne += 1\n                        colonne -= 1\n                    else:\n                        try:\n                            if self.RB_01_Value.isChecked():\n                                None\n                            else:\n                                tableau.setDisplayUnit(caseTableau(ligne,colonne), unitePs)\n                        except Exception:\n                            None\n                        tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n\n                except Exception:\n                    None #objetdetail = \".\"\n                colonne += 1\n\n            if self.CB_10_Weight_Total.isChecked():    # poids total\n                try:\n                    volumeShape = FreeCAD.ActiveDocument.getObject(objListe[ 0]).Shape.Volume #Volume\n                    objetdetail = str(arround(((volumeShape * densite) * uniteP) / 1000.0) * (float(objListe[ 2])))\n\n                    if self.RB_01_Value.isChecked():\n                        None                                                        # 10.0\n                    if self.RB_02_Val_Gr.isChecked():\n                        objetdetail = objetdetail + \" \" + unitePs                   # 10 kg\n                    if self.RB_03_Val_Gr_Ph.isChecked():\n                        objetdetail = objetdetail + \" \" + unitePs + \" \" + \"W_Total\" # 10 kg W. Total\n\n                    tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                    tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n\n                    if self.CB_08_Split.isChecked():\n                        objectNumeric = objetdetail.split(\" \")\n                        if self.CB_03_Colonne.isChecked():                          #Title colonne color\n                            tableau.setBackground(caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                        for spl in objectNumeric:\n                            objetdetail = spl\n                            tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                            tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n                            tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                            colonne += 1\n                        colonne -= 1\n                    else:\n                        try:\n                            if self.RB_01_Value.isChecked():\n                                None\n                            else:\n                                tableau.setDisplayUnit(caseTableau(ligne,colonne), unitePs)\n                        except Exception:\n                            None\n                        tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n\n                except Exception:\n                    None #objetdetail = \".\"\n                colonne += 1\n\n            if self.CB_11_Surface.isChecked():    # Surface\n                try:\n                    surfaceShape = FreeCAD.ActiveDocument.getObject(objListe[ 0]).Shape.Area     #Surface\n                    objetdetail  = str(arround(float(surfaceShape) * float(uniteS)))\n                    if self.RB_01_Value.isChecked():\n                        None                                                        # 10.0\n                    if self.RB_02_Val_Gr.isChecked():\n                        objetdetail = objetdetail + \" \" + uniteSs                   # 10 m2\n                    if self.RB_03_Val_Gr_Ph.isChecked():\n                        objetdetail = objetdetail + \" \" + uniteSs + \" \" + \"Surface\" # 10 m2 Surface\n\n                    tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                    tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n\n                    if self.CB_08_Split.isChecked():\n                        objectNumeric = objetdetail.split(\" \")\n                        if self.CB_03_Colonne.isChecked():                                     #Title colonne color\n                            tableau.setBackground(caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                        for spl in objectNumeric:\n                            objetdetail = spl\n                            tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                            tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n                            tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                            colonne += 1\n                        colonne -= 1\n                    else:\n                        try:\n                            if self.RB_01_Value.isChecked():\n                                None\n                            else:\n                                tableau.setDisplayUnit(caseTableau(ligne,colonne), uniteSs)\n                        except Exception:\n                            None\n                        tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n\n                except Exception:\n                    None #objetdetail = \".\"\n                colonne += 1\n\n            if self.CB_12_BBox.isChecked():                                         # BoundBox\n                try:\n                    boundBoxShape = FreeCAD.ActiveDocument.getObject(objListe[ 0]).Shape.BoundBox\n                    for i in range(4):\n                        objetdetail = typeCoor = \"\"\n                        if   i == 0:\n                            BoundBox = boundBoxShape.XLength                        # Length x bBox\n                            typeCoor = \"X\"\n                        elif i == 1:\n                            BoundBox = boundBoxShape.YLength                        # Length y bBox\n                            typeCoor = \"Y\"\n                        elif i == 2:\n                            BoundBox = boundBoxShape.ZLength                        # Length z bBox\n                            typeCoor = \"Z\"\n                        elif i == 3:\n                            BoundBox = boundBoxShape.DiagonalLength                 # Diagonal bBox\n                            typeCoor = \"Diag\"\n\n                        objetdetail = str(arround(float(BoundBox) * uniteM))\n\n                        if self.RB_01_Value.isChecked():\n                            None                                                                 # 10.0\n                        if self.RB_02_Val_Gr.isChecked():\n                            objetdetail = objetdetail + \" \" + uniteMs                            # 10 mm\n                        if self.RB_03_Val_Gr_Ph.isChecked():\n                            objetdetail = str(objetdetail) + \" \" + uniteMs + \" BBox\" + typeCoor  # 10 mm BoundBox\n\n                        tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                        tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n\n                        if self.CB_08_Split.isChecked():\n                            objectNumeric = objetdetail.split(\" \")\n                            if self.CB_03_Colonne.isChecked():                      #Title color\n                                tableau.setBackground(caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                            for spl in objectNumeric:\n                                objetdetail = spl\n                                tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                                tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n                                tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                                colonne += 1\n                        else:\n                            try:\n                                if self.RB_01_Value.isChecked():\n                                    None\n                                else:\n                                    tableau.setDisplayUnit(caseTableau(ligne,colonne), uniteMs)\n                            except Exception:\n                                None\n                            tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                            colonne += 1\n                except Exception:\n                    None\n\n            if self.CB_13_Translate.isChecked():                                    # Placement_Translate\n                try:\n                    for i in range(3):\n                        objetdetail = \"\"\n                        basePlacement = FreeCAD.ActiveDocument.getObject(objListe[ 0]).Placement.Base[i]\n                        objetdetail = str(arround(float(basePlacement) * uniteM))\n                        \n                        if self.RB_01_Value.isChecked():\n                            None                                                                 # 10.0\n                        if self.RB_02_Val_Gr.isChecked():\n                            objetdetail = objetdetail + \" \" + uniteMs                            # 10 mm\n                        if self.RB_03_Val_Gr_Ph.isChecked():\n                            objetdetail = str(objetdetail) + \" \" + uniteMs + \" T\" + (chr(88 + i))# 10 mm T\n\n                        tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                        tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n\n                        if self.CB_08_Split.isChecked():\n                            objectNumeric = objetdetail.split(\" \")\n                            if self.CB_03_Colonne.isChecked():                      #Title color\n                                tableau.setBackground(caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                            for spl in objectNumeric:\n                                objetdetail = spl\n                                tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                                tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n                                tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                                colonne += 1\n                        else:\n                            try:\n                                if self.RB_01_Value.isChecked():\n                                    None\n                                else:\n                                    tableau.setDisplayUnit(caseTableau(ligne,colonne), uniteMs)\n                            except Exception:\n                                None\n                            tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                            colonne += 1\n                except Exception:\n                    None\n\n            if self.CB_14_Rotation.isChecked():                                     # Placement_Rotation Yaw (Z) # Pitch (Y) # Roll (X)\n                try:\n                    for i in range(3):\n                        objetdetail = \"\"\n                        rotationPlacement = FreeCAD.ActiveDocument.getObject(objListe[ 0]).Placement.Rotation.toEuler()[i]\n                        objetdetail = str(arround(float(rotationPlacement)))\n\n                        try:\n                            tableau.setDisplayUnit(caseTableau(ligne,colonne), \"\")\n                        except Exception:\n                            None\n                        if self.RB_01_Value.isChecked():\n                            None                                                                 # 10.0\n                        if self.RB_02_Val_Gr.isChecked():\n                            objetdetail = objetdetail + \" \" + \"deg\"                              # 10 deg\n                        if self.RB_03_Val_Gr_Ph.isChecked():\n                            objetdetail = objetdetail + \" \" + \"deg\" + \" R\" + str((chr(88 + i)))  # 10 deg R\n\n                        tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                        tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n\n                        if self.CB_08_Split.isChecked():\n                            objectNumeric = objetdetail.split(\" \")\n                            if self.CB_03_Colonne.isChecked():                      #Title color\n                                tableau.setBackground(caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                            for spl in objectNumeric:\n                                objetdetail = spl\n                                tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                                tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n                                tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                                colonne += 1\n                        else:\n                            tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                            colonne += 1\n                except Exception:\n                    None\n\n            if self.CB_15_Dimension.isChecked():                                    # Dimension\n                try:\n                    objectNumeric = \"\"\n                    obj = FreeCAD.ActiveDocument.getObject(objListe[0])\n                    for modele in obj.PropertiesList:\n                        if str(impost).find(str(modele))!= -1:\n                            valeur = affDim(objListe[0], str(modele))\n                            if valeur != 0.0:\n                                objectNumeric = objetdetail = \"\"\n                                objetdetail = str(valeur)\n    \n                                if grandeur == \"mm\":\n                                    grandeur = uniteMs\n                                    objetdetail = str(arround(float(valeur) * uniteM))\n                                else:\n                                    grandeur = grandeur\n    \n                                if self.RB_01_Value.isChecked():\n                                    objectNumeric = objetdetail                                      # 0,0 = 10.0\n                                if self.RB_02_Val_Gr.isChecked():\n                                    objectNumeric = objetdetail + \" \" + grandeur                     # 1,0 = 10 mm\n                                if self.RB_03_Val_Gr_Ph.isChecked():\n                                    objectNumeric = objetdetail + \" \" + grandeur + \" \" + modele      # 1,1 = 10 mm Width\n    \n                                tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                                tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n    \n                                if self.CB_08_Split.isChecked():\n                                    objectNumeric = objectNumeric.split(\" \")\n                                    if self.CB_03_Colonne.isChecked():              #Title color\n                                        tableau.setBackground(caseTableau(ligne,colonne), (TextColorText_R, TextColorText_G, TextColorText_B, TextColorText_L))\n                                    for spl in objectNumeric:\n                                        objetdetail = spl\n                                        tableau.setAlignment(caseTableau(ligne,colonne), str(\"right\"))\n                                        tableau.setAlignment(caseTableau(ligne,colonne), str(\"vcenter\"))\n                                        tableau.set(caseTableau(ligne,colonne), str(objetdetail))\n                                        colonne += 1\n                                else:\n                                    objectNumeric = str(objectNumeric)\n                                    try:\n                                        if self.RB_01_Value.isChecked():\n                                            None\n                                        else:\n                                            tableau.setDisplayUnit(caseTableau(ligne,colonne), grandeur)\n                                    except Exception:\n                                        None\n                                    tableau.set(caseTableau(ligne,colonne), (objectNumeric))\n                                    colonne += 1\n                except Exception:\n                    None\n\n            ligne += 1\n            compteurPB +=1\n            self.progressBar_01.setValue(compteurPB)\n\n        self.progressBar_01.setValue(0)\n\n        ui.on_PB_SpreadSheet_clicked()\n        del listeSortedBis[:]\n        App.ActiveDocument.recompute()\n\n########SpreadSheet section fin #######################################################################################################\n\n    def loadObjects(self):\n        global doc\n        global listeObjetsOriginal\n        global listeSorted\n        global ui\n        global titre\n        global impost\n\n        enteteTitres  = QtWidgets.QTreeWidgetItem([\"Etiquette\",])                          # titres entete 1 colonnes\n        self.treeWidget.setHeaderItem(enteteTitres)                                        # affichage des titres #([\"Tree\",\"First\",...])\n        documentActif = QtWidgets.QTreeWidgetItem(self.treeWidget, [str(doc)+\" Original\"]) # titre du document\n\n        del listeObjetsOriginal[:]\n        del listeSorted[:]\n\n        listeType = []\n        del listeType[:]\n\n        c=0\n        #### Liste ######\n        for obj in FreeCAD.ActiveDocument.Objects:\n            objName    = obj.Name\n            objLabel   = obj.Label\n            objGroupe  = \"\"\n            objLName   = 0\n            objLLabel  = 0\n            objLGroupe = 0\n            objSignal  = 0\n\n            if objLabel[0].islower():                                               # firt char lower\n                objLabel  = objLabel[0].upper() + objLabel[1:]\n                objSignal = 1\n\n            ####recherche de groupe et enfants debut####\n            if len(obj.OutList) != 0:\n                if len(obj.OutList) > 1:\n                    objGroupe = obj.Label + \" (\" + str(len(obj.OutList)) + \" Objects)\"\n                else:\n                    objGroupe = obj.Label + \" (\" + str(len(obj.OutList)) + \" Object)\"\n                for enfants in obj.OutList:\n                    objGroupe += \"\\n\"  + \" ( \" + enfants.Label + \" )\"\n            else:\n                objGroupe = \"-\"\n            ####recherche de groupe et enfants fin####\n\n#       #[objName, objLabel, \"False\", objGroupe, objLName, objLLabel, objLGroupe, objSignal, objTypeSolid, objTypeTypeID, objTypeShape, [objNumeric]]\n\n            ####recherche de type d objet debut####\n            objTypeSolid = objTypeTypeID = objTypeShape = \"\"\n            try:\n                if str(obj.Shape.Solids).find('Solid')!= -1:\n                    objTypeSolid = \"Solid\"\n                    listeType.append(\"Solid\")\n            except Exception:\n                None\n            try:\n                listeType.append(str(obj.TypeId.split(\"::\")[1]))\n                objTypeTypeID = str(obj.TypeId.split(\"::\")[1])\n            except Exception:\n                None\n            try:\n                listeType.append(str(obj.Shape.ShapeType))\n                objTypeShape = str(obj.Shape.ShapeType)\n            except Exception:\n                None\n           ####recherche de type d objet fin####\n\n            objLName   = len(objName)      # length\n            objLLabel  = len(objLabel)     # length\n            objLGroupe = len(objGroupe)    # length\n\n           ####recherche de type numerique debut####\n            objNumeric = \"\"\n            for i in obj.PropertiesList:\n                if str(impost).find(str(i))!= -1:\n                    if (affDim(obj.Name, str(i))) != 0.0:\n                        objNumeric = objNumeric + str(int(affDim(obj.Name, str(i))))+\",\" # int numeric\n           ####recherche de type numerique fin####\n\n####\n#            if Gui.activeDocument().getObject(objName).Visibility == True:\n#                listeObjetsOriginal.append([objName, objLabel, \"True\", objGroupe, objLName, objLLabel, objLGroupe, objSignal, objTypeSolid, objTypeTypeID, objTypeShape, [objNumeric]])\n#            else:\n#                listeObjetsOriginal.append([objName, objLabel, \"False\", objGroupe, objLName, objLLabel, objLGroupe, objSignal, objTypeSolid, objTypeTypeID, objTypeShape, [objNumeric]])\n            listeObjetsOriginal.append([objName, objLabel, str(Gui.activeDocument().getObject(objName).Visibility), objGroupe, objLName, objLLabel, objLGroupe, objSignal, objTypeSolid, objTypeTypeID, objTypeShape, [objNumeric]])\n####\n####\n        self.treeWidget.clear()                                                     # efface le contenu du widget\n        listeSorted = copy.deepcopy(listeObjetsOriginal)                            # original organisation on begin\n        titre = \" Original\"                                                         # original organisation on begin\n#\n#        listeSorted = sorted(listeSorted, key=itemgetter(0))                        # sorted by Name on begin\n#        titre = \" by Name\"                                                          # sorted by Name on begin\n####\n####\n        listeType = sorted(set(listeType))                                          # supprime les doublons et met en ordre liste Type\n        for i in range(len(listeType)):\n            self.ComboB_Type.addItem(_fromUtf8(\"\"))                                 # include in ComboBox\n            self.ComboB_Type.setItemText(i, listeType[i])\n####\n        ui.sorted_List(titre + \" (O \" + str(len(listeSorted)) + \")\")\n#        ui.tableauSpreadsheet()\n\n    def on_PB_Visibility_clicked(self):\n        global visibilite\n        global group\n        global ui\n        global listeSorted\n\n        group = 0\n        if visibilite == 0:\n            visibilite = 1\n        else:\n            visibilite = 0\n\n        visible = cache = 0\n        for i in listeSorted:\n            if i[2] == \"True\":\n                visible += 1\n            else:\n                cache += 1\n        self.treeWidget.clear()                                                     # efface le widget\n        ui.sorted_List(titre + \" (V \" + str(visible) + \") (H \" + str(cache) + \") = (O \" + str(visible + cache) + \")\")\n\n    def on_PB_Group_clicked(self):\n        global group\n        global visibilite\n        global ui\n        global listeSorted\n\n        visibilite = 0\n        if group == 0:\n            group = 1\n        else:\n            group = 0\n\n        groupe = simple = 0\n        for i in listeSorted:\n            if i[3] == \"-\":\n                groupe += 1\n            else:\n                simple += 1\n\n        self.treeWidget.clear()                                                     # efface le widget\n        ui.sorted_List(titre + \" (G \" + str(groupe) + \") (S \" + str(simple) + \") = (O \" + str(groupe + simple) + \")\")\n\n    def on_PB_Original_clicked(self):   # tableau organisation\n        global listeObjetsOriginal\n        global listeSorted\n        global ui\n        global titre\n\n        self.lineEdit_Search.clear()\n        for obj in listeObjetsOriginal:\n            if obj[2] == \"True\":\n                Gui.activeDocument().getObject(obj[0]).Visibility = True\n            else:\n                Gui.activeDocument().getObject(obj[0]).Visibility = False\n\n        listeSorted = copy.deepcopy(listeObjetsOriginal)\n        self.treeWidget.clear()\n        titre = \" Original\"\n        ui.sorted_List(titre + \" (O \" + str(len(listeSorted)) + \")\")\n        self.treeWidget.verticalScrollBar().setStyleSheet(\"background-color: QPalette.Base;\")\n\n    def on_PB_All_Visible_clicked(self):\n        global listeSorted\n        global ui\n        global titre\n\n        i = 0\n        for obj in listeSorted:\n            Gui.activeDocument().getObject(obj[0]).Visibility = True\n            listeSorted[i][2] = \"True\"\n            i += 1\n        self.treeWidget.clear()                                                     # efface le widget\n        ui.sorted_List(titre + \" (O \" + str(len(listeSorted)) + \")\")\n\n    def on_PB_All_Hidden_clicked(self):\n        global listeSorted\n        global ui\n        global titre\n\n        i = 0\n        for obj in listeSorted:\n            Gui.activeDocument().getObject(obj[0]).Visibility = False\n            listeSorted[i][2] = \"False\"\n            i += 1\n        self.treeWidget.clear()                                                     # efface le widget\n        ui.sorted_List(titre + \" (O \" + str(len(listeSorted)) + \")\")\n\n    def on_PB_Reload_clicked(self):\n        global doc\n        global ui\n        global titre\n\n        self.PB_SpreadSheet.setStyleSheet(\"background-color: QPalette.Base\")\n        doc = App.activeDocument()\n        if doc == None:\n            doc = FreeCAD.newDocument()\n        doc = doc.Name #unicode(doc.Name)\n\n        self.lineEdit_Search.clear()\n        self.treeWidget.clear()\n        self.RB_01_NameLabel.setChecked(True)#\n        titre = \" Original\"\n        ui.loadObjects()\n\n    def on_RB_Pressed(self):\n        global ui\n        global titre\n\n        self.treeWidget.clear()\n        ui.on_lineEdit_Search_Pressed()\n\n    def on_lineEdit_Search_Pressed(self):\n        global ui\n        global titre\n        global listeSorted\n        global searchString\n        global listeObjetsOriginal\n        global listeByStringSear\n\n        self.treeWidget.clear()\n        titre = \" by string\"\n        texte = self.lineEdit_Search.text()\n        searchString = \" Searched\"\n        listeSorted = copy.deepcopy(listeObjetsOriginal)\n        del listeByStringSear[:]\n\n        if texte != \"\":\n            comptName = comptLabel = comptNumeric = 0\n\n            # Search by Name + Label (not casse)\n            if self.RB_01_NameLabel.isChecked():\n                texte = texte.upper()\n                for i in range(len(listeSorted)):\n                    if texte in listeSorted[i][0][:len(texte)].upper():             # Name  upper\n                        listeByStringSear.append(listeSorted[i])\n                        comptName += 1\n                    if texte in listeSorted[i][1][:len(texte)].upper():             # Label upper\n                        listeByStringSear.append(listeSorted[i])\n                        comptLabel += 1\n\n            # Search by Name (casse)\n            elif self.RB_02_Name_CS.isChecked():                                    # case sensitivity\n                for i in range(len(listeSorted)):\n                    if texte in listeSorted[i][0][:len(texte)]:                     # Name\n                        listeByStringSear.append(listeSorted[i])\n                        comptName += 1\n\n            # Search by Label (not casse)\n            elif self.RB_03_Label_NC.isChecked():\n                for i in range(len(listeSorted)):\n                    if texte.upper() in listeSorted[i][1][:len(texte)].upper():     # Label\n                        listeByStringSear.append(listeSorted[i])\n                        comptLabel += 1\n\n            # Search by Name + Label casse sensitivity\n            elif self.RB_04_NamLabel_CS.isChecked():\n                for i in range(len(listeSorted)):\n                    if texte in listeSorted[i][0][:len(texte)]:                     # Name  sensitivity\n                        listeByStringSear.append(listeSorted[i])\n                        comptName += 1\n                    if listeSorted[i][7] == 1:\n                        casse = listeSorted[i][1]\n                        casse = casse[0].lower() + casse[1:]\n                        if texte in casse[:len(texte)]:                             # Label sensitivity\n                            listeByStringSear.append(listeSorted[i])\n                            comptLabel += 1\n                    elif texte in listeSorted[i][1][:len(texte)]:                   # Label sensitivity\n                        listeByStringSear.append(listeSorted[i])\n                        comptLabel += 1\n                        \n            # Search by case sensitivity in word\n            elif self.RB_05_NameLabel_AL.isChecked():\n                for i in range(len(listeSorted)):\n                    if texte in listeSorted[i][0]:                                  # Name sensitivity in word\n                        listeByStringSear.append(listeSorted[i])\n                        comptName += 1\n                    if listeSorted[i][7] == 1:\n                        casse = listeSorted[i][1]\n                        casse = casse[0].lower() + casse[1:]\n                        if texte in casse:                                          # Label sensitivity in word\n                            listeByStringSear.append(listeSorted[i])\n                            comptLabel += 1\n                    elif texte in listeSorted[i][1]:                                # Label sensitivity in word\n                        listeByStringSear.append(listeSorted[i])\n                        comptLabel += 1\n\n            titre = \" by string\"\n\n            # Search by Numeric value\n            if self.RB_06_Numeric_Num.isChecked():\n                titre = \" by numeric\"\n                for i in range(len(listeSorted)):\n                    decoNumer = listeSorted[i][11][0].split(\",\")\n                    if texte in decoNumer:                                          # Numeric\n                        listeByStringSear.append(listeSorted[i])\n                        comptNumeric += 1\n            listeSorted = copy.deepcopy(listeByStringSear)\n\n            ui.sorted_List(titre +\" (N \" + str(comptName) + \") (L \" + str(comptLabel) + \") (Nu \" + str(comptNumeric) + \") = (T \" + str(comptName + comptLabel + comptNumeric) + \")\")\n        else:\n            listeSorted = copy.deepcopy(listeObjetsOriginal)\n            ui.on_PB_ClearLEdit_clicked()\n\n    def on_PB_ClearLEdit_clicked(self):\n        global ui\n        global titre\n        global searchString\n\n        searchString = \"\"\n        self.treeWidget.clear()\n        self.lineEdit_Search.clear()\n        #self.RB_01_NameLabel.setChecked(True)\n        titre = \" Original\"\n        ui.sorted_List(titre + \" (O \" + str(len(listeSorted)) + \")\")\n\n    def on_PB_Select_clicked(self):\n        global listeSorted\n        global ui\n        global titre\n        global selections\n\n        self.treeWidget.setToolTip(\"The title display the option, number and type object(s) displayed\" + \"\\n\" + \"\\n\" + \n                                   \"O = Objects\" + \"\\n\" + \n                                   \"N = Name\" + \"\\n\" + \n                                   \"L = Label\" + \"\\n\" + \n                                   \"T = Total\" + \"\\n\" + \n                                   \"G = Group\" + \"\\n\" + \n                                   \"S = Single\" + \"\\n\" + \n                                   \"V = Visible\" + \"\\n\" + \n                                   \"H = Hidden\" + \"\\n\\n\" +\n                                   \"If one object are selected :\" + \"\\n\" + \n                                   \"the Placement Base, Rotation and Center of mass is displayed\" + \"\\n\" + \n                                   \"if available !\")\n        if selections == 0:\n            self.PB_Select.setText(\"Deselect\")\n            self.PB_Select.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_24.png\"))\n            self.PB_Select.setToolTip(\"Deselect all object(s) selected <img src=\" + self.path + \"Macro_FCTreeView_24.png\" + \" />\")\n            self.treeWidget.setSelectionMode(QtWidgets.QAbstractItemView.ContiguousSelection)\n            self.treeWidget.selectAll()\n            for obj in listeSorted:\n                FreeCADGui.Selection.addSelection(App.ActiveDocument.getObject(obj[0]))\n                #FreeCADGui.Selection.addSelection(App.ActiveDocument.getObject(unicode(obj[0])))\n            selections = 1\n        else:\n            self.PB_Select.setText(\"Select\")\n            self.PB_Select.setIcon(QtGui.QIcon(self.path + \"Macro_FCTreeView_23.png\"))\n            self.PB_Select.setToolTip(\"Select all object(s) displayed <img src=\" + self.path + \"Macro_FCTreeView_23.png\" + \" />\")\n            self.treeWidget.clearSelection()\n            FreeCADGui.Selection.clearSelection()\n            selections = 0\n\n    def SIGNAL_ComboB_Type_Changed(self, item):\n        global ui\n        global titre\n        global listeSorted\n        global searchString\n        global listeObjetsOriginal\n        global listeByStringSear\n\n        self.lineEdit_Search.clear()\n        texte = self.ComboB_Type.itemText(item)\n        self.treeWidget.clear()\n        titre = \" by type object\"\n        searchString = \" Searched\"\n        listeSorted = copy.deepcopy(listeObjetsOriginal)\n\n        del listeByStringSear[:]\n#       [objName, objLabel, str(Gui.activeDocument().getObject(objName).Visibility), objGroupe, objLName, objLLabel, objLGroupe, objSignal, objTypeSolid, objTypeTypeID, objTypeShape, [objNumeric]]\n        if texte != \"\":\n            comp = 0\n            # Search by type object\n            for i in range(len(listeSorted)):\n                if (texte in listeSorted[i][8]) or (texte in listeSorted[i][9]) or (texte in listeSorted[i][10]):\n                    listeByStringSear.append(listeSorted[i])\n                    comp += 1\n            titre = \" by \" + texte\n            listeSorted = copy.deepcopy(listeByStringSear)\n            ui.sorted_List(titre + \" ( \" + texte + \" \" + str(comp) + \")\")\n        else:\n            listeSorted = copy.deepcopy(listeObjetsOriginal)\n            ui.on_PB_ClearLEdit_clicked()\n\n    def on_PB_Quit_clicked(self):\n        global ui\n#        self.vueActive.removeEventCallback(\"SoMouseButtonEvent\",self.click)         # desinstalle la fonction souris\n        FreeCADGui.Selection.removeObserver(s)                                      # desinstalle la fonction residente SelObserver\n        self.window.hide()                                                          # hide the window and close the macro\n\n        FreeCAD.Console.PrintMessage(\"Quit FCTreeView\" + \"\\n\")\n\n##################################################################################################\nclass SelObserver:\n    def addSelection(self, document, object, element, position):  # Selection\n        global sourisPass\n        global listeSorted\n        global ui\n\n        None\n#\n#        if sourisPass == 0:\n#            if object in listeSorted[0]:\n#                print \"wahou\"\n#                print object\n#            sourisPass = 1\n#        else:\n#            sourisPass = 0\n#        \n#\n##        print object\n#\n###    def setPreselection(self,doc,obj,sub):             # preselection\n###        print \"setPreselection\"\n###    def removeSelection(self,doc,obj,sub):             # Effacer l'objet selectionne\n###        print \"removeSelection\"\n###    def setSelection(self,doc):                        # Selection dans ComboView\n###        print \"SelObserver quit macro\"\n###    def clearSelection(self,doc):                      # Si clic sur l'ecran, effacer la selection\n###        print \"clearSelection\"                         # Si clic sur un autre objet, efface le precedent\n#\ns=SelObserver()\nFreeCADGui.Selection.addObserver(s)                    # installe la fonction en mode resident\n####################################################################################################\n\ndoc = App.activeDocument()\nif doc == None:\n    doc = FreeCAD.newDocument()\ndoc = doc.Name\n\n#####Section demarrage et controle#################################################################\n#\nmw = FreeCADGui.getMainWindow()\ndw=mw.findChildren(QtWidgets.QDockWidget)    # pour QtWidgets Docked et pas les Flotants\n\n\nfor i in dw:\n    if str(i.objectName()) == __title__:\n        FreeCAD.Console.PrintError(__title__ + \" is already open see \\\"Menu > View > Panels\\\"\" + \"\\n\")\n        #va=i.toggleViewAction()\n        if i.isVisible():\n            #va.setChecked(False)                   # activer False\n            i.setVisible(False)                    # visible False\n        else:\n            #va.setChecked(True)                    # activer True\n            i.setVisible(True)                     # visible True\n        break\n\nif i.objectName() != __title__ :                   # macro Name\n    if testing == 1:                               # MainWindow\n        MainWindow = QtWidgets.QMainWindow()       # create a new window volant\n        MainWindow.setObjectName(__title__)        # macro internal Name\n        ui = Ui_MainWindow(MainWindow)\n        ui.setupUi(MainWindow)\n        MainWindow.show()\n        #ui.loadObjects()\n        ui.on_PB_Reload_clicked()                  # load and run the macro\n\n    #\n    #####DockWidget################################################################################\n    #\n    else:\n        MainWindow = QtWidgets.QDockWidget()       # create a new dockwidget\n        MainWindow.setObjectName(__title__)\n        ui = Ui_MainWindow(MainWindow)\n        ui.setupUi(MainWindow)\n        FCmw = FreeCADGui.getMainWindow()\n    \n        if testing == 2:                           # RightDock\n            FCmw.addDockWidget(PySide2.QtCore.Qt.RightDockWidgetArea,MainWindow) # add the widget to the main window Right\n        else:                                      # LeftDock\n            FCmw.addDockWidget(PySide2.QtCore.Qt.LeftDockWidgetArea,MainWindow)  # add the widget to the main window Left\n        #ui.loadObjects()\n        ui.on_PB_Reload_clicked()                  # load and run the macro\n    \n\n",
    "url": "https://wiki.freecad.org/Macro_FCTreeView",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/67517ef758ff20005d0a6adcfd8c9190/raw/59bc2028978c82744c83c6b138ab3ef30e0bf6f3/Macro_FCTreeView.FCMacro",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_FCTreeView",
    "version": "00.09",
    "license": "",
    "date": "2020/09/24",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_FCTreeView.png",
    "icon_source": "https://wiki.freecad.org/images/6/64/Macro_FCTreeView.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Mouse over cb",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro displays in the report view all elements below the cursor (all elements covered by other elements will also be displayed)<br /><br />Macro version: 00.00<br />Last modified: 2016-12-13<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/5/55/Macro_Mouse_over_cb.png\">ToolBar Icon</a><br />Author: Chris_G<br /> ",
    "comment": "This macro displays in the report view all elements below the cursor (all elements covered by other elements will also be displayed)",
    "code": "from pivy import coin\nimport FreeCADGui\n\ndef mouse_over_cb( event_callback):\n    event = event_callback.getEvent()\n    pos = event.getPosition().getValue()\n    listObjects = FreeCADGui.ActiveDocument.ActiveView.getObjectsInfo((int(pos[0]),int(pos[1])))\n    obj = []\n    if listObjects:\n        FreeCAD.Console.PrintMessage(\"\\n *** Objects under mouse pointer ***\")\n        for o in listObjects:\n            label = str(o[\"Object\"])\n            if not label in obj:\n                obj.append(label)\n        FreeCAD.Console.PrintMessage(\"\\n\"+str(obj))\n\n\nview = FreeCADGui.ActiveDocument.ActiveView\n\nmouse_over = view.addEventCallbackPivy( coin.SoLocation2Event.getClassTypeId(), mouse_over_cb )\n\n# to remove Callback :\n#view.removeEventCallbackPivy( coin.SoLocation2Event.getClassTypeId(), mouse_over_cb)",
    "url": "https://wiki.freecad.org/Macro_Mouse_over_cb",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2016-12-13",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Chris_G",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Mouse_over_cb.png",
    "icon_source": "https://wiki.freecad.org/images/5/55/Macro_Mouse_over_cb.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Normal Vector",
    "on_wiki": true,
    "on_git": false,
    "desc": "Get normal vector of preselected face<br /><br />Macro version: 1.0<br />Last modified: 2016-09-26<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/8/8b/Macro_Normal_Vector.png\">ToolBar Icon</a><br />Author: ulrich1a<br /> ",
    "comment": "Get normal vector of preselected face",
    "code": "Gui.Selection.getSelectionEx()[0].SubObjects[0].Faces[0].normalAt(0,0)",
    "url": "https://wiki.freecad.org/Macro_Normal_Vector",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2016-09-26",
    "src_filename": "",
    "filename_from_url": "",
    "author": "ulrich1a",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Normal_Vector.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/8/8b/Macro_Normal_Vector.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "ObjectInfo",
    "on_wiki": true,
    "on_git": false,
    "desc": "This WorkBench lets you know the volume information surface area, center of mass and moment of intertia of the selected object.<br /><br />This is not a macro but one WorkBench, uncompress the .zip file and paste the complete directory in the Mod user directory <a rel=\"nofollow\" class=\"external text\" href=\"https://github.com/KeithSloan/FreeCAD_Info/archive/master.zip\">Info</a><br /><br />Macro version: 1.0<br />Last modified: 2012-11-09<br />FreeCAD version: Until 0.17 <b>and PyQt4</b><br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/2/29/Macro_ObjectInfo.png\">ToolBar Icon</a><br />Author: keithsloan52<br /> ",
    "comment": "This WorkBench lets you know the volume information surface area, center of mass and moment of intertia of the selected object.",
    "code": "import webbrowser \n\n##########\n# WorkBenche\n# Code used to download the zip file from FreeCAD\n##########\n\nFreeCAD.Console.PrintMessage(\"\\n\" + \"You must download the Info.zip file in the author github KeithSloan/FreeCAD_Infosite\" + \"\\n\")\nFreeCAD.Console.PrintMessage(\"http://keithsloan.dynu.com/Keith&Jenny/\" + \"\\n\")\nwebbrowser.open(\"https://github.com/KeithSloan/FreeCAD_Info/archive/master.zip\")",
    "url": "https://wiki.freecad.org/Macro_ObjectInfo",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2012-11-09",
    "src_filename": "",
    "filename_from_url": "",
    "author": "keithsloan52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_ObjectInfo.png",
    "icon_source": "https://wiki.freecad.org/images/2/29/Macro_ObjectInfo.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "screw maker1 2",
    "on_wiki": true,
    "on_git": false,
    "desc": "Creates a screw, bolt... with or without thread, according to ISO standards.<br /><br />Macro version: 2.3.1<br />Last modified: 2018-10-22<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/0/00/Macro_screw_maker1_2.png\">ToolBar Icon</a><br />Author: Ulrich Brammer<br /> ",
    "comment": "Generate a screw",
    "code": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\nMacro to generate screws with FreeCAD.\nVersion 1.4 from 1st of September 2013\nVersion 1.5 from 23rd of December 2013\nCorrected hex-heads above M12 not done.\nVersion 1.6 from 15th of March 2014\nAdded PySide support\n\nVersion 1.7 from April 2014\nfixed bool type error. (int is not anymore accepted at linux)\nfixed starting point of real thread at some screw types.\n\nVersion 1.8 from July 2014\nfirst approach for a faster real thread\n\nVersion 1.9 / 2.0 July 2015\nnew calculation of starting point of thread\nshell-based approach for screw generation\nadded:\nISO 14582 Hexalobular socket countersunk head screws, high head\nISO 14584 Hexalobular socket raised countersunk head screws\nISO 7380-2 Hexagon socket button head screws with collar\nDIN 967 Cross recessed pan head screws with collar\nISO 4032 Hexagon nuts, Style 1\nISO 4033 Hexagon nuts, Style 2\nISO 4035 Hexagon thin nuts, chamfered\nEN 1661 Hexagon nuts with flange\nISO 7094 definitions  Plain washers - Extra large series\nISO 7092 definitions  Plain washers - Small series\nISO 7093-1 Plain washer - Large series\nScrew-tap to drill inner threads in parts with user defined length\n\nScrewMaker can now also used as a python module.\nThe following shows how to generate a screw from a python script:\n  import screw_maker2_0\n\n  threadDef = 'M3.5'\n  o = screw_maker2_0.Screw()\n  t = screw_maker2_0.Screw.setThreadType(o,'real')\n  # Creates a Document-Object with label describing the screw\n  d = screw_maker2_0.Screw.createScrew(o, 'ISO1207', threadDef, '20', 'real')\n\n  # creates a shape in memory\n  t = screw_maker2_0.Screw.setThreadType(o,'real')\n  s = screw_maker1_9d.Screw.makeIso7046(o, 'ISO14582', threadDef, 40.0)\n  Part.show(s)\n\nVersion 2.1 August 2015\nadded:\nISO 8676 Hexagon head screw with metric fine pitch thread\n\nVersion 2.2 May 2018\n- Extend function \"moveScrew\" to check for Body and Part.\n- Add Screw to Part if Body is in Part.\n- Search for plane support face to get correct orientation\n- fix failed hex-head\n\nVersion 2.3 Oct 2018\n- fix missing function equal_vertex\n\nto do: check ISO7380 usage of rs and rt, actual only rs is used\ncheck chamfer angle on hexogon heads and nuts\n***************************************************************************\n*   Copyright (c) 2013, 2014, 2015 2018                                   *\n*   Ulrich Brammer <ulrich1a[at]users.sourceforge.net>                    *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n*                                                                         *\n***************************************************************************\n\"\"\"\nfrom __future__ import division\n\n__Name__ = 'Screw Maker'\n__Comment__ = 'Generate a screw'\n__Author__ = \"Ulrich Brammer <ulrich1a@users.sourceforge.net>\"\n__Version__ = '2.3.1'\n__Date__ = '2018-10-22'\n__License__ = 'LGPL2+'\n__Web__ = 'http://freecadweb.org/wiki/Macro_screw_maker1_2'\n__Wiki__ = 'http://freecadweb.org/wiki/Macro_screw_maker1_2'\n__Icon__ = ''\n__Help__ = 'Select the characteristics of the screw and click on the create button'\n__Status__ = ''\n__Requires__ = ''\n__Communication__ = ''\n__Files__ = ''\n\nimport math\n\nimport FreeCAD\nimport FreeCADGui\nimport Part\nfrom FreeCAD import Base\nimport DraftVecUtils\n\ntry:\n  from PySide import QtCore, QtGui\n  #FreeCAD.Console.PrintMessage(\"PySide is used\" + \"\\n\")\nexcept ImportError:\n  #FreeCAD.Console.PrintMessage(\"PyQt4 is needed\" + \"\\n\")\n  from PyQt4 import QtCore, QtGui\n\ntry:\n  _encoding = QtGui.QApplication.UnicodeUTF8\n  def tr(context, text):\n    return QtGui.QApplication.translate(context, text, None, _encoding)\nexcept AttributeError:\n  def tr(context, text):\n    return QtGui.QApplication.translate(context, text, None)\n\nDEBUG = False # set to True to show debug messages; does not work, still todo.\n\ndebObject = None\n\n# Diameters included in this library/macro.\n# Some ISO-standards may include more diameters!\n# Dictionary used for user messages\nstandard_diameters = {\n  'ISO4017': ('M1.6', 'M64'), # ISO 4017 Hex-head-screw\n  'ISO4014': ('M1.6', 'M64'), # ISO 4014 Hex-head-bolt\n  'EN1662':  ('M5',   'M16'), # EN 1662 Hexagon bolts with flange, small series\n  'EN1665':  ('M5',   'M20'), # EN 1665 Hexagon bolts with flange, heavy series\n  'ISO8676': ('M8x1', 'M64x4'), # ISO 8676 Hexagon head screw with metric fine pitch thread\n  'ISO4762': ('M1.6', 'M64'), # ISO 4762 Hexagon socket head cap screws\n  'ISO2009': ('M1.6', 'M10'), # ISO 2009 Slotted countersunk flat head screws\n  'ISO2010': ('M1.6', 'M10'), # ISO 2010 Slotted raised countersunk head screws\n  'ISO1580': ('M1.6', 'M10'), # ISO 1580 Slotted pan head screws\n  'ISO7045': ('M1.6', 'M10'), # ISO 7045 Pan head screws type H cross recess\n  'ISO7046': ('M1.6', 'M10'),\n  'ISO7047': ('M1.6', 'M10'),\n  'ISO1207': ('M3',   'M10'), # ISO 1207 Slotted cheese head screws\n  'ISO7048': ('M2.5', 'M8'),  # ISO 7048 Cross-recessed cheese head screws with type H cross recess\n  'ISO7380-1':('M3',  'M16'), # ISO 7380 Hexagon socket button head screws\n  'ISO7380-2':('M3',  'M16'), # ISO 7380 Hexagon socket button head screws with collar\n  'DIN967'  :('M3',   'M8'),  # DIN 967 Cross recessed pan head screws with collar\n  'ISO10642':('M3',   'M20'), # ISO 10642 Hexagon socket countersunk head screws\n  'ISO14579':('M2',   'M20'), # ISO 14579 Hexalobular socket head cap screws\n  'ISO14580':('M2',   'M10'), # ISO 14580 Hexalobular socket cheese head screws\n  'ISO14581':('M2',   'M10'), # ISO 14581 Hexalobular socket countersunk flat head screws (to do!!)\n  'ISO14582':('M3',   'M10'), # ISO 14582 Hexalobular socket countersunk head screws, high head\n  'ISO14583':('M2',   'M10'), # ISO 14583 Hexalobular socket pan head screws\n  'ISO14584':('M2',   'M10'), # ISO 14584 Hexalobular socket raised countersunk head screws\n  'ISO7089': ('M1.6', 'M64'), # Washer\n  'ISO7090': ('M5',   'M64'), # ISO 7090 definitions Plain washers, chamfered - Normal series\n  'ISO7091': ('M1.6', 'M64'), # ISO 7091 definitions  Plain washer - Normal series Product Grade C\n  'ISO7092': ('M1.6', 'M36'), # ISO 7092 definitions  Plain washers - Small series\n  'ISO7093-1': ('M3', 'M36'), # ISO 7093-1 Plain washer - Large series\n  'ISO7094': ('M5',   'M36'), # ISO 7094 definitions  Plain washers - Extra large series\n  'ISO4032': ('M1.6', 'M64'), # ISO 4032 Hexagon nuts, Style 1\n  'ISO4033': ('M5',   'M36'), # ISO 4033 Hexagon nuts, Style 2\n  'ISO4035': ('M1.6', 'M64'), # ISO 4035 Hexagon thin nuts, chamfered\n  'ISO4036': ('M1.6', 'M10'), # ISO 4035 Hexagon thin nuts, unchamfered, todo no function coded\n  'EN1661':  ('M5',   'M20')} # EN 1661 Hexagon nuts with flange\n\n# ISO 4017 Hex-head-screw\n#           P,    c,  dw,    e,     k,   r,   s\niso4017head={\n  'M1.6':  (0.35, 0.2, 2.9,  3.4,   1.1, 0.1,  3.2),\n  'M2':    (0.40, 0.2, 3.7,  4.4,   1.4, 0.1,  4.0),\n  'M2.5':  (0.45, 0.2, 4.6,  5.5,   1.7, 0.1,  5.0),\n  'M3':    (0.5,  0.2, 5.2,  6.1,   2.0, 0.1,  5.5),\n  '(M3.5)':(0.6,  0.2, 5.2,  6.6,   2.4, 0.1,  5.5),\n  'M4':    (0.7,  0.2, 6.6,  7.7,   2.8, 0.2,  7.0),\n  'M5':    (0.8,  0.2, 7.5,  8.9,   3.5, 0.2,  8.0),\n  'M6':    (1.0,  0.2, 9.5,  11.05, 4.0, 0.25, 10.0),\n  'M8':    (1.25, 0.3, 11.7, 14.5,  5.3, 0.25, 13.0),\n  'M10':   (1.50, 0.3, 14.7, 17.9,  6.4, 0.4,  16.0),\n  'M12':   (1.75, 0.3, 16.7, 20.1,  7.5, 0.6,  18.0),\n  '(M14)': (2.00, 0.3, 20.5, 24.5,  8.8, 0.6,  22.0),\n  'M16':   (2.00, 0.4, 22.4, 26.9, 10.0, 0.6,  24.0),\n  '(M18)': (2.50, 0.4, 25.4, 30.2, 11.5, 0.6,  27.0),\n  'M20':   (2.50, 0.4, 28.2, 33.7, 12.5, 0.8,  30.0),\n  '(M22)': (2.50, 0.4, 31.8, 37.7, 14.0, 0.8,  34.0),\n  'M24':   (3.00, 0.4, 33.7, 40.1, 15.0, 0.8,  36.0),\n  '(M27)': (3.00, 0.4, 38.0, 45.2, 17.0, 1.0,  41.0),\n  'M30':   (3.50, 0.4, 42.8, 50.9, 18.7, 1.0,  46.0), #dw not in class A, e not in class A\n  '(M33)': (3.50, 0.4, 46.6, 55.4, 21.0, 1.0,  50.0),\n  'M36':   (4.00, 0.4, 51.2, 61.0, 22.5, 1.0,  55.0), #dw not in class A, e not in class A\n  '(M39)': (4.00, 0.5, 55.9, 66.5, 25.0, 1.0,  60.0),\n  'M42':   (4.50, 0.7, 60.0, 71.3, 26.0, 1.2,  65.0),\n  '(M45)': (4.50, 0.7, 64.7, 77.0, 28.0, 1.2,  70.0),\n  'M48':   (5.00, 0.7, 69.5, 82.6, 30.0, 1.6,  75.0),\n  '(M52)': (5.00, 0.7, 74.5, 88.3, 33.0, 1.6,  80.0),\n  'M56':   (5.50, 0.7, 78.7, 93.6, 35.0, 2.0,  85.0),\n  '(M60)': (5.50, 0.7, 82.7, 99.2, 38.0, 2.0,  90.0),\n  'M64':   (6.00, 0.7, 88.2,104.9, 40.0, 2.0,  95.0)\n  }\n\niso4017length = {\n  '2': ( 1.8,  2.2),\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '100':(99.3, 100.7),\n  '110':(109.3, 110.7),\n  '120':(119.3, 120.7),\n  '130':(129.2, 130.8),\n  '140':(139.2, 130.8),\n  '150':(149.2, 150.8),\n  '160':(159.2, 160.8),\n  '180':(179.2, 180.8),\n  '200':(199.1, 200.9)\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso4017range = {\n  'M1.6':  ('2', '16'),\n  'M2':    ('4', '20'),\n  'M2.5':  ('5', '25'),\n  'M3':    ('5', '30'),\n  '(M3.5)':('8', '35'),\n  'M4':    ('6', '40'),\n  'M5':    ('8', '50'),\n  'M6':   ('12', '60'),\n  'M8':   ('16', '80'),\n  'M10':  ('20','100'),\n  'M12':  ('25','120'),\n  '(M14)':('25','140'),\n  'M16':  ('30','150'),\n  '(M18)':('35','200'),\n  'M20':  ('40','160'),\n  '(M22)':('45','200'),\n  'M24':  ('50','180'),\n  '(M27)':('50','100'),\n  'M30':  ('60','200'),\n  '(M33)':('65','200'),\n  'M36':  ('70','200'),\n  '(M39)':('80','200'),\n  'M42':  ('70','200'),\n  '(M45)':('90','200'),\n  'M48': ('100','200'),\n  '(M52)':('100','200'),\n  'M56':  ('110','200'),\n  '(M60)':('120','200'),\n  'M64':  ('120','200')\n  }\n\n# ISO 8676 Hexagon head screw with metric fine pitch thread\n#                P,    c,  dw,    e,     k,   r,   s\niso8676def={\n  'M8x1':      (1.00, 0.3, 11.7, 14.5,  5.3, 0.25, 13.0),\n  'M10x1':     (1.00, 0.3, 14.7, 17.9,  6.4, 0.4,  16.0),\n  '(M10x1.25)':(1.25, 0.3, 14.7, 17.9,  6.4, 0.4,  16.0),\n  'M12x1.5':   (1.50, 0.3, 16.7, 20.1,  7.5, 0.6,  18.0),\n  '(M12x1.25)':(1.75, 0.3, 16.7, 20.1,  7.5, 0.6,  18.0),\n  '(M14x1.5)': (1.50, 0.3, 20.5, 24.5,  8.8, 0.6,  22.0),\n  'M16x1.5':   (1.50, 0.4, 22.4, 26.9, 10.0, 0.6,  24.0),\n  '(M18x1.5)': (1.50, 0.4, 25.4, 30.2, 11.5, 0.6,  27.0),\n  'M20x1.5':   (1.50, 0.4, 28.2, 33.7, 12.5, 0.8,  30.0),\n  '(M20x2)':   (2.00, 0.4, 28.2, 33.7, 12.5, 0.8,  30.0),\n  '(M22x1.5)': (1.50, 0.4, 31.8, 37.7, 14.0, 0.8,  34.0),\n  'M24x2':     (2.00, 0.4, 33.7, 40.1, 15.0, 0.8,  36.0),\n  '(M27x2)':   (2.00, 0.4, 38.0, 45.2, 17.0, 1.0,  41.0),\n  'M30x2':     (2.00, 0.4, 42.8, 50.9, 18.7, 1.0,  46.0), #dw not in class A, e not in class A\n  '(M33x2)':   (2.00, 0.4, 46.6, 55.4, 21.0, 1.0,  50.0),\n  'M36x3':     (3.00, 0.4, 51.2, 61.0, 22.5, 1.0,  55.0), #dw not in class A, e not in class A\n  '(M39x3)':   (3.00, 0.5, 55.9, 66.5, 25.0, 1.0,  60.0),\n  'M42x3':     (3.00, 0.7, 60.0, 71.3, 26.0, 1.2,  65.0),\n  '(M45x3)':   (3.00, 0.7, 64.7, 77.0, 28.0, 1.2,  70.0),\n  'M48x3':     (3.00, 0.7, 69.5, 82.6, 30.0, 1.6,  75.0),\n  '(M52x4)':   (4.00, 0.7, 74.5, 88.3, 33.0, 1.6,  80.0),\n  'M56x4':     (4.00, 0.7, 78.7, 93.6, 35.0, 2.0,  85.0),\n  '(M60x4)':   (4.00, 0.7, 82.7, 99.2, 38.0, 2.0,  90.0),\n  'M64x4':     (4.00, 0.7, 88.2,104.9, 40.0, 2.0,  95.0)\n  }\n\niso8676length = {\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '100':(99.3, 100.7),\n  '110':(109.3, 110.7),\n  '120':(119.3, 120.7),\n  '130':(129.2, 130.8),\n  '140':(139.2, 130.8),\n  '150':(149.2, 150.8),\n  '160':(159.2, 160.8),\n  '180':(179.2, 180.8),\n  '200':(199.1, 200.9),\n  '220':(217.7, 222.3),\n  '240':(237.7, 242.3),\n  '260':(219.1, 220.9),\n  '280':(219.1, 220.9),\n  '300':(219.1, 220.9),\n  '320':(219.1, 220.9),\n  '340':(219.1, 220.9),\n  '360':(219.1, 220.9),\n  '380':(219.1, 220.9),\n  '400':(219.1, 220.9),\n  '420':(219.1, 220.9),\n  '440':(219.1, 220.9),\n  '460':(219.1, 220.9),\n  '480':(219.1, 220.9),\n  '500':(496.85, 503.15)\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso8676range = {\n  'M8x1':      ('16', '80'),\n  'M10x1':     ('20','100'),\n  '(M10x1.25)':('20','100'),\n  'M12x1.5':   ('25','120'),\n  '(M12x1.25)':('25','120'),\n  '(M14x1.5)': ('30','140'),\n  'M16x1.5':   ('35','160'),\n  '(M18x1.5)': ('35','180'),\n  'M20x1.5':   ('40','200'),\n  '(M20x2)':   ('40','200'),\n  '(M22x1.5)': ('45','220'),\n  'M24x2':     ('40','200'),\n  '(M27x2)':   ('55','260'),\n  'M30x2':     ('40','200'),\n  '(M33x2)':   ('65','360'),\n  'M36x3':     ('40','200'),\n  '(M39x3)':   ('80','380'),\n  'M42x3':     ('90','420'),\n  '(M45x3)':   ('90','440'),\n  'M48x3':     ('100','480'),\n  '(M52x4)':   ('100','500'),\n  'M56x4':     ('120','500'),\n  '(M60x4)':   ('120','500'),\n  'M64x4':     ('130','500')\n  }\n\n# ISO 4014 Hex-head-bolt\n#          P,      b1,    b2,    b3,  c,   dw,    e,    k,   r,   s\niso4014head={\n  'M1.6':  (0.35,   9.0,  15.0,  28.0, 0.2,  2.3,  3.4,  1.1, 0.1,  3.2),\n  'M2':    (0.40,  10.0,  16.0,  29.0, 0.2,  3.0,  4.4,  1.4, 0.1,  4.0),\n  'M2.5':  (0.45,  11.0,  17.0,  30.0, 0.2,  4.0,  5.5,  1.7, 0.1,  5.0),\n  'M3':    (0.50,  12.0,  18.0,  31.0, 0.2,  4.6,  6.1,  2.0, 0.1,  5.5),\n  '(M3.5)':(0.60,  13.0,  19.0,  32.0, 0.2,  5.1,  6.6,  2.4, 0.1,  6.0),\n  'M4':    (0.70,  14.0,  20.0,  33.0, 0.2,  5.9,  7.7,  2.8, 0.2,  7.0),\n  'M5':    (0.80,  16.0,  22.0,  35.0, 0.2,  6.9,  8.9,  3.5, 0.2,  8.0),\n  'M6':    (1.00,  18.0,  24.0,  37.0, 0.2,  8.9, 11.05, 4.0, 0.25,10.0),\n  'M8':    (1.25,  22.0,  28.0,  41.0, 0.3, 11.7, 14.5,  5.3, 0.4, 13.0),\n  'M10':   (1.50,  26.0,  32.0,  45.0, 0.3, 14.7, 17.9,  6.4, 0.4, 16.0),\n  'M12':   (1.75,  30.0,  36.0,  49.0, 0.3, 16.7, 20.1,  7.5, 0.6, 18.0),\n  '(M14)': (2.00,  34.0,  40.0,  53.0, 0.3, 20.5, 24.5,  8.8, 0.6, 22.0),\n  'M16':   (2.00,  38.0,  44.0,  57.0, 0.4, 22.4, 26.9, 10.0, 0.6, 24.0),\n  '(M18)': (2.50,  42.0,  48.0,  61.0, 0.4, 25.4, 30.2, 11.5, 0.6, 27.0),\n  'M20':   (2.50,  46.0,  52.0,  65.0, 0.4, 28.2, 33.7, 12.5, 0.8, 30.0),\n  '(M22)': (2.50,  50.0,  56.0,  69.0, 0.4, 31.8, 37.7, 14.0, 0.8, 34.0),\n  'M24':   (3.00,  54.0,  60.0,  73.0, 0.4, 33.7, 40.1, 15.0, 0.8, 36.0),\n  '(M27)': (3.00,  60.0,  66.0,  79.0, 0.4, 38.0, 45.2, 17.0, 1.0, 41.0),\n  'M30':   (3.50,  66.0,  72.0,  85.0, 0.4, 42.8, 50.9, 18.7, 1.0, 46.0), #dw not in class A, e not in class A\n  '(M33)': (3.50,  78.0,  78.0,  91.0, 0.4, 46.6, 55.4, 21.0, 1.0, 50.0),\n  'M36':   (4.00,  84.0,  84.0,  97.0, 0.4, 51.2, 60.8, 22.5, 1.0, 55.0),\n  '(M39)': (4.00,  90.0,  90.0, 103.0, 0.5, 55.9, 66.5, 25.0, 1.0, 60.0),\n  'M42':   (4.50,  96.0,  96.0, 109.0, 0.6, 60.0, 71.3, 26.0, 1.2, 65.0),\n  '(M45)': (4.50, 102.0, 102.0, 115.0, 0.7, 64.7, 77.0, 28.0, 1.2, 70.0),\n  'M48':   (5.00, 108.0, 108.0, 121.0, 0.6, 69.5, 82.6, 30.0, 1.6, 75.0),\n  '(M52)': (5.00, 116.0, 116.0, 129.0, 0.7, 74.5, 88.3, 33.0, 1.6, 80.0),\n  'M56':   (5.50, 137.0, 137.0, 137.0, 0.6, 78.7, 93.6, 35.0, 2.0, 85.0),\n  '(M60)': (5.50, 145.0, 145.0, 145.0, 0.7, 82.7, 99.2, 38.0, 2.0, 90.0),\n  'M64':   (6.00, 153.0, 153.0, 153.0, 0.6, 88.2,104.9, 40.0, 2.0, 55.0)\n  }\n\niso4014length = {\n  '12':(11.65, 12.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '100':(99.3, 100.7),\n  '110':(109.3, 110.7),\n  '120':(119.3, 120.7),\n  '130':(129.2, 130.8),\n  '140':(139.2, 130.8),\n  '150':(149.2, 150.8),\n  '160':(159.2, 160.8),\n  '180':(179.2, 180.8),\n  '200':(199.1, 200.9),\n  '220':(219.1, 220.9),\n  '240':(237.7, 242.3),\n  '260':(219.1, 220.9),\n  '280':(219.1, 220.9),\n  '300':(219.1, 220.9),\n  '320':(219.1, 220.9),\n  '340':(219.1, 220.9),\n  '360':(219.1, 220.9),\n  '380':(219.1, 220.9),\n  '400':(219.1, 220.9),\n  '420':(219.1, 220.9),\n  '440':(219.1, 220.9),\n  '460':(219.1, 220.9),\n  '480':(219.1, 220.9),\n  '500':(496.85, 503.15),\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso4014range = {\n  'M1.6':('12', '16'),\n  'M2':  ('16', '20'),\n  'M2.5':('16', '25'),\n  'M3':  ('20', '30'),\n  '(M3.5)':('20', '35'),\n  'M4':  ('25', '50'),\n  'M5':  ('25', '50'),\n  'M6':  ('30', '130'),\n  'M8':  ('30', '180'),\n  'M10': ('35', '150'),\n  'M12': ('50', '150'),\n  '(M14)': ('50', '160'),\n  'M16': ('55', '200'),\n  '(M18)':('70','180'),\n  'M20': ('60', '300'),\n  '(M22)':('70','220'),\n  'M24': ('80', '220'),\n  '(M27)':('90', '220'),\n  'M30': ('110','300'),\n  '(M33)':('130','320'),\n  'M36': ('140','360'),\n  '(M39)':('150','380'),\n  'M42': ('160','440'),\n  '(M45)':('180','440'),\n  'M48': ('180','480'),\n  '(M52)':('200','480'),\n  'M56': ('220','500'),\n  '(M60)':('220','500'),\n  'M64': ('260','500')\n  }\n\n# EN 1662 Hexagon bolts with flange, small series\n#          P,   b0,    b1,   b2,   b3,   c,  dc,    dw,    e,     k,   kw,  lf,  r1,   s\nen1662def={\n  'M5': (0.80, 25.0, 16.0,  0.0,  0.0, 1.0, 11.4,  9.4,  7.59,  5.6, 2.3, 1.4, 0.2, 7.0),\n  'M6': (1.00, 30.0, 18.0,  0.0,  0.0, 1.1, 13.6, 11.6,  8.71,  6.9, 2.9, 1.6, 0.25, 8.0),\n  'M8': (1.25, 35.0, 22.0, 28.0,  0.0, 1.2, 17.0, 14.9, 10.95,  8.5, 3.8, 2.1, 0.4, 10.0),\n  'M10':(1.50, 40.0, 26.0, 32.0,  0.0, 1.5, 20.8, 18.7, 14.26,  9.7, 4.3, 2.1, 0.4, 13.0),\n  'M12':(1.75, 45.0, 30.0, 36.0,  0.0, 1.8, 24.7, 22.5, 17.62, 12.1, 5.4, 2.1, 0.6, 16.0),\n  '(M14)':(2.00, 50.0, 34.0, 40.0,  0.0, 2.1, 28.6, 26.4, 19.86, 12.9, 5.6, 2.1, 0.6, 18.0),\n  'M16':(2.00, 55.0, 38.0, 44.0, 57.0, 2.4, 32.8, 30.6, 23.15, 15.2, 6.8, 3.2, 0.6, 21.0)}\n\n# range of typical screw lengths\n#    min_length,  max_length\nen1662range = {\n  'M5': ('10', '50'),\n  'M6': ('12', '60'),\n  'M8': ('16', '80'),\n  'M10':('20','100'),\n  'M12':('25','120'),\n  '(M14)':('30','140'),\n  'M16':('35','160')\n  }\n\nen1662length = {\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '90':(89.3, 90.7),\n  '100':(99.3, 100.7),\n  '110':(109.3, 110.7),\n  '120':(119.3, 120.7),\n  '130':(129.2, 130.8),\n  '140':(139.2, 130.8),\n  '150':(149.2, 150.8),\n  '160':(159.2, 160.8)\n  }\n\n# EN 1665 Hexagon bolts with flange, heavy series\n#          P,    b0,  b1,   b2,   b3,   c,  dc,    dw,    e,     k,   kw,  lf,  r1,   s\nen1665def={\n  'M5': (0.80, 25.0, 16.0,  0.0,  0.0, 1.0, 11.8,  9.8,  8.71,  5.8, 2.6, 1.4, 0.2,  8.0),\n  'M6': (1.00, 30.0, 18.0,  0.0,  0.0, 1.1, 14.2, 12.2, 10.95,  6.6, 3.0, 1.6, 0.25,10.0),\n  'M8': (1.25, 35.0, 22.0, 28.0,  0.0, 1.2, 18.0, 15.8, 14.26,  8.1, 3.9, 2.1, 0.4, 13.0),\n  'M10':(1.50, 40.0, 26.0, 32.0,  0.0, 1.5, 22.3, 19.6, 17.62, 10.4, 4.1, 2.1, 0.4, 16.0),\n  'M12':(1.75, 45.0, 30.0, 36.0,  0.0, 1.8, 26.6, 23.8, 19.86, 11.8, 5.6, 2.1, 0.6, 18.0),\n  '(M14)':(2.00, 50.0, 34.0, 40.0,  0.0, 2.1, 30.5, 27.6, 23.15, 13.7, 6.5, 2.1, 0.6, 21.0),\n  'M16':(2.00, 55.0, 38.0, 44.0, 57.0, 2.4, 35.0, 31.9, 26.51, 15.4, 7.3, 3.2, 0.6, 24.0),\n  'M20':(2.50, 65.0, 46.0, 52.0, 65.0, 3.0, 43.0, 39.9, 33.23, 18.9, 8.9, 4.2, 0.8, 30.0)}\n\n# range of typical screw lengths\n#    min_length,  max_length\nen1665range = {\n  'M5': ('10', '50'),\n  'M6': ('12', '60'),\n  'M8': ('16', '80'),\n  'M10':('20','100'),\n  'M12':('25','120'),\n  '(M14)':('30','140'),\n  'M16':('35','160'),\n  'M20':('65','200')\n  }\n\nen1665length = {\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '90':(89.3, 90.7),\n  '100':(99.3, 100.7),\n  '110':(109.3, 110.7),\n  '120':(119.3, 120.7),\n  '130':(129.2, 130.8),\n  '140':(139.2, 130.8),\n  '150':(149.2, 150.8),\n  '160':(159.2, 160.8),\n  '180':(179.2, 180.8),\n  '200':(199.1, 200.9)\n  }\n\n# ISO 1207 definitions Class A, Slotted cheese head screws\n#          P,     a,   b,   dk,  dk_mean, da,  k,  n_min, r, t_min, x\niso1207def={\n  'M1.6':(0.35, 0.7, 25.0,  3.0,  2.9,  2.0, 1.1, 0.46, 0.1, 0.45, 0.9),\n  'M2':  (0.40, 0.8, 25.0,  3.8,  3.7,  2.6, 1.4, 0.56, 0.1, 0.6, 1.0),\n  'M2.5':(0.45, 0.9, 25.0,  4.5,  4.4,  3.1, 1.8, 0.66, 0.1, 0.7, 1.1),\n  'M3':  (0.50, 1.0, 25.0,  5.5,  5.4,  3.6, 2.0, 0.86, 0.1, 0.85, 1.25),\n  '(M3.5)':(0.60, 1.2, 38.0,  6.0,  5.9,  4.1, 2.4, 1.06, 0.1, 1.0, 1.5),\n  'M4':  (0.70, 1.4, 38.0,  7.0,  6.9,  4.7, 2.6, 1.26, 0.2, 1.1, 1.75),\n  'M5':  (0.80, 1.6, 38.0,  8.5,  8.4,  5.7, 3.3, 1.26, 0.2, 1.3, 2.0),\n  'M6':  (1.00, 2.0, 38.0, 10.0,  9.9,  6.8, 3.9, 1.66, 0.25,1.6, 2.5),\n  'M8':  (1.25, 2.5, 38.0, 13.0, 12.85, 9.2, 5.0, 2.06, 0.4, 2.0, 3.2),\n  'M10': (1.50, 3.0, 38.0, 16.0, 15.85, 11.2,6.0, 2.56, 0.4, 2.4, 3.8)}\n\n# range of typical screw lengths\n#    min_length,  max_length\niso1207range = {\n  'M1.6':('2', '16'),\n  'M2':  ('3', '20'),\n  'M2.5':('3', '25'),\n  'M3':  ('4', '30'),\n  '(M3.5)':('5', '35'),\n  'M4':  ('5', '40'),\n  'M5':  ('6', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '80'),\n  'M10':('12', '80')}\n\n# slotted cheese head screws\n# nom length: l_min, l_max\niso1207length = {\n  '2': (1.8,  2.2),\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.05, 55.95),\n  '60':(59.05, 60.95),\n  '65':(64.05, 65.95),\n  '70':(69.05, 70.95),\n  '75':(74.05, 75.95),\n  '80':(79.05, 80.95)\n  }\n\n# ISO 14580 definitions , Hexalobular socket cheese head screws\n#          P,     a,   b,   dk,  dk_mean, da,  k,  n_min, r, t_min, x\n#           tt,    k,    A,  t_mean\niso14580def={\n  'M2':  ('T6',  1.55, 1.75, 0.8),\n  'M2.5':('T8',  1.85, 2.40, 0.9),\n  'M3':  ('T10', 2.40, 2.80, 1.2),\n  '(M3.5)':('T15', 2.60, 3.35, 1.3),\n  'M4':  ('T20', 3.10, 3.95, 1.5),\n  'M5':  ('T25', 3.65, 4.50, 1.7),\n  'M6':  ('T30', 4.40, 5.60, 2.1),\n  'M8':  ('T45', 5.80, 7.95, 2.9),\n  'M10': ('T50', 6.90, 8.95, 3.3)}\n\n# range of typical screw lengths\n#    min_length,  max_length\n# iso14580range = iso1207range\n\n# nom length: l_min, l_max\niso14580length = {\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.05, 55.95),\n  '60':(59.05, 60.95),\n  '65':(64.05, 65.95),\n  '70':(69.05, 70.95),\n  '75':(74.05, 75.95),\n  '80':(79.05, 80.95)\n  }\n\n\n\n# ISO 7048 definitions Class A,\n# Cross-recessed cheese head screws with type H or Z cross recess\n#          P,     a,   b,   dk,  dk_mean, da,  k,   r,   x, cT,   mH,   mZ\niso7048def={\n  'M2.5':(0.45, 0.9, 25.0,  4.5,  4.4,  3.1, 1.8, 0.1, 1.1, '1', 2.7, 2.4),\n  'M3':  (0.50, 1.0, 25.0,  5.5,  5.4,  3.6, 2.0, 0.1, 1.25,'2', 3.5, 3.5),\n  '(M3.5)':(0.60, 1.2, 38.0,  6.0,  5.9,  4.1, 2.4, 0.1, 1.5, '2', 3.8, 3.7),\n  'M4':  (0.70, 1.4, 38.0,  7.0,  6.9,  4.7, 2.6, 0.2, 1.75,'2', 4.1, 4.0),\n  'M5':  (0.80, 1.6, 38.0,  8.5,  8.4,  5.7, 3.3, 0.2, 2.0, '2', 4.8, 4.6),\n  'M6':  (1.00, 2.0, 38.0, 10.0,  9.9,  6.8, 3.9, 0.25,2.5, '3', 6.2, 6.1),\n  'M8':  (1.25, 2.5, 38.0, 13.0, 12.85, 9.2, 5.0, 0.4, 3.2, '3', 7.7, 7.5)\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso7048range = {\n  'M2.5':('3', '25'),\n  'M3':  ('4', '30'),\n  '(M3.5)':('5', '35'),\n  'M4':  ('5', '40'),\n  'M5':  ('6', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '80')}\n\n# nom length: l_min, l_max\niso7048length = {\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '60':(59.05, 60.95),\n  '70':(69.05, 70.95),\n  '80':(79.05, 80.95)\n  }\n\n\n# Button Head Screw\n# nom length: l_min, l_max\niso7380length = {\n  #'2.5':(2.3,  2.7),\n  #'3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.05, 55.95),\n  '60':(59.05, 60.95),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '90':(89.3, 90.7)\n  }\n\n# ISO 7380-1 definitions Class A\n# http://www.agrati.com/it/unificati/it/gamma/unificati/home02.htm\n#          P,   b,     a,   da, dk,  dk_mean,s_mean,t_min, r, k,   e,    w,\niso7380def={\n  'M3':  (0.50, 18.0, 1.0,  3.6,  5.7,  5.5, 2.03, 1.04, 0.1, 1.65, 2.3,  0.2),\n  'M4':  (0.70, 20.0, 1.4,  4.7,  7.6,  7.4, 2.54, 1.30, 0.2, 2.20, 2.87, 0.3),\n  'M5':  (0.80, 22.0, 1.6,  5.7,  9.5,  9.3, 3.05, 1.56, 0.2, 2.75, 3.44, 0.38),\n  'M6':  (1.00, 24.0, 2.0,  6.8, 10.5, 10.3, 4.05, 2.08, 0.25,3.3,  4.58, 0.74),\n  'M8':  (1.25, 28.0, 2.5,  9.2, 14.0, 13.8, 5.05, 2.60, 0.4, 4.4,  5.72, 1.05),\n  'M10': (1.50, 32.0, 3.0, 11.2, 17.5, 17.3, 6.05, 3.12, 0.4, 5.5,  6.86, 1.45),\n  'M12': (1.75, 36.0, 3.5, 13.7, 21.0, 20.7, 8.06, 4.16, 0.6, 6.6,  9.15, 1.63),\n  'M16': (2.00, 44.0, 3.5, 17.7, 28.0, 27.8, 10.06,5.20, 0.6, 8.8, 11.43, 2.25)\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso7380range = {\n  'M3':  ('6', '30'),\n  'M4':  ('6', '40'),\n  'M5':  ('8', '50'),\n  'M6':  ('10', '60'),\n  'M8': ('12', '80'),\n  'M10':('16', '90'),\n  'M12':('20', '90'),\n  'M16':('25', '90')}\n\n# ISO 7380-2 definitions\n#          P,   b,     c,   da, dk,    dk_c,s_mean,t_min, r,  k,   e,    w,\niso7380_2def={\n  'M3':  (0.50, 18.0, 0.7,  3.6,  5.2,  6.9, 2.03, 1.04, 0.1, 1.65, 2.3,  0.2),\n  'M4':  (0.70, 20.0, 0.8,  4.7,  7.2,  9.4, 2.54, 1.30, 0.2, 2.20, 2.87, 0.3),\n  'M5':  (0.80, 22.0, 1.0,  5.7,  8.8, 11.8, 3.05, 1.56, 0.2, 2.75, 3.44, 0.38),\n  'M6':  (1.00, 24.0, 1.2,  6.8, 10.0, 13.6, 4.05, 2.08, 0.25,3.3,  4.58, 0.74),\n  'M8':  (1.25, 28.0, 1.5,  9.2, 13.2, 17.8, 5.05, 2.60, 0.4, 4.4,  5.72, 1.05),\n  'M10': (1.50, 32.0, 2.0, 11.2, 16.5, 21.9, 6.05, 3.12, 0.4, 5.5,  6.86, 1.45),\n  'M12': (1.75, 36.0, 2.4, 13.7, 19.4, 26.0, 8.06, 4.16, 0.6, 6.6,  9.15, 1.63),\n  'M16': (2.00, 44.0, 2.8, 17.7, 26.0, 34.0, 10.06,5.20, 0.6, 8.8, 11.43, 2.25)\n  }\n\n\n# DIN 967 definitions: Cross recessed pan head screw with collar\n#          P,   b,     c,   da,   dk,   r,  k,    rf,  x,    cT,  mH,   mZ\ndin967def={\n  'M3':  (0.50, 25.0, 0.7,  3.6,  7.5, 0.1, 2.35,  3.8, 1.25, '1', 3.0, 2.9),\n  '(M3.5)':(0.60, 38.0, 0.8,  4.1,  9.0, 0.1, 2.60,  4.6, 1.5,  '2', 4.2, 3.9),\n  'M4':  (0.70, 38.0, 1.0,  4.7, 10.0, 0.2, 3.05,  5.8, 1.75, '2', 4.6, 4.3),\n  'M5':  (0.80, 38.0, 1.2,  5.7, 11.5, 0.2, 3.55,  6.6, 2.0,  '2', 5.0, 4.7),\n  'M6':  (1.00, 38.0, 1.6,  6.8, 14.5, 0.25,4.55,  8.2, 2.5,  '3', 7.1, 6.7),\n  'M8':  (1.25, 38.0, 2.0,  9.2, 19.0, 0.4, 5.90, 11.0, 3.2,  '4', 9.0, 8.8)\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\ndin967range = {\n  'M3':  ('4', '30'),\n  '(M3.5)':  ('5', '35'),\n  'M4':  ('5', '40'),\n  'M5':  ('6', '45'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '60')\n}\n# Button Head Screw\n# nom length: l_min, l_max\ndin967length = {\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.05, 55.95),\n  '60':(59.05, 60.95)\n  }\n\n\nL_iso2009length =['2.5','3','4','5','6','8','10','12','14','16','20', \\\n   '25','30','35','40','45','50','55','60','65','70','75','80']\n# nom length: l_min, l_max\niso2009length = {\n  '2.5':(2.3,  2.7),\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.05, 55.95),\n  '60':(59.05, 60.95),\n  '65':(64.05, 65.95),\n  '70':(69.05, 70.95),\n  '75':(74.05, 75.95),\n  '80':(79.05, 80.95)\n  }\n\n\n# ISO 2009 definitions Class A\n#          P, a, b, dk_theo, dk_mean, k, n_min, r, t_mean, x\niso2009def={\n   'M1.6':(0.35, 0.7, 25, 3.6, 2.8,  1.0,  0.46, 0.2, 0.4, 0.9),\n   'M2':  (0.40, 0.8, 25, 4.4, 3.6,  1.2,  0.56, 0.3, 0.5, 1.0),\n   'M2.5':(0.45, 0.9, 25, 5.5, 4.5,  1.5,  0.66, 0.3, 0.6, 1.1),\n   'M3':  (0.50, 1.0, 25, 6.3, 5.3,  1.65, 0.86, 0.4, 0.7, 1.25),\n   '(M3.5)':(0.60, 1.2, 38, 8.2, 7.1,  2.35, 1.06, 0.4, 1.0, 1.5),\n   'M4':  (0.70, 1.4, 38, 9.4, 8.2,  2.7,  1.26, 0.5, 1.1, 1.75),\n   'M5':  (0.80, 1.6, 38,10.4, 9.2,  2.7,  1.26, 0.6, 1.2, 2.0),\n   'M6':  (1.00, 2.0, 38,12.6, 11.2, 3.3,  1.66, 0.7, 1.4, 2.5),\n   'M8':  (1.25, 2.5, 38,17.3, 15.6, 4.65, 2.06, 1.0, 2.0, 3.2),\n   'M10': (1.50, 3.0, 38,20.0, 18.1, 5.0,  2.56, 1.2, 2.3, 3.8)}\n\n# range of typical screw lengths\n#    min_length,  max_length\niso2009range = {\n  'M1.6':('2.5', '16'),\n  'M2':  ('3', '20'),\n  'M2.5':('4', '25'),\n  'M3':  ('5', '30'),\n  '(M3.5)':('6', '35'),\n  'M4':  ('6', '40'),\n  'M5':  ('8', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '80'),\n  'M10':('12', '80')}\n\n\n# ISO 7046 definitions Class A\n# ISO 7046 Countersunk flat head screws (common head style)\n# with type H or type Z cross recess\n# Parameters P, a, b, dk_theo, dk_mean, k, r, x to be read from iso2009def\n# Length = iso7045length\n#          cT,   mH,   mZ\niso7046def={\n  'M1.6':('0', 1.6, 1.6),\n  'M2':  ('0', 1.9, 1.9),\n  'M2.5':('1', 2.9, 2.8),\n  'M3':  ('1', 3.2, 3.0),\n  '(M3.5)':('2', 4.4, 4.1),\n  'M4':  ('2', 4.6, 4.4),\n  'M5':  ('2', 5.2, 4.0),\n  'M6':  ('3', 6.8, 6.6),\n  'M8':  ('4', 8.9, 8.8),\n  'M10': ('4', 10.0,9.8)}\n\n# range of typical screw lengths\n#    min_length,  max_length\niso7046range = {\n  'M1.6':('3', '16'),\n  'M2':  ('3', '20'),\n  'M2.5':('3', '25'),\n  'M3':  ('4', '30'),\n  '(M3.5)':('5', '35'),\n  'M4':  ('5', '40'),\n  'M5':  ('6', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '60'),\n  'M10':('12', '60')}\n\n# ISO 2010, ISO 7047 definitions Class A: Raised Countersunk head screws\n# ISO 2010 slotted screws (common head style)   range = iso2009range\n# ISO 7047  with type H or type Z cross recess  range = iso7046range\n# Parameters P, a, b, dk_theo, dk_mean, k, r, x to be read from iso2009def\n# Length = iso7045length\n#          rf, t_mean, cT,   mH,   mZ\nRaised_countersunk_def={\n  'M1.6':(3.0,  0.7, '0', 1.9,  1.9),\n  'M2':  (4.0,  0.9, '0', 2.0,  2.2),\n  'M2.5':(5.0,  1.1, '1', 3.0,  2.8),\n  'M3':  (6.0,  1.3, '1', 3.4,  3.1),\n  '(M3.5)':(8.5,  1.5, '2', 4.8,  4.6),\n  'M4':  (9.5,  1.8, '2', 5.2,  5.0),\n  'M5':  (9.5,  2.2, '2', 5.4,  5.3),\n  'M6':  (12.0, 2.6, '3', 7.3,  7.1),\n  'M8':  (16.5, 3.5, '4', 9.6,  9.5),\n  'M10': (19.5, 4.1, '4', 10.4,10.3)}\n\n\n\n# ISO 14582 definitions\n#          P,    a,    b, dk_theo, dk_mean,k,   r,  tt, A, t_mean\niso14582def={\n  'M3':  (0.50, 1.0, 18.0,  7.40,  6.5, 2.20, 0.10, 'T10', 2.80, 1.1),\n  'M4':  (0.70, 1.4, 20.0, 10.02,  9.0, 3.01, 0.20, 'T20', 3.95, 1.6),\n  'M5':  (0.80, 1.6, 22.0, 12.00, 10.8, 3.50, 0.20, 'T25', 4.50, 1.8),\n  'M6':  (1.00, 2.0, 24.0, 14.44, 13.1, 4.22, 0.25, 'T30', 5.60, 2.2),\n  'M8':  (1.25, 2.5, 28.0, 19.38, 17.8, 5.69, 0.40, 'T45', 7.93, 2.8),\n  'M10': (1.50, 3.0, 32.0, 23.00, 21.1, 6.50, 0.40, 'T50', 8.95, 3.3)}\n\n# range of typical screw lengths\n#    min_length,  max_length\niso14582range = {\n  'M3':  ('8', '30'),\n  'M4':  ('8', '40'),\n  'M5':  ('8', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '80'),\n  'M10':('12', '100')}\n\n# nom length: l_min, l_max\niso14582length = {\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '90':(89.3, 90.7),\n  '100':(99.3, 100.7)\n  }\n\n\n\n# ISO 1580 definitions Class A, Slotted pan head screws\n#           P,    a,   b, dk_max,da,  k, n_min,  r,  rf, t_mean, x\niso1580def={\n  'M1.6':(0.35, 0.7, 25,  3.2, 2.0, 1.0, 0.46, 0.1, 0.5, 0.4, 0.9),\n  'M2':  (0.4,  0.8, 25,  4.0, 2.6, 1.3, 0.56, 0.1, 0.6, 0.5, 1.0),\n  'M2.5':(0.45, 0.9, 25,  5.0, 3.1, 1.5, 0.66, 0.1, 0.8, 0.6, 1.1),\n  'M3':  (0.5,  1.0, 25,  5.6, 3.6, 1.8, 0.86, 0.1, 0.9, 0.7, 1.25),\n  '(M3.5)':(0.6,  1.2, 38,  7.0, 4.1, 2.1, 1.06, 0.1, 1.0, 0.8, 1.5),\n  'M4':  (0.7,  1.4, 38,  8.0, 4.7, 2.4, 1.26, 0.2, 1.2, 1.0, 1.75),\n  'M5':  (0.8,  1.6, 38,  9.5, 5.7, 3.0, 1.26, 0.2, 1.5, 1.2, 2.0),\n  'M6':  (1.0,  2.0, 38, 12.0, 6.8, 3.6, 1.66, 0.25,1.8, 1.4, 2.5),\n  'M8':  (1.25, 2.5, 38, 16.0, 9.2, 4.8, 2.06, 0.4, 2.4, 1.9, 3.2),\n  'M10': (1.50, 3.0, 38, 20.0,11.2, 6.0, 2.56, 0.4, 3.0, 2.4, 3.8)}\n\n\n\n# ISO 7045 definitions Class A, Pan head screws with type H or type Z\n# partly used also for ISO 14583 Hexalobular socket pan head screws\n#   cross recess; cT = size of cross recess\n#           P,    a,   b, dk_max,da,  k,   r,   rf,  x,  cT,   mH,   mZ\niso7045def={\n  'M1.6':(0.35, 0.7, 25,  3.2, 2.0, 1.3, 0.1, 2.5, 0.9, '0', 1.7, 1.6),\n  'M2':  (0.4,  0.8, 25,  4.0, 2.6, 1.6, 0.1, 3.2, 1.0, '0', 1.9, 2.1),\n  'M2.5':(0.45, 0.9, 25,  5.0, 3.1, 2.1, 0.1, 4.0, 1.1, '1', 2.7, 2.6),\n  'M3':  (0.5,  1.0, 25,  5.6, 3.6, 2.4, 0.1, 5.0, 1.25,'1', 3.0, 2.8),\n  '(M3.5)':(0.6,  1.2, 38,  7.0, 4.1, 2.6, 0.1, 6.0, 1.5, '2', 3.9, 3.9),\n  'M4':  (0.7,  1.4, 38,  8.0, 4.7, 3.1, 0.2, 6.5, 1.75,'2', 4.4, 4.3),\n  'M5':  (0.8,  1.6, 38,  9.5, 5.7, 3.7, 0.2, 8.0, 2.0, '2', 4.9, 4.7),\n  'M6':  (1.0,  2.0, 38, 12.0, 6.8, 4.6, 0.25,10., 2.5, '3', 6.9, 6.7),\n  'M8':  (1.25, 2.5, 38, 16.0, 9.2, 6.0, 0.4, 13., 3.2, '4', 9.0, 8.8),\n  'M10': (1.50, 3.0, 38, 20.0,11.2, 7.5, 0.4, 16., 3.8, '4', 10.1,9.9)}\n\n# nom length: l_min, l_max\niso7045length = {\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.05, 55.95),\n  '60':(59.05, 60.95)\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso7045range = {\n  'M1.6':('3', '16'),\n  'M2':  ('3', '20'),\n  'M2.5':('3', '25'),\n  'M3':  ('4', '30'),\n  '(M3.5)':('5', '35'),\n  'M4':  ('5', '40'),\n  'M5':  ('6', '45'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '60'),\n  'M10':('12', '60')}\n\n\n# ISO 14583 Hexalobular socket pan head screws\n#   hexalobular recess;    tt = size of hexalobular recess\n\n#           tt,    A,  t_mean\niso14583def={\n  'M2':  ('T6',  1.75, 0.7),\n  'M2.5':('T8',  2.40, 1.0),\n  'M3':  ('T10', 2.80, 1.2),\n  '(M3.5)':('T15', 3.35, 1.3),\n  'M4':  ('T20', 3.95, 1.5),\n  'M5':  ('T25', 4.50, 1.7),\n  'M6':  ('T30', 5.60, 2.2),\n  'M8':  ('T45', 7.95, 3.0),\n  'M10': ('T50', 8.95, 3.8)}\n\n\n#iso14583range = iso7046range\n#iso14583length = iso7045length\n\n# ISO 14584 Hexalobular socket raised countersunk head screws\n#           P,   b, dk_theo, dk_mean, f,  k,   r,   rf,    x,    tt,    A,  t_mean\niso14584def={\n  'M2':  (0.40, 25.0,  4.4,  3.8,  0.5, 1.20, 0.2,  4.0, 1.00, 'T6',  1.75, 0.7),\n  'M2.5':(0.45, 25.0,  5.5,  4.7,  0.6, 1.50, 0.3,  5.0, 1.10, 'T8',  2.40, 1.0),\n  'M3':  (0.50, 25.0,  6.3,  5.5,  0.7, 1.65, 0.4,  6.0, 1.25, 'T10', 2.80, 1.2),\n  '(M3.5)':(0.60, 38.0,  8.2,  7.3,  0.8, 2.35, 0.4,  8.5, 1.50, 'T15', 3.35, 1.3),\n  'M4':  (0.70, 38.0,  9.4,  8.4,  1.0, 2.70, 0.5,  9.5, 1.75, 'T20', 3.95, 1.5),\n  'M5':  (0.80, 38.0, 10.4,  9.3,  1.2, 2.70, 0.6,  9.5, 2.00, 'T25', 4.50, 1.7),\n  'M6':  (1.00, 38.0, 12.6, 11.3,  1.4, 3.30, 0.7, 12.0, 2.50, 'T30', 5.60, 2.2),\n  'M8':  (1.25, 38.0, 17.3, 15.8,  2.0, 4.65, 1.0, 16.5, 3.20, 'T45', 7.95, 3.0),\n  'M10': (1.50, 38.0, 20.0, 18.3,  2.3, 5.00, 1.2, 19.5, 3.80, 'T50', 8.95, 3.8)}\n\n\n# range of typical screw lengths\n#    min_length,  max_length\niso14584range = {\n  'M2':  ('3', '20'),\n  'M2.5':('3', '25'),\n  'M3':  ('4', '30'),\n  '(M3.5)':('5', '35'),\n  'M4':  ('5', '40'),\n  'M5':  ('6', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '60'),\n  'M10':('12', '60')}\n\n#iso14584length = iso7045length\n\n\n# ISO 4762 Hexagon socket head cap screws (Allen screw)\n# ISO 4762 definitions\n#           P,   b,  dk_max,  da,  ds_min,   e,    lf,   k,   r,   s_mean, t,    v,   dw,   w\niso4762def={\n  'M1.6':(0.35,  15.0,  3.0,  2.0,  1.46,  1.73, 0.34,  1.6, 0.1,  1.56,  0.7, 0.16, 2.72, 0.55),\n  'M2':  (0.40,  16.0,  3.8,  2.6,  1.86,  1.73, 0.51,  2.0, 0.1,  1.56,  1.0, 0.2,  3.48, 0.55),\n  'M2.5':(0.45,  17.0,  4.5,  3.1,  2.36,  2.30, 0.51,  2.5, 0.1,  2.06,  1.1, 0.25, 4.18, 0.85),\n  'M3':  (0.50,  18.0,  5.5,  3.6,  2.86,  2.87, 0.51,  3.0, 0.1,  2.56,  1.3, 0.3,  5.07, 1.15),\n  'M4':  (0.70,  20.0,  7.0,  4.7,  3.82,  3.44, 0.60,  4.0, 0.2,  3.06,  2.0, 0.4,  6.53, 1.40),\n  'M5':  (0.80,  22.0,  8.5,  5.7,  4.82,  4.58, 0.60,  5.0, 0.2,  4.06,  2.5, 0.5,  8.03, 1.9),\n  'M6':  (1.00,  24.0, 10.0,  6.8,  5.82,  5.72, 0.68,  6.0, 0.25, 5.06,  3.0, 0.6,  9.38, 2.3),\n  'M8':  (1.25,  28.0, 13.0,  9.2,  7.78,  6.86, 1.02,  8.0, 0.4,  6.06,  4.0, 0.8, 12.33, 3.3),\n  'M10': (1.50,  32.0, 16.0, 11.2,  9.78,  9.15, 1.02, 10.0, 0.4,  8.07,  5.0, 1.0, 15.33, 4.0),\n  'M12': (1.75,  36.0, 18.0, 13.7, 11.73, 11.43, 1.45, 12.0, 0.6, 10.07,  6.0, 1.2, 17.23, 4.8),\n  '(M14)':(2.00,  40.0, 21.0, 15.7, 13.73, 13.72, 1.45, 14.0, 0.6, 12.07,  7.0, 1.4, 20.17, 5.8),\n  'M16': (2.00,  44.0, 24.0, 17.7, 15.73, 16.00, 1.45, 16.0, 0.6, 14.08,  8.0, 1.6, 23.17, 6.8),\n  'M20': (2.50,  52.0, 30.0, 22.4, 19.67, 19.44, 2.04, 20.0, 0.8, 17.10, 10.0, 2.0, 28.87, 8.6),\n  'M24': (3.00,  60.0, 36.0, 26.4, 23.67, 21.73, 2.04, 24.0, 0.8, 19.15, 12.0, 2.0, 34.81, 10.4),\n  'M30': (3.50,  72.0, 45.0, 33.4, 29.67, 25.15, 2.89, 30.0, 1.0, 22.15, 15.5, 2.4, 43.61, 13.1),\n  'M36': (4.00,  84.0, 54.0, 39.4, 35.61, 30.85, 2.89, 36.0, 1.0, 27.15, 19.0, 3.0, 52.54, 15.3),\n  'M42': (4.50,  96.0, 63.0, 45.6, 41.61, 36.58, 3.06, 42.0, 1.2, 32.15, 24.0, 4.2, 61.34, 16.3),\n  'M48': (5.00, 108.0, 72.0, 52.6, 47.61, 41.14, 3.91, 48.0, 1.6, 36.15, 28.0, 4.8, 70.34, 17.5),\n  'M56': (5.50, 124.0, 84.0, 63.0, 55.54, 46.84, 5.95, 56.0, 2.0, 41.15, 34.0, 5.6, 82.26, 19.0),\n  'M64': (6.00, 140.0, 96.0, 71.0, 63.54, 52.54, 5.95, 64.0, 2.0, 46.15, 38.0, 6.4, 94.26, 22.0)\n  }\n\n# nom length: l_min, l_max\niso4762length = {\n  '2.5':(2.3,  2.7),\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '14':(13.65, 14.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '75':(74.4, 75.6),\n  '80':(79.4, 80.6),\n  '100':(99.3, 100.7),\n  '110':(109.3, 110.7),\n  '120':(119.3, 120.7),\n  '130':(129.2, 130.8),\n  '140':(139.2, 130.8),\n  '150':(149.2, 150.8),\n  '160':(159.2, 160.8),\n  '180':(179.2, 180.8),\n  '200':(199.1, 200.9),\n  '220':(219.1, 220.9),\n  '240':(237.7, 242.3),\n  '260':(219.1, 220.9),\n  '280':(219.1, 220.9),\n  '300':(219.1, 220.9)\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso4762range = {\n  'M1.6':('2.5', '16'),\n  'M2':  ('3', '20'),\n  'M2.5':('4', '25'),\n  'M3':  ('5', '30'),\n  '(M3.5)':('6', '35'),\n  'M4':  ('6', '40'),\n  'M5':  ('8', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '80'),\n  'M10':('16', '100'),\n  'M12':('20', '120'),\n  '(M14)':('25', '140'),\n  'M16':('25', '160'),\n  'M20':('16', '100'),\n  'M24':('40', '200'),\n  'M30':('45', '200'),\n  'M36':('55', '200'),\n  'M42':('60', '300'),\n  'M48':('100','300'),\n  'M56':('110','300'),\n  'M64':('120','300')\n  }\n\n\n# ISO 14579 Hexalobular socket head cap screws\n#   hexalobular recess;    tt = size of hexalobular recess\n\n#           tt,    A,  t_mean\niso14579def={\n  'M2':  ( 'T6',  1.75, 0.8),\n  'M2.5':( 'T8',  2.40, 1.0),\n  'M3':  ('T10',  2.80, 1.2),\n  'M4':  ('T20',  3.95, 1.7),\n  'M5':  ('T25',  4.50, 1.9),\n  'M6':  ('T30',  5.60, 2.3),\n  'M8':  ('T45',  7.95, 3.2),\n  'M10': ('T50',  8.95, 3.8),\n  'M12': ('T55', 11.35, 5.0),\n  '(M14)': ('T60', 13.45, 5.8),\n  'M16': ('T70', 15.70, 6.8),\n  '(M18)': ('T80', 17.75, 7.8),\n  'M20': ('T90', 20.20, 9.0),\n  }\n\n# range of typical screw lengths\n#    min_length,  max_length\niso14579range = {\n  'M2':  ('3', '20'),\n  'M2.5':('4', '25'),\n  'M3':  ('5', '30'),\n  'M4':  ('6', '40'),\n  'M5':  ('8', '50'),\n  'M6': ('10', '60'),\n  'M8': ('12', '80'),\n  'M10':('16','100'),\n  'M12':('20','120'),\n  '(M14)':('25','140'),\n  'M16':('25','160'),\n  '(M18)':('30','180'),\n  'M20':('30','200'),\n  }\n\niso14579length = {\n  '3': ( 2.8,  3.2),\n  '4': ( 3.76, 4.24),\n  '5': ( 4.76, 5.24),\n  '6': ( 5.76, 6.24),\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '90':(89.3, 90.7),\n  '100':(99.3, 100.7),\n  '110':(109.3, 110.7),\n  '120':(119.3, 120.7),\n  '130':(129.2, 130.8),\n  '140':(139.2, 130.8),\n  '150':(149.2, 150.8),\n  '160':(159.2, 160.8),\n  '180':(179.2, 180.8),\n  '200':(199.1, 200.9)\n  }\n\n\n# ISO 10642 Hexagon socket countersunk head screws (Allen screw)\n# ISO 10642 definitions\n#           P,   b,  dk_theo, dk_mean,da,  ds_min,   e,  k,   r,   s_mean, t,    w\niso10642def={\n  'M3':  (0.50, 18.0,  6.72,  6.0,  3.3,  2.86,  2.31, 1.86, 0.1,  2.06,  1.1, 0.25),\n  'M4':  (0.70, 20.0,  8.96,  8.0,  4.4,  3.82,  2.88, 2.48, 0.2,  2.56,  1.5, 0.45),\n  'M5':  (0.80, 22.0, 11.20, 10.0,  5.5,  4.82,  3.45, 3.10, 0.2,  3.06,  1.9, 0.66),\n  'M6':  (1.00, 24.0, 13.44, 12.0,  6.6,  5.82,  4.59, 3.72, 0.25, 4.06,  2.2, 0.70),\n  'M8':  (1.25, 28.0, 17.92, 16.0,  8.54, 7.78,  5.73, 4.96, 0.4,  5.06,  3.0, 1.16),\n  'M10': (1.50, 32.0, 22.40, 20.5, 10.62, 9.78,  6.87, 6.20, 0.4,  6.06,  3.6, 1.62),\n  'M12': (1.75, 36.0, 26.88, 25.0, 13.5, 11.73,  9.15, 7.44, 0.6,  8.07,  4.3, 1.80),\n  '(M14)': (2.00, 40.0, 30.80, 28.4, 15.5, 13.73, 11.43, 8.40, 0.6, 10.07,  4.5, 1.62),\n  'M16': (2.00, 44.0, 33.60, 31.0, 17.5, 15.73, 11.43, 8.80, 0.6, 10.07,  4.8, 2.20),\n  'M20': (2.50, 52.0, 40.32, 38.0, 22.0, 19.67, 13.72, 10.16, 0.8, 12.10,  5.6, 2.20)}\n\n# range of typical screw lengths\n#    min_length,  max_length\niso10642range = {\n  'M3':  ('8', '30'),\n  'M4':  ('8', '40'),\n  'M5':  ('8', '50'),\n  'M6':  ('8', '60'),\n  'M8': ('10', '80'),\n  'M10':('12','100'),\n  'M12':('20','100'),\n  '(M14)':('25','100'),\n  'M16':('30','100'),\n  'M20':('35','100'),\n  }\n\niso10642length = {\n  '8': ( 7.71, 8.29),\n  '10':( 9.71, 10.29),\n  '12':(11.65, 12.35),\n  '16':(15.65, 16.35),\n  '20':(19.58, 20.42),\n  '25':(24.58, 25.42),\n  '30':(29.58, 30.42),\n  '35':(34.5,  35.5),\n  '40':(39.5,  40.5),\n  '45':(44.5,  45.5),\n  '50':(49.5,  50.5),\n  '55':(54.4, 55.6),\n  '60':(59.4, 60.6),\n  '65':(64.4, 65.6),\n  '70':(69.4, 70.6),\n  '80':(79.4, 80.6),\n  '90':(89.3, 90.7),\n  '100':(99.3, 100.7),\n  }\n\n\n# ISO 7089 definitions Washer\n#           d1_min, d2_max, h, h_max\niso7089def={\n  'M1.6':( 1.7,  4.0, 0.3, 0.35),\n  'M2':  ( 2.2,  5.0, 0.3, 0.35),\n  'M2.5':( 2.7,  6.0, 0.5, 0.55),\n  'M3':  ( 3.2,  7.0, 0.5, 0.55),\n  'M4':  ( 4.3,  9.0, 0.8, 0.90),\n  'M5':  ( 5.3, 10.0, 1.0, 1.10),\n  'M6':  ( 6.4, 12.0, 1.6, 1.80),\n  'M8':  ( 8.4, 16.0, 1.6, 1.80),\n  'M10': (10.5, 20.0, 2.0, 2.20),\n  'M12': (13.0, 24.0, 2.5, 2.70),\n  'M16': (17.0, 30.0, 3.0, 3.30),\n  'M20': (21.0, 37.0, 3.0, 3.30),\n  'M24': (25.0, 44.0, 4.0, 4.30),\n  'M30': (31.0, 56.0, 4.0, 4.30),\n  'M36': (37.0, 66.0, 5.0, 5.60),\n  'M42': (45.0, 78.0, 8.0, 9.0),\n  'M48': (52.0, 92.0, 8.0, 9.0),\n  'M56': (62.0,105.0,10.0, 11.0),\n  'M64': (70.0,115.0,10.0, 11.0)\n  }\n\n\n# ISO 7090 definitions Plain washers, chamfered - Normal series\n# chamfer angle 30\u00b0 / 45\u00b0\n# chamfer      h/4 / h/2\n#           d1_min, d2_max, h, h_max\niso7090def={\n  'M5':  ( 5.3, 10.0, 1.0, 1.10),\n  'M6':  ( 6.4, 12.0, 1.6, 1.80),\n  'M8':  ( 8.4, 16.0, 1.6, 1.80),\n  'M10': (10.5, 20.0, 2.0, 2.20),\n  'M12': (13.0, 24.0, 2.5, 2.70),\n  'M16': (17.0, 30.0, 3.0, 3.30),\n  'M20': (21.0, 37.0, 3.0, 3.30),\n  'M24': (25.0, 44.0, 4.0, 4.30),\n  'M30': (31.0, 56.0, 4.0, 4.30),\n  'M36': (37.0, 66.0, 5.0, 5.60),\n  'M42': (45.0, 78.0, 8.0, 9.0),\n  'M48': (52.0, 92.0, 8.0, 9.0),\n  'M56': (62.0,105.0,10.0, 11.0),\n  'M64': (70.0,115.0,10.0, 11.0)\n  }\n\n\n# ISO 7091 definitions  Plain washer - Normal series Product Grade C\n#           d1_min, d2_max, h, h_max\niso7091def={\n  'M1.6':( 1.8,  4.0, 0.3, 0.35),\n  'M2':  ( 2.4,  5.0, 0.3, 0.35),\n  'M2.5':( 2.9,  6.0, 0.5, 0.55),\n  'M3':  ( 3.4,  7.0, 0.5, 0.55),\n  'M4':  ( 4.5,  9.0, 0.8, 0.90),\n  'M5':  ( 5.5, 10.0, 1.0, 1.10),\n  'M6':  ( 6.6, 12.0, 1.6, 1.80),\n  'M8':  ( 9.0, 16.0, 1.6, 1.80),\n  'M10': (11.0, 20.0, 2.0, 2.20),\n  'M12': (13.5, 24.0, 2.5, 2.70),\n  'M16': (17.5, 30.0, 3.0, 3.30),\n  'M20': (22.0, 37.0, 3.0, 3.30),\n  'M24': (26.0, 44.0, 4.0, 4.30),\n  'M30': (33.0, 56.0, 4.0, 4.30),\n  'M36': (39.0, 66.0, 5.0, 5.60),\n  'M42': (45.0, 78.0, 8.0, 9.0),\n  'M48': (52.0, 92.0, 8.0, 9.0),\n  'M56': (62.0,105.0,10.0, 11.0),\n  'M64': (70.0,115.0,10.0, 11.0)\n  }\n\n\n# ISO 7092 definitions  Plain washers - Small series\n#           d1_min, d2_max, h, h_max\niso7092def={\n  'M1.6':( 1.7,  3.5, 0.3, 0.35),\n  'M2':  ( 2.2,  4.5, 0.3, 0.35),\n  'M2.5':( 2.7,  5.0, 0.5, 0.55),\n  'M3':  ( 3.2,  6.0, 0.5, 0.55),\n  'M4':  ( 4.3,  8.0, 0.5, 0.55),\n  'M5':  ( 5.3,  9.0, 1.0, 1.10),\n  'M6':  ( 6.4, 11.0, 1.6, 1.80),\n  'M8':  ( 8.4, 15.0, 1.6, 1.80),\n  'M10': (10.5, 18.0, 1.6, 1.80),\n  'M12': (13.0, 20.0, 2.0, 2.20),\n  'M16': (17.0, 28.0, 2.5, 2.70),\n  'M20': (21.0, 34.0, 3.0, 3.30),\n  'M24': (25.0, 39.0, 4.0, 4.30),\n  'M30': (31.0, 50.0, 4.0, 4.30),\n  'M36': (37.0, 60.0, 5.0, 5.60)\n  }\n\n\n\n# ISO 7093-1 definitions  Plain washers - Large series\n#           d1_min, d2_max, h, h_max\niso7093def={\n  'M3':    ( 3.2,  9.0, 0.8, 0.90),\n  '(M3.5)':( 3.7, 11.0, 0.8, 0.90),\n  'M4':    ( 4.3, 12.0, 1.0, 1.10),\n  'M5':    ( 5.3, 15.0, 1.0, 1.10),\n  'M6':    ( 6.4, 18.0, 1.6, 1.80),\n  'M8':    ( 8.4, 24.0, 2.0, 2.20),\n  'M10':   (10.5, 30.0, 2.5, 2.70),\n  'M12':   (13.0, 37.0, 3.0, 3.30),\n  '(M14)': (15.0, 44.0, 3.0, 3.30),\n  'M16':   (17.0, 50.0, 3.0, 3.30),\n  '(M18)': (19.0, 56.0, 4.0, 4.30),\n  'M20':   (21.0, 60.0, 4.0, 4.30),\n  '(M22)': (23.0, 66.0, 5.0, 5.60),\n  'M24':   (25.0, 72.0, 5.0, 5.60),\n  '(M27)': (30.0, 85.0, 6.0, 6.60),\n  'M30':   (33.0, 92.0, 6.0, 6.60),\n  '(M33)': (36.0,105.0, 6.0, 6.60),\n  'M36':   (39.0,110.0, 8.0, 9.00)\n  }\n\n\n# ISO 7094 definitions  Plain washers - Extra large series\n#           d1_min, d2_max, h, h_max\niso7094def={\n  'M5':    ( 5.5, 18.0, 2.0, 2.3),\n  'M6':    ( 6.6, 22.0, 2.0, 2.3),\n  'M8':    ( 9.0, 28.0, 3.0, 3.6),\n  'M10':   (11.0, 34.0, 3.0, 3.6),\n  'M12':   (13.5, 44.0, 4.0, 4.6),\n  '(M14)': (15.5, 50.0, 4.0, 4.6),\n  'M16':   (17.5, 56.0, 5.0, 6.0),\n  '(M18)': (20.0, 60.0, 5.0, 6.0),\n  'M20':   (22.0, 72.0, 6.0, 7.0),\n  '(M22)': (24.0, 80.0, 6.0, 7.0),\n  'M24':   (26.0, 85.0, 6.0, 7.0),\n  '(M27)': (30.0, 98.0, 6.0, 7.0),\n  'M30':   (33.0,105.0, 6.0, 7.0),\n  '(M33)': (36.0,115.0, 8.0, 9.2),\n  'M36':   (39.0,125.0, 8.0, 9.2)\n  }\n\n\n\n\n# ISO 4757:1983 Definition of cross recess type H\n#          b, e_min, g, f_mean, r, t1, alpha, beta\niso4757def = {\n  '0': (0.61, 0.26, 0.81, 0.34, 0.3, 0.22, 138.0, 7.0 ),\n  '1': (0.97, 0.41, 1.27, 0.54, 0.5, 0.34, 138.0, 7.0 ),\n  '2': (1.47, 0.79, 2.29, 0.70, 0.6, 0.61, 140.0, 5.75),\n  '3': (2.41, 1.98, 3.81, 0.83, 0.8, 1.01, 146.0, 5.75),\n  '4': (3.48, 2.39, 5.08, 1.23, 1.0, 1.35, 153.0, 7.0 )\n  }\n\n# ISO 10664 Hexalobular internal driving feature for bolts and screws\n#           A,     B,   Re\niso10664def = {\n  'T6': ( 1.75,  1.205, 0.14),\n  'T8': ( 2.40,  1.67, 0.20),\n  'T10':( 2.80,  1.98, 0.24),\n  'T15':( 3.35,  2.35, 0.28),\n  'T20':( 3.95,  2.75, 0.32),\n  'T25':( 4.50,  3.16, 0.39),\n  'T30':( 5.60,  3.95, 0.46),\n  'T40':( 6.75,  4.76, 0.56),\n  'T45':( 7.93,  5.55, 0.59),\n  'T50':( 8.95,  6.36, 0.78),\n  'T55':(11.35,  7.92, 0.77),\n  'T60':(13.45,  9.48, 1.07),\n  'T70':(15.70, 11.08, 1.20),\n  'T80':(17.75, 12.64, 1.53),\n  'T90':(20.20, 14.22, 1.54),\n  'T100':(22.40,15.81, 1.73)\n  }\n\n\n\n# ISO 4032 Hex-head-nut\n#           P,   c,  damax, dw,    e,     m,  mw,  s_nom\niso4032def={\n  'M1.6':  (0.35, 0.2, 1.84, 2.9,  3.4,   1.3, 0.8,  3.2),\n  'M2':    (0.40, 0.2, 2.3,  3.7,  4.4,   1.6, 1.1,  4.0),\n  'M2.5':  (0.45, 0.2, 2.9,  4.6,  5.5,   2.0, 1.4,  5.0),\n  'M3':    (0.5,  0.2, 3.45, 5.2,  6.1,   2.4, 1.7,  5.5),\n  '(M3.5)':(0.6,  0.2, 4.00, 5.7,  6.6,   2.8, 2.0,  6.0),\n  'M4':    (0.7,  0.2, 4.6,  6.6,  7.7,   3.2, 2.3,  7.0),\n  'M5':    (0.8,  0.2, 5.75, 7.5,  8.9,   3.5, 3.5,  8.0),\n  'M6':    (1.0,  0.2, 6.75, 9.5,  11.05, 4.7, 3.9, 10.0),\n  'M8':    (1.25, 0.3, 8.75, 11.7, 14.5,  6.8, 5.2, 13.0),\n  'M10':   (1.50, 0.3, 10.8, 14.7, 17.9,  8.4, 6.4,  16.0),\n  'M12':   (1.75, 0.3, 13.0, 16.7, 20.1, 10.8, 8.3,  18.0),\n  '(M14)': (2.00, 0.3, 15.1, 20.5, 24.5, 12.8, 9.7,  22.0),\n  'M16':   (2.00, 0.4, 17.3, 22.4, 26.9, 14.8, 11.3,  24.0),\n  '(M18)': (2.50, 0.4, 19.5, 24.9, 29.6, 15.8, 12.3,  27.0),\n  'M20':   (2.50, 0.4, 21.6, 28.2, 33.7, 18.0, 13.5,  30.0),\n  '(M22)': (2.50, 0.4, 23.7, 31.4, 37.3, 19.4, 15.0,  34.0),\n  'M24':   (3.00, 0.4, 25.9, 33.7, 40.1, 21.5, 16.2,  36.0),\n  '(M27)': (3.00, 0.4, 29.1, 38.0, 45.2, 23.8, 18.0,  41.0),\n  'M30':   (3.50, 0.4, 32.4, 42.8, 50.9, 25.6, 19.4,  46.0),\n  '(M33)': (3.50, 0.4, 35.6, 46.6, 55.4, 28.7, 21.4,  50.0),\n  'M36':   (4.00, 0.4, 38.9, 51.2, 61.0, 31.0, 23.5,  55.0),\n  '(M39)': (4.00, 0.5, 42.1, 55.9, 66.5, 33.4, 24.5,  60.0),\n  'M42':   (4.50, 0.7, 45.4, 60.0, 71.3, 34.0, 25.9,  65.0),\n  '(M45)': (4.50, 0.7, 48.6, 64.7, 77.0, 36.0, 27.9,  70.0),\n  'M48':   (5.00, 0.7, 51.8, 69.5, 82.6, 38.0, 29.1,  75.0),\n  '(M52)': (5.00, 0.7, 56.2, 74.5, 88.3, 42.0, 32.1,  80.0),\n  'M56':   (5.50, 0.7, 60.5, 78.7, 93.6, 45.0, 34.7,  85.0),\n  '(M60)': (5.50, 0.7, 64.8, 82.7, 99.2, 48.0, 38.7,  90.0),\n  'M64':   (6.00, 0.7, 69.1, 88.2,104.9, 51.0, 39.3,  95.0)\n  }\n\n\n\n# ISO 4033 Hexagon nuts style 2\n#           P,   c,  damax, dw,    e,     m,  mw,  s_nom\niso4033def={\n  'M5':    (0.8,  0.2, 5.75, 7.5,  8.9,   5.1, 3.5,  8.0),\n  'M6':    (1.0,  0.2, 6.75, 9.5,  11.05, 5.7, 3.9, 10.0),\n  'M8':    (1.25, 0.3, 8.75, 11.7, 14.5,  7.5, 5.2, 13.0),\n  'M10':   (1.50, 0.3, 10.8, 14.7, 17.9,  9.3, 6.4,  16.0),\n  'M12':   (1.75, 0.3, 13.0, 16.7, 20.1, 12.0, 8.3,  18.0),\n  '(M14)': (2.00, 0.3, 15.1, 20.5, 24.5, 14.1, 9.7,  22.0),\n  'M16':   (2.00, 0.4, 17.3, 22.4, 26.9, 16.4, 11.3,  24.0),\n  'M20':   (2.50, 0.4, 21.6, 28.2, 33.7, 20.3, 13.5,  30.0),\n  'M24':   (3.00, 0.4, 25.9, 33.7, 40.1, 23.9, 16.2,  36.0),\n  'M30':   (3.50, 0.4, 32.4, 42.8, 50.9, 28.6, 19.4,  46.0),\n  'M36':   (4.00, 0.4, 38.9, 51.2, 61.0, 33.1, 23.5,  55.0)\n  }\n\n# ISO 4035 Hexagon thin nuts, chamfered\n#           P,   c,  damax, dw,    e,     m,  mw,  s_nom\niso4035def={\n  'M1.6':  (0.35, 0.2, 1.84, 2.9,  3.4,   1.0,  0.8,  3.2),\n  'M2':    (0.40, 0.2, 2.3,  3.7,  4.4,   1.2,  1.1,  4.0),\n  'M2.5':  (0.45, 0.2, 2.9,  4.6,  5.5,   1.6,  1.4,  5.0),\n  'M3':    (0.5,  0.2, 3.45, 5.2,  6.1,   1.8,  1.7,  5.5),\n  '(M3.5)':(0.6,  0.2, 4.00, 5.7,  6.6,   2.0,  2.0,  6.0),\n  'M4':    (0.7,  0.2, 4.6,  6.6,  7.7,   2.2,  2.3,  7.0),\n  'M5':    (0.8,  0.2, 5.75, 7.5,  8.9,   2.7,  3.5,  8.0),\n  'M6':    (1.0,  0.2, 6.75, 9.5,  11.05, 3.2,  3.9, 10.0),\n  'M8':    (1.25, 0.3, 8.75, 11.7, 14.5,  4.0,  5.2, 13.0),\n  'M10':   (1.50, 0.3, 10.8, 14.7, 17.9,  5.0,  6.4, 16.0),\n  'M12':   (1.75, 0.3, 13.0, 16.7, 20.1,  6.0,  8.3, 18.0),\n  '(M14)': (2.00, 0.3, 15.1, 20.5, 24.5,  7.0,  9.7, 22.0),\n  'M16':   (2.00, 0.4, 17.3, 22.4, 26.9,  8.0, 11.3, 24.0),\n  '(M18)': (2.50, 0.4, 19.5, 24.9, 29.6,  9.0, 12.3, 27.0),\n  'M20':   (2.50, 0.4, 21.6, 28.2, 33.7, 10.0, 13.5, 30.0),\n  '(M22)': (2.50, 0.4, 23.7, 31.4, 37.3, 11.0, 15.0, 34.0),\n  'M24':   (3.00, 0.4, 25.9, 33.7, 40.1, 12.0, 16.2, 36.0),\n  '(M27)': (3.00, 0.4, 29.1, 38.0, 45.2, 13.5, 18.0, 41.0),\n  'M30':   (3.50, 0.4, 32.4, 42.8, 50.9, 15.0, 19.4, 46.0),\n  '(M33)': (3.50, 0.4, 35.6, 46.6, 55.4, 16.5, 21.4, 50.0),\n  'M36':   (4.00, 0.4, 38.9, 51.2, 61.0, 18.0, 23.5, 55.0),\n  '(M39)': (4.00, 0.5, 42.1, 55.9, 66.5, 19.5, 24.5, 60.0),\n  'M42':   (4.50, 0.7, 45.4, 60.0, 71.3, 21.0, 25.9, 65.0),\n  '(M45)': (4.50, 0.7, 48.6, 64.7, 77.0, 22.5, 27.9, 70.0),\n  'M48':   (5.00, 0.7, 51.8, 69.5, 82.6, 24.0, 29.1, 75.0),\n  '(M52)': (5.00, 0.7, 56.2, 74.5, 88.3, 26.0, 32.1, 80.0),\n  'M56':   (5.50, 0.7, 60.5, 78.7, 93.6, 28.0, 34.7, 85.0),\n  '(M60)': (5.50, 0.7, 64.8, 82.7, 99.2, 30.0, 38.7, 90.0),\n  'M64':   (6.00, 0.7, 69.1, 88.2,104.9, 32.0, 39.3, 95.0)\n  }\n\n# ISO 4036 Hexagon thin nuts, unchamfered\n#           P,      e,   m,  s_nom\niso4036def={\n  'M1.6':  (0.35,  3.4, 1.0,  3.2),\n  'M2':    (0.40,  4.4, 1.2,  4.0),\n  'M2.5':  (0.45,  5.5, 1.6,  5.0),\n  'M3':    (0.5,   6.1, 1.8,  5.5),\n  '(M3.5)':(0.6,   6.6, 2.0,  6.0),\n  'M4':    (0.7,   7.7, 2.2,  7.0),\n  'M5':    (0.8,   8.9, 2.7,  8.0),\n  'M6':    (1.0,  10.9, 3.2, 10.0),\n  'M8':    (1.25, 14.5, 4.0, 13.0),\n  'M10':   (1.50, 17.9, 5.0, 16.0)}\n\n# EN 1661 Hexagon nuts with flange\n#          P,    damax,  c,  dc,    dw,    e,     m,   mw,   r,   s\nen1661def={\n  'M5'   :(0.80,  5.75, 1.0, 11.8,  9.8,  8.79,  5.0, 2.5,  0.30,  8.0),\n  'M6'   :(1.00,  6.75, 1.1, 14.2, 12.2, 11.05,  6.0, 3.1,  0.36, 10.0),\n  'M8'   :(1.25,  8.75, 1.2, 17.9, 15.8, 14.38,  8.0, 4.6,  0.48, 13.0),\n  'M10'  :(1.50, 10.80, 1.5, 21.8, 19.6, 17.77, 10.0, 5.9,  0.60, 16.0),\n  'M12'  :(1.75, 13.00, 1.8, 26.0, 23.8, 20.03, 12.0, 6.8,  0.72, 18.0),\n  '(M14)':(2.00, 15.10, 2.1, 29.9, 27.6, 23.36, 14.0, 7.7,  0.88, 21.0),\n  'M16'  :(2.00, 17.30, 2.4, 34.5, 31.9, 26.75, 16.0, 8.9,  0.96, 24.0),\n  'M20'  :(2.50, 21.60, 3.0, 42.8, 39.9, 33.23, 20.0,10.7,  1.20, 30.0)}\n\n# Tuning table to get valid shapes\n#         P, tunIn, tunEx\ntuningTable={\n  'M1.6':(0.35, 516, 516),\n  'M2':  (0.40, 515, 516),\n  'M2.5':(0.45, 515, 515),\n  'M3':  (0.5,  480, 502),\n  '(M3.5)':(0.6,  480, 502),\n  'M4':  (0.7,  510, 519), #last value needed for ISO7380\n  'M5':  (0.8,  510, 510),\n  'M6':  (1.0,  515, 515),\n  'M8':  (1.25, 516, 516),\n  'M10': (1.50, 515, 515),\n  'M12': (1.75, 513, 513),\n  '(M14)': (2.00, 513, 513),\n  'M16': (2.00, 513, 513),\n  'M20': (2.50, 513, 513),\n  'M24': (3.00, 513, 513),\n  '(M27)': (3.00, 513, 513),\n  'M30': (3.50, 513, 513),\n  '(M33)': (3.50, 513, 513),\n  'M36': (4.00, 513, 513),\n  'M42': (4.50, 515, 515),\n  '(M45)': (4.50, 515, 515),\n  'M48': (5.00, 515, 505), # ISO4014: 505, 502 or 488; ISO4017: above 505\n  '(M52)': (5.00, 508, 508),\n  'M56': (5.50, 508, 508),\n  '(M60)': (5.50, 508, 508),\n  'M64': (6.00, 489, 489) # Nut ISO4032: 489\n  }\n\n\ndef equal_vertex(vert1, vert2, p=5):\n  # compares two vertices\n  return (round(vert1.X - vert2.X,p)==0 and round(vert1.Y - vert2.Y,p)==0 and round(vert1.Z - vert2.Z,p)==0)\n\ntry:\n  _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n  _fromUtf8 = lambda s: s\n\nclass Ui_ScrewMaker(object):\n  def setupUi(self, ScrewMaker):\n    FCUi = FreeCADGui.UiLoader()\n\n    ScrewMaker.setObjectName(_fromUtf8(\"ScrewMaker\"))\n    ScrewMaker.resize(450, 362)\n    ScrewMaker.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedKingdom))\n    self.layoutWidget = QtGui.QWidget(ScrewMaker)\n    self.layoutWidget.setGeometry(QtCore.QRect(348, 35, 102, 161))\n    self.layoutWidget.setObjectName(_fromUtf8(\"layoutWidget\"))\n    self.verticalLayout_2 = QtGui.QVBoxLayout(self.layoutWidget)\n    #self.verticalLayout_2.setMargin(0)\n    self.verticalLayout_2.setObjectName(_fromUtf8(\"verticalLayout_2\"))\n    self.ScrewTypeLabel = QtGui.QLabel(self.layoutWidget)\n    self.ScrewTypeLabel.setObjectName(_fromUtf8(\"ScrewTypeLabel\"))\n    self.verticalLayout_2.addWidget(self.ScrewTypeLabel)\n    self.NomDiaLabel = QtGui.QLabel(self.layoutWidget)\n    self.NomDiaLabel.setObjectName(_fromUtf8(\"NomDiaLabel\"))\n    self.verticalLayout_2.addWidget(self.NomDiaLabel)\n    self.NomLenLabel = QtGui.QLabel(self.layoutWidget)\n    self.NomLenLabel.setObjectName(_fromUtf8(\"NomLenLabel\"))\n    self.verticalLayout_2.addWidget(self.NomLenLabel)\n    self.UserLenLabel = QtGui.QLabel(self.layoutWidget)\n    self.UserLenLabel.setObjectName(_fromUtf8(\"UserLenLabel\"))\n    self.verticalLayout_2.addWidget(self.UserLenLabel)\n\n    self.layoutWidget1 = QtGui.QWidget(ScrewMaker)\n    self.layoutWidget1.setGeometry(QtCore.QRect(3, 35, 350, 166))\n    #self.layoutWidget1.setGeometry(QtCore.QRect(10, 5, 315, 200))\n    self.layoutWidget1.setObjectName(_fromUtf8(\"layoutWidget1\"))\n    self.verticalLayout = QtGui.QVBoxLayout(self.layoutWidget1)\n    #self.verticalLayout.setMargin(0)\n    self.verticalLayout.setObjectName(_fromUtf8(\"verticalLayout\"))\n    self.ScrewType = QtGui.QComboBox(self.layoutWidget1)\n    self.ScrewType.setObjectName(_fromUtf8(\"ScrewType\"))\n    for i in range(33):\n      self.ScrewType.addItem(_fromUtf8(\"\"))  # 0\n\n    self.verticalLayout.addWidget(self.ScrewType)\n    self.NominalDiameter = QtGui.QComboBox(self.layoutWidget1)\n    self.NominalDiameter.setObjectName(_fromUtf8(\"NominalDiameter\"))\n    for i in range(52):\n      self.NominalDiameter.addItem(_fromUtf8(\"\")) # 0\n\n    self.verticalLayout.addWidget(self.NominalDiameter)\n    self.NominalLength = QtGui.QComboBox(self.layoutWidget1)\n    self.NominalLength.setObjectName(_fromUtf8(\"NominalLength\"))\n    for i in range(48):\n      self.NominalLength.addItem(_fromUtf8(\"\")) #0\n\n    self.verticalLayout.addWidget(self.NominalLength)\n    #self.UserLen = QtGui.QComboBox(self.layoutWidget1)\n    self.UserLen = FCUi.createWidget(\"Gui::InputField\")\n    self.UserLen.setObjectName(_fromUtf8(\"UserLen\"))\n    #self.UserLen.addItem(_fromUtf8(\"\"))\n    self.UserLen.setProperty(\"text\", \"0 mm\")\n    self.verticalLayout.addWidget(self.UserLen)\n\n    #self.CommentLabel = QtGui.QLabel(self.layoutWidget)\n    self.CommentLabel = QtGui.QLabel(ScrewMaker)\n    self.CommentLabel.setObjectName(_fromUtf8(\"CommentLabel\"))\n    self.CommentLabel.setGeometry(QtCore.QRect(10, 184, 411, 21))\n    #self.verticalLayout.addWidget(self.CommentLabel)\n\n    self.layoutWidget2 = QtGui.QWidget(ScrewMaker)\n    #self.layoutWidget2.setGeometry(QtCore.QRect(10, 200, 321, 83))\n    self.layoutWidget2.setGeometry(QtCore.QRect(3, 200, 321, 120))\n    self.layoutWidget2.setObjectName(_fromUtf8(\"layoutWidget2\"))\n    self.verticalLayout_3 = QtGui.QVBoxLayout(self.layoutWidget2)\n    #self.verticalLayout_3.setMargin(0)\n    self.verticalLayout_3.setObjectName(_fromUtf8(\"verticalLayout_3\"))\n    self.SimpleScrew = QtGui.QRadioButton(self.layoutWidget2)\n    self.SimpleScrew.setChecked(True)\n    self.SimpleScrew.setObjectName(_fromUtf8(\"SimpleScrew\"))\n    self.verticalLayout_3.addWidget(self.SimpleScrew)\n    self.SymbolThread = QtGui.QRadioButton(self.layoutWidget2)\n    self.SymbolThread.setObjectName(_fromUtf8(\"SymbolThread\"))\n    self.verticalLayout_3.addWidget(self.SymbolThread)\n    self.RealThread = QtGui.QRadioButton(self.layoutWidget2)\n    self.RealThread.setObjectName(_fromUtf8(\"RealThread\"))\n    self.verticalLayout_3.addWidget(self.RealThread)\n    self.MessageLabel = QtGui.QLabel(ScrewMaker)\n    self.MessageLabel.setGeometry(QtCore.QRect(10, 10, 411, 21))\n    self.MessageLabel.setProperty(\"Empty_text\", _fromUtf8(\"\"))\n    self.MessageLabel.setObjectName(_fromUtf8(\"MessageLabel\"))\n    self.CreateButton = QtGui.QToolButton(ScrewMaker)\n    self.CreateButton.setGeometry(QtCore.QRect(180, 320, 111, 26))\n    self.CreateButton.setObjectName(_fromUtf8(\"CreateButton\"))\n    self.ScrewAvailable = True\n\n    self.simpThread = self.SimpleScrew.isChecked()\n    self.symThread = self.SymbolThread.isChecked()\n    self.rThread = self.RealThread.isChecked()\n\n    self.theScrew = Screw()\n\n    self.retranslateUi(ScrewMaker)\n    self.NominalDiameter.setCurrentIndex(5)\n    self.NominalLength.setCurrentIndex(9)\n    QtCore.QObject.connect(self.ScrewType, QtCore.SIGNAL(_fromUtf8(\"currentIndexChanged(int)\")), self.guiCheck_Data)\n    QtCore.QObject.connect(self.CreateButton, QtCore.SIGNAL(_fromUtf8(\"pressed()\")), self.guiCreateScrew)\n    QtCore.QObject.connect(self.NominalDiameter, QtCore.SIGNAL(_fromUtf8(\"currentIndexChanged(int)\")), self.guiCheck_Data)\n    QtCore.QObject.connect(self.NominalLength, QtCore.SIGNAL(_fromUtf8(\"currentIndexChanged(int)\")), self.guiCheck_Data)\n    QtCore.QMetaObject.connectSlotsByName(ScrewMaker)\n\n  def retranslateUi(self, ScrewMaker):\n    ScrewMaker.setWindowTitle(tr('ScrewMaker', 'Screw-Maker 2.2'))\n    self.ScrewTypeLabel.setText(tr('ScrewMaker', 'Type of Screw'))\n    self.NomDiaLabel.setText(tr('ScrewMaker', 'Nomimal\\nDiameter'))\n    self.NomLenLabel.setText(tr('ScrewMaker', 'Nominal\\nLength'))\n    self.UserLenLabel.setText(tr('ScrewMaker', 'User length \\nfor screw-tap'))\n    self.CommentLabel.setText(tr('ScrewMaker', 'Values in brackets are not recommended!'))\n    self.ScrewType.setItemText(0, tr('ScrewMaker', 'ISO4017: Hexagon head screws'))\n    self.ScrewType.setItemText(1, tr('ScrewMaker', 'ISO4014: Hexagon head bolts'))\n    self.ScrewType.setItemText(2, tr('ScrewMaker', 'EN1662: Hexagon bolts with flange, small\\n    series'))\n    self.ScrewType.setItemText(3, tr('ScrewMaker', 'EN1665: Hexagon bolts with flange, heavy\\n    series'))\n    self.ScrewType.setItemText(4, tr('ScrewMaker', 'ISO8676: Hexagon head screw with\\n    metric fine pitch thread'))\n    self.ScrewType.setItemText(5, tr('ScrewMaker', 'ISO4762: Hexagon socket head cap screws'))\n    self.ScrewType.setItemText(6, tr('ScrewMaker', 'ISO7380-1: Hexagon socket button head\\n    screws'))\n    self.ScrewType.setItemText(7, tr('ScrewMaker', 'ISO7380-2: Hexagon socket button head\\n    screws with collar'))\n    self.ScrewType.setItemText(8, tr('ScrewMaker', 'DIN967: Cross recessed pan head screws\\n    with collar'))\n    self.ScrewType.setItemText(9, tr('ScrewMaker', 'ISO10642: Hexagon socket countersunk \\n    head screws'))\n    self.ScrewType.setItemText(10, tr('ScrewMaker', 'ISO2009: Slotted countersunk flat head\\n    screws'))\n    self.ScrewType.setItemText(11, tr('ScrewMaker', 'ISO2010: Slotted raised countersunk head\\n    screws'))\n    self.ScrewType.setItemText(12, tr('ScrewMaker', 'ISO1207: Slotted cheese head screws'))\n    self.ScrewType.setItemText(13, tr('ScrewMaker', 'ISO1580: Slotted pan head screws'))\n    self.ScrewType.setItemText(14, tr('ScrewMaker', 'ISO7045: Pan head screws, type H cross recess'))\n    self.ScrewType.setItemText(15, tr('ScrewMaker', 'ISO7046: Countersunk flat head screws\\n    H cross recess'))\n    self.ScrewType.setItemText(16, tr('ScrewMaker', 'ISO7047: Raised countersunk head screws\\n    H cross recess'))\n    self.ScrewType.setItemText(17, tr('ScrewMaker', 'ISO7048: Cheese head screws type H cross recess'))\n    self.ScrewType.setItemText(18, tr('ScrewMaker', 'ISO14579: Hexalobular socket head cap screws'))\n    self.ScrewType.setItemText(19, tr('ScrewMaker', 'ISO14580: Hexalobular socket cheese head\\n    screws'))\n    self.ScrewType.setItemText(20, tr('ScrewMaker', 'ISO14583: Hexalobular socket pan head screws'))\n    self.ScrewType.setItemText(21, tr('ScrewMaker', 'ISO14582: Hexalobular socket countersunk\\n    head screws, high head'))\n    self.ScrewType.setItemText(22, tr('ScrewMaker', 'ISO14584: Hexalobular socket raised\\n    countersunk head screws'))\n    self.ScrewType.setItemText(23, tr('ScrewMaker', 'ISO7089: Plain washers - Normal series'))\n    self.ScrewType.setItemText(24, tr('ScrewMaker', 'ISO7090: Plain washers, chamfered - Normal series'))\n    self.ScrewType.setItemText(25, tr('ScrewMaker', 'ISO7092: Plain washers - Small series'))\n    self.ScrewType.setItemText(26, tr('ScrewMaker', 'ISO7093-1: Plain washer - Large series'))\n    self.ScrewType.setItemText(27, tr('ScrewMaker', 'ISO7094: Plain washers - Extra large series'))\n    self.ScrewType.setItemText(28, tr('ScrewMaker', 'ISO4032: Hexagon nuts, Style 1'))\n    self.ScrewType.setItemText(29, tr('ScrewMaker', 'ISO4033: Hexagon nuts, Style 2'))\n    self.ScrewType.setItemText(30, tr('ScrewMaker', 'ISO4035: Hexagon thin nuts, chamfered'))\n    self.ScrewType.setItemText(31, tr('ScrewMaker', 'EN1661: Hexagon nuts with flange'))\n    self.ScrewType.setItemText(32, tr('ScrewMaker', 'ScrewTap: ISO Screw-Tap'))\n\n    self.NominalDiameter.setItemText(0, tr('ScrewMaker', 'M1.6'))\n    self.NominalDiameter.setItemText(1, tr('ScrewMaker', 'M2'))\n    self.NominalDiameter.setItemText(2, tr('ScrewMaker', 'M2.5'))\n    self.NominalDiameter.setItemText(3, tr('ScrewMaker', 'M3'))\n    self.NominalDiameter.setItemText(4, tr('ScrewMaker', '(M3.5)'))\n    self.NominalDiameter.setItemText(5, tr('ScrewMaker', 'M4'))\n    self.NominalDiameter.setItemText(6, tr('ScrewMaker', 'M5'))\n    self.NominalDiameter.setItemText(7, tr('ScrewMaker', 'M6'))\n    self.NominalDiameter.setItemText(8, tr('ScrewMaker', 'M8'))\n    self.NominalDiameter.setItemText(9, tr('ScrewMaker', 'M10'))\n    self.NominalDiameter.setItemText(10, tr('ScrewMaker', 'M12'))\n    self.NominalDiameter.setItemText(11, tr('ScrewMaker', '(M14)'))\n    self.NominalDiameter.setItemText(12, tr('ScrewMaker', 'M16'))\n    self.NominalDiameter.setItemText(13, tr('ScrewMaker', '(M18)'))\n    self.NominalDiameter.setItemText(14, tr('ScrewMaker', 'M20'))\n    self.NominalDiameter.setItemText(15, tr('ScrewMaker', '(M22)'))\n    self.NominalDiameter.setItemText(16, tr('ScrewMaker', 'M24'))\n    self.NominalDiameter.setItemText(17, tr('ScrewMaker', '(M27)'))\n    self.NominalDiameter.setItemText(18, tr('ScrewMaker', 'M30'))\n    self.NominalDiameter.setItemText(19, tr('ScrewMaker', 'M36'))\n    self.NominalDiameter.setItemText(20, tr('ScrewMaker', '(M33)'))\n    self.NominalDiameter.setItemText(21, tr('ScrewMaker', 'M42'))\n    self.NominalDiameter.setItemText(22, tr('ScrewMaker', '(M45)'))\n    self.NominalDiameter.setItemText(23, tr('ScrewMaker', 'M48'))\n    self.NominalDiameter.setItemText(24, tr('ScrewMaker', '(M52)'))\n    self.NominalDiameter.setItemText(25, tr('ScrewMaker', 'M54'))\n    self.NominalDiameter.setItemText(26, tr('ScrewMaker', '(M60)'))\n    self.NominalDiameter.setItemText(27, tr('ScrewMaker', 'M64'))\n\n    self.NominalDiameter.setItemText(28, tr('ScrewMaker', 'M8x1'))\n    self.NominalDiameter.setItemText(29, tr('ScrewMaker', 'M10x1'))\n    self.NominalDiameter.setItemText(30, tr('ScrewMaker', '(M10x1.25)'))\n    self.NominalDiameter.setItemText(31, tr('ScrewMaker', 'M12x1.5'))\n    self.NominalDiameter.setItemText(32, tr('ScrewMaker', '(M12x1.25)'))\n    self.NominalDiameter.setItemText(33, tr('ScrewMaker', '(M14x1.5)'))\n    self.NominalDiameter.setItemText(34, tr('ScrewMaker', 'M16x1.5'))\n    self.NominalDiameter.setItemText(35, tr('ScrewMaker', '(M18x1.5)'))\n    self.NominalDiameter.setItemText(36, tr('ScrewMaker', 'M20x1.5'))\n    self.NominalDiameter.setItemText(37, tr('ScrewMaker', '(M20x2)'))\n    self.NominalDiameter.setItemText(38, tr('ScrewMaker', '(M22x1.5)'))\n    self.NominalDiameter.setItemText(39, tr('ScrewMaker', 'M24x2'))\n    self.NominalDiameter.setItemText(40, tr('ScrewMaker', '(M27x2)'))\n    self.NominalDiameter.setItemText(41, tr('ScrewMaker', 'M30x2'))\n    self.NominalDiameter.setItemText(42, tr('ScrewMaker', '(M33x2)'))\n    self.NominalDiameter.setItemText(43, tr('ScrewMaker', 'M36x3'))\n    self.NominalDiameter.setItemText(44, tr('ScrewMaker', '(M39x3)'))\n    self.NominalDiameter.setItemText(45, tr('ScrewMaker', 'M42x3'))\n    self.NominalDiameter.setItemText(46, tr('ScrewMaker', '(M45x3)'))\n    self.NominalDiameter.setItemText(47, tr('ScrewMaker', 'M48x3'))\n    self.NominalDiameter.setItemText(48, tr('ScrewMaker', '(M52x4)'))\n    self.NominalDiameter.setItemText(49, tr('ScrewMaker', 'M56x4'))\n    self.NominalDiameter.setItemText(50, tr('ScrewMaker', '(M60x4)'))\n    self.NominalDiameter.setItemText(51, tr('ScrewMaker', 'M64x4'))\n\n    self.NominalLength.setItemText(0, tr('ScrewMaker', '2'))\n    self.NominalLength.setItemText(1, tr('ScrewMaker', '2.5'))\n    self.NominalLength.setItemText(2, tr('ScrewMaker', '3'))\n    self.NominalLength.setItemText(3, tr('ScrewMaker', '4'))\n    self.NominalLength.setItemText(4, tr('ScrewMaker', '5'))\n    self.NominalLength.setItemText(5, tr('ScrewMaker', '6'))\n    self.NominalLength.setItemText(6, tr('ScrewMaker', '8'))\n    self.NominalLength.setItemText(7, tr('ScrewMaker', '10'))\n    self.NominalLength.setItemText(8, tr('ScrewMaker', '12'))\n    self.NominalLength.setItemText(9, tr('ScrewMaker', '16'))\n    self.NominalLength.setItemText(10, tr('ScrewMaker', '20'))\n    self.NominalLength.setItemText(11, tr('ScrewMaker', '25'))\n    self.NominalLength.setItemText(12, tr('ScrewMaker', '30'))\n    self.NominalLength.setItemText(13, tr('ScrewMaker', '35'))\n    self.NominalLength.setItemText(14, tr('ScrewMaker', '40'))\n    self.NominalLength.setItemText(15, tr('ScrewMaker', '45'))\n    self.NominalLength.setItemText(16, tr('ScrewMaker', '50'))\n    self.NominalLength.setItemText(17, tr('ScrewMaker', '55'))\n    self.NominalLength.setItemText(18, tr('ScrewMaker', '60'))\n    self.NominalLength.setItemText(19, tr('ScrewMaker', '65'))\n    self.NominalLength.setItemText(20, tr('ScrewMaker', '70'))\n    self.NominalLength.setItemText(21, tr('ScrewMaker', '80'))\n    self.NominalLength.setItemText(22, tr('ScrewMaker', '90'))\n    self.NominalLength.setItemText(23, tr('ScrewMaker', '100'))\n    self.NominalLength.setItemText(24, tr('ScrewMaker', '110'))\n    self.NominalLength.setItemText(25, tr('ScrewMaker', '120'))\n    self.NominalLength.setItemText(26, tr('ScrewMaker', '130'))\n    self.NominalLength.setItemText(27, tr('ScrewMaker', '140'))\n    self.NominalLength.setItemText(28, tr('ScrewMaker', '150'))\n    self.NominalLength.setItemText(29, tr('ScrewMaker', '160'))\n    self.NominalLength.setItemText(30, tr('ScrewMaker', '180'))\n    self.NominalLength.setItemText(31, tr('ScrewMaker', '200'))\n    self.NominalLength.setItemText(32, tr('ScrewMaker', '220'))\n    self.NominalLength.setItemText(33, tr('ScrewMaker', '240'))\n    self.NominalLength.setItemText(34, tr('ScrewMaker', '260'))\n    self.NominalLength.setItemText(35, tr('ScrewMaker', '280'))\n    self.NominalLength.setItemText(36, tr('ScrewMaker', '300'))\n    self.NominalLength.setItemText(37, tr('ScrewMaker', '320'))\n    self.NominalLength.setItemText(38, tr('ScrewMaker', '340'))\n    self.NominalLength.setItemText(39, tr('ScrewMaker', '360'))\n    self.NominalLength.setItemText(40, tr('ScrewMaker', '380'))\n    self.NominalLength.setItemText(41, tr('ScrewMaker', '400'))\n    self.NominalLength.setItemText(42, tr('ScrewMaker', '420'))\n    self.NominalLength.setItemText(43, tr('ScrewMaker', '440'))\n    self.NominalLength.setItemText(44, tr('ScrewMaker', '460'))\n    self.NominalLength.setItemText(45, tr('ScrewMaker', '480'))\n    self.NominalLength.setItemText(46, tr('ScrewMaker', '500'))\n    self.NominalLength.setItemText(47, tr('ScrewMaker', 'User'))\n    #self.UserLen.setItemText(0, tr('ScrewMaker', 'regular pitch'))\n    self.SimpleScrew.setText(tr('ScrewMaker', 'Simple Screw (no thread at all!)'))\n    self.SymbolThread.setText(tr('ScrewMaker', 'Symbol Thread (not implemented yet)'))\n    self.RealThread.setText(tr('ScrewMaker', 'Real Thread (takes time, memory intensive)\\nMay not work for all screws!'))\n    self.MessageLabel.setText(tr('ScrewMaker', 'Select your screw type'))\n    self.MessageLabel.setProperty('Errortext', tr('ScrewMaker', 'Combination not implemented'))\n    self.MessageLabel.setProperty('OK_text', tr('ScrewMaker', 'Screw is made'))\n    self.CreateButton.setText(tr('ScrewMaker', 'create'))\n\n  def guiCheck_Data(self):\n    ST_text = str(self.ScrewType.currentText())\n    ST_text = ST_text.split(':')[0]\n    ND_text = str(self.NominalDiameter.currentText())\n    NL_text = str(self.NominalLength.currentText())\n    M_text, self.ScrewAvailable  = self.theScrew.check_Data(ST_text, ND_text, NL_text)\n    self.MessageLabel.setText(tr('ScrewMaker', M_text))\n\n  def guiCreateScrew(self):\n    #self.simpThread = self.SimpleScrew.isChecked()\n    #self.symThread = self.SymbolThread.isChecked()\n    #self.rThread = self.RealThread.isChecked()\n    if self.SimpleScrew.isChecked():\n      threadType = 'simple'\n    if self.SymbolThread.isChecked():\n      threadType = 'symbol'\n    if self.RealThread.isChecked():\n      threadType = 'real'\n\n    ND_text = str(self.NominalDiameter.currentText())\n    NL_text = str(self.NominalLength.currentText())\n    ST_text = str(self.ScrewType.currentText())\n    ST_text = ST_text.split(':')[0]\n\n    if (ST_text == 'ScrewTap') or (ST_text == 'ISO8676'):\n      if NL_text == 'User':\n        textValue = self.UserLen.property(\"text\")\n        stLength = FreeCAD.Units.parseQuantity(textValue).Value\n        NL_text = str(stLength)\n\n    myObj = self.theScrew.createScrew(ST_text, ND_text, NL_text, threadType)\n\n\ndef get_diameter(thread_type):\n  \"\"\"Return the screw diameter as float\n\n  Accepted input format are e.g. 'M5', 'M8x1', '(M3.5)', '(M10x1.25)'.\n  \"\"\"\n  thread_string = thread_type.lstrip('(M').rstrip(')')\n  dia = float(thread_string.split('x')[0])\n  return dia\n\n\nclass Screw(object):\n  def __init__(self):\n    self.objAvailable = True\n    self.Tuner = 510\n    testCirc=Part.makeCircle(2.0,Base.Vector(0.0,0.0,-0.0),Base.Vector(0.0,0.0,-1.0))\n    testDisk = Part.Face(Part.Wire(testCirc))\n    z = testDisk.Surface.Axis.z\n    if z > 0:\n      self.circleAxis = Base.Vector(0.0,0.0,1.0)\n    else:\n      self.circleAxis = Base.Vector(0.0,0.0,-1.0)\n\n  def check_Data(self, ST_text, ND_text, NL_text):\n    #FreeCAD.Console.PrintMessage(\"Data checking\" + NL_text + \"\\n\")\n    #set screw not ok\n    self.objAvailable = False\n    M_text = \"Select your screw type\"\n    Type_text = ''\n    if ST_text == 'ISO4017':\n      table = iso4017head\n      tab_len = iso4017length\n      tab_range = iso4017range\n      Type_text = 'Screw'\n\n    if ST_text == 'EN1662':\n      table = en1662def\n      tab_len = en1662length\n      tab_range = en1662range\n      Type_text = 'Screw'\n\n    if ST_text == 'EN1665':\n      table = en1665def\n      tab_len = en1665length\n      tab_range = en1665range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO8676':\n      table = iso8676def\n      tab_len = iso8676length\n      tab_range = iso8676range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO2009':\n      table = iso2009def\n      tab_len = iso2009length\n      tab_range = iso2009range\n      Type_text = 'Screw'\n    if ST_text == 'ISO2010':\n      table = iso2009def\n      tab_len = iso2009length\n      tab_range = iso2009range\n      Type_text = 'Screw'\n    if ST_text == 'ISO4762':\n      table = iso4762def\n      tab_len = iso4762length\n      tab_range = iso4762range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO10642':\n      table = iso10642def\n      tab_len = iso10642length\n      tab_range = iso10642range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO4014':\n      table = iso4014head\n      tab_len = iso4014length\n      tab_range = iso4014range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO1207':\n      table = iso1207def\n      tab_len = iso1207length\n      tab_range = iso1207range\n      Type_text = 'Screw'\n    if ST_text == 'ISO1580':\n      table = iso1580def\n      tab_len = iso2009length\n      tab_range = iso2009range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO7045':\n      table = iso7045def\n      tab_len = iso7045length\n      tab_range = iso7045range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO7046':\n      table = iso7046def  # contains only cross recess data\n      tab_len = iso7045length\n      tab_range = iso7046range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO7047':\n      table = iso2009def\n      tab_len = iso7045length\n      tab_range = iso7046range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO7048':\n      table = iso7048def\n      tab_len = iso7048length\n      tab_range = iso7048range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO7380-1':\n      table = iso7380def\n      tab_len = iso7380length\n      tab_range = iso7380range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO7380-2':\n      table = iso7380_2def\n      tab_len = iso7380length\n      tab_range = iso7380range\n      Type_text = 'Screw'\n\n    if ST_text == 'DIN967':\n      table = din967def\n      tab_len = din967length\n      tab_range = din967range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO14579':\n      table = iso14579def\n      tab_len = iso14579length\n      tab_range = iso14579range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO14580':\n      table = iso14580def\n      tab_len = iso14580length\n      tab_range = iso1207range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO14583':\n      table = iso14583def\n      tab_len = iso7045length\n      tab_range = iso7046range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO14584':\n      table = iso14584def\n      tab_len = iso7045length\n      tab_range = iso14584range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO14582':\n      table = iso14582def\n      tab_len = iso14582length\n      tab_range = iso14582range\n      Type_text = 'Screw'\n\n    if ST_text == 'ISO7089':\n      table = iso7089def\n      Type_text = 'Washer'\n\n    if ST_text == 'ISO7090':\n      table = iso7090def\n      Type_text = 'Washer'\n\n    if ST_text == 'ISO7091':\n      table = iso7091def\n      Type_text = 'Washer'\n\n    if ST_text == 'ISO7092':\n      table = iso7092def\n      Type_text = 'Washer'\n\n    if ST_text == 'ISO7093-1':\n      table = iso7093def\n      Type_text = 'Washer'\n\n    if ST_text == 'ISO7094':\n      table = iso7094def\n      Type_text = 'Washer'\n\n    if ST_text == 'ISO4032':\n      table = iso4032def\n      Type_text = 'Nut'\n\n    if ST_text == 'ISO4033':\n      table = iso4033def\n      Type_text = 'Nut'\n\n    if ST_text == 'ISO4035':\n      table = iso4035def\n      Type_text = 'Nut'\n\n    if ST_text == 'ISO4036':\n      table = iso4036def\n      Type_text = 'Nut'\n\n    if ST_text == 'EN1661':\n      table = en1661def\n      Type_text = 'Nut'\n\n    if ST_text == 'ScrewTap':\n      table = tuningTable\n      Type_text = 'Screw-Tap'\n\n    if ND_text not in table:\n       ND_min, ND_max = standard_diameters[ST_text]\n       M_text = ST_text+' has diameters from '+ ND_min +' to ' + ND_max + ' and not ' + ND_text +'!'\n       self.objAvailable = False\n       # set scew not ok\n    else:\n      if Type_text == 'Screw':\n        #NL_text = str(self.NominalLength.currentText())\n        NL_min, NL_max = tab_range[ND_text]\n        NL_min_float = float(NL_min)\n        NL_max_float = float(NL_max)\n        if (NL_text == 'User') and (ST_text != 'ISO8676'):\n          M_text = 'User length is only available for the screw-tab and ISO 8676!'\n          self.objAvailable = False\n        else:\n          if NL_text == 'User':\n            M_text = 'ISO 8676 with user length is ok!'\n            self.objAvailable = True\n          else:\n            NL_text_float = float(NL_text)\n            if (NL_text_float<NL_min_float)or(NL_text_float>NL_max_float)or(NL_text not in tab_len):\n              if '(' in ND_text:\n                ND_text = ND_text.lstrip('(').rstrip(')')\n              M_text = ST_text+'-'+ ND_text +' has lengths from '+ NL_min +' to ' + NL_max + ' and not ' + NL_text +'!'\n              self.objAvailable = False\n              # set screw not ok\n            else:\n              if '(' in ND_text:\n                ND_text = ND_text.lstrip('(').rstrip(')')\n              M_text = ST_text+'-'+ ND_text +'x'+ NL_text +' is in library available! '\n              self.objAvailable = True\n              #set screw ok\n      else: # Washers and Nuts\n        if Type_text != 'Screw-Tap':\n          if '(' in ND_text:\n            ND_text = ND_text.lstrip('(').rstrip(')')\n          M_text = ST_text+'-'+ ND_text +' is available in library!'\n          self.objAvailable = True\n          #set washer/nut ok\n        else:\n          if NL_text == 'User':\n            M_text = 'Screw-tab with user length is ok!'\n            self.objAvailable = True\n          else:\n            #NL_text = str(self.NominalLength.currentText())\n            if '(' in ND_text:\n              ND_text = ND_text.lstrip('(').rstrip(')')\n            M_text = ST_text+'-'+ ND_text +' with '+ NL_text +'mm length is available in library!'\n            self.objAvailable = True\n            #set screwTap ok\n\n    #print \"Data checking: \", self.NominalLength.currentText(), \"\\n\"\n    #FreeCAD.Console.PrintMessage(\"Set Check_result into text \" + str(self.objAvailable) + M_text + \"\\n\")\n    return M_text, self.objAvailable\n\n\n  def createScrew(self, ST_text, ND_text, NL_text, threadType):\n    #self.simpThread = self.SimpleScrew.isChecked()\n    #self.symThread = self.SymbolThread.isChecked()\n    #self.rThread = self.RealThread.isChecked()\n    if threadType == 'real':\n      self.rThread = True\n    else:\n      self.rThread = False\n\n    if self.objAvailable:\n      try:\n        # first we check if valid numbers have been entered\n        #FreeCAD.Console.PrintMessage(\"NominalLength: \" + self.NominalLength.currentText() + \"\\n\")\n        #FreeCAD.Console.PrintMessage(\"NominalDiameter: \" + self.NominalDiameter.currentText() + \"\\n\")\n        #FreeCAD.Console.PrintMessage(\"SimpleThread: \" + str(self.SimpleScrew.isChecked()) + \"\\n\")\n        #FreeCAD.Console.PrintMessage(\"SymbolThread: \" + str(self.SymbolThread.isChecked()) + \"\\n\")\n        #FreeCAD.Console.PrintMessage(\"RealThread: \" + str(self.RealThread.isChecked()) + \"\\n\")\n\n        #ND_text = str(self.NominalDiameter.currentText())\n        #NL_text = str(self.NominalLength.currentText())\n        #ST_text = str(self.ScrewType.currentText())\n        #ST_text = ST_text.split(':')[0]\n        #dia = float(ND_text.lstrip('M'))\n        l = float(NL_text)\n        if ST_text == 'ISO4017':\n           table = iso4017head\n        if ST_text == 'ISO4014':\n           table = iso4014head\n        if ST_text == 'EN1662':\n           table = en1662def\n        if ST_text == 'EN1665':\n           table = en1665def\n        if ST_text == 'ISO8676':\n           table = iso8676def\n        if ST_text == 'ISO2009':\n           table = iso2009def\n        if ST_text == 'ISO2010':\n           table = iso2009def\n        if ST_text == 'ISO4762':\n           table = iso4762def\n        if ST_text == 'ISO10642':\n           table = iso10642def\n        if ST_text == 'ISO1207':\n           table = iso1207def\n        if ST_text == 'ISO1580':\n           table = iso1580def\n        if ST_text == 'ISO7045':\n           table = iso7045def\n        if ST_text == 'ISO7046':\n           table = iso7045def\n        if ST_text == 'ISO7047':\n           table = iso7045def\n        if ST_text == 'ISO7048':\n           table = iso7048def\n        if ST_text == 'ISO7380-1':\n           table = iso7380def\n        if ST_text == 'ISO7380-2':\n           table = iso7380_2def\n        if ST_text == 'DIN967':\n           table = din967def\n        if ST_text == 'ISO14579':\n           table = iso14579def\n        if ST_text == 'ISO14580':\n           table = iso14580def\n        if ST_text == 'ISO14582':\n           table = iso14582def\n        if ST_text == 'ISO14583':\n           table = iso14583def\n        if ST_text == 'ISO14584':\n           table = iso14584def\n        if ST_text == 'ISO7089':\n           table = iso7089def\n        if ST_text == 'ISO7090':\n           table = iso7090def\n        if ST_text == 'ISO7091':\n           table = iso7091def\n        if ST_text == 'ISO7092':\n           table = iso7092def\n        if ST_text == 'ISO7093-1':\n           table = iso7093def\n        if ST_text == 'ISO7094':\n           table = iso7094def\n        if ST_text == 'ISO4032':\n           table = iso4032def\n        if ST_text == 'ISO4033':\n           table = iso4033def\n        if ST_text == 'ISO4035':\n           table = iso4035def\n        if ST_text == 'ISO4036':\n           table = iso4036def\n        if ST_text == 'EN1661':\n           table = en1661def\n        if ST_text == 'ScrewTap':\n           table = tuningTable\n        if ND_text not in table:\n           FreeCAD.Console.PrintMessage(\"Combination of type \"+ST_text \\\n              + \" and diameter \" + ND_text +\" not available!\" + \"\\n\")\n        #self.MessageLabel.setText(tr('ScrewMaker', 'not implemented'))\n\n      except ValueError:\n        #print \"Error! nom_dia and length values must be valid numbers!\"\n        FreeCAD.Console.PrintMessage(\"Error! nom_dia and length values must be valid numbers!\\n\")\n      else:\n        doc=FreeCAD.activeDocument()\n        done = False\n        if (ST_text == 'ISO4014') or (ST_text == 'ISO4017') or (ST_text == 'ISO8676'):\n          screw = self.makeIso4017_2(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'EN1662') or (ST_text == 'EN1665'):\n          screw = self.makeEN1662_2(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'ISO2009') or (ST_text == 'ISO2010') or (ST_text == 'ISO1580'):\n          screw = self.makeSlottedScrew(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'ISO4762') or (ST_text == 'ISO14579'):\n          screw = self.makeIso4762(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'ISO1207') or (ST_text == 'ISO14580') or (ST_text == 'ISO7048'):\n          screw = self.makeIso1207(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'ISO7045') or (ST_text == 'ISO14583'):\n          screw = self.makeIso7045(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'ISO7046') or (ST_text == 'ISO7047') or \\\n          (ST_text == 'ISO14582') or (ST_text == 'ISO14584') or (ST_text == 'ISO10642'):\n          screw = self.makeIso7046(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'ISO7380-1') or (ST_text == 'ISO7380-2') or (ST_text == 'DIN967'):\n          screw = self.makeIso7380(ST_text, ND_text,l)\n          Type_text = 'Screw'\n          done = True\n        if (ST_text == 'ISO7089') or (ST_text == 'ISO7090') or (ST_text == 'ISO7093-1') or \\\n          (ST_text == 'ISO7091') or (ST_text == 'ISO7092') or (ST_text == 'ISO7094'):\n          screw = self.makeIso7089(ST_text, ND_text)\n          Type_text = 'Washer'\n          done = True\n        if (ST_text == 'ISO4032') or (ST_text == 'ISO4033') or (ST_text == 'ISO4035'):\n          screw = self.makeIso4032(ST_text, ND_text)\n          Type_text = 'Nut'\n          done = True\n        if ST_text == 'EN1661':\n          screw = self.makeEN1661(ND_text)\n          Type_text = 'Nut'\n          done = True\n        if ST_text == 'ScrewTap':\n          screw = self.makeScrewTap(ND_text,l)\n          Type_text = 'Screw-Tap'\n          done = True\n        if not done:\n          FreeCAD.Console.PrintMessage(\"No valid Screw Type!\" +  \"\\n\")\n        if '(' in ND_text:\n          ND_text = ND_text.lstrip('(').rstrip(')')\n\n        if Type_text == 'Screw':\n          label = ST_text + \"-\" + ND_text +\"x\"+ NL_text +\"_\"\n        else:\n          if (Type_text == 'Nut'):\n            label = ST_text + '-' + ND_text +'_'\n          else:\n            if Type_text == 'Screw-Tap':\n              label = ST_text + '-' + ND_text +'x'+ NL_text +'_'\n            else: # washer\n              label = ST_text + '-' + ND_text.lstrip('M') +'_'\n        ScrewObj = doc.addObject(\"Part::Feature\")\n        ScrewObj.Label=label\n        ScrewObj.Shape=screw\n        #FreeCAD.Console.PrintMessage(\"Placement: \"+ str(ScrewObj.Placement) +\"\\n\")\n        #FreeCAD.Console.PrintMessage(\"The label: \"+ label +\"\\n\")\n        self.moveScrew(ScrewObj)\n        #ScrewObj.Label = label\n        if self.gotPart:\n          self.thePart.addObject(ScrewObj)\n        doc.recompute()\n        # Part.show(screw)\n        return ScrewObj\n\n  def getFaceAxis(self, sp, c):\n    fList = []\n    fAxis = None\n    if len(c.Vertexes) ==1:\n      theVert = c.Vertexes[0]\n      # search for faces which have a vertex equal to theVert.\n      for f in sp.Faces:\n        for v in f.Vertexes:\n          if equal_vertex(v, theVert):\n            fList.append(f)\n    print (str(fList))\n    # search for a plane face\n    for f in fList:\n      if hasattr(f,'Surface'):\n        FreeCAD.Console.PrintMessage('type of surface: ', str(f.Surface))\n        if f.Surface.isPlanar():\n          fAxis = f.Surface.normal(0,0)\n          print ('got planar Face with normal: ', str(f.Surface.normal(0,0)))\n          print ('Orientation: ', str(f.Orientation))\n          if f.Orientation == 'Reversed':\n            fAxis = fAxis.multiply(-1.0)\n    return fAxis\n\n  def moveScrew(self, ScrewObj_m):\n    #FreeCAD.Console.PrintMessage(\"In Move Screw: \" + str(ScrewObj_m) + \"\\n\")\n    self.gotBody = False\n    self.gotPart = False\n\n    mylist = FreeCAD.Gui.Selection.getSelectionEx()\n    if (mylist.__len__() == 1):\n       # check selection\n       #FreeCAD.Console.PrintMessage(\"Selektionen: \" + str(mylist.__len__()) + \"\\n\")\n       Pnt1 = None\n       Axis1 = None\n       Axis2 = None\n       theSelection = mylist[0]\n       #FreeCAD.Console.PrintMessage( \"ObjectName: \" + str(theSelection.ObjectName) + \"\\n\")\n       if hasattr(theSelection, 'Object'):\n         if hasattr(theSelection.Object, 'InList'):\n           inLength = len(theSelection.Object.InList)\n           #FreeCAD.Console.PrintMessage( \"InList: \" + str(theSelection.Object.InList) + \"\\n\")\n           for b in theSelection.Object.InList:\n             #FreeCAD.Console.PrintMessage( \"OType: \" + str(b.TypeId) + \"\\n\")\n             if b.TypeId == 'PartDesign::Body':\n               self.gotBody = True\n               self.bPlacement = b.Placement\n               for par in b.InList:\n                 if par.TypeId == 'App::Part':\n                   self.gotPart = True\n                   self.thePart = par\n\n                   break\n\n       for o in FreeCADGui.Selection.getSelectionEx():\n          #FreeCAD.Console.PrintMessage( \"name: \" + str(o) + \"\\n\")\n          #FreeCAD.Console.PrintMessage( \"Properties: \" + str(o.PropertiesList) + \"\\n\")\n\n          #for s in o.SubElementNames:\n             #FreeCAD.Console.PrintMessage( \"name: \" + str(s) + \"\\n\")\n          for s in o.SubObjects:\n             #FreeCAD.Console.PrintMessage( \"object: \"+ str(s) + \"\\n\")\n             #FreeCAD.Console.PrintMessage( \"Properties: \" + str(s.PropertiesList) + \"\\n\")\n             if hasattr(s,\"Curve\"):\n                #FreeCAD.Console.PrintMessage( \"The Object is a Curve!\\n\")\n                if hasattr(s.Curve,\"Center\"):\n                   \"\"\"\n                   FreeCAD.Console.PrintMessage( \"The object has a Center!\\n\")\n                   FreeCAD.Console.PrintMessage( \"Curve attribute. \"+ str(s.__getattribute__('Curve')) + \"\\n\")\n                   FreeCAD.Console.PrintMessage( \"Center: \"+ str(s.Curve.Center) + \"\\n\")\n                   FreeCAD.Console.PrintMessage( \"Axis: \"+ str(s.Curve.Axis) + \"\\n\")\n                   \"\"\"\n                   Pnt1 = s.Curve.Center\n                   Axis1 = s.Curve.Axis\n                   fAxis = self.getFaceAxis(o.Object.Shape, s)\n                   if fAxis:\n                     Axis1 = fAxis\n             if hasattr(s,'Surface'):\n                #print 'the object is a face!'\n                if hasattr(s.Surface,'Axis'):\n                   Axis1 = s.Surface.Axis\n\n             if hasattr(s,'Point'):\n                #FreeCAD.Console.PrintMessage( \"the object seems to be a vertex! \"+ str(s.Point) + \"\\n\")\n                Pnt1 = s.Point\n\n       if (Axis1 != None):\n          #FreeCAD.Console.PrintMessage( \"Got Axis1: \" + str(Axis1) + \"\\n\")\n          Axis2 = Base.Vector(0.0,0.0,1.0)\n          Axis2_minus = Base.Vector(0.0,0.0,-1.0)\n\n          # Calculate angle\n          if Axis1 == Axis2:\n             normvec = Base.Vector(1.0,0.0,0.0)\n             result = 0.0\n          else:\n             if Axis1 == Axis2_minus:\n                normvec = Base.Vector(1.0,0.0,0.0)\n                result = math.pi\n             else:\n                normvec = Axis1.cross(Axis2) # Berechne Achse der Drehung = normvec\n                normvec.normalize() # Normalisieren fuer Quaternionenrechnung\n                #normvec_rot = normvec\n                result = DraftVecUtils.angle(Axis1, Axis2, normvec) # Winkelberechnung\n          sin_res = math.sin(result/2.0)\n          cos_res = math.cos(result/2.0)\n          normvec.multiply(-sin_res) # Berechnung der Quaternionen-Elemente\n          #FreeCAD.Console.PrintMessage( \"Winkel = \"+ str(math.degrees(result)) + \"\\n\")\n          #FreeCAD.Console.PrintMessage(\"Normalvektor: \"+ str(normvec) + \"\\n\")\n\n          pl = FreeCAD.Placement()\n          pl.Rotation = (normvec.x,normvec.y,normvec.z,cos_res) #Drehungs-Quaternion\n\n          #FreeCAD.Console.PrintMessage(\"pl mit Rot: \"+ str(pl) + \"\\n\")\n          #neuPlatz = Part2.Object.Placement.multiply(pl)\n          neuPlatz = ScrewObj_m.Placement\n          FreeCAD.Console.PrintMessage(\"The Position     \"+ str(neuPlatz) + \"\\n\")\n          neuPlatz.Rotation = pl.Rotation.multiply(ScrewObj_m.Placement.Rotation)\n          # neuPlatz.move(Pnt1)\n          FreeCAD.Console.PrintMessage(\"The Position in Body    \"+ str(neuPlatz) + \"\\n\")\n          if self.gotBody:\n            FreeCAD.Console.PrintMessage(\"got Placement: \"+ str(self.bPlacement) + \"\\n\")\n            #neuPlatz.Rotation = neuPlatz.Rotation.multiply(self.bPlacement.Rotation)\n            neuPlatz.Rotation = neuPlatz.Rotation.multiply(self.bPlacement.Rotation)\n            Pnt1 = self.bPlacement.multVec(Pnt1)\n          neuPlatz.move(Pnt1)\n          #if self.gotBody:\n            #neuPlatz.move(self.bPlacement.Base)\n\n          # Python is not phytonic in FreeCAD 0.17, need to add allocation.\n          ScrewObj_m.Placement = neuPlatz\n          #FreeCAD.Console.PrintMessage(\"die rot. Position: \"+ str(neuPlatz) + \"\\n\")\n\n\n\n  # make Washer\n  def makeIso7089(self,SType ='ISO7089', ThreadType ='M6'):\n    dia = get_diameter(ThreadType)\n    #FreeCAD.Console.PrintMessage(\"die Scheibe mit dia: \" + str(dia) + \"\\n\")\n    if SType == 'ISO7089':\n      d1_min, d2_max, h, h_max = iso7089def[ThreadType]\n    if SType == 'ISO7090':\n      d1_min, d2_max, h, h_max = iso7090def[ThreadType]\n    if SType == 'ISO7091':\n      d1_min, d2_max, h, h_max = iso7091def[ThreadType]\n    if SType == 'ISO7092':\n      d1_min, d2_max, h, h_max = iso7092def[ThreadType]\n    if SType == 'ISO7093-1':\n      d1_min, d2_max, h, h_max = iso7093def[ThreadType]\n    if SType == 'ISO7094':\n      d1_min, d2_max, h, h_max = iso7094def[ThreadType]\n      #FreeCAD.Console.PrintMessage(\"got: \" + SType + \"\\n\")\n\n    #FreeCAD.Console.PrintMessage(\"die Scheibe mit d1_min: \" + str(d1_min) + \"\\n\")\n\n    #Washer Points\n    Pnt0 = Base.Vector(d1_min/2.0,0.0,h_max)\n    Pnt2 = Base.Vector(d2_max/2.0,0.0,h_max)\n    Pnt3 = Base.Vector(d2_max/2.0,0.0,0.0)\n    Pnt4 = Base.Vector(d1_min/2.0,0.0,0.0)\n    if SType == 'ISO7090':\n      Pnt1 = Base.Vector(d2_max/2.0-h_max/4.0,0.0,h_max)\n      Pnt2 = Base.Vector(d2_max/2.0,0.0,h_max*0.75)\n      edge1 = Part.makeLine(Pnt0,Pnt1)\n      edgeCham = Part.makeLine(Pnt1,Pnt2)\n      edge1 = Part.Wire([edge1, edgeCham])\n    else:\n      edge1 = Part.makeLine(Pnt0,Pnt2)\n\n    edge2 = Part.makeLine(Pnt2,Pnt3)\n    edge3 = Part.makeLine(Pnt3,Pnt4)\n    edge4 = Part.makeLine(Pnt4,Pnt0)\n    #FreeCAD.Console.PrintMessage(\"Edges made Pnt2: \" + str(Pnt2) + \"\\n\")\n\n    aWire=Part.Wire([edge1,edge2,edge3,edge4])\n    #Part.show(aWire)\n    aFace =Part.Face(aWire)\n    head = aFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #FreeCAD.Console.PrintMessage(\"Washer revolved: \" + str(dia) + \"\\n\")\n\n    return head\n\n\n  # make ISO 2009 Slotted countersunk flat head screws\n  # make ISO 2010 Slotted raised countersunk head screws\n  # make ISO 1580 Pan head slotted screw (Code is nearly identical to iso1207)\n  def makeSlottedScrew(self,SType ='ISO1580', ThreadType ='M6',l=25.0):\n    dia = get_diameter(ThreadType)\n    if SType == 'ISO1580':\n      #FreeCAD.Console.PrintMessage(\"der Kopf mit l: \" + str(l) + \"\\n\")\n      #P, a, b, dk, dk_mean, da, k, n_min, r, t_min, x = iso1580def[ThreadType]\n      P, a, b, dk_max, da, k, n_min, r, rf, t_min, x = iso1580def[ThreadType]\n      #FreeCAD.Console.PrintMessage(\"der Kopf mit iso: \" + str(dk_max) + \"\\n\")\n      ht = k\n      headEnd = r\n\n      #Length for calculation of head fillet\n      sqrt2_ = 1.0/math.sqrt(2.0)\n      r_fil = rf\n      beta = math.radians(5.0)   # angle of pan head edge\n      alpha = math.radians(90.0 - (90.0+5.0)/2.0)\n      tan_beta = math.tan(beta)\n      # top head diameter without fillet\n      rK_top = dk_max/2.0 - k * tan_beta\n      fillet_center_x = rK_top - r_fil + r_fil * tan_beta\n      fillet_center_z = k - r_fil\n      fillet_arc_x = fillet_center_x + r_fil * math.sin(alpha)\n      fillet_arc_z = fillet_center_z + r_fil * math.cos(alpha)\n      #FreeCAD.Console.PrintMessage(\"rK_top: \" + str(rK_top) + \"\\n\")\n      if (b > (l - 1.0*P)):\n        bmax = l- 1.0*P\n      else:\n        bmax = b\n\n      #Head Points\n      Pnt0 = Base.Vector(0.0,0.0,k)\n      Pnt2 = Base.Vector(fillet_center_x,0.0,k)\n      Pnt3 = Base.Vector(fillet_arc_x,0.0,fillet_arc_z)\n      Pnt4 = Base.Vector(fillet_center_x + r_fil*math.cos(beta),0.0,fillet_center_z+ r_fil * math.sin(beta))\n      Pnt5 = Base.Vector(dk_max/2.0,0.0,0.0)\n      Pnt6 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n      Pnt7 = Base.Vector(dia/2.0+r-r*sqrt2_,0.0,-r+r*sqrt2_) #arc-point of fillet\n      #Pnt8 = Base.Vector(dia/2.0,0.0,-r)        # end of fillet\n      PntR = Base.Vector(dia/2.0,0.0,-r)        # end of fillet\n      PntT0 = Base.Vector(0.0,0.0,-r)        # helper point for real thread\n\n      edge1 = Part.makeLine(Pnt0,Pnt2)\n      edge2 = Part.Arc(Pnt2,Pnt3,Pnt4).toShape()\n      edge3 = Part.makeLine(Pnt4,Pnt5)\n      edge4 = Part.makeLine(Pnt5,Pnt6)\n      edge5 = Part.Arc(Pnt6,Pnt7,PntR).toShape()\n      headWire=Part.Wire([edge1,edge2,edge3,edge4,edge5])\n\n    if (SType == 'ISO2009') or (SType == 'ISO2010'):\n      P, a, b, dk_theo, dk_mean, k, n_min, r, t_mean, x = iso2009def[ThreadType]\n      dk_max = dk_theo\n      t_min = t_mean\n      ht = 0.0 # Head height of flat head\n      if (SType == 'ISO2010'):\n        rf, t_mean, cT, mH, mZ = Raised_countersunk_def[ThreadType]\n        #Lengths and angles for calculation of head rounding\n        beta = math.asin(dk_mean /2.0 / rf)   # angle of head edge\n        tan_beta = math.tan(beta)\n        alpha = beta/2.0 # half angle\n        # height of raised head top\n        ht = rf - (dk_mean/2.0) / tan_beta\n        h_arc_x = rf * math.sin(alpha)\n        h_arc_z = ht - rf + rf * math.cos(alpha)\n\n      cham = (dk_theo - dk_mean)/2.0\n      rad225 = math.radians(22.5)\n      rad45 = math.radians(45.0)\n      rtan = r*math.tan(rad225)\n      headEnd = k + rtan\n\n      if (b > l - k - rtan/2.0 - 1.0*P):\n        bmax = l-k-rtan/2.0 - 1.0*P\n      else:\n        bmax = b\n\n      #Head Points\n      Pnt0 = Base.Vector(0.0,0.0,ht)\n      Pnt1 = Base.Vector(dk_mean/2.0,0.0,0.0)\n      Pnt2 = Base.Vector(dk_mean/2.0,0.0,-cham)\n      Pnt3 = Base.Vector(dia/2.0+r-r*math.cos(rad45),0.0,-k-rtan+r*math.sin(rad45))\n      # Arc-points\n      Pnt4 = Base.Vector(dia/2.0+r-r*(math.cos(rad225)),0.0,-k-rtan+r*math.sin(rad225))\n      PntR = Base.Vector(dia/2.0,0.0,-k-rtan)\n      #PntA = Base.Vector(dia/2.0,0.0,-a_point)\n      PntT0 = Base.Vector(0.0,0.0,-k-rtan)        # helper point for real thread\n\n      if (SType == 'ISO2010'): # make raised head rounding\n        Pnt0arc = Base.Vector(h_arc_x,0.0,h_arc_z)\n        edge1 = Part.Arc(Pnt0,Pnt0arc,Pnt1).toShape()\n      else:\n        edge1 = Part.makeLine(Pnt0,Pnt1)  # make flat head\n\n      edge2 = Part.makeLine(Pnt1,Pnt2)\n      edge3 = Part.makeLine(Pnt2,Pnt3)\n      edgeArc = Part.Arc(Pnt3,Pnt4,PntR).toShape()\n      headWire=Part.Wire([edge1,edge2,edge3,edgeArc])\n\n\n    ### make the new code with math.modf(l)\n    residue, turns = math.modf((bmax)/P)\n    halfturns = 2*int(turns)\n    if residue < 0.5:\n      a_point = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a_point = l - (turns+2.0) * P\n    #halfturns = halfturns + 2\n    offSet = headEnd - a_point\n    PntA = Base.Vector(dia/2.0,0.0,-a_point)        # Start of thread\n\n\n    if self.rThread:\n      edgeZ1 = Part.makeLine(PntR,PntT0)\n      edgeZ0 = Part.makeLine(PntT0,Pnt0)\n      aWire=Part.Wire([headWire, edgeZ1, edgeZ0])\n\n    else:\n      # bolt points\n      PntB1 = Base.Vector(dia/2.0,0.0,-l)\n      PntB2 = Base.Vector(0.0,0.0,-l)\n\n      edgeB2 = Part.makeLine(PntB1,PntB2)\n      edgeZ0 = Part.makeLine(PntB2,Pnt0)\n\n      if a_point <= r:\n        edgeB1 = Part.makeLine(PntR,PntB1)\n        aWire=Part.Wire([headWire, edgeB1, edgeB2, edgeZ0])\n      else:\n        edgeRA = Part.makeLine(PntR,PntA)\n        edgeB1 = Part.makeLine(PntA,PntB1)\n        aWire=Part.Wire([headWire, edgeRA, edgeB1, edgeB2, edgeZ0])\n\n    aFace =Part.Face(aWire)\n    head = aFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n\n    #Parameter for slot-recess: dk_max, n_min, k, t_min\n    slot = Part.makePlane(dk_max, n_min, \\\n        Base.Vector(dk_max/2.0,-n_min/2.0,ht+1.0),Base.Vector(0.0,0.0,-1.0))\n    slot = slot.extrude(Base.Vector(0.0,0.0,-t_min-1.0))\n    #Part.show(slot)\n    head = head.cut(slot)\n    #FreeCAD.Console.PrintMessage(\"der Kopf geschnitten: \" + str(dia) + \"\\n\")\n    #Part.show(head)\n\n    if self.rThread:\n      rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n      rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n      #Part.show(rthread)\n      headFaces = []\n      if (SType == 'ISO2009'):\n        for i in range(0,len(head.Faces)-2):\n          headFaces.append(head.Faces[i])\n        headFaces.append(head.Faces[len(head.Faces)-1])\n\n      if (SType == 'ISO1580') or (SType == 'ISO2010'):\n        for i in range(0,len(head.Faces)-1):\n          headFaces.append(head.Faces[i])\n\n      for threadFace in rthread.Faces:\n        headFaces.append(threadFace)\n\n      newHeadShell = Part.Shell(headFaces)\n      #Part.show(newHeadShell)\n      head = Part.Solid(newHeadShell)\n\n    return head\n\n\n\n\n\n\n  # ISO 7045 Pan head screws with type H or type Z cross recess\n  # ISO 14583 Hexalobular socket pan head screws\n  def makeIso7045(self, SType ='ISO7045', ThreadType ='M6',l=25.0):\n    dia = get_diameter(ThreadType)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit l: \" + str(l) + \"\\n\")\n    P, a, b, dk_max,da, k, r, rf, x, cT, mH, mZ  = iso7045def[ThreadType]\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit iso: \" + str(dk_max) + \"\\n\")\n\n    #Lengths and angles for calculation of head rounding\n    beta = math.asin(dk_max /2.0 / rf)   # angle of head edge\n    #print 'beta: ', math.degrees(beta)\n    tan_beta = math.tan(beta)\n\n\n    if SType == 'ISO14583':\n       tt, A, t_mean = iso14583def[ThreadType]\n       beta_A = math.asin(A/2.0 / rf)   # angle of recess edge\n       tan_beta_A = math.tan(beta_A)\n\n       alpha = (beta_A + beta)/2.0 # half angle\n       #print 'alpha: ', math.degrees(alpha)\n       # height of head edge\n       he = k - A/2.0/tan_beta_A + (dk_max/2.0) / tan_beta\n       #print 'he: ', he\n       h_arc_x = rf * math.sin(alpha)\n       h_arc_z = k - A/2.0/tan_beta_A + rf * math.cos(alpha)\n       #FreeCAD.Console.PrintMessage(\"h_arc_z: \" + str(h_arc_z) + \"\\n\")\n    else:\n       alpha = beta/2.0 # half angle\n       #print 'alpha: ', math.degrees(alpha)\n       # height of head edge\n       he = k - rf + (dk_max/2.0) / tan_beta\n       #print 'he: ', he\n       h_arc_x = rf * math.sin(alpha)\n       h_arc_z = k - rf + rf * math.cos(alpha)\n       #FreeCAD.Console.PrintMessage(\"h_arc_z: \" + str(h_arc_z) + \"\\n\")\n\n    if (b > (l - 1.0*P)):\n       bmax = l- 1.0*P\n    else:\n       bmax = b\n\n    ### make the new code with math.modf(l)\n    residue, turns = math.modf((bmax)/P)\n    halfturns = 2*int(turns)\n    if residue < 0.5:\n      a_point = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a_point = l - (turns+2.0) * P\n    #halfturns = halfturns + 2\n    offSet = r - a_point\n    #FreeCAD.Console.PrintMessage(\"The transition at a: \" + str(a) + \" turns \" + str(turns) + \"\\n\")\n\n    sqrt2_ = 1.0/math.sqrt(2.0)\n\n    #Head Points\n    Pnt1 = Base.Vector(h_arc_x,0.0,h_arc_z)\n    Pnt2 = Base.Vector(dk_max/2.0,0.0,he)\n    Pnt3 = Base.Vector(dk_max/2.0,0.0,0.0)\n    Pnt4 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n    Pnt5 = Base.Vector(dia/2.0+r-r*sqrt2_,0.0,-r+r*sqrt2_) #arc-point of fillet\n    Pnt6 = Base.Vector(dia/2.0,0.0,-r)        # end of fillet\n    Pnt7 = Base.Vector(dia/2.0,0.0,-a_point)        # Start of thread\n    #FreeCAD.Console.PrintMessage(\"Points defined a_point: \" + str(a_point) + \"\\n\")\n\n\n    if (SType == 'ISO14583'):\n      #Pnt0 = Base.Vector(0.0,0.0,k-A/4.0)\n      Pnt0 = Base.Vector(0.0,0.0,k-A/8.0)\n      PntFlat = Base.Vector(A/8.0,0.0,k-A/8.0)\n      PntCham = Base.Vector(A/1.99,0.0,k)\n      edgeCham0 = Part.makeLine(Pnt0,PntFlat)\n      edgeCham1 = Part.makeLine(PntFlat,PntCham)\n      edgeCham2 = Part.Arc(PntCham,Pnt1,Pnt2).toShape()\n      #edge1 = Part.Wire([edgeCham0,edgeCham1,edgeCham2])\n      edge1 = Part.Wire([edgeCham0,edgeCham1])\n      edge2 = Part.makeLine(Pnt2,Pnt3)\n      edge2 = Part.Wire([edgeCham2, edge2])\n      # Part.show(edge2)\n\n      # Here is the next approach to shorten the head building time\n      # Make two helper points to create a cutting tool for the\n      # recess and recess shell.\n      PntH1 = Base.Vector(A/1.99,0.0, 2.0*k)\n      PntH2 = Base.Vector(0.0,0.0, 2.0*k)\n      edgeH1 = Part.makeLine(PntCham,PntH1)\n      edgeH2 = Part.makeLine(PntH1,PntH2)\n      edgeH3 = Part.makeLine(PntH2,Pnt0)\n\n    else:\n      Pnt0 = Base.Vector(0.0,0.0,k)\n      edge1 = Part.Arc(Pnt0,Pnt1,Pnt2).toShape()  # make round head\n      edge2 = Part.makeLine(Pnt2,Pnt3)\n\n      # Here is the next approach to shorten the head building time\n      # Make two helper points to create a cutting tool for the\n      # recess and recess shell.\n      PntH1 = Base.Vector(dk_max/2.0,0.0, 2.0*k)\n      PntH2 = Base.Vector(0.0,0.0, 2.0*k)\n      edgeH1 = Part.makeLine(Pnt2,PntH1)\n      edgeH2 = Part.makeLine(PntH1,PntH2)\n      edgeH3 = Part.makeLine(PntH2,Pnt0)\n\n    edge3 = Part.makeLine(Pnt3,Pnt4)\n    edge4 = Part.Arc(Pnt4,Pnt5,Pnt6).toShape()\n    #FreeCAD.Console.PrintMessage(\"Edges made h_arc_z: \" + str(h_arc_z) + \"\\n\")\n\n    #if self.RealThread.isChecked():\n    if self.rThread:\n      aWire=Part.Wire([edge2,edge3,edge4])\n    else:\n      # bolt points\n      PntB1 = Base.Vector(dia/2.0,0.0,-l)\n      PntB2 = Base.Vector(0.0,0.0,-l)\n      edgeB2 = Part.makeLine(PntB1,PntB2)\n      if a_point <= r:\n        edgeB1 = Part.makeLine(Pnt6,PntB1)\n        aWire=Part.Wire([edge2, edge3, edge4, edgeB1, edgeB2])\n      else:\n        edge5 = Part.makeLine(Pnt6,Pnt7)\n        edgeB1 = Part.makeLine(Pnt7,PntB1)\n        aWire=Part.Wire([edge2, edge3, edge4, edge5, edgeB1, edgeB2])\n\n\n\n    hWire = Part.Wire([edge1,edgeH1,edgeH2,edgeH3]) # Cutter for recess-Shell\n    hFace = Part.Face(hWire)\n    hCut = hFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(hWire)\n\n    headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #head = Part.Solid(headShell)\n    #Part.show(aWire)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n    headFaces = headShell.Faces\n\n    if (SType == 'ISO14583'):\n      recess, recessShell = self.makeIso10664_3(tt, t_mean, k)\n      recessShell = recessShell.cut(hCut)\n      topFace = hCut.Faces[1]\n      topFace = topFace.cut(recess)\n      #Part.show(topFace)\n      #Part.show(recessShell)\n      #Part.show(headShell)\n      headFaces.append(topFace.Faces[0])\n      #headFaces.append(hCut.Faces[2])\n\n    else:\n      #Lengths and angles for calculation of recess positioning\n      beta_cr = math.asin(mH /2.0 / rf)   # angle of recess edge\n      tan_beta_cr = math.tan(beta_cr)\n      # height of cross recess cutting\n      hcr = k - rf + (mH/2.0) / tan_beta_cr\n      #print 'hcr: ', hcr\n\n      #Parameter for cross-recess type H: cT, mH\n      recess, recessShell = self.makeCross_H3(cT, mH, hcr)\n      recessShell = recessShell.cut(hCut)\n      topFace = hCut.Faces[0]\n      topFace = topFace.cut(recess)\n      #Part.show(topFace)\n      #Part.show(recessShell)\n      #Part.show(headShell)\n      headFaces.append(topFace.Faces[0])\n\n    #Part.show(hCut)\n    headFaces.extend(recessShell.Faces)\n\n\n    #if self.RealThread.isChecked():\n    if self.rThread:\n      #head = self.cutIsoThread(head, dia, P, turns, l)\n      rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n      rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n      #head = head.fuse(rthread)\n      #Part.show(rthread)\n      for threadFace in rthread.Faces:\n        headFaces.append(threadFace)\n\n    newHeadShell = Part.Shell(headFaces)\n    #Part.show(newHeadShell)\n    head = Part.Solid(newHeadShell)\n\n    return head\n\n\n  # make Cheese head screw\n  # ISO 1207 slotted screw\n  # ISO 7048 cross recessed screw\n  # ISO 14580 Hexalobular socket cheese head screws\n  def makeIso1207(self,SType ='ISO1207', ThreadType ='M6',l=25.0):\n    dia = get_diameter(ThreadType)\n    '''\n    if '(' in TreadType:\n      threadString = ThreadType.lstrip('(M')\n      dia = float(ThreadType.rstrip(')'))\n    else:\n      dia=float(ThreadType.lstrip('M'))\n    '''\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit l: \" + str(l) + \"\\n\")\n    if (SType == 'ISO1207') or (SType == 'ISO14580'):\n       P, a, b, dk, dk_mean, da, k, n_min, r, t_min, x = iso1207def[ThreadType]\n    if SType == 'ISO7048':\n       P, a, b, dk, dk_mean, da, k, r, x, cT, mH, mZ  = iso7048def[ThreadType]\n    if (SType == 'ISO14580'):\n       tt, k, A, t_min = iso14580def[ThreadType]\n\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit iso: \" + str(dk) + \"\\n\")\n\n    #Length for calculation of head fillet\n    r_fil = r*2.0\n    beta = math.radians(5.0)   # angle of cheese head edge\n    alpha = math.radians(90.0 - (90.0+5.0)/2.0)\n    tan_beta = math.tan(beta)\n    # top head diameter without fillet\n    rK_top = dk/2.0 - k * tan_beta\n    fillet_center_x = rK_top - r_fil + r_fil * tan_beta\n    fillet_center_z = k - r_fil\n    fillet_arc_x = fillet_center_x + r_fil * math.sin(alpha)\n    fillet_arc_z = fillet_center_z + r_fil * math.cos(alpha)\n    #FreeCAD.Console.PrintMessage(\"rK_top: \" + str(rK_top) + \"\\n\")\n\n    if (b > (l - 1.0*P)):\n       bmax = l- 1.0*P\n    else:\n       bmax = b\n\n    ### make the new code with math.modf(l)\n    residue, turns = math.modf((bmax)/P)\n    halfturns = 2*int(turns)\n    if residue < 0.5:\n      a_point = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a_point = l - (turns+2.0) * P\n    #halfturns = halfturns + 2\n    offSet = r - a_point\n\n    sqrt2_ = 1.0/math.sqrt(2.0)\n\n    #Head Points\n    Pnt2 = Base.Vector(fillet_center_x,0.0,k)\n    Pnt3 = Base.Vector(fillet_arc_x,0.0,fillet_arc_z)\n    Pnt4 = Base.Vector(fillet_center_x + r_fil*math.cos(beta),0.0,fillet_center_z+ r_fil * math.sin(beta))\n    Pnt5 = Base.Vector(dk/2.0,0.0,0.0)\n    Pnt6 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n    Pnt7 = Base.Vector(dia/2.0+r-r*sqrt2_,0.0,-r+r*sqrt2_) #arc-point of fillet\n    Pnt8 = Base.Vector(dia/2.0,0.0,-r)        # end of fillet\n    Pnt9 = Base.Vector(dia/2.0,0.0,-a_point)        # Start of thread\n    #FreeCAD.Console.PrintMessage(\"Points defined fillet_center_x: \" + str(fillet_center_x) + \"\\n\")\n\n    if (SType == 'ISO14580'):\n      # Pnt0 = Base.Vector(0.0,0.0,k-A/4.0) #Center Point for countersunk\n      Pnt0 = Base.Vector(0.0,0.0,k-A/8.0) #Center Point for flat countersunk\n      PntFlat = Base.Vector(A/8.0,0.0,k-A/8.0) # End of flat part\n      Pnt1 = Base.Vector(A/1.99,0.0,k)     #countersunk edge at head\n      edgeCham0 = Part.makeLine(Pnt0,PntFlat)\n      edgeCham1 = Part.makeLine(PntFlat,Pnt1)\n      edgeCham2 = Part.makeLine(Pnt1,Pnt2)\n      edge1 = Part.Wire([edgeCham1,edgeCham2]) # make head with countersunk\n      PntH1 = Base.Vector(A/1.99,0.0, 2.0*k)\n\n    else:\n      Pnt0 = Base.Vector(0.0,0.0,k)\n      edge1 = Part.makeLine(Pnt0,Pnt2)  # make flat head\n\n\n    edge2 = Part.Arc(Pnt2,Pnt3,Pnt4).toShape()\n    edge3 = Part.makeLine(Pnt4,Pnt5)\n    edge4 = Part.makeLine(Pnt5,Pnt6)\n    edge5 = Part.Arc(Pnt6,Pnt7,Pnt8).toShape()\n    #FreeCAD.Console.PrintMessage(\"Edges made fillet_center_z: \" + str(fillet_center_z) + \"\\n\")\n\n    if SType == 'ISO1207':\n      #Parameter for slot-recess: dk, n_min, k, t_min\n      recess = Part.makePlane(dk, n_min, \\\n        Base.Vector(dk/2.0,-n_min/2.0,k+1.0),Base.Vector(0.0,0.0,-1.0))\n      recess = recess.extrude(Base.Vector(0.0,0.0,-t_min-1.0))\n\n      if self.rThread:\n        Pnt11 = Base.Vector(0.0,0.0,-r)        # helper point for real thread\n        edgeZ1 = Part.makeLine(Pnt8,Pnt11)\n        edgeZ0 = Part.makeLine(Pnt11,Pnt0)\n        aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5, \\\n            edgeZ1, edgeZ0])\n      else:\n        # bolt points\n        PntB1 = Base.Vector(dia/2.0,0.0,-l)\n        PntB2 = Base.Vector(0.0,0.0,-l)\n\n        edgeB2 = Part.makeLine(PntB1,PntB2)\n\n        if a_point <= r:\n          edgeB1 = Part.makeLine(Pnt8,PntB1)\n          aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5, \\\n              edgeB1, edgeB2])\n        else:\n          edge6 = Part.makeLine(Pnt8,Pnt9)\n          edgeB1 = Part.makeLine(Pnt9,PntB1)\n          aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5,edge6, \\\n              edgeB1, edgeB2])\n\n      aFace =Part.Face(aWire)\n      head = aFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360.0)\n      head = head.cut(recess)\n      # FreeCAD.Console.PrintMessage(\"der Kopf geschnitten: \" + str(dia) + \"\\n\")\n      #Part.show(head)\n      if self.rThread:\n        screwFaces = []\n        for i in range(0, len(head.Faces)-1):\n          screwFaces.append(head.Faces[i])\n        rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n        for threadFace in rthread.Faces:\n          screwFaces.append(threadFace)\n\n        screwShell = Part.Shell(screwFaces)\n        head = Part.Solid(screwShell)\n\n\n\n    else:\n      if self.rThread:\n        aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5 ])\n      else:\n        # bolt points\n        PntB1 = Base.Vector(dia/2.0,0.0,-l)\n        PntB2 = Base.Vector(0.0,0.0,-l)\n\n        edgeB2 = Part.makeLine(PntB1,PntB2)\n\n        if a_point <= r:\n          edgeB1 = Part.makeLine(Pnt8,PntB1)\n          aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5, \\\n              edgeB1, edgeB2])\n        else:\n          edge6 = Part.makeLine(Pnt8,Pnt9)\n          edgeB1 = Part.makeLine(Pnt9,PntB1)\n          aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5,edge6, \\\n              edgeB1, edgeB2])\n\n      #aFace =Part.Face(aWire)\n      headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360.0)\n      #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n\n      if SType == 'ISO7048':\n        # hCut should be just a cylinder\n        hCut = Part.makeCylinder(fillet_center_x,k,Pnt0)\n        recess, recessShell = self.makeCross_H3(cT, mH, k)\n        recessShell = recessShell.cut(hCut)\n        topFace = headShell.Faces[0].cut(recess)\n        screwFaces = [topFace.Faces[0]]\n        screwFaces.extend(recessShell.Faces)\n      if (SType == 'ISO14580'):\n        # Ring-cutter for recess shell\n        PntH2 = Base.Vector(A/8.0,0.0, 2.0*k)\n        edgeH1 = Part.makeLine(Pnt1,PntH1)\n        edgeH2 = Part.makeLine(PntH1,PntH2)\n        edgeH3 = Part.makeLine(PntH2,PntFlat)\n        hWire = Part.Wire([edgeCham1,edgeH1,edgeH2,edgeH3]) # Cutter for recess-Shell\n        hFace = Part.Face(hWire)\n        hCut = hFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n        #Part.show(hWire)\n\n        recess, recessShell = self.makeIso10664_3(tt, t_min, k)\n        recessShell = recessShell.cut(hCut)\n        topFace = headShell.Faces[0].cut(recess)\n        screwFaces = [topFace.Faces[0]]\n        screwFaces.extend(recessShell.Faces)\n\n      for i in range(1, len(headShell.Faces)):\n        screwFaces.append(headShell.Faces[i])\n\n      if self.rThread:\n        #head = self.cutIsoThread(head, dia, P, turns, l)\n        rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n        #head = head.fuse(rthread)\n        #Part.show(rthread)\n        for threadFace in rthread.Faces:\n          screwFaces.append(threadFace)\n\n      screwShell = Part.Shell(screwFaces)\n      head = Part.Solid(screwShell)\n\n    return head\n\n\n\n  # make the ISO 4017 Hex-head-screw\n  # make the ISO 4014 Hex-head-bolt\n  def makeIso4017_2(self,SType ='ISO4017', ThreadType ='M6',l=40.0):\n    dia = get_diameter(ThreadType)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit l: \" + str(l) + \"\\n\")\n    if SType == 'ISO4017':\n      P, c, dw, e,k,r,s = iso4017head[ThreadType]\n      residue, turns = math.modf((l-1*P)/P)\n      halfturns = 2*int(turns)\n\n    if SType == 'ISO8676':\n      P, c, dw, e,k,r,s = iso8676def[ThreadType]\n      residue, turns = math.modf((l-r-1*P)/P)\n      halfturns = 2*int(turns)\n\n    if SType == 'ISO4014':\n      P, b1, b2, b3, c, dw, e, k, r, s = iso4014head[ThreadType]\n      if l<= 125.0:\n         b = b1\n      else:\n         if l<= 200.0:\n            b = b2\n         else:\n            b = b3\n      residue, turns = math.modf((b)/P)\n      halfturns = 2*int(turns)\n\n    if residue < 0.5:\n      a = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a = l - (turns+2.0) * P\n    #halfturns = halfturns + 2\n    offSet = r - a\n\n    sqrt2_ = 1.0/math.sqrt(2.0)\n    cham = (e-s)*math.sin(math.radians(15)) # needed for chamfer at head top\n\n    #Head Points  Usage of k, s, cham, c, dw, dia, r, a\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit halfturns: \" + str(halfturns) + \"\\n\")\n    Pnt0 = Base.Vector(0.0,0.0,k)\n    Pnt2 = Base.Vector(s/2.0,0.0,k)\n    Pnt3 = Base.Vector(s/math.sqrt(3.0),0.0,k-cham)\n    Pnt4 = Base.Vector(s/math.sqrt(3.0),0.0,c)\n    Pnt5 = Base.Vector(dw/2.0,0.0,c)\n    Pnt6 = Base.Vector(dw/2.0,0.0,0.0)\n    Pnt7 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n    Pnt8 = Base.Vector(dia/2.0+r-r*sqrt2_,0.0,-r+r*sqrt2_) #arc-point of fillet\n    Pnt9 = Base.Vector(dia/2.0,0.0,-r)        # end of fillet\n    Pnt10 = Base.Vector(dia/2.0,0.0,-a)        # Start of thread\n\n    edge1 = Part.makeLine(Pnt0,Pnt2)\n    edge2 = Part.makeLine(Pnt2,Pnt3)\n    edge3 = Part.makeLine(Pnt3,Pnt4)\n    edge4 = Part.makeLine(Pnt4,Pnt5)\n    edge5 = Part.makeLine(Pnt5,Pnt6)\n    edge6 = Part.makeLine(Pnt6,Pnt7)\n    edge7 = Part.Arc(Pnt7,Pnt8,Pnt9).toShape()\n\n    # create cutting tool for hexagon head\n    # Parameters s, k, outer circle diameter =  e/2.0+10.0\n    extrude = self.makeHextool(s, k, s*2.0)\n\n    #if self.RealThread.isChecked():\n    if self.rThread:\n      Pnt11 = Base.Vector(0.0,0.0,-r)        # helper point for real thread\n      edgeZ1 = Part.makeLine(Pnt9,Pnt11)\n      edgeZ0 = Part.makeLine(Pnt11,Pnt0)\n      aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5,edge6,edge7, \\\n          edgeZ1, edgeZ0])\n\n      aFace =Part.Face(aWire)\n      head = aFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360.0)\n      #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n\n      # Part.show(extrude)\n      head = head.cut(extrude)\n      #FreeCAD.Console.PrintMessage(\"der Kopf geschnitten: \" + str(dia) + \"\\n\")\n      #Part.show(head)\n\n      headFaces = []\n      for i in range(18):\n        headFaces.append(head.Faces[i])\n\n      if (dia < 3.0) or (dia > 5.0):\n        rthread = self.makeShellthread(dia, P, halfturns, True, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a-2.0*P))\n        #rthread.translate(Base.Vector(0.0, 0.0,-2.0*P))\n        #Part.show(rthread)\n        for tFace in rthread.Faces:\n          headFaces.append(tFace)\n        headShell = Part.Shell(headFaces)\n        head = Part.Solid(headShell)\n      else:\n        rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a-2.0*P))\n        #rthread.translate(Base.Vector(0.0, 0.0,-2.0*P))\n        #Part.show(rthread)\n        for tFace in rthread.Faces:\n          headFaces.append(tFace)\n        headShell = Part.Shell(headFaces)\n        head = Part.Solid(headShell)\n        cyl = self.cutChamfer(dia, P, l)\n        #FreeCAD.Console.PrintMessage(\"vor Schnitt Ende: \" + str(dia) + \"\\n\")\n        head = head.cut(cyl)\n\n    else:\n      # bolt points\n      cham_t = P*math.sqrt(3.0)/2.0*17.0/24.0\n\n      PntB0 = Base.Vector(0.0,0.0,-a)\n      PntB1 = Base.Vector(dia/2.0,0.0,-l+cham_t)\n      PntB2 = Base.Vector(dia/2.0-cham_t,0.0,-l)\n      PntB3 = Base.Vector(0.0,0.0,-l)\n\n      edgeB1 = Part.makeLine(Pnt10,PntB1)\n      edgeB2 = Part.makeLine(PntB1,PntB2)\n      edgeB3 = Part.makeLine(PntB2,PntB3)\n\n      edgeZ0 = Part.makeLine(PntB3,Pnt0)\n      if a <= r:\n        edgeB1 = Part.makeLine(Pnt9,PntB1)\n        aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5,edge6,edge7, \\\n            edgeB1, edgeB2, edgeB3, edgeZ0])\n\n      else:\n        edge8 = Part.makeLine(Pnt9,Pnt10)\n        edgeB1 = Part.makeLine(Pnt10,PntB1)\n        aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5,edge6,edge7,edge8, \\\n            edgeB1, edgeB2, edgeB3, edgeZ0])\n\n      aFace =Part.Face(aWire)\n      head = aFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360.0)\n      #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n\n      # Part.show(extrude)\n      head = head.cut(extrude)\n      #FreeCAD.Console.PrintMessage(\"der Kopf geschnitten: \" + str(dia) + \"\\n\")\n\n    return head\n\n\n  # EN 1662 Hex-head-bolt with flange - small series\n  # EN 1665 Hexagon bolts with flange, heavy series\n  def makeEN1662_2(self,SType ='EN1662', ThreadType ='M8',l=25.0):\n    dia = get_diameter(ThreadType)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit l: \" + str(l) + \"\\n\")\n    if SType == 'EN1662':\n       P, b0, b1, b2, b3, c, dc, dw, e, k, kw,f, r1, s = en1662def[ThreadType]\n    else:\n       P, b0, b1, b2, b3, c, dc, dw, e, k, kw,f, r1, s = en1665def[ThreadType]\n    if l< b0:\n       b = l - 2*P\n    else:\n       if l<= 125.0:\n          b = b1\n       else:\n          if l<= 200.0:\n             b = b2\n          else:\n             b = b3\n\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit isoEN1662: \" + str(c) + \"\\n\")\n    cham = s*(2.0/math.sqrt(3.0)-1.0)*math.sin(math.radians(25)) # needed for chamfer at head top\n\n    ### make the new code with math.modf(l)\n    residue, turns = math.modf((b)/P)\n    halfturns = 2*int(turns)\n    if residue < 0.5:\n      a_point = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a_point = l - (turns+2.0) * P\n    #halfturns = halfturns + 2\n    offSet = r1 - a_point\n\n    sqrt2_ = 1.0/math.sqrt(2.0)\n\n    # Flange is made with a radius of c\n    beta = math.radians(25.0)\n    tan_beta = math.tan(beta)\n\n    # Calculation of Arc points of flange edge using dc and c\n    arc1_x = dc/2.0 - c/2.0 + (c/2.0)*math.sin(beta)\n    arc1_z = c/2.0 + (c/2.0)*math.cos(beta)\n\n    hF = arc1_z + (arc1_x -s/2.0) * tan_beta  # height of flange at center\n\n    kmean = arc1_z + (arc1_x - s/math.sqrt(3.0)) * tan_beta + kw * 1.1 + cham\n    #kmean = k * 0.95\n\n\n    #Hex-Head Points\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit math a: \" + str(a_point) + \"\\n\")\n    PntH0 = Base.Vector(0.0,0.0,kmean*0.9)\n    PntH1 = Base.Vector(s/2.0*0.8 - r1/2.0,0.0,kmean*0.9)\n    PntH1a = Base.Vector(s/2.0*0.8-r1/2.0+r1/2.0*sqrt2_,0.0,kmean*0.9 +r1/2.0 -r1/2.0*sqrt2_)\n    PntH1b = Base.Vector(s/2.0*0.8,0.0,kmean*0.9 +r1/2.0)\n    PntH2 = Base.Vector(s/2.0*0.8,0.0,kmean -r1)\n    PntH2a = Base.Vector(s/2.0*0.8+r1-r1*sqrt2_,0.0,kmean -r1 +r1*sqrt2_)\n    PntH2b = Base.Vector(s/2.0*0.8 + r1 ,0.0,kmean)\n    PntH3 = Base.Vector(s/2.0,0.0,kmean)\n    #PntH4 = Base.Vector(s/math.sqrt(3.0),0.0,kmean-cham)   #s/math.sqrt(3.0)\n    #PntH5 = Base.Vector(s/math.sqrt(3.0),0.0,c)\n    #PntH6 = Base.Vector(0.0,0.0,c)\n\n    edgeH1 = Part.makeLine(PntH0,PntH1)\n    edgeH2 = Part.Arc(PntH1,PntH1a,PntH1b).toShape()\n    edgeH3 = Part.makeLine(PntH1b,PntH2)\n    edgeH3a = Part.Arc(PntH2,PntH2a,PntH2b).toShape()\n    edgeH3b = Part.makeLine(PntH2b,PntH3)\n\n    hWire=Part.Wire([edgeH1,edgeH2,edgeH3,edgeH3a,edgeH3b])\n    topShell = hWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(hWire)\n    #Part.show(topShell)\n\n    # create a cutter ring to generate the chamfer at the top of the hex\n    chamHori = s/math.sqrt(3.0) - s/2.0\n    PntC1 = Base.Vector(s/2.0-chamHori,0.0,kmean+kmean)\n    PntC2 = Base.Vector(s/math.sqrt(3.0)+chamHori,0.0,kmean+kmean)\n    PntC3 = Base.Vector(s/2.0-chamHori,0.0,kmean+cham)\n    PntC4 = Base.Vector(s/math.sqrt(3.0)+chamHori,0.0,kmean-cham-cham)   #s/math.sqrt(3.0)\n    edgeC1 = Part.makeLine(PntC3, PntC1)\n    edgeC2 = Part.makeLine(PntC1, PntC2)\n    edgeC3 = Part.makeLine(PntC2, PntC4)\n    edgeC4 = Part.makeLine(PntC4, PntC3)\n    cWire = Part.Wire([edgeC4, edgeC1, edgeC2, edgeC3])\n    cFace = Part.Face(cWire)\n    chamCut = cFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(cWire)\n    #Part.show(chamCut)\n\n\n    # create hexagon\n    mhex=Base.Matrix()\n    mhex.rotateZ(math.radians(60.0))\n    polygon = []\n    vhex=Base.Vector(s/math.sqrt(3.0),0.0,kmean)\n    for i in range(6):\n       polygon.append(vhex)\n       vhex = mhex.multiply(vhex)\n    polygon.append(vhex)\n    hexagon = Part.makePolygon(polygon)\n    hexFace = Part.Face(hexagon)\n    solidHex = hexFace.extrude(Base.Vector(0.0,0.0,c-kmean))\n    #Part.show(solidHex)\n    hexCham = solidHex.cut(chamCut)\n    #Part.show(hexCham)\n\n    topFaces = topShell.Faces\n\n    topFaces.append(hexCham.Faces[6])\n    topFaces.append(hexCham.Faces[12])\n    topFaces.append(hexCham.Faces[14])\n    topFaces.append(hexCham.Faces[13])\n    topFaces.append(hexCham.Faces[8])\n    topFaces.append(hexCham.Faces[2])\n    topFaces.append(hexCham.Faces[1])\n\n    hexFaces = [hexCham.Faces[5], hexCham.Faces[11], hexCham.Faces[10]]\n    hexFaces.extend([hexCham.Faces[9], hexCham.Faces[3], hexCham.Faces[0]])\n    hexShell = Part.Shell(hexFaces)\n\n    # Center of flange:\n    Pnt0 = Base.Vector(0.0,0.0,hF)\n    Pnt1 = Base.Vector(s/2.0,0.0,hF)\n\n    # arc edge of flange:\n    Pnt2 = Base.Vector(arc1_x,0.0,arc1_z)\n    Pnt3 = Base.Vector(dc/2.0,0.0,c/2.0)\n    Pnt4 = Base.Vector((dc-c)/2.0,0.0,0.0)\n\n    Pnt5 = Base.Vector(dia/2.0+r1,0.0,0.0)     #start of fillet between head and shank\n    Pnt6 = Base.Vector(dia/2.0+r1-r1*sqrt2_,0.0,-r1+r1*sqrt2_) #arc-point of fillet\n    Pnt7 = Base.Vector(dia/2.0,0.0,-r1)        # end of fillet\n    Pnt8 = Base.Vector(dia/2.0,0.0,-a_point)        # Start of thread\n\n    edge1 = Part.makeLine(Pnt0,Pnt1)\n    edge2 = Part.makeLine(Pnt1,Pnt2)\n    edge3 = Part.Arc(Pnt2,Pnt3,Pnt4).toShape()\n    edge4 = Part.makeLine(Pnt4,Pnt5)\n    edge5 = Part.Arc(Pnt5,Pnt6,Pnt7).toShape()\n\n    # make a cutter for the hexShell\n    PntHC1 = Base.Vector(0.0,0.0,arc1_z)\n    PntHC2 = Base.Vector(0.0,0.0,0.0)\n\n    edgeHC1 = Part.makeLine(Pnt2,PntHC1)\n    edgeHC2 = Part.makeLine(PntHC1,PntHC2)\n    edgeHC3 = Part.makeLine(PntHC2,Pnt0)\n\n    HCWire = Part.Wire([edge2, edgeHC1, edgeHC2, edgeHC3, edge1])\n    HCFace = Part.Face(HCWire)\n    hex2Cut = HCFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n\n    hexShell = hexShell.cut(hex2Cut)\n    #Part.show(hexShell)\n\n    topFaces.extend(hexShell.Faces)\n\n    # bolt points\n    cham_t = P*math.sqrt(3.0)/2.0*17.0/24.0\n\n    PntB0 = Base.Vector(0.0,0.0,-a_point)\n    PntB1 = Base.Vector(dia/2.0,0.0,-l+cham_t)\n    PntB2 = Base.Vector(dia/2.0-cham_t,0.0,-l)\n    PntB3 = Base.Vector(0.0,0.0,-l)\n\n    edgeB2 = Part.makeLine(PntB1,PntB2)\n    edgeB3 = Part.makeLine(PntB2,PntB3)\n\n    #if self.RealThread.isChecked():\n    if self.rThread:\n      aWire=Part.Wire([edge2,edge3,edge4,edge5])\n      boltIndex = 4\n\n    else:\n      if a_point <=r1:\n        edgeB1 = Part.makeLine(Pnt7,PntB1)\n        aWire=Part.Wire([edge2,edge3,edge4,edge5, edgeB1, edgeB2, edgeB3])\n        boltIndex = 7\n      else:\n        edgeB1 = Part.makeLine(Pnt8,PntB1)\n        edge6 = Part.makeLine(Pnt7,Pnt8)\n        aWire=Part.Wire([edge2,edge3,edge4,edge5,edge6, \\\n            edgeB1, edgeB2, edgeB3])\n        boltIndex = 8\n\n\n    #aFace =Part.Face(aWire)\n    #Part.show(aWire)\n    headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n    #Part.show(headShell)\n    chamFace = headShell.Faces[0].cut(solidHex)\n    #Part.show(chamFace)\n\n    topFaces.append(chamFace.Faces[0])\n    for i in range(1,boltIndex):\n      topFaces.append(headShell.Faces[i])\n\n\n    if self.rThread:\n      if (dia < 3.0) or (dia > 5.0):\n        rthread = self.makeShellthread(dia, P, halfturns, True, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point-2.0*P))\n        for tFace in rthread.Faces:\n          topFaces.append(tFace)\n        headShell = Part.Shell(topFaces)\n        screw = Part.Solid(headShell)\n      else:\n        rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point-2.0*P))\n        for tFace in rthread.Faces:\n          topFaces.append(tFace)\n        headShell = Part.Shell(topFaces)\n        head = Part.Solid(headShell)\n        cyl = self.cutChamfer(dia, P, l)\n        #FreeCAD.Console.PrintMessage(\"vor Schnitt Ende: \" + str(dia) + \"\\n\")\n        screw = head.cut(cyl)\n    else:\n      screwShell = Part.Shell(topFaces)\n      screw = Part.Solid(screwShell)\n\n    return screw\n\n  def makeIso7046(self, SType ='ISO7046', ThreadType ='M6', l=25.0):\n    \"\"\"ISO 7046, ISO 7047, ISO 10642, ISO 14582, ISO 14584\n\n    Used for ISO 7046 countersunk flat head screws with H cross recess\n    Used for ISO 7047 raised countersunk head screws with H cross recess\n    Used for ISO 10642 Hexagon socket countersunk head screws\n    Used for ISO 14582 Hexalobular socket countersunk head screws, high head\n    Used for ISO 14584 Hexalobular socket raised countersunk head screws\n    \"\"\"\n    dia = get_diameter(ThreadType)\n    #FreeCAD.Console.PrintMessage(\"The 2009 head with l: \" + str(l) + \"\\n\")\n    if (SType == 'ISO10642'):\n      P,b,dk_theo,dk_mean,da, ds_min, e, k, r, s_mean, t, w =iso10642def[ThreadType]\n      ePrax = s_mean / math.sqrt(3.0) / 0.99\n      ht = 0.0\n      a = 2*P\n      t_mean = t\n    else: #still need the data from iso2009def, but this screw can not created here\n      P, a, b, dk_theo, dk_mean, k, n_min, r, t_mean, x = iso2009def[ThreadType]\n      ht = 0.0 # Head height of flat head\n    if SType == 'ISO7046':\n      cT, mH, mZ  = iso7046def[ThreadType]\n    if (SType == 'ISO7047'):\n      rf, t_mean, cT, mH, mZ = Raised_countersunk_def[ThreadType]\n      #Lengths and angles for calculation of head rounding\n      beta = math.asin(dk_mean /2.0 / rf)   # angle of head edge\n      tan_beta = math.tan(beta)\n      alpha = beta/2.0 # half angle\n      # height of raised head top\n      ht = rf - (dk_mean/2.0) / tan_beta\n      #print 'he: ', he\n      h_arc_x = rf * math.sin(alpha)\n      h_arc_z = ht - rf + rf * math.cos(alpha)\n      #FreeCAD.Console.PrintMessage(\"h_arc_z: \" + str(h_arc_z) + \"\\n\")\n\n    if (SType == 'ISO14582'):\n      P, a, b, dk_theo, dk_mean, k, r, tt, A, t_mean = iso14582def[ThreadType]\n      ePrax = A / 2.0 / 0.99\n\n    if (SType == 'ISO14584'):\n      P, b, dk_theo, dk_mean, f, k, r, rf, x, tt, A, t_mean = iso14584def[ThreadType]\n      ePrax = A / 2.0 / 0.99\n      #Lengths and angles for calculation of head rounding\n      beta = math.asin(dk_mean /2.0 / rf)   # angle of head edge\n      tan_beta = math.tan(beta)\n      ctp = - (dk_mean/2.0) / tan_beta # Center Top Edge = center for rf\n      betaA = math.asin(ePrax / rf)   # angle of head edge at start of recess\n      ht = ctp + ePrax / math.tan(betaA)\n      alpha = betaA + (beta - betaA)/2.0 # half angle of top Arc\n      h_arc_x = rf * math.sin(alpha)\n      h_arc_z = ctp + rf * math.cos(alpha)\n\n\n    FreeCAD.Console.PrintMessage(\"The head with iso r: \" + str(r) + \"\\n\")\n    cham = (dk_theo - dk_mean)/2.0\n    rad225 = math.radians(22.5)\n    rad45 = math.radians(45.0)\n    rtan = r*math.tan(rad225)\n    #FreeCAD.Console.PrintMessage(\"Checking rtan: \" + str(rtan) + \"\\n\")\n\n    if (b > (l - k - rtan/2.0 - 1.0*P)):\n      bmax = l - k - rtan/2.0 - 1.0*P\n    else:\n      bmax = b\n\n    ### make the new code with math.modf(l)\n    residue, turns = math.modf((bmax)/P)\n    halfturns = 2*int(turns)\n    if residue < 0.5:\n      a_point = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a_point = l - (turns+2.0) * P\n    #halfturns = halfturns + 2\n    offSet = k + rtan - a_point\n\n    #Head Points\n    Pnt1 = Base.Vector(dk_mean/2.0,0.0,0.0)\n    Pnt2 = Base.Vector(dk_mean/2.0,0.0,-cham)\n    Pnt3 = Base.Vector(dia/2.0+r-r*math.cos(rad45),0.0,-k-rtan+r*math.sin(rad45))\n\n    # Arc-points\n    Pnt4 = Base.Vector(dia/2.0+r-r*(math.cos(rad225)),0.0,-k-rtan+r*math.sin(rad225))\n    Pnt5 = Base.Vector(dia/2.0,0.0,-k-rtan)\n    Pnt6 = Base.Vector(dia/2.0,0.0,-a_point)\n\n    if (SType == 'ISO10642') or (SType == 'ISO14582'):\n      if (SType == 'ISO10642'):\n        recess, recessShell = self.makeAllen2(s_mean, t_mean, 0.0 )\n        Pnt0 = Base.Vector(ePrax/2.0,0.0,-ePrax/2.0)\n        PntCham = Base.Vector(ePrax,0.0,0.0)\n        edge1 = Part.makeLine(Pnt0,PntCham)\n        edgeCham2 = Part.makeLine(PntCham,Pnt1)\n        edge2 = Part.makeLine(Pnt1,Pnt2)\n        edge2 = Part.Wire([edgeCham2,edge2])\n        PntH0 = Base.Vector(ePrax/2.0,0.0, ht + k)\n        PntH1 = Base.Vector(ePrax,0.0, ht + k)\n      if (SType == 'ISO14582'):\n        recess, recessShell = self.makeIso10664_3(tt, t_mean, 0.0) # hexalobular recess\n        Pnt0 = Base.Vector(0.0,0.0,0.0)\n        edge1 = Part.makeLine(Pnt0,Pnt1)\n        edge2 = Part.makeLine(Pnt1,Pnt2)\n\n\n      # bolt points with bolt chamfer\n      cham_b = P*math.sqrt(3.0)/2.0*17.0/24.0\n\n      PntB1 = Base.Vector(dia/2.0,0.0,-l+cham_b)\n      PntB2 = Base.Vector(dia/2.0-cham_b,0.0,-l)\n      PntB3 = Base.Vector(0.0,0.0,-l)\n      if a_point <= (k + rtan):\n        edgeB0 = Part.makeLine(Pnt5,PntB1)\n      else:\n        edgeB0 = Part.makeLine(Pnt6,PntB1)\n      edgeB2 = Part.makeLine(PntB1,PntB2)\n      edgeB3 = Part.makeLine(PntB2,PntB3)\n      edgeB1 = Part.Wire([edgeB2,edgeB3])\n\n    else:\n      # bolt points\n      PntB1 = Base.Vector(dia/2.0,0.0,-l)\n      PntB2 = Base.Vector(0.0,0.0,-l)\n      if a_point <= (k + rtan):\n        edgeB0 = Part.makeLine(Pnt5,PntB1)\n      else:\n        edgeB0 = Part.makeLine(Pnt6,PntB1)\n      edgeB1 = Part.makeLine(PntB1,PntB2)\n\n      if (SType == 'ISO7047'): # make raised head rounding\n        Pnt0 = Base.Vector(0.0,0.0,ht)\n        Pnt0arc = Base.Vector(h_arc_x,0.0,h_arc_z)\n        edge1 = Part.Arc(Pnt0,Pnt0arc,Pnt1).toShape()\n        edge2 = Part.makeLine(Pnt1,Pnt2)\n        PntH0 = Base.Vector(0.0,0.0, ht + k)\n        PntH1 = Base.Vector(dk_mean/2.0,0.0, ht + k)\n        recess, recessShell = self.makeCross_H3(cT, mH, ht)\n      if (SType == 'ISO7046'):\n        # ISO7046\n        FreeCAD.Console.PrintMessage(\"ISO7046: \" + str(ht) + \"\\n\")\n        Pnt0 = Base.Vector(0.0,0.0,ht)\n        edge1 = Part.makeLine(Pnt0,Pnt1)  # make flat head\n        edge2 = Part.makeLine(Pnt1,Pnt2)\n        recess, recessShell = self.makeCross_H3(cT, mH, ht)\n\n      if (SType == 'ISO14584'): # make raised head rounding with chamfer\n        Pnt0 = Base.Vector(ePrax/2.0,0.0,ht-ePrax/4.0)\n        PntCham = Base.Vector(ePrax,0.0,ht)\n        PntArc = Base.Vector(h_arc_x,0.0,h_arc_z)\n        edge1 = Part.makeLine(Pnt0,PntCham)\n        edgeArc = Part.Arc(PntCham,PntArc,Pnt1).toShape()\n        edge2 = Part.makeLine(Pnt1,Pnt2)\n        edge2 = Part.Wire([edgeArc,edge2])\n        PntH0 = Base.Vector(ePrax/2.0,0.0, ht + k)\n        PntH1 = Base.Vector(ePrax,0.0, ht + k)\n        recess, recessShell = self.makeIso10664_3(tt, t_mean, ht) # hexalobular recess\n\n    edge3 = Part.makeLine(Pnt2,Pnt3)\n    edgeArc = Part.Arc(Pnt3,Pnt4,Pnt5).toShape()\n    edgeArc1 = Part.makeLine(Pnt3,Pnt4)\n    edgeArc2 = Part.makeLine(Pnt4,Pnt5)\n    edge6 = Part.makeLine(Pnt5,Pnt6)\n\n    if self.rThread:\n      #aWire=Part.Wire([edge1,edge2,edge3,edgeArc])\n      aWire=Part.Wire([edge2,edge3,edgeArc])\n    else:\n      if a_point <= (k + rtan):\n        aWire=Part.Wire([edge2,edge3,edgeArc, edgeB0, edgeB1])\n      else:\n        aWire=Part.Wire([edge2,edge3,edgeArc,edge6, edgeB0, edgeB1])\n\n    #Part.show(aWire)\n    headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    headFaces = headShell.Faces\n    #Part.show(headShell)\n\n    if (SType == 'ISO7046') or (SType == 'ISO14582'):\n      # hCut is just a cylinder for ISO7046\n      hCut = Part.makeCylinder(dk_mean/2.0,k,Pnt0)\n      #Part.show(hCut)\n      topFace = hCut.Faces[2]\n    else:\n      if (SType == 'ISO7047'):\n        edgeH1 = Part.makeLine(Pnt1,PntH1)\n      else:\n        edgeH1 = Part.makeLine(PntCham,PntH1)\n      edgeH2 = Part.makeLine(PntH1,PntH0)\n      edgeH3 = Part.makeLine(PntH0,Pnt0)\n      hWire = Part.Wire([edge1,edgeH1,edgeH2,edgeH3]) # Cutter for recess-Shell\n      hFace = Part.Face(hWire)\n      hCut = hFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n      Part.show(hWire)\n      #Part.show(hCut)\n      topFace = hCut.Faces[0]\n\n    recessShell = recessShell.cut(hCut)\n    topFace = topFace.cut(recess)\n    #Part.show(topFace)\n    #Part.show(recessShell)\n    #Part.show(headShell)\n    headFaces.append(topFace.Faces[0])\n    headFaces.extend(recessShell.Faces)\n\n\n    if (SType == 'ISO10642') or (SType == 'ISO14582'):\n      if self.rThread:\n        if (dia < 3.0) or (dia > 5.0):\n          #if True:\n          rthread = self.makeShellthread(dia, P, halfturns, True, offSet)\n          rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n          #head = head.fuse(rthread)\n          #Part.show(rthread)\n          for threadFace in rthread.Faces:\n            headFaces.append(threadFace)\n\n          screwShell = Part.Shell(headFaces)\n          screw = Part.Solid(screwShell)\n        else:\n          '''\n          # head = self.cutIsoThread(head, dia, P, turns, l)\n          rthread = self.makeShellthread(dia, P, halfturns, False)\n          rthread.translate(Base.Vector(0.0, 0.0,-a_point-2.0*P))\n          head = head.fuse(rthread)\n          head = head.removeSplitter()\n          cyl = self.cutChamfer(dia, P, l)\n          #FreeCAD.Console.PrintMessage(\"vor Schnitt Ende: \" + str(dia) + \"\\n\")\n          head = head.cut(cyl)\n          '''\n\n          rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n          rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n          #head = head.fuse(rthread)\n          #Part.show(rthread)\n          for threadFace in rthread.Faces:\n            headFaces.append(threadFace)\n\n          screwShell = Part.Shell(headFaces)\n          screw = Part.Solid(screwShell)\n          cyl = self.cutChamfer(dia, P, l)\n          screw = screw.cut(cyl)\n      else:\n        screwShell = Part.Shell(headFaces)\n        screw = Part.Solid(screwShell)\n\n    else:\n      if self.rThread:\n        rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n        #head = head.fuse(rthread)\n        #Part.show(rthread)\n        for threadFace in rthread.Faces:\n          headFaces.append(threadFace)\n\n      screwShell = Part.Shell(headFaces)\n      screw = Part.Solid(screwShell)\n\n    return screw\n\n  def makeIso4762(self, SType ='ISO4762', ThreadType ='M6',l=25.0):\n    \"\"\"ISO 4762 Allen Screw head and ISO 14579 Hexalobular socket head cap\n    \"\"\"\n    dia = get_diameter(ThreadType)\n    #FreeCAD.Console.PrintMessage(\"der 4762Kopf mit l: \" + str(l) + \"\\n\")\n    P, b, dk_max, da, ds_mean, e, lf, k, r, s_mean, t, v, dw, w = iso4762def[ThreadType]\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit iso r: \" + str(r) + \"\\n\")\n    if SType == 'ISO14579':\n      tt, A, t = iso14579def[ThreadType]\n      #Head Points 30\u00b0 countersunk\n      # Pnt0 = Base.Vector(0.0,0.0,k-A/4.0) #Center Point for countersunk\n      Pnt0 = Base.Vector(0.0,0.0,k-A/8.0) #Center Point for flat countersunk\n      PntFlat = Base.Vector(A/8.0,0.0,k-A/8.0) # End of flat part\n      Pnt1 = Base.Vector(A/1.99,0.0,k)     #countersunk edge at head\n      edgeCham0 = Part.makeLine(Pnt0,PntFlat)\n      edgeCham1 = Part.makeLine(PntFlat,Pnt1)\n      edge1 = Part.Wire([edgeCham0,edgeCham1])\n\n      # Here is the next approach to shorten the head building time\n      # Make two helper points to create a cutting tool for the\n      # recess and recess shell.\n      PntH1 = Base.Vector(A/1.99,0.0, 2.0*k)\n\n    else:\n      e_cham = 2.0 * s_mean / math.sqrt(3.0)\n      #Head Points 45\u00b0 countersunk\n      Pnt0 = Base.Vector(0.0,0.0,k-e_cham/1.99/2.0) #Center Point for countersunk\n      PntFlat = Base.Vector(e_cham/1.99/2.0,0.0,k-e_cham/1.99/2.0) # End of flat part\n      Pnt1 = Base.Vector(e_cham/1.99,0.0,k)     #countersunk edge at head\n      edgeCham0 = Part.makeLine(Pnt0,PntFlat)\n      edgeCham1 = Part.makeLine(PntFlat,Pnt1)\n      edge1 = Part.Wire([edgeCham0,edgeCham1])\n      PntH1 = Base.Vector(e_cham/1.99,0.0, 2.0*k)\n\n\n    PntH2 = Base.Vector(0.0,0.0, 2.0*k)\n    edgeH1 = Part.makeLine(Pnt1,PntH1)\n    edgeH2 = Part.makeLine(PntH1,PntH2)\n    edgeH3 = Part.makeLine(PntH2,Pnt0)\n    hWire = Part.Wire([edge1,edgeH1,edgeH2,edgeH3]) # Cutter for recess-Shell\n    hFace = Part.Face(hWire)\n    hCut = hFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(hWire)\n    '''\n\n\n    PntH2 = Base.Vector(A/8.0,0.0, 2.0*k)\n    edgeH1 = Part.makeLine(Pnt1,PntH1)\n    edgeH2 = Part.makeLine(PntH1,PntH2)\n    edgeH3 = Part.makeLine(PntH2,PntFlat)\n    hWire = Part.Wire([edgeCham1,edgeH1,edgeH2,edgeH3]) # Cutter for recess-Shell\n    hFace = Part.Face(hWire)\n    hCut = hFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(hWire)\n    '''\n\n\n    sqrt2_ = 1.0/math.sqrt(2.0)\n    #depth = s_mean / 3.0\n\n    '''\n    if (b > l - 2*P):\n       bmax = l-2*P\n    else:\n       bmax = b\n    halfturns = round(2.0*(bmax+P)/P) # number of thread turns\n    if self.RealThread.isChecked():\n      a_real = l-(halfturns+2)*P/2.0  # point to fuse real thread\n    else:\n      a_real = l-halfturns*P/2.0  # starting point of thread\n    if a_real < r:\n      a_point = r*1.3\n    else:\n      a_point = a_real\n    '''\n\n\n    if (b > (l - 1.0*P)):\n       bmax = l- 1.0*P\n    else:\n       bmax = b\n\n    ### make the new code with math.modf(l)\n    residue, turns = math.modf((bmax)/P)\n    halfturns = 2*int(turns)\n    if residue < 0.5:\n      a_point = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a_point = l - (turns+2.0) * P\n    #halfturns = halfturns + 2\n    offSet = r - a_point\n    #FreeCAD.Console.PrintMessage(\"The transition at a: \" + str(a) + \" turns \" + str(turns) + \"\\n\")\n\n\n\n\n    #rad30 = math.radians(30.0)\n    #Head Points\n    Pnt2 = Base.Vector(dk_max/2.0-v,0.0,k)   #start of fillet\n    Pnt3 = Base.Vector(dk_max/2.0-v+v*sqrt2_,0.0,k-v+v*sqrt2_) #arc-point of fillet\n    Pnt4 = Base.Vector(dk_max/2.0,0.0,k-v)   #end of fillet\n    Pnt5 = Base.Vector(dk_max/2.0,0.0,(dk_max-dw)/2.0) #we have a chamfer here\n    Pnt6 = Base.Vector(dw/2.0,0.0,0.0)           #end of chamfer\n    Pnt7 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n    Pnt8 = Base.Vector(dia/2.0+r-r*sqrt2_,0.0,-r+r*sqrt2_) #arc-point of fillet\n    Pnt9 = Base.Vector(dia/2.0,0.0,-r)        # end of fillet\n    Pnt10 = Base.Vector(dia/2.0,0.0,-a_point)        # start of thread\n\n    edge1 = Part.makeLine(Pnt0,Pnt1)\n    edge2 = Part.makeLine(Pnt1,Pnt2)\n    edge3 = Part.Arc(Pnt2,Pnt3,Pnt4).toShape()\n    edge4 = Part.makeLine(Pnt4,Pnt5)\n    edge5 = Part.makeLine(Pnt5,Pnt6)\n    edge6 = Part.makeLine(Pnt6,Pnt7)\n    edge7 = Part.Arc(Pnt7,Pnt8,Pnt9).toShape()\n\n    '''\n    # bolt points\n    PntB1 = Base.Vector(dia/2.0,0.0,-l-P)  # Chamfer is made with a cut later\n    PntB2 = Base.Vector(0.0,0.0,-l-P)\n    #PntB3 = Base.Vector(0.0,0.0,-l)\n\n    edgeB0 = Part.makeLine(Pnt10,PntB1)\n    edgeB1 = Part.makeLine(PntB1,PntB2)\n    #edgeB2 = Part.makeLine(PntB2,PntB3)\n    edgeZ0 = Part.makeLine(PntB2,Pnt0)\n\n\n    aWire=Part.Wire([edge1,edge2,edge3,edge4,edge5,edge6,edge7,edge8, \\\n        edgeB0, edgeB1, edgeZ0])\n    '''\n\n\n\n    if self.rThread:\n      aWire=Part.Wire([edge2,edge3,edge4,edge5,edge6,edge7])\n\n    else:\n      # bolt points\n      cham_t = P*math.sqrt(3.0)/2.0*17.0/24.0\n\n      PntB1 = Base.Vector(dia/2.0,0.0,-l+cham_t)\n      PntB2 = Base.Vector(dia/2.0-cham_t,0.0,-l)\n      PntB3 = Base.Vector(0.0,0.0,-l)\n\n      #edgeB1 = Part.makeLine(Pnt10,PntB1)\n      edgeB2 = Part.makeLine(PntB1,PntB2)\n      edgeB3 = Part.makeLine(PntB2,PntB3)\n\n      if a_point <= r:\n        edgeB1 = Part.makeLine(Pnt9,PntB1)\n        aWire=Part.Wire([edge2,edge3,edge4,edge5,edge6,edge7, \\\n            edgeB1, edgeB2, edgeB3])\n      else:\n        edge8 = Part.makeLine(Pnt9,Pnt10)\n        edgeB1 = Part.makeLine(Pnt10,PntB1)\n        aWire=Part.Wire([edge2,edge3,edge4,edge5,edge6,edge7,edge8, \\\n            edgeB1, edgeB2, edgeB3])\n      #Part.show(aWire)\n\n    headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #head = Part.Solid(headShell)\n    #Part.show(aWire)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n    headFaces = headShell.Faces\n\n\n    if SType == 'ISO14579':\n      #recess = self.makeIso10664(tt, t, k) # hexalobular recess\n      recess, recessShell = self.makeIso10664_3(tt, t, k) # hexalobular recess\n    else:\n      recess, recessShell = self.makeAllen2(s_mean, t, k )\n\n    recessShell = recessShell.cut(hCut)\n    topFace = hCut.Faces[1]\n    #topFace = hCut.Faces[0]\n    topFace = topFace.cut(recess)\n    #Part.show(topFace)\n    #Part.show(recessShell)\n    #Part.show(headShell)\n    headFaces.append(topFace.Faces[0])\n    #headFaces.append(hCut.Faces[2])\n\n    #allenscrew = head.cut(recess)\n    #Part.show(hCut)\n    headFaces.extend(recessShell.Faces)\n\n    #if self.RealThread.isChecked():\n    if self.rThread:\n      #if (dia < 3.0) or (dia > 5.0):\n      if True:\n        # head = self.cutIsoThread(head, dia, P, turns, l)\n        rthread = self.makeShellthread(dia, P, halfturns, True, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point-2.0*P))\n        #Part.show(rthread)\n        for tFace in rthread.Faces:\n          headFaces.append(tFace)\n        headShell = Part.Shell(headFaces)\n        allenscrew = Part.Solid(headShell)\n\n      else:\n        # head = self.cutIsoThread(head, dia, P, turns, l)\n        rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point-2.0*P))\n        for tFace in rthread.Faces:\n          headFaces.append(tFace)\n        headShell = Part.Shell(headFaces)\n        allenscrew = Part.Solid(headShell)\n        cyl = self.cutChamfer(dia, P, l)\n        # FreeCAD.Console.PrintMessage(\"vor Schnitt Ende: \" + str(dia) + \"\\n\")\n        allenscrew = allenscrew.cut(cyl)\n    else:\n      headShell = Part.Shell(headFaces)\n      allenscrew = Part.Solid(headShell)\n\n\n    return allenscrew\n\n\n\n\n  # make ISO 7380-1 Button head Screw\n  # make ISO 7380-2 Button head Screw with collar\n  # make DIN 967 cross recessed pan head Screw with collar\n  def makeIso7380(self, SType ='ISO7380-1', ThreadType ='M6',l=25.0):\n    dia = get_diameter(ThreadType)\n    #todo: different radii for screws with thread to head or with shaft?\n    sqrt2_ = 1.0/math.sqrt(2.0)\n\n    if (SType =='DIN967'):\n      P, b, c, da, dk, r, k, rf, x, cT, mH, mZ = din967def[ThreadType]\n\n      rH = rf # radius of button arc\n      alpha = math.acos((rf-k+c)/rf)\n\n      #Head Points\n      Pnt0 = Base.Vector(0.0,0.0,k)\n      PntArc = Base.Vector(rf*math.sin(alpha/2.0),0.0,k-rf + rf*math.cos(alpha/2.0)) #arc-point of button\n      Pnt1 = Base.Vector(rf*math.sin(alpha),0.0,c)     #end of button arc\n      PntC0 = Base.Vector((dk)/2.0,0.0,c)     #collar points\n      PntC2 = Base.Vector((dk)/2.0,0.0,0.0)     #collar points\n      Pnt4 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n\n      edge1 = Part.Arc(Pnt0,PntArc,Pnt1).toShape()\n      edgeC0 = Part.makeLine(Pnt1,PntC0)\n      edgeC1 = Part.makeLine(PntC0,PntC2)\n      edge2 = Part.Wire([edgeC0, edgeC1])\n      edge3 = Part.makeLine(PntC2,Pnt4)\n      #Points for recessShell cutter\n      PntH0 = Base.Vector(0.0,0.0,2.0*k)\n      PntH1 = Base.Vector(rf*math.sin(alpha),0.0,2.0*k)\n      recess, recessShell = self.makeCross_H3(cT, mH, k)\n\n    else:\n      if (SType =='ISO7380-1'):\n        P, b, a, da, dk, dk_mean,s_mean, t_min, r, k, e, w = iso7380def[ThreadType]\n\n        # Bottom of recess\n        e_cham = 2.0 * s_mean / math.sqrt(3.0) / 0.99\n        #depth = s_mean / 3.0\n\n        ak = -(4*k**2 + e_cham**2 - dk**2)/(8*k) # helper value for button arc\n        rH = math.sqrt((dk/2.0)**2 + ak**2) # radius of button arc\n        alpha = (math.atan(2*(k + ak)/e_cham) + math.atan((2*ak)/dk))/2\n\n        Pnt2 = Base.Vector(rH*math.cos(alpha),0.0,-ak + rH*math.sin(alpha)) #arc-point of button\n        Pnt3 = Base.Vector(dk/2.0,0.0,0.0)   #end of fillet\n        Pnt4 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n        edge3 = Part.makeLine(Pnt3,Pnt4)\n\n      if (SType =='ISO7380-2'):\n        P, b, c, da, dk, dk_c,s_mean,t_min, r, k, e, w = iso7380_2def[ThreadType]\n\n        # Bottom of recess\n        e_cham = 2.0 * s_mean / math.sqrt(3.0) / 0.99\n        #depth = s_mean / 3.0\n\n        ak = -(4*(k-c)**2 + e_cham**2 - dk**2)/(8*(k-c)) # helper value for button arc\n        rH = math.sqrt((dk/2.0)**2 + ak**2) # radius of button arc\n        alpha = (math.atan(2*(k -c + ak)/e_cham) + math.atan((2*ak)/dk))/2\n\n        Pnt2 = Base.Vector(rH*math.cos(alpha),0.0,c -ak + rH*math.sin(alpha)) #arc-point of button\n        Pnt3 = Base.Vector(dk/2.0,0.0,c)   #end of fillet\n        Pnt4 = Base.Vector(dia/2.0+r,0.0,0.0)     #start of fillet between head and shank\n        PntC0 = Base.Vector((dk_c-c)/2.0,0.0,c)     #collar points\n        PntC1 = Base.Vector(dk_c/2.0,0.0,c/2.0)     #collar points\n        PntC2 = Base.Vector((dk_c-c)/2.0,0.0,0.0)     #collar points\n\n        edgeC0 = Part.makeLine(Pnt3,PntC0)\n        edgeC1 = Part.Arc(PntC0,PntC1,PntC2).toShape()\n        edge3 = Part.makeLine(PntC2,Pnt4)\n        edge3 = Part.Wire([edgeC0, edgeC1, edge3])\n\n      #Head Points\n      Pnt0 = Base.Vector(e_cham/4.0,0.0,k-e_cham/4.0) #Center Point for chamfer\n      Pnt1 = Base.Vector(e_cham/2.0,0.0,k)     #inner chamfer edge at head\n      #Points for recessShell cutter\n      PntH0 = Base.Vector(e_cham/4.0,0.0,2.0*k)\n      PntH1 = Base.Vector(e_cham/2.0,0.0,2.0*k)\n\n      edge1 = Part.makeLine(Pnt0,Pnt1)\n      edge2 = Part.Arc(Pnt1,Pnt2,Pnt3).toShape()\n      recess, recessShell = self.makeAllen2(s_mean, t_min, k)\n\n    if (b > (l - 1.0*P)):\n       bmax = l- 1.0*P\n    else:\n       bmax = b\n\n    ### make the new code with math.modf(l)\n    residue, turns = math.modf((bmax)/P)\n    halfturns = 2*int(turns)\n    if residue < 0.5:\n      a_point = l - (turns+1.0) * P\n      halfturns = halfturns +1\n    else:\n      halfturns = halfturns + 2\n      a_point = l - (turns+2.0) * P\n    offSet = r - a_point\n\n\n    Pnt5 = Base.Vector(dia/2.0+r-r*sqrt2_,0.0,-r+r*sqrt2_) #arc-point of fillet\n    Pnt6 = Base.Vector(dia/2.0,0.0,-r)        # end of fillet\n    Pnt7 = Base.Vector(dia/2.0,0.0,-a_point)        # start of thread\n\n    edge4 = Part.Arc(Pnt4,Pnt5,Pnt6).toShape()\n    edge5 = Part.makeLine(Pnt6,Pnt7)\n\n    if (SType =='DIN967'):\n      # bolt points\n      PntB1 = Base.Vector(dia/2.0,0.0,-l)\n      PntB2 = Base.Vector(0.0,0.0,-l)\n      edgeB2 = Part.makeLine(PntB1,PntB2)\n    else:\n      # bolt points\n      cham_b = P*math.sqrt(3.0)/2.0*17.0/24.0\n\n      PntB1 = Base.Vector(dia/2.0,0.0,-l+cham_b)\n      PntB2 = Base.Vector(dia/2.0-cham_b,0.0,-l)\n      PntB3 = Base.Vector(0.0,0.0,-l)\n\n      edgeB2 = Part.makeLine(PntB1,PntB2)\n      edgeB3 = Part.makeLine(PntB2,PntB3)\n      edgeB2 = Part.Wire([edgeB2, edgeB3])\n\n    if self.rThread:\n      aWire=Part.Wire([edge2,edge3,edge4])\n    else:\n      if a_point <= r:\n        edgeB1 = Part.makeLine(Pnt6,PntB1)\n        aWire=Part.Wire([edge2,edge3,edge4, edgeB1, edgeB2])\n      else:\n        edge5 = Part.makeLine(Pnt6,Pnt7)\n        edgeB1 = Part.makeLine(Pnt7,PntB1)\n        aWire=Part.Wire([edge2,edge3,edge4,edge5, edgeB1, edgeB2])\n\n    #Part.show(aWire)\n    headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(headShell)\n    headFaces = headShell.Faces\n\n    edgeH1 = Part.makeLine(Pnt1,PntH1)\n    edgeH2 = Part.makeLine(PntH1,PntH0)\n    edgeH3 = Part.makeLine(PntH0,Pnt0)\n    hWire = Part.Wire([edge1,edgeH1,edgeH2,edgeH3]) # Cutter for recess-Shell\n    hFace = Part.Face(hWire)\n    hCut = hFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(hWire)\n    topFace = hCut.Faces[0]\n\n    recessShell = recessShell.cut(hCut)\n    topFace = topFace.cut(recess)\n    #Part.show(topFace)\n    #Part.show(recessShell)\n    #Part.show(headShell)\n    headFaces.append(topFace.Faces[0])\n    headFaces.extend(recessShell.Faces)\n\n\n    if self.rThread:\n      #if (dia < 3.0) or (dia > 5.0):\n      if True:\n        if (SType =='DIN967'):\n          rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        else:\n          rthread = self.makeShellthread(dia, P, halfturns, True, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n        for threadFace in rthread.Faces:\n          headFaces.append(threadFace)\n\n        screwShell = Part.Shell(headFaces)\n        screw = Part.Solid(screwShell)\n      else:\n        rthread = self.makeShellthread(dia, P, halfturns, False, offSet)\n        rthread.translate(Base.Vector(0.0, 0.0,-a_point -2.0*P))\n        for threadFace in rthread.Faces:\n          headFaces.append(threadFace)\n\n        screwShell = Part.Shell(headFaces)\n        screw = Part.Solid(screwShell)\n        cyl = self.cutChamfer(dia, P, l)\n        screw = screw.cut(cyl)\n    else:\n      screwShell = Part.Shell(headFaces)\n      screw = Part.Solid(screwShell)\n\n    return screw\n\n\n\n\n  def makeHextool(self,s_hex, k_hex, cir_hex):\n    # makes a cylinder with an inner hex hole, used as cutting tool\n    # create hexagon\n    mhex=Base.Matrix()\n    mhex.rotateZ(math.radians(60.0))\n    polygon = []\n    vhex=Base.Vector(s_hex/math.sqrt(3.0),0.0,-k_hex*0.1)\n    for i in range(6):\n       polygon.append(vhex)\n       vhex = mhex.multiply(vhex)\n    polygon.append(vhex)\n    hexagon = Part.makePolygon(polygon)\n    # create circle\n    circ = Part.makeCircle(cir_hex/2.0, Base.Vector(0.0,0.0,-k_hex*0.1), self.circleAxis)\n    # Create the face with the circle as outline and the hexagon as hole\n    face=Part.Face([Part.Wire(circ),hexagon])\n\n    # Extrude in z to create the final cutting tool\n    exHex=face.extrude(Base.Vector(0.0,0.0,k_hex*1.2))\n    # Part.show(exHex)\n    return exHex\n\n\n  def makeShellthread(self, d, P, halfrots, withcham, offSet):\n    d = float(d)\n\n    #rotations = int(rots)-1\n    halfrots_int = int(halfrots)\n    rotations = (halfrots_int // 2) - 1\n    if halfrots_int % 2 == 1:\n      #FreeCAD.Console.PrintMessage(\"got half turn: \" + str(halfrots_int) + \"\\n\")\n      halfturn = True\n      # bot_off = - P/2.0 # transition of half a turn\n      bot_off = 0.0 # nominal length\n    else:\n      halfturn = False\n      bot_off = 0.0 # nominal length\n\n    H=P*math.cos(math.radians(30)) # Gewindetiefe H\n    r=d/2.0\n\n    # helix = Part.makeHelix(P,P,d*511/1000.0,0) # make just one turn, length is identical to pitch\n    helix = Part.makeHelix(P,P,d*self.Tuner/1000.0,0) # make just one turn, length is identical to pitch\n    helix.translate(FreeCAD.Vector(0.0, 0.0,-P*9.0/16.0))\n\n    extra_rad = P\n    # points for screw profile\n    ps0 = (r,0.0, 0.0)\n    ps1 = (r-H*5.0/8.0,0.0, -P*5.0/16.0)\n    ps2 = (r-H*17.0/24.0,0.0, -P*7.0/16.0) # Center of Arc\n    ps3 = (r-H*5.0/8.0,0.0, -P*9.0/16.0 )\n    ps4 =  (r, 0.0, -P*14.0/16.0)\n    ps5 = (r,0.0, -P)\n    ps6 = (r+extra_rad,0.0, -P)\n    ps7 = (r+extra_rad,0.0, 0.0)\n\n    edge0 = Part.makeLine(ps0,ps1)\n    edge1 = Part.Arc(FreeCAD.Vector(ps1),FreeCAD.Vector(ps2),FreeCAD.Vector(ps3)).toShape()\n    edge2 = Part.makeLine(ps3,ps4)\n    edge3 = Part.makeLine(ps4,ps5)\n    edge4 = Part.makeLine(ps5,ps6)\n    edge5 = Part.makeLine(ps6,ps7)\n    edge6 = Part.makeLine(ps7,ps0)\n\n    W0 = Part.Wire([edge0, edge1, edge2, edge3, edge4, edge5, edge6])\n\n    makeSolid=True\n    isFrenet=True\n    pipe0 = Part.Wire(helix).makePipeShell([W0],makeSolid,isFrenet)\n    # pipe1 = pipe0.copy()\n\n    TheFaces = []\n    TheFaces.append(pipe0.Faces[0])\n    #Part.show(pipe0.Faces[0])\n    TheFaces.append(pipe0.Faces[1])\n    #Part.show(pipe0.Faces[1])\n    TheFaces.append(pipe0.Faces[2])\n    #Part.show(pipe0.Faces[2])\n    TheFaces.append(pipe0.Faces[3])\n    #Part.show(pipe0.Faces[3])\n\n    TheShell = Part.Shell(TheFaces)\n    # print \"Shellpoints: \", len(TheShell.Vertexes)\n\n\n    i = 1\n    for i in range(rotations-2):\n       TheShell.translate(FreeCAD.Vector(0.0, 0.0, -P))\n\n       for flaeche in TheShell.Faces:\n         TheFaces.append(flaeche)\n\n    #FreeCAD.Console.PrintMessage(\"Base-Shell: \" + str(i) + \"\\n\")\n    # Make separate faces for the tip of the screw\n    botFaces = []\n    for i in range(rotations-2, rotations, 1):\n       TheShell.translate(FreeCAD.Vector(0.0, 0.0, -P))\n\n       for flaeche in TheShell.Faces:\n         botFaces.append(flaeche)\n    #FreeCAD.Console.PrintMessage(\"Bottom-Shell: \" + str(i) + \"\\n\")\n\n    # making additional faces for transition to cylinder\n\n    pc1 = (r + H/16.0,0.0,P*1/32.0)\n    pc2 = (r-H*5.0/8.0,0.0,-P*5.0/16.0 )\n    pc3 = (r-H*17.0/24.0,0.0, -P*7.0/16.0 ) # Center of Arc\n    pc4 = (r-H*5.0/8.0,0.0, -P*9.0/16.0 )\n    pc5 =  (r+ H/16.0, 0.0, -P*29.0/32.0 )\n\n    edgec0 = Part.makeLine(pc5,pc1)\n    edgec1 = Part.makeLine(pc1,pc2)\n    edgec2 = Part.Arc(FreeCAD.Vector(pc2),FreeCAD.Vector(pc3),FreeCAD.Vector(pc4)).toShape()\n    edgec3 = Part.makeLine(pc4,pc5)\n\n    cut_profile = Part.Wire([edgec1, edgec2, edgec3, edgec0 ])\n\n    alpha_rad = math.atan(2*H*17.0/24.0/P)\n    alpha = math.degrees(alpha_rad)\n    Hyp = P/math.cos(alpha_rad)\n    # tuning = 511/1000.0\n    tuning = self.Tuner/1000.0\n    angled_Helix = Part.makeHelix(Hyp,Hyp*1.002/2.0,d*tuning,alpha)\n\n    SH_faces = []\n\n    if halfturn:\n      half_Helix = Part.makeHelix(P,P/2.0,d*self.Tuner/1000.0,0) # make just half a turn\n      angled_Helix.rotate(Base.Vector(0,0,0),Base.Vector(0,0,1),180)\n      angled_Helix.translate(FreeCAD.Vector(0.0, 0.0,P/2.0))\n      # Part.show(half_Helix)\n      # Part.show(angled_Helix)\n      pipe_cut = Part.Wire([half_Helix, angled_Helix]).makePipeShell([cut_profile],True,isFrenet)\n      SH_faces.append(pipe_cut.Faces[0])\n      SH_faces.append(pipe_cut.Faces[1])\n      SH_faces.append(pipe_cut.Faces[2])\n      SH_faces.append(pipe_cut.Faces[4])\n      SH_faces.append(pipe_cut.Faces[5])\n      SH_faces.append(pipe_cut.Faces[6])\n\n    else:\n      pipe_cut = Part.Wire(angled_Helix).makePipeShell([cut_profile],True,isFrenet)\n      SH_faces.append(pipe_cut.Faces[0])\n      SH_faces.append(pipe_cut.Faces[1])\n      SH_faces.append(pipe_cut.Faces[2])\n\n    # Part.show(pipe_cut)\n\n\n    Shell_helix = Part.Shell(SH_faces)\n\n    # rect_helix_profile, needed for cutting a tube-shell\n    pr1 = (r +H/16.0, 0.0, 0.0)\n    pr2 = (r -H/16.0, 0.0, 0.0)\n    pr3 = (r -H/16.0, 0.0, P)\n    pr4 = (r +H/16.0, 0.0, P)\n\n    edge_r1 = Part.makeLine(pr1,pr2)\n    edge_r2 = Part.makeLine(pr2,pr3)\n    edge_r3 = Part.makeLine(pr3,pr4)\n    edge_r4 = Part.makeLine(pr4,pr1)\n    rect_profile = Part.Wire([edge_r1, edge_r2, edge_r3, edge_r4 ])\n    rect_helix = Part.Wire(helix).makePipeShell([rect_profile], True, isFrenet)\n    # if halfturn:\n    #   rect_helix.rotate(Base.Vector(0,0,0),Base.Vector(0,0,1),180)\n    rect_helix.translate(FreeCAD.Vector(0.0, 0.0,- P))\n    # Part.show(rect_helix)\n\n    # rect_ring, needed for cutting the Shell_helix\n    pr5 = (r +H*1.1, 0.0, P*1.1)\n    pr6 = (r, 0.0, P*1.1)\n    pr7 = (r, 0.0, -P*1.1)\n    pr8 = (r +H*1.1, 0.0, -P*1.1)\n\n    edge_r5 = Part.makeLine(pr5,pr6)\n    edge_r6 = Part.makeLine(pr6,pr7)\n    edge_r7 = Part.makeLine(pr7,pr8)\n    edge_r8 = Part.makeLine(pr8,pr5)\n    rect_profile = Part.Wire([edge_r5, edge_r6, edge_r7, edge_r8 ])\n\n    rect_Face =Part.Face(rect_profile)\n    rect_ring= rect_Face.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(rect_ring)\n\n    Shell_helix = Shell_helix.cut(rect_ring)\n    Shell_helix.translate(FreeCAD.Vector(0.0, 0.0, P))\n    # Part.show(Shell_helix)\n\n    # shell_ring, the transition to a cylinder\n    pr9 = (r, 0.0, P-offSet)\n    pr10 = (r, 0.0, -P )\n    edge_r9 = Part.makeLine(pr9,pr10)\n    shell_ring= edge_r9.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n\n    shell_ring = shell_ring.cut(pipe_cut)\n    #Part.show(shell_ring)\n    shell_ring = shell_ring.cut(rect_helix)\n    shell_ring.translate(FreeCAD.Vector(0.0, 0.0, P))\n    #Part.show(shell_ring)\n\n    for flaeche in shell_ring.Faces:\n      TheFaces.append(flaeche)\n\n    for flaeche in Shell_helix.Faces:\n      TheFaces.append(flaeche)\n\n    if withcham:\n      #FreeCAD.Console.PrintMessage(\"with chamfer: \" + str(i) + \"\\n\")\n      # cutting of the bottom Faces\n      # bot_off = 0.0 # nominal length\n      cham_off = H/8.0\n      cham_t = P*math.sqrt(3.0)/2.0*17.0/24.0\n\n      # points for chamfer: common-Method\n      pch0 =  (0.0, 0.0, -(rotations)*P + bot_off) # bottom center\n      pch1 =  (r-cham_t,0.0, -(rotations)*P + bot_off)\n      pch2 =  (r+cham_off, 0.0, -(rotations)*P + cham_t +cham_off  + bot_off)\n      pch3 =  (r+cham_off, 0.0, -(rotations)*P + 3.0*P + bot_off)\n      pch4 =  (0.0, 0.0, -(rotations)*P + 3.0*P + bot_off)\n\n      edgech0 = Part.makeLine(pch0,pch1)\n      edgech1 = Part.makeLine(pch1,pch2)\n      edgech2 = Part.makeLine(pch2,pch3)\n      edgech3 = Part.makeLine(pch3,pch4)\n      edgech4 = Part.makeLine(pch4,pch0)\n\n      Wch_wire = Part.Wire([edgech0, edgech1, edgech2, edgech3, edgech4])\n      cham_Face =Part.Face(Wch_wire)\n      cham_Solid = cham_Face.revolve(Base.Vector(0.0,0.0,-(rotations-1)*P),Base.Vector(0.0,0.0,1.0),360)\n      # Part.show(cham_Solid)\n\n      BotShell = Part.Shell(botFaces)\n      BotShell = BotShell.common(cham_Solid)\n      # Part.show(BotShell)\n\n      cham_faces = []\n      cham_faces.append(cham_Solid.Faces[0])\n      cham_faces.append(cham_Solid.Faces[1])\n      cham_Shell = Part.Shell(cham_faces)\n      # Part.show(cham_Shell)\n\n      pipe0.translate(FreeCAD.Vector(0.0, 0.0, -(rotations-1)*P))\n      # Part.show(pipe0)\n\n      # Part.show(Fillet_shell)\n      cham_Shell = cham_Shell.cut(pipe0)\n      pipe0.translate(FreeCAD.Vector(0.0, 0.0, -P))\n      # Part.show(pipe0)\n      cham_Shell = cham_Shell.cut(pipe0)\n\n      '''\n      botFaces2 = []\n      for flaeche in BotShell.Faces:\n        botFaces2.append(flaeche)\n      for flaeche in cham_Shell.Faces:\n        botFaces2.append(flaeche)\n      '''\n\n    else: # tip of screw without chamfer\n      #FreeCAD.Console.PrintMessage(\"without chamfer: \" + str(i) + \"\\n\")\n\n      commonbox = Part.makeBox(d+4.0*P, d+4.0*P, 3.0*P)\n      commonbox.translate(FreeCAD.Vector(-(d+4.0*P)/2.0, -(d+4.0*P)/2.0,-(rotations)*P+bot_off))\n      #commonbox.translate(FreeCAD.Vector(-(d+4.0*P)/2.0, -(d+4.0*P)/2.0,-(rotations+3)*P+bot_off))\n      #Part.show(commonbox)\n\n      BotShell = Part.Shell(botFaces)\n      #Part.show(BotShell)\n\n      BotShell = BotShell.common(commonbox)\n      #BotShell = BotShell.cut(commonbox)\n      bot_edges =[]\n      bot_z =  1.0e-5 -(rotations)*P + bot_off\n\n      for kante in BotShell.Edges:\n         if (kante.Vertexes[0].Point.z<=bot_z) and (kante.Vertexes[1].Point.z<=bot_z):\n            bot_edges.append(kante)\n            # Part.show(kante)\n      bot_wire = Part.Wire(Part.__sortEdges__(bot_edges))\n\n      #botFaces2 = []\n      #for flaeche in BotShell.Faces:\n      #  botFaces2.append(flaeche)\n\n      bot_face = Part.Face(bot_wire)\n      bot_face.reverse()\n      #botFaces2.append(bot_face)\n\n    '''\n\n    BotShell2 = Part.Shell(botFaces2)\n    # Part.show(BotShell2)\n\n    TheShell2 = Part.Shell(TheFaces)\n\n    # This gives a shell\n    FaceList = []\n    for flaeche in TheShell2.Faces:\n      FaceList.append(flaeche)\n    for flaeche in BotShell2.Faces:\n      FaceList.append(flaeche)\n\n    TheShell = Part.Shell(FaceList)\n    # Part.show(TheShell)\n    '''\n    for flaeche in BotShell.Faces:\n      TheFaces.append(flaeche)\n    if withcham:\n      for flaeche in cham_Shell.Faces:\n        TheFaces.append(flaeche)\n    else:\n      TheFaces.append(bot_face)\n    TheShell = Part.Shell(TheFaces)\n\n    #print self.Tuner, \" \", TheShell.ShapeType, \" \", TheShell.isValid(), \" hrots: \", halfrots_int, \" Shellpunkte: \", len(TheShell.Vertexes)\n\n    return TheShell\n\n  # if da<>None: make Shell for a nut else: make a screw tap\n  def makeInnerThread_2(self, d, P, rotations, da, l):\n    d = float(d)\n    bot_off = 0.0 # nominal length\n\n    H=P*math.cos(math.radians(30)) # Gewindetiefe H\n    r=d/2.0\n\n    helix = Part.makeHelix(P,P,d*self.Tuner/1000.0,0) # make just one turn, length is identical to pitch\n    helix.translate(FreeCAD.Vector(0.0, 0.0,-P*9.0/16.0))\n\n    extra_rad = P\n\n    # points for inner thread profile\n    ps0 = (r,0.0, 0.0)\n    ps1 = (r-H*5.0/8.0,0.0, -P*5.0/16.0)\n    ps2 = (r-H*5.0/8.0,0.0, -P*9.0/16.0 )\n    ps3 =  (r, 0.0, -P*14.0/16.0)\n    ps4 = (r+H*1/24.0,0.0, -P*31.0/32.0) # Center of Arc\n    ps5 = (r,0.0, -P)\n    ps6 = (r+extra_rad,0.0, -P)\n    ps7 = (r+extra_rad,0.0, 0.0)\n\n    #ps6 = (r-extra_rad,0.0, -P)\n    #ps7 = (r-extra_rad,0.0, 0.0)\n\n    edge0 = Part.makeLine(ps0,ps1)\n    edge1 = Part.makeLine(ps1,ps2)\n    edge2 = Part.makeLine(ps2,ps3)\n    edge3 = Part.Arc(FreeCAD.Vector(ps3),FreeCAD.Vector(ps4),FreeCAD.Vector(ps5)).toShape()\n    edge4 = Part.makeLine(ps5,ps6)\n    edge5 = Part.makeLine(ps6,ps7)\n    edge6 = Part.makeLine(ps7,ps0)\n\n    W0 = Part.Wire([edge0, edge1, edge2, edge3, edge4, edge5, edge6])\n    # Part.show(W0)\n\n    makeSolid=True\n    isFrenet=True\n    pipe0 = Part.Wire(helix).makePipeShell([W0],makeSolid,isFrenet)\n    # pipe1 = pipe0.copy()\n\n    TheFaces = []\n    TheFaces.append(pipe0.Faces[0])\n    TheFaces.append(pipe0.Faces[1])\n    TheFaces.append(pipe0.Faces[2])\n    TheFaces.append(pipe0.Faces[3])\n\n    TheShell = Part.Shell(TheFaces)\n    # print \"Shellpoints: \", len(TheShell.Vertexes)\n\n    # Handling of the top faces\n    if da is not None:\n      TheShell.translate(FreeCAD.Vector(0.0, 0.0, -P))\n      for flaeche in TheShell.Faces:\n       TheFaces.append(flaeche)\n      TheShell.translate(FreeCAD.Vector(0.0, 0.0, -P))\n      for flaeche in TheShell.Faces:\n       TheFaces.append(flaeche)\n\n      cham_i_delta = da/2.0 - (r-H)\n      cham_i = cham_i_delta * math.tan(math.radians(15.0))\n\n      offSet = rotations*P - l\n      #FreeCAD.Console.PrintMessage(\"Der Offset: \" + str(offSet/P) + \"\\n\")\n\n      # points for chamfer: common-Method\n      pch0 =  (da/2.0-cham_i_delta, 0.0, -cham_i - offSet) # bottom chamfer\n      pch1 =  (da/2.0, 0.0, 0.0 - offSet)  #\n      pch2 =  (da/2.0, 0.0, -4.0*P - offSet)\n      pch3 =  (da/2.0-cham_i_delta, 0.0, -4.0*P - offSet)\n\n      edgech0 = Part.makeLine(pch0,pch1)\n      edgech1 = Part.makeLine(pch1,pch2)\n      edgech2 = Part.makeLine(pch2,pch3)\n      edgech3 = Part.makeLine(pch3,pch0)\n\n      Wch_wire = Part.Wire([edgech0, edgech1, edgech2, edgech3])\n      cham_Face =Part.Face(Wch_wire)\n      cham_Solid = cham_Face.revolve(Base.Vector(0.0,0.0,-(rotations-1)*P),Base.Vector(0.0,0.0,1.0),360)\n      #Part.show(cham_Solid)\n      #Part.show(Wch_wire)\n\n      rawTopShell = Part.Shell(TheFaces)\n      topShell = rawTopShell.common(cham_Solid)\n\n      # Making a Cutter for the cham face\n      commonbox = Part.makeBox(d+4.0*P, d+4.0*P, 2.0*P)\n      commonbox.translate(FreeCAD.Vector(-(d+4.0*P)/2.0, -(d+4.0*P)/2.0,-2.0*P))\n      #Part.show(commonbox)\n\n      cutterShell = rawTopShell.common(commonbox)\n      bot_edges =[]\n      bot_z =  1.0e-5 -2.0*P\n\n      for kante in cutterShell.Edges:\n         if (kante.Vertexes[0].Point.z<=bot_z) and (kante.Vertexes[1].Point.z<=bot_z):\n            bot_edges.append(kante)\n            # Part.show(kante)\n      bot_wire = Part.Wire(Part.__sortEdges__(bot_edges))\n\n      bot_face = Part.Face(bot_wire)\n      bot_face.reverse()\n      t_face = bot_face.copy()\n      t_face.translate(Base.Vector(0.0, 0.0, 2.0*P))\n      cutterFaces = cutterShell.Faces\n      cutterFaces.append(bot_face.Faces[0])\n      cutterFaces.append(t_face.Faces[0])\n      cutShell = Part.Shell(cutterFaces)\n      chamFcutter = Part.Solid(cutShell)\n\n      #Part.show(chamFcutter)\n      topCham = cham_Solid.Faces[0]\n      topCham = topCham.cut(chamFcutter)\n\n      #Part.show(topCham)\n      TheFaces = [topCham.Faces[0]]\n      TheFaces.extend(topShell.Faces)\n\n      for i in range(rotations-4):\n         TheShell.translate(FreeCAD.Vector(0.0, 0.0,- P))\n         for flaeche in TheShell.Faces:\n           TheFaces.append(flaeche)\n\n    else:\n      commonbox = Part.makeBox(d+4.0*P, d+4.0*P, 3.0*P)\n      commonbox.translate(FreeCAD.Vector(-(d+4.0*P)/2.0, -(d+4.0*P)/2.0,-(3.0)*P))\n      topShell = TheShell.common(commonbox)\n      top_edges =[]\n      top_z =  -1.0e-5\n\n      for kante in topShell.Edges:\n         if (kante.Vertexes[0].Point.z>=top_z) and (kante.Vertexes[1].Point.z>=top_z):\n            top_edges.append(kante)\n            # Part.show(kante)\n      top_wire = Part.Wire(Part.__sortEdges__(top_edges))\n      top_face = Part.Face(top_wire)\n\n      TheFaces = [top_face.Faces[0]]\n      TheFaces.extend(topShell.Faces)\n\n      for i in range(rotations-2):\n         TheShell.translate(FreeCAD.Vector(0.0, 0.0,- P))\n         for flaeche in TheShell.Faces:\n           TheFaces.append(flaeche)\n\n    #FreeCAD.Console.PrintMessage(\"Base-Shell: \" + str(i) + \"\\n\")\n    # Make separate faces for the tip of the screw\n    botFaces = []\n    for i in range(rotations-2, rotations, 1):\n       TheShell.translate(FreeCAD.Vector(0.0, 0.0,- P))\n\n       for flaeche in TheShell.Faces:\n         botFaces.append(flaeche)\n    #FreeCAD.Console.PrintMessage(\"Bottom-Shell: \" + str(i) + \"\\n\")\n\n    if da is not None:\n      # points for chamfer: common-Method\n      pch0 =  (da/2-cham_i_delta, 0.0, -(rotations)*P + cham_i) # bottom chamfer\n      pch1 =  (da/2, 0.0, -(rotations)*P)  #\n      pch2 =  (da/2, 0.0, -(rotations)*P + 3.0*P)\n      pch3 =  (da/2-cham_i_delta, 0.0, -(rotations)*P + 3.0*P)\n      #pch4 =  (r-2.0*cham_i_delta, 0.0, -(rotations)*P + 3.0*P)\n\n      edgech0 = Part.makeLine(pch0,pch1)\n      edgech1 = Part.makeLine(pch1,pch2)\n      edgech2 = Part.makeLine(pch2,pch3)\n      edgech3 = Part.makeLine(pch3,pch0)\n\n      Wch_wire = Part.Wire([edgech0, edgech1, edgech2, edgech3])\n      cham_Face =Part.Face(Wch_wire)\n      cham_Solid = cham_Face.revolve(Base.Vector(0.0,0.0,-(rotations-1)*P),Base.Vector(0.0,0.0,1.0),360)\n      #Part.show(cham_Solid)\n      #Part.show(Wch_wire)\n\n      BotShell = Part.Shell(botFaces)\n      #Part.show(BotShell)\n      chamFcutter.translate(FreeCAD.Vector(0.0, 0.0,-(rotations-1)*P))\n      #Part.show(chamFcutter)\n\n\n      BotShell = BotShell.common(cham_Solid)\n      #Part.show(BotShell)\n\n      cham_face = cham_Solid.Faces[0]\n      cham_face = cham_face.cut(chamFcutter)\n      #Part.show(cham_face)\n\n      for flaeche in BotShell.Faces:\n        TheFaces.append(flaeche)\n      if da is not None:\n        TheFaces.append(cham_face.Faces[0])\n      else:\n        TheFaces.append(bot_face)\n      TheShell = Part.Shell(TheFaces)\n\n      #print self.Tuner, \" \", TheShell.ShapeType, \" \", TheShell.isValid(), \" hrots: \", halfrots_int, \" Shellpunkte: \", len(TheShell.Vertexes)\n\n      return TheShell\n\n    else: # make of screw tap\n      #FreeCAD.Console.PrintMessage(\"without chamfer: \" + str(i) + \"\\n\")\n\n      commonbox = Part.makeBox(d+4.0*P, d+4.0*P, 3.0*P)\n      commonbox.translate(FreeCAD.Vector(-(d+4.0*P)/2.0, -(d+4.0*P)/2.0,-(rotations)*P+bot_off))\n      #commonbox.translate(FreeCAD.Vector(-(d+4.0*P)/2.0, -(d+4.0*P)/2.0,-(rotations+3)*P+bot_off))\n      #Part.show(commonbox)\n\n      BotShell = Part.Shell(botFaces)\n      #Part.show(BotShell)\n\n      BotShell = BotShell.common(commonbox)\n      #BotShell = BotShell.cut(commonbox)\n      bot_edges =[]\n      bot_z =  1.0e-5 -(rotations)*P + bot_off\n\n      for kante in BotShell.Edges:\n         if (kante.Vertexes[0].Point.z<=bot_z) and (kante.Vertexes[1].Point.z<=bot_z):\n            bot_edges.append(kante)\n            # Part.show(kante)\n      bot_wire = Part.Wire(Part.__sortEdges__(bot_edges))\n\n      bot_face = Part.Face(bot_wire)\n      bot_face.reverse()\n\n      for flaeche in BotShell.Faces:\n        TheFaces.append(flaeche)\n      if da is not None:\n        raise NotImplementedError('da must be None')\n        # TODO: Fix cham_Shell undefined.\n        for flaeche in cham_Shell.Faces:\n          TheFaces.append(flaeche)\n      else:\n        TheFaces.append(bot_face)\n      TheShell = Part.Shell(TheFaces)\n      TheSolid = Part.Solid(TheShell)\n\n      #print self.Tuner, \" \", TheShell.ShapeType, \" \", TheShell.isValid(), \" hrots: \", halfrots_int, \" Shellpunkte: \", len(TheShell.Vertexes)\n\n      return TheSolid\n\n  def makeIso4032(self, SType='ISO4032', ThreadType='M6'):\n    \"\"\"ISO 4032 Hex-nut and 4033 Hex-nut\"\"\"\n    dia = get_diameter(ThreadType)\n    if SType == 'ISO4032':\n      # P, c, damax,  dw,    e,     m,   mw,   s_nom\n      P, c, da, dw, e, m, mw, s = iso4032def[ThreadType]\n    if SType == 'ISO4033':\n      # P, c, damax,  dw,    e,     m,   mw,   s_nom\n      P, c, da, dw, e, m, mw, s = iso4033def[ThreadType]\n    if SType == 'ISO4035':\n      # P, c, damax,  dw,    e,     m,   mw,   s_nom\n      P, c, da, dw, e, m, mw, s = iso4035def[ThreadType]\n\n    residue, turns = math.modf(m/P)\n    #halfturns = 2*int(turns)\n\n    if residue > 0.0:\n      turns += 1.0\n      #halfturns = halfturns +2\n    #offSet = r - a\n\n    sqrt2_ = 1.0/math.sqrt(2.0)\n    cham = (e-s)*math.sin(math.radians(15)) # needed for chamfer at nut top\n    H=P*math.cos(math.radians(30)) # Gewindetiefe H\n    cham_i_delta = da/2.0 - (dia/2.0-H*5.0/8.0)\n    cham_i = cham_i_delta * math.tan(math.radians(15.0))\n\n\n    if self.rThread:\n      Pnt0 = Base.Vector(da/2.0-2.0*cham_i_delta,0.0,m - 2.0*cham_i)\n      Pnt7 = Base.Vector(da/2.0-2.0*cham_i_delta,0.0,0.0+ 2.0*cham_i)\n    else:\n      Pnt0 = Base.Vector(dia/2.0-H*5.0/8.0,0.0,m - cham_i)\n      Pnt7 = Base.Vector(dia/2.0-H*5.0/8.0,0.0,0.0+ cham_i)\n\n    Pnt1 = Base.Vector(da/2.0,0.0,m)\n    Pnt2 = Base.Vector(s/2.0,0.0,m)\n    Pnt3 = Base.Vector(s/math.sqrt(3.0),0.0,m-cham)\n    Pnt4 = Base.Vector(s/math.sqrt(3.0),0.0,cham)\n    Pnt5 = Base.Vector(s/2.0,0.0,0.0)\n    Pnt6 = Base.Vector(da/2.0,0.0,0.0)\n\n    edge0 = Part.makeLine(Pnt0,Pnt1)\n    edge1 = Part.makeLine(Pnt1,Pnt2)\n    edge2 = Part.makeLine(Pnt2,Pnt3)\n    edge3 = Part.makeLine(Pnt3,Pnt4)\n    edge4 = Part.makeLine(Pnt4,Pnt5)\n    edge5 = Part.makeLine(Pnt5,Pnt6)\n    edge6 = Part.makeLine(Pnt6,Pnt7)\n    edge7 = Part.makeLine(Pnt7,Pnt0)\n\n    # create cutting tool for hexagon head\n    # Parameters s, k, outer circle diameter =  e/2.0+10.0\n    extrude = self.makeHextool(s, m, s*2.0)\n\n    aWire=Part.Wire([edge0,edge1,edge2,edge3,edge4,edge5,edge6,edge7])\n    # Part.show(aWire)\n    aFace =Part.Face(aWire)\n    head = aFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360.0)\n    #Part.show(head)\n\n    # Part.show(extrude)\n    nut = head.cut(extrude)\n    # Part.show(nut)\n\n    if self.rThread:\n      '''\n      threadCutter = self.makeInnerThread(dia, P, int(turns), None, m)\n      # Part.show(threadCutter)\n      threadCutter.translate(Base.Vector(0.0, 0.0,turns*P))\n      nut = nut.cut(threadCutter)\n      '''\n      nutFaces = [nut.Faces[2]]\n      for i in range(4,25):\n        nutFaces.append(nut.Faces[i])\n\n\n      threadShell = self.makeInnerThread_2(dia, P, int(turns), da, m)\n      threadShell.translate(Base.Vector(0.0, 0.0,turns*P))\n      #Part.show(threadShell)\n      nutFaces.extend(threadShell.Faces)\n\n      nutShell = Part.Shell(nutFaces)\n      nut = Part.Solid(nutShell)\n      #Part.show(nutShell)\n\n    return nut\n\n  def makeEN1661(self, ThreadType='M8'):\n    \"\"\"EN 1661 Hexagon nuts with flange\n\n    chamfer at top of hexagon is wrong = more than 30\u00b0\n    \"\"\"\n    dia = get_diameter(ThreadType)\n    P, da, c, dc, dw, e, m, mw, r1, s = en1661def[ThreadType]\n\n    residue, turns = math.modf(m/P)\n    #halfturns = 2*int(turns)\n\n    if residue > 0.0:\n      turns += 1.0\n\n    #FreeCAD.Console.PrintMessage(\"the nut with isoEN1661: \" + str(c) + \"\\n\")\n    cham = s*(2.0/math.sqrt(3.0)-1.0)*math.sin(math.radians(25)) # needed for chamfer at head top\n\n    sqrt2_ = 1.0/math.sqrt(2.0)\n\n    # Flange is made with a radius of c\n    beta = math.radians(25.0)\n    tan_beta = math.tan(beta)\n\n    # Calculation of Arc points of flange edge using dc and c\n    arc1_x = dc/2.0 - c/2.0 + (c/2.0)*math.sin(beta)\n    arc1_z = c/2.0 + (c/2.0)*math.cos(beta)\n\n    hF = arc1_z + (arc1_x -s/2.0) * tan_beta  # height of flange at center\n\n    #kmean = arc1_z + (arc1_x - s/math.sqrt(3.0)) * tan_beta + mw * 1.1 + cham\n    #kmean = k * 0.95\n\n\n    #Hex-Head Points\n    #FreeCAD.Console.PrintMessage(\"the nut with kmean: \" + str(m) + \"\\n\")\n    PntH0 = Base.Vector(da/2.0,0.0,m)\n    PntH1 = Base.Vector(s/2.0,0.0,m)\n    edgeH1 = Part.makeLine(PntH0,PntH1)\n\n    hWire=Part.Wire([edgeH1])\n    topShell = hWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(hWire)\n    #Part.show(topShell)\n\n    # create a cutter ring to generate the chamfer at the top of the hex\n    chamHori = s/math.sqrt(3.0) - s/2.0\n    PntC1 = Base.Vector(s/2.0-chamHori,0.0,m+m)\n    PntC2 = Base.Vector(s/math.sqrt(3.0)+chamHori,0.0,m+m)\n    PntC3 = Base.Vector(s/2.0-chamHori,0.0,m+cham)\n    PntC4 = Base.Vector(s/math.sqrt(3.0)+chamHori,0.0,m-cham-cham)   #s/math.sqrt(3.0)\n    edgeC1 = Part.makeLine(PntC3, PntC1)\n    edgeC2 = Part.makeLine(PntC1, PntC2)\n    edgeC3 = Part.makeLine(PntC2, PntC4)\n    edgeC4 = Part.makeLine(PntC4, PntC3)\n    cWire = Part.Wire([edgeC4, edgeC1, edgeC2, edgeC3])\n    cFace = Part.Face(cWire)\n    chamCut = cFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #Part.show(cWire)\n    #Part.show(chamCut)\n\n\n    # create hexagon\n    mhex=Base.Matrix()\n    mhex.rotateZ(math.radians(60.0))\n    polygon = []\n    vhex=Base.Vector(s/math.sqrt(3.0),0.0,m)\n    for i in range(6):\n       polygon.append(vhex)\n       vhex = mhex.multiply(vhex)\n    polygon.append(vhex)\n    hexagon = Part.makePolygon(polygon)\n    hexFace = Part.Face(hexagon)\n    solidHex = hexFace.extrude(Base.Vector(0.0,0.0,c-m))\n    #Part.show(solidHex)\n    hexCham = solidHex.cut(chamCut)\n    #Part.show(hexCham)\n\n    topFaces = topShell.Faces\n\n    topFaces.append(hexCham.Faces[1])\n    topFaces.append(hexCham.Faces[2])\n    topFaces.append(hexCham.Faces[8])\n    topFaces.append(hexCham.Faces[13])\n    topFaces.append(hexCham.Faces[14])\n    topFaces.append(hexCham.Faces[12])\n    topFaces.append(hexCham.Faces[6])\n\n    hexFaces = [hexCham.Faces[5], hexCham.Faces[11], hexCham.Faces[10]]\n    hexFaces.extend([hexCham.Faces[9], hexCham.Faces[3], hexCham.Faces[0]])\n    hexShell = Part.Shell(hexFaces)\n\n\n    H=P*math.cos(math.radians(30)) # Gewindetiefe H\n    cham_i_delta = da/2.0 - (dia/2.0-H*5.0/8.0)\n    cham_i = cham_i_delta * math.tan(math.radians(15.0))\n\n    # Center of flange:\n    Pnt0 = Base.Vector(0.0,0.0,hF)\n    Pnt1 = Base.Vector(s/2.0,0.0,hF)\n\n    # arc edge of flange:\n    Pnt2 = Base.Vector(arc1_x,0.0,arc1_z)\n    Pnt3 = Base.Vector(dc/2.0,0.0,c/2.0)\n    Pnt4 = Base.Vector((dc-c)/2.0,0.0,0.0)\n    Pnt5 = Base.Vector(da/2.0,0.0,0.0)     #start of fillet between flat and thread\n\n    edge1 = Part.makeLine(Pnt0,Pnt1)\n    edge2 = Part.makeLine(Pnt1,Pnt2)\n    edge3 = Part.Arc(Pnt2,Pnt3,Pnt4).toShape()\n    edge4 = Part.makeLine(Pnt4,Pnt5)\n\n    # make a cutter for the hexShell\n    PntHC1 = Base.Vector(0.0,0.0,arc1_z)\n    PntHC2 = Base.Vector(0.0,0.0,0.0)\n\n    edgeHC1 = Part.makeLine(Pnt2,PntHC1)\n    edgeHC2 = Part.makeLine(PntHC1,PntHC2)\n    edgeHC3 = Part.makeLine(PntHC2,Pnt0)\n\n    HCWire = Part.Wire([edge2, edgeHC1, edgeHC2, edgeHC3, edge1])\n    HCFace = Part.Face(HCWire)\n    hex2Cut = HCFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n\n    hexShell = hexShell.cut(hex2Cut)\n    #Part.show(hexShell)\n\n    topFaces.extend(hexShell.Faces)\n\n    if self.rThread:\n      aWire=Part.Wire([edge2,edge3,edge4])\n      boltIndex = 3\n\n    else:\n      Pnt7 = Base.Vector(dia/2.0-H*5.0/8.0,0.0,m - cham_i)\n      Pnt6 = Base.Vector(dia/2.0-H*5.0/8.0,0.0,0.0+ cham_i)\n      edge5 = Part.makeLine(Pnt5,Pnt6)\n      edge6 = Part.makeLine(Pnt6,Pnt7)\n      edge7 = Part.makeLine(Pnt7,PntH0)\n      aWire=Part.Wire([edge2,edge3,edge4,edge5,edge6,edge7])\n      boltIndex = 6\n\n\n    #aFace =Part.Face(aWire)\n    #Part.show(aWire)\n    headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    #FreeCAD.Console.PrintMessage(\"der Kopf mit revolve: \" + str(dia) + \"\\n\")\n    #Part.show(headShell)\n    chamFace = headShell.Faces[0].cut(solidHex)\n    #Part.show(chamFace)\n\n    topFaces.append(chamFace.Faces[0])\n    for i in range(1,boltIndex):\n      topFaces.append(headShell.Faces[i])\n\n\n    if self.rThread:\n      #rthread = self.makeShellthread(dia, P, halfturns, True, offSet)\n      #rthread.translate(Base.Vector(0.0, 0.0,-a_point-2.0*P))\n      threadShell = self.makeInnerThread_2(dia, P, int(turns), da, m)\n      threadShell.translate(Base.Vector(0.0, 0.0,turns*P))\n      #Part.show(threadShell)\n      for tFace in threadShell.Faces:\n        topFaces.append(tFace)\n      headShell = Part.Shell(topFaces)\n      screw = Part.Solid(headShell)\n    else:\n      screwShell = Part.Shell(topFaces)\n      screw = Part.Solid(screwShell)\n\n    return screw\n\n  def makeScrewTap(self, ThreadType ='M6',l=25.0):\n    \"\"\"ISO 7380-1, ISO 7380-2, DIN 967\n\n    make ISO 7380-1 Button head Screw\n    make ISO 7380-2 Button head Screw with collar\n    make DIN 967 cross recessed pan head Screw with collar\n    \"\"\"\n    dia = get_diameter(ThreadType)\n\n    P, tunIn, tunEx  = tuningTable[ThreadType]\n\n    residue, turns = math.modf((l)/P)\n    turns += 1.0\n    #FreeCAD.Console.PrintMessage(\"ScrewTap residue: \" + str(residue) + \" turns: \" + str(turns) + \"\\n\")\n\n\n    if self.rThread:\n      screwTap = self.makeInnerThread_2(dia, P, int(turns), None, 0.0)\n      screwTap.translate(Base.Vector(0.0, 0.0,(1-residue)*P))\n    else:\n      H=P*math.cos(math.radians(30)) # Gewindetiefe H\n      r=dia/2.0\n\n      # points for inner thread profile\n      Pnt0 = Base.Vector(0.0,0.0,(1-residue)*P)\n      Pnt1 = Base.Vector(r-H*5.0/8.0,0.0,(1-residue)*P)\n      Pnt2 = Base.Vector(r-H*5.0/8.0,0.0,-l)\n      Pnt3 = Base.Vector(0.0,0.0,-l)\n\n      edge1 = Part.makeLine(Pnt0,Pnt1)\n      edge2 = Part.makeLine(Pnt1,Pnt2)\n      edge3 = Part.makeLine(Pnt2,Pnt3)\n      aWire=Part.Wire([edge1,edge2,edge3])\n      headShell = aWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360.0)\n      screwTap = Part.Solid(headShell)\n\n    return screwTap\n\n  def cutChamfer(self, dia_cC, P_cC, l_cC):\n    cham_t = P_cC*math.sqrt(3.0)/2.0*17.0/24.0\n    PntC0 = Base.Vector(0.0,0.0,-l_cC)\n    PntC1 = Base.Vector(dia_cC/2.0-cham_t,0.0,-l_cC)\n    PntC2 = Base.Vector(dia_cC/2.0+cham_t,0.0,-l_cC+cham_t+cham_t)\n    PntC3 = Base.Vector(dia_cC/2.0+cham_t,0.0,-l_cC-P_cC-cham_t)\n    PntC4 = Base.Vector(0.0,0.0,-l_cC-P_cC-cham_t)\n\n    edgeC1 = Part.makeLine(PntC0,PntC1)\n    edgeC2 = Part.makeLine(PntC1,PntC2)\n    edgeC3 = Part.makeLine(PntC2,PntC3)\n    edgeC4 = Part.makeLine(PntC3,PntC4)\n    edgeC5 = Part.makeLine(PntC4,PntC0)\n    CWire=Part.Wire([edgeC1,edgeC2,edgeC3,edgeC4,edgeC5])\n    #Part.show(CWire)\n    CFace =Part.Face(CWire)\n    cyl = CFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    return cyl\n\n  def makeCross_H3(self, CrossType = '2', m = 6.9, h = 0.0):\n    \"\"\"Cross recess type H\n\n    m = diameter of cross at top of screw at reference level for penetration depth\n    \"\"\"\n    b, e_mean, g, f_mean, r, t1, alpha, beta = iso4757def[CrossType]\n\n    rad265 = math.radians(26.5)\n    rad28 = math.radians(28.0)\n    tg = (m-g)/2.0/math.tan(rad265) # depth at radius of g\n    t_tot = tg + g/2.0 * math.tan(rad28) # total depth\n    #FreeCAD.Console.PrintMessage(\"Cross H3: \" + str(b) + \"\\n\")\n\n    # print 'tg: ', tg,' t_tot: ', t_tot\n    hm = m / 4.0\n    hmc = m / 2.0\n    rmax = m / 2.0 + hm*math.tan(rad265)\n\n    Pnt0 = Base.Vector(0.0,0.0,hm)\n    Pnt1 = Base.Vector(rmax,0.0,hm)\n    Pnt3 = Base.Vector(0.0,0.0,0.0)\n    Pnt4 = Base.Vector(g/2.0,0.0,-tg)\n    Pnt5 = Base.Vector(0.0,0.0,-t_tot)\n\n    edge1 = Part.makeLine(Pnt0,Pnt1)\n    edge3 = Part.makeLine(Pnt1,Pnt4)\n    edge4 = Part.makeLine(Pnt4,Pnt5)\n    # FreeCAD.Console.PrintMessage(\"Edges made Pnt1: \" + str(Pnt1) + \"\\n\")\n\n    aWire=Part.Wire([edge1,edge3,edge4])\n    crossShell = aWire.revolve(Pnt3,Base.Vector(0.0,0.0,1.0),360)\n    #FreeCAD.Console.PrintMessage(\"Peak-wire revolved: \" + str(e_mean) + \"\\n\")\n    cross = Part.Solid(crossShell)\n    #Part.show(cross)\n\n    # the need to cut 4 corners out of the above shape.\n    # Definition of corner\n    # The angles 92 degrees and alpha are defined on a plane which has\n    # an angle of beta against our coordinate system.\n    # The projected angles are needed for easier calculation!\n    rad_alpha = math.radians(alpha/2.0)\n    rad92 = math.radians(92.0/2.0)\n    rad_beta = math.radians(beta)\n\n    rad_alpha_p = math.atan(math.tan(rad_alpha)/math.cos(rad_beta))\n    rad92_p = math.atan(math.tan(rad92)/math.cos(rad_beta))\n\n    tb = tg + (g-b)/2.0 * math.tan(rad28) # depth at dimension b\n    rbtop = b/2.0 + (hmc + tb)*math.tan(rad_beta) # radius of b-corner at hm\n    rbtot = b/2.0 - (t_tot - tb)*math.tan(rad_beta) # radius of b-corner at t_tot\n\n    dre = e_mean/2.0 / math.tan(rad_alpha_p)  # delta between corner b and corner e in x direction\n    #FreeCAD.Console.PrintMessage(\"delta calculated: \" + str(dre) + \"\\n\")\n\n    dx = m/2.0 * math.cos(rad92_p)\n    dy = m/2.0 * math.sin(rad92_p)\n\n    PntC0 = Base.Vector(rbtop,0.0,hmc)\n    PntC1 = Base.Vector(rbtot,0.0,-t_tot)\n    PntC2 = Base.Vector(rbtop+dre,+e_mean/2.0,hmc)\n    PntC3 = Base.Vector(rbtot+dre,+e_mean/2.0,-t_tot)\n    PntC4 = Base.Vector(rbtop+dre,-e_mean/2.0,hmc)\n    PntC5 = Base.Vector(rbtot+dre,-e_mean/2.0,-t_tot)\n\n    PntC6 = Base.Vector(rbtop+dre+dx,+e_mean/2.0+dy,hmc)\n    #PntC7 = Base.Vector(rbtot+dre+dx,+e_mean/2.0+dy,-t_tot)\n    PntC7 = Base.Vector(rbtot+dre+2.0*dx,+e_mean+2.0*dy,-t_tot)\n    PntC8 = Base.Vector(rbtop+dre+dx,-e_mean/2.0-dy,hmc)\n    #PntC9 = Base.Vector(rbtot+dre+dx,-e_mean/2.0-dy,-t_tot)\n    PntC9 = Base.Vector(rbtot+dre+2.0*dx,-e_mean-2.0*dy,-t_tot)\n\n    #wire_hm = Part.makePolygon([PntC0,PntC2,PntC6,PntC8,PntC4,PntC0])\n    #face_hm =Part.Face(wire_hm)\n    #Part.show(face_hm)\n\n    wire_t_tot = Part.makePolygon([PntC1,PntC3,PntC7,PntC9,PntC5,PntC1])\n    # Part.show(wire_t_tot)\n    edgeC1 = Part.makeLine(PntC0,PntC1)\n    #FreeCAD.Console.PrintMessage(\"edgeC1 mit PntC9\" + str(PntC9) + \"\\n\")\n\n    makeSolid=True\n    isFrenet=False\n    corner = Part.Wire(edgeC1).makePipeShell([wire_t_tot],makeSolid,isFrenet)\n    #Part.show(corner)\n\n    rot_axis = Base.Vector(0.,0.,1.0)\n    sin_res = math.sin(math.radians(90)/2.0)\n    cos_res = math.cos(math.radians(90)/2.0)\n    rot_axis.multiply(-sin_res) # Calculation of Quaternion-Elements\n    #FreeCAD.Console.PrintMessage(\"Quaternion-Elements\" + str(cos_res) + \"\\n\")\n\n    pl_rot = FreeCAD.Placement()\n    pl_rot.Rotation = (rot_axis.x,rot_axis.y,rot_axis.z,cos_res) #Rotation-Quaternion 90\u00b0 z-Axis\n\n    crossShell = crossShell.cut(corner)\n    # Part.show(crossShell)\n    cutplace = corner.Placement\n\n    cornerFaces = []\n    cornerFaces.append(corner.Faces[0])\n    cornerFaces.append(corner.Faces[1])\n    cornerFaces.append(corner.Faces[3])\n    cornerFaces.append(corner.Faces[4])\n\n    cornerShell = Part.Shell(cornerFaces)\n    cornerShell = cornerShell.common(cross)\n    addPlace = cornerShell.Placement\n\n    crossFaces = cornerShell.Faces\n\n    for i in range(3):\n      #cutplace.Rotation = pl_rot.Rotation.multiply(corner.Placement.Rotation)\n      corner.Placement.Rotation = pl_rot.Rotation.multiply(corner.Placement.Rotation)\n      crossShell = crossShell.cut(corner)\n      #addPlace.Rotation = pl_rot.Rotation.multiply(cornerShell.Placement.Rotation)\n      cornerShell.Placement.Rotation = pl_rot.Rotation.multiply(cornerShell.Placement.Rotation)\n      for coFace in cornerShell.Faces:\n        crossFaces.append(coFace)\n\n    # Part.show(crossShell)\n    for i in range(1,6):\n      crossFaces.append(crossShell.Faces[i])\n\n    crossShell0 = Part.Shell(crossFaces)\n\n    crossFaces.append(crossShell.Faces[0])\n    crossShell = Part.Shell(crossFaces)\n\n    cross = Part.Solid(crossShell)\n\n\n    #FreeCAD.Console.PrintMessage(\"Placement: \" + str(pl_rot) + \"\\n\")\n\n    cross.Placement.Base = Base.Vector(0.0,0.0,h)\n    crossShell0.Placement.Base = Base.Vector(0.0,0.0,h)\n    #Part.show(crossShell0)\n    #Part.show(cross)\n    return cross, crossShell0\n\n  def makeAllen2(self, s_a=3.0, t_a=1.5, h_a=2.0):\n    \"\"\"Allen recess cutting tool\n\n    Parameters used: s_mean, k, t_min, dk\n    \"\"\"\n    # h_a  top height location of cutting tool\n    # s_a hex width\n    # t_a dept of the allen\n    # dk_a diameter not needed anymore\n\n    e_cham = 2.0 * s_a / math.sqrt(3.0)\n    depth = s_a / 3.0\n    #FreeCAD.Console.PrintMessage(\"allen tool: \" + str(s_a) + \"\\n\")\n\n    # Points for an arc at the peak of the cone\n    rCone = e_cham/4.0\n    hyp = (depth*math.sqrt(e_cham**2/depth**2+1.0)*rCone)/e_cham\n    radAlpha = math.atan(e_cham/depth)\n    radBeta = math.pi/2.0 - radAlpha\n    zrConeCenter=hyp - depth -t_a\n    xArc1=math.sin(radBeta)*rCone\n    zArc1=zrConeCenter - math.cos(radBeta)*rCone\n    xArc2=math.sin(radBeta/2.0)*rCone\n    zArc2=zrConeCenter - math.cos(radBeta/2.0)*rCone\n    zArc3 = zrConeCenter - rCone\n\n    # The round part of the cutting tool, we need for the allen hex recess\n    PntH1 = Base.Vector(0.0,0.0,-t_a-depth-depth)\n    PntH2 = Base.Vector(e_cham,0.0,-t_a-depth-depth)\n    PntH3 = Base.Vector(e_cham,0.0,-t_a+depth)\n    PntH4 = Base.Vector(0.0,0.0,-t_a-depth)\n\n    PntA1 = Base.Vector(xArc1,0.0,zArc1)\n    PntA2 = Base.Vector(xArc2,0.0,zArc2)\n    PntA3 = Base.Vector(0.0,0.0,zArc3)\n\n    edgeA1 = Part.Arc(PntA1,PntA2,PntA3).toShape()\n\n    edgeH1 = Part.makeLine(PntH1,PntH2)\n    edgeH2 = Part.makeLine(PntH2,PntH3)\n    edgeH3 = Part.makeLine(PntH3,PntA1)\n    edgeH4 = Part.makeLine(PntA3,PntH1)\n\n    hWire=Part.Wire([edgeH1,edgeH2,edgeH3,edgeA1,edgeH4])\n    # Part.show(hWire)\n    hFace =Part.Face(hWire)\n    roundtool = hFace.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n\n    # create hexagon\n    mhex=Base.Matrix()\n    mhex.rotateZ(math.radians(60.0))\n    polygon = []\n    vhex=Base.Vector(s_a/math.sqrt(3.0),0.0,1.0)\n    for i in range(6):\n       polygon.append(vhex)\n       vhex = mhex.multiply(vhex)\n    polygon.append(vhex)\n    hexagon = Part.makePolygon(polygon)\n    hexFace = Part.Face(hexagon)\n    solidHex = hexFace.extrude(Base.Vector(0.0,0.0,-1.0-t_a-depth*1.1))\n    allen = solidHex.cut(roundtool)\n    # Part.show(allen)\n\n    allenFaces = [allen.Faces[0]]\n    for i in range(2,9):\n      allenFaces.append(allen.Faces[i])\n    allenShell = Part.Shell(allenFaces)\n    solidHex.Placement.Base = Base.Vector(0.0,0.0,h_a)\n    allenShell.Placement.Base = Base.Vector(0.0,0.0,h_a)\n    return solidHex, allenShell\n\n  def makeIso10664_3(self,RType ='T20',t_hl=3.0, h_hl = 0):\n    \"\"\"ISO 10664 Hexalobular internal driving feature for bolts and screws\"\"\"\n    # t_hl depth of the recess\n    # h_hl top height location of Cutting tool\n    A, B, Re = iso10664def[RType]\n    sqrt_3 = math.sqrt(3.0)\n    depth=A/4.0\n    offSet = 1.0\n\n    # Chamfer cutter for the hexalobular recess\n    PntH1 = Base.Vector(0.0,0.0,-t_hl-depth-1.0)\n    #PntH2 = Base.Vector(A/2.0*1.02,0.0,-t_hl-depth-1.0)\n    #PntH3 = Base.Vector(A/2.0*1.02,0.0,-t_hl)\n    PntH2 = Base.Vector(A,0.0,-t_hl-depth-1.0)\n    PntH3 = Base.Vector(A,0.0,-t_hl+depth)\n    PntH4 = Base.Vector(0.0,0.0,-t_hl-depth)\n\n    # Points for an arc at the peak of the cone\n    rCone = A/4.0\n    hyp = (depth*math.sqrt(A**2/depth**2+1.0)*rCone)/A\n    radAlpha = math.atan(A/depth)\n    radBeta = math.pi/2.0 - radAlpha\n    zrConeCenter=hyp - depth -t_hl\n    xArc1=math.sin(radBeta)*rCone\n    zArc1=zrConeCenter - math.cos(radBeta)*rCone\n    xArc2=math.sin(radBeta/2.0)*rCone\n    zArc2=zrConeCenter - math.cos(radBeta/2.0)*rCone\n    zArc3 = zrConeCenter - rCone\n\n    PntA1 = Base.Vector(xArc1,0.0,zArc1)\n    PntA2 = Base.Vector(xArc2,0.0,zArc2)\n    PntA3 = Base.Vector(0.0,0.0,zArc3)\n\n    edgeA1 = Part.Arc(PntA1,PntA2,PntA3).toShape()\n\n    edgeH1 = Part.makeLine(PntH1,PntH2)\n    edgeH2 = Part.makeLine(PntH2,PntH3)\n    edgeH3 = Part.makeLine(PntH3,PntA1)\n    edgeH4 = Part.makeLine(PntA3,PntH1)\n\n    hWire=Part.Wire([edgeH1,edgeH2,edgeH3,edgeA1])\n    cutShell = hWire.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)\n    cutTool = Part.Solid(cutShell)\n\n\n    Ri = -((B+sqrt_3*(2.*Re-A))*B+(A-4.*Re)*A)/(4.*B-2.*sqrt_3*A+(4.*sqrt_3-8.)*Re)\n    #print '2nd  Ri last solution: ', Ri\n    beta=math.acos(A/(4*Ri+4*Re)-(2*Re)/(4*Ri+4*Re))-math.pi/6\n    #print 'beta: ', beta\n    Rh=(sqrt_3*(A/2.0-Re))/2.0\n    Re_x = A/2.0 - Re + Re*math.sin(beta)\n    Re_y = Re*math.cos(beta)\n    Ri_y = B/4.0\n    Ri_x = sqrt_3*B/4.0\n\n    mhex=Base.Matrix()\n    mhex.rotateZ(math.radians(60.0))\n    hexlobWireList = []\n\n    PntRe0=Base.Vector(Re_x,-Re_y,offSet)\n    PntRe1=Base.Vector(A/2.0,0.0,offSet)\n    PntRe2=Base.Vector(Re_x,Re_y,offSet)\n    edge0 = Part.Arc(PntRe0,PntRe1,PntRe2).toShape()\n    #Part.show(edge0)\n    hexlobWireList.append(edge0)\n\n    PntRi = Base.Vector(Ri_x,Ri_y,offSet)\n    PntRi2 = mhex.multiply(PntRe0)\n    edge1 = Part.Arc(PntRe2,PntRi,PntRi2).toShape()\n    #Part.show(edge1)\n    hexlobWireList.append(edge1)\n\n    for i in range(5):\n       PntRe1 = mhex.multiply(PntRe1)\n       PntRe2 = mhex.multiply(PntRe2)\n       edge0 = Part.Arc(PntRi2,PntRe1,PntRe2).toShape()\n       hexlobWireList.append(edge0)\n       PntRi = mhex.multiply(PntRi)\n       PntRi2 = mhex.multiply(PntRi2)\n       if i == 5:\n          edge1 = Part.Arc(PntRe2,PntRi,PntRe0).toShape()\n       else:\n          edge1 = Part.Arc(PntRe2,PntRi,PntRi2).toShape()\n       hexlobWireList.append(edge1)\n    hexlobWire=Part.Wire(hexlobWireList)\n    #Part.show(hWire)\n\n    face=Part.Face(hexlobWire)\n\n    # Extrude in z to create the cutting tool for the screw-head-face\n    Helo=face.extrude(Base.Vector(0.0,0.0,-t_hl-depth-offSet))\n    # Make the recess-shell for the screw-head-shell\n\n    hexlob = Helo.cut(cutTool)\n    #Part.show(hexlob)\n    hexlobFaces = [hexlob.Faces[0]]\n    for i in range(2,15):\n      hexlobFaces.append(hexlob.Faces[i])\n\n    hexlobShell = Part.Shell(hexlobFaces)\n\n    hexlobShell.Placement.Base = Base.Vector(0.0,0.0,h_hl)\n    Helo.Placement.Base = Base.Vector(0.0,0.0,h_hl)\n\n    return Helo, hexlobShell\n\n  def setThreadType(self, TType = 'simple'):\n    self.simpThread = False\n    self.symThread = False\n    self.rThread = False\n    if TType == 'simple':\n      self.simpThread = True\n    if TType == 'symbol':\n      self.symThread = True\n    if TType == 'real':\n      self.rThread = True\n\n  def setTuner(self, myTuner = 511):\n    self.Tuner = myTuner\n\n\nclass ScrewMacro(object):\n  d = QtGui.QWidget()\n  d.ui = Ui_ScrewMaker()\n  d.ui.setupUi(d)\n  if __name__ == '__main__':\n    d.show()\n\n\ndef main():\n  o = ScrewMacro()\n\nif __name__ == '__main__':\n  main()\n",
    "url": "http://freecadweb.org/wiki/Macro_screw_maker1_2",
    "raw_code_url": "https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/master/ObjectCreation/ScrewMaker.FCMacro",
    "wiki": "http://freecadweb.org/wiki/Macro_screw_maker1_2",
    "version": "2.3.1",
    "license": "",
    "date": "2018-10-22",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Ulrich Brammer <ulrich1a@users.sourceforge.net>",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_screw_maker1_2.png",
    "icon_source": "https://wiki.freecad.org/images/0/00/Macro_screw_maker1_2.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "3D Parametric Curve",
    "on_wiki": true,
    "on_git": false,
    "desc": "Draw a function described by parametric equations x(t), y(t) and z(t) with the possibility to choose between B-spline and polyline for the type of line between points.<br /><br />Macro version: 2.0<br />Last modified: 2015-03-06<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/f/f5/Macro_3D_Parametric_Curve.png\">ToolBar Icon</a><br />Author: Lucio Gomez (psicofil)<br /> ",
    "comment": "Draw a function described by parametric equations x(t), y(t) and z(t) with the possibility to choose between B-spline and polyline for the type of line between points.",
    "code": "# -*- coding: utf-8 -*-\n# Create a 3D parametric Curve.\n# Author: Gomez Lucio\n# Modified by Laurent Despeyroux on 9th feb 2015\n#   - 3 helping variables added a, b and c\n#   - enlarged GUI\n#   - more flexible GUI\n#   - basic error mangement\n \nimport FreeCAD\nfrom PySide import QtGui,QtCore\nimport Part\nimport Draft\nfrom math import *\n \nclass ParamCurv(QtGui.QWidget):\n    def __init__(self):\n        super(ParamCurv, self).__init__()\n        self.initUI()\n    def initUI(self):\n        self.t0 = QtGui.QLabel(\"Equation :\",self)\n        self.ta = QtGui.QLabel(\"    a(t) \",self)\n        self.la = QtGui.QLineEdit(self)\n        self.la.setText(\"37\")\n        self.tb = QtGui.QLabel(\"    b(a,t) \",self)\n        self.lb = QtGui.QLineEdit(self)\n        self.lb.setText(\"1\")\n        self.tc = QtGui.QLabel(\"    c(a,b,t) \",self)\n        self.lc = QtGui.QLineEdit(self)\n        self.lc.setText(\"(a+cos(a*t)*2)*b\")\n        self.t1 = QtGui.QLabel(\"    X(a,b,c,t) \",self)\n        self.l1 = QtGui.QLineEdit(self)\n        self.l1.setText(\"cos(t)*c\")\n        self.t2 = QtGui.QLabel(\"    Y(a,b,c,t) \",self)\n        self.l2 = QtGui.QLineEdit(self)\n        self.l2.setText(\"sin(t)*c\")\n        self.t3 = QtGui.QLabel(\"    Z(a,b,c,t) \",self)\n        self.l3 = QtGui.QLineEdit(self)\n        self.l3.setText(\"0\")\n        self.t31 = QtGui.QLabel(\"Parameters :\",self)\n        self.t4 = QtGui.QLabel(\"    Min t \",self)\n        self.l4 = QtGui.QLineEdit(self)\n        self.l4.setText(\"0\")\n        self.t5 = QtGui.QLabel(\"    Max t \",self)\n        self.l5 = QtGui.QLineEdit(self)\n        self.l5.setText(\"6.283185\")\n        self.t6 = QtGui.QLabel(\"    Interval \",self)\n        self.l6 = QtGui.QLineEdit(self)\n        self.l6.setText(\"0.01\")\n        self.t7 = QtGui.QLabel(\"Type of Line :\",self)\n        self.op1 = QtGui.QCheckBox(\"    Polyline\",self)\n        self.poly = False\n        self.op1.stateChanged.connect(self.polyState)\n        self.op1.setCheckState(QtCore.Qt.Checked)\n        self.op2 = QtGui.QCheckBox(\"    Bspline\",self)\n        self.bsline = False\n        self.op2.stateChanged.connect(self.bsplineState)\n        self.t8 = QtGui.QLabel(\"    Closed Curve\",self)\n        self.op3 = QtGui.QCheckBox(\"\",self)\n        self.cclose = False\n        self.op3.stateChanged.connect(self.ccloseState)\n        self.createbutt = QtGui.QPushButton(\"Create Curve\",self)\n        self.exitbutt = QtGui.QPushButton(\"Close\",self)\n        layout = QtGui.QGridLayout()\n        self.resize(420, 380)\n        self.setWindowTitle(\"Parametric Curve \")\n        i = 0\n        layout.addWidget(self.t0, i, 0)\n        i = i+1\n        layout.addWidget(self.ta, i, 0)\n        layout.addWidget(self.la, i, 1)\n        i = i+1\n        layout.addWidget(self.tb, i, 0)\n        layout.addWidget(self.lb, i, 1)\n        i = i+1\n        layout.addWidget(self.tc, i, 0)\n        layout.addWidget(self.lc, i, 1)\n        i = i+1\n        layout.addWidget(self.t1, i, 0)\n        layout.addWidget(self.l1, i, 1)\n        i = i+1\n        layout.addWidget(self.t2, i, 0)\n        layout.addWidget(self.l2, i, 1)\n        i = i+1\n        layout.addWidget(self.t3, i, 0)\n        layout.addWidget(self.l3, i, 1)\n        i = i+1\n        layout.addWidget(self.t31, i, 0)\n        i = i+1\n        layout.addWidget(self.t4, i, 0)\n        layout.addWidget(self.l4, i, 1)\n        i = i+1\n        layout.addWidget(self.t5, i, 0)\n        layout.addWidget(self.l5, i, 1)\n        i = i+1\n        layout.addWidget(self.t6, i, 0)\n        layout.addWidget(self.l6, i, 1)\n        i = i+1\n        layout.addWidget(self.t8, i, 0)\n        layout.addWidget(self.op3, i, 1)\n        i = i+1\n        layout.addWidget(self.t7, i, 0)\n        i = i+1\n        layout.addWidget(self.op1, i, 0)\n        layout.addWidget(self.op2, i, 1)\n        i = i+1\n        layout.addWidget(self.createbutt, i, 0)\n        layout.addWidget(self.exitbutt, i, 1)\n        self.setLayout(layout)\n        self.show()\n        QtCore.QObject.connect(self.createbutt, QtCore.SIGNAL(\"pressed()\"),self.draw)\n        QtCore.QObject.connect(self.exitbutt, QtCore.SIGNAL(\"pressed()\"),self.close)\n    def ccloseState(self, state):\n        if state == QtCore.Qt.Checked:\n            self.cclose = True\n        else:\n            self.cclose = False\n    def bsplineState(self, state):\n        if state == QtCore.Qt.Checked:\n            self.bsline = True\n            self.op1.setCheckState(QtCore.Qt.Unchecked)\n        else:\n            self.bsline = False\n    def polyState(self, state):\n        if state == QtCore.Qt.Checked:\n            self.poly = True\n            self.op2.setCheckState(QtCore.Qt.Unchecked)\n        else:\n            self.poly = False\n    def draw(self):\n        msgBox = QtGui.QMessageBox()\n        fa = str(self.la.text())\n        fb = str(self.lb.text())\n        fc = str(self.lc.text())\n        fx = str(self.l1.text())\n        fy = str(self.l2.text())\n        fz = str(self.l3.text())\n        t = float(str(self.l4.text()))\n        tf = float(self.l5.text())\n        intv = float(str(self.l6.text()))\n        d=(tf-t)/intv\n        matriz = []\n        for i in range(int(d)):\n            try:\n              value=\"a\"\n              a=eval(fa)\n              value=\"b\"\n              b=eval(fb)\n              value=\"c\"\n              c=eval(fc)\n              value=\"X\"\n              fxx=eval(fx)\n              value=\"Y\"\n              fyy=eval(fy)\n              value=\"Z\"\n              fzz=eval(fz)\n            except ZeroDivisionError:\n              msgBox.setText(\"Error division by zero in calculus of \"+value+\"() for t=\"+str(t)+\" !\")\n              msgBox.exec_()\n            except:\n              msgBox.setText(\"Error in the formula of \"+value+\"() !\")\n              msgBox.exec_()\n            matriz.append(FreeCAD.Vector(fxx,fyy,fzz))\n            t+=intv\n        curva = Part.makePolygon(matriz)\n        if self.bsline == True:\n            Draft.makeBSpline(curva,closed=self.cclose,face=False)\n        if self.poly == True:\n            Draft.makeWire(curva,closed=self.cclose,face=False)\n    def close(self):\n        self.hide()\n \nParamCurv()",
    "url": "https://wiki.freecad.org/Macro_3D_Parametric_Curve",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2015-03-06",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Lucio Gomez (psicofil)",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_3D_Parametric_Curve.png",
    "icon_source": "https://wiki.freecad.org/images/f/f5/Macro_3D_Parametric_Curve.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Draw 2D Function",
    "on_wiki": true,
    "on_git": false,
    "desc": "Use it to draw a function described by a \"equation\" [z=F(x)] (Z-X plane)<br /><br />Macro version: 1.0<br />Last modified: 2011-08-01<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/3/36/Macro_Draw_2D_Function.png\">ToolBar Icon</a><br />Author: unknown<br /> ",
    "comment": "Use it to draw a function described by a \"equation\" [z=F(x)] (Z-X plane)",
    "code": "# F = variable used in the function,\n# X = initial value of x,\n# Nb = Number of step,\n# Z = function express with x\n# ZZ = function express with xx\n\nimport FreeCAD, FreeCADGui, Part\nimport math\nF=800\nX=-500\nNb=10\nStep=1000/Nb\nY=0\nfor I in range(Nb):\n\tXX=X+Step \n \tZ=X*X/(4*F)\n \tZZ=XX*XX/(4*F)\n \tif I==0:\n \t\tprint( \"Le test est vrai !\")\n \t\tnomme=Part.makeLine((X,Y,Z),(XX,Y,ZZ))\n \t\tWWire=Part.Wire([nomme])\n \telse :\n \t\tprint( \"Le test est 2 !\")\n \t\tnomme=Part.makeLine((X,Y,Z),(XX,Y,ZZ))\t\t\n \t\tWWire=Part.Wire([WWire,nomme])\n \tX=XX \n \nPart.show(WWire)",
    "url": "https://wiki.freecad.org/Macro_Draw_2D_Function",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2011-08-01",
    "src_filename": "",
    "filename_from_url": "",
    "author": "unknown",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Draw_2D_Function.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/3/36/Macro_Draw_2D_Function.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Draw Parametric 2D Function",
    "on_wiki": true,
    "on_git": false,
    "desc": "Draws 2-dimensional, parametric and optionally polar equations.<br /><br />Macro version: 2.0<br />Last modified: 2012-08-30<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/0/03/Macro_Draw_Parametric_2D_Function.png\">ToolBar Icon</a><br />Author: T4b<br /> ",
    "comment": "Draws 2-dimensional, parametric and optionally polar equations.",
    "code": "import FreeCAD, FreeCADGui, Part\nimport math\n\ndef evalFunction(suppliedFunction, n):\n\t\"\"\"This function uses eval to evaluate suppliedFunction.\n\t\n\tIt does in no way check whether suppliedFunction is evil, thus it is itself evil!\n\t\"\"\"\n\treturn eval(suppliedFunction)\n\ndef draw2Dfunction(xFunction=\"n\", yFunction=\"n\", n=-5, nd=10, step=10, z=0, pol=0):\n\t\"\"\"Draws 2-dimensional mathemathical functions\n\t\n\tThe function is drawn for n's between n and n+nd, in steps of 1/step, on the z-coordinate z.\n\tEquations for x and y can be given (xFunction and yFunction arguments), they default to n.\n\t\n\tIf pol=1 then x is interpreted as r and y is interpreted as t.\n\t\"\"\"\n\tnStart=n\n\twhile math.fabs(n-nd)-1.0/step>0:\n\t\tprint( \"n: \" + str(n))\n\t\tx=evalFunction(xFunction, n)\n\t\ty=evalFunction(yFunction, n)\n\t\tnNext=n+math.copysign(1,nd-n)/step \n\t\tprint( \"nNext: \" + str(nNext))\n\t\txNext=evalFunction(xFunction, nNext)\n\t\tyNext=evalFunction(yFunction, nNext)\n\t\tif pol==0:\n\t\t\tnextSeg=(x,y,z),(xNext,yNext,z)\n\t\telse:\n\t\t\tnextSeg=(x*math.cos(y),x*math.sin(y),z),(xNext*math.cos(yNext),xNext*math.sin(yNext),z)\n\t\tprint( \"nextSeg: \" + str(nextSeg))\n\t\tnomme=Part.makeLine(*nextSeg)\n\t\tif n==nStart:\n\t\t\tWWire=Part.Wire([nomme])\n\t\telse:\n\t\t\tWWire=Part.Wire([WWire,nomme])\n\t\tn=nNext\n\tPart.show(WWire)\n#Example usage:\ndraw2Dfunction(xFunction=\"0.5*n\", yFunction=\"-0.75*n\", n=0, nd=-math.pi, step=50, pol=1)",
    "url": "https://wiki.freecad.org/Macro_Draw_Parametric_2D_Function",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2012-08-30",
    "src_filename": "",
    "filename_from_url": "",
    "author": "T4b",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Draw_Parametric_2D_Function.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/0/03/Macro_Draw_Parametric_2D_Function.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Parametric Curve FP",
    "on_wiki": true,
    "on_git": false,
    "desc": "Update of Macro 3D Parametric Curve, but with new features. Creates a Feature Python object, offers spreadsheet and JSON integration, expanded parameters.<br />It has support for the same a, b, c parameters, but also can have as many d parameters in the form of d1, d2, d3, d4, etc. as you like.<br />It also supports saving formulas to a text file in JSON format and support for Spreadsheet integration of the current formula.<br />Full documentation can be found <a rel=\"nofollow\" class=\"external text\" href=\"https://github.com/mwganson/Parametric_Curve_FP\">Full Documentation on Github Parametric_Curve_FP</a> on github.<br /><br />Macro version: 2025.01.28b<br />Last modified: 2025-01-28<br />FreeCAD version: 1.0<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/images/5/59/Parametric_Curve_FP.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Update of Macro 3D Parametric Curve, but with new features. Creates a Feature Python object, offers spreadsheet and JSON integration, expanded parameters.",
    "code": "# -*- coding: utf-8 -*-\n__version__ = \"2025.01.28b\"\n__title__ = \"Parametric_Curve_FP\"\n__author__ = \"<TheMarkster> 2021, based on macro 3D Parametric Curve by Gomez Lucio,  Modified by Laurent Despeyroux on 9th feb 2015\"\n__license__ = \"LGPL 2.1\"\n__doc__ = \"Parametric curve from formula\"\n__usage__ = '''Activate the tool and modify properties as desired'''\n\n\nimport FreeCAD, FreeCADGui\nfrom pivy import coin\nfrom math import *\nimport statistics\nimport Part\nimport json\nimport os, sys\nimport subprocess, os\nimport platform\nimport re\nfrom PySide import QtGui,QtCore\n\n\n# Albert Einstein once remarked how he \"stood on the shoulders of giants\" in giving credit to those\n# great thinkers who came before him and who helped pave the way for his Theory of Relativity.\n# I'm certainly no Einstein, but in making this macro, I, too, have built upon the work of others\n# who came before.  Thanks, in particular, to Gomez Lucio, author of the original parametric curve\n# macro, and to Laurent Despeyroux, who extended it, and Paul McGuire for his work on FourFn parser.\n# Also thanks to users openBrain and edwilliams16 of the FreeCAD forum for their help with regular\n# expression parsing and testing / debugging / helping with other coding aspects.\n\n# In order to avoid using eval() and the security implications therefrom, I have borrowed and modified\n# some code for using pyparsing.  I added the ability to include a dictionary of constants to evaluate().\n# For example, evaluate(\"a+b*3\", {\"a\":1,\"b\":2}) evalutes to 7.  I also added some additional math functions\n# to the fn dictionary.  And user edwilliams16 at the FreeCAD forum has fixed a bug in the fnumber\n# regular expression, which was failing in cases of \".5\" instead of \"0.5\". --Mark\n\n# <begin imported code from FourFN.py>\n\n# https://github.com/pyparsing/pyparsing/blob/master/examples/fourFn.py\n#\n\n# fourFn.py\n#\n# Demonstration of the pyparsing module, implementing a simple 4-function expression parser,\n# with support for scientific notation, and symbols for e and pi.\n# Extended to add exponentiation and simple built-in functions.\n# Extended test cases, simplified pushFirst method.\n# Removed unnecessary expr.suppress() call (thanks Nathaniel Peterson!), and added pyparsing.Group\n# Changed fnumber to use a pyparsing.Regex, which is now the preferred method\n# Reformatted to latest pypyparsing features, support multiple and variable args to functions\n#\n# Copyright 2003-2019 by Paul McGuire\n#\n# ------- added by <TheMarkster> -- to fix conflict with another addon\nsyspath = sys.path\nnewsyspath = [sp for sp in sys.path if not \"cadquery\" in sp]\nsys.path = newsyspath\nimport pyparsing\nimport importlib\nimportlib.reload(pyparsing)\n#-------------\n#from pyparsing import (\n#    pyparsing.Literal,\n#    pyparsing.Word,\n#    pyparsing.Group,\n#    pyparsing.Forward,\n#    pyparsing.alphas,\n#    pyparsing.alphanums,\n#    pyparsing.Regex,\n#    pyparsing.ParseException,\n#    pyparsing.CaselessKeyword,\n#    pyparsing.Suppress,\n#    pyparsing.delimitedList,\n#)\n#----------------\nsys.path = syspath\n# ------- end <TheMarkster> code\nimport math\nimport operator\n\nexprStack = []\n\n\ndef push_first(toks):\n    exprStack.append(toks[0])\n\n\ndef push_unary_minus(toks):\n    for t in toks:\n        if t == \"-\":\n            exprStack.append(\"unary -\")\n        else:\n            break\n\n\nbnf = None\n\n\ndef BNF():\n    '''\n    expop   :: '^'\n    multop  :: '*' | '/'\n    addop   :: '+' | '-'\n    integer :: ['+' | '-'] '0'..'9'+\n    atom    :: PI | E | real | fn '(' expr ')' | '(' expr ')'\n    factor  :: atom [ expop factor ]*\n    term    :: factor [ multop factor ]*\n    expr    :: term [ addop term ]*\n    '''\n    global bnf\n    if not bnf:\n        # use pyparsing.CaselessKeyword for e and pi, to avoid accidentally matching\n        # functions that start with 'e' or 'pi' (such as 'exp'); Keyword\n        # and pyparsing.CaselessKeyword only match whole words\n        e = pyparsing.CaselessKeyword(\"E\")\n        pi = pyparsing.CaselessKeyword(\"PI\")\n        # fnumber = Combine(pyparsing.Word(\"+-\"+nums, nums) +\n        #                    Optional(\".\" + Optional(pyparsing.Word(nums))) +\n        #                    Optional(e + pyparsing.Word(\"+-\"+nums, nums)))\n        # or use provided pyparsing_common.number, but convert back to str:\n        # fnumber = ppc.number().addParseAction(lambda t: str(t[0]))\n        #fnumber = pyparsing.Regex(r\"[+-]?\\d+(?:\\.\\d*)?(?:[eE][+-]?\\d+)?\")\n        fnumber = pyparsing.Regex(r'[-+]?(?:(?:\\d*\\.\\d+)|(?:\\d+\\.?))(?:[Ee][+-]?\\d+)?')\n        ident = pyparsing.Word(pyparsing.alphas, pyparsing.alphanums + \"_$\")\n\n        plus, minus, mult, div = map(pyparsing.Literal, \"+-*/\")\n        lpar, rpar = map(pyparsing.Suppress, \"()\")\n        addop = plus | minus\n        multop = mult | div\n        expop = pyparsing.Literal(\"^\")\n\n        expr = pyparsing.Forward()\n        expr_list = pyparsing.delimitedList(pyparsing.Group(expr))\n        # add parse action that replaces the function identifier with a (name, number of args) tuple\n        def insert_fn_argcount_tuple(t):\n            fn = t.pop(0)\n            num_args = len(t[0])\n            t.insert(0, (fn, num_args))\n\n        fn_call = (ident + lpar - pyparsing.Group(expr_list) + rpar).setParseAction(\n            insert_fn_argcount_tuple\n        )\n        atom = (\n            addop[...]\n            + (\n                (fn_call | pi | e | fnumber | ident).setParseAction(push_first)\n                | pyparsing.Group(lpar + expr + rpar)\n            )\n        ).setParseAction(push_unary_minus)\n\n        # by defining exponentiation as \"atom [ ^ factor ]...\" instead of \"atom [ ^ atom ]...\", we get right-to-left\n        # exponents, instead of left-to-right that is, 2^3^2 = 2^(3^2), not (2^3)^2.\n        factor = pyparsing.Forward()\n        factor <<= atom + (expop + factor).setParseAction(push_first)[...]\n        term = factor + (multop + factor).setParseAction(push_first)[...]\n        expr <<= term + (addop + term).setParseAction(push_first)[...]\n        bnf = expr\n    return bnf\n\n\n# map operator symbols to corresponding arithmetic operations\nepsilon = 1e-12\nopn = {\n    \"+\": operator.add,\n    \"-\": operator.sub,\n    \"*\": operator.mul,\n    \"/\": operator.truediv,\n    \"^\": operator.pow,\n}\n\nfn = {\n    \"sin\": math.sin,\n    \"sinh\": math.sinh,\n    \"cos\": math.cos,\n    \"cosh\": math.cosh,\n    \"tan\": math.tan,\n    \"tanh\": math.tanh,\n    \"exp\": math.exp,\n    \"atan\": math.atan,\n    \"atanh\": math.atanh,\n    \"acos\": math.acos,\n    \"acosh\": math.acosh,\n    \"asin\": math.asin,\n    \"asinh\": math.asinh,\n    \"sqrt\": math.sqrt,\n    \"ceil\": math.ceil,\n    \"floor\": math.floor,\n    \"log\": math.log,\n    \"factorial\":math.factorial,\n    \"abs\": abs,\n    \"degrees\": math.degrees,\n    \"degree\": math.degrees,\n    \"deg\": math.degrees,\n    \"lgamma\": math.lgamma,\n    \"gamma\": math.gamma,\n    \"radians\": math.radians,\n    \"rad\": math.radians,\n    \"trunc\": int,\n    \"round\": round,\n    \"sgn\": lambda a: -1 if a < -epsilon else 1 if a > epsilon else 0,\n    # functionsl with multiple arguments\n    \"copysign\": lambda a, b: 1 * (math.copysign(a,b)),\n    \"multiply\": lambda a, b: a * b,\n    \"mod\": lambda a, b: a % b,\n    \"interval\": lambda a, b, t: 1 * ((t >= a) and (t < b)),\n    \"lt\":lambda a, b: 1 * (a < b),\n    \"lte\": lambda a, b: 1 * (a <= b),\n    \"gt\": lambda a, b: 1 * (a > b),\n    \"gte\": lambda a, b: 1 * (a >= b),\n    \"isequal\": lambda a, b: 1 * (a == b),\n    \"isclose\": lambda a, b: 1 * (math.isclose(a, b, abs_tol = 1e-9)),\n    \"isclosetol\": lambda a, b, tol: 1 * (math.isclose(a, b, abs_tol = tol)),\n    \"floordiv\": lambda a, b: a // b,\n    \"atan2\": lambda a, b: math.atan2(a, b),\n    \"perm\": lambda a, b: math.perm(a, b),\n    \"hypot\": math.hypot,\n    \"ternary\": lambda a, b, c: b if a else c,\n    # functions with a variable number of arguments\n    \"any\": lambda *a: 1 * any(a),\n    \"all\": lambda *a: 1 * all(a),\n    \"sum\": lambda *a: sum(a),\n    \"avg\": lambda *a: sum(a)/float(len(a)),\n    \"mean\": lambda *a: sum(a)/float(len(a)),\n    \"gmean\": lambda *a: statistics.geometric_mean(a),\n    \"hmean\": lambda *a: statistics.harmonic_mean(a),\n    \"mode\": lambda *a: statistics.mode(a),\n    \"median\": lambda *a: statistics.median(a),\n    \"stdev\": lambda *a: statistics.stdev(a),\n    \"prod\": lambda *a: math.prod(a),\n}\n\n\ndef evaluate_stack(s,vars):\n    op, num_args = s.pop(), 0\n    if isinstance(op, tuple):\n        op, num_args = op\n    if op == \"unary -\":\n        return -evaluate_stack(s,vars)\n    if op in \"+-*/^\":\n        # note: operands are pushed onto the stack in reverse order\n        op2 = evaluate_stack(s,vars)\n        op1 = evaluate_stack(s,vars)\n        return opn[op](op1, op2)\n    elif op == \"PI\":\n        return math.pi  # 3.1415926535\n    elif op == \"E\":\n        return math.e  # 2.718281828\n    elif op in vars:\n        return vars[op]\n    elif op in fn:\n        # note: args are pushed onto the stack in reverse order\n        args = reversed([evaluate_stack(s,vars) for _ in range(num_args)])\n        return fn[op](*args)\n    elif op[0].isalpha():\n        raise Exception(\"invalid identifier '%s'\" % op)\n    else:\n        # try to evaluate as int first, then as float if int fails\n        try:\n            return int(op)\n        except ValueError:\n            return float(op)\n\n# vars is a dictionary of variable names\n# example:\n# vars = {\"a\":1,\"b\":2}\n# then where \"a\" or \"b\" is found a value is substituted\n# evaluate(\"a+b\",vars) thus returns 3 --Mark\n\ndef evaluate(s, vars={}):\n    if s == \"\": #return 0 in case the user has left the field blank --Mark\n        return 0\n    s= checkForFCEval(s)\n\n\n    exprStack[:] = []\n    try:\n        results = BNF().parseString(s, parseAll=True)\n        val = evaluate_stack(exprStack[:],vars)\n    except pyparsing.ParseException as pe:\n        raise Exception(s, \"failed parse:\", str(pe))\n    except Exception as e:\n        raise Exception (s, \"failed eval:\", str(e), exprStack)\n    else:\n        return val\n\n# implement FreeCAD.DocumentObject.evalExpression(str)\n# usage: fc(freecad_expression_string)\n\ndef checkForFCEval(s):\n    if \"fc(\" in s:\n        idx = s.index(\"fc(\")\n        idx2 = s.index(\")\",idx)+1\n        fc_Total = s[idx:idx2] #example fc(dd.ddFloat)\n        fc_Eval = fc_Total[3:-1] # example dd.ddFloat\n        if \"fc(\" in fc_Eval:\n            FreeCAD.Console.PrintError(\"ParametricCurve::Unsupported -- Nested fc(expr) functions not supported.\\n\")\n        evaluated = FreeCAD.ActiveDocument.Objects[0].evalExpression(fc_Eval)\n        evaluated = evaluated.Value if hasattr(evaluated,\"Value\") else evaluated\n        s = s.replace(fc_Total,str(evaluated))\n        return checkForFCEval(s) #in case there are multiple fc(expr) calls in the same string\n    else:\n        return s\n\n# <end imported code from FourFn.py>\n\n\nclass Curve:\n    def __init__(self, obj):\n        obj.addExtension(\"Part::AttachExtensionPython\")\n        obj.addProperty(\"App::PropertyLinkList\",\"Dependencies\",\"Curve\",\n\"If using fc(expr) to link to another object, add the object to these links to force parametric recomputes when that object changes\")\n        obj.addProperty(\"App::PropertyString\",\"a\",\"Equation1(a,b,c)\",\"a(t)\").a=\"6\"\n        obj.addProperty(\"App::PropertyString\",\"b\",\"Equation1(a,b,c)\",\"b(a,t)\").b=\"1\"\n        obj.addProperty(\"App::PropertyString\",\"c\",\"Equation1(a,b,c)\",\"c(a,b,t)\").c=\"20\"\n        obj.addProperty(\"App::PropertyStringList\",\"d\",\"Equation1(a,b,c)\",\"d1(a,b,c,t)\"+chr(10)+\"d2(a,b,c,t,d1)\"+chr(10)+\"d3(a,b,c,t,d1,d2)\"+chr(10)+\"d4(a,b,c,t,d1,d2,d3)\"+chr(10)+\"...\"+chr(10))\n        obj.addProperty(\"App::PropertyString\",\"X\",\"Equation2(X,Y,Z)\",\"X(a,b,c,d1-dN,t)\").X=\"(a+b*cos(c*t))*cos(t)\"\n        obj.addProperty(\"App::PropertyString\",\"Y\",\"Equation2(X,Y,Z)\",\"Y(a,b,c,d1-dN,X,t)\").Y=\"(a+b*cos(c*t))*sin(t)\"\n        obj.addProperty(\"App::PropertyString\",\"Z\",\"Equation2(X,Y,Z)\",\"Z(a,b,c,d1-dN,X,Y,t)\").Z=\"b*sin(c*t)\"\n        obj.addProperty(\"App::PropertyFloat\",\"F_a\",\"Floats\",\"a as a float if it is a constant (readonly)\")\n        obj.addProperty(\"App::PropertyFloat\",\"F_b\",\"Floats\",\"b as a float if it is a constant (readonly)\")\n        obj.addProperty(\"App::PropertyFloat\",\"F_c\",\"Floats\",\"c as a float if it is a constant (readonly)\")\n        obj.addProperty(\"App::PropertyFloatList\",\"F_d\",\"Floats\",\"di as a float if it is a constant (readonly)\\n\\\n1-indexed, e.g. F_d[1] = d1, F_d[2] = d2, etc.\")\n        obj.addProperty(\"App::PropertyFloat\",\"F_X\",\"Floats\",\"X as a float if it is a constant (readonly)\")\n        obj.addProperty(\"App::PropertyFloat\",\"F_Y\",\"Floats\",\"Y as a float if it is a constant (readonly)\")\n        obj.addProperty(\"App::PropertyFloat\",\"F_Z\",\"Floats\",\"Z as a float if it is a constant (readonly)\")\n        for prop in [\"F_a\",\"F_b\",\"F_c\",\"F_d\",\"F_X\",\"F_Y\",\"F_Z\"]:\n            obj.setEditorMode(prop,1) #readonly\n        obj.addProperty(\"App::PropertyFloat\",\"t_min\",\"Equation3(T Params)\",\"start value for t\").t_min = 0.0\n        obj.addProperty(\"App::PropertyFloat\",\"t_max\",\"Equation3(T Params)\",\"Max t\").t_max = 2*pi\n        obj.addProperty(\"App::PropertyFloat\",\"Interval\",\"Equation3(T Params)\",\"Interval\").Interval = 0.1\n        obj.addProperty(\"App::PropertyBool\",\"Closed\",\"Curve\",\"Whether curve is closed\").Closed=False\n        obj.addProperty(\"App::PropertyBool\",\"PlusOneIteration\",\"Curve\",\"Fixes a bug, but changes existing behavior.  Set to False if it breaks an existing model.\").PlusOneIteration = True\n        obj.addProperty(\"App::PropertyVectorList\",\"Points\",\"Curve\",\"Points used to make the curve. Regenerated each recompute.\").Points =[]\n        obj.addProperty(\"App::PropertyString\",\"Version\", \"Base\", \"Version this object was created with\").Version = __version__\n        obj.addProperty(\"App::PropertyEnumeration\",\"ShapeType\",\"Curve\",\"Options: BSpline, Polygon, Points\").ShapeType=[\"BSpline\",\"Polygon\",\"Points\"]\n        obj.ShapeType = \"BSpline\" #default\n        obj.addProperty(\"App::PropertyLink\",\"Spreadsheet\",\"Spreadsheet\",\"Link a spreadsheet\")\n        obj.addProperty(\"App::PropertyBool\",\"UpdateSpreadsheet\",\"Spreadsheet\",\"[Trigger] Push current formula to linked spreadsheet, creates one and links it if necessary.\").UpdateSpreadsheet=False\n        obj.addProperty(\"App::PropertyBool\",\"UseSpreadsheet\",\"Spreadsheet\",\"If True, poperties are readonly and must come from spreadsheet.  If false, spreadsheet is ignored and properties are set to read/write.\").UseSpreadsheet=False\n        obj.addProperty(\"App::PropertyString\",\"Continuity\",\"Curve\",\"Continuity of Curve\")\n        obj.setEditorMode('Continuity',1)\n        obj.addProperty(\"App::PropertyBool\",\"MakeFace\",\"Curve\",\"Make a face from curve object if possible.  Can't be done with points or if shape isn't closed.\")\n        obj.addProperty(\"App::PropertyFile\",\"File\",\"JSON\",\"JSON format file to contain data\")\n        obj.setEditorMode(\"File\",2)#hidden\n        obj.addProperty(\"App::PropertyBool\",\"Sorted\",\"JSON\", \"Sort formula names\")\n        obj.addProperty(\"App::PropertyEnumeration\",\"Formulas\",\"JSON\",\"Formulas in JSON data\").Formulas=[\"formula\"]\n        obj.addProperty(\"App::PropertyBool\",\"EditFormulas\",\"JSON\",\"[Trigger] brings up editor dialog\")\n#        obj.addProperty(\"App::PropertyBool\",\"WriteFile\",\"JSON\",\"[Trigger] Updates JSON file with current data.  WARNING: will overwrite all current data, use AppendFile to add current formula to file.\").WriteFile = False\n#        obj.addProperty(\"App::PropertyBool\",\"RenameFormula\",\"JSON\",\"[Trigger] Changes current Formula name to string in FormulaName\").RenameFormula = False\n        obj.addProperty(\"App::PropertyString\",\"FormulaName\",\"JSON\",\"Modify this for changing formula name, and then toggle Rename Formula to True\")\n        obj.setEditorMode(\"FormulaName\",2) #hidden --renaming now done in editor\n#        obj.addProperty(\"App::PropertyBool\",\"NewFormula\",\"JSON\",\"[Trigger] Creates new formula adds to Formulas\").NewFormula = False\n#        obj.addProperty(\"App::PropertyBool\",\"OpenFile\",\"JSON\",\"[Trigger] Opens JSON file in default system editor for text files.\").OpenFile = False\n#        obj.addProperty(\"App::PropertyBool\",\"ReadFile\",\"JSON\",\"[Trigger] Reads JSON file.  WARNING: will clobber current formula, use AppendFile to save current formula to file before reading if you want to save it\").OpenFile = False\n#        obj.addProperty(\"App::PropertyBool\",\"AppendFile\",\"JSON\",\"[Trigger] Appends current formula to JSON file.\").AppendFile = False\n#        obj.addProperty(\"App::PropertyBool\",\"DeleteFormula\",\"JSON\",\"[Trigger] Removes current formula from internal data, does not modify JSON file\").DeleteFormula=False\n        obj.Proxy = self\n        self.JSON_Data = {}\n        self.previousFormula = \"\"\n        self.bInihibitUpdates = False\n        self.bInhibitRecompute = False\n        self.newFormula(obj) #initialize with a new formula\n        self.editingMode = False\n        self.fpName = obj.Name\n\n    def setReadOnly(self,fp,bReadOnly):\n        '''if bReadOnly = True, we set the properties linked to the spreadsheet readonly, else set them normal mode'''\n        if bReadOnly:\n            mode = 1\n        else:\n            mode = 0\n        if not hasattr(fp,\"a\"):\n            return\n        fp.setEditorMode('a',mode)\n        fp.setEditorMode('b',mode)\n        fp.setEditorMode('c',mode)\n        fp.setEditorMode('d',mode)\n        fp.setEditorMode('X',mode)\n        fp.setEditorMode('Y',mode)\n        fp.setEditorMode('Z',mode)\n        fp.setEditorMode('t_min',mode)\n        fp.setEditorMode('t_max',mode)\n        fp.setEditorMode('Interval',mode)\n\n    def readJSONFile(self,fp,txt=None):\n        if txt == None:\n            if not self.checkFile(fp):\n                return\n            try:\n                f = open(fp.File)\n            except:\n                #could not open file\n                #assume user entered name for new file\n                f = open(fp.File,\"w\")\n                f.close()\n                FreeCAD.Console.PrintMessage(\"New JSON file created: \"+str(os.path.realpath(f.name))+chr(10))\n                self.writeJSONFile(fp)\n                fp.File = os.path.realpath(f.name)\n                return\n            self.JSON_Data = json.load(f)\n            f.close()\n        else: #txt != None\n            self.JSON_Data = json.loads(txt)\n        #now rename any \"t\" to \"t_min\"\n        for k,v in self.JSON_Data.items():\n            if \"t\" in v.keys():\n                self.JSON_Data[k][\"t_min\"] = self.JSON_Data[k][\"t\"]\n                self.JSON_Data[k].pop(\"t\")\n                FreeCAD.Console.PrintMessage(f\"ParametricCurve: renaming 't' to 't_min' in {k}\"+chr(10))\n        formula_names = []\n        for pn in self.JSON_Data:\n            formula_names.append(pn)\n        fp.Formulas = sorted(formula_names) if hasattr(fp,\"Sorted\") and fp.Sorted else formula_names\n        #Formulas, when the left hand operand, accepts a list\n        #but when the right hand operand, it gives a string, the current formula\n        self.bInihibitUpdates=True\n        self.updateJSONFormula(fp,fp.Formulas)\n        self.bInihibitUpdates=False\n\n    def deleteFormula(self,fp):\n        if not fp.FormulaName:\n            FreeCAD.Console.PrintError(\"No formula selected.\"+chr(10))\n            return\n        self.JSON_Data.pop(fp.FormulaName,None)\n        if len(self.JSON_Data.keys()) == 0:\n            FreeCAD.Console.PrintMessage(\"Must have at least one formula, new one created using existing equations.\"+chr(10))\n            self.newFormula(fp) #must have at least one formula\n        FreeCAD.ActiveDocument.recompute()\n        fp.Formulas = list(self.JSON_Data.keys())\n\n    def appendFile(self,fp):\n        if not self.checkFile(fp):\n            return\n        try:\n            f = open(fp.File)\n        except:\n            #could not open file\n            #assume user entered name for new file\n            f = open(fp.File,\"w\")\n            f.close()\n            FreeCAD.Console.PrintMessage(\"New JSON file created: \"+str(os.path.realpath(f.name))+\"\"+chr(10))\n            self.writeJSONFile(fp)\n            fp.File = os.path.realpath(f.name)\n            return\n        data = json.load(f) #load current data first\n        f.close()\n        for formula in self.JSON_Data.keys():\n            if formula in data: #find a new unique name for this formula and append it\n                FreeCAD.Console.PrintWarning(\"Skipping: \"+formula+\" (already in file).  Rename \"+formula+\" and try again, if desired.\"+chr(10))\n            else: #formula not already in data file\n                FreeCAD.Console.PrintMessage(\"Appending: \"+formula+\" to file.\"+chr(10))\n                data[formula] = self.JSON_Data[formula]\n\n        with open(fp.File,\"w\") as outfile:\n            json.dump(data,outfile)\n\n    def checkFile(self,fp):\n        if not fp.File: #checks to see if there is filename in File property\n            FreeCAD.Console.PrintError(\"No linked JSON file.  Create a new JSON file or link one via the File property.  You can also just enter a name in the File property to create a new file.\"+chr(10))\n            return False\n        return True\n\n    def writeJSONFile(self,fp):\n        if not self.checkFile(fp):\n            return\n        if self.JSON_Data == {}:\n            self.JSON_Data = { #new file, so we just get the one formula\n                \"formula\":{\n                \"a\":fp.a,\n                \"b\":fp.b,\n                \"c\":fp.c,\n                \"d\":fp.d,\n                \"X\":fp.X,\n                \"Y\":fp.Y,\n                \"Z\":fp.Z,\n                \"t_min\":str(fp.t) if hasattr(fp,\"t\") else str(fp.t_min),\n                \"t_max\":str(fp.t_max),\n                \"interval\":str(fp.Interval)\n                }}\n        with open(fp.File,\"w\") as outfile:\n            json.dump(self.JSON_Data,outfile)\n\n    def renameFormula(self,fp):\n        newName = fp.FormulaName\n        if fp.Formulas in self.JSON_Data.keys():\n            self.JSON_Data[fp.FormulaName] = self.JSON_Data.pop(fp.Formulas)\n            fp.Formulas = list(self.JSON_Data.keys())\n            fp.Formulas = newName\n\n    def newFormula(self,fp):\n\n        ii = 1\n        trialName = \"formula\"\n        while (trialName in self.JSON_Data):\n            ii += 1\n            trialName = \"formula\"+str(ii)\n\n        self.JSON_Data[trialName] ={\n                \"a\":fp.a,\n                \"b\":fp.b,\n                \"c\":fp.c,\n                \"d\":fp.d,\n                \"X\":fp.X,\n                \"Y\":fp.Y,\n                \"Z\":fp.Z,\n                \"t_min\":str(fp.t) if hasattr(fp,\"t\") else str(fp.t_min),\n                \"t_max\":str(fp.t_max),\n                \"interval\":str(fp.Interval)\n                }\n        fp.Formulas = list(self.JSON_Data.keys())\n        fp.Formulas = trialName\n        fp.FormulaName = trialName\n\n    def updateJSON_Data(self,fp,formulaName): #update json data from current fp settings\n        if hasattr(fp,\"a\"):\n            self.JSON_Data[formulaName][\"a\"] = fp.a\n        if hasattr(fp,\"b\"):\n            self.JSON_Data[formulaName][\"b\"] = fp.b\n        if hasattr(fp,\"c\"):\n            self.JSON_Data[formulaName][\"c\"] = fp.c\n        if hasattr(fp,\"d\"):\n            self.JSON_Data[formulaName][\"d\"] = fp.d\n        if hasattr(fp,\"X\"):\n            self.JSON_Data[formulaName][\"X\"] = fp.X\n        if hasattr(fp,\"Y\"):\n            self.JSON_Data[formulaName][\"Y\"] = fp.Y\n        if hasattr(fp,\"Z\"):\n            self.JSON_Data[formulaName][\"Z\"] = fp.Z\n        if hasattr(fp,\"t\"):\n            self.JSON_Data[formulaName][\"t\"] = str(fp.t)\n        if hasattr(fp,\"t_min\"):\n            self.JSON_Data[formulaName][\"t_min\"] = str(fp.t_min)\n        if hasattr(fp,\"t_max\"):\n            self.JSON_Data[formulaName][\"t_max\"] = str(fp.t_max)\n        if hasattr(fp,\"Interval\"):\n            self.JSON_Data[formulaName][\"interval\"] = str(fp.Interval)\n\n    def updateJSONFormula(self,fp,formulaName):\n        #FreeCAD.Console.PrintMessage(\"updateJSONFormula\"+chr(10))\n        #when changing formulas if expressions are used the expressions override the new\n        #values from the formula, so we try to set them all to None\n        if not hasattr(fp,\"a\"):\n            return\n        if bool(fp.ExpressionEngine):\n            propstrs = [\"a\",\"b\",\"c\",\"X\",\"Y\",\"Z\",\"t\",\"t_min\",\"t_max\",\"interval\"]\n            for propstr in propstrs:\n                try:\n                    fp.setExpression(propstr,None)\n                except Exception:\n                    pass\n            FreeCAD.Console.PrintWarning(\"ParameticCurve: clearing expressions\\n\")\n        fp.a = self.JSON_Data[formulaName][\"a\"]\n        fp.b = self.JSON_Data[formulaName][\"b\"]\n        fp.c = self.JSON_Data[formulaName][\"c\"]\n        fp.d = self.JSON_Data[formulaName][\"d\"]\n        fp.X = self.JSON_Data[formulaName][\"X\"]\n        fp.Y = self.JSON_Data[formulaName][\"Y\"]\n        fp.Z = self.JSON_Data[formulaName][\"Z\"]\n        if hasattr(fp,\"t\"):\n            fp.t = evaluate(self.stripComments(self.JSON_Data[formulaName][\"t_min\"]))\n        else:\n            fp.t_min = evaluate(self.stripComments(self.JSON_Data[formulaName][\"t_min\"]))\n        fp.t_max = evaluate(self.stripComments(self.JSON_Data[formulaName][\"t_max\"]))\n        fp.Interval = evaluate(self.stripComments(self.JSON_Data[formulaName][\"interval\"]))\n\n\n    def updateToSpreadsheet(self,fp):\n        sheet = None\n        if fp.Spreadsheet == None:\n            sheet = FreeCAD.ActiveDocument.addObject(\"Spreadsheet::Sheet\",\"PC_Sheet\")\n            fp.Spreadsheet = sheet\n            FreeCAD.Console.PrintMessage(\"Spreadsheet linked.\\\\nSet Use Spreadsheet to True to use those aliases.\"+chr(10))\n\n        if not hasattr(fp.Spreadsheet,\"a_cell\"):\n            if not sheet and fp.UseSpreadsheet: #not a new spreadsheet, but one already that exists\n                from PySide import QtGui\n                mw = QtGui.QApplication.activeWindow()\n                items = [\"Add aliases to spreadsheet\",\"Cancel\"]\n                item,ok = QtGui.QInputDialog.getItem(mw,\"Set aliases\",\"Warning: setting aliases will clobber any existing data in cells A1 - B9.  Set aliases anyway?\",items,0)\n                if ok and item == items[0]:\n                    sheet = fp.Spreadsheet\n                else:\n                    return\n\n            if sheet:\n                fp.Spreadsheet.set('A1',\"a_cell\")\n                fp.Spreadsheet.setAlias('B1',\"a_cell\")\n                fp.Spreadsheet.set('A2',\"b_cell\")\n                fp.Spreadsheet.setAlias('B2',\"b_cell\")\n                fp.Spreadsheet.set('A3',\"c_cell\")\n                fp.Spreadsheet.setAlias('B3',\"c_cell\")\n                fp.Spreadsheet.set('A4',\"X\")\n                fp.Spreadsheet.setAlias('B4',\"X\")\n                fp.Spreadsheet.set('A5',\"Y\")\n                fp.Spreadsheet.setAlias('B5',\"Y\")\n                fp.Spreadsheet.set('A6',\"Z\")\n                fp.Spreadsheet.setAlias('B6',\"Z\")\n                fp.Spreadsheet.set('A7',\"t_min\")\n                fp.Spreadsheet.setAlias('B7',\"t_min\")\n                fp.Spreadsheet.set('A8',\"t_max\")\n                fp.Spreadsheet.setAlias('B8',\"t_max\")\n                fp.Spreadsheet.set('A9',\"interval\")\n                fp.Spreadsheet.setAlias('B9',\"interval\")\n                for dd in range(0,len(fp.d)):\n                    fp.Spreadsheet.set('A'+str(dd+10),'d'+str(dd+1))\n                    fp.Spreadsheet.setAlias('B'+str(dd+10),'d'+str(dd+1))\n        fp.Spreadsheet.set('a_cell',self.stripComments(fp.a))\n        fp.Spreadsheet.set('b_cell',self.stripComments(fp.b))\n        fp.Spreadsheet.set('c_cell',self.stripComments(fp.c))\n        for dd in range(0,len(fp.d)):\n            fp.Spreadsheet.set('A'+str(dd+10),'d'+str(dd+1))\n            fp.Spreadsheet.setAlias('B'+str(dd+10),'d'+str(dd+1))\n            fp.Spreadsheet.set('d'+str(dd+1),self.stripComments(fp.d[dd]))\n        fp.Spreadsheet.set('X',self.stripComments(fp.X))\n        fp.Spreadsheet.set('Y',self.stripComments(fp.Y))\n        fp.Spreadsheet.set('Z',self.stripComments(fp.Z))\n        if hasattr(fp,\"t\"):\n            fp.Spreadsheet.set('t_min',str(fp.t))\n        else:\n            fp.Spreadsheet.set('t_min',str(fp.t_min))\n        fp.Spreadsheet.set('t_max',str(fp.t_max))\n        fp.Spreadsheet.set('interval',str(fp.Interval))\n\n\n    def updateFromSpreadsheet(self,fp):\n        if not fp.Spreadsheet or not hasattr(fp.Spreadsheet,\"a_cell\"):\n            return\n        if fp.UseSpreadsheet == False:\n            self.setReadOnly(fp,False)\n            return\n        else:\n            self.setReadOnly(fp,True)\n        doc = FreeCAD.ActiveDocument\n        doc.openTransaction(\"Update from Spreadsheet\")\n\n        fp.a=str(fp.Spreadsheet.a_cell)\n        fp.b=str(fp.Spreadsheet.b_cell)\n        fp.c=str(fp.Spreadsheet.c_cell)\n        dd=0\n        k = \"d\"+str(dd+1)\n        new_d = []\n        while hasattr(fp.Spreadsheet,k):\n            new_d.append(str(getattr(fp.Spreadsheet,k)))\n            dd += 1\n            k = \"d\"+str(dd+1)\n        fp.d = new_d\n        fp.X=str(fp.Spreadsheet.X)\n        fp.Y=str(fp.Spreadsheet.Y)\n        fp.Z=str(fp.Spreadsheet.Z)\n        if hasattr(fp,\"t\"):\n            fp.t = fp.Spreadsheet.t_min\n        else:\n            fp.t_min = fp.Spreadsheet.t_min\n        fp.t_max=fp.Spreadsheet.t_max\n        fp.Interval=fp.Spreadsheet.interval\n\n        if fp.FormulaName:\n            self.bInihibitUpdates=True\n            self.updateJSONFormula(fp,fp.FormulaName)\n            self.bInihibitUpdates=False\n        doc.commitTransaction()\n    def onChanged(self, fp, prop):\n        '''Do something when a property has changed'''\n        doc = FreeCAD.ActiveDocument\n        #FreeCAD.Console.PrintMessage(\"Change property: \" + str(prop) + \"\"+chr(10))\n        if prop == \"Spreadsheet\" and fp.Spreadsheet != None:\n            self.updateFromSpreadsheet(fp)\n\n        elif prop == \"UseSpreadsheet\" and fp.UseSpreadsheet == True:\n            if not fp.Spreadsheet:\n                FreeCAD.Console.PrintError(\"No spreadsheet linked.\\\\n  Create one with Update Spreadsheet or link existing one first.\"+chr(10))\n            self.setReadOnly(fp, True)\n        elif prop == \"UseSpreadsheet\" and fp.UseSpreadsheet == False:\n            self.setReadOnly(fp,False)\n        elif prop == \"Spreadsheet\" and fp.Spreadsheet == None: #user removed link to Spreadsheet\n            self.setReadOnly(fp,False)\n\n        elif prop == \"UpdateSpreadsheet\" and fp.UpdateSpreadsheet == True:\n            doc.openTransaction(\"Update to Spreadsheet\")\n            self.bInhibitRecompute = True\n            self.updateToSpreadsheet(fp)\n            fp.UpdateSpreadsheet = False\n            doc.commitTransaction()\n\n        elif prop == \"File\" and fp.File != None:\n            #self.readJSONFile(fp)\n            FreeCAD.Console.PrintMessage(\"File linked.\\n\\\nUse Read File to import into object.\\n\\\nUse Append File to append formulas to file.\\n\\\nUse Write File to overwrite all data in file.\\n\\\nUse Open File to open file in external editor.\\n\\\n\")\n\n        elif prop == \"Formulas\" and fp.File != None:\n            self.bInihibitUpdates = True\n            self.updateJSONFormula(fp,fp.Formulas)\n            self.bInihibitUpdates = False\n            fp.FormulaName = fp.Formulas\n\n        elif prop == \"WriteFile\" and fp.File != None and fp.WriteFile == True:\n            self.bInhibitRecompute = True\n            self.writeJSONFile(fp)\n            fp.WriteFile = False\n        elif prop == \"RenameFormula\" and fp.RenameFormula == True and fp.File != None:\n            doc.openTransaction(\"Rename formula\")\n            self.bInhibitRecompute = True\n            self.renameFormula(fp)\n            fp.RenameFormula = False\n            doc.commitTransaction()\n        elif prop == \"NewFormula\" and fp.NewFormula == True:\n            doc.openTransaction(\"Create new formula\")\n            self.bInhibitRecompute = True\n            self.newFormula(fp)\n            fp.NewFormula = False\n            doc.commitTransaction()\n        elif prop == \"OpenFile\" and fp.OpenFile == True:\n            fp.OpenFile = False\n            self.bInhibitRecompute = True\n            sys = platform.system()\n            if fp.File:\n                if 'Windows' in sys:\n                    import webbrowser\n                    webbrowser.open(fp.File)\n                elif 'Linux' in sys:\n                    os.system(\"xdg-open '%s'\" % fp.File)\n                elif 'Darwin' in sys:\n                    subprocess.Popen([\"open\", fp.File])\n                else:\n                    FreeCAD.Console.PrintError(\"We were unable to determine your platform, and thus cannot open your file for you.\"+chr(10))\n        elif prop == \"Sorted\":\n            formulas = [key for key in self.JSON_Data.keys()]\n            fp.Formulas = sorted(formulas) if fp.Sorted else formulas\n        elif prop == \"ReadFile\" and fp.ReadFile == True:\n            fp.ReadFile = False\n            doc.openTransaction(\"Read file\")\n            if fp.File:\n                self.readJSONFile(fp)\n            doc.commitTransaction()\n        elif prop == \"AppendFile\" and fp.AppendFile == True:\n            fp.AppendFile = False\n            self.bInhibitRecompute = True\n            self.appendFile(fp)\n        elif prop == \"DeleteFormula\" and fp.DeleteFormula == True:\n            doc.openTransaction(\"Delete formula\")\n            fp.DeleteFormula = False\n            self.deleteFormula(fp)\n            doc.commitTransaction()\n        elif prop == \"a\" or prop == \"b\" or prop == \"c\" or prop == \"d\" or prop == \"X\" or prop == \"Y\" or prop == \"Z\" or prop == \"t\" or prop == \"t_min\" or prop == \"t_max\" or prop == \"Interval\":\n            if fp.FormulaName and not self.bInihibitUpdates:\n                self.updateJSON_Data(fp,fp.Formulas) #update self.JSON_Data on every property change\n        elif prop == \"MakeFace\" and fp.MakeFace == True:\n            self.bInhibitRecompute = True\n            if fp.MakeFace and fp.Shape.isClosed():\n                try:\n                    face = Part.makeFace(fp.Shape,\"Part::FaceMakerCheese\")\n                    fp.Shape = face\n                except:\n                    pass\n        elif prop == \"EditFormulas\" and fp.EditFormulas == True:\n            fp.EditFormulas = False\n            t = QtCore.QTimer()\n            t.singleShot(50, self.showEditor)\n\n    def stripComments(self,string):\n        \"\"\"returns a string with everything after # removed, including #\"\"\"\n        strip1 = string\n        if not \"#\" in string and not \"{\" in string and not \"}\" in string:\n            return string\n        elif \"#\" in string:\n            idx = string.index(\"#\")\n            strip1 = string[:idx]\n        if not \"{\" in strip1 and not \"}\" in strip1:\n            return strip1\n        idx2 = strip1.index(\"{\")\n        idx3 = strip1.index(\"}\")\n        return strip1[:idx2] + strip1[idx3+1:]\n\n    def makeCurve(self, fp):\n        self.updateFromSpreadsheet(fp)\n        vars = {\"a\":0,\"b\":0,\"c\":0,\"X\":0,\"Y\":0,\"Z\":0,\"t\":0}\n\n        fa = self.stripComments(fp.a)\n        fb = self.stripComments(fp.b)\n        fc = self.stripComments(fp.c)\n        fx = self.stripComments(fp.X)\n        fy = self.stripComments(fp.Y)\n        fz = self.stripComments(fp.Z)\n        t = fp.t if hasattr(fp,\"t\") else fp.t_min\n        tf = fp.t_max\n        intv = fp.Interval\n        if not intv:\n            FreeCAD.Console.PrintWarning(\"ParametricCurve: interval must be non-zero, return null shape.\\n\")\n            return Part.Shape()\n        if (tf-t)*intv <= 0:\n            FreeCAD.Console.PrintWarning(f\"Infinite loop avoided.  t_max - t * Interval cannot be less than 0.  Interval used will be {intv * -1}\\n\")\n            intv *= -1\n        iterations = int((tf-t)/intv)\n        matriz = []\n        plus1 = 1\n        if hasattr(fp,\"PlusOneIteration\") and fp.PlusOneIteration:\n            lastT = t + iterations * intv\n            while lastT < tf and not math.isclose(lastT, tf, abs_tol = 1e-9): #don't add if almost equal\n                plus1 += 1\n                lastT += intv\n        else:\n            plus1 = 0  # restore old bug for compatibility\n        for i in range(iterations + plus1):\n            if hasattr(fp,\"PlusOneIteration\") and fp.PlusOneIteration:\n                if i == int(iterations) + plus1 - 1: #last iteration\n                    t = tf\n            try:\n                vars[\"t\"] = t\n                value=\"a ->\"+str(fa)\n                a=evaluate(fa,vars)\n                vars[\"a\"]=a\n                value=\"b ->\"+str(fb)\n                b=evaluate(fb,vars)\n                vars[\"b\"] = b\n                value=\"c ->\"+str(fc)\n                c=evaluate(fc,vars)\n                vars[\"c\"]=c\n                for dd in range(0,len(fp.d)):#fp.d[0] = d1, fp.d[1] = d2, etc\n                    k = \"d\"+str(dd+1)# where dd = 0, k = \"d1\"\n                    value = k+\" ->\"+str(fp.d[dd])\n                    vars[k] = evaluate(self.stripComments(fp.d[dd]),vars)\n                value=\"X ->\"+str(fx)\n                fxx=evaluate(fx,vars)\n                vars[\"X\"]=fxx\n                value=\"Y ->\"+str(fy)\n                fyy=evaluate(fy,vars)\n                vars[\"Y\"]=fyy\n                value=\"Z ->\"+str(fz)\n                fzz=evaluate(fz,vars)\n                vars[\"Z\"]=fzz\n            except ZeroDivisionError:\n                FreeCAD.Console.PrintError(\"Error division by zero in calculus of \"+value+\"() for t=\"+str(t)+\" !\")\n            except:\n                FreeCAD.Console.PrintError(\"Error in the formula of \"+value+\"() !\")\n\n            matriz.append(FreeCAD.Vector(fxx,fyy,fzz))\n            t+=intv\n        if not matriz:\n            FreeCAD.Console.PrintWarning(\"ParametricCurve: --vector list is empty, returning null shape\\n\")\n            return Part.Shape()\n        if fp.ShapeType == \"Polygon\" and fp.Closed == True:\n            matriz.append(matriz[0])\n        fp.Points = matriz\n        curva = Part.makePolygon(matriz)\n        if fp.ShapeType == \"BSpline\":\n            curve = Part.BSplineCurve()\n            curve.interpolate(matriz, PeriodicFlag=fp.Closed)\n            return curve.toShape()\n        elif fp.ShapeType == \"Polygon\":\n            return curva\n        else: #fp.ShapeType == \"Points\":\n            vertices = [Part.Vertex(p) for p in fp.Points]\n            comp = Part.Compound(vertices)\n            return comp\n\n    def execute(self, fp):\n        '''Do something when doing a recomputation, this method is mandatory'''\n        if self.bInhibitRecompute: #some things do not require a recompute, such as saving to JSON file or updating spreadsheet\n            self.bInhibitRecompute = False\n            return\n\n        fp.Shape = self.makeCurve(fp)\n        if hasattr(fp.Shape,\"Continuity\"):\n            fp.Continuity = fp.Shape.Continuity\n        else:\n            fp.Continuity = \"N/A\"\n        if fp.MakeFace and fp.Shape.isClosed():\n            try:\n                face = Part.makeFace(fp.Shape,\"Part::FaceMakerCheese\")\n                fp.Shape = face\n            except:\n                pass\n        #FreeCAD.Console.PrintMessage(\"Recompute Python Curve feature\"+chr(10))\n        self.updateFloats(fp)\n\n    def updateFloat(self, fp, propstr, propfloat):\n        try:\n            fval = evaluate(self.stripComments(getattr(fp,propstr)))\n            setattr(fp,propfloat,fval)\n        except Exception:\n            setattr(fp,propfloat,0.0)\n\n    def updateFloats(self, fp):\n        if not hasattr(fp, \"F_a\"): #do not break existing objects created with earlier versions\n            return\n        propstrs = [\"a\",\"b\",\"c\",\"X\",\"Y\",\"Z\"]\n        for propstr in propstrs:\n            self.updateFloat(fp,propstr,f\"F_{propstr}\")\n        d_vals = [0.0] #dummy first value so we can 1-index into the array\n        for dd,val in enumerate(fp.d):\n            try:\n                d_vals.append(evaluate(self.stripComments(val)))\n            except:\n                d_vals.append(0.0)\n        d_vals = d_vals if not d_vals == [0.0] else []\n        setattr(fp, \"F_d\",d_vals)\n\n    def showEditor(self):\n        '''show the formula editor'''\n        if not hasattr(self,\"fpName\"):\n            FreeCAD.Console.PrintError(\"Formula editor not available for objects created with older versions.\\n\")\n            return #object made with old version\n        fp = FreeCADGui.Selection.getSelection()[0]\n        if not FreeCADGui.Control.activeDialog():\n            editor = TaskEditFormulasPanel(fp)\n            FreeCADGui.Control.showDialog(editor)\n            self.editingMode = True\n        else:\n            self.editingMode=False\n            FreeCAD.Console.PrintError(\"Another task dialog is active.  Close that one and try again.\\n\")\n            return\n\n\nclass TaskEditFormulasPanel: #formula editor\n    def __init__(self, fp):\n        self.blockSignals = True\n        self.fp = fp\n        self.sorted = fp.Sorted if hasattr(fp,\"Sorted\") else False\n#        self.json = self.shallowCopy(self.fp.Proxy.JSON_Data)\n        self.clipboard = QtGui.QApplication.clipboard()\n        self.form = QtGui.QWidget()\n        self.form.setObjectName(\"formulaEditor\")\n        self.form.editor = self #used by context menu handler\n        layout=QtGui.QVBoxLayout()\n        layout.setObjectName(\"layout\")\n        commandBox = QtGui.QHBoxLayout()\n        commandBox.setObjectName(\"commandBox\")\n        self.formulaList = QtGui.QListWidget()\n        commandBox.addWidget(self.formulaList)\n        self.formulaList.currentItemChanged.connect(self.formulaListCurrentItemChanged)\n\n        #layout is a vbox, the entire layout of the Edit Formulas panel, beneath the standard buttons\n        #commandBox is a hbox containing the formula list and topButtonBox\n        #topButtonBox is a vbox containing buttons related to top level commands\n        #hBoxBottom is similar to commandBox, hbox containing various line edits and\n        #bottomButtonBox, a vbox containing buttons related commands for the line edits\n\n        formulasLabel = QtGui.QLabel(\"Formulas in editor memory:\")\n        layout.addWidget(formulasLabel)\n\n        layout.addLayout(commandBox)\n        hBoxBottom = QtGui.QHBoxLayout()\n        hBoxBottom.setObjectName(\"hBoxBottom\")\n        formulaBox = QtGui.QGridLayout()\n        formulaBox.setObjectName(\"formulaBox\")\n        hBoxBottom.addLayout(formulaBox)\n        bottomButtonBox = QtGui.QVBoxLayout()\n        bottomButtonBox.setObjectName(\"bottomButtonBox\")\n        hBoxBottom.addLayout(bottomButtonBox)\n        divider = QtGui.QLabel(\"Current formula:\")\n        layout.addWidget(divider)\n        layout.addLayout (hBoxBottom)\n        topButtonBox = QtGui.QVBoxLayout()\n        topButtonBox.setObjectName(\"topButtonBox\")\n        commandBox.addLayout(topButtonBox)\n\n        self.form.setLayout(layout)\n\n        self.checkBoxSorted = QtGui.QCheckBox(\"Sorted\")\n        self.checkBoxSorted.setLayoutDirection(QtCore.Qt.LeftToRight)\n        self.checkBoxSorted.setToolTip (\"Sort formulas\")\n        self.checkBoxSorted.clicked.connect(self.checkBoxSortedClicked)\n        self.checkBoxSorted.setChecked(self.sorted)\n        topButtonBox.addWidget(self.checkBoxSorted)\n\n        buttonPlus = QtGui.QPushButton(\"+\")\n        buttonPlus.setToolTip (\"Add new formula, a copy of selected formula\")\n        topButtonBox.addWidget(buttonPlus)\n        buttonPlus.clicked.connect(self.buttonPlusClicked)\n\n        buttonMinus = QtGui.QPushButton(\"-\")\n        buttonMinus.setToolTip(\"Delete formula\")\n        topButtonBox.addWidget(buttonMinus)\n        buttonMinus.clicked.connect(self.buttonMinusClicked)\n\n        buttonImport = QtGui.QPushButton(\"Import\")\n        buttonImport.setToolTip (\"Import one or more formulas from a JSON file\\n\\\nDoes not overwrite existing memory contents\\n\")\n        topButtonBox.addWidget(buttonImport)\n        buttonImport.clicked.connect(self.buttonImportClicked)\n\n        buttonCopy = QtGui.QPushButton(\"Copy\")\n        buttonCopy.setToolTip (\"Copy formula to clipboard\")\n        bottomButtonBox.addWidget(buttonCopy)\n        buttonCopy.clicked.connect(self.buttonCopyClicked)\n\n        buttonPaste = QtGui.QPushButton(\"Paste\")\n        buttonPaste.setToolTip(\"Paste formula from clipboard\")\n        bottomButtonBox.addWidget(buttonPaste)\n        buttonPaste.clicked.connect(self.buttonPasteClicked)\n\n        buttonRename = QtGui.QPushButton(\"Rename\")\n        buttonRename.setToolTip (\"Rename formula\")\n        bottomButtonBox.addWidget(buttonRename)\n        buttonRename.clicked.connect(self.buttonRenameClicked)\n\n        buttonClear = QtGui.QPushButton(\"Clear One\")\n        buttonClear.setToolTip (\"Clear current formula\")\n        bottomButtonBox.addWidget(buttonClear)\n        buttonClear.clicked.connect(self.buttonClearClicked)\n\n        buttonClearAll = QtGui.QPushButton(\"Clear\")\n        buttonClearAll.setToolTip (\"Clear all formulas\")\n        topButtonBox.addWidget(buttonClearAll)\n        buttonClearAll.clicked.connect(self.buttonClearAllClicked)\n\n        buttonOpen = QtGui.QPushButton(\"Open\")\n        buttonOpen.setToolTip (\"Open JSON file\")\n        topButtonBox.addWidget(buttonOpen)\n        buttonOpen.clicked.connect(self.buttonOpenClicked)\n\n        buttonSave = QtGui.QPushButton(\"Save\")\n        buttonSave.setToolTip (\"Save JSON file\")\n        topButtonBox.addWidget(buttonSave)\n        buttonSave.clicked.connect(self.buttonSaveClicked)\n\n        buttonSaveOne = QtGui.QPushButton(\"Save One\")\n        buttonSaveOne.setToolTip (\"Save current formula to a JSON file\\n\\\nOverwrites any existing content in the file\\n\")\n        bottomButtonBox.addWidget(buttonSaveOne)\n        buttonSaveOne.clicked.connect(self.buttonSaveOneClicked)\n\n        buttonAppend = QtGui.QPushButton(\"Append One\")\n        buttonAppend.setToolTip (\"Append current formula to a JSON file\")\n        bottomButtonBox.addWidget(buttonAppend)\n        buttonAppend.clicked.connect(self.buttonAppendClicked)\n\n        buttonAppendAll = QtGui.QPushButton(\"Append\")\n        buttonAppendAll.setToolTip (\"Append one or more formulas to a JSON file\")\n        topButtonBox.addWidget(buttonAppendAll)\n        buttonAppendAll.clicked.connect(self.buttonAppendAllClicked)\n\n        bottomButtonBox.addStretch()\n\n        formulaBox.addWidget(QtGui.QLabel(\"a:\"),0,0,QtCore.Qt.AlignRight)\n        self.a_Line = QtGui.QLineEdit()\n        formulaBox.addWidget(self.a_Line,0,1)\n\n        formulaBox.addWidget(QtGui.QLabel(\"b:\"),1,0,QtCore.Qt.AlignRight)\n        self.b_Line = QtGui.QLineEdit()\n        formulaBox.addWidget(self.b_Line,1,1)\n\n        formulaBox.addWidget(QtGui.QLabel(\"c:\"),2,0,QtCore.Qt.AlignRight)\n        self.c_Line = QtGui.QLineEdit()\n        formulaBox.addWidget(self.c_Line,2,1)\n\n        dsize = 5\n        formulaBox.addWidget(QtGui.QLabel(\"d1:\\nd2:\\nd3:\\ndN:\\n...\"),3,0,dsize,1,QtCore.Qt.AlignRight)\n        self.d_Lines = QtGui.QPlainTextEdit()\n        formulaBox.addWidget(self.d_Lines,3,1,dsize,1)\n\n        formulaBox.addWidget(QtGui.QLabel(\"X:\"),4+dsize,0,QtCore.Qt.AlignRight)\n        self.X_Line = QtGui.QLineEdit()\n        formulaBox.addWidget(self.X_Line,4+dsize,1)\n\n        formulaBox.addWidget(QtGui.QLabel(\"Y:\"),5+dsize,0,QtCore.Qt.AlignRight)\n        self.Y_Line = QtGui.QLineEdit()\n        formulaBox.addWidget(self.Y_Line,5+dsize,1)\n\n        formulaBox.addWidget(QtGui.QLabel(\"Z:\"),6+dsize,0,QtCore.Qt.AlignRight)\n        self.Z_Line = QtGui.QLineEdit()\n        formulaBox.addWidget(self.Z_Line,6+dsize,1)\n\n        formulaBox.addWidget(QtGui.QLabel(\"t_min:\"),7+dsize,0,QtCore.Qt.AlignRight)\n        self.t_min_Line = QtGui.QLineEdit()\n        formulaBox.addWidget(self.t_min_Line,7+dsize,1)\n\n        formulaBox.addWidget(QtGui.QLabel(\"interval:\"),8+dsize,0,QtCore.Qt.AlignRight)\n        self.interval_Line = QtGui.QLineEdit()\n        formulaBox.addWidget(self.interval_Line,8+dsize,1)\n\n        formulaBox.addWidget(QtGui.QLabel(\"t_max:\"),9+dsize,0,QtCore.Qt.AlignRight)\n        self.t_max_Line = QtGui.QLineEdit()\n        formulaBox.addWidget(self.t_max_Line,9+dsize,1)\n\n        self.form.setWindowTitle(f\"Formula editor v{__version__}\")\n        self.fp.Proxy.editingMode = True\n        self.blockSignals = False\n        self.json = self.shallowCopy(self.fp.Proxy.JSON_Data)\n        self.updateFormulaList()\n        self.populateLines(self.formulaList.itemAt(0,0).text())\n\n    def shallowCopy(self,fromdict):\n        \"\"\"make shallow copy of dictionary of dictionaries\"\"\"\n        todict = {}\n        for k,v in fromdict.items():\n            formula = {}\n            for kk,vv in v.items():\n                formula[kk] = vv\n            todict[k] = formula\n        return todict\n\n    def updateFormulaList(self):\n        self.blockSignals = True\n        self.formulaList.clear()\n        keys = self.json.keys() if not self.sorted else sorted(self.json.keys())\n        for key in keys:\n            self.formulaList.addItem(key)\n        self.blockSignals = False\n        self.formulaList.setCurrentItem(self.formulaList.itemAt(0,0))\n\n    def formulaListCurrentItemChanged(self,current,prev):\n        if self.blockSignals:\n            return\n        #FreeCAD.Console.PrintMessage(f\"current = {current.text() if current else None}, prev = {prev.text() if prev else None}\\n\")\n        if prev:\n            self.saveLinesToJson(prev.text())\n        if current:\n            #FreeCAD.Console.PrintMessage(f\"populating lines with {current.text()}\\n\")\n            self.populateLines(current.text())\n\n    def importFormula(self, fromDict, formulaName):\n        '''adds fromDict[formulaName] to self.json'''\n        current = self.formulaList.currentItem().text()\n        self.saveLinesToJson(current)\n        if not formulaName in self.json:\n            self.json[formulaName] = fromDict[formulaName]\n        else: #name conflict\n            newName = formulaName\n            while newName in self.json:\n                newName,ok = QtGui.QInputDialog.getText(FreeCADGui.getMainWindow(), \"Formula exists\",\"Formula exists already, enter a new name:\",text=formulaName)\n                if not ok:\n                    return False\n            self.json[newName] = fromDict[formulaName]\n        return True\n\n    def buttonImportClicked(self,btn):\n        current = self.formulaList.currentItem().text()\n        self.saveLinesToJson(current)\n        fname = QtGui.QFileDialog.getOpenFileName(FreeCADGui.getMainWindow(),\"Open a JSON file\",filter='*.*')[0]\n        if not fname:\n            return\n        try:\n            f = open(fname)\n        except Exception as ex:\n            FreeCAD.Console.PrintError(f\"ParametricCurve::Exception {ex}\\n\")\n            return\n        try:\n            jtemp = json.load(f)\n        except Exception as ex:\n            FreeCAD.Console.PrintError(f\"ParametricCurve::Exception {ex}\\nFile not opened.\\n\")\n            f.close()\n            return\n        f.close()\n    #now rename any \"t\" to \"t_min\"\n        for k,v in jtemp.items():\n            if \"t\" in v.keys():\n                jtemp[k][\"t_min\"] = jtemp[k][\"t\"]\n                jtemp[k].pop(\"t\")\n                FreeCAD.Console.PrintMessage(f\"ParametricCurve: renaming 't' to 't_min' in {k}\"+chr(10))\n        items = [k for k in jtemp.keys()]\n        if not items:\n            return #nothing to import\n        if len(items) == 1:\n            self.importFormula(jtemp, items[0])\n        else:\n            dlg = SelectObjects(items,\"Select formulas to import:\")\n            dlg.all.setCheckState(QtCore.Qt.Checked)\n            ok = dlg.exec_()\n            if not ok:\n                return []\n            selected = dlg.selected\n            for key in jtemp.keys():\n                if key in selected:\n                    success = self.importFormula(jtemp,key)\n                    if not success:\n                        break\n        self.updateFormulaList()\n\n    def checkBoxSortedClicked(self,btn):\n        self.sorted = not self.sorted\n        self.checkBoxSorted.setChecked(self.sorted)\n        self.updateFormulaList()\n\n    def buttonOpenClicked(self,btn):\n        fname = QtGui.QFileDialog.getOpenFileName(FreeCADGui.getMainWindow(),\"Open a JSON file\",filter='*.*')[0]\n        if not fname:\n            return\n        try:\n            f = open(fname)\n        except Exception as ex:\n            FreeCAD.Console.PrintError(f\"ParametricCurve::Exception {ex}\\n\")\n            return\n        try:\n            self.json = json.load(f)\n        except Exception as ex:\n            FreeCAD.Console.PrintError(f\"ParametricCurve::Exception {ex}\\nFile not opened.\\n\")\n            f.close()\n            return\n        f.close()\n    #now rename any \"t\" to \"t_min\"\n        for k,v in self.json.items():\n            if \"t\" in v.keys():\n                self.json[k][\"t_min\"] = self.json[k][\"t\"]\n                self.json[k].pop(\"t\")\n                FreeCAD.Console.PrintMessage(f\"ParametricCurve: renaming 't' to 't_min' in {k}\"+chr(10))\n        self.updateFormulaList()\n\n    def setupAppend(self,all=False):\n        fname = QtGui.QFileDialog.getOpenFileName(FreeCADGui.getMainWindow(),\"Append to a JSON file\",filter='*.*')[0]\n        if not fname:\n            return\n        try:\n            f = open(fname)\n        except Exception as ex:\n            FreeCAD.Console.PrintError(f\"ParametricCurve::Exception opening file: {ex}\\n\")\n            return\n        try:\n            contents = f.read()\n            jtemp = json.loads(contents) if contents else dict()\n        except Exception as ex:\n            FreeCAD.Console.PrintError(f\"ParametricCurve::Exception {ex}\\nFile not opened.\\n\")\n            f.close()\n            return\n        f.close()\n        if not all:\n            current = self.formulaList.currentItem().text()\n            self.appendFormula(fname, current, jtemp)\n        else:\n            items = []\n            for ii in range(self.formulaList.count()):\n                items.append(self.formulaList.item(ii).text())\n            dlg = SelectObjects(items,\"Select formulas to append:\")\n            dlg.all.setCheckState(QtCore.Qt.Checked)\n            ok = dlg.exec_()\n            if not ok:\n                return []\n            selected = dlg.selected\n            for sel in selected:\n                success = self.appendFormula(fname,sel,jtemp)\n                if not success:\n                    break #user canceled\n\n    def appendFormula(self, fname, formulaName, jtemp):\n        current = formulaName\n        item = self.json[current]\n        newName = current\n        while newName in jtemp:\n            newName,ok = QtGui.QInputDialog.getText(FreeCADGui.getMainWindow(), \"Formula exists\",\"Formula exists already, enter a new name:\",text=current)\n            if not ok:\n                return False\n        jtemp[newName] = item\n        FreeCAD.Console.PrintMessage(f\"Appending '{newName}': {jtemp[newName]} to {fname}\\n\")\n        with open(fname,\"w\") as outfile:\n            json.dump(jtemp,outfile)\n        return True\n\n    def buttonAppendClicked(self,btn):\n        current = self.formulaList.currentItem().text()\n        self.saveLinesToJson(current)\n        self.setupAppend()\n\n    def buttonAppendAllClicked(self,btn):\n        current = self.formulaList.currentItem().text()\n        self.saveLinesToJson(current)\n        self.setupAppend(all=True)\n\n    def buttonSaveClicked(self,btn):\n        current = self.formulaList.currentItem().text()\n        self.saveLinesToJson(current)\n        fname = QtGui.QFileDialog.getSaveFileName(FreeCADGui.getMainWindow(),\"Save all formulas to a JSON file\",filter='*.*')[0]\n        if not fname:\n            return\n        items = [key for key in self.json.keys()]\n        dlg = SelectObjects(items,\"Select formulas to save:\")\n        dlg.all.setCheckState(QtCore.Qt.Checked)\n        ok = dlg.exec_()\n        if not ok:\n            return\n        selected = dlg.selected\n        if not selected:\n            return\n        new_dict = {}\n        for sel in selected:\n            new_dict[sel] = self.json[sel]\n        with open(fname,\"w\") as outfile:\n            json.dump(new_dict,outfile)\n\n    def buttonSaveOneClicked(self,btn):\n        current = self.formulaList.currentItem().text()\n        self.saveLinesToJson(current)\n        fname = QtGui.QFileDialog.getSaveFileName(FreeCADGui.getMainWindow(),\"Save a formula to JSON file\",dir=current)[0]\n        if not fname:\n            return\n        jtemp = self.shallowCopy(self.json)\n        pops = [key for key in jtemp.keys() if not key == current]\n        for pop in pops:\n            jtemp.pop(pop)\n        with open(fname,\"w\") as outfile:\n            json.dump(jtemp,outfile)\n        for key in jtemp.keys():\n            FreeCAD.Console.PrintMessage(f\"saved '{key}': {jtemp[key]} to {fname}\\n\")\n\n    def buttonClearAllClicked(self,btn):\n        self.json = dict()\n        self.updateFormulaList()\n        self.buttonClearClicked(True)\n        self.buttonPlusClicked(True)\n\n    def buttonClearClicked(self,btn):\n        current = self.formulaList.currentItem().text() if self.formulaList.currentItem() else \"\"\n        lines = [self.a_Line, self.b_Line, self.c_Line,\n                 self.X_Line, self.Y_Line, self.Z_Line, self.t_min_Line,\n                 self.interval_Line, self.t_max_Line]\n        for line in lines:\n            line.setText(\"\")\n        self.d_Lines.setPlainText(\"\")\n        self.saveLinesToJson(current) if current else None\n\n    def buttonPlusClicked(self, btn):\n        ii = 1\n        trialName = \"formula1\"\n        while (trialName in self.json):\n            ii += 1\n            trialName = \"formula\"+str(ii)\n        self.json[trialName] ={\n                \"a\":self.a_Line.text(),\n                \"b\":self.b_Line.text(),\n                \"c\":self.c_Line.text(),\n                \"d\":self.d_Lines.toPlainText().split(\"\\n\"),\n                \"X\":self.X_Line.text(),\n                \"Y\":self.Y_Line.text(),\n                \"Z\":self.Z_Line.text(),\n                \"t_min\":self.t_min_Line.text(),\n                \"t_max\":self.t_max_Line.text(),\n                \"interval\":self.interval_Line.text()\n                }\n        self.updateFormulaList()\n        self.blockSignals = True\n        self.formulaList.setCurrentItem(self.formulaList.findItems(trialName, QtCore.Qt.MatchExactly)[0])\n        self.blockSignals = False\n\n    def buttonRenameClicked(self, btn):\n        current = self.formulaList.currentItem().text()\n        newName,ok = QtGui.QInputDialog.getText(FreeCADGui.getMainWindow(), \"Parametric Curve FP\",\"Enter name:\")\n        if ok:\n            if newName in self.json:\n                FreeCAD.Console.PrintError(f\"{newName} already exists\\n\")\n                return\n            else:\n                self.json[newName] = self.json.pop(current,None)\n                self.updateFormulaList()\n                #FreeCAD.Console.PrintMessage(f\"blocksignals = {self.blockSignals}\\n\")\n                self.formulaList.setCurrentItem(self.formulaList.findItems(newName, QtCore.Qt.MatchExactly)[0])\n\n    def buttonMinusClicked(self, btn):\n        self.fp.Document.openTransaction(\"ParametricCurve::Delete Formula\")\n        self.blockSignals = True\n        row = self.formulaList.currentRow()\n        self.json.pop(self.formulaList.currentItem().text(),None)\n        self.updateFormulaList()\n        if len(self.json.keys()) == 0:\n            self.buttonClearClicked(True)\n            self.buttonPlusClicked(True)\n        self.formulaList.setCurrentRow(row if row < self.formulaList.count() else self.formulaList.count()-1)\n        self.populateLines(self.formulaList.item(0).text())\n        self.blockSignals = False\n        self.fp.Document.commitTransaction()\n\n    def buttonCopyClicked(self, btn):\n        current = self.formulaList.currentItem().text()\n        tempDict = {current:self.json[current]}\n        jsonstr = str(tempDict).replace('\"','\"\"\"').replace(\"'\",'\"')\n        self.clipboard.setText(jsonstr)\n        FreeCAD.Console.PrintMessage(f\"string in clipboard: {jsonstr}\\n\")\n\n    def buttonPasteClicked(self, btn):\n        cliptext = self.clipboard.text()\n        #FreeCAD.Console.PrintMessage(f\"cliptext = {cliptext}\\n\")\n        if not cliptext:\n            FreeCAD.Console.PrintError(\"No text in clipboard\\n\")\n            return\n        else:\n            try:\n                tempDict = json.loads(cliptext)\n            except Exception as ex:\n                FreeCAD.Console.PrintError(f\"ParametricCurve::PasteException: {ex}\\n\")\n                return\n        self.buttonPlusClicked(True)\n        current = self.formulaList.currentItem().text()\n        keyName = [k for k in tempDict.keys()][0]\n        if keyName in self.json:\n            FreeCAD.Console.PrintWarning(f\"{keyName} already exists, so using default formula name: {current}\\n\")\n            newName = current\n        else:\n            newName = keyName\n        self.json.pop(current,None)\n        self.json[newName] = tempDict[keyName]\n        self.updateFormulaList()\n        self.formulaList.setCurrentRow(self.formulaList.count()-1)\n        self.populateLines(newName)\n\n    def saveLinesToJson(self,key=\"\"):\n#        FreeCAD.Console.PrintMessage(f\"saveLinesToJson({key}), blockSignals = {self.blockSignals}\\n\")\n        cur = self.json[key]\n#        FreeCAD.Console.PrintMessage(f\"key = {key}\\n\")\n        cur[\"a\"] = self.a_Line.text() if hasattr(self,\"a_Line\") else \"\"\n        cur[\"b\"] = self.b_Line.text() if hasattr(self,\"b_Line\") else \"\"\n        cur[\"c\"] = self.c_Line.text() if hasattr(self,\"c_Line\") else \"\"\n        cur[\"d\"] = self.d_Lines.toPlainText().split(\"\\n\")  if hasattr(self,\"d_Lines\") else \"\"\n        cur[\"X\"] = self.X_Line.text() if hasattr(self,\"X_Line\") else \"\"\n        cur[\"Y\"] = self.Y_Line.text() if hasattr(self,\"Y_Line\") else \"\"\n        cur[\"Z\"] = self.Z_Line.text() if hasattr(self,\"Z_Line\") else \"\"\n        cur[\"t_min\"] = self.t_min_Line.text() if hasattr(self,\"t_min_Line\") else \"\"\n        cur[\"interval\"] = self.interval_Line.text() if hasattr(self,\"interval_Line\") else \"\"\n        cur[\"t_max\"] = self.t_max_Line.text() if hasattr(self,\"t_max_Line\") else \"\"\n\n    def populateLines(self,key):\n#        FreeCAD.Console.PrintMessage(f\"populateLines({key})\\n\")\n#        FreeCAD.Console.PrintMessage(f\"self.json[{key}] = {self.json[key]}\\n\")\n        self.blockSignals = True\n        cur = self.json[key]\n        self.a_Line.setText(cur[\"a\"])\n        self.b_Line.setText(cur[\"b\"])\n        self.c_Line.setText(cur[\"c\"])\n        self.d_Lines.setPlainText(\"\\n\".join(cur[\"d\"]))\n        self.X_Line.setText(cur[\"X\"])\n        self.Y_Line.setText(cur[\"Y\"])\n        self.Z_Line.setText(cur[\"Z\"])\n        self.t_min_Line.setText(cur[\"t_min\"])\n        self.interval_Line.setText(cur[\"interval\"])\n        self.t_max_Line.setText(cur[\"t_max\"])\n        self.blockSignals = False\n\n    def reject(self):\n        if not FreeCAD.ActiveDocument:\n            FreeCADGui.Control.closeDialog()\n            return\n        self.fp.Proxy.editingMode = False\n        FreeCADGui.Control.closeDialog()\n        FreeCADGui.activeDocument().resetEdit()\n        FreeCAD.ActiveDocument.recompute()\n\n    def accept(self):\n        if not FreeCAD.ActiveDocument:\n            FreeCADGui.Control.closeDialog()\n            return\n        self.fp.Document.openTransaction(\"ParametricCurve::Accept\")\n        if hasattr(self.fp,\"Sorted\"):\n            self.fp.Sorted = self.sorted\n        self.saveLinesToJson(self.formulaList.currentItem().text())\n        jsonstr = str(self.json).replace('\"','\"\"\"').replace(\"'\",'\"')\n        self.fp.Proxy.readJSONFile(self.fp,jsonstr)\n        if not self.fp: #user deleted or closed document perhaps\n            self.fp.Document.abortTransaction()\n            return\n        self.fp.Proxy.JSON_Data = self.shallowCopy(self.json)\n        if hasattr(self.fp.Proxy,\"editingMode\"):\n            self.fp.Proxy.editingMode = False\n        self.fp.Document.commitTransaction()\n        FreeCADGui.Control.closeDialog()\n        FreeCADGui.ActiveDocument.resetEdit()\n        FreeCAD.ActiveDocument.recompute()\n\n    def getStandardButtons(self):\n        return int(QtGui.QDialogButtonBox.Ok) | int(QtGui.QDialogButtonBox.Cancel) | int(QtGui.QDialogButtonBox.Reset) | int(QtGui.QDialogButtonBox.Apply)\n\n    def clicked(self, button):\n        if not FreeCAD.ActiveDocument:\n            FreeCAD.Console.PrintError(\"No document.\\n\")\n            return\n        if button == QtGui.QDialogButtonBox.Reset:\n            self.sorted = self.fp.Sorted if hasattr(self.fp,\"Sorted\") else False\n            self.json =self.shallowCopy(self.fp.Proxy.JSON_Data)\n            self.updateFormulaList()\n            self.formulaList.setCurrentRow(0)\n            self.populateLines(next(iter(self.json))) #first key\n        elif button == QtGui.QDialogButtonBox.Apply:\n            self.fp.Document.openTransaction(\"ParametricCurve::Apply\")\n            if hasattr(self.fp,\"Sorted\"):\n                self.fp.Sorted = self.sorted\n            FreeCAD.Console.PrintMessage(\"Applying... Can be undone\\n\")\n            self.saveLinesToJson(self.formulaList.currentItem().text())\n            jsonstr = str(self.json).replace('\"','\"\"\"').replace(\"'\",'\"')\n            self.fp.Proxy.readJSONFile(self.fp,jsonstr)\n            self.fp.Formulas = self.formulaList.currentItem().text()\n            self.fp.Document.commitTransaction()\n            self.fp.Document.recompute()\n\n#select objects dialog class\nclass SelectObjects(QtGui.QDialog):\n    def __init__(self, objects, label=\"\"):\n        QtGui.QDialog.__init__(self)\n        scrollContents = QtGui.QWidget()\n        scrollingLayout = QtGui.QVBoxLayout(self)\n        scrollContents.setLayout(scrollingLayout)\n        scrollArea = QtGui.QScrollArea()\n        scrollArea.setVerticalScrollBarPolicy(QtGui.Qt.ScrollBarAlwaysOn)\n        scrollArea.setHorizontalScrollBarPolicy(QtGui.Qt.ScrollBarAlwaysOff)\n        scrollArea.setWidgetResizable(True)\n        scrollArea.setWidget(scrollContents)\n        vBoxLayout = QtGui.QVBoxLayout(self)\n        vBoxLayout.addWidget(QtGui.QLabel(label))\n        self.all = QtGui.QCheckBox(\"All\")\n        #self.all.setCheckState(QtCore.Qt.Checked) #set by caller\n        self.all.stateChanged.connect(self.allStateChanged)\n        vBoxLayout.addWidget(self.all)\n        vBoxLayout.addWidget(scrollArea)\n        self.setLayout(vBoxLayout)\n        buttons = QtGui.QDialogButtonBox(\n            QtGui.QDialogButtonBox.Ok.__or__(QtGui.QDialogButtonBox.Cancel),\n            QtCore.Qt.Horizontal, self)\n        buttons.accepted.connect(self.accept)\n        buttons.rejected.connect(self.reject)\n        self.checkBoxes = []\n        self.selected = []\n        for ii,object in enumerate(objects):\n            self.checkBoxes.append(QtGui.QCheckBox(object))\n            self.checkBoxes[-1].setCheckState(self.all.checkState())\n            scrollingLayout.addWidget(self.checkBoxes[-1])\n        vBoxLayout.addWidget(buttons)\n    def allStateChanged(self, arg):\n        self.checkAll(self.all.checkState())\n    def checkAll(self, state):\n        for cb in self.checkBoxes:\n            cb.setCheckState(state)\n    def accept(self):\n        self.selected = []\n        for cb in self.checkBoxes:\n            if cb.checkState():\n                self.selected.append(cb.text())\n        super().accept()\nclass CurveVP:\n    '''Creates a 3D parametric curve'''\n    def __init__(self, obj):\n        '''Set this object to the proxy object of the actual view provider'''\n        obj.Proxy = self\n\n    def onDelete(self, vobj, subelements):\n       if vobj.Object.Proxy.editingMode:\n           FreeCADGui.Control.closeDialog()\n       return True\n\n    def attach(self, obj):\n        '''Setup the scene sub-graph of the view provider, this method is mandatory'''\n        self.Object = obj.Object\n\n    def updateData(self, fp, prop):\n        '''If a property of the handled feature has changed we have the chance to handle this here'''\n        # fp is the handled feature, prop is the name of the property that has changed\n        pass\n\n    def canDropObject(self, incoming):\n        return incoming.isDerivedFrom(\"App::TextDocument\")\n\n    def dropObject(self,vobj, incoming):\n        if incoming.isDerivedFrom(\"App::TextDocument\"):\n            if incoming.Text:\n                FreeCAD.Console.PrintWarning(\"Parametric_Curve_FP: Ensure document has been saved since last edit of Text document.\\n\")\n                vobj.Object.Document.openTransaction(\"Drop Text Document\")\n                vobj.Object.Proxy.readJSONFile(vobj.Object,incoming.Text)\n                vobj.Object.Document.commitTransaction()\n            else:\n                FreeCAD.Console.PrintError(\"Empty text document.  Save file and try again.\\n\")\n\n    def getDisplayModes(self,obj):\n        '''Return a list of display modes.'''\n        modes=[]\n        modes.append(\"Flat Lines\")\n        return modes\n\n    def getDefaultDisplayMode(self):\n        '''Return the name of the default display mode. It must be defined in getDisplayModes.'''\n        return \"Flat Lines\"\n\n    def setDisplayMode(self,mode):\n        '''Map the display mode defined in attach with those defined in getDisplayModes.\\\n                Since they have the same names nothing needs to be done. This method is optional'''\n        return mode\n\n    def onChanged(self, vp, prop):\n        '''Here we can do something when a single property got changed'''\n        #FreeCAD.Console.PrintMessage(\"Change property: \" + str(prop) + \"\"+chr(10))\n\n    def setupContextMenu(self, vobj, menu):\n        if vobj.Object.Proxy.editingMode == False:\n            text = \"Edit Formulas...\"\n            mode = 0\n        else:\n            text = \"Accept Formulas\"\n            mode = 6\n        action = menu.addAction(text)\n        action.triggered.connect(lambda: self.setEdit(vobj,mode))\n        attachAction = menu.addAction(\"Edit Attachment...\")\n        attachAction.triggered.connect(lambda: self.setEdit(vobj,8))\n\n    def setEdit(self,vp,modNum):\n        FreeCAD.Console.PrintLog(f\"ParametricCurve::setEdit: modNum = {modNum}\\n\")\n        if modNum == 0:\n            vp.Object.Proxy.showEditor()\n        elif modNum == 1:\n            FreeCADGui.runCommand(\"Std_TransformManip\",0)\n            return True\n        elif modNum == 3:\n            FreeCADGui.runCommand('Part_ColorPerFace',0)\n        elif modNum == 6: #accept changes and end edit mode\n            FreeCADGui.getMainWindow().findChild(QtGui.QWidget,\"formulaEditor\").editor.accept()\n        elif modNum == 8:\n            FreeCADGui.runCommand(\"Part_EditAttachment\",0)\n        else:\n            FreeCAD.Console.PrintMessage(f\"modNum = {modNum}\\n\")\n        return False\n\n    def getIcon(self):\n        '''Return the icon in XPM format which will appear in the tree view. This method is\\\n                optional and if not defined a default icon is shown.'''\n        return '''\n/* XPM */\nstatic char *_ce4cf5b663f4b5f9c7b8e8d0afb135esksMX5u0XGPbxtkI[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 202 2 \",\n\"   c #EA0004\",\n\".  c #EB030C\",\n\"X  c #EC0C0D\",\n\"o  c #EB0610\",\n\"O  c #EB0B13\",\n\"+  c #EB0D19\",\n\"@  c #EC1214\",\n\"#  c #ED1B17\",\n\"$  c #EC141C\",\n\"%  c #EC1A1F\",\n\"&  c #EC1720\",\n\"*  c #EC1B23\",\n\"=  c #EC1B2C\",\n\"-  c #EB1A30\",\n\";  c #EE2321\",\n\":  c #ED2A38\",\n\">  c #EF3534\",\n\",  c #EF3834\",\n\"<  c #ED2E41\",\n\"1  c #EE3041\",\n\"2  c #EF424A\",\n\"3  c #F1474A\",\n\"4  c #F04D56\",\n\"5  c #F25559\",\n\"6  c #F05463\",\n\"7  c #F15C6A\",\n\"8  c #F3666B\",\n\"9  c #F26674\",\n\"0  c #F36C78\",\n\"q  c #F57B75\",\n\"w  c #1B8939\",\n\"e  c #3AA657\",\n\"r  c #3DAE5A\",\n\"t  c #2DBA52\",\n\"y  c #35B255\",\n\"u  c #34B857\",\n\"i  c #3AB45A\",\n\"p  c #3BBB5D\",\n\"a  c #44A85E\",\n\"s  c #45AE61\",\n\"d  c #4CAF66\",\n\"f  c #54A469\",\n\"g  c #5AA66D\",\n\"h  c #53AF6B\",\n\"j  c #44B462\",\n\"k  c #49B365\",\n\"l  c #44BD63\",\n\"z  c #4BBC69\",\n\"x  c #53B16C\",\n\"c  c #5DAC72\",\n\"v  c #5CB473\",\n\"b  c #58BA72\",\n\"n  c #66A577\",\n\"m  c #63AD76\",\n\"M  c #69A779\",\n\"N  c #65AE79\",\n\"B  c #6BAC7C\",\n\"V  c #62B377\",\n\"C  c #65B179\",\n\"Z  c #65B97C\",\n\"A  c #39C65E\",\n\"S  c #3EC461\",\n\"D  c #3DCB62\",\n\"F  c #3DD464\",\n\"G  c #3FDA67\",\n\"H  c #3BE668\",\n\"J  c #41CA65\",\n\"K  c #4CC56C\",\n\"L  c #45CD69\",\n\"P  c #4BCB6D\",\n\"I  c #50C36F\",\n\"U  c #43D268\",\n\"Y  c #46D36B\",\n\"T  c #43DC6B\",\n\"R  c #48DB6E\",\n\"E  c #57C474\",\n\"W  c #4EDC73\",\n\"Q  c #54DA77\",\n\"!  c #43E36D\",\n\"~  c #42EB6E\",\n\"^  c #4BE473\",\n\"/  c #46EE72\",\n\"(  c #4AEC74\",\n\")  c #4FEF79\",\n\"_  c #51E979\",\n\"`  c #45F473\",\n\"'  c #49F476\",\n\"]  c #43FE75\",\n\"[  c #4DF378\",\n\"{  c #47FE79\",\n\"}  c #4DFD7C\",\n\"|  c #53F57D\",\n\" . c #51FD7F\",\n\".. c #F27080\",\n\"X. c #F47C8B\",\n\"o. c #7B9B83\",\n\"O. c #7CA486\",\n\"+. c #73AC82\",\n\"@. c #79AC86\",\n\"#. c #7CAD89\",\n\"$. c #6EBA82\",\n\"%. c #79B087\",\n\"&. c #55FF84\",\n\"*. c #59FF87\",\n\"=. c #5EFF89\",\n\"-. c #60FF8C\",\n\";. c #85A58D\",\n\":. c #82AC8D\",\n\">. c #80B18D\",\n\",. c #87AC91\",\n\"<. c #8BAD94\",\n\"1. c #93A798\",\n\"2. c #93AD9A\",\n\"3. c #99AE9E\",\n\"4. c #86B392\",\n\"5. c #8CB296\",\n\"6. c #8FB399\",\n\"7. c #92B19A\",\n\"8. c #97B49F\",\n\"9. c #9DAAA0\",\n\"0. c #9DB3A3\",\n\"q. c #9AB9A2\",\n\"w. c #A3ACA5\",\n\"e. c #ABAEAC\",\n\"r. c #B1ABAF\",\n\"t. c #A2B2A6\",\n\"y. c #A5B3A9\",\n\"u. c #ABB3AD\",\n\"i. c #A4BBAA\",\n\"p. c #B3ABB1\",\n\"a. c #BFACBA\",\n\"s. c #AFB3B0\",\n\"d. c #B4B3B4\",\n\"f. c #B9B2B7\",\n\"g. c #BDB5BA\",\n\"h. c #B7BCB8\",\n\"j. c #F68785\",\n\"k. c #F58A8D\",\n\"l. c #F58A93\",\n\"z. c #F69495\",\n\"x. c #F79993\",\n\"c. c #F6939C\",\n\"v. c #F9A69E\",\n\"b. c #F59AA7\",\n\"n. c #C1B5BD\",\n\"m. c #F8A4A6\",\n\"M. c #F7A1AB\",\n\"N. c #F8AAAD\",\n\"B. c #FAB6AD\",\n\"V. c #F9B4B4\",\n\"C. c #FBBCB7\",\n\"Z. c #FABDBC\",\n\"A. c #BAC0BC\",\n\"S. c #B5C8BA\",\n\"D. c #FBC2BA\",\n\"F. c #CEB3C7\",\n\"G. c #CCB5C6\",\n\"H. c #C6BAC3\",\n\"J. c #CABCC6\",\n\"K. c #CEBDCA\",\n\"L. c #F8BAC9\",\n\"P. c #C4C4C4\",\n\"I. c #CDC6CB\",\n\"U. c #D2C3CE\",\n\"Y. c #D0CBCF\",\n\"T. c #C6D0C9\",\n\"R. c #D8C4D3\",\n\"E. c #D4CBD2\",\n\"W. c #DACAD6\",\n\"Q. c #DDCDD9\",\n\"!. c #DAD5D8\",\n\"~. c #FAC6C8\",\n\"^. c #FCD7CD\",\n\"/. c #E2C5DA\",\n\"(. c #E0CDDB\",\n\"). c #FBCED2\",\n\"_. c #E3D1DE\",\n\"`. c #FDDBD3\",\n\"'. c #FEE6DC\",\n\"]. c #E6D2E1\",\n\"[. c #E9D5E4\",\n\"{. c #E6DBE3\",\n\"}. c #ECDCE8\",\n\"|. c #FBDAE4\",\n\" X c #F3DDED\",\n\".X c #FCDFEA\",\n\"XX c #F7DEF0\",\n\"oX c #EEE5EC\",\n\"OX c #FEE8E2\",\n\"+X c #F2E1EE\",\n\"@X c #FEF3EA\",\n\"#X c #F6E3F1\",\n\"$X c #FAE6F4\",\n\"%X c #F3EEF2\",\n\"&X c #FBEAF4\",\n\"*X c #FFEDFC\",\n\"=X c #FEF3F3\",\n\"-X c #FFFDF6\",\n\";X c #FEF3FD\",\n\":X c #FFFAFF\",\n\">X c #FFFEFF\",\n\",X c white\",\n/* pixels */\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X:X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X5.t q.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xn.{ -./ E.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xi.V E.,X,X,X,X,X,X,Xk =.-.=.c ,X,X,X,X,X,X,XP.m S.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X[.H =.H t.,X,X,X,X,XU.' =.=.-.~ _.,X,X,X,X,X7.` =.A *X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xe.&.-.-.} 3.,X,X,X,X@.*.=.-.=.*.5.,X,X,X,X<.} -.=. .n.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xu.&.=.=.=.' h.,X,X:XS =.=.&.=.=.j ,X,X,X0.{ -.-.=.&.y.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xw.&.=.=.=.=.` h.,Xe.&.-.Q e.W =.&.f.,Xt.{ -.=.=.-.&.t.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xe.&.=.=.&.*.=.' +._ =./ W.,Xn.} -.Q B  .-.&. .-.-. .f.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,XI.J.:X,X,X,X,X,Xu.&.=.E F.B &.=.=.=.=.c ,X,X,Xx =.=.=.-.} @.F.I =.&.g.,X,X,X,X,X,XH.W.,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,Xi.` } p :.].,X,X,Xs.&.*.0.,X,X2.{ -.-.&.e.,X,X,Xy.&.=.=.' 3.,X,X5.&.&.n.,X,X,XW.#.p } H h.,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X%.=.=.=.*.! N K.,X0.&.&.d.,X,X,X;.&.-.i ,X,X,X,X*XD -.} 1.,X,X,Xu.&.&.w.,XJ.c / *.-.-.*.5.,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,Xt.&.=.=.-.=.=.[ r ) =.&.f.,X,X,X,X@.] ;.,X,X,X,X,X@.] 5.,X,X,X,Xu.&.=._ i  .*.-.-.=.=.&.r.,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X+XG =.-.-.*.&.=.-.=.=.&.f.,X,X,X,X,Xf.,X,X,X,X,X,X:Xg.,X,X,X,X,Xu.&.=.=.-.*.&.*.-.=.-.D :X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,XN =.-.&.;.0.c ~ *.-.&.0.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X1.*.-.*.! n t.#.&.-.*.@.,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,Xn.} -.A :X,X,X_.@.D { p.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xe.{ S :._.,X,X.XT -./ W.,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,Xx =.( _.,X,X,X,X#Xp.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xp.*X,X,X,X,XK. .=.c ,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,Xt.&.&.2.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X#.*.&.d.,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,Xa.&.=.l ,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X*XJ -.} K.,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X{.B j j j j j s ^ =.=.&.d.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X0.&.-.-.R j j j j j k B oX,X,X,X\",\n\",X,X,X,Xy =.=.-.=.-.-.-.-.-.=.=.v ,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xk -.=.-.-.-.=.=.-.=.=.*.k ,X,X,X\",\n\",X,X,X,Xx =.-.=.=.=.[ p i i i u n ,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xf u i i i p &.=.=.-.=.*.m ,X,X,X\",\n\",X,X,X,X_.! =.-.=.^ J.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xf.) -.=.=.F  X,X,X,X\",\n\",X,X,X,X,XP.~ =.-.S :X,X,X,X,X,X,X,X,X,X&X5 > : B.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,XXXT -.-.! !.,X,X,X,X\",\n\",X,X,X,X,X,XP.~ -.*.@.,X,X,X,X,X,X,X,X|.  $ $ o x.,X,X,Xl.2 1 @X,X,X,X,X,X,X,X,X,X,X4 2 4 ,X,X,X,X,X,X,X,X,XM =.=.! E.,X,X,X,X,X\",\n\",X,X,X,X,X,X,XA.` =.&.;.,X,X,X,X,X,X,X: $ * %   z.,X,X&X  O 4 ,X,X,X,X,X,X,X,X,X,X,Xb.. . v.,X,X,X,X,X,X,Xo.&.-.~ Y.,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,Xd. .=.} 7.,X,X,X,X,X,X  * % > N.Z.,X,X7 $ . ^.,X,X,X,X,X,X,X,X,X,X,X,X+ % @ ,X,X,X,X,X,X@.&.=.( P.,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,Xp -.-.{ q.,X,X,X,X$X. * o ~.,X,X,X,X. $ % ,X,X,X,X,X,X,X,X,X,X,X,X,X9 $ . B.,X,X,X,X:.&.=.=.j ,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X:Xu.z -.-.=.*.e ,X,X,X).c.+ * @ j.m.=X,Xb.O + q ,X|.m.N.m.).,X,XM.N.N.B.,XL.o $ 5 ,X,X,X,Xt *.-.-.=.x f.,X,X,X,X,X,X\",\n\",X,X,X,XQ.#.p &.=.=.&.p ,.$X,X,X,X9 . * * * @   `.,X6 $ O D.,X,X  O O O ,X|.  O   x.,X,X  % X ,X,X,X,X X@.S &.=.=.&.p <.[.,X,X,X\",\n\",X,X*XM / *.-.-.&.h d.,X,X,X,X,X,X0 O * * * %   `.,X= & . @X,X,XX.O * o '.X.@ % ; ,X,X,X- * . @X,X,X,X,X,X:Xw.x &.=.-.*.G +.:X,X\",\n\",X:Xz *.=.=.-.&.<.,X,X,X,X,X,X,X,Xc.2 $ * * 2 2 OX,X. * . ,X,X,X,Xo * $ q : & . D.,X,X,X4 $ o Z.,X,X,X,X,X,X,X,X>.*.-.-.-.*.b ,X\",\n\",X_.H -.=.-.-.[ W.,X,X,X,X,X,X,X,X,X;Xo * o ~.,X,X&X. * @ ,X,X,X,XX.O * * * % > ,X,X,X,X7 $ O V.,X:X,X,X,X,X:X,XK.r k k k z w :X\",\n\",X,Xq.H *.-.=.=.P g.,X,X,X,X,X,X,X,X.X. * o C.,X,X&X. % ; ,X,X,X,X,X+ * * * o `.,X:X,X:X9 + O V.,X,X,X,X,X,X,Xs.W =.-.-.=.H S.,X\",\n\",X,X,XQ.B F &.=.-. .h 9.*X,X,X,X,X,X.X. ; O C.,X,X&X. * # ,X,X,X,X,XO * * * + j.,X,X,X,X8 $ O V.,X,X:X,X$X9.k &.=.=.*.F B }.,X,X\",\n\",X,X,X,X,X#X2.j  .-.=.&.D 8.,X,X,X,X#X. * o C.,X,X:X. % . ,X,X,X,X..O * $ * * . ,X,X:X,X6 + O V.,X,X,X4.F &.=.-.} d 0.#X:X,X,X,X\",\n\",X,X,X,X,X,X,X,Xs.) -.=.=.e ,X,X,X,X.X. * O Z.,X,X,X+ % . -X,X,X,X. * $ j.O * O x.,X,X,X< * . ^.,X,X,Xy =.=.=.^ g.,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X;XJ -.=.Y #X,X,X,X,X#X. * O C.,X,X,X< $ O ^.,X,X9 O *   ,X= * * @ ,X:X,X. *   ,X,X,X,X{.T =.=.l ,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,Xv =.=.K +X,X,X,X,X,X|.  O   V.,X,X,XX.@ O k.,X=X  O . 3 :Xl.  O   x.,X).. & > ,X,X,X,X,X{.J =.*.C ,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X:Xv *.=.J *X,X,X,X,X,X,X=Xk.z.k.'.,X,X,X|.. % > ,X~.k.z.l.`.,X=Xk.c.l.m.,Xk.+ O j.,X,X,X,X,X,X XU =.&.B ,X,X,X,X,X,X\",\n\",X,X,X,X,X,XZ &.=.| J.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X< % . @X,X,X,X:X,X:X,X,X,X:X,X,X= %   ,X,X,X,X,X,X,X,Xd.&.=.&.C ,X,X,X,X,X\",\n\",X,X,X,X,XV &.=.-.y ,X,X,X:X,X,X,X,X,X,X,X,X,X,X,X,X,X~.  O 8 ,X,X,X,X,X,X,X,X,X,X,XL.. O q ,X,X,X,X,X,X,X,X;XD -.-.*.B ,X,X,X,X\",\n\",X,X,X,X2.&.-.=.-.=.v 0.0.t.0.0.!.,X,X,X,X,X,X,X,X,X,X,X6 * o =X,X,X,X,X,X,X,X,X,X,X: $ * :X,X:XY.0.0.t.t.3.f =.=.-.=.} t.,X,X,X\",\n\",X,X,X,Xu -.=.-.=.-.*.*.&.&.&.&.r ,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X:X,X,X:X:X,X,X:X,X,X,X,X,X,X,X,Xt &.*.&.&.&.=.=.-.=.=.-.j ,X,X,X\",\n\",X,X,X,X+.~ &.&.&.&.&.&.*.=.-.*.:.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X:X,X,X,X,X:X,X,X,X:X,X,X,XB =.=.=.*.&.&.&.*.&.&.~ 5.,X,X,X\",\n\",X,X,X,X,XW.e.t.t.0.s.p.$.=.=.! [.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,XU./ =.=.@.u.y.t.w.0.u.Q.,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,XG. .*.V ,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X:X,X,X,X:X,Xh =.} /.,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X@.*.&.p.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X:X,X,X:X:X,X,X:X,X:X,X,X,X:X,X,X,Xe.&.&.5.,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X*XD -.A ;X,X,X,X XO.s oX,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X!.s <.$X,X,X,X[.! -.S :X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X7.*.-.R  X,XG.+.T *.&.w.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X8.&.*.U #.K.,XR.( -.&.w.,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,Xj -.=.-.L i } *.-.=.&.d.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xw.&.-.-.*.} r Y -.-.=.h ,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,XH. .=.-.=.-.-.=.*.=.=.&.f.,X,X,X,X}.a !.,X,X,X,X:XT.a $X,X,X,X,Xu.&.=.=.*.=.-.=.-.-.=.' U.,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X4.*.=.-.-.*./ c y.Z =.&.f.,X,X,X XU =.f ,X,X,X,X,Xa *.P $X,X,X,Xu.&.=.$.t.h } =.=.=.=.&.0.,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X@.&.*.&.U B W.,X,Xu.&.&.u.,X,X XY =.=.H ].,X,X,XU.' =.=.P *X,X,Xt.&. .g.,X,XJ.m T &.=.&.6.,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X%Xm V 2.+X,X,X,X,Xu.&.*.#.,X[.Y =.=.=.*.6.,X,X,X@.*.=.-.=.K  X,XB *. .n.,X,X,X:X}.2.V c =X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xu.&.-.| c ! =.=.[ =.=.l :X,X*XJ =.*.[ =.-.R g | =. .n.,X:X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xy.&.=.-.=.=.=.E /.Z =.*.,.,X+.*.*.%./.K =.=.=.=.=.&.y.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X6.*.=.=.=.*.I ;X,X(./ -.&.e *.-.G #X,X*XP =.=.-.=.&.t.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xu.&.=.=.=.I *X,X,X,Xh =.=.-.-.=.N ,X,X:X$XP =.=.-.&.d.,X:X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xf.&.=.*.K *X,X,X,X,Xw.*.=.=.=. .d.,X,X,X,X#XL =.-.' R.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,Xj ` g *X,X,X,X,X,X*XA -.=.=.p :X,X,X,X,X,X+Xh { d ,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X&XU.,X,X,X,X,X,X,X,X#.&.=.&.2.,X,X,X,X,X,X,X,XK.;X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X*XJ *.l :X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\",\n\",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,XoX5.*X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X\"\n};\n\n'''\n\n    def __getstate__(self):\n        '''When saving the document this object gets stored using Python's json module.\\\n                Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\\\n                to return a tuple of all serializable objects or None.'''\n        return None\n\n    def __setstate__(self,state):\n        '''When restoring the serialized object from document we have the chance to set some internals here.\\\n                Since no data were serialized nothing needs to be done here.'''\n        return None\n\n# end of CurveVP\n\ndef makeCurve(Parametric_Curve_FP):\n    sheet = None\n    textDoc = None\n    txt = \"\"\"\n{\n\"helix\": {\"a\": \"1  #pitch\", \"b\": \"5 #height\", \"c\": \"1 #base radius\",\n\"d\": [\n\"{d1} 20 #angle deg\",\n\"{d2} 1  # 1= RH  0 = LH\",\n\"{d3} t*b/a\",\n\"{d4} c + b*t*sin(rad(d1))/(2*pi)\",\n\"{d5} ternary(d2, 1, -1)\"],\n\"X\": \"d4*cos(d3*d5)\", \"Y\": \"d4*sin(d3*d5)\", \"Z\": \"b*t/(2*pi)\",\n\"t_min\": \"0\", \"t_max\": \"2*pi\", \"interval\": \"0.1\"},\n\n\"ellipse\": {\"a\": \"20 #major radius\", \"b\": \"10 #minor radius (ignored if c != 0)\",\n\"c\": \"0.5 #eccentricity (0 to ignore and use a and b, else b^2 = a^2*(1 - c^2)\",\n\"d\": [\n\"{d1} 0 # x center\",\n\"{d2} 0 # y center\",\n\"{d3} 20 # angle from x-axis to major axis (deg)\",\n\"{d4} ternary(c, a*(1-c*c)^0.5, b)\",\n\"{d5} a * cos(t) # x -unrotated ellipse\",\n\"{d6} d4 * sin(t) # y- unrotated ellipse\",\n\"{d7} radians(d3) # angle in radians\"\n],\n\"X\": \"d1 + d5 * cos(d7) - d6 * sin(d7)\", \"Y\": \"d2 + d5 * sin(d7) + d6 * cos(d7)\", \"Z\": \"0\",\n\"t_min\": \"0.0\", \"t_max\": \"2*pi\", \"interval\": \"0.1\"},\n\n\"amoeba\": {\"a\": \"36.3\", \"b\": \"12\", \"c\": \"1.5\", \"d\": [\"(a+c*sin(b*t))\"],\n\"X\": \"cos(t)*d1\", \"Y\": \"sin(t)*d1\", \"Z\": \"0\",\n\"t_min\": \"0.0\", \"t_max\": \"2*pi\", \"interval\": \"0.1\"},\n\n\"coil\": {\"a\": \"6\", \"b\": \"1\", \"c\": \"20\", \"d\": [],\n\"X\": \"(a + b * cos(c*t))*cos(t)\", \"Y\": \"(a + b * cos(c*t))*sin(t)\", \"Z\": \"b*sin(c*t)\",\n\"t_min\": \"0.0\", \"t_max\": \"2*pi\", \"interval\": \"0.02\"},\n\n\"holesaw\": {\"a\": \"12  # radius\", \"b\": \"6 #no of teeth\", \"c\": \"5.000000 #sine amplitude\",\n\"d\": [\"\"], \"X\": \"cos(t)*a\", \"Y\": \"sin(t)*a\", \"Z\": \"c*sin(b*t)\",\n\"t_min\": \"0.0\", \"t_max\": \"2*pi\", \"interval\": \"0.1\"},\n\n\"sawtooth\": {\"a\": \"40 #radius\", \"b\": \"5 #number teeth\", \"c\": \"0.8 # tooth parameter between 0 and 1\",\n\"d\": [\"10 #amplitude\", \"mod(b*t, 1)\", \"# best with polygon\"],\n\"X\": \"a*cos(2*pi*t)\", \"Y\": \"a*sin(2*pi*t)\", \"Z\": \"d1*(lt(d2,c)*d2/c + gte(d2,c)*(1-d2)/(1-c))\",\n\"t_min\": \"0.0\", \"t_max\": \"1.0\", \"interval\": \"0.01\"},\n\n\"sinbraid_round_3\": {\"a\": \"10\", \"b\": \"sin(t*10/3) #radial amplitude\", \"c\": \"cos(t*5/3)*5 #vertical amplitude\", \"d\": [],\n\"X\": \"a*sin(t)+b*sin(t)\", \"Y\": \"a*cos(t)+b*cos(t)\", \"Z\": \"c\",\n\"t_min\": \"0.0\", \"t_max\": \"6*pi\", \"interval\": \"0.02\"},\n\n\"sinbraid_round_4_3\": {\"a\": \"10  #radius\", \"b\": \"sin(t*9/4)   # radial amplitude\", \"c\": \"cos(t*3/4)*4  # vertical amplitude\", \"d\": [],\n\"X\": \"a*sin(t)+b*sin(t)\", \"Y\": \"a*cos(t)+b*cos(t)\", \"Z\": \"c\",\n\"t_min\": \"0.0\", \"t_max\": \"8*pi\", \"interval\": \"0.1\"},\n\n\"para_curve\": {\"a\": \"10 #radius plane\", \"b\": \"4 #period\", \"c\": \"3 #amplitude\", \"d\": [\"(a+c*sin(b*t+pi/2)) #formula\"],\n\"X\": \"cos(t)*d1 #polar X\", \"Y\": \"sin(t)*d1  #polarY\", \"Z\": \"0\",\n\"t_min\": \"0.0\", \"t_max\": \"2*pi\", \"interval\": \"0.1\"}\n}\n\"\"\"\n    sel = FreeCADGui.Selection.getSelection()\n    if sel and sel[0].isDerivedFrom(\"Spreadsheet::Sheet\"):\n        sheet = sel[0]\n    elif sel and sel[0].isDerivedFrom(\"App::TextDocument\"):\n        textDoc = sel[0]\n    if not FreeCAD.ActiveDocument:\n        FreeCAD.newDocument()\n    pc=FreeCAD.ActiveDocument.addObject(\"Part::FeaturePython\",\"ParametricCurve\")\n    if Parametric_Curve_FP:\n        Parametric_Curve_FP.Curve(pc)\n        Parametric_Curve_FP.CurveVP(pc.ViewObject)\n    else: #for debugging/testing only\n        Curve(pc)\n        CurveVP(pc.ViewObject)\n    FreeCAD.ActiveDocument.recompute()\n    FreeCADGui.Selection.clearSelection()\n    FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Name,pc.Name)\n    if sheet:\n        pc.Spreadsheet = sheet\n    elif textDoc:\n        FreeCAD.Console.PrintWarning(\"Parametric_Curve_FP: Ensure the document has been saved since the last edit of the Text document\\n\")\n        FreeCAD.Console.PrintMessage(f\"Attempting to import:\\n{textDoc.Text}\\n\")\n        pc.Proxy.readJSONFile(pc,textDoc.Text)\n    else:\n        pc.Proxy.readJSONFile(pc,txt)\n        FreeCADGui.SendMsgToActiveView(\"ViewSelection\",True)\n\n\nif __name__ == \"__main__\":\n    import importlib\n    import Parametric_Curve_FP\n    importlib.reload(Parametric_Curve_FP)\n    makeCurve(Parametric_Curve_FP)\n\n",
    "url": "https://wiki.freecad.org/Macro_Parametric_Curve_FP",
    "raw_code_url": "https://gist.github.com/mwganson/473920ad317fb2dc3e37638112874e2a/raw/da0639b423b73af5f71f8806c27524f468633346/Parametric_Curve_FP.py",
    "wiki": "",
    "version": "2025.01.28b",
    "license": "",
    "date": "2025-01-28",
    "src_filename": "",
    "filename_from_url": "",
    "author": "<TheMarkster> 2021, based on macro 3D Parametric Curve by Gomez Lucio,  Modified by Laurent Despeyroux on 9th feb 2015",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Parametric_Curve_FP.svg",
    "icon_source": "https://wiki.freecadweb.org/images/5/59/Parametric_Curve_FP.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Airfoil Import & Scale",
    "on_wiki": true,
    "on_git": false,
    "desc": "When starting the macro, the configuration window is displayed. Enter the length of the rope and choose the desired line type, DWire or BSpline and click the OK button to see the explorer window appear choose the file to build the profile. If a profile is selected, run the macro the configuration window is displayed and the Save button is available. If the Save button is clicked, the explorer window is displayed choose the path and a file name to save your profile on disk, the length of the rope and the type of wire are ignored only the X and Y coordinates are saved in the file.<br /><br />Macro version: 3.0.0<br />Last modified: 2024-11-27<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecad.org/wiki/images/0/0c/Macro_Airfoil_Import_%26_Scale.png\">ToolBar Icon</a><br />Author: quick61<br /> ",
    "comment": "Imports and scales an Airfoil in the form of a Draft Wire (DWire) or Basic Spline (BSpline)",
    "code": "# This Macro, when run, will first provide the user with a file browser to\n# locate and select a .dat airfoil text file. Once selected, a chord length is\n# entered and upon pressing the OK button, a properly scaled airfoil is\n# produced. There are two versions provided here. Version 1.5 should work on\n# FreeCAD versions, 0.13 stable as well as all 0.14 versions. Version 2 should\n# only be used with FreeCAD versions equal to or greater than 0.14 3077 and\n# will work best with versions built with OCE/OCC versions 6.7 or greater (See\n# the Wiki page for all available version).\n#\n# (c) quick61\n\n__Name__ = 'Airfoil Import and Scale'\n__Comment__ = 'Imports and scales an Airfoil in the form of a Draft Wire (DWire) or Basic Spline (BSpline)'\n__Author__ = \"quick61\"\n__Version__ = '3.0.0'\n__Date__ = '2024-11-27'\n__License__ = ''\n__Web__ = \"https://forum.freecad.org/viewtopic.php?f=22&t=5554\"\n__Wiki__ = \"https://www.freecad.org/wiki/Macro_Airfoil_Import_%26_Scale\"\n__Icon__ = 'https://www.freecad.org/wiki/images/0/0c/Macro_Airfoil_Import_%26_Scale.png'\n__Help__ = ''\n__Naca__ = \"http://airfoiltools.com/airfoil/index\"\n__Status__ = 'stable'\n__Requires__ = 'Freecad >= 0.14.3706'\n__Communication__ = ''\n__Files__ = ''\n\n\nimport FreeCAD as app\nimport FreeCADGui as Gui\nimport PySide\nfrom PySide import QtCore, QtGui\nfrom PySide.QtGui import QLineEdit, QRadioButton\nimport Draft\nimport importAirfoilDAT\nimport os\n\n# Select .dat airfoil data file to be imported\n# PySide returns a tuple (filename, filter) instead of just a string like in PyQt\n\nglobal filename\nglobal nameFile\n\nclass AirfoilImporterAndScaler():\n    def __init__(self):\n        self.dialog = None\n        self.s1 = None\n\n        # Make dialog box and get the scale size\n        self.dialog = QtGui.QDialog()\n        self.dialog.resize(350,100)\n        self.dialog.setWindowTitle(\"Airfoil Import & Scale\")\n        la = QtGui.QVBoxLayout(self.dialog)\n        t1 = QtGui.QLabel(\"Chord Length\")\n        la.addWidget(t1)\n\n        self.s1 = QtGui.QDoubleSpinBox()\n        self.s1.setDecimals(5)\n        self.s1.setMinimum(-9999999.9999999)\n        self.s1.setMaximum(9999999.9999999)\n        self.s1.setSuffix(\" mm (Length)\")\n        self.s1.setValue(1.0)\n        la.addWidget(self.s1)\n\n        ####\n        self.FreeCAD_ParamGetSet = FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/Airfoil_Import_and_Scale\")\n        self.FreeCAD_ParamGetSet.SetString(u\"Version\", __Version__ + \" (\" + __Date__ + \")\")\n        self.numberCut = self.FreeCAD_ParamGetSet.GetInt(\"numberCut\", 150)       # number of coordinates\n        self.FreeCAD_ParamGetSet.SetInt(\"numberCut\", self.numberCut)\n        ####\n        # Add radio buttons to select between DWire and BSpline\n        self.radio1 = QtGui.QRadioButton(\"Make DWire\")\n        self.radio2 = QtGui.QRadioButton(\"Make BSpline\")\n        self.radio3 = QtGui.QRadioButton(\"Save\")\n\n        # set default to DWire & make radio buttons - Change self.radio1.setChecked(True) to\n        # self.radio2.setChecked(True) to set BSpline as default\n\n        self.radio1.setChecked(True)\n        la.addWidget(self.radio1)\n        self.radio1.setToolTip(\"Create DWire Airfoil\")\n        la.addWidget(self.radio2)\n        self.radio2.setToolTip(\"Create BSplinee Airfoil\")\n        #### save button\n        la.addWidget(self.radio3)\n        self.numberCut = self.FreeCAD_ParamGetSet.GetInt(\"numberCut\")       # number of coordinates\n        self.radio3.setToolTip(u\"Only available if one Airfoil to save is selected\" + \"\\n\"\n                               u\"The actual value of definition is \" + str(self.numberCut) + \" points\" + \"\\n\"\n                               u\"For change this value, go to\" + \"\\n\"\n                               u\"User parameter:BaseApp/Preferences/Macros/Airfoil_Import_and_Scale\" + \"\\n\"\n                               u\"Change the 'numberCut' value\")\n        self.radio3.setEnabled(False)\n        selected = \"\"\n        selected = FreeCADGui.Selection.getSelection()\n        if len(selected) != 0:\n            self.radio3.setEnabled(True)\n        ####\n        # Add OK / Cancel buttons\n        okbox = QtGui.QDialogButtonBox(self.dialog)\n        okbox.setOrientation(QtCore.Qt.Horizontal)\n        okbox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)\n        la.addWidget(okbox)\n        QtCore.QObject.connect(okbox, QtCore.SIGNAL(\"accepted()\"), self.proceed)\n        QtCore.QObject.connect(okbox, QtCore.SIGNAL(\"rejected()\"), self.close)\n        QtCore.QMetaObject.connectSlotsByName(self.dialog)\n        self.dialog.show()\n        self.dialog.exec_()\n\n    def proceed(self):\n        global filename\n        global nameFile\n\n        param = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")# macro path\n        macroPath = param.GetString(\"MacroPath\",\"\") + \"/\"                   # macro path\n\n        filePath = \"\"\n        filePath = self.FreeCAD_ParamGetSet.GetString(u\"filePath\", filePath)\n        filePath = filePath.replace(u\"\\\\\",\"/\")      # convert the \"\\\" to \"/\"\n\n        if filePath == \"\":\n            filePath = self.FreeCAD_ParamGetSet.GetString(u\"filePath\", macroPath)\n\n        if self.radio1.isChecked() or self.radio2.isChecked():\n\n            OpenName, filefilter = QtGui.QFileDialog.getOpenFileName(None, \"Open An Airfoil File\", filePath, \"*.dat\")\n            if OpenName != \"\":\n                ####new2\n                pathFile      = os.path.dirname(OpenName) + \"/\"  #1# = C:/Provisoire400/\n                racineDrive   = os.path.splitdrive(OpenName)[0]  #2# = C:\n                formatFichier = os.path.splitext(OpenName)[1]    #3# = .png\n                OpenName      = os.path.splitext(OpenName)[0]    #4# = /home/kubuntu/.FreeCAD/Macro/Texture_007_H #= C:/Provisoire400/image3D\n                nameFile      = os.path.basename(OpenName)       #5# = image3D\n                SaveNameformatFichier = OpenName + formatFichier #6# = C:/Provisoire400/image3D.png\n                pathFileSaveNameformatFichier = pathFile + nameFile + formatFichier #7# = C:/Provisoire400/image3D.png\n                ####new2\n                self.FreeCAD_ParamGetSet.SetString(\"filePath\", pathFile)\n\n                if self.radio1.isChecked():\n                    try:\n                        # This produces a scaled Airfoil with a DWire\n                        scalefactor=self.s1.value()\n                        f1=SaveNameformatFichier\n                        importAirfoilDAT.insert(f1,\"Unnamed\")\n                        points = FreeCAD.ActiveDocument.Wire\n                        nacaDWire = Draft.scale([points], scale=FreeCAD.Vector(scalefactor,scalefactor,scalefactor), center=FreeCAD.Vector(0.0, 0.0, 0.0), copy=True)\n                        nacaDWire.MakeFace = False\n                        nacaDWire.Label = nameFile + \"_(DWire)(\" + str(scalefactor) + \")\"\n                    except Exception:\n                        app.Console.PrintError(\"Error, not a valid .dat file\\n\")\n\n                if self.radio2.isChecked():\n                    try:\n                        # This produces a scaled Airfoil with a BSpline\n                        scalefactor=self.s1.value()\n                        f1=SaveNameformatFichier\n                        importAirfoilDAT.insert(f1,\"Unnamed\")\n                        points = FreeCAD.ActiveDocument.Wire.Points\n                        bspline = Draft.make_bspline(points, closed=True)\n                        App.getDocument('Unnamed').recompute()\n                        nacaBSpline = Draft.scale(bspline, scale=FreeCAD.Vector(scalefactor,scalefactor,scalefactor), center=FreeCAD.Vector(0.0, 0.0, 0.0), copy=True)\n                        nacaBSpline.MakeFace = False\n                        nacaBSpline.Label = nameFile + \"_(BSpline)(\" + str(scalefactor) + \")\"\n                        App.activeDocument().removeObject(bspline.Name)\n                    except Exception:\n                        app.Console.PrintError(\"Error, not a valid .dat file\\n\")\n\n                try:    \n                    App.getDocument(\"Unnamed\").getObject(nameFile).removeObjectsFromDocument()\n                    App.getDocument('Unnamed').removeObject(nameFile)\n                    App.getDocument('Unnamed').recompute()\n                except Exception:\n                    None\n\n                Gui.SendMsgToActiveView(\"ViewFit\")\n            self.close()    # close the window\n\n        if self.radio3.isChecked():\n\n            SaveName, Filter = QtGui.QFileDialog.getSaveFileName(None, \"Save An Airfoil File\", filePath, \"*.dat\")\n            if SaveName != \"\":\n                ####new2\n                pathFile      = os.path.dirname(SaveName) + \"/\"  #1# = C:/Provisoire400/\n                racineDrive   = os.path.splitdrive(SaveName)[0]  #2# = C:\n                formatFichier = os.path.splitext(SaveName)[1]    #3# = .png\n                SaveName      = os.path.splitext(SaveName)[0]    #4# = /home/kubuntu/.FreeCAD/Macro/Texture_007_H #= C:/Provisoire400/image3D\n                nameFile      = os.path.basename(SaveName)       #5# = image3D\n                SaveNameformatFichier = SaveName + formatFichier #6# = C:/Provisoire400/image3D.png\n                pathFileSaveNameformatFichier = pathFile + nameFile + formatFichier #7# = C:/Provisoire400/image3D.png\n                ####new2\n                self.FreeCAD_ParamGetSet.SetString(\"filePath\", pathFile)\n\n                if \".\" in SaveNameformatFichier:\n                    None\n                else:\n                    SaveNameformatFichier += \".dat\"    # Mint\n\n                try:\n                    selected = FreeCADGui.Selection.getSelection()[0]\n                    pointsDirection = []\n                    pointsDirection = selected.Shape.discretize(Number=self.numberCut)  # discretize pour calculer la direction (avec un deuxieme point)\n\n                    f = open(SaveNameformatFichier, 'w')     # path to write\n                    f.write(\"NACA\" + nameFile + \"\\n\")        # title \n\n                    for coor in pointsDirection:\n                        f.write(\" \" + str(round(coor.x, 5)) + \"  \" + str(round(coor.y, 5)) + \"\\n\")\n\n                    f.close()     # close the file\n                except Exception:\n                    app.Console.PrintError(\"Error, to Save .dat file\\n\")\n            self.close()  # close the window\n\n    def close(self):\n        self.dialog.hide()\n\nAirfoilImporterAndScaler()\n\n",
    "url": "https://forum.freecad.org/viewtopic.php?f=22&t=5554",
    "raw_code_url": "",
    "wiki": "https://www.freecad.org/wiki/Macro_Airfoil_Import_%26_Scale",
    "version": "3.0.0",
    "license": "",
    "date": "2024-11-27",
    "src_filename": "",
    "filename_from_url": "",
    "author": "quick61",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Airfoil_Import_%26_Scale.png",
    "icon_source": "https://www.freecad.org/wiki/images/0/0c/Macro_Airfoil_Import_%26_Scale.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Apothem Based Prism GUI",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro will present the user with a dialog to provide the distance between centers, the number of sides, and height and will create a prism based on the apothem, or inradius of a polygon. This can be extremely handy when one only knows the distance between flats. An example of this would be hexagonal stock of plastics or metal provided by vendors. Most vendors define such stock by the distance between flats. If one is using such stock in their projects, this Macro can be a real time saver.<br /><br />Macro version: 1.0<br />Last modified: 2014-12-31<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/4/4e/Part_Prism_Apothem.svg\">ToolBar Icon</a><br />Author: Quick61<br /> ",
    "comment": "This macro will present the user with a dialog to provide the distance between centers, the number of sides, and height and will create a prism based on the apothem, or inradius of a polygon. This can be extremely handy when one only knows the distance between flats. An example of this would be hexagonal stock of plastics or metal provided by vendors. Most vendors define such stock by the distance between flats. If one is using such stock in their projects, this Macro can be a real time saver.",
    "code": "# # # # # # # # # # #\n#\n# Apothem Based Prism\n#\n# This script will take the input of the distance between flats, (apothem, aka inradius), \n# and the number of sidesfor a regular polygon along with a height and produce a \n# correctly sized prism derived from the circumradius.\n#\n# # # # # # # # # # #\n \nimport FreeCAD, FreeCADGui, Part, PartGui, math\nfrom FreeCAD import Base\nfrom PySide import QtGui, QtCore\nfrom math import cos, radians\nApp = FreeCAD\nGui = FreeCADGui\n \nclass p():\n \n \n    def priSm(self):\n \n        try:\n            dbf = float(self.d1.text())\n            nos = int(self.d2.text())\n            hth = float(self.d3.text())\n            aR = dbf / 2\n            op1 = 180/float(nos)\n            coS = cos(math.radians(op1))\n            cR = aR / coS\n            prism=App.ActiveDocument.addObject(\"Part::Prism\",\"Prism\")\n            prism.Polygon=nos\n            prism.Circumradius=cR\n            prism.Height=hth\n            prism.Placement=Base.Placement(Base.Vector(0.00,0.00,0.00),Base.Rotation(0.00,0.00,0.00,1.00))\n            prism.Label='Prism'\n            App.ActiveDocument.recompute()\n            Gui.SendMsgToActiveView(\"ViewFit\")\n        except:\n            FreeCAD.Console.PrintError(\"Unable to complete task\")\n \n            self.close()\n \n    def close(self):\n        self.dialog.hide()\n \n \n#\n# Make dialog box and get input for distance between flats, number of sides, and height\n#\n \n    def __init__(self):\n        self.dialog = None\n \n        self.dialog = QtGui.QDialog()\n        self.dialog.resize(280,110)\n \n        self.dialog.setWindowTitle(\"Apothem Based Prism\")\n        la = QtGui.QVBoxLayout(self.dialog)\n \n        iN1 = QtGui.QLabel(\"Distance Between Flats\")\n        la.addWidget(iN1)\n        self.d1 = QtGui.QLineEdit()\n        la.addWidget(self.d1)\n \n        iN2 = QtGui.QLabel(\"Number Of Sides (Best results - use even numbers)\")\n        la.addWidget(iN2)\n        self.d2 = QtGui.QLineEdit()\n        la.addWidget(self.d2)\n \n        iN3 = QtGui.QLabel(\"Prism Height\")\n        la.addWidget(iN3)\n        self.d3 = QtGui.QLineEdit()\n        la.addWidget(self.d3)\n \n        okbox = QtGui.QDialogButtonBox(self.dialog)\n        okbox.setOrientation(QtCore.Qt.Horizontal)\n        okbox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)\n        la.addWidget(okbox)\n        QtCore.QObject.connect(okbox, QtCore.SIGNAL(\"accepted()\"), self.priSm)\n        QtCore.QObject.connect(okbox, QtCore.SIGNAL(\"rejected()\"), self.close)\n        QtCore.QMetaObject.connectSlotsByName(self.dialog)\n        self.dialog.show()\n        self.dialog.exec_()\n \np()",
    "url": "https://wiki.freecad.org/Macro_Apothem_Based_Prism_GUI",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-12-31",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Quick61",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Part_Prism_Apothem.svg",
    "icon_source": "https://www.freecadweb.org/wiki/images/4/4e/Part_Prism_Apothem.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "BSurf from grid",
    "on_wiki": true,
    "on_git": false,
    "desc": "Makes a B-spline surface through a grid of points.<br /><br />Macro version: 0.1<br />Last modified: 2022-07-31<br />Author: heda<br /> ",
    "comment": "Makes a BSpline surface through a grid of points.",
    "code": "\n\n# -*- coding: utf-8 -*-\n\n# ***************************************************************************\n# *                                                                         *\n# *   Copyright (c) 2022 - heda <heda@fc-forum>                             *\n# *                                                                         *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU Lesser General Public License (LGPL)    *\n# *   as published by the Free Software Foundation; either version 2 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENCE text file.                                 *\n# *                                                                         *\n# *   This program is distributed in the hope that it will be useful,       *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU Library General Public License for more details.                  *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with this program; if not, write to the Free Software   *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\n__Name__ = 'BSurf_from_grid'\n__Comment__ = 'Makes a BSpline surface through a grid of points.'\n__Author__ = 'heda'\n__Version__ = '0.1'\n__Date__ = '2022-07-31'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = ''\n__Wiki__ = 'https://wiki.freecad.org/Macro_Grid_2_BSurf'\n__Icon__ = ''\n__Help__ = 'Select structured point-cloud, set options, run macro'\n__Status__ = 'functional'\n__Requires__ = ''\n__Communication__ = ''\n__Files__ = ''\n\n\"\"\"\ninspired by:\nhttps://forum.freecadweb.org/viewtopic.php?f=22&t=69941&start=10\ncred to snow54\n\nit is assumed that the cloud is:\n    - structured\n    - aligned with xy grid,\ni.e. a constant y divides 2 horizontal rows of points,\nanalogue for x and vertical columns of points\n\n\nusage:\nselect a pointcloud and run macro    \n\noptions:\nwires: convert boundary wires to spline (draft wb),\n       in surf wb, use boundry edges and verts on wires as vertex-constraints\n\nsplines: in surf wb, use outer contour as boundry edges,\n         inner edges can be used as edge constraints\n\nbsurf: surface directly created with poles/knots from interpolated spline\n\nmkwframe: in case of bsurf, symbolic wireframe of splines (draft wb)\n\"\"\"\n\nimport numpy as np\nfrom scipy import interpolate\n\nimport FreeCAD as App\nimport FreeCADGui as Gui\nimport Draft, Part\n\nVector = App.Vector\n\ndoc = App.ActiveDocument\n\ntry:\n    cloud, = Gui.Selection.getSelection()\nexcept ValueError as e:\n    raise RuntimeWarning('a point cloud needs to be selected.')\n\npoints = cloud.Points.Points\nbb = cloud.Points.BoundBox\n\noptions = o = dict(MakeWires=False,\n                   MakeBSplines=False,\n                   MakeBSurf=True,\n                   MakeWFrame=True)\n\n## a bit of options logic...\nif o['MakeWires']: o['MakeBSplines'] = False\nif o['MakeBSplines']: o['MakeBSurf'] = o['MakeWires'] = False\nif o['MakeBSurf'] and o['MakeWFrame']:\n    o['MakeBSplines'] = True; o['MakeWires'] = False\nif not o['MakeBSurf']: o['MakeWFrame'] = False\n\n\ndef RGB(*args):\n    return tuple((float(i/255) for i in args))\n\n\nhstep = min((p.y for p in points))\nvstep = min((p.x for p in points))\n\nwiregroup = doc.addObject('App::DocumentObjectGroup', 'Wires')\nhwires = doc.addObject('App::DocumentObjectGroup', 'HWires')\nvwires = doc.addObject('App::DocumentObjectGroup', 'VWires')\nwiregroup.addObjects([hwires, vwires])\n\nfor wg, step, getter in ((hwires, hstep, 'y'),\n                         (vwires, vstep, 'x')):\n    wires = list()\n    empty = False\n    cc = bb.YMin if getter == 'y' else bb.XMin\n    cc -= step/2\n    while not empty:\n        polypoints = list()\n        for pt in points:\n            value = getattr(pt, getter)\n            if cc < value < cc + step:\n                polypoints.append(pt)\n        if polypoints:\n            if o['MakeWires'] or (o['MakeBSurf'] and not o['MakeWFrame']):\n                maker = Draft.make_wire\n            elif o['MakeBSplines']:\n                maker = Draft.make_bspline\n            wires.append(maker(polypoints, closed=False))\n            cc += step\n        else:\n            empty = True\n\n    wg.addObjects(wires)\n\nGui.Selection.clearSelection()\n\nif o['MakeBSurf']:\n    degree_u = degree_v = 3\n    periodic = False\n\n    lowerx, lowery = hwires.Group[0], vwires.Group[0]\n    x = np.array([pt.x for pt in lowerx.Points])\n    y = np.array([pt.y for pt in lowery.Points])\n    Z = np.array([[pt.z for pt in hw.Points] for hw in hwires.Group])\n\n    ## Create spline surface\n    g = interpolate.RectBivariateSpline(x, y, Z.T)\n    coefgs = g.get_coeffs()\n    coefgs = np.reshape(coefgs, Z.T.shape).T\n    knots = g.get_knots()\n    # Convert knot vector format\n    knot_u, mult_u = np.unique(knots[1], return_counts=True)\n    knot_v, mult_v = np.unique(knots[0], return_counts=True)\n    # Normalize knot vectors\n    knot_u = (knot_u - knot_u.min()) / (knot_u.max() - knot_u.min())\n    knot_v = (knot_v - knot_v.min()) / (knot_v.max() - knot_v.min())\n    \n    # Calculate spline coefficients for x and y\n    gx = interpolate.make_interp_spline(x, x)\n    coefgx = gx.tck[1]\n    gy = interpolate.make_interp_spline(y, y)\n    coefgy = gy.tck[1]\n\n    getVector = lambda iz, jz: Vector(coefgx[jz],\n                                      coefgy[iz],\n                                      coefgs[iz, jz])\n\n    # Create control point vectors\n    ctrl = [[getVector(iZ, jZ) for jZ, lc in enumerate(lr)]\n            for iZ, lr in enumerate(coefgs)]\n    \n    # Create spline surface in FreeCAD\n    bs = Part.BSplineSurface()\n    bs.buildFromPolesMultsKnots(ctrl, mult_u, mult_v, knot_u, knot_v,\n                                periodic, periodic, degree_u, degree_v)\n    \n    surf = Part.show(bs.toShape(), 'BSplineSurf')\n    surf.Label2 = 'spline surface through points'\n    surf.ViewObject.ShapeColor = RGB(0, 170, 255)\n\n    if not o['MakeWFrame']:\n        for obj in hwires.Group + vwires.Group + [hwires, vwires, wiregroup]:\n            doc.removeObject(obj.Name)\n\n\ndoc.recompute()\n\nav = Gui.ActiveDocument.ActiveView\nav.viewIsometric()\nav.fitAll()\n\n",
    "url": "https://wiki.freecad.org/Macro_BSurf_from_grid",
    "raw_code_url": "",
    "wiki": "https://wiki.freecad.org/Macro_Grid_2_BSurf",
    "version": "0.1",
    "license": "",
    "date": "2022-07-31",
    "src_filename": "",
    "filename_from_url": "",
    "author": "heda",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Circle",
    "on_wiki": true,
    "on_git": false,
    "desc": "Creates a circle or arc giving radius, diameter, circumference, area, startangle, endangle, arc, anglecenter, cord, arrow, center (point), placemObject on choice (without GUI). The new circle is created in the real coordinate of object, not in the coordinate of the Body.<br /><span style=\"background-color: #ffeeee\">(Command line, paste this complete macro in the Python console)</span>.<br /><br />Macro version: 0.4<br />Last modified: 2019-06-19<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/9/9d/Macro_Circle.png\">ToolBar Icon</a><br />Author: mario52<br /> ",
    "comment": "Creates a circle or arc giving radius, diameter, circumference, area, startangle, endangle, arc, anglecenter, cord, arrow, center (point), placemObject on choice (without GUI). The new circle is created in the real coordinate of object, not in the coordinate of the Body.",
    "code": "#-*- coding: utf-8 -*-\n#from math import sqrt, pi\n# creer un cercle ou un arc entierement parametrabel en utilisant :\n# create a circle or arc fully parametrabel using:\n#\n# paste the complete macro in the Python console\n#\n# x x x coordinates\n#with radius\n#with diameter\n#with circumference\n#with area\n#with startangle\n#with endangle\n#with [arc and anglecenter]      in combination (angle in degrees)\n#with [cord and arrow]           in combination\n#with center (if center as different 0 one point is created on center of circle)\n#give placemObject  \n# ex :pl=FreeCAD.Placement()\n#     pl.Rotation.Q=(0.0,-0.0,-0.0,1.0)\n#     pl.Base=FreeCAD.Vector(-1.89847898483,-0.490152746439,0.0)\n#     placemObject = pl\n# s'il n'y a pas de parametre \"circle()\" une liste des fonctions s'affiche dans la Vue rapport\n# if there is no parameter \"circle()\" a list of functions is displayed in the report view\n\n__title__   = \"circle\"\n__author__  = \"Mario52\"\n__version__ = \"0.4\"\n__date__    = \"19/06/2019\"\n\nimport Draft #, Part\nimport FreeCAD\nApp = FreeCAD\n\ndef circle(x=0.0,y=0.0,z=0.0,radius=0.0,diameter=0.0,circumference=0.0,area=0.0,startangle=0.0,endangle=0.0,arc=0.0,anglecenter=0.0,cord=0.0,arrow=0.0,center=0,placemObject=\"\"):\n    from math import sqrt, pi\n    if placemObject == \"\":\n        pl = FreeCAD.Placement()\n        pl.Rotation = FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation()   \n        pl.Base = FreeCAD.Vector(x,y,z)\n    else:\n        pl = FreeCAD.Placement()\n        pl = placemObject                                  # placement imposted\n    if diameter != 0:                                      # with diameter\n        radius = diameter / 2.0\n    elif circumference != 0:                               # with circumference\n        radius = (circumference / pi) / 2.0\n    elif area != 0:                                        # with area\n        radius =  sqrt((area / pi))\n    elif (cord != 0) and (arrow != 0):                     # with cord and arrow\n        radius = ((arrow**2) + (cord**2) / 4.0) / (arrow*2) \n    elif (arc != 0) and (anglecenter != 0):                # with arc and anglecenter central in degrees\n        radius = ((360/anglecenter)*arc) / pi/2.0\n        if endangle != 0:\n            startangle  = endangle - anglecenter\n        endangle   = anglecenter + startangle\n        startangle  = endangle - anglecenter\n    if radius != 0:\n        try:\n            Draft.makeCircle(radius,placement=pl,face=False,startangle=startangle,endangle=endangle,support=None)\n            if center != 0:\n                x=pl.Base.x\n                y=pl.Base.y\n                z=pl.Base.z\n                Draft.makePoint(x,y,z)\n            \n        except Exception:\n            App.Console.PrintError(\"Unexpected keyword argument\" + \"\\n\")\n        App.ActiveDocument.recompute()\n    else:\n        App.Console.PrintMessage(\"Unexpected keyword argument\" + \"\\n\")\n        App.Console.PrintMessage(\"circle(x,y,z,radius,diameter,circumference,area,startangle,endangle,[arc,anglecenter],[cord,arrow],center,placemObject)\" + \"\\n\")\n        App.Console.PrintMessage(\"circle(radius=10.0,placemObject=App.Placement(App.Vector(11,20,30), App.Rotation(30,40,0), App.Vector(0,0,0)))\" + \"\\n\")\n#example\n#circle(arc=50,anglecenter=20,center=1)\n#circle(x=10.0,y=10.0,z=10.0,radius=10.0)\n#circle(radius=10.0,center=1,placemObject=App.Placement(App.Vector(11,20,30), App.Rotation(30,40,0), App.Vector(0,0,0)))",
    "url": "https://wiki.freecad.org/Macro_Circle",
    "raw_code_url": "",
    "wiki": "",
    "version": "0.4",
    "license": "",
    "date": "19/06/2019",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Circle.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/9/9d/Macro_Circle.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "CirclePlus",
    "on_wiki": true,
    "on_git": false,
    "desc": "Creates circle or arc giving radius, diameter, circumference, area, startangle, endangle, arc, anglecenter, cord, arrow, center (point), placemObject on choice (With GUI)<br /><br />Macro version: 0.4<br />Last modified: 2019/04/07<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/4/4c/Macro_CirclePlus.png\">ToolBar Icon</a>.<br />Author: mario52<br /> ",
    "comment": "Creates circle or arc giving radius, diameter, circumference, area, startangle, endangle, arc, anglecenter, cord, arrow, center (point), placemObject on choice (With GUI)",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n#\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2018 2019 <mario52>                                     *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#Circle_Plus 2018/07/10 2018/07/14 2019/04/05 (incrementDS) 2019/04/06 2019/04/07\n#\n#OS: Windows 10\n#Word size of OS: 64-bit\n#Word size of FreeCAD: 64-bit\n#Version: 0.18.16093 (Git)\n#Build type: Release\n#Branch: releases/FreeCAD-0-18\n#Hash: 690774c0effe4fd7b8d2b5e2fb2b8c8d145e21ce\n#Python version: 2.7.14\n#Qt version: 4.8.7\n#Coin version: 4.0.0a\n#OCC version: 7.2.0\n#\n__title__   = \"CirclePlus\"\n__author__  = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__Wiki__    = \"http://www.freecadweb.org/wiki/index.php?title=Macro_CirclePlus\"\n__version__ = \"00.04\"\n__date__    = \"2019/04/07\"\n\nimport PySide\nfrom PySide import QtGui ,QtCore\nfrom PySide.QtGui import *\nfrom PySide.QtCore import *\n\nimport pivy\nfrom pivy import coin\nimport OpenSCAD2Dgeom\n\nimport time\nimport Draft, Part, PartGui, FreeCADGui, FreeCAD\nfrom FreeCAD import Base\nimport math\nfrom math import sqrt, pi, sin, cos, asin\n\nGui = FreeCADGui\nApp = FreeCAD\n\n############################\n# create a circle or arc fully parametrabel using:\n# x x x coordinates\n#with radius\n#with diameter\n#with circumference\n#with area\n#with startangle\n#with endangle\n#with [arc and anglecenter]      in combination (angle in degrees)\n#with [cord and arrow]           in combination\n############################\n\n#### Config begin ####\nglobal decimales  ; decimales   = 4\nglobal incrementDS; incrementDS = 1.0 # 0.1    # step for increment on begin \n\n#### Config end ######\n\nglobal ui         ; ui         = \"\"\nglobal s          ; s          = \"\"\nglobal sourisPass ; sourisPass = 0\n\nglobal positionX  ; positionX = 0.0\nglobal positionY  ; positionY = 0.0\nglobal positionZ  ; positionZ = 0.0\n\n\nclass Ui_MainWindow(object):\n\n    def __init__(self ):\n        self.window = MainWindow\n        #self.path  = FreeCAD.ConfigGet(\"AppHomePath\")\n        #self.path  = FreeCAD.ConfigGet(\"UserAppData\")\n        #self.path  = \"your path\"\n        param = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")# macro path\n        self.path = param.GetString(\"MacroPath\",\"\") + \"/\"                        # macro path\n        self.path = self.path.replace(\"\\\\\",\"/\")\n#        print \"Path for the icons : \" , self.path\n\n        self.PointSize     = 8    #heigth text\n\n        self.Radius        = 0.0\n        self.Diameter      = self.Radius * 2.0\n        self.Circumference = 0.0\n        self.Area          = 0.0\n        self.StartAngle    = 0.0\n        self.EndAngle      = 0.0\n        self.Arc           = 0.0\n        self.AngleCenter   = 0.0\n        self.Cord          = 0.0\n        self.Arrow         = 0.0\n        self.Face          = False\n\n        self.vueActive = FreeCADGui.ActiveDocument.ActiveView\n        self.click = self.vueActive.addEventCallback(\"SoMouseButtonEvent\",self.souris)\n\n    def souris(self,info):\n        global sourisPass\n        global positionX\n        global positionY\n        global positionZ\n        if (info[\"Button\"] == \"BUTTON1\") and (info[\"State\"] == \"DOWN\"):\n            sourisPass = 0\n            positionX = positionY = positionZ = 0.0\n            self.DS_01_Coord_X.setValue(positionX)\n            self.DS_02_Coord_Y.setValue(positionY)\n            self.DS_03_Coord_Z.setValue(positionZ)\n\n    def setupUi(self, MainWindow):\n        global decimales\n        global incrementDS\n\n        self.window = MainWindow\n        MainWindow.setObjectName(\"MainWindow\")\n        MainWindow.resize(226, 295)\n\n        self.centralwidget = QtGui.QWidget(MainWindow)\n        self.centralwidget.setObjectName(\"centralwidget\")\n\n        ############################################\n        self.fontGlobal_08 = QtGui.QFont()               # Windows Linux pour tous les textes\n        self.fontGlobal_08.setFamily(\"Arial\")            # Windows Linux pour tous les textes\n        self.fontGlobal_08.setPointSize(self.PointSize)  # Windows Linux pour tous les textes\n        #self.xxxxx.setFont(self.fontGlobal_08)                           # Windows Linux\n        #self.xxxxx.setFont(QtGui.QFont(\"\",weight=QtGui.QFont.Bold))      # Windows Linux Bold\n        #self.xxxxx.setStyleSheet(\"color: red; font: bold \"+str(self.PointSize+3)+\"px;\")# Bold\n        #self.xxxxx.setIcon(QtGui.QIcon.fromTheme(\"media-playback-start\"))         # icone resource\n        ############################################\n\n        self.GBox_01_Coordinate = QtGui.QGroupBox(self.centralwidget)\n        self.GBox_01_Coordinate.setGeometry(QtCore.QRect(5, 10, 216, 181))\n        self.GBox_01_Coordinate.setFont(self.fontGlobal_08)               # Windows Linux\n        self.GBox_01_Coordinate.setObjectName(\"GBox_01_Coordinate\")\n\n        self.DS_01_Coord_X = QtGui.QDoubleSpinBox(self.GBox_01_Coordinate)\n        self.DS_01_Coord_X.setGeometry(QtCore.QRect(10, 20, 91, 22))\n        self.DS_01_Coord_X.setFont(self.fontGlobal_08)                    # Windows Linux\n        self.DS_01_Coord_X.setObjectName(\"DS_01_Coord_X\")\n        self.DS_01_Coord_X.setDecimals(decimales)\n        self.DS_01_Coord_X.setMinimum(-9999999.9999999)\n        self.DS_01_Coord_X.setMaximum(9999999.9999999)\n        self.DS_01_Coord_X.setSuffix(\" mm\")\n        self.DS_01_Coord_X.setWrapping(True)\n        self.DS_01_Coord_X.setAccelerated(True)\n        self.DS_01_Coord_X.valueChanged.connect(self.on_DS_01_Coord_X_valueChanged)\n\n        self.label_01_X = QtGui.QLabel(self.GBox_01_Coordinate)\n        self.label_01_X.setGeometry(QtCore.QRect(110, 25, 51, 16))\n        self.label_01_X.setFont(self.fontGlobal_08)                       # Windows Linux\n        self.label_01_X.setObjectName(\"label_01_X\")\n\n        self.DS_02_Coord_Y = QtGui.QDoubleSpinBox(self.GBox_01_Coordinate)\n        self.DS_02_Coord_Y.setGeometry(QtCore.QRect(10, 50, 91, 22))\n        self.DS_02_Coord_Y.setFont(self.fontGlobal_08)                    # Windows Linux\n        self.DS_02_Coord_Y.setObjectName(\"DS_02_Coord_Y\")\n        self.DS_02_Coord_Y.setDecimals(decimales)\n        self.DS_02_Coord_Y.setMinimum(-9999999.9999999)\n        self.DS_02_Coord_Y.setMaximum(9999999.9999999)\n        self.DS_02_Coord_Y.setSuffix(\" mm\")\n        self.DS_02_Coord_Y.setWrapping(True)\n        self.DS_02_Coord_Y.setAccelerated(True)\n        self.DS_02_Coord_Y.valueChanged.connect(self.on_DS_02_Coord_Y_valueChanged)\n\n        self.label_02_Y = QtGui.QLabel(self.GBox_01_Coordinate)\n        self.label_02_Y.setGeometry(QtCore.QRect(110, 55, 16, 16))\n        self.label_02_Y.setFont(self.fontGlobal_08)                       # Windows Linux\n        self.label_02_Y.setObjectName(\"label_02_Y\")\n\n        self.DS_03_Coord_Z = QtGui.QDoubleSpinBox(self.GBox_01_Coordinate)\n        self.DS_03_Coord_Z.setGeometry(QtCore.QRect(10, 80, 91, 22))\n        self.DS_03_Coord_Z.setFont(self.fontGlobal_08)                    # Windows Linux\n        self.DS_03_Coord_Z.setObjectName(\"DS_03_Coord_Z\")\n        self.DS_03_Coord_Z.setDecimals(decimales)\n        self.DS_03_Coord_Z.setMinimum(-9999999.9999999)\n        self.DS_03_Coord_Z.setMaximum(9999999.9999999)\n        self.DS_03_Coord_Z.setSuffix(\" mm\")\n        self.DS_03_Coord_Z.setWrapping(True)\n        self.DS_03_Coord_Z.setAccelerated(True)\n        self.DS_03_Coord_Z.valueChanged.connect(self.on_DS_03_Coord_Z_valueChanged)\n\n        self.label_03_Z = QtGui.QLabel(self.GBox_01_Coordinate)\n        self.label_03_Z.setGeometry(QtCore.QRect(110, 85, 16, 16))\n        self.label_03_Z.setFont(self.fontGlobal_08)                       # Windows Linux\n        self.label_03_Z.setObjectName(\"label_03_Z\")\n\n        self.PB_03_Reset_Coordinate = QtGui.QPushButton(self.GBox_01_Coordinate)\n        self.PB_03_Reset_Coordinate.setGeometry(QtCore.QRect(160, 20, 41, 83))\n        self.PB_03_Reset_Coordinate.setFont(self.fontGlobal_08)           # Windows Linux\n        self.PB_03_Reset_Coordinate.setObjectName(\"PB_03_Reset_Coordinate\")\n        self.PB_03_Reset_Coordinate.setIcon(QtGui.QIcon.fromTheme(\"view-refresh\"))# icone resource\n        self.PB_03_Reset_Coordinate.clicked.connect(self.on_PB_03_Reset_Coordinate_clicked)\n\n        self.PB_03_Egual = QtGui.QPushButton(self.GBox_01_Coordinate)\n        self.PB_03_Egual.setGeometry(QtCore.QRect(160, 20, 15, 15))\n        self.PB_03_Egual.setFont(self.fontGlobal_08)                      # Windows Linux\n        self.PB_03_Egual.setObjectName(\"PB_03_Egual\")\n        self.PB_03_Egual.clicked.connect(self.on_PB_03_Egual_clicked)\n\n        self.DS_04_Radius = QtGui.QDoubleSpinBox(self.GBox_01_Coordinate)\n        self.DS_04_Radius.setGeometry(QtCore.QRect(10, 115, 91, 22))\n        self.DS_04_Radius.setFont(self.fontGlobal_08)                     # Windows Linux\n        self.DS_04_Radius.setObjectName(\"DS_04_Radius\")\n        self.DS_04_Radius.setDecimals(decimales)\n        self.DS_04_Radius.setSingleStep(incrementDS)\n        self.DS_04_Radius.setMinimum(0.0)\n        self.DS_04_Radius.setMaximum(9999999.9999999)\n        self.DS_04_Radius.setSuffix(\" mm\")\n        self.DS_04_Radius.setWrapping(True)\n        self.DS_04_Radius.setAccelerated(True)\n        self.DS_04_Radius.setValue(self.Radius)\n        self.DS_04_Radius.valueChanged.connect(self.on_DS_04_Radius_valueChanged)\n\n        self.label_DS_04_Radius = QtGui.QLabel(self.GBox_01_Coordinate)\n        self.label_DS_04_Radius.setGeometry(QtCore.QRect(110, 115, 91, 22))\n        self.label_DS_04_Radius.setFont(self.fontGlobal_08)                  # Windows Linux\n        self.label_DS_04_Radius.setObjectName(\"label_DS_04_Radius\")\n\n        self.DS_05_Diameter = QtGui.QDoubleSpinBox(self.GBox_01_Coordinate)\n        self.DS_05_Diameter.setGeometry(QtCore.QRect(10, 145, 91, 22))\n        self.DS_05_Diameter.setFont(self.fontGlobal_08)                   # Windows Linux\n        self.DS_05_Diameter.setObjectName(\"DS_05_Diameter\")\n        self.DS_05_Diameter.setDecimals(decimales)\n        self.DS_05_Diameter.setSingleStep(incrementDS)\n        self.DS_05_Diameter.setMinimum(0.0)\n        self.DS_05_Diameter.setMaximum(9999999.9999999)\n        self.DS_05_Diameter.setSuffix(\" mm\")\n        self.DS_05_Diameter.setWrapping(True)\n        self.DS_05_Diameter.setAccelerated(True)\n        self.DS_05_Diameter.setValue(self.Diameter)\n        self.DS_05_Diameter.valueChanged.connect(self.on_DS_05_Diameter_valueChanged)\n\n        self.label_DS_05_Diameter = QtGui.QLabel(self.GBox_01_Coordinate)\n        self.label_DS_05_Diameter.setGeometry(QtCore.QRect(110, 145, 91, 22))\n        self.label_DS_05_Diameter.setFont(self.fontGlobal_08)                # Windows Linux\n        self.label_DS_05_Diameter.setObjectName(\"label_DS_05_Diameter\")\n\n        ####\n        self.GBox_02_Options = QtGui.QGroupBox(self.centralwidget)\n        self.GBox_02_Options.setGeometry(QtCore.QRect(5, 195, 216, 21))\n        self.GBox_02_Options.setFont(self.fontGlobal_08)                  # Windows Linux\n        self.GBox_02_Options.setCheckable(True)\n        self.GBox_02_Options.setChecked(False)\n        self.GBox_02_Options.setObjectName(\"GBox_02_Options\")\n        self.GBox_02_Options.clicked.connect(self.on_GBox_02_Options)\n\n        self.DS_06_Circumference = QtGui.QDoubleSpinBox(self.GBox_02_Options)\n        self.DS_06_Circumference.setGeometry(QtCore.QRect(10, 25, 91, 22))\n        self.DS_06_Circumference.setFont(self.fontGlobal_08)              # Windows Linux\n        self.DS_06_Circumference.setObjectName(\"DS_06_Circumference\")\n        self.DS_06_Circumference.setDecimals(decimales)\n        self.DS_06_Circumference.setSingleStep(incrementDS)\n        self.DS_06_Circumference.setMinimum(0.0)\n        self.DS_06_Circumference.setMaximum(9999999.9999999)\n        self.DS_06_Circumference.setSuffix(\" mm\")\n        self.DS_06_Circumference.setWrapping(True)\n        self.DS_06_Circumference.setAccelerated(True)\n        self.DS_06_Circumference.setValue(0.0)\n        self.DS_06_Circumference.valueChanged.connect(self.on_DS_06_Circumference_valueChanged)\n\n        self.label_06_Circumference = QtGui.QLabel(self.GBox_02_Options)\n        self.label_06_Circumference.setGeometry(QtCore.QRect(110, 25, 91, 22))\n        self.label_06_Circumference.setFont(self.fontGlobal_08)           # Windows Linux\n        self.label_06_Circumference.setObjectName(\"label_06_Circumference\")\n\n        self.DS_07_Area = QtGui.QDoubleSpinBox(self.GBox_02_Options)\n        self.DS_07_Area.setGeometry(QtCore.QRect(10, 55, 91, 22))\n        self.DS_07_Area.setFont(self.fontGlobal_08)                       # Windows Linux\n        self.DS_07_Area.setObjectName(\"DS_07_Area\")\n        self.DS_07_Area.setDecimals(decimales)\n        self.DS_07_Area.setSingleStep(incrementDS)\n        self.DS_07_Area.setMinimum(0.0)\n        self.DS_07_Area.setMaximum(9999999.9999999)\n        self.DS_07_Area.setSuffix(\" mm2\")\n        self.DS_07_Area.setWrapping(True)\n        self.DS_07_Area.setAccelerated(True)\n        self.DS_07_Area.valueChanged.connect(self.on_DS_07_Area_valueChanged)\n\n        self.label_07_Area = QtGui.QLabel(self.GBox_02_Options)\n        self.label_07_Area.setGeometry(QtCore.QRect(110, 55, 91, 22))\n        self.label_07_Area.setFont(self.fontGlobal_08)                    # Windows Linux\n        self.label_07_Area.setObjectName(\"label_07_Area\")\n\n        self.DS_08_StartAngle = QtGui.QDoubleSpinBox(self.GBox_02_Options)\n        self.DS_08_StartAngle.setGeometry(QtCore.QRect(10, 85, 91, 22))\n        self.DS_08_StartAngle.setFont(self.fontGlobal_08)                 # Windows Linux\n        self.DS_08_StartAngle.setObjectName(\"DS_08_StartAngle\")\n        self.DS_08_StartAngle.setDecimals(decimales)\n        self.DS_08_StartAngle.setSingleStep(incrementDS)\n        self.DS_08_StartAngle.setMinimum(-360.0)\n        self.DS_08_StartAngle.setMaximum(360.0)\n        self.DS_08_StartAngle.setSuffix(\" deg\")\n        self.DS_08_StartAngle.setWrapping(True)\n        self.DS_08_StartAngle.setAccelerated(True)\n        self.DS_08_StartAngle.valueChanged.connect(self.on_DS_08_StartAngle_valueChanged)\n\n        self.label_08_StartAngle = QtGui.QLabel(self.GBox_02_Options)\n        self.label_08_StartAngle.setGeometry(QtCore.QRect(110, 85, 91, 22))\n        self.label_08_StartAngle.setFont(self.fontGlobal_08)              # Windows Linux\n        self.label_08_StartAngle.setObjectName(\"label_08_StartAngle\")\n\n        self.DS_09_EndAngle = QtGui.QDoubleSpinBox(self.GBox_02_Options)\n        self.DS_09_EndAngle.setGeometry(QtCore.QRect(10, 115, 91, 22))\n        self.DS_09_EndAngle.setFont(self.fontGlobal_08)                   # Windows Linux\n        self.DS_09_EndAngle.setObjectName(\"DS_09_EndAngle\")\n        self.DS_09_EndAngle.setDecimals(decimales)\n        self.DS_09_EndAngle.setSingleStep(incrementDS)\n        self.DS_09_EndAngle.setMinimum(-360.0)\n        self.DS_09_EndAngle.setMaximum(360.0)\n        self.DS_09_EndAngle.setSuffix(\" deg\")\n        self.DS_09_EndAngle.setWrapping(True)\n        self.DS_09_EndAngle.setAccelerated(True)\n        self.DS_09_EndAngle.valueChanged.connect(self.on_DS_09_EndAngle_valueChanged)\n\n        self.label_09_EndAngle = QtGui.QLabel(self.GBox_02_Options)\n        self.label_09_EndAngle.setGeometry(QtCore.QRect(110, 115, 91, 22))\n        self.label_09_EndAngle.setFont(self.fontGlobal_08)                # Windows Linux\n        self.label_09_EndAngle.setObjectName(\"label_09_EndAngle\")\n\n        self.DS_10_Arc = QtGui.QDoubleSpinBox(self.GBox_02_Options)\n        self.DS_10_Arc.setGeometry(QtCore.QRect(10, 145, 91, 22))\n        self.DS_10_Arc.setFont(self.fontGlobal_08)                        # Windows Linux\n        self.DS_10_Arc.setObjectName(\"DS_10_Arc\")\n        self.DS_10_Arc.setDecimals(decimales)\n        self.DS_10_Arc.setSingleStep(incrementDS)\n        self.DS_10_Arc.setMinimum(0.0)\n        self.DS_10_Arc.setMaximum(9999999.9999999)\n        self.DS_10_Arc.setSuffix(\" mm\")\n        self.DS_10_Arc.setWrapping(True)\n        self.DS_10_Arc.setAccelerated(True)\n        self.DS_10_Arc.valueChanged.connect(self.on_DS_10_Arc_valueChanged)\n\n        self.label_10_Arc = QtGui.QLabel(self.GBox_02_Options)\n        self.label_10_Arc.setGeometry(QtCore.QRect(110, 145, 91, 22))\n        self.label_10_Arc.setFont(self.fontGlobal_08)                     # Windows Linux\n        self.label_10_Arc.setObjectName(\"label_10_Arc\")\n\n        self.DS_11_AngleCenter = QtGui.QDoubleSpinBox(self.GBox_02_Options)\n        self.DS_11_AngleCenter.setGeometry(QtCore.QRect(10, 175, 91, 22))\n        self.DS_11_AngleCenter.setFont(self.fontGlobal_08)                # Windows Linux\n        self.DS_11_AngleCenter.setObjectName(\"DS_11_AngleCenter\")\n        self.DS_11_AngleCenter.setDecimals(decimales)\n        self.DS_11_AngleCenter.setSingleStep(incrementDS)\n        self.DS_11_AngleCenter.setMinimum(0.0)\n        self.DS_11_AngleCenter.setMaximum(360.0)\n        self.DS_11_AngleCenter.setSuffix(\" deg\")\n        self.DS_11_AngleCenter.setWrapping(True)\n        self.DS_11_AngleCenter.setAccelerated(True)\n        self.DS_11_AngleCenter.valueChanged.connect(self.on_DS_11_AngleCenter_valueChanged)\n\n        self.label_11_AngleCenter = QtGui.QLabel(self.GBox_02_Options)\n        self.label_11_AngleCenter.setGeometry(QtCore.QRect(110, 175, 91, 22))\n        self.label_11_AngleCenter.setFont(self.fontGlobal_08)             # Windows Linux\n        self.label_11_AngleCenter.setObjectName(\"label_11_AngleCenter\")\n\n        self.DS_12_Cord = QtGui.QDoubleSpinBox(self.GBox_02_Options)\n        self.DS_12_Cord.setGeometry(QtCore.QRect(10, 205, 91, 22))\n        self.DS_12_Cord.setFont(self.fontGlobal_08)                       # Windows Linux\n        self.DS_12_Cord.setObjectName(\"DS_12_Cord\")\n        self.DS_12_Cord.setDecimals(decimales)\n        self.DS_12_Cord.setSingleStep(incrementDS)\n        self.DS_12_Cord.setMinimum(0.0)\n        self.DS_12_Cord.setMaximum(9999999.9999999)\n        self.DS_12_Cord.setSuffix(\" mm\")\n        self.DS_12_Cord.setWrapping(True)\n        self.DS_12_Cord.setAccelerated(True)\n        self.DS_12_Cord.valueChanged.connect(self.on_DS_12_Cord_valueChanged)\n\n        self.label_12_Cord = QtGui.QLabel(self.GBox_02_Options)\n        self.label_12_Cord.setGeometry(QtCore.QRect(110, 205, 91, 22))\n        self.label_12_Cord.setFont(self.fontGlobal_08)                    # Windows Linux\n        self.label_12_Cord.setObjectName(\"label_12_Cord\")\n\n        self.DS_13_Arrow = QtGui.QDoubleSpinBox(self.GBox_02_Options)\n        self.DS_13_Arrow.setGeometry(QtCore.QRect(10, 235, 91, 22))\n        self.DS_13_Arrow.setFont(self.fontGlobal_08)                      # Windows Linux\n        self.DS_13_Arrow.setObjectName(\"DS_13_Arrow\")\n        self.DS_13_Arrow.setDecimals(decimales)\n        self.DS_13_Arrow.setSingleStep(incrementDS)\n        self.DS_13_Arrow.setMinimum(0.0)\n        self.DS_13_Arrow.setMaximum(9999999.9999999)\n        self.DS_13_Arrow.setSuffix(\" mm\")\n        self.DS_13_Arrow.setWrapping(True)\n        self.DS_13_Arrow.setAccelerated(True)\n        self.DS_13_Arrow.valueChanged.connect(self.on_DS_13_Arrow_valueChanged)\n\n        self.label_13_Arrow = QtGui.QLabel(self.GBox_02_Options)\n        self.label_13_Arrow.setGeometry(QtCore.QRect(110, 235, 91, 22))\n        self.label_13_Arrow.setFont(self.fontGlobal_08)                   # Windows Linux\n        self.label_13_Arrow.setObjectName(\"label_13_Arrow\")\n\n        ####\n        self.CB_01_Center = QtGui.QCheckBox(self.centralwidget)\n        self.CB_01_Center.setGeometry(QtCore.QRect(5, 220, 61, 18))\n        self.CB_01_Center.setFont(self.fontGlobal_08)                     # Windows Linux\n        self.CB_01_Center.setObjectName(\"CB_01_Center\")\n        self.CB_01_Center.setChecked(False)\n#        self.CB_01_Center.clicked.connect(self.on_CB_01_Center_clicked)\n\n        self.CB_02_Info = QtGui.QCheckBox(self.centralwidget)\n        self.CB_02_Info.setGeometry(QtCore.QRect(90, 220, 61, 18))\n        self.CB_02_Info.setFont(self.fontGlobal_08)                       # Windows Linux\n        self.CB_02_Info.setObjectName(\"CB_02_Info\")\n        self.CB_02_Info.setChecked(False)\n#        self.CB_02_Info.clicked.connect(self.on_CB_02_Info_clicked)\n\n        self.CB_03_Face = QtGui.QCheckBox(self.centralwidget)\n        self.CB_03_Face.setGeometry(QtCore.QRect(170, 220, 61, 18))\n        self.CB_03_Face.setFont(self.fontGlobal_08)                       # Windows Linux\n        self.CB_03_Face.setObjectName(\"CB_03_Face\")\n        self.CB_03_Face.setChecked(False)\n#        self.CB_03_Face.clicked.connect(self.on_CB_03_Face_clicked)\n\n        self.CB_04_Sector = QtGui.QCheckBox(self.centralwidget)\n        self.CB_04_Sector.setGeometry(QtCore.QRect(5, 240, 61, 18))\n        self.CB_04_Sector.setFont(self.fontGlobal_08)                     # Windows Linux\n        self.CB_04_Sector.setObjectName(\"CB_04_Sector\")\n        self.CB_04_Sector.setChecked(False)\n#        self.CB_04_Sector.clicked.connect(self.on_CB_04_Sector_clicked)\n\n        self.CB_05_Segment = QtGui.QCheckBox(self.centralwidget)\n        self.CB_05_Segment.setGeometry(QtCore.QRect(90, 240, 61, 18))\n        self.CB_05_Segment.setFont(self.fontGlobal_08)                     # Windows Linux\n        self.CB_05_Segment.setObjectName(\"CB_05_Segment\")\n        self.CB_05_Segment.setChecked(False)\n#        self.CB_05_Segment.clicked.connect(self.on_CB_05_Segment_clicked)\n\n#        self.CB_06_incrementDS = QtGui.QCheckBox(self.centralwidget)\n#        self.CB_06_incrementDS.setGeometry(QtCore.QRect(170, 240, 61, 18))\n#        self.CB_06_incrementDS.setFont(self.fontGlobal_08)                     # Windows Linux\n#        self.CB_06_incrementDS.setObjectName(\"CB_06_incrementDS\")\n#        self.CB_06_incrementDS.setText(\"(\" + str(incrementDS) + \")\")\n#        self.CB_06_incrementDS.setChecked(False)\n#        self.CB_06_incrementDS.clicked.connect(self.on_CB_06_incrementDS_clicked)\n\n        self.DS_06_incrementDS = QtGui.QDoubleSpinBox(self.centralwidget)\n        self.DS_06_incrementDS.setGeometry(QtCore.QRect(170, 240, 50, 18))\n        self.DS_06_incrementDS.setFont(self.fontGlobal_08)                        # Windows Linux\n        self.DS_06_incrementDS.setObjectName(\"DS_06_incrementDS\")\n        self.DS_06_incrementDS.setDecimals(3)\n        self.DS_06_incrementDS.setSingleStep(0.01)    #0.001\n        self.DS_06_incrementDS.setMinimum(0.0)\n        self.DS_06_incrementDS.setMaximum(9999999.9999999)\n        self.DS_06_incrementDS.setValue(incrementDS)\n        self.DS_06_incrementDS.setWrapping(True)\n        self.DS_06_incrementDS.setAccelerated(True)\n        self.DS_06_incrementDS.valueChanged.connect(self.on_DS_06_incrementDS_clicked)\n\n        self.SP_01_Caracter = QtGui.QDoubleSpinBox(self.centralwidget)\n        self.SP_01_Caracter.setGeometry(QtCore.QRect(5, 265, 50, 22))\n        self.SP_01_Caracter.setFont(self.fontGlobal_08)                   # Windows Linux\n        self.SP_01_Caracter.setObjectName(\"SP_01_Caracter\")\n        self.SP_01_Caracter.setMinimum(0.0)\n        self.SP_01_Caracter.setMaximum(9999999)\n        self.SP_01_Caracter.setValue(self.PointSize)\n        self.SP_01_Caracter.valueChanged.connect(self.on_SP_01_Caracter_valueChanged)\n\n        self.PB_01_Quit = QtGui.QPushButton(self.centralwidget)\n        self.PB_01_Quit.setGeometry(QtCore.QRect(115, 265, 50, 23))\n        self.PB_01_Quit.setFont(self.fontGlobal_08)                       # Windows Linux\n        self.PB_01_Quit.setObjectName(\"PB_01_Quit\")\n        self.PB_01_Quit.setIcon(QtGui.QIcon.fromTheme(\"application-exit\"))        # icone resource\n        self.PB_01_Quit.clicked.connect(self.on_PB_01_Quit_clicked)\n\n        self.PB_02_Create = QtGui.QPushButton(self.centralwidget)\n        self.PB_02_Create.setGeometry(QtCore.QRect(170, 265, 50, 23))\n        self.PB_02_Create.setFont(self.fontGlobal_08)                     # Windows Linux\n        self.PB_02_Create.setObjectName(\"PB_02_Create\")\n        self.PB_02_Create.setIcon(QtGui.QIcon.fromTheme(\"media-playback-start\"))  # icone resource\n        self.PB_02_Create.clicked.connect(self.on_PB_02_Create_clicked)\n\n        MainWindow.setCentralWidget(self.centralwidget)\n\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n        MainWindow.setWindowIcon(QtGui.QIcon(self.path + 'Macro_CirclePlus.png')) # change l'icone de la fenetre principale\n        MainWindow.setWindowTitle(__title__+\" (\"+__version__+\", \"+__date__+\")\")\n        MainWindow.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint)\n\n        self.GBox_01_Coordinate.setTitle(\"Coordinate (v.\"+__version__+\")\")\n        self.label_01_X.setText(\"X\")\n        self.label_01_X.setStyleSheet(\"color: red; font: bold \"+str(self.PointSize+3)+\"px;\")\n        self.label_02_Y.setText(\"Y\")\n        self.label_02_Y.setStyleSheet(\"color: green; font: bold \"+str(self.PointSize+3)+\"px;\")\n        self.label_03_Z.setText(\"Z\")\n        self.label_03_Z.setStyleSheet(\"color: blue; font: bold \"+str(self.PointSize+3)+\"px;\")\n        #self.PB_03_Reset_Coordinate.setText(\"Reset\")\n        self.PB_03_Reset_Coordinate.setToolTip(\"Reset the coordinate value \" + \"\\n\"\n                                                                            \"Same click mouse in the 3D view\")\n        self.PB_03_Egual.setText(\"=\")\n        self.PB_03_Egual.setToolTip(\"This button copy the X value in the Y and Z window\")\n        self.GBox_02_Options.setTitle(\"Options\")\n        self.label_DS_04_Radius.setText(\"Radius\")\n        self.label_DS_05_Diameter.setText(\"Diameter\")\n        self.label_06_Circumference.setText(\"Circumference\")\n        self.label_07_Area.setText(\"Area\")\n        self.label_08_StartAngle.setText(\"StartAngle\")\n        self.label_09_EndAngle.setText(\"EndAngle\")\n        self.label_10_Arc.setText(\"Arc\")\n        self.label_11_AngleCenter.setText(\"AngleCenter\")\n        self.label_12_Cord.setText(\"Cord\")\n        self.label_13_Arrow.setText(\"Arrow\")\n        \n        self.CB_01_Center.setText(\"Point\")\n        self.CB_02_Info.setText(\"Info\")\n        self.CB_03_Face.setText(\"Face\")\n        self.CB_04_Sector.setText(\"Sector\")\n        self.CB_05_Segment.setText(\"Segment\")\n#        self.CB_06_incrementDS.setToolTip(\"Step increment\")\n        self.DS_06_incrementDS.setToolTip(\"Step increment\")\n        self.PB_01_Quit.setText(\"Quit\")\n        self.PB_02_Create.setText(\"Ok\")\n\n        #### ToolTip\n        self.DS_01_Coord_X.setToolTip(\"Coordinate X center circle \" + \"\\n\")\n        self.DS_02_Coord_Y.setToolTip(\"Coordinate Y center circle \" + \"\\n\")\n        self.DS_03_Coord_Z.setToolTip(\"Coordinate Z center circle \" + \"\\n\")\n        self.DS_04_Radius.setToolTip(\"Radius of circle \" + \"\\n\" + \"(The diameter is automatically adapted) \" + \"\\n\")\n        self.DS_05_Diameter.setToolTip(\"Diameter of circle \" + \"\\n\" + \"(The radius is automatically adapted) \" + \"\\n\")\n        self.GBox_02_Options.setToolTip(\"Option availlable \" + \"\\n\"\n                                                    \"If the command work with another command \" + \"\\n\"\n                                                    \"the frame of the command are colored in green \" + \"\\n\"\n                                                    \"If one facultative option is avaiabl , the is colored in orange \" + \"\\n\" \n                                                    \"Close this option window reset all value given\" )\n        self.DS_06_Circumference.setToolTip(\"Length Circumference of circle \" + \"\\n\" )\n        self.DS_07_Area.setToolTip(\"Area of circle \" + \"\\n\"\n                                                    \"The circle is create with face \" + \"\\n\" )\n        self.DS_08_StartAngle.setToolTip(\"Start angle of circle \" + \"\\n\"\n                                                    \"The Start angle work with\" + \"\\n\"\n                                                    \"Start angle, End angle, Radius, Diameter \" + \"\\n\" )\n        self.DS_09_EndAngle.setToolTip(\"End angle of circle \" + \"\\n\"\n                                                    \"The End angle work with\" + \"\\n\"\n                                                    \"Start angle, End angle, Radius, Diameter \" + \"\\n\" )\n        self.DS_10_Arc.setToolTip(\"Length Arc of circle  \" + \"\\n\"\n                                                    \"The Arc work with\" + \"\\n\"\n                                                    \"Arc, Angle center\" + \"\\n\"\n                                                    \"(option: startangle) \" + \"\\n\" )\n        self.DS_11_AngleCenter.setToolTip(\"Angle center Arc in degrees \" + \"\\n\"\n                                                    \"The radius is automaticly calculated\" + \"\\n\"\n                                                    \"The Angle center work with\" + \"\\n\"\n                                                    \"Arc, Angle center\" + \"\\n\"\n                                                    \"(option: startangle) \" + \"\\n\" )\n        self.DS_12_Cord.setToolTip(\"Length of Cord\" + \"\\n\"\n                                                    \"The Cord work with\" + \"\\n\"\n                                                    \"Cord, Arrow\" )\n        self.DS_13_Arrow.setToolTip(\"Length of Arrow \" + \"\\n\"\n                                                    \"The Arrow work with\" + \"\\n\"\n                                                    \"Cord, Arrow\" + \"\\n\" )\n        self.CB_01_Center.setToolTip(\"Create Point center circle \" + \"\\n\")\n        self.CB_02_Info.setToolTip(\"Display info in the Report View \" + \"\\n\")\n        self.CB_03_Face.setToolTip(\"Create face on circle \" + \"\\n\" )\n        self.CB_04_Sector.setToolTip(\"Create on Sector \" + \"\\n\"\n                                                    \"If availlable\")\n        self.CB_05_Segment.setToolTip(\"Create on Segment \" + \"\\n\"\n                                                    \"If availlable\")\n        self.SP_01_Caracter.setToolTip(\"Change the height of the text \" )\n        self.PB_01_Quit.setToolTip(\"Quit the macro Circle \" + \"\\n\" + \"Good bye \")\n        self.PB_02_Create.setToolTip(\"Create the circle\" + \"\\n\"\n                                                     \"If one error is detected te buttom is colored in red\" )\n    ####\n\n    def reset_Label(self):\n        self.label_DS_04_Radius.setText(\"Radius\")\n        self.label_DS_05_Diameter.setText(\"Diameter\")\n        self.label_06_Circumference.setText(\"Circumference\")\n        self.label_07_Area.setText(\"Area\")\n        self.label_08_StartAngle.setText(\"StartAngle\")\n        self.label_09_EndAngle.setText(\"EndAngle\")\n        self.label_10_Arc.setText(\"Arc\")\n        self.label_11_AngleCenter.setText(\"AngleCenter\")\n        self.label_12_Cord.setText(\"Cord\")\n        self.label_13_Arrow.setText(\"Arrow\")\n\n    def on_DS_01_Coord_X_valueChanged(self, value):         # \n        global positionX\n\n        positionX = value\n\n    def on_DS_02_Coord_Y_valueChanged(self, value):         # \n        global positionY\n\n        positionY = value\n\n    def on_DS_03_Coord_Z_valueChanged(self, value):         # \n        global positionZ\n\n        positionZ = value\n\n    def on_PB_03_Reset_Coordinate_clicked(self):\n        global positionX\n        global positionY\n        global positionZ\n\n        positionX = positionY = positionZ = 0.0\n        self.DS_01_Coord_X.setValue(positionX)\n        self.DS_02_Coord_Y.setValue(positionY)\n        self.DS_03_Coord_Z.setValue(positionZ)\n\n    def on_PB_03_Egual_clicked(self):\n        global positionX\n        global positionY\n        global positionZ\n\n        positionY = positionZ = positionX\n        self.DS_01_Coord_X.setValue(positionX)\n        self.DS_02_Coord_Y.setValue(positionY)\n        self.DS_03_Coord_Z.setValue(positionZ)\n\n\n    def on_DS_04_Radius_valueChanged(self, value):         # radius\n        self.Radius = value\n        self.Face = False\n        ui.reset_Label()\n        self.label_DS_05_Diameter.setStyleSheet(\"background-color: QPalette.Base\")\n        self.PB_02_Create.setStyleSheet(  \"background-color: QPalette.Base\")\n\n        #self.DS_04_Radius.setValue(0.0)        ; self.Radius = 0.0\n        self.label_DS_04_Radius.setStyleSheet(\"background-color: white;\\n\"\n                                              \"border:2px solid rgb(0, 187, 0);\")     # bord white and green\n        self.DS_05_Diameter.setValue(self.Radius * 2.0)\n        self.label_DS_05_Diameter.setStyleSheet(\"background-color: white;\\n\"\n                                                \"border:2px solid rgb(0, 187, 0);\")     # bord white and green\n        self.DS_06_Circumference.setValue(0.0) ; self.Circumference = 0.0\n        self.label_06_Circumference.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_07_Area.setValue(0.0)          ; self.Area = 0.0\n        self.label_07_Area.setStyleSheet(\"background-color: QPalette.Base\")\n        #self.DS_08_StartAngle.setValue(0.0)    ; self.StartAngle = 0.0\n        self.label_08_StartAngle.setStyleSheet(\"background-color: white;\\n\"\n                                               \"border:2px solid rgb(245, 121, 0);\")    # bord white and orange\n        #self.DS_09_EndAngle.setValue(0.0)      ; self.EndAngle = 0.0\n        self.label_09_EndAngle.setStyleSheet(\"background-color: white;\\n\"\n                                             \"border:2px solid rgb(245, 121, 0);\")    # bord white and orange\n        self.DS_10_Arc.setValue(0.0)           ; self.Arc = 0.0\n        self.label_10_Arc.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_11_AngleCenter.setValue(0.0)   ; self.AngleCenter = 0.0\n        self.label_11_AngleCenter.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_12_Cord.setValue(0.0)          ; self.Cord = 0.0\n        self.label_12_Cord.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_13_Arrow.setValue(0.0)         ; self.Arrow = 0.0\n        self.label_13_Arrow.setStyleSheet(\"background-color: QPalette.Base\")\n\n    def on_DS_05_Diameter_valueChanged(self, value):       # diameter\n        self.Diameter = value\n        self.DS_04_Radius.setValue(self.Diameter / 2.0)\n        ui.reset_Label()\n\n    def on_GBox_02_Options(self):  # \n        self.Face = False\n        ui.reset_Label()\n        if self.GBox_02_Options.isChecked():\n            MainWindow.resize(226, 545)\n            self.GBox_02_Options.setGeometry(QtCore.QRect(5, 195, 216, 271))\n            self.CB_01_Center.setGeometry(QtCore.QRect(5, 470, 61, 18))\n            self.CB_02_Info.setGeometry(QtCore.QRect(90, 470, 61, 18))\n            self.CB_03_Face.setGeometry(QtCore.QRect(170, 470, 61, 18))\n            self.CB_04_Sector.setGeometry(QtCore.QRect(5, 490, 61, 18))\n            self.CB_05_Segment.setGeometry(QtCore.QRect(90, 490, 61, 18))\n#            self.CB_06_incrementDS.setGeometry(QtCore.QRect(170, 490, 61, 18))\n            self.DS_06_incrementDS.setGeometry(QtCore.QRect(170, 490, 50, 18))\n            self.SP_01_Caracter.setGeometry(QtCore.QRect(5, 515, 61, 22))\n            self.PB_01_Quit.setGeometry(QtCore.QRect(115, 515, 50, 23))\n            self.PB_02_Create.setGeometry(QtCore.QRect(170, 515, 50, 23))\n        else:\n            MainWindow.resize(226, 295)\n            self.GBox_02_Options.setGeometry(QtCore.QRect(5, 195, 216, 21))\n            self.CB_01_Center.setGeometry(QtCore.QRect(5, 220, 61, 18))\n            self.CB_02_Info.setGeometry(QtCore.QRect(90, 220, 61, 18))\n            self.CB_03_Face.setGeometry(QtCore.QRect(170, 220, 61, 18))\n            self.CB_04_Sector.setGeometry(QtCore.QRect(5, 240, 61, 18))\n            self.CB_05_Segment.setGeometry(QtCore.QRect(90, 240, 61, 18))\n#            self.CB_06_incrementDS.setGeometry(QtCore.QRect(170, 240, 61, 18))\n            self.DS_06_incrementDS.setGeometry(QtCore.QRect(170, 240, 50, 18))\n            self.SP_01_Caracter.setGeometry(QtCore.QRect(5, 265, 50, 22))\n            self.PB_01_Quit.setGeometry(QtCore.QRect(115, 265, 50, 23))\n            self.PB_02_Create.setGeometry(QtCore.QRect(170, 265, 50, 23))\n\n            #self.DS_04_Radius.setValue(0.0)        ; self.Radius = 0.0\n            #self.DS_05_Diameter.setValue(0.0)      ; self.Diameter = 0.0\n            self.DS_06_Circumference.setValue(0.0) ; self.Circumference = 0.0 ; self.label_06_Circumference.setStyleSheet(\"background-color: QPalette.Base\")\n            self.DS_07_Area.setValue(0.0)          ; self.Area = 0.0          ; self.label_07_Area.setStyleSheet(\"background-color: QPalette.Base\")\n            self.DS_08_StartAngle.setValue(0.0)    ; self.StartAngle = 0.0    ; self.label_08_StartAngle.setStyleSheet(\"background-color: QPalette.Base\")\n            self.DS_09_EndAngle.setValue(0.0)      ; self.EndAngle = 0.0      ; self.label_09_EndAngle.setStyleSheet(\"background-color: QPalette.Base\")\n            self.DS_10_Arc.setValue(0.0)           ; self.Arc = 0.0           ; self.label_10_Arc.setStyleSheet(\"background-color: QPalette.Base\")\n            self.DS_11_AngleCenter.setValue(0.0)   ; self.AngleCenter = 0.0   ; self.label_11_AngleCenter.setStyleSheet(\"background-color: QPalette.Base\")\n            self.DS_12_Cord.setValue(0.0)          ; self.Cord = 0.0          ; self.label_12_Cord.setStyleSheet(\"background-color: QPalette.Base\")\n            self.DS_13_Arrow.setValue(0.0)         ; self.Arrow = 0.0         ; self.label_13_Arrow.setStyleSheet(\"background-color: QPalette.Base\")\n\n    def on_DS_06_Circumference_valueChanged(self, value):  # Circumference\n        self.Circumference = value\n        self.Face = False\n        ui.reset_Label()\n        self.DS_04_Radius.setValue(0.0)        ; self.Radius = 0.0\n        self.label_DS_04_Radius.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_05_Diameter.setValue(0.0)      ; self.Diameter = 0.0\n        self.label_DS_05_Diameter.setStyleSheet(\"background-color: QPalette.Base\")\n#        self.DS_06_Circumference.setValue(0.0) ; self.Circumference = 0.0\n        self.label_06_Circumference.setStyleSheet(\"background-color: white;\\n\"\n                                            \"border:2px solid rgb(0, 187, 0);\")     # bord white and green\n        self.DS_07_Area.setValue(0.0)          ; self.Area = 0.0\n        self.label_07_Area.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_08_StartAngle.setValue(0.0)    ; self.StartAngle = 0.0\n        self.label_08_StartAngle.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_09_EndAngle.setValue(0.0)      ; self.EndAngle = 0.0\n        self.label_09_EndAngle.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_10_Arc.setValue(0.0)           ; self.Arc = 0.0\n        self.label_10_Arc.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_11_AngleCenter.setValue(0.0)   ; self.AngleCenter = 0.0\n        self.label_11_AngleCenter.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_12_Cord.setValue(0.0)          ; self.Cord = 0.0\n        self.label_12_Cord.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_13_Arrow.setValue(0.0)         ; self.Arrow = 0.0\n        self.label_13_Arrow.setStyleSheet(\"background-color: QPalette.Base\")\n\n    def on_DS_07_Area_valueChanged(self, value):           # Area\n        self.Area = value\n        self.Face = True\n        ui.reset_Label()\n        self.DS_04_Radius.setValue(0.0)        ; self.Radius = 0.0\n        self.label_DS_04_Radius.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_05_Diameter.setValue(0.0)      ; self.Diameter = 0.0\n        self.label_DS_05_Diameter.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_06_Circumference.setValue(0.0) ; self.Circumference = 0.0\n        self.label_06_Circumference.setStyleSheet(\"background-color: QPalette.Base\")\n#        self.DS_07_Area.setValue(0.0)          ; self.Area = 0.0\n        self.label_07_Area.setStyleSheet(\"background-color: white;\\n\"\n                                         \"border:2px solid rgb(0, 187, 0);\")     # bord white and green\n        self.DS_08_StartAngle.setValue(0.0)    ; self.StartAngle = 0.0\n        self.label_08_StartAngle.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_09_EndAngle.setValue(0.0)      ; self.EndAngle = 0.0\n        self.label_09_EndAngle.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_10_Arc.setValue(0.0)           ; self.Arc = 0.0\n        self.label_10_Arc.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_11_AngleCenter.setValue(0.0)   ; self.AngleCenter = 0.0\n        self.label_11_AngleCenter.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_12_Cord.setValue(0.0)          ; self.Cord = 0.0\n        self.label_12_Cord.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_13_Arrow.setValue(0.0)         ; self.Arrow = 0.0\n        self.label_13_Arrow.setStyleSheet(\"background-color: QPalette.Base\")\n\n    def on_DS_08_StartAngle_valueChanged(self, value):     # StartAngle\n        self.StartAngle = value\n        self.Face = False\n        ui.reset_Label()\n        if self.Arc == 0: \n            #self.DS_04_Radius.setValue(0.0)        ; self.Radius = 0.0\n            self.label_DS_04_Radius.setStyleSheet(\"background-color: white;\\n\"\n                                                  \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n            #self.DS_05_Diameter.setValue(0.0)      ; self.Diameter = 0.0\n            self.label_DS_05_Diameter.setStyleSheet(\"background-color: white;\\n\"\n                                                    \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n            #self.DS_09_EndAngle.setValue(0.0)      ; self.EndAngle = 0.0\n            self.label_09_EndAngle.setStyleSheet(\"background-color: white;\\n\"\n                                                 \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n            self.DS_10_Arc.setValue(0.0)           ; self.Arc = 0.0\n            self.label_10_Arc.setStyleSheet(\"background-color: QPalette.Base\")\n            self.DS_11_AngleCenter.setValue(0.0)   ; self.AngleCenter = 0.0\n            self.label_11_AngleCenter.setStyleSheet(\"background-color: QPalette.Base\")\n        else:\n            self.Radius   = 0.0\n            self.EndAngle = 0.0\n            self.label_10_Arc.setStyleSheet(\"background-color: white;\\n\"\n                                            \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n            self.label_11_AngleCenter.setStyleSheet(\"background-color: white;\\n\"\n                                                    \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n\n        self.DS_06_Circumference.setValue(0.0) ; self.Circumference = 0.0\n        self.label_06_Circumference.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_07_Area.setValue(0.0)          ; self.Area = 0.0\n        self.label_07_Area.setStyleSheet(\"background-color: QPalette.Base\")\n        #self.DS_08_StartAngle.setValue(0.0)    ; self.StartAngle = 0.0\n        self.label_08_StartAngle.setStyleSheet(\"background-color: white;\\n\"\n                                               \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n        self.DS_12_Cord.setValue(0.0)          ; self.Cord = 0.0\n        self.label_12_Cord.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_13_Arrow.setValue(0.0)         ; self.Arrow = 0.0\n        self.label_13_Arrow.setStyleSheet(\"background-color: QPalette.Base\")\n\n    def on_DS_09_EndAngle_valueChanged(self, value):       # EndAngle\n        self.EndAngle = value\n        self.Face = False\n        ui.reset_Label()\n        #self.DS_04_Radius.setValue(0.0)        ; self.Radius = 0.0\n        self.label_DS_04_Radius.setStyleSheet(\"background-color: white;\\n\"\n                                              \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n        #self.DS_05_Diameter.setValue(0.0)      ; self.Diameter = 0.0\n        self.label_DS_05_Diameter.setStyleSheet(\"background-color: white;\\n\"\n                                                \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n        self.DS_06_Circumference.setValue(0.0) ; self.Circumference = 0.0\n        self.label_06_Circumference.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_07_Area.setValue(0.0)          ; self.Area = 0.0\n        self.label_07_Area.setStyleSheet(\"background-color: QPalette.Base\")\n        #self.DS_08_StartAngle.setValue(0.0)    ; self.StartAngle = 0.0\n        self.label_08_StartAngle.setStyleSheet(\"background-color: white;\\n\"\n                                               \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n        #self.DS_09_EndAngle.setValue(0.0)      ; self.EndAngle = 0.0\n        self.label_09_EndAngle.setStyleSheet(\"background-color: white;\\n\"\n                                             \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n        self.DS_10_Arc.setValue(0.0)           ; self.Arc = 0.0\n        self.label_10_Arc.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_11_AngleCenter.setValue(0.0)   ; self.AngleCenter = 0.0\n        self.label_11_AngleCenter.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_12_Cord.setValue(0.0)          ; self.Cord = 0.0\n        self.label_12_Cord.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_13_Arrow.setValue(0.0)         ; self.Arrow = 0.0\n        self.label_13_Arrow.setStyleSheet(\"background-color: QPalette.Base\")\n\n    def on_DS_10_Arc_valueChanged(self, value):            # Arc\n    #with [arc and anglecenter] + radius      in combination (angle in degrees)\n        self.Arc = value\n        self.Face = False\n        ui.reset_Label()\n        self.DS_04_Radius.setValue(0.0)        ; self.Radius = 0.0\n        self.label_DS_04_Radius.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_05_Diameter.setValue(0.0)      ; self.Diameter = 0.0\n        self.label_DS_05_Diameter.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_06_Circumference.setValue(0.0) ; self.Circumference = 0.0\n        self.label_06_Circumference.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_07_Area.setValue(0.0)          ; self.Area = 0.0\n        self.label_07_Area.setStyleSheet(\"background-color: QPalette.Base\")\n        #self.DS_08_StartAngle.setValue(0.0)    ; self.StartAngle = 0.0\n        self.label_08_StartAngle.setStyleSheet(\"background-color: white;\\n\"\n                                            \"border:2px solid rgb(245, 121, 0);\")     # bord white and orange\n        self.DS_09_EndAngle.setValue(0.0)      ; self.EndAngle = 0.0\n        self.label_09_EndAngle.setStyleSheet(\"background-color: QPalette.Base\")\n        #self.DS_10_Arc.setValue(0.0)           ; self.Arc = 0.0\n        self.label_10_Arc.setStyleSheet(\"background-color: white;\\n\"\n                                            \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n        #self.DS_11_AngleCenter.setValue(0.0)   ; self.AngleCenter = 0.0\n        self.label_11_AngleCenter.setStyleSheet(\"background-color: white;\\n\"\n                                            \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n        self.DS_12_Cord.setValue(0.0)          ; self.Cord = 0.0\n        self.label_12_Cord.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_13_Arrow.setValue(0.0)         ; self.Arrow = 0.0\n        self.label_13_Arrow.setStyleSheet(\"background-color: QPalette.Base\")\n\n    def on_DS_11_AngleCenter_valueChanged(self, value):    # AngleCenter\n    #with [arc and anglecenter] + radius      in combination (angle in degrees)\n        self.AngleCenter = value\n        self.Face = False\n        ui.reset_Label()\n        self.DS_04_Radius.setValue(0.0)        ; self.Radius = 0.0\n        self.label_DS_04_Radius.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_05_Diameter.setValue(0.0)      ; self.Diameter = 0.0\n        self.label_DS_05_Diameter.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_06_Circumference.setValue(0.0) ; self.Circumference = 0.0\n        self.label_06_Circumference.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_07_Area.setValue(0.0)          ; self.Area = 0.0\n        self.label_07_Area.setStyleSheet(\"background-color: QPalette.Base\")\n        #self.DS_08_StartAngle.setValue(0.0)    ; self.StartAngle = 0.0\n        self.label_08_StartAngle.setStyleSheet(\"background-color: white;\\n\"\n                                            \"border:2px solid rgb(245, 121, 0);\")     # bord white and orange\n        self.DS_09_EndAngle.setValue(0.0)      ; self.EndAngle = 0.0\n        self.label_09_EndAngle.setStyleSheet(\"background-color: QPalette.Base\")\n        #self.DS_10_Arc.setValue(0.0)           ; self.Arc = 0.0\n        self.label_10_Arc.setStyleSheet(\"background-color: white;\\n\"\n                                            \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n        #self.DS_11_AngleCenter.setValue(0.0)   ; self.AngleCenter = 0.0\n        self.label_11_AngleCenter.setStyleSheet(\"background-color: white;\\n\"\n                                            \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n        self.DS_12_Cord.setValue(0.0)          ; self.Cord = 0.0\n        self.label_12_Cord.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_13_Arrow.setValue(0.0)         ; self.Arrow = 0.0\n        self.label_13_Arrow.setStyleSheet(\"background-color: QPalette.Base\")\n\n    def on_DS_12_Cord_valueChanged(self, value):           # Cord\n    #with [cord and arrow]           in combination\n        self.Cord = value\n        self.Face = False\n        ui.reset_Label()\n        self.DS_04_Radius.setValue(0.0)        ; self.Radius = 0.0\n        self.label_DS_04_Radius.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_05_Diameter.setValue(0.0)      ; self.Diameter = 0.0\n        self.label_DS_05_Diameter.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_06_Circumference.setValue(0.0) ; self.Circumference = 0.0\n        self.label_06_Circumference.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_07_Area.setValue(0.0)          ; self.Area = 0.0\n        self.label_07_Area.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_08_StartAngle.setValue(0.0)    ; self.StartAngle = 0.0\n        self.label_08_StartAngle.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_09_EndAngle.setValue(0.0)      ; self.EndAngle = 0.0\n        self.label_09_EndAngle.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_10_Arc.setValue(0.0)           ; self.Arc = 0.0\n        self.label_10_Arc.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_11_AngleCenter.setValue(0.0)   ; self.AngleCenter = 0.0\n        self.label_11_AngleCenter.setStyleSheet(\"background-color: QPalette.Base\")\n        #self.DS_12_Cord.setValue(0.0)          ; self.Cord = 0.0\n        self.label_12_Cord.setStyleSheet(\"background-color: white;\\n\"\n                                         \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n        #self.DS_13_Arrow.setValue(0.0)         ; self.Arrow = 0.0\n        self.label_13_Arrow.setStyleSheet(\"background-color: white;\\n\"\n                                            \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n\n    def on_DS_13_Arrow_valueChanged(self, value):          # Arrow\n    #with [cord and arrow]           in combination\n        self.Arrow = value\n        self.Face = False\n        ui.reset_Label()\n        self.DS_04_Radius.setValue(0.0)        ; self.Radius = 0.0\n        self.label_DS_04_Radius.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_05_Diameter.setValue(0.0)      ; self.Diameter = 0.0\n        self.label_DS_05_Diameter.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_06_Circumference.setValue(0.0) ; self.Circumference = 0.0\n        self.label_06_Circumference.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_07_Area.setValue(0.0)          ; self.Area = 0.0\n        self.label_07_Area.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_08_StartAngle.setValue(0.0)    ; self.StartAngle = 0.0\n        self.label_08_StartAngle.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_09_EndAngle.setValue(0.0)      ; self.EndAngle = 0.0\n        self.label_09_EndAngle.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_10_Arc.setValue(0.0)           ; self.Arc = 0.0\n        self.label_10_Arc.setStyleSheet(\"background-color: QPalette.Base\")\n        self.DS_11_AngleCenter.setValue(0.0)   ; self.AngleCenter = 0.0\n        self.label_11_AngleCenter.setStyleSheet(\"background-color: QPalette.Base\")\n        #self.DS_12_Cord.setValue(0.0)          ; self.Cord = 0.0\n        self.label_12_Cord.setStyleSheet(\"background-color: white;\\n\"\n                                         \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n        #self.DS_13_Arrow.setValue(0.0)         ; self.Arrow = 0.0\n        self.label_13_Arrow.setStyleSheet(\"background-color: white;\\n\"\n                                          \"border:2px solid rgb(115, 210, 22);\")     # bord white and green\n\n#    def on_CB_06_incrementDS_clicked(self):\n#        global incrementDS\n#\n#        if self.CB_06_incrementDS.isChecked():\n#            incrementDS = 0.1\n#        else:\n#            incrementDS = 1.0\n#        self.CB_06_incrementDS.setText(\"(\" + str(incrementDS) + \")\")\n#        self.DS_04_Radius.setSingleStep(incrementDS)\n#        self.DS_05_Diameter.setSingleStep(incrementDS)\n##        self.DS_06_Circumference.setSingleStep(incrementDS)\n##        self.DS_07_Area.setSingleStep(incrementDS)\n##        self.DS_08_StartAngle.setSingleStep(incrementDS)\n##        self.DS_09_EndAngle.setSingleStep(incrementDS)\n##        self.DS_10_Arc.setSingleStep(incrementDS)\n##        self.DS_11_AngleCenter.setSingleStep(incrementDS)\n##        self.DS_12_Cord.setSingleStep(incrementDS)\n##        self.DS_13_Arrow.setSingleStep(incrementDS)\n\n    def on_DS_06_incrementDS_clicked(self, value):\n        global incrementDS\n\n        incrementDS = value\n        self.DS_04_Radius.setSingleStep(incrementDS)\n        self.DS_05_Diameter.setSingleStep(incrementDS)\n        self.DS_06_Circumference.setSingleStep(incrementDS)\n        self.DS_07_Area.setSingleStep(incrementDS)\n        self.DS_08_StartAngle.setSingleStep(incrementDS)\n        self.DS_09_EndAngle.setSingleStep(incrementDS)\n        self.DS_10_Arc.setSingleStep(incrementDS)\n        self.DS_11_AngleCenter.setSingleStep(incrementDS)\n        self.DS_12_Cord.setSingleStep(incrementDS)\n        self.DS_13_Arrow.setSingleStep(incrementDS)\n\n    def on_SP_01_Caracter_valueChanged(self, value):\n        self.PointSize = value\n        self.fontGlobal_08.setPointSize(self.PointSize)\n        self.GBox_01_Coordinate.setFont(self.fontGlobal_08)\n        self.DS_01_Coord_X.setFont(self.fontGlobal_08)\n        self.label_01_X.setFont(self.fontGlobal_08)\n        self.label_01_X.setStyleSheet(\"color: red; font: bold \"+str(self.PointSize+3)+\"px;\")\n        self.DS_02_Coord_Y.setFont(self.fontGlobal_08)\n        self.label_02_Y.setFont(self.fontGlobal_08)\n        self.label_02_Y.setStyleSheet(\"color: green; font: bold \"+str(self.PointSize+3)+\"px;\")\n        self.DS_03_Coord_Z.setFont(self.fontGlobal_08)\n        self.label_03_Z.setFont(self.fontGlobal_08)\n        self.label_03_Z.setStyleSheet(\"color: blue; font: bold \"+str(self.PointSize+3)+\"px;\")\n\n        self.PB_03_Reset_Coordinate.setFont(self.fontGlobal_08)\n        self.GBox_02_Options.setFont(self.fontGlobal_08)\n        self.DS_04_Radius.setFont(self.fontGlobal_08)\n        self.label_DS_04_Radius.setFont(self.fontGlobal_08)\n        self.DS_05_Diameter.setFont(self.fontGlobal_08)\n        self.label_DS_05_Diameter.setFont(self.fontGlobal_08)\n        self.DS_06_Circumference.setFont(self.fontGlobal_08)\n        self.label_06_Circumference.setFont(self.fontGlobal_08)\n        self.DS_07_Area.setFont(self.fontGlobal_08)\n        self.label_07_Area.setFont(self.fontGlobal_08)\n        self.DS_08_StartAngle.setFont(self.fontGlobal_08)\n        self.label_08_StartAngle.setFont(self.fontGlobal_08)\n        self.DS_09_EndAngle.setFont(self.fontGlobal_08)\n        self.label_09_EndAngle.setFont(self.fontGlobal_08)\n        self.DS_10_Arc.setFont(self.fontGlobal_08)\n        self.label_10_Arc.setFont(self.fontGlobal_08)\n        self.DS_11_AngleCenter.setFont(self.fontGlobal_08)\n        self.label_11_AngleCenter.setFont(self.fontGlobal_08)\n        self.DS_12_Cord.setFont(self.fontGlobal_08)\n        self.label_12_Cord.setFont(self.fontGlobal_08)\n        self.DS_13_Arrow.setFont(self.fontGlobal_08)\n        self.label_13_Arrow.setFont(self.fontGlobal_08)\n        self.SP_01_Caracter.setFont(self.fontGlobal_08)\n        self.PB_02_Create.setFont(self.fontGlobal_08)\n        self.PB_01_Quit.setFont(self.fontGlobal_08)\n\n    def on_PB_01_Quit_clicked(self):\n        global s\n\n        self.vueActive.removeEventCallback(\"SoMouseButtonEvent\",self.click) # desinstalle la fonction souris\n        FreeCADGui.Selection.removeObserver(s)                              # desinstalle la fonction residente SelObserver\n        self.window.hide()\n        FreeCAD.Console.PrintMessage(\"Quit\" + \"\\n\")\n\n    def on_PB_02_Create_clicked(self):\n        global positionX\n        global positionY\n        global positionZ\n\n        if self.Circumference != 0:                                      # with circumference\n            self.Radius = (self.Circumference / pi) / 2.0\n        elif self.Area != 0:                                             # with area\n            self.Radius =  sqrt((self.Area / pi))\n        elif (self.Cord != 0) and (self.Arrow != 0):                     # with cord and arrow\n            self.Radius = ((self.Arrow**2) + (self.Cord**2) / 4.0) / (self.Arrow*2.0) \n        elif (self.Arc != 0) and (self.AngleCenter != 0):                # with arc and anglecenter central in degrees\n            self.Radius = ((360.0 / self.AngleCenter)*self.Arc) / pi/2.0\n            if self.EndAngle != 0:\n                self.StartAngle  = self.EndAngle - self.AngleCenter\n            self.EndAngle   = self.AngleCenter + self.StartAngle\n            self.StartAngle = self.EndAngle    - self.AngleCenter\n    \n        if self.Radius != 0:\n            if self.CB_03_Face.isChecked():\n                self.Face = True\n\n            try:\n                pl=FreeCAD.Placement()\n                r = FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation()         # get camera orientation\n                pl=FreeCAD.Placement()                                                  # placement object\n                pl.Rotation.Q = r.Q                                                     # set camera orientation\n                pl.Base = App.Vector(positionX, positionY, positionZ)\n                circle = Draft.makeCircle(self.Radius, placement=pl, face=self.Face, startangle=self.StartAngle, endangle=self.EndAngle, support=None)\n                Draft.autogroup(circle)\n\n                if self.CB_01_Center.isChecked():\n                    Draft.makePoint(pl.Base)\n\n                try:\n                    if (self.CB_04_Sector.isChecked()):     #Sector\n                        pointsC = []\n                        pointsC = circle.Shape.discretize(3)\n                        line01  = Draft.makeWire([pl.Base, pointsC[0]],closed=False,face=False,support=None); Draft.autogroup(line01)\n                        line02  = Draft.makeWire([pl.Base, pointsC[2]],closed=False,face=False,support=None); Draft.autogroup(line02)\n                        ##Compound\n                        secteur = App.activeDocument().addObject(\"Part::Compound\",\"Sector\")\n                        secteur.Links = [line01, circle, line02]\n                        ##face #https://www.freecadweb.org/wiki/Macro_Creating_faces_from_a_DXF_file\n                        if self.CB_03_Face.isChecked():\n                            try:\n                                edges = sum((line01.Shape.Edges, circle.Shape.Edges, line02.Shape.Edges),[])\n                                face = OpenSCAD2Dgeom.edgestofaces(edges)\n                                faceobj = doc.addObject(\"Part::Feature\",\"Sector\")\n                                faceobj.Label = \"Sector\"\n                                faceobj.Shape = face\n                            except Exception:\n                                None\n                        App.activeDocument().recompute()\n                except Exception:\n                    App.Console.PrintError(\"Sector not possible\" + \"\\n\")\n\n                try:\n                    if (self.CB_05_Segment.isChecked()):    #Segment\n                        pointsC = []\n                        pointsC = circle.Shape.discretize(3)\n                        line01  = Draft.makeWire([pointsC[0], pointsC[2]],closed=False,face=False,support=None); Draft.autogroup(line01)\n                        ##Compound\n                        secteur = App.activeDocument().addObject(\"Part::Compound\",\"Segment\")\n                        secteur.Links = [line01, circle]\n                        ##face #https://www.freecadweb.org/wiki/Macro_Creating_faces_from_a_DXF_file\n                        if self.CB_03_Face.isChecked():\n                            try:\n                                edges = sum((line01.Shape.Edges, circle.Shape.Edges),[])\n                                face = OpenSCAD2Dgeom.edgestofaces(edges)\n                                faceobj = doc.addObject(\"Part::Feature\",\"Segment\")\n                                faceobj.Label = \"Segment\"\n                                faceobj.Shape = face\n                            except Exception:\n                                None\n                        App.activeDocument().recompute()\n                except Exception:\n                    App.Console.PrintError(\"Segment not possible\" + \"\\n\")\n\n                self.Face = False\n\n                self.label_DS_04_Radius.setStyleSheet(\"background-color: QPalette.Base\")     # origin system\n                self.label_DS_05_Diameter.setStyleSheet(\"background-color: QPalette.Base\")   # origin system\n                self.label_06_Circumference.setStyleSheet(\"background-color: QPalette.Base\") # origin system\n                self.label_07_Area.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n                self.label_08_StartAngle.setStyleSheet(\"background-color: QPalette.Base\")    # origin system\n                self.label_09_EndAngle.setStyleSheet(\"background-color: QPalette.Base\")      # origin system\n                self.label_10_Arc.setStyleSheet(\"background-color: QPalette.Base\")           # origin system\n                self.label_11_AngleCenter.setStyleSheet(\"background-color: QPalette.Base\")   # origin system\n                self.label_12_Cord.setStyleSheet(\"background-color: QPalette.Base\")          # origin system\n                self.label_13_Arrow.setStyleSheet(\"background-color: QPalette.Base\")         # origin system\n\n                self.Circumference = ((self.Radius * 2.0) * pi)\n                self.Area = ((self.Radius ** 2.0) * pi)\n\n                if self.CB_02_Info.isChecked():\n                    FreeCAD.Console.PrintMessage(\"Radius        : \" + str(self.Radius) + \"\\n\")\n                    FreeCAD.Console.PrintMessage(\"Diameter      : \" + str(self.Radius * 2.0) + \"\\n\")\n                    FreeCAD.Console.PrintMessage(\"Circumference : \" + str(self.Circumference) + \"\\n\")\n                    FreeCAD.Console.PrintMessage(\"Area          : \" + str(self.Area) + \"\\n\")\n                    FreeCAD.Console.PrintMessage(\"StartAngle    : \" + str(self.StartAngle) + \"\\n\")\n                    FreeCAD.Console.PrintMessage(\"EndAngle      : \" + str(self.EndAngle) + \"\\n\")\n                    FreeCAD.Console.PrintMessage(\"Arc           : \" + str(self.Arc) + \"\\n\")\n                    FreeCAD.Console.PrintMessage(\"AngleCenter   : \" + str(self.AngleCenter) + \"\\n\")\n                    FreeCAD.Console.PrintMessage(\"Cord          : \" + str(self.Cord) + \"\\n\")\n                    FreeCAD.Console.PrintMessage(\"Arrow         : \" + str(self.Arrow) + \"\\n\")\n                    FreeCAD.Console.PrintMessage(\"________________\" + \"\\n\")\n\n                self.label_DS_04_Radius.setText(\"Rad\" + \" (\" + str(round(self.Radius,2)) + \")\")\n                self.label_DS_05_Diameter.setText(\"Dia\" + \" (\" + str(round(self.Radius * 2.0,2)) + \")\")\n                self.label_06_Circumference.setText(\"Cir\" + \" (\" + str(round(self.Circumference,2)) + \")\")\n                self.label_07_Area.setText(\"Arc\" + \" (\" + str(round(self.Area,2)) + \")\")\n                self.label_08_StartAngle.setText(\"Sta\" + \" (\" + str(round(self.StartAngle,2)) + \")\")\n                self.label_09_EndAngle.setText(\"End\" + \" (\" + str(round(self.EndAngle,2)) + \")\")\n                self.label_10_Arc.setText(\"Arc\" + \" (\" + str(round(self.Arc,2)) + \")\")\n                self.label_11_AngleCenter.setText(\"ACe\" + \" (\" + str(round(self.AngleCenter,2)) + \")\")\n                self.label_12_Cord.setText(\"Cor\" + \" (\" + str(round(self.Cord,2)) + \")\")\n                self.label_13_Arrow.setText(\"Arr\" + \" (\" + str(round(self.Arrow,2)) + \")\")\n                self.PB_02_Create.setStyleSheet(\"background-color: QPalette.Base\")\n\n            except Exception:\n                App.Console.PrintError(\"Unexpected keyword argument\" + \"\\n\")\n        else:\n            App.Console.PrintError(\"Unexpected keyword argument\" + \"\\n\")\n            #self.DS_04_Radius.setStyleSheet(\"background-color: red\")\n            #self.DS_05_Diameter.setStyleSheet(\"background-color: red\")\n            self.PB_02_Create.setStyleSheet(\"background-color: red\")                   # This function gives a color button\n\n#################################################################################################\nclass SelObserver:\n    def addSelection(self, document, object, element, position):  # Selection\n        global ui\n        global sourisPass\n        global positionX\n        global positionY\n        global positionZ\n\n        positionX = positionY = positionZ =0.0\n\n        if sourisPass == 0:\n            sourisPass = 1\n            #print position\n            positionX = position[0]\n            positionY = position[1]\n            positionZ = position[2]\n\n            ui.DS_01_Coord_X.setValue(positionX)\n            ui.DS_02_Coord_Y.setValue(positionY)\n            ui.DS_03_Coord_Z.setValue(positionZ)\n        else:\n            sourisPass = 0\n            \n##    def setPreselection(self,doc,obj,sub):             # preselection\n##        print \"setPreselection\"\n##    def removeSelection(self,doc,obj,sub):             # Effacer l'objet selectionne\n##        print \"removeSelection\"\n##    def setSelection(self,doc):                        # Selection dans ComboView\n##        print \"SelObserver quit macro\"\n##    def clearSelection(self,doc):                      # Si clic sur l'ecran, effacer la selection\n##        print \"clearSelection\"                         # Si clic sur un autre objet, efface le precedent\n\ns=SelObserver()\nFreeCADGui.Selection.addObserver(s)                    # installe la fonction en mode resident\n##################################################################################################\n\ndoc = FreeCAD.ActiveDocument\nif doc == None:\n    doc = FreeCAD.newDocument()\n\nMainWindow = QtGui.QMainWindow()\nui = Ui_MainWindow()\nui.setupUi(MainWindow)\nMainWindow.show()\n\n",
    "url": "https://wiki.freecad.org/Macro_CirclePlus",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/0ed8129bacbe9124a41e3ae1d378d5b7/raw/3f810ac142dd0d9245c5ccc964b8b2d7d750b276/Macro%2520CirclePlus.FCMacro",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_CirclePlus",
    "version": "00.04",
    "license": "",
    "date": "2019/04/07",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_CirclePlus.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/4/4c/Macro_CirclePlus.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Cut Circle",
    "on_wiki": true,
    "on_git": false,
    "desc": "Cuts circles or arcs into multiple arcs. The created arcs can be colored alternately to distinguish them.<br /><span style=\"background-color: #ffeeee\">(Command line, paste the complete macro in the Python console)</span>.<br /><br />Macro version: 00.03<br />Last modified: 2019-07-02<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/9/93/Macro_Cut_Circle.png\">ToolBar Icon</a><br />Author: mario52<br /> ",
    "comment": "Cuts circles or arcs into multiple arcs. The created arcs can be colored alternately to distinguish them.",
    "code": "# selection circle(s) (circles and arcs)\n# give number of cut, biColor 0/1\n# cut the circle to x arcs\n# if biColor is <> 0 the arcs are colored alternately Red White Red White ....\n# \n \n__title__   = \"cutCircle\"\n__author__  = \"Mario52\"\n__date__    = \"02/07/2019\"\n__version__ = \"00.03\"\n\nimport Draft\nglobal biscolor ; biscolor = 0\ndef cutCircle(number = 2, biColor = 0):\n    global biscolor\n    def defbiColor(objet):\n        global biscolor\n        if biscolor == 0:\n            FreeCADGui.ActiveDocument.getObject(objet.Name).LineColor = (1.0,0.0,0.0) # 255 = 1 (10 = (1/255 * 10 ))\n            biscolor = 1\n        else:\n            FreeCADGui.ActiveDocument.getObject(objet.Name).LineColor = (1.0,1.0,1.0) # 255 = 1 (10 = (1/255 * 10 ))\n            biscolor = 0\n    selection = FreeCADGui.Selection.getSelection()\n    for piece in selection:\n        nom = piece.Name\n        if (nom[:6] == \"Circle\") or (nom[:8] == \"Cylinder\"):\n            circonference = piece.Shape.Length\n            rayon = piece.Radius\n            placem = piece.Placement\n \n            if (nom[:8] == \"Cylinder\"):\n                pivot0 = float(piece.Angle/number)\n                FreeCAD.Console.PrintMessage(\"Cylinder\"+\"\\n\")\n            else:\n                pivot0 = float(360/number)\n                FreeCAD.Console.PrintMessage(\"Circle\"+\"\\n\")\n            pivot1 = 0.0\n            for i in range(number):\n                cercle = Draft.makeCircle(radius=rayon,placement=placem,face=False,startangle=(pivot1),endangle=(pivot0+pivot1),support=None)\n                if biColor != 0:\n                    defbiColor(cercle)\n                pivot1 += pivot0\n        elif nom[:3] == \"Arc\":\n            FreeCAD.Console.PrintMessage(\"Arc\"+\"\\n\")\n            circonference = piece.Shape.Length\n            rayon = piece.Radius\n            placem = piece.Placement\n            First = float(piece.FirstAngle)\n            Last  = float(piece.LastAngle)\n            pivot0 = abs((First - Last) / number)\n            pivot1 = 0.0\n            for i in range(number):\n                cercle = Draft.makeCircle(radius=rayon,placement=placem,face=False,startangle=(pivot1+First),endangle=(pivot0+pivot1+First),support=None)\n                if biColor != 0:\n                    defbiColor(cercle)\n                pivot1 += pivot0\n    App.ActiveDocument.recompute()\n\n#cutCircle(5, 1)  # here with 5 arcs and colored\n#cutCircle(4)     #",
    "url": "https://wiki.freecad.org/Macro_Cut_Circle",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.03",
    "license": "",
    "date": "02/07/2019",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Cut_Circle.png",
    "icon_source": "https://wiki.freecad.org/images/9/93/Macro_Cut_Circle.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Cut Line",
    "on_wiki": true,
    "on_git": false,
    "desc": "Cut a line giving as an argument number cut, create line, bicolor, create point. The new line is created in the real coordinate of object, not in the coordinate of the Body.<br /><span style=\"background-color: #ffeeee\">(Command line, paste this complete macro in the Python console)</span>.<br /><br />Macro version: 2.0<br />Last modified: 2019/06/17<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/3/35/Macro_Cut_Line.png\">ToolBar Icon</a><br />Author: mario52<br /> ",
    "comment": "Cut a line giving as an argument number cut, create line, bicolor, create point. The new line is created in the real coordinate of object, not in the coordinate of the Body.",
    "code": "#################################################################\n# http://forum.freecadweb.org/viewtopic.php?f=3&t=4217&hilit=discretize\n# 08/03/2015 2019/06/17\n\n__title__   = \"cutLine\"\n__author__  = \"Mario52\"\n__version__ = \"00.02\"\n__date__    = \"2019/06/17\"\n\nimport Draft, Part\ndef cutLine(numberOfPoints = 2, createPoint = 1, createLine = 0, biColor = 0):           # create a points of forme\n\n    def createLines(numberOfPoints, points, biColor):                                        # create line\n        biscolor = 0\n        for lin in range(numberOfPoints-1):\n            creaLine = [FreeCAD.Vector(points[lin]),FreeCAD.Vector(points[lin+1])]\n            wire = Draft.makeWire(creaLine,closed=False,face=False,support=None)\n            if biColor != 0:                                                                 # biColor \n                if biscolor == 0:\n                    FreeCADGui.ActiveDocument.getObject(wire.Name).LineColor = (1.0,0.0,0.0) # 255 = 1 (10 = (1/255 * 10 ))\n                    biscolor = 1\n                else:\n                    FreeCADGui.ActiveDocument.getObject(wire.Name).LineColor = (1.0,1.0,1.0) # 255 = 1 (10 = (1/255 * 10 ))\n                    biscolor = 0\n    try:\n        points = []\n        points[:] = []\n        selectionObjects = FreeCADGui.Selection.getSelectionEx()         # getSelectionEx\n        numberOfPoints += 1\n        for selection in selectionObjects:\n            compteur = pas = 0\n            for selectedEdge in selection.SubObjects:\n                    FreeCAD.Console.PrintMessage(selectionObjects[0].SubElementNames[compteur] + \"\\n\")                   \n#                    print( selectionObjects[0].SubElementNames[compteur])# getSelectionEx\n                    compteur += 1                                              \n                    points = selectedEdge.discretize(numberOfPoints)   \n                    if createLine != 0:\n                        createLines(numberOfPoints, points, biColor)\n                    for p in points:\n                        if createPoint != 0:\n                            Draft.makePoint( p.x, p.y, p.z)\n                        FreeCAD.Console.PrintMessage(str(compteur)+\" X\"+ str(p.x)+\" Y\"+ str(p.y)+ \" Z\"+ str(p.z) + \"\\n\")\n#                        print( compteur,\" X\", p.x, \" Y\", p.y, \" Z\", p.z)\n                    pas = 1                                              #\n\n            if pas == 0:                                                 # the not SubObjects\n                selectionObjects = FreeCADGui.Selection.getSelection()   # select all elements\n                FreeCAD.Console.PrintMessage(selectionObjects[0].Name + \"\\n\")\n#                print( selectionObjects[0].Name)                         # getSelection()\n                compteur = 0\n                for ii in enumerate(selectionObjects[0].Shape.Edges): \n                    compteur += 1\n                    points = ii[1].discretize(numberOfPoints)            # discretize the element\n                    for p in points:\n                        if createPoint != 0:\n                            Draft.makePoint( p.x, p.y, p.z)              # create points\n                        FreeCAD.Console.PrintMessage(str(compteur)+\" X\"+ str(p.x)+\" Y\"+ str(p.y)+ \" Z\"+ str(p.z) + \"\\n\")\n#                         print( compteur, \" X\", p.x, \" Y\", p.y, \" Z\", p.z)  # list and display the coordinates\n                    if createLine != 0:\n                        createLines(numberOfPoints, points, biColor)\n    except:\n        FreeCAD.Console.PrintError(\"Error\" + \"\\n\" + \"Give : cutLine(numberOfPoints = 2, createPoint = 1, createLine = 0, biColor = 0)\"+\"\\n\")\n        FreeCAD.Console.PrintError(\"Select the complete shape or separate wire(s) line, circle ...\"+\"\\n\")\n\n#        print( \"Error : Give cutLine(numberOfPoints = 2, createPoint = 1, createLine = 0, biColor = 0)\")\n\n# Example in command line (paste the macro in FC Python console) and write:\n#cutLine(2, createLine = 1, biColor = 1, createPoint = 0)",
    "url": "https://wiki.freecad.org/Macro_Cut_Line",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.02",
    "license": "",
    "date": "2019/06/17",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Cut_Line.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/3/35/Macro_Cut_Line.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FCCamGroover",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro creates a groove in a cylinder for a cam to ride in.<br />The object created is similar to the one shown in this <a rel=\"nofollow\" class=\"external text\" href=\"https://youtu.be/io1JL1U7kUs\">youtube video</a>.<br /><br />Macro version: 2020.06.13<br />Last modified: 2020.06.13<br />FreeCAD version: 019 and above<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/b/ba/Cam-groover-icon-32x32.png\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "This macro creates a groove in a cylinder for a cam to ride in.",
    "code": "# -*- coding: utf-8 -*-\nimport FreeCAD\nfrom FreeCAD import Base\nfrom PySide import QtGui,QtCore\nimport Part, Draft\nfrom math import *\nimport time\nimport math\n\n\n__title__ = \"FC Cam Groover\"\n__author__ = \"TheMarkster\"\n__url__ = \"https://www.freecadweb.org/wiki/Macro_FCCamGroover\"\n__Wiki__ =\"https://www.freecadweb.org/wiki/Macro_FCCamGroover\"\n__date__ = \"2020.06.13\" \n__version__ = __date__\n\nmsg = u\"\"\"FC Cam Groover v\"\"\"+__version__+\"\"\", a macro to create a cam groove in a cylinder, Copyright (c) 2018 by 'TheMarkster'<br/>\n<br/> \nCredit to Gomez Lucio and Laurent Despeyroux for their macro, '3D Parametric Curve Macro', 2015, which provided inspiration\nfor some of the code used herin.  Thanks also to emills2 for his invaluable feedback. All errors are mine, not theirs.<br/>\n<br/>\nThe grooved cylinder produced will be similar to the one depicted in this video: <a href = 'https://youtu.be/io1JL1U7kUs'>https://youtu.be/io1JL1U7kUs</a><br/>\n<br/>\nParameters supported: cylinder height, cylinder radius, groove depth, groove width, strokes per revolution, stroke range, steps (precision) <br/>\n<br/>\nThis file is a supplement to the FreeCAD CAx development system.                                                                            \n<br/>\nThis program is free software; you can redistribute it and/or modify  \nit under the terms of the GNU Lesser General Public License (LGPL)    \nas published by the Free Software Foundation; either version 2 of     \nthe License, or (at your option) any later version.                   \n<br/>                                                             \n<br/>\nThis software is distributed in the hope that it will be useful,      \nbut WITHOUT ANY WARRANTY; without even the implied warranty of        \nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         \nGNU Library General Public License at <a href='http://www.gnu.org/licenses'>http://www.gnu.org/licenses</a> \nfor more details.<br/>                                                               \n<br/>\nFor more information about the GNU Library General Public License     \nwrite to the Free Software Foundation, Inc., 59 Temple Place,         \nSuite 330, Boston, MA  02111-1307 USA                                 \n<br/>\n\"\"\"\ntitle = u\"\"\"Welcome to FC Cam Groover Macro\"\"\"\nicon=QtGui.QMessageBox.Information\ndiag = QtGui.QMessageBox(icon, title, msg)\ndiag.setWindowModality(QtCore.Qt.ApplicationModal)\ndiag.setTextFormat(QtCore.Qt.RichText); \ndiag.exec_()\n\nwindow = QtGui.QMainWindow()\n\ndef say(msg):\n    FreeCAD.Console.PrintMessage(msg);\n\ndef processEvents():\n     time.sleep(0.001)\n     QtGui.QApplication.processEvents()\n\ndef getDouble(txt1,txt2,default,start=0,decimals=4):\n    inp,ok = QtGui.QInputDialog.getDouble(window, txt1,txt2,default, start,1000000, decimals)\n    if ok:\n        return inp\n    else:\n        raise StandardError('User canceled')\n\ndef getInt(txt1,txt2,default):\n    inp, ok = QtGui.QInputDialog.getInt(window, txt1,txt2,default, 1, 100000, 1)\n    if ok:\n        return inp\n    else:\n        raise StandardError('User canceled')\n\n\ndef getDistance3d(x1, y1, z1, x2, y2, z2):\n    return math.sqrt((x1 - x2)**2 + (y1 - y2)**2 + (z1 - z2)**2)\n\nradius = getDouble(u'Radius of Cylinder',u'Enter radius of cylinder (in mm).\\nMake sure it\\'s big enough or the operation will fail:',10)\ncylinderHeight = getDouble(u'Height of Cylinder', u'Enter the height of the cylinder. (in mm)\\n(Can be adjusted after the macro finishes.)',10)\ndepth = getDouble(u'Depth of Groove', u'Enter the depth of the groove to be cut into the cylinder (in mm):',2)\nslotHeight = getDouble(u'Height of Groove',u'Enter the height of the slot to be cut into the cylinder.\\n\\nNote: this is not the stroke length, which will be input below. (in mm) ',2)\ninnerRadius = radius-depth\nstrokeFactor = getDouble(u'Stroke Length',u'Enter the axial length of the stroke: (in mm)',5)\nstrokeFactor /= radius\nstrokesPerRevolution = getInt(u'Strokes per Revolution',u'Enter the number of strokes per revolution of the cylinder.\\n1 or 2 seems to work okay, but anything beyond 3 could be troublesome:', 2)\nsteps = getInt(u'Steps',u'Enter number of steps (points) in curve, the more points the more precise the curve,\\nbut the longer to process.  If it\\'s too small the operation *will* fail.\\nExperiment with this value if you are having trouble with a particular groove.\\nThe default is 628:',628)\n\n#inspiration for this makeBSpline function is from the 3d parametric curve macro\n#it is not an exact copy/paste of the code, but rather is based on the same principles\n#but without overhead of the gui\n\n\ndef makeBSpline(strokesPerRevolution,strokeFactor,radius,steps):\n    a = strokesPerRevolution\n    b = strokeFactor\n    c = radius\n    interval = (2*math.pi)/float(steps)\n    points=[]\n    t = 0.0\n    maxT = 2*math.pi\n    counter=0\n    while t <= maxT:\n        say(u'Step '+str(counter)+u' of '+str(steps)+u'\\n')\n        counter +=1\n        processEvents()\n        x = math.cos(t)*c\n        y = math.sin(t)*c\n        z = math.sin(t*a/2.0)*math.cos(t*a/2.0)*c*b\n        points.append(App.Vector(x,y,z))\n        t += interval\n\n    Draft.makeBSpline(points,closed=True,face=False)\n    say(u'Done with BSpline\\n')\n    processEvents()\n\n\nif not App.ActiveDocument:\n    App.newDocument()\ntoBeRemoved=[] #temporary objects to be removed to clean up tree\nsay(u'Making BSpline...\\n')\nprocessEvents()\nmakeBSpline(strokesPerRevolution,strokeFactor,radius,steps)\nApp.ActiveDocument.recompute()\nbs = App.ActiveDocument.ActiveObject\n\n\n\n#we use an array of circles aligned along the bspline to create a new\n#bspline that closely follows (but is not exact copy of) original bspline\n#each circle has a vertex, similar to the seam line of a cylinder\n#these vertices are used to create a list of points from which the new\n#bspline is created\n#simply moving the original bspline along the z axis does not work because\n#the groove will narrow in places and widen in others.  the circles ensure\n#better (though probably still not perfect) uniformity of the groove\n\n\nDraft.makeCircle(slotHeight,face=False)\ncir = App.ActiveDocument.getObject('Circle')\ncir.Placement=App.Placement(App.Vector(0,0,0), App.Rotation(90,0,0), App.Vector(0,0,0))\nApp.ActiveDocument.recompute()\nsay(u'Making a draft path array of '+str(steps)+' circles, waiting for FreeCAD...\\n')\nprocessEvents()\ntry:\n    Draft.make_path_array(cir,bs,count=steps,align=True,align_mode='Tangent',tan_vector=App.Vector(0,0,1),force_vertical=True)\nexcept:\n    title = u\"\"\"Potential incompatibility with this version of FreeCAD\"\"\"\n    msg='There is a potential incompatibility with this version of FreeCAD.  If the groove does not appear correct after processing completes \\\nupdate to version 0.19 or later and try again.'\n    icon=QtGui.QMessageBox.Information\n    diag = QtGui.QMessageBox(icon, title, msg)\n    diag.setWindowModality(QtCore.Qt.ApplicationModal)\n    diag.setTextFormat(QtCore.Qt.RichText); \n    diag.exec_()\n    Draft.makePathArray(cir,bs,count=steps,xlate=None,align=True)\nApp.ActiveDocument.recompute()\npa = App.ActiveDocument.getObject('PathArray')\npoints = []\nfor v in pa.Shape.Vertexes:\n    points.append(v.Point)\nDraft.makeBSpline(points,True,None)\nbs1 = App.ActiveDocument.ActiveObject\nApp.ActiveDocument.recompute()\n\nsay(u'Scaling bspline1...\\n')\nprocessEvents()\nDraft.scale([bs],FreeCAD.Vector(innerRadius/float(radius),innerRadius/float(radius),1.0),center=FreeCAD.Vector(0.0,0.0,0.0),copy=True)\nbs2 = App.ActiveDocument.ActiveObject\nsay(u'Scaling bspline2...\\n')\nprocessEvents()\nDraft.scale([bs1],FreeCAD.Vector(innerRadius/float(radius),innerRadius/float(radius),1.0),center=FreeCAD.Vector(0.0,0.0,0.0),copy=True)\nbs3 = App.ActiveDocument.ActiveObject\n#now make the original bsplines bigger so they extend outside the cylinder edges (to prevent issues with boolean cut later on)\nDraft.scale([bs],FreeCAD.Vector(1.05,1.05,1.0),center=FreeCAD.Vector(0.0,0.0,0.0),copy=False)\nsay(u'Scaling bspline2...\\n')\nprocessEvents()\nDraft.scale([bs1],FreeCAD.Vector(1.05,1.05,1.0),center=FreeCAD.Vector(0.0,0.0,0.0),copy=False)\nsay(u'Making ruled surfaces.')\nprocessEvents()\nFreeCAD.ActiveDocument.addObject('Part::RuledSurface', 'Ruled Surface')\nFreeCAD.ActiveDocument.ActiveObject.Curve1=(bs1,['Edge1'])\nFreeCAD.ActiveDocument.ActiveObject.Curve2=(bs3,['Edge1'])\nFreeCAD.ActiveDocument.ActiveObject.Orientation = u\"Forward\"\nrs = FreeCAD.ActiveDocument.ActiveObject\nsay(u'.')\nprocessEvents()\nFreeCAD.ActiveDocument.addObject('Part::RuledSurface', 'Ruled Surface')\nFreeCAD.ActiveDocument.ActiveObject.Curve1=(bs2,['Edge1'])\nFreeCAD.ActiveDocument.ActiveObject.Curve2=(bs3,['Edge1'])\nFreeCAD.ActiveDocument.ActiveObject.Orientation=u\"Forward\"\nrs1 = FreeCAD.ActiveDocument.ActiveObject\nsay(u'.')\nprocessEvents()\nFreeCAD.ActiveDocument.addObject('Part::RuledSurface', 'Ruled Surface')\nFreeCAD.ActiveDocument.ActiveObject.Curve1=(bs1,['Edge1'])\nFreeCAD.ActiveDocument.ActiveObject.Curve2=(bs,['Edge1'])\nFreeCAD.ActiveDocument.ActiveObject.Orientation=u\"Forward\"\nrs2 = FreeCAD.ActiveDocument.ActiveObject\nsay(u'.')\nprocessEvents()\nFreeCAD.ActiveDocument.addObject('Part::RuledSurface', 'Ruled Surface')\nFreeCAD.ActiveDocument.ActiveObject.Curve1=(bs2,['Edge1'])\nFreeCAD.ActiveDocument.ActiveObject.Curve2=(bs,['Edge1'])\nFreeCAD.ActiveDocument.ActiveObject.Orientation = u\"Forward\"\nrs3 = FreeCAD.ActiveDocument.ActiveObject\nsay(u'. Done.\\n')\nprocessEvents()\n\ntoBeRemoved.extend([bs.Name,bs1.Name,bs2.Name,bs3.Name,rs.Name,rs1.Name,rs2.Name,rs3.Name,pa.Name,cir.Name])\n\nApp.ActiveDocument.recompute()\n\nsay(u'Building shell...\\n')\nprocessEvents()\ntry:\n    _=Part.Shell([App.ActiveDocument.getObject(rs3.Name).Shape.Faces[0], App.ActiveDocument.getObject(rs2.Name).Shape.Faces[0], App.ActiveDocument.getObject(rs.Name).Shape.Faces[0], App.ActiveDocument.getObject(rs1.Name).Shape.Faces[0], ])\nexcept:\n    say('Exception making shell.  You might try increasing the number of steps, which sometimes helps.\\n')\n    raise StandardError('Exception creating shell object.')\nif _.isNull(): raise RuntimeError('Failed to create shell')\nApp.ActiveDocument.addObject('Part::Feature','Shell').Shape=_.removeSplitter()\ndel _\nshell = App.ActiveDocument.ActiveObject\ntoBeRemoved.extend([shell.Name])\n\n\nApp.ActiveDocument.recompute()\n\nsay(u'Making shell into a solid...\\n')\nprocessEvents()\n\n__s__=App.ActiveDocument.Shell.Shape\n__s__=Part.Solid(__s__)\n__o__=App.ActiveDocument.addObject(\"Part::Feature\",\"GrooveFeature\")\n__o__.Label=\"GrooveFeature\"\n__o__.Shape=__s__\ndel __s__, __o__\nshellSolid = App.ActiveDocument.ActiveObject\nApp.ActiveDocument.recompute()\n\nsay('Building cylinder...\\n')\nprocessEvents()\nApp.ActiveDocument.addObject(\"Part::Cylinder\",\"Cylinder\")\nApp.ActiveDocument.ActiveObject.Label = \"Cylinder\"\nApp.ActiveDocument.getObject(\"Cylinder\").Radius = str(radius)\nApp.ActiveDocument.getObject(\"Cylinder\").Height = str(cylinderHeight)\ncylinder = App.ActiveDocument.ActiveObject\n\n\nshellSolid.Placement=App.Placement(App.Vector(0,0,-slotHeight/2.0), App.Rotation(0,0,0), App.Vector(0,0,0)) #center groove in cylinder\ncylinder.Placement=App.Placement(App.Vector(0,0,-cylinderHeight/2.0), App.Rotation(10,0,0), App.Vector(0,0,0)) #rotate slightly to move the edge lines apart\n\nApp.ActiveDocument.recompute()\n\nsay(u'Cleaning up temporary objects.')\nprocessEvents()\nfor tbr in toBeRemoved:\n    App.ActiveDocument.removeObject(tbr)\n    say(u'.')\n    processEvents()\nsay(u'. Done.\\n')\n\nApp.ActiveDocument.recompute()\nGui.SendMsgToActiveView(\"ViewFit\")\n\nmsg=u\"\"\"\nDone.  Last thing you need to do is the boolean cut from the Part workbench, cutting Groove Feature from the cylinder, \nif all looks good.  It is recommended to check the geometry via the Part workbench menu with RunBoPCheck = True enabled \nin Tools -> Edit Parameters -> Preferences -> Mod -> Part -> CheckGeometry.  If the check fails, go back and do it again \nwith a different number of steps.  Sometimes it might be necessary to adjust the z-position Placement of the Groove Feature.\n\"\"\"\ntitle=u'Thanks for using FC Cam Groover'\nicon=QtGui.QMessageBox.Information\ndiag = QtGui.QMessageBox(icon, title, msg)\ndiag.setWindowModality(QtCore.Qt.ApplicationModal)\ndiag.setTextFormat(QtCore.Qt.RichText); \ndiag.exec_()",
    "url": "https://wiki.freecad.org/Macro_FCCamGroover",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_FCCamGroover",
    "version": "2020.06.13",
    "license": "",
    "date": "2020.06.13",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Cam-groover-icon-32x32.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/b/ba/Cam-groover-icon-32x32.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FCCircularText",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro makes use of the <a href=\"/Draft_ShapeString\" title=\"Draft ShapeString\">Draft ShapeString</a> tool to create a text line placed in different circular orientations, including circumferential and helical (in the fashion of a Trajan Column). It can also be used to create a clock face with Arabic numerals <i>1, 2, 3,</i> etc., or Roman numerals <i>I, II, III,</i> etc.<br /><br />Macro version: 0.22e<br />Last modified: 2024/07/11<br />FreeCAD version: 0.19 and more<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/c/c1/FCCircularTextButtom.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "This macro creates a text around a cylinder or along a path line",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2014 2015 2016 2017 2018 2019 2020 2021 2022 <mario52>  *\n*                 2023 2024                                               *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*   http://www.freecadweb.org/wiki/index.php?title=Macro_FCCircularText   *\n*           WARNING! All changes in this file will be lost and            *\n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n## FCCircularText.FCMacro    # Icon fromTheme FreeCAD\n## ver 0.14-2 #00.14-4 #00.15 (rmu)#00.16 #0.16b #0.16c #0.16d #0.17 2020/09/26 #0.17b 2020/09/28#0.18 2021/01/19 #0.19 2021/03/15 #0.20 2021/04/05\n## 0.21 2022/05/31 # 0.22 2022/06/06 # 0.22b 2023/11/15 # 0.22c 2023/11/17 # 0.22d 2024/07/11 # \n##\n###################################################################################################\n##\n##OS: Windows 10 build 19045                                 #OS: Windows 10 build 19045\n##Word size of FreeCAD: 64-bit                               #Word size of FreeCAD: 64-bit\n##Version: 0.21.2.33771 (Git)                                #Version: 0.22.0dev.34667 (Git)\n##Build type: Release                                        #Build type: Release\n##Branch: releases/FreeCAD-0-21                              #Branch: main\n##Hash: b9bfa5c5507506e4515816414cd27f4851d00489             #Hash: af5b8714a8371162addb97dd25c29250fcecf7ad\n##Python 3.8.10, Qt 5.15.2, Coin 4.0.1, Vtk 8.2.0, OCC 7.6.3 #Python 3.10.12, Qt 5.15.8, Coin 4.0.0, Vtk 9.2.5, OCC 7.6.3\n##Locale: French/Mars (fr_MA)                                #Locale: French/Mars (fr_MA)\n##\n###################################################################################################\n#\n__Title__    = \"FCCircularText\"\n__Author__   = \"Mario52\"\n__Version__  = \"0.22e\"\n__Date__     = \"2024/07/11\" #YYYY/MMM/DD\n\n__Comment__  = \"This macro creates a text around a cylinder or along a path line\"\n__Web__      = \"https://forum.freecadweb.org/viewtopic.php?f=3&t=7384%22\"\n__Wiki__     = \"https://wiki.freecadweb.org/Macro_FCCircularText\"\n__Icon__     = \"https://wiki.freecadweb.org/images/c/c1/FCCircularTextButtom.png\"\n__IconL__    = \"/usr/lib/freecad/Mod/plugins/icons/FCCircularTextButtom.png\"\n__IconW__    = \"C:/Users/YourUserName/AppData/Roaming/FreeCAD/Macro\"\n__Github__   = \"https://gist.github.com/mario52a/a25e802498bae6959335\"\n__Help__     = \"start the macro and follow the instructions\"\n__Status__   = \"stable\"\n__Requires__ = \"freecad 0.19 and higher\"\n__Communication__ = \"https://wiki.freecadweb.org/index.php?title=User:Mario52\"\n#\n\nimport PySide2\nfrom PySide2 import (QtWidgets, QtCore, QtGui)\nfrom PySide2.QtWidgets import (QWidget, QApplication, QSlider, QGraphicsView, QGraphicsScene, QVBoxLayout, QStyle)\nfrom PySide2.QtGui import (QPainter, QColor, QIcon)\nfrom PySide2.QtSvg import *\n\nimport Draft, Part, FreeCAD, math, PartGui, FreeCADGui\nfrom math import sqrt, pi, sin, cos, asin, degrees, radians, tan\nfrom FreeCAD import Base\nimport os, time, sys\n\nApp=FreeCAD\nGui=FreeCADGui\n\ntry:\n    import webbrowser\nexcept Exception:\n    None\n\n#### Detect version macro ########################################### #22/03/2021\ntry:\n    import urllib\n    from urllib import request\nexcept Exception:\n    print(\"Not access urllib\")\n\n#### Detect version macro ########################################### #22/03/2021\ndef vesionSearch():\n    try:\n        contentPage = request.urlopen(\"https://wiki.freecadweb.org/Macro_\" + __Title__).readlines()\n        versionDetect = dateDetect = \"\"\n        effacer = 0\n        for i in contentPage:\n            if \"ctEven macro-version\" in str(i):\n                versionDetect = str((str(i).split(\">\")[1]))\n                versionDetect = versionDetect.split(\"\\\\\")[0]\n            if \"ctEven macro-date\" in str(i):\n                dateDetect = str((str(i).split(\">\")[1]))\n                dateDetect = dateDetect.split(\"\\\\\")[0]\n            if (versionDetect != \"\") and (dateDetect != \"\"):\n                break\n        try:\n            if (versionDetect == __Version__) and (dateDetect == __Date__):\n                None\n            else:\n                msg = (\"New version availlable : \" + \"\\n\" + \n                      str(versionDetect) + \":\" + str(dateDetect) + \"\\n\" + \n                      \"You can install with AddonManager\")\n                FreeCAD.Console.PrintMessage(\"your actual version    : \" + str(__Version__) + \" : \" + str(__Date__) + \"\\n\")\n                FreeCAD.Console.PrintMessage(\"new version availlable : \" + str(versionDetect) + \" : \" + str(dateDetect) + \"\\n\")\n                diag = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Information, 'New Version', msg)\n                diag.setWindowModality(QtCore.Qt.ApplicationModal)\n                diag.setWindowFlags(PySide2.QtCore.Qt.WindowStaysOnTopHint)  # PySide cette fonction met la fenetre en avant\n                diag.exec_()\n        except Exception:\n            None\n        return versionDetect, dateDetect\n    except Exception:\n        FreeCAD.Console.PrintError(\"Not search version not connected for testing or internal error\" + \"\\n\")\n#\nglobal switchVersionSearch; switchVersionSearch = 0  # Search version switchable in \n                                                     # Tools/Edit parameter/BaseApp/Preferences/Macros/FCMmacros/FCCircularText\nswitchVersionSearch = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"switchVersionSearch\")\nif switchVersionSearch == 1:\n    vesionSearch()\n#### Detect version macro ###########################################\n\nimport sys,traceback\ndef sayexc(mess=''):\n    exc_type, exc_value, exc_traceback = sys.exc_info()\n    ttt=repr(traceback.format_exception(exc_type, exc_value,exc_traceback))\n    lls=eval(ttt)\n    l=len(lls)\n    l2=lls[(l-3):]\n    FreeCAD.Console.PrintError(mess + \"\\n\" +\"-->  \".join(l2))\n\nimport os\nimport platform\nglobal verPython ;  verPython = sys.version_info\n\nclass ConfigManager():\n\n    def __init__(self,name):\n        self.name=\"Plugins/\"+name\n\n    def get(self,param,default,defaultWindows=None,defaultMac=None):\n            global verPython\n            os=platform.system()\n            #os='Linux'\n            #os='Windows'\n            #os='Darwin'\n            v=False\n            if not defaultWindows:\n                defaultWindows=default\n            if not defaultMac:\n                defaultMac=default\n            if os =='Windows' :\n                default= defaultWindows\n            if os =='Darwin' :\n                default= defaultMac\n\n            if verPython.major < 3:\n                if default.__class__ == unicode:\n                    default=str(default)\n            else:\n#                encoder = str(encoder)\n#                return encoder\n                None\n\n            if default.__class__ == int:\n                v=FreeCAD.ParamGet('User parameter:'+self.name).GetInt(param)\n                if not v:\n                    FreeCAD.ParamGet('User parameter:'+self.name).SetInt(param,default)\n            if default.__class__ == float:\n                v=FreeCAD.ParamGet('User parameter:'+self.name).GetFloat(param)\n                if not v:\n                    FreeCAD.ParamGet('User parameter:'+self.name).SetFloat(param,default)\n            if default.__class__ == str:\n                v=FreeCAD.ParamGet('User parameter:'+self.name).GetString(param)\n                if not v:\n                    FreeCAD.ParamGet('User parameter:'+self.name).SetString(param,default)\n            if default.__class__ == bool:\n                v=FreeCAD.ParamGet('User parameter:'+self.name).GetBool(param)\n                if not v:\n                    FreeCAD.ParamGet('User parameter:'+self.name).SetBool(param,default)\n            if not v:\n                v=default\n            return v\n\nglobal ui               ;ui = \"\"\nglobal s                ;s  = \"\"\nglobal points           ;points   = 0.0\nglobal coor_X           ;coor_X   = 0.0\nglobal coor_Y           ;coor_Y   = 0.0\nglobal coor_Z           ;coor_Z   = 0.0\nglobal vec              ;vec      = 0\n\nglobal PolicePath\nglobal originalFontName\nglobal originalFontPath\n\ncm=ConfigManager(\"circular text\")\nPolicePath=cm.get(\"PolicePath\",\"/usr/share/fonts/\",\"C:/Windows/Fonts/ARIAL.TTF\",\"/Library/Fonts/Arial.ttf\")\n\nimport FreeCADGui\nGui=FreeCADGui\nglobal rayon            ;rayon            = 10.0               # radius\nglobal texte            ;texte            = \"FreeCAD the best\" # FreeCad The Best your text\nglobal debut            ;debut            = 0                  # begin text\nglobal rotation         ;rotation         = 360                # must exceed the number of characters of text\nglobal SizeCaractere    ;SizeCaractere    = 2.0                # size font\n\nglobal precision        ;precision        = 0.0                #\nglobal correctionAngle  ;correctionAngle  = 0.0                #\nglobal correctionRayon  ;correctionRayon  = 0.0                #\nglobal debout           ;debout           = 1                  # 1=stand   0=flat\nglobal exterieur        ;exterieur        = 1                  # 1=exteral 0=internal\nglobal baseHelix        ;baseHelix        = 0.0                # base of helix\nglobal endHelix         ;endHelix         = 0.0                # end of helix (heigth)\nglobal pasHelix         ;pasHelix         = 2.0                # Pas of helix\nglobal nombreCarParTour ;nombreCarParTour = 10                 # number char by Pas\n\nglobal PlacementX       ;PlacementX       = 0.0                # Placement character axis X\nglobal PlacementY       ;PlacementY       = 0.0                # Placement characher axis Y\nglobal PlacementZ       ;PlacementZ       = 0.0                # Placement characher axis Z\n\nglobal inclinaisonX     ;inclinaisonX     = 0                  # inclination character axis X\nglobal inclinaisonY     ;inclinaisonY     = 0                  # inclination character axis Y\nglobal inclinaisonZ     ;inclinaisonZ     = 0                  # inclination character axis Z + correctionAngle\n\nglobal cercleClock      ;cercleClock      = rayon              # diameter support clock\nglobal nombreFaces      ;nombreFaces      = 0                  # number Faces of support 0=none 1=circle 2=rectangle 3=triangle 4,5 ... polygon\nglobal romain           ;romain           = 0                  # number type roman or arabic\nglobal redressement     ;redressement     = 0                  # character V or circular\n\nglobal comP             ;comP             = \"\"                 # contener \nglobal nameL            ;nameL            = \"\"                 # contener \nglobal epaisseurExtrus  ;epaisseurExtrus  = 0.0                # epaisseur extrusion caracteres\nglobal epaisSupportClock;epaisSupportClock= 0.0                # epaisseur extrusion support clock\n\nglobal compount1        ;compount1        = 0                  # cree un compose des caracteres\n\n#### for delete last object\nglobal FcString         ##;FcString        = \"\"                 # conteneur\nglobal FcStringPoints   ##;FcStringPoints  = \"\"                 # conteneur\nglobal circleGuide      ##;circleGuide     = \"\"                 # cercle guide repere\nglobal helixGuide       ##;helixGuide      = \"\"                 # helix guide repere\nglobal suppExtrude      ##;suppExtrude     = \"\"                 # extrusion support clock\nglobal createCompound   ##;createCompound  = \"\"                 # compound texte\nglobal selComplete      ##;selComplete     = \"\"                 #     \n#### for delete last object\n\n# pointColor\nglobal red              ;red   = 1.0  # 1 = 255 [ color num x = (1/255)*x ]\nglobal green            ;green = 0.0  #\nglobal blue             ;blue  = 0.0  #\n\n#### section color\nglobal setStyleBase     ; setStyleBase     = \"background-color: QPalette.Base\"\nglobal setStylePathR    ; setStylePathR    = \"background-color: #F8E0E0\"   # Red   (248, 224, 224)\nglobal setStylePathG    ; setStylePathG    = \"background-color: #E0F8E0\"   # Green (224, 248, 224)\nglobal setStyleRed      ; setStyleRed      = \"background-color: #e00000\"   # rgb   (224, 0, 0)\nglobal setStyleOrange   ; setStyleOrange   = \"background-color: #ffa500\"   # rgb   (255, 165, 0)\nglobal setStyleBlueLight; setStyleBlueLight= \"background-color: #c3d0e8\"   # rgb   (195, 208, 232)\n\nif FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/MainWindow\").GetString(\"StyleSheet\") != \"\":\n    setStyleBlueLight = setStylePathR = setStylePathG = setStyleRed = setStyleOrange = setStyleBase\n    #print(\"StyleSheet desactivated\")\n#### section color\n\n#path#################################################################\nglobal path                                                          #\n#path  = FreeCAD.ConfigGet(\"AppHomePath\")                             # path FreeCAD installation\n#path  = FreeCAD.ConfigGet(\"UserAppData\")                             # path FreeCAD User data\n#path  = \"your path\"                                                  # your directory path\nparam = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\") # macro path\npath  = param.GetString(\"MacroPath\",\"\") + \"/\"                        # macro path\npath  = path.replace(\"\\\\\",\"/\")                                       # convert the \"\\\" to \"/\"\n#FreeCAD.Console.PrintMessage( \"Path for the icons : \" + path  + \"\\n\")# \n######################################################################\n##\nglobal setPathLatestDirectoryManual   #; setPathLatestDirectoryManual   = \"C:\\\\ ???\" # mode manuel\nsetPathLatestDirectoryManual = FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetString(u\"setPathLatestDirectoryManual\")\nif setPathLatestDirectoryManual == \"\": setPathLatestDirectoryManual = \"C:/\"\nFreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetString(u\"setPathLatestDirectoryManual\", setPathLatestDirectoryManual)    #*\"C:\\ ???\"\n##\n#### Section Icones ####\n## icon fromTheme by FreeCAD\n## base64 easyw-fc method\n## https://forum.freecadweb.org/viewtopic.php?f=9&t=24742&start=100#p363271\nimport base64\n#FCCircularTextButtom=\\\n#\"\"\"\n#Qk3KGQEAAAAAAIoAAAB8AAAAyAAAAFoAAAABACAAAwAAAEAZAQATCwAAEwsAAAAAAAAAAAAAAAD/AAD/AAD/AAAAAAAA/0JHUnMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAmHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Yd3f/mHd3/5h3d/+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+Xdnb/l3Z2/5d2dv+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5d1df+XdXX/l3V1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+Xdnb/mHd3/5h3d/+Yd3f/l3V1/4JlZf9/Y2P/f2Nj/4xtbf+Uc3P/gWVl/5l3d/+Yd3f/mHd3/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdXX/lnV1/5Z1df+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+Ydnb/jGxs/4FkZP9qUlL/dltb/11KTP8OFBX/BhYd/wAUG/9qUlL/FCYw/xYbH/8RHSb/IyMn/3FXV/8SFRX/DRMU/wYWHf8DFRv/hWZm/3NZWf9pUlL/aVFR/2lRUf+Jamr/lnR0/5h1df+Ydnb/l3V1/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5h2dv99YWH/a1NT/wwYHv9LOzr/HjZB/w8dJv8LHyr/FSIr/xcwPv8THCP/BCAv/wUgLv8UGyD/FRsg/w4eKP8MHin/ER0l/xUbIP8VGyH/DB4p/wweKf8RGR3/Exsh/xQcIv8DIC//BCAv/xUdJP9+YmH/QDMz/w4WGf9LOz3/alJS/3xgYP+XdHT/mHV1/5h2dv+XdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnR0/5Z0dP+WdHT/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5d0dP+Kamr/OS8v/yAuNf8dNUH/Dh4o/wcgLf8UGiD/EB0m/wkfLP8NHij/Ehwj/xIfKP8VHiX/FR8n/xElMf8QJjT/EyUw/xMlMP8RKjn/ESo5/xErOv8RKzr/ESs6/xEqOf8TKDX/FSUw/xUiLP8VICn/Dx8p/xcaHf8ZGBb/Ehwj/wweKv8GIC7/EB0m/2xUU/87Ly//ERca/1tHSP9qUlL/jW1t/5Zzc/+XdHT/l3R0/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Wc3P/lnNz/5Zzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+ScXH/X0lJ/yZGU/8PHSf/Dh4o/xMbIv8PHif/CB8s/xIcJP8VHSP/ESIt/wsnNv8FLD7/BTBD/wYyR/8GNEr/BzdN/wg5Uf8KPFP/FSk3/wtCW/8MRF7/Dkhh/w9JY/8RTGf/EU1o/xNPav8TUGr/E09q/xJOaP8RS2X/D0hh/wxCWv8KPlX/EzJD/xEtPf8UJjH/ESEs/xoWE/8TGyL/DB4q/wYgLf8KGiL/fWFh/2VOTv9ZRkX/dltb/4JkZP+YdXX/lnR0/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/jm1u/0s2NP8QHSb/Exwj/xkZGv8LHyr/BSAu/xMcI/8THib/BSY2/wUqO/8FLD//BS9C/wUxRf8GM0j/BTVL/wY3Tv8KN0z/DjZK/w44Tf8XIiv/ED5U/xFAV/8SQ1v/FEdf/xZLY/8YT2j/G1Rt/x5Zc/8iaoj/Jm6N/ylzkv8rdpX/LHeW/yx3lv8sdZT/J26M/yNohf8dX3v/FlJt/xNDWv8TNkn/Ei9A/xYiKv8WGx//GBgY/xQbIf8JHyv/EB0m/xUbH/9xWFj/lnR0/4tsbP+XdXX/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXNz/5Vzc/+Vc3P/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5h0dP8YBgD/PnaL/y9WZf8QHSb/BSAu/wofK/8THST/BSQz/wUnN/8FKDn/BSo8/wQsPv8LKjr/Dyc2/xIlMf8VICj/FiAo/xMlMf8RKjn/FCc0/xQoNf8SL0D/EjFC/xMzRf8TNUf/FDdK/xU6Tf8VPFD/Fz5S/xgwPf8ZMkD/GjRC/yFOYv8nWnD/K2F4/zeAnf87hqT/RZq7/0qixP9KocP/Rpu8/0GSs/84haT/KnCO/yFif/8SS2X/FTlL/xUpNv8SISz/Ehsh/xYbIP9aRkb/ERUU/w8YHf9tU1P/fF9f/4RlZf+WcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/hGVl/xQbIf8MHin/ER0l/wUgLv8IHyz/Dx4n/wUjMf8FJDP/BSU0/wclM/8SICr/Fh0i/xEhLP8LJzb/BSw//wUvQv8FMUX/BjNI/wY2S/8SKzr/CzhN/wk9Vf8KP1j/C0Jb/w1FX/8OSGP/EExn/xJQa/8UU2//F1dz/xlceP8dYH3/H2SC/yJphv8lbYv/IlZt/yVbcv8iS13/IkZW/zRtg/8/gJn/UaG//1qw0P9nye3/Zsfq/1u32f9Sqsz/PYys/y93lv8cWXT/FEFX/xQtPP8WICj/Ehsh/wseKv8MHin/ABIY/45tbf+Xc3P/hWZm/5d0dP+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv9sU1P/Fxod/xkZGf8QHSb/BCAu/xQcIf8FIS7/BSEu/wYgLf8SHCP/Exwi/wYjMf8FJjb/BSk5/wUrPf8FLUD/BS9D/wYyRv8GNEn/BjdN/xYiKv8IO1P/CT5W/wpAWf8MQ1z/DUZg/w9KZP8RTWj/E1Fs/xVVcf8YWXX/Gl16/x1if/8gZoP/JGuJ/ydvjv8qdZT/Km6K/zB6mP82haX/OYmp/z2Or/83e5b/NXSO/ypTZP89doz/VJy0/27N5v932/P/f+n+/3LW7f9lw97/TKC//zJ6mf8eXXj/FEBV/xUqN/8XHCD/Gxob/0s6Ov8HFx7/GBsf/2xTU/+HZ2f/lnNz/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lXJy/5Vycv+VcnL/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/l3Nz/xoTFP8HDBr/Cx8q/wsfKv8LHyr/ER0k/wUeK/8FHCb/Exof/wYdKP8FIS7/BSQz/wUnN/8FKTr/BSw+/wUuQf8FMET/BjNH/wY1Sv8JNUr/Eyw7/wg8VP8KP1f/C0Fa/wxEXv8OR2H/D0tl/xFOaf8UUm7/FlZy/xhadv8bXnv/HmOA/yFnhf8lbIr/JGB6/xwyPf8YDgP/GRkZ/ydWa/87jq//P5Gy/0KXuP9GnL7/SqLD/06myP9Rq8z/SJSx/z15kP8zYXL/Y7G4/3rV2P+L8PP/j/f//4Dj9f9pxt//TKC9/y92lP8bUmv/FTFB/xMiLf8QHCT/Cx4q/w4cJv9VQUH/lnJy/41sbP+WcnL/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+CY2P/M1pj/0Bzff86aHL/BSAu/wsfKv8RHCP/BRok/xMYHP8FGiT/BR4q/wUiMP8FJTT/BSg4/wUqPP8FLT//BS9C/wUxRf8GM0j/BjZL/xIrOv8LOE3/CT1V/wo/WP8LQlv/DUVf/w5IY/8QTGb/ElBr/xRUb/8XV3P/GVt4/x1gff8fZIH/ImmH/yNge/8XFxn/I1Vq/zB8m/8vc4//GyYs/y5nf/9Ak7T/RJm6/0eev/9AiKX/O3uU/0mWtP9Ytdj/XLrd/2C+4v9hwOL/W7LS/1Kct/84ZnX/c7/C/5Pr6/+c+Pn/l/b+/4Lg8f9fudP/PYyp/yJifv8TP1P/FiMs/xgWE/8nISH/HB0h/yAfIv9tU1P/fF9f/5Bubv+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5Rxcf+UcXH/lHFx/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/3ZaWv8ZGRn/Ch8r/xAbI/8FIC7/Cx8q/xAbIf8MFx3/Cxcd/wQcJv8FICz/BSMx/wUmNf8FKTn/BSs9/wUtQP8FL0P/BjJG/wY0Sf8GN03/FiIr/wg7U/8JPlb/CkBZ/wxDXf8NRmD/D0pk/xU7T/8WPVH/F0de/xhYdf8aXXr/HmJ//yBlg/8ja4n/HDtK/yJTaP8uepn/KmaA/ylgeP8ZGRj/NnyZ/0GVtv9Fmrz/QIup/xUAAP8pT1//FwkA/0uYtf9du97/YMDj/2TE6P9nye3/as3x/27T9/9v0/f/YLbV/1GVq/9mqKz/h83M/6P09P+l/v//j+v2/2vH3f9HmbX/JWaD/xRAVf8VJzP/Ehsi/wsfK/8KHin/ERgb/5Zycv+UcHD/lXJy/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+VcXH/TTs7/xMZHv8qSlf/GBoc/xEdJf8LHyr/EBoh/w0WG/8EGCH/BR0o/wUhLv8FJDL/BSc3/wUpOv8FLD7/BS5B/wUwRP8GMkf/BjVK/wk1Sv8TLDv/CDxU/wo/V/8LQVr/DERe/w5HYf8SQln/GCAl/xkZGP8YR17/GFp2/xtee/8eY4D/IWeF/yRrif8ZFRL/KGmF/y97m/8eOET/ID1K/xogJP8/krP/Qpe4/0edv/8XDAH/PoGc/1Ot0P8zZ3v/QIGZ/1684P9iweX/Zcbq/2nK7v9py+7/OGl7/2fD5f902v7/dt3//3je/f943vr/X63A/0Jwef+Kzs3/o+zs/6r///+U7/n/cM3h/0aXtP8lZoL/FjxP/xQiLP8XGBn/RjY2/25TU/8mIiX/dVlY/5Btbf+VcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+UcHD/lHBw/5RwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/4JjY/8XGRv/Fhkc/xkXFv8QHSb/FBwi/wUgLv8VGh3/DRcc/wQaI/8FHir/BSIv/wUlNP8FKDj/BSo8/wUtP/8FL0L/BTFF/wYzSP8GNUv/ESs7/ws4Tf8JPVX/CkBY/wtCW/8NRV//Dklj/xJDW/8ZICX/GSUt/xdRa/8ZW3j/HWB9/x9kgf8iaYf/JW2L/xkbHP8mXXb/MX6e/zSEpP8nWG3/NHmV/z+TtP9Embr/SJ7A/xYAAP9GkrD/VbHU/yhKWP9DhZ7/X77h/2PD5v9mx+v/aszw/1Ofu/8MAAD/c9j9/3Xb//933v//euH//3vj//995f//fuf//3vg9/9qxNf/VZSg/4HBw/+l7+//qv///5Hu+f9qxdz/QZCt/x9adP8UNkj/GB0h/w0eKP8KHir/IiIn/1RBQf+Ma2v/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5NwcP+TcHD/k3Bw/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//alFR/xUZHf8ZGRn/DxAT/y5WZf8RHSb/Cx8q/xIdJf8HFx//BBsm/wUfLP8FIzH/BSY1/wUoOf8FKz3/BS1A/wUvQ/8GMkb/BjRJ/wY3Tf8WIiv/CDtT/wk+Vv8KQFn/DENd/w1GYP8PSmT/EU1o/xVGXv8WU23/F1h0/xpdev8eYn//IGWC/yNqiP8mb47/IEpd/xkXFv8cLDX/HC02/yJKW/85hqT/QZW2/0WavP9JoML/HCgu/x8xOv8iOkX/MFtt/1263f9gwOP/ZMTo/2jJ7f9rzfH/QXuQ/0qLov9z2P3/dtz//3jf//964f//e+P//33m//9+5///f+j//3/p//+A6f//fuX7/2rD1/9WlaH/jNXW/6X29v+j/P//h+b0/1210f8ye5n/GE1l/xMrOf8PHyn/Ehwk/0g4OP+MaWn/dFhY/5Btbf+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5RwcP9MOzr/DgEA/0WEnP86b4P/KktY/xkaG/8XGhz/CB8s/xMYHP8FHCf/BSEu/wUkMv8FJzf/BSk6/wUsPv8FLkH/BTBE/wYyR/8GNUr/CTVK/xMsO/8IPFT/Cj9X/wtBWv8MRF7/Dkdh/xBLZf8RTmn/FFJu/xZWcv8YWnb/G157/x5jgP8hZ4T/JGyK/yhxj/8rdJP/KGJ7/yhfd/8rZHv/Ooqq/z6Rsf9Cl7j/R5y+/0qhw/9Opcf/PX6X/0CDnP9Ztdj/Xrzf/2HB5f9lxun/acvv/2rM8P8PAAD/XK3L/3Ta/v933f//eeD//3ri//985P//feb//37n//+A6f//asLU/16svP9y0OP/e+H3/3/p//984/v/Xq3B/0RweP96ubj/oPf3/5b2/v9y0ef/SJu5/yJkgP8RO1D/Fh4k/xIXGf8OHSb/JSMo/1VBQv+LaWn/k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//i2ho/xQYGv8RAQD/RYSb/x4tM/8TICn/Exwj/wofK/8FIC7/Dx0n/wsaIv8FIjD/BSU0/wUoOP8FKjz/BS0//wUvQv8FMUX/BjNI/wY1S/8RLDv/CzdN/wk9Vf8KQFj/C0Jb/w1FX/8OSWP/EExm/xJQa/8UU2//F1dz/xlbeP8dYH3/H2OB/yJphv8mboz/KXOR/yx4l/8wfZz/NIKi/ziIqP88jq7/P5K0/0SZuv9Inr//TKTF/1Cpy/9UrtH/V7TW/1y53P9fvuH/Y8Pm/2fI7P9qzPD/U5+7/w4AAP9y1/v/ddv//3je//954f//e+P//33l//995v//f+j//2O2yP8xWGX/MFRc/ytMU/8fKy7/aMDU/33m//985P//e+P//3TX9f9Rlav/VoyR/3/MzP+U9/r/gOX2/1WtzP8weZf/FUhf/xUnM/8QHif/CR8s/wkZIP9RPj7/k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Nvb/+Tb2//k29v/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv9zV1f/FRkd/xkZGf8VGx//Fhoe/wYoOP8QHCT/KFlu/xgaHP8MHin/Exsh/wYgLf8FJjX/BSg5/wUrPf8FLUD/BS9D/wYyRv8GNEn/BjdN/xYjLP8IO1L/CT5W/wpAWf8MQ13/DUZg/w9KZP8RSmT/E1Bs/xVVcf8XWHX/Gl16/x5if/8fZIL/I2qI/ydvjv8qdZT/LXmY/zF/n/81hKT/OYqq/z2PsP9Blbb/RZq8/0mgwv9Npcf/UavN/1Ww0v9Ztdj/Xbve/2C/4/9kxOj/aMru/2vN8f9Be5H/SYmg/3PY/f923P//eN///3rh//974///feb//37n//+B6///Hiou/1OXpf+B6v//WKGx/xcQDv+A6v//feX//3vj//964f//eN7//3bc//9y1vv/Zb/g/0mGmP9cnJ7/jfT4/4Pt+/9fu9j/O4mo/xhUbv8ULz//Fhwg/xsdIP9qUFD/VUFB/3BUVP+QbGz/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/k25u/0w6Ov8XGRv/FRkd/x0qMP8VHST/BCk6/yNJWv8cLDX/Fhsf/xUbIP8FIC7/FRsg/wUmNv8FKTr/BSw+/wUuQf8FMET/BjJH/wY1Sv8KNUn/Eyw6/wg8VP8KP1f/C0Fa/wxEXv8OR2H/EEli/xkbHf8UUGr/FlVx/xksN/8bWXT/HmOA/yBjf/8fUGb/J2+N/yt2lf8vfJv/M4Gh/zeGpv86i6z/PpCx/0KWuP9HnL7/SqLD/06nyf9SrM//VrLU/1q32v9dvN//YcHk/2XG6v9py+//bM/z/0F7kP9esc//dNn+/3fd//954P//euL//3zk//995v//fuf//4Hs//8JAAD/ZLbI/4Hs//8/c37/UJKh/37n//985f//e+P//3ng//933v//ddr//3LX/P9v1Pj/bdD0/2fH6/9GiKD/SoWM/3TR3f984/j/Y8Hi/0GSsv8dXHf/EDhM/xcdIv8PHSf/CB4r/yclKf9vVFT/kGxs/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+Sbm7/km5u/5Jubv+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+JZ2f/SYaT/xcRD/8VGR3/PXWJ/xEiLP8KJjT/JlFj/xEiLP8PIy7/EBoi/wwdKP8JHyz/Ehog/wUpOv8FLD//BS9C/wUxRf8GM0j/BjVL/xEsPP8LN03/CT1V/wpAWP8LQlv/DUVf/w5JY/8UO0//GRwf/xVPaf8YRFn/GTVE/x1hfv8eYX7/GSQr/xkZGf8eQE//KGmE/x0zP/8kT2L/N4io/zqJqf8wa4P/QI+u/0iewP9MpMb/UKnL/1Su0f9YtNb/W7nc/1+94P9jwub/Z8js/2rM8P9szvP/cNX6/3LX/P912///d97//3ng//964v//feX//33m//9/6P//f+n//1KVpP8lOj//N2Js/xcPDP9lucz/feb//3zk//974v//eN///3bd//902f7/cdb6/27S9v9rzvL/aMru/2XG6f9gv+L/Tpy6/zx1if9hs8n/c9f4/2LB5P8+jq7/H2B8/xI6Tv8VHiX/DB4p/xQaH/9ENDT/km5u/45ra/+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5Ftbf+RbW3/kW1t/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/3NWVv9Ac37/GBEO/wcAAP9Kjqf/Byg3/w8YIf82f57/Fycw/w8aIv82gaD/IkNS/xgaG/8KHyv/EiAp/wUtQP8FL0P/BjJG/wY0Sf8GN03/FiMt/wg7Uv8JPlb/CkBZ/wxDXf8NRmD/D0pk/xgoMv8ZHyP/GSIo/xkoMf8ZNEP/HV56/xxKX/8ZHyP/GRwd/yFOYv8ZGxz/HztJ/xkVEv8saID/IDtI/x0tNf8fND7/JEVT/0WUsv9Rq83/UqvN/1aw0v9du97/YL/j/2TE6P9oyu7/as3x/23Q9P9x1fr/c9j8/3bc//943///euH//3vj//995f//fub//3/o//9/6f//feT6/2nA0v9BdID/EwAA/4Dq//995f//e+P//3rh//943v//dtz//3PY/f9w1fn/bdH1/2rN8f9nyOz/ZMTo/2C/4v9cut3/WbbZ/0ydvP83boT/RYOa/2bF6f9at9r/PY2t/x9gfP8PPFH/Fh0j/x8eIv9AMjL/Gh0h/21SUv+Qa2v/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+SbW3/LSUk/xQaH/8VGRz/OW2B/yRCT/8EKTr/IUVV/zmJqf8kTWD/HC85/ytheP8XIin/FRsf/xAdJv8JHyz/Eh0l/wUvQ/8GMkf/BjVK/wo1Sf8TKzr/CDxU/wo/V/8LQVr/DERe/w5IYf8QSGL/GRka/xgoMv8YQVX/GUVa/xkiKP8eYHz/Hllz/xopMf8aKTH/KnGP/xgPBf8ZGRn/I0tc/yNJWv83fpv/Q5i5/ytabv8aHyL/NGyC/0SNqf8tV2j/EgAA/y1UZP9BgJf/Zcbq/2rM8P9rzfL/btL2/3LW+/902f3/dt3//3ng//964v//fOT//33m//9+5///f+j//4Dp//+A6f//gev//z9yff9QkqL/fuf//3zl//974///eeD//3jf//9WoLr/ctf7/2/T+P9sz/P/acvv/2bH6/9iwub/X73h/1u42/9Xs9b/VK7Q/1CpzP9Kn8D/NG6F/z54j/9atdf/UarM/zeFpP8bW3f/DzpP/xIiLf8MHir/CB4r/ywnKv9sUVH/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+RbGz/kWxs/5FsbP+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/4hlZf8TFxn/FRkc/xUZHf89c4j/ESEr/womNP8mUGP/GA4D/xIcJP8WHSL/EyEr/wk3TP8NNEf/FBwj/xEdJf8SHCT/Ex8n/wcyR/8GNUv/ESw8/ww3TP8JPVX/CkBY/wtCW/8NRV//Dklj/xBLZv8VQlj/Fz1R/xhJYP8ZW3j/HWF+/x9jgf8iaIb/JGeD/yhvjP8sd5b/KmiC/ylfdv81gaD/FwQA/zmDoP9Dl7j/P4mn/y1bbv8mRlP/Ghwd/z5+l/8xXW//WLDR/yxRYP9Lkav/aszw/2zP8/9w1Pj/cdX5/3TZ/f933v//eeD//3ri//995f//feb//3/o//9/6P//gOn//4Dp//+A6v//bcfb/3HQ5v995v//fOT//3vj//944P//acPh/xUAAP8uU2H/UZm0/2vO8v9oyu7/Zcbq/2HB5P9evN//WrbZ/1ay1P9SrM7/TqfJ/0uixP9Hnb7/QZKy/y5lfP82boP/TqXG/0abvP8vepn/F1Zx/xA0R/8VHSP/ER0l/xIWFv+GZGT/jmlp/49qav+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/ak9P/xIZH/8aGRj/CAAA/0qPqP8NJDH/Dxki/ytgd/8IJzb/Ex4m/xQbIf8WIiv/BzlP/wc5UP8YKjb/GEBU/xkZGv8THCP/EyAp/w0xRP8WJC7/CTpR/wo9Vf8LQFj/DENb/w5GX/8PSWP/EUxm/xNQa/8VVG//F1h0/xpdef8dYn//IGWC/yNqiP8mb43/KnST/y55mP8xf57/NYSk/zmJqf8pWGz/Ij9N/x81QP8xZnv/Ll1x/x4uNf9Po8P/N2+F/0mSrv9gv+L/PHWL/0qOp/9qzfH/bdD0/3HW+/85aXv/IjU8/3ni//964f//eeD8/33m//9+5v//f+j//3/p//+A6f//gOn//3/p//9/6P//fuf//33l//974///euL//3jf//9Vnrb/GRkY/xYJAP9Zq8n/a83x/2fI7P9kxOj/YL/i/1y63f9Ztdj/VbDT/1Gqzf9Npcf/SaDC/0WavP9Blbb/PY+w/zeEpP8oXHP/MGR5/0OVtv86i6z/Jm2L/xJMZ/8PMEH/Fhwi/wcWG/8AFyH/Niss/4tnZ/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/kGtr/5Bra/+Qa2v/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/5Bra/9KODj/ERkf/xUZHP82Znn/as3x/0SDm/8iR1j/HDVC/wQpOf8gQlL/MXGM/xIrOf8HOU//DDRI/xdCV/8XLDj/FiQu/xAdJv8GIC7/EB0l/xgaHP8SIy//EiQw/xIlMf8SJjP/Eic0/xIqOP8TKzr/Ey8//xYvPv8ZLzz/GTE//xo1Q/8dTWT/H1Fn/yVjfv8rdZT/LnqZ/zOAoP82hqb/Oour/z6Rsv88iKb/QI2s/0ujxP8uXnH/PoCZ/1ez1v8dKjD/PXmQ/0qRrP8gMTn/Y77g/2vO8v9u0vb/ctf8/wAAAP9ty+r/eeD//2i/2f8AAAD/gOv//1CSof+A6v//gOn//4Dp//+A6f//f+n//37n//9+5///feX//3vj//954f//d97//3ff//8aHR//MVlo/0+Xsv9py+//Zsfr/2PC5v9fvuH/W7jb/1i01/9UrtH/T6jK/0ykxv9InsD/RJm6/0CTtP87ja3/OIeo/zSCov8veZf/I1Rp/ypccP84hqX/L3qa/x1gfP8MQ1v/ECk3/xEdJv8FIC7/DRsj/19HR/+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/h2Rk/xIXGf8OCQr/N2l8/zxyhv83Z3r/KkpX/xkWE/8SISv/CCg3/yhZb/8uaoP/CjZL/wc5T/8SKTf/Fk9p/xMrOf8HOVD/EC4+/xYcIf8WGyD/ER0l/xIaH/9iSkv/Zk1P/2ZNT/9mTVD/YUtP/xQjLf8XJjH/Fyo3/wsvQf8GNEj/CDpQ/w00SP8PPFL/EzpO/xU1R/8YPlH/IUNT/yJGV/8uaoP/MW6H/0OYuv9Inb//TKPF/1CqzP9Ur9L/V7TW/0KDnP82an7/Ghwd/1iryv9qzfH/bM/z/3DV+f8yW2r/FAAA/2/P7v954P//U5qu/1SarP9kuMz/SoeV/23I3P9Cd4L/VJmn/4Dq//9/6f//fuf//37m//985P//e+P//3jf//923f//dNr+/3PZ/v9v1Pj/bM/0/2jK7v9lxur/YsHk/1683/9attn/V7LV/1Ksz/9Opsj/S6LE/0acvv9Cl7j/PpGy/zqLrP82hqb/M4Gg/y97m/8rdpX/J22K/x9MYf8oYnr/Lnua/yRrif8UUm3/DDhO/xIhLP8VGyD/FxgY/3VXV/+OaWn/j2lp/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/49qav+Pamr/j2pq/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf9wU1P/Ehkf/zFba/9Egpn/JDxG/xAjLv8SHCT/FBsh/wgoNv8NICv/NHyZ/x08Sv8HOU//BjpQ/xgtOf8WUGv/FiQu/xIrOv8SKjj/FlRw/xg/VP8YISn/Fhsf/zQrLv98XFz/jmlp/45paf+OaWn/kGpq/5Bqav+Qamr/iGRk/39eXf9+Xl7/alBR/2VNT/9LPkT/FCc0/w4vQf8JO1H/EUli/xJAVv8aUGn/GUBU/yVSZf8rVmj/PoKc/0ubuf9YtNf/XLrd/2HA5P9lx+v/aMnt/2rN8f9t0PX/cdX6/z92i/9Ggpb/dNf3/3vk//8nQUj/R4OR/z5wfP9kuMr/KEJJ/xIAAP9AdX//ZLfI/3/o//9+5///feX//3vj//964v//eN7//3Xc//9z2P3/cdX5/23R9f9rzfH/Z8js/2TF6P9gv+P/XLrd/1m12P9VsNP/UarM/02lx/9JoML/RZq8/0GVtv89j7D/OYmq/zWEpP8yf5//LnmZ/yp0k/8ncI7/JGuJ/x9adP8cQVL/JWN+/yRsiv8aXHj/DUVe/w8tPv8UHST/ABcg/wAWIP9XQUL/iWVl/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmlp/45paf+OaWn/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/j2lp/0o4OP8RGR//GRkZ/xAUGf8YGx7/BCk6/yA7R/8YGx3/BSk5/xs1Qv82gJ//Eys6/wc5T/8MNEj/F0JX/xguO/8TKTb/EDFD/xkfI/8YMD7/GSYu/xc8T/8RHCT/BCAu/wAaJf9aQ0P/i2Zm/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/49paf+Qamr/kGlp/31cW/9zVFX/ZUxP/zMxOv8RLDz/CTpQ/xZRa/8URVz/G01k/x1LYP80ZXj/QH2U/0yUr/9pzPD/a87y/27S9v9x1vr/b9Dz/3LV9f943///aMHa/xAAAP89b3z/O2t1/3zj+v8AAAD/TIuZ/xQAAP9luMr/fuf//37n//995f//c9Tu/1CTp/943///ddv//3LX/P9w1Pj/bND0/2nL7/9mx+v/Y8Pm/1++4f9buNv/WLTX/1Sv0f9PqMr/TKTG/0iewP9EmLr/QJO0/zyNrv84h6j/NIKi/zB9nf8sd5f/KXOR/yZujP8iaYf/H2SC/x1hfv8ZSmH/HEVY/yBjgP8bXnv/EU1o/ws5Tv8TIiz/Cx8q/wkfLP8QFhf/aU1N/49paf+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+GYmL/FBcW/xEZH/8WGRz/Fxkb/xMgKf8KJjX/KFlu/xMgKP8IKDf/KVpv/y9rhP8KNkr/BzlP/xIpN/8WT2n/FCcz/xUjLP8QHij/Ei9A/ww/Vv8YO07/FlVx/xdPaf8XLz3/FRsf/xUbIP82LC//bVBQ/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/j2lp/49paf97W1r/cVRV/2RMT/82NUD/CDJF/xNMZf8dWHL/Il12/yFRZv85boP/TpSu/2S83P912///d93//3ng//912PP/ddbv/3/o//+A6v//f+n//1qltf8OAAD/RoCM/4Dr//9+5///fub//3zk//9fsMb/Fhwg/yQ5Qv9pxeb/ctf7/2/S9/9szvP/aMru/2XG6v9iweX/Xrzf/1q22v9Xs9b/UqzP/06myP9LosT/Rpy+/0KXuP8+kbL/Oous/zaGpv8zgaD/L3ub/yt2lf8ocZD/JWyK/yFnhf8eY4D/G157/xhadv8WUWz/FzpN/xpIXf8ZW3f/E1Br/wpAWf8OLDz/FB0k/xQcIv8fHyL/iWVl/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/45oaP+OaGj/jmho/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/21KSf9Vm6r/GhkY/wwCAf9Egpr/DCYz/w4fKv8pWW7/DCYz/w0gK/80epf/MnaS/xUmMf8GOlD/GC06/xhDWP8LNUn/CDhO/xQkL/8XGBn/FyQu/xdOaP8WVXH/FlVy/xcvPP8OMkX/GRkY/xkZGf8JHSf/TTo7/35dXf+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/45oaP+GYmL/e1pZ/2JKTf84NT7/CjRH/xVPaP8dVm//IFVt/ydbcv9De43/Xq3F/3LT7P995v//fuf//3/o//9/6f//ger//4Ls//+B6///f+j//37n//995f//e+P//1Wdsf9PlKv/VZ62/0N9k/9ftNP/P3aK/1msy/9nyOz/ZcXo/2C/4/9cut3/WbXY/1Wx1P9Qqsz/TaXH/0mgwv9Fmrz/QZW2/z2PsP85iar/NYSk/zJ/nv8ueZn/KnST/ydvjv8ka4n/IGaE/x1hf/8aXXr/GFh1/xVUcP8TUWz/E0Rc/xgzQf8VUW3/ElBr/wxDXf8KM0j/FB8o/w4eKP8AFyH/AxUa/3pZWf+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+OaGj/STEv/0iDj/8WGRz/K1Jh/zpvg/8EKTn/GzdE/zV+nP8QIy7/GjVC/zeEpP8qX3b/FCMt/xUjLf8YNEP/Fyw5/wc5T/8GOlD/GCs2/xZXdP8ZKjT/FlVw/xZVcf8WUm3/Eyo4/xUmMf8XQlf/FzxP/xAcJf8EIC7/FB4n/2BGRv+KZWX/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/45oaP+GYmL/ellZ/2NLTv8AIzL/CTpP/yFgfP8hWHH/Jl12/0F7jP9Zo7P/ddfs/4Dq//+A6f//gOn//3/p//9/6P//fuf//33l//995///BgAA/0F4jP8vVGL/SIif/xMAAP8yW2v/CAAA/2jL7/9MlbH/VqzM/1u42/9Ytdf/VK7R/06nyf9MpMb/SJ7A/0SYuv9Ak7T/PI2u/ziIqP80gqL/MH2d/yx4l/8pc5H/Jm6M/yJph/8fZIL/HGB9/xlbeP8XV3P/FFNv/xJQa/8QTGf/Dklj/xQyQ/8VPE//EExm/wxEXf8HOE7/ECYz/wweKf8KHyv/EBgd/2hNTf+OaGj/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+NZ2f/jWdn/41nZ/+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/45oaP8OFBT/GRkZ/xMZHv8+d4z/ERoi/wgoN/8lTmD/NoCf/xkYGP8fOkf/KFds/xQnM/8SHCP/FB8n/xArOv8TKjf/BzlP/ws1Sf8YQFT/Fk9p/xg6S/8WVXH/FlVx/xdFW/8NM0b/GBka/xdKY/8WVXH/F0hf/xkZGf8WIyz/FxcX/wsaIf9rTk7/jWdn/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/45oaP+AXV3/b1JS/0s+RP8EMEL/F1Js/yRhfP8fUmr/QXqK/1WaqP9vyt7/gOr//37n//9+5v//fOT//2W70/8/dIX/Upqy/2K52P9iuNj/GRka/xkZGf8SAAD/T5q1/ytPXv8RAAD/UaTE/1i01/9TrdD/TqbI/0uixP9GnL7/Qpa4/z6Rsv86i6z/Noam/zOBoP8ve5v/K3aV/yhxkP8lbIr/IWeF/x5jgP8bXnv/GFp2/xZWcv8UUm7/Ek9p/xBLZf8OSGL/DEVe/w86UP8UMUH/DkRd/wtCW/8HOVD/Dyk4/xMdJP8VHCL/HCIn/21QUP+GYWH/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jmdn/wMVGv8aGRj/DAMC/0OAl/8MJjP/Dh8q/yhZbf8VFBX/Ehwk/xUfJv8XICf/BzlQ/xErOv8THCP/GBwf/ws1Sf8HOU//Eik3/xZUb/8YPlH/F05n/xZVcf8WVXL/Fy89/w4xQ/8XR13/GENY/xg8T/8XSGD/DjFD/xYsOP8eRlr/Fhkc/w0dKP85LjD/a05O/41mZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jWZm/4VhYf93V1f/YUpN/wApPP8VTWb/KGiE/yZed/86coX/VJmp/3PT6/985P//e+P//3nh//923P//c9j9/3LX/P9Ljqb/FAAA/0qQqv83aXv/Fw4G/xUAAP9On77/MmF0/xsiJv9MpMb/SaDC/0WavP9Blbb/PY+w/zmJqv81hKT/Mn+e/y56mf8qdJP/J2+O/yNrif8gZoP/HWF+/xpdef8YWHX/FVVw/xNRbP8RTWj/D0pk/w1HYP8MRF3/CkFZ/ww6Uf8ULDv/Cz9X/wo/WP8IOU//CS0+/xIdJf8NHin/DR4p/zouMf+GYWH/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/jGZm/4xmZv+MZmb/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+MZmb/UTw8/xcZG/8pTVv/S4+p/wQqOv8cOUf/JE5h/wgnNv8VGyD/FBsh/xMqOP8HOU//DDRI/xg3SP8XISj/BzlP/wY6UP8YKzf/FlZz/xknMf8WVHD/FlVx/xZSbf8TKjj/FSYx/xgzQv8ZOEn/Gk1l/xoyQP8cQlT/H1Bm/yhYbf8vbIT/GCky/wofK/8KHir/Oi4w/2pNTf+NZmb/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/jmdn/3VVVP9gSU3/ACk7/xRMZf8paoX/IVVt/0F7jv9WoLX/bszr/3Xb//9y1/z/cNT4/23R9f9rz/T/Z8ru/ztyh/8ZGRn/OnSK/1Wtz/8WAAD/RpSy/0ykxv9InsD/RJi6/0CTtP88ja7/OIio/zSCov8wfZ3/LXiX/ylzkf8mboz/ImmH/x9kgv8cYH3/GVt4/xdXc/8UU2//ElBr/xBMZ/8PSWP/DUZf/wtDXP8KQFj/CT1V/wg6Uv8TKTf/DjVK/wg8U/8HN03/CS0+/xIdJf8FIC7/FBsh/zwsK/94V1f/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf9qTU3/FBkd/0eIof9lxOf/M2N2/yZSZf8THyf/Byg3/yZQY/8nU2f/CzVJ/wc5T/8SKTb/FlBq/xMqOP8HOU//CzVJ/xhAVP8XT2n/GDA9/xZVcf8WVXH/F0Vb/w0zRf8YICb/F0xl/xYtO/8UGBz/G0RY/yBlgv8gV3D/NHqW/zqLq/86jKz/J1Zp/xcbHv8nVmr/FRYX/zsuL/9qTU3/jWZm/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+OZ2f/dFRU/19ITP8ALkH/GVVv/ydlf/8nX3f/R4Sa/2K62v9w1Pn/bM/z/2jK7v9lxur/Y8To/0+duv9UrMz/KEpY/yZIVf9Npsj/S6LE/0acvv9Clrj/PpGy/zuMrP83hqb/M4Gg/y97m/8rdpX/KHGQ/yRsiv8hZ4X/HmOA/xtee/8ZWnb/FlZy/xRSbv8STmn/EEtl/w5IYv8MRV7/C0Ja/wo/V/8IPFT/CDlQ/wc3Tv8QLDz/DTJF/wc4T/8GNUv/BS1A/xAfKf8OHij/GS05/046Ov99W1v/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tlZf+LZWX/i2Vl/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4VgYP8MAAD/So6o/0J/lv8xWmr/GRQQ/wwlM/8NICv/NHqX/x9CU/8HOU//BjpQ/xguOv8XQ1n/DzBB/wc5T/8SKTf/FlRw/xg+Uv8SN0r/GDdI/xdOZ/8XMD7/DjJE/xgyQf8WVXH/FlRw/xg1Rf8UKDX/GSMp/x5CU/85iaj/Oour/zqLq/8oWW7/FiMs/yldc/8XCAD/DB8q/wweKf87LjH/akxM/4xlZf+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4VgYP9sT0//Sz5F/wA1Sv8iY3//HU5k/y9id/9NlK7/X7na/2TE6P9hv+P/Xbve/1m12P8/gJr/K1Rk/02lx/9JoML/RZq8/0GUtv89j7D/OYqq/zWEpP8yf5//LnqZ/yp1k/8nb47/I2qI/yBmg/8dYX7/Gl16/xhYdf8VVXD/E1Fs/xFNaP8PSmT/DUdg/wxEXf8KQVn/CT5W/wg7U/8HOU//BzZN/wY0Sf8PKjn/Eig2/wY1S/8GMkf/CSo7/xIdJf8DIC//CB8s/wcYH/+BXV3/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/i2Rk/4tkZP+LZGT/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/i2Rk/1g8Of8xXW7/ESEr/w0eKf8YGx3/BSk5/xo0Qf82gqD/Eyo4/wc5T/8MNEf/F0BV/xdIX/8UJzT/CzVJ/xgsN/8WVnL/GCEn/xUuPf8UN0n/FTlM/xkbHf8XHyX/F0hf/xZVcf8WVXH/GDdI/wo2S/8cQVL/KFpu/zqLq/86i6v/Ooqp/xszP/8iSVr/IkVV/zuOr/8uaID/GCw2/w8eKP8UGyH/PS4u/2NISP+FYGD/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+LZGT/hF9f/2ZLTP88OUP/AkJa/x9Zcv8fUGb/P3qQ/1Kkw/9cut3/WLTX/1Gpyv9Jm7v/TKTG/0iev/9EmLr/QJO0/zyOrv84iKj/NIOi/zB9nf8teJf/KXOR/yZujP8iaYf/H2SC/xxgff8ZW3j/F1dz/xRTb/8SUGv/EExn/w5JY/8NRl//C0Nc/wpAWP8JPVX/CDpR/wc4T/8GNkv/BjNI/wUxRf8JLD7/DCw9/wUyRv8FMEP/CSg4/xIdJf8MHin/Fxod/z4vLv9+W1v/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/jWVl/wAZIf8HKDf/HzVA/xMgKP8HKDf/KVlv/y9shv8LNUn/BzlP/xIoNv8WUGr/GSo1/xAvQP8WJC7/GSw3/xg4SP8YMUD/FS06/xUaHv8WMkL/ElFt/xc3SP8WU2//FlVx/xZUb/8VKTX/DzBB/x5HW/8zeZX/Oour/zqLq/80fJj/Ehwk/y9th/8oWW3/L2yF/zuNrf86jKz/GCUu/xYYG/9AhJ//I0BN/wMWHP9lSUj/fVpa/4tjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4tkZP9/W1r/XEdL/wAvQ/8fX3v/Gkdd/zBjeP8/gJn/U6/S/06nyf9LosT/Rpy9/0KWuP8+kbL/O4yt/zeGpv8zgaH/L3ub/yx2lf8ocZD/JGyK/yFnhf8eYoD/G157/xlad/8WVnL/FFJu/xJOav8QS2X/Dkhi/wxFXv8LQlr/Cj9X/wg8VP8IOlD/BzdO/wY1Sv8GM0f/BTBE/wUuQf8NJzb/Dig2/wUvQv8FLT//DCQy/w8dJ/8QHSb/ERsj/1tCQf+MZGT/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4pjY/+KY2P/imNj/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/eVZW/wQVHP8oWW3/DCUy/w0gK/80eZb/IERV/wc5T/8GOlD/GC47/xdEWf8QLj7/Fhoe/xEfKf8MO1H/EDlO/xdIYP8WVnL/F0Vb/xQeJf8ZHB3/GDRD/xZVcf8WVXH/F0tj/w8wQv8WLTn/HkFS/zmJqP86i6v/Oour/yhabv8WIyz/OIal/zR6lv84f5z/Kltv/y5qg/8UGB3/PHyV/z6Amv8mRVL/CwQJ/wsfKv8EGiP/TDg5/29PT/+LY2P/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/hF5e/2RJS/86OET/Ekpj/x9ac/8jTmH/OnqS/0STs/9Fmrz/QZS2/z2PsP85iqr/NYSk/zF/n/8uepn/KnWU/ydvjv8jaoj/IGaD/x1hfv8aXXn/GFl1/xVVcP8TUWz/EU1o/w9KZP8NR2D/DERd/wpBWf8JPlb/CDtT/wc5T/8HNkz/BjRJ/wYyRv8FMEP/BS1A/wUrPf8PIy//DCc2/wUsPv8FKjv/FB4l/wcgLf8KHyv/Ehwk/1g/P/+KY2P/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/dFNU/xUSEP8EKTn/GTNA/zqMrf8oWGz/EC9A/ww0R/8XQVb/FzA+/wc5T/8MNEf/Fhkb/xkRBv8XKDT/FlRw/xZVcf8WUm3/FCo3/xQnM/8XR17/FlVx/xZVcf8YN0n/CjZL/xxAUv8oWW3/Oour/zqLq/86iqn/GzM//yJIWf8fO0f/FgwE/yJFVP85fJf/QIyq/z6EoP9Jmrn/LVdp/2zQ9f9hvN3/SY2m/yVGVP8UAwD/EwAA/z4uLv9kSEj/hF5e/4piYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4tjY/9pS0z/Sz5G/wA7Uv8YT2f/HEle/zFpf/87iKb/PI6v/ziIqP80g6P/MH2d/y14l/8pc5L/JW6M/yJph/8fZIL/HF99/xlceP8XV3T/FFNv/xJQa/8QTGf/Dklj/w1GX/8LQ1z/CkBY/wk9Vf8IO1L/BzhP/wY2S/8GM0j/BTFF/wUvQv8FLT//BSo7/wUoOP8THyj/Byg4/wUpO/8FJzf/FBwi/wkfK/8fNUH/HS01/3dVVf+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+JYmL/iWJi/4liYv+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+JYmL/Vj9A/wwmM/8oWW7/NX6c/yZRZP8PKTf/Fxsg/xdEWv8TKTf/BzlP/ww0SP8YQFX/FlNu/xg1RP8WVXH/FlVx/xdGXP8OMkX/GRgY/xZSbf8WVXH/FlRv/xUpNf8NM0b/HT9Q/ytgdv87jK3/Oour/zV8mf8SHCT/L22G/yxjev82gJ3/KVxy/xQLBP8XBQD/O3yV/1Ksz/9Lj6n/acvv/2nL7/9py+//So6n/0uRq/9RnLj/GRkZ/wsfKv8CGCD/TDg5/2lLS/+LY2P/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+JYWH/fFhY/0s8Qv8AM0f/Fk9p/xlBVf8rYXf/M3ya/zOBof8ve5v/LHeW/yhxkP8kbIr/IWeF/x5igP8bXnv/GVp3/xZWcv8UUm7/Ek5p/xBLZf8OSGL/DEVe/wtCWv8KP1f/CDxU/wg6UP8HN03/BjVK/wYzR/8FMET/BS5B/wUsPv8FKTr/BSc3/wUkM/8UHiX/BSc2/wUmNv8SHib/CR8s/wkfLP8PHif/ABQY/4NdXf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+JYmL/TDc3/yhXbP8lU2f/FiAo/xEcI/8TJjL/FCUx/w4xQ/8HOU//Eik3/xZUcP8XRVv/F0hf/xZVcf8WVXL/FzFA/w4yRP8ZHyT/FlVy/xZVcf8XS2P/DzBB/xQsOf8lbIn/I112/yRRZP8xcoz/LmmC/xcjK/8pXXP/NoGe/zqLq/86i6v/MXKN/xIeJ/87e5T/PoCa/1621v9py+//acvv/2nL7/8wWWn/VKTB/0WEnP9VpMH/SYyl/wAAAP8KIC3/FBwi/wAPD/9dQ0L/fVlZ/4liYv+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/3tYV/9hSEz/AC5C/xJKY/8XPE//Jlhu/ytxjv8qdZT/J2+O/yNqiP8gZYP/HWF+/xpdef8YWXX/FVVw/xNRbP8RTWj/D0pk/w1HYP8MRF3/CkFZ/wk+Vv8IO1P/BzlP/wc2TP8GNEn/BjJG/wUwQ/8FLUD/BSs9/wUpOf8FJjb/BSMx/xMcI/8IIi//BSU0/woiL/8QHSb/DR4p/xcaHf8WGx//bk5O/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGFh/4hhYf+IYWH/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP95Vlb/ZEdH/xMoNP8JN0z/FCUv/xMbIf8VIyz/BzlP/wY6UP8YLTr/FlZy/xgyQP8WVHD/FlVx/xZSbf8UKjf/FCo3/xZTbv8YOEj/F0NY/xc5Sv8IOE3/HEBS/x5IW/8VHCL/JVxz/yhje/8kT2L/KFpv/yJFVP87ja3/Oour/zqLq/8qXXP/Ex8o/0mauf8tWWr/a87z/2nL7/9py+//Ybzd/xMAAP9kwuX/M19w/2G83v9pzPD/a87z/0B7kP81YG7/YbPM/zxvfv8MGiH/PC4w/2ZISP98WFj/iWFh/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+EXV3/YEdK/wAtP/8QRl//FjlM/yFPZP8lbo3/ImmH/x9kgf8cX33/GVx4/xdXdP8UVG//ElBr/xBMZ/8OSWP/DUZf/wtDW/8KQFj/CT1V/wg7Uv8HOE//BjZL/wYzSP8FMUX/BS9C/wUtP/8FKjz/BSg4/wUlNP8FIjD/BR4r/xAcI/8FIS//BSMx/xQcIv8EIC7/Exwj/xcaHv9POTn/iGFh/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+IYGD/iGBg/4hgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+AW1v/VT9B/wo2Sv8QLj7/GD9U/xUnMv8HOU//CjdL/xg5S/8WUWz/GDRE/xZVcf8WVXH/F0Zd/w4yRf8YISf/GDxO/xk/Uv8aVG3/Gz1O/xxAUf8dQ1b/LWd//ydWaf8SERP/HUBP/y1tiP84iKf/LGN6/zqLq/86i6v/Ooqq/x05R/8XISj/Uq3P/0F9lP9qzPD/acvv/2nL7/9Jjab/O3CE/2rM8f9lweP/T5aw/0WDm/9Sn7z/QXuR/1mmvv964f//SYeY/y9WX/8DAAD/Dh4o/w0aIf88LS3/ZUhI/3tYWP+IYWH/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/g11d/19FSP8ALUD/EEZf/xczQ/8eT2X/HmOA/xtee/8ZWnf/FlZy/xRSbv8STmn/EEtl/w5IYf8MRV7/C0Ja/wk/V/8JPFT/CDpR/wc3Tf8GNUr/BjNH/wUwRP8FLkH/BSw+/wUpOv8FJzf/BSQz/wUhLv8FHSn/Fhkc/wQeKv8FIS7/FRsg/wQgL/8PHSf/DRMb/xAZHf+CXFz/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dgYP+HYGD/h2Bg/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+IYGD/X0NC/xcnMf8YQFT/DzFD/wc5T/8QLj//F0xl/xdGXP8XQVb/FlVx/xZVcv8XMkH/DjJE/xkoMf8XQ1n/Exsi/xUgKP8cTWP/IWiG/x9GWP85iKj/Oour/zV+m/8jRlb/FxcZ/ydWav82gZ//Oour/zqLq/82f53/Dh4p/zx7lP9GlLL/V6fF/2nL7/9py+//acvv/zFaav9UpMH/VKG+/wkAAP9CfZP/YbfW/2a/3v9Rlqz/euL//33m//9Vmqj/gev//3bX6/9bp7b/QHN9/0Z+iv8/cXz/Exgb/zstL/9dQkH/cVBQ/4phYf+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4RcXP9dRUn/CTFE/xA9U/8XMUH/GlBp/xhad/8VVXH/E1Fs/xFNaP8PSmT/DUdg/wxEXf8KQVn/CT5W/wg7U/8HOVD/BzZM/wY0Sf8GMkb/BTBD/wUtQP8FKz3/BSk5/wUmNv8FIzH/BSAt/wQcJ/8SGBz/Bhsl/wUgLP8UHCH/BCAu/xEdJf8sUF7/JT1H/3NRUf+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//h19f/4dfX/+HX1//hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+HX1//aUpK/w4TEP8HOU//BzlQ/xYsOf8WVXH/FzND/xQwQP8XQVb/FlJu/xQpNv8UKDT/GD9T/xZVcf8WVHD/GSAl/xUlL/8bMj7/J1hs/zqLq/86i6v/Ooys/x86R/8aLTb/I0ZW/zuMrf86i6v/Oour/ypedP8SHyj/Spu6/zVtg/9mxej/acvv/2nL7/9ivd//FAAA/2TB5P9DgZj/Wq7N/z94jv8PAAD/OWl5/1qowf964v//X7DH/2vD1v+A6f//gOn//4Dp//9NjZr/g+7//2Cvv/89b3r/AgAA/wkfLP8QHSf/AhEQ/19ERP9qS0v/f1pa/4dfX/+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv95VVX/STpA/wAzSP8SMkT/FzhJ/xVOaP8SUGv/EExn/w5JY/8NRV//C0Nb/wpAWP8JPVX/CDtS/wc4T/8GNkv/BjNI/wUxRf8FL0L/BS0//wUqPP8FKDj/BSU0/wUiMP8FHiv/BBok/xIYG/8DGSP/CR4p/xEdJv8FIC7/ER0l/w0eKf8QGyL/eVZW/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/gVtb/zcyOv8NM0b/GDlK/xZRbP8YICb/FTJC/xM9Uv8YIyv/FiAo/xkXFf8WU27/FlVx/xZUcP8WKDT/DDNG/x5IW/8zeJT/Oour/zqLq/85h6b/ERoi/ypgdv8sZHv/Oour/zqLq/86iqr/HTpH/xgkK/9SrdD/O3mR/0WEnP9jv+H/as3x/0qOp/86b4P/Y7/h/0+Ys/9py+//acvv/2C52v8zXm//W6nB/3nh//9HgpT/gu3//4Dp//+A6f//g+7//1KWpP+B6v//UpWj/4Ls//922Oz/W6W1/z1vev8+cX//SISW/xMMDP8MGyL/OSwu/11CQv9yUFD/iWBg/4dfX/+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/eFVV/zYzPP8HNkv/FC8//xU/VP8PTGb/Dkdh/wxEXv8LQlr/CT9X/wk8VP8IOlH/BzdN/wY1Sv8GM0f/BTBE/wUuQf8FLD7/BSo7/wUnN/8FJDP/BSEu/wUdKf8EGCH/ERYa/wQaJf8TGyH/CB8s/wQgL/8VGyD/GhkY/zYpKf+HX1//hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4ZeXv+GXl7/hl5e/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/gFlZ/0g0M/8FLDr/ETZH/xg4Sf8UKDT/FBoe/xU9Uf8SUm3/GCw4/xZVcf8WVXH/F0xk/xAvQP8ULTr/HkFR/zmJqP86i6v/Oour/y1nf/8THSX/LGZ9/yhXa/8ydpH/O4yt/zaAnv8PHSj/PHuU/1Kszv8/gpz/VKvM/0GAl/9Ae5H/KUhV/1mty/9Kj6n/YLrb/2nL7/9py+//as7y/wsAAP9tyub/fOX//1Wbqf+A6f//gOn//4Dp//9luMr/ab/R/4Hr//9Ffor/V56t/27J3P+D7v//YrPE/2rF3v985f//DQAA/woAAP8JDRb/CR8s/xYbH/8TFhb/STQ0/2VHR/9zUFD/f1hY/4deXv+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hl5e/2ZISv8DKTn/DjJG/xUvP/8PQlv/DENd/wpBWf8JPlb/CDtT/wc5UP8HNkz/BjRJ/wYyRv8FMEP/BS1A/wUrPf8FKTn/BSY2/wUjMf8FIC3/BBwn/wgXHv8JFx//Bx4p/w4eKP8FIC7/Fxoe/wIAAP8MICv/ZEZG/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4ZdXf9gQkH/FlVx/xZSbf8YN0j/Fhod/xgoMv8YP1P/FlVx/xZVcf8YOUv/CTdM/xo0Qf8nV2v/Oour/zqLq/86jKz/HjpH/xotNv86jK3/Nn6b/zZ5lP8pWW3/J1Rn/xMQE/9Km7v/NWyB/yxUZP8VDAX/PXiO/1KhwP9cstL/aMru/z94jf9qzfH/acvv/2nL7/9RnLj/MFRg/3vj//9fsMf/a8TW/4Dp//+A6f//gOn//02Mmf+C7f//c9Lm/2i+0P984vn/YbLF/0R7if80XGP/fOX//2O50v8lP0r/as7y/1yy0f9Kj6n/M2Bx/z94jv85a37/FBwi/xAdJ/8QGyL/NSos/15DQ/9rS0v/c1FR/4deXv+GXl7/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4JbW/9UP0P/AC1B/xMpN/8SN0r/CkBZ/wk9Vf8IO1L/BzhP/wY2S/8GM0j/BTFF/wUvQv8FLT//BSo8/wUoOP8FJTT/BSIw/wUeK/8EGiT/Cxgf/xIbIP8NHin/CB8s/wYgLf8THCP/UJKg/ydBR/94VFT/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXV3/hV1d/4VdXf+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4BZWf9DNjr/Fk1m/xdLZP8PMEL/GBgY/xZTbv8WVXH/FlRw/xYoM/8MNEf/HD5O/zN4k/86i6v/Oour/ziHpv8RGyP/Kl5z/x0xO/8WDwr/Jk5f/z2GpP89hJ//R5a0/1GqzP9Ae5L/aszx/1anxP9AepD/EwMA/0qQqv9jv+H/T5ey/2nL7/9py+//acvv/z53jP9ap7//euH//0aCk/+C7f//gOn//4Dp//+C7f//U5el/4Dp//9Rk6H/Lk9W/xMAAP87a3f/YbPH/3ba9P954f//U5mu/0iKo/9py+//acvv/2nL7/9PmbT/YLvc/zRhc/81ZHX/PHGG/wQAAP8OCg7/IjpE/xICAP8XGh3/Exof/zIoKv9fQkL/a0pK/3VRUf9+WFj/h11d/4ZdXf+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP90UVH/LjA8/w0uQP8UKjf/CDxU/wg6Uf8HN03/BjVK/wYzR/8FMET/BS5B/wUsPv8FKjv/BSc3/wUkM/8EHyv/DBsk/xIYHP8THCP/Bx8t/wUgLv8XGh3/GRcV/yVHVf8VGyD/ChQU/4ddXf+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4VcXP+FXFz/hVxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4VcXP9hRET/EBUU/wQlM/8ZKDL/FlVx/xZVcf8XTGX/EC9A/xQsOv8bM0D/M3iT/zqMrP86i6v/LWiA/xIdJf8ua4T/MnWQ/zR8mf8lT2H/FREQ/ytVZv9Jm7r/R5Sy/1enxf9py+//acvv/2nL7/8yXG3/VaTC/0uQqv9gudr/acvv/2nL7/9qzfL/EAAA/2e/2f985f//V5+u/4Dp//+A6f//gOn//2W5yv9pwNL/g+7//1KVo/+A6f//bsjb/1GUov8vU1z/YbTL/3zl//8IAAD/Wq3M/2nL7/9py+//as3x/0J/lv9qzvP/AQAA/2vP9P9qzPD/acvv/1msy/80aoD/RI+s/xcdIv8OExn/DB4q/wkfK/8WGx//GRUS/xYaHv8VGx//LiYp/19CQv9eQkL/dFFR/3VSUv90UVH/hVxc/4ZdXf+GXV3/hl1d/4ZdXf+BWlr/Uj1C/wArPv8VIy3/CzZK/wc2TP8GNEr/BTJH/wQwRP8ELkH/Cig4/wslNP8RISr/Ehgd/xUbIP8QHSb/BCAu/wweKf8YGh3/IT5K/woXIf8UHCL/GRkZ/xUZHf9cQUH/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFxc/4RcXP+EXFz/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/eVRU/w84Sv8WVXH/FlVx/xg6TP8JN0z/GzhH/yZujf8jWHD/JVJl/zR8mP8eOkf/Gi85/yhYbP85h6f/Oour/zqLq/8qYHb/FRsg/0qbu/82boP/ZcTm/2nL7/9py+//Y8Di/xQAAP9kweT/PnaL/2rN8v9py+//acvv/1Gduf8OAAD/e+T//2a91f9Bd4X/WqOz/3LR5P+C7f//To6c/4Ls//9musz/aL7Q/4Dp//+A6f//gOr//1CTof975P//Y7nS/yM6Q/9qzfL/acvv/2nL7/9hvN7/So6o/2jK7v9Yrcz/NGR3/0F+lP9Rm7f/UZy4/0WPrP80a4H/DhEX/zeDo/8uaYL/K2N6/x41QP8pXXP/Fxsf/w8TGf8LHyr/Cx4q/xUbIP8ZFxX/Fhoe/xAdJv8WHSP/Ghsd/xkbHf8YHCD/KCIl/19CQv9fQkL/RTM0/xIjLv8YHSH/Eik3/xQiLP8VGyD/FRsg/xYbH/8RHSX/FBwi/w0eKf8FIC7/DB4p/xgbHv8XLjr/CB8s/xMcI/83aHv/PHGG/xcZG/8TAAD/OWZv/3FOTv+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+EW1v/hFtb/4RbW/+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/dFBQ/zM4RP8WTGX/Figz/ww0SP8eTGD/HDpJ/x1AUP8pbIj/KGF6/yBCUf8xc4//KFdr/zqMrP86i6v/Oouq/x06SP8ZKTL/UavN/z97kf9qzPD/acvv/2nL7/9LkKr/OW2B/2nL8P9Ae5H/ZMLk/2nM8P9py+//PnaL/1Scsv964f//ZbvT/2S5zv932/L/X6/A/0J5hP8+b3r/gev//06OnP+C7P//gOn//4Dp//994/n/Uper/3nh//9Sma3/SImi/2nL7/9py+//acvv/0+YtP9gutv/QX2U/y1WZf9FiKL/U6fG/0+iwf8/gZv/UKnL/xMdJP8kS13/Oous/zqLrP86i6z/Kl1z/ytheP8PFRz/N4Oi/y5ogf8oWW7/HjVA/xw8S/8TKzn/Ehsi/w4cJf8RHSX/GRkZ/xgZGf8LHyr/BSAu/w4eKP8YGx3/Eh4m/wweKf8FIC7/Dx4n/xkZGf8VGR3/Bx8t/wUgLv8XGhz/HzhD/xUlLv8LHyv/Fxod/xkXF/8gPEn/ECMu/xQLCP8+d4z/Ehkf/0F1gP9AeoX/hVxc/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/2FDQ/9BLy//Qi8u/yE6SP8ydpH/IkZW/xYUFP8gRlb/L3WS/zJ2kf8ydZD/Oour/zqLq/83gqD/Dx0n/zt6kv9HlbP/V6jF/2nL7/9py+//acvv/zJdbv9UpMH/aszw/1601P9JiqL/Roef/1qvzv8PAAD/Z8Da/3zk//8oQkf/JD1D/xgZG/9Ojp3/bMfZ/3vh9v+C7f//Upak/4Dp//+A6f//gOn//2O1xv9owNr/e+X//w0AAP9ZrMr/acvv/2nL7/9qzfH/QoCW/2jJ7P8LAAD/Q4GY/y1UY/8SAAD/FQ0J/1Cnyf9Ej6z/EyAo/y5pgv86i6z/Oous/zmKqv8lT2L/L3GN/x0tNv81fZv/NoGf/zuNr/8lU2f/GzxM/ws1Sf8YP1L/F0tj/xdAVf8YMkD/Eiw7/xggJv8YLTr/GC05/xgsN/8YKjX/F0JX/xMaIf8VISr/FiIq/xg9UP8YLDj/FiIr/xYiK/8ZICX/NoCd/xQSFP8IJzf/KVlt/xIZIP8JGyf/S5Cq/wgAAP8XGRr/Fhoe/1s/P/+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/g1pa/4NaWv+DWlr/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4NaWv+DWlr/LThC/ziGpf86i6v/NHuX/xwsNP8cLzj/KFhs/zmIp/86i6v/Oour/ythd/8OIi7/Spy7/zZuhP9lxOf/acvv/2nL7/9kwuT/FQAA/2PA4v9BfJP/HCkw/1Kct/9tzvH/VqK8/2K20f954P7/YLHI/2zF2P9/5/3/a8PV/0uIlf8mPUL/d9ru/2a7zP9ovtD/gOn//4Dp//+A6v//UJKg/3vk//9it9D/ITM7/2rN8v9py+//acvv/2G83v9Kj6j/VaXD/z94jv9py+//acru/2jK7v8/eY7/RI2q/zVthP8OHij/NXya/zqLrP86i6z/M3eU/y1rhP8xeJb/LnWT/yZedv8iVWv/HTxL/xw8S/8VKjf/Eis5/xZSbf8WVXH/FlZy/xkkLP8RLz//GDZH/xZWc/8WVnL/F0lh/xdDWP8XT2n/ES08/wc5T/8OMkX/GEBU/xcsOP8GOlD/BzlP/yRPYf8ua4T/CyY0/xAjLv8ZGBj/KktY/1yz0v9Qmrb/ERke/xgZGv8UGR3/cE1N/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf99Vlb/UTs8/yxke/82gJ7/Eh0m/ypgd/8oV2v/Oous/zqLq/86i6v/HjpH/xcpNP9OpMX/QHyT/2rM8P9py+//acvv/0uRq/85bID/ZMPm/0yTrf9OlrH/JEFN/xseIP9Ad4n/bsvo/3rh//9HgpP/gev//4Dp//+A6f//gu3//1SZp/+A6f//To+c/4Hr//+A6f//gOn//4Lt//9MjaD/eeH//3nh//83Z3r/U6G+/2C62/9qzfL/T5m0/2C62/9DgJf/UZy3/2nL7/9py+//aczw/0WFnf9SrM7/Ehog/xw6SP86i6z/Oous/zqLrP8qXXT/K2N7/xcYGf8XFxj/GiIo/xcfJP8laof/IVly/w0zRv8YKjb/FlVx/xZVcf8WUGv/Fj1Q/xRFXP8XKjX/Fys3/xcoNP8ZHiL/FlJs/xg8T/8KN0v/BzlP/xQnNP8RKjn/FiAo/xYgKP8dMDr/L22G/yNHV/8EKTr/Fh0k/wweKv8bKC//RYSc/z10if8SGR//EBog/xEWFf+DWlr/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JZWf+CWVn/gllZ/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/fVVV/1A6PP9ALi7/Nist/zJ2kf86i6v/Oour/zmIp/8QGiP/L2B0/1GqzP8tVWb/TZSv/2bF6P9qzPD/N2h6/1Skwf9Mkqz/X7nZ/2nL7/9oye3/XbTU/xUAAP9owNr/fOT//1acq/+A6f//gOn//4Dp//9musv/asDT/4Lt//9TmKb/gOn//4Dp//+A6f//aL7R/2G0zP965P//VqC3/2K41/9lvt7/VaG9/zdnef8xWmr/acvu/wQAAP9py+//acvv/2nL7/9oye3/M2d8/0eVs/8TISn/Kl1z/zqLrP86i6z/Ooqr/yZTZv8XJzD/IkVV/zN5lf8taIH/IUFQ/xokKv8bO0v/CzVJ/xg/Uv8WVXH/FlVx/xdAVf8ZGxz/Fx4k/xYfJv8WHiT/D0BX/xgtOv8WVXH/Fyk1/wc5T/8IOE7/GBwg/xYcIf8WHCH/FR4l/zZ/nf86iqr/ERwl/wUpOv8kSlv/FBgc/xEiLf86boP/ERUa/xcZG/8TGR7/Wj4+/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/glhY/4JYWP+CWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP9lRUT/LGJ5/zmHpv86i6v/LmqC/xAhLf9Ejqv/UKfI/0qWs/9VrM7/PXiO/0B6kP8kO0X/X7fY/zxyhv9qzfL/acvv/2nL7/9Snrr/EgAA/3ri//9gscj/bMbZ/4Dp//+A6f//gOn//02Mmv+B6///a8PW/0qFkv9ovtD/e+H2/4Hq//9SlKL/e+L//2S60/8XDQX/EAAA/x8tM/85an3/T5ex/2nK7v9WpsP/P3iN/2nL7/9py+//acvv/1ipx/9EjKj/O3qS/w4eKP81fJr/Oous/zqLrP8zeJT/KVpw/xUfJv8tZn7/Oous/zqLrP84hqb/HUBR/xUqN/8SKzn/FlJt/xZVcf8WVnL/GSMq/w0zRv8YIij/GCk0/xgpM/8ZIyr/F0JX/xZPaf8RLTz/BzlP/w4yRP8YO07/FyMr/xYgKP8XICb/IDxJ/y9shf8LJjT/ECIu/ydUZ/8LJTT/CyY0/zNeb/8QGB7/GBka/xQZHf9mRkb/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BWFj/gVhY/4FYWP+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/98VFP/Tzs9/y1jev8gP03/ESYv/0ygwf8xYHL/GSEm/xspL/9Cgpr/YLze/2XF6P9lxOf/TZSv/2nL7/9py+//acvv/0eIoP9Sma//euH//1OZrP942/D/gOn//4Dp//+C7P//VJmo/4Dp//9sxNf/bcjc/23J3f9TmKj/To6c/0+RpP964f//Upit/0N/lv9mxej/WavK/z51iv8dKC3/a8/z/0SCmf9RnLf/acvv/2nL7/9py/D/Roae/1Ou0f9JnLz/FQAA/zJ2kv83gqH/OYio/ypedP8sZX3/DxYc/zmIqf86i6z/Oous/zFyjf8eR1v/DTNG/xgrN/8WVXH/FlVx/xZQa/8XHiT/DjFD/xdKYf8WVXH/FlVy/xg0RP8WUmz/GD1Q/wo3S/8HOU//FCk1/xdOaP8RLDv/BzlP/w0yRf8ydI7/I0dX/wUpOv8XJCv/JExd/wUpOv8UIiv/Om2A/yM9R/8QFBn/FBcX/4JYWP+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4FXV/+BV1f/gVdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/e1NT/15AQP92UFD/Rzo+/1Catv9mxun/Up+7/ytNW/8eLDL/WKrI/02Urv9fuNn/acvv/2nL7/9py+//LE5c/2fA2/974v//T5Gg/4Hr//+A6f//gOn//2a7zf9qwNP/guz//yU8Qf8LAAD/JD1E/06Qof9rxdz/ddj0/3zl//8YFRT/U6C9/2nL7/9py+//as3x/0OAl/9pzPD/BQAA/2nK7v9py+//acvv/2nK7v8zZnv/TaHB/z6En/9Dka//OX+a/zJvh/8pWGz/KFht/xgpM/8iRVX/Oous/zqLrP86jK3/JVNn/xs7S/8LNUn/GD5S/xZVcf8WVXH/F0FV/xIrOv8VKjf/FlRv/xZVcf8WU2//GCw4/xZVcv8XKTT/BzlP/wg4Tv8XNET/GD5R/wo2Sv8HOU//FSw5/ziFo/8RHij/BSk6/yNKW/8SIi3/BSk6/xgdIf8qS1j/Up67/xQXGf9YPDz/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFdX/4BXV/+AV1f/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv9kQ0P/Q3SJ/1msy/9pyu7/acvu/xUAAP9kweT/O2+D/2rO8v9py+//acvv/1611f8QAAD/eeH//27L5f9ktsf/gOn//4Dp//+A6f//To2a/4Dq//9nvc//ab/R/3vh9v9erLz/MFVd/wcAAP9wz+v/ZLvU/w0AAP9py+//acvv/2nL7/9hvN3/S5Cp/1eoxv8wWWn/as3y/2nL7/9py+//WKnI/0OLpv88fJX/FRwi/xYPCf8aKjP/HjI7/zV7mP81fpv/FR8m/y1mfv86i6z/Oous/ziGpf8eR1r/IWJ9/xklLf8YO03/FlBq/xZRbP8ZIyr/CzVJ/xg2Rv8WVXH/FlVx/xdJYP8YPE//FlBq/xEtPP8HOU//DjJF/xdIX/8XKjb/BzlQ/wg5Tv8YJCv/JlNl/xEhLP8QHij/Kl50/w0gLP8MJjT/ERwk/xcXGP8iN0D/FRkd/25KSv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv99VFT/bUhH/0JKVP85anz/LCYo/1isy/9Mk67/acvv/2nL7/9py+//Roef/1GXrf964f//YrTK/0uJl/9sxNf/feT5/4Ls//9Vmqn/gOn//0+Qnf+A6f//gOn//4Dp//+D7v//SYia/3rh//9Rl6z/Qn6U/2nL7/9py+//acvv/06Xsv9gutv/Z8fr/0KBmf8yXW7/TpWw/1uwz/9Gh5//VbHU/xksNv8dO0r/NX6c/y1mf/8pXXP/GiEk/y1mff8QFh3/OYeo/zqLrP86i6z/NHyZ/x5KX/8dTGL/HVp1/xtVcP8ZPlH/F0BU/xciKv8OMUL/F0ph/xZVcf8WVXH/GDVG/xA3S/8YIir/FyIq/xYiKv8YICb/F0xl/xEsO/8HOU//DTNF/xYeJf8WHSP/GiIn/ziHpv8oWm7/CCg4/xUkLf8uU2H/Fxkb/yQ5Pv83Y23/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/4BWVv+AVlb/gFZW/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/gFVV/3pSUv9+VFT/Wjs5/1Ohvv9oyu7/acvv/2nL7/8rTlz/Z8Db/3vi//9ap7v/bsvh/2vE2f9RlKP/Omdx/2KzxP+C7P//U5im/4Dp//+A6f//gOn//2rA0/9htMz/euP//zlodv9ToL3/acvv/2nL7/9qzfH/Q4CX/2rN8f8nRFD/PniO/06cuf9Sp8f/R5Ku/0WPrP9Jl7b/Ex8o/ypedP86i6z/Oous/zqMrf8mUmX/GS03/yJFVf86i6z/Oous/zqLrP8rYXj/GzxM/xQlMP8ZFhP/Fhga/xYaHv8XQ1j/Eis6/xIrOf8WUm7/FlVx/xZTb/8ZHyP/FyAn/xcdI/8XICj/DzBB/xdIYP8YPlH/CjZK/wc5T/8VKDT/FB8m/w8dJ/8YGx3/LmmB/xo1Qv8FKTr/OGyA/ypPXv8XGx3/asLU/1Y8PP9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1VV/39VVf9/VVX/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP98UlL/bEZE/0NPWv9OmLP/XLLS/xIAAP902Pb/bszl/yQ5Pf8bICH/LExU/1Saqv9wzeD/fuX7/2i+0P9ovtD/gOn//4Dp//+A6f//UpWj/3ng/v9vzur/BwAA/2jK7f9py+//acvv/2G83f9LkKr/VqbE/zJdbv87b4P/HSsy/xMBAP8oT1//U67R/zx8lf8PHSb/NXya/zqLrP86i6z/M3iU/y5shv8iSlv/J1Ro/ziGpv85h6j/Ooyt/xwzP/8UKjf/DzBB/xdIX/8XSF//GEBU/xkbHf8KNkv/GCw4/xZVcf8WVXH/F0lg/xg7Tv8XMD7/Fxwg/xcdIv8ZGhz/F0NY/xcqNf8HOVD/CDhO/yRPYf8xc47/DyEs/w4kMP8pWW7/Dh8q/w0eKv9FhZ3/DgQC/xYbH/8WDQn/bUlJ/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9/VFT/f1RU/39UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/f1RU/3ZPT/9ILSv/aUZG/1o0MP8rSFH/et3y/3vf9f9mu83/QHN+/z9xe/+B6///T5Ge/3/o/v+A6f//gOn//4Ls//9PkaP/euL//1mku/9BfJP/acvv/2nL7/9py+//Tpax/2C62/9FhZz/S5Cq/2nM8P9mxej/XLPT/zNfcP9UsNP/GjA7/x07Sf86i6z/Oous/zqLrP8rYHb/OIen/zN+nf8rbIj/JFdu/yFPZP8fPEr/HDZD/w0zRv8VKzj/FlRw/xZVcf8WUGr/GB4j/xAuP/8YQlb/FlVx/xZVcv8YM0L/FlJt/xg+Uv8LNkr/BjlQ/xUmMf8XS2T/ESw6/wc5T/8NMkX/MnSO/yhXa/8HKDj/FCAo/xkXFf87cIT/XrfX/0J/lv8VGR3/Ehke/xkZGf9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35UVP9+VFT/flRU/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/0wzM/9QjZv/bsjb/37m/P9pwNL/YrLD/4Hs//9UmKf/gOr//4Dp//+A6f//asLU/2G0y/954f//X7HL/z94jf9Yqsn/Zsbp/2rN8v9DgJf/a87z/wgAAP9fuNn/acvv/2nL7/9qzfH/MmV5/0iXtf8THyf/Kl51/zqLrP86i6z/O42u/yZSZv8cKzP/GA8G/xUhKP8dNkL/HTtK/yVujf8bPlD/CTdM/xg3SP8WVXH/FlVx/xdBVf8UTWf/FEJY/xguO/8YLDj/GCs3/xkoM/8WVnL/Fycy/wc5T/8IOE7/FCUx/xQjLf8XICb/FyEo/xopMv82gJ3/GjI+/wUpOv8UHCL/Dh0n/y1TYv9cs9L/KEpY/xcZG/8UGR3/Qi4u/39UVP9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/flNT/35TU/9+U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/flNT/3pRUf9pQkH/T1BW/y9RWP9SU1n/P2p0/2i+0P+A6f//gOn//4Dp//9TlqT/ed/8/27M6P9YpL3/bs7x/2G21f9RmrX/NmV3/0aGnv9VpcL/MFlo/2rM8f9py+//acvv/1ipx/9CiaT/PHyV/w8cJv81fJr/Oous/zqLrP81fZv/JU5g/xUeJf8rYnn/LWV+/y1mf/8aJy7/HDxM/xQpNv8PMEH/F0pj/xZVcf8WVnL/GSYv/xgoM/8XJzH/Fycy/xYrOP8OQVj/GEFV/xZQa/8RLDv/BzlP/w4yRf8YHB//FiAn/xUcIf8XJjD/OYem/zR6lv8NIS3/DCUz/yE/TP8WHiT/EyAq/0aGnv8OBQL/GRkZ/xUZHf9rR0f/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99U1P/fVNT/31TU/99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv9+UlL/dk5O/35TU/9UODj/SoKP/27I2/9/5/3/guz//06Pof974///WKS7/xcaHf8RAAD/Kk1c/0J8kv9ds9L/as3x/0WFnf9Lkav/acvv/2nL7/9py+//R4ef/1Sx1P8cNUH/HTtJ/zqLrf86i6z/Oous/yxlff8qX3X/EBce/ziGpf86i6z/Oous/zV9m/8bNEH/DTNG/xUrOP8WVHD/FlVx/xZQav8YHSH/DTNG/xgeI/8WHyX/GB4j/xgdIf8WUm3/GD5R/wk3TP8HOU//FSk2/xdDWP8WGyD/Fhwh/xgZGv8vbIX/KFdr/wcoOP8VJS7/JU9h/wcoOP8WJjD/PXOI/xUZHf8TGR7/GRkZ/3dOTv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv95T0//aEA+/09SV/9Bcnz/SSEa/z5uff8pRk//SYyl/2C63P9Mkqz/NmZ4/yM4Qf9rz/T/BwAA/1+42f9py+//acvv/2rN8v8xZHj/UarN/zh3kP8gPUv/NHyZ/zmJqv87ja7/JlNm/xozP/8hRVX/Oous/zqLrP86i6z/K2J5/xs9Tv8JN0z/GDdI/xZVcf8WVXH/F0JX/xQnMv8SKjj/FlRv/xZWcv8WVHD/GSs2/xZWcv8XJzH/BzlP/wg4Tv8XNET/GD9T/wo3S/8GOlD/Fi07/ziGpP8aMj7/BSk6/yNLXP8bNkT/BSk6/zdpfP8rTlv/HCYr/xQZHf9SNzf/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fVJS/31SUv99UlL/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fVFR/3hPT/94Tk7/flJS/0kyMv9BfJL/X7nZ/2jK7v9rz/T/Qn6V/1SjwP8wWWj/aszx/2nL7/9py+//WKrI/0GHov9FkrD/QYyp/0CNq/83epX/L2iA/yNJWf8lT2H/EyAo/ylbcf86i6z/Oous/zuMrv8bMDv/FCk2/w8wQf8XSmP/FlVx/xZWcv8ZJzD/DTNF/xgrN/8WVXH/FlVx/xdJYP8XQFX/FlJt/xMrOP8HOU//DjJE/xdIYP8YKDP/BjlQ/wg4Tv8kT2H/NHqX/w0hLf8MJTP/Klxx/w0gLP8MJjT/GRUT/1anxP8/eI7/FRkd/2RCQv98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fVFR/29ISP9iOjb/TkpT/y9RYP9ILCn/PB8X/0uRq/9py+//acvv/2nL7/9Lkar/UKfJ/ypXaf8YDgT/FAQA/x06Rv8kR1b/PI+w/y1ngP8QHSb/NHuY/zqLrP86i6z/NHyZ/x9OZP8dTmX/FiIr/xg/U/8WVHD/FlBq/xgdIf8MNEj/GEBV/xZVcf8WVXH/GDNC/xdKYv8XQ1n/DDVI/wc5T/8SKzr/F05o/xMqOP8HOU//DTNF/yVNXv8lTmD/EiEr/xglLf8lT2H/Byg4/xMgKf8NHin/KEZS/x43Qv9BLC3/dUxM/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3xRUf98UVH/fFFR/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP98UFD/fVFR/3xQUP9wSUn/T01X/zhoev9Qmrb/YLrc/ydBTP85dIz/EBsk/yRKW/8ydZH/LGR7/yhXa/8nVWn/Ikpc/xs3Rf86i6z/Oous/zqLrP8rYnn/IV54/x1NYv8cVm//GlNs/xk/U/8YOEn/FCcy/xIqOP8WU2//FlVx/xZWcv8YJzH/EjRH/xkmLv8WIiv/FiMt/xkkLf8XRVv/DDRH/wc5T/8UJzL/FCEq/xgaHP8pWm//OYmo/xozQP8FKTr/Nmh7/xMIAv8YGRr/QSws/2tGRv97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e1BQ/3tQUP97UFD/e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/98UFD/fVFR/2xGRv9hODT/a0VF/3VLS/8+Kir/JlBj/zqMrf86i6z/NX6c/yNJWv8VHSP/KVtx/zqLrP86i6z/O42u/xw7S/8YHyT/GBoc/xkTDf8YFBH/FSs3/xdGXf8NM0X/GCs2/xZVcf8WVXH/FlBq/xggJ/8WJjH/FiYy/xIsO/8UKjf/FlRw/xgvPf8HOU7/BzlP/xcgJv8RHSb/FBwi/x83Q/8wcYv/DSAt/wslM/9Gh5//EQUA/080NP95Tk7/e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/97T0//e09P/3tPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3ZNTf9sRkb/VjMv/1gyLP8YQlH/bEZG/z4sLf8qXnT/Oous/zqLrP80e5n/GzI+/xEtPf8SKjn/F0pi/xdIYP8YOUr/GBod/ww0SP8YQFX/FlVx/xZVcf8YPlH/F0de/xYvPv8VGyD/Fxoc/xkbHP8WUGr/Eyo4/wc5T/8JN03/LWV9/yJGVv8NJTP/FyQs/yVPYf8IKDj/GR8m/1c1M/9oRET/fFBQ/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pPT/96T0//ek9P/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3xPT/96Tk7/cklJ/2ZAP/9WMi7/TTo+/xU2Qv9qRET/Py80/xkmLv8XQVb/FlVx/xdIX/8VHCD/Eik3/xZUb/8WVXH/FlZy/xkiKf8WVG//Fy88/wc5T/8GOlH/Fygz/xdGXP8MM0f/BzlP/xErOv8sZXz/HTA6/xAjLv8cGhv/Vzg3/1g5OP9rRUX/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/e09P/3pOTv93TEz/aURE/2lERP9WNzX/VDc2/3dNTf9XOTj/GzJB/xMyQf8TLzz/TjMz/1I3OP8SHCH/DyQv/xAjLf9LMTH/IhoY/xAjLf8cJi//Wjo6/2tFRf9fPj7/akRE/3xPT/96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv96Tk7/ek5O/3pOTv95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf97Tk7/e05O/3tOTv96Tk7/eU1N/3tOTv97Tk7/e05O/3pOTv97Tk7/e05O/3tOTv95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eU1N/3lNTf95TU3/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94TEz/eExM/3hMTP94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3hLS/94S0v/eEtL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0tL/3dLS/93S0v/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3dKSv93Skr/d0pK/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/dklJ/3ZJSf92SUn/\n#\"\"\"\n####\noutDoor_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAHNhbS4gbWFycyAyNyAxODoxMDozMyAyMDIxSE9UGQAAAat6VFh0RGVzY3JpcHRpb24AACiRVZJbb5wwEIXf91dYfl98hQUERLkoUqVsVGWbqK8OGRGaYCLbG7b/vraBbeIHpG/O8fF4THVxGt7RJxjbj7rGLKEYgW7Hl153NX78dbvN8UWDNtX+x9Ul8l5ty5Pta/zq3EdJyDRNySSS0XSEU8rI7/3doX2FQW17bZ3SLWDk/aUe79UA9kO1MOt3Y6tcPHNJ+nME04Hemh46eE80OLLvn1X88ORkXzB6Wtvk2LeEqqcepmaDULVXzvQnXwpLMVZjmjCap0WBPfIZBRc0oAhIKc8FCyhrvPWyp4ziJYGzWKRSZjT1Jh4jqBQslwFjBBOZKKI6R/AsZTu5RoglQhS7LHQhlgieZiKgmGWeyTy0IWSUU5bn+Roh2dxpWN4i+XcU31HG15sxBBA/mYosI6oO49G0EId1bUC50TSP+k2Pk67IWjiLfsY3ykFj1ZCgQRmL+A6xvGS0FAJxytmyaTX+36m7w1/rYGhuDcD15Q3ycypW91kM/p/KuPvj8AxfOvlSC5YH+OzDgzf+YhU5U7jXep+KhB+z2fwD3xHBm1Sqc+0AAAAQdEVYdFNvZnR3YXJlAEZyZWVDQURjGmLPAAAAI3RFWHRUaXRsZQBDOi9Qcm92aXNvaXJlNDAwL291dGRvb3IyLnBuZ+0gPY4AABaOSURBVHic7V15eBTFtv/1DAGSD7jIloCgKJDMksSFACrMQ7giuCIuzxhIEAS5vuf23FBCMlkAUa9eFhERAWUJeC+LiCI+31X4AoIQLkiWmQSQsIgJawy5ISTMzPujpnuqu6t7OpOZzCTM75svqa46faqq+zfnnDq9DJeU9CzCCMPfaMNxXLDHEEYrRJhYYQQEbXS6MLHC8D+uCYu1tepH/yq8v/MI/ypsfWg9xPrm4g9KTXHnnwUk02zSrEvxsVLTA9eNbIrmVoMW7Aq3nP8nvWm4MEVMF6Es/+40dcqGC38BALjE1S4AdnwiEX6o65+b2F1LREuyWF+d+z9603BhMk8R+RQ4WYG56bVegItVyYnrOcBluCCkb9xNdiyl93m42z3e+moNCHVibT77vVA2XHhazCQJq1QKzE1mjRIESRer3kVtSsuGC1P5Stet1//21bltws5ju4/SPIAWhhB1hZsq/5cUjBfTAI6cP/47wLRSjWWVz7OWMEmoZHKLsW9y5Gii4ZfTA214mzSMi77X1/GEKELLYm2s+I4UjBdTAQiUUoYWujTFUKn3K/WDsrK8gMsNesAVGeEAKo0XJxE9NnxGWh+NGd3ksYUEQoJYG353e4fkyOEWw6F8+y24CAXSqDtByGq0xli39DrJFPjldG8A2mMsWZnBLTmMF58GXIDLhpWk5rGeY5SEWwSC7Ar/8du3AExVycQ4JUb+trngti4dnGK2azRavsdYiT1PAnA49XLthHCHfu/DV2iPsbyA4+TynKkqjdSUYBWA62wl99zzqkaFIYWgWay/n9oKwFT1JO/v1L2YirliSqoISDcTe54UKKXXOYV6h1MHnm2JPU/y3NIUYxGmCpKHfu/NGoNkd5FtM1VNAFwXjSb8BgD/2ft+hX1DFEEg1hcnvwFgqnpC9dyruDn5LuqsUouxxKxyUJYJiT1PgaIXxS2w6OXhVmLPU5cb9IJAZIQjsecpwEUrp3ZR86fv/xG7zJUEuEqwFsCTfR6QzSVE0ayucO3xrwGY/3iMlbQUgXcTojqFvxIBqSaVzYQYD6vuNu34aHsKParCij4JMSf1Oocgw0q0SjmREHPycoOOFhKidcqMybXJfai7hoiZ/3gKcBVjHYCnbnyQNdPQQvNZrLzyLeY/xgEcEAlcoTyg2w8mxJxUJZMSmh65Q69zfLQ9RV5fWNEHQELMCYdT73DqE2JOkhqZTpd4EwAiIxx00+UGPV8j2Z1prjiZTheA5Mi7AOe6418DSOn7kNJ0QgHNQaw1x74CYP7jEaAtwAiQATTG5fkQY3nPOCTEnCCVMuowd2Rbl4SYE7S5olS5SFNkhBMMqHhDBsx/PAG4isvXAxh/08Oqow0aAu4KVx3dHF89FtBznF7OifjoExK7RUDRPbAxlhwJMSfFFaJzzI9LLcYCb644zmOBiipviI8W0Y5qZWhw17gkHtNlMZQCrqLKPvHVjwGuomMbU/uNVZlOsBBYi7XyyJfx1ZKAQHCCblZdqNELNV06SA40XfB/jCWAmWjQADkzPCiqvIElo6RE7gSZURfW7zVFd7oqVMVXjys6uimt/yM+jT+ACCCxPj+8Kb76PgCAC3Dwf93GiWIVunRwXKhpA+BCjU6sQ8vYmhRj6XUOdQFydpWZ55U3Hsmiyhvio4/zC0Z1bVLKxkcf55kq7Te+emzRkS8BTBwwTttImgOBcoUrSjcmXBpFLe5EJ9vc4zhhVZcODoArPtPX3MPDMzAWjV6Nli/esPjMjVrmYu5x3LMbx3SCkNOL9oNUgRYQmpTZ6fLoiY+mh9EecAKXyVbCpYcBV+HhTZPiHtUyo2ZAQCzWcvuGhEujAR3AsEA0q4rP9BXOsbnHCZayRvk7LazybNKM0UgySolKjlReqcWweSFiZbWeXPYBYO5xovhMb6AdUCcIJFx6oLB042TDY42ZSKCg4/yN5fYNCZckd4NIQyLBMkli9rFJB2V7MXbXvDBUkXGD5BGokUg/5h7HFfwg51W5ciXdpGX9AYuhJLqTI7qTA0Bltd5iOMR/KyIAYVWEhEv3Lbdv8Ps59QF+doVLi/+RWDOSN/LyQ+9Blw6OkrM3UYssDkC+PdG9LVp8CdAes6vszoDDqTf3KC8521dSb+ruMWl6naPkbF+O02KoAHjNpsoFaBmPMDmYS/LvB1ym7scAEHpBdJR0gJPsklgz+pBt/VTzE8xRNRsC4QolfBKxwdT9uE8huVKE3qQYq+RsX1P3cmKQHE49oVHJ2RtBUUpmrpgxlvq9DxIB+b7qjlLaajGUAQCuAPWyvKADaAAjSG1u+JNYSwq/SKy5m5RN3csthsol+UMBaD7ZEqjYJ69OUKs3FHNLp9c5KUp5AkRirsRKvMfvMm6pT1lrQJZvjy05eyPgApzAVb7gmXtijeVQ0d+nJTyp2l1g4WdXSFhq7HbcYjizYkfvacN3fbLTIjSSf+KlH9tdsm6bUTJa8s1GxFgAbOf6GruVwx1vSVYb7nyE7VxfhScyFPNYXr+wHMc0V/Qmp6SHcoL0vp7B3/LvIb8UfvHcLcleBhEw+DN4Jxp5VvUCkG+//tlh+QA0fFk5ABbDIVm9fNO3GIvJYDezbeduGlRRqtc5ZR+H7dxNtnM3KceLGu2uV0ktXxuVAbB78ePJbSz85goXHci75d/DjN3KgTb59h6Thp8GsGLHDRaDysFSgeRINS7GSrv6vUzeC1a2MaRV2OX1g1DqbcfRjYyx5DJySand0pbdAL9CbAO0RVAjLX+6QrJ+sRjOA1i66w5D1xOThp/It/fhpyfzJbKeNxfcSquSiMv+AkBqwz8hw6oIY6MH79NeANIavvNsVLj/74vpz7xBVNQjw7cyiKjsCpl09EjfWjv84IG8FwaOb8Rk/Ad/Bu+GruVARL69q/18P81LP/fH0PWYxVAkEEsm5kFqw4/0pm9s8COYA0itsA3CEbGY57FV/v4ZTTGWKiTCzPx+cIxWgK4Veo0YRDB0/RXgNhfcOjbp4OaC2+R7pTbsEKqCziQtkA/SbVkrAGBfTF/ZHnLXJq2ZOnRrvt0ANpiekQOw8qF0ABO/nqNp3P6D31zh/wxJW/fzykW3XZdv78pxiOtyzGKoWLHjhv7RLoq7HPhLzhdqdIauxwTrzV835OU4bkJ9vrC5uq3nPAUtamga6ClMqLABGIRyAKvb3k1JMbwhKypgXogUtUt2af5HZvxssfLtnS2G87DrSbqBxFh8Iweg9MLNcV3KyfaFGp3gCsnVaACja06hBoNwenVbkx8HFlKgpzahfjtfOVzp1gZviwNJJUu02R2i/11hvr3rkUodEDNp+CmqWtRLlw5O6nIhunRwDKo4A6Cuonsr5hMTwnwn1O/ga6SZvyl3bRHkHx9ckm+PFeuQWC/GCQ0CsfxiJJfe+waAMQdvXnf5WFJ1XP9op8VwJt/ey2I4bTGcLNvdnxfkAK7s4s0AF3ud2w8OqjiLGqxpZxIkrk0IR2DClXy+ZigAjkO+3VxZrXt8cGFlteSxDmbwzkCLd4UA+kc7LIbzy3bfFXtdOV/H6GJQxXlSEA5oGATCARl/ZRdV7Vq/N175qhGDVf9qv/32uqhfiVBLd4XJke3WXT5y++77CJny7b0tBsEhujsaf2U/gDXtzH7st1WCHKLxV3bza8luldXCRRs1+6QQ7Dcr/HutkDtc1Q/tSjiOG9D5qMVQkW/vvXzPCGFdk1J3AEBeezOuYZfXWJDDBSClohjA8j33Ay6OU8rXixbgwk0+LdIVfjTiFVI4XNVvQOejA6uS9rfbmgwjAIvh1OE9A0hrSt1B4RiF4QPI0Uup25fXPomvU0yQ7m/3/cArfYVLAS3bFQ7o/CvQAcDAK8P2Y2ey3WwxnAaQUlcI6psXRlOQ196cUlcAIK/97Uoy+9ttG3glAbgEuB9jbOmuENvePAgcHDN3ZFLlzQUoHrhnXEpdUV77eD92EQY5nil1/wKQ1/5WlVsFj879hRRapCuU40ilvn+0c5Ghw/4DmwYiVJ4baWXg6XUwr30iXb+/3TcDrwwGaunKlu0KBfSPdlgM5+q2xyRFjtrfbmNSfZhbgcLayPiUy4fWRiYAALiCtluS6v/j6NwlAPq/dZ8g1oKJ9fKuhdvefIGULYYzddt7ktkm1T9e0HY9gDC9AoS1kfFPXS589U9lAJLqRx15e4FcpgUTa97QF4Ry3fbuayMThXunkuqTAX1B2zVJ9SHxyFvrw6t/KkuqH/fU5QNH5i0A8NKqqPmpQXaFOo5DEz80kj+MAsBbZhGS6tMK2m4oaLuheSZ27aCg7Yak+icArI10B1sSVgFNPcU+fPwcY617vhbAkbcXDJhB3pwpUj6o4WlAX9B2GYBBDWHr1VTsi9gAYFBDMseR14SIFoZH3v5WKAfFFTZzjxjUMBXQ7YtYgjC9fAVPqVTAISSrVND8Z9lvFmvAjKTDcwqoCuHyAicu4/CcVwAMmLEQ0O2L+BBhejUGPKWe4SnlObC0f5CEWS3aYjVO0eE5LwAYMGMxoNsXMQ9henkDT6lpgNOrlZIF7wEcGBN+s1j7ImqEcmz6S+pa8/ZEkcLhOc8BiE3/BNDti3ifVA6+GmaYCHvbbAAw+Op/A06OU6RU2ex3lJpatMXyBYRhZbPdv5gVm74C0O1tM5dsXuMMI3wCMPjqS4CzbPZ/yWVi02dpURUEixWYG1g4WQGSOCDljlrwxCJ/U+6oLZs9CUBs+ioSlu1t4z5qg68+HoBBhij2tllPCoOvvk68nvDF21YYJREumz0zNj0bgLfz2MotlrQzBXqlAohNXzP4aibPsCxhl9ZKMopPb/Hv+XCCN+dySqkgNv25stmL6fi9BcdYMkhvOmMiNn0xoCubPQ0UvQjbaAy+mi2sLve2mUnVt2ySCWQCMPhqBs8nTzqqbPYU8KwakyA6LKRyW2FU2WxrbHqm8puSMOPAkqAQq6kq0g8uAfA65gk12nUSybiZSwFd6axnQMX1SkqGOGZTJHtT3BTqPPtZv57eHOLIEcgkfqWbCwA5IAKr4mYuApx8lsFZOus1wYzRxypu5oscVw9qYRiUMDrQT0JLslmQWS9Plitu5gqAK531tEwJLUZnxTDE8Q6t+Wf9a/KhBIttEg4RDHG8zb9HVPiAH7/oES5yHLYVRhFDFTdzMZ9i8EyftmGls+ZQ5Y9BpbKC8pR9kFeFcsTNXAlwsrfiysEY9xDH+1ST+wT8rH9ZRUtTaMekDqX5rwDEBHKpPgEhhWCQ4mYuUUpcxc2cBTgAz0PkpbMWvLQqCsD81FrCrZZtsT54/JUcTPWLKhl8GKFnlyGOeSxj6S7/rH8BvmKIYz5fdLH+NoJDEpTOmkgKYxJq42YuZbIqbua7EkoRhMKtDQiQxWpsjNXs8PR6h3OhBuK6mJuyF936E1T8JO+F3a9gqAAYMibbc5fzGgIzRFUELsZiRkWevsjqz577FwCGjE8VrnlxqmedY0lKlqLylSnDbmmYDoEkJOJkz7YrPZUFig2STqUvWLPnppHtMQm1hoxlknUiLymZuHuTZ9VzwBVhMygWy2so0whkFX9KCvbcD7TI5+2JImtAe+4Ue+5kLbvYcx+150p+2CPEgkTvULFzPppAe242PKx6EcAe3W6hNcs8xTe1TUHQfrpXSI0KeVF77iQAhoyVvIjiwOy5jwAwZHxlz30IgCHja5+GEAqMZDOpUelQGoaMV4EGudrWfa2Q0ROLXmmGjNUqWo6eiwLQr1utPdf9U3323AcBGDK2+n3EIQwl2xYB6Pfovl+Q/BpsyDQ+k2NbhlaQec+1L88wTAawR7flThe5hOxiRUIAYMxcTH5vx5YzFTy9Uu6oFb9qjJG+IiAMI+jXrdaee78x81txL1rCLPmmHMz3zHLU1BgBli3nPqkawJi5maUQ4miMGpmnQnIEOAC2nLdk8txubsvCp14ncrn25cFKJ/nfYs0qXQ4AKdid996dLvLDG1cBHfWbclIYM5cBnC1HU5hFcPRcVL9utUqbvsGWM5Ia0g9N0OOm1OlqqUez5YwFYMzc5FWJ5AIOq5c3lJpCITcZwBhr0fg3dq95907Xk8qrvBqgk7BhzPwM0Nly0rR3YczcQnTach4wZvruCmlKSWoayzBbzhhQlOrVyc0PUnO6OqpXp1pbzjhj5kaF3d0vORZy7uqQiO3mvlw0/o0Q4FWAg/ePJkzfvfodAHe6UnhKRYpFaLfFATBmrpbUMNGvW63AKgDGzK2yvbz6QeJNRgK41MAOljtG1NpyRlLcUnobu9sP2nLuBc8hQilj5jdkR1vOg6SJcEvWlSQlIWnixN7TPQVJjF9lNX40YXoosAp+efxL/bM4dfri1Om7uTz542Ic17Gx2mg0fWwSVnWMqKU/pOlSQ5QtZ6T24QmsMlm/NVm3Ck0m6xaT9StCqdPVUbacR5kaTNY1WuZoyyEPQYk85uLU6YE+m9o/zZRu+DjtzZ9WzgVwF6Y1Q3fKkE6WZpXJKvJ6JdkjSeulhqiS7JGSVjlKsu+lWeW3IStAnpII4u9QyNGm2Xr6OO1NAIReMjQ2A+4HCLwBi1UATNYfaJmS7JEmK+NXMLT19aB3oUZoe1m4l6bKauycbQMw9+jnfuyi6WjuBOmSiW9NhxCeS9fPrDiJnWughOXycm1yeQ86RtSarKJfuxBgsv5Ykj2COMSOEbXi5ALo/EJJ9r30jiXZjFwDpOtESa4BgrYxCbXbCqO2FUaVZD9jsn5KqX0e4vv+lkx8C78CobESpBGc22ZIXvQnzLsLUwAO6ByEQVAoyR7BrFcinFfIEw00WME73enqkuwJpLytMKokW3RBhvaA7x5bGWp8EhCESzrvla9ylybhpxVzAAzlXvdBj78GTpwdidYlkBBOvUeBTPJcgwTmrC9lt4xKQYwWWLEUsVXvla8KWVYh6Df6fTp5BoBdy913Pw7lZgRrJEoZh8aCJpM5i6TWPPf6FWc9BKA46xEA5ix2KguAOWtlcRYjn0co9dfjqxB6vk+CoF2EprHsmXRS2LVsNikM5ayy+1uUwiylEIoZYDEmy7RVqpCmryT5J3PWd7Lb/VTSVJJWt05z1ufFWRPlou+fWB0CZ8w7QuvW5OVTeIZ9mk0KQ7mcZujXnKUllvJyT0uvTrUk/1mcNdqctU0uQMwVnT5Vwi7XHABVVqNwQASE1PlSQUhYLDlWTHU/47VraSYpDNNJfxiNNXAf56JyDIqsnjArPlsxlRWf/X2RdZSKwiKrO/MOoFen2vjsTfIYa6fT/S0Sph+K50YbQstiyfHZs+5DvPMTlfDL6xzUBC41RBVZR8RnM4wWYRWfa9CK09VRRdYxAOKzv+X1PACFpeJOZ4ZQFiYb2udEE7i//S0v2GNoBF6+PkUoV1ndvwA4TPeBb3msIusIekkYn71d0l2R9W46iRqf/SPruVDP3yLrKKUlIe0BhZED+OzZDLRGhLrFkmD+aeprwF8c2rnkFVpmmG4+NKNjRK2Q/yyy3i1plbHKO0ikBZZ9Elj1+TQPmVrU4W8EuPnz1wZ7DH5G2sfseH+YbhFf9JxNwWgRCC5PUkmxSs1i7XS+CIBcY5Fjwe+t7VCrgFuw4FqZbepiNuEEHshTWYRntOdSx6rnMn0dXWsDt3DhumCPIVTwfHSypObDyvDB8REtLMYKKBadkdIofHB8RojmscJo6QhbrDACgrDFCiMg+H/jr8YDI6DeAgAAAABJRU5ErkJggg==\n\"\"\"\noutDoorWord_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAHNhbS4gbWFycyAyNyAyMTo0NjozMSAyMDIxsNcRgwAAAap6VFh0RGVzY3JpcHRpb24AACiRVZLJTuQwEIbv/RSW7x2vWTpKgliENBKNRvSA5mpCKXggDrLdpOftx87SAz5E+qv++lxVTnVx6t/RJ1inB1NjllCMwLTDizZdjR9/3W4LfNGgTbX/cXWJgte48uR0jV+9/ygJGccxGUUy2I5wShn5vb87tK/Qq602zivTAkbBX5rhXvXgPlQLc/5uaJWf7lxIf45gOzBbq6GD98SAJ3v9rKYPT07uBaOntU2OQ0uoetIwNhuEqr3yVp9CKB7FWI1pwhgXRYqD5LMUVIooRZSU0oLxKGWNt0Hv0jTN8ULgbA5KwWhE8AlBJct3EcEnBJN5lmVRzgjBZEGLFSFWRLoTsUYsiLRII1GIOc0zUUSGkFM6ZXkuVoRkS6fhBIvk36X4LuX0erOMABI2U5FlRdVhONoWpmVdW1B+sM2jeTPDaCqyBs7JsOMb5aFxqk9Qr6xDPEeclTIrBUOccrYUrcb/laY7/HUe+ubWAlxf3qCwp93qPiej/6ey/v7YP8OXTr7EouUBPnV88CYMVpGzinOt81Qk/pjN5h/VOMGW1stEMQAAABB0RVh0U29mdHdhcmUARnJlZUNBRGMaYs8AAAAndEVYdFRpdGxlAEM6L1Byb3Zpc29pcmU0MDAvb3V0ZG9vcldvcmQyLnBuZ0LOpFMAABVWSURBVHic7V15eBRVtv/dDiQk+Bx9sjoDgfdGqXQWJhJgRJrBbWZ0VEZUJCGAoOKC88Z5qIAQkhAUnXH7HINAIOyERURAGZ/viQ6dhT0CWQp1PllUCLsQQrbufn/crupbVbequ5OqTgf699XX37m37nLq3l+dc+rW0iQtbRIiiMBsdCCEtLUOEVyBiBArAkvQwWaLECsC8xGxWBFYgquUWJ+c22Zia3+4/g4TW7sycMW6wi1nPjfYK5x9HDDtwEUsMth7/w13mtVRO8KVYLE2n/4/baZwdoKSOqrD1DvqQEbDo+nrCd4uryyiUNvEA13uCqCjdox2SaxNp/6XTQpnxzOEMBC4SYNMPciF1QwDCJPplYWzE5WFPQBELGWrjeh6dzAKtAO0G1e4seYzWU44N04SCQDm3NAjE/TzW3P4tK5Hk6nmllImgCfh3GNS3V7A0Wosl+s/2P23rVApXBDWFuvDE/8jywnnMoEbgeMBmCI9DxigNwwWWnoFxC0p8xhAmFPFU40VckMje/zOJCVDjXAk1objn1Ih4VyGNG309zivuAFdgmNV/xt/kOX9P/6Cq1v/G78HsP/Hn/PUCIpb3CQAJJwbK2V6qrFKzn+o5++5KoUnwsgVrv/hH1Swnx8NEMbFEc2vXpJFq2IsSqADx730Sun5vXLvDweO/4LnBBEYn6CxXtwksZ8fI5OsCkW05iM/v4d3COGFtrdY677fSgX7+VGUTwGESiqYEGOpqMOF22OzETdbXodeAfpBjrnS0dkDwH4+HfAAniqsvb666u67XwigbpuhLYm19tgnAOznH9bwCTpmxscbaV578aoE7Q31WKXKl1nFa6fFMZac1LNhatjPP3ouwQ5JtUd7/YFbrG3RNq6w6MjHABJ/egiAkth+rtqSexxjSUaItkprI/eDJ3pJHent9QBI7vE9gJSex2j5gGMsFfwaLb6de/OnvoVIowasEhsApMffZ9hOqBFqi7X68BYAiT89CFwL1GoMFVSGR5pghcW61BDVOcatLWzQDi+fA4klOHiiF5dbeoRjWg7WD/rsU3KP7+WICgyJDU0dPT89lUc+BJDR536DowslQkesVd9tBpD40wjgGiBKY068yeQeR+XkwRPxNNMh7HGKaQ5ht1McCKBzjEvHGvkNtjj8o1xh4ycZbk+Ujbj0SOb22GzEpW3QrBgrucdReCl+BAqeaRun56qn8vBHAMb0fcCg2dAgFK5wxb82AUi68DAQRYgNuARcyytIkror5k8imQ8VNb1pSfqr40YDjNwVScoquUGqCeWN3qlHqyT3OFZR07v1MZbq2H37pN6TexytqJHcroevVdKFEYCn4rvNY/9zBF/pUMFyi7X824+SLtwLdNIE4BfZqU3q7jNUMhzCPqc4oKKmN0AuNURRc6WBuTEWN9+XSTnEI4GZMVZFTe+k7kepnNT9qEMod4qp8I6SBwBO6LRHq1y4v+JfmwCM++UfjcpZCRuxEsu//Sjpwn1AR6m7y0AdQIBaKUd7PQgADqEcgFO8hZapqOndOcYFIKn7UWlS1deJmkNjd/HdLgU1A26PTZnZW5blOZZbYPcyssGFrX8fLbcjCw5hL6URZZUMh3BAczjqYUy6cF/ShXuXf/uRpfNrAJvNRizaln2zMfnivYQQQpoJaSSknhBCCLgbi8qT8fO3jwBwqcEG+Ao4hN0AHMIuTXUSgMBN0hwCya8ldT+qUqnypDzN22VlWKrpK6MnqwSiapPqIPdLB6TyZO/Kk70rT8Y7hANOMQWANIOq3juzyeSL9yz7ZqN1U2ywWeIKC8UNAJIv0pupzQA1BgF1VHkynlu48mS85BAHacwVlMmWxFgyErsd5eY7xWGqAlLwrroYRMtiLI1uHqc4gM1/ethmp9gfgEM4UH+iK1dJoA6IBeoAAB2BxuSLvzt46EMAE4WHdKpYAktcIYDki/R5I7c+CfhOkCKx2xEA0pqCMUyIsVjzwG2fmisoaWcjbuk0CFwNTuOSDvGsMmxHid2OsMkt+36l3yBtsxMQAzQDHQCSfPG3yRfvKhQ3WDHXejDfFS6u/iCl9g6ZY1zXw3VG3lFRpGiOL5NGWondjkiNEMJxOlqPQwwVUF9eqnqvOhW/wDlWb69+y1xZT2GfClR2CHsAOIR98EWcXj5dF+dmumah0qcj05EbQEi9YRAkDAAFletTaodrvJJfJ6Wer6pT8ZBiLBUcwi6HsEtVPgBBTwGv1aw6FU83mqtKaiHtNbho0JP5g2PveoQVFjgfgnT54hRTKbccwn6t5rwcTr8ptcMKKtebO90GMDPGWnBwbUrtsCCv5H241GDrHMOGI6qKpOpUvL3rkU/3/1qz7K6q0qoYS49M+iSzKsaiEjVaTjEV8CxwjnjKsYnm27se1lGpHnADHiBKtSOldviBinVPJT+qcyBmwuQFUh5LueeQboxFW0jochhA5xh39ek+rJ+UJXvXI9Wn+2ha1nbElbVJv/ksuItSBlzR8oZTrPp0H8BDD9ze9TC/tCZIMGy2GZDPQFq0of+lAfsPrn2m/2i9mmbBNIs176ui/pdug5cTNodQA2BhsUNTUNcZdY5xAyShy2EdI+8FNVcOYWd1cR9DKxW4N9TL1INcuAXPYxkbLY4aC4tHJnT5Tl9PNof7DD7nAshEN6UH05cb6DVUDZsMPsZSN8jCIexaWDyqurgvr0zLYqwWQ+sEEYwflMnka6H6dB9qtFRwCOVy8K7Tl0of1S5bQpcfABfgwuWQEMtEV0gIhBu+Y137pKHbC0p+I+83qCue6SvccBjSkwsOobygZCS81t7HTvFMX7GkrzQulsRYwcOsGEthtMQzfWgZQjxS5P4VRAWJdejBYbBww2GHUOMUuwD4Vd2Qr8pX/2nAmBYcauAw56pwxQMzATx5236HcJa26xR7MscJ5SwaxVh0QUG6icGlgnFm62Msv5teRb2kAYM5u8QzfcQzfdm9BSUj6WmmLNYXuuD37hBO+3Ithvkr7w7hlCwXlAwzPGY5x2uNmJlTEUXPhQUyZwTA2KZP/ehtHlZ0/L3UbwtiLO2zo4qkU0xRrrwbx1hqOIRzEJtD4A2temzGIRyHL0gMJMbSnmSBR9m+9jMbP+MVwMpoQb9rkzG2kU/ildH0HpdRjMVAvXdR6YMAAM+h0r6ZKJXG1jjG4jTuEC6iHBbNuwwTLFbhPdMCK+i3I2Mvw2FeZqP65fpQEkgPejpoSb8ymt740porA3vmF1zrCKfYzSGc9BWy2mKZ2IFTvNYhXGBznhjyz0WltwMIOMbyk8xsVHwlJhxoFDi02qpOjJXRqq/WGBgzY+hdPTAl2osrzE+tWVOOfFxDk06xp+QNVQV1YyxlAZ93G9PwpbxvVYxibqwdG+uhOpzMhm3MruGSyA+5NOvGRsbMIRx3it2oPLm89rrcattn7cdiabG4bDiA4GMsjGnYLsurYhJMVitcwR6p8nQaxvOG8oh5mKTKUBHpUcGegOLx/HbjCp1irDOWrCmvzU+9RrknEFZ5C4xpKKbS1UMmPShJtl3K1N7JUMG/9fKWay+uEAB7Pmn8oJ8YK6O+BMDqTgna0hHIwzKm3ilnGhJDZd6I7Aonl9fmp56fgfZwVcgiP7VpsmS0Cndo19zV0XpGfRkV5LGLwADyKB07dvvUrvNWd7pV2mNwwejd5RBOTi6vzU+t9+a2F1coIz8Vk30Okb8EDCCjfieA1Z3s5vZ+laBXry9Xw05Py9Wdfs3cC+LHWPDaKt8N6fblCr3IT+04ubxW+kCiuv2M+t2IUMoM0DHMqN8hJQfqma7J5bX5qVHskw75w//yp+3vWKebaRbLIVwGbEBM4Y5bgZhCxOyN+WRAg/zGNwGQUb8XEUqZDXk8pTN2gGqBdG/M1gENd03EF6qKlhotk13hkp2D5PbSGu/bG7MFQFrjg+mXywEUxdoRCcwtAx3ejMt7i2Jvke3WnuiP0xrvJaRxyc4hQMOEwb51nPZBrBl/PAucXbITLHPSGkcCHfdEr01DeH0L5QpGUWxi+uV9AIpi+++J3pzWOAJo4pa0lFjk+effa30rbw95TpZ/Of1xIAaIBqLTL4tAVFFsyp7odQDSGiP0ChH2RH8MIK3xEaAJaJS2+m/nLpPL/KXUhKnXQ4fWs/atW5/j5qdfriyKTaHP/aU1pgNRe6JXRrhlNSRKjQZc6ZcPAK6i2Ju5JS29LjR/ueHbuYtvevnZ0XXVa+L6E4BdCB3YNH5P9DIAA5si9DIfuzt+DGBg01jATYgLwJq4RMCVXrd/TdxN2vJv3frclB35FiljgsV6YWf+G4MnsznfvDrvppf/m1t4YNMEwLa742IpGWGYCZAoNRFwq+4JAlgTlzi6bv+auP/QVrTOaFn9GSN+4wObngRsgG13x/cRoVcrIFFqEuDmvpAD4JtX3wCQp8l/cdc8S4llVdOBYGDTZMC2u+PfpWSEYQGB8gnAwKZnDShljL8Neval3fNM1csHqywWIXoP8RHtNqj5z5IBe5MWHdQcLt/SDCvs6rCFCoOan6evOxPi1tzRV4zz16+8ZtCgdf7KBIv12oBntJlfv/LmzTOmBtvUoOYXABtAdnV4XcqJMIzl04vS6/MtMVEqTNv7voWuMDxXwgc1T5MY9gqTeXWRjOHTdIlMgTzzrsDNM6bpGy0rF0inTZvf+lbm3vK0KufmGVOADkCUcrNJv6qNKAWiFIhEshy5/SuSZDKTKAY1ZzF88jC2yiPFVbIgby7lr+vrV+YY9Dh9nwmzz4VVMZbkCrnuH/oyGx9AJQ9qzpVb29VhJttdO+WZhkl5EodY+0SUgvzLfZBBO85GCOsYSw+WXm8Odr3CUnZXB/UraINdYUe1nVFbVDmDXXMlGgHwEBK0p/OLfjOnH5ozl7trxlcL2t86Vr+ZU4Ks0So1BrteV9nFnVFG/2FkHe207GE6fYMxSGAEaGyP+QzTwuqnG0xoJevAwikb3r4ut7rFLRya86Qs95sp3yhtuXKDXW9qLr99be6M+nOLW/bXL316zsP7DQVdtOg388VDc/6mysw6sLCd3SuU4HcdSyX7cGjOeAD9Zq7UtKbauH2pojQOqwAy2PWuMgc6SS70rAsrEN4vlIKqO+3L8t7MQ/uYL6BuJf1mLmKqawdEIej5QasfTbbxvj/bkg2AkDWe0TuI7dCcp3hHHtl8Y4utPh4cmvNEcHUZCFkThaz089kJVuvc9n+EqQcxL1PIWiXmZcg5Qtb6NtQnBBDzHgYgZK1TZmZiaybuNcGNCllPA407bF+9M2qK1bPewayG3hk1Zce6N4WsSUBH5j9OEFScJGQVinkT9faKeY8AELI2tFzL9gAxbxQVhKwiX+5WwnJLzJskZLVsCSpEcZ6Zn+OW2tQGN9p1LH50BRAha6mcEPM4X50T8+R/WNDGFvyIylAHY3240EZ4XMEgyFM3IuaNZI4LTL5vBIQBy1mHyB09/YNV1DJx0vVg5jrWu6Nf2LHmjV+77wyqlpinXrWPgELMS5dlIWs54BGyloh5EwAIWQsDtD1C1stAM9AMNAFNO2xl745+IQTRj8l/IIDgg24W3HgTQMKstdpipm9i3p10M9hrTb8PMkf6gerYK36Mkw+ZsgqAmDepBR3tsP3z7+kvmjvjejDtqpBu72W8WEY+Z+5tG/w7tzyUAcUKCbPW+S9kAapn30k3Nmlq+76/FEyYZXr46JL+ziiKBr4WnZPazfw/acof81IZ+UR5bBRcr6+33AXDYq1dx9LGOpQul11xTKavmJTvRfXsO3kLcnr96pXRO1gFkm6sk0smzFpKMxNmFSj1113HkpNl5B/5Y14yfbr1YMlyw7zMqWUrX7/VI/97bBPgUg4B9697UT17QsKsZabrYwBj81M92/uJvdioOosUSJi1ibnP46me/bB5bfu+3VBGPp6XOTWUC0smu0J5e3/s1DKyqYxs1ClQS8hFQkDIeULOsQpVzx6v1ZLWUiVN2bjg7rVnb7Nn+764Vz3bkngLUlAFwJ69BsoYq3r2Y1LvT/prqomQZkJACCkjm98fO9WiidbbLFwgnT9uGoDS5a8NgXwWxkmPZF0CAFzQqxsYgl1ugI5ghMuuuNioOplS9uxtVbl6XwpVCdpfVRmwV3ZVud4vuSfdWGfPXqe6t1iVO9aevZx3+B5Nju/QSvEhgPnjpoXSVlFw/rfNXMwfN60UH5RCFXr/G3At8DOasGcX2LMXqyras1fJclXuKEuVVFkjv1CFXJZCirFQlTuOCvbsxfbsAv0aXpRiw/xx0+jpHXqE4pbOgvHTAZQumzsE2lX162Ry27MLq3J1l92rch+xQjd79uf6Pd4BTXTFzWwlqnJ9F4b27A+orarKbfmfv5ViOYAF46eH3lDJCN3rXwsfm166dC6AIeDccqawZy8FiPRQshdfHoob3s+q2DncUJWrCN7t2UVVuelMcqnxmxSlWAxg4WPTEfBtBIsQ0pvQBRNeBlC65FUAt5GxAAGu17s8BkhiThFAKnMUf66XmLOREL3oim3EeLkByhwF6Jgk5nxRmXM7jbHkUUrM2VaZc4cyk/tIDDfMUpUBQCpzHmC7pqG67P4IQWLOavlJZUI8vFiNALUlnhXyCLctpSja4IXVRRNfBlBSSOk1Hvh34/KJOWsrcx6V5A+tVi8QWLf6QCmVmLO+MicQ138e+FmJ5z1IoxoOlKJos8dmFj8+A0DJYu/bXbcR1ZPECq0Sc9bzllJDh8qc2xNzvgBQmXOH38ItQ2LORnZBKzFnnY7XOwN4gOsBlHiWQRrJ8KEURRu/Yl/4xAwqlCySGTZdU6rNVKTekMqyYHYXm5UPwvvFDSWev1KJjl64UYoiXB70W/Kk93WukgLve3BDbVmhVKAi23e5px0SGlTJyaTcbdxilqLY7X3IWB6rsJg5HbSxxdJi6STvqBUv9H4fZagtt+3UQVLuFwAqsi0xV4Gg2O0dB3lkwmzG+CBvv726rXXwg8cW+r7AM9TGvk6ovQ3s904wV0CLJsvDk1UC9y0dlcDZit0+a710Ukgtt1kIO4ulxbKnfCNbvGAGu2uo7a8hV8cSFLsVkSV7yGE/P3yES4wVIJY/PYtNFs9/iU0Otb0VWnVajmK34ipYdVztaUp00A4slgFWPKPk2fv871M6ot7l5ocGTtfz2kyV5u15EvhoZxbLGCufzebmO+f9l9+6jij6bTu/o+H7sxqn69kWa3XlDLoO2rfFChCrJvMJx8KZHxBLgm0WVwGHuCD5+Wv9l4oggiBxVVisCEKPKyrGiiB88P/jRfmWCaclHgAAAABJRU5ErkJggg==\n\"\"\"\ninDoor_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAHNhbS4gbWFycyAyNyAxNToyOTo1NyAyMDIxaTUvgwAAAah6VFh0RGVzY3JpcHRpb24AACiRVZJdT6wwEIbv91c0vV/6yWcA40dMTFxz4h6NtxUniEoxpSvrvz9tgT3aC5J35p2nM1PKs2P/gb7AjN2gK8wiihHoZnjpdFvhh7/X2wyf1WhT7m4uzpHz6rE4jl2FX639LAiZpimaRDSYlnBKGXna3e6bV+jVttOjVboBjJy/0MOd6mH8VA3M+duhUTbcuZDeDmBa0FvTQQsfkQZLdt2zCh8eHccXjB7XNjl2LaHysYOp3iBU7pQ13dGF/FGMVXhLI0ZZylLsNA+augDlXotZ0zzOhNeywj4d50mGFwZni4ezOHMevjBcRRK0CDWZlMIjuQxpIVmaxCtDsJlLqcidRyyIhLHcI8TShuRUhvzMoCljCVsZcmaE4zyS/5bit5ThBWfpAcRtpyTLmsr9cDANhIVdGlB2MPWDftfDpEuyBk5Jt+crZaEeVR+hXpkR8RSxuOB5EaeIu70sRavxf6Vu99+jhb6+NgCX51fIvUW+uk9J7/+jjL079M/wo5MfMW+5h6/OP3rtBivJSfm51nlK4n/OevMPN0LCPyIGy50AAAAQdEVYdFNvZnR3YXJlAEZyZWVDQURjGmLPAAAAInRFWHRUaXRsZQBDOi9Qcm92aXNvaXJlNDAwL2luZG9vcjIucG5nZ04VUAAAD2pJREFUeJztXXt0FcUZ/81NKLorp1S0WG+LEEAQLbU+TlSstdQXiigc8GAIrwRCRAIRSHgZAkF5BAIh4REC4REwcMSq1SpWLVJQLD6OSj2gYsBHI1rlqEd3rSa52z9md3bu7n0ld/fu7s39nT17ZmdnZ76Z+e33fTs7O0uuuioPKaRgNdIJIU7LkEISIkWsFGxBus+XIlYK1iOlsVKwBSlitQ2H/etiT3xd0zT7JHE5UqbQiJd/VR3hrNBUG3tWEVh4/emCNsjkQXR0jXXogipDTJuoExkRsnrZb6TvHz6fblW5bkCHI9bB7mv5Qwtp1CaYyz3k1yl+wxczEiuO9egopvDA+ZU04BSTooIX7KBfZf+NXxY6JE68SGaN9dJ5a1jYtXwKCSbtAb96P/zpqwecE6c9SEJi7e+2mga8RaaQYFV4ya/eJIPPzHROnDYgeUzhi7+ooIEk4JMZrFL7/asB3PT1LEfFiY5k0FgvdF2FJOWTGbSaL/orANz8zWynxQkLDxPr+Z+vpIEOQiketMov+FcBuOXbIqfFCQFPmsLnupSjQ/LJANoCz/tXArjtu2KnxQmCxzTWvnNWIEWpYNDWeM5fPuT7OU7LosMzxHpWXA6HKCX72zwXMvFyCk21+/wrANwuzU1w0SFBhg51hRwR8LezlyFRXRWSQ0LLSSg0qOh7RQG0TWH7AN3LZ19uzCRRVJP9eUN/mJeYsiKA3Hmn80KEw9NnLYXNXWJgktDcCAAgbKeijcTS9gEoASAApVXucn1QQfZX6s7/zbeviKggw4Y5WXwEPNX5Yftan/FJ+Ol9gAAEqkvA7SMTi/EpiFgKlIC254kVgNKq7VuhtMrnDlEFsLOOw35cYFPmUUHuvtuxssPhyU4PwZ4W1/n04zGOTzQANQDonGLcCiIWOD5B11W80mJ8YvSixEIr4xYCrVBa5fNH2FRZWt+7mx+0I+eoIMOHO1NwODyRvsTyVtb59MM7ID6NT764iQWOYQGTNaSBVo1YAS3MuNWCQCuUFigtcvcsVUIb6j68pcTaPGMBGTHCgVJD4vG0MljasjqfpDdACIgP8KmUaiexwFlDnVjSmP58uWL920a9paurAJRWafItQenXNUBpQaAZSguV2Vp6yf68Ea0LLcwwFpCRIxNdZEg8RhZbTinhu1dAfBqftL1OLD4AxjApqw+flbi7EQhLLGnMxSEFEOvfCnawOFZN+vOeIwJNNjpT1i9ZuxVKMwItUH6SexRazq2RSqmFGUaFK8ax9mKRVe2oUurbAyA+kLSw6RRKJ8YXAkDK6ksPTp5ROz6jmyzd2xuA2NBoyoLQy482CQP9Oj/ooTTu9+KON7UkXBEaq3hK7TkijM6UpRk5YmUtCKAQ4aNVcs/ZsFR1JbijyT33LEpkeWY8qpRa0nwqpb5+HiRNZZXKLR+nt0jwXjeF0ph+AE6eETK6yXy2LEbjlv5gKGX1ZawSdx2jPpY09jJo9BJ3vG54MJRyb6Q0Ejc9wzwtaeooGglAXLMBgWYEfqKb3MfKW+4estiSrGKBw+8K97QutIpVwpmnQdJB0ngtYQqHrizPKrHhQwBsxEG6t7eZbSFyyB4QInL81eL217hCQ5curt8j3T9a1VsPTBUr1mreHhE+mC9fvNSSJhKaah/1l45OK4s/q1jgmCnc3VICK1S9qqi+elKjFP/gxgJKBFZRaKw6YfCx2oeBfjnYRJqLDnpQEKt3SQXZ+imibSDCe7Pl/pbNC0pYd/uIQ4BFrBK+2CN8+Zh03/CQCaSJg6SJ10oTMqXxV2tx/CBnsEbj3CyKk2cE5m9JWb1jlOpok3C0STBFk1BH7PFTPyvNUj/XkeaWSguWAkQ4ViD8e1I7XlkaIDTV7m4pSUz/OmMKd/24IE5WqYrq850g6dLUUQCk/GHipmfoWWnSYJbyyCkBQGavKLYMms/OW73wFpAYKCnuOs6GsqSxvw2T1sQtBUx1iVU7oLRIM3LF1dVAM0sslawSFxdEVrdtQmJ63AGNZQmrhKZa4bNtAKRpWQBq9lMNoQRbQxw5JWT2kjlWhXO/ACCjm0x9LLHhQ7GhkW6mwvVeERs+oCYPgJR9iR6/853g9CE6Usq7XRs8C8pYrKwxjqXRMCHC29mWKK1dPy5IQC8n2seq/2GeBaz6dD186dKMHBpTs1/IHyyLNU/yfcEoJW47rD0bMjfLHABCPRJS86e5X40A5E4Z4QSTsi9lYco2s48l1h2Qcm/kLiJ0fIF56zqruLpIpVViaR4IEd4cIV/5ePwuRAI6PaGmcLs01wJWfbwGvk5SYT6LzB8sixv+AgKQEOoKgO68h/HgxUfel8b0o6bQ4LwzH4tSaoK4nD878dll226fh+DRLMYqsleBqCcWvjtEpVMfAKcMFWv+qnGLz5WxLTgSPsAnHLlVzvx7PM0oNNXW++cZKmI5Eqextn0/xwJWnVoO38+kmQXQFBUAcf0eEDqVRR/2zOwlU++Ki0fQYfAYKdmrKKOIwc1iOixn3/KJ56ygCQ1S5exbDmDrEH1aG2UYd4nWApjDClK5lX+XuPFxpquoDhbXrIdCpCLDVGNt1M2i/rK730lOzoroqazA1u+K4yGW7M8TGsvg+5lUPA/M/FVthy8dJF0dwVL3aVLerdA0lrjtcLgxUvks3XjldCkHUHebcXZv7nO2tA9fkLhhL5QWBFqkgrF8mil1wqZc7p1PyQRpyXaxaAiav5EHHY6zMWl97UOCTOGWb4viZdUH8+HrTGeqqKyq3AyfQhWPNHWkuPEJs/MOwDxGKp89kB5M0r7zAUBV0eTnjc3t87Vb6uhQ9dbUUYYYsWKtNGsGzyomobRyn1g4KP6i7e73RJjCzd/MjpdVx2cirTMjDbWAbERKun80AOm+4WLNU/QScfML0uSbuTwUQJGFK+nB5K6rtHjH3jrkvbASQO3NRezVIXszDSCMYGzQywKy293vrngJHQOCRzU1SNMn0oDmbxkT0IvkLtcAyNM+lXaQTwZMeXHVppvUj07Za2myV0EPAKZVjYiniGW3Sqw5MzNedfVuPtLO0qdrapAK86BRKn+wLG58XHPGg6yh3OW6fHU1B7fwicd9+ysMMZq0RkhldVrQJ/xzoPzHo/E0bDKYwnZD9ucJ74xFmhA0tZyD6mytawBJh48jU1fdDt533hp3Uqr9iDwjKMY8PG0KN3wZ94Q1RVE3fdKmCpVV1TvU4SsFIIp87h0App5fCe01jpvvnFhAhyf4GKniH2LBFfFm63VTGDcUzsHSNZbKqrVb+Fcmcre7pqkL9hEABQcrYfNjnX0oOFhZfUNhwcHKad3X0nDQ6bg1Vsc1hbI/T3h9GNLPMXwSI5Yvo0NZGhRAkX95D4CCC6oYy6YfWuvWmsWKSFUI77/H+D5x6/bFuRMXtUes2GAjsapOF8T9Vkv79EVh34gaoACQu4+Zri517HEqxQ7iQ7jvtptPRL1a7tQXaZ1t1Snu1VgAoCjS0j0AxEVTdb3F0Uu+cBKAGReuS3pKFb5SXTmIW8Gb+BAbh8LC5vkH9uYezzQP4ZVr0amrdqQEfdKujZEW+tcDSHpWhULcnqP9xLIv87huKXnQq8KR22hYWrRRLKPea/A0gA7IKACAtOYQ2dv+y4XmE/JNpwhZb51ERrjbFCLAhRXzGKm7hbcYs/61vuKa+y3M0NbW8xFu5r61mwUI8tZVH0vO0BebsE94d26zj1ipY2wV1TsaS1EARe5bNvuijTSi6LUNrpbd9aj4ZCprTMthr48VL5QgUyj3Ky/quRFA8esb0IEdLAthXxva+DFFca8auVPf6CJEAEcseUB1ca8a+6T1Cua8oeoYC5oXsE9Od2ssBMTiO6Ry9aMud4uaaFjSGvY1abqrB4HUJaYAYE7GJleL6gAsaQ27mtTdGosupwEgpa5McLvGIm7tMaH5hHz9q2zGyLIr8ue/tclZkVwC2g5x9pvQfELu1Ne+3ne3xgqGh0S1BA9fPoUGFrxt1x3VETUWBT/NzeWi2gE67czaivPPkimNhZKjtV4R1XI89Lu8kqOhJyC1Y8ThwX6b45YoOtyusUr6b6EBl8tpE/IHyxGUFmucNiIRLWmvxlp4yZay45PiyYGJ19F4tfiyydBMYem7mz1Xfds1VumAuuiJIqGjO1jwZt29+aVBx4D2wbcn4XYfi2HRpZMWH4tT+bkFpQNyWThcpRYfq2PJvNJHPGycj2XVRlF2vI4QlA7IpZvjUsWzlR2vg7aGZdSK1+wXvFhfz2ishZeoty9d3GfhJblL3tvqrEiWIEL7L3lva0n/nKjJ3AkPaKyH3g8iEFvcp6R/juOytXtjsCSZCzfPaCweD3+wbcHFE+HB+9iMqFXw6IOhJ4lFWUUDS09sj5Byft8JACKnSSSoPDxibH/PdZM3Xuks+3A7DczrM8FwKhb55/edwHJwCmbJtTVLYrrEE93Ew5Mai4dZ/rm9xwNY3rgjcrJEgopk+JUBPZzXZ4JBVDOWN+7wXC95foCU9pn5cG7v8TQcvASjY2Drzi9v3EGZFMvPMmC6Q7wCj2msFSfr52SM4wPgtNGcjHH8kp78PwEdrCaTE8CKk/VmQcLJtuJkPTxoBCm84WOZwfeWoQqjM+XyU/XFmeP4SMurWdxrnCGm/FR91KuYGOWn6lkOHu2CyPCYxgKw8qOdRT2D1kM3V4EQYkhmbTVZzvy/WClRVn60M8KFIcXwXBfEAg8MkJo3iil1aqfy8dT80cNVH+t9XNRzrFWlF/Ucy343R//rRP9eQWPCSWsQlY93vD3t2LynsQBUfLJrVo9sNgTPV4G6Viym4pNdszKzzcnajVk9sqH9E6Xik12G+JNnhNkXjeXjmbQRZPBiF0SFV32s1Z/qnWeuwqwe2XyCcMnaB/qDndWf6nShyOgmM6UVDiFPebQLIsOTGisc1vznkQcyx9BwSMfLwrJm/kZnFfO0ohZkOJUc6zqHhFc1VlQ88OsxlU2P8DEW1tTwkzD+b2GRC+JPMfGSsgvc/Yl921HZ1FDoz6KeVqFf1V7amJY1NWU0qmxq4OML/VlaMEJBSdXaEZCEGmvtZw0zMrMMA6SwQTHwGc64MCtkPEPUN4NJhqTysRiqTu+ennmvIdKqmjI7yJMJmlNfdXq3uZyq07s1GSwRwQMgVVW7nZbBXhRcoDOs+nMLKltwwb3mH7HSQ0vyTw6Q6uo9TsvgPUzrPtocue6LVEvqSEIfKwFY/98QHEq1JI/k9LFScBwpjZWCLUhprBRswf8B1rdUXZX5miQAAAAASUVORK5CYII=\n\"\"\"\ninDoorWord_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAGRpbS4gbWFycyAyOCAxNjozOTozNSAyMDIx1WNyCAAAAa16VFh0RGVzY3JpcHRpb24AACiRVZLJTuQwEIbv/RSW7x2vCUnkBLEIaSQajegBzdWkS8EDcZDjJj1vP3aWHvAh0l/1+3MtUZen7h19ghtMbyvMEooR2KY/GNtW+OnX3TbHlzXaqN2P6ysUvHYoT4Op8Kv3HyUh4zgmo0h61xJOKSO/d/f75hU6vTV28No2gFHwl7Z/0B0MH7qBOX/fN9pPby6kP0dwLditM9DCe2LBk5150dOHJ6fhgNHzWibHoSSkng2M9QYhtdPemVMIxaMZq/CWJoyKLE9x0LzCNKHiIrsoohSTpBmjMko5uWnOaJHhBcFnBGWyYDyYOJ91mvGURT0zClGwiOQzQ0iac7kyxMrIGc+CSSwMmVIZmULMmhd5GssUcmKmlGfpypBsrjWeYJH8uxTfpZwWOMsIIGE4iixTUvv+6BqY5nXjQPve1U/2zfajVWQNnJNhzLfaQ30wXYI67QbEc8SyUhSlSBGnnC2XVuP/m7bd/x08dPWdA7i5ukVhFcXqPiej/6d2/uHYvcCXSr7EouURPk3ceR0aU+SsYl9rP4rEf7Pe/AOyssIb//oDAQAAABB0RVh0U29mdHdhcmUARnJlZUNBRGMaYs8AAAAldEVYdFRpdGxlAEM6L1Byb3Zpc29pcmU0MDAvaW5kb29yV29yZC5wbmfSZtnLAAAPbklEQVR4nO2deXgWxR3Hv/smSJzVqlWredQVEMEGNUo9qq1nPRHa2oqCkkjABEQwQAJRzgA55YxcQjjCJShWrVKsR0XBotZaikrqLUZosGprq7vKw7H9Y3bnnXd3332v2ffdN+/7ed4nmZ2Znf3N7Hd/Mzs7+77SBReUIUsW0eRKkpRqG7J0QLLCyuIJuYFAVlhZxJMRHuvVUxd6VPIle+7xqOR0p6MJa/spC+yRpK3Jo8O9qjhL9tK9Iz06YrqQ9l3hK/nz+U3vNORIuMNtV0L0/fP2UUkxx0ekn8fadvKD/GaSlRQlFqteUYLqv2zfvUk3JwWkjbC2nmScKn8qyR3e5m1K8MK4/PPyVJiTDPzeFb504jwaSEc9OcJXZKsSDF/5xehUmOMVPvVYW06YSwMdRk+O8LV7STEuoau+HJMic0TiO2G9ePwcdHQ9OcKqvEUxLqqrvxqbOnMSxS9d4QvHzaaBDJSUBdYCLypzAFzzn4qUmhMnqfdYzx87C1k9OUHb5AXFuOSu/boypebERiqF9dwxM5GVVCRY+zyvzAJw3X/HpdScaElZV/jHox/wm6Q0xeHm3z9GUkueU2YCuOGb8ak2JwLSjTcm28RnjmpEik6Yo3QY5OCnkABIALvYJC3nVPcyU1iRG7+tSv6ho0Tq0yepxm2WG5J2JuwyIt+/AykABCBJgAQpYMiIbkKCBHVAF34XecNnsPh0nf+nazmK9SjJrWAf9b7kHC4mpL59k2TWpiPrkZRGZ3oi374OKWAqiQUkdVAved27QXmZwlIHdgXQ2k740gryNfmRz0IOECosQIduBqBD17VOZ7C8yalv3+/u9/oosSL165cMm57Oq/O0iXnnRP73MqQcSAEgx9CTqS216FyaJ0RYhqq6AWhtJwX5GiuKiixEWzpLdBKWrnOBw9B1rfNZQcM8awFa/X7fT/Co/DhIxl3hU51rvW5T8u/NkHKCHwDWDgxUVRbp8NAkecOn5r6SOuA0iwOLFbK/1RTZ4aArFd0atMCnlToAv9w/UWzh8eH5XeGTnWq8UFXwJH35BKQcSLnh80oA1OLzYOvmGOrAbpyqhKDbw0TbwSvMI3k9pdT++sAksSXHgbce64ncGcKbzzgr+9ZAykUgF1Ku3TkZmNFqcW9YVRVDrVvbiXrbadaRVgKQb1/zzoGRtqYnlZqbD04WWGYceCisx3Omi20yQ1J7mxHIhdQpdF7AghGvDr6IBlgPaHda6sAzEDN65Cxhs5kO7Jtt0A9DPyTcgZG2pieUGQB+c2iKqDJjxauu8DFpmnBVkbYmBDqZkmJIXMBSFwmmpMKNqygJDqRs2PUUEqOWXEID8vItAMjXzwuXFy3ncWX6LfpUIQXGiiceayOqBarKaPHdsxDoFJIgOW5Yq1OQr8mrdwABtbgwRECSLdv63bH0kODkEo0DM24Y1cEXA9i0kwBQh14FQG5+FtDJV5u8kNdjyrT+qBZSWkyIF9aj+lSxqiIfViPQGQHW99k15FgFI1Je9aarXCJX32Eqy43IItu0k/Qt1FhYLb1eXrqZ7ku++B30g4Z7FgFpa9qoVN8qTRNSWvQEAgFJ4Ee8qt6fwG7+QxNtkUHJBSPlVW8gNK4gX5PXvet8vPgusZD50giod14YtG35VgB9C7VNO4la1ocvjuxbpynl7g+gooe0NT2qTxV7oiN/JKEIaQiKppSTd82lSNYxle1A7s4rSehOm7o9xXRXurxsi9z8At1Uh/fjdtRJewvZu0ygtjYcmiL2XLsjUljrD04W5a40pZzsGsme3wX/Mr8UFJBkd1Thwxbc+lB1wGmxG+4gIx655Q255XUA8opX+Hg65LKXRvYsEqit9QcnCzzd7vhlBSmPppSTt4eq01cAkOu4rtA6WrerR3LKZs/sQGs7UQd0sUyQGrOmic5gWT2ZvHI7cNhM0uWlz6pl1wNQ775ZXrQROtRRRSy3PPuAqBE9aWt6WJk0qHNtguVEg7DB+5rvJwhxV5pSTnbcrtatNyPcnArnyRxxr5o5ul//MZ15B6AOOJ0li1FVWO/lMDVPUUcOBOfD1IrRwGi5sUbrNlGIttYqE4vy6hIsJyKpX5rMoynl5K+/Qu5RodFS9I4nnoPmdqUB9sgZ3ISqFjiVHN4Te6l6qFrcJibUshu4+0QdobeNRp6qSXL9fq27mDnnJJx0H3aFjn0cuKGVY2cXGmNzY1reOcHwET35pMFyQ8nm+pV9QlZ5FORrJZvraWqL64IncjDKx4u64whMLb2WheXFj0M/GNyctwSHD6hjRxo600Heq9J6NsanLX6stvq7+wfLDXEUEj1iPNbKb6sSv5I0pZy89gvk/sCW4uiowg2nzNKOupjfLDmq0THMdhzyjLWhWcPY8oewMnQZJznwIbcVtiNUh1xGA7TLY+5KvedWi7uSZ81VK8cAUCfMkGvGkdZyraDJvbWd11h/vyuYIa+X107LX10ht5iTiwkG+D7RngrtmKvZbkOOfsBastnNia2y5UAruNXoZH+r4y5qyaXgRlFURvJDvwc4d9W0HDjA/Jylr2RE1FA4PBeWv7pCuuaudm1oZJinN+Z/7Yc30cBdx8x0yGZS+pyhgEBAiK3O8DYs496oIdoOGlBLfmqV1NJnoB8CDkX5aJu8Xaqd02yEo9CQI16fd794LE0pJ9suxBHHqQ2PhySw6SubmdqJ/Wmg9NhZfG7/wBmGZlQC0PtLfN8nL/uTISnAYX6Vm9M33JWus2xxS4qSUV1huLEUnypBgnZyEYAy8+Vpv+nJkbLjZi+5pjJEVctfMiUVDj3MKC3KRTtuZFJXKEnqrOf4CLm2CgHwutFOKQUw/Pg5dIdkWicEKik6YFKHXglAbqZVZgvnQ7FG6OHVFhuZ0hUCAOxjn+BonY5S7za+hcY/NsfAiC30esCiq8aCyav0OgDykqfD76dbtxLTlZbX6+4T5nrdhn4SVnhLtC6VI4wvyvKNtQlwz0tzASy8cgyYvIb1AyAveozLxV74AYJ3hWI8VqZNkDoMsLTu1QBGntTUMSTFM2rrPADzLx8NUzfaib+VNup6fwmAWl4qz10UZtdEhZWEk+5rj6X1qBtlfOOob4wUzb3bmgA8eFk5gFGhX69qYnmqqGvnrvT5LSH8JSzbGOve/PkdWFI85a88CNuVpY4ZIc+eFxLlOMCPnQwSFmlr0i7dap0J9YdtSWb0n+fP+9koY+xVEewoAdiebcdJ2giLvHyudsVbYl/LGbN9QUbqCgDGbF8w99KRCF0AKNdUAfvTyGMlWsSSZVNwZITv+omDjFUVZeyrC+ZcMpI9jZbrp4hSFZLStiI8lpQjxFLS1sTuiSpeW5jhwgJQ8Vrw91S07iPIe3QZRXp4rIAkIcEPfcmdvHqFqNXZla8vTNyqDvapUBZpPRuhG6pSi85Wi86Ou4WTYLAQjxWA82O+GGCilDbqlacvTtSkjkjl6YtnoYm8XUadevRoeb0sMekxxoJkfNEU+ctN2kV/iDiEd19CpOX18r7W6cq4LotnYinQHC6DXUN0Ly+NckbIXWGOMQVlKyq+ZWiZOcsQK9JGHXnWyPFdH3LM6705VgR5LLMrJH/rr/XeyFLimyDO6sqFqm4PWQL+JPyXS0UPG7CZRSX4wCFDZtvjo+EnwwHc96avVYXEPVbDR8MIZnMRAjSR9VgR8X8TCRljSdxHANkxVjjqzh9GA/W9h0/YsSS1xrgjYozVfQTaNji9YBMnzKTa84bx8RP/7uumTDI+v/oEPYQ2xliJ6krL6zWxRzMtpaawDKHvSNWeN2zSzqUJWpq+0AZh+NyvJ+qxJvVsrkE5+exRAEJ6Q94e+5vmNYVlk9/KXG3x+FtXwpbNeDjAmvK2MR84/ZxSADPOLWMxmUwH91gG5tt/2vkbEl7cCADTzi6F+U6L3YfxeQBMfScTdeZvXQn0WIJ8FrOHaqh61zK7gZY8VGHVu5YJOHz64HOPJeht81NvEdgbhqN61zLqw6p73UVj2Gt6NJLFdzzSrmoCPFZ1rxXVKCf7nhU01xDV6mRJkqa1LgcwtWAo/xYoPQE0qQMzrXW5vx2WqDGWOCz2hDOPxU//x3IAU348lL9/9FulhOP/CooZY00/Z+UUbCZv3pJ4UdF7LH5zxrsrAEw+a4j7Xh0G/1dQqMeKqyjLEqKYPNaknkNYTM17KyLu1TGoeW+F/yso7PWvmsKWSXjMPY/jMrSawpbQCMMec64haN7EHiXBTJI0sUcJPy9PRWbOR/i+4eOl9v2VaVE5r94rdNRQ7XmrnPI6GFD3QcuEMwcDmNijpO6DFhbP5uKZqixT80aJqWt7ajYA3myBpMs1I7IrrDt/1YQdd1JJ1Z3vqKHY4KdDeeo/bLm/+2AAfQu1+g9bANBNhneNzw5Ej+sI/fblCWcOdskTN2miK9Eeq773ajOYaLENH626r/BOAPd3H9zw0ar7zriTJfE207BLBlHw5cNUWMNHbtePF2aki8fy8us4xUFPqv2ZNA89xy4ZEjSgtZ3wv0pHNy1qYxTkay6pceOuY1/hl+9ucKTx49UAqroV82+aN368mjeZt7/x49VV3Yoh+rKu6lbMfluAmsRHhjsW0xbbJXH8fLIs+G6C1M4Dn6weX1jMwu7zEQ98stoemQjjuxqHLsjX7EdvbSdV3YrpQR2JmCEm/H+yGL72WIyZu9fQADN25u414wqLAIzvWsxSx3Up4jOLgv78yczda8JPqkm8AUELuxS5e7XooZVKh3NlIOAV+1R9YD5+5mMAjOtSJPYoFHs8+51pe2YaOevTNbRDFGtSWnzSw2M5MrttbUXhoE07SWVh0E+InSCtUAaxsEuZfBIb4NPI2W1rK5RBre2k8vSi2W1rnffviKSxx5IkzPlsLf3pWwCbdhI2xhdVPkKEYk1iRBPZ2k4qlEEpb7GkfdLYY1Hm7lk3pvAOcBMNc/es86JO9oayOCcG7SLHnjaIjxE12EoX0uCuMCLz9q7jN4XXqCBfm7fXWawsafQpd/Dx/IwXy+mFbb5FxCv2GYFLKxlJvJjYuJ4xb+/D4o3yMR3BY3lNazsZfcrtTf90VgZrQPbTrADsmTOtndN+jJU0+Ia6N3+gZYD1YPt6Gm/PnJlkPVYEuHG3ETPq5IEsaf6+9Y4NmG3VrMdyY8HnG0aeNABAazsZZXojcD9Fbm89L37ENR2RFizYkGob/M49PzK0RTepdBb+K9tubmQ9VmQWffEIgBH5t/Gb2WZzJzvGipbFXz5CA9kWi4asx8riCf8H4kRcbgxvNpQAAAAASUVORK5CYII=\n\"\"\"\nFlatInDoor_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAHNhbS4gbWFycyAyNyAxNjoxNDo0OCAyMDIxU/IYRgAAAY56VFh0RGVzY3JpcHRpb24AACiRVZJbb5wwEIXf91dYfsc3vASQIcpFkSJlo6rbRH11yIi4DSYy3rD597VZ2AY/IJ3x8eczY9TlsXtHn+AG09sKc8IwAtv0r8a2FX76dZfk+LJGG7W7v75CwWuH8jiYCr95/1FSOo4jGVPSu5YKxjj9vXvYN2/Q6cTYwWvbAEbBX9r+UXcwfOgGTvsPfaP9dOdM+nMA14JNnIEW3okFT3fmRU8fQY7DK0bPS0yBQySkng2M9QYhtdPemWMoxaU5rzAjLMvyfIuDFJOcVpTpWsoKJ1FzJrd4Jgi+8gixAoo1QcwEmcqsWAjpmpCuM6SBkHBS8HybF1GfEEXGxPYcQq4Rco2Q6xBSTo93khFAw2AUnSek9v3BNTDN6saB9r2rn+xf249W0aVw3gwjvtUe6kF3BHXaDUhcIJ6VXJYyR4IJPh9ajP9P2nb/NXjo6jsHcHN1ixjhxeI+b0b/D+3846F7gW9JvtWi5Sd8mvjedWhM0bOKfS39KBr/y3rzD6i8wRKgalZVAAAAEHRFWHRTb2Z0d2FyZQBGcmVlQ0FEYxpizwAAACZ0RVh0VGl0bGUAQzovUHJvdmlzb2lyZTQwMC9GbGF0aW5kb29yMi5wbmcIk9lDAAALgklEQVR4nO2da3AT1xXHz3r4pGmndNpOm1FbQXgEL4/AlEyaNn2QQsIbbGIRGyy/sBxjzNOAn5Itvx9gwts2fmMbMNjFJoQQEtJOpm3aySRtErmE0qC2d9pO26k77ehzPxz7suxKQrtaafde8Rt9uHv37r3n3PPXuatde1dYvtwJj3mM3swQBMFoG0zNzf/9PGD9i1/4YYwtYYvHwnqIN//7M1mN1ecN2JLYRFnNS1/8UVRsYpMZCQnxLqw3/vMuLQeTkRJlS6nU1nzpx5GaxTjxm7GuT97GQvhiCo20HyqytTNX6NI5c8SjsF7/9zugn54CQjsnIALAui+/EL2xzEl8LYXj/3oboiwpGTgWymvDV34Ss3ENJ14y1tg/b0FsJSVFKq+NX11piA0xJi6EdfUfbxklKSlUXpu+tspoW6IO50vh6N9vgnGJKiBWnxdTV9LXXzTalijCc8Ya+dubppIUhaau5G+8ZLQt0YJPYV356w0wWaJSQlPXlidWG22L/nC4FA6TN0wuKQpNXSnWNUbbojO8ZaxLf7nOiqoomLrs31xrtCF6wpWwLv75deZUhaC2tn5rndGG6AY/S+GQ75q+qlLeZlai44iorVTber06NBZOMtbg/XFdYiwVU9qsDQBwPauJ1qztPiRvDw/aR24AagvHZR0ehDXw+ViEQaV62jZ7I628ntkoa6acK2l7KrJIjEFtSbtlFOaXwv57VyMJJEoqfc4m3ExQNNjQVwwA444GAAg9V7QTVFgkVrEeFOAjY2kDJeWYu3ksvV7o3xysmXR+wpwrx9zNAEBA1KYtTFrYCbuwLazeu6PagkdsYsa8pKvb68ZgAgDG0usBYNP5UmVLDcJCMuYlaU5dqK2MeUlqDzQPDC+F3XdGNKsq66lkuuolDZaNptWCxXJ1e13SYJmssXR+1M5V1lPJoDV1obawBxZhO2OpBZe/7AVbBICR1BoASB4qH02rAQDw++HhnJQ8VD6SWjOaVktr1M4VDgEAxK0xdbEbHVaF1TlxWW2ciE3MSXwZAKQO09gjstnYcqHiyivVwfaGQHoUAMysmthyoUJt6sKkhTYzR0JCgsDcR5uqchemSDtJueTCXSmXXLSsHCv03mAfOq702NyFKeFcdJVi9Xk7Jy4bPuFaPgKDqIoNqsq5yK7sxz7sBoBhu2fY7gEA+7A79Ihhmjds94DFAgBgsQzbPXQUQRCci+xqtRX+uObCbq9U66extH18UVW6IjYxb/HWiy9X4ubWy5WyBrhLWa8Z2iEdVNa/Nhf0Mi82MPyrMHykAVb6mzpSBQAJymujWkkdqRpKdj8Y1GIBvz/CeWYuTIydvJ/+aEjtd31m1QSW00Y9g0muoWQ3lqNiX0D8/rRRj3Sady5NVXUij2fxO5emRsW86MCYsFRBbGLBsrQBqMDNwSQXJg+wWAaTXNt+Wh368EiQda6c44JlaWp/JLIVKZaWwhMfDIQfCWITC7+zLQEgfaymf2P5VK3fTzcNdBwNmPwwUdVRDEUK+M5Y1DXHeG3fhqlL6hhUx3itIX5TMwBgZtUEcYebtHA13L18e9RM0xk+hUVs4p5n0qWOZVyr611fSsuxd5qOjgZMlZ5Rd8OHoWAxsxS2vt+n6oxE6VfW9frpXbpZpRa0gRrQvbZk8jfhLoiYtPY964iSbfrCYcYiNnH/dzPM6RWd7a41xRH2YHI4FBaYcvZzbjR2rj4s01POjUZ4js/VkJmlUBWdqw9jIfdmU+iWRoGGaViUWYmXkJvbbLQNj6bpva4wv9PEJh56Prt91UHlLudbhnkqtSegGWod1M2yqMHhUohRzLvVAgBtK4uk9VgZe/JutbStLMLRI59vJkLG4VKY/84RmF5lsHzmhQO4q21lEdYYYpVev0aZCBmHGSugRztvH53eG1trogATIeNKWMQmlq1wKv0peLfV5F6WrXCS2+H+NmQiZLwthZy5ExAmfGQgY3luneXvMo+U4z/YAwCTb4d7CZ4JHxkQlirM785rz+8GgD3vHdd2uNXnJbdE96p8XY3Sn8fCiinHvl+IBZSXZkzuJjwWlknY94uTbjgVfnvzuznD9Baqo/V7u0Ls3f/LkzGzJIQBR5/bJbNEbRTMHzXeMlZoTOLsgV+ditAQkzgSAt4yFgAUvT+1prQ8W0A3scyNs+Z3hLeMdfDXp2UOSR3kwFliE2vXFZrfDQYyVt36QnIt/KvSoWrM72w4MOEFbxlL6Q5nGQsY8YKBjBU+Vp+XjIsNG6cuERV/cAamv9/SsgkpHjuu5u5CVG3RhxkPP9WHD/jzSAYDDnKVsRD+PJLBhIO8nWNBkFOQumV5pR+2xd6YaMBEyITSUjam++DosfD/Krw5aS/drF2aR8tlH5nRWc2umRkOMxZMf6drnnYGrI891JLy37ZH2BUr8eLwHAsABAGql0zFsuJ3U7GsXuKsedpJN2MDNQNBhUltOHClVeUzZ/QyLbpwmLGsPi+5IsIScH3cAZJIyDZjCQ4NAJ7FuWCxVC9x0hq1sBKvBEEAJj6tKftVPb3T/UmH4TZ7FufKLHF/0jH93G8QBNh/+aiqBzO1puw33KkwPyw93DZ8VVl93n3DR421tmpRLj7iVlZf+ek5AKhalCuo8Qgxwg+NGPfglShj9Xn3XjLmXwiRyk/PYXKqXLjjofrpzb2XjqhKV8fsB/S1MKqwlLFe21qk9lnWxhpc5e2s8nYCQOXCHbQSDcN6hnxRC5+/ChGrz0suisdfKZLVuxJzaNkzoTrAIXAl5ig79Ex0uhJz3OL0oBYL+P17LraofQcCW5ESPJ4uo21QR+FQs9oHJ59IffBMjooF8idqVP9enxmgPQfssGJB9tSjdQEm3YmRuMAEzPwqpB8NBDu85k6XbK8uhlUsyFburbnTpU1VShfY+NTUdGuJlaEUDDSp/caf2nYIAMrmZwFA7WfdZfOzaP6o/UzdDGAniPTYhzpX7I3ceLZg6eSdotZJq89bMNA0daDFUjY/q+5uD6oKAp0Ul83PCja0VFUAIG1Je6u720MHkh2uVlXBLGSAuroetX6agfz+Rg0vADuTfrhkbqa0sv4PPdLNMPdivWxTeTgmRdyb398I6l9ZiDarOsQksHpL56yjmPSpf/1fvzgJifQlKA33eqXeF8/JQCk03OstnpMBQe6f0KOwmawT2oZ2WDI3U9t5FbGJZx3FTIYn0Gvbecbq81p93kl3YsO9Xoy9HL8fUBAA0kIwAnZCKxvu9YLfr01VrMNqxgKAtowS0qv1dct9IvbwyMbK+ZHWHH7S0fjHvmAN8nrrJ0GjqohNbMsoYTU2rP/ZTHtmCenRqC0AIL1ie6ZcW02f9wHAodkOLCvnR1Zz+EkHHiJt4OypB00vgUaITWzPZFhVwHTGihyrz0t6pu4RdWSVNt/vPzgrHSWFJ1sBJsdiOTTb0Xy/HwAOzkpXNpt0JzqhPpK1j9jEjqxS1qMiNDf3G21DpOzoqov8JAbvQp7LLi2ypWNNiy/AzNC9FNpsR1cdRJClpJacyy59dDtzI7S0nDfaBh3I6azV5QRZepO7M6csWLMD394OAEf+dD6ns5ZW6mVAiHEZQjhyhAdhAUD2OX20RQnnLyl0H7FrBw+qAp7Osbpzy0mHlhP5YMT4GgGxid255ZwEg/VfhTJ6nOWkXU9txQxiE3uc/KgK+PsX+x5nBWkXIeb5RjO44PY4K4w2RGe4ylhIb14FAJA2BlIXsYloLXdB4OgcS0bfqy5y1tTaIjax71UXn7PPZcai9Oe7yBkzLou4/PXnc6sq4DhjIed3ugGAnDZR6iI2Ea3ied75zliUgQI3OWV86sJENVDgjoMp5z1jUQZ3VQIAOWmMvFBSaENcTHecZCzKUGElAJATU5fUo60weu0ex42nmY6bjCXlwu4qLJDj0UpgKCk6UNxNMcD/AdrsIMEWx26aAAAAAElFTkSuQmCC\n\"\"\"\nFlatInDoorWord_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAGRpbS4gbWFycyAyOCAxOTowNjozOSAyMDIx5LtZ0AAAAY96VFh0RGVzY3JpcHRpb24AACiRVZLdbpwwEIXv9yks3+NflgIyRGmiSJWyUdVtot467Ig4CSYy3rB9+9osbIMvLJ2Z488zY6urU/eOPsENprcV5oRhBLbpD8a2FX78fZfk+KpGG7X78f0aBa8dytNgKvzi/UdJ6TiOZJSkdy0VjHH6Z3e/b16g04mxg9e2AYyCv7T9g+5g+NANnPP3faP9dOdMej2Ca8EmzkAL78SCpzvzrKdNkNNwwOhpKVPgUBJSTwbGeoOQ2mnvzCmE4tKcV5gRlslMSBykmOS0opRrmVY4iTplWY5nguArjxAroFgTxEzg/FshF4JcE+S6BhkICScFz7d5EfUZUWRMbLcLIl0j0jUiXReRptPjnWUE0DAYRecJqX1/dA1Ms7pxoH3v6kf7ZvvRKroELskw4lvtoT6YjqBOuwGJHPGiZFkpCySY4POhxfj/pG33fwcPXX3nAG6ubxEjvFjcl2T0/9TOPxy7Z/hSyZdYtPyCTxPfuw6NKXpRsa+lH0Xjv6w3/wB/98D5TMV6+AAAABB0RVh0U29mdHdhcmUARnJlZUNBRGMaYs8AAAApdEVYdFRpdGxlAEM6L1Byb3Zpc29pcmU0MDAvRmxhdGluZG9vcldvcmQucG5nUyvypgAADBhJREFUeJztnWlQHMcVx/9D6dNUpeJUkkpSJLVJbMfW4EtBjmUrrhxO4li2kEEGBAiQQFxC2NaBuJblvmTLwpYEAoQkQAIZBJKQLdlJnOODc/hILB/IFR8JlXQlqSQVp1LVn/PhDb2jWWBndmePnuVXlKqnp6ff635/vZ6d2dlR1q4txQorOM0qRVFi7cMKLmRFWEvy8v9+FbTNg5/6ThQ8kZFVSUkrwtK58t9fGjeT5+eCHsI8mnHzoU9/11GPJGYlY+HyJ7+gghUlmTAdInS24Ybvhe+Y1CSusF78z8+pEIKelkJ0xaAr7OHPfN+pzuUiEZfCS/9+BY7qKRCTwjZ+9oHI2YpPEitjzf7rZ4iwpEyQLZJX2ud+EDW7MSdRhHXxnz9FdCVlRMhr0+d/GBMHok9CLIXn//GTWEnKSPL8HKWu9C/8KNa+RByXZ6yZv7+M2CWqQETqyvjig7H2JbK4WVjTf3spfiRlRKSuzV/6cax9iRSuXQqn2JX4VBUhUldm8kOx9iUiuDNjTf71cjyrSkCpK+vLG2LtiPO4UFjP/+VFKVRFkLayv/JwrB1xGLcthRPzLzilKtN9wECcMkTayvE84khvcYKrMtb4ny+FGWyjmHK/ujFIY/gbh2mXtBXUokS4R1hn/jQbTnRJUnlfSxM1QefF2FiILGQfSFvGPqXGJUvh2EcXQ44oSSr/xk0AkkJ1gA7HgsJCc4a0JbqSGjdkrNEPL4QWSJJUwU2PAriU30WVaWN1IXsym99FPYQjLxdEBICSllYfax/CYuSD8yHEjyRVeHM6gItbO/07VBWcA9h02t606J2oKgBwToeH7Bs5JjUuWQptwTza9lsyELDwpY83nM/toEKSnUXxfG6HrkjOqebi1s708Ybtt2SEkLpoQSQP5UXupfDE+9N2UwLzaEW3bhZjnslpJ01kTHgVBRkTXgCKgpmcdioHxdiDv2ZhRSu6dTMABi0EbdGxkiKxsIavnQtBVcWrH1t0wGIepre0mWqWYXpLG6lq89lGU3Pj4cWrH7OrLYsOxC0JtBQyj1aSkjmd1SpqMid9mZO+qaxWAIHzYHVmOM+c9AUuneLwqazWzElfSUqmLW1R0ipJybTYPt5IUuRk6L0pWwmAebTS27KmDKqCqk5ltSqUFVR1KquV/vQT8IW9yyAamyuBrKkmOpzaULn0tqygV/NNRGz+Io6swrIVHubRym7Pnsxsoc3sc83Z55rBOVR1MrNFL8P/mU7UBPeB8+xzzaJmMrNFSA2AbtHQpuz2bOvaSp6fG3x3MnJzGFGkXAr7r561nq6YR6u4c4u+UqkqOKch58y0TGQ0QVWff6w5Z6YFwERGExXEumZlckQb6g2c58y0JCX5+xcWQ0PGAAFQcnJag7eKM/remrAlrJ135VB5PN0HIPe8f8hL1YgLWsZdgeiNCVUF56L9eLpP7+T6+nD8lwj5lkK7UalckyuOpUpjbwCgquPpPtrU1QCA87wLbXkX2pZ35jpjnIv2QlV5F9pIW8KEoiiVa3JtnWw5M3HRRcql0CLMo1Wl5pk/rqnqmUcb82fbaSt/tn0szQvjisM57bVyjVT0Q9AhY2leUlX+bLveCecmu9ahj4dVqXl2D4wtEl/HsoJpdAWXOkY3NkBVx9K8BZc6AltSZThTQv3TMkqS1eG84FKH6PnxtVttXX2QLkySCevZ18csBoN5tCfuzg8cW+ELnSOP1ENVRzc26GUAkYxc4QudCyZC70SuMMHdF0iXGxrnAISqtl/usnVzcClObqgTnW+/3LXgxuKNd99TYDFp0Wq4+54CB1yMFpJlLIswj7ZnXeFSAyu60g3gxEO1YtOpOaCeCcfnVa5IuVNYsBCG4pd6FlpG3psl2HvvNutnWnJFSqal8KlXT1o/25VoXBaRa0QuzFjMo+3/dpHbRiVdxpLLXYtINKia+4utrIZ0/l5zf3F0vAofmZZC67hyUJBqXCsZSyYkGteKsGRConFJsxS2vTJg8fexGx8oc+JiZzwiS7DgyozlvhEJJBrairBkQqKhJYqwetdXUeHJVw9H1x2/aSOhuSFRsKT5op/1IS16+O5fHwEAVe1dX9W7vipqbveur9K/OWhEVY0+hDm0+GSVPP8HrLLciBYemjh03649vzkSJYc4N9l65t5dAA7dtwuALTckCpbLl8KD6yr9Oxa+fyeewImJSwD2/vao8M2WGxIFS5qM1b5hF7ts7dbHFe2Glmv69sIX2Onffb87KlpGc+AH11UaTftR1YPrKj+5stpiP7IEC67MWACqX+t76ls7AV1S1a/1UX30x6p7oqpP31Np9ESH8+rX+hpg9UReomBJk7FsoSjY/3qfcTOG7H+978DdOwFAVXW5G7Dlm0TBcmfGWnRQPWsrjJs1b/RH2g2yWPNGP9kyOUC7bApLmmC5NmMZ6U6tAAwn7wCAnrUVtW9GUFvCKOmp9s3+QHOKgtrZ5+w8q+Ooi5FklYUfcZWM5Pk5Nqt1pz0BoDu13L+D89o3j4mt7tTy7tQKY42DdKeWm36KTdcZACAEo8yjj0gWZMpYPZueYBetf0PcX677/bHAyqVqHINzstv1zXLAkC9VtTu1XLhkHYkiBbeeYwFQFKVzTRmFc5kxRnT4/s5VFZzX/2EAQOeaMrFr/4Vetz6zKlPGsk7y/By7oGGNvmkaY8ddZaIcweGraueasoa3BgCA84a3Bvy2jLssI1ekXJuxAHivDrbfWYrrlQT4VyXv1cEIjV6YVhTFe3UQJllw7r06WH3+kPWnup/O2C1XnCTLWAc372bTlp8entEalcG2O0rN+zhvfDsg2E7T+PZg2x2lRhO6J/rqbK83ucIEd2csAIqi+N4ZWqw+GtZ97wwJQ623l4j7S753hvZOP2Prpy6lC1OSokCuP+skz8/tOfdMzB2mv6Z3h+jqQ9O7frVZgXm0Q5l7Yu6/3T/5MlZv1l42afWiQ/L8HJvSerP22rXSnLLDX37veODewMrgfb53HICi4MnJg+5OVwjjrURuxqgq02Zzyo7mlB1QVb1gH1uqYp5Q/lfEA9J8g9TIs9n7bP328JOTB231Twe2zA23zA1TuTllh3GXuJ4u6u12bh27/ccJkn0qDI3k+Tn2vPbcln1WGvtW64+x08y0XhumGkXRd7VeGza2tDWBj5992la6em7LPknjI985FnE4p5pN2HzRw1ntcE510JZt75+ggmlixESZZsy3ulgcsjxVE08lzltPEiJjEcnzc2xCO5IbXFtGvLcUma48XTdjli9K7Rq3pyrm0Y7kVssbHFkzFoCjefvZGftv1RrXjubtt9i+4RvbSTodfzxpEJZ5xoLOYeWZAyG8uFDe0EBqYQHo21rDTtvX1hmtb2vN8s3qb96mlzjv/OCUcZJsCWvn6R7Yf9Uq82h9W2skDkxCLYWC5Pk5dloD0J+/uLzqbtom7id2fXgq4GTLsMF5YANBxVhPaG9Y7c+XW1WQPWMBOFZQy0ZtvwqQ2rMxjXow7qq9sZBU1f3RCBb/CpeiNzNsmigf7UYYb7SXPSgAVsXaAQcITVsQ8hpdRF4wSIcgnUFV/fXXf9eZCFNSzKMFeiIj0mcsYqCwjo2Eoi1cL6+BQv8PtZtQFKXn49Garxt+bJ3zno9Haf7KRrqMvYUG82gDhXVuiAeg9PSMxtoHxyg91RVOXLHwdnticFudFYtUCNMumbZiURaUAwfGYu2Dk5Sc7Aw/xoSVu0YO2hraXu9IV3GC2z4VHi+qZydCXBNNOCWaoDCPdryo3l1xcMs5lpHh4gY27Iy2ogDzaMPFDW6LgfsyFnFiRwM7LoG2mEc7scOFqoIrMxZxssTLhuJXW3QCd7LE687Zd2vGIk6VetmghiieLVmEebRTpV647yF0Ay58xN7IqdJGAGwwXlIXJSryyt24OWMJRsoa2UDsUxfzaCNljXD3f+UFXHuOZWK03AeAHYuNvChRjZb7EmKuASRIxhKMVfgAsP7oyYskRXYTaaYTJmMZOb2zCQDri6C8xFV7spVwU5xoGcvImcomAOyo/76NI/f7jJ0jISVFJGLGMjK+q1mU2RHbIjPdTxS9JfScAkjkjBXIRFWzKLPDlp5bNB6CFT0ZUPr7J2Ptwwou5P8e/HuFIUbb6QAAAABJRU5ErkJggg==\n\"\"\"\nFlatOutDoor_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAQ13pUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjarZppcmM5DoT/8xRzBG4gyONwQ8TcYI4/H55ku1xVPdUdMVaXJT89cQESmQmqw/3Pvy38i59aUg5VtLfRWuSnjjry5EWPXz/3/fy6lmJ9fn/8pPfvFH58Q8v77cwVf/3+W+v7enlf/xiofT4z0G/eSPLTB8rn/PnbxPNz4vxtRdJT/PbTv/6ZnW52X7ubtRGG9trUa4rwMQw3LqJUno81Hso/4bU+j8Gjxxl3qvHEHRePnUbKqURLNZ2QZrJ00+F5p80aa75Zec555/Jc60XzyLvEkkr1R7KsZZRTesll51tKqaHkz7WkZ97xzLdTZ+aTuDUnBkt85H8+wp9u+DsPsx2JUUoeTC1PrPids+cheRiL/+Y2EpLsnTd5Avzx+PwJPyS2kEF5wtzZ4IzrNcSS9IWt8gCgcJ/w/MJX0uNZyw9KKnMLi0mFFMSWiqSWouasKdWSOwmarDyXmhcZSCL5sMhcS2nkpoMj5uYzmp57s+TXdUqF/EhpRcnNKJNk1SrgR2sHQ1OKVBFpotJlyAyttNqktabNa25q0aqiTVW7Dp299Nqlt66999HnyKNQkjLa0NHHGHMy56xhyuTTkzvmXHmVVZestnT1NdbcwGfXLbtt3X2PPU8+5dQjpx09/Ywzb7pAKdx65bart99xp4E1K1ZNrJlat2HzM2vvrP7y+AdZS++s5SdTfp9+Zo2rqj7QM0RynhHPGRnLNZFx9QwA6Ow5iz3Vmj1znrM4MlUhmUWK5+akOENqpLDelMXSZ+6+Mve38xaI9Z/ylv9O5oKn7v+QuRxu+Slvv8nacSbc8VWNXoUe01ioPiv7wHB7jmBNEqs4slhi5FJpUm1lJqqyYy/P+1Nf9+dLMT1vSrnPvUlJFm8GH+01WF9k52ukpVrFSP6+s0rTAUXl3Xuue4KKbSeqyR3SLwRYQl3RorVB9JsYuz5nkBBCTkyv9LzGPky+bJYLtbaV5qjaRlogZmu+t2qcKxyzNGXZqv0elbiYM+uxxD3UeDOJ8WgtN8pazy1t5Kj73tXrmVNXBGk6wry6teWm1SC3aUDjkAUWYPnsk7uUznpyr9bWKFQKI5089wIua46opzKSBBZQ+u1w0vX9HDtMdUl7HqSZPJ7Z6iHc6fDho2MaoLSlAGRq3j5aBeyBt3ttdy0gG0E2YenXCKnJvEV3naMfntCfscBmqgto6WKMaCteXhW5pYVqo4vOIbLz5I9RgPyc7RQr1wvgdpageqmslcAc60iLojqr2FESl0269SBa7yqHOrQl6OeUkeH30UpHu4BcTYy0GXyTlmi9tQf5cqrVm4E7aDu7BzPX8ILakTmzQpwv6Iez16RQ0toHxeHjZ4OWMxfE3/YtIDidaFdlDIjtBMkqJ9vdQHS1mwV4jlb72fwmiDpuIc4kDGuwqTaDIy64O3vW61mh/FeRQBqpwUUN6G1tERJJHQmYpy2I5gBwx0IiqqBdJhVGPRf0nEwKVV1boiR2mJ2yhQjOtDhuB9qAYjeIoEN4jWn2vPdKHRHcZZBGydo4ScmVHsl1rMJOAtsvG0riql74S/iQbt5pkwID/ZLIpbqxWADVJkUo1z0O82M9WH8ep7VwIIwKFkZy5He2TGHufm7HfrTh+1ngMOdO4izOw8aioKWXlMpI3Jwc8CGz5HRtd2vQkzlxQv8JfIzZPH+TtdejrXmloK5NiA7MALp+ZJQAaWiT/Q+Y5/fEE744DIoFJ/xxj7T3qIQur7tZbWkKCvvnLKJ+I3/wHmjL4T3KtF9G8fkIIJ9vVPWZuVJkckrlzd4PK9RSxtVkXWoMK0HXFKQnl6gdpgLFE+DNigNPs4BgPk3tQSqVcitxOukVfB5B7retffdmIKaDUeolpi5FzRet2oyPJpglnqpnPjbSSISXFJyYiqJcAxnBXVKoGobvEIKFYXxBCMeEEO2msa4siIjxy5otswgEJC3QSdlMytMmyMPQZv9E2BbvBmMKJCDpe9FsQgPKKDLWX00hUUzXdpwJuyaLTAzrDy/uvVuvM46wWC/xpvT3mhMd29QLWy0TxkZL2eEecMlif43CLGqZiusNRUFMssBOXacFFrags3gcwxHhHqn6skpBEc9i52PuC7ZlrgpGYECn9YkRx1+DZCvge7Ww0JrU4uVucHDzQtOXwKew/+1NhRrnv0JklXsbCjycF22TOs3INhzJ6GGUe+CafnqLs2Hp+5xyCfcjyAf2tQWKoC4weXQinuQRSVo1x4EZ8NCjdqESN2HjCgpQoEvcah1JYH3I8kTIQXCuM+V9bc2L78GAXDnrGqlcrwnyCDdRjT5YEoUd/N/WtKH9PiEFGAnIA61toABRvhd6QRkr2xxOXfgmaz0GxyI+Ch4lUM7niEnqayeZY+0Zq3vryliGY/JqUHpMd+C4Q5e0kxZZpzvapHhCdwUGZcfowfaOzObYENxBMvLaOLpE6khmdXPkYgNJLaUCj1rFk50ALOlty15xzskHeQwP9CAzK5EgXmGIyhl7ZRLT2QxIJIRsgb30h3djCwORwzDKxcAQQ8GvVoI0aA+pE3wASs+O9OA6Dvq0YX7GKomaxBdS7Vo2zIiHpD8h2ER5utdrbvukw/tXQPumvG90b8KoNx9nBVDlxUHQUR0DXWcdCy46GBYsdRkasQl1kEJkl/GY0GgRF7aHIk/D7dBuhnQaWYX10Sa4z7ntBD0t2wDLh5YXU4VlVsQn4nuSOWfDrmJui6XAun3hWU/GiQALN5BYWT4qJ5w3CyZnyLlfDIztzfV/kua3253Nw18w8vvlSp+D1fki6p8vv3j64Wyf72OS95wP8+/2OYfPyZQTDcfFAESKAu/sTUPbNeH4AxU+19cnmoBoMoJlrRdVRZ0AU8SlRxusdYNLyL0hvR1vZtmZfWq30ClRP0jBpSeKlF5lF/zwIhL0hQduQxPxg/AJ1QK7UbeZWi7OvSSyuf5tTAR4X06xQk1jCCDUevIm2MemY6E2lO0UYR0Ac1p7HFQuwzsSzIvhMWAuCU+9O11ABhAdno8VY03odfbO6fUXjsDf7PH3F7yKA+01kYcRW+dSpB+bqTZsK/Gmq8r0yzJiIorsowyghR1Z20OJ+4QBH7cROwMRIpQQyaAlyPPWhY2pjnqGwbBRkJBxSWCVmsKbEAIEE8WEGghKRxzwMuG2Tj10HJDhDLvtJwKE4OFUHG/BNmLMGtluBfY7XjhVaMvEc80geMpSAqkcFOjJj4a65R+I5aCqaqbQ2qlstEDDBQI8yXvPCSt6QPiDRVnvUG0MbiW9jwOGFCWil815EG1OFUKijkZDMvEJI5XuB0HQoRIe6CuxYBkCv+UZDtkv2HRs1iksl2Q6BVyCSefpxgY4ysWa4vS2y9HPqFfn9hGeQvlndUKZSv9yR6/SDB8O7AFR/cG3PXiJf+PCcQGogQ1NDAFZoG8mxWX0vuLDs97/wj8kb0OnnbaLMNNmE09aXDLRPb00P37MEFALWqFkuOAbif6NZSlysTZKgREn/fh7gAkr0UTSumB3JtEeh+QANWuoUJkBHS+n4+4JdMRboQ7oBTbq5LTp+W6NNgWlXE7QyCilTDeB3HZ6GG9NC+iyGsRP72gEN00NF10+sQUQ9uPtcRGPycS5ZFwxesC6IAd9KsoPmzryR0OaQkov9a4goySK7Y9/o2wJ74DA0gD6OcZcM58AarwpvNRFFLplEg1WHeVwK0aUpTVFfhpuzyI63HEfAIsC1Yq6OoXnWXKAiOhEj/CguYD5sFnsvUNNiD6BBKn0oGb3bJqrRecHSipWqZJdWlS3hMSOdt2RBUlE9E+wKznXuieSCKg8csSQHCHo1NGVjTmIuQ2CHaHKx9YYjUoLkUYUTt+VYmxQc9FKL9pcjMw7HNwagZiRAvHLCOu9+ydQmsSLrfnqL96k9+cLbxod+iJAZ/LgjJZ/ue7VltorXeu5gEN7NKy/SHbKc6GdV7GVFHKB+WcvT1+dBhqBU4QgW8d10vrshTfB/yELaT0HCNttGgbYGWl3bz0xOz2s1i5VBDOeQf/a3BjDbQopbowTKkRyO5aD9o2qAIXqEMfjl0UHmN3gHKoyYA1pV2DuhTWnaWFLM2M0BMxSqiPRp8L29JBFMNvYTTi9ef+Hl5pEXLy5GS3gmLFXbGAlP8+gPyyPU1y6MS2jpTs2XQ8NA59w33uWYZimN1PIHYWXqM4DspE9OiVcNysZ9qohlslqEOsq5Z2qBag+b/CoN++aX1nyaAcR+reeLnUni/7BmzhwxqsJovDfjfRf16SsxZs2TGp7zCZr24OtPYVyA40crTCdWgcm0b0W1kE8HAQTB3pJGbaanu8ao3Zf+7w/A0N6gND1/wAk+OjNLPc8HG8vjpdvEu9crt+sQfzlQvj9Lbl3aNKPdHP1w35fLOJFfvEzbjRx/ofun1UUuXDEDor2MgROFTadr6hGGJZ6dBjAWwuK3koLu1USGx4k80IR0Zlf3dGC7xsyzQkWCbpy80sokGPgce2ae23sPcpWTJFL+kT6qiTVXbLQuQ+jeWapF1+BGaUDJyfY9QbCzU/gJuhGUi+OwZkcsiN5r3ChMLf4wP7Fy7jOvbQJEApyhEg02rgGiUY/2RA/pJWtBysANBi44nXofLslAJZw/tnNtSJ58DKIMu+yP1P/cmxrVeBQvl2DgPwC3LpxR+LCWVfa0Qh7zoMazHfQ9xcMCLAYNJ3YePCGwulYo7eGGtLkuERZNgwqvWFVzMmK0GO/T+HxFuXaAqY5lkz3xFrovDGhGDDaUvWDuZaZLMIxjYhebOmluYS0aXmrlwnVsYWFAocQqzAQXT4CeNWSWxnKBTrKbr4EqC7vnNAP2kI6GTSe8FPKiChXF56baqqhI9xpIc6ApwATnB+NG0U+N/2wYFuJrPeqmGFP2mZ8PxKrcyCaSDlliX5p8LMCEIfXPNDE3P0npN/nG7Y/u+Tw85X2mbBPgXBz/yn230ryK7sWfqz2D5X/Xu0fJux7tasTAKP3csDAigF31F7Tv2sSh9Q9J2i9+hcZXgpQYk2Ow0Nv0ZCaTHPr8L/wtn+ZAo4ILbZH3f1guQQGHtBexFtjOtx/ntbnxlGtMS6V6ueF0V2aI4WWBO+MkJ0KIP2ohzUqPYW3VAh59i9KxmnOk3eDOW4EqQd2wa75Ma15d3r97IdeNPkxFrqW0B1L9NHmxyF0M8dbRD+8vlA5JK6v06MXp4IsjALLpNLLdvvTVuLz9CLFUC3a4ATeIGwmpuZhTOTJKUcRdau+w8fTdLyOfyFT6VIEQzET4sRwfhKBwWfrA4+HVyn7RkRRza/3mmEF6IbaijQ4QM5w95PuCeLybzwwUuxrNQ3tcTGG6fdTX0ww1Eqlj4ry6e54M6MZOK7R8MsYgDh270YoNNqIfqFQOrAdLt0SYiMIEVYrKmaVSvdzjubfSJFHtic4g23KAvJ1expBzvDjyMgUtCh1rlBoPDaVbsW/OWEB27bRF0NnxasQDiBqz0m3eSzc7UHUe25C3XvGFdXCagKWGOj6GfF9Ogzmj+cuP4OLj0TRIUZJ81TXa2chnOYmgmvv7V8Jet+EvockbvJY9C/1wULoevZfl8i34gu/VN8fi49mchLngdplf/V6Dh8vfvOcvMzoBEfDKYBKLABveJZXxNKZvm6kmZDaGGi74EUYGGvkh3130hYaVa3PzPtyG2aieg0DewV2JBSNXEMKff58bgvH/w+F36/or56L2Rnhv7W2IPPh+mRnAAAABmJLR0QA0wAAAAA3Fr72AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAB3RJTUUH5QMbDjk0b0ve2gAADB5JREFUeNrtXWlwFMcVfiO5ypUOZTbBgWAgiuMktgoTGwOOCcEJtqEQIIw4dEuAQEK7uiUWSehYrS5WWiGtVtKukNCB7oPD5i6IrQDBOYhNZA5BCDEKEEKFH5uq1OQn+dGzs7OzsyshrdB0a17tj9k3b6bf1/3Ne909PTPM4sVxoIgi3pYXGIZRakERhVgTK3/cXf/zivjRmAn/juaQqSbMe++plVr4fbqV20IIWBYAllaqPRkjBADYEh/iwX6KEmvpUs0Ur4Iv0iw8n4T0+kWVxrMxNuA1kvZKKpzawrIAsMyUgP9dTq0DhL5Is/AaV1lmSsA1t8yUMBr7y6l1osMpJ5aPz5Qm1qXkWhxvlpsTfXzsGjvVRJXD7ZIiChZ3lcmV4sKz5eZEJWJNAYbxedBOrEvJte/XJDnZCZMmzxW7RrIyLybViFOt/XCJ8yvEokqEnXGWBYBf1SbbuSJhjvdeSDSLkqlrZV5INPOs4s8p3HUxqUakV1IhATKgqQaAFZaUETtYIrMLidWuyhWWFHxCXGmup8XJ1Kl0hIBlsaVor7uES4f4MPQK164AHmw+sKbyEUuol1Ty+gFNtbCUgd2NQo2TsT1Feiha8ljShc5U+Fl8lbA/NCqMCH2uNon6Uh/Wp4kO/bA+7bP4KidjN5bYTHKXxKwPda1AYSo8H1fJUYplVzakS+cggaxsSD8fV+nUGQewaf0A4AicdbW36fzxhko/hNPZyoZ0D0WMUMMjHa503uUiqxozzsXux9waJbpVjRkA0PfgtKM79WLuyB04XTHe6IczwXPXjCEa4XKpHD5RPiocJbre+6cAYMWLec90cqH9wIMivBEyby31aW5UNb96tZZKYGdijDhoBTS7Bdg9fJLrOX0r32vdu/8VAkCY3zrOBwAPDtBMrICAPST6fXp7Od5Y07LHkw1CwLKSNl33TniRT5L0UumHJB04vb3cg9tKKpw0ObWtDDfY2tbM0bgvwtj5zXEA+AjpJg75R0gHAL/R6QFAZRzmLwN+IHl6e/na1kyaiUX0qNCz84FtWSeiDYDQqW1lgW1ZWNl+99OV3y4AgOcAGxd0XlvAhS7BSNCD8yeiDSIURKbCwMBssjw+HrUPh6v17dnPZI+nCVZNK3j+Pp/7b4FjegJA0vPjUfv4eObg37MgVVLhuIVlP+7YK3T808hSAPi4Y6+7I2w6/1XT9JM2AzJNDwDndLqtPwkSzi9gtyX4xGtckCqpcELkWHgJrm6h25JKXoK6clpuH139kn7S5yBXv6Q/e0fHxy0xmex8CurK4UCNIt3LNxUGBeWS4uvRsGJMoI3duZ6VQmm+dSRgeqGM5kH+k68yDrtGpmcCpaRCr8mR0CJ3ozwPyqahwwHTi2QFJGB60Rltnko/tKknzwENoaNhxViD/wLLburJI3duldm8OZ8UX/uDC/nrGwC29OX3Bxfiv1v6JFA03uhfoyqWJ5bTttzY+VucoPGLAe2LwyRBKRHL+xLcrwOAvi16XPUcz9yEq4brfWu/UyxnbEKfg/t1fVv0wtFJcL+O6FtB5I0KQw4X9G4uEF7ZIYcLJEHIGdm67xafvJ67a0GIk3YkRMqocGIl7KgeALo36gAhQAjzDCuxWAd7AmeUyBxY4IySE9dy1G+FCgMV5hYFa5kIXkEafqyQG6UjBAh1b9RhvXWwJ3BGKQBDwg/Ea1ZZNvxYIQ1LSMPDi0i/ODo35AmfhrDp/Ne/vI8U548/yU5YGM5BYNmIT4hvDoJToUiijhe3r8/FV7xN67dhpoGg9ZgbZho+uZoF4dxMKTULeilZ6Bd9ogQA2gJzSAXAshiFh9bg0WGwcp/Hio4uBVqk+kp70CwDiZ4fe5yVsiRKpDy0bq/EmBEAWHbrSbm3Gm0PU5AbgHFDtKzJlmASCG4mEjJspGfNe+UfDm2aXU4uGI5SLsu2sMSc4SJxc0AWEdcPZQ9TkIpl02zjEZ1WZRwWkmnH2TJBJCYsMFOVCul4Oi/2XPkIcBBqWp3JmykRS4lY3uwmyrzhKCFW2aWm4LkVRCMJnlvRp92t0g9RQiwiUqH1gwy8of58P33jQcnhobfMlIglIZYV6U5jb6lH5rGN7YI/JcRCyPpBhmag0m2FIAQsqxmolDlc2adC50cMhFRL+G2V0IaSgMWygJBlRboDHQAA1P06TVgbyqhwXJJ00VTzfqo0z4R1zQ3RKRqFIMShEwFnWVwt8h//yj1iJV+qBgDz8hS8jTfElzhFfSwHRueX4WKYuDaIAErGqDDld2ZcoXhDJPrz1ohXTXTEK4ZhMMbqXyZL1gApQsl0AzVDQh5I6uUaZz1hQKghFlBGLNLlBeVt3MoVokQsaSkKSGw/kxL1mlmJWErEUq51JWLJVYzvcl/b0v7JQs21rkSsSZbyJRp+ztD4rsZ2yl+JWErEGqOULVYDwJ4rlvIl9i8DCl92AErEUiLWmIWfj0YIWDbrSysAGBapKbjWW24nGtYnUzNG9yHkiWHGsEgt9XE27nlilX6o5TYF3/5jqPkRFbFYNvurel9fqR6J6M6a0sFS+ljPlAf3vRO/9+oBiR4J9zEmpYOl9LG8dFmXLtyFU6QxKLX5WOIO/1oSm6FpKNEYlErTTRBiIlbuYEPxW3GAUMnbHJNyBxsAnuJwlTvYYMdBautQ9skd0iKW4Ou6DAO+vgwA5H3Ns4rIbHjwZsL+TWmU3bNl8vIaacKTfrgydr6FLJ8bb2hU+qH8a1Q1hLK6QRasAoDCBbEAoLveSA2xqGKWKTijsU8T96aVJKfx/BxCAKB/M7bgxkEaiEUHn3x9ffLeiMHbNvAnxe2G62qVfghYKLhxsGD+TkwyvEE6vWj4ij1uiaJbzfhlpCrjcMN1NSnvINXfbMJDQv3NJv3NJv6VqgXzd2JoeIM80eubiL4y8v134FRSdKsZALi4hZBN67drQb2cPT9wLd4culsaEQgfa4PCIfLaiCksbCaXVXlvxDg6KHZu8fSy6fzjfyZTbtV/HV8Tph0Zmn1uhYemjAqf78yWfRLr6VP7VJaMH4+2DsbXhmuZUULj3i2g9LGel+S+zl3TJX9twUEr9/UYHx+GH+eq9EPWwXiZZooRoQE4oI1kL0MhmFjCRiq904q5lfPT7dwu/K6HyEzrYLysOuzWwXhLZKZnaKV3WvGPg0YgsZjS0lZy02D2j7cBwL6/tQr/8umD16vbyzRvH5h0by1/2QUA1iiavzFO0QQpQg4+gePlGYa7h3hk9dFZlrZdCQsbJtHNuqtxeIaduTsl7nWQ/dZOw91D/MQP97OzSjwKi86quxpXdzVuslhVH52FeZ/12tapQCzGYGgjHUPmj6KFf8v+3ubBzKbzT3znud6Pq/0q9sDWbIcPCAHLunOSHmKVlbVRf/XseTXakSUBbFo/AEhaNOH0qvkyFgAatmU7eWIPq+Xf0FzztN2EdhXtD6OEM40AgF+nXqOLnTh6YUrhgph7jho23mvn/aG75hmjsZ1uYu32i8LZp2K4XaTBmdG79MKUOhizV7Jody5RSKyKig6KWZXxg0jchPv/0SHWAwAA1u9o4r6nlbx4jGsKzH/eiTeaduSM6ABXupRjNKVC2ntYLFt5v0MIM31eJJ8csb55J8cG88GdwkNTlrjlWfUVJ0s8lVB5v8NddQodqLzfkT4v0lVPVcSqrOykmFRpcyMAoOpBp1iJELCsSO8q2xuL3e3CTHKsQbBvuJ7TtTheM0o3iCRWVRXNxEqdEwEApoedIo1IOeYz8+dJnRPBR0HXM3N7nR/jNj3s5PXjdEaG4kPTY92SK+kAodQ5EfgvxwbHS0TG+ONpZHrYhTWmh10C3ojtub3CWVzODNwdQvqPMZm66O5ipbwS7pSwAIBlq//ZNc5zis6Q8kq4o/vl5uSSNrxynC4p81iT038XbpsfdY8TNCaBkCjCqTJ3VWp+1O3alzc/6k6eHTZ+l2TXxzKbu2FqSNL3w3DoqvlXtxdO5UwmJ4Z5owglYpEhibNCcZPXPu4ZP+Laxz2Js0IxpWof9ziV4qUilHks0kK0F/E6LxpOmBlK6DLiCannurpe6kFqvheCm9zy796JOK2QZ94tQolYshbrk171yyHWJ73eB+s8LJiQIgiNWFZrn1ILinhd/g+rxqbcdNJWWwAAAABJRU5ErkJggg==\n\"\"\"\nFlatOutDoorWord_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAPjHpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjarZltchsxj4T/8xR7BH6BII9DEmTV3mCPvw9GsmMneZNs1Vq2JY1m+AE0uhujcP7nv2/4L35qLD1U0d5Ga5GfOurIkxc9/vg57+fXsRTr8//jJ73/p/D1Ay3vjzNH/PX7vdb38fI+/jFQ+3xmoN98kOSnC8rn/PnbxPNz4vxtRVXijV9/+o+/e63fe167m7URhvba1GuK8DEMJy6GKs9ljYfyJ7zW5zF49DjjTjVa3HHx2GmknEq8qSYLaaabTjKed9qsseaTleecdy7PsV40j7xLLKlUf6SbtYxipZdcdj6llBpK/lxLeuYdz3w7dWa2xKk5MVjikj8+wt9O+JfHvTsSo5Q8mFqeWPE/Z89D8jAW/89pJCTdd97kCfDH4/MnfElsIYPyhLmzwRnXa4gl6Qe2ygOAwnnC8wtfSc2zlh+UVOYWFpMKKYgtFUktRc1ZU6oldxI0WXkuNS8ykESyschcS2nkpoMj5uYaTc+5WfLrOKVCfqS0ouRmlEmyahXwo7WDoSlFqog0UekyZIZWWm3SWtPmNTe1aFXRpqpdh85eeu3SW9fe++hz5FEoSRlt6OhjjDmZc9YwZXL15Iw5V15l1SWrLV19jTU38Nl1y25bd99jT8tWrJpYM7Vuw+ZJByiFU4+cdvT0M868YO2WW6/cdvX2O+78zNo7q788/g9ZS++s5SdTfp5+Zo2jqj7QM0RynhHPGRnLNZFx9QwA6Ow5iz3Vmj1znrM4MlUhmUWK58ZSnCE1UlhPynLTZ+5+ZO6f8xaI9d/ylv8lc8FT9/+QuRxO+Slvv8maORPu+KpGr0KPaSxU3y3bYLg9R7hNEqswWSwxcqg0qXdlJqqyYy/P51Nf5+dDMT0fSjnPuUlJFh8GH+01WF9k5zVS675/0zK7bR2praRjMMqwtTrCotbWAh7QaW1rl9HCyrJkCtTVWFMl5zDMkd3PVIKc5Ggrq8iE40bu1TzMZ7U+GSmfaXw8Z28hZZVR2qrESbOcpBcStpZvL3t3X7WOC0DO5tS0Y+rnwp3Kpq4vrUxZaUjQCpnkszrhz8jD7Kc2LaartWmnj1bSIcHgIpHdWfKGAyHpugvpzVp3IzdOtXkNYjDG2nmd3AaQumXt0ffKQyrIPrPqnvWWfg5r6SLIQJ+7cbqWXUQ0UbTAp7Zy917Kgs+dydAUZW3C2XOkZbaq3VYGkV7CWlcfmXJs6UBrYLAYyDamsFunjlz7JWFkdo+S5vRFxTKAYCpnWY2XNXeAI7fK0ENWOhnbbWW7Yc6zL1vfZ1fiVxkeCYpvmAEMOUYgjhh1k/q0WcdoqbYjw/ohr6bpXAlGFaPAzLqPMHQFSElzm3lpA1F7KpppTE6J5r1d70uuprrvScNiqYSmnDBTMV+eUOMUr61NgQAovTKtdsrY2YDqUYefjdnM99s3n0UyMM7Yp44Ubh/wYp5HfQApM7GNfJolmIAQExBRQFlVURPeGvU18mrX6s27dZAJK8WAVJeeI+hBQCjsYbXBDr4cMA+H7AXVrQEJSSWv0kHhWUIGqdAFK0FNeewAq1yRRdzyeBYKt3wJtRfsOTX9tZzDf67n7+UM7SnsvYqBi/eo5qG1cdjEhkbY4+c08/qZ3T+UVj5HgZ1+HsWnWyAHuPhnEvon0VA5tqjfNPuGA245lN9OLU6NleLIaw4rS/qKVteuKZsZhYkTqt0C7AmkFZ7h9EPlXCkwTZ0H3hfYe0Z4wYu2FOtySBxUgp2Te248Oll8v2cFYcxmELvjasK0S/3XTlmz2lln3XlsJVu9QOiSJfKBl+UaluEdmfBz1GAz73kazrBtXxZJKmUn5j0VB3hvF3hq20xIyGH8cQASQnFE4aZCANphZSHBDI5ZWHJRmKUuo+I6kdK145Heq8cFUoPoxlbUbEdW1M4GSV4z6c54ZtCb2A9uE7gqJAEFUWqzjXKB860OTtAz253KGicj78rRWY+j19rkBFYVWO2itqjtjq46XA8Izp39QEX4WeFXuh4v8c2p1vSaDd9FwW8thMwaWVtgxCiEAYGnDJGV1GxC+VfHqQQOKRmMRwkhcugdrLVqOvi1bpCzQuYFWgxzYK6hSpQYtsI6xHKuQj/NEzsFXi9D8BVXklgqBEihLipdzNn/Ot2yLVTkUobsZ5aLyu7IBZYMnoZPOiDc26JC/RuojtQV4NI/TMLJuOcU+E1ykTDOMaaA/IwrUPfkooFQA03U3xRxOsvVzsYiuhv2GrgRUA1M4DekLI52Q+ygbO5uJD6zud0b+du6YiEop7EMbSiJzb1SwuqQ1z3hm3RVQLc9FaeLFTE0cVqGvkJSW/gEMA+U5J6B0jZfcdtoFBXtNXuJP/L29IQwNkFjaQHfhfB1RgKTpGGSp6xI2oScE+VbyHhdk1DqFoiFNZjAs4j8ZovxVsCOqzVItHcUoBmgjS27KwRycwNlNurUzRwdC7UwpC44zSr6pLAu8t9Ws0vtBgeKKOV4cQW3bRfAzFbiF655U80lTGDr9+wUvtPTD3b6pL5/Yr5Wwot4d/scLL8Y8efDb0b06aX/mOM9ZW1h+3wfk7znfBi8lc8NvNkWiOdse0fY+tlX9lrOeIWJQALf2BF1EoDczYSDGICkI7ALJZK5oD/mLgXWEuwMVAL2uAAW7UrgDddlzpC3ZhokPHo/mFa6Ve9XBxkfkWIrn6dKRZW+HanxOWBGNkNbcPOAfSintfAwlOg+MTnYOZNt0KThvjCGmChQAPkDRyiHWitFN55sCM6/gw+3xlpB21kFjR1YHJwFHNyoAwxickdZ0rjuYIhVPeMuRCNtaBGaxfOcMB7hw4VVQozyRz9t+0inY6g6MJd0cXmwEbr9u8zh19F+eUvuv+fu97gIvwNG/xRsS6vN+kXnF86HIvz1QPjdKRSRevFntn8wJVjMHJf7QFK+OGtn6gXxbVBkpVUBIAGuJEQZcsFp9nbcnEZ6M4BEaLK7KHeoQs8CT1gflLjCWXAX+KSJsrP5l3BsKBlJwEJfXk3vfwZ5X8QaYwwbmOOLmIPhjepH7wZnOnAXpIY/Ty61dEcNmaUfjI2l7xF3SWB2s8hx8F/OLXQ7OOnGXjqFRed3O1SANib6hETEWf4KLvI4XcBKHhOgikRs1QNVOMJoC99gRmaKZy3rgBNfWKfV7Fuivw8/H/j2XkAoxh5i2wp7NrdnIAKXS0rWipF4nNMXbj+QeERHUY1Km+SiDuMA8EFR4+EaDoFuWeVunEn1VgOXTfwyzrjh7y/r5vngRpxxL005djvhpW24PKIEtAzjDVZaCyJh7nNkz9jQU1ZfnZqBNb1G7WGfPCXifXnhHMhAbj4/XOUTH/EO/tuRGH8+EOKvp7xZIx97ygBouO1k5z8f9urILySPoM8RkPzUkhsIT9F6Dth6FR6M4N0RtpvcZaQZDSj0XDTCVBEIQPwCXSFdApaQZoMX/XgHSQOHMFWO4uSu1hX3BX0z0cYBUux9pqjJMbS0iRjwD1gn3YZK0eYefDzNLj4fX1cHipV9bcNA1cISnOgeMuF8DZjTXRJ5Zbn4mxl4TbOaUcFZopthZYInLd5a74pRo1PYrAk7utC/hAfI1Z2wUDZgdF10fQdO9lsnoxvpFqCCO6awxnXBH9QHHfYo1IxkmirkAp+WXQHABG8uki7MLLgRXeWCO/4GfZlAA1MvPKDU26S3wUWgsIz5RNbradFsY7tQlLgqzZQ3P2Hisuc1v50o3mUviou4UY2NXtO7jVTvK8VzDb8HhCl9Ukvy04AMhneRLcAgNP0F718wGuYmF2OenKx3VTdqNNSjP43FdERNwswV+fVWEEWaPOTIb+N27OjO170kWlYhEHevtALe6uLy+njChoRE3fQSg2wUHBR8UUfx+zV1Buwtyezy3M2mMcZ0Qpm4XLZ/aVdWXcgH/hj66efuTnDJiJ5GkBIBfaxcXgFbPgmpbOyOIpoObcqQ7n/UTEqYGmtsw+9f8o/u9WX1QBgJch3FiaaBYT9xeD+8O+0x8gihYfZLQxPBIB5PZbOHiXmAASZbi7T0VByXcDBF2gJilsNTfSxlAArkWEeFZGac3lGQbE5GKxoWdzdDX1KlkNRbJvqtr6UZ3rXpQrGxxH29tEyegm32Urq/VL4XfvhR+fm798iRtuh5VdoHwfzhQPhxBGzAhIgVstbHoMtH7VioaxeLJHkgigahTy8GlMJrf4r4/RiBs2k/WknAY9A6CUkQbAZ7JUSTJtDvt0DgtAbUAaE6y2nBl4Etw59TvhQwRevvBtW7PT+t5ZNqSrv0a6SCTkhmdl5G95YHrpIE15O0KGWl+YKaKxTw3IdsngRz1++3Vqrv5x6w+46wsdyTsDgFBKDUvMMnYg5B/XVy67ka5E9b2vdlwoYZUJpO3DpLpkQgAgpwGt3wGGAB2WJt0AeX0/31NNZ7k+Na6ChZzsntHVTERUoHPqOVlBLN3+outbL0Ngxewx/YLeCSfme3Rg0RhOtfQASqAQI+9GvDuRVSobFC5dky7hZ0Y7XI36BoELKRWCgOOM7XN0qOLLQV/g+sHeJN0/XeDHA/lt+L9W6j9aS21e+qVSPOmInRC13RYx+JrnRIwNu0E5rfk2iRJ2drv5/j3+NMp3HxW5w0YYg9TkC9M1P3qce/WDC6ZeiZPhl3s02CN8Ko7EJhcAOD1rqAN3p6wJCm22YnBdotdpOp9IUjeLCcPcyEL/q9S8uBP4wUhHP8Mrw6fhoz8L0Y8JG/9+o/DoRfjnDgfTkQ/tBbKdRoeddo+S7Or6vDl7Of+1QfTvZ79X/6pm/V/3Xk8H1ojJJWZXsR/UhVCXl8VoQKuBI89x+QdCoI54PS4peu35SRAFc9t/Ywr7WlbId0YIq9Fzoo6Wo6kF2KgqxObO1B4EoH1eArKhVOxUOwqEgEKxXtq6+rBt2WN7M0SLNz5a40DguQ1bj9WytcKAVMgtHexDAUSEFboJHsFgFmb88d3wVw/CYINc2LdRbie++kcvANNvw7kdQbNVFuf24XUXt+S2OCI3Q/k3X4iIrucqL6LealeG0mpzOK9IbN/UNmFahnxxvSK9ITqlcxiOxbQ6Eqst+rxHM0ufoJhi+5pxIfPv9TRsOfUvoLWP6AlfBXsECRHb2v0Z/oU/7Dc/hyYNTk7QbdIgbAFSwiwM0zOse6z5cXCJ4rbDt+q5xzMPJyvGGU0P1OolvjxkKFvOIDYUe6IiBI8V96YjoiaAzdxgWAJ6p/+Ty1idJTg8aM0mIq183pIHYMjjmA/f0s1YFteC0s/sNzeF7oBTgxhv8FLDGEwxoX18IAAAAGYktHRADTAAAAADcWvvYAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAHdElNRQflAxsVFgU8+qocAAAK90lEQVR42u1da3AT1xU+ayhNbyYTJpNHO2UgTRtCCiQUaJPQkLaAAQMmYHCwCTjB4IdkW1hYfiHjt41sbOSn5BeYV2weAQIuODycTELDhCQ4FAgFEkhxCRPCdIZfd9o/aX/c1dXVai1btoX3ru43+rG6e1d7zr3ffuecXe2uNH16PAgIDDVGSpIkRkFAEGuwOGdpULS8VJEoeDD0xAoJCXbFEiMQCEivvGIMHm/Pmh2AEGDsbnJ9nWE3CjaIUDgQfJJaDwAerGK+ilxThMLBYmZNMl0+Y6oDhAjt2PaA4oypTmGGDkPhzJkpQcKnj1NqycJrtSnKdldAVKwKkAEUAd2dCIVDjI+SaxQtf6ozeRxM3i4HLCB6GEPTO9eCjuOv3kLhh8bqPuo+hD5KrvmLY72yE0KA8eBHQ2kAQm7i0vQOY2JASIh+a21JX1ChC8CHxmpJkmY5U1nRopjlTJ3lTAWMASHSc8BQoTXGgLG8C5c9s5ypkt6hn1DYlWhnv85uMLONCjc/MFSRDt7wscovsD8iSdCVaCeiOLvBHAwFqD6rwtCmDYoo05VoD23awMYjFcd9rOr3fgHgVPxWQIhwmm3p7cdPxW+lPfVTFYaGpunGmZNxlWRhbnOaooVgXovlxLoKmvfQbqrbDtYSNrvyuUcFhsQAURUG5nCRpBPrKlRXubmFEJlaucVHzeg/PBjsksN5LRb6272Zp5tSUZo/P103fOqM3QIAYdvT6bJ33Uc6dMZuUV7bcYFsDgDtP3T52Ff0k7P7aY/iZ+V2Vs+oSWqdeSVWWFiGXvPH42vKVdsXtGZ4rHUxbEFrRtvd0+7sG3zNbhe4ebDyqTn93PuC1gy5HSHAmFjivYmiXYRCLWLhjkyycOztMjbWLNyRKbdgDAD3bVPb4PQcyT2jvsdlDrh7nr4rE+LNn4e6d+SpSUq2YbxwRyY79tQ8fURDPV8rDN+VpXoSkrpMOuy+cxIAQkMy+yRTr8WgJHP31PdlihqT7KIjxkaWO2JsVCB9jLwOJkW3inV09WYAWLw720d2vOu7EwAwd8TAKaUs6EZkAsBJWxkAjM7qpvsiZnTEbCasIl97G/jFu7N1MCf6JNaRVaUsh+hXtnHn7ffnjsgKxN7Jz5602d4aM191dL3H/MiqUp1dQNT132YQ8qAUQoDx0jbrztudADD/J1kBvVI3PyTr/du2NWPDyNfDK0tofFSMubwKAACWtln1cQFRn4oV0Z5zKLrYnTgTMcA4oj2nted42KjsoYp9vhE2KruzZzMAxI5b0JtiHYoupjlZRHuObmZDtznWsr2bAOBgVBFbmm2/dTxs1MYHaQbZXeetUva8Bh3zg1FFbPGop7mQli/PheBA882/Lvipdbj2fvy/JSSdVwRrwqrI/XqbBSkyMi8YWNV0o2PhQ9bhteHYf0pGZ3V7n99644AOpyAobqZo/Oboop9ZteDninfz9y3P77NI1INiRUUV6JtVzutHwlGORozpwMWG8a+3R+QBQPQhPY98kNz+pRUfw9GmjutFKw8XQu8nSAWxOED91cOLH87VlIeLH849eq0wacJSfR/K+r+vUJsO6n7Y9axYNV8dXPKIFguuJY/kvXelwDRxmSAWt7mVpGXb9Dzyug2F9osHIh7N16xvEY/mH7qcb34hUigWj3IlCQsFsYYSlRf2LRtdKKgvQmEgyi6tWxj5WOGBC7npU6OEYnEWCUW8FsQKrnowKIilv1C4+bN3VjxezItXek1FdHsntDBVECt442D0kyXt56zWl1eLUKgJ1L6W6t2Y8nEVd5m7jqMhT4pVM9PzMXz0kRsYU7aZzlRzF190GTT4IFb1qyYlnzBWfaQHcYevmRLEGm647uKiDamfyM8hrvpjCulQ/arp/t+mCsUSxOob9hnJNOSZz9apJunms3X2GcnMw4/5Uyy3my6PeCeWKPe05JT73kOhWA8KaZ/W92Zs5ctJ7KzwUhXuvpNZ9Oe1ErUfPJ44TxrTPq0XijXccsVhKHRTCgAALOfqK15KUnSwnOOPW5LF4tC+lVv+YKRqlP6ZQ27xPvXg6mD9oOWtMeXa92vn7Qz29mjiGsGPP/6P5Ry7SijWkMKlRjKlFK8PwRgAMj53ULniKUdBCDDO+NzB2jxihMfbNIjXxEGRYz0IngHGmV842QhYNt1wv2sqL2lW5hfOsukGACj/vZE6ouIsQqQP3Uoo1hAg67yzP7mXbZqBo/qxtSfdFhpX1g+bs847Zdf4qRlH8nVZDQBs0xKZEW9QjSyjs7pbbelrxm7Rfo7L5oiEPVnnG2QfvYtcjNVd1h5CJAn4+ihIZpuWSFdldzfwcni09qSXzY0nNmd3N7BXFNxHDsYAkN3dIHuNENEqLj485Vilv0tQSdt7uSRSPi+h9UR67DjtihZr9sYvG2XvGL82ftnoHfV4ma+R/OXuTNpOpoFOifVCo/VCY8mUBC5qQzeTXMaTBWI/a3zJlATCNuuFRl7mixvFKn4xnh7KOX9vkltoxaSQLoRKpiTkSE3bOtPXPl2hNV+2/dPi8XQ/hFg+Ee8osWQ3uZIr3hQLYwDYdLGJ2LzpojwBRS/Eu8nnVS1qzcGWby3K5/p5RvbiF+Opa6zv1HGhWAFPTQhyLzUXTo7zSL9cArZ1oaHlmCXumUptHiS5l5ppg+wCACBED5XcS83UO75mKoS7YrBwclzh5DjF2rzLzXmXmxV//SOr7IsMzTe18gbA5ptp9kUGhYXUBTfnXH+OZb3jq3jn5p3Q+V+10HQEAAomxRVMivP9QmjaATxfAj1caL6ZVhVuLJgUx6qvwkfykbmFkLePvICntyDII87Qy7uDPDGeqAo3Nt0Y5hfjNt3YUBVu9M9TjAEgf+I64BB8Xitk/rSkur7gyjZFxV69OKnp6Ib4X9uHiVVmam3BlW15v11Ljo38ieuoqX6llRykwgUF23g8IHKfXwsAhf/wz3jTkfqE3zxobjV+Y655PUnVfvYtrwpf5A7++ygUa1Aourp9AKcSapckN75nTnz2wXGr4Wtz7ZJkyYf0uriV+/xa4tSmCbG8yxUASEVF2yHIkHy4DgAM4wNOL+d1c93SZN99cp6LdWeNaje0FV/jcoKC5DnvHqiPSAEA5yFz4LjlvG4mO+rv4KpRCgBKrrdyOj9SSckOCFYYD9YAgGF81VCzKtWxzDSADTc++zZdLv2a73mRSkuDl1gEhndrAMD43GDp5bgmP1HCudwEQY9gDIXK/DpyPQA4Dsi0SJpQ7Xdsvbqe/g5w98/JABFLDAFLLwCoP+Dx6BFVnhEmeW8rIBRLicxnYuQl1wvIy27uAoD6/SqkaXzD4zlKYgRViSUGQQ0IEaqVr9jFNmf8KgYAMiGm/NtdYpCEYvlC+tOrCZM8av6+rhqJcROK5R8qbu0GAMu41S4CqYgZYCzGTShWvwIfYFzZs4cyqbJnT9rYVUKxhGINAVTFKW3sqq3/2tOvzgJCsSjMY96kGVV/xQlj++13BLGEYg1EsVJ/yRKOaRQJVv8QAiAF86fquzY5xwLwXOVBOa9GSXx8f4RiydGt+k6bcigQUm8XCZbIsfqE6RfRAzhfJUpCkWP5wbDa79sVMtabOFE6AoByKwGhWABQd3dv8lNRCh2iLaoloVAvoVj+ACGWTwT1P+xVHx/m+o8YQKFY6nDc22d8YoVbilykcdzb19v1HMDYcW+fIJZQLP8qRFXGGB5f4WOtgFAsFTT8e79a6eersxg23/g/mXvYz95OsgMAAAAASUVORK5CYII=\n\"\"\"\n####\nhelix_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAYAAAD99hnWAAAABmJLR0QA0wAAAAA3Fr72AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAB3RJTUUH5QMbDA0hujgdqAAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAACAASURBVHja7Z15eBRltv8/VUWHJITsITvZFyBhC/sWSEBAdhgBFbkqjiMKwlyE0VFANkUWBwVldFQUEBDUCIRdloR9D4QlkH0newIBklSq8/ujOp100kGcuffO/Eif53mf2qu7q8/3Ped8z6n3Fbp1e7WGZi4VFXfxsfiJvBKFtLtdEASwsnKivLyAvLyLtGkTRuvWTtjZtcUkzUtaCIKACSBl5FUoPLSYRH7SVib21ZBbpJAodMXFJYw7dy6Sn6+e6+8/HAsLW8zNrU3a0xwAIoomgDg4eFFRMZn4K1uY2FdDWp4CQOvWbQC4cwdcXbuRm3uB8vICrLS/UiU+YwKJyYI0H7GwsKFXr+nEFWTg3GIfldVQXp6Pv80lhMAR3L69h/7BIscTLuDiq0EQBEzP7skXoXfv15ttDFJcnN7ksVu39gDQP1ikshqc7SQuZnfGz/oiLS3DuN+yu0l7TC7Wky2iKDLMfz9peQpR57QAvD1OA0CKvQhAfOkI7j7M41zSOYKDnWlp2Q17i8s8pIdJe5qDBenXb0azZ7EePrzLgwcljAneD8DOhGEM899PyxaQWdoFT9vLpNxR2H5aS7t2o7C0tMPC4rfjj6KidG7e3P27rjHJfxhA+vef2ewAUlFxl+dCtgDwj7PDcHDw1u+P9NjCrWw1SA9yl8gsDeNynhqsjw7aR2ZpVzKqf9t6pKaeBSAn5zZejndJzVctVPv2o2jVyt4U4P//ApDw8DebHUDG+q4nuSCMY2nOTOu+l6SCMI6lqiC4ezeP8AABD5uLfH8hjN4e50hTpmJhYc3Dh3eJcP+e3befxtHRq8n7FxamE+Z8gM3HbDE3d0GWS1CUIiTJAkV5gFZ7H0/Pnri6BmNhYWPSwv/kGKS5MjHH0pxxdPRm240pTG6/GX+numN/3iATEjIGNzd74ByBVgnE5TsD4GovIQg8ksG6ezePEksFSbKjm1cBNTW5HE/Q0i+oJRfS26LVPiQz8yzZ2XFotZWEhIzB0dHbpI3/iRZk0KDZzc6CdGh1lvB2l1m8fxjhXnnIlWfRSDC0qxlHrncBIKLDZTIKFJLyu/HTZXgu7AIAe5JGPJYyJyefpbDQkm5eyUA1F9K9qKhIQ6vNRqPxAhRkOQtRtKBPuxoyy7vg69vTpJH/aRakObJYNx/2Yvd2mB2xh+RCla5t5ynxbvRwnJy8KShIo629QkZxd+TKM/xlqERSfjeulveiTZvH+4zc3Go0GjPOpXrSwyeHBw9OotF04A+98/nxdDWSZIUouqDV3iG7QCTvbi4FBVEEBHSjVStbU0BvcrH+vRIQ0Js9mb0BCLYARXueSJ88jqQJDPDKA+BImguv9pD4/vp/8XyH7wCB+Pu9mrxnYuIZxnc8T1qegiQNRquVmT38DKujO2FpORxZzuPH0x5ANZJkjUbjhFbriof9FfLK7QGZxMQbQBVQQWBgbxwdTfVfJoD8m+VWRW9OXHTlj9134d8GrqYpfHqsF2M75XEzU6FVKxv+cX40f+y+i/M32zcZWAcG9uZopis+ZlGIoi2ynI2rvYQk2QMaQESS7FGUEioqzgMwsa+G7Se1WFpa6M5RgJaABbdvX+X27Qu4unrj6hqgIwrKTIG9ycX6vxdnZx92ZcyioCCVaWG76Oh9nuSCHpzMG0ebNgKCAG2dJIQEgaaeWX5+Kq1b2xN9JhyNpgVzRp4jtxhAQpaLWDX1GqduegMaampEBMGHHadrsLT0BbRAC92yuh5QZHJz88nNzQIqqagoQqt9QJcuE7CyssfS0gSW/9Ugfdiwuc0+UfjgQRmDPW7Q3k3NXXxwZIxe+fLzU+nT5mfaeUokF/TkRkVvo9eP89sAQEKWwqaTLwA1aLX3GNM1GR/nm6zYGci8Mbf59MAYoAbQMqrzTXyck/n0wBAdMGqbYqRV65qMLJchy7kA+Pr2w9bWhTZtfEza/L8BkOHD59U0d3D8beR3RF/uzs5bLowJusPILqr7k5KnsPb8y/pzm+qtn3L5GylFvUiSe5OYmEBOjpMeBIZAucGafUMRxVb6Y28O3cnq6DA0mjYNANJwWddkOV8HFhFZztJ/Dz+/fnh4dDBZFZOL9T8n9++XkJKncLasDy4ucLbMl6N7O9DP/ks05n2Z2f0bbuT24mxpn0feZ+918PS8S1aWFaIoATVMGxBHsGe8alky27NiZzvMze2Q5SzmjDyhv7YuRqkFiNQkWGS5gN7+Wk4nWQEy5ubBVFUVAJW4ml8gJka974gRfzFptylI/x8woQL4Oks8uHiXVq3UnrdVK1s6+Uh8FOPKsdxXWDV8A7u3u+Ls7Gv0HrvTX2HGgK9IyDrJOfE1oIaKivMEe8Yz+9vBQA2vRRawdtpV4CYzv27P6ugBQA2S1BpRtKxncRo2yWBbkmxxsU9EkjoDCt294zieoJaxnLgO5ubeKEoliYnnsLV1pk0bb5OWmwDyz4u1tSMpeQpvhH3FitjxODv7kpeXAsFqtrxVK1uizlQxKvAO5+/6Gb1Hq1a2bL0+nsuXK9BoVOuxdtoVZn87FI3GE9DydWxbtNoAFKWUtdMOAzBn02hE0UrvbhkutUa2FUTRhl0Xe1NVlYVWmwKImJuHIYotkeUiunsncibZnaysPLKysoBThIb2w8rK1uR6/TMd6Jgxf232Qfr9+2WEu1xjRKezpOQp+DpL7LnSkwv3+gLwQsBKVh6fgIuL7yPvceLEQ0TRWhd3lLH6he91IGmrU/S6Nm3AJZ7qeo1nPh7VACTGgFK3PqrzdWpqkvB1kVgeJTOgnR81NamcSW6vszAWdPe+zPm09oiiRh/Yg0zbtj7Y2rbB2dlkVUwW5HeAo7y8mNi8UGIPhnLvXhGtWzvQqpUNHVt8SCcfCV9nCWtrxybrr+7cSaGkREEUPfVKLoq2zNk0hZ/nbiWjQGH2t8MMgPJ1bDeCPa+gKPcQRRtArAcE0ShQZDmHPu0yeGtjb6CGSX2K8XFOZs2+/kA5vf1LqalJQBA8gfp5FZUFy8jIJSMjAziFl5cfNjZqWcCjgG8CSDMGyP37pXw14SvaOolkFGiZ/N04XF3r3Khfcybxaw60bu2AlZWtwbXt+IBQb4n4NIVJvSWmrhuLRiPWswIginY88/FzKEoJa16M1l87+9thvBaZR1snCUly0MUZtdeJ9YAhGgBGkuzILVaQJFtE0ZLdca6M6iwwpmsuu+OCuJDuglbrgaLcRaOxMcKAmVFLF6en5wDpeHq6U1KSg729m65jsDWhor6LNWHC/GbrYk3vsJyr2X35KcGNCcE5dHQ/ydXsvnR0PwnA1ey+nCztbxRYvRziCWqjnhefprDmwDw9MCoqTmJm1l7vbtU2WU4Daljz4h4SMsP4x7EgnXtVY6RpjW6rDNhxVkf3QaNxBbS8OTSKFTt9MTdvjyznsmpqHH/5vheiaM6j6GKttpyBAwcDkJYWT2VxLKn5Wvr0ec5op2CyIM1IcnOToQMcyumIq6stPyUITOgucTVHYOHhiUxol8OE7qfhvMCpMkOQWFnZca1yANcyB5Cbm8y5c4qB9Xh3nMi4XhtJyVN49pMxSJI9omiNRuML1DD3+xk6N6ymCXA0tCTqtlZbBois2Nkec/O2euCs2TeMeWP2s2afL3NGXuTUTX9E0dYIVWwIFl9fe+7dK8a+ajvQT/9SV3FxLrlJ22hpH46Dg5uBVTUBpNnQuwIBbhLp6fF06DCAP7TLJTFH4XTZANzc4HSZPz9vduf9iB84fXdAk/exsXFEkpR6cUMNK/eEMK7XOa6kKmydtRNfZ4moM91YvssZjcZHb2maBketxRD021rtXVa/sBOAm5kK38R21Z8nirasju7HqqlHcbTWsDraEY1G0yRVXAsSe3snqu5sIQ/wDeyIEzG4OkhsP3mUzr4a4hKO6n/n00/PapbuV7NNFLq7+/PzhT7se/MUiTl1Sbv6z6O273jUM7p3rwhR9NUpq6CzDHZEnelJJ59TTP38LWQ5ha2zfubsBxIpeQpXUnuyck9jF8ywCQbbinIXgLnfvwxomTbgEsGeV+vFNQN4a2NfxnU7qiMDtE3QxipgZPkO7u79yCmE4wla2pvFE+Igcb20PwMGuBEbu1k3zJGWnl0jEASB5qgrzTpIP1seTtQWd/32goHbuHYtltDQcMrLSxkflEt87gCj7FV5eSl37xZy5gxoNEI9hRZ0VqQjc0ccB0Q0Gj+mfj4XrbYURSli66yf2TzjLFM//7NBUP9oiyLqzpHQassJ9rzK7G+H6I+vefEwCZkd+Dp26iOZsDpG7AJVqZc4nqDl+aciicuu4XppfzrYHucOk3mqTyQt5VgGDHie2NhNdOgAoaHhzc/TePbZxc02SC8vL9XFFKrr0MMqhtnDTnP4ikyAmwTAjD2v64/n5CQxOiCbENdYAC4lKyz5ZWE95QZZTkSj8TPY1xgAIMvJv8PdUs95ecBaAL44PII/Re7hm9g/GZyz8vkNzP42Ao3G3UigXwcUrfYu/v6VDPGJ5Y7VfFzKl1BQOYDMSnfsH26m2GIKMTEbGdk/EsG2E1ZWtpSXlzbLoL1Zuljl5aXM7PYpAe4qCBKzFeKzw9mZ4MGupGf051lbO2JtrSpFdnYS30zaTlsnkVVRCt9fHYQgeOgsBjqlT6JqWxRmk8frQCI0cJfq3CaNxv83rEfjfd/Evsm0AWdZ8+J+QGLagIs6Jqx1vWvEerRxw9yKulSUB/j5hZGWexStWAaAU8tYapwWIBRGQMlmnn9+CTk5SRSmXSE+/jDPP7+kecaqU6YsbXYW5MWgRcTnhLMrQXWvRgdnE+oWQ2QXDYcvy6y9MIvWrW2NAqusrIC3+23B31Wiw3+/oWOLVFk47hhhfrGMXvWe3posnZhDmN9xhn84UQeapq1KU+DQakt1sY2NfvuPA28S7Hmh0Xecs2lSE9RxnTV58OBbpkxZSnl5KWZ5H+uvvVkeQSc3cDKLocBmISYB4YUXljUrgGRnJ7JhyjZm756BlZVdo2N/HfQ9Ae6S0eP15cqVoyQlDaqn0LDrrUUM//BZNBp/nTX5kcNXZAAC3CQScxRGrnhdp+iPD5KKipNc+OgCUWfCWL7LBY3Gm4a5FUBX9/VoZkyWM3l54CEsrSO5UuKOjY0jyclxTOt+gpM3qnB3lLhy/3nc3QNM6GiOLlZtwG2MlfH0DGRT0iLaJ73HG10/YVPSIu7dK6GsrBAbG0dat64DzM2bHrrgHL21UOMWNWDf985WVvwczqIolSLWaku4tWY9iybE6/YZd73q1usAYmYWClwATnP2AzMdE9aDlXva8/bonSyL6oW5ec/HiGMEFKWQM/mRRNjAKK/vAUgRBvLNhf74+XWmrDIOx4cb0RRFkl7pgcOD76h2nWPw200s1hMsnp6BJGYr/G3kWqZteQ4Pj8Y95aGsFwnz34QgCAxwvsKsl06Qka8lMUcdcXF5zAtIUu3wJobPL2ntD/jPnMTFZIWFP3XSg1AU7fCfOZF972wFwh8ZnzTcJ4p29Jn/Mptn/IOefx0NwNZZUZxachEPR3OWRUH9PIzxmEaLVnuPiIhOeHgEUAKU1ESQlZVIrzbfEuwhsSfTE2uPCCydIsjISqS79SawlkhsxiPZtxAEsdn96L9fmUO/3Mscmr2Nw5dlPop9ARsbJ1q3tgdgZGC2PuYY1z+WLvPDcXLyoKAgi50zYxjinsUpsT6watBoAgmaPZNFE+JIWvsDYMZ724sQxfo9r2AUVA1sXJMguZLah7Mf7KLP/JeY+vlbzBn+EeN6mbH9v88D53n2kzEG7ldj63EPT88+DTqMIKr4EHhPN6WDqN+fx1KVrDC5WM1LbGzsia+MZNhaT+b2+46vnt2iZ7MAAtwl5u5/i7t31WmlAgO70rq1HX8ZsJFfLkby3ha3eu6VqnwVFUcxM+vMoqhBLPypM9Hz1ugVXpYTgRqS1v7AtuPhDYBS89jL1fv6AwJzR9xg9b6+dPKR6PnXMWg0PshySj3a2DgbNmiQY5PJvtP33sLODkyDeDRjF+vevWL6OFymg6v6wtL1lpFsS/+Ae9eKKS0t1J9na+uItbU9r4au4peLkVhb25OZeQu8YW+yh46irevxtdoSUr+KZVsMLNoxCFG0Z/SqxWg0NWi1JSSt3QbAtuP9WRQ10CCwf3xLou5bva8/G19fzpzhx/F1NkOSHFGTkf6PpIm12lLs7NoYuEr37hVTWlpgYE1M0owBUguOVSdfZLhvFm8Oj2H4Z554egZhbe3QCEzXcwezL8UDT09BX7tVWFjfRVIVcdGkOBKzFSaHqwnERTsG6RVaFO3xn/kskuTYwN36LWDUUscxhPkdV12/Fa8jirZMWTedzTPWE3WmF6Joj/HyFEOAVFUlYG0drL+vT/WvDOt2TA3S8xQGdNAQe13mq2svmoBST0RRVNmcJ72Vl5fQwfUwX9+Yh5dXMDeUwXy6P5wvntlEeXmJ/rysrNtkZd3CxsaBG8pgvLyCEUUBO7s2bIup4vp1xwbKLBDmf4SLSRFsiwlncnisLm8h6IGk0QTqFFkwuM5wvXFbOC6Wyf1P8dRSlQmLnvc5Wm0ZiyasIzm3H8ui6p8v1ls2XBfRak/gVDiP8vISystLGNb+GEm5Cu8emcqhe8t5cccUbhcN5oPITQy1ecfgmTTn1mwsSFlZgS7+qLMUZ0vCGMtRysoK9Pvn9NnAxUQF8xZD6eDyK9fvDOZsSRg2Ng7EZLzSyArI8m0C3CVGLuuiP3br808Ien2WbltokPMwjF0eJWF+sfjPfA5zc39Grwpn11tLiJ73GWqm/ATKDg0rfhZYFNX/kYyYLCdzdrk5KXkKxQ8dcCp4i5Q8CaUG/Uj1bdsGk0Ewqy6HEWJ+ibldV7Pq8ltYW9s3bwtSOxllc2gBbhLtpV/12zY2Duy8FMl/996AIAhkZt4isrOGsACJsWFqqXcHl1/5cPAq2rf4lUOHlEYPcOlzWSRmK3pwLPyhC9tiwrn1+SdotSWNrI1xy8Ej1g23h3/4LKNXzWf0qvms+Lk3k/uf0r8n0pQlUZRcZvwUga+zRGbmLcb1MmPDzZf1+aD6zcbGgRtVYaTkKZSVFdCc9MNYazYslrd3O3ZejmTmsKOM+qItXl6qP34w3ZMxXSXKb5cw1CeLw3Fq5vu9o/P0vWdQ3iHaOx9Eo1lq5M6HGL74JTQa9PmORTsi9JZkW0x4vZgEI1akadr3YvJAHfPVjzC/GC4mK2g0gXWxT1Q4YX6xKEpRPWtlGNhrtWU8/XQ7vLyCSck7xJTAbwCJPXu+YEF/c+wLnRsxV7XWtLmWuDfbIP02TzH6y7Z4ewcbACcxR6G7zUXaOx8E4JNzr+Dl5WBw3eyF1ZibN77noh0f6sFhuD+CdzZB6lcxhPkfYfjiqQbK3RgYjV2wRVGDdK7WMS4mDyTM7xiynKRn0WQ5iQA3CUlyagJkAopSjLe3OsXDvqK/UlKSz39JX5G/wZLY6zKlpfkIAgYkxd27Rfh6Swi3TFNdNxuApKff5I1OX7Hl3l8b/emfnn+FtWM2ABITvxzMspFfsTN/tYHCSJLH7/5Mc/MIgl7vwqJJl38DFMb2CzorEQEM0jFah0lau41tx9VXgCf3P8624/3qMVmN6eHhw1vrf6+NjYMaS1WuZmNUAr2dMvivoK/xdVZf5Np4+xW8vNpRWlpASp6Ct3e7Zs9iCbNmrX3iixV9qg4wKvRXknIVPr/6R+zs2lBSoiYB7ezaYGPjgL9WtR6Xyrvxfv8PScxWWHvhjyo9bPt3Fu34oJEia7UlLJp0mTD/IyoNu2zOY1K5DaXxX6DVFrNo0ipgMAt/6FwX44w7QpjfMb0LpuZVGt6j7t2UKVP8DAJtn6oDAMQ97KZ3pdLTE5ji/6UeKL7OEgdvDSG31VMmgMye/WQDpKysmPe6f8icg9Pw9g7WbyflqgG3v6vE7vghXKnoputl7SkrK6Zr6wvMeOowGfla/P/0nM49MpSFzxyFmkO8t/Ullj6XxeQBMfi/9jz7FmwE4KmFEZibR/xusMjybfYt2KTfE+AuEfT6myiKmsxUcyq2jwCZut6pUzo9e3bU701LS2BGxy8f61tcTFbIdfqk2QPkiXexSktVS2Fv74wgCEz2WEr0tWGktRyqKs2hm6wa8jUPT+yhu7/6AtVn6a+SYjuU8V+3JcIzQ5etrmlkPcL8jzBy2Vw0GnsW7QgkzP8ISX//nsQc9Rxl53FW/Ig+aH/MPot9CzbpYha13mvXO/NZNGkVk8PNSMxWCHCX2BYzoF7wX2OUPnZxMTNwJyPdMvRl9w0lspNGX5oPYGk7AtPkSuqMLU88e5WUq9DJ/DxpqKA4ltsWb++641M2DeH9wfv5LP5VItwysLd31h/belau11vX9dKKUqB/Lbf+/m2x4XpALHzmiM79ivgnv32dgk4ON9PnVhY+c5TJ4TH1XK/G4JDl23h7dzO4W1xld9rl7CfATWLx+b/qXa+0tJvAl+y597e6k80wCc0kD7IjdwEjQw7hXXmQS8kKA10zDY6fPr1b9c992pPachg2Ng76Y+fPV9VTvjogaDQBJOYo3PpMzXdotSVcTIrgvS3u+nPf2+LxT/8xS5+rm/fjYpKC/5+e1wXjsPCHzjqQFtJUbqV79yKjOY695WvYFf8UC7p/QHp6AoIg8Ebol9wsGt7scx7GmqhmUp/sZmNjz4eX3gVgYj8zXh/0K14VB0hPv0l6+k2SPzcnoWh4o+vOnNmvc3OM1zeNXPZntsVUIYq2iKIti3YMMohV6iv575GRy+YQ5n9En2hctONDHZVbB4LEbKXePgyAotWW0L59D6PP4u7dYo7dacu241X89Pw3+FQeIMBN4tidtjQHXfi97YmPQVJTb+rXM32Gsfxyd0I05wl22EewjvpPzgVRpzwAxcX5TO/wd9r4hBMXV9Ok+yOKtiz6cWmj4HjhH94lLEAiwE3C/7UX0GiaonObMOuiXSNGTBTtkOXbOuBt4GLSEL1FaUgXV1XFYWs7ttF9veT9jO5zkLZtRP6w4Q3WHUlndOhBEnMUfHzam/wp40H6k/vj7Er280z3g3rqcufZKmz913E81Yvj+a/h49NOx3QVMdFlMaPdDtbFEscVFv7UUTc8aGOR5USi31ZfWb2UPJAFOzzQaAJ0hYqq+L9mjP16dPa8ljpWXakuBiDZt2CjbmCJ2tov4zmU8eODaPi/elXtZ1Sngzz/zVO4uHjh69uODNqx7FJ3JrosxqlgBsktFxnUqpkEhHnz1j+xNG8X+U1+zpqOj087ysqK+OKL99j6Z8O090+Z0wFwcGhDcXEt46Wu79nj0EAB1eX8sTFM7HeC4FmTWPxMNl39YojoqOHIVZmRy6fo2afGIBAeGYxrtSXc+myNnmVSLdDzepDVWhBjlHMdcG+zb8FGEgqe5mpFd2xtHUhNvcmq4V/y1r5X9Z1CfWlbuZ83hhxixdYKklstxtbWBJJmYUH06qf7jVv/rCH13tOUOQzDvmQ/PlZ7meC5noz7T1Ns285AMb75JgGNxt5oD18LDo3GnyW/BAADmT92AQDRb2/WDSi3FOMVvMZ7fYDod1ezLTbCgAXbt2Cj3t3SaAIbFEA2ll69zEgofJpgp72McjtAYo7C+7lPk5it4OtrPDOeaT6Mzw5BWPBeistN4Gg2LFZa+QjeCvuSzlVvMtByEfFpCncdVbbGz3ovEz+W8XWWSBV7GFxXVlasm1iz8dRoilJIW6eGI6/XsGDHC0AEY1bOYmI/M+aPPYrxARQwyorVSh0LprpYAW6SQamKohSw8A/vNOmeubpqyLIYzq/31zL3wKsAjPLdresomn5Wsblev3mOicV6wtpdx2F8fPlV0spH8EvOdEK9JVJTbxj45yl5CnZ2DmgSXyclRT1240ZqvYGlDUGi0fhy5KrM4mdydL25uj/67S0s2OGGKNoQPGsSXf2O8ejREnkEeNT9omjLtthwfSlLbRyCMMQoQBSlQG8xBQH8/Npz+MFaLlXOIMBdoqysqMlnNcAtw+BaU1Ob+Kg32v5/bmVlxaSk3AQEMjU98PXtwPqLIxjrtp6OFTORFTi73Jz4NIWTJ/czc6S5LnMscPp0OY1HR69T5DErp9PVL5brH68nas5SouYswd+1draoxx2MujEwLiYNIunvW6ioqAPEwh86E+AmIcu3kOXbRHbWNJlfWfrcBlYO+5KTJ/cbPAtf3w4kZiu83X0JZWXFRp/VqI77SSgawZOqD/9seyJp3rKyQga1WkzWQ11JxUM4W/w6/fo9zYmynnhUncPbKpq5e4fxZo89dPXbQ+x1tcdITb3RYOichiO3C4iiDeNWv4MsJ7P4mRwW7HDXg6Oi4hiJ606x/cQAmh6cQaBx9S0s2jEQdao1D+pP45aYo7D0OXUoosNxcj0SwDA435M6msnh+wkN7dmoTCTqzmLmuS/iL90Wsy2misuVM/XHPnrqCwBuyj2xsTSVlxj8U+++++UTx2KlpNygh/lnFLp9pqdx/e4vILnVYoqK8gzO9fVV+X+bwn0M9t9Hz7+O1M0EZfzNv9lDTxLqfQqA+LS+rIx214/mPn/sUrr6SQxf1h9z83AjwbjwiH1Nr8tyIkl/3/II6ligouIIa2dZEmQfzdGKz5roOIpopzlHkH00kV1UNi8jX0titsIveYtNFK9xFuvJ7TFqf5utrSPnit6gBwsY6iORUaBalqpqSL6oUGT3JuAFycORpNqpy2hkbmcPPcWYnufoN388IDB35HZSPzfn+A2Z+LS+LPlFHbTa3FzAcIao337G88fG6OIWGLn8eQMQaDQBbIsdwOQBsbrCSRrFK/37WzAydB9vH3oDPz/jn2dr60guT5Nb+TRff39DR287Y2vrgK1pOkLjOjR//j+eyDyInL4XZymaFKslevrWPut18pSRaLye1h8/qoNNKgAADsBJREFUXzmDvq3W0dZJYvWp4Zw759WkP/r1n/7G1HXjDCzM7KEngROEequFiy+tf01X3Cg0YTUaLxvmVdT1yQaJyEU/d0ZRCo1aD1m+TdIXW2jbRuTzw0M5meeNn59hZry0tIjgFmcJsldn272YqFDu9YUJAc2V5jXzHsGFqhnY2Tnq9+1KG0mY8z7KyopwlqK5UDUDf/8O5LmuZ1v6dE6erD/ZZcM5/VSrM3dkrsGxldEuhHpLTPtiLvFpvdkw/e9G2a9Hta5+MQTPmqjLq4STlKuQ8Mk2HTjCmdjvOAvHxxmpC1OtR79+JSRmK6zYUUGQfTQfDl6vY6zqnseYNvMJso9mQ8IMAKwcxuJSvheX8r0mOrc50bylpUXcuzydxYtf4fvv/4YgQHLydUpLi+jYsRe/xlXhc28+Ho4Sjo4u+utUV8aDhlMl158h9qX1UxnT8zyzh55ElpOR5RROLNlFfFovQMvH+zro8hHFGJ/+rKaJZWO6d/uJfoxbvYAlvwwkeNYkJvY7Xu++dedrtSV07NiL2yWjuFo9i+PV63n3yHRdx4D+9wMcr16Pg4MLAW4Sp/K9EBAYGbKP0tIiE6XbXIoVi4vzcALef/9rSksLuXNjL20qdsNdKLCZgX/ff5CfugcKdxPY4j3ulI0itdqL3NxiwPyRlJ8oWhH+/nNsmL6JjTNq8yjw8b52iKJW/8afmkNpGMcYY8TU5aXk/iR8soPgWc+g0fgzcvlkQNAXOdbGHYpS0OhNQkXJx84uiHxGEKAbZdrfP8RoLCYIAsXFeSTmKAQEhJBPCIk5uykuzsPe3tHkTzWHUhMnJxcog6Sk6wgCdDDfy6UshZb+s2lVkcaVvZ/g1Wc5GUIvCgvv4N0ijd4W65h9fJBudtiGwFDHltJq76EoZbo4Y4puEhz1HEVJY8P0DTpmq2e9AF1okiquH7wv+aUf726rwdzcV5eM9DOgf6uq4kjKVeqNv1snkyfb81v/oSCodV3R8UW8GLSW727PxN8fSkqKCAiVEG6D6eXBJgDyOAzL/09ia+tIqf8ycq6cJcChhrd3VDCxt1r2+sDcmzKrsQjJ74L/Ml1PG8KZJG/gClptqa73FwwUWastZ9PMn8gqrHtV9Z2tz+t68FIkyY6p60bqen2fegDBCOAag0SrLUOS3Gg4xu78sUvo6ifpmK3JDcrm1WF/HB07/CZL5u8fwp7rI/hz6AIScyA7Ow2A/wpcS2JOY4tjknqdy+LF3zwxLFZpaREndv2Fc0lapk6dw8aNq3lt4gQsHu5CEqGFrjzc1kri7U0qcHxdJFZH90WjcUerva+bj1xEkmz1YJHlLFZMOcK7P7ys285kxZSDBp89b/MIXYLxt8bcpQF1vJxQb0k/ogjA1HXqfIaynKx3sQxfrVWX6sDWsWxMexN//w6/+XySkq4zNeBTIjtr9BMC7S35wFS921zyIIIAznYSc+Z8RFzcGcb30vD37T8BEBk5gQAHsHi4i5viDJYs6UBpaSHn484gSQ+AakTRAlG0RB3s+T6ynK4Di42ux07XzQOoxcNR4oW1ExBFG2Q5gy2z9/PcmqfqgeRxwHFa57L9UWeNijmx5Bc2zthejzK2axDE11q1Mg7esSXMD5b0+Yxtx6vId/kIW1tHI8C4xnNtP8XebjSbkt5kU5KAo6MztraO2NmZQPAokSIjx77/pDAOlZUPcPSO5MqVM9xLj6KyqoZXZ3+Dp2cAUVFfY+vaHo3zMF2CrA0WFpakp2eQldWYihUEDZLUGkmyoro6n/2XrVg19Ry/xnvTooUjO07Z06KFE2ppiA3WZgrP9jvBketd+a2aq1r54+Afmbt5PC1auCAI5kiSHV/96sy4HjeJT+vDq0Oi8HWs4UxyWxrOjltdncWLLw4jSxpFbE4v0is64u7u3eiZ2BdGM63T9xSX19DTOwl36QzxZb1o1coKCwtLE1P1W8WKTxJnDQJxcWcBsPYeT0uP8bz33ktkZ6fSP1ikMiuK4hufkJ2dxnvvvURpaRExMbcA2Uir1jeNxgVJsmfe5v4oShGynIFG4wZUI8vpyHI6kZ3jmbd5SCNq+FEtPq07J5bsrlcVrNUDYM2BPkxdN4ExPc/ojhvmVMLDH+p/t52dE4GBIY2eR1LSdYYF7WF9ylIumP+DpFyFrZmz6GGbxnTf+Tp615TreOTg1U8Se2Fvr3L/hw791IjmPJ5QS7tq6eH/M3PnrmLlyrewtIwAqnRslUT9OTVUV+shwzsewNtZIi2vNkgPZeeFPCTJiZcHHiXYQ+JwXIgONIqRYNx4W3OgJwAx729k59kwQGBMzwvsPKvmVTQab1LyFBSlsB55oLpXK4bu4WiqQKXHyEfHHbkK9vaO3L59jW6eEBgYQlqJCxBNYeEdE73bnGIQgIiIUUREjCIx8RpZWakcPPgjhw79iJudSE6JlinjnmFz1A68T72DKLoClTpgSEZAIqmDPztLfHF4tI5xesDwjumM6XYTCOGbYwNrixKQpFIDRX4UOGQ5g2kDC1hzoCcro9uwccYeAHae7cGaAz2R5WTmjswjPk2pVx+mXltVdZW3D41k+ZBothX0xs7OsYmYTNCTF896fkLSvbEIlgL29k4k5Sr1LK9Jmoxrly//7okeerSkpJCCgjvsj1pNTolqRebNW01c3GliY+MRRat6AGnRACTqcmjIASCAfVfb6s4XGRoSxc4LwYzplgCEcOBaR7TachTlHuqcgR7UzdXROLeybNI/8HCUOBzXmY0nezQATzobZ+zWBeov1qvtUtvkyQqBgSH4F77C3uLZBAY2TdO2vhPNsED1XtN/GYmHhw9h1mn4t/6FI1XLmwSXSXQA+eijjTXN5cfevq1alQMHdgBgaemNOoSgmQ4cLeoBpQ4kWm0lwzvmAGl4O6t5ibQ8hQPXxgIif4rcybr9vdFo3PWgkOWcRnRxbVPzKlFMWh3CD3OucTiuExtPdudxXuCR5TSWLh3F4cO76Nn6Z+SAVb+p5LdvX2Oi29+I6KiWuB+5KnNU/sgEjsdLFDYfCQwMITAwhIiIUfp9iYnX2bJlM2qZSS1QNHqghLipQX/UOS2WloORLxfqLIQrspwNiDjbSrrYo1pvITQaFx0Y7iPLaYCksyrqnB1ZhQrm5l15YW0AHz77I1P71rDxZLdHWB3VFXp7dA5+BdMYMkRie9Gqx1LywMAQ4via7fuv6bdN7O5jWpAVKzbVmB5DrSuWx5YtWw2sSqh7LmBGfHZbQt2zqKnJ4lySFo2miz6LrgLCrUGA33hCzVpAvTzwKAKd2Hiyq96ivNg/kSCPq7yzdZKRbH6t5blHePg9PD19cXJyeSQ4Dh/eRdeuvbGzczL9uf8KQFauNAGksUtynaysdI4ePQGYoSiVyLI6jGjPAA/is72Q5WIUpRxogbl5QANwSDScZbbhHILGXLCpfS8T5BHPrazOfHs8sBFQZDmDd180p1XgqN8Ee+jDecRbrDC5USYW639egoJCCAoKoWvXnixbNhsAjcYNRXlATU0OIW45XE73x8zMiU6eecAt4rP96oFDMQKOuibLd/QuU1XVbd0YuyIbT3ZCq/Xjxf5JfPjsduZtHmxQQBkZaU6Y0y523fYhKCi0ye9/6dIpsFAQ2mNiqf5FkYYOHf++KWNqvFlYWNK9+wCsrKy5desMNTUV5JZak1NijijWUF1dhJtdAYJgQf691jR+76Nxhl6Wc1ky+QJHr7kAWt58Oo4e/umcvmVBdXUuIHI1043D14IRRXMEwUx3XQYDBwZjcf8UeUJvHB2dG33fw4d3YWfngGvpGsb0NENTepCLd/wQRQlLS1PW/J9qH3/8vcnFeky5dSuezMwU9u5Va6VE0RYzMwdd/VbTLFh910urfcj0IcdZf2gQotgaEKmouIZWe5NxPUQghH1XfRsVTU4bcIVgz6sUCuNpHTy60XdLSIhniM0arrT8CHt7R4qLCykoyGWg5Wp8nSWOZ43hdpUPwcGhpj/y91iQYcMmmCzIYzZHR2f8/ILp0SOc9u07c/78r1RXl6AopbRoYYlhiYmCsTcIBaEFjq0UhnS8wpnbrRCEGiTJlpnDM/guJpBgtxoCnE+SXBBCixYO1NRUUF2dj52/O5V2I3APHmD0uznl/oW7D2qw9HkOQYCKigckJFxF4/0KJ3NCsBdLGev1HRuOgp9fsOn/NE1/8L8nDg5OODg4sWbNFoqLC7l48SRt2/qSmZnBkSOndAyYxqhV0WqriL7cGghhZJcC4Lwur+KPmZkHB6615k+RiShKCaJoiShaoCildGwZRSlvGY0piosLCXWUOHzvzwTrjhcU3OGlDruIF/oRHNwR6Mie4r5062aKS35nkG56CP8aWBx56qkxAAQHhzJkyAhu3brGt99+B1jogFIHliGhl9lzsQ0gkF2cw9Ws3ohiK0CiqiqRWSPSdXdWUIsmRWT5GK725rR0djX65l9BQS5ZFQq0rHszMKhyFfHKeBw8HA2+q0l+J837ySdbTTHI/5Ko1uUMR46cAFoCGrTaajp6JHI5PQBFKWdEWD67z8s6pqyL6vdK1vr4RKt9yOzhx6hsPQHvsDFGPychIR6n6hTsqtUizZIWEwi1/YUj5f9tijn+VYB8+qkJIP8XkpBwjczMNC6e2EpBuQsg0tW7kpqaIq5mdUIULZHlYrp43apnVURkuZBVU69xq+XjKXtCQjyOch1YEi3m0qaNq6lq958FyNq120wA+T+zKAUsXDgTUbREkqyAFihKpS6Ab4kkWaMo9xkRls/h630AiZde6qVz3zr+7s/Kz8/F/8FKPBwl4svGIrn3xd7elFn/XQBZt84EkH8HUM6fP8nu3dt0rpUdslyiW2+rc7FaIctlvDC+M137j/2XPu/mzas4yilIHiaA/G6AfPbZDyaA/Bvl5s2rrFu3DI3GBllWhxUyN/dHFC0YPLgT3bv3Min1v1FMLNa/Wdq378jnn/9AUZHqEq1du4yKiiTMzd1o29YLBwcTOP6tFmT9+u0mC/IfaFUA2rXraHoY/2b5fwVSnZsOTb4OAAAAAElFTkSuQmCC\n\"\"\"\n####\nClockArabicAxis_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAHZlbi4gbWFycyAyNiAyMzozNzo0NiAyMDIxpjiGYgAAAYl6VFh0RGVzY3JpcHRpb24AACiRVZLbTuMwEIbv+xSW7+MzSxO5QRyEhETRii6IWxNGwUAc5LhN9+3XTpsu9kXkf+b3l5mx9cW++0I78IPt3QpzwjAC1/Rv1rUr/PTntljiixot9Pru6hJFrxuq/WBX+D2E74rScRzJKEnvWyoY4/Rlfb9p3qEzhXVDMK4BjKK/cv2D6WD4Ng0c8vd9Y8L0zyPpYwu+BVd4Cy18EQeBru2rmT6C7Ic3jJ7nMgWOJSH9bGGsFwjptQne7mMoLcP5CjPCSlZyhaMUk5xWkjKX6iClKM/wESB4ZhEi44kcICKgmAi85DNB5gSZlyAjoThnZMmUWMoUmBmRomaGyhkqZ6i8CqWmyzvIBKBxMJoeJ6Q3/dY3MM3q2oMJva+f3KfrR6fpHDgl44hvTIB6B46gzvgBiV9IyEqeVypumODHQ7Px/0nXbv4OAbr61gNcX94gRng5u0/J5P9tfHjYdq/wo5IfsWR5hJ1N913HxjQ9qdTX3I+m6V3Wi39qXMDpxowhpAAAABB0RVh0U29mdHdhcmUARnJlZUNBRGMaYs8AAAAqdEVYdFRpdGxlAEM6L1Byb3Zpc29pcmU0MDAvQ2xvY2tBcmFiaWNBeGlzLnBuZyvZjtIAAAnWSURBVHic7Z3tVxXHHce/w/HV/Ae1Sc2DNiaNNS/S9NQcTVOPpppqitYHHlWQqyHABa6ggILgBREELhdQioAiCOqJGGOe1KNpYrTt6Tk97UlMjsckTWxtTv+Bed0Xs3fv3r3rdbnsZXZ253P2xexvZme/v2GY3+zssJAXXwxAoXCaeYQQ0RoUHkR1LEVGmJeVpTqWwnnUiJWK21XHACzrKU02ckxZCh3VsVJCKQBjE92qHOBGzu2GUy+37RAgzPWoUGjNzYp+vQPpTaQZGVseLdNPb9WfXN5eJEyoW/H1iPXp3hEwtqKv3Gwv7zMOS8lNxC0r+so/3TtiWUDh644FAJRatAClYOyV/opPaodh6jeMvdJfYbrC721ohX9D4celvQAF8ElZ9NVjQWPWq0dLAGRlaad6E/Fiul2rgTHftmEKsohv+Li013gabwNKTVmmMg+rjYfL3xyvTE+At/FLKLy+u8cY9fgpGAMASq0DYozkLO1yYGX3rtTtp5cEANAbb0ZWDlal64RM+CYUUgrg+u6eVUPVAFYNVV+rHOTpa4FuUKpnJWNqomuVgzyGrors1sOiJbzm+Dljq4aqU1/iGfwyYmkYRqbVvW/y5OoToavB4ykGLaP9avA4ADC2+kTokS23+kTIeJWdSzyDLzrWlZ1H+SwblF4t6XpteI+5RIosQ8eK1wNcLenSC1helXx3PzS1jj9CIaUA1ozWfFg2AEqv7Dy6ZrTGmK9nWbZG3MjjmjG6mQqkvLtPgiDHFyMWH2MIIXxkso56jIHSD4s6156stbjQcJpMijb84K1+fqEv2tkAWbt2r2gNc8r724/w58HXT5kdf7+0z9I+23sBrx8zL+57Hn+EQgPrTu+7vDtqGfXWDVbAsP7pAJTyan0VBDmeCoXvFhzW0+vH6x5ajjFQermwPVUZZ8T4bs6uQ9avrxetwRku5beZp9WMvTFh7d2lQCR1AQf0BCIA3hiqzFD9LscjofBibmt8JR3xx7dLgUj2sNVKN2MAsicbMheksoerLua2eqN504BkZ+8XrcEBpnPCoHTDSMLS+XRxN0+Y7Io5wCtzrKStngA2joYubD0ESqeLuzeOhgQpswXXqZ0wtvHsAaFyHCArK4t44OCh7cLWQyb7pvOND8ty1aH9NGIvxV2u1s5BNm1qEtarHeX8tk6e2DxWY5mVbHcncql9GF4JhcCW07Xn/nAQlJ7f1gnGtrx9MCFbosd+xlJv45ECuZ8KpzY05Uw366c5081TG5r4S5tzhR2A9kPiuS7xdCr/SMI5Y0YXdFyiNm1ITk6LaA1pMpndyJcYci+aXdCydKzKiEKXnbzqpiUoBZB7Zt+cS3MSkpt7SLSG9DmTG1tqZyzvHWkcOfP7A7xv5b1zSEsnkjeZwVcCcwPJzw+L1pA+4+v3m0amgnflcGd8axuAgrPxdf/x9dqCoiwupIYUFLSK1pA+p9c1gNLCcw08wY2F5xrEqrKDJpixwssSt38KvPBUSAjZ9l4bgLHNYQCnt7SCMW5xLdveaxvbHPbA09/DkPupEIDxz/p2vH3g5No6/lQ4tjkMxnZ8cDj11SJhDJSO/a7e1SLThezY0S5ag/OMrtkHSosuNIoW4l+8EAqTKf7oCAAveiYN8odChSvx5oilEI7qWIqMoEKhIiOoEUuREWTtWAO/rgJgep8D4K0/9QhSNFu4R0b9yRaJkDIU9q2oTH5xyy0DaxvKP3L1mnsyMXesvuFGqYweQdIPr2m9irGKK4f13SZ6uu+39aIFzoy4OzcTvsxWcbNX82iF3W+7uQf5OlZ0eRBA8Gp78LMoIST4WZS3fnR50JgWLXMG8F7F3SGERJcHo6/V8bTmEaXi1KWJfB2Lj09GS+WtPt1oTMuCSXDqU1mQdfIeebm86nY/T/csK+Of2COEGNMi9c2U2DaHnmVlPDJGVu2Nf8lSog37MUhVVb9oDTOme2VtsrH6eodur77eMbeKZkX3r8ostikbLHK5w5EvFBJCQjc6E5xgLHSjk8QmKzwtEaG/DCR8eYsxzcKYjO5ohEIDc9qTFf5A1jmWwuXMU/1KkQnUiKXICGrEUmSEeYDqWQrnUSOWIiOoOZYiI3hwxGp9YRdPNPzjj2KV2KT1hV2ySLUPaWgYEq3BScJLA6bdf/v/6WoHdcH7/xwRrcVJsgiBZ454r+LvQwBQGl4aEC4sxaH/Grhc50wPj8yxWpaU6OnGv/bG7b8Mwn07Hbjaxs9PtCwp0f+dmMe+4+CFOVbzS0G+VYZj9ohS1/lIKXj3ohRA0xcnADS/FGxZUsLTHkDK3Q1Gmp8vAQyxD2h+vkTP5RaB8iw5+LcoAD1qcyO3iBXmJE1Nw3PfnR3k4C8qAGg/qthpfIscAMYO3nGjj5pUjmFPnzvVzhT551jJ3xg27pJjrPnLERe62PRcsXF2FRfslZkWaW4eEa1hVjQ+Wxx/EoT2S9/y1Ujjs8UtX7naNaPCuBcA1y9MlkOQlpZR0Rpmy4HFRca1q0N/l2+zNRK9kNQFI154KgzfHd3/TJGeltSj8N1RANwRSV0wQsLhk6I1KDyI/JN3t1K/aDtPtN07JVKHIDz1Sie9o37RdufrXFqqPetRWr+0VLiPc39Iv0A6S+oWbgeldQu3O1nnz0sBgLH2z4/zZ1Vn65cC//17dQP7nt7GH8Tavxlzsk4AjPE6278Z09O+wr9zrL1PFfJedeSLwUy0gd6wR749ve/pQp5w/jZuxQvLDWlQ+6TWqzru2OpVtT/brac77gzauUVCtdp/Fp6ZSKkhHR3jojXMKTVPFOjrkJ1f2tq3WfPcLiDh/WPqC/Xynd+NJ9wxZvEDPhqx9iwo0D6cB4Cxo9+P2/F9z4IC/lLv6PfjeiU1TxTwU2v4y0pKtR4Gqlv809p+mWOFFgf0LtV1fwL2AxOlALruT/DyXfcnQosDqV8V8/pDiwPaOWNd9ydCP8kHpXsWFPBcz+OLEav68Xy9V3X/eyINl5MveWQl3Xfje+2Nhf3Q4PDJiNXznzMAqn5aAkqrnwmAMW6xBWOgtPrxfK2Sx/Jm+mG3qsfy4iHYffukMwTp6bHdxPJT+eM84+6UyANbvlcuim1SBfR/5xy59+g9xOndzhtkAcQ/R+TBZOTesOErZ/auujcMxLbjxXcR2rodADAWuTcceTAp3P25PHwxxzLR+99JAMH5uXZ8D87PBdD79WTcsnAnYHeq1Pv1sP3CXsIXcyxLoj9M2X8wDM7Pjf4wBaDiRzl8+cC37WYTEo1OidbgdsqfKgYSttL3fSv91uFM498Ryz79/xote7JIXz3v/99Z1WaPxI9zrDQY+C7+lwGqxeygRixFRlAjliIjqBFLkRH+D8RgQNbNnFNAAAAAAElFTkSuQmCC\n\"\"\"\nClockRomanAxis_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAHZlbi4gbWFycyAyNiAyMzozOToyOCAyMDIxNyAJugAAAYp6VFh0RGVzY3JpcHRpb24AACiRVZLdTuMwEIXv+xSW7+P/3W0iN4gFIa1E0YpSxK0Jo2AgDnLcpvv2a6dNwb6wdGaOP8+MrS8O3Qfagx9s71aYE4YRuKZ/sa5d4e3DTbHEFzVa6PWf35coet1QHQa7wq8hfFaUjuNIRkl631LBGKdP69tN8wqdKawbgnENYBT9levvTAfDp2ngmL/tGxOmO0+ktx34FlzhLbTwQRwEurbPZtoEOQwvGD3OZQocS0L60cJYLxDSaxO8PcRQWobzFWaElazkCkcpJjmtJGUu1VFKUf7AJ4DgmUWIjCdygIiAYiLwks8EmRNkXoKMhOIXI0umxFKmwMyIFDUzVM5QOUPlVSg1Pd5RJgCNg9H0NCG96Xe+gWlWVx5M6H29de+uH52mc+CcjCO+NgHqPTiCOuMHJH4iIStZVmKJBBP8dGg2fp107ebfEKCrbzzA1eU1YoSXs/ucTP6/xoe7XfcM3yr5FkuWe9jb9N51bEzTs0p9zf1omv5lvfgPa47A6yDhDRkAAAAQdEVYdFNvZnR3YXJlAEZyZWVDQURjGmLPAAAALXRFWHRUaXRsZQBDOi9Qcm92aXNvaXJlNDAwL0Nsb2NrUm9tYW5BeGlzXzAwMC5wbmcZq+c1AAAIpElEQVR4nO2ca1cbxxnH/6PjV88naJvGadO0LjhxnGtPnNaN4xIf05NzGiclAWOHYIwoRiAJAcYYkEBgYu4gg7kEOzZgJ24uJ2mbOCklcWP7tOfUae3m1jRN4ksvX2Be98WIRQJJLIbVambnd/bF7Oyu5v/MPHqe3Z2R2P33l0KjWW3WMMbs1qBREO1YGktY43Jpx9KsPjpiJeWCbwhEm9qKFuxeaDgOzjf1lhsFW2VmKNqxkvJw377zB45d8A093LcPAIjAudFdiwuaWHQqTAnnIDrvPSK86icDFS5X9IjRb7oDE+LciHXOM7h50JP6nM2DnnOeQRCJcmxX6YiVGic61vsVAwBAdM4z+NNIpcmrFnSUdqzUOC4Vzpb3g2hL115RWNp8IpEQ368Y2DJUZVQvNxXOlvfHXq48LuYwhNmMsUeHvQBmy/tTnDwbGAPw6LBX+NaCTzAKSyKceMXaZcIRqXCmrFcUth71AZh/uJtzl+RX0dYeN2PYetQ34x/5Q/Xo1h63OMpMp8KZst4FT5ROwDGpkAjAjH8EIHAurM4Z9b/rPTrjH8npK0t81dyZogzhJRwQGZBzmEmFRKIt44nSCbCcnGq7NaSJd/Z2izEGAM4fG6uer5zbtapRyz4/Y3FEKhRsGw8AOFs5BABE71QNg/Nt44GzJV2w7uGOSLTimG6O4phUGAvn2ydq3iruBNHZyqHtkRoAVuSpt4o7Ado+UeOoJChwUMQyyD1Wyxhyj9X+7rnDomwVzrtnN2C5uXV2a0gfvy16HkQ/H1rihbtm5TgvFcY+6Gksgz3+eL3dGjQK4sR7LE0aUCQVvlbQ9sR0g90qNPOoELFezQ+nmJnR2ALbsaPRbg2rwCvF3eD8ydPS2/LKM60genJC+tf0iqRCMZ0stS1n8lpAFDuVKTUqpEKDM3ktC2ryzjTbomRZvPzLkOFSQvCZvJAUylPA8vKCdmu4eV56Kjg/r7yIp0/UplPMTfDSU0EguvxBqJ23iPOnfx20T9pKkTwViuWd8bv5r4bEnhwzdHOaXS6c2tEsvCp/sg6y6E8Cy89fmD7kZXpnB4CCqf12C1k20080GYGq4DUVRkSpe6zUK0IzlqmCQ+IGa+frrQBkk58YyVNhPLveCJ98pn3qF4273gjbrWU5cC4ES537FqBWxEJ0AbFcRu1+s00qvaZQzbGe/U07VMkmUqNUKtRkDqpFLE2GoB1LYwk6FWosQUcsjSVox9JYgk6FGkuQL2INbfGXz/aYr9fYgnyOBaKhLf597/UaFUce8YEIXLIX7gk58ogvYX2svVIgYSrkHERHchs8b7cDGNzsFStPPOf6VJhrS7K8TLphYh5Pv90aboaBbTE/h+S88o9SWqEwEqZCAefGAqaqDwYkNWIx/T9O/J+oVR8MpFnJCpHSsfpy6sQCJu/5wb6cuv7H9ouy3bpWgySpULphYl5vxG4Ny6P3Z7UAfL8/PF+zqULcZvkuSGaLwqyR7ZsAcO6/GImV7b8Y6XmoAkqslhGGLMZ/UbLvjJSpMFnvy2jLQlRJhRJGrGS/9+JcPlsWEZjtTFgvnWnyRaya97qSHZLNFJWRMGJpZEC+iKWRAh2xNJawBtCepVl9FIlYh+4tE+9I6y8dtVuLBlDjHqv9HrfxDkIBc9RA7ojVttFt/LNUw19HALTf4xYF6WjbKKvyhMgascJ3lxoudfBvowDaNkZrZLRImNO2yWeYIzvSRiwicN54eRTxTtZ4eVQ6i1o3lApDWjeUgij8kNcwTV5YY+OY3RpWRMuPqgCA86YrYwBa7toLoqY/ybTub6EJ8buSwpqaZFUfunOvsdav+e9jCWukIIUhzX+W6RsSi6z3WACCH40H15cEPxoHELqzxMiGokYWswwTgutLQBR6sMowIbi+RN7RYc3N43ZrWBFiPAAY4yERi8VLbU4sEkesKETgPPTxC4iJUs3Ze0RB1Gcmzdl7hLzm7D0gCj5QaRgiDkk9MiwUytyuN0lTVtSNFi/VavlL5i6Eb7rPAwCct3zyAoQVRMhszeZxMfkBkZE+wHnrpUj0P7o5t1taKlovRQCAqClrD2Os9dMJIbvpPo/d0lYBad9jxRD+MG49OGPR/Bj+bCLDrQt/GDm4rhhEjfdWCMEADq4rznDZZmDh8DG7NawyDRv3gfO2f8hkV8MPnjOCrlzKkyH/zXs8B+4uB9D++XG5zGr//DiAA98vgirz6CqkQoP6DeUADl0eSmhU/R1Fh/55PM2SloWQp8aIqBaxOq4MJzWIqP6Ooo4vXkyrIKeiwP+zzNNxZTjZof13/QpAxxcv7v/es6KssRTVIlZC6m7fLWZ7mHg3IQppahfP/+tEGtrKNFyMQflNONPhL0+IkT785QnjUN3tu61tl8jSJjJ2Uz9i1XxnF0CdX500PMwwuSbbDVDtd3d3fnXSquY5B1Ht+rLOj9VZHWoGpZ4KExN1JgSy3AC6vj4pTA5kuY0/2bKqEzgH0PXJSCDLXZPtBuddX1vmwRmG4hGrem0hQN1XJwO3FRq3WdVrC4W3dV+drP5haffVSQv7gIgx1v3pqGg0cNuu7quTljWWQSgesXquTSJmkqfn2qThVdEyKEUP+G8tBFHPZ6MJd00iPr/n2qS4vHptoVClNipMQptBZCX/ulLhVb3Xp9icQ6W6Kv4EkTf9txaabLT3+lTs5b3Xp4ymlUfxiGXQd2MKgPeWnaIQtXru9is14gTvLTtFMgWlCnKL8X072qiQ4ZAOdwHMOVvfjen4GkGKS2JOIALnfTemEXUyk40u2YSam1MiVgrMRKyqbxUA1P/vaeNks/3GeexVzkHxp8Il4HzgP6dMOBaLK0Szoal+M/P5SuKIN+/JtsH/nkp9giDmzWr0KgCV38y3XX8mb86OWObwfCMfoMj/Tsd1lemg5UxYJHLabg0aBdERS2MJ+qlQYwk6Ymks4f9F+9KmnMxKIgAAAABJRU5ErkJggg==\n\"\"\"\nClockArabicRedress_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAHZlbi4gbWFycyAyNiAyMzozODoyNCAyMDIxV5ndggAAAYp6VFh0RGVzY3JpcHRpb24AACiRVZLdTuMwEIXv+xSW7+P/3W0iN4gFIa1E0YpSxK0Jo2AgDnLcpvv2a6dNwb6wdGaOP8+MrS8O3Qfagx9s71aYE4YRuKZ/sa5d4e3DTbHEFzVa6PWf35coet1QHQa7wq8hfFaUjuNIRkl631LBGKdP69tN8wqdKawbgnENYBT9levvTAfDp2ngmL/tGxOmO0+ktx34FlzhLbTwQRwEurbPZtoEOQwvGD3OZQocS0L60cJYLxDSaxO8PcRQWobzFWaElazkCkcpJjmtJGUu1VFKUf7AJ4DgmUWIjCdygIiAYiLwks8EmRNkXoKMhOIXI0umxFKmwMyIFDUzVM5QOUPlVSg1Pd5RJgCNg9H0NCG96Xe+gWlWVx5M6H29de+uH52mc+CcjCO+NgHqPTiCOuMHJH4iISu5rIRCggl+OjQbv066dvNvCNDVNx7g6vIaMcLL2X1OJv9f48PdrnuGb5V8iyXLPexteu86NqbpWaW+5n40Tf+yXvwHaJjA5pimR4gAAAAQdEVYdFNvZnR3YXJlAEZyZWVDQURjGmLPAAAAOnpUWHRUaXRsZQAACJlzttIPKMovyyzOzyxKNTEw0HfOyU/OdixKTMpMDkpNKUotLo43MDDQK8hLBwBJgQ8KiReJIgAACGNJREFUeJztnWlvG0UYx/+O+mq+ACDuqwJxFrVQQD25JAoIEKRtSkNTkqbN4Thpk0CTEudwCCGJncRJC6U3PVMIAoQEBQqp2goqARWl4hCnCgI+wPOaF+OM12tnvXbi7szs/F55H8/sPs/s4//Mzo53A3PnroPBMNPMCgQCXvtg0BCTWIaCMKuoyCSWYeYxiuXEqfpRAPdFq9KNHNtXBoFJLEcYA2BtopOhEW7knGrZfX93mQeOSY/pCjNzIhgXCSSaKGEkWjBUIzZPbt61oGetZ47KilGsDEzUDltlKb2JuGXhcO1E846MBQwmsTLBGIgWxYNfNL0JW94QLYoHbW1m2jAdf3WFx6sGedIsGa1Lty/pq+Cb/ENRUeJb0US8lrAfrxoEGIic29C2c5/gI8X6bENMdHDWqIV9qqbIaBe1lm4NOTRh1p3ril8S69P10YzDJqvdfWKJWg8MVDq0n5ud64ovusJj6wYSJ5iIf+BRHwtt432Z1ZiOzZ6oBTwUWy+6xQwHdbdzXSkK+AAAIHp4cIMIO8W+faPVaK+Yaj8W2ib2luWgRM471xtfdIWPvLkJgDVQHvUjQ1VW+1RNIewflfclRAj4uKLftn/ng/qhna34oitMJ2PU2btC3p9axmrOFXMtoxO+UKx0MkadwUiUYidyv7c8yuiESSwn47LdzbB0Z3wzU8U8j6gxpivMYizoETXGKFYWY0GPqDEmsbIYC3pEjQk8+WSL1z5Ml/GSCICnDtgDmcouIeMlESX8dI8WipV2M+6dlV1gjM+Pj5dHQfT0wVbP3JuaST8BsPHyKABpXc0V5RPr7bWJicqUQMQNHP6ZMUnDtPoJuV3NEYWvCseKO6xzlSKQseIOPj/+7JGXRbG3V3TyTXmw+QlgbE0fdLl+VPheoe3nbrMXj7XxzeKxNgBcCaRCnIOkhQjAWHGHh17NFCp3hUTLj4YBHC7tRdplV3pcskXKncfk/OrhZ8L8J7H8aFgyT/NB4a5w5Tvt1lUrtkDS45I90kkBlt1Pd6isWKkop1hWDqzqAQCikvEOid3MAZNY3rO/5BUAIFr1bqesPuaMwl2hjWQgRGDMHpesXcy+Fd0AQLT6vS6H9ajKoa1i7XuitfT9CIC9j7fwmVIJI927PAIARKXvR+TzbloESku7vfZhuuwp7gLw/JFWmyUJ0fMfSBfmnsc2p68ZBCT1Nld07AqBsqNbdj36krjOKvvwFRl7mYxZBUD+C1gXBMrKerz2waAh+oyxDFKhT1dokAqjWIaCYBLLUBDU7gq3Lt1oXeOw4bP+LBWkxxqR0uEorFijSxpsT2RQNxbO6LJWPpcLAIxtXbqx6viApx7lj6qJNbK4nidT9YcRsTm6rJVvqsjI4nq+7q/68yiAkUdblF5NqnZXKO4A1k7EhheGMtwiVI3aiVhiLpcIjI0srq+diHnsU16oqlgCm//DC0PBE4NeOTMduNs8mqEFdVyPgycGFT0/GiWWLo84G3z4xcRIi0jdWAJ1dcNe+5AnsYeaActfcThEoZOqRgQgdn9tyj1EZcNRWLHqP+mNPthkTSkNrg3rT8X5h+h9NUr/G2yWmm5PQtRwOnEmBu6tAdBwOq5oRMJ/vtlwOj7wQBPcPcpGQlRVrP751WAMZB9jKRoOYPe/f361tOsT3aCqYm36cqRvSSMY659fDST/4qJoOECiK+9f2pgyalQ2IlUVC5gcVFnGWI1fjaobTeNXo6/dXaVNRIHGxtHspQyGHFFZsQwSo+oYyyA5swCTWYaZxyiWoSBoNcbqnlMpPm/+5nUPPckD7rxybk+FPooVubPSepete05ly7fKnCThvDanQxPF6rpjHT8xradjALruDYGxyJ2VrWff8No1d+iyNEOgj2IBlnnq5A1pbx1yReft68SKZCUcdoMmiiXI+jAj2ei4rYK/TVj5e52paKJYbee2t99aAcY67uEve2Ygaju3XYHoGAP3/+46GMWSjfAt5fZnbKiwkil8SznAwmeG9HutoYQPYZkGROEzQ+EzQ3yBQHhe0GuHnEj8GKZ4VZ3qaKJYXK7az+/g0bSf39E2txaSC8DkazWtP4DwvCCI2s/v8MyrGUKTMRYnPRZFo1PUbSu6KBYRGHv55hc6f9gJYMtNa/n4XeboOr+OWze33FUjjBJ77RZNFKvrx52tc2rAGD89fFqo68edykWnnMNToYtiAZFvR1pmlyU3f9qlWGS2908rTiAS2e21DxePzXdUZbASdf+8+yIcq/usjxbratIVTpMZb4SXbliTfG5MwY4iM/p0hW7o+W6rdfPF2zYA6PllT6HagKjnlz1iy08trdkEaS7wrCro/KQ1q/yGvxRL0HxdKZ+PePXXvQVpAMYgchfgByrAYeTFr2MsxgD0/uY2q5quLbX+3a/3N3dZYnl3cPOt63u/35aPq2riR8VqvGZ1TtOnjdesTt7UYwyMNV1b+trv+5zKEwCIMnwPzrU0w6+KBcDdaHrT1Yms6vsjkRObbq4EYw51RUltbjHlgR8Vi3dq/X++5T70lMJEznU3XvWcqGX7yj+t7VfFcv+wDcbAcyU5xnIhPIxlPIR/Wtt3ilV/xap8Hg+UOsZquPK56IX9U5WNXthfP7uCF0tWB6IX9vunsf2qWLmKB1Hsr0QmhW6scB5j8fIpz40BYj+rsE565vDlX+wTk6I5BB7760Cazam6KB+6vCRTXf3xnWIN/p04zW4DJwJjoctLRMWcqg/+fcBvLczx3Rgrb3hDBS9bqfQTHC8avlOsXBn+52DtpSvBWPD6F8S//9R9guNFwyhWduL/Hqq5ZEVyME4U//eQaTZnjGK5YuS/Q9ZN02hZMYplKAhGsQwFwSiWoSD8D0o3XlSXgE8wAAAAAElFTkSuQmCC\n\"\"\"\nClockRomanRedress_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAHZlbi4gbWFycyAyNiAyMzozODo1NCAyMDIxkj7jDAAAAYp6VFh0RGVzY3JpcHRpb24AACiRVZLbTuMwEIbv+xSW7+MzbBO5QRyEhETRii6IWxNGwUAc5LhN9+3XTpsu9oWlf+b355mx9cW++0I78IPt3QpzwjAC1/Rv1rUr/PTntljiixot9Pru6hJFrxuq/WBX+D2E74rScRzJKEnvWyoY4/Rlfb9p3qEzhXVDMK4BjKK/cv2D6WD4Ng0c8vd9Y8J055H0sQXfgiu8hRa+iINA1/bVTJsg++ENo+e5TIFjSUg/WxjrBUJ6bYK3+xhKy3C+woywkpVc4SjFJKeVpMylOkgpyjN8BAieWYTIeCIHiAgoJgIv+UyQOUHmJchIKH4xsmRKLGUKzIxIUTND5QyVM1RehVLT4x1kAtA4GE2PE9KbfusbmGZ17cGE3tdP7tP1o9N0DpySccQ3JkC9A0dQZ/yAxDkSspLL6kwhwQQ/HpqN/0+6dvN3CNDVtx7g+vIGMcLL2X1KJv9v48PDtnuFH5X8iCXLI+xseu86NqbpSaW+5n40Tf+yXvwDamDA6Y1fl4EAAAAQdEVYdFNvZnR3YXJlAEZyZWVDQURjGmLPAAAAOXpUWHRUaXRsZQAACJlzttIPKMovyyzOzyxKNTEw0HfOyU/ODsrPTcwLSk0pSi0ujjcwMNAryEsHADwWDsUWRotoAAAG6ElEQVR4nO2dW0wUVxjH/2fj03kzToyPNTHpS1PbBC9hfGm9hBBjk9pEy0VtVTCytNxFQbQFNIAgKhAL2ioCYlNtmliK9cJLR6sS2xpfmli16Uur4yVtMs99OMsw7LDLojs7c858v+zDmdvOd77z7f87M+fMLMvKKgJBpJs5jDG/bSAUhAKL8IQ5kQgFFpF+SLES0lbco2s8u3lL3OL1ulOGaVV/sdMu+GpmQIkwIgE1vSUA2op7xKKuccO02MTv0Fkg3FAqTIZhWrrGW4u6RVTVnohGIrFNtt/IgdNCqTAZu0+WHtx6TNe4KDtdxVzSRTihwEqVOEdRYCUnLKmwacsRXePvHNoetzhW1WeYVv2pTxMdKJKgrvEDHx917pZ6KpzxFEoSls773tNlAMaq+sSiuyc+LWNVfQD2ni4TsSVW2ockP9Ymxd0UIyyBxRhb2VEMoHFz57XKXsO0GvrLWdJWb9zcCWBlRzFjrKG/HMC1yl5GgZUaYUmFAiE8APYPVNjXd0iczgzTmtxkWYaFqzsOGyZ0jkiEGaYlCqmcOlR+Rmg77yxBT9zJZ4OVAOwta/oqpx4Sv8Oszqg84Qosuye+L7/986Eqe30GnBAqPyM8V4UAfoh2A2garq7f2KZrvCHvUNNwtdiUASeEx8+CsChW3YZWgOd2RxlD87makZIucZUntpJipZ2wBBYA5/0F0RMf+ahV9MQ9dYLo44fHzwK2dm2t3zYQChIixSIyCQUW4QkhuiokMokKilX5XpPO8f7ZensRQPt39b4aNTtEFQAYlmSWJ0KFwAIAHrt3ULGuMW6AWQqEzaLQIZXliVAhFXZebNC3HKpY16hzgHPDtDovNjiHAuVCgRaBMopljy4DOPL9PqnrpEaLKBJYR0f2I3e/rvEN/TWyV0iNFlEhFQqEYp3b1PrhwC6/bXkl1GgRRSb6nS1oAZA3WAsgmrPPb3NmjbNJ/LYlPaiQCneu2Qvw/KHdjMU6Wz0yV0qBFoECqXDHqnpxrS4qcvxKk77xwGDewcLhPX6b9pLI3iICVljY7LcNhIKokAqJACJ9KiSCCSkW4QkUWIQnUCokPIEUi/AECizCEygVEp5AikV4gmSBlbe0XNd4yUhzd24dgJKR2LBBd26dYVpDtw77al0acFZQ1EjSqkmZCiMRVjp64FjOnryl5cPjnRuzygA+PN4p76zRONxvdZOumSRTLIGwOTZrNKtM1/gnlw5KWI+E2I3iLsiCxIH19Z2j+ppaGR+dmBEKLH9w2yxjLZJAgeUPwuYP3ooCsfdd4e3Sb37t8tuutKFGYPltwuxhDOsXR0USPP9bl76yRtf4eQkrkgi7UdwFWZBVsURUXbjbzRgqr7W1v1u9fnH0wt1uv01LD6RYmUbnMEyrfXmJeK/Vt7bxlgUJf9ZuRAXF5H0AsVn8zppKAquq6vHbBkJBJFMsQhak7GMRwYcUi/CEOQBFFpF+SLEIT6A+FuEJpFiEJ5BiEZ4gpWLlLCoCMHq/N26NzmFYGL3fa+/g3jNQOO20X247er+38c0iUfDZvldAyvdjXfqjT9d4zqIie41465phwf6HnLhCMBFmi4JhTdpvF+RFSsXCxPTRHx9Ms0m6qQFx5slidnLk7mMJ41cv3Abwyw9PrF64DRJODYgzTxazkyPr4weXH55ALKQmX5JOBAeJFUtkwyuPGIArj046Mggplv/I2scCcPXPk7pWuuq1rQB31oL6WEFAYsUSuJ/SIcUKAhIrFhCbZjn215d2LcT0y2kLAcQ5TRSO6aMIttmpwJqavvLbBkJBpE+FRDCROxUSgYUUi/AEWW+QEgFHfcVasWCTrvGWe8fj1oj7qy33jrt3SAu73thhmNZPf/c7TwrLannQn94TBZMIY1D7Y/zTD2DFgk32GucQkPNuZJrPa1q6xu1FQevDft8dkpmP+oqFicGf648ZgOz5hQC//vhM9vxCeH830v5aJV+3lAT1FYsx3HhyBkD2/ELG7AaO1Z95pljOk4ogvvHkjO+uyNgnFIplk2S0xws/CKX82WRhkyuE5z7WxL+RFwD85tOBaRXLzbJ5BbrGO36fnCJc8XpRbPhl6vppufl0QNeKlmvxJw0DYVGsW88GdW17KiPW7qOWzSu49WzQvXVWrguJn23ColiYEK3bzwedVU6uWI6jAGDJ3HyA334+uGRufpJD3IfLPqL8EoToEfvbz4dEfMQtxq1PQOy5DMO0HB6b2XWpfbmChEixXo7xF0O6tm3J3DwAAB9/MTSjyBEITx/rVbDTGaZ2lch1SSDFmpk7/57Vta3urhK5LgmkWLPgl/+GpwYWuS4hrKtr2G8bCAUhxSI8gfpYhCeQYhGe8D/VKzz4EoGwzAAAAABJRU5ErkJggg==\n\"\"\"\n####\nPathBase_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAGpldS4gbWFycyAyNSAyMjoyNzo1NyAyMDIxjp4Z6gAAAZJ6VFh0RGVzY3JpcHRpb24AACiRVZJbT+MwEIXf+yssv8e3uJuLnCAuQkKiaEUB8WrCKBiIgxyXdP/9xmlTsB8inZnjz8fjqLN994m+wQ2mtxXmhGEEtulfjW0r/PhwneT4rEYrtbm5OEeT1w7lfjAVfvP+q6R0HEcypqR3LRWMcfq8ud02b9DpxNjBa9sARpO/tP2d7mD40g0c+rd9o/185pH0vgPXgk2cgRY+iQVPN+ZFzx9B9sMrRk9LTIGnSEg9GRjrFUJqo70z+6kUlua8wowIlmV5gScpgmTzCjKNpaxwwkhW/JF5jo8EwSOPEBFQxAQRCJzkqVyv+UJIY0IaZ0gnQlLkhMuCs4BMDylCW2YLQ8YMGTNknELK+fUOMgDoNBlFjyNS237nGpiHdelA+97Vj/bD9qNVdCmcmtOMr7SH+h12BHXaDUiskRClyMp1hgQT/LhpMf7stO323+Chq68dwOX5FWKEF4v71Az+v9r5u133Ar+S/KoFyz18m/Dg9XQxRU8q3Gu5j6Lhx6xX/wFyvcFVQrT5KwAAABB0RVh0U29mdHdhcmUARnJlZUNBRGMaYs8AAAAidEVYdFRpdGxlAEM6L1Byb3Zpc29pcmU0MDAvUGF0aFRvcC5wbmdUeJvoAAAOaklEQVR4nO2dWXcUxxXH/63DU3+PnMRrHAtiO3GIcbxgzG5rWCwUoQ1JCCEkgYT2XUIb2jeQEEIgLDCYxWCbxHa8xjGTeInt5OR71HMeqqa6uru6p2fUPZvqd+Yc9VTdqrp17+2qrurukbZxYwkUCr/ZoGlasnVQZCAqsBSBsCErSwWWwn/UiKUIBBVYikBQU6EiEDJhxPr02DiAzePHkq2IwkDbvLky2TrEw98qxpyy/jiRlj3KMLQXXjiebB1i5uPyUXak6wBAiOV4y1T6dSrD0LZsqUq2DrHxUdkIdJ0FkzMvTqdZvzKMNLvG+mvpWfHrn2ZOSHJ1HYSkV78yD+2ll6qTrUMMPCgZpgcvz8nVflAyLM6JTmKKoEmnEevD4iE+CbqpLcySadS7DCOZgfVB0aD49dXztZ6KeZjpeFUqrpKFtnXrycS3er9gADCv6QAAry24KXO/YIBGlbtYTDr4UpXCTlKnQnFlp+uIOHvbhVN22XuH+/nx/YIBqUwcuLSoWAtJCKz38s/wS6XXF+uMRLBp7t7hfp7uxBrVZs35VFvaQbtvNb6QsnYSfa/wTl4fwMaqHUv1WVlyMbtWO5bqWVnXgl51EHbC1lhb+kLjacdSPU/xMRiytMQitk1T7uT1MU8DIGTnpdMA7uT1uZSV5oq1uShgtAU2/66xR+mI0X1d56erv6ZIxjWWroOQXcsNmoZbuT08pHYtN9zK7bl9qJd3UlI2Msy4q80r2bXcIKaz5sy79kmwQIpAiHGOAfDVFImeCvdcabx5sBu6fiu3BzAWhnuuNBrzka6DEEfF3HNhWmyKYrRdk6RNZp2w50ojPbh5sNtIjTiF54oylsSoJHuDlBAAe1eaTFo4bIHuXWm6caALAHSd9nbvSpMowHIBEEKzaB28lJjFhaUWoLmW+jMMw1wcXYc52rgFpAZ3IUmBFZmM3rjaDIdtTKlib1xtfmd/Jx94JKaxFRflQcgbV5uNiqPtta6fWZIZliIM+RYLezdIIFPhtVAHgJzVFjchXQf1OkCFaSnq7JzVFqeVmkkS5mdm6Feh+LVQhygmrdZlzqXqRelI2kL7RY2ZlaXxbjLzApbrURen2NFyclr9U5WxmtMufg1dkzSxmtNu33nnhENu9WevRlGAtsiaMNfPleG5dvVMBR1kMgPqKbkFzMRqAS0UaluDYlbefrMNgMkrMEJn3/U2iTDM4020qLJAg8xSM6vcaUgD9l1vYwKEOJa1dcEumb4Yxo8g7R0Xi7Xv2v791tiMm5W9rYB1/LRw4IapOVYkAg+pQW9a1V41FeelVva2ipF04Ea7oVskkasqUSkSTEZBB/3TF5NBCAHAO+tLH7UDBzqiS3njyh42SR+82WFPocc8i1OzYlzBDMWrDK+EzZKCvcQWmT7mac4qEClr7YVDnemI1Q4yaB9XVloAxBEkvq0KL+9utjwsxVIAEMIjzNJc9ZVmejB8sBNA3KrQ4rw2qsZb73bCvOSkKZd3N4tluUqiwm+928kL2ktlyGpRGlURJ1KX1awAwHDs/c3KytJ8+XBFD93uMlIAEHLodmTJquuXdzfzIjQORnK7RnK7fNFhJLfr0O0u3lz1lWapmKEPM4HQBVuiNVfXAYi9SLuPeIaYTCG9JAXi9I5f94a4HvTrpZ1NNPbz7nRrmpZ3p5srfWlnk6ZpVctNAEYPdfulgEjenW7aYtVyU9Vyk1xbQT1DYUBMtNQpRl4QaicGSy+ML+IAJtztia8V/zdINU27uL2Buu3Pd3uk1R+/1AhgLK8n0BllLK+ncqlBbE6qLQCmMOCiM4NaPFNe1lja0QgY09+f7/aAWgNeb8s64esGqa4bagEQ9h4vbDvNBAihS7+J/N4EPKsykd8LoGLxNIDKpQb6VcTUfUIO3+v1uAfop91SA2nf43aTbyNWwf2+hdfqxfV8wf0+a92RqJo83JdIt0we7gNw9EI9jTBxf1XTNFHt6Nbw8jZH2iF1FhAOQTscZze1goIz0aU8M7+1Tr6IjSSGQ5jytcWYKF+og33jPjIJFr4fRTGxd1GFU5z5rc4Pi/rRR62oqD+6VCyce+UUIN+KDIcw43dzcVB6nj3hLkZY8Yduipk6RYi7cCpDO2LXn3WQ4oezAnu6wTJoERIOYbZ4IBXmj9nigSPnThpbqTFNbYSUPBhI02lw7mX2ShINo5IHA6Z0vt3gh7P8D6wjfzG9LTj7Ui2AcAhzJYOp4465ksFZ1ALGunru5ZMWza2k89UV9YLlBiiPM4avD9YG/gRp2UdDRTM1SL1lVNlHQwCKZmqyV0k4hOy7OrU+TedMv1gDmDYMU60jUTG6wENHuD7hYtwgAM6XDq1xzR7PiDW1pRpA+cfDXoQLp6sBzJcNp6Y35suGEarOXjXOV+YGC4Qg0uU0HLAAAIRwl1EPUso/HqZfNU3z0VmxBdbkC8avu0xtqT76yVkXYQAFUycALJSfTWVfLJSfXfgk0jXLI2LmJUg6ToIiJv0jw9XUlmrLlq8v3VzTVOixbFrMHcc+HcmfqMpeta45eC6AWF8/HN9s/EYXrSHxjG+u4jFEHcFTjn06ImpIR4HFihFfNq5ju1colqz8bNRdOH+iCsDFY1HEUoeLx0alzxhG7amF8c1V45urNNlLlIkHMN2c4VFFO1X52SgXoMtkv9qNYSocfd70257uBfPGKgEsVY6lwWAlsFQ5tvS5oTxNjG9mGPvDcT6xHv98LMmzqO3+ptR9PvorhhHLUtKLcPwBn1QuHR8HkDdWGUdZ0+lHCAip+mLcdw29U/XFOFdn9PlKGmFcJaatroPewPEPryPW2d9VMA0i4+rI79nPX5/4csIinDtSAWC5aiK9hiuR5aqJ3JGKQ6PH6HE8VSRk34v6xe4CkRNfTjD3wWEVQgj89tcGaa+Hn6sAUP2VTV3ZiwlOdkvzJRQun5h462wFgNyRissnvMZW9VcTw89ViFuR1KkSY7rYOUbspqY1O2HEGRAO8aurNWphVqm6etKeOvTsUX5c83erAMs1hxcXOzh8FMAVWbVpSkw9Gnr2qPS1NrsZEc3OntoCGxp5cbFOCQ73cH33l3zE4k1CFsi1X08CGHwm0itdh9ifVTpb+6tnMlmpmTwwdJSG10qNmwMGnzGiSrRS7deTcdg5BnR96NmjtEV5E4hEkuwe7krNpO/u0mprp+ypA78tpx0++Q9JrlUS1vMgaql0ZP9gOT24KrMYxbvdDGHAo7yXRvkxz7Uk8oao48Iht+6sBcmI1b+J6XHqmykxt39TOYBT35j0oF9pFiUcgpaJv+v59skpAPsGyvcPltNjEWYB44FBz/Xa7Bwnus5OckJEH7GajSeqWfqpb6b2DZTHpmosSLYbBJ0k6f2byvs3lVuy6h5O1z2cpgKrp6Z9XLWmGqunpgHsG7BawLAoIXUPo1uAnb0yO8dK3cNpywRncRBXDLrOs2hUBeesLE2D5SMEli1dOCPtn3CIXV1l9uda3TSAUH9ZqL+MppzZWMYntfrwdNQaYpWP+qkPT7MxSeag+vB0fXhadGuovwzAtTofmnb6bLC8JdqXXUrHzPrwjJd0Ts6ZUgDX6uS5Gca1uhna35wzZbZfKPE8tRACoC+7jCc42dYL9eEZ5iN2OSVTI9JiOHhPWUcsjsd0i0CyRpHEf67Xz1yvl/gmakHmfhlrVOn0P2f4nNiXXerkwcR4ynqNJTTsKZ3yZl8pgHdOzwYyXacw75yeZXaJeLT36VL3IhZ5A13vfbo0anF3Gv41K95ytrYbuXWTAE+ZVoXdTx2Rbqvw9MZvZ+2xL54E65DGb2dBTRTBxQ6ihXlZlm4EhKk2S0Oe0HUAPb85wgvSCsPbSfYqbjTMJsBRxohl6Uz3U0e6nzpiBDsAh+Fqb88RADcb54I+CVKZpu/mqIncb+WKFm76bk6abnylF0yReVP0SBRNzHfeuGezV02NBoptH8v8E81dvy4x0l3PxfU5XIk0fz+3u6sEwJ7ukneb5uwCnU+W0OGq+fs5CBbrfLIEsG3B21/P1HUQQj1Ca3DRhLVlI2FuMp5uaPnhHD3oeKKYZRpLDK6Wo14uWeuHW83nAOzqLKYRRr9SOp4o9vK+dcsP5zqfLBZjQuIXD9Zu+eGcKB8OMWUS5iWtpeWcU17748WA6QUVHmSt/2aldnYUA7jtXMn6hJqFQo3T/ngxPUu56Tg8i32PHFskDXfIKpHCitiqSgBaa+t5d4m2x4rYkSzCmMyPUSpZn+xoL4LtRwbttmp7rMj9x/V4ES7pxeA72oto00nxzoaoEqZeUSJXlHSVoXDiTut5ANkoQsRWjlFFj388bxgZxplsSvQGjelwiOmQeGJ45r39p3l60PpoIT2gUdX+07y6vnKh/af57W2F1FY72ovuts3zrNZHC/lIZpiRj16W/+fo+V8Sb28rBEAbSpZnnJ/HcqbjZ2aalkcKodaDHnivfT4b7GykXn+v3QgvENLxs/Xk5EamUFNTYTjb/PXWQt5ict0S/283bGspCAP3OhZUYHmh8z8LANCBbS0FAF5vLcxeRTiE7LuAbARqeaSQFTFX0vyrAqk8rZZyr2Mh6T6JZ8SibAQAdCa9B+nG/c4FAE2/jMQBIeEQtqGAptMU+tfuGhpVXf81TubXmgtEAVpJKvgk/hGrq+uCv6qsQ8SlDwsRYQlpBB9Mjxdrmra16bClqve7LiA1QoqidXcvJluH9UvDL/IB9PxvEcCrjfk8nc2SthW3/UXtD7oXg1JubWg9PYvJ1kFh4pWGfMj+EZUYVR+mvNe03t6LydZBkYGsy3/frgieZP/rXkWGEv92g0LhghqxFIGgRixFIKgRSxEIasRSBIIasRSBoEYsRSBYX7FXKHxBjViKQFDXWIpAUCOWIhDUiKUIBDViKQJBjViKQFAjliIQ1IilCIT/A4Nr7zm0fKKbAAAAAElFTkSuQmCC\n\"\"\"\nPathCenter_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAGpldS4gbWFycyAyNSAyMjoyNTo0NSAyMDIxS9eb0wAAAZJ6VFh0RGVzY3JpcHRpb24AACiRVZJbb6MwEIXf8yssv+MbzgaQoepFlSo11arZVvvq0hF1t5jKOCX779cmIVv7AXFmjj+Ox6iLQ/+BvsCNZrA15oRhBLYdXo3tavz06zYr8EWDVmp7d3WJgteO1WE0NX7z/rOidJomMuVkcB0VjHH6e3u/a9+g15mxo9e2BYyCv7LDg+5h/NQtHPv3Q6v9/M0T6X0PrgObOQMdfBALnm7Ni54fghzGV4yel5gCh0hIPRuYmhVCaqu9M4dQiktzXmNGBNtsihIHKaJk84oyT6WsccbIpvwhiwKfCIInHiESoEgJIhI4KXK5XvOFkKeEPM2QB0JWFoTLkrOIzI8pYltuFoZMGTJlyDSFlPPtHWUE0DAZRU8jUrth71qYh3XtQPvBNU/2jx0mq+hSODfDjG+0h+Yd9gT12o1IrJEQlVhXMrwwwU+bFuP/nbbb/R099M2tA7i+vEGM8HJxn5vR/1M7/7DvX+Bbkm+1aHmELxMvvAkHU/Ss4rmW8ygaf8xm9Q9vw8FQ2xzHKAAAABB0RVh0U29mdHdhcmUARnJlZUNBRGMaYs8AAAAldEVYdFRpdGxlAEM6L1Byb3Zpc29pcmU0MDAvUGF0aENlbnRlci5wbmdGXVPwAAANs0lEQVR4nO2d+XMcxRXHv6PyT/NXJNyEcIQ1FBBIlanChY0sImMvtrFlW5ZW1mFZSJa01rm6T8sXui/bcgReGeNDYMdQQIWQmMAGYnACJOT4J/pX54fX09M7M3tqRruS+lNTrlEfr1+/96a7p2dnrK1fH4BC4TbrNE3LtA6KVYgKLIUnrMvJUYGlcB81Yik8QQWWwhPUVKjwBDViKTxBBZbCE9RUqPAENWIpPEEFlsIT1FSo8AQ1Yik8QQWWwhPUVKjwhJUxYn2wv1/+c/NsXaY0USSJtnlzfaZ1iMf7+/oAQNejUhkD8MqZrNZ8jaPl5gYzrUNMrhX0miHFGD+RUracy17l1zjali1HM62DM1f39PAYYgxA3txRMx0QWSJdkVVoeXkNmdbBgSu7u0XovHreQcOkCgCOWYplILvvChnLn2/MyXHIyZ9vfG9XF8WWvQsi68ru7vz5Ru8VVVjJxrvCSzs7xUIqgXqM2cvw6oyRkCzs4FogY4H17o4O+c/X3ml2LBZHPVFFLvLujg7LLaQKrPR4d0dHLKckQ2amwgV/u8X9FGfbwy1mEmPbwy2O82BiseIW0mmiVDiy4G9HtAscnJI0GRixwtvb+FQlo+sAFvzt/oVWAJFc5gsjeLE9vqi+7a1WsQAY8y+0hre3UboasVJA1ym86JwsmZ79ljuwLmwLkcavXww5pFN8JE39Ai/sC5sbEK9fDMl9itXBC9tCFh0UYmEqSDs8MjEVMgZphnp7ayuAiB++MDNO4FvUwdjgjgRBduSdVgC+MCJ+AMwXxs5LbZbZ07GDb29tha5f2BYCsPNSCqG8iiE7kDt4eC3BRNrOnQmmGxeZz2+h4WrXe+0iJeIHjOA4trN9Pr8FMIcfUdJZGqHrNHWSKMCQE92WVQ1B3FbWIMJ00HUtlwG4GwYA2Upk/Dh2y9GWEd6mrs/nt2iaJkfVG5c7hnZ1mC43VmCJpYFLsJhGBFnMiozxVnR9Pr+FVFLwy5WxNy53gLG7YXwFQNeFlchQsh+d2b27M7V4XhpzeU1i5U6zHoA9VzvtuSLCRK6DHEQvCxgjaXN5TSJkLdXlilRSDmXHttYgc3lNe652Vp1vgnzRynbW9ViuIZZ1xNKkQYuiquBaV8G1LmsuUHCtS4TXXF6TRYglGuSxh8oD8C1yK1Sdb3KsSO3yhshSTm2tTcg4whd0RNkZQNz5JDMbpLQk2rvYHavxKK10/dyW6McyUlTtXeymtLO5DTzL6LZYdR2ea0T0naPcNEk4m9tAdc9taRQyFZB8YRrK+DNO7Gj79vV4p9Ps5qMA9n/QY0mM+Pl9n8ilkjTAivJmokBcMVJde4sigKhAxZmjiA4se0VeN1qBtQwZ7a10w8OrEWtmUxDgjuTOBgqv95bPBiNnjGlbzjVcXni9V2hUeL3XFCXDGOXadTerSA8Kh/f3zmwKii0Jx4oyGRnFM4jFwmRDIm1TeBJY0y/XR62BjCFnZlMwMouRwj7cwPTL9TzLdhtokXbgRp9jK8koTtJIH98iwFjEj3IERwqdZZJKM5uCsRpdfZjOIhjTNK1sph7ASGFf2sHh/gbp5MY6MVUV3+znKcY94FhR//TGuuKb/XKWKAkgpYeDCYnqHWPFN/tRhINTdWS4saL+pCquXoT9xYVdfLM/J4dPKdOoh+SalPBw8R74cEDIpqgKfDgwubEW0rAU+HCATjzSQtO0iZdqLT/CGS8eKJmsBXBwqm68eMBahzFZ89WPrlOX6S9Nw8RLtXwRDACY3FgncpPH5e0G7kXGSj4aFCkUVSUfDfJcXZ94qdbddi2I7plRJamkadpEYHAiMAigZLLWXstT3bIKe5fJX2QxsZJJw19ePSu0i83J0Uo/Pjb6Yk2sn316ghFVpR8fs0+yUwePFY3VBCaOQL5nXDPzIEcyzuiLNWJjufTjY5SSnr+8mgpJ7MiGahquyj4ZsrTjUbtE2SdDIxuqk2luunTowKhUkjG7qqscXR99sYZORVQt3V8uT4VC15EN1SKqyj89bi3g/XRT/ulxwLwtHdlQHavkTNlxvpVq/NB57SD8JW7PXfNXRcWJlCIxIad/UyUmIAqsQ384Yc1lTE70FFkfAPZ2LQoDOOO2TbIZ0X16HGJ1FgAnoyVEO3TopFsqCk69cFj8lKXys5OWdDAmJy4DvF1Cav3UC4cBcx1W+dnJvacPU9ZZD8yStXA7ABE/zh46Kf6ULZOqTK2y8pRrCkqcfL5Sfm7DMRQ9/EdPGo2vj6xAlD42lQpOVQI4541lshPR5ZPPV1r2S9Nzlof7WPJzGw5jAKo+P738q+Oqz08DOPHrQ8moNHf49J6ThwpOVc4dPr28ai4T3A6GWQQ8GIxfxWAJztKqqt5aopbHn6t4809RQnafqABwvuqt489VyOmWYplC1iqOStQLAOeXbKLsgfc9+hdstLKUu2n3aapob765pPpDz3LrV//ZlPPG8QoAv1ua5GyAOoIk+kJ2kI2QhQw9W2F/hktLYbit/JK2G4SiNbeGRSI5Y756OE7FlcJ89fB89TCAN45XxCnG7aDrQ8/GK5ZZuJKMgbGaW8M1t4bNvXWg5tawu8rnaBrSPgT2xKWIzbbj7ZphALuGyncNlVuyjj1TbtqBsSNfDGdc21iHQCgJ4xnukS+Gjz1T7rLXjhwZSW+sG3i6DOCPMGv/woXsGCwD8E66MrMZ6hqk3g08XWZ+JEIyQhYiVBVKDjxdJvbZAfN+2a1epD9icfhudVRixq9OL44LtSMXakcA7Bgso5S6L0fkVzkyrmFiZ9k85Quj7ssR3hFXe5HmdkPf+lLAvLnof6oMxs1FuG50FT9qC9eN+vtLXx8oC9eN9q0vld8U6n+qrP6r0UwrmAByd9/6UpoE678a1bx5hrsuPTnByCiAXp8RXvwxEwOwEHFFsexloX50e1+pv78UNImIN4Vi/KqMW8kwWibRdRoRKKqCEWtUwb0fxuUAWtpHMDIWjIzRzUUkl0X8gK73+kp7faVLEZv9x0L9mHhuzY0ABCNjMcrzoT2DZuFuQvTmsEVJh8T0Dy0YHHMlQnuePBilN2MAjv7VHeHZRs+TBy3PrS/GMKNcMuPWIGXExpXQhyvpqoYp7GP1PHkwVta23oMRPxq+Hre8OxqnyspFjpWGr8fJjtt6nXvKzcxYw9fjy6ynHe4gyTt0JPMCaqqktsbq/lUJgMZvxh1zNY1ndT1RwrWHa3N21sFY4zfjmoZLDeMAtnaXvNZTQueCridK5HtG7+h6osTRKdwRhsu2dpdEaH/BePObl2OMyriopNbYOJFMuc7HAzRaNv3NWj6/KwDgPZuczscD9sIrnYR2gGSKOIXd1Aewt2KmE8YzwSjdDLxQL+W7wljl7enNtydW2XDV8Vggzgh0uWnit50BAPldgctNE7wwY5C82HzbZRc2357oeIzHUOfjAZJv6mlMfGIv9PJts6IQ4oWbkl1jSUpEwXvl6vSctciGcyxwpXnySvMkuZa/6yJ+9avr0PWOxwKua9Xy7aT8uq8cVS3fTlIu/5adNwo4ktTOe/ujxXTxtX43aUnnH+ALZ35zeRkO8ha5sP3R4ljFrrZMUplILuN3M9I9TZyKaR+t303Ssqn90WIe+IazXu0ojviNAp4pYD9S23mPVTh0ZyoVMSuV0J2p0CNF5KE4XQ49UiS/0Q/gWuuUSIeut/2yOHRnKqq8raE0VZS+GpzXzoPsWusU13QZv32f+IV2bg4FAIqtJL3OWOjOFIXUlraiLW1FlGgVSFEVPWPaQy0ZxZy2QHlMQw7WtOSnSuI1Fi/IWNvfp+X00CNFNA9a0tcCcbosX4eUshiaFua2fMBSjGFRMyZj5Ps0tOJ3f7kMwGJoejE07VgA3q+JU7grjFVyLUyCKcNY+z+mhWXeb5sG4MMByor4obVZC8u1Wx4+AF1v/cUBS3pCxMenkcgvXnstwRqr+aFCcf21PHyg4/sZkS5ffF5quJLg5mKs4/sZi1UoixZeAF5pPUBPGykOYtkwedtubimkE/5lV12X/bUUyemR9Iil6yDrAJ0/zABYD9wNo/MHqwXXLE0PFiLhPjtjnT/MoAObms04ANAc5n+SbQUJbSvkENc7ZgD4UAgAut78UKEskGvI2DJ4LcGI1fXjbOMD+0lL8W/Tg4UA7i7q9JEubxVccTDW9eOsxSqND+y3fErpRuesD/vFe5di+G8KRwVKLPO+3LTfknKjcxbGrxS413Qduk7OsrAMXtO6us4kU67h/n38zP5FUKD7n0kJWfWQlezWaLh/Hw0VIounAJRomlcKMvm/RIjF77usbVkblWHMUT0v0Lq7U2vm6H37+JlThPX8KzVpa4Gj95kxJOzjmGhmGcQKrJvJeY23kgnvaD09Z9OrGbx3Lz+zRVjvT2nKXH0E790rAshiFp7llO6iAWO14jXpf/Gz96ezdMivp6mtVGfi+FXXzUvUIHjvXnuiJ617htbbe84VQfX3FIjzvn+7I3N1QJZxtEn9PQXW75TAfBNrRZtR6+tbwdqvAup+XuAwzDPW/5+V7Zds/M/G1xQD/52r/dkee+JKd0uar38pXGTwf3OWlFXgFDViKTxBjVgKT1AjlsIT1Iil8IR10a9XKxTuoEYshSeoNZbCE9SIpfAENWIpPEGNWApPUCOWwhPUiKXwBDViKTzh/7gOCAfQ4SdiAAAAAElFTkSuQmCC\n\"\"\"\nPathTop_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAGpldS4gbWFycyAyNSAyMjozMDoyMyAyMDIxWwtjhQAAAZJ6VFh0RGVzY3JpcHRpb24AACiRVZJbT+MwEIXf+yssv8f3bpPICeIiJCSKVnRB+2rCKJglDnJc0v33G6dNF/sh0pk5/nw8jr44dB/oC/xge1dhThhG4Jr+1bq2wk+/brMcX9Ropbd3V5do8rqhPAy2wm8hfJaUjuNIRkl631LBGKe/t/e75g06k1k3BOMawGjyl65/MB0Mn6aBY/++b0yYzzyR3vfgW3CZt9DCB3EQ6Na+mPkjyGF4xeh5iSnwFAnpZwtjvUJIb03w9jCV4jKcV5gRwTabvMCTFFGyeUUpU6kqnDGyKX6oPMcnguCJR4gEKFKCiAROcqnWa74QZEqQaQY5EbIiJ1wVnEWkPKaIbbVZGCplqJSh0hRKza93lBFAp8loehqR3vV738A8rGsPJvS+fnJ/XD86TZfCuTnN+MYEqN9hT1Bn/IDEGglRSlYKiQQT/LRpMf7f6drd3yFAV996gOvLG8QILxb3uRn9P40PD/vuBb4l+VaLlkf4svHB6+limp5VvNdyH03jj1mv/gFq/sFIS5is2AAAABB0RVh0U29mdHdhcmUARnJlZUNBRGMaYs8AAAAidEVYdFRpdGxlAEM6L1Byb3Zpc29pcmU0MDAvUGF0aFRvcC5wbmdUeJvoAAANrElEQVR4nO2d+XMcxRXHv6PyT/MXJEBOcwZTQBYTAgUFFBBMjMBgL5Fk+ZC8kqzDuu/7su7DsiVblizbkiXhNQFjK8YxFFDEIUDYhBRHbiCcyT/QP+eH7unpnZ2dnZ2d2dVK/an9YaaP16/fe/O6Z3a0Uu66qwASidtsUBQl1TpI1iAysCSesCEjQwaWxH1kxpJ4ggwsiSfIpVDiCTJjSTxBBpbEE+RSKPEEmbEkniADS+IJcimUeILMWBJPkIEl8QS5FEo8QWYsiSfIwJJ4glwKJZ4gM5bEE2RgSTxBLoUST5AZS+IJMrAkniCXQkncnPN37Qi2WbdZjRkruKNTPA35o7b0BfVj/7l2zzRa73CPcCOf83fB0uaK39/hvWJ2Obu9AxGR5AuaxBYNKV7uW1FBCIDnXujwVsX1ytntHVCZkemBtalXy1JY83w7DyAxD0FVAfiCJOtFdtEsP9POywHCImwrAeBbUWlo8sYSl2FmB4Cz2zss7KxkZXUlRaOoVC+z1doXZJdC9ku6Skvb2thkCMl+qUs8pQ1o46VtTEjID18QogRJIiwvtwGgQcKMLMQW9YKptVO8x6paaqUHPKpyzndzjRafZrV0ArqqhADIOd8NgJbRY9o+5MdSsC3kx2h2d7LmsWZ5HwAwqigAcs53M4/wBVFVoQUcdQE0L6RyKaw40wJgfGcPgAW00EKuz0JmC09OuRd6ACw+3cIvl9wLPRkZRoG5F3oWgi18K1C11EqFS5zBHRRmac0dC5ktgB5eehYAoKopy1jlC80ADuX2GoZXFGX+yWYAPD52XexdyGxm1VqJldaEQNvyU9Mcyu11fwLrBjFCdl3shbZK0GPdWeFLZGoC68B8E910KyvG0eefbOaJavfKQWjT0G9JwqdqgHZh7GIDzaPZWCWxB7ceohiQFp7e2sTONTelYCk8+UQjtrI9oK4QVwss5ey91Be22BHClbavM9260XvG08GmvZf6XJjA+qD0VCPb+FIIsTA7N+zJJxrpabIz1tyWhpBff+wk6i2GTt4r/SZ6aQ1s6jy3pUF7WsGupNJTjQAm9/a7NJu1DN1L+FZgWCjmtjTQ07xXTMxICxUFGUoSYVEVBAjJvzyQf3mAKU1I/uUBekBX67ktDWKvsPUbsDmW4cEEp+RkQ+z+65uSkw3QHjtTT+VfHlC4VVWVRpiFhOQthTOP1dGoClwZBGC4p9PV0GLrxOP1rCQ8qmBjKZx5rE7ck9HjwJVB7AOAotm64rl6AMf2DSYwobUMS1dBErgyyD3FrArNR8CJx+upNyNJUsYqmq0DvQKEfMPdX/DqEDsWcww9pfFBSMGrQ1xpi4FmHqvT5w+Y9poODHFLeTjntMXKWQDzhbA+mpKMwCqcqRVjmRYef7SWBk3ha8OKohS+Nsx1Zcfap/C1YdrGTmCxiNQ6Rut1vGCY3pYef7TWq2mnLVGdBVhbVSQFd4WGESMVyMhQ9r8+IpyGV6vq9CM1YgPO0Yer+fH+10eirra0paoCCG0l08GakB+zRSYC1yH7jlWLp9OP1AD63bq1VcPKvQ5/quiJ/aN8SEVRmF8JKX5jlLcUG5hS/MYoXyWPPlxtqNWjSvv+x0Isb+lbUenOL1LgOiTMWdpml0dVXM7y9nFD3lQlgLniMQUoeXNs8sFKqOrUQ1U0qkreHOODTz5YKeoaTSAXwuQYELZokUJ4CZNAIYRuJkDI1ENVJW+OOZvpWkJRFGoH0SlGZ0V40EAylkLjEJpTefnhBypYOSFlb41HfgkoUvbW+OEHKsJ2+uLDME0+NUrZW+MGNVhfgI4ljh7aSiaDlSE/TpXqvdYPe45UADhVOs7NH249zVAw8WAkSlnZIU/UBHYfLgdwOlz+xP3lumbi4wAAhBz4nV1lmJxwaHeTIVSVCp+4vzzaWLQqtJXQO+3Tnpll1WLqL45uOkosZ3m1x6Jazh+YMJSXX52gagEwLOHlV42NLWByBAm8e/nVifKrE/qjfM0citn9TphAuiyqqi+I3YfLE5h9+hHNXxzmNe0T21nl5YfjD+7Y5B4qA7AQXfj4fWXiacXv41aDSVBVEBKt+/h9ZcbUBcRuTwh9l9VC/zVG7qGysBd3AThyCkepqDiSkEZm7Bwv9QVR+bb7kiMZu7fUYqCxe0uNWzFCYrcnpPLtIzvHS2nhGQ9MtKqg/or8hoNejc78mKEocP1Dtylj95Z6IdzwqfrDEYvaSEvZbK8oWKw8wu2ehImk6qNHlbDS6RsJOBTr/uOGkXtKAPiCqH5n0m3ZThG+h7Y5X9psqWoSQPZoSc5YKT1ee+hvMQDV77A5jtxTQkOt+p3J0Z+XiFU2cT9jQfurrJRfiyyEhEWw5t3J2O1hVH65moVX9mhJymfk7id7tATaWwzcODyqat6dZMeqOnJPfHN3+a4wa4SlK9h7ucVrAP2dxtr3pqwbD/+sRLyFFHm+ZoqWZ42UeKZssqHOEq4lhlhS+95UzO+bTXE5Y+l/XKqqQ3cXp/yKZBkrIglFfobuLmbmJKTuj1ORDc7WTp2tnQLwq+HUz8s144QFlmYHVRWNYJrFY37czFjPDRWDv64JQFUHNxcPbi52cYi4GNxczDKWjQvOZstg3VEAzw2lbFJuQZ1Fp8NnPbiZRVX9+0d5y8iUZov6el10guwY2A/gXP3Rft9+0U80ZzSEXBsoLvp9+8VHWaZqiG3s6ElnCuCce9ZLJtxT9JRNX9iMikbgtXF5UKmvP+aKrv2+InrQEDoWVmIML3eGc6Kbttky6NDvKxIMale9HQNsvudcMmDSoJqLausWgNEIrCoey1CUhgZ37NL30yL6/knjn44ZygFjeAHGZkmg76dFYurS0QodqLS9n4XXCy6ZMQlQnQ0K68ZBuH2cGkdpbJxOSE0AwME7C/nf3jT92UTgwTsLRS1N2ySBMDVEnKrEBAIAUjWpuHi2rxDAr82cbm4cQuBoahsi7w6cQ0jzB9OmAps/mAbQewdzg5uDxoNBDbE8LpV67yhs/mC6945CfqmE/HgWhS82rerYeuZgIYAXm6ZN52pqHFrowF9Kc/NxJzoKbOst4N8JtPwlTFrP7QX0wFCe7vB5ibPe1ssKX0rYpF5A1Uuabi48xxJ/GE0s77m9gL+1kvJnNi5+9HnpjyegKDjfcpy7MOVKGj40qs63HE/aiO59V0hI24czJsKilactbR/OdN0WMH0N+uXWGQBPdQee7ingpynnqe4AgJdbZ5LphET3WJldAQTZtj2aqLUUVQA6NwlRpaoAum4LtH+kx9CFtpnMrgA0j15oS2V4dW4KIIj2j4xR1bkpIJ6K+rtCok/e2TpISMfHs2K5bv3V8aWhizDLEdLx8Sx9vcQwd0VRLrbPXmyfpQ0zuwIp0TOzK9C5KRDyA6rauUnXoXNTgHlH+IgNXMHy7xZi8WTnPmh/MmsOtf4aouPWfeINecfHsxYT5OHVces+aqukQYdjv5QBQFU7bhUUMLx9FdkgYVzaY2lqdX5ywlDjjvzVQftP8vki2PnJCZsz034HAT7sC/mx0mE0kets7cgH2EArn2hq89BRVao/by82iPSgM5TOTueC2m7JB0x+7ZQVEtL1V8+NmDTabtGjyv68xF7ij4r/JgGzW/DL9nxT+aIapq5xNjsLlK6uOWc9n2jLA3Cpa6715jxWZPbQtvtvDuWvNlpvzqMuiWtGkb2o3TiXnNrfgCjWVCbTBIg2BWcTjIbzu8K7AADdCnr+zvRouSk8wlQVVF0A0JulIy035Qn3Ign1eqV7DsCWVmYWHhC0PF64HFFIDAVVtfXmvKjusK61jdLTczJBEZE037iXHZmtkr3/cH9Er2m+cS+9muNS3k6vx1v2Gkou2/CIs15MHyCaSs6maYrS23sqQREWNN2wBzBZIg/+08NBvaDphj3U4vY1Z12gX1HWfX/RvMeBYr/ttatPpFaR+jiYZjSUgwcTFRGTxuv3sCNVBSF9//J8RNdpvF73h039WZeIn5aw7q7bSsP0f1RdScBrXDGDJtHKnaH09Z1OXIpNGjbuBtD/7+SN6CING3dTu9vRnzWG+btN0SRQ+0QmeNctxucCzR360C4Nl9TASncaNu6ON6rE9pHujNYrrMI9Z5uMxYeLFfTxshr/X+GqZeDT+TisRYh5e9XkF8Xrf7yLu3bg0/nIqoaNuw3liTDw6bw+oqYt4p2gJa6+6CcB6n6kO8zCtuZV7F2JeLo4ZfCzeaaqqoKQwc/m3R1CZixvIGTo84Vo0RO1SlVBQ1Nj6PMFfuy6p4Y+X6j9Ya5HwmXGcpOaH+Q6SFd6L8Mv0QHc8dYCE2H4PwteCJcZyzWqv7+Tx8fIF2cMdmW1ZlUiI1+cYY0pwjbIC09ZK5MIMmO5DSGjXxq9VfW9nXYyGa8d/fKM3jG8Kl2QGcs1xr5arLwuBxaphZCxrxYjK1lH9scBxuqxrxbpQXo5SmYsNxn/ehEREVBxbY79L7Arr8uhQsQSLjmN2BDzu3CJOxAy/vVStMrxr5cqrs2m8VdxbY5eoW/q08xNMmN5S/k12TbT1aFvlsqvyQZMXgk59M1S2rlJ7rG8hxAAE98ux7T0xLfLAA58N8tQmI4ukhnLWw7/dxlA2Xey7NuZduGkqYNkxkoGR/73/Hozs8xYEk+QGUviCTJjSTxBZiyJJ/wf5rD5cB5CUWIAAAAASUVORK5CYII=\n\"\"\"\nPathBaseOrthogonal_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAGx1bi4gbWFycyAyOSAxOToxMzoxOSAyMDIx7RzH1gAAAY96VFh0RGVzY3JpcHRpb24AACiRVZLLTsMwEEX3/QrL+/oZaB05QTyEhEQRooDYmjAKhsZBjkvK3xOnTcFeRLozd45nxtFnu2aDvsF3tnUF5oRhBK5q36yrC/z0eD1f4rMSzfTq5uIcDV7X5bvOFvg9hK+c0r7vSS9J62sqGOP0ZXW7rt6hMXPrumBcBRgN/ty1d6aB7stUsM/ftpUJ450H0scWfA1u7i3UsCEOAl3ZVzN+BNl1bxg9T20KPLSE9LOFvpwhpFcmeLsbQvEYzgvMiGBKsgwPUkTJxhOlTGVW4DkjSp6K5QIfCIInHiESoEgJIhI4WSwEV8uJIFOCTHuQMpYwTtTJqRKRKfdtxHymJkiWQrIUkqVtZNn4fHsZAXRYjaaHHel1u/UVjNu69GBC68sn9+na3mk6BY7JYclXJkC52TqCGuM7JBTiKucy5woJJvihaDL+Vbp6/dMFaMprD3B5foUY4WpyH5PRf298uNs2r/Cvk3+xaHmAbxtfvBwG0/So4lzTPJrGP7Oc/QLm/cF0GibyEAAAABB0RVh0U29mdHdhcmUARnJlZUNBRGMaYs8AAAAqdEVYdFRpdGxlAEM6L1Byb3Zpc29pcmU0MDAvUGF0aEJvdHRvbU9ydGhvLnBuZ1hkEN4AAA0JSURBVHic7Z35cxtFFse/SuWn+VOWpWBLWRYcFggsy8YkkDhYiZ04JL4ly47v+5DkI75vy47ji5DEjmzsJLAJBDaBbEFxmV0W2P1P+uf9oUet1mg0mhlppJHVn1Klenp6Xr9+/fz6mCOOI0cqIRCkmsMOhyPTOggOIMKxBJZw+NAh4ViC1JMdEeubhmBsZt6UJ/2aCHTiyMurybQOWnxdvwAAkqRyjhAAR6dtrX/O4nj5ZW+mdYjLP+vmZZciROV0+NSfZ+3bhJzFvkPh09o53qtematVniWEFlA04WntHE0oLhEY5WntnGkb2texZAh5db4OgELNV+frvvLOAoAkPa2do2UAfOWdZe5o96bZG2pe0za06arwiWeGzaviaXgseOWJZ0a9DCGQpK+8s8eCV6xU88Ai258Q0+5h+4il+Ufz+mJ9uAwAPHZPU3PouVagB/MRy9amJ+SNpQbzCkrSY/f0G0sNqVQpB/hH9RRLP3ZP04RRM9p0KGSYU+/N5cbPKyfpYGrzBtoUOg9huzzGx8SMRaxHFRP84V+vN6kW06/eo4oJZgj+KluHZNtCV9xJTCoy41iflY8r9jwfVUy8tdIcW9KweoS8tdIcuUiSqOTPysdVi6tWmuPw5mL2MdoPGRgKH5aOqWx7StJn5ePH11qiiqpmRouKPUtbdHythVUkt1Ft+553OI2KcpasWRU+uDzKYmz+eqsi/2HpGJ9J0dbwYemYnJIkEJK/3qosLkmRMrFw3qZae45j2j0OOdILq/jtjTbVfHr49kYbi2cJpEXHIf4sLyQCIeo/AJL04PJoypucjaja0xgnTrSbc0kTfHxxWDElVCJJIOTkjfZIYYDlKEUhcrswwS3FsN/Ek5awulyD9ZRpU2Ri8q76qAIHVemdDzvul1yFJEGSZDdSlRM9UYtbo54FTpybj7mMaVNkwrE0IhYArjHv3uy8d2EIiO8xhETKaAdCNfk8ETnCsTjMO1ZG9g9P3+5S5HTfHWTpXgyx9P59OEOc00RHqdO3u+5dGGR+EysWwF5xWHI4ICVosiTduzCkKioHyZpVIQBI0l7xYMFmN4CuvQGa5wxFzu+7oorzh84QAUCvBb+5QkjBZrfOpuhpsghaQFRPGSWtjnVmq+ejc/00bOwWDSgciM6Ezmz1oCAqu3O3n6XpJV0YGCroAcCkIb4ryJVyCMfSRTjA7xYNADiz1WPoaguHwm1XQJFTGOoFsH+CAHCG4AzJOduugMZDMsPv9bJ0+44sU/a2c5FiiRsSnsLraXLO3mHc2QkAKDzUu+0K8Mttu9wrDBX6Y2fc267AvgvOEPZd8mxJdr6w9q7tPm11Rgr7aKJt2y9nEQJA+0LXdl+o0M9vjCXUP6ciVqjQHzmQh5FwUDBiNB5LHOvOe77Y/SrqUs4Qzu747oR8UWcJAXB2x6dfl1GXD0Cry0cP2+AfDafjYuTJ0pxyLCB6VcQ91HB2x0eTmb9XuFnQx7yqaFf+U2je6nOGwB5KZPk8hw4Zrmv8nJ8KB9Aa8rEcbRI0mZCiXb8JZbIUvr/oFJaukJJ86Cj1t3SY6OK9AM2hHV+8J4/ZmwV9qa1xoigwUSSH7uatvuYtFfl8m1WFyPaNX+CgwsxCvWqiKFC8F5kcm+6sFA+Ft071sO65fTo86T4NALcRmYOntlLKZHE/gMbbPQCaNnvpoSpatRNy/m5/rg2DFDr3pcY5f7f/1qme83f7YXwQpFi2KpQksAXgJ8pZvHVrrukLAwDqb3ZTD6OHCm6dUls5J3p342ATHgRxC7JxSu4PJDMfcJSUDCYupZsbJ7u07geHufhxKitV5cqH8tb5TMlglGIaEJIGxWzIjZNdoKsrPgQQgiR6ynHx4lDiUrr54EQnc6x9F2ZTKtwEdTc6aYLf2Y/H+59kWNtMQa0UZSJuYWjOLI5Ll64mrxnPen4H3Vm4/EApeT2/gyZiT1mHd0OudD5FLaWtSGcTLEW1U9bzO1iAMNdSy1aFkrSe38Hny7qGn0tJGwuXhxcuDwPwbnQkLp0IZvHkRdkEhCdYfGbpw2E9D1pqkOJVoWetbX89ElTXjnOPiYX/Aso+HUn/sitYOuJZa6tZb6fp5AWm1m52YO14e9mnsmVW/9bG8s211LJVIbvNFJ1Z8Wg0U3uPS+Wj1SutADxrbUvlo0lKOxiLx+qV1v01sL1r3p8M3VqNxVFREf9Fg0Qsv6n+Wkvl52OqZ2l+xqm63gLgmsGGR5rD3a2ySYsMEa/XlIGAkGRal/RQSK0sSfsnCHN8KrPqC+WrfDYZPZYrxyuXm6l7LVeqv2+oDjN91n7Q5tpfmlkrIruM9O8keoeo6ovxZBqXiqFQkkAI3bd1hoj78YT9b7StVE+ULzUBqFxuXqmeSFheht2jDfdBdg2Ii6838buM8lQ4/NKz+3GUHZLsRIfbPWn64uCxRn7XajUJUZmibLERMKC53GRCPE/ULwkea6SJeAUyBd9ZnieTrOGywpqNMkFS2w2yDEJi16vZwppnCkDZYmPZYqOe8sxwWgVsuR/BOqvmyynqVWueKYfDUfPlVMJGmSBlq8IN77TtB0B1NrzTl+brAZQGGza80zqvSmi39I+Sc6/IXwurfarVioXXGvAaADih/DJRCnVOdvJO5+wf1M5k01wjhg9qZwC8P3fl0nw9TSckod2SNKxJuMVTvALxngxASnVOzQZpZoyYam7UzV6crXt/7sqNutmEhW3qWAmrJiQyZzd0oUGEY0Xx4ZW5kpnai7N1NK1RUqdjTR+NfHW4/mstgSlEW7d9l7Jp00drqW4p7EZjjjWVp/yiOnV/3nwAGr6ZT1qxjHGzfv7CtBdAyUztzfq4DUloN9km3K7j9NHa9Fgmnm503nKzfj72NNU2heodcjig/wdAvpEsSfJbgeybguwHAwLt+bvVMH+rYR7AhWmvigXkzotvInCGiv6azVSeUmAKf7xuU3le9uPP7rug0GEqz2tFx5kaChXba1AO2AdjZLzduFA8WXN+ykvTirOTL3kBNH2rzJcJb6KyAhMv1qTtiyOTL3n5SElVpc8y0XyaEwUhTd8upFC1w+ZksSdZqQWbv4uy74HwKwDYbFoomqgBUDxZs9nEtTFyS0fr8ubvYrpKkiZerFGYK/Uo3r0L33Br/m5h/E81LD5FIERF1eRIevJOCA5KiFJlqzkI4Ny4p2iiZqs52PJ9cOyFyP86FrfhhLR8H4x30lpzSRKtnWUwhR0Oh0J/ioaqpjEZsQDcaQne+UFOH1y/krnTEjw75jk37gHQ2hLpM42GGzo1+ke5s1t/UPkP9EzAV8EGwbEXPK0/BGOrsKL7zEesAxylVAm1LrpG3QDOjnlCrYsJy2vYhz81csQNRBaP1MPafkwsPy6EtP24yGqgOuvRKrWYjFjOEJxwq55q30/CKPZmu20RQOGI2zXqpmkNEkasYSfnUtEfABs54k7GjKzqwhE3VZt1VtqiwWHAWFUaNwQAaqADHsm225YKR6rDfbYUv6CGHSJvBlCXat+X5Qw7q+nketjpZpnGcQAoHKlW0zBNvWN8HwvhT+zF+fawdfs09vnttMu9VThSrWqiWDvwOBxhByKk46eljp+WWLGOn5a4txiM/Xj51Kt22pe0tbLuZ3KO1fmva/FOmZKXfXzUcQ3AmatV7w1Xs0MenXMsncUMwVSKvd7uc6wc8Z6E7HZeKxiqAnDmatVuZ5RvaZiIPzX0hyo9xfRD14Bd/4541eDzVdz3TszINIGBiHV6sBIh+RHpXFsSarDXtQzg9GAl9TCE4u/txX7ETPOtfxNGZm8eDD5f1f3zMoCB5yrZ+qD75+V0OpaZy4RfKbjbvXxqoBLhexJ3u5Vd2POfZZaOnNL8woUhI58aqAR7R54QSNLAc5VA1Koznb1mco4lIlYs93quA3i3vwK0m8M52vT+oiwTeLaCJvQbmVaK8A3c3l+uMyHUpWgtaXYsXeXeCVTwh8Kv4nG/9zrC5qL9TXPUkaTAsxV9v8YUkB8E1VUjret+7/X7v8o5DgcUMtPfXyJiWcLHfSsATvrLEe54msPw/bbie6acjlP+31f4fpPPskzoMDKVT4XbrT8O6ynk95eftFqRgwjvXvRfhXsB8hzI90w5fwhCmKupwlxKXaYN0BuxjgA+36oTZQf+cYaU84lvFcAJXxmiHcLvW+37XZl8wH2PCoD/v6uqBqZCFJLt2RMOv3810zrkEG/3lanms+/zBP6n7A7VS/5u+15zBAJrmdYhR8nvLTV6yYPs6Szzz2MJkuRhf8RLjvfEdTK+WBb1VWb+F3uBgk8H1uOdytLuEY4lsAQxFAosQUQsgSVk6RdiBHZHRCyBJYg5lsASRMQSWIKIWAJLEBFLYAkiYgksQUQsgSWIiCWwBMOv2AsEehARS2AJYo4lsAQRsQSWICKWwBJExBJYgohYAksQEUtgCSJiCSzh/84pl2uIBqYTAAAAAElFTkSuQmCC\n\"\"\"\nPathCenterOrthogonal_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAGx1bi4gbWFycyAyOSAxOToxMzo1NiAyMDIx6AVREAAAAZJ6VFh0RGVzY3JpcHRpb24AACiRVZLbTuMwEIbv+xSW7+tjaOvIScVBSCtRtKIL4tako2BoHOS4pPv2G6dNF/si0j/zz+eZcfT62OzRN/jOtq7AnDCMwFXtzrq6wM9/7ucrvC7RTG9+3Vyjweu6/NjZAr+H8JVT2vc96SVpfU0FY5y+bh621Ts0Zm5dF4yrAKPBn7v20TTQfZkKTvmHtjJhvPNM+jiAr8HNvYUa9sRBoBv7ZsaPIMduh9HL1KbAQ0tIv1joyxlCemOCt8chFI/hvMCMCKYky/AgRZRsPFHKVGYFnjOi5EKslvhMEDzxCJEARUoQkcDJcim4Wk0EmRJk2oOUsYRxoq4WSkSmPLUR85maIFkKyVJIlraRZePznWQE0GE1mp53pLftwVcwbuvWgwmtL5/dp2t7p+kUuCSHJd+ZAOX+4AhqjO+QUIirnMv8aoEEE/xcNBn/V7p6+7cL0JT3HuD2+g4xwtXkviSj/7fx4fHQvMGPTn7EouUJvm188XIYTNOLinNN82ga/8xy9g/nmMF1A2hTQgAAABB0RVh0U29mdHdhcmUARnJlZUNBRGMaYs8AAAAqdEVYdFRpdGxlAEM6L1Byb3Zpc29pcmU0MDAvUGF0aENlbnRlck9ydGhvLnBuZ4n6U7AAAAxpSURBVHic7Z1pcxzFGcf/o/Kr/hqphFRxBFhSIeGoggLHYMkgIS2WsbAl65Z1WLKttY6VtLplW7as2zotGwlWIGMhy4RQgUoIIZVsIBBCCJCP0W/Ji57p6Z2Z1c7uzOyh7V/Ni1Z3T/fT/TzzdE/39Ep57LFqSCRuc0BRlHTLINmHSMOSeMKBvDxpWBL3kR5L4gnSsCSeIIdCiSdIjyXxBGlYEk+QQ6HEE6THkniCNCyJJ8ihUOIJmeWxPqi6bBl/cKEtxZJIHKIcPHg23TIAwO8qLwEAIdbJlP52MSPklNhEOXToXLplwL2Ki7pJUWpMZkmUvrCcflElNsmkoZBSAC+unDdE75aPgRAQcq/iIk/dLR/jGcy3SJywWz7mvEvTb1h3T45yd3V4td0szuHVdp4nSlrNk6W9CfuGuydHWcB5l2bMWyGlBWuBvLy9MgCIkpYNmoTcPTlasBbwWL6cgRBQ6twq0uyxtsuGubvaQ5IjNy9oeYS7hNmYdFru4oLHSo1K7hwfMsS8dKvDEONEEmlYzhF1tF02zAJmNdnE86Hw9rFBwGId4c7xocL1TjEmuG00PsbAy1HZbh8b5KUVrneyP82lSZKBdazwhp60eXjrsbZKBwAYhi01hhBmc5F8CsAXjllI17uDPDxY2KWGKC3a6BJll07LBSh1a47h/VCoCfrKm9087p2j/RG/0ZiGirphRcdWPw933h5AKSL51Bc2viFulQ6wKt452m8uxCCAxMwrb3bzruN9lbR1pOitsCQc5G98gbdDOAoAzLZ8O+qqQSxJRoqDm/5QSTgIYNMfivjV+I6t/pHiYEk4uOkPMe+tl2C1gi8aHCtNYkbJpz+GkdFvheGSPq7gTX9IT/ADbOxjzoy533hel5fg2yGglJlX4O0QL9BYgtXgK5bm3+xJolH7nr8DyJq3QkKgzaUAzUWZ8oRL+l59u3evQgRbGfP3AjgfVvNH8qlvx1iCGH6rWCiZkPjV5TbZsECqWYM+o4r2JaVbfRtFPcz43iruLd3qMxTAUwF9jFMNpRi8cDbxEpsjhsVieYGZsjiceWT0UKhC1JHrcmlIjF4vDB67HYI4PSQElG4UmUYobevGGGOERvzYCOu3x2kaIRtFPUwGCYC2jSCK1JmGc6vIUzzjtXf7uTWMH+sXk9YLgyBkvTC4XhjUc7LJlvmCvnujhq0u3w7hgywbdu0I5l3zsw7RLJyX5vlQyGY/b7zcXbY9YE4t2x5gb4ss9eaRLnMelqomUWpZjnpvtCdrXe++etw6M0eOhoyWW1E9n0FD4VqBceE74kfklja1IiTKaGLsD77+3iAvjYcRvZoSR2BCmPdiPqnlVtdE2eAe2d1qftZh0FfkVlQqV5aohYRwYShcK+hcK+iMep8nRF2jCuPEzpA+kEWPbid2hmKVaUhSywcQ20vrFWlce30IQPPNzuabnYbMXM61AmNSLqBalaYOrizeLVxNSVeRl5enOLxUUSgFpeW7w+W7w6BUXaYC8vIUFmO4yneHE6sCiHuXblPaNzZTJ9XN1Ka1jiQK3JfXjfwOw2zVF0bEbzWFBZKuxelQuPxCgFlVxb0RAIqChpVAZFUfAVdevFBxb4SliiRcLVXn43ayaVUoAKbLRwA0rAROr15g4WgxcnQoBMCU0rASEN2VQVPJb+m41bOsnPrldgAzFaN4H0uH2u0sqdvh1Pv8y8b42dR6o9+ZZypG65fbG1YCqnjRYucmvO3qvq3NR9cerr0VLh1qB4BDALCEdjHJrSoSxVDvXOVY7eJ5MOs/ZJ0nhyCEq6zqgzF8oEbv9RFvIjjyWNefPyd+waN+AGPasUmXVzDXO191EcD1589F/PDtWOfJCbQlQ7ZdsXBQPTpR/fuLbtXg0lBIhW+qTOe3MsewAMw/dxaEAJTtByjVOWdYNR9emn/urK4m4bO+68+fq/nwkiu1KLW11oePbTL7bBvftAGwKJQ2+2wbgLo/OCrfiUjWycJSvlnmnKJyri1qiQFqt7iiMjf3Cpfqxo1lETL7bFv9R+NuVZEAsQ5VQ+2++o/GUYdTs62Vc21LdemQMB3MPNPKAuyh4qqZeaZVXbty6Tid0wVSLiX7pJOjCgog5ftxQMz9RHY1fHyl4eMrLPNy/RUAp2ZbT822xi155pn4eTIcQF++Xq6/wuMbPr7i8v7p6dNXHdrm5NMtET/4LoqK5lob/+i0/BRwcqqFBVZj9Mbk02qGrGjO3qj6CgNCcyafbuHzB1faqDQ2TiR6z7WnmgE0/WmCh1XE0YdSnidbODHZDOCGqUOuPdXMn5PsahHHQmWGj5HcbqDS1HQt0Xsmnmzi4Yj2nXHzJ9fE+OZPEi42E3j9WhOAteg+mXiyifd71rVLVUq0GZlPsjBcbJ3TyTuXT1GUlj9P8vgsXR662TxZNtHIzOtm86Q5g8PuSjFXn2g0mxQAXxiisjguNi6ZyTugj3oRP858OoV99MXcrZYp1rSyiUZFUa4+0WhQ1dUnGtMtoy1Uq6IUlJ75dOrMp1P6sShCvG7FASdGGvHjjTNTCtD6l6msepLj8MaZKQCvXTl9/Opp/MYiQ+Y3dvzXp/nDL2on4ocvzI9FeSiA06HQ4e2ZzHrr9LHxBsN0pO2zaWSDYalQ2vbZNJP22HgDgPXWaR8aWKKnukvSY7E9po226Wzp4eTYaJsuvdwA7QNrWJnUpV+pejr71+nUSmeLy4+r4iEMANyqQMjlxxu8k9mRx9rH7orz5tkZH+oBq3P9HPcWrF1mz48D4KUGHc2xMrAnPcK3Q5h6jl6qf+vcjGWe1PfG2C/rWeD836xF2vvjAHgps/RYduFbC69erA+fnzVnSE9vxHOWbH1BFHj0sToe9k7mPEVBopcgVk5cIpvtswD8Y3WZ0Bt7VM1gbx6b7bPGJEIABCKzzmWIdR0AErPZktFahPnjm0MeS0PZbJ8rGa0tGa0DsNk+JyaN+GrFrIHIHFKEURGByBwXZsRXxyUZ8dUKO28eqk8JBGI2fvjR2lhJIhf+kbLuSw/Dj9by9Wve2OIRtXP0n82BxW6pp52jCiZIxSkeqeXnWbgw4p9eay3eHCv6qyb91/dYV2bs25CrdHw+P/RIjeFgyDsX5gG8MlwD7YXR+HUhIQCGH63t+HzeawkVRRl6pIb/yeZVrF413vT/GbzWmo23QqGzjL8Yo57r8EKwDIXpqfML1Va2OuZ9qIG2os3jAQw+XJOCBW5dKr7Jlk99YXR+Mc+qZSINPqyaHZfQa6lsvRV2/fM6gMLBagC3O68bUnPFsLQfiDM7ab4YUTRUY9U/UZkHflEt/sn61ikmZzn4cI1YMg+nTFm21rEMLyA5SPeX1/sfqhbGEWMG9TCx9vi926UrlWfuf6gaMM4uBn5R3f2lM9sSzhwA+lFhF0p2gC2PJebZ9zOqWAS/WuBhyz64070A4KX+KgAvD1RD+KAIQOjBKusf+iKk/6FqsfCEEazqTvfCna/0utKoLLse60ioCsB2cCFHzcoGrCe3gwuA2l3aLpCQidKef+k21PdAFbOt0INVYnwSsHqjtONGsUljy2P1PVClbWFWGZJ6v170QqxsROzJ93oWfahk4SOhKv7O2Pv1otjfvV8v9t5f6cS7MNt9r2cx1s3pcloH4mchRMmn7Md0jRuZsc7uSQAg6oAJs4De+ytdKbmgrxIAH20zEBsei9IfY/wuLXJ4ymUmVlfs9C75cAra8hIn6iklpPf+yr5/L+1dRX7vKUNM3J8MTZvHslNv6JuYDZZ2xYnVFSzeeDwOlk+pxe2He4zGBOBu3xIAZq8xq6Y09M1SuhSU8FuhJBaxekmM7//PMg+/GKww5DwMCxsS2Q2ptxtqEqvo/nmFZXyKSXgdS2JBrB0IU7wYvte/DKDrPtUODAOlIZt6e4z6mTENfLuslkYIKB34djmNipMeyymD/11hAUMnWcQT0nVfBY/XIQSUvj9gime32xGCEDAbFZbK0qs1aVipYOi71Y6fnmRLVp0/K9djEPMHpO0ibNrywNB3q0j3OCOHwhTC/0MCoNqZFj/8/WoSnTz8/aplfCboS3qsFDHyww0AgZ+c0KM0NzPyw43918HxFkjlEqirMPPKBfbyWKP/W2OB/fc8SbzG0fEviSQWKflHmJLcQ3osiSdIjyXxBOmxJJ4gPZbEE6THknhCwkfsJRI7SI8l8QQ5x5J4gvRYEk+QHkviCdJjSTxBeiyJJ0iPJfEE6bEknvB/306Rt9BxsccAAAAASUVORK5CYII=\n\"\"\"\nPathTopOrthogonal_Icon_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAMgAAABaCAIAAABylI6BAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAKnRFWHRBdXRob3IARnJlZUNBRCAoaHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZylLpZ5SAAAAKHRFWHRDcmVhdGlvbiBUaW1lAGx1bi4gbWFycyAyOSAxOToxNDozMSAyMDIx8rE5WwAAAZF6VFh0RGVzY3JpcHRpb24AACiRVZLbTuMwEIbv+xSW7+sztI6cIA5CWokitF3Q3powCt5tHOS4pPv2xGnTxb6I9M/883lmHHN1aHfoE0LvOl9iThhG4OvuzfmmxM+/7pdrfFWhhdn8uLlGo9f3xaF3JX6P8aOgdBgGMkjShYYKxjj9vXnY1u/Q2qXzfbS+BoxGf+G7R9tC/2FrOOYfutrG6c4T6c8eQgN+GRw0sCMeIt24Vzt9BDn0bxi9zG0KPLaEzIuDoVogZDY2BncYQ+lYzkvMiGBaMoVHKZJk00lS5lKVeMmIlpdivcInguCZR4gMKHKCSAROVivB9XomyJwg8x6kTCWME31xqUViymMbKa/0DFE5ROUQlbeh1PR8R5kAdFyNoacdmW23DzVM27oNYGMXqmf/13eDN3QOnJPjku9shGq39wS1NvRIaMR1wVUhORJM8FPRbPxf6Zvtvz5CW90HgNvrO8QI17P7nEz+Jxvi4759hW+dfIsly0/4dOnFq3EwQ88qzTXPY2j6M6vFF+QPwW8+lcBxAAAAEHRFWHRTb2Z0d2FyZQBGcmVlQ0FEYxpizwAAACd0RVh0VGl0bGUAQzovUHJvdmlzb2lyZTQwMC9QYXRoVG9wT3J0aG8ucG5nLOG9wgAADL5JREFUeJztnflzHMUVx7+z5Z/6f0hCqMQFJKFStYYEElKYMhRxhGMbS2Bj2da1uiXrXN3a1WXdh23dpy3ZwitjO0YBCiigMASSoKpc5DC5IKn8Cf1zfuiZntnZmdmd2Zldabc/pZJHfbx+/d7b1zO9M2PpwIEABAK32SdJUrp1EGQgIrAEnrDP5xOBJXAfkbEEniACS+AJYikUeILIWAJPEIEl8ASxFAo8QWQsgSeIwBJ4glgKBZ4gMpbAE0RgCTxBLIUCTxAZS+AJIrAEniCWQoEniIwl8AQRWAJP2C1LYcedfrOqvqPtqdRE4ArSsWMdaRy+/XZfIs38EePy45vpVF5gQdqWwrZbvdo/B453GjZ77eVeADt5+nL/NgFw62Tfi68adxSkF+nEia4UD9lys4cfD1qOvpXXA0IAgNLY2p08+LcJKM2NpHoKGczNmz0Ako+KlGas4FaYHw/ldgOwGDuSG9ZGVd5Wt06UP4KdHApgK9LDayO56hC6LoJE+AwAMCRJACK5Ycc2TF1gNUdC7GA4LwRAAm6ckEteuhky7UYpq9WpOZwXugG1V3ArzMQC4OEoLnjtwnw0nBeKKK5xbMMUXRU2vtoNYPTlMAAfsHm8G1AiQImwk7fUZLN5vJvXmml48lZ4M6J+nuTAPQEAoBSE3DgR0soUJIhscEJAqePwSEXGatjsAjB2soeNdP1Yl/7MiRAAm8e7T93uie1uoaHa/iQaNrv8EezkwR9RT8hE0kocnZsYzjNWakw/fqqXDXPtaCePqlfuyBeG1452AgAh14918ULeJkEFx0/1XkP0FWKsQEE8JEmS3QGAZQEAgF0zersUnt/oADB5us+nq6A0/26fTynNv9u3fkTekdLpY1c9dp3I8tZOHvwR2xKyE72n2IdfORtxsCb6JM9guk7l9/OS9SMdXFddYyjzWT/SoU2iiQ+nFT6V3+9AQjajtRWLJPk3+7FvRq+WwpqrbQAunhkwkE4pgKsvxHxRQymLDCk6sOwNTOnZ7QHWyb9NdnLo1Ug7S11mnN0esDdExqFz1tntgSs5bVCO2YFdP3iyFFattQK4fO6CfgVk8ARrgqoSIVdy2greuGDWcvVwK6tdPdyqu4oseOPC6uFWtjJaj8uNaDFQNmAYCbvoqrBytQXAdMGgqVyjbXQtOpWsNVw93KqVXPjmoL45Iew6cSeHRsWZUssDbvVwa+Gbg9a6ZR7W/nIcHi4HVsVKEMBM4ZCVUEJAadFbQ7ri5eeD7ECSpKK3hpafD8aujGbS+F/axlohjJ0c6o9AOzQflEXYyk9bYhXLBsyM7DywvFgKzWSWvD28+Fwz87SuDS/XX4AQsvx8sOTtYZ2oxeeaWS1vxv5VAyUGdsoFoGIlOFc8zFWKUsBkuEylbKkZwFzxsPFJyy5ZCksXmwDMl4xwiQvPNvHawDsjalNCFp9r5iULzzbxqAq8M8I0CrwzIpcTIoeRjtjvp83O3pSsxpfCsqXm+ZIRfTOjq4dswGK+jk0hBQKjTvWJIrDQCGBBkTZ/qBGI9jSlAErfHZ0/1Gi48w5KS9/VK2MgRwulqkCLUzdWqxmFaatVWB6LEEM1MhKty2Q7a0nOFC4vhUza7DMNxumE0vlDjeXvjc0+0yCXMJRmscrIjU2Cpvy9sflDDVxO+XtjsW3ksaAmJJ9PWiobK55rABBYaFwqi+5FCFMysRnveXw+SfUXR9m+SvNSWDRbD2C5fFwCZg7W86iqeH+ct5HLKZUkiZXPHKxnVbyZoS5aITrU9pRWvD+e4FTYlJfLx5nmxXMN7Di2TQbDXTar8VdUC0JAKf9YWnjBEDfPsaJEUVr5wYSBbEJmDtZXfjABgP2G/c03zvTTddqtfMM2lR9MTD9dZ6bnSsVE4UwdszIOGrfJPApn6gCsVEyok6SUuwPMsCzBK7/tGsTn80lJ/jAt16om2Z8a0VHNqj+c1C55rvxEzyReM+U8TFe7VjVpZBd3NNydP9o5Gk65+sNJFm38t90hks1YZy/VArhSPcWkXHyqlqeQSz85b9bLzXxAKYCae1MWImvuTV18qpaHdezoV6qnAPhRK2+iZnTG0rlMhhCtv2ruTdXcm9LW2/5KxxUL2hCifKOZ/KAAaj+6qCiQQOvE7ixlm6gZHFgMPsHajy5O/bgGiLr0vvhULTTmdUBSgZU/VQ1gvfaSoYjzH18y65her1lMmd91cwY167Wm+u9dDF12/uNLkz+qjtr9IQQACzgLP1rgQsbSSqj71eWJJ6vMthknnqzizZIcNBkMp8zV5uRPVW+cT6eernN6sgrAxvnLsfPXekR2Ewsvp48O7HMcV69MVAG4VmegJUMnefyJKs1i5HBQV4gdffwJOeJBaf0nl1EHAK9MVJ2erLpWl1GxBUO/AADqP7msPeD+cuasZDOWaXdCmMYNn04DGPthJY+qhk+n0xtYahhxNLmKz+h6/fSp8Ur2+bleP50q7bzi1HglgOv10wa2t8xMziJEamhwYrKTY5UANk36jv6gUr+rrkRV46/T46EolQyhFECsemymMJ/snsDCX6plYjdI4dxlUmPjjINuL49WwOSVCk2/mQEw8niFWVVaMNRHi7VubL6vKrYaebwijXOxi055GFoj9lNHKZJwmdTUZLvnSyMVAG40zQw/VqF++6tJUc2/3TNGTxw2a/5Z2kNz5P4CMPxYBRATRiZfxSYzR+fnWPqOinLBz2Yzcg8o0jybN1wO9s6IvbPRxXSONM9KwNCBcuObAwgBpcHPZnV9k5mi86tCtSMhoLRlZzZ5bXY5W8FZP8rZ8Z6YZu5QOYCt4GyUshpnARj0l7PYGjpQri1Pkn2WL+YwIHeoDMBWcE4torRlZ860Q6Yw6C9jB2wTddBfDmA3T1znqUF/mZIConRu2ZmTqwC7wWCBw4yl67UnPr4uoLkTmn3zkztUdrNlN8bWicEyADdb5mI9wz8hsbjoR3vnWC9eKAXwWuu8rs9eOeFIFn6ZQik/i2cufK11Pn1q6TFzExDn2TsX/egkY8V2yYa4av/dPID+75dq/0Qbjg+UAnjxQumttl0RW0yfW21GUYU4z96lJ2Md6w8AuN2+ENshWzKWBj7l2+0LAI71B5hHeSbr+P1C6rWy8BHHQjF3A8teB8P22RdX+inf6Vg42hdgx8p+REr14aPf6bCKKhg5q/dRuW/nH1z7MNjexzJsn80Zi/OLzkUAfpSwP4/2BVhJCvh5bwmUZOlHoOuP5uMS0vuoUYMkbmQwJNGMdaSnBMDdrkXD5tkXV1ZT5k8vMn/f7fI2vLhr/ChR4sOgWfefFsPfLWFbVj3fK1FLoJ7Rp+2q0PUHsfcucaf8evfSC+FiKI5/vXvJdR2YfCZcq42VbuzhCEIAyHEG+Yw+9PmSm4GVSKNwuPgFs7p4b/jIZl7vXgp9R/a9H8U7ea6FFw8p2AnZ0OdLALhKgOo+VuUiiWasA0AotBx6pMiwNkpXIPznZRdU293EtZtsE2WVYRuqyFMNtR2ybaWcUJT9mQS7F+mG3nF9yUnoHCsc1qgS7+1Wab9BNDV0P1IEoOcv5sHB7vtQUgJ7+Ie9wJLBoiT21iOdzJ91G3yYfxk2DimGJKHr4aheVnp6g6O7G2y+4CoDifvADyGgtPevK7yg86FC1uuNnhW1RPnfXFh4seOuSBGM/pcXbV9r+3Y9XKT7/Hc9XKRVJgU4/K6w729WWmZ4XPH3i8SbqeGD4J0PFarW4y+Fiw4vbRp7s1c1daJ21b0ihRD9uN7j8H6szM9JJvTfXwXQvr+A/WlqB0r776+aVUqS1L6/gEdn//1V9AHAW/fRvr/AH5EDjo1l29CEsNF5AR8rlV4TgeWEgS/W2IGFGRJ66RSlA1+saRsOfLHW9u1zcSXERdtXlklI+/4CrrnXuHPbjCAWy5hTj3kY2ZJgBaUX/r5mniwdybSPw4zV+q1zZlWD/7jiXJ0MIqGM5c1NLF68oc8uCW2Q6rEwh9gvtUXmmsv97YYsP/3iJJg2hv55VVcbfPAMK0/icYRdkLGcDTT8L705OCKuGAmeYxk3IyT44BkLI7sytKeIq0KvSPAcq/mbZ0b+vc6rmh7Ij/uOwjh4IdM+4qrQA+R3gBmXs6rRL9cbv5HPti6bHshX2yh7+qNfrju+KnRfpn1ExnKZsa822IHOQrycV419tdHw9dOAwXPJY19tJGVgzXcDrsm0ichY6WT8PxsA6r92Wlfo3LyUMgluynSEyFjpZ+K/17R/OjYtlyNJrsl0jMhYAk+w/Yi9cgYqIktghb2MNfW/6+xAZCyBNSn6X+wF2Ybz1xgJBBaIjCXwBJGxBJ4gMpbAE0TGEniCyFgCT/g/kK9vUz+IRxwAAAAASUVORK5CYII=\n\"\"\"\n####\n\nhomeIcon = [\n\"24 24 14 1\",\n\" \tc None\",\n\".\tc #EF2929\",\n\"+\tc #A40000\",\n\"@\tc #DDDFDC\",\n\"#\tc #888A85\",\n\"$\tc #DDDEDB\",\n\"%\tc #DCDEDB\",\n\"&\tc #DCDEDC\",\n\"*\tc #DBDDDA\",\n\"=\tc #BABDB6\",\n\"-\tc #555753\",\n\";\tc #729FCF\",\n\">\tc #3465A4\",\n\",\tc #8191AA\",\n\"                        \",\n\"                        \",\n\"           .+           \",\n\"          ..++          \",\n\"         ....++         \",\n\"        .....+++        \",\n\"       ....@#++++       \",\n\"      ....@@@#++++      \",\n\"     ....@@@@@#++++     \",\n\"    ....@@@@$@@#++++    \",\n\"   ....@@@$@@%@@#++++   \",\n\"  ....@@@@@@@@%@@#++++  \",\n\"  ...@@@%%%%&%%*@@#+++  \",\n\"  ..@@@@@@@@@@@@@@@#++  \",\n\"   #@@=#---@@=====@#    \",\n\"   #@@=#---@@;>>>;@#    \",\n\"   #@@,#---@@;>>>;@#    \",\n\"   #@@,#---@@;>>>;@#    \",\n\"   #@@=#---@@-----@#    \",\n\"   #@@=#---@@@@@@@@#    \",\n\"   #@@=##--@@@@@@@@#    \",\n\"   #################    \",\n\"                        \",\n\"                        \"]\n\nhelpIcon = [\n\"24 24 4 1\",\n\"   c None\",\n\".  c #016AC5\",\n\"+  c #F8F8FF\",\n\"@  c #FFFFFF\",\n\"........................\",\n\".++++++++++++++++++++++.\",\n\".++++++++++++++++++++++.\",\n\".++..................++.\",\n\".++..................++.\",\n\".++......@@@@@@......++.\",\n\".++.....@@@@@@@@.....++.\",\n\".++.....@@@..@@@.....++.\",\n\".++.....@@....@@.....++.\",\n\".++.....@@....@@.....++.\",\n\".++...........@@.....++.\",\n\".++..........@@@.....++.\",\n\".++.........@@@......++.\",\n\".++........@@@.......++.\",\n\".++........@@........++.\",\n\".++........@@........++.\",\n\".++..................++.\",\n\".++........@@........++.\",\n\".++........@@........++.\",\n\".++..................++.\",\n\".++..................++.\",\n\".++++++++++++++++++++++.\",\n\".++++++++++++++++++++++.\",\n\"........................\"]\n\nexecuteIcon = [\n\"24 24 3 1\",\n\"   c None\",\n\".  c #4E9A06\",\n\"+  c #FFFFFF\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                  .     \",\n\"                 .+.    \",\n\"                .+.+.   \",\n\"               .+...+.  \",\n\"              .+.....+. \",\n\"     .       .+.......+.\",\n\"    .+.     .+.......+. \",\n\"   .+.+.   .+.......+.  \",\n\"  .+...+. .+.......+.   \",\n\" .+.....+.+.......+.    \",\n\".+.......+.......+.     \",\n\" .+.............+.      \",\n\"  .+...........+.       \",\n\"   .+.........+.        \",\n\"    .+.......+.         \",\n\"     .+.....+.          \",\n\"      .+...+.           \",\n\"       .+.+.            \",\n\"        .+.             \",\n\"         .              \",\n\"                        \"]\n\nquitIcon = [\n\"24 24 3 1\",\n\"   c None\",\n\".  c #FFFFFF\",\n\"+  c #CC0000\",\n\"          ....          \",\n\"++++++++++....++++++++++\",\n\"+.......++....++.......+\",\n\"+.......++....++.......+\",\n\"+.......++....++.......+\",\n\"+...++++++....++++++...+\",\n\"+...++++++....++++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+......................+\",\n\"+......................+\",\n\"+......................+\",\n\"++++++++++++++++++++++++\"]\n\nresetIcon = [\n\"24 24 3 1\",\n\"   c None\",\n\".  c #3465A4\",\n\"+  c #888A85\",\n\"                        \",\n\"      ........          \",\n\"     .++++++++.         \",\n\"    .++..+....+.  ..... \",\n\"    .+.. .+....+. .+++. \",\n\"    .+.   .+....+..+.+. \",\n\"    ...    .+....+.+.+. \",\n\"            .+....+..+. \",\n\"             .+......+. \",\n\"              .+.....+. \",\n\"               .+....+. \",\n\"  ......        .+...+. \",\n\"  .++++.         .++++. \",\n\"  .+...+.        ...... \",\n\"  .+....+.              \",\n\"  .+.....+.             \",\n\"  .+......+.            \",\n\"  .+..+....+.           \",\n\"  .+.+.+....+.    ...   \",\n\"  .+.+..+....+.   .+.   \",\n\"  .+++. .+....+. ..+.   \",\n\"  .....  .+....+..++.   \",\n\"          .++++++++.    \",\n\"           ........     \"]\n\nsetIconNoReset = [\n\"24 24 4 1\",\n\" \tc None\",\n\".\tc #A40000\",\n\"+\tc #3465A4\",\n\"@\tc #888A85\",\n\"                        \",\n\"      ++++++++          \",\n\"     +@@@@@@@@+         \",\n\"    +@@++@++++@+  +++++ \",\n\"    +@++ +@++++@+ +@@@+ \",\n\".   +@+   +@++++@++@+@+.\",\n\"... +++    +@++++@+@+...\",\n\".....       +@++++@.....\",\n\".......      +@++.......\",\n\" ........     +........ \",\n\"   ........  ........@+ \",\n\"  +++..............++@+ \",\n\"  +@@@@..........+@@@@+ \",\n\"  +@+++..........++++++ \",\n\"  +@+..............     \",\n\"  +........  ........   \",\n\" ........+@+   ........ \",\n\".......++++@+    .......\",\n\".....@+@++++@+    +.....\",\n\"...@+@++@++++@+   +@+...\",\n\". +@@@+ +@++++@+ ++@+  .\",\n\"  +++++  +@++++@++@@+   \",\n\"          +@@@@@@@@+    \",\n\"           ++++++++     \"\n]\n\nstandIcon = [\n\"16 16 9 1\",\n\"   c None\",\n\".  c #010400\",\n\"+  c #28090D\",\n\"@  c #4C0000\",\n\"#  c #770000\",\n\"$  c #AE0000\",\n\"%  c #262826\",\n\"&  c #CB0000\",\n\"*  c #FD0705\",\n\"***********     \",\n\"***********     \",\n\"**  ***  **     \",\n\"**  *...........\",\n\"    *...........\",\n\"    *..  ...  ..\",\n\"    ***  ...    \",\n\"    ***  ...    \",\n\"    ***  ...    \",\n\"    ***  ...    \",\n\"    ***  ...    \",\n\"   ***** ...    \",\n\"         ...    \",\n\"         ...    \",\n\"        .....   \",\n\"                \"]\n\nflatIcon = [\n\"16 16 9 1\",\n\"   c None\",\n\".  c #020400\",\n\"+  c #2B0500\",\n\"@  c #620502\",\n\"#  c #770301\",\n\"$  c #970300\",\n\"%  c #B40100\",\n\"&  c #E60002\",\n\"*  c #FE0004\",\n\"                \",\n\"                \",\n\"                \",\n\"                \",\n\"    **    .     \",\n\"   ***   ...    \",\n\"   **    ...    \",\n\"  ***   ..      \",\n\"  ***   ..      \",\n\"  ****&#...     \",\n\" *****$+.....%  \",\n\" **  &.+%@...@. \",\n\" **  ..#*&%@....\",\n\"**** ...  *&$...\",\n\" ***  ..   ** ..\",\n\"               .\"]\n\nromanIcon = [\n\"16 16 5 1\",\n\"   c None\",\n\".  c #FD9806\",\n\"+  c #FD9904\",\n\"@  c #FD9905\",\n\"#  c #FD9906\",\n\"                \",\n\"                \",\n\"             @@ \",\n\"         @@@@@  \",\n\"     @@@@@  @@  \",\n\"  @@@@  @@  @@  \",\n\"@@  @@  @@   @@ \",\n\"@@@ @@   @@  @@ \",\n\" @@@@    @@  @@ \",\n\"  +@@    @@  @@ \",\n\"   #@@@   @  @@@\",\n\"  @@ .@@  @@@@  \",\n\"  @#  @@@@@     \",\n\" +@@@@@         \",\n\" @@             \",\n\"                \"]\n\narabicIcon = [\n\"16 16 5 1\",\n\"   c None\",\n\".  c #F6972B\",\n\"+  c #F6982B\",\n\"@  c #F5972B\",\n\"#  c #F7982B\",\n\"                \",\n\"                \",\n\"                \",\n\"          ..    \",\n\"   ..   .....   \",\n\"  ...       ..  \",\n\"    .      ..   \",\n\"    .+     ..   \",\n\"    .+    @.    \",\n\"    .+   #....  \",\n\"    ...  ...    \",\n\"  ....          \",\n\"            ... \",\n\"     .......    \",\n\"   ...          \",\n\"                \"]\n\nredressIcon = [\n\"16 16 4 1\",\n\"   c None\",\n\".  c #010400\",\n\"+  c #000000\",\n\"@  c #FD9905\",\n\"                \",\n\"                \",\n\"..   ..+        \",\n\" .     .        \",\n\" .    ++  ..    \",\n\" .   +     .    \",\n\"...  ...   .    \",\n\"           .    \",\n\"   @      ...   \",\n\"   @            \",\n\"   @   @    ..+ \",\n\"   @  @       . \",\n\"   @@@       .+ \",\n\"   @@         . \",\n\"            ..+ \",\n\"                \"]\n\naxialIcon = [\n\"16 16 4 1\",\n\"   c None\",\n\".  c #000000\",\n\"+  c #010400\",\n\"@  c #FD9905\",\n\"                \",\n\"                \",\n\"++   ++.        \",\n\" +     +        \",\n\" +    ..     +. \",\n\" +   .       +. \",\n\"+++  +++    +   \",\n\"          ++    \",\n\"   @       +    \",\n\"   @            \",\n\"   @   @        \",\n\"   @  @    +   +\",\n\"   @@@     + + +\",\n\"   @@      .+.+.\",\n\"                \",\n\"                \"]\n\nsetIconDel = [\n\"24 24 4 1\",\n\" \tc None\",\n\".\tc #EF0013\",\n\"+\tc #EF0113\",\n\"@\tc #FFFFFF\",\n\"                        \",\n\"      .           .     \",\n\"     .@.         .@.    \",\n\"    .@.@.       .@.@.   \",\n\"   .@..+@.     .@+..@.  \",\n\"  .@..+++@.   .@+++..@. \",\n\"   .@.+.++@. .@+++++@.  \",\n\"    .@+..++@.@+++++@.   \",\n\"     .@++.++@+++++@.    \",\n\"      .@+++++++++@.     \",\n\"       .@+++++++@.      \",\n\"        .@+++++@.       \",\n\"       .@+++++++@.      \",\n\"      .@+++++++++@.     \",\n\"     .@+++++@+++++@.    \",\n\"    .@+++++@.@+++++@.   \",\n\"   .@+++++@. .@+++++@.  \",\n\"  .@..+++@.   .@+++..@. \",\n\"   .@..+@.     .@+..@.  \",\n\"    .@.@.       .@.@.   \",\n\"     .@.         .@.    \",\n\"      .           .     \",\n\"                        \",\n\"                        \"]\n\nsetIconCommand = [\n\"24 24 5 1\",\n\" \tc None\",\n\".\tc #A40000\",\n\"+\tc #8F5902\",\n\"@\tc #C17D11\",\n\"#\tc #EDD400\",\n\"                        \",\n\"            #           \",\n\"           ###          \",\n\"            #           \",\n\"   ##    ++++++    ##   \",\n\"   ##  +++@@@@+++  ##   \",\n\"     #++@@++++@@++#     \",\n\"     ++@++  # ++@++     \",\n\"     +@+#   #   +@+     \",\n\"    ++@+ #  #  #+@++    \",\n\"  # +@+   ++++#  +@+    \",\n\" ###+@+###+@@+   +@+ #  \",\n\"  # +@+   +@@+###+@+### \",\n\"    +@+   ++++   +@+ #  \",\n\"    ++@+ # #  # +@++    \",\n\"     +@+#  #   #+@+     \",\n\"     ++@++ #  ++@++     \",\n\"      ++@@++++@@++#     \",\n\"      #+++@@@@+++  ##   \",\n\"    ##   ++++++    ##   \",\n\"    ##     #            \",\n\"          ###           \",\n\"           #            \",\n\"                        \"\n]\n\nsetIconHelix = [\n\"24 24 5 1\",\n\" \tc None\",\n\".\tc #A40000\",\n\"+\tc #3566A4\",\n\"@\tc #729FCF\",\n\"#\tc #EDD400\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"        #++@@++         \",\n\"      ##.++@@++         \",\n\"      ..##+@@++         \",\n\"        ..###++         \",\n\"         +...##         \",\n\"         ++@@..##       \",\n\"         ++@@++..#      \",\n\"         ++@@++##.      \",\n\"        #++@@++..       \",\n\"      ##.++@@++         \",\n\"      ## ++@@++         \",\n\"      ..##+@@++         \",\n\"        ..###++         \",\n\"         +...##         \",\n\"         ++@@..##       \",\n\"         ++@@++..#      \",\n\"         ++@@++##       \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\nsetIconClock = [\n\"24 24 8 1\",\n\" \tc None\",\n\".\tc #C17D11\",\n\"+\tc #8F5902\",\n\"@\tc #BABDB6\",\n\"#\tc #EDD400\",\n\"$\tc #A40000\",\n\"%\tc #CE5C00\",\n\"&\tc #171018\",\n\"                        \",\n\"         .....          \",\n\"      ++........        \",\n\"     +...++++++...      \",\n\"    +..@@@@#@@@++..     \",\n\"   +..#@@@@#@@@@#+..    \",\n\"  +..@@#@@@#@@$#@@+..   \",\n\"  +.#@@@%@@%@@$@@@#+.   \",\n\" +..@#@@@@@#@$@@@#@+..  \",\n\" +.@@@%@@@@@$$@@%@@@+.  \",\n\" +.@@@@@@@@@$$@@@@@@+.  \",\n\" +.@@@@@@@@&&@@@@@@@+.  \",\n\" +.###%@@@@&&@@@%###+.  \",\n\" +.@@@@@@@@$$@@@@@@@+.  \",\n\" +.@@@%@@@@@$$@@%@@@+.  \",\n\" +..@#@@@@@#$$$@@#@+..  \",\n\"  +.#@@@%@@%@$$@@@#+.   \",\n\"   ..@@#@@@#@@$$@@+..   \",\n\"   +..#@@@@#@@@$#+..    \",\n\"    +..@@@@#@@@++..     \",\n\"     +...++++++...      \",\n\"      ++........        \",\n\"         ......         \",\n\"                        \"\n]\n\nsetIconPath = [\n\"24 24 4 1\",\n\" \tc None\",\n\".\tc #905902\",\n\"+\tc #FFFFFF\",\n\"@\tc #EDD400\",\n\".+...@                  \",\n\".+...@                  \",\n\"..+...@                 \",\n\"..+....@                \",\n\"....+...@               \",\n\"....+....@              \",\n\"@........@              \",\n\"@.........@             \",\n\" @....+...@             \",\n\" @....+...@@@           \",\n\"  @....+.....@@         \",\n\"  @....+.......@        \",\n\"   @............@@      \",\n\"   @@.....++......@     \",\n\"    @.......++.....@@@  \",\n\"    @@@..............@@ \",\n\"       @........++.....@\",\n\"        @@........++....\",\n\"          @.............\",\n\"           @............\",\n\"            @@.......+..\",\n\"              @......++.\",\n\"              @@@.....+.\",\n\"                        \"\n]\n\nsetIconProgress = [\n\"24 24 3 1\",\n\" \tc None\",\n\".\tc #3465A4\",\n\"+\tc #729FCF\",\n\"                        \",\n\"                        \",\n\"  ............          \",\n\"  .++++++++..           \",\n\"  .+++++++..            \",\n\"  .++++++..             \",\n\"  .++++++..             \",\n\"  .+++++++..            \",\n\"  .++++++++..           \",\n\"  .+++++++++..          \",\n\"  .++..++++++..         \",\n\"  .+....++++++..        \",\n\"  ...  ..++++++..       \",\n\"  ..    ..++++++..      \",\n\"  .      ..++++++..     \",\n\"          ..++++++..    \",\n\"           ..++++++..   \",\n\"            ..++++...   \",\n\"             ..++...    \",\n\"              .....     \",\n\"               ...      \",\n\"                .       \",\n\"                        \",\n\"                        \"\n]\n\nsetIconInDoor = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #A30500\",\n\"+\tc #555755\",\n\"@\tc #EF2B29\",\n\"#\tc #2F65A5\",\n\"$\tc #888A88\",\n\"%\tc #6D9FD0\",\n\"&\tc #BCBCB3\",\n\"*\tc #DDDFDC\",\n\"                        \",\n\"   #                    \",\n\"  #%#      @.           \",\n\" #%%%#    @@#.          \",\n\"  #%%%#  @@##..         \",\n\"   #%%%#@@###...        \",\n\"    #%%####%#....       \",\n\"     ##%##%%#$....      \",\n\"     @##%%%%#*$....     \",\n\"    @@##%%%%#**$....    \",\n\"   @@##%%%%%#***$....   \",\n\"  @@##%%%%%%#****$....  \",\n\"  @##########*****$...  \",\n\"  @@***************$..  \",\n\"   $**&$+++**&&&&&*$    \",\n\"   $**&$+++**%###%*$    \",\n\"   $**$$+++**%###%*$    \",\n\"   $**$$+++**%###%*$    \",\n\"   $**&$+++**+++++*$    \",\n\"   $**&$+++********$    \",\n\"   $**&$$++********$    \",\n\"   $$$$$$$$$$$$$$$$$    \",\n\"                        \",\n\"                        \"\n]\n\nsetIconOutDoor = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #A30500\",\n\"+\tc #555755\",\n\"@\tc #EF2B29\",\n\"#\tc #2F65A5\",\n\"$\tc #888A88\",\n\"%\tc #6D9FD0\",\n\"&\tc #BCBCB3\",\n\"*\tc #DDDFDC\",\n\"                        \",\n\" ##########             \",\n\" #%%%%%%## @.           \",\n\" #%%%%%## @@..          \",\n\" #%%%%%# @@@@..         \",\n\" #%%%%%#@@@@@...        \",\n\" #%%%%%%#@@*$....       \",\n\" #%###%%%#***$....      \",\n\" ### @#%%%#***$....     \",\n\" ## @@@#%%%#***$....    \",\n\" # @@@@*#%%%#***$....   \",\n\"  @@@@***#%#*****$....  \",\n\"  @@@*****#*******$...  \",\n\"  @@***************$..  \",\n\"   $**&$+++**&&&&&*$    \",\n\"   $**&$+++**%###%*$    \",\n\"   $**$$+++**%###%*$    \",\n\"   $**$$+++**%###%*$    \",\n\"   $**&$+++**+++++*$    \",\n\"   $**&$+++********$    \",\n\"   $**&$$++********$    \",\n\"   $$$$$$$$$$$$$$$$$    \",\n\"                        \",\n\"                        \"\n]\n\nsetIconFree = [\n\"24 24 8 1\",\n\" \tc None\",\n\".\tc #7D94C9\",\n\"+\tc #6480C0\",\n\"@\tc #3E62B0\",\n\"#\tc #AABBDE\",\n\"$\tc #C3D0E8\",\n\"%\tc #92A5D3\",\n\"&\tc #000000\",\n\"                        \",\n\"           ..+          \",\n\"      @@@@#$$#.         \",\n\"     +#$#%$$###+++      \",\n\"    +$%###$$#%#$##.     \",\n\"    %+%#+%$$$##$#%%+    \",\n\"  @+@#$$#@@+##%#%%.+@   \",\n\"  %$$$$$###%@%%+..+.+   \",\n\" .$$$$$$#$$#.@@#$$%@@@  \",\n\"@.##$$$####%+%#$$$#%#+  \",\n\"+#$$$$###%%..+$$$$#$$%+ \",\n\"@$$###%#%%%%%+$$$####%+ \",\n\"+##%%%%%%%%%%+$##$#%%.+ \",\n\" +%%....+++++.####%%%.%+\",\n\"  @@@@@   .#%%%%%%%%%%%+\",\n\"           %###%%%%...+@\",\n\"            @@@@@@@@@@@ \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"     &         &&    &  \",\n\"      & &&       & &&   \",\n\"      &&          &     \",\n\"      &                 \"\n]\n\nsetIconStamp = [\n\"24 24 8 1\",\n\" \tc None\",\n\".\tc #787670\",\n\"+\tc #CE6E21\",\n\"@\tc #A37D5E\",\n\"#\tc #E48234\",\n\"$\tc #C69165\",\n\"%\tc #ACADAA\",\n\"&\tc #D6D9D5\",\n\"          @@@@@         \",\n\"         @####$$        \",\n\"         @####+$        \",\n\"         @####+$        \",\n\"         @+##++$        \",\n\"         @+++++$        \",\n\"          @+++@         \",\n\"          .&%%.         \",\n\"          .&%%.         \",\n\"        ...&%%...       \",\n\"     .....%&%%&.....    \",\n\"    ...&&&%&%%&&&&...   \",\n\"   ..&&&&&%&%%&&&&&&..  \",\n\"   ..&&&&&%&%%&&&&&&..  \",\n\"   .&&&&&&&%%%&&&&&&&.  \",\n\"   .&&&&&&&%%&&&&&&&&.  \",\n\"   ..&&&&&&&&&&&&&&&..  \",\n\"    .&&&&&&&&&&&&&&&.   \",\n\"    ...&&&&&&&&&&&...   \",\n\"    &&...&&&&&&&...&&   \",\n\"     %&&.........&&%    \",\n\"      %%&&&&&&&&&%%     \",\n\"        %%%%%%%%%       \",\n\"                        \"\n]\n\n#### matplotlib debut 1/5 #################################################################\n#import PySide2\n#from PySide2 import (QtWidgets, QtCore, QtGui)\n#from PySide2.QtWidgets import (QWidget, QApplication, QSlider, QGraphicsView, QGraphicsScene, QVBoxLayout, QStyle)\n\nimport re\nimport operator\nfrom operator import itemgetter #, attrgetter, methodcaller    # pour sort \n\n\nfolderNewIcon = [\n\"24 24 11 1\",\n\" \tc None\",\n\".\tc #FCE94F\",\n\"+\tc #EDD400\",\n\"@\tc #555753\",\n\"#\tc #BABDB6\",\n\"$\tc #2B4F89\",\n\"%\tc #D3D7CF\",\n\"&\tc #5479AB\",\n\"*\tc #B8BBB5\",\n\"=\tc #B6BAB4\",\n\"-\tc #2E5089\",\n\" ......                 \",\n\"........                \",\n\"........                \",\n\".+++++++                \",\n\".+.....+@@@@@@@@@@@@    \",\n\".+......###########@    \",\n\".+....$$$$$########@    \",\n\" +....$%%%$$$$$$$$$$$$& \",\n\" @####$$$$$$$$$$$$$$$$& \",\n\" @####$$$$$$$$$$$$$$$$& \",\n\"  @###$$$$$$$$$$$$$$$$& \",\n\"  @#*$$$$$$$$$$$$$$$$$& \",\n\"  @#=$$$$$$$$$$$$$$$$$& \",\n\"  @#=$$$$$$$$$$$$$$$$$& \",\n\"  @#=$$$$$$$$$$$$$$$&&& \",\n\"  @##$$$$$$$$$$$$$$$&   \",\n\"   @$$$$$$$$$$$$$$$$&   \",\n\"   @$-$$$$$$$$$$$$$$&   \",\n\"   @$$$$$$$$$$$$$$$&&   \",\n\"   &&&&&&&&&&&&&&&&&    \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \"]\n\nsetIconTTF = [\n\"16 16 6 1\",\n\"   c None\",\n\".  c #204A87\",\n\"+  c None\",\n\"@  c #729FCF\",\n\"#  c #CC0000\",\n\"$  c #EDD400\",\n\".+++++++++++@@@@\",\n\".++++++++@+@++@@\",\n\".++#####++++@@+@\",\n\".+++$#$$$++@+@+@\",\n\".++++#$+++++++@+\",\n\".++++#$#####++++\",\n\".++++#$+$#$$$+++\",\n\".++++#$++#$+++++\",\n\".@++++$++#$+###+\",\n\".@@++++++#$+#$$$\",\n\"..@@+++++#$+#$++\",\n\"...@@+++++$+###+\",\n\"....@@++++++#$$$\",\n\".....@@+++++#$++\",\n\"......@@+++++$++\",\n\"................\"]\n\nsetIconFON = [\n\"16 16 6 1\",\n\"   c None\",\n\".  c #204A87\",\n\"+  c None\",\n\"@  c #F57900\",\n\"#  c #CC0000\",\n\"$  c #EDD400\",\n\".+++++++++++@@@@\",\n\".++++++++@+@++@@\",\n\".++###++++++@@+@\",\n\".++#$$$++++@+@+@\",\n\".++#$+++++++++@+\",\n\".++###+###++++++\",\n\".++#$$$#$#$+++++\",\n\".++#$++#$#$+++++\",\n\".@++$++#$#$##+#+\",\n\".@@++++#$#$##$#$\",\n\"..@@+++###$#$##$\",\n\"...@@+++$$$#$##$\",\n\"....@@+++++#$+#$\",\n\".....@@++++#$+#$\",\n\"......@@++++$++$\",\n\"................\"]\n\nsetIconOTF = [\n\"16 16 6 1\",\n\"   c None\",\n\".  c #204A87\",\n\"+  c None\",\n\"@  c #4E9A06\",\n\"#  c #CC0000\",\n\"$  c #EDD400\",\n\".+++++++++++@@@@\",\n\".++++++++@+@++@@\",\n\".++###++++++@@+@\",\n\".++#$#$++++@+@+@\",\n\".++#$#$+++++++@+\",\n\".++#$#$###++++++\",\n\".++#$#$+#$$+++++\",\n\".++###$+#$++++++\",\n\".@++$$$+#$+###++\",\n\".@@+++++#$+#$$$+\",\n\"..@@++++#$+#$+++\",\n\"...@@++++$+###++\",\n\"....@@+++++#$$$+\",\n\".....@@++++#$+++\",\n\"......@@++++$+++\",\n\"................\"]\n\nsetIconPOL = [\n\"16 16 12 1\",\n\"   c None\",\n\".  c #204A87\",\n\"+  c None\",\n\"@  c #06989A\",\n\"#  c #73D216\",\n\"$  c #000000\",\n\"%  c #75507B\",\n\"&  c #729FCF\",\n\"*  c #CC0000\",\n\"=  c #F57900\",\n\"-  c #EDD400\",\n\";  c #4E9A06\",\n\".+++++++++++@#$%\",\n\".++++++++$+#++&$\",\n\".++***++++++=@+%\",\n\".++*-*-++++*+&+$\",\n\".++*-*-+++++++*+\",\n\".++***-***++++++\",\n\".++*---*-*-+++++\",\n\".++*-++*-*-+++++\",\n\".$++-++*-*-*++++\",\n\".*@++++*-*-*-+++\",\n\"..#*+++***-*-+++\",\n\"...;#+++---*-+++\",\n\"....%=+++++*-+++\",\n\".....;$++++****+\",\n\"......@%++++----\",\n\"................\"]\n\n#import glob\n#files_TTF = glob.glob(self.pathFont + \"/*.TTF\") \n##################################\nimport matplotlib\nimport matplotlib.font_manager\nimport matplotlib.font_manager as fontman\nimport matplotlib.font_manager as fontconfig\nfrom matplotlib.font_manager import FontProperties\n#from matplotlib.ft2font import FT2Font\n##################################\n\n#### Config Begin matplotlib font #######################\n                                                        # # https://en.wikipedia.org/wiki/Web_colors\nglobal setColorTTF       ; setColorTTF       = \"blue\"   # .TTF   color by \"extension name\" or hexa \"#0000FF\" \nglobal setColorFON       ; setColorFON       = \"orange\" # .FON   color by \"extension name\" or hexa \"#FFA500\" #FON give error\nglobal setColorOTF       ; setColorOTF       = \"green\"  # .OTF   color by \"extension name\" or hexa \"#008000\"\nglobal setColorPOL       ; setColorPOL       = \"black\"  # .OTHER color by \"extension name\" or hexa \"#000000\"\n                                                      #####\nglobal switchModeTextList; switchModeTextList= 1        # 0 = mode text normal (et noir) coupe le switchFontComBox\n                                                        # 1 = permet le switchFontComBox 1 (default)\n                                                      #####\nglobal switchFontComBox  ; switchFontComBox  = 0        # 0 = (et switchModeTextList= 1) mode texte (en couleur) dans liste ComboBox plus rapide (default)\n                                                        # 1 = (et switchModeTextList= 1) fontFamily dans liste ComboBox plus lent mais plus beau!\n                                                      #####\nglobal setSystemFonts    ; setSystemFonts    = 1        # 0 = matplotlib.font_manager.findSystemFonts(\"C:/\", \"ttf\") \n                                                        #     fait toutes les fontes (dans tous les dossiers et sous dossiers du DD) time !!\n                                                        # 1 = fontman.findSystemFonts(self.pathFont)\n                                                        #     fait toutes les fontes du repertoire (et dans tous les sous dossiers) (default)\n                                                      #####\nglobal seTtextAlignement ; seTtextAlignement = 0        # 0 = AlignLeft (default)\n                                                        # 1 = AlignCenter\n                                                        # 2 = AlignRight\n                                                      #####\nglobal setFontByDefault  ; setFontByDefault  = \"ARIAL\"  # Font by Default\n                                                      #####\n#### Config End matplotlib font #########################\n                                                      #####\nglobal switchResetFALSE  ; switchResetFALSE  = 0        # 0 = reset (False by default)\n                                                        # 1 = pas de reset (non conseille) certains switch peuvent rester ouvert ou fermer inopinement !\n                                                      #####\nglobal setPathOrthogonal ; setPathOrthogonal = 0        # \nglobal setPathTangent    ; setPathTangent    = 1        # \nglobal setPositionBase   ; setPositionBase   = 1        # \nglobal setPositionCenter ; setPositionCenter = 0        # \nglobal setPositionTop    ; setPositionTop    = 0        # \n                                                      #####\nglobal setMainWindowMoveX; #setMainWindowMoveX= 0        # position X macro window\nglobal setMainWindowMoveY; #setMainWindowMoveY= 0        # position Y macro window\nglobal setFrameWindowSizeX #setFrameWindowSizeX=0        # dimension X macro window\nglobal setFrameWindowSizeY #setFrameWindowSizeY=0        # dimension Y macro window\n#### Config #############################################\n\ndef setPolicePath():\n    global PolicePath\n    global originalFontPath\n    global originalFontName\n\n    if platform.system()   == \"Windows\" :\n        PolicePath = originalFontPath = \"C:/Windows/Fonts/\"\n        setFontByDefault = originalFontName = \"ARIAL\"\n    elif platform.system() == \"Linux\" :\n        PolicePath = originalFontPath = \"/usr/share/fonts/\"\n        setFontByDefault = originalFontName = \"UBUNTU-M\"\n    elif platform.system() == \"Darwin\":\n        PolicePath = originalFontPath = \"/Library/Fonts/\"\n        setFontByDefault = originalFontName = \"Arial\"\n    if platform.system() == \"Linux\" :\n        PolicePath = originalFontPath = \"/usr/share/fonts/\"\n        setFontByDefault = originalFontName = \"Monospace\"\nsetPolicePath()\n\n###### Read Configuration begin ####\nseTtextAlignement  = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetInt(\"seTtextAlignement\")\nsetSystemFonts     = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"setSystemFonts\")\nswitchFontComBox   = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"switchFontComBox\")\nswitchModeTextList = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"switchModeTextList\")\nsetFontByDefault   = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetString(\"setFontByDefault\")\nif setFontByDefault == \"\": setPolicePath()\nswitchResetFALSE   = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"switchResetFALSE\") \n#                    switchResetFALSE: desactive cree des erreurs de fonctionnement attention a l utilisation !!\nsetMainWindowMoveX = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetInt(\"setMainWindowMoveX\")\nsetMainWindowMoveY = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetInt(\"setMainWindowMoveY\")\nsetFrameWindowSizeX= FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetInt(\"setFrameWindowSizeX\")\nsetFrameWindowSizeY= FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetInt(\"setFrameWindowSizeY\")\n\nsetPathOrthogonal = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"setPathOrthogonal\")\nsetPathTangent    = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"setPathTangent\")\nsetPositionBase   = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"setPositionBase\")\nsetPositionCenter = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"setPositionCenter\")\nsetPositionTop    = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"setPositionTop\")\n\n###### Read Configuration end   ####\n\n\ndef createSpace(texte):    # detecte majuscule et ajoute un espace devant la lettre\n    # return createSpace(TexTe) = Tex Te , if createSpace(TEXTE) = TEXTE\n    if texte.isupper():\n        stringSpace = texte\n    else:\n        try:\n            stringSpace = texte[0]\n            for i in texte[1:]:\n                if re.search(r\"[A-Z]\", i): i = \" \" +  i\n                stringSpace += i\n        except Exception:\n            stringSpace = texte\n    return stringSpace\n\ndef family(chaine):\n    # return family(chaine)[1] = Family , family(chaine)[2] = typeCar (form [a, b, c ...]\n    famille = typeCar = \"\"\n    try:\n        if chaine.find('-') != -1:\n            famille = chaine[:chaine.find('-')]\n            typeCar = chaine[chaine.find('-')+1:]\n        else:\n            famille = chaine\n            typeCar = \"\"\n    except Exception:\n        famille = chaine\n        typeCar = \"\"\n    typeCar = str(createSpace(typeCar)).split()\n    return [createSpace(famille), typeCar]\n\nclass MyLabelPatience():        # fenetre image d'attente de chargement\n    global path\n    label = QtWidgets.QLabel()\n    label.setText(\"<img src=\" + path + \"FCCircularTextButtom.png><b><center>Wait please</center> \\n\\n<center>i search the fonts !\\n\\n</right></b>\")\n    ecran = FreeCADGui.getMainWindow().frameGeometry()\n    xF = 250; yF = 250\n    xW = (ecran.width()/2) - (xF/2)\n    yW = (ecran.height()/2)- (yF/2)\n    label.setGeometry(xW, yW, xF, yF)\n    label.setStyleSheet(\"QLabel {background-color : #F0C300;font: 12pt; }\");\n    label.setWindowFlags(PySide2.QtCore.Qt.WindowFlags(PySide2.QtCore.Qt.FramelessWindowHint))        # pas de bords\n    label.setWindowFlags(PySide2.QtCore.Qt.WindowStaysOnTopHint)         # PySide cette fonction met la fenetre en avant\n#### matplotlib fin 1/5 #################################################################\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\nclass Ui_MainWindow(object):\n\n    def __init__(self):\n        global path\n        self.path          = path\n\n        #### matplotlib debut 2/5 apres __init__ #################################################################\n        #### matplotlib font textEdit\n        self.FontTextSize  = 20\n        self.fonteComp     = \"\"\n        self.font          = QtGui.QFont()\n        self.tableau       = [] #Index (), [chemin plus nom fichier (nomPathPolice), nom sans extension (nomSimple), nomSimpleExt (nomSimple + Ext)]\n        self.index         = 0  #Index ()\n        #### matplotlib font textEdit\n    def searchFont(self,pathSearch, setFontByDefault):    #modify\n        global PolicePath\n        global setSystemFonts\n        global seTtextAlignement\n        global switchFontComBox\n        global switchModeTextList\n        #global setFontByDefault    #modify\n\n        MyLabelPatience.label.show()\n        FreeCADGui.updateGui()                                 # rafraichi l'ecran\n\n        files_All_Fonts = \"\"\n        ##https://matplotlib.org/_modules/matplotlib/font_manager.html\n\n        if setSystemFonts == 0:\n            files_All_Fonts = matplotlib.font_manager.findSystemFonts(pathSearch, \"ttf\")  # fait toutes les fontes ? ()\n        else:\n            files_All_Fonts = fontman.findSystemFonts(pathSearch)                         # fait toutes les fontes (et dans tous les sous dossiers)\n\n        if len(files_All_Fonts) > 0:           \n            self.tableau = []\n            self.index = 0\n\n            for fonte in files_All_Fonts:\n                ####\n                nomPathPolice = nomFichier = nomSimpleExt = nomSimple = nomExtension = nameName = \"\"\n\n                nomPathPolice = fonte.replace(\"\\\\\",\"/\")     # convert the \"\\\" to \"/\"\n                nomFichier    = nomPathPolice.split(\"/\")    # complet split\n                nomSimpleExt  = nomFichier[-1]              # nom avec extension\n                nomSimple     = nomFichier[-1][:-4]         # nom sans extension\n                nomExtension  = nomSimpleExt[nomSimpleExt.rfind('.')+1:].upper() # extension\n\n                ####\n                try:\n#                    nameFamily    = matplotlib.font_manager.FontProperties(fname=fonte).get_family()            ##['sans-serif']\n#                    nameStyle     = matplotlib.font_manager.FontProperties(fname=fonte).get_style()              #normal\n#                    nameVariant   = matplotlib.font_manager.FontProperties(fname=fonte).get_variant()            #normal\n#                    nameWeight    = matplotlib.font_manager.FontProperties(fname=fonte).get_weight()             #normal\n#                    nameStretch   = matplotlib.font_manager.FontProperties(fname=fonte).get_stretch()            #normal\n#                    nameFileComp  = matplotlib.font_manager.FontProperties(fname=fonte).get_file()              ##c:\\windows\\fonts\\NotoNaskhArabicUI-Regular.ttf\n#                    nameSize      = matplotlib.font_manager.FontProperties(fname=fonte).get_size()               #10.0\n                    nameName      = matplotlib.font_manager.FontProperties(fname=fonte).get_name()              ##Noto Naskh Arabic UI\n#                    nameSizePoint = matplotlib.font_manager.FontProperties(fname=fonte).get_size_in_points()     #10.0\n#                    nameSlant     = matplotlib.font_manager.FontProperties(fname=fonte).get_slant()              #normal\n#                    namePattern   = matplotlib.font_manager.FontProperties(fname=fonte).get_fontconfig_pattern() #:family=sans-serif:style=normal:variant=normal:weight=normal:stretch=normal:file=c:\\windows\\fonts\\NotoNaskhArabicUI-Regular.ttf:size=10.0\n                except Exception:\n                    nameFamily = nameStyle = nameVariant = nameWeight = nameStretch = nameFileComp = nameSize = nameName = nameSizePoint = nameSlant = namePattern = \"\"\n                ####\n                if nameName == \"\" :\n                    nameName = nomSimple\n                self.tableau.append([0, nomPathPolice, nomSimple, nomSimpleExt.upper(), nomExtension.upper(), nameName])\n                \n            self.tableau = sorted(self.tableau, key=itemgetter(3))          # sorted by nomSimple.upper()\n\n            try:\n                for line in range(len(self.tableau)):                       # enleve les doubles (bon)\n                    if self.tableau[line][2] == self.tableau[line + 1][2]:  # enleve les doubles (bon)\n                        del(self.tableau[line + 1])                         # enleve les doubles (bon)\n            except Exception:\n                None\n\n            self.comboBoxPy.clear()\n            for line in range(len(self.tableau)): \n                try:\n                    self.tableau[line][0] = line                 # ajoute le numero de ligne\n                    if self.tableau[line][2].upper() == setFontByDefault.upper(): # detecte la fonte de base\n                        self.index = line\n                        PolicePath = self.tableau[line][1]\n                    ####Section common color and font begin ######################\n                    model = self.comboBoxPy.model()\n\n                    if switchModeTextList == 1:\n                        if self.tableau[line][4] == \"TTF\":\n                            item = QtGui.QStandardItem(QtGui.QPixmap(setIconTTF), str(line))\n                            item.setForeground(QtGui.QColor(setColorTTF))\n                        elif self.tableau[line][4] == \"FON\":\n                            item = QtGui.QStandardItem(QtGui.QPixmap(setIconFON), str(line))\n                            item.setForeground(QtGui.QColor(setColorFON))\n                        elif self.tableau[line][4] == \"OTF\":\n                            item = QtGui.QStandardItem(QtGui.QPixmap(setIconOTF), str(line))\n                            item.setForeground(QtGui.QColor(setColorOTF))\n                        else:\n                            item = QtGui.QStandardItem(QtGui.QPixmap(setIconPOL), str(line))\n                            item.setForeground(QtGui.QColor(setColorPOL))\n\n                        if   seTtextAlignement == 0:\n                            item.setTextAlignment(QtCore.Qt.AlignLeft)\n                        elif seTtextAlignement == 1:\n                            item.setTextAlignment(QtCore.Qt.AlignCenter)\n                        elif seTtextAlignement == 2:\n                            item.setTextAlignment(QtCore.Qt.AlignRight)\n                        else:\n                            self.comboBoxPy.addItem(self.tableau[line][2])    \n                        model.appendRow(item)\n                    else:\n                        self.comboBoxPy.addItem(\"\")\n                    self.comboBoxPy.setItemText(line, self.tableau[line][2])\n                    ####Section item color and font end ##########################\n\n                    ####Section setfont Family switchFontComBox begin#############\n                    if (switchFontComBox == 1) and (switchModeTextList == 1):\n                        typeCar = font = \"\"\n                        font = QtGui.QFont()\n                        #font = item.font()\n\n                        typeCar   = family(self.tableau[line][2])[1]\n                        font.setBold(False)\n                        font.setItalic(False)\n\n                        if len(typeCar) > 0:\n                            for option in typeCar:\n                                if option == \"Bold\":\n                                    font.setBold(True)\n                                if (option == \"Italic\") or (option == \"It\") or (option == \"Slanted\"):\n                                    font.setItalic(True)\n                                if option == \"Oblique\":\n                                    font.setItalic(True)\n                        #'Bold''Regular''Slanted''Italic''Medium''Extra''Light''Condensed''Black''It''Semibold'\n                        \n                        font.setFamily(self.tableau[line][5])\n                        font.setPixelSize(15)\n                        if switchModeTextList == 1:\n                            item.setFont(font)\n                        else:\n                            self.comboBoxPy.addItem(\"\")\n                    ####Section setfont Family switchFontComBox end###############\n\n                except Exception:\n                    FreeCAD.Console.PrintMessage(\"searchFont()\" + \"\\n\")\n                    None\n\n            self.lineEdit_NameFile.setText(\"(\" + str(self.index + 1) + \"/\" + str(len(self.tableau)) + \") \" + self.tableau[self.index][1])\n            self.comboBoxPy.setCurrentIndex(self.index)\n            self.fonteComp = self.tableau[self.index][1]\n            MyLabelPatience.label.close()\n            #### matplotlib fin 2/5 apres __init__ #################################################################\n\n    def setupUi(self, MainWindow):\n        self.window = MainWindow\n\n        global ui\n        global PolicePath\n        global rayon\n        global texte\n        global rotation\n        global SizeCaractere\n        global debout\n        global exterieur\n\n        global precision\n        global correctionAngle\n        global correctionRayon\n        global baseHelix\n        global endHelix\n        global nombreCarParTour\n\n        global epaisseurExtrus\n        global epaisSupportClock\n        \n        global setPathOrthogonal\n        global setPathTangent\n        global setPositionBase\n        global setPositionCenter\n        global setPositionTop\n        global switchResetFALSE\n        global setMainWindowMoveX\n        global setMainWindowMoveY\n        global setFrameWindowSizeX\n        global setFrameWindowSizeY\n        global setPathLatestDirectoryManual\n        global setFontByDefault\n\n        MainWindow.setObjectName(_fromUtf8(\"MainWindow\"))\n#        MainWindow.setMaximumSize(QtCore.QSize(370, 638))\n#        MainWindow.setMinimumSize(QtCore.QSize(400, 640))\n#        MainWindow.move(setMainWindowMoveX, setMainWindowMoveY) # position macro\n        MainWindow.setGeometry(setMainWindowMoveX, setMainWindowMoveY, setFrameWindowSizeX, setFrameWindowSizeY)\n\n        self.centralWidget = QtWidgets.QWidget(MainWindow)\n        self.centralWidget.setObjectName(_fromUtf8(\"centralWidget\"))\n\n        ###################\n        grid = QtWidgets.QGridLayout()\n        self.centralWidget.setLayout(grid)\n        ####\n        self.scrollArea = QtWidgets.QScrollArea(self.centralWidget)    # cadre scrollarea contenant le widget GUI\n        self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)\n        self.scrollArea.setWidgetResizable(True)\n        grid.addWidget(self.scrollArea, 0, 0)\n        vbox = QtWidgets.QVBoxLayout()\n        self.scrollArea.setLayout(vbox)\n        ####\n        self.scrollAreaWidgetContents_2 = QtWidgets.QWidget()          #widget contenant le GUI\n        vbox.addWidget(self.scrollAreaWidgetContents_2)\n        vbox = QtWidgets.QVBoxLayout()\n        self.scrollAreaWidgetContents_2.setLayout(vbox)\n        ###################\n\n        self.groupBox_00 = QtWidgets.QGroupBox()\n        self.groupBox_00.setFlat(False)\n        self.groupBox_01 = QtWidgets.QGroupBox()\n        self.groupBox_01.setFlat(False)\n\n        ####\n        self.textEdit = QtWidgets.QTextEdit()\n        self.textEdit.textChanged.connect(self.on_textEdit_Changed)\n#        self.textEdit.setMaximumHeight(100)\n        ####\n        self.frame_Option = QtWidgets.QFrame()\n        self.frame_Option.setFrameShape(QtWidgets.QFrame.StyledPanel)\n        self.frame_Option.setFrameShadow(QtWidgets.QFrame.Plain) #Raised Sunken\n        self.PB_Reverse = QtWidgets.QPushButton()\n        self.PB_Reverse.clicked.connect(self.on_PB_Reverse)\n        self.CB_Word = QtWidgets.QCheckBox()\n        self.CB_Word.setText(_fromUtf8(\"Word\"))\n        self.CB_Word.clicked.connect(self.on_CB_Word)\n        ####\n        self.PB_Help = QtWidgets.QPushButton(MainWindow)\n        self.PB_Help.setIcon(QtGui.QIcon(QtGui.QPixmap(helpIcon)))      # help icone dans une variable\n        self.PB_Help.clicked.connect(self.on_PB_Help_clicked)           # help\n        ####\n        #### matplotlib debut 3/5 setupUi #################################################################\n\n        self.lineEdit_NameFile = QtWidgets.QLineEdit()\n        #self.lineEdit_NameFile.returnPressed.connect(self.on_lineEdit_NameFile) \n\n        ####add\n        self.lineEdit_NameFile_button = QtWidgets.QPushButton(MainWindow)\n        self.lineEdit_NameFile_button.setIcon(QtGui.QIcon(QtGui.QPixmap(folderNewIcon)))\n        self.lineEdit_NameFile_button.clicked.connect(self.on_lineEdit_NameFile_button) \n\n        self.PB_systemPath = QtWidgets.QPushButton(MainWindow)\n        self.PB_systemPath.setIcon(QtGui.QIcon(QtGui.QPixmap(homeIcon)))    # icone dans une variable \n        self.PB_systemPath.clicked.connect(self.on_PB_systemPath)\n        ####add\n\n        self.comboBoxPy = QtWidgets.QComboBox()\n        ####\n        self.pathFont = PolicePath[:len(PolicePath)-(PolicePath[::-1].index(\"/\"))-1]\n#        self.pathFont = setPathLatestDirectoryManual\n        ####\n        ui.searchFont(self.pathFont, setFontByDefault)\n        QtCore.QObject.connect(self.comboBoxPy, QtCore.SIGNAL(\"currentIndexChanged(int)\"), self.on_fontComboBoxPython)\n        #### matplotlib fin 3/5 setupUi #################################################################\n        ####\n        self.groupBox_02 = QtWidgets.QGroupBox()\n\n        self.DS_Radius_Circle = QtWidgets.QDoubleSpinBox()\n        self.DS_Radius_Circle.setMinimum(-99999999.0)\n        self.DS_Radius_Circle.setMaximum(99999999.0)\n        self.DS_Radius_Circle.setValue(rayon)\n        self.DS_Radius_Circle.valueChanged.connect(self.on_DS_Radius_Circle) #connection doubleSpinBox\n        self.label_10 = QtWidgets.QLabel()\n\n        self.DS_Size_Character = QtWidgets.QDoubleSpinBox()\n        self.DS_Size_Character.setMinimum(0.0)\n        self.DS_Size_Character.setMaximum(99999999.0)\n        self.DS_Size_Character.setSingleStep(1.0)\n        self.DS_Size_Character.setValue(SizeCaractere)\n        self.DS_Size_Character.valueChanged.connect(self.on_DS_Size_Character) #connection doubleSpinBox\n        self.label_4 = QtWidgets.QLabel()\n\n        self.S_Begin_Angle = QtWidgets.QSpinBox()\n        self.S_Begin_Angle.setMaximum(360.0)\n        self.S_Begin_Angle.setValue(debut)\n        self.S_Begin_Angle.valueChanged.connect(self.on_S_Begin_Angle) #connection SpinBox\n        self.label_13 = QtWidgets.QLabel()\n\n        self.S_End_Angle = QtWidgets.QSpinBox()\n        self.S_End_Angle.setMaximum(360)\n        self.S_End_Angle.setValue(rotation)\n        self.S_End_Angle.valueChanged.connect(self.on_S_End_Angle) #connection SpinBox\n        self.label_14 = QtWidgets.QLabel()\n\n        self.DS_Correction_Angle = QtWidgets.QDoubleSpinBox()\n        self.DS_Correction_Angle.setMinimum(-359.00)\n        self.DS_Correction_Angle.setMaximum(359.00)\n        self.DS_Correction_Angle.setValue(correctionAngle)\n        self.DS_Correction_Angle.valueChanged.connect(self.on_DS_Correction_Angle) #connection doubleSpinBox\n        self.label_7 = QtWidgets.QLabel()\n\n        self.DS_Correction_Radius = QtWidgets.QDoubleSpinBox()\n        self.DS_Correction_Radius.setMinimum(-99999999.0)\n        self.DS_Correction_Radius.setMaximum(99999999.0)\n        self.DS_Correction_Angle.setValue(correctionAngle)\n        self.DS_Correction_Radius.setValue(correctionRayon)\n        self.DS_Correction_Radius.valueChanged.connect(self.on_DS_Correction_Radius) #connection doubleSpinBox\n        self.label_8 = QtWidgets.QLabel()\n\n        self.DS_Extrude = QtWidgets.QDoubleSpinBox()\n        self.DS_Extrude.setEnabled(False)\n        self.DS_Extrude.setMinimum(-99999999.0)\n        self.DS_Extrude.setMaximum(99999999.0)\n        self.DS_Extrude.setValue(epaisseurExtrus)\n        self.DS_Extrude.valueChanged.connect(self.on_DS_Extrude) #connection doubleSpinBox\n\n        self.CH_Extrude = QtWidgets.QCheckBox()\n        self.CH_Extrude.clicked.connect(self.on_CH_Extrude) #connection checkBox\n\n        self.DS_PlacementX = QtWidgets.QDoubleSpinBox()\n        self.DS_PlacementX.setEnabled(False)\n        self.DS_PlacementX.setSpecialValueText(_fromUtf8(\"\"))\n        self.DS_PlacementX.setMinimum(-9999999.0)\n        self.DS_PlacementX.setMaximum(9999999.99)\n        self.DS_PlacementX.valueChanged.connect(self.on_DS_PlacementX) #connection doubleSpinBox\n\n        self.DS_PlacementY = QtWidgets.QDoubleSpinBox()\n        self.DS_PlacementY.setEnabled(False)\n        self.DS_PlacementY.setSpecialValueText(_fromUtf8(\"\"))\n        self.DS_PlacementY.setMinimum(-9999999.0)\n        self.DS_PlacementY.setMaximum(9999999.99)\n        self.DS_PlacementY.valueChanged.connect(self.on_DS_PlacementY) #connection doubleSpinBox\n\n        self.DS_PlacementZ = QtWidgets.QDoubleSpinBox()\n        self.DS_PlacementZ.setEnabled(False)\n        self.DS_PlacementZ.setSpecialValueText(_fromUtf8(\"\"))\n        self.DS_PlacementZ.setMinimum(-9999999.0)\n        self.DS_PlacementZ.setMaximum(9999999.99)\n        self.DS_PlacementZ.valueChanged.connect(self.on_DS_PlacementZ) #connection doubleSpinBox\n\n        self.CH_Sp_Placement = QtWidgets.QCheckBox()\n        self.CH_Sp_Placement.clicked.connect(self.on_CH_Sp_Placement) #connection checkBox\n\n        self.DS_InclinaisonX = QtWidgets.QSpinBox()\n        self.DS_InclinaisonX.setEnabled(False)\n        self.DS_InclinaisonX.setMinimum(-360.0)\n        self.DS_InclinaisonX.setMaximum(360.0)\n        self.DS_InclinaisonX.setValue(inclinaisonX)\n        self.DS_InclinaisonX.valueChanged.connect(self.on_DS_InclinaisonX) #connection doubleSpinBox\n\n        self.DS_InclinaisonY = QtWidgets.QSpinBox()\n        self.DS_InclinaisonY.setEnabled(False)\n        self.DS_InclinaisonY.setMinimum(-360)\n        self.DS_InclinaisonY.setMaximum(360)\n        self.DS_InclinaisonY.setValue(inclinaisonY)\n        self.DS_InclinaisonY.valueChanged.connect(self.on_DS_InclinaisonY) #connection doubleSpinBox\n\n        self.DS_InclinaisonZ = QtWidgets.QSpinBox()\n        self.DS_InclinaisonZ.setEnabled(False)\n        self.DS_InclinaisonZ.setMinimum(-360.0)\n        self.DS_InclinaisonZ.setMaximum(360.0)\n        self.DS_InclinaisonZ.setValue(inclinaisonZ)\n        self.DS_InclinaisonZ.valueChanged.connect(self.on_DS_InclinaisonZ) #connection doubleSpinBox\n\n        self.CH_Sp_Inclination = QtWidgets.QCheckBox()\n        self.CH_Sp_Inclination.clicked.connect(self.on_CH_Sp_Inclination) #connection checkBox\n\n        ####\n        self.groupBox_03 = QtWidgets.QGroupBox()\n\n        self.graphicsView = QtWidgets.QGraphicsView()\n        ####Screen Graphic BitMap\n        ##https://doc.qt.io/qtforpython/PySide2/QtCore/Qt.html\n        self.graphicsView = QtWidgets.QGraphicsView()\n        self.graphicsView.setObjectName(\"graphicsView\")\n        self.graphicsView.setFixedSize(210,100)\n        pic = QtGui.QPixmap()\n        pic.loadFromData(base64.b64decode(outDoor_Icon_b64))  #indoor_Icon_b64  # bmp converti\n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(self.scene)\n\n#        pic = QtGui.QPixmap(outDoorIcon)          # xpm\n#        self.scene = QtWidgets.QGraphicsScene()   # xpm bmp converti (general)\n#        self.scene.addPixmap(QtGui.QPixmap(pic))  # xpm bmp converti (general)\n#        self.graphicsView.setScene(self.scene)    # xpm bmp converti (general)\n#        ####Screen Graphic BitMap\n        ####\n\n        self.RA_Choice_Outdoor = QtWidgets.QRadioButton()\n        self.RA_Choice_Outdoor.setChecked(True)\n        self.RA_Choice_Outdoor.setIcon(QtGui.QIcon(QtGui.QPixmap(setIconOutDoor))) # icone dans une variable \n        self.RA_Choice_Outdoor.clicked.connect(self.on_RA_Choice_Outdoor) #connection radioButton\n\n        self.RA_Choice_Indoor = QtWidgets.QRadioButton()\n        self.RA_Choice_Indoor.setIcon(QtGui.QIcon(QtGui.QPixmap(setIconInDoor))) # icone dans une variable \n        self.RA_Choice_Indoor.clicked.connect(self.on_RA_Choice_Indoor) #connection radioButton\n\n        self.RA_Choice_Helix = QtWidgets.QRadioButton()\n        self.RA_Choice_Helix.setIcon(QtGui.QIcon(QtGui.QPixmap(setIconHelix))) # icone dans une variable \n        self.RA_Choice_Helix.clicked.connect(self.on_RA_Choice_Helix) #connection radioButton\n\n        self.RA_Choice_Clock = QtWidgets.QRadioButton()\n        self.RA_Choice_Clock.setIcon(QtGui.QIcon(QtGui.QPixmap(setIconClock))) # icone dans une variable \n        self.RA_Choice_Clock.clicked.connect(self.on_RA_Choice_Clock) #connection radioButton\n\n        #self.RA_Choice_Stamp = QtWidgets.QRadioButton()\n        #self.RA_Choice_Stamp.setIcon(QtGui.QIcon(QtGui.QPixmap(setIconStamp))) # icone dans une variable \n        #self.RA_Choice_Stamp.clicked.connect(self.on_RA_Choice_Stamp) #connection radioButton \n\n        self.PU_Flat = QtWidgets.QPushButton()\n        self.PU_Flat.setEnabled(True)\n        self.PU_Flat.setIcon(QtGui.QIcon(QtGui.QPixmap(standIcon))) # icone dans une variable \n        self.PU_Flat.clicked.connect(self.on_PU_Flat)\n        ####\n        #### Tab Onglets\n        self.tabWidget = QtWidgets.QTabWidget()\n        self.tabWidget.setTabPosition(QtWidgets.QTabWidget.North)\n        self.tabWidget.setTabShape(QtWidgets.QTabWidget.Rounded)\n\n        self.tabWidget.blockSignals(False) #just for not showing the initial message\n        self.tabWidget.tabBarClicked.connect(self.on_tabWidget) #changed!\n        #self.tabWidget.currentChanged.connect(self.on_tabWidget) #changed!\n\n        self.DS_Step_Of_The_Helix = QtWidgets.QDoubleSpinBox()\n        self.DS_Step_Of_The_Helix.setMaximum(99999999.99)\n        self.DS_Step_Of_The_Helix.setValue(pasHelix)\n        self.DS_Step_Of_The_Helix.valueChanged.connect(self.on_DS_Step_Of_The_Helix) #connection doubleSpinBox\n        self.label_12 = QtWidgets.QLabel()\n\n        self.DS_Number_Char_Per_Turn = QtWidgets.QSpinBox()\n        self.DS_Number_Char_Per_Turn.setMaximum(99999999)\n        self.DS_Number_Char_Per_Turn.setValue(nombreCarParTour)\n        self.DS_Number_Char_Per_Turn.valueChanged.connect(self.on_DS_Number_Char_Per_Turn) #connection doubleSpinBox\n        self.label = QtWidgets.QLabel()\n\n        self.DS_Base_Helix = QtWidgets.QDoubleSpinBox()\n        self.DS_Base_Helix.setEnabled(False)\n        self.DS_Base_Helix.setMinimum(-99999999.0)\n        self.DS_Base_Helix.setMaximum(99999999.0)\n        self.DS_Base_Helix.setValue(baseHelix)\n        self.DS_Base_Helix.valueChanged.connect(self.on_DS_Base_Helix) #connection doubleSpinBox\n        self.label_2 = QtWidgets.QLabel()\n\n        self.DS_End_Helix = QtWidgets.QDoubleSpinBox()\n        self.DS_End_Helix.setEnabled(False)\n        self.DS_End_Helix.setMinimum(-99999999.0)\n        self.DS_End_Helix.setMaximum(99999999.0)\n        self.DS_End_Helix.setValue(endHelix)\n        self.DS_End_Helix.valueChanged.connect(self.on_DS_End_Helix) #connection doubleSpinBox\n        self.label_3 = QtWidgets.QLabel()\n\n        #### clock\n\n        self.DS_Number_Faces_Support = QtWidgets.QSpinBox()\n        self.DS_Number_Faces_Support.setMaximum(999)\n        self.DS_Number_Faces_Support.setValue(nombreFaces)\n        self.DS_Number_Faces_Support.valueChanged.connect(self.on_DS_Number_Faces_Support) #connection SpinBox\n        self.label_5 = QtWidgets.QLabel()\n\n        self.CB_RomanOrArabic = QtWidgets.QCheckBox() # replace by CheckBox pour ne plus avoir le flip/flop\n        self.CB_RomanOrArabic.setIcon(QtGui.QIcon(QtGui.QPixmap(arabicIcon))) # icone dans une variable \n        self.CB_RomanOrArabic.clicked.connect(self.on_PU_Roman)\n\n        self.DS_Radius_Support = QtWidgets.QDoubleSpinBox()\n        self.DS_Radius_Support.setMaximum(99999999.99)\n        self.DS_Radius_Support.setValue(cercleClock)\n        self.DS_Radius_Support.setEnabled(False)\n        self.DS_Radius_Support.valueChanged.connect(self.on_DS_Radius_Support) #connection doubleSpinBox\n        self.label_11 = QtWidgets.QLabel()\n\n        self.CB_RedressChiffres = QtWidgets.QCheckBox() # replace by CheckBox pour ne plus avoir le flip/flop\n        self.CB_RedressChiffres.setIcon(QtGui.QIcon(QtGui.QPixmap(axialIcon))) # icone dans une variable \n        self.CB_RedressChiffres.clicked.connect(self.on_PU_Redress)\n\n        self.DS_Extrude_Support = QtWidgets.QDoubleSpinBox()\n        self.DS_Extrude_Support.setMaximum(99999999.0)\n        self.DS_Extrude_Support.setEnabled(False)\n        self.DS_Extrude_Support.setValue(epaisSupportClock)\n        self.DS_Extrude_Support.valueChanged.connect(self.on_DS_Extrude_Support) #connection doubleSpinBox\n        self.label_6 = QtWidgets.QLabel()\n\n        #### Path\n\n        self.frame_Path = QtWidgets.QFrame()\n        self.frame_Path.setFrameShape(QtWidgets.QFrame.StyledPanel)\n        self.frame_Path.setFrameShadow(QtWidgets.QFrame.Plain) #Raised) Sunken\n        self.RB_Path_01 = QtWidgets.QRadioButton()\n        self.RB_Path_01.setChecked(setPathOrthogonal)\n        self.RB_Path_01.clicked.connect(self.on_RB_Path_Image)\n        self.RB_Path_02 = QtWidgets.QRadioButton()\n        self.RB_Path_02.setChecked(setPathTangent)\n        self.RB_Path_02.clicked.connect(self.on_RB_Path_Image)\n\n        self.frame_Position = QtWidgets.QFrame()\n        self.frame_Position.setFrameShape(QtWidgets.QFrame.StyledPanel)\n        self.frame_Position.setFrameShadow(QtWidgets.QFrame.Plain) #.Raised) Sunken\n        self.RB_Position_01 = QtWidgets.QRadioButton()\n        self.RB_Position_01.setChecked(setPositionBase)\n        self.RB_Position_01.clicked.connect(self.on_RB_Path_Image)\n        self.RB_Position_02 = QtWidgets.QRadioButton()\n        self.RB_Position_02.setChecked(setPositionCenter)\n        self.RB_Position_02.clicked.connect(self.on_RB_Path_Image)\n        self.RB_Position_03 = QtWidgets.QRadioButton()\n        self.RB_Position_03.setChecked(setPositionTop)\n        self.RB_Position_03.clicked.connect(self.on_RB_Path_Image)\n\n#### plus tard\n#        self.horizontalSlider_01_Str = QtWidgets.QSlider()\n#        self.horizontalSlider_01_Str.setOrientation(QtCore.Qt.Horizontal)\n#        self.label_Path_01 = QtWidgets.QLabel()\n#        self.horizontalSlider_02_Car = QtWidgets.QSlider()\n#        self.horizontalSlider_02_Car.setOrientation(QtCore.Qt.Horizontal)\n#        self.label_Path_02 = QtWidgets.QLabel()\n#        self.horizontalSlider_03_Tra = QtWidgets.QSlider()\n#        self.horizontalSlider_03_Tra.setOrientation(QtCore.Qt.Horizontal)\n#        self.label_Path_03 = QtWidgets.QLabel()\n#### plus tard\n\n        #### Command\n\n        self.CB_01_Points = QtWidgets.QCheckBox()\n        self.CB_01_Points.setIcon(QtGui.QIcon.fromTheme(\"Draft\",QtGui.QIcon(\":/icons/Draft_Dot.svg\")))\n        self.CB_02_Circle = QtWidgets.QCheckBox()\n        self.CB_02_Circle.setIcon(QtGui.QIcon.fromTheme(\"Draft\",QtGui.QIcon(\":/icons/Draft_Circle.svg\")))\n        self.CB_03_BBox = QtWidgets.QCheckBox()\n        self.CB_03_BBox.setIcon(QtGui.QIcon.fromTheme(\"Draft\",QtGui.QIcon(\":/icons/sel-bbox.svg\")))\n        self.CB_04_Progression = QtWidgets.QCheckBox()\n        self.CB_04_Progression.setIcon(QtGui.QIcon(QtGui.QPixmap(setIconProgress))) # progress icone dans une variable \n        self.CB_05_Reset = QtWidgets.QCheckBox()\n        if switchResetFALSE == 1:\n            self.CB_05_Reset.setChecked(True)\n            self.CB_05_Reset.setIcon(QtGui.QIcon(QtGui.QPixmap(setIconNoReset))) # reset icone dans une variable \n        else:\n            self.CB_05_Reset.setChecked(False)\n            self.CB_05_Reset.setIcon(QtGui.QIcon(QtGui.QPixmap(resetIcon))) # reset icone dans une variable \n        self.CB_05_Reset.clicked.connect(self.on_CB_05_Reset)\n\n        self.CB_06_ModeFree = QtWidgets.QCheckBox()\n        self.CB_06_ModeFree.setIcon(QtGui.QIcon(QtGui.QPixmap(setIconFree))) # progress icone dans une variable \n        self.CB_06_ModeFree.clicked.connect(self.on_CB_06_ModeFree)\n\n        self.PB_Delete_Last = QtWidgets.QPushButton()\n        self.PB_Delete_Last.setIcon(QtGui.QIcon(QtGui.QPixmap(setIconDel))) # del icone dans une variable \n        self.PB_Delete_Last.clicked.connect(self.on_PB_Delete_Last)\n\n        self.PU_Exit = QtWidgets.QPushButton()\n        self.PU_Exit.setIcon(QtGui.QIcon(QtGui.QPixmap(quitIcon))) # quit icone dans une variable \n        #self.PU_Exit.setIconSize(QtCore.QSize(26, 26))\n        self.PU_Exit.clicked.connect(self.on_PU_Exit)\n\n        self.PU_Reset = QtWidgets.QPushButton()\n        self.PU_Reset.setEnabled(True)\n        self.PU_Reset.setIcon(QtGui.QIcon(QtGui.QPixmap(resetIcon)))  # reset icone dans une variable \n        self.PU_Reset.clicked.connect(self.on_PU_Reset)\n\n        self.PU_Benchmarks = QtWidgets.QPushButton()\n        self.PU_Benchmarks.setIcon(QtGui.QIcon(QtGui.QPixmap(executeIcon)))# execute icone dans une variable \n        self.PU_Benchmarks.clicked.connect(self.on_PU_Benchmarks)\n\n        self.PU_Execute = QtWidgets.QPushButton()\n        self.PU_Execute.setIcon(QtGui.QIcon(QtGui.QPixmap(executeIcon)))# execute icone dans une variable \n        self.PU_Execute.clicked.connect(self.on_PU_Execute)\n        #### Tab Onglets\n        ####\n        #### gridLayout begin #######################\n        self.grid_00 = QtWidgets.QGridLayout()  #self.centralWidget  #scrollAreaWidgetContents_2 #self.\n        #self.grid_00.setContentsMargins(10, 10, 10, 10)\n        self.grid_00.addWidget(self.groupBox_00, 0, 0, 1, 1)    # groupBox_01\n        vbox.addWidget(self.groupBox_00)      # englobe le cadre principal (titre + date)\n        ####\n        ##\n        self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox_00)\n        self.gridLayout_2.setContentsMargins(10, 10, 10, 10)\n        ##\n        self.gridLayout_Texte = QtWidgets.QGridLayout(self.groupBox_01)  # groupes .....\n        self.gridLayout_Texte.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_Texte.addWidget(self.textEdit, 0, 0, 1, 1)\n        ##\n        self.gridLayout_frame_Option = QtWidgets.QGridLayout(self.frame_Option)\n        self.gridLayout_frame_Option.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_frame_Option.addWidget(self.PB_Reverse, 0, 0, 1, 1)\n        self.gridLayout_frame_Option.addWidget(self.CB_Word, 1, 0, 1, 1)\n        self.gridLayout_frame_Option.addWidget(self.PB_Help,2, 0, 1, 1)\n        self.gridLayout_Texte.addWidget(self.frame_Option, 0, 1, 1, 1)\n        ##\n        self.gridLayout_Texte.addWidget(self.lineEdit_NameFile,1, 0, 1, 1)#_Font\n        self.gridLayout_Texte.addWidget(self.lineEdit_NameFile_button,1, 1, 1, 1)#_Font\n        self.gridLayout_Texte.addWidget(self.comboBoxPy,2, 0, 1, 1)#_Font\n        self.gridLayout_Texte.addWidget(self.PB_systemPath,2, 1, 1, 1)#_Font\n        self.gridLayout_2.addWidget(self.groupBox_01, 0, 0, 1, 1)\n        ####\n        self.gridLayout_Config = QtWidgets.QGridLayout(self.groupBox_02)\n        self.gridLayout_Config.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_Config.addWidget(self.groupBox_03, 0, 0, 7, 2)\n        self.gridLayout_Choice = QtWidgets.QGridLayout(self.groupBox_03)\n        self.gridLayout_Choice.addWidget(self.RA_Choice_Outdoor, 0, 0, 1, 1)\n        self.gridLayout_Choice.addWidget(self.RA_Choice_Indoor, 1, 0, 1, 1)\n        self.gridLayout_Choice.addWidget(self.RA_Choice_Helix, 0, 1, 1, 1)  # Visible False not used but stay cause new TAB\n        self.gridLayout_Choice.addWidget(self.RA_Choice_Clock, 1, 1, 1, 1)  # Visible False not used but stay cause new TAB \n        #self.gridLayout_Choice.addWidget(self.RA_Choice_Stamp,2, 1, 1, 1)\n        self.gridLayout_Choice.addWidget(self.PU_Flat, 2, 0, 1, 2)\n        self.gridLayout_Choice.addWidget(self.graphicsView, 3, 0, 1, 2)\n        ##\n        self.gridLayout_Config.addWidget(self.DS_Radius_Circle, 0, 2, 1, 1)\n        self.gridLayout_Config.addWidget(self.label_10, 0, 3, 1, 1)\n        self.gridLayout_Config.addWidget(self.DS_Size_Character, 1, 2, 1, 1)\n        self.gridLayout_Config.addWidget(self.label_4, 1, 3, 1, 1)\n        self.gridLayout_Config.addWidget(self.S_Begin_Angle, 2, 2, 1, 1)\n        self.gridLayout_Config.addWidget(self.label_13, 2, 3, 1, 1)\n        self.gridLayout_Config.addWidget(self.S_End_Angle, 3, 2, 1, 1)\n        self.gridLayout_Config.addWidget(self.label_14, 3, 3, 1, 1)\n        self.gridLayout_Config.addWidget(self.DS_Correction_Angle, 4, 2, 1, 1)\n        self.gridLayout_Config.addWidget(self.label_7, 4, 3, 1, 1)\n        self.gridLayout_Config.addWidget(self.DS_Correction_Radius, 5, 2, 1, 1)\n        self.gridLayout_Config.addWidget(self.label_8, 5, 3, 1, 1)\n        self.gridLayout_Config.addWidget(self.DS_Extrude, 6, 2, 1, 1)\n        self.gridLayout_Config.addWidget(self.CH_Extrude, 6, 3, 1, 1)\n        self.gridLayout_Config.addWidget(self.DS_PlacementX, 7, 0, 1, 1)\n        self.gridLayout_Config.addWidget(self.DS_PlacementY, 7, 1, 1, 1)\n        self.gridLayout_Config.addWidget(self.DS_PlacementZ, 7, 2, 1, 1)\n        self.gridLayout_Config.addWidget(self.CH_Sp_Placement, 7, 3, 1, 1)\n        self.gridLayout_Config.addWidget(self.DS_InclinaisonX, 8, 0, 1, 1)\n        self.gridLayout_Config.addWidget(self.DS_InclinaisonY, 8, 1, 1, 1)\n        self.gridLayout_Config.addWidget(self.DS_InclinaisonZ, 8, 2, 1, 1)\n        self.gridLayout_Config.addWidget(self.CH_Sp_Inclination, 8, 3, 1, 1)\n        self.gridLayout_2.addWidget(self.groupBox_02, 1, 0, 1, 1)\n        ####\n        self.TAB_Command = QtWidgets.QWidget()\n        self.gridLayout_Command = QtWidgets.QGridLayout(self.TAB_Command)\n        self.gridLayout_Command.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_Command.addWidget(self.CB_01_Points, 0, 0, 1, 1)\n        self.gridLayout_Command.addWidget(self.CB_02_Circle, 0, 1, 1, 1)\n        self.gridLayout_Command.addWidget(self.CB_03_BBox, 0, 2, 1, 1)\n        self.gridLayout_Command.addWidget(self.CB_04_Progression, 0, 3, 1, 1)\n        self.gridLayout_Command.addWidget(self.CB_06_ModeFree, 1, 0, 1, 1)\n        self.gridLayout_Command.addWidget(self.CB_05_Reset, 1, 2, 1, 1)\n        self.gridLayout_Command.addWidget(self.PB_Delete_Last, 1, 3, 1, 1)\n        self.gridLayout_Command.addWidget(self.PU_Execute, 2, 0, 1, 1)\n        self.gridLayout_Command.addWidget(self.PU_Benchmarks, 2, 1, 1, 1)\n        self.gridLayout_Command.addWidget(self.PU_Reset, 2, 2, 1, 1)\n        self.gridLayout_Command.addWidget(self.PU_Exit, 2, 3, 1, 1)\n        self.tabWidget.addTab(self.TAB_Command, QtGui.QIcon(QtGui.QPixmap(setIconCommand)), \"\")\n        ####\n        self.gridLayout_2.addWidget(self.tabWidget, 2, 0, 1, 2)     #linge, colonne, ligne case, nombre de cases)\n        self.TAB_Helix = QtWidgets.QWidget()\n        self.gridLayout_Helix = QtWidgets.QGridLayout(self.TAB_Helix)\n        self.gridLayout_Helix.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_Helix.addWidget(self.DS_Step_Of_The_Helix, 0, 0, 1, 1)\n        self.gridLayout_Helix.addWidget(self.label_12, 0, 1, 1, 1)\n        self.gridLayout_Helix.addWidget(self.DS_Number_Char_Per_Turn, 0, 2, 1, 1)\n        self.gridLayout_Helix.addWidget(self.label, 0, 3, 1, 1)\n        self.gridLayout_Helix.addWidget(self.DS_Base_Helix, 1, 0, 1, 1)\n        self.gridLayout_Helix.addWidget(self.label_2, 1, 1, 1, 1)\n        self.gridLayout_Helix.addWidget(self.DS_End_Helix, 1, 2, 1, 1)\n        self.gridLayout_Helix.addWidget(self.label_3, 1, 3, 1, 1)\n        self.tabWidget.addTab(self.TAB_Helix, QtGui.QIcon(QtGui.QPixmap(setIconHelix)), \"\")\n        ####\n        self.TAB_Clock = QtWidgets.QWidget()\n        self.gridLayout_Clock = QtWidgets.QGridLayout(self.TAB_Clock)\n        self.gridLayout_Clock.addWidget(self.DS_Number_Faces_Support, 0, 0, 1, 1)\n        self.gridLayout_Clock.addWidget(self.label_5, 0, 1, 1, 1)\n        self.gridLayout_Clock.addWidget(self.CB_RomanOrArabic, 0, 2, 1, 1)\n        self.gridLayout_Clock.addWidget(self.DS_Radius_Support, 1, 0, 1, 1)\n        self.gridLayout_Clock.addWidget(self.label_11, 1, 1, 1, 1)\n        self.gridLayout_Clock.addWidget(self.CB_RedressChiffres, 1, 2, 1, 1)\n        self.gridLayout_Clock.addWidget(self.DS_Extrude_Support, 2, 0, 1, 1)\n        self.gridLayout_Clock.addWidget(self.label_6, 2, 1, 1, 1)\n        self.tabWidget.addTab(self.TAB_Clock, QtGui.QIcon(QtGui.QPixmap(setIconClock)), \"\")\n        ####\n        self.TAB_Path = QtWidgets.QWidget()\n        self.gridLayout_Path = QtWidgets.QGridLayout(self.TAB_Path)\n        self.gridLayout_Path.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_frame_Path = QtWidgets.QGridLayout(self.frame_Path)\n        self.gridLayout_frame_Path.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_frame_Path.addWidget(self.RB_Path_01, 0, 1, 1, 1)\n        self.gridLayout_frame_Path.addWidget(self.RB_Path_02, 0, 2, 1, 1)\n        self.gridLayout_Path.addWidget(self.frame_Path, 0, 0, 1, 1)\n        ##\n        self.gridLayout_frame_Position = QtWidgets.QGridLayout(self.frame_Position)\n        self.gridLayout_frame_Position.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_frame_Position.addWidget(self.RB_Position_01, 0, 0, 1, 1)\n        self.gridLayout_frame_Position.addWidget(self.RB_Position_02, 0, 1, 1, 1)\n        self.gridLayout_frame_Position.addWidget(self.RB_Position_03, 0, 2, 1, 1)\n        self.gridLayout_Path.addWidget(self.frame_Position, 1, 0, 1, 1)\n        self.tabWidget.addTab(self.TAB_Path, QtGui.QIcon(QtGui.QPixmap(setIconPath)), \"\")\n        ####\n#        self.TAB_Stamp = QtWidgets.QWidget() # tab Stamp\n#        self.gridLayout_Stamp = QtWidgets.QGridLayout(self.TAB_Stamp)\n#        self.gridLayout_Stamp.setContentsMargins(10, 10, 10, 10)\n#\n#        self.tabWidget.addTab(self.TAB_Stamp, QtGui.QIcon(QtGui.QPixmap(setIconStamp)), \"\")\n        ####\n        ###########################################################scrollArea\n        self.scrollArea.setWidget(self.scrollAreaWidgetContents_2)\n        ###########################################################scrollArea\n        #### gridLayout end #######################\n        ####\n        ####\n        MainWindow.setCentralWidget(self.centralWidget)\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n        global originalFontPath\n        global originalFontName\n        global setPathLatestDirectoryManual\n\n        MainWindow.setWindowFlags(PySide2.QtCore.Qt.WindowStaysOnTopHint)                         # PySide cette fonction met la fenetre en avant\n        MainWindow.setWindowTitle(_fromUtf8(__Title__))\n        MainWindow.setWindowIcon(QtGui.QIcon(_fromUtf8(self.path + \"FCCircularTextButtom.png\")))  # change l'icone de la fenetre principale\n        self.groupBox_00.setTitle(_fromUtf8(\"Ver : \" + __Version__ + \" : \" +  __Date__) + \" (rmu)\")\n\n        self.groupBox_01.setTitle(_fromUtf8(\"Text to be displayed  ( \"+str(len(texte))+\" characters )\"))\n        self.textEdit.setHtml(_fromUtf8(texte))\n        self.textEdit.setToolTip(_fromUtf8(\"Your text to be displayed\" + \"\\n\"\n                                           \"the last character superpose de first character ! \" + \"\\n\"\n                                           \"you must adding one space after the last character\" + \"\\n\"\n                                           \"you must adding space for adjust, the space is consirdered as character\"))\n        self.PB_Reverse.setText(_fromUtf8(\"Reverse\"))\n        self.PB_Reverse.setToolTip(_fromUtf8(\"Reverse the text edited\"))\n        try:\n            self.lineEdit_NameFile.setText(_fromUtf8(\"(\" + str(self.index + 1) + \"/\" + str(len(self.tableau)) + \") \" + self.tableau[self.index][1]))\n        except Exception:\n            None\n        self.lineEdit_NameFile.setToolTip(_fromUtf8(\"(Number index / Number Fonts) Complete path and name of Font file\"))\n        self.lineEdit_NameFile_button.setText(_fromUtf8(\"Other\"))\n        self.lineEdit_NameFile_button.setToolTip(_fromUtf8(\"Search other folder font\" + \"\\n\"\n                                                \"Latest directory visited :\" + \"\\n\" +\n                                                 setPathLatestDirectoryManual))\n        self.PB_systemPath.setText(_fromUtf8(\"Origine\"))\n        self.PB_systemPath.setToolTip(_fromUtf8(\"Return origine\" + \"\\n\" +\n                                                \"( \" + originalFontPath + originalFontName + \" )\"))\n\n        self.PB_Help.setText(_fromUtf8(\"Help\"))\n        self.CB_Word.setText(_fromUtf8(\"Word\"))\n        self.CB_Word.setToolTip(_fromUtf8(\"If Word is checked, the text are clipped to each space\" + \"\\n\"\n                                          \"one space egual one character.\" + \"\\n\\n\"\n                                          \"If in mode Path you work with a circle,\" + \"\\n\"\n                                          \"the last character superpose de first character ! \" + \"\\n\"\n                                          \"you must adding one space after the last character\" + \"\\n\"\n                                          \"for spacing the last and the first character\" + \"\\n\\n\"\n                                          \"You must work with the space as the character\"))\n\n        #### matplotlib debut 4/5 retranslateUi #################################################################\n        self.comboBoxPy.setToolTip(\"Choice your Font\" + \"\\n\" +\n                                   \"\\n\" +\n                                   \"You must modify the configuration of display\" + \"\\n\" +\n                                   \"Menu Edit parameter: User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__ + \":\" + \"\\n\" +\n                                   \"####\" + \"\\n\" +\n                                   \"switchModeTextList= 1\\t# 0 = mode text normal (the switchFontComBox is enabled)\" + \"\\n\"\n                                   \"\\t\\t\\t# 1 = switchFontComBox authorized (default)\" + \"\\n\"\n                                   \"\\t\\t\\t#####\" + \"\\n\"\n                                   \"switchFontComBox  = 1\\t# 0 = mode text in color .. faster\" + \"\\n\"\n                                   \"\\t\\t\\t# 1 = fontFamily listed ComboBox slower but beautiful (default)\" + \"\\n\"\n                                   \"\\t\\t\\t#####\" + \"\\n\"\n                                   \"setSystemFonts    = 1\\t# 0 = matplotlib.font_manager.findSystemFonts\" + \"\\n\"\n                                   \"\\t\\t\\t#   all fonts in System font\" + \"\\n\"\n                                   \"\\t\\t\\t# 1 = fontman.findSystemFonts(self.pathFont) (default)\" + \"\\n\"\n                                   \"\\t\\t\\t# all fonts in all directory and sub directory\" + \"\\n\"\n                                   \"\\t\\t\\t#####\" + \"\\n\"\n                                   \"seTtextAlignement = 0\\t# 0 = AlignLeft (default)\" + \"\\n\"\n                                   \"\\t\\t\\t# 1 = AlignCenter\" + \"\\n\"\n                                   \"\\t\\t\\t# 2 = AlignRight\" + \"\\n\"\n                                   \"\\t\\t\\t#####\" + \"\\n\"\n                                   \"setFontByDefault = \"\"ARIAL\"\"\\t # ARIAL\" + \"\\n\"\n                                   \"\\t\\t\\t#####\" + \"\\n\"\n                                   \"switchResetFALSE = 0\\t # 0 by default.\" + \"\\n\"\n                                   \"If you use this option [ switchResetFALSE = 1 ] some switch can be opened when it should not be\" + \"\\n\"\n                                   \"then it is advisable to do a reset after a change one option\" + \"\\n\"\n                                   \"####\" + \"\\n\"\n                                   \"Actual configuration : \" + str(switchModeTextList) + \", \" + str(switchFontComBox) + \", \" + str(setSystemFonts) + \", \"\n                                                             + str(seTtextAlignement) + \", \" + setFontByDefault + \", \" + str(switchResetFALSE) + \"\\n\"\n                                   \"####\" + \"\\n\" +\n                                   \"Read the info\")\n        #### matplotlib fin 4/5 retranslateUi #################################################################\n\n        self.groupBox_02.setTitle(_fromUtf8(\"Configuration\"))\n        self.DS_Radius_Circle.setToolTip(_fromUtf8(\"Give the radius of circle\"))\n        self.DS_Radius_Circle.setSuffix(_fromUtf8(\" mm\"))\n        self.label_10.setText(_fromUtf8(\"Radius of circle\"))\n        self.DS_Size_Character.setToolTip(_fromUtf8(\"Size of the font\"))\n        self.DS_Size_Character.setSuffix(_fromUtf8(\" mm\"))\n        self.label_4.setText(_fromUtf8(\"Character size\"))\n        self.S_Begin_Angle.setToolTip(_fromUtf8(\"Starting text of the circle \"))\n        self.S_Begin_Angle.setSuffix(_fromUtf8(\" deg\"))\n        self.label_13.setText(_fromUtf8(\"Starting angle\"))\n        self.S_End_Angle.setToolTip(_fromUtf8(\"End text of the circle \"))\n        self.S_End_Angle.setSuffix(_fromUtf8(\" deg\"))\n        self.label_14.setText(_fromUtf8(\"Ending angle\"))\n        self.DS_Correction_Angle.setToolTip(_fromUtf8(\"Correct angle for tangent the text of thr circle or give a tilt angle\" + \"\\n\"\n                                                      \"this option is adding to the original angle (Sp. inclination)\"))\n        self.DS_Correction_Angle.setSuffix(_fromUtf8(\" deg\"))\n        self.label_7.setText(_fromUtf8(\"Correction Angle\"))\n        self.DS_Correction_Radius.setToolTip(_fromUtf8(\"Correct of the radius (depend of correction angle)\" + \"\\n\"\n                                                       \"this option is adding to the original radius (Radius of circle)\"))\n        self.DS_Correction_Radius.setSuffix(_fromUtf8(\" mm\"))\n        self.label_8.setText(_fromUtf8(\"Correction Radius\"))\n        self.DS_Extrude.setSuffix(_fromUtf8(\" mm\"))\n        self.DS_Extrude.setToolTip(_fromUtf8(\"Thickness of the extrude of character. If thickness = 0 then not extrude\"))\n        self.CH_Extrude.setText(_fromUtf8(\"Extrude Char.\"))\n        self.CH_Extrude.setToolTip(_fromUtf8(\"Choice extrude character or not\"))\n        ####\n        self.DS_PlacementX.setSuffix(_fromUtf8(\" X mm\"))\n        self.DS_PlacementX.setToolTip(_fromUtf8(\"Placement direction X\" + \"\\n\" \n                                                \"Not used with the Clock option\"))\n        self.DS_PlacementY.setSuffix(_fromUtf8(\" Y mm\"))\n        self.DS_PlacementY.setToolTip(_fromUtf8(\"Placement direction Y\" + \"\\n\" \n                                                \"Not used with the Clock option\"))\n        self.DS_PlacementZ.setSuffix(_fromUtf8(\" Z mm\"))\n        self.DS_PlacementZ.setToolTip(_fromUtf8(\"Placement direction Z\"+ \"\\n\"\n                                                \"For Clock option only this Z axis is available\"))\n        self.CH_Sp_Placement.setText(_fromUtf8(\"Placement\"))\n        self.CH_Sp_Placement.setToolTip(_fromUtf8(\"Placement of character in the choice\"))\n        #carDegrees = b' \\xc2\\xb0'.decode(\"utf-8\")    #thanks wmayer    https://forum.freecadweb.org/viewtopic.php?f=13&t=36380&p=308476#p308357\n        self.DS_InclinaisonX.setSuffix(_fromUtf8(\" deg (Yaw)\"))\n        self.DS_InclinaisonX.setToolTip(_fromUtf8(\"Inclination character in axis Z\"))\n        self.DS_InclinaisonY.setSuffix(_fromUtf8(\" deg (Pitch)\"))\n        self.DS_InclinaisonY.setToolTip(_fromUtf8(\"Inclination character axis Y\"))\n        self.DS_InclinaisonZ.setSuffix(_fromUtf8(\" deg (Roll)\"))\n        self.DS_InclinaisonZ.setToolTip(_fromUtf8(\"Inclination character axis X\"))\n        self.CH_Sp_Inclination.setText(_fromUtf8(\"Sp. inclination\"))\n        self.CH_Sp_Inclination.setToolTip(_fromUtf8(\"Inclination of character in the choice or alls plane \"))\n        ####\n        self.groupBox_03.setTitle(_fromUtf8(\"Choice\"))\n        self.RA_Choice_Outdoor.setText(_fromUtf8(\"Outdoor\"))\n        self.RA_Choice_Outdoor.setToolTip(_fromUtf8(\"Create the text on the outer face of the cylinder\"))\n        self.RA_Choice_Indoor.setText(_fromUtf8(\"Indoor\"))\n        self.RA_Choice_Indoor.setToolTip(_fromUtf8(\"Create the text on the inside of the cylinder\"))\n        self.RA_Choice_Helix.setText(_fromUtf8(\"Helix\"))\n        self.RA_Choice_Helix.setToolTip(_fromUtf8(\"Create the text in a helix\"))\n        self.RA_Choice_Clock.setText(_fromUtf8(\"Clock\"))\n        self.RA_Choice_Clock.setToolTip(_fromUtf8(\"Create the text to form a clock\"))\n        #self.RA_Choice_Stamp.setText(_fromUtf8(\"Stamp\"))\n        #self.RA_Choice_Stamp.setToolTip(_fromUtf8(\"Create stamp text (text reversed)\"))\n        self.PU_Flat.setText(_fromUtf8(\"Mode Stand\"))\n        self.PU_Flat.setToolTip(_fromUtf8(\"Click for create the text Flat\"))\n        ####\n        self.tabWidget.setTabText(self.tabWidget.indexOf(self.TAB_Helix), _fromUtf8(\"Helix\"))\n        self.tabWidget.setTabToolTip(1,_fromUtf8(\"Create one helix\"))\n        self.DS_Step_Of_The_Helix.setSuffix(_fromUtf8(\" mm\"))\n        self.DS_Step_Of_The_Helix.setToolTip(_fromUtf8(\"Step of the text along the helix (min Size Caractere)\"))\n        self.label_12.setText(_fromUtf8(\"Step of Helix\"))\n        self.DS_Number_Char_Per_Turn.setToolTip(_fromUtf8(\"Number of characters for one turn of helix\"))\n        self.label.setText(_fromUtf8(\"Char. per turn\"))\n        self.DS_Base_Helix.setToolTip(_fromUtf8(\"Base (begin) of helix (to activate Step of Helix must be zero)\"))\n        self.DS_Base_Helix.setSuffix(_fromUtf8(\" mm\"))\n        self.label_2.setText(_fromUtf8(\"Base Helix\"))\n        self.DS_End_Helix.setToolTip(_fromUtf8(\"Final height of the helix (to activate Step of Helix must be zero)\"))\n        self.DS_End_Helix.setSuffix(_fromUtf8(\" mm\"))\n        self.label_3.setText(_fromUtf8(\"End Helix\"))\n        ####\n        self.tabWidget.setTabText(self.tabWidget.indexOf(self.TAB_Clock), _fromUtf8(\"Clock\"))\n        self.tabWidget.setTabToolTip(2,_fromUtf8(\"Create one clock with character mode Arabic or Roman\"))\n        self.DS_Radius_Support.setSuffix(_fromUtf8(\" mm\"))\n        self.DS_Radius_Support.setToolTip(_fromUtf8(\"Radius of the support the clock (By defaut : Radius of circle)\"))\n        self.label_11.setText(_fromUtf8(\"Radius of support\"))\n        self.CB_RomanOrArabic.setText(_fromUtf8(\"Mode Arabic\"))\n        self.CB_RomanOrArabic.setToolTip(_fromUtf8(\"The characters is in Roman or Arabic (default)\"))\n        self.DS_Number_Faces_Support.setToolTip(_fromUtf8(\"Number of side of the support 0=none, 1=circle, 2=rectangle, 3=triangle, 4=square, 5=pentagon . . . . (Thickness egal extrude)\"))\n        self.label_5.setText(_fromUtf8(\"Support number face\"))\n        self.CB_RedressChiffres.setText(_fromUtf8(\"Axial\"))\n        self.CB_RedressChiffres.setToolTip(_fromUtf8(\"Click for activate the mode Redress\"))\n        self.DS_Extrude_Support.setToolTip(_fromUtf8(\"Thickness of the extrude the support.\" + \"\\n\"\n                                                     \"If thickness = 0 then not extrude\" + \"\\n\"\n                                                     \"If thickness of support is bigger than character\" + \"\\n\"\n                                                     \"the SpinBox is colored in red\" + \"\\n\"\n                                                     \"if the CheckBox [Extrude Char.] is not checked\" + \"\\n\"\n                                                     \"the SpinBox is colored in orange for warn that the character is at the base of the support\"))\n        self.DS_Extrude_Support.setSuffix(_fromUtf8(\" mm\"))\n        self.label_6.setText(_fromUtf8(\"Extrude support\"))\n        ####\n        self.tabWidget.setTabText(self.tabWidget.indexOf(self.TAB_Path), _fromUtf8(\"Path\")) # tab Path\n        self.tabWidget.setTabEnabled(3, False)\n        self.tabWidget.setTabToolTip(3,_fromUtf8(\"The string follow the wire selected (Based on X, Y plane)\" + \"\\n\"\n                                               \"The buttons Outdoor, Helix, Indoor, Clock and\"\n                                               \"the button Mode Stand / Flat are ignored\" + \"\\n\"\n                                               \"The direction of the text depend of the direction Left/Right of the wire selected\" + \"\\n\"\n                                               \"in this case use the Reverse Button\"))\n        self.RB_Path_01.setText(_fromUtf8(\"Orthogonal\"))\n        self.RB_Path_01.setToolTip(_fromUtf8(\"The character is orthogonal\"))\n        self.RB_Path_02.setText(_fromUtf8(\"Tangent\"))\n        self.RB_Path_02.setToolTip(_fromUtf8(\"The character is tangent on position wire selected\"))\n\n        self.RB_Position_01.setText(_fromUtf8(\"BB Base\"))\n        self.RB_Position_01.setToolTip(_fromUtf8(\"The BoundBox of the character is on Base\"))\n        self.RB_Position_02.setText(_fromUtf8(\"BB Center\"))\n        self.RB_Position_02.setToolTip(_fromUtf8(\"The BoundBox of the character is on BB Center\"))\n        self.RB_Position_03.setText(_fromUtf8(\"BB Top\"))\n        self.RB_Position_03.setToolTip(_fromUtf8(\"The BoundBox of the character is on BB Top\"))\n#  later      self.label_Path_01.setText(_fromUtf8(\"Rotation str\"))\n#  later      self.label_Path_02.setText(_fromUtf8(\"Rotation car\"))\n#  later      self.label_Path_03.setText(_fromUtf8(\"Translation\"))\n        ####\n#        self.tabWidget.setTabText(self.tabWidget.indexOf(self.TAB_Stamp), _fromUtf8(\"Stamp\")) # tab Stamp\n#        self.tabWidget.setTabToolTip(4,_fromUtf8(\"Stamp\"))\n        ####\n        self.tabWidget.setTabText(self.tabWidget.indexOf(self.TAB_Command), _fromUtf8(\"Command\"))\n        self.tabWidget.setTabToolTip(0,_fromUtf8(\"Command section\"))\n        self.CB_01_Points.setText(_fromUtf8(\"Points\"))\n        self.CB_01_Points.setToolTip(_fromUtf8(\"Create points repere\"))\n        self.CB_02_Circle.setText(_fromUtf8(\"Circle\"))\n        self.CB_02_Circle.setToolTip(_fromUtf8(\"Create Circle repere\" + \"\\n\"\n                                               \"if helix is used one helix is created with the circle\"))\n        self.CB_03_BBox.setText(_fromUtf8(\"BoundBox\"))\n        self.CB_03_BBox.setToolTip(_fromUtf8(\"Create BoundBox on character\"))\n        self.CB_04_Progression.setText(_fromUtf8(\"Progression\"))\n        self.CB_04_Progression.setToolTip(_fromUtf8(\"Visualise the character in construction\"))\n        self.CB_05_Reset.setText(_fromUtf8(\"Reset\"))\n        self.CB_05_Reset.setToolTip(_fromUtf8(\"Reset checkBox False by default (reset on all push button execute)\" + \"\\n\"\n                                              \"If you check this option No reset is performed\" + \"\\n\"\n                                              \"and if the result is not good\" + \"\\n\"\n                                              \"ex: the old internal coordinate hare conserved or other...\" + \"\\n\"\n                                              \"push the Reset button or \" + \"\\n\"\n                                              \"uncheck this checkBox and try or restart FCCircularText\"))\n        self.CB_06_ModeFree.setText(_fromUtf8(\"Free\"))\n        self.CB_06_ModeFree.setToolTip(_fromUtf8(\"Mode Free, all pre-settings are ignored\" + \"\\n\"\n                                                 \"Free as a cloud\"))\n        self.PB_Delete_Last.setText(_fromUtf8(\"Del\"))\n        self.PB_Delete_Last.setToolTip(_fromUtf8(\"Delete the last object created\"))\n        self.PU_Exit.setText(_fromUtf8(\"Exit\"))\n        self.PU_Exit.setToolTip(_fromUtf8(\"Exit FCCircularText\"))\n        self.PU_Reset.setText(_fromUtf8(\"Reset\"))\n        self.PU_Reset.setToolTip(_fromUtf8(\"Reset all parameters of the macro\"))\n        self.PU_Execute.setText(_fromUtf8(\"Run\"))\n        self.PU_Execute.setToolTip(\"Execute the process\") # without Compount\n        self.PU_Benchmarks.setText(_fromUtf8(\"Run+Comp\"))\n        self.PU_Benchmarks.setToolTip(_fromUtf8(\"Execute the process and one Compount of the characters is create\"))\n        ####\n\n    #### matplotlib debut 5/5 #################################################################\n    def on_fontComboBoxPython(self,indeX):                                          # 0: for fontComboBoxPython\n        global PolicePath\n        global setFontByDefault\n\n        self.index = indeX\n        self.lineEdit_NameFile.setText(\"(\" + str(self.index + 1) + \"/\" + str(len(self.tableau)) + \") \" + self.tableau[self.index][1])\n        PolicePath = self.tableau[self.index][1]\n\n        famille = typeCar = self.font = \"\"\n        self.font = QtGui.QFont()\n        typeCar   = family(self.tableau[self.index][2])[1]\n        self.font.setBold(False)\n        self.font.setItalic(False)\n\n        if len(typeCar) > 0:\n            for option in typeCar:\n                if option == \"Bold\":\n                    self.font.setBold(True)\n                if (option == \"Italic\") or (option == \"It\") or (option == \"Slanted\"):\n                    self.font.setItalic(True)\n                if option == \"Oblique\":\n                    self.font.setItalic(True)\n        #'Bold''Regular''Slanted''Italic''Medium''Extra''Light''Condensed''Black''It''Semibold'#+\n        \n        self.font.setFamily(self.tableau[self.index][5])\n        self.font.setPointSize(self.FontTextSize)\n        ####\n        self.fonteComp   = self.tableau[self.index][1]\n        setFontByDefault = self.tableau[self.index][2]\n#        FreeCAD.Console.PrintMessage(str(self.index) + \" , \" + self.tableau[self.index][1] + \" , \" + self.tableau[self.index][2] + \" , ' \" + famille + \"' , ' \" + typeCar + \" ' \\n\")\n    #### matplotlib fin 5/5 #################################################################\n\n    def on_lineEdit_NameFile(self, setFontByDefault):\n        self.pathFont = self.lineEdit_NameFile.text() \n        try:\n            self.pathFont  = self.pathFont.split(\")\") [1]\n        except Exception:\n            self.pathFont  = self.pathFont\n\n        ui.searchFont(self.pathFont, setFontByDefault)\n        QtCore.QObject.connect(self.comboBoxPy, QtCore.SIGNAL(\"currentIndexChanged(int)\"), self.on_fontComboBoxPython)\n\n    def on_lineEdit_NameFile_button(self): # path manual\n        global setPathLatestDirectoryManual\n        global ui\n\n        OpenName = \"\"\n        ####  mint\n        if platform.node() == \"mint\":\n            OpenName, Filter = PySide2.QtWidgets.QFileDialog.getOpenFileName(None, u\"Read a font file\", setPathLatestDirectoryManual, \"(otf *.otf);;(ttf *.ttf);;(ttc *.ttc);;(*.*);;(*)\")#PySide2 Mint\n        ####  mint\n        else:\n            OpenName, Filter = PySide2.QtWidgets.QFileDialog.getOpenFileName(None, u\"Read a font file\", setPathLatestDirectoryManual, \"*.otf *.ttf *.ttc ;;OpenType Font (*.otf);;TrueType Font (*.ttf);;TrueType Collection (*.ttc);;All (*.*);;All (*)\")#PySide2\n        try:\n            if OpenName != \"\":    # \"C:/Temp/FontesTemp/arial.ttf\"\n                ####new2\n                pathFile      = os.path.dirname(OpenName) + \"/\"  #1# = C:/Provisoire400/\n                racineDrive   = os.path.splitdrive(OpenName)[0]  #2# = C:\n                formatFichier = os.path.splitext(OpenName)[1]    #4# = .png\n                OpenName      = os.path.splitext(OpenName)[0]    #5# = /home/kubuntu/.FreeCAD/Macro/Texture_007_H #= C:/Provisoire400/image3D\n                nomFichier    = os.path.basename(OpenName)       #3# = image3D\n                SaveNameformatFichier = OpenName + formatFichier #6# = C:/Provisoire400/image3D.png\n                pathFileSaveNameformatFichier = pathFile + nomFichier + formatFichier #7# = C:/Provisoire400/image3D.png\n                ####new2\n                setPathLatestDirectoryManual = pathFile\n                FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetString(u\"setPathLatestDirectoryManual\", setPathLatestDirectoryManual)    #*\"C:\\ ???\"\n                ui.searchFont(pathFile, nomFichier)\n        except Exception:\n            None\n\n    def on_PB_systemPath(self):    # return font origin system\n        global ui\n        global setSystemFonts\n        global originalFontPath\n        global originalFontName\n        global setLastFontPath\n        global searchFontName\n\n        setSystemFonts = 1\n        setLastFontPath  = originalFontPath\n        ui.searchFont(originalFontPath, originalFontName)\n\n    def on_textEdit_Changed(self):        #connection textEdit\n        global ui\n\n        ui.on_CB_Word()\n\n    def on_PB_Reverse(self):              #connection Reverse\n        global texte\n\n        texte = self.textEdit.toPlainText()\n        texte = texte[::-1]\n        self.textEdit.setText(_fromUtf8(texte))\n\n    def on_CB_Word(self):\n        global texte\n\n        texte = \"\"\n        texte = self.textEdit.toPlainText()\n\n        try:\n            selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0]\n        except Exception:\n            selectedEdge = \"\"\n\n        if self.CB_Word.isChecked():\n            texte = texte.split(\" \")\n            mot = \"word\"\n        else:\n            mot = \"characters\"\n\n        if (texte.count(\" \") == 1) or (texte.count(\" \") == 0):\n            espace = \"space\"\n        else:\n            espace = \"spaces\"\n\n        if str(selectedEdge) != \"\":\n            self.groupBox_01.setTitle(\"Text to be displayed  ( \"+str(len(texte))+ \" \" + mot + \" ) ( \" + str(texte.count(\" \")) + \" \" + espace + \" ) ( Lenght \" + str(round(selectedEdge.Length,3)) + \" mm )\")\n        else:\n            self.groupBox_01.setTitle(\"Text to be displayed  ( \"+str(len(texte))+ \" \" + mot + \" ) ( \" + str(texte.count(\" \")) + \" \" + espace + \" )\")\n\n        if self.RA_Choice_Outdoor.isChecked():\n            self.Image_RA_Choice_Outdoor()\n        if self.RA_Choice_Indoor.isChecked():\n            self.Image_RA_Choice_Indoor()\n\n    def on_PU_Reset_Placement(self):           # Reset_Placement\n        global PlacementX\n        global PlacementY\n        global PlacementZ\n        global coor_X\n        global coor_Y\n        global coor_Z\n\n        coor_X = coor_Y = coor_Z = 0.0\n        PlacementX = PlacementY = PlacementZ = 0.0\n        self.CH_Sp_Placement.setChecked(False)  ; self.CH_Sp_Placement.setStyleSheet(\"QCheckBox {\" + setStyleBase + \"}\")\n        self.DS_PlacementX.setValue(PlacementX)\n        self.DS_PlacementX.setEnabled(False)    ; self.DS_PlacementX.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\")\n        self.DS_PlacementY.setValue(PlacementY)\n        self.DS_PlacementY.setEnabled(False)    ; self.DS_PlacementY.setStyleSheet(\"QDoubleSpinBox {\" +setStyleBase  + \"}\")\n        self.DS_PlacementZ.setValue(PlacementZ)\n        self.DS_PlacementZ.setEnabled(False)    ; self.DS_PlacementZ.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\")\n#        App.Console.PrintMessage(str(\"on_PU_Reset_Placement \")+\"\\n\")\n\n    def on_PU_Reset_Inclination(self):           # Reset_Inclination\n        global inclinaisonX\n        global inclinaisonY\n        global inclinaisonZ\n\n        inclinaisonX = inclinaisonY = inclinaisonZ = 0.0\n        self.CH_Sp_Inclination.setChecked(False); self.CH_Sp_Inclination.setStyleSheet(\"QCheckBox {\" + setStyleBase + \"}\")\n        self.DS_InclinaisonX.setValue(inclinaisonX)\n        self.DS_InclinaisonX.setEnabled(False)  ; self.DS_InclinaisonX.setStyleSheet(\"QSpinBox {\" + setStyleBase + \"}\")\n        self.DS_InclinaisonY.setValue(inclinaisonY)\n        self.DS_InclinaisonY.setEnabled(False)  ; self.DS_InclinaisonY.setStyleSheet(\"QSpinBox {\" + setStyleBase + \"}\")\n        self.DS_InclinaisonZ.setValue(inclinaisonZ)\n        self.DS_InclinaisonZ.setEnabled(False)  ; self.DS_InclinaisonZ.setStyleSheet(\"QSpinBox {\" + setStyleBase + \"}\")\n#        App.Console.PrintMessage(str(\"on_PU_Reset_Inclination \")+\"\\n\")\n\n    def Image_RA_Choice_Outdoor(self):        #\n        global debout\n\n        ####\n        pic = QtGui.QPixmap()\n        if debout == 1:\n            if self.CB_Word.isChecked():\n                pic.loadFromData(base64.b64decode(outDoorWord_Icon_b64))    # bmp converti\n            else:\n                pic.loadFromData(base64.b64decode(outDoor_Icon_b64))    # bmp converti\n        else:\n            if self.CB_Word.isChecked():\n                pic.loadFromData(base64.b64decode(FlatOutDoorWord_Icon_b64))    # bmp converti\n            else:\n                pic.loadFromData(base64.b64decode(FlatOutDoor_Icon_b64))    # bmp converti\n\n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(self.scene)\n        ####\n\n    def on_RA_Choice_Outdoor(self):           #\n        global ui\n        global exterieur\n        global epaisseurExtrus\n        global switchResetFALSE\n\n        ui.Image_RA_Choice_Outdoor()\n        epaisseurExtrus = 0.0\n        self.tabWidget.setCurrentIndex(0)\n        self.DS_Extrude.setValue(epaisseurExtrus)\n        self.DS_Extrude.setEnabled(False)\n        self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\") # origin system\n        self.CH_Extrude.setChecked(False)\n        exterieur = 1\n        self.S_Begin_Angle.setEnabled(True)\n        self.S_End_Angle.setEnabled(True)\n        self.DS_Correction_Radius.setEnabled(True)\n        self.DS_Correction_Angle.setEnabled(True)\n        self.PU_Flat.setEnabled(True)\n        if switchResetFALSE == 0:    # zero (False) by default = reset\n            ui.on_PU_Reset_Placement()\n            ui.on_PU_Reset_Inclination()\n\n    def Image_RA_Choice_Indoor(self):       #\n        global debout\n\n        ####\n        pic = QtGui.QPixmap()\n        if debout == 1:\n            if self.CB_Word.isChecked():\n                pic.loadFromData(base64.b64decode(inDoorWord_Icon_b64))    # bmp converti\n            else:\n                pic.loadFromData(base64.b64decode(inDoor_Icon_b64))    # bmp converti\n        else:\n            if self.CB_Word.isChecked():\n                pic.loadFromData(base64.b64decode(FlatInDoorWord_Icon_b64))    # bmp converti\n            else:\n                pic.loadFromData(base64.b64decode(FlatInDoor_Icon_b64))    # bmp converti\n            self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(self.scene)\n        ####\n\n    def on_RA_Choice_Indoor(self):          #\n        global ui\n        global exterieur\n        global epaisseurExtrus\n        global switchResetFALSE\n\n        ui.Image_RA_Choice_Indoor()\n        epaisseurExtrus = 0.0\n        self.tabWidget.setCurrentIndex(0)\n        self.DS_Extrude.setValue(epaisseurExtrus)\n        self.DS_Extrude.setEnabled(False)\n        self.CH_Extrude.setChecked(False)\n        exterieur = 0\n        self.S_Begin_Angle.setEnabled(True)\n        self.S_End_Angle.setEnabled(True)\n        self.DS_Correction_Radius.setEnabled(True)\n        self.DS_Correction_Angle.setEnabled(True)\n        self.PU_Flat.setEnabled(True)\n        if switchResetFALSE == 0:    # zero (False) by default = reset\n            ui.on_PU_Reset_Placement()\n            ui.on_PU_Reset_Inclination()\n\n    def Image_RA_Choice_Helix(self):              #\n        ####\n        pic = QtGui.QPixmap()\n        pic.loadFromData(base64.b64decode(helix_Icon_b64))    # bmp converti\n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(self.scene)\n        ####\n\n    def on_RA_Choice_Helix(self):              #\n        global ui\n        global exterieur\n        global cercleClock\n        global nombreFaces\n        global debout\n        global epaisseurExtrus\n        global switchResetFALSE\n\n        ui.Image_RA_Choice_Helix()\n        ui.tabWidget.setTabEnabled(1, True)\n        ui.tabWidget.setCurrentIndex(1)\n        epaisseurExtrus = 0.0\n        self.DS_Extrude.setValue(epaisseurExtrus)\n        self.DS_Extrude.setEnabled(False)\n        self.CH_Extrude.setChecked(False)\n        exterieur = 2\n        nombreFaces = 0\n        self.DS_Number_Faces_Support.setValue(nombreFaces)\n        cercleClock = 0\n        self.DS_Radius_Support.setValue(cercleClock)\n        self.DS_Radius_Support.setEnabled(False)\n        debout = 1\n        self.PU_Flat.setText(_fromUtf8(\"Mode Stand\"))\n\n        self.S_Begin_Angle.setEnabled(True)\n        self.S_End_Angle.setEnabled(True)\n        self.DS_Correction_Radius.setEnabled(True)\n        self.DS_Correction_Angle.setEnabled(True)\n        self.PU_Flat.setEnabled(False)##\n        if switchResetFALSE == 0:    # zero (False) by default = reset\n            ui.on_PU_Reset_Placement()\n            ui.on_PU_Reset_Inclination()\n\n    def Image_RA_Choice_Clock(self):\n        global redressement\n\n        ####\n        pic = QtGui.QPixmap()\n        if self.CB_RomanOrArabic.isChecked():\n            if redressement == 1:\n                pic.loadFromData(base64.b64decode(ClockRomanRedress_Icon_b64))    # bmp converti\n            else:\n                pic.loadFromData(base64.b64decode(ClockRomanAxis_Icon_b64))    # bmp converti\n        else:\n            if redressement == 1:\n                pic.loadFromData(base64.b64decode(ClockArabicRedress_Icon_b64))    # bmp converti\n            else:\n                pic.loadFromData(base64.b64decode(ClockArabicAxis_Icon_b64))    # bmp converti\n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(self.scene)\n        ####\n\n    def on_RA_Choice_Clock(self):\n        global ui\n        global exterieur\n        global debout\n        global correctionRayon\n        global correctionAngle\n        global epaisseurExtrus\n        global switchResetFALSE\n        global romain\n\n        ui.Image_RA_Choice_Clock()\n        ui.tabWidget.setTabEnabled(2, True)\n        ui.tabWidget.setCurrentIndex(2)\n        epaisseurExtrus = 0.0\n        self.DS_Extrude.setValue(epaisseurExtrus)\n        self.DS_Extrude.setEnabled(False)\n        self.CH_Extrude.setChecked(False)\n        exterieur = 3\n        debout = 0\n        self.PU_Flat.setEnabled(False)\n        self.S_Begin_Angle.setEnabled(False)\n        self.S_End_Angle.setEnabled(False)\n#        correctionRayon = 0\n        self.DS_Correction_Radius.setEnabled(False)\n        self.DS_Correction_Radius.setValue(0.0)\n#        correctionAngle = 10.0\n        self.DS_Correction_Angle.setEnabled(False)\n        self.DS_Correction_Angle.setValue(0.0)\n        if switchResetFALSE == 0:              # zero (False) by default = reset\n            ui.on_PU_Reset_Placement()\n            ui.on_PU_Reset_Inclination()\n\n    def on_tabWidget(self, value):              # Tab \n        global ui\n        global setStylePathG\n        global setStyleBase\n\n        if   value == 0:            # Command\n            self.tabWidget.setStyleSheet(\"QTabWidget {\" + setStyleBase + \"}\")\n            None\n        elif value == 1:            # Helix\n            self.RA_Choice_Helix.setChecked(True)\n            self.on_RA_Choice_Helix()\n        elif value == 2:            # Clock\n            self.RA_Choice_Clock.setChecked(True)\n            self.on_RA_Choice_Clock()\n        elif value == 3:            # Path\n            self.tabWidget.setStyleSheet(\"QTabWidget {\" + setStylePathG + \"}\")\n            None\n        elif value == 4:            # Stamp\n            #self.tabWidget.setStyleSheet(\"QTabWidget {\" + setStyleBase + \"}\")\n            #self.RA_Choice_Stamp.setChecked(True)\n            #self.on_RA_Choice_Stamp()\n            #self.on_RA_Choice_Stamp()\n            None\n\n    def on_PU_Flat(self):         # Flat or Stand\n        global debout\n\n        pic = QtGui.QPixmap()\n        if debout == 1:\n            debout = 0\n            self.PU_Flat.setText(_fromUtf8(\"Mode Flat\"))\n            self.PU_Flat.setToolTip(_fromUtf8(\"Click for create the text Stand\"))\n            self.PU_Flat.setIcon(QtGui.QIcon(QtGui.QPixmap(flatIcon))) # icone dans une variable \n            # self.RA_Choice_Outdoor.setText(_fromUtf8(\"Indoor\"))\n            # self.RA_Choice_Indoor.setText(_fromUtf8(\"Outdoor\"))\n            if self.RA_Choice_Outdoor.isChecked():\n                if self.CB_Word.isChecked():\n                    pic.loadFromData(base64.b64decode(FlatOutDoorWord_Icon_b64))  # bmp converti\n                else:\n                    pic.loadFromData(base64.b64decode(FlatOutDoor_Icon_b64))      # bmp converti\n            elif self.RA_Choice_Indoor.isChecked():\n                if self.CB_Word.isChecked():\n                    pic.loadFromData(base64.b64decode(FlatInDoorWord_Icon_b64))   # bmp converti\n                else:\n                    pic.loadFromData(base64.b64decode(FlatInDoor_Icon_b64))       # bmp converti\n        else:\n            debout = 1\n            self.PU_Flat.setText(_fromUtf8(\"Mode Stand\"))\n            self.PU_Flat.setToolTip(_fromUtf8(\"Click for create the text Flat\"))\n            self.PU_Flat.setIcon(QtGui.QIcon(QtGui.QPixmap(standIcon))) # icone dans une variable \n            # self.RA_Choice_Outdoor.setText(_fromUtf8(\"Outdoor\"))\n            # self.RA_Choice_Indoor.setText(_fromUtf8(\"Indoor\"))\n            if self.RA_Choice_Outdoor.isChecked():\n                pic.loadFromData(base64.b64decode(outDoor_Icon_b64))  # bmp converti\n            elif self.RA_Choice_Indoor.isChecked():\n                pic.loadFromData(base64.b64decode(inDoor_Icon_b64))  # bmp converti\n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(self.scene)\n#        App.Console.PrintMessage(str(\"on_PU_Flat \")+str(debout)+\"\\n\")\n\n#    def on_RA_Choice_Stamp(self):\n#        global ui\n#\n#        if self.RA_Choice_Helix.isChecked() or self.RA_Choice_Clock.isChecked():\n#            self.RA_Choice_Outdoor.setChecked(True)\n#            self.on_RA_Choice_Outdoor()\n\n    def on_DS_Radius_Circle(self,value):\n        global rayon\n        global cercleClock\n\n        rayon = value  \n        cercleClock = rayon\n        self.DS_Radius_Support.setValue(cercleClock)\n\n    def on_DS_Size_Character(self,value):\n        global SizeCaractere\n\n        SizeCaractere = value\n\n    def on_S_Begin_Angle(self,value):          #\n        global debut\n\n        debut = value\n\n    def on_S_End_Angle(self,value):            #\n        global rotation\n\n        rotation = value\n\n    def on_DS_PlacementX(self,value):          #\n        global PlacementX\n\n        PlacementX = value\n\n    def on_DS_PlacementY(self,value):          #\n        global PlacementY\n\n        PlacementY = value\n\n    def on_DS_PlacementZ(self,value):          #\n        global PlacementZ\n\n        PlacementZ = value\n\n    def on_CH_Sp_Placement(self):              # Placement or not Placement\n        global ui\n\n        if self.CH_Sp_Placement.isChecked(): \n            self.DS_PlacementX.setEnabled(True)\n            self.DS_PlacementY.setEnabled(True)\n            self.DS_PlacementZ.setEnabled(True)\n            self.DS_PlacementX.setStyleSheet(u\"QDoubleSpinBox {border-width: 2px; border-style: solid; border-color: #FF0000}\") # Red   rgb(255,0,0)\n            self.DS_PlacementY.setStyleSheet(u\"QDoubleSpinBox {border-width: 2px; border-style: solid; border-color: #008500}\") # Green rgb(0, 133, 0)\n            self.DS_PlacementZ.setStyleSheet(u\"QDoubleSpinBox {border-width: 2px; border-style: solid; border-color: #0000FF}\") # Blue  rgb(0,0,255)\n        else:\n            ui.on_PU_Reset_Placement()\n        if self.RA_Choice_Clock.isChecked():\n            self.DS_PlacementX.setEnabled(False)\n            self.DS_PlacementY.setEnabled(False)\n\n    def on_DS_Correction_Angle(self,value):    # \n        global correctionAngle\n\n        correctionAngle = value\n\n    def on_DS_Correction_Radius(self,value):   # \n        global correctionRayon\n\n        correctionRayon = value\n\n    def on_DS_Extrude(self,value):             # \n        global epaisseurExtrus\n        global epaisSupportClock\n        global setStyleBase\n        global setStyleRed\n        global setStyleOrange\n        global setStyleBlueLight\n\n        epaisseurExtrus = value\n        if self.CB_06_ModeFree.isChecked():\n            self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBlueLight + \"}\")\n        else:\n            if self.RA_Choice_Clock.isChecked():\n                if epaisseurExtrus > epaisSupportClock:\n                    self.DS_Extrude_Support.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\") # origin system\n                    self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\") # origin system\n                    self.CH_Extrude.setStyleSheet(\"QCheckBox {\" + setStyleBase + \"}\") # origin system\n                else:\n                    if epaisSupportClock >= epaisseurExtrus:\n                        self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleRed + \"}\")\n                        self.DS_Extrude_Support.setStyleSheet(\"QDoubleSpinBox {\" + setStyleRed + \"}\")\n                    else:\n                        self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleOrange + \"}\")\n                if epaisseurExtrus == 0:\n                    self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleOrange + \"}\")\n\n    def on_CH_Extrude(self):                   #\n        global epaisseurExtrus\n        global epaisSupportClock\n        global setStyleBase\n        global setStyleOrange\n        global setStyleBlueLight\n\n        if self.CH_Extrude.isChecked(): \n            self.DS_Extrude.setEnabled(True)\n            epaisseurExtrus = 1.0\n        else:\n            self.DS_Extrude.setEnabled(False)\n            self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\") # origin system\n            epaisseurExtrus = 0.0\n        if self.CB_06_ModeFree.isChecked(): \n            self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBlueLight + \"}\")\n        else:\n            if (epaisSupportClock != 0) and (epaisSupportClock >= epaisseurExtrus):\n                self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleOrange + \"}\")\n                self.DS_Extrude_Support.setStyleSheet(\"QDoubleSpinBox {\" + setStyleOrange + \"}\")\n                self.CH_Extrude.setStyleSheet(\"QCheckBox {\" + setStyleOrange + \"}\")\n            else:\n                self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\") # origin system\n                self.CH_Extrude.setStyleSheet(\"QCheckBox {\" + setStyleBase + \"}\") # origin system\n        self.DS_Extrude.setValue(epaisseurExtrus)\n\n    def on_DS_InclinaisonX(self,value):        # \n        global inclinaisonX\n\n        inclinaisonX = value\n\n    def on_DS_InclinaisonY(self,value):        # \n        global inclinaisonY\n\n        inclinaisonY = value\n\n    def on_DS_InclinaisonZ(self,value):        # \n        global inclinaisonZ\n\n        inclinaisonZ = value\n\n    def on_CH_Sp_Inclination(self):            #\n        global ui\n\n        if self.CH_Sp_Inclination.isChecked(): \n            self.DS_InclinaisonX.setEnabled(True)\n            self.DS_InclinaisonY.setEnabled(True)\n            self.DS_InclinaisonZ.setEnabled(True)\n        else:\n            ui.on_PU_Reset_Inclination()\n\n    def on_DS_Step_Of_The_Helix(self,value):   # \n        global pasHelix\n        global baseHelix\n        global endHelix\n\n        pasHelix = value\n        if pasHelix == 0:\n            baseHelix = endHelix = 0.0\n            self.DS_Base_Helix.setValue(baseHelix)\n            self.DS_Base_Helix.setEnabled(True)\n            self.DS_End_Helix.setValue(endHelix)\n            self.DS_End_Helix.setEnabled(True)\n        else:\n            baseHelix = endHelix = 0.0\n            self.DS_Base_Helix.setValue(baseHelix)\n            self.DS_Base_Helix.setEnabled(False)\n            self.DS_End_Helix.setValue(endHelix)\n            self.DS_End_Helix.setEnabled(False)\n\n    def on_DS_Number_Char_Per_Turn(self,value):# \n        global nombreCarParTour\n\n        nombreCarParTour = value\n\n    def on_DS_Base_Helix(self,value):          # \n        global baseHelix\n\n        baseHelix = value\n\n    def on_DS_End_Helix(self,value):           # \n        global endHelix\n\n        endHelix = value\n\n    def on_RB_Path_Image(self):      # Path Images a Afficher\n\n        pic = QtGui.QPixmap()\n        if self.RB_Path_01.isChecked():                # Orthogonal\n            if self.RB_Position_01.isChecked():        # Path BB Base\n                pic.loadFromData(base64.b64decode(PathBaseOrthogonal_Icon_b64))  # bmp converti\n            elif self.RB_Position_02.isChecked():      # Path BB Center\n                pic.loadFromData(base64.b64decode(PathCenterOrthogonal_Icon_b64))# bmp converti\n            elif self.RB_Position_03.isChecked():      # Path BB Top\n                pic.loadFromData(base64.b64decode(PathTopOrthogonal_Icon_b64))   # bmp converti\n        elif self.RB_Path_02.isChecked():              # Follow on direction\n            if self.RB_Position_01.isChecked():        # Path BB Base\n                pic.loadFromData(base64.b64decode(PathBase_Icon_b64))   # bmp converti\n            elif self.RB_Position_02.isChecked():      # Path BB Center\n                pic.loadFromData(base64.b64decode(PathCenter_Icon_b64)) # bmp converti\n            elif self.RB_Position_03.isChecked():      # Path BB Top\n                pic.loadFromData(base64.b64decode(PathTop_Icon_b64))    # bmp converti\n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(self.scene)\n\n    def on_DS_Radius_Support(self,value):      #  Clock\n        global cercleClock\n\n        cercleClock = value\n\n    def on_DS_Number_Faces_Support(self,value): # number Faces of support 0=none 1=circle 2=rectangle 3=triangle 4,5 ... polygon\n        global nombreFaces                     #  Clock\n        global epaisSupportClock\n        global cercleClock\n\n        nombreFaces = value\n        self.DS_Radius_Support.setEnabled(True)\n        self.DS_Extrude_Support.setEnabled(True)\n        self.DS_Extrude_Support.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\") # origin system\n        if nombreFaces == 0:\n            self.label_5.setText(_fromUtf8(\"Support number face\"))\n            epaisSupportClock = 0.0\n            self.DS_Radius_Support.setEnabled(False)\n            self.DS_Radius_Support.setValue(cercleClock)\n            self.DS_Extrude_Support.setEnabled(False)\n            self.DS_Extrude_Support.setValue(epaisSupportClock)\n        elif nombreFaces == 1:\n            self.label_5.setText(_fromUtf8(\"Support Circle\"))\n        elif nombreFaces == 2:\n            self.label_5.setText(_fromUtf8(\"Support Rectangle\"))\n        elif nombreFaces == 3:\n            self.label_5.setText(_fromUtf8(\"Support Triangle\"))\n        elif nombreFaces == 4:\n            self.label_5.setText(_fromUtf8(\"Support Square\"))\n        else :\n            self.label_5.setText(_fromUtf8(\"Support Polygone\"))\n\n    def on_DS_Extrude_Support(self,value):     #  Clock\n        global epaisSupportClock\n        global epaisseurExtrus\n        global setStyleBase\n        global setStyleRed\n        global setStyleOrange\n\n        epaisSupportClock = value\n        if epaisSupportClock >= epaisseurExtrus:\n            if self.CH_Extrude.isChecked():\n                self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleRed + \"}\")\n                self.DS_Extrude_Support.setStyleSheet(\"QDoubleSpinBox {\" + setStyleRed + \"}\")\n                self.CH_Extrude.setStyleSheet(\"QCheckBox {\" + setStyleBase + \"}\")\n            else:\n                self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleOrange + \"}\")\n                self.DS_Extrude_Support.setStyleSheet(\"QDoubleSpinBox {\" + setStyleOrange + \"}\")\n                self.CH_Extrude.setStyleSheet(\"QCheckBox {\" + setStyleOrange + \"}\")\n        else:\n            self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\")\n            self.DS_Extrude_Support.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\")\n            self.CH_Extrude.setStyleSheet(\"QCheckBox {\" + setStyleBase + \"}\")\n        if epaisSupportClock == 0:\n            self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\")\n            self.DS_Extrude_Support.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\")\n            self.CH_Extrude.setStyleSheet(\"QCheckBox {\" + setStyleBase + \"}\")\n\n        self.DS_PlacementZ.setEnabled(True)\n\n    def on_PU_Roman(self):                     # Roman or Arabic Clock\n        global redressement\n        global romain\n\n        pic = QtGui.QPixmap()\n        if self.CB_RomanOrArabic.isChecked():\n            ####\n            if redressement == 1:\n                pic.loadFromData(base64.b64decode(ClockRomanRedress_Icon_b64))    # bmp converti\n            else:\n                pic.loadFromData(base64.b64decode(ClockRomanAxis_Icon_b64))    # bmp converti\n            ####\n            romain = 1\n            self.CB_RomanOrArabic.setText(_fromUtf8(\"Mode Roman\"))\n            self.CB_RomanOrArabic.setToolTip(_fromUtf8(\"Check for activate the mode Arabic\"))\n            self.CB_RomanOrArabic.setIcon(QtGui.QIcon(QtGui.QPixmap(romanIcon))) # icone dans une variable \n        else:\n            ####\n            if redressement == 1:\n                pic.loadFromData(base64.b64decode(ClockArabicRedress_Icon_b64))    # bmp converti\n            else:\n                pic.loadFromData(base64.b64decode(ClockArabicAxis_Icon_b64))    # bmp converti\n            ####\n            romain = 0\n            self.CB_RomanOrArabic.setText(_fromUtf8(\"Mode Arabic\"))\n            self.CB_RomanOrArabic.setToolTip(_fromUtf8(\"Check for activate the mode Roman\"))\n            self.CB_RomanOrArabic.setIcon(QtGui.QIcon(QtGui.QPixmap(arabicIcon))) # icone dans une variable \n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(self.scene)\n\n    def on_PU_Redress(self):                   # Redress or circumferencial Clock\n        global redressement\n        global romain\n\n        pic = QtGui.QPixmap()\n#        if redressement == 1:\n        if self.CB_RedressChiffres.isChecked():\n            ####\n            if romain == 1:\n                pic.loadFromData(base64.b64decode(ClockRomanRedress_Icon_b64))    # bmp converti\n            else:\n                pic.loadFromData(base64.b64decode(ClockArabicRedress_Icon_b64))    # bmp converti\n            ####\n            redressement = 1\n            self.CB_RedressChiffres.setText(_fromUtf8(\"Redress\"))\n            self.CB_RedressChiffres.setIcon(QtGui.QIcon(QtGui.QPixmap(redressIcon))) # icone dans une variable \n            self.CB_RedressChiffres.setToolTip(_fromUtf8(\"Click for activate the mode Axial\"))\n        else:\n            ####\n            if romain == 1:\n                pic.loadFromData(base64.b64decode(ClockRomanAxis_Icon_b64))    # bmp converti\n            else:\n                pic.loadFromData(base64.b64decode(ClockArabicAxis_Icon_b64))    # bmp converti\n            ####\n            redressement = 0\n            self.CB_RedressChiffres.setText(_fromUtf8(\"Axial\"))\n            self.CB_RedressChiffres.setIcon(QtGui.QIcon(QtGui.QPixmap(axialIcon))) # icone dans une variable \n            self.CB_RedressChiffres.setToolTip(_fromUtf8(\"Click for activate the mode Redress\"))\n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(self.scene)\n\n    def on_CB_05_Reset(self):                  #\n        global switchResetFALSE\n\n        if self.CB_05_Reset.isChecked():\n            switchResetFALSE = 1\n            self.CB_05_Reset.setText(_fromUtf8(\"Not Reset\"))\n            self.CB_05_Reset.setIcon(QtGui.QIcon(QtGui.QPixmap(setIconNoReset))) # reset icone dans une variable \n            self.CB_05_Reset.setToolTip(_fromUtf8(\"Reset checkBox False by default (reset on all push button execute)\" + \"\\n\"\n                                                  \"If you check this option No reset is performed\" + \"\\n\"\n                                                  \"and if the result is not good\" + \"\\n\"\n                                                  \"ex: the old internal coordinate hare conserved or other...\" + \"\\n\"\n                                                  \"push the Reset button or \" + \"\\n\"\n                                                  \"uncheck this checkBox and try or restart FCCircularText\" + \"\\n\"\n                                                  \" ACTUAL TRUE NOT RESET\"))\n        else:\n            switchResetFALSE = 0\n            self.CB_05_Reset.setText(_fromUtf8(\"Reset\"))\n            self.CB_05_Reset.setIcon(QtGui.QIcon(QtGui.QPixmap(resetIcon))) # reset icone dans une variable \n            self.CB_05_Reset.setToolTip(_fromUtf8(\"Reset checkBox False by default (reset on all push button execute)\" + \"\\n\"\n                                                  \"If you check this option No reset is performed\" + \"\\n\"\n                                                  \"and if the result is not good\" + \"\\n\"\n                                                  \"ex: the old internal coordinate hare conserved or other...\" + \"\\n\"\n                                                  \"push the Reset button or \" + \"\\n\"\n                                                  \"uncheck this checkBox and try or restart FCCircularText\" + \"\\n\"\n                                                  \" ACTUAL FALSE RESET ALL PUSH EXECUTE BUTTON\"))\n\n    def on_PB_Delete_Last(self):                  # delete the last object created\n        global FcString\n        global FcStringPoints\n        global circleGuide\n        global helixGuide\n        global suppExtrude\n        global createCompound\n        global selComplete\n\n        try:\n            App.ActiveDocument.getObject(FcStringPoints.Name).removeObjectsFromDocument()\n            App.ActiveDocument.removeObject(FcStringPoints.Name)\n        except Exception: None\n        try:\n            App.ActiveDocument.getObject(FcString.Name).removeObjectsFromDocument()\n            App.ActiveDocument.removeObject(FcString.Name)\n        except Exception: None\n        try:\n            App.ActiveDocument.removeObject(circleGuide.Name)\n        except Exception: None\n        try:\n            App.ActiveDocument.removeObject(helixGuide.Name)\n        except Exception: None\n        try:\n            App.ActiveDocument.removeObject(suppExtrude.Name)\n        except Exception: None\n        try:\n            App.ActiveDocument.removeObject(createCompound.Name)\n        except Exception: None\n        App.ActiveDocument.recompute()\n\n        try:\n            #restore previous selection\n            Gui.Selection.clearSelection()\n            for s in selComplete:\n                Gui.Selection.addSelection(s.Object,s.SubElementNames)\n            selComplete = \"\"\n        except Exception: None\n\n    def on_CB_06_ModeFree(self):                #\n        global ui\n        global setStyleBlueLight\n        global setStyleBase\n        global debout\n\n        if self.CB_06_ModeFree.isChecked():\n            self.RA_Choice_Outdoor.setChecked(True)\n            self.on_RA_Choice_Outdoor()\n            debout = 0\n            self.on_PU_Flat()\n            self.PU_Flat.setEnabled(True)\n            self.groupBox_03.setEnabled(False)\n            self.tabWidget.setTabEnabled(1, False)\n            self.tabWidget.setTabEnabled(2, False)\n            self.tabWidget.setTabEnabled(4, False)\n            self.S_Begin_Angle.setEnabled(False)\n            self.S_End_Angle.setEnabled(False)\n            self.DS_Correction_Angle.setEnabled(False)\n            self.DS_Correction_Radius.setEnabled(False)\n\n            self.CB_06_ModeFree.setStyleSheet(\"QCheckBox {\" + setStyleBlueLight + \"}\")\n            self.DS_Radius_Circle.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBlueLight + \"}\")\n            self.label_10.setStyleSheet(\"QLabel {\" + setStyleBlueLight + \"}\")\n            self.DS_Size_Character.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBlueLight + \"}\")\n            self.label_4.setStyleSheet(\"QLabel {\" + setStyleBlueLight + \"}\")\n            self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBlueLight + \"}\")\n            self.CH_Extrude.setStyleSheet(\"QCheckBox {\" + setStyleBlueLight + \"}\")\n            self.CH_Sp_Placement.setChecked(True)   ; self.CH_Sp_Placement.setStyleSheet(\"QCheckBox {\" + setStyleBlueLight + \"}\")\n            self.DS_PlacementX.setEnabled(True)     ; self.DS_PlacementX.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBlueLight + \"}\")\n            self.DS_PlacementY.setEnabled(True)     ; self.DS_PlacementY.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBlueLight + \"}\")\n            self.DS_PlacementZ.setEnabled(True)     ; self.DS_PlacementZ.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBlueLight + \"}\")\n            self.CH_Sp_Inclination.setChecked(True) ; self.CH_Sp_Inclination.setStyleSheet(\"QCheckBox {\" + setStyleBlueLight + \"}\")\n            self.DS_InclinaisonX.setEnabled(True)   ; self.DS_InclinaisonX.setStyleSheet(\"QSpinBox {\" + setStyleBlueLight + \"}\")\n            self.DS_InclinaisonY.setEnabled(True)   ; self.DS_InclinaisonY.setStyleSheet(\"QSpinBox {\" + setStyleBlueLight + \"}\")\n            self.DS_InclinaisonZ.setEnabled(True)   ; self.DS_InclinaisonZ.setStyleSheet(\"QSpinBox {\" + setStyleBlueLight + \"}\")\n        else:\n            self.CB_06_ModeFree.setStyleSheet(\"QCheckBox {\" + setStyleBase + \"}\")\n            self.groupBox_03.setEnabled(True)\n            self.tabWidget.setTabEnabled(1, True)\n            self.tabWidget.setTabEnabled(2, True)\n            self.tabWidget.setTabEnabled(4, True)\n            self.S_Begin_Angle.setEnabled(True)\n            self.S_End_Angle.setEnabled(True)\n            self.DS_Correction_Angle.setEnabled(True)\n            self.DS_Correction_Radius.setEnabled(True)\n\n            self.DS_Radius_Circle.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\")\n            self.label_10.setStyleSheet(\"QLabel {\" + setStyleBase + \"}\")\n            self.DS_Size_Character.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\")\n            self.label_4.setStyleSheet(\"QLabel {\" + setStyleBase + \"}\")\n            self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\")\n            self.CH_Extrude.setStyleSheet(\"QCheckBox {\" + setStyleBase + \"}\")\n            self.on_PU_Reset()\n\n    def on_PU_Reset(self):                     #\n        global ui\n        global points\n        global coor_X\n        global coor_Y\n        global coor_Z\n        global vec\n\n        global PolicePath\n\n        global rayon\n        global texte\n        global debut\n        global rotation\n        global SizeCaractere\n\n        global precision\n        global correctionAngle\n        global correctionRayon\n        global debout\n        global exterieur\n        global baseHelix\n        global endHelix\n        global pasHelix\n        global nombreCarParTour\n\n        global PlacementX\n        global PlacementY\n        global PlacementZ\n\n        global inclinaisonX\n        global inclinaisonY\n        global inclinaisonZ\n\n        global cercleClock\n        global nombreFaces\n        global romain\n        global redressement\n\n        global comP\n        global nameL\n        global epaisseurExtrus\n        global epaisSupportClock\n        global compount1\n        global setStyleBase\n\n        texte = \"\"\n        self.CB_Word.setChecked(False)\n\n        exterieur = 1\n        self.RA_Choice_Outdoor.setText(_fromUtf8(\"Outdoor\"))\n        self.RA_Choice_Indoor.setText(_fromUtf8(\"Indoor\"))\n        self.RA_Choice_Outdoor.setChecked(True)\n        pic = QtGui.QPixmap()\n        pic.loadFromData(base64.b64decode(outDoor_Icon_b64))  # bmp converti\n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(self.scene)\n        self.tabWidget.setCurrentIndex(0)\n\n        debout = 1\n        self.PU_Flat.setText(_fromUtf8(\"Mode Stand\"))\n        self.PU_Flat.setToolTip(_fromUtf8(\"Click for create the text Flat\"))\n        self.PU_Flat.setEnabled(True)\n        self.PU_Flat.setIcon(QtGui.QIcon(QtGui.QPixmap(standIcon))) # icone dans une variable \n\n        SizeCaractere = 2.0\n        self.DS_Size_Character.setValue(SizeCaractere)\n        self.DS_Size_Character.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\")\n        rayon = 10.0\n        self.DS_Radius_Circle.setValue(rayon)\n        self.DS_Radius_Circle.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\")\n        self.label_10.setStyleSheet(\"QLabel {\" + setStyleBase + \"}\")\n\n        debut = 0\n        self.S_Begin_Angle.setValue(debut)\n        self.S_Begin_Angle.setEnabled(True)\n        rotation = 360\n        self.S_End_Angle.setValue(rotation)\n        self.S_End_Angle.setEnabled(True)\n\n        correctionAngle = 0.0\n        self.DS_Correction_Angle.setValue(correctionAngle)\n        self.DS_Correction_Radius.setEnabled(True)\n        correctionRayon = 0.0 #0.15\n        self.DS_Correction_Radius.setValue(correctionRayon)\n        self.DS_Correction_Angle.setEnabled(True)\n\n        epaisseurExtrus = 0.0\n        self.DS_Extrude.setValue(epaisseurExtrus)\n        self.DS_Extrude.setEnabled(False)\n        self.DS_Extrude.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\")\n        self.CH_Extrude.setChecked(False)\n        self.CH_Extrude.setStyleSheet(\"QCheckBox {\" + setStyleBase + \"}\")\n        self.label_4.setStyleSheet(\"QLabel {\" + setStyleBase + \"}\")\n\n        ui.on_PU_Reset_Placement()\n        ui.on_PU_Reset_Inclination()\n\n        self.CB_06_ModeFree.setChecked(False)\n\n        baseHelix = 0.0\n        self.DS_Base_Helix.setValue(baseHelix)\n        self.DS_Base_Helix.setEnabled(False)\n        endHelix = 0.0\n        self.DS_End_Helix.setValue(endHelix)\n        self.DS_Base_Helix.setEnabled(False)\n        pasHelix = 2.0\n        self.DS_Step_Of_The_Helix.setValue(pasHelix)\n        nombreCarParTour = 10\n        self.DS_Number_Char_Per_Turn.setValue(nombreCarParTour)\n\n        nombreFaces = 0\n        self.DS_Number_Faces_Support.setValue(nombreFaces)\n        self.label_5.setText(_fromUtf8(\"Support number face\"))\n        cercleClock = rayon\n        self.DS_Radius_Support.setValue(cercleClock)\n        self.DS_Radius_Support.setEnabled(False)\n        epaisSupportClock   = 0.0\n        self.DS_Extrude_Support.setEnabled(False)\n        self.DS_Extrude_Support.setValue(epaisSupportClock)\n        self.DS_Extrude_Support.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\")\n\n        romain = 0\n        self.CB_RomanOrArabic.setIcon(QtGui.QIcon(QtGui.QPixmap(arabicIcon))) # icone dans une variable \n        self.CB_RomanOrArabic.setText(_fromUtf8(\"Mode Arabic\"))\n        self.CB_RomanOrArabic.setChecked(False)\n\n        redressement = 0\n        self.CB_RedressChiffres.setText(_fromUtf8(\"Axial\"))\n        self.CB_RedressChiffres.setIcon(QtGui.QIcon(QtGui.QPixmap(axialIcon))) # icone dans une variable \n        self.CB_RedressChiffres.setToolTip(_fromUtf8(\"Check for activate the mode Redress\"))\n        self.CB_RedressChiffres.setChecked(False)\n\n        compount1 = 0\n        ui.on_CB_Word() # texte = self.textEdit.toPlainText()\n\n    def on_PU_Benchmarks(self):                # Benchmarks\n      try:\n        global compount1\n        global ui\n\n        compount1 = 1\n        ui.on_PU_Execute()\n      except:\n        sayexc(\"Error\")\n\n    def on_PU_Execute(self):         # Execute\n        global ui\n        global PolicePath\n        global switchResetFALSE\n\n        global points\n        global coor_X\n        global coor_Y\n        global coor_Z\n        \n        global PlacementX\n        global PlacementY\n        global PlacementZ\n\n        global inclinaisonX\n        global inclinaisonY\n        global inclinaisonZ\n\n        global vec\n        global rayon\n        global texte\n        global debut\n        global rotation\n        global SizeCaractere\n\n        global ii\n        global precision\n        global correctionAngle\n        global correctionRayon\n        global debout\n        global exterieur\n        global baseHelix\n        global endHelix\n        global pasHelix\n        global nombreCarParTour\n\n        global cercleClock\n        global nombreFaces\n        global romain\n        global redressement\n\n        global comP\n        global nameL\n\n        global epaisseurExtrus\n        global epaisSupportClock\n        global compount1\n\n        #### for delete\n        global FcString\n        global FcStringPoints\n        global circleGuide\n        global helixGuide\n        global suppExtrude\n        global createCompound\n        global selComplete\n        #### for delete\n\n        points   = []\n        comP     = []\n        nameL    = []\n\n        del   points[:]\n        del     comP[:]\n        del    nameL[:]\n\n        doc = FreeCAD.ActiveDocument\n        if doc == None:\n            doc = FreeCAD.newDocument(\"FCCircularText\")\n\n#### Path\n        # create text on wire, arc, circle edge... \n        #\n        try:\n            ssel = FreeCADGui.Selection.getSelectionEx()\n            selectedEdge = lineSelected = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0]  # select one element\n            selComplete = Gui.Selection.getCompleteSelection()\n        except Exception:\n            selectedEdge = None\n            ssel = \"\"\n            Gui.Selection.clearSelection()\n            None\n        passNoOk = 0\n        if (hasattr(selectedEdge,'Surface')) or (hasattr(selectedEdge,'Point')):\n            passNoOk = 1\n\n        if (len(ssel) != 0) and (passNoOk == 0):    # Path\n\n            textLabel = texte[0:10]\n            if self.CB_Word.isChecked():\n                textLabel = textLabel[0]\n            else:\n                textLabel = textLabel[0:10]\n\n            FreeCAD.ActiveDocument.openTransaction(\"FCCTp\")\n            FcString = doc.addObject(\"App::DocumentObjectGroup\",\"FcStringP_\" + textLabel)\n            if self.CB_01_Points.isChecked():\n                FcStringPoints = doc.addObject(\"App::DocumentObjectGroup\",\"FcStringPoints_\" + textLabel)\n\n            try:\n                numberOfPoints = len(texte)                                                        # Decomposition number (or precision you can change)\n                points = selectedEdge.discretize(numberOfPoints)                                   # discretize the element\n                pasTab = 0\n\n                for position in range(len(texte)):                                                             # list and display the coordinates\n\n                    if texte[position] != \" \":\n                        ss=Draft.makeShapeString(String=texte[position],FontFile=PolicePath,Size=SizeCaractere,Tracking=0)\n    \n                        XLongueur = ss.Shape.BoundBox.XLength                                          # Length x boundBox rectangle\n                        YLongueur = ss.Shape.BoundBox.YLength                                          # Length y boundBox rectangle\n                        ZLongueur = ss.Shape.BoundBox.ZLength                                          # Length z boundBox rectangle\n                        XXLongueur = 0.0\n                        YYLongueur = 0.0\n                        ZZLongueur = 0.0\n    \n                        if self.RB_Position_01.isChecked():\n                            None\n                        elif self.RB_Position_02.isChecked():\n                            XXLongueur = -XLongueur/2.0; YYLongueur = -YLongueur/2.0; #ZZLongueur = -ZLongueur/2.0\n                        elif self.RB_Position_03.isChecked():\n                            XXLongueur = 0; YYLongueur = -YLongueur; #ZZLongueur = -ZLongueur\n    \n                        pl = FreeCAD.Placement()                                                # placement object\n    \n                        if self.RB_Path_01.isChecked():\n    #                        pl.Base=FreeCAD.Vector(points[position][0] - (XXLongueur), points[position][1] - (YYLongueur), points[position][2])\n                            pl.Base=FreeCAD.Vector(points[position][0] + (XXLongueur), points[position][1] + (YYLongueur), points[position][2])\n                            pl.Rotation = App.Rotation(inclinaisonX, inclinaisonY, inclinaisonZ)\n                            pl = pl.multiply(App.Placement(App.Vector(PlacementX, PlacementY, PlacementZ), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)))\n                        else:\n                            ##Extract macro_Perpendicular_To_Wire\n                            if pasTab == 0:\n                                pointsDirection = []\n                                pointsDirection = lineSelected.discretize(Number = ((len(texte)-1) * 10))   # discretize the path line first selection\n                                pasTab = 1\n                            try:\n                                v=pointsDirection[position*10].sub(pointsDirection[(position*10) + 1])      # avec vecteurs 1 et 2 (direction debut ligne)\n                            except Exception:\n                                v=pointsDirection[-2].sub(pointsDirection[-1])                              # avec vecteurs 1 et 2 (direction debut ligne)\n    \n                            r=App.Rotation(App.Vector(-1,0,0),v)\n                            pl.Rotation.Q = r.Q\n                            pl = pl.multiply(App.Placement(App.Vector(0.0,0.0,0.0), App.Rotation(inclinaisonX, inclinaisonY, inclinaisonZ), App.Vector(0.0,0.0,0.0)))\n    \n                            try:\n                                pl.Base = pointsDirection[position*10]\n                            except Exception:\n                                pl.Base = pointsDirection[-1]\n                            pl = pl.multiply(App.Placement(App.Vector(XXLongueur + PlacementX, YYLongueur + PlacementY, ZZLongueur + PlacementZ), App.Rotation(correctionAngle, 0.0,0.0), App.Vector(0.0,0.0,0.0)))\n    \n                        ####\n                        if self.CB_03_BBox.isChecked():\n                            ss.ViewObject.BoundingBox = True\n                        ####\n                        ssLabel = texte[position]\n                        ss.Label = ssLabel\n                        try:\n                            if texte[position + 1] == \" \":\n                                ss.Label = ssLabel + \"+[space]\"\n                        except Exception:\n                            None\n                        FcString.addObject(ss)  # contener character\n    #                    FcString = doc.addObject(\"App::DocumentObjectGroup\",\"FcString\")\n    \n                        ####\n                        if epaisseurExtrus != 0:         # extrusion characrters\n                            CharExtrude = Draft.extrude(ss,Base.Vector(0.0,0.0,epaisseurExtrus))\n                            CharExtrude.Placement=pl \n                            CharExtrude.Label = ssLabel #texte[position]\n                            App.ActiveDocument.getObject(CharExtrude.Name).recompute()\n                            try:\n                                CharExtrude.ViewObject.DisplayMode = u\"Flat Lines\"\n                            except Exception:\n                                None\n                            ####\n                            if self.CB_03_BBox.isChecked():\n                                CharExtrude.ViewObject.BoundingBox = True\n                            ####\n                            comP.append(CharExtrude.Shape)\n    #                            nameL.append(CharExtrude.Name)\n                            FcString.addObject(CharExtrude)  # contener extrude\n                        else:\n                            ss.Placement = pl\n                            #ss.Support=None\n                            try:\n                                ss.ViewObject.DisplayMode = u\"Flat Lines\"\n                            except Exception:\n                                None\n                            comP.append(ss.Shape)\n    #                            nameL.append(ss.Name)\n                        ####\n                        if self.CB_01_Points.isChecked():\n                            pointRepere = Draft.makePoint(pl.Base)\n                            pointRepere.ViewObject.PointColor = (1.0,0.0,0.0)\n                            pointRepere.Label = ssLabel #texte[position]\n                            App.ActiveDocument.getObject(pointRepere.Name).recompute()\n                            FcStringPoints.addObject(pointRepere)\n                        ####\n                        if self.CB_04_Progression.isChecked():\n                            FreeCADGui.updateGui()                                 # rafraichi l'ecran\n                        ####\n            except Exception:\n                App.Console.PrintError(str(\"Discretize Error or selection error\")+\"\\n\")\n            FreeCAD.ActiveDocument.commitTransaction()\n#### Path fin\n#\n#### Circular begin\n        else:\n            FreeCAD.ActiveDocument.openTransaction(\"FCCTc\")\n            if ((exterieur == 0) and (debout == 0)):    # normal circular\n                vecligne=[FreeCAD.Vector(PlacementX,PlacementY,PlacementZ),FreeCAD.Vector(rayon + correctionRayon,0.0,0.0)]      # \n            else:\n                if exterieur == 3:\n                    vecligne=[FreeCAD.Vector(PlacementX,PlacementY,PlacementZ),FreeCAD.Vector(rayon - (SizeCaractere/2),0.0,0.0)]      # \n                elif debout == 0:\n                    vecligne=[FreeCAD.Vector(PlacementX,PlacementY,PlacementZ),FreeCAD.Vector(rayon + correctionRayon - SizeCaractere,0.0,0.0)]      # \n                else:\n                    vecligne=[FreeCAD.Vector(PlacementX,PlacementY,PlacementZ),FreeCAD.Vector(rayon + correctionRayon,0.0,0.0)]      # \n\n            ligne = Draft.makeWire(vecligne,closed=False,face=False,support=None)     # creation de la ligne de base\n            lineName = ligne.Name\n            FreeCAD.activeDocument().recompute(None,True,True)\n\n            ii  = -1\n            ii2 = -1\n\n            #nombre = len(texte) - 1    # moins - 1 pour aller de 0 degres a 0 degres dans la boucle pour compatible avec Path\n            nombre = len(texte)        # si pas - 1 ex: pour 36 lettres va de 0 degres a 350 degres\n\n            coor_Z = PlacementZ\n            boucler = 1\n            helixSpline = []\n\n            texteLabel = texte[0:10]\n            if (exterieur == 0) or (debout == 0):\n                texte = texte[::-1]\n                if (exterieur == 0) and (debout == 0):\n                    texte = texte[::-1]\n\n            if exterieur == 2:        # helix\n                if nombreCarParTour == 0:\n                    nombreCarParTour = 1\n                    App.Console.PrintError(\"Insufficient number\"+\"\\n\")\n                pas = 0.0\n                nombre = nombreCarParTour\n                if pasHelix != 0:\n                    pas = pasHelix / (nombreCarParTour)\n                else:\n                    pas = ((((endHelix - SizeCaractere)-baseHelix)/(len(texte) / nombreCarParTour))/(nombreCarParTour)) # pas of helix\n                    coor_Z += baseHelix\n                boucler = int(len(texte) / nombreCarParTour)\n                if (len(texte) % nombreCarParTour) != 0: # calcul number spires Helix\n                    boucler += 1\n            else:\n                nombreCarParTour = 1\n\n            if exterieur == 3:         # Clock\n                FcString = doc.addObject(\"App::DocumentObjectGroup\",\"FcClock\")\n                if self.CB_01_Points.isChecked():\n                    FcStringPoints = doc.addObject(\"App::DocumentObjectGroup\",\"FcStringPoints_Clock\")\n                nombre = 12\n                if romain == 0:\n                    texte = [\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"10\",\"11\",\"12\"]\n                    textLabel = \"Arabic\"\n                else:\n                    texte = [\"I\",\"II\",\"III\",\"IIII\",\"V\",\"VI\",\"VII\",\"VIII\",\"IX\",\"X\",\"XI\",\"XII\"]\n                    textLabel = \"Roman\"\n                texte = texte[::-1]\n            else:\n                textLabel = texte[0:10]\n                #print(textLabel)\n                if self.CB_Word.isChecked():\n                    textLabel = texteLabel[0]\n                else:\n                    textLabel = texteLabel[0:10]\n                FcString = doc.addObject(\"App::DocumentObjectGroup\",\"FcString_\" + textLabel)\n                if self.CB_01_Points.isChecked():\n                    FcStringPoints = doc.addObject(\"App::DocumentObjectGroup\",\"FcStringPoints_\" + textLabel)\n\n#            if exterieur == 2:        # helix\n#                boucler = int(len(texte) / nombreCarParTour)\n#                if (len(texte) % nombreCarParTour) != 0: # calcul number spires Helix\n#                    boucler += 1\n\n            ####Boucle principale############################################################################\n            for hel in range(boucler):\n                ii = -1\n                ####Boucle de travail#################################################\n                #for angleTr in range(debut,rotation,((rotation-debut)/nombre)): # old\n                for angleTrFloat in range((debut*10000),(rotation*10000),int((round(((float(rotation)-float(debut))/float(nombre)),4)*10000)) ): # 10000 pour 4 decimales\n                    angleTr = (float(angleTrFloat)/10000.0)\n                    ii  += 1\n                    ii2 += 1\n                    ligne.Placement = App.Placement(App.Vector(PlacementX,PlacementY,PlacementZ), App.Rotation(App.Vector(0.0,0.0,1.0),angleTr), App.Vector(0.0,0.0,0.0))\n                    ligne.ViewObject.LineColor = (1.0,0.,0.0)\n                    lineName = ligne.Name\n                    FreeCAD.activeDocument().recompute(None,True,True)\n\n                    #print(ii+1,\" \",angleTr)\n                    a = ligne.End # fin de ligne\n                    coor_X = (a[0])\n                    coor_Y = (a[1])\n\n                    if (ii < nombre) and (ii2 < len(texte)):\n                        if exterieur == 3:                  # clock\n                            ligne.Placement = App.Placement(App.Vector(PlacementX,PlacementY,PlacementZ), App.Rotation(App.Vector(0.0,0.0,1.0),angleTr+90), App.Vector(0.0,0.0,0.0))\n                            FreeCAD.activeDocument().recompute(None,True,True)\n\n                            try:\n                                a = ligne.Shape.Edges[0].Vertexes[1]                       # fin de ligne\n                            except Exception:\n                                a = ligne.End                                              # 0.19 fin de ligne\n\n                            try:\n                                coor_X = (a.Point.x)\n                                coor_Y = (a.Point.y)\n                            except Exception:\n                                coor_X = (a.x)                                             # 0.19 fin de ligne\n                                coor_Y = (a.y)\n\n                        if texte[ii2] != \" \":\n                            ss = Draft.makeShapeString(String=texte[ii2],FontFile=PolicePath,Size=SizeCaractere,Tracking=0)\n                            \n                            ssLabel = texte[ii2]\n                            ss.Label = ssLabel\n                            FcString.addObject(ss)  # contener character\n\n                            try:\n                                if texte[ii2 + 1] == \" \":\n                                    ss.Label = ssLabel = ss.Label + \"+[space]\"\n                            except Exception:\n                                None\n\n                            centreX = (ss.Shape.BoundBox.Center[0])\n                            centreY = (ss.Shape.BoundBox.Center[1])\n                            centreZ = (ss.Shape.BoundBox.Center[2])\n                            lengthX = (ss.Shape.BoundBox.XLength)\n                            lengthY = (ss.Shape.BoundBox.YLength)\n                            lengthZ = (ss.Shape.BoundBox.ZLength)\n                            \n                            plm=\"\"\n                            plm=FreeCAD.Placement()\n                            plm.Base=FreeCAD.Vector(coor_X, coor_Y, coor_Z)\n                            FreeCAD.activeDocument().recompute(None,True,True)\n                            if self.CB_06_ModeFree.isChecked():\n                                plm = App.Placement(App.Vector(coor_X, coor_Y, coor_Z), App.Rotation(angleTr+inclinaisonX+correctionAngle, inclinaisonY, inclinaisonZ), App.Vector(0.0, 0.0, 0.0)) # pitch,roll...1   \n                                FreeCAD.activeDocument().recompute(None,True,True)\n                            else:\n                                if debout == 1:           # debout\n                                    if exterieur == 0:    # circumferential internal\n                                        plm = App.Placement(App.Vector(coor_X,coor_Y,coor_Z), App.Rotation(angleTr-90-correctionAngle+inclinaisonX,inclinaisonY,90+inclinaisonZ), App.Vector(0.0,0.0,0.0)) # pitch,roll...1\n                                    elif exterieur == 1:  # circumferential external\n                                        plm = App.Placement(App.Vector(coor_X,coor_Y,coor_Z), App.Rotation(angleTr+90+correctionAngle+inclinaisonX,inclinaisonY,90+inclinaisonZ), App.Vector(0.0,0.0,0.0)) # pitch,roll...1\n                                    elif exterieur == 2:  # circumferential helix\n                                        plm = App.Placement(App.Vector(coor_X,coor_Y,coor_Z), App.Rotation(angleTr+90+correctionAngle+inclinaisonX,inclinaisonY,90+inclinaisonZ), App.Vector(0.0,0.0,0.0)) # pitch,roll...1\n                                        coor_Z = coor_Z + pas\n                                else:                     # a plat\n                                    if exterieur == 1:    # exterieur (superieur)\n                                        plm = App.Placement(App.Vector(coor_X,coor_Y,coor_Z), App.Rotation(angleTr-90-correctionAngle+inclinaisonX,inclinaisonY,inclinaisonZ), App.Vector(0.0,0.0,0.0)) # pitch,roll...1\n                                    elif exterieur == 3:  # circumferential plat (clock)\n                                        if redressement == 1:\n                                            plm = App.Placement(App.Vector(coor_X-centreX,coor_Y-centreY,coor_Z), App.Rotation(inclinaisonX,inclinaisonY,inclinaisonZ), App.Vector(0.0,0.0,0.0)) # pitch,roll...1\n                                        else:\n                                            plm = App.Placement(App.Vector(coor_X-centreX,coor_Y-centreY,coor_Z), App.Rotation(angleTr+inclinaisonX,inclinaisonY,inclinaisonZ), App.Vector(centreX,centreY,centreZ)) # pitch,roll...1\n                                    else:                 # interieur  (inferieur)\n                                        plm = App.Placement(App.Vector(-coor_X,-coor_Y,-coor_Z), App.Rotation(angleTr+90+correctionAngle+inclinaisonX,180+inclinaisonY,180+inclinaisonZ), App.Vector(0.0,0.0,0.0)) # pitch,roll...1   \n                                FreeCAD.activeDocument().recompute(None,True,True)\n                                #######################################################\n                                #### plm = plm.multiply(App.Placement(App.Vector(0.0, 0.0, 0.0), App.Rotation(App.Vector(0.0, 0.0, 1.0), 0.0), App.Vector(0.0, 0.0, 0.0)))\n                                #######################################################\n                                #### ___________________Test_Memo\n                                #### normal outdoor stand\n                                #### Placement [Pos=(10,0,0), Yaw-Pitch-Roll=(90,0,90)]\n                                #### _____\n                                #### plus 90 degres \"X\" Yaw (macro) *Psi*\n                                #### Placement [Pos=(10,0,0), Yaw-Pitch-Roll=(180,0,90)]\n                                #### plus 90 Z (FC)\n                                #### App.getDocument(\"FCCircularText\").ShapeString.Placement=App.Placement(App.Vector(10,0,0), App.Rotation(180,0,90), App.Vector(0,0,0))\n                                #### _____\n                                #### plus 90 degres \"Y\" Pitch (macro) *Phi*\n                                #### Placement [Pos=(10,0,0), Yaw-Pitch-Roll=(0,90,0)]\n                                #### plus 90 Y (FC)\n                                #### App.getDocument(\"FCCircularText\").ShapeString.Placement=App.Placement(App.Vector(10,0,0), App.Rotation(90,90,90), App.Vector(0,0,0))\n                                #### _____\n                                #### plus 90 degres \"Z\" Roll (macro) *Theta*\n                                #### Placement [Pos=(10,0,0), Yaw-Pitch-Roll=(90,0,180)]\n                                #### plus 90 X (FC)\n                                #### App.getDocument(\"FCCircularText\").ShapeString.Placement=App.Placement(App.Vector(10,0,0), App.Rotation(90,0,180), App.Vector(0,0,0))\n                                #### ____________________Test_Memo\n                                ######################################################\n                            \n                            if self.RA_Choice_Helix.isChecked():\n                                helixSpline.append(plm.Base)    # helix\n                            \n                            if epaisseurExtrus != 0:         # extrusion characrters\n                                CharExtrude = Draft.extrude(ss,Base.Vector(0,0,epaisseurExtrus))\n                                CharExtrude.Label = ssLabel # texte[ii2]\n                                CharExtrude.Placement=plm \n                                try:\n                                    CharExtrude.ViewObject.DisplayMode = u\"Flat Lines\"\n                                except Exception:\n                                    None\n                                if self.CB_03_BBox.isChecked():\n                                    CharExtrude.ViewObject.BoundingBox = True\n                                App.ActiveDocument.getObject(CharExtrude.Name).recompute()\n                                comP.append(CharExtrude.Shape)\n#                                nameL.append(CharExtrude.Name)\n                                FcString.addObject(CharExtrude)  # contener extrude\n                            else:                 # \n                                ss.Placement=plm \n                                #ss.Support=None\n                                try:\n                                    ss.ViewObject.DisplayMode = u\"Flat Lines\"\n                                except Exception:\n                                    None\n                                if self.CB_03_BBox.isChecked():\n                                    ss.ViewObject.BoundingBox = True\n                                comP.append(ss.Shape)\n#                                nameL.append(ss.Name)\n#                                points += [FreeCAD.Vector(coor_X,coor_Y,coor_Z)]  # coordinates makeBSpline\n                            ####\n                            if self.CB_01_Points.isChecked():\n                                pointRepere = Draft.makePoint(plm.Base)\n                                pointRepere.ViewObject.PointColor = (1.0,0.,0.0)\n                                pointRepere.Label = ssLabel #texte[ii2]\n                                App.ActiveDocument.getObject(pointRepere.Name).recompute()\n                                FcStringPoints.addObject(pointRepere)\n                            ####\n                            if self.CB_04_Progression.isChecked():\n                                FreeCADGui.updateGui()                                 # rafraichi l'ecran\n                            ####\n            FreeCAD.ActiveDocument.commitTransaction()\n\n            #BSpline = Draft.makeBSpline(points,closed=False)                  # makeBSpline repere\n            App.ActiveDocument.removeObject(lineName)     # remove ligne de base directrice\n\n        FreeCAD.ActiveDocument.openTransaction(\"FCCTc\")\n        if (self.CB_02_Circle.isChecked()) and (passNoOk == 0): # create Circle\n            pll = FreeCAD.Placement()\n            pll = App.Placement(App.Vector(PlacementX,PlacementY,PlacementZ), App.Rotation(App.Vector(0,0,1),0), App.Vector(0,0,0))\n            circleGuide = Draft.makeCircle(radius=rayon, placement=pll, face=False, support=None)\n            FreeCAD.activeDocument().recompute(None,True,True)\n            circleGuide.Label = \"circleRepere_\" + textLabel\n            circleGuide.ViewObject.LineColor = (1.0,0.0,0.0)\n            Draft.autogroup(circleGuide)\n            if self.RA_Choice_Helix.isChecked():        # helix\n                helixGuide = Draft.makeBSpline(helixSpline, closed=False, face=False, support=None)\n                FreeCAD.activeDocument().recompute(None,True,True)\n                helixGuide.Label = \"helixRepere_\" + textLabel\n                helixGuide.ViewObject.LineColor = (1.0,0.0,0.0)\n                Draft.autogroup(helixGuide)            \n\n        if compount1 == 1:                            # create compount\n            comp = Part.makeCompound(comP)\n            Part.show(comp)\n            createCompound = App.ActiveDocument.ActiveObject\n            createCompound.Label = \"Comp_\" + textLabel\n        ####Boucle de travail fin########################################################################\n\n        ####Extrude support clock#############################################\n        if nombreFaces > 0:                           # support clock\n            pl = FreeCAD.Placement()\n            if nombreFaces == 1:                      # circle\n                pl.Base = FreeCAD.Vector(0.0,0.0,0.0)\n                supp = Draft.makeCircle(cercleClock,placement=pl,face=True,support=None)\n            if nombreFaces == 2:                      # rectangle\n                cercleClock = cercleClock * 2\n                pl.Base = FreeCAD.Vector(-cercleClock, (-cercleClock / 2.0), 0.0)\n                supp = Draft.makeRectangle((cercleClock * 2.0), cercleClock, placement=pl, face = True)\n            if nombreFaces > 2:                       # polygone with number faces\n                if nombreFaces == 4:\n                    rotateSupport = 45\n                else:\n                    rotateSupport = 90\n                pl = App.Placement(App.Vector(0.0,0.0,0.0), App.Rotation(rotateSupport,0,0), App.Vector(0,0,0))\n                supp = Draft.makePolygon(nombreFaces,cercleClock,inscribed = False,placement = pl,face = True,support=None)\n            supp.MakeFace = True\n\n            FreeCAD.activeDocument().recompute(None,True,True)\n            FcString.addObject(supp)                  # contener support\n\n            if epaisSupportClock != 0:                # extrude support clock\n                suppExtrude = Draft.extrude(supp,Base.Vector(0,0,epaisSupportClock))\n                App.ActiveDocument.getObject(suppExtrude.Name).recompute()\n                # try:\n                suppExtrude.ViewObject.DisplayMode = u\"Flat Lines\"\n                if self.CB_03_BBox.isChecked():\n                    suppExtrude.ViewObject.BoundingBox = True\n                # except Exception:\n                    # None\n                FcString.addObject(suppExtrude)       # contener support extrude\n\n        if ui.RA_Choice_Helix.isChecked():\n            ui.tabWidget.setCurrentIndex(1)\n            ui.Image_RA_Choice_Helix()\n        elif ui.RA_Choice_Clock.isChecked():\n            ui.tabWidget.setCurrentIndex(2)\n            ui.Image_RA_Choice_Clock()\n\n        # deselectionner tous les objets\n        try:\n            for obj in FreeCAD.ActiveDocument.Objects:# deselectionne tout\n                FreeCADGui.Selection.removeSelection(obj)\n        except Exception:\n            None\n\n        App.activeDocument().recompute()\n        FreeCAD.ActiveDocument.commitTransaction()\n#### Circular end\n\n        ####Info################################################\n        App.Console.PrintMessage(\"______________\" +\"\\n\")\n        App.Console.PrintMessage( PolicePath + \"\\n\")\n        App.Console.PrintMessage(\"Texte         : \" + str(texte) + \"\\n\")\n        App.Console.PrintMessage(\"Rayon         : \" + str(rayon) + \"\\n\")\n        App.Console.PrintMessage(\"SizeCaractere : \" + str(SizeCaractere) + \"\\n\")\n        App.Console.PrintMessage(\"Rotation      : \" + str(debut) + \"/\" + str(rotation) + \"\\n\")\n        App.Console.PrintMessage(\"Debout        : \" + str(debout) + \"\\n\")\n        App.Console.PrintMessage(\"Placement     : \" + str(PlacementX) + \", \" + str(PlacementY) + \", \" + str(PlacementZ) + \"\\n\")\n        App.Console.PrintMessage(\"Rotation      : \" + str(inclinaisonX) + \", \" + str(inclinaisonY) + \", \" + str(inclinaisonZ) + \"\\n\")\n        App.Console.PrintMessage(\"_______________\" +\"\\n\")\n\n        ####Reset################################################\n        if switchResetFALSE == 0:    # zero (False) by default = reset\n            ui.on_PU_Reset()\n\n    def on_PB_Help_clicked(self):\n        try:\n            webbrowser.open(__Wiki__)\n            App.Console.PrintMessage(\"https://wiki.freecadweb.org/Macro_FCCircularText\" + \"\\n\")\n        except Exception:\n            App.Console.PrintMessage(u\"Not access\")\n\n    def on_PU_Exit(self):                      # Exit\n        global ui\n        global s\n        global switchResetFALSE\n        global setFontByDefault\n        global switchModeTextList\n        global switchFontComBox\n        global setSystemFonts\n        global seTtextAlignement\n        global switchVersionSearch\n        global setMainWindowMoveX\n        global setMainWindowMoveY\n        global setFrameWindowSizeX\n        global setFrameWindowSizeY\n\n        FreeCADGui.Selection.removeObserver(s)                              # desinstalle la fonction residente\n        ###### Write Configuration begin ####\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetBool(\"switchResetFALSE\", switchResetFALSE)     # True or False (False by default)\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetString(\"setFontByDefault\", setFontByDefault)   # \"Arial\"\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetBool(\"switchModeTextList\", switchModeTextList) # True or False\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetBool(\"switchFontComBox\", switchFontComBox)     # True or False\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetBool(\"setSystemFonts\", setSystemFonts)         # True or False\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetInt(\"seTtextAlignement\", seTtextAlignement)    # 0, 1, 2\n        #### geometry\n        positionWindowXY = MainWindow.geometry()\n        setMainWindowMoveX  = positionWindowXY.x()\n        setMainWindowMoveY  = positionWindowXY.y()\n        positionWindowXY = MainWindow.size()\n        setFrameWindowSizeX = positionWindowXY.width()\n        setFrameWindowSizeY = positionWindowXY.height()\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetInt(\"setMainWindowMoveX\",  setMainWindowMoveX)      # setMainWindowMoveX\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetInt(\"setMainWindowMoveY\",  setMainWindowMoveY)      # setMainWindowMoveY\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetInt(\"setFrameWindowSizeX\", setFrameWindowSizeX)     # setFrameWindowSizeX\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetInt(\"setFrameWindowSizeY\", setFrameWindowSizeY)     # setFrameWindowSizeY\n        #### geometry\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetBool(\"setPathOrthogonal\", ui.RB_Path_01.isChecked())    # True or False\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetBool(\"setPathTangent\", ui.RB_Path_02.isChecked())       # True or False\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetBool(\"setPositionBase\", ui.RB_Position_01.isChecked())  # True or False\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetBool(\"setPositionCenter\", ui.RB_Position_02.isChecked())# True or False\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetBool(\"setPositionTop\", ui.RB_Position_03.isChecked())   # True or False\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetBool(\"switchVersionSearch\", switchVersionSearch)        # True or False\n        ###### Write Configuration end   ####\n\n        App.Console.PrintMessage(\"Fin FCCircularText\"+\"\\n\")\n        self.window.hide()\n####\nFreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetString(\"Version\",__Version__ + \" (\" + __Date__ + \")\")# \n##StyleSheet       = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/MainWindow\").GetString(\"StyleSheet\")\n\n####### Read Configuration begin ####\n#seTtextAlignement  = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetInt(\"seTtextAlignement\")\n#setSystemFonts     = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"setSystemFonts\")\n#switchFontComBox   = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"switchFontComBox\")\n#switchModeTextList = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"switchModeTextList\")\n#setFontByDefault   = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetString(\"setFontByDefault\")\n#switchResetFALSE   = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"switchResetFALSE\") \n##                    switchResetFALSE: desactive cree des erreurs de fonctionnement attention a l utilisation !!\n#setMainWindowMoveX = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetInt(\"setMainWindowMoveX\")\n#setMainWindowMoveY = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetInt(\"setMainWindowMoveY\")\n#setFrameWindowSizeX= FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetInt(\"setFrameWindowSizeX\")\n#setFrameWindowSizeY= FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetInt(\"setFrameWindowSizeY\")\n#\n#setPathOrthogonal = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"setPathOrthogonal\")\n#setPathTangent    = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"setPathTangent\")\n#setPositionBase   = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"setPositionBase\")\n#setPositionCenter = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"setPositionCenter\")\n#setPositionTop    = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"setPositionTop\")\n#\n#if setFontByDefault == \"\":\n#    if platform.system()   == \"Windows\" :\n#        PolicePath = originalFontPath = \"C:/Windows/Fonts/\"\n#        setFontByDefault = originalFontName = \"ARIAL\"\n#    elif platform.system() == \"Linux\" :\n#        PolicePath = originalFontPath = \"/usr/share/fonts/\"\n#        setFontByDefault = originalFontName = \"UBUNTU-M\"\n#    elif platform.system() == \"Darwin\":\n#        PolicePath = originalFontPath = \"/Library/Fonts/\"\n#        setFontByDefault = originalFontName = \"Arial\"\n#if platform.system() == \"Linux\" :\n#      PolicePath = originalFontPath = \"/usr/share/fonts/\"\n\n####### Read Configuration end   ####\n##################################################################################################\nclass SelObserver:\n    def addSelection(self, document, object, element, position):  # Selection\n        global ui\n        global PlacementX\n        global PlacementY\n        global PlacementZ\n        global correctionAngle\n        global setStylePathR # #F8E0E0\n        global setStylePathG # #E0F8E0\n        global setStyleBase\n\n        if ui.CB_06_ModeFree.isChecked(): \n            None\n        else:\n            try:\n                selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0]  # select one subElement\n                if (hasattr(selectedEdge,'Surface')) or (hasattr(selectedEdge,'Point')):\n                    if (hasattr(selectedEdge,'Point')):\n                        PlacementX = position[0]\n                        PlacementY = position[1]\n                        PlacementZ = position[2]\n                        ui.CH_Sp_Placement.setChecked(True)\n                        ui.DS_PlacementX.setValue(PlacementX)\n                        ui.DS_PlacementY.setValue(PlacementY)\n                        ui.DS_PlacementZ.setValue(PlacementZ)\n                        ui.on_CH_Sp_Placement()\n                    elif (hasattr(selectedEdge,'Surface')):\n                        None    # later\n                else:\n                    ui.tabWidget.setTabEnabled(3, True)\n                    ui.tabWidget.setCurrentIndex(3)\n                    ui.tabWidget.setStyleSheet(\"QTabWidget {\" + setStylePathG + \"}\")\n                    pathLength = \"Path ( \" + str(round(selectedEdge.Length, 2)) + \" mm )\"\n                    ui.tabWidget.setTabText(3, _fromUtf8(pathLength))\n                    ui.tabWidget.setTabEnabled(1, False)\n                    ui.tabWidget.setTabEnabled(2, False)\n                    ui.groupBox_03.setEnabled(False)\n                    ui.groupBox_03.setStyleSheet(\"QGroupBox {\" + setStylePathR + \"}\")\n                    ui.DS_Radius_Circle.setEnabled(False)\n                    ui.DS_Radius_Circle.setStyleSheet(\"QDoubleSpinBox {\" + setStylePathR + \"}\")\n                    ui.S_Begin_Angle.setEnabled(False)\n                    ui.S_Begin_Angle.setStyleSheet(\"QSpinBox {\" + setStylePathR + \"}\")\n                    ui.S_End_Angle.setEnabled(False)\n                    ui.S_End_Angle.setStyleSheet(\"QSpinBox {\" + setStylePathR + \"}\")\n                    ui.DS_Correction_Radius.setEnabled(False)\n                    ui.DS_Correction_Radius.setStyleSheet(\"QDoubleSpinBox {\" + setStylePathR + \"}\")\n                    ui.CB_02_Circle.setChecked(False)\n                    ui.CB_02_Circle.setEnabled(False)\n                    ui.CB_02_Circle.setStyleSheet(\"QCheckBox {\" + setStylePathR + \"}\")\n                    correctionAngle = 0.0\n                    ui.DS_Correction_Angle.setValue(correctionAngle)\n                    ui.on_RB_Path_Image()\n            except Exception:\n                selectedEdge = None\n                ui.tabWidget.setTabEnabled(1, True)\n                ui.tabWidget.setTabEnabled(2, True)\n                None\n\n##    def setPreselection(self,doc,obj,sub):             # preselection\n##        print \"setPreselection\"\n##    def removeSelection(self,doc,obj,sub):             # Effacer l'objet selectionne\n##        print \"removeSelection\"\n##    def setSelection(self,doc):                        # Selection dans ComboView\n##        print \"SelObserver quit macro\"\n    def clearSelection(self,doc):                       # Si clic sur l'ecran, effacer la selection\n        global ui\n\n        if ui.CB_06_ModeFree.isChecked(): \n            None\n        else:\n            ui.tabWidget.setStyleSheet(\"QTabWidget {\" + setStyleBase + \"}\") # tab \n            ui.tabWidget.setTabEnabled(3, False)     # tab Path\n            ui.tabWidget.setTabEnabled(1, True)      # tab \n            ui.tabWidget.setTabEnabled(2, True)      # tab \n            ui.tabWidget.setTabText(3, _fromUtf8(\"Path\"))\n            ui.groupBox_03.setEnabled(True)\n            ui.groupBox_03.setStyleSheet(\"QGroupBox {\" + setStyleBase + \"}\")\n            if ui.CB_06_ModeFree.isChecked(): \n                None\n            else:\n                ui.DS_Radius_Circle.setEnabled(True)\n                ui.DS_Radius_Circle.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\")\n                ui.S_Begin_Angle.setEnabled(True)\n                ui.S_Begin_Angle.setStyleSheet(\"QSpinBox {\" + setStyleBase + \"}\")\n                ui.S_End_Angle.setEnabled(True)\n                ui.S_End_Angle.setStyleSheet(\"QSpinBox {\" + setStyleBase + \"}\")\n                ui.DS_Correction_Radius.setEnabled(True)\n                ui.DS_Correction_Radius.setStyleSheet(\"QDoubleSpinBox {\" + setStyleBase + \"}\")\n            ui.CB_02_Circle.setEnabled(True)\n            ui.CB_02_Circle.setStyleSheet(\"QCheckBox {\" + setStyleBase + \"}\")\n            if ui.RA_Choice_Outdoor.isChecked():\n                ui.Image_RA_Choice_Outdoor()\n            elif ui.RA_Choice_Indoor.isChecked():\n                ui.Image_RA_Choice_Indoor()\n            elif ui.RA_Choice_Helix.isChecked():\n                ui.Image_RA_Choice_Helix()\n            elif ui.RA_Choice_Clock.isChecked():\n                ui.Image_RA_Choice_Clock()\n\ns=SelObserver()\nFreeCADGui.Selection.addObserver(s)                    # installe la fonction en mode resident\n###################################################################################################\n\n# create new document\ndoc = FreeCAD.ActiveDocument\nif doc == None:\n    doc = FreeCAD.newDocument(\"FCCircularText\")\n\n# deselectionner tous les objets\ntry:\n    for obj in FreeCAD.ActiveDocument.Objects:         # deselectionne tout\n        FreeCADGui.Selection.removeSelection(obj)\nexcept Exception:\n    None\n\nMainWindow = QtWidgets.QMainWindow()\nui = Ui_MainWindow()\nui.setupUi(MainWindow)\nMainWindow.show()\n",
    "url": "https://forum.freecadweb.org/viewtopic.php?f=3&t=7384%22",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/a25e802498bae6959335/raw/b80bc84eb1f39084a20564cf02c48764906fd6b8/Macro_FCCircularText.FCMacro",
    "wiki": "https://wiki.freecadweb.org/Macro_FCCircularText",
    "version": "0.22e",
    "license": "",
    "date": "2024/07/11",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\FCCircularTextButtom.png",
    "icon_source": "https://wiki.freecadweb.org/images/c/c1/FCCircularTextButtom.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FCHoneycombMaker",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro creates a parametric honeycomb grid.<br />The parametric properties are contained in a spreadsheet.<br />You could also change the base object for the honeycomb grid to achieve other interesting arrays, such as this egg crate by changing the base hexagon object with an egg-shaped ellipsoid.<br />Including hexagon radius, separation between hexagons, etc., can be modified via an included spreadsheet.<br /><br />Macro version: 2020.10.30<br />Last modified: 2020-10-30<br />FreeCAD version: 0.17 and above<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/2/2d/FCHoneycombMakerIcon.png\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "This macro creates a parametric honeycomb grid.",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2018-2019 <TheMarkster>                                 *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License at http://www.gnu.org/licenses     *\n*   for more details.                                                     *\n*                                                                         *\n*   For more information about the GNU Library General Public License     *\n*   write to the Free Software Foundation, Inc., 59 Temple Place,         *\n*   Suite 330, Boston, MA  02111-1307 USA                                 *\n*                                                                         *\n***************************************************************************\n\"\"\"\n\n\n\n\"\"\"\nFCHoneycombMaker\n\nThis is a macro to aid in creation of a honeycomb grid.  Parameters,\nincluding hexagon radius, separation between hexagons, etc., can be modified via an included spreadsheet.\n\"\"\"\n\n__title__ = \"FCHoneycombMaker\"\n__author__ = \"TheMarkster\"\n__url__ = \"https://github.com/mwganson/FCHoneycombMaker\"\n__Wiki__ = \"https://github.com/mwganson/FCHoneycombMaker/blob/master/README.md\"\n__date__ = \"2020.10.30\" #year.month.date\n__version__ = __date__\n\n\n\n\nimport FreeCAD\nimport math\nimport Part,Draft,DraftTools\nfrom PySide import QtCore, QtGui\nimport ProfileLib.RegularPolygon\nimport Sketcher\n\nRADIUS = 2\nSEPARATION = .25 \nPLATE_WIDTH = 20\nPLATE_LENGTH = 55\nPLATE_HEIGHT = 5\n\nFreeCAD.Console.PrintMessage ('\\nFCHoneycombMaker v'+__version__+'\\n')\n\n\ndef makeHexagonSketch(sketchName):\n    #would use the polygon tool, but is buggy and sometimes creates squares instead of hexagons, so the manual way\n    sketch = App.ActiveDocument.getObject(sketchName)\n#we just place the vertices any old where and then constrain them into place later\n    sketch.addGeometry(Part.LineSegment(App.Vector(-2.000000,1.448548,0),App.Vector(0.500515,2.469759,0)),False)\n    sketch.addGeometry(Part.LineSegment(App.Vector(0.500515,2.469759,0),App.Vector(2.000000,1.696951,0)),False)\n    sketch.addConstraint(Sketcher.Constraint('Coincident',0,2,1,1)) \n    sketch.addGeometry(Part.LineSegment(App.Vector(2.000000,1.696951,0),App.Vector(2.736140,-0.676675,0)),False)\n    sketch.addConstraint(Sketcher.Constraint('Coincident',1,2,2,1)) \n    sketch.addGeometry(Part.LineSegment(App.Vector(2.736140,-0.676675,0),App.Vector(1.000000,-2.415493,0)),False)\n    sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) \n    sketch.addGeometry(Part.LineSegment(App.Vector(1.000000,-2.415493,0),App.Vector(-3.000000,-1.000000,0)),False)\n    sketch.addConstraint(Sketcher.Constraint('Coincident',3,2,4,1)) \n    sketch.addGeometry(Part.LineSegment(App.Vector(-3.000000,-1.000000,0),App.Vector(-2.000000,1.365748,0)),False)\n    sketch.addConstraint(Sketcher.Constraint('Coincident',4,2,5,1)) \n    sketch.addConstraint(Sketcher.Constraint('Coincident',5,2,0,1)) \n    sketch.addGeometry(Part.Circle(App.Vector(0.000000,0.000000,0),App.Vector(0,0,1),3.535498),False) #construction circle\n    sketch.addConstraint(Sketcher.Constraint('Coincident',6,3,-1,1)) \n    sketch.addConstraint(Sketcher.Constraint('Radius',6,3.535498)) \n    sketch.setDatum(7,App.Units.Quantity('2.000000 mm'))\n    sketch.addConstraint(Sketcher.Constraint('PointOnObject',4,2,6)) #constrain all vertices to the circumference\n    sketch.addConstraint(Sketcher.Constraint('PointOnObject',0,1,6)) \n    sketch.addConstraint(Sketcher.Constraint('PointOnObject',0,2,6)) \n    sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,2,6)) \n    sketch.addConstraint(Sketcher.Constraint('PointOnObject',2,2,6)) \n    sketch.addConstraint(Sketcher.Constraint('PointOnObject',3,2,6)) \n    sketch.toggleConstruction(6) \n    sketch.addConstraint(Sketcher.Constraint('Equal',5,0)) #set all lines equal\n    sketch.addConstraint(Sketcher.Constraint('Equal',0,1)) \n    sketch.addConstraint(Sketcher.Constraint('Equal',1,2)) \n    sketch.addConstraint(Sketcher.Constraint('Equal',2,3)) \n    sketch.addConstraint(Sketcher.Constraint('Equal',3,4)) \n    sketch.addConstraint(Sketcher.Constraint('Horizontal',0)) #make one of them horizontal\n    sketch.setExpression('Constraints[7]', u'EditMe.radius')\n\n\n\n\n\nif not App.ActiveDocument:\n    App.newDocument()\nif hasattr(App.ActiveDocument,\"EditMe\"):\n    raise StandardError(\"FCHoneycombMaker Error: Please run only once per document.  Create a new document and try again.\\n\")\n\nworksheet = App.ActiveDocument.addObject(\"Spreadsheet::Sheet\", \"EditMe\")\nworksheet.setColumnWidth('A',150)\nset = worksheet.set\n\nworksheet.mergeCells('A11:G25')\nmsg1 = \"\"\"Instructions:\n\nYou should only run the macro once unless you want to start again from scratch.\n\nEdit the values in column B to define your honeycomb.  You can also edit the objects (plate, arrays, etc.), but it's \nprobably better to do all the editing here in the spreadsheet at least until you get it more or less like you want it before\ndoing some final tweaking directly on the objects.\n\nHexagon radius -- the circumradius of the individual hexagons (circle with each vertex on its circumference).\n\nHexagon separation -- distance between each hexagon, the thickness of the grid produced after cutting the hexagons from the plate.\n\nPlate dimensions -- sets the dimensions of the plate out of which the honeycomb can be cut.  These values are used to calculate\nthe countX and countY variables.  You can delete the plate object if you wish to apply the hexagon arrays to a different structure.\n\nTweak X,Y,Z -- Edit these to move both hexagon arrays independently of the plate object, for example to center the arrays inside \nthe plate.\n\nCountX and CountY -- number of hexagons in the 2 arrays.  These are calculated based on the plate size, radius of hexagons, and \nseparation between them, but you will probably want to modify these manually.  Just remember if you modify them you are replacing \nthe formulas in those cells with immediate values, and thus they won't be recalulated for you if other changes are made.\n\nIf you would prefer a round plate, simply delete the plate object and replace it with a cylinder, and then use the Tweak values \nand countX and countY variables to arrange the hexagon arrays to your liking.\n\n\"\"\"\nset('A13', msg1)\n\n\naliases={'radius':'B2', 'separation':'B3', 'width':'B4', 'length':'B5', 'height':'B6', 'tweakX':'B8','tweakY':'B9','tweakZ':'B10',\n'xInterval':'E2', 'yInterval':'E3', 'firstX':'E4', 'firstY':'E5','countX':'E6', 'countY':'E7','array2XPos':'E8','array2YPos':'E9',\n\n }\n\nfor k,v in aliases.items():\n   worksheet.setAlias(v,k)\n\n\n\nset('A1', 'User Variables')\nset('D1','Calculated Values')\nset('A2', 'Hexagon Radius:')\nset(aliases['radius'], str(RADIUS))\nset('A3', 'Hexagon Separation:')\nset(aliases['separation'], str(SEPARATION))\nset('A4', 'Grid Width:')\nset(aliases['width'], str(PLATE_WIDTH))\nset('A5', 'Grid Length:')\nset(aliases['length'], str(PLATE_LENGTH))\nset('A6', 'Grid Height:')\nset(aliases['height'], str(PLATE_HEIGHT))\nset('A8', 'Tweak X:')\nset(aliases['tweakX'],u'0')\nset('A9', 'Tweak Y:')\nset(aliases['tweakY'],u'0')\nset('A10', 'Tweak Z:')\nset(aliases['tweakZ'],u'0')\n\n\n\n\nset('D2','X Interval:')\nset(aliases['xInterval'],'=2*sin(60deg)*(B2*2+(B3-0.267949*B2))')\nset('D3', 'Y Interval:')\nset(aliases['yInterval'], '=2*B2+(B3-0.267949*B2)' )\nset('D4', 'First X:')\nset(aliases['firstX'], '=B2')\nset('D5', 'First Y:')\nset(aliases['firstY'], '=B2')\nset('D6', 'Count X:')\nset(aliases['countX'], '=round((B5) / E2) + 2')\nset('D7', 'Count Y:')\nset(aliases['countY'], '=round((B4) / E3) + 2')\nset ('D8', 'Array2 XPos:')\nset (aliases['array2XPos'], '=sin(60deg)*(B2*2+B3-0.26794899999999999*B2)')\nset ('D9', 'Array2 YPos:')\nset (aliases['array2YPos'],'=E3/2')\n\n\n\n\n\n#xInterval = float(worksheet.getContents(aliases['xInterval']))\nxInterval = 2*math.sin(math.pi/180.0*60)*(RADIUS*2+(SEPARATION-0.267949))\nyInterval = 2*RADIUS+(SEPARATION-0.267949)\n#yInterval = float(worksheet.getContents(aliases['yInterval']))\nfirstX = RADIUS\nfirstY = RADIUS\n\ncountY = int((PLATE_LENGTH) / yInterval)\ncountX = int((PLATE_WIDTH) / xInterval)\n\n\n\n\nApp.ActiveDocument.addObject(\"Part::RegularPolygon\",\"HoneycombHexagon\")\nApp.ActiveDocument.HoneycombHexagon.Polygon=6\nApp.ActiveDocument.HoneycombHexagon.setExpression('Circumradius','EditMe.radius')\nhexagonObject = App.ActiveDocument.getObject(\"HoneycombHexagon\")\nGui.ActiveDocument.getObject(\"HoneycombHexagon\").Visibility=False\n\n\nextrudedHexagonObject = App.ActiveDocument.addObject('Part::Extrusion', 'ExtrudedHexagon')\nextrudedHexagonObject.Base = hexagonObject\nextrudedHexagonObject.setExpression('LengthFwd','EditMe.height')\nextrudedHexagonObject.Solid=True\n#extrudedHexagonObject.Placement=App.Placement(App.Vector(firstX,firstY,0),App.Rotation(0,0,0),App.Vector(0,0,0))\nextrudedHexagonObject.setExpression('Placement.Base.x','EditMe.firstX+EditMe.tweakX')\nextrudedHexagonObject.setExpression('Placement.Base.y','EditMe.firstY+EditMe.tweakY')\nextrudedHexagonObject.setExpression('Placement.Base.z', 'EditMe.tweakZ')\n\nxvector = App.Vector(xInterval,0,0)\nyvector = App.Vector(0, yInterval,0)\nif not hasattr(Draft,\"make_ortho_array\"):\n    row1Array = Draft.makeArray(extrudedHexagonObject, xvector,yvector,countX,countY,name=\"HoneycombArray1\")\n    row2Array = Draft.makeArray(extrudedHexagonObject, xvector,yvector,countX,countY,name=\"HoneycombArray2\")\nelse:\n    row1Array = Draft.make_ortho_array(extrudedHexagonObject, v_x=xvector,v_y=yvector,n_x=countX,n_y=countY,use_link=False)\n    row2Array = Draft.make_ortho_array(extrudedHexagonObject, v_x=xvector,v_y=yvector,n_x=countX,n_y=countY,use_link=False)\nApp.ActiveDocument.recompute()\nrow2Array.Placement = App.Placement(App.Vector(math.sin(60*math.pi/180.0)*(RADIUS*2+(SEPARATION-0.267949)),yInterval,0),App.Rotation(0,0,0),App.Vector(0,0,0))\n#row2Array.setExpression('Placement.Base.x','sin(60deg) * (EditMe.radius * 2 + (EditMe.separation-0.267949*EditMe.radius))')\nrow2Array.setExpression('Placement.Base.x','EditMe.array2XPos')\n#row2Array.setExpression('Placement.Base.y','EditMe.yInterval/2.0')\nrow2Array.setExpression('Placement.Base.y','EditMe.array2YPos')\nrow1Array.setExpression('IntervalX.x','EditMe.xInterval')\nrow1Array.setExpression('IntervalY.y','EditMe.yInterval')\nrow1Array.setExpression('NumberX','EditMe.countX')\nrow1Array.setExpression('NumberY','EditMe.countY')\n\nrow2Array.setExpression('IntervalX.x','EditMe.xInterval')\nrow2Array.setExpression('IntervalY.y','EditMe.yInterval')\nrow2Array.setExpression('NumberX','EditMe.countX')\nrow2Array.setExpression('NumberY','EditMe.countY')\n\nApp.activeDocument().addObject(\"Part::MultiFuse\",\"Fused_Arrays\")\n#App.activeDocument().Fused_Arrays.Shapes = [App.activeDocument().HoneycombArray1,App.activeDocument().HoneycombArray2,]\nApp.activeDocument().Fused_Arrays.Shapes = [row1Array,row2Array,]\nif not hasattr(Draft,\"make_ortho_array\"):\n    Gui.activeDocument().HoneycombArray1.Visibility=False\n    Gui.activeDocument().HoneycombArray2.Visibility=False\nelse:\n    row1Array.Visibility=False\n    row2Array.Visibility=False\n\n\nwindow = QtGui.QApplication.activeWindow()\nitems=('Part Design Workbench Body','Part Workbench Object')\nitem,ok = QtGui.QInputDialog.getItem(window, \"Select object type\", \"Select your object type.  It can be a Part Design body or a Part Cut object.\", items, 0, False)\nif ok:\n    if item == items[0]: #PD Body\n\n        App.ActiveDocument.addObject(\"Part::Plane\", \"HoneycombPlane\")\n        App.ActiveDocument.HoneycombPlane.setExpression('Length', u'EditMe.length')\n        App.ActiveDocument.HoneycombPlane.setExpression('Width', u'EditMe.width')\n        App.ActiveDocument.HoneycombPlane.setExpression('Placement.Base.x', u'EditMe.array2XPos + EditMe.radius * 2')\n        App.ActiveDocument.HoneycombPlane.setExpression('Placement.Base.y', u'EditMe.array2YPos + EditMe.radius * 2')\n\n        App.activeDocument().addObject(\"Part::Cut\",\"BaseFeatureFace\")\n        App.ActiveDocument.getObject(\"BaseFeatureFace\").ViewObject.Visibility=False\n        App.activeDocument().BaseFeatureFace.Base = App.activeDocument().HoneycombPlane\n        App.activeDocument().BaseFeatureFace.Tool = App.activeDocument().Fused_Arrays\n        Gui.activeDocument().HoneycombPlane.Visibility=False\n        Gui.activeDocument().Fused_Arrays.Visibility=False\n        App.ActiveDocument.recompute()\n        App.activeDocument().addObject('PartDesign::Body','HoneycombBody')\n        App.activeDocument().HoneycombBody.BaseFeature = App.activeDocument().BaseFeatureFace\n        Gui.activeView().setActiveObject('pdHoneycombBody', App.activeDocument().HoneycombBody)\n        App.activeDocument().HoneycombBody.newObject(\"PartDesign::Pad\",\"HoneycombPad\")\n        App.activeDocument().HoneycombPad.Profile = (App.activeDocument().BaseFeature, [\"Face1\"])\n        App.activeDocument().HoneycombPad.Length = 10.0\n        App.ActiveDocument.recompute()\n        Gui.activeDocument().setEdit('HoneycombPad', 0)\n        Gui.activeDocument().hide(\"BaseFeature\")\n        App.ActiveDocument.HoneycombPad.setExpression('Length', u'EditMe.height')\n        App.ActiveDocument.HoneycombPad.Length2 = 100.000000\n        App.ActiveDocument.HoneycombPad.Type = 0\n        App.ActiveDocument.HoneycombPad.UpToFace = None\n        App.ActiveDocument.HoneycombPad.Reversed = 0\n        App.ActiveDocument.HoneycombPad.Midplane = 0\n        App.ActiveDocument.HoneycombPad.Offset = 0.000000\n        App.ActiveDocument.recompute()\n        Gui.activeDocument().resetEdit()\n    else: #Part object\n        #plate = Part.makeBox(PLATE_WIDTH,PLATE_LENGTH,PLATE_HEIGHT)\n        #plate = Part.makeBox(worksheet.B4, worksheet.B5, worksheet.B6)\n        App.ActiveDocument.addObject(\"Part::Box\", \"Plate\")\n        plateObject = App.ActiveDocument.getObject(\"Plate\")\n        App.ActiveDocument.Plate.setExpression('Length', u'EditMe.length')\n        App.ActiveDocument.Plate.setExpression('Width', u'EditMe.width')\n        App.ActiveDocument.Plate.setExpression('Height', u'EditMe.height')\n        App.ActiveDocument.Plate.setExpression('Placement.Base.x', u'EditMe.array2XPos + EditMe.radius * 2')\n        App.ActiveDocument.Plate.setExpression('Placement.Base.y', u'EditMe.array2YPos + EditMe.radius * 2')\n\n        App.activeDocument().addObject(\"Part::Cut\",\"HoneycombGrid\")\n        App.activeDocument().HoneycombGrid.Base = App.activeDocument().Plate\n        App.activeDocument().HoneycombGrid.Tool = App.activeDocument().Fused_Arrays\n        Gui.activeDocument().Plate.Visibility=False\n        Gui.activeDocument().Fused_Arrays.Visibility=False\n\n\n\nApp.ActiveDocument.recompute()\nGui.SendMsgToActiveView(\"ViewFit\")",
    "url": "https://wiki.freecad.org/Macro_FCHoneycombMaker",
    "raw_code_url": "",
    "wiki": "https://github.com/mwganson/FCHoneycombMaker/blob/master/README.md",
    "version": "2020.10.30",
    "license": "",
    "date": "2020.10.30",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\FCHoneycombMakerIcon.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/2/2d/FCHoneycombMakerIcon.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FCSpring Helix Variable",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro creates a spring with customizable, any turn may change the spring configuration can be saved in a file with the extension <b>.FCSpring</b> or coordinates <b>.FCSpringCoor</b>.<br />Are detected: Surface (Face direction), Cylinder (Radius), Ellipse (MinorRadius), Sphere (Radius), Toroid (Radius1), Plane (Direction), Line (follow the Direction ), Point (XYZ vertex position)<br />If no object is detected (not selection) the spring is created at the point XYZ 0., 0., 0.<br />See the <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/Macro_FCSpring_Helix_Variable#Examples\">examples</a><br /> <p><br /> Download <a rel=\"nofollow\" class=\"external text\" href=\"https://forum.freecadweb.org/download/file.php?id=80844\">the Icons</a> in .zip file<br /><br />Macro version: 01.19<br />Last modified: 2024/07/11<br />FreeCAD version: 0.19 and bigger<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/6/69/FCSpring_Helix_Variable.png\">ToolBar Icon</a><br />Author: Mario52<br /> </p> ",
    "comment": "This macro creates a spring with customizable, any turn may change the spring configuration can be saved in a file with the extension .FCSpring or coordinates .FCSpringCoor.",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\nfrom __future__ import division\n\"\"\"\n***************************************************************************\n*   Copyright (c) <mario52> 2014-2015-2016-2017 2018 2019 2020 2022 2023  *\n*                           2024                                          *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#\n#OS: Windows 10 build 19045                                  #OS: Linux Mint 20.1 (X-Cinnamon/cinnamon)\n#Word size of FreeCAD: 64-bit                                #Word size of FreeCAD: 64-bit\n#Version: 0.22.0dev.33981 (Git)                              #Version: 0.22.0dev.37928 (Git) AppImage\n#Build type: Release                                         #Build type: Release\n#Branch: master                                              #Branch: main\n#Hash: 5a153e50ffb6046b6cc4dba498344032f6edb952              #Hash: e7699b531eba4bee262f7214699f07b96f66ba7b\n#Python 3.10.12, Qt 5.15.8, Coin 4.0.0, Vtk 9.2.5, OCC 7.6.3 #Python 3.11.9, Qt 5.15.13, Coin 4.0.2, Vtk 9.2.6, OCC 7.7.2\n#Locale: French/Mars (fr_MA)                                 #Locale: C/Default (C)\n#\n#\n__Title__   = \"FCSpring_Helix_Variable\"\n__Author__  = \"Mario52\"\n__Url__     = \"http://www.freecadweb.org/index-fr.html\"\n__Wiki__    = \"http://www.freecadweb.org/wiki/index.php?title=Macro_FCSpring_Helix_Variable\"\n__GitHub__  = \"https://gist.github.com/mario52a/68c81c32a0727a693d3a\"\n__Version__ = \"01.19\"\n__Date__    = \"2024/07/11\" # YYYY/MM/DD\n#\n#\nimport PySide2\nfrom PySide2 import QtWidgets, QtCore, QtGui\nfrom PySide2.QtWidgets import * #(QWidget, QApplication, QSlider, QGraphicsView, QGraphicsScene, QVBoxLayout, QStyle)\nfrom PySide2.QtGui import *\nfrom PySide2.QtCore import *\n#from PySide2.QtGui import (QPainter, QColor, QIcon)\n#from PySide2.QtSvg import *\n\ntry:\n    import webbrowser\nexcept Exception:\n    None\n\nimport os, sys #, time\nimport Draft, Part, FreeCAD, math, PartGui, FreeCADGui, FreeCAD\nfrom math import sqrt, pi, sin, cos, asin, tan, degrees, radians, sqrt\nfrom FreeCAD import Base\nApp = FreeCAD\n\n####chrono################\nimport time\nglobal depart ; depart  = 0.0\nglobal arrivee; arrivee = 0.0\ndef chrono(switch):    # 0=depart autre=stop\n#time.strftime('%X %x %Z')#'15:44:07 12/14/19 Paris, Madrid'\n    global depart\n    global arrivee\n    try:\n        if switch == 0:\n            depart = time.time()#time.clock()\n            App.Console.PrintMessage(\"Chrono begin   : \"+str(time.strftime('%X'))+\"\\n\")\n        else:\n            arrivee = time.time()#time.clock()\n            App.Console.PrintMessage(\"Chrono end     : \"+str(time.strftime('%X'))+\"\\n\")\n            parcouru = ((arrivee - depart)/60.0)\n            App.Console.PrintError(\"Time execution : \"+str(\"%.3f\" % parcouru)+\" min\"+\"\\n\\n\")\n        return parcouru\n        FreeCADGui.updateGui()    \n    except Exception: None\n####chrono################\n\n##path###########################################################################\nglobal path\n#path = FreeCAD.ConfigGet(\"AppHomePath\")\n#path = FreeCAD.ConfigGet(\"UserAppData\")\n#path = \"your path\"\nparam = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")# macro path\npath = param.GetString(\"MacroPath\",\"\") + \"/\"                        # macro path\npath = path.replace(\"\\\\\",\"/\")                                       # convert the \"\\\" to \"/\"\n#print( \"Path for the icons : \" , path )\n##path###########################################################################\n                                                 \nglobal numberSpires        ;numberSpires         = 10     # number Spires of spring\nglobal rayon               ;rayon                = 20.0   # radius of spring\nglobal pas                 ;pas                  = 15.0   # \" ! float \" (pas) pitch of spire\nglobal precision           ;precision            = 5.0    # \" ! float \" 360/precision number points for 1 turn\nglobal typeLine            ;typeLine             = 0      # typeLine 0=BSpline or 1=Wire\nglobal helixS              ;helixS               = 0.0    # tableau\nglobal numberSpiresModified;numberSpiresModified = 1      # number (pas) pitch to modify\nglobal pasSpire            ;pasSpire             = 0      #pas    # (pas) pitch of spire to modify\nglobal radiusS             ;radiusS              = 0.0    # tableau radius to modify\nglobal rayonSpire          ;rayonSpire           = 0      #rayon  # new radius\nglobal affPoint            ;affPoint             = 0      # aff points\nglobal debutAngle          ;debutAngle           = 0      # begin angle rotation\nglobal finAngle            ;finAngle             = 360    # end angle rotation\nglobal modifyAngle         ;modifyAngle          = 0      # interrupteur angle\nglobal radius_2_Cone       ;radius_2_Cone        = rayon  # radius_2_Cone en cas d'helice\nglobal spireConeUne        ;spireConeUne         = 0      # interrupteur cone si une seule spire spireConeUne = 1\nglobal spireConeComp       ;spireConeComp        = 0      # compensation pour cone\nglobal spireReverse        ;spireReverse         = 0      # 0 = sens antihoraire si = 1 sens horaire\nglobal lissageSpire        ;lissageSpire         = 0      # niveau de lissage\nglobal lissageS            ;lissageS             = 0      # tableau\nglobal fichierOpen         ;fichierOpen          = 0      # switch fichier precision\nglobal nomF                ;nomF                 = \"Name File\" # name file\nglobal points              ;points               = []     # tableau points\nglobal zoom                ;zoom                 = 0      # zoom textEdit\nglobal ressort             ;ressort              = \"\"\n\nglobal s                   ;s                    = \"\"     # resident\nglobal ui                  ;ui                   = \"\"     # resident\nglobal sel                 ;sel                  = \"\"     # resident selection\n\nglobal pointsDirection     ;pointsDirection      = []     # tableau direction\nglobal Direction_Begin     ;Direction_Begin      = 0      # direction tableau 0\nglobal Direction_Distance  ;Direction_Distance   = 0.1    # precision Distance coupure et deplacement\nglobal plr                 ;plr                  = \"\"     # placement sur selection\nglobal coor_Z              ;coor_Z               = 0.0    # pour calcul placement\nglobal hauteurCylindre     ;hauteurCylindre      = 0.0    # adapter la hauteur du ressort\nglobal vecteurSouris       ;vecteurSouris        = \"\"     # vecteur Selobserver\nglobal centerFaceOrPoint   ;centerFaceOrPoint    = 0      # centrage de l'axe sur face ou au point souris\nglobal axisSpring          ;axisSpring           = \"\"     # axe de l'objet pour le ressort\nglobal switchReverse       ;switchReverse        = 0      # switchReverse\nglobal switchAdaptRadius   ;switchAdaptRadius    = 0      # switchAdaptRadius\nglobal selectedCircle      ;selectedCircle       = []     # tableau Circle\n\n\n#### Configuration begin ################################################\n#### NOT MODIFY THE CODE HERE ####\n#### for modify : go to : FreeCAD >Menu >Tools >Edit parameters... >BaseApp/Preferences/Macros/FCMmacros/FCInfo ####\n##\nFreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetString(u\"Version\", __Version__ + \" (\" + __Date__ + \")\")\n##\nglobal seTPositionFlyRightLeft  #; seTPositionFlyRightLeft  = 2    # 1 = fly, 2 = RightDock other= LeftDock\nseTPositionFlyRightLeft = FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetInt(u\"seTPositionFlyRightLeft\")\nif seTPositionFlyRightLeft == 0: seTPositionFlyRightLeft = 1\nFreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetInt(u\"seTPositionFlyRightLeft\", seTPositionFlyRightLeft)                           #*1, 2, other\n##\nglobal seTWidgetPosition        #; seTWidgetPosition        = 0   # position the widget Left or Right\nseTWidgetPosition = FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(u\"seTWidgetPosition\")\nFreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetBool(u\"seTWidgetPosition\", seTWidgetPosition)                # True or False\n##\nglobal switchQFileDialogMint    # special LinuxMint\nswitchQFileDialogMint = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetBool(\"switchQFileDialogMint\")\nif switchQFileDialogMint == 0:\n    FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetBool(\"switchQFileDialogMint\", switchQFileDialogMint)\ntry:\n    if os.uname()[1] == \"mint\":\n        switchQFileDialogMint = 1\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetBool(\"switchQFileDialogMint\", switchQFileDialogMint)  #*Special Mint\nexcept Exception:\n    None\n##\nglobal setPathLatestDirectory   #; setPathLatestDirectory   = \"C:\\ ???\"\nsetPathLatestDirectory = FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).GetString(u\"setPathLatestDirectory\")\nif setPathLatestDirectory == \"\": setPathLatestDirectory = path\nFreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetString(u\"setPathLatestDirectory\", setPathLatestDirectory)    #*\"C:\\ ???\"\n##\n#### Configuration end ################################################\n##\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\ndef errorDialog(msg):\n    diag = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Critical,u\"Error Message\",msg )\n    diag.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) # PySide #cette fonction met la fenetre en avant\n#    diag.setWindowModality(QtCore.Qt.ApplicationModal)         # la fonction a ete desactivee pour favoriser \"WindowStaysOnTopHint\"\n    diag.exec_()\n\nclass Ui_MainWindow(object):\n\n    def setupUi(self, MainWindow):\n        global path\n        global numberSpires\n        global rayon\n        global pas\n        global precision\n        global typeLine\n        global helixS\n        global pasSpire\n        global radiusS\n        global spireReverse\n        global nomF\n        global zoom\n        global sel\n        global Direction_Distance\n        global seTPositionFlyRightLeft\n        global seTWidgetPosition\n\n        self.window = MainWindow\n        ####\n        if seTPositionFlyRightLeft == 1:\n            MainWindow.setObjectName(_fromUtf8(u\"MainWindow\"))    # volant\n#            MainWindow.resize(500, 503)\n#            MainWindow.setMinimumSize(QtCore.QSize(500, 503))\n            #MainWindow.setMaximumSize(QtCore.QSize(380, 590))\n            #MainWindow.move(1300, 120)                           # deplace la fenetre\n\n#        MainWindow.setMinimumSize(QtCore.QSize(250, 600))\n#        MainWindow.resize(300, 650)\n#        MainWindow.setGeometry(960, 160, 270, 660)\n#        MainWindow.setMaximumSize(QtCore.QSize(270, 660))\n\n        self.centralWidget = QtWidgets.QWidget(MainWindow)\n\n        ###################\n        grid = QtWidgets.QGridLayout()\n        self.centralWidget.setLayout(grid)\n        ####\n        self.scrollArea = QtWidgets.QScrollArea(self.centralWidget)    # cadre scrollarea contenant le widget GUI\n        self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)\n        self.scrollArea.setWidgetResizable(True)\n        grid.addWidget(self.scrollArea, 0, 0)\n        vbox = QtWidgets.QVBoxLayout()\n        self.scrollArea.setLayout(vbox)\n        ####\n        self.scrollAreaWidgetContents_2 = QtWidgets.QWidget()          #widget contenant le GUI\n        vbox.addWidget(self.scrollAreaWidgetContents_2)\n        vbox = QtWidgets.QVBoxLayout()\n        self.scrollAreaWidgetContents_2.setLayout(vbox)\n        ###################\n\n        self.groupBox0 = QtWidgets.QGroupBox()  #self.centralWidget\n        self.groupBox0.setFlat(False)\n        self.groupBox_01 = QtWidgets.QGroupBox() #self.groupBox0\n        self.groupBox_01.setFlat(False)\n\n        self.DS_Numb_Spires = QtWidgets.QSpinBox()\n        self.DS_Numb_Spires.setMinimum(1)\n        self.DS_Numb_Spires.setMaximum(9999999)\n        self.DS_Numb_Spires.setValue(numberSpires)\n        self.DS_Numb_Spires.valueChanged.connect(self.on_DS_Numb_Spires)       #connection doubleSpinBox\n\n        self.DS_Pas_Spring = QtWidgets.QDoubleSpinBox()\n        self.DS_Pas_Spring.setDecimals(3)\n#        self.DS_Pas_Spring.setMinimum(0.001)\n        self.DS_Pas_Spring.setMaximum(9999999.99)\n        self.DS_Pas_Spring.setValue(pas)\n        self.DS_Pas_Spring.valueChanged.connect(self.on_DS_Pas_Spring)         #connection doubleSpinBox\n\n        self.DS_Radius_Sping = QtWidgets.QDoubleSpinBox()\n        self.DS_Radius_Sping.setDecimals(3)\n#        self.DS_Radius_Sping.setMinimum(0.001)\n        self.DS_Radius_Sping.setMaximum(9999999.99)\n        self.DS_Radius_Sping.setValue(rayon)\n        self.DS_Radius_Sping.valueChanged.connect(self.on_DS_Radius_Sping)     #connection doubleSpinBox\n\n        self.DS_Precision_Turn = QtWidgets.QSpinBox()\n        self.DS_Precision_Turn.setMinimum(1)\n        self.DS_Precision_Turn.setMaximum(360)\n        self.DS_Precision_Turn.setValue(precision)\n        self.DS_Precision_Turn.valueChanged.connect(self.on_DS_Precision_Turn) #connection doubleSpinBox\n\n        self.DS_Radius_2_Cone = QtWidgets.QDoubleSpinBox()\n        self.DS_Radius_2_Cone.setEnabled(False)\n        self.DS_Radius_2_Cone.setDecimals(3)\n        self.DS_Radius_2_Cone.setMaximum(9999999.99)\n#        self.DS_Radius_2_Cone.setMinimum(rayon)\n        self.DS_Radius_2_Cone.setValue(rayon)\n        self.DS_Radius_2_Cone.valueChanged.connect(self.on_DS_Radius_2_Cone)   # connection\n\n        self.CH_Cone = QtWidgets.QCheckBox()\n        self.CH_Cone.setEnabled(True)\n        self.CH_Cone.clicked.connect(self.on_CH_Cone)                          # connection\n        \n        self.LAB_Numb_Spires = QtWidgets.QLabel()\n        self.LAB_Pas_Spring = QtWidgets.QLabel()\n        self.LAB_Radius_Spring = QtWidgets.QLabel()\n        self.LAB_Precision_Turn = QtWidgets.QLabel()\n        self.LAB_Radius_2_Cone = QtWidgets.QLabel()\n        self.LAB_Radius_2_Cone.setVisible(False)\n\n        self.SP_Begin_Angle = QtWidgets.QSpinBox()\n        self.SP_Begin_Angle.setEnabled(False)\n        self.SP_Begin_Angle.setMinimum(0)\n        self.SP_Begin_Angle.setMaximum(360)\n        self.SP_Begin_Angle.setValue(0)\n        self.SP_Begin_Angle.valueChanged.connect(self.on_SP_Begin_Angle)       # connection\n\n        self.SP_End_Angle = QtWidgets.QSpinBox()\n        self.SP_End_Angle.setEnabled(False)\n        self.SP_End_Angle.setMinimum(1)\n        self.SP_End_Angle.setMaximum(360)\n        self.SP_End_Angle.setValue(360)\n        self.SP_End_Angle.valueChanged.connect(self.on_SP_End_Angle)           # connection\n\n        self.LAB_Begin_Angle = QtWidgets.QLabel()\n        self.LAB_End_Angle = QtWidgets.QLabel()\n\n        self.CB_B_E_Angle = QtWidgets.QCheckBox()\n        self.CB_B_E_Angle.clicked.connect(self.on_CB_B_E_Angle)                # connection radioButton\n\n        ####\n\n        self.groupBox_02 = QtWidgets.QGroupBox()\n\n        self.RA_Wire = QtWidgets.QRadioButton()\n#        self.RA_Wire.setChecked(True)\n        self.RA_Wire.setIcon(QtGui.QIcon.fromTheme(\"Draft\",QtGui.QIcon(\":/icons/Draft_Wire.svg\")))\n        self.RA_Wire.clicked.connect(self.on_RA_Wire)                          #connection radioButton\n\n        self.RA_BSpline = QtWidgets.QRadioButton()\n        self.RA_BSpline.setChecked(True)\n        self.RA_BSpline.setIcon(QtGui.QIcon.fromTheme(\"Draft\",QtGui.QIcon(\":/icons/Draft_BSpline.svg\")))\n        self.RA_BSpline.clicked.connect(self.on_RA_BSpline)                    #connection radioButton\n\n        self.CH_Points = QtWidgets.QCheckBox()\n        self.CH_Points.setEnabled(True)\n#        self.CH_Points.setStatusTip(_fromUtf8(\"\"))\n        self.CH_Points.setChecked(False)\n        self.CH_Points.setIcon(QtGui.QIcon.fromTheme(\"Draft\",QtGui.QIcon(\":/icons/Draft_Point.svg\")))\n        self.CH_Points.clicked.connect(self.on_CH_Points) #\n\n        self.CH_Reverse = QtWidgets.QCheckBox()\n        self.CH_Reverse.setEnabled(True)\n#        self.CH_Reverse.setStatusTip(_fromUtf8(\"\"))\n        self.CH_Reverse.setChecked(False)\n        self.CH_Reverse.clicked.connect(self.on_CH_Reverse)                    #\n        ####\n\n        self.groupBox_03 = QtWidgets.QGroupBox()\n\n        self.PB_Adapt_Radius = QtWidgets.QPushButton()\n        self.PB_Adapt_Radius.setEnabled(False)\n        self.PB_Adapt_Radius.clicked.connect(self.on_PB_Adapt_Radius)          #\n\n        self.PB_Center_Point = QtWidgets.QPushButton()\n        self.PB_Center_Point.setEnabled(False)\n        self.PB_Center_Point.clicked.connect(self.on_PB_Center_Point)          #\n\n        self.CB_Position = QtWidgets.QCheckBox()\n        self.CB_Position.setEnabled(False)\n        self.CB_Position.clicked.connect(self.on_CB_Position)                  #\n\n        self.PB_CreaCircle = QtWidgets.QPushButton()\n        self.PB_CreaCircle.setEnabled(False)\n        self.PB_CreaCircle.clicked.connect(self.on_PB_CreaCircle)              #\n        ####\n\n        self.groupBox_04 = QtWidgets.QGroupBox()\n        self.groupBox_04.setEnabled(False)\n        #self.groupBox_04.setCheckable(True)\n        #self.groupBox_04.setChecked(False)\n        self.groupBox_04.setStyleSheet(\"QGroupBox {background-color: QPalette.Base}\")      # origin system\n\n        self.PB_Begin_End = QtWidgets.QPushButton()\n        self.PB_Begin_End.clicked.connect(self.on_PB_Begin_End)                # connection\n\n        self.PB_Reverse_Spr = QtWidgets.QPushButton()\n        self.PB_Reverse_Spr.clicked.connect(self.on_PB_Reverse_Spr)            # connection\n\n        self.DS_horizontalSlider = QtWidgets.QDoubleSpinBox()\n        self.DS_horizontalSlider.setDecimals(1)\n        self.DS_horizontalSlider.setMinimum(0)\n        self.DS_horizontalSlider.setMaximum(9999999999.0)\n        self.DS_horizontalSlider.setValue(0)\n        self.DS_horizontalSlider.setSingleStep(Direction_Distance)\n        self.DS_horizontalSlider.stepUp()\n        #self.DS_horizontalSlider.stepDown()\n        self.DS_horizontalSlider.valueChanged.connect(self.on_DS_horizontalSlider) #connection doubleSpinBox\n\n        self.PB_Reverse_Com = QtWidgets.QPushButton()\n        self.PB_Reverse_Com.clicked.connect(self.on_PB_Reverse_Com)\n\n        self.horizontalSlider = QtWidgets.QSlider()\n        self.horizontalSlider.setMaximum(100)\n        self.horizontalSlider.setMinimum(0)\n        self.horizontalSlider.setSliderPosition(0)\n        self.horizontalSlider.setSingleStep(Direction_Distance)\n        self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal)\n        self.horizontalSlider.valueChanged.connect(self.on_horizontal_slider)  # connection\n        ####\n\n        self.groupBox_05 = QtWidgets.QGroupBox()\n        self.groupBox_05.setCheckable(False)\n        self.groupBox_05.setChecked(False)\n\n        self.SP_Numbering_Spire = QtWidgets.QSpinBox()\n        self.SP_Numbering_Spire.setMinimum(1)\n        self.SP_Numbering_Spire.setMaximum(numberSpires)\n        self.SP_Numbering_Spire.setPrefix(\"Num: \")\n        self.SP_Numbering_Spire.valueChanged.connect(self.on_S_Numbering_Spire) #connection SpinBox\n\n        self.CH_Smooting = QtWidgets.QCheckBox()\n        self.CH_Smooting.setEnabled(True)\n\n        self.CH_Smooting.clicked.connect(self.on_CH_Smooting)                  # connection\n        \n        self.SP_Lissage = QtWidgets.QSpinBox()\n        self.SP_Lissage.setVisible(False)\n        self.SP_Lissage.setMinimum(0)\n        self.SP_Lissage.setMaximum(int(360/precision)-1)\n        self.SP_Lissage.valueChanged.connect(self.on_S_Lissage)                #connection SpinBox\n\n        self.DS_Pas_Spire = QtWidgets.QDoubleSpinBox()\n        self.DS_Pas_Spire.setValue(0) #pas\n        self.DS_Pas_Spire.setDecimals(3)\n        self.DS_Pas_Spire.setMaximum(9999999.99)\n        self.DS_Pas_Spire.valueChanged.connect(self.on_DS_Pas_Spire)           #connection doubleSpinBox\n\n        self.PU_To_Pas = QtWidgets.QPushButton()\n        self.PU_To_Pas.clicked.connect(self.on_PU_To_Pas)                      # connection\n\n        self.DS_Radius_Spire = QtWidgets.QDoubleSpinBox()\n        self.DS_Radius_Spire.setDecimals(3)\n        self.DS_Radius_Spire.setValue(0) #rayon\n#        self.DS_Radius_Spire.setMinimum(0.001)\n        self.DS_Radius_Spire.setMaximum(9999999.99)\n        self.DS_Radius_Spire.valueChanged.connect(self.on_DS_Radius_Spire)     # connection doubleSpinBox\n\n        self.PU_To_Radius = QtWidgets.QPushButton()\n        self.PU_To_Radius.clicked.connect(self.on_PU_To_Radius)                # connection\n\n#        section progressBar 1\n        self.PBA_progressBar = QtWidgets.QProgressBar()\n        self.PBA_progressBar.setCursor(QtCore.Qt.WaitCursor)\n        self.PBA_progressBar.setValue(0)\n        self.PBA_progressBar.setVisible(False)\n        self.PBA_progressBar.setOrientation(QtCore.Qt.Horizontal)\n        self.PBA_progressBar.setAlignment(QtCore.Qt.AlignCenter)\n\n        self.LAB_Numbering_Spire = QtWidgets.QLabel()\n        self.LAB_Pas_Spire = QtWidgets.QLabel()\n        self.LAB_Radius_Spire = QtWidgets.QLabel()\n\n        self.PU_Accept_Value = QtWidgets.QPushButton()\n        self.PU_Accept_Value.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton))) #\n        self.PU_Accept_Value.clicked.connect(self.on_PU_Accept_Value)          # connection\n\n        self.PB_Clear = QtWidgets.QPushButton()\n        self.PB_Clear.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogResetButton))) #\n        self.PB_Clear.clicked.connect(self.on_PB_Clear)                        # connection\n\n        self.PB_Zoom = QtWidgets.QPushButton()\n        self.PB_Zoom.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_FileDialogContentsView))) #\n        self.PB_Zoom.clicked.connect(self.on_PB_Zoom)                          # connection\n\n        self.textEdit = QtWidgets.QTextEdit()\n        self.textEdit.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)\n\n        ####\n        self.groupBox_06 = QtWidgets.QGroupBox()\n\n        #self.label_11_Name = QtWidgets.QLabel()\n\n        self.PU_Read = QtWidgets.QPushButton()\n        self.image_02 = path+\"FCSpring_Helix_Variable_Icon_02.png\"                          # image\n        icon02 = QtGui.QIcon()                                                              #\n        icon02.addPixmap(QtGui.QPixmap(self.image_02),QtGui.QIcon.Normal, QtGui.QIcon.Off)  #\n        self.PU_Read.setIcon(icon02)                                                        #\n        self.PU_Read.clicked.connect(self.on_PU_Read)                          # connection\n\n        self.PU_Save = QtWidgets.QPushButton()\n        self.image_03 = path+\"FCSpring_Helix_Variable_Icon_03.png\"                          # image\n        icon03 = QtGui.QIcon()                                                              #\n        icon03.addPixmap(QtGui.QPixmap(self.image_03),QtGui.QIcon.Normal, QtGui.QIcon.Off)  #\n        self.PU_Save.setIcon(icon03)                                                        #\n        self.PU_Save.clicked.connect(self.on_PU_Save)\n\n        self.PU_Read_Coord = QtWidgets.QPushButton()\n        self.PU_Read_Coord.setEnabled(True)\n        self.image_02b = path+\"FCSpring_Helix_Variable_Icon_02b.png\"                         # image\n        icon02b = QtGui.QIcon()                                                              #\n        icon02b.addPixmap(QtGui.QPixmap(self.image_02b),QtGui.QIcon.Normal, QtGui.QIcon.Off) #\n        self.PU_Read_Coord.setIcon(icon02b)                                                  #\n        self.PU_Read_Coord.clicked.connect(self.on_PU_Read_Coord)              # connection\n\n        self.PU_Save_Coord = QtWidgets.QPushButton()\n        self.image_03b = path+\"FCSpring_Helix_Variable_Icon_03b.png\"                         # image\n        icon03b = QtGui.QIcon()                                                              #\n        icon03b.addPixmap(QtGui.QPixmap(self.image_03b),QtGui.QIcon.Normal, QtGui.QIcon.Off) #\n        self.PU_Save_Coord.setIcon(icon03b)                                                  #\n        self.PU_Save_Coord.clicked.connect(self.on_PU_Save_Coord)              # connection\n        ####\n        self.CB_05_Position = QtWidgets.QCheckBox()\n        if seTPositionFlyRightLeft == 1:\n            self.CB_05_Position.setVisible(False)\n        self.CB_05_Position.setChecked(seTWidgetPosition)\n        self.CB_05_Position.clicked.connect(self.on_CB_05_Position)            #connection checkBox\n\n        self.PU_Quit = QtWidgets.QPushButton()\n        self.image_04 = path+\"FCSpring_Helix_Variable_Icon_04.png\"                          # image\n        icon04 = QtGui.QIcon()                                                              #\n        icon04.addPixmap(QtGui.QPixmap(self.image_04),QtGui.QIcon.Normal, QtGui.QIcon.Off)  #\n        self.PU_Quit.setIcon(icon04)                                                        #\n        self.PU_Quit.clicked.connect(self.on_PU_Quit)                          # connection\n\n        self.PU_Reset = QtWidgets.QPushButton()\n        self.image_05 = path+\"FCSpring_Helix_Variable_Icon_05.png\"                          # image\n        icon05 = QtGui.QIcon()                                                              #\n        icon05.addPixmap(QtGui.QPixmap(self.image_05),QtGui.QIcon.Normal, QtGui.QIcon.Off)  #\n        self.PU_Reset.setIcon(icon05)                                                       #\n        self.PU_Reset.clicked.connect(self.on_PU_Reset)                        # connection\n\n        self.PU_Launch = QtWidgets.QPushButton()\n        self.PU_Launch.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogOkButton))) #\n        self.PU_Launch.clicked.connect(self.on_PU_Launch)                      # connection\n\n        self.PU_Help = QtWidgets.QPushButton()\n        self.PU_Help.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_MessageBoxQuestion))) # image\n        self.PU_Help.clicked.connect(self.on_PU_Help)                          # connection\n        \n        #### Layout debut ########################\n        self.grid0 = QtWidgets.QGridLayout() #self.centralWidget\n        self.grid0.setContentsMargins(10, 10, 10, 10)\n        self.grid0.addWidget(self.groupBox0, 0, 0, 1, 1)\n        ####\n        self.grid_00 = QtWidgets.QGridLayout(self.groupBox0)\n        #self.grid_00.setContentsMargins(10, 10, 10, 10)\n        self.grid_00.addWidget(self.groupBox_01, 0, 0, 1, 1)\n        vbox.addWidget(self.groupBox0)      # englobe le cadre principal (titre + date)\n        ####\n        self.grid_01 = QtWidgets.QGridLayout(self.groupBox_01)\n        #self.grid_01.setContentsMargins(10, 10, 10, 10)\n        self.grid_01.addWidget(self.DS_Numb_Spires, 0, 0, 1, 1)\n        self.grid_01.addWidget(self.LAB_Numb_Spires, 0, 1, 1, 1)\n        self.grid_01.addWidget(self.DS_Pas_Spring, 0, 2, 1, 1)\n        self.grid_01.addWidget(self.LAB_Pas_Spring, 0, 3, 1, 1)\n        self.grid_01.addWidget(self.DS_Radius_Sping, 2, 0, 1, 1)\n        self.grid_01.addWidget(self.LAB_Radius_Spring, 2, 1, 1, 2)\n        self.grid_01.addWidget(self.DS_Precision_Turn, 2, 2, 1, 1)\n        self.grid_01.addWidget(self.LAB_Precision_Turn, 2, 3, 1, 1)\n        self.grid_01.addWidget(self.DS_Radius_2_Cone, 4, 0, 1, 1)\n        self.grid_01.addWidget(self.CH_Cone, 4, 1, 1, 1)\n        self.grid_01.addWidget(self.LAB_Radius_2_Cone, 4, 2, 1, 1)\n        self.grid_01.addWidget(self.SP_Begin_Angle, 5, 0, 1, 1)\n        self.grid_01.addWidget(self.LAB_Begin_Angle, 5, 1, 1, 1)\n        self.grid_01.addWidget(self.SP_End_Angle, 5, 2, 1, 1)\n        self.grid_01.addWidget(self.LAB_End_Angle, 5, 3, 1, 1)\n        self.grid_01.addWidget(self.CB_B_E_Angle, 4, 2, 1, 1)\n        ####\n        self.grid_00.addWidget(self.groupBox_02, 1, 0, 1, 1)\n        self.grid_02 = QtWidgets.QGridLayout(self.groupBox_02)\n        #self.grid_02.setContentsMargins(10, 10, 10, 10)\n        self.grid_02.addWidget(self.RA_BSpline, 0, 0, 1, 1)\n        self.grid_02.addWidget(self.RA_Wire, 0, 1, 1, 1)\n        self.grid_02.addWidget(self.CH_Points, 0, 2, 1, 1)\n        self.grid_02.addWidget(self.CH_Reverse, 0, 3, 1, 1)\n        ####\n        self.grid_00.addWidget(self.groupBox_03, 2, 0, 1, 1)\n        self.grid_03 = QtWidgets.QGridLayout(self.groupBox_03)\n        #self.grid_03.setContentsMargins(10, 10, 10, 10)\n        self.grid_03.addWidget(self.PB_Adapt_Radius, 0, 0, 1, 1)\n        self.grid_03.addWidget(self.PB_Center_Point, 0, 1, 1, 1)\n        self.grid_03.addWidget(self.CB_Position, 0, 2, 1, 1)\n        self.grid_03.addWidget(self.PB_CreaCircle, 0, 3, 1, 1)\n        ####\n        self.grid_00.addWidget(self.groupBox_04, 3, 0, 1, 1)\n        self.grid_04 = QtWidgets.QGridLayout(self.groupBox_04)\n        #self.grid_04.setContentsMargins(10, 10, 10, 10)\n        self.grid_04.addWidget(self.PB_Begin_End, 0, 0, 1, 1)\n        self.grid_04.addWidget(self.PB_Reverse_Spr, 0, 1, 1, 1)\n        self.grid_04.addWidget(self.DS_horizontalSlider, 0, 2, 1, 1)\n        self.grid_04.addWidget(self.PB_Reverse_Com, 0, 3, 1, 1)\n        self.grid_04.addWidget(self.horizontalSlider, 1, 0, 1, 4)\n        ####\n        self.grid_00.addWidget(self.groupBox_05, 4, 0, 1, 1)\n        self.grid_05 = QtWidgets.QGridLayout(self.groupBox_05)\n        #self.grid_05.setContentsMargins(10, 10, 10, 10)\n        self.grid_05.addWidget(self.SP_Numbering_Spire, 0, 0, 1, 1)\n        self.grid_05.addWidget(self.LAB_Numbering_Spire, 0, 1, 1, 1)\n        self.grid_05.addWidget(self.SP_Lissage, 0, 3, 1, 1)\n        self.grid_05.addWidget(self.CH_Smooting, 0, 3, 1, 1)\n        self.grid_05.addWidget(self.DS_Pas_Spire, 1, 0, 1, 1)\n        self.grid_05.addWidget(self.LAB_Pas_Spire, 1, 1, 1, 1)\n        self.grid_05.addWidget(self.PU_To_Pas, 1, 3, 1, 1)\n        self.grid_05.addWidget(self.DS_Radius_Spire, 2, 0, 1, 1)\n        self.grid_05.addWidget(self.LAB_Radius_Spire, 2, 1, 1, 1)\n        self.grid_05.addWidget(self.PU_To_Radius, 2, 3, 1, 1)\n        ####\n        self.grid_05.addWidget(self.PU_Accept_Value, 3, 0, 1, 4)\n        self.grid_05.addWidget(self.PBA_progressBar, 4, 0, 1, 4)\n        self.grid_05.addWidget(self.textEdit, 5, 0, 2, 3)\n        self.grid_05.addWidget(self.PB_Clear, 5, 3, 1, 1)\n        self.grid_05.addWidget(self.PB_Zoom,6 ,3, 1, 1)\n        ####\n        self.grid_00.addWidget(self.groupBox_06, 5, 0, 1, 1)\n        self.grid_06 = QtWidgets.QGridLayout(self.groupBox_06)\n        #self.grid_06.setContentsMargins(10, 10, 10, 10)\n        self.grid_06.addWidget(self.PU_Read, 0, 0, 1, 2)\n        self.grid_06.addWidget(self.PU_Save, 0, 2, 1, 2)\n        self.grid_06.addWidget(self.PU_Read_Coord, 1, 0, 1, 2)\n        self.grid_06.addWidget(self.PU_Save_Coord, 1, 2, 1, 2)\n        ##\n        self.grid_06.addWidget(self.CB_05_Position, 2, 0)\n        ##\n        self.grid_06.addWidget(self.PU_Quit, 3, 0, 1, 1)\n        self.grid_06.addWidget(self.PU_Reset, 3, 1, 1, 1)\n        self.grid_06.addWidget(self.PU_Launch,3, 2, 1, 1)\n        self.grid_06.addWidget(self.PU_Help, 3, 3, 1, 1)\n        #### GridLayout fin\n\n        ###########################################################scrollArea\n        self.scrollArea.setWidget(self.scrollAreaWidgetContents_2)\n        ###########################################################scrollArea\n\n        if seTPositionFlyRightLeft == 1:                                                 # 1=MainWindow separate\n            MainWindow.setWindowTitle(__Title__  + u\" rmu (\" + __Version__ + \") (\" + __Date__ + \")\")\n            MainWindow.setCentralWidget(self.centralWidget)\n            #MainWindow.move(1000, 120)                           # deplace la fenetre\n        else:\n            MainWindow.setWindowTitle(__Title__  + u\" rmu (\" + __Version__ + \") (\" + __Date__ + \")\")\n            MainWindow.setWidget(self.centralWidget)\n\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n        global sel\n        MainWindow.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)     # PySide cette fonction met la fenetre en avant\n\n        MainWindow.setWindowIcon(QtGui.QIcon(path+'FCSpring_Helix_Variable.png'))# change l'icone de la fenetre principale\n        MainWindow.setWindowTitle(\"FCSpring Helix Variable\")\n####\n        self.groupBox0.setTitle(\"ver : \" + __Version__ + \" : \" + __Date__ + \" (rmu)\" )\n        self.groupBox_01.setTitle(_fromUtf8(\"Configure\"))\n        self.DS_Numb_Spires.setToolTip(_fromUtf8(\"Number total of coil of the spring\"))\n        self.DS_Numb_Spires.setSuffix(\" coils\")\n        self.LAB_Numb_Spires.setText(_fromUtf8(\"Number of coil\"))\n        self.LAB_Numb_Spires.setToolTip(_fromUtf8(\"Number total of coil of the spring\"))\n        self.LAB_Pas_Spring.setText(_fromUtf8(\"Pitch of spring\"))\n        self.LAB_Pas_Spring.setToolTip(_fromUtf8(\"Pitch of spring (distance between two vertices)\"))\n        self.DS_Pas_Spring.setToolTip(_fromUtf8(\"Pitch of spring (distance between two vertices)\"))\n        self.DS_Pas_Spring.setSuffix(\" mm\")\n        self.DS_Radius_Sping.setToolTip(_fromUtf8(\"Radius of spring\"))\n        self.DS_Radius_Sping.setSuffix(\" mm\")\n        self.LAB_Radius_Spring.setText(_fromUtf8(\"Radius of spring\"))\n        self.LAB_Radius_Spring.setToolTip(_fromUtf8(\"Radius of spring\"))\n        self.DS_Precision_Turn.setSuffix(\"  ( \" + str(int(360/precision)) + \" points )\")\n        self.DS_Precision_Turn.setToolTip(_fromUtf8(\"Precision for the line (points = (360/precision))\"+\"\\n\"+\n                                                    \"Actual: \" + str(int(360/precision)) + \" points for 1 turn\"+\"\\n\"+\n                                                    \"Loading a file or angle checked the value displayd change color in blue just to inform\"))\n        self.LAB_Precision_Turn.setText(_fromUtf8(\"Precision\"))\n        self.LAB_Precision_Turn.setToolTip(_fromUtf8(\"The precision is the number point (360/precision) for create one turn of the spring\"+\"\\n\"+\n                                          \"Loading a file or angle checked the value displayed change color in blue just to inform\"))\n        self.DS_Radius_2_Cone.setToolTip(_fromUtf8(\"Radius for make a cone\"+\"\\n\"+\n                                                   \"This radius is always greater than the principal radius\"))\n        self.DS_Radius_2_Cone.setSuffix(\" mm\")\n        self.CH_Cone.setText(_fromUtf8(\"Spring conical\"))\n        self.CH_Cone.setToolTip(_fromUtf8(\"Check for create one conical helix\"))\n        self.LAB_Radius_2_Cone.setText(_fromUtf8(\"Radius 2 of the cone\"))\n        self.SP_Begin_Angle.setToolTip(_fromUtf8(\"Begin angle first coil\"))\n        self.SP_Begin_Angle.setSuffix(_fromUtf8(\" deg\"))\n        self.LAB_Begin_Angle.setText(_fromUtf8(\"Begin\"))\n        self.SP_End_Angle.setToolTip(_fromUtf8(\"End angle ultimate coil\"))\n        self.SP_End_Angle.setStatusTip(_fromUtf8(\"End angle to ultimate coil\"))\n        self.SP_End_Angle.setSuffix(_fromUtf8(\" deg\"))\n        self.LAB_End_Angle.setText(_fromUtf8(\"End\"))\n        self.CB_B_E_Angle.setText(_fromUtf8(\"Angles\")) #Beg/End\n        self.CB_B_E_Angle.setToolTip(_fromUtf8(\"Check the option modify to begin and ultimate angle of coils\"+\"\\n\"+\n                                               \"The final result depend on the level of precision given\"+\"\\n\"+\n                                               \"Optimal : 1 , Precision = 360 points (1 point by degree)\"))\n#####\n        self.groupBox_02.setTitle(_fromUtf8(\"Type line\"))\n        self.RA_BSpline.setToolTip(_fromUtf8(\"Type line BSpline\"))\n        self.RA_BSpline.setText(_fromUtf8(\"BSpline\"))\n        self.RA_Wire.setText(_fromUtf8(\"Wire\"))\n        self.RA_Wire.setToolTip(_fromUtf8(\"Type line Wire\"))\n        self.CH_Points.setToolTip(_fromUtf8(\"Check to create points to alls nodes of the precision of turn\"))\n        self.CH_Points.setText(_fromUtf8(\"Points\"))\n        self.CH_Reverse.setToolTip(_fromUtf8(\"Check to create spring clockwise direction\"))\n        self.CH_Reverse.setText(_fromUtf8(\"Reverse\"))\n#####\n        self.groupBox_03.setTitle(_fromUtf8(\"Options\"))\n        self.PB_Adapt_Radius.setText(_fromUtf8(\"Normal\")) #AdpRa\n        self.PB_Adapt_Radius.setToolTip(_fromUtf8(\"Mode normal\"+\"\\n\"+\n                                                  \"\"+\"\\n\"+\n                                                  \"For create the spring to the circle radius selected:\"+\"\\n\"+\n                                                  \"1: configure the complete spring\"+\"\\n\"+\n                                                  \"2: select the circle, arc ... to work\"+\"\\n\"+\n                                                  \"  (are detected : Circle, Arc, Ellipse, Sphere, Toroid, Cone, Ellipse (minor radius))\"+\"\\n\"+ \n                                                  \"3: push this mode Normal button (it change to Adapt Rad.)\"+\"\\n\"+\n                                                  \"4: push the Launch button\"))#adapt radius\n        self.PB_Center_Point.setText(_fromUtf8(\"Point Mouse\")) #CFace\n        self.PB_Center_Point.setToolTip(_fromUtf8(\"Create Spring to the point mouse (Default)\"+\"\\n\"+\n                                                  \"\"+\"\\n\"+\n                                                  \"For create the spring to center face:\"+\"\\n\"+\n                                                  \"1: configure the complete spring\"+\"\\n\"+\n                                                  \"2: select the face to work\"+\"\\n\"+\n                                                  \"3: push this Point Mouse button (it change to Center Face)\"+\"\\n\"+\n                                                  \"4: push the Launch button\"))#center face\n        self.CB_Position.setText(_fromUtf8(\"Position\"))\n        self.CB_Position.setToolTip(_fromUtf8(\"Move the position of the spring selected along the axis selected  \"+\"\\n\"+\n                                              \"\"+\"\\n\"+\n                                              \"For use this option:\"+\"\\n\"+\n                                              \"1: select the axis to work\"+\"\\n\"+\n                                              \"2: select the spring to move (or object)\"+\"\\n\"+\n                                              \"This command not verify the objects selected  \"\n                                              \"(Give always the number selection)\"+\"\\n\"))\n        self.CB_Position.setText(_fromUtf8(\"Position\"))\n        self.PB_CreaCircle.setText(_fromUtf8(\"Circle\"))\n        self.PB_CreaCircle.setToolTip(_fromUtf8(\"Create a circle on 3 points selected  \"+\"\\n\"+\n                                                \"First select tree points  \"+\"\\n\"))\n#####\n        self.groupBox_04.setTitle(_fromUtf8(\"Position ( \" + str(len(sel)) + \" )\"))\n        self.groupBox_04.setToolTip(_fromUtf8(\"Position (number selection) number of points\"))\n        self.PB_Begin_End.setToolTip(_fromUtf8(\"Align the spring to begin , end or center axis \"+\"\\n\"))\n        self.PB_Begin_End.setText(_fromUtf8(\"Begin / End\"))\n        self.PB_Reverse_Spr.setText(_fromUtf8(\"Reverse Spr.\"))\n        self.PB_Reverse_Spr.setToolTip(_fromUtf8(\"Reverse the spring on its axis \"+\"\\n\"))\n        self.DS_horizontalSlider.setToolTip(_fromUtf8(\"Placement spring along the axis\"+\"\\n\"))\n        self.DS_horizontalSlider.setSuffix(\" mm\")\n        self.PB_Reverse_Com.setText(_fromUtf8(\"Reverse Count.\"))\n        self.PB_Reverse_Com.setToolTip(_fromUtf8(\"Reverse the counter of the spring on its axis \"+\"\\n\"))\n#####\n        self.groupBox_05.setTitle(_fromUtf8(\"Coil special dimension\"))\n        self.groupBox_05.setToolTip(_fromUtf8(\"This section allows you to adjust the distance from the coil named. EX: 1 spire = 2 mm\"))\n        self.SP_Numbering_Spire.setToolTip(_fromUtf8(\"Numbering of coil for 1 to max = Number of coil (\"+str(numberSpires)+\")\"))\n        self.LAB_Numbering_Spire.setToolTip(_fromUtf8(\"Numbering of coil for 1 to max =  Number of coil\"))\n        self.LAB_Numbering_Spire.setText(_fromUtf8(\"Number of coil\"))\n        self.SP_Lissage.setToolTip(_fromUtf8(\"Smoothing the line if the difference between two coils\"+\"\\n\"+\n                                            \"The maximum value is egual of the precision number point given -1 (\" + str(int(360/precision)-1)+\")\"+\"\\n\"+\n                                            \"The finish and precision are influenced by this value\"+\"\\n\"+\n                                            \"PS: The result can be satisfying or completely wrong (prototype state)\"))\n        self.CH_Smooting.setText(_fromUtf8(\"Smooting\"))\n        self.CH_Smooting.setToolTip(_fromUtf8(\"Smoothing the line if the difference between two coils\"+\"\\n\"+\n                                              \"The maximum value is egual of the precision number point given -1 (\" + str(int(360/precision)-1)+\")\"+\"\\n\"+\n                                              \"The finish and precision are influenced by this value\"+\"\\n\"+\n                                              \"PS: The result can be satisfying or completely wrong (prototype state)\"))\n        self.DS_Pas_Spire.setToolTip(_fromUtf8(\"Pitch of the coil (The pitch is the distance betwen 2 vertices)\"))\n        self.DS_Pas_Spire.setSuffix(\" mm\")\n        self.LAB_Pas_Spire.setToolTip(_fromUtf8(\"Pitch of the coil (The pitch is the distance betwen 2 vertices)\"))\n        self.LAB_Pas_Spire.setText(_fromUtf8(\"Pitch of coil\"))\n        self.PU_To_Pas.setText(str(pas) + \" mm\")\n        self.PU_To_Pas.setToolTip(_fromUtf8(\"Align the value to pitch global configured\"))\n        self.DS_Radius_Spire.setToolTip(_fromUtf8(\"Radius of coil \"))\n        self.DS_Radius_Spire.setSuffix(\" mm\")\n        self.PU_To_Radius.setText(str(rayon) + \" mm\")\n        self.PU_To_Radius.setToolTip(_fromUtf8(\"Align the value to radius global configured\"))\n        self.LAB_Radius_Spire.setToolTip(_fromUtf8(\"Radius of coil \"))\n        self.LAB_Radius_Spire.setText(_fromUtf8(\"Radius of coil\"))\n        #self.PBA_progressBar.setToolTip(_fromUtf8(\" \"))\n        self.PU_Accept_Value.setText(_fromUtf8(\"Accept the value modified\"))\n        self.PU_Accept_Value.setToolTip(_fromUtf8(\"Accept the value for the coil \"))\n        self.PB_Clear.setText(_fromUtf8(\"Clear\"))\n        self.PB_Clear.setToolTip(_fromUtf8(\"Clear text edit\"))\n        self.PB_Zoom.setText(_fromUtf8(\"Zoom\"))\n        self.PB_Zoom.setToolTip(_fromUtf8(\"Zoom the text edit window\"))\n        self.textEdit.setText(_fromUtf8(\"\"))\n        self.textEdit.setToolTip(_fromUtf8(\"List alls modification of coil \"))\n####\n        self.groupBox_06.setTitle(_fromUtf8(\"Command\"))\n        self.groupBox_06.setToolTip(_fromUtf8(\"Menu command\"))\n        self.PU_Read.setText(_fromUtf8(\"Load\"))\n        self.PU_Read.setToolTip(_fromUtf8(\"Read the file \"))\n        self.PU_Save.setText(_fromUtf8(\"Save\"))\n        self.PU_Save.setToolTip(_fromUtf8(\"Save the file\"))\n        self.PU_Read_Coord.setText(_fromUtf8(\"Load coordinates\"))\n        self.PU_Read_Coord.setToolTip(_fromUtf8(\"Load the coordinates file \"))\n        self.PU_Save_Coord.setText(_fromUtf8(\"Save coordinates\"))\n        self.PU_Save_Coord.setToolTip(_fromUtf8(\"Save the coordinates file \"))\n        ##\n        self.CB_05_Position.setText(u\"Left/Right\")\n        self.CB_05_Position.setToolTip(u\"Change the window macro position Right of Left\")\n        ##\n        self.PU_Quit.setText(_fromUtf8(\"Quit\"))\n        self.PU_Quit.setToolTip(_fromUtf8(\"Quit the macro\"))\n        self.PU_Reset.setText(_fromUtf8(\"Reset\"))\n        self.PU_Reset.setToolTip(_fromUtf8(\"Reset complete the data \"))\n        self.PU_Launch.setText(_fromUtf8(\"Launch \"))\n        self.PU_Launch.setToolTip(_fromUtf8(\"Launch the macro and create the spring\"))\n        self.PU_Help.setText(_fromUtf8(\"Help \"))\n        self.PU_Help.setToolTip(_fromUtf8(\"Dislay the wiki page in the FreeCAD browser\"))\n####\n    def on_PU_Reset(self, zero = 0):                                           # Reset 0=Reset total 1=Reset mise a jour\n        global numberSpires\n        global rayon\n        global pas\n        global precision\n        global typeLine\n        global affPoint\n        global helixS\n        global numberSpiresModified\n        global pasSpire\n        global radiusS\n        global rayonSpire\n        global affPoint\n        global debutAngle\n        global finAngle\n        global modifyAngle\n        global radius_2_Cone\n        global spireConeUne\n        global spireConeComp\n        global spireReverse\n        global lissageSpire\n        global lissageS\n        global fichierOpen\n        global nomF\n        global zoom\n        global pointsDirection\n        global Direction_Begin\n        global plr\n        global sel\n        global switchAdaptRadius\n        global centerFaceOrPoint\n        global selectedCircle\n\n        if zero == 0:                                                          # 0 = Reset total\n            numberSpires         = 10\n            rayon                = 20.0\n            pas                  = 15.0\n            precision            = 5.0\n            typeLine             = 0\n            affPoint             = 0\n            helixS               = 0.0\n            radiusS              = 0.0\n            numberSpiresModified = 1\n            pasSpire             = 0 #pas\n            rayonSpire           = 0 #rayon\n            modifyAngle          = 0\n            radius_2_Cone        = rayon\n            fichierOpen          = 0\n            nomF                 = \"Name File\"\n\n        self.DS_Numb_Spires.setValue(numberSpires)\n        self.DS_Radius_Sping.setValue(rayon)\n        self.DS_Pas_Spring.setValue(pas)\n        self.DS_Precision_Turn.setValue(precision)\n        self.DS_Precision_Turn.setEnabled(True)\n        self.DS_Precision_Turn.setToolTip(_fromUtf8(\"Precision for the line (points = (360/precision))\"+\"\\n\"+\n                                                    \"Actual: \" + str(int(360/precision)) + \" points for 1 turn\"+\"\\n\"+\n                                                    \"Loading a file or angle checked the value displayd change color in blue just to inform\"))\n        self.LAB_Numb_Spires.setText(\"Number of coil\")\n\n        ############### font and color Label\n        font = QtGui.QFont()\n        self.LAB_Precision_Turn.setFont(font)\n        self.LAB_Precision_Turn.setStyleSheet(\"QLabel {Base}\")\n        ############### font and color\n\n        ############### font and color\n        palette = QtGui.QPalette()\n        brush = QtGui.QBrush(QtGui.QColor(\"Base\"))\n        brush.setStyle(QtCore.Qt.SolidPattern)\n        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)\n        self.DS_Precision_Turn.setPalette(palette)\n        font = QtGui.QFont()\n        font.setBold(False)\n        self.DS_Precision_Turn.setFont(font)\n        ###############\n\n        self.CB_B_E_Angle.setChecked(False)\n        self.SP_Begin_Angle.setEnabled(False)\n        debutAngle = 0\n        self.SP_Begin_Angle.setValue(debutAngle)\n        self.SP_End_Angle.setEnabled(False)\n        finAngle   = 360\n        self.SP_End_Angle.setValue(finAngle)\n        modifyAngle = 0\n\n        self.CH_Points.setChecked(False)\n        affPoint = 0\n        self.CH_Reverse.setChecked(False)\n        spireReverse = 0\n        ###############\n        sel = \"\"\n        del pointsDirection[:]\n        plr = \"\"\n        Direction_Begin = 0\n\n        switchAdaptRadius  = 0\n        self.PB_Adapt_Radius.setEnabled(False)\n        self.PB_Adapt_Radius.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")  # origin system\n        self.PB_Adapt_Radius.setText(\"Normal\")\n\n        self.PB_Center_Point.setEnabled(False)\n        self.PB_Center_Point.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")  # origin system\n        centerFaceOrPoint = 0\n        self.PB_Center_Point.setText(_fromUtf8(\"Point Mouse\"))\n\n        self.CB_Position.setEnabled(False)\n        self.CB_Position.setStyleSheet(\"QCheckBox {background-color: QPalette.Base}\")      # origin system\n\n        self.PB_CreaCircle.setEnabled(False)\n        self.PB_CreaCircle.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")    # origin system\n        del selectedCircle[:]\n\n        self.DS_horizontalSlider.setValue(0)\n        self.horizontalSlider.setValue(0)\n        self.groupBox_04.setEnabled(False)\n        self.groupBox_04.setStyleSheet(\"QGroupBox {background-color: QPalette.Base}\")      # origin system\n        self.groupBox_04.setTitle(\"Position (\" + str(len(sel)) + \")\")\n\n        ###############\n        self.SP_Numbering_Spire.setValue(numberSpiresModified)\n        self.SP_Numbering_Spire.setMaximum(numberSpires)\n        self.DS_Pas_Spire.setValue(0)    #pas\n        self.DS_Radius_Spire.setValue(0) #rayon\n        self.textEdit.setText(\"\")\n        self.textEdit.clear()\n\n        lissageSpire = 0\n        self.SP_Lissage.setValue(0)\n        self.SP_Lissage.setVisible(False)\n        self.SP_Lissage.setMaximum(int(360/precision)-1)\n        self.SP_Lissage.setToolTip(_fromUtf8(\"Smoothing the line if the difference between two coils\"+\"\\n\"+\n                                            \"The maximum value is egual of the precision number point given -1 (\" + str(int(360/precision)-1)+\")\"+\"\\n\"+\n                                            \"The finish and precision are influenced by this value\"+\"\\n\"+\n                                            \"PS: The result can be satisfying or completely wrong (prototype state)\"))\n        self.CH_Smooting.setChecked(False)\n        self.CH_Smooting.setVisible(True)\n        self.CH_Smooting.setToolTip(_fromUtf8(\"Smoothing the line if the difference between two coils\"+\"\\n\"+\n                                              \"The maximum value is egual of the precision number point given -1 (\" + str(int(360/precision)-1)+\")\"+\"\\n\"+\n                                              \"The finish and precision are influenced by this value\"+\"\\n\"+\n                                              \"PS: The result can be satisfying or completely wrong (prototype state)\"))\n        lissageS = []\n        del lissageS[:]\n        lissageS = numberSpires*[0]\n        self.SP_Lissage.setValue(0)\n\n        self.PBA_progressBar.setVisible(False)\n        self.PU_Accept_Value.setVisible(True)\n\n        zoom = 140\n        self.textEdit.setGeometry(QtCore.QRect(20, zoom, 211, 51))\n\n        helixS = []\n        del helixS[:]\n        helixS = numberSpires*[pas]\n\n        radiusS = []\n        del radiusS[:]\n        radiusS = numberSpires*[rayon]\n\n        self.CH_Cone.setChecked(False)\n        self.DS_Radius_2_Cone.setValue(rayon)\n        self.DS_Radius_2_Cone.setEnabled(False)\n        spireConeUne  = 0\n        spireConeComp = 0\n#        App.Console.PrintMessage(\"on_PU_Reset \"+\"\\n\")\n\n    def on_DS_Numb_Spires(self,value):                                         # nombre de spire total\n        global pas\n        global numberSpires\n        numberSpires = value\n        a = ui\n        a.on_PU_Reset(1)\n        self.SP_Numbering_Spire.setToolTip(_fromUtf8(\"Numbering of coil for 1 to max = Number of spires (\"+str(numberSpires)+\")\"))\n#        App.Console.PrintMessage(\"on_DS_Numb_Spires \"+str(numberSpires)+\"\\n\")\n\n    def on_DS_Radius_Sping(self,value):                                        # rayon axial du ressort\n        global rayon\n        rayon = value\n        self.PU_To_Radius.setText(str(rayon) + \" mm\")\n        a = ui\n        a.on_PU_Reset(1)\n#        App.Console.PrintMessage(\"on_DS_Radius_Sping \"+str(rayon)+\"\\n\")\n\n    def on_DS_Pas_Spring(self,value):                                          # pas (pitch) du ressort\n        global pas\n        global numberSpires\n        global numberSpiresModified\n        global pasSpire\n        pas = value\n        self.PU_To_Pas.setText(str(pas) + \" mm\")\n        a = ui\n        a.on_PU_Reset(1)\n#        App.Console.PrintMessage(\"on_DS_Pas_Spring \"+str(pas)+\"\\n\")\n\n    def on_DS_Precision_Turn(self,value):                                      # \" ! float \" 360/precision number points for 1 turn\n        global precision\n        precision = value\n        ############### font and color Label\n        font = QtGui.QFont()\n        self.LAB_Precision_Turn.setFont(font)\n        self.LAB_Precision_Turn.setStyleSheet(\"QLabel {Base}\")\n        ############### font and color\n        ############### font and color\n        palette = QtGui.QPalette()\n        brush = QtGui.QBrush(QtGui.QColor(\"QBrush {Base}\"))\n        brush.setStyle(QtCore.Qt.SolidPattern)\n#        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)\n        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)\n        self.DS_Precision_Turn.setPalette(palette)\n        font = QtGui.QFont()\n        font.setBold(False)\n#        font.setWeight(75)\n        self.DS_Precision_Turn.setFont(font)\n        ###############\n        self.DS_Precision_Turn.setSuffix(\"  ( \" + str(int(360/precision)) + \" points )\")\n        self.DS_Precision_Turn.setToolTip(_fromUtf8(\"Precision for the line (points = (360/precision))\"+\"\\n\"+\n                                                    \"Actual: \" + str(int(360/precision)) + \" points for 1 turn\"+\"\\n\"+\n                                                    \"Loading a file or angle checked the value displayd change color in blue just to inform\"))\n        self.SP_Lissage.setMaximum(int(360/precision)-1)\n        self.CH_Smooting.setToolTip(_fromUtf8(\"Smoothing the line if the difference between two coils\"+\"\\n\"+\n                                              \"The maximum value is egual of the precision number point given -1 (\" + str(int(360/precision)-1)+\")\"+\"\\n\"+\n                                              \"The finish and precision are influenced by this value\"+\"\\n\"+\n                                              \"PS: The result can be satisfying or completely wrong (prototype state)\"))\n#        App.Console.PrintMessage(\"on_DS_Precision_Turn \"+str(precision)+\"\\n\")\n\n    def on_CH_Cone(self):                                                      # Cone\n        global radius_2_Cone\n        global rayon\n        if self.CH_Cone.isChecked():\n            self.DS_Radius_2_Cone.setEnabled(True)\n#            self.LAB_Radius_2_Cone.setVisible(True)\n        else:\n            self.DS_Radius_2_Cone.setEnabled(False)\n#            self.LAB_Radius_2_Cone.setVisible(False)\n        radius_2_Cone = rayon\n        self.DS_Radius_2_Cone.setValue(radius_2_Cone)\n#        App.Console.PrintMessage(\"on_CH_Cone\"+\"\\n\")\n\n    def on_SP_Begin_Angle(self,value):                                          # \n        global debutAngle\n        debutAngle = value\n#        App.Console.PrintMessage(\"on_SP_Begin_Angle \"+str(debutAngle)+\"\\n\")\n\n    def on_SP_End_Angle(self,value):                                            # \n        global finAngle\n        finAngle = value\n#        App.Console.PrintMessage(\"on_SP_End_Angle \"+str(finAngle)+\"\\n\")\n\n    def on_CB_B_E_Angle(self):                                                 # \n        global debutAngle\n        global finAngle\n        global modifyAngle\n        global precision\n        global fichierOpen\n        if self.CB_B_E_Angle.isChecked(): \n            modifyAngle = 1\n            self.SP_Begin_Angle.setEnabled(True)\n            self.SP_End_Angle.setEnabled(True)\n            if fichierOpen == 0:\n                precision = 1\n            fichierOpen = 0\n            self.DS_Precision_Turn.setValue(precision)\n\n            ############### font and color Label\n            font = QtGui.QFont()\n            self.LAB_Precision_Turn.setFont(font)\n            self.LAB_Precision_Turn.setStyleSheet(\"QLabel {color : #0000ff}\")\n            ############### font and color\n            ############### font and color DoubleSpinBox\n            palette = QtGui.QPalette()\n            brush = QtGui.QBrush(QtGui.QColor( 0, 0, 255))\n            brush.setStyle(QtCore.Qt.SolidPattern)\n#            palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)\n            palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)\n            self.DS_Precision_Turn.setPalette(palette)\n            font = QtGui.QFont()\n            font.setBold(True)\n            font.setWeight(75)\n            self.DS_Precision_Turn.setFont(font)\n            ###############\n\n        else:\n            modifyAngle = 0\n#            self.DS_Precision_Turn.setEnabled(True)\n            self.SP_Begin_Angle.setEnabled(False)\n            self.SP_End_Angle.setEnabled(False)\n            self.CB_B_E_Angle.setChecked(False)\n            self.SP_Begin_Angle.setEnabled(False)\n            debutAngle = 0\n            self.SP_Begin_Angle.setValue(debutAngle)\n            self.SP_End_Angle.setEnabled(False)\n            finAngle   = 360\n            self.SP_End_Angle.setValue(finAngle)\n#        App.Console.PrintMessage(\"CB_B_E_Angle \"+\"\\n\")\n\n    def on_RA_Wire(self):                                                      # \n        global typeLine\n        typeLine = 1\n#        App.Console.PrintMessage(\"on_RA_Wire \"+str(typeLine)+\"\\n\")\n\n    def on_RA_BSpline(self):                                                   # \n        global typeLine\n        typeLine = 0\n#        App.Console.PrintMessage(\"on_RA_BSpline \"+str(typeLine)+\"\\n\")\n\n    def on_CH_Points(self):                                                    # \n        global affPoint\n        if self.CH_Points.isChecked(): \n            affPoint = 1\n        else:\n            affPoint = 0\n#        App.Console.PrintMessage(\"on_CH_Points \"+\"\\n\")\n\n    def on_CH_Reverse(self):                                                   # reverse the rotation Rigth/Left\n        global spireReverse\n        if self.CH_Reverse.isChecked(): \n            spireReverse = 1\n        else:\n            spireReverse = 0\n#        App.Console.PrintMessage(\"on_CH_Reverse \" + str(spireReverse)+\"\\n\")\n\n    def on_DS_Radius_2_Cone(self,value):                                       # Diametre num 2 , Helix Conique\n        global rayon\n        global numberSpires\n        global helixS\n        global radiusS\n        global radius_2_Cone\n        global spireConeUne\n        global spireConeComp\n        global lissageS\n\n        if self.CH_Cone.isChecked():\n            numberSpires = self.DS_Numb_Spires.value()\n\n            numberSpires += 1\n            self.SP_Numbering_Spire.setMaximum(numberSpires)\n            helixS = []\n            del helixS[:]\n            helixS = (numberSpires)*[pas]\n            radiusS = []\n            del radiusS[:]\n            radiusS = (numberSpires)*[rayon]\n            lissageS = []\n            del lissageS[:]\n            lissageS = numberSpires*[0]\n\n            if value < rayon:\n                radius_2_Cone = value = rayon\n            radius_2_Cone = value\n            self.DS_Radius_2_Cone.setValue(radius_2_Cone)\n            if numberSpires != 1:\n                spireConeUne = 0\n                cone = (radius_2_Cone - rayon) / (numberSpires -1)# +1 \n                for i in range(numberSpires):\n                    radiusS[i] = rayon + (cone * (i)) #  \n            else:\n                spireConeUne = 1\n            spireConeComp = 1\n#        App.Console.PrintMessage(\"on_DS_Radius_2_Cone \"+str(radius_2_Cone)+\" \"+str(spireConeUne)+\"\\n\")\n\n    ####\n    def on_PB_Adapt_Radius(self):                                              # Adapt circle\n        global switchAdaptRadius\n        if switchAdaptRadius == 0:\n            switchAdaptRadius = 1\n            self.PB_Adapt_Radius.setText(\"Adapt Rad.\")\n        else:\n            switchAdaptRadius = 0\n            self.PB_Adapt_Radius.setText(\"Normal\")\n#        App.Console.PrintMessage(\"on_CB_Adapt_Radius \"+str(switchAdaptRadius)+\"\\n\")\n\n    def on_PB_Center_Point(self):                                              # Center Face or Point\n        global centerFaceOrPoint\n        if centerFaceOrPoint == 0:\n            centerFaceOrPoint = 1\n            self.PB_Center_Point.setText(_fromUtf8(\"Center Face\"))\n        else:\n            centerFaceOrPoint = 0\n            self.PB_Center_Point.setText(_fromUtf8(\"Point Mouse\"))\n#        App.Console.PrintMessage(\"on_CB_Center_Point \"+str(centerFaceOrPoint)+\"\\n\")\n\n    def on_PB_Begin_End(self):                                                 # place the spring to left center rigth\n        global Direction_Begin\n        global pointsDirection\n        global ressort\n        global coor_Z\n        self.horizontalSlider.setMaximum(len(pointsDirection))\n        ressort.Placement.Base = pointsDirection[0]\n        if (Direction_Begin == 0):\n            Direction_Begin = 1\n            ressort.Placement.Base = pointsDirection[0]\n            self.horizontalSlider.setValue(0)\n        elif (Direction_Begin == 1):\n            ressort.Placement.Base = pointsDirection[int((len(pointsDirection) / 2))]\n            self.horizontalSlider.setValue(int((len(pointsDirection) / 2)))\n            Direction_Begin = 2\n        elif (Direction_Begin == 2):\n            Direction_Begin = 0\n            ressort.Placement.Base = pointsDirection[-1]\n            self.horizontalSlider.setValue(len(pointsDirection))\n    \n        FreeCAD.ActiveDocument.recompute()\n#        App.Console.PrintMessage(\"on_CB_01_Begin_End\"+\"\\n\") FreeCAD.Vector(\n\n    def on_PB_Reverse_Spr(self):                                               # reverse the spring\n        global ressort\n        a = FreeCAD.ActiveDocument.getObject(ressort.Name).Placement\n        b = App.Placement(App.Vector(0.0,0.0,0.0), App.Rotation(App.Vector(0.0,1.0,0.0),180.0), App.Vector(0,0,0))\n        c = a.multiply(b)\n        FreeCAD.ActiveDocument.getObject(ressort.Name).Placement = c\n#        App.Console.PrintMessage(\"on_PB_Reverse_Spr\"+\"\\n\")\n\n    def on_DS_horizontalSlider(self,val):                                      # \n        global pointsDirection\n        global ressort\n        global Direction_Distance\n        if len(pointsDirection) != 0:\n            self.DS_horizontalSlider.setSingleStep(Direction_Distance)\n            self.horizontalSlider.setValue(val*10)\n            try:\n                ressort.Placement.Base = FreeCAD.Vector(pointsDirection[int(val*10)])\n            except Exception:\n                None\n            FreeCAD.ActiveDocument.recompute()\n#        App.Console.PrintMessage(\"on_DS_horizontalSlider\"+\"\\n\")\n\n    def on_PB_Reverse_Com(self):                                               # reverse the compteur\n        global pointsDirection\n        global ressort\n        pointsDirection.reverse()\n        self.DS_horizontalSlider.setValue(0)\n        self.horizontalSlider.setValue(0)\n        ressort.Placement.Base = pointsDirection[0]\n#        App.Console.PrintMessage(\"on_PB_Reverse_Com\"+\"\\n\")\n\n    def on_horizontal_slider(self, val):                                       # connection on_horizontal_slider\n        global pointsDirection\n        if len(pointsDirection) != 0:\n            self.DS_horizontalSlider.setValue(val/10)\n#        App.Console.PrintMessage(\"on_horizontal_slider \" + str(val/10)+\"\\n\")\n\n    def on_CB_Position(self):                                                  # Position\n        global switchAdaptRadius\n        global centerFaceOrPoint\n        global Direction_Distance\n        global Direction_Begin\n        global pointsDirection\n        global ressort\n        global sel\n\n        if self.CB_Position.isChecked():\n            self.PB_Adapt_Radius.setEnabled(False)\n            self.PB_Adapt_Radius.setChecked(False)\n            self.PB_Adapt_Radius.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")   # origin system\n            switchAdaptRadius = 0\n            self.PB_Center_Point.setEnabled(False)\n            self.PB_Center_Point.setChecked(False)\n            self.PB_Center_Point.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")   # origin system\n            centerFaceOrPoint = 0\n            self.groupBox_04.setEnabled(True)\n            self.groupBox_04.setStyleSheet(\"QGroupBox {background-color: white;\\n\"\n                                           \"border:2px solid rgb(0, 187, 0);}\")      # bord white and green\n\n            selobject = FreeCADGui.Selection.getSelection()                         # Select an object\n            del pointsDirection[:]\n            sel = FreeCADGui.Selection.getSelectionEx()\n            self.groupBox_04.setTitle(\"Position (\" + str(len(sel)) + \")\")\n            try:\n                Direction_Begin = 0\n                pointsDirection = sel[0].Object.Shape.discretize(Distance = Direction_Distance) #\n    \n                ressort = selobject[1]\n                self.horizontalSlider.setValue(0)\n    \n                self.groupBox_04.setTitle(\"Position (\" + str(len(sel)) + \")(Points: \" + str(len(pointsDirection)) + \")\")\n                self.horizontalSlider.setMaximum(len(pointsDirection))\n                self.DS_horizontalSlider.setMaximum(int(len(pointsDirection)/10))\n                self.DS_horizontalSlider.setValue(len(pointsDirection)/10)\n            except Exception:\n                del pointsDirection[:]\n                self.groupBox_04.setTitle(\"Position (\" + str(0) + \")\")\n                App.Console.PrintError(\"Wrong selection\"+\"\\n\")\n        else:\n#            centerFaceOrPoint = 0\n            self.groupBox_04.setEnabled(False)\n            self.groupBox_04.setStyleSheet(\"QGroupBox {background-color: QPalette.Base}\")       # origin system\n\n            FreeCADGui.Selection.clearSelection() \n            sel = selobject = \"\"\n            del pointsDirection[:]\n            self.groupBox_04.setTitle(\"Position (\" + str(len(sel)) + \")\")\n            None\n#        App.Console.PrintMessage(\"on_CB_Position \"+\"\\n\")\n\n    def on_PB_CreaCircle(self):                                                # create circle on 3 points\n        global selectedCircle\n\n        if len(selectedCircle) == 3:\n            if (selectedCircle[0]==selectedCircle[1]) or (selectedCircle[0]==selectedCircle[2]) or selectedCircle[1]==selectedCircle[2] :\n                App.Console.PrintError(\"Bad selection the points are egual\"+\"\\n\")\n            else:\n                try:\n                    C1 = Part.Arc(FreeCAD.Vector(selectedCircle[0]),FreeCAD.Vector(selectedCircle[1]),FreeCAD.Vector(selectedCircle[2]))\n                    S1 = Part.Shape([C1])                                      # create arc base\n                    Part.show(S1)\n \n                    obj = App.ActiveDocument.ActiveObject                      # select the object created\n                    Gui.Selection.addSelection(obj)\n                    sel = obj.Shape\n        \n                    CircleDirection = sel.Curve.Axis                           # decode the datas\n                    CircleRayon     = sel.Curve.Radius\n                    CircleAxis      = sel.Curve.Center\n        \n                    App.ActiveDocument.removeObject(obj.Label)                 # remove arc master\n        \n                    v = CircleDirection                                        # give direction to circle\n                    r = App.Rotation(App.Vector(0,0,1),v)\n                    pl=FreeCAD.Placement()\n                    pl.Base=FreeCAD.Vector(CircleAxis)\n                    pl.Rotation.Q = r.Q\n                    circle3Points = Draft.makeCircle(radius=CircleRayon, placement=pl, face=False, support=None)\n                    circle3Points.ViewObject.LineColor = (1.0,0.0,0.0)         # give color\n                    circle3Points.Label = \"SpringCircle (\" + str(round(CircleRayon,3)) + \" r)\" # give label\n                except Exception:\n                    App.Console.PrintError(\"Three points are collinear or bad selection\"+\"\\n\")\n            del selectedCircle[:]\n            FreeCAD.ActiveDocument.recompute()\n        #self.PB_CreaCircle.setEnabled(False)\n#        App.Console.PrintMessage(\"on_PB_CreaCircle \"+\"\\n\")\n        ####\n\n    def on_S_Numbering_Spire(self,value):                                      # numero de la spire a modifier\n        global numberSpires\n        global numberSpiresModified\n        global lissageSpire\n\n        self.SP_Numbering_Spire.setMaximum(numberSpires)\n        numberSpiresModified = value\n        lissageSpire = 0\n        self.SP_Lissage.setValue(lissageSpire)\n        self.SP_Lissage.setVisible(False)\n        self.CH_Smooting.setVisible(True)\n        self.CH_Smooting.setChecked(False)\n#        App.Console.PrintMessage(\"on_S_Nubering_Spire \"+str(numberSpiresModified)+\"\\n\")\n\n    def on_CH_Smooting(self):                                                  # lissage precision\n        global lissageSpire\n        global precision\n\n        self.SP_Lissage.setVisible(True)\n        self.CH_Smooting.setVisible(False)\n        self.CH_Smooting.setToolTip(_fromUtf8(\"Smoothing the line if the difference between two coils\"+\"\\n\"+\n                                              \"The maximum value is egual of the precision number point given -1 (\" + str(int(360/precision)-1)+\")\"+\"\\n\"+\n                                              \"The finish and precision are influenced by this value\"+\"\\n\"+\n                                              \"PS: The result can be satisfying or completely wrong (prototype state)\"))\n        lissageSpire = 0\n#        App.Console.PrintMessage(\"on_CH_Smooting \"+str(lissageSpire)+\"\\n\")\n\n    def on_S_Lissage(self,value):                                              # option lissageS des raccords\n        global lissageSpire\n        global precision\n\n        lissageSpire = value\n        self.SP_Lissage.setMaximum(int(360/precision)-1)\n        self.SP_Lissage.setToolTip(_fromUtf8(\"Smoothing the line if the difference between two coils\"+\"\\n\"+\n                                            \"The maximum value is egual of the precision number point given -1 (\" + str(int(360/precision)-1)+\")\"+\"\\n\"+\n                                            \"The finish and precision are influenced by this value\"+\"\\n\"+\n                                            \"PS: The result can be satisfying or completely wrong (prototype state)\"))\n#        App.Console.PrintMessage(\"on_S_Lissage \"+str(lissageSpire)+\"\\n\")\n\n    def on_DS_Pas_Spire(self,value):                                           # pas (pitch) de la spire a modifier\n        global pasSpire\n\n        pasSpire = value\n#        App.Console.PrintMessage(\"on_DS_Pas_Spire \"+str(pasSpire)+\"\\n\")\n\n    def on_PU_To_Pas(self):                                                    # aligne le pas (pitch) de la spire\n        global pasSpire\n        global pas\n\n        pasSpire = pas\n        self.DS_Pas_Spire.setValue(pasSpire)\n#        App.Console.PrintMessage(\"on_PU_To_Pas \"+str(pasSpire)+\"\\n\")\n\n    def on_DS_Radius_Spire(self,value):                                        # pas (pitch) du rayon a modifier\n        global rayonSpire\n        rayonSpire = value\n#        App.Console.PrintMessage(\"on_DS_Radius_Spire \"+str(rayonSpire)+\"\\n\")\n\n    def on_PU_To_Radius(self):                                                 # aligne le rayon\n        global rayonSpire\n        global rayon\n\n        rayonSpire = rayon\n        self.DS_Radius_Spire.setValue(rayonSpire)\n#        App.Console.PrintMessage(\"on_PU_To_Radius_Value \"+str(rayonSpire)+\"\\n\")\n\n    def on_PU_Accept_Value(self):                                              # accepter la modification de la spire\n        global numberSpiresModified\n        global numberSpires\n        global pasSpire\n        global rayonSpire\n        global helixS\n        global radiusS\n        global lissageSpire\n        global lissageS\n\n        if rayonSpire != 0:\n            if numberSpiresModified == 1:\n                helixS[0] = pasSpire\n                radiusS[0]= rayonSpire\n                lissageS[0] = lissageSpire\n                self.textEdit.append(\"Coil number \" + str(numberSpiresModified) + \" = \" + str(helixS[0]) + \" \" + str(radiusS[0]) + \" \" + str(lissageS[0]))\n                App.Console.PrintMessage(\"Coil number \" + str(numberSpiresModified) + \" = \" + str(helixS[0]) + \" \" + str(radiusS[0]) + \" \" + str(lissageS[0])+\"\\n\")\n            else:\n                helixS[numberSpiresModified-1] = pasSpire\n                radiusS[numberSpiresModified-1]= rayonSpire\n                lissageS[numberSpiresModified-1] = lissageSpire\n                self.textEdit.append(\"Coil number \" + str(numberSpiresModified) + \" = \" + str(helixS[numberSpiresModified-1]) + \" \" + str(radiusS[numberSpiresModified-1]) + \" \" + str(lissageS[numberSpiresModified-1]))\n                App.Console.PrintMessage(\"Coil number \" + str(numberSpiresModified) + \" = \" + str(helixS[numberSpiresModified-1]) + \" \" + str(radiusS[numberSpiresModified-1]) + \" \" + str(lissageS[numberSpiresModified-1])+\"\\n\")\n    \n            self.SP_Lissage.setValue(0)\n            self.SP_Lissage.setVisible(False)\n            self.CH_Smooting.setVisible(True)\n            self.CH_Smooting.setChecked(False)\n            lissageSpire = 0\n        else:\n            self.textEdit.setTextColor(QColor(\"red\"))\n            self.textEdit.append(\"Coil number \" + str(numberSpiresModified) + \" Radius zero not allowed do \" )\n            self.textEdit.setTextColor(QColor(\"Base\"))\n            App.Console.PrintError(\"Coil number \" + str(numberSpiresModified) + \" Radius zero not allowed do \"+\"\\n\")\n#        App.Console.PrintMessage(\"on_PU_Accept_Value \"+\"\\n\")\n\n    def on_PB_Clear(self):                                                     # \n        self.textEdit.setText(\"\")\n        self.textEdit.clear()\n#        App.Console.PrintMessage(\"on_PB_Clear \"+\"\\n\")\n\n    def on_PB_Zoom(self):                                                     # \n        global zoom\n\n        if zoom == 0:\n            zoom = 1\n            self.PU_Accept_Value.setText(_fromUtf8(\"Accept\"))\n            self.grid_05.addWidget(self.PU_Accept_Value, 3, 3, 1, 1)\n            self.grid_05.addWidget(self.textEdit, 0, 0, 7, 3)\n        else:\n            zoom = 0\n            self.grid_05.addWidget(self.PU_Accept_Value, 3, 0, 1, 4)\n            self.PU_Accept_Value.setText(_fromUtf8(\"Accept the value modified\"))\n            self.grid_05.addWidget(self.textEdit, 5, 0, 2, 3)\n#        App.Console.PrintMessage(\"on_PB_Loupe \"+\"\\n\")\n\n    def on_PU_Quit(self):                                                      # Quit\n        global s\n\n        App.Console.PrintMessage(\"\\n\"+\"Fin FCSpring_Helix_Variable\"+\"\\n\"+\"___________________________\"+\"\\n\")\n        FreeCADGui.Selection.removeObserver(s)                                 # desinstalle la fonction residente\n        try:\n            self.window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)    # destroy\n            self.window.deleteLater()                                     # destroy\n            self.window.destroy()                                         # destroy\n        except Exception:\n            self.window.hide()\n            None\n#        App.Console.PrintMessage(\" \"+\"\\n\")\n\n    def on_PU_Read(self):                                                      # lecture\n        global path\n        global numberSpires\n        global rayon\n        global pas\n        global precision\n        global typeLine\n        global affPoint\n        global helixS\n        global radiusS\n        global debutAngle\n        global finAngle\n        global modifyAngle\n        global radius_2_Cone\n        global spireConeUne\n        global spireConeComp\n        global spireReverse\n        global lissageS\n        global fichierOpen\n        global nomF\n        global setPathLatestDirectory\n\n        OpenName = \"\"\n        ####  mint\n        if switchQFileDialogMint == True:   # Mint\n            OpenName, Filter = QtWidgets.QFileDialog.getOpenFileName(None, u\"Read a file FCSpring\", setPathLatestDirectory, \"(FCSpring *.FCSpring);;\")#PySide2 Mint\n            #OpenName, Filter = PySide2.QtWidgets.QFileDialog.getOpenFileName(None, u\"Read a file FCSpring\", setPathLatestDirectory, \"*.FCSpring;;*\")#PySide2 Mint\n            print(OpenName, Filter)\n        ####  mint\n        else:\n            OpenName, Filter = QtWidgets.QFileDialog.getOpenFileName(None, u\"Read a file FCSpring\", setPathLatestDirectory, \"*.FCSpring;;\")#PySide2\n\n        try:\n            if OpenName != \"\":\n                ####new2\n                pathFile      = os.path.dirname(OpenName) + \"/\"  #1# = C:/Provisoire400/\n                setPathLatestDirectory = pathFile\n                FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetString(u\"setPathLatestDirectory\", setPathLatestDirectory)    #*\"C:\\ ???\"\n                #racineDrive   = os.path.splitdrive(OpenName)[0]  #2# = C:\n                #formatFichier = os.path.splitext(OpenName)[1]    #4# = .png\n                #OpenName      = os.path.splitext(OpenName)[0]    #5# = /home/kubuntu/.FreeCAD/Macro/Texture_007_H #= C:/Provisoire400/image3D\n                #nomFichier    = os.path.basename(OpenName)       #3# = image3D\n                #SaveNameformatFichier = OpenName + formatFichier #6# = C:/Provisoire400/image3D.png\n                #pathFileSaveNameformatFichier = pathFile + nomFichier + formatFichier #7# = C:/Provisoire400/image3D.png\n                ####new2\n\n                try:\n\n                    #### Chrono begin ##################################\n                    chrono(0)                 # chrono begin          ##\n                    ####################################################\n\n                    file = open(OpenName, \"r\") # read\n                    Header = file.readline().rstrip('\\n\\r')                                                                #1\n                    if (Header == \"FCString\") or (Header == \"FCString2\") or (Header == \"FCString3\") or (Header == \"FCString4\"):\n                        a = ui\n                        a.on_PU_Reset(0)\n                        App.Console.PrintMessage(\"____________________\"+\"\\n\")\n\n                        self.textEdit.clear()\n                        op = OpenName.split(\"/\")\n                        op2 = op[-1].split(\".\")\n                        nomF = op2[0]\n\n                        App.Console.PrintMessage(nomF+\"\\n\")\n                        App.Console.PrintMessage(str(Header)+\"\\n\")\n                        numberSpires = file.readline().rstrip('\\n\\r')                                                      # 2\n                        numberSpires = int(numberSpires)\n                        self.DS_Numb_Spires.setValue(numberSpires)\n                        App.Console.PrintMessage(str(numberSpires)+\"\\t\"+\"Number coil\"+\"\\n\")\n\n                        rayon = file.readline().rstrip('\\n\\r')                                                             # 3\n                        rayon = float(rayon)\n                        radiusS = numberSpires*[rayon]\n                        self.DS_Radius_Sping.setValue(rayon)\n                        App.Console.PrintMessage(str(rayon)+\"\\t\"+\"Radius\"+\"\\n\")\n\n                        pas = file.readline().rstrip('\\n\\r')                                                               # 4\n                        pas = float(pas)\n                        helixS = numberSpires*[pas]\n                        self.DS_Pas_Spring.setValue(pas)\n                        App.Console.PrintMessage(str(pas)+\"\\t\"+\"Pitch\"+\"\\n\")\n\n                        precision = file.readline().rstrip('\\n\\r')                                                         # 5\n                        precision = float(precision)\n                        self.DS_Precision_Turn.setValue(precision)\n                        App.Console.PrintMessage(str(precision)+\"\\t\"+\"Precision\"+\"\\n\")\n\n                        if (Header == \"FCString3\") or (Header == \"FCString4\"):\n                            typeLine, spireReverse = file.readline().rstrip(',\\n\\r').split()                               # 6 \n                            spireReverse = int(spireReverse)\n                            if spireReverse == 0:\n                                self.CH_Reverse.setChecked(False)\n                            else:\n                                self.CH_Reverse.setChecked(True)\n                        else:\n                            typeLine = file.readline().rstrip('\\n\\r')\n\n                        typeLine = int(typeLine)\n                        if typeLine == 0:\n                            self.RA_BSpline.setChecked(True)\n                        else:\n                            self.RA_Wire.setChecked(True)\n                        if (Header == \"FCString2\") or (Header == \"FCString3\") or (Header == \"FCString4\"):\n                            self.CH_Points.setChecked(False) # reset point\n                            affPoint = 0\n\n                            debutAngle = file.readline().rstrip('\\n\\r')                                                     # 7\n                            debutAngle = int(debutAngle)\n                            self.SP_Begin_Angle.setValue(int(debutAngle))\n\n                            finAngle = file.readline().rstrip('\\n\\r')                                                       # 8\n                            finAngle = int(finAngle)\n                            self.SP_End_Angle.setValue(int(finAngle))\n\n                            modifyAngle = file.readline().rstrip('\\n\\r')                                                    # 9\n                            modifyAngle = int(modifyAngle)\n                            if modifyAngle == 1:\n                                self.CB_B_E_Angle.setChecked(True) \n                                fichierOpen = 1\n                            else:\n                                self.CB_B_E_Angle.setChecked(False)\n                                fichierOpen = 0\n                            a = ui\n                            a.on_CB_B_E_Angle()\n                            try:\n                                sp, sc, ra = file.readline().rstrip(',\\n\\r').split()                                        # 10\n                                spireConeUne  = int(sp)   # cone\n                                spireConeComp = int(sc)   # compensation\n                                radius_2_Cone = float(ra) # radius 2 cone\n                            except Exception:\n                                spireConeUne  = 0\n                                spireConeComp = 0\n                                radius_2_Cone = 0\n\n                            if (spireConeUne == 1) or (spireConeComp == 1):\n                                self.DS_Radius_2_Cone.setEnabled(True)\n                                self.DS_Radius_2_Cone.setValue(radius_2_Cone)\n                                self.CH_Cone.setChecked(True)\n                                self.LAB_Numb_Spires.setText(\"Number real (\"+str(numberSpires - 1)+\")\")\n                                self.LAB_Numb_Spires.setToolTip(_fromUtf8(\"The number of coil for a spring conical registered\"+\"\\n\" \n                                                                  \"is number of coil displayed minus 1\"))\n                            else:\n                                self.DS_Radius_2_Cone.setEnabled(False)\n                                self.DS_Radius_2_Cone.setValue(rayon)\n                                self.CH_Cone.setChecked(False)\n#                                self.CH_Cone.setEnabled(False)\n                                self.LAB_Numb_Spires.setText(\"Number of coil\")\n                                self.LAB_Numb_Spires.setToolTip(_fromUtf8(\"Number of coil\"))\n                            App.Console.PrintMessage(str(spireConeUne)+\" \"+str(radius_2_Cone)+\"\\t\"+\"Radius cone\"+\"\\n\\n\")\n                      \n                        dummy = file.readline().rstrip('\\n\\r')                                                               # 11\n\n                        del lissageS[:]\n                        lissageS = numberSpires*[0]\n\n                        i = 0\n                        for ligne in file:\n                            if (Header == \"FCString4\"):\n                                a , b , c = ligne.rstrip('\\n\\r').split()\n                                helixS[i]   = float(a)\n                                radiusS[i]  = float(b)\n                                lissageS[i] = int(c)\n                                App.Console.PrintMessage(str(i+1)+\":  \"+str(helixS[i])+\"   \"+str(radiusS[i])+\"   \"+str(lissageS[i])+\"\\n\")\n                                self.textEdit.append(\"Coil number \" + str(i+1) + \" = \" + str(helixS[i]) + \" \" + str(radiusS[i])+\"   \"+str(lissageS[i])) # 12\n                            else:\n                                a , b = ligne.rstrip('\\n\\r').split()\n                                helixS[i] = float(a)\n                                radiusS[i] = float(b)\n                                App.Console.PrintMessage(str(i+1)+\":  \"+str(helixS[i])+\"   \"+str(radiusS[i])+\"\\n\")\n                                self.textEdit.append(\"Coil number \" + str(i+1) + \" = \" + str(helixS[i]) + \" \" + str(radiusS[i]))                        # 12\n                            i += 1\n                        App.Console.PrintMessage(\"____________________\"+\"\\n\")\n                        self.textEdit.verticalScrollBar().setValue(0)          # \n                        self.textEdit.verticalScrollBar().setSliderPosition(0) #\n\n                    else:\n                        self.PU_Reload.setEnabled(False)\n                        App.Console.PrintMessage(\"Error file not FCSpring or not FCSpring2.3.4\"+\"\\n\")\n                        errorDialog(\"Error file not FCSpring or not FCSpring2.3.4 \"+\"\\n\")\n                finally:\n                    file.close()\n\n                #### Chrono(1) end #################################\n                chrono(1)                 # chrono(1) end         ##\n                ####################################################\n\n                #self.label_11_Name.setText(nomF)\n        except Exception:\n            App.Console.PrintMessage(\"Error in reading the file \"+OpenName+\"\\n\")\n            errorDialog(\"Error in reading the file \"+OpenName)\n\n    def on_PU_Save(self):                                                      # enregistrement\n        global path\n        global numberSpires\n        global rayon\n        global pas\n        global precision\n        global typeLine\n        global helixS\n        global radiusS\n        global debutAngle\n        global finAngle\n        global modifyAngle\n        global radius_2_Cone\n        global spireConeUne\n        global spireConeComp\n        global spireReverse\n        global lissageS\n        global setPathLatestDirectory\n\n        SaveName = \"\"\n        ####  mint\n        if switchQFileDialogMint == True:   # Mint\n            SaveName, Filter = QtWidgets.QFileDialog.getSaveFileName(None, \"Save a file FCSpring\", setPathLatestDirectory, \"(*.FCSpring)\")#PySide2 Mint\n            if \".FCSpring\" in SaveName:\n                None\n            else:\n                Filter = Filter[Filter.find(\".\"):Filter.find(\")\")]\n                SaveName = SaveName + Filter\n        ####  mint\n        else:\n            SaveName, Filter = QtWidgets.QFileDialog.getSaveFileName(None, \"Save a file FCSpring\", setPathLatestDirectory, \"*.FCSpring;;FCSpring (*.FCSpring);;\")#PySide2\n\n        if SaveName == \"\":\n            App.Console.PrintMessage(u\"Process aborted\" + \"\\n\")\n            errorDialog(u\"Process aborted\")\n        else:\n            App.Console.PrintMessage(u\"Registration of \" + SaveName + \"\\n\")\n            ####new2\n            pathFile      = os.path.dirname(SaveName) + \"/\"  #1# = C:/Provisoire400/\n            setPathLatestDirectory = pathFile\n            FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetString(u\"setPathLatestDirectory\", setPathLatestDirectory)    #*\"C:\\ ???\"\n            #racineDrive   = os.path.splitdrive(SaveName)[0]  #2# = C:\n            #formatFichier = os.path.splitext(SaveName)[1]    #4# = .png\n            #SaveName      = os.path.splitext(SaveName)[0]    #5# = /home/kubuntu/.FreeCAD/Macro/Texture_007_H #= C:/Provisoire400/image3D\n            #nomFichier    = os.path.basename(SaveName)       #3# = image3D\n            #SaveNameformatFichier = SaveName + formatFichier #6# = C:/Provisoire400/image3D.png\n            #pathFileSaveNameformatFichier = pathFile + nomFichier + formatFichier #7# = C:/Provisoire400/image3D.png\n            ####new2\n\n            #self.label_11_Name.setText(SaveName)\n            try:\n                file = open(SaveName, 'w') # write\n                try:\n                    file.write(\"FCString4\"+\"\\n\")                               # 1\n                    file.write(str(numberSpires)+\"\\n\")                         # 2\n                    file.write(str(rayon)+\"\\n\")                                # 3\n                    file.write(str(pas)+\"\\n\")                                  # 4\n                    file.write(str(precision)+\"\\n\")                            # 5\n                    file.write(str(typeLine)+\"\\t\"+str(spireReverse)+\"\\n\")      # 6\n                    file.write(str(debutAngle)+\"\\n\")                           # 7\n                    file.write(str(finAngle)+\"\\n\")                             # 8\n                    file.write(str(modifyAngle)+\"\\n\")                          # 9\n                    file.write(str(spireConeUne)+\"\\t\"+str(spireConeComp)+\"\\t\"+str(radius_2_Cone)+\"\\n\")             # 10\n                    file.write(\"Coil\"+\"\\t\"+\"Radius\"+\"\\t\"+\"Smooting\"+\"\\t\"+\"(If you change the file, always use Tab no space)\"+\"\\n\") # 11\n                    for i in range(numberSpires):\n                        file.write(str(helixS[i])+\"\\t\"+str(radiusS[i])+\"\\t\"+str(lissageS[i])+\"\\n\")                 # 12\n                finally:\n                    file.close()\n            except Exception:\n                App.Console.PrintError(\"Error Registration file \"+SaveName+\"\\n\")\n                errorDialog(\"Error Registration file \"+SaveName)\n\n    def on_PU_Save_Coord(self):                                                # Save coordinates x y z\n        global points\n        global setPathLatestDirectory\n\n        if len(points) > 2:\n            SaveName = \"\"\n            ####  mint\n            if switchQFileDialogMint == True:   # Mint\n                SaveName, Filter = QtWidgets.QFileDialog.getSaveFileName(None, \"Save a file FCSpringCoor\", setPathLatestDirectory, \"(*.FCSpringCoor)\")#PySide2 Mint\n                if \".FCSpringCoor\" in SaveName:\n                    None\n                else:\n                    Filter = Filter[Filter.find(\".\"):Filter.find(\")\")]\n                    SaveName = SaveName + Filter\n            ####  mint\n            else:\n                SaveName, Filter = QtWidgets.QFileDialog.getSaveFileName(None, \"Save a file FCSpringCoor\", setPathLatestDirectory, \"*.FCSpringCoor;;FCSpringCoor (*.FCSpringCoor);;\")#PySide2\n\n            if SaveName == \"\":\n                App.Console.PrintMessage(u\"Process aborted\" + \"\\n\")\n                errorDialog(u\"Process aborted\")\n            else:\n                App.Console.PrintMessage(u\"Registration of \" + SaveName + \"\\n\")\n                ####new2\n                pathFile      = os.path.dirname(SaveName) + \"/\"  #1# = C:/Provisoire400/\n                setPathLatestDirectory = pathFile\n                FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetString(u\"setPathLatestDirectory\", setPathLatestDirectory)    #*\"C:\\ ???\"\n                #racineDrive   = os.path.splitdrive(SaveName)[0]  #2# = C:\n                #formatFichier = os.path.splitext(SaveName)[1]    #4# = .png\n                #SaveName      = os.path.splitext(SaveName)[0]    #5# = /home/kubuntu/.FreeCAD/Macro/Texture_007_H #= C:/Provisoire400/image3D\n                #nomFichier    = os.path.basename(SaveName)       #3# = image3D\n                #SaveNameformatFichier = SaveName + formatFichier #6# = C:/Provisoire400/image3D.png\n                #pathFileSaveNameformatFichier = pathFile + nomFichier + formatFichier #7# = C:/Provisoire400/image3D.png\n                ####new2\n                #self.label_11_Name.setText(SaveName)\n                try:\n                    file = open(SaveName, 'w') # write\n                    try:\n                        for i in points:\n                            file.write(str(i[0])+\" \"+str(i[1])+\" \"+str(i[2])+\"\\n\") # save the coordinates x y z\n                    finally:\n                        file.close()\n                except Exception:\n                    App.Console.PrintMessage(\"Error Registration file \"+SaveName+\"\\n\")\n                    errorDialog(\"Error Registration file \"+SaveName)\n        else:\n            App.Console.PrintError(\"Not data to save\"+\"\\n\")\n#        App.Console.PrintMessage(\"on_PU_Save_Coord\"+\"\\n\")\n\n    def on_PU_Read_Coord(self):                                                # Read coordinates x y z\n        global typeLine\n        global nomF\n        global points\n        global setPathLatestDirectory\n\n        OpenName = \"\"\n        ####  mint\n        if switchQFileDialogMint == True:   # Mint\n            OpenName, Filter = QtWidgets.QFileDialog.getOpenFileName(None, u\"Read a file FCSpringCoor\", setPathLatestDirectory, \"(FCSpringCoor *.FCSpringCoor);;\")#PySide2 Mint\n        ####  mint\n        else:\n            OpenName, Filter = QtWidgets.QFileDialog.getOpenFileName(None, u\"Read a file FCSpringCoor\", setPathLatestDirectory, \"*.FCSpringCoor\")#PySide2\n\n        try:\n            if OpenName != \"\":\n                ####new2\n                pathFile      = os.path.dirname(OpenName) + \"/\"  #1# = C:/Provisoire400/\n                setPathLatestDirectory = pathFile\n                FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetString(u\"setPathLatestDirectory\", setPathLatestDirectory)    #*\"C:\\ ???\"\n                #racineDrive   = os.path.splitdrive(OpenName)[0]  #2# = C:\n                #formatFichier = os.path.splitext(OpenName)[1]    #4# = .png\n                #OpenName      = os.path.splitext(OpenName)[0]    #5# = /home/kubuntu/.FreeCAD/Macro/Texture_007_H #= C:/Provisoire400/image3D\n                #nomFichier    = os.path.basename(OpenName)       #3# = image3D\n                #SaveNameformatFichier = OpenName + formatFichier #6# = C:/Provisoire400/image3D.png\n                #pathFileSaveNameformatFichier = pathFile + nomFichier + formatFichier #7# = C:/Provisoire400/image3D.png\n                ####new2\n\n                try:\n\n                    #### Chrono(0) begin ###############################\n                    chrono(0)                 # chrono(0) begin       ##\n                    ####################################################\n\n                    file = open(OpenName, \"r\") # read\n                    a = ui\n                    a.on_PU_Reset(0)\n                    App.Console.PrintMessage(\"____________________\"+\"\\n\")\n\n                    self.DS_Numb_Spires.setValue(numberSpires)\n                    self.DS_Pas_Spring.setValue(pas)\n                    self.DS_Radius_Sping.setValue(rayon)\n                    self.textEdit.clear()\n                    op = OpenName.split(\"/\")\n                    op2 = op[-1].split(\".\")\n                    nomF = op2[0]\n                    points = []\n                    del points[:]\n                    App.Console.PrintMessage(nomF+\"\\n\")\n\n                    self.PU_Accept_Value.setVisible(False)\n                    self.PBA_progressBar.setVisible(True)\n                    self.PBA_progressBar.setMaximum(0)\n                    self.PBA_progressBar.setMinimum(0)\n#                    self.PBA_progressBar.setValue(0)\n                    X = Y = Z = 0.0\n                    for ligne in file:\n                        X , Y , Z = ligne.rstrip('\\n\\r').split()\n                        points.append(FreeCAD.Vector(float(X),float(Y),float(Z)))            # append the coordinates\n\n                    if typeLine == 1:\n                        ressort = Draft.makeWire(points,closed=False,face=False,support=None)# creation spring makeWire\n                    else:\n                        ressort = Draft.makeBSpline(points,closed=False)                     # creation spring Draft \" makeBSpline \" remis pour facilite avec axes\n#                        ressort = Part.BSplineCurve()                                        # creation spring Part  \" BSplineCurve \"\n#                        ressort.interpolate(points,False)\n#                        ressort0 = Part.Edge(ressort)\n#                        Part.show(ressort0)\n            \n                    try:\n                        App.ActiveDocument.ActiveObject.Label =  \"Spring_\" + unicode(nomF)\n                    except Exception:\n                        try:\n                            App.ActiveDocument.ActiveObject.Label =  \"Spring_\" + nomF\n                        except Exception:\n                            App.ActiveDocument.ActiveObject.Label =  \"Spring_XX\"\n                    \n                    FreeCAD.ActiveDocument.recompute()\n            \n                    self.PBA_progressBar.setVisible(False)\n                    self.PU_Accept_Value.setVisible(True)\n\n                    #### Chrono(1) end #################################\n                    chrono(1)                 # chrono(1) end         ##\n                    ####################################################\n\n                finally:\n                    file.close()\n \n                #self.label_11_Name.setText(nomF)\n                self.textEdit.append(\"Coordinates file\")# + \"\\n\")\n                self.textEdit.setTextColor(QColor(\"blue\"))\n                self.textEdit.append(\"PS: For Info The values showing in the configuration menu do not match the data of the spring\"+\"\\n\")\n                self.textEdit.setTextColor(QColor(\"Base\"))\n\n        except Exception:\n            App.Console.PrintMessage(\"Error in reading the file \"+OpenName+\"\\n\")\n            errorDialog(\"Error in reading the file \"+OpenName)\n        App.Console.PrintMessage(\"on_PU_Read_Coord\"+\"\\n\")\n\n    def on_PU_Launch(self):                                                    # Execute\n        global numberSpires\n        global rayon\n        global pas\n        global precision\n        global typeLine\n        global helixS\n        global pasSpire\n        global radiusS\n        global affPoint\n        global debutAngle\n        global finAngle\n        global modifyAngle\n        global radius_2_Cone\n        global spireConeUne\n        global spireConeComp\n        global spireReverse\n        global lissageSpire\n        global lissageS\n        global points\n        global nomF\n        global ressort\n\n        global pointsDirection\n        global Direction_Begin\n        global Direction_Distance\n        global plr\n        global coor_Z\n        global ui\n        global sel\n        global hauteurCylindre\n        global vecteurSouris\n        global centerFaceOrPoint\n        global axisSpring\n        global switchReverse\n        global switchAdaptRadius\n\n        if rayon != 0:\n            doc = FreeCAD.ActiveDocument\n            if doc == None:\n                doc = FreeCAD.newDocument()\n\n            ressort = \"\"\n\n        ############ Section object selected Begin ####################################################\n            sel = FreeCADGui.Selection.getSelectionEx()                        #0# Select an object or sub object\n            try:\n                if len(sel) != 0:\n\n                    #### Chrono begin ##################################\n                    chrono(0)                 # chrono begin          ##\n                    ####################################################\n\n                    subObjet = sel[0].SubObjects[0]\n                    selobject = FreeCADGui.Selection.getSelection()            # Select an object\n    \n                    FCSpring = doc.addObject(\"App::DocumentObjectGroup\",\"FCSpring\")\n                    switchReverse = 0\n                    xL = yL = 0.0\n                    hauteurCylindre = sum(helixS)                              # calcul hauteur Cylindre / axe\n\n                    if hasattr(sel[0].SubObjects[0],\"Surface\"):\n                        subObjet = sel[0].SubObjects[0]\n                        if (str(subObjet.Surface) == \"<Cylinder object>\") or (str(subObjet.Surface) == \"<SurfaceOfExtrusion object>\"):      # face\n                            try:\n                                GlobalCenter = LineCoorX = LineCoorY = CircleCenter = CircleRadius = EllipseCenter = EllipseRadius = 0.0\n                                for a0 in subObjet.Edges:\n                                    if (str(a0.Curve)[1:5]) == \"Line\" :\n#                                        print( \"xLine\" )\n                                        LineCoorX = a0.Vertexes[1].Point\n                                        LineCoorY = a0.Vertexes[0].Point\n                                    if (str(a0.Curve)[0:6]) == \"Circle\" :\n#                                        print( \"xCircle\" )\n                                        GlobalCenter = CircleCenter = a0.Curve.Center\n                                        CircleRadius = a0.Curve.Radius\n                                        xL = CircleCenter\n                                        rayonX = CircleRadius\n                                    if (str(a0.Curve)[1:8]) == \"Ellipse\" :\n#                                        print( \"xEllipse\" )\n                                        GlobalCenter = EllipseCenter = a0.Curve.Center\n                                        EllipseRadius = a0.Curve.MinorRadius\n                                        #EllipseRadius = a0.Curve.MajorRadius   #option\n                                        rayonX = EllipseRadius\n                                        xL = EllipseCenter\n    \n                                if LineCoorX.distanceToPoint(GlobalCenter) > LineCoorY.distanceToPoint(GlobalCenter):\n                                    Direction = LineCoorX.sub(LineCoorY)\n                                else:\n                                    Direction = LineCoorY.sub(LineCoorX)\n                                if switchAdaptRadius == 1:\n                                    rayon = rayonX\n                                    self.DS_Radius_Sping.setValue(rayon)\n                                yL = Direction + xL\n                                points=[xL,yL]\n                            except Exception:\n                                App.Console.PrintError(\"<Cylinder object> + <SurfaceOfExtrusion object\"+\"\\n\")\n\n                        elif str(subObjet.Surface) == \"<Plane object>\":        # extremites\n                            try:\n#                                print( \"<Plane object>\" )\n                                subObjet = sel[0].SubObjects[0]\n                                obj  = selobject[0]\n                                comp = subObjet\n                                if centerFaceOrPoint != 0:\n                                    yL = sel[0].SubObjects[0].CenterOfMass     # Center Of face\n                                else:\n                                    yL = vecteurSouris                         # clic point\n                                uv = comp.Surface.parameter((yL))\n                                nv = comp.normalAt(uv[0], uv[1]).normalize().multiply(hauteurCylindre)\n                                xL = nv + yL\n                                points=[xL,yL]\n                            except Exception:\n                                App.Console.PrintError(\"<Plane object>\"+\"\\n\")\n\n                        elif (str(subObjet.Surface)[0:6] == \"Sphere\"):         # Sphere\n                            try:\n#                                print( \"Sphere\" )\n                                subObjet = sel[0].SubObjects[0]\n                                if switchAdaptRadius == 1:\n                                    rayon = selobject[0].Radius.Value          # selobject[0].Radius2.Value # option\n                                    self.DS_Radius_Sping.setValue(rayon)\n\n                                obj  = selobject[0]\n                                comp = subObjet\n                                if centerFaceOrPoint != 0:\n                                    xL = subObjet.Surface.Center               # Center\n                                    direction = subObjet.Surface.Axis.normalize().multiply(hauteurCylindre)\n                                    yL = direction + xL\n                                else:\n                                    xL = vecteurSouris                         # clic point\n                                    uv = comp.Surface.parameter((xL))\n                                    nv = comp.normalAt(uv[0], uv[1]).normalize().multiply(hauteurCylindre)\n                                    yL = nv + xL\n                                points=[xL,yL]\n                            except Exception:\n                                App.Console.PrintError(\"Sphere\"+\"\\n\")\n\n                        elif (str(subObjet.Surface) == \"<Toroid object>\") or (str(subObjet.Surface) == \"<Cone object>\"):   # Toroid + Cone\n                            try:\n#                                print( str(subObjet.Surface) )\n                                subObjet = sel[0].SubObjects[0]\n                                if switchAdaptRadius == 1:\n                                    rayon = selobject[0].Radius1.Value         # selobject[0].Radius2.Value # option\n                                    self.DS_Radius_Sping.setValue(rayon)\n                                obj  = selobject[0]\n                                comp = subObjet\n                                if centerFaceOrPoint != 0:\n                                    xL = subObjet.Surface.Center               # Center\n                                    direction = subObjet.Surface.Axis.normalize().multiply(hauteurCylindre)\n                                    yL = direction + xL\n                                else:\n                                    xL = vecteurSouris                         # clic point\n                                    uv = comp.Surface.parameter((xL))\n                                    nv = comp.normalAt(uv[0], uv[1]).normalize().multiply(hauteurCylindre)\n                                    yL = nv + xL\n                                points=[xL,yL]\n                            except Exception:\n                                App.Console.PrintError(str(subObjet.Surface)+\"\\n\")\n                        else:\n                            try:\n#                                print( \"Terminus\" )\n                                obj  = selobject[0]\n                                comp = subObjet\n                                xL = vecteurSouris                             # clic point\n                                uv = comp.Surface.parameter((xL))\n                                nv = comp.normalAt(uv[0], uv[1]).normalize().multiply(hauteurCylindre)#hauteurCylindre\n                                yL = nv + xL\n                                points=[xL,yL]\n                            except Exception:\n                                App.Console.PrintError(\"Face\"+\"\\n\")\n\n                    else:\n                        ###OK tous points############################################# \n                        if (len(sel[0].SubObjects) == 2):\n                            xL = sel[0].SubObjects[0].Vertexes[0].Point\n                            yL = sel[0].SubObjects[1].Vertexes[0].Point\n                            points=[xL,yL]\n                        elif (len(sel) == 2):\n                            xL = sel[0].SubObjects[0].Vertexes[0].Point\n                            yL = sel[1].SubObjects[0].Vertexes[0].Point\n                            points=[xL,yL]\n                        elif (len(sel) == 1):\n                            try:\n                                if (hasattr(subObjet.Curve,\"Center\")) and (hasattr(subObjet.Curve,\"Radius\")):       # arc or circle\n#                                    print( \"Circle/Arc\" )\n                                    subObjet = sel[0].SubObjects[0]\n                                    if switchAdaptRadius == 1:\n                                        rayon = subObjet.Curve.Radius\n                                        self.DS_Radius_Sping.setValue(rayon)\n                                    yL = subObjet.Curve.Center\n                                    direction = subObjet.Curve.Axis.normalize().multiply(hauteurCylindre)                      # option\n                                    edgeO = selobject[0]                       # edge\n                                    edgeObject = edgeO.Shape.Edges[0]\n                                    e = edgeObject\n                                    xL = direction + yL\n                                    points=[xL,yL]\n                                elif (str(subObjet.Curve)[1:5]) == \"Line\" :\n#                                    print( \"Line\" )\n                                    xL = subObjet.Vertexes[1].Point\n                                    yL = subObjet.Vertexes[0].Point\n                                    points=[xL,yL]\n                                elif (str(subObjet.Curve) == \"<Ellipse object>\"): # Ellipse\n#                                    print( \"Ellipse\" )\n                                    subObjet = sel[0].SubObjects[0]\n                                    if switchAdaptRadius == 1:\n                                        rayon = subObjet.Curve.MinorRadius\n                                        self.DS_Radius_Sping.setValue(rayon)\n                                    xL = subObjet.Curve.Center\n                                    direction = subObjet.Curve.Axis.normalize().multiply(hauteurCylindre)                      # option\n                                    edgeO = selobject[0]                       # edge\n                                    edgeObject = edgeO.Shape.Edges[0]\n                                    e = edgeObject\n                                    yL = direction + xL\n                                    points=[xL,yL]\n                                else:\n#                                    print( \"Ouf.Curve\" )\n                                    xL = sel[0].SubObjects[0].Vertexes[0].Point\n                                    yL = xL + (FreeCAD.Vector(0.0, 0.0, hauteurCylindre))\n                                    points=[xL,yL]\n                            except Exception:\n                                xL = sel[0].SubObjects[0].Vertexes[0].Point\n                                try:\n                                    yL = sel[0].SubObjects[0].Vertexes[1].Point\n                                except Exception:\n                                    yL = xL + (FreeCAD.Vector(0.0, 0.0, hauteurCylindre))\n                                points=[xL,yL]\n                        ###OK tous points############################################# \n    \n                    axisSpring = sel = \"\"\n                    axisSpring = Draft.makeWire(points,closed=False,face=False,support=None)  # make line\n                    axisSpring.ViewObject.LineColor  = (1.0,0.0,0.0)                          # give axis LineColor\n                    axisSpring.ViewObject.DrawStyle  = \"Dashdot\"\n                    axisSpring.Label = \"Spring Axis (\" + str(axisSpring.Length.Value) + \")\"\n                    FCSpring.addObject(axisSpring)\n                    FreeCADGui.updateGui()                                     # rafraichi l'ecran\n                    FreeCAD.ActiveDocument.recompute()\n                    #doc.removeObject(axisSpring.Name)                          # remove axis if .. option\n    \n                    obj = App.ActiveDocument.getObject(axisSpring.Name)\n                    Gui.Selection.addSelection(obj)                            # select the object \n                    sel = FreeCADGui.Selection.getSelectionEx()\n                    pointsDirection = sel[0].Object.Shape.discretize(Distance = Direction_Distance) # discretize\n    \n                    v=pointsDirection[0].sub(pointsDirection[1])\n                    r=App.Rotation(App.Vector(0,0,1),v)\n                    plr=FreeCAD.Placement()\n                    plr.Rotation.Q = r.Q\n    \n                    self.horizontalSlider.setMaximum(len(pointsDirection))\n                    self.DS_horizontalSlider.setMaximum(int(len(pointsDirection)/10))\n                    self.DS_horizontalSlider.setValue(len(pointsDirection)/10)\n    \n#                    self.groupBox_04.setEnabled(True)\n#                    self.groupBox_04.setStyleSheet(\"QGroupBox {background-color: white;\\n\"\n#                                                   \"border:2px solid rgb(0, 187, 0);}\")   # bord white and green\n                else:\n                    plr = \"xx\"\n    \n#                self.groupBox_04.setTitle(\"Position (\" + str(len(sel)) + \")(Points: \" + str(len(pointsDirection)) + \")\")\n            except Exception:\n                App.Console.PrintError(\"Error selection \" + \"\\n\")\n                switchReverse = 0\n                sel = \"\"\n            FreeCAD.ActiveDocument.recompute()\n            FreeCADGui.updateGui()                                             # rafraichi l'ecran\n            Gui.updateGui()                                                    # rafraichi l'ecran\n        ############ Section object selected End ######################################################\n\n            self.PU_Accept_Value.setVisible(False)\n            self.PBA_progressBar.setVisible(True)\n            self.PBA_progressBar.setMaximum(numberSpires * (360 / int(precision)))\n            self.PBA_progressBar.setValue(0)\n    \n            coor_X = coor_Y = coor_Z = 0.0\n            angleTr  = 0\n            points   = []\n            del   points[:]\n            pas2 = 0.0\n            PBA = 0                                                            # compteur PgrogressBar\n            App.Console.PrintMessage(\"____________________\"+\"\\n\")\n            App.Console.PrintMessage(\"Pitch       \" + str(pas)+\"\\n\")\n            App.Console.PrintMessage(\"Radius      \" + str(rayon)+\"\\n\")\n            App.Console.PrintMessage(\"Precision   \" + str(precision)+\"\\n\")\n            App.Console.PrintMessage(\"DebutAngle  \" + str(debutAngle)+\"\\n\")\n            App.Console.PrintMessage(\"FinAngle    \" + str(finAngle)+\"\\n\")\n            App.Console.PrintMessage(\"List Helix  \" + str(helixS)+\"\\n\")\n            App.Console.PrintMessage(\"List Radius \" + str(radiusS)+\"\\n\")\n            App.Console.PrintMessage(\"List Smoot1 \" + str(lissageS)+\"\\n\")\n    \n            for spir in range(numberSpires-spireConeComp):                     # number spires Helix\n                pas2 = helixS[spir]\n                PBA += 1\n    \n                if spir != numberSpires - 1:                                   # pas travail normal\n                    pastr = ((radiusS[spir + 1]-radiusS[spir]) / (360/precision))\n                elif spireConeUne == 1:                                        # cone une seule spire\n                    pastr = (radius_2_Cone / (360/precision))\n                else:\n                    pastr = 0.0\n    \n                pasRadius = radiusS[spir]                                      # pas pour le rayon\n                i = 0\n                debutAngleX = 0\n                finAngleX   = 360\n    \n                if modifyAngle == 1:\n                    if (spir == 0) :\n                        debutAngleX = debutAngle\n    \n                if (spir == numberSpires - 1 - spireConeComp): #or (spir == numberSpires):\n                    finAngleX  = finAngle + int(precision)\n    \n                for angleTr in range(0,finAngleX,int(precision)):              # boucle for 1 turn (360/precision) degrees\n                    pasRadius = radiusS[spir]+((pastr*i))\n                    i+=1\n                    self.PBA_progressBar.setValue( PBA )\n                    PBA += 1\n                    \n                    vecligne=[FreeCAD.Vector(0,0,0),FreeCAD.Vector(pasRadius ,0.0,0.0)]\n                    ligne = Draft.makeWire(vecligne,closed=False,face=False,support=None) #creation de la ligne de base\n                    #ligneName = ligne.Name\n\n                    if spireReverse == 0:                                      # counterclockwise\n                        ligne.Placement = FreeCAD.ActiveDocument.Line.Placement=App.Placement(App.Vector(0.0,0.0,0.0), App.Rotation(App.Vector(0,0,1),angleTr), App.Vector(0,0,0))\n                    else:                                                      # clockwise direction\n                        ligne.Placement = FreeCAD.ActiveDocument.Line.Placement=App.Placement(App.Vector(0.0,0.0,0.0), App.Rotation(App.Vector(0,0,1),-angleTr), App.Vector(0,0,0))\n\n                    FreeCAD.activeDocument().recompute(None,True,True)\n\n                    try:\n                        a = ligne.Shape.Edges[0].Vertexes[1]                       # fin de ligne\n                    except Exception:\n                        a = ligne.End                                              # fin de ligne\n\n                    try:\n                        coor_X = (a.Point.x)\n                        coor_Y = (a.Point.y)\n                    except Exception:\n                        coor_X = (a.x)\n                        coor_Y = (a.y)\n    \n                    if angleTr >= debutAngleX:\n                        points += [FreeCAD.Vector(coor_X,coor_Y,coor_Z)]       # coordinates makeBSpline contener\n    \n                    if (affPoint == 1) and (angleTr >= debutAngleX):\n                        point = Draft.makePoint(coor_X,coor_Y,coor_Z)          # create point repere for test\n                        FreeCADGui.activeDocument().getObject(point.Name).PointColor = (1.0,0.0,0.0)\n    \n                    coor_Z += (pas2 / (360/precision))                         # pas of spring\n                    \n                    App.ActiveDocument.removeObject(ligne.Name)                # remove ligne de base directrice\n                    #App.ActiveDocument.removeObject(ligneName)                # remove ligne de base directrice\n\n            ############# Smooting begin  ### prototype#############################################################################################\n    \n            if (numberSpires >= 2) and (sum(lissageS[:]) != 0):\n    \n                compBar = compBar1 = 0                                         # progressBar\n                compBar = sum(lissageS[:])                                     # progressBar\n                self.PBA_progressBar.setMaximum(compBar)                       # progressBar\n                self.PBA_progressBar.setValue(0)                               # progressBar\n        \n                decalageM = 0                                                  # decalage montant\n                pointTravailBase = int(360/precision)                          # nombre de points dans la boucle\n        \n                if debutAngle != 0:\n                    decalageM = (pointTravailBase - int((360-debutAngle)/precision)) # decalageM debutAngle\n                    if lissageS[0] != 0:                                                           # lissage spire 1\n                        if lissageS[0] > int((360-debutAngle)/precision):\n                            lissageS[0] = int((360-debutAngle)/precision) - 1\n\n                    if (lissageS[1] != 0):                                                         # lissage spire 2\n                        if lissageS[1] > int((360-debutAngle)/precision):\n                            lissageS[1] = int((360-debutAngle)/precision) - 1\n    \n                if finAngle != 360:\n                    if lissageS[-1] != 0:                                                          # lissage derniere spire \n                        if lissageS[-1] > (pointTravailBase - int((360-finAngle)/precision)):\n                            lissageS[-1] = (pointTravailBase - int((360-finAngle)/precision)) - 1\n    \n                    if lissageS[-2] != 0:                                                          # lissage avant derniere spire \n                        if lissageS[-2] > (pointTravailBase - int((360-finAngle)/precision)):\n                            lissageS[-2] = (pointTravailBase - int((360-finAngle)/precision)) - 1\n\n                    try:\n                        if (lissageS[-3] != 0) and ((spireConeUne == 1) or (spireConeComp == 1)):  # lissage avant derniere spire cas cone (N_spire-1)\n                            if lissageS[-3] > (pointTravailBase - int((360-finAngle)/precision)):\n                                lissageS[-3] = (pointTravailBase - int((360-finAngle)/precision)) - 1\n                    except Exception:\n                        None\n                        App.Console.PrintError(\"Error0 smooting\"+\"\\n\")\n\n                ############################################# lissage Gauche Superieur\n    \n                x0 = 2                                                         # division premiere spire\n                x1 = 0                                                         # avance G/D\n                x2 = 1                                                         # largeur en points\n                x3 = 2                                                         # division  \n\n                for ii in range(1 , numberSpires):\n                    pointTravail = pointTravailBase * ii\n                    compBar1 += 1                                              # progressBar\n                    self.PBA_progressBar.setValue(compBar1)                    # progressBar\n                   \n                    if lissageS[ii-1] != 0:\n                        x1 = 0    # avance G/D\n                        boucler = lissageS[ii-1]\n    \n                        if (ii-1 == 0) and (debutAngle != 0):                  # nombre de points\n                            if (boucler) > (pointTravailBase - int((360-debutAngle)/precision)):\n                                boucler = lissageS[0] - (pointTravailBase - int((360-debutAngle)/precision))\n    \n                        try:\n                            for i in (range(boucler)):\n                                compBar1 += 1                                             # progressBar\n                                self.PBA_progressBar.setValue(compBar1)                   # progressBar\n                                if i == 0:\n                                    a = points[pointTravail-1-decalageM][2]  # G          # C\n                                    b = points[pointTravail+1-decalageM][2]  # D          # C\n                                    c = (((b - a)/x0) + a)                                # C\n                                    points[pointTravail+(i)-decalageM][2] = c             # C\n                                else:\n                                    x1 += 1\n                                    a = points[pointTravail+(x1-x2)-decalageM][2]  # G    # D\n                                    b = points[pointTravail+(x1+x2)-decalageM][2]  # D    # D\n                                    c = (((b - a)/x3) + a)                      # D\n                                    points[pointTravail+(x1)-decalageM][2] = c            # D\n            \n                                    a = points[pointTravail+(-x1-x2)-decalageM][2]  # G   # G\n                                    b = points[pointTravail+(-x1+x2)-decalageM][2]  # D   # G\n                                    c = (((b - a)/x3) + a)                                # G\n                                    points[pointTravail+(-x1)-decalageM][2] = c           # G\n                        except Exception:\n                            App.Console.PrintError(\"Error1 smooting coil num : \"+str(ii)+\"  value : \"+str(lissageS[ii-1])+\"\\n\"+\n                                                   \"Choose a lower smoothing value\"+\"\\n\")\n        \n                ############################################# lissage Droit Inferieur\n\n                compBar1 = 0\n                for ii in range(1 , numberSpires):\n                    pointTravail = pointTravailBase * (ii )\n                    compBar1 += 1                                              # progressBar\n                    self.PBA_progressBar.setValue(compBar1)                    # progressBar\n        \n                    if lissageS[ii] != 0:\n                        x1 = 0    # avance G/D\n                        boucler = lissageS[ii]\n        \n                        try:\n                            for i in (range(boucler)):\n                                compBar1 += 1                                  # progressBar\n                                self.PBA_progressBar.setValue(compBar1)        # progressBar\n                                if i == 0:\n                                    a = points[pointTravail-1-decalageM][2]  # G         # C\n                                    b = points[pointTravail+1-decalageM][2]  # D         # C\n                                    c = (((a - b)/x0) + b)                               # C\n                                    points[pointTravail+(i)-decalageM][2] = c            # C\n                                else:\n                                    #############################################             # lissage Gauche Sup\n                                    x1 += 1\n                                    a = points[pointTravail+(x1-x2)-decalageM][2]  # G   # D\n                                    b = points[pointTravail+(x1+x2)-decalageM][2]  # D   # D\n                                    c = (((a - b)/x3) + b)                         # D\n                                    points[pointTravail+(x1)-decalageM][2] = c           # D\n            \n                                    a = points[pointTravail+(-x1-x2)-decalageM][2]  # G  # G\n                                    b = points[pointTravail+(-x1+x2)-decalageM][2]  # D  # G\n                                    c = (((a - b)/x3) + b)                          # G\n                                    points[pointTravail+(-x1)-decalageM][2] = c          # G\n                        except Exception:\n                            App.Console.PrintError(\"Error2 smooting coil num : \"+str(ii)+\"  value : \"+str(lissageS[ii-1])+\"\\n\"+\n                                                   \"Choose a lower smoothing value\"+\"\\n\")\n    \n                App.Console.PrintMessage(\"List Smoot2 \" + str(lissageS)+\"\\n\")\n                App.Console.PrintMessage(\"____________________\"+\"\\n\")\n    \n            ############ Smooting end ##########################################################################################################\n    \n            if typeLine == 1:\n                ressort = Draft.makeWire(points,closed=False,face=False,support=None)# creation spring makeWire\n            else:\n                ressort = Draft.makeBSpline(points,closed=False)               # creation spring Draft \" makeBSpline \" remis pour facilite avec axes\n#                ressortT = Part.BSplineCurve()          ##                    # creation spring Part  \" BSplineCurve \"\n#                ressortT.interpolate(points,False)      ##\n#                ressort = Part.Edge(ressortT)           ##\n#                Part.show(ressort)                      ##\n\n            if (plr != \"xx\") and (len(pointsDirection)!= 0):                   # placement if axis selected\n                pointsDirection.reverse()\n                plr.Base = pointsDirection[-1]#\n                ressort.Placement = plr\n                self.horizontalSlider.setValue(0)\n\n            if nomF != \"Name File\": # name file\n                App.ActiveDocument.ActiveObject.Label =  \"Spring_\" + nomF\n            else:\n                App.ActiveDocument.ActiveObject.Label =  \"Spring (\" + str(rayon) + \" r)\"\n\n            try:\n                FCSpring.addObject(ressort)\n                FCSpring.Label = \"Spring (\" + str(rayon) + \" r)\"\n            except Exception:\n                None\n            FreeCAD.ActiveDocument.recompute()\n    \n            self.PBA_progressBar.setVisible(False)\n            self.PU_Accept_Value.setVisible(True)\n\n            #### Chrono(1) end #################################\n            chrono(1)                 # chrono(1) end         ##\n            ####################################################\n\n        else:\n            App.Console.PrintError(\"Radius zero not allowed do\"+\"\\n\")\n            self.textEdit.setTextColor(QColor(\"red\"))\n            self.textEdit.append(\"Radius zero not allowed do \" )\n            self.textEdit.setTextColor(QColor(\"Base\"))\n####on_PU_Launch end ###################################################################################\n\n    def selectOk(self, val):\n        global switchAdaptRadius\n        global centerFaceOrPoint\n        global sel\n        global vecteurSouris\n        global selectedCircle\n\n        try:\n            sel = FreeCADGui.Selection.getSelectionEx()                                # display the type line selected\n            self.textEdit.append(str(sel[0].SubObjects[0].Curve))\n        except Exception:\n            try:\n                self.textEdit.append(str(sel[0].SubObjects[0].Surface))\n            except Exception:\n                None\n        if val == 1:\n            self.PB_Adapt_Radius.setEnabled(True)\n            self.PB_Adapt_Radius.setStyleSheet(\"QPushButton {background-color: white;\\n\"\n                                               \"border:2px solid rgb(0, 187, 0);}\")     # bord white and green\n            self.PB_Center_Point.setEnabled(True)\n            self.PB_Center_Point.setStyleSheet(\"QPushButton {background-color: white;\\n\"\n                                               \"border:2px solid rgb(0, 187, 0);}\")     # bord white and green\n            if len(sel) == 2:\n                self.CB_Position.setEnabled(True)\n                self.CB_Position.setStyleSheet(\"QCheckBox {background-color: white;\\n\"\n                                               \"border:2px solid rgb(0, 187, 0);}\")     # bord white and green\n            if len(selectedCircle) == 3:\n                self.PB_CreaCircle.setEnabled(True)\n                self.PB_CreaCircle.setStyleSheet(\"QPushButton {background-color: white;\\n\"\n                                               \"border:2px solid rgb(0, 187, 0);}\")     # bord white and green\n            elif len(selectedCircle) > 3:\n                self.PB_CreaCircle.setEnabled(False)\n                self.PB_CreaCircle.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")    # origin system\n                del selectedCircle[:]\n        else:\n            self.PB_Adapt_Radius.setEnabled(False)\n            self.PB_Adapt_Radius.setChecked(False)\n            self.PB_Adapt_Radius.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")      # origin system\n            self.PB_Adapt_Radius.setText(\"Normal\")\n            switchAdaptRadius = 0\n            self.PB_Center_Point.setEnabled(False)\n            self.PB_Center_Point.setChecked(False)\n            self.PB_Center_Point.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")      # origin system\n            self.PB_Center_Point.setText(_fromUtf8(\"Point Mouse\"))\n            centerFaceOrPoint = 0\n            self.CB_Position.setEnabled(False)\n            self.CB_Position.setChecked(False)\n            self.CB_Position.setStyleSheet(\"QCheckBox {background-color: QPalette.Base}\")          # origin system\n            self.PB_CreaCircle.setEnabled(False)\n            self.PB_CreaCircle.setChecked(False)\n            self.PB_CreaCircle.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\")        # origin system\n        switchAdaptRadius = 0\n        self.groupBox_04.setTitle(\"Position (\" + str(len(sel)) + \")\") #(Points: \" + str(len(pointsDirection)) + \")\n\n    def on_CB_05_Position(self):\n        global FCmw\n        global seTPositionFlyRightLeft\n        global seTWidgetPosition\n\n        if seTPositionFlyRightLeft != 1:\n            if self.CB_05_Position.isChecked():\n                FCmw.addDockWidget(QtCore.Qt.LeftDockWidgetArea,myNewFreeCADWidget) # add the widget to the main window Left\n                FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetInt(u\"seTPositionFlyRightLeft\", 3)     #*1, 2, other\n                FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetBool(u\"seTWidgetPosition\", True)       # True or False\n            else:\n                FCmw.addDockWidget(QtCore.Qt.RightDockWidgetArea,myNewFreeCADWidget)# add the widget to the main window Right\n                FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetInt(u\"seTPositionFlyRightLeft\", 2)     #*1, 2, other\n                FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __Title__).SetBool(u\"seTWidgetPosition\", False)      # True or False\n\n    def on_PU_Help(self):\n        try:\n            webbrowser.open(\"http://www.freecadweb.org/wiki/index.php?title=Macro_FCSpring_Helix_Variable\")\n            App.Console.PrintMessage(\"http://www.freecadweb.org/wiki/index.php?title=Macro_FCSpring_Helix_Variable\" + \"\\n\")\n        except Exception:\n            App.Console.PrintMessage(u\"Not access\")\n    \nclass SelObserver:\n    print( \"run..\" )\n    def addSelection(self,document, object, element, position):                # Selection\n        global ui\n        global vecteurSouris\n        global selectedCircle\n\n        vecteurSouris = FreeCAD.Vector(position)\n        selectedCircle.append(vecteurSouris)\n        ff = ui\n        ff.selectOk(1)\n#        App.Console.PrintMessage(\"addSelection\"+\"\\n\")\n    def clearSelection(self,doc):                                              # Si clic sur l'ecran, effacer la selection\n        global ui\n        global selectedCircle\n\n        del selectedCircle[:]\n        ff = ui\n        ff.selectOk(0)\n\ndoc = FreeCAD.ActiveDocument\nif doc == None:\n    doc = FreeCAD.newDocument(__Title__)\n\nhelixS = []\ndel helixS[:]\nhelixS = numberSpires*[pas]\nradiusS = []\ndel radiusS[:]\nradiusS = numberSpires*[rayon]\nlissageS = []\ndel lissageS[:]\nlissageS = numberSpires*[0]\n\ns=SelObserver()\nFreeCADGui.Selection.addObserver(s)          # installe the function in resident mode\n\n#MainWindow = QtWidgets.QMainWindow()\n#MainWindow.setObjectName(__Title__)          # macro internal Name\n#ui = Ui_MainWindow()\n#ui.setupUi(MainWindow)\n#MainWindow.show()\n\nmw = FreeCADGui.getMainWindow()\ndw=mw.findChildren(QtWidgets.QDockWidget)\n\nfor i in dw:\n    if str(i.objectName()) == __Title__:\n        if i.isVisible():\n            i.setVisible(False)\n        else:\n            if seTPositionFlyRightLeft == 1:                 # MainWindow\n                None\n            else:\n                myNewFreeCADWidget = QtWidgets.QDockWidget() # create (restore) a new dockwidget\n                myNewFreeCADWidget.setObjectName(__Title__)\n                ui = Ui_MainWindow()\n                ui.setupUi(myNewFreeCADWidget)\n                FCmw = FreeCADGui.getMainWindow()\n                i.setVisible(True)\n        break\n\nif i.objectName() != __Title__:                              # macro internal Name\n    #\n    #####MainWindow################################################################################\n    if seTPositionFlyRightLeft == 1:                 # MainWindow\n        MainWindow = QtWidgets.QMainWindow()         # create a new window volant\n        MainWindow.setObjectName(__Title__)          # macro internal Name\n        ui = Ui_MainWindow()\n        ui.setupUi(MainWindow)\n        MainWindow.show()\n    #####DockWidget################################################################################\n    #\n    else:\n        myNewFreeCADWidget = QtWidgets.QDockWidget() # create a new dockwidget\n        myNewFreeCADWidget.setObjectName(__Title__)\n        ui = Ui_MainWindow()\n        ui.setupUi(myNewFreeCADWidget)\n        FCmw = FreeCADGui.getMainWindow()\n        if seTPositionFlyRightLeft == 2:             # RightDock\n            FCmw.addDockWidget(QtCore.Qt.RightDockWidgetArea,myNewFreeCADWidget) # add the widget to the main window Right\n        else:                                        # LeftDock\n            FCmw.addDockWidget(QtCore.Qt.LeftDockWidgetArea,myNewFreeCADWidget)  # add the widget to the main window Left\n\n",
    "url": "https://wiki.freecad.org/Macro_FCSpring_Helix_Variable",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/68c81c32a0727a693d3a/raw/91cbf54580d8af331f9b371f4951a40b9ef506f3/Macro_FCSpring_Helix_Variable.FCMacro",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_FCSpring_Helix_Variable",
    "version": "01.19",
    "license": "",
    "date": "2024/07/11",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\FCSpring_Helix_Variable.png",
    "icon_source": "https://wiki.freecad.org/images/6/69/FCSpring_Helix_Variable.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FCSpring On Surface",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro creates a helix (or spring) around a solid object whatever its shape, the helix follows the entire surface of the object (Python2 is required).<br /><br />Macro version: 00.01<br />Last modified: 2024/01/15<br />FreeCAD version: 0.18 and above<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/3/38/FCSpring_On_Surface.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "This macro creates a helix (or spring) around a solid object whatever its shape, the helix follows the entire surface of the object (Python2 is required).",
    "code": "# -*- coding: utf-8 -*-\n#from __future__ import unicode_literals\n#\n\"\"\"\n***************************************************************************\n*   Copyright (c)  2019 2020 2021 2022 2023 2024 <mario52>                *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#Macro_FCSpring On Surface 20/12/2019 /_00 15/01/2024\n#\n#OS: Windows 10 build 19045\n#Word size of FreeCAD: 64-bit\n#Version: 0.22.0dev.35554 (Git)\n#Build type: Release\n#Branch: main\n#Hash: 8e2ab9f76888ac4da971f9d5069cec7bcc2b572f\n#Python 3.10.13, Qt 5.15.8, Coin 4.0.2, Vtk 9.2.6, OCC 7.6.3\n#Locale: French/Mars (fr_MA)\n#\n__title__   = \"FCSpring On Surface\"\n__author__  = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__Wiki__    = \"http://www.freecadweb.org/wiki/index.php?title=FCSpring_On_Surface\"\n__version__ = \"00.01\"\n__date__    = \"2024/01/15\" #YYYY/MM/DD\n\n#original code by wandererfan\n#How to intersect a line with a part\n#http://www.forum.freecadweb.org/viewtopic.php?f=22&t=5456\n\nimport PySide2\nfrom PySide2 import QtGui ,QtCore, QtWidgets\nfrom PySide2.QtGui import *\nfrom PySide2.QtCore import *\n\nimport time\nimport math\nfrom math import sqrt, pi, sin, cos, asin\nimport Draft, Part, FreeCADGui, FreeCAD\nfrom FreeCAD import Base\n\nGui = FreeCADGui\nApp = FreeCAD\n\nglobal ui         ; ui         = \"\"\nglobal lineLength ; lineLength = 0.0  # longueur de la ligne\nglobal noPass     ; noPass     = 1    # switch observer\nglobal detectFace ; detectFace = 0\nglobal sel        ; sel        = \"\"\nglobal objet      ; objet      = \"\"\n\n####chrono################\nimport time\nglobal depart ; depart  = 0.0\nglobal arrivee; arrivee = 0.0\ndef chrono(sec):    # 0=depart autre=stop\n#time.strftime('%X %x %Z')#'15:44:07 12/14/19 Paris, Madrid'\n    global depart\n    global arrivee\n    if sec == 0:\n        depart = time.time()#time.clock()\n        App.Console.PrintMessage(\"Chrono begin   : \"+str(time.strftime('%X'))+\"\\n\")\n    else:\n        arrivee = time.time()#time.clock()\n        App.Console.PrintMessage(\"Chrono end     : \"+str(time.strftime('%X'))+\"\\n\")\n        parcouru = ((arrivee - depart)/60.0)\n        App.Console.PrintError(\"Time execution : \"+str(\"%.3f\" % parcouru)+\" min\"+\"\\n\")\n#    FreeCADGui.updateGui()    \n####chrono################\n\nclass Ui_MainWindow(object):\n\n    def __init__(self ):\n        self.window = MainWindow\n        #self.path  = FreeCAD.ConfigGet(\"AppHomePath\")\n        #self.path  = FreeCAD.ConfigGet(\"UserAppData\")\n        #self.path  = \"your path\"\n#        param = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")# macro path\n#        self.path = param.GetString(\"MacroPath\",\"\") + \"/\"                   # macro path\n#        self.path = self.path.replace(\"\\\\\",\"/\")\n#        print(\"Path for the icons : \" , self.path)\n\n        self.Pas        = 1.0\n        self.Hauteur    = 0.0\n        self.Precision  = 36\n        self.steps      = (360.0 / self.Precision)\n        self.longueurFil= 0.0\n        self.coor_X     = 0.0\n        self.coor_Y     = 0.0\n        self.coor_Z     = 0.0\n\n        self.PointSize     = 8    #heigth text\n\n    def setupUi(self, MainWindow):\n        self.window = MainWindow\n\n        MainWindow.setObjectName(\"MainWindow\")\n        MainWindow.resize(251, 455)\n#        MainWindow.move(1150, 100)                # position window\n\n        self.label_00_Title = QtWidgets.QLabel(MainWindow)\n        self.label_00_Title.setGeometry(QtCore.QRect(20, 5, 226, 16))\n        self.label_00_Title.setObjectName(\"label_00_Title\")\n\n        ####\n        self.GB_00_Configuration = QtWidgets.QGroupBox(MainWindow)\n        self.GB_00_Configuration.setGeometry(QtCore.QRect(15, 25, 186, 126))\n        self.GB_00_Configuration.setObjectName(\"GB_00_Configuration\")\n\n        self.DS_GB_00_01_Pas = QtWidgets.QDoubleSpinBox(self.GB_00_Configuration)\n        self.DS_GB_00_01_Pas.setGeometry(QtCore.QRect(15, 20, 86, 22))\n        self.DS_GB_00_01_Pas.setObjectName(\"DS_GB_00_01_Pas\")\n        self.DS_GB_00_01_Pas.setMaximum(999999)\n        self.DS_GB_00_01_Pas.setValue(self.Pas)\n        self.DS_GB_00_01_Pas.setDecimals(4)\n        self.DS_GB_00_01_Pas.setToolTip(\"The screw pitch (default = 1)\")\n        self.DS_GB_00_01_Pas.valueChanged.connect(self.on_DS_GB_00_01_Pas)\n\n        self.Label_GB_00_01_Pas = QtWidgets.QLabel(self.GB_00_Configuration)\n        self.Label_GB_00_01_Pas.setGeometry(QtCore.QRect(115, 25, 66, 16))\n        self.Label_GB_00_01_Pas.setObjectName(\"Label_GB_00_01_Pas\")\n\n        self.DS_GB_00_02_Hauteur = QtWidgets.QDoubleSpinBox(self.GB_00_Configuration)\n        self.DS_GB_00_02_Hauteur.setGeometry(QtCore.QRect(15, 55, 86, 22))\n        self.DS_GB_00_02_Hauteur.setObjectName(\"DS_GB_00_02_Hauteur\")\n#        self.DS_GB_00_02_Hauteur.setValue()\n        self.DS_GB_00_02_Hauteur.setMaximum(999999)\n        self.DS_GB_00_02_Hauteur.setDecimals(4)\n        self.DS_GB_00_02_Hauteur.setToolTip(\"The height of the shape\" + \"\\n\"\n                                            \"the default height is calculte\" + \"\\n\"\n                                            \"by the max height of the BoundBox\")\n        self.DS_GB_00_02_Hauteur.valueChanged.connect(self.on_DS_GB_00_02_Hauteur)\n\n        self.label_GB_00_02_Hauteur = QtWidgets.QLabel(self.GB_00_Configuration)\n        self.label_GB_00_02_Hauteur.setGeometry(QtCore.QRect(115, 60, 66, 16))\n        self.label_GB_00_02_Hauteur.setObjectName(\"label_GB_00_02_Hauteur\")\n\n        self.SP_GB_00_03_Precision = QtWidgets.QSpinBox(self.GB_00_Configuration)\n        self.SP_GB_00_03_Precision.setGeometry(QtCore.QRect(15, 90, 86, 22))\n        self.SP_GB_00_03_Precision.setObjectName(\"DS_GB_00_03_Precision\")\n        self.SP_GB_00_03_Precision.setValue(self.Precision)\n        self.SP_GB_00_03_Precision.setMaximum(360)\n        self.SP_GB_00_03_Precision.setMinimum(1)\n        self.SP_GB_00_03_Precision.setToolTip(\"The number of points for one turn\" + \"\\n\"\n                                              \"(default = \" + str(self.Precision) + \")\")\n        self.SP_GB_00_03_Precision.valueChanged.connect(self.on_SP_GB_00_03_Precision)\n\n        self.label_GB_00_02_Precision = QtWidgets.QLabel(self.GB_00_Configuration)\n        self.label_GB_00_02_Precision.setGeometry(QtCore.QRect(115, 95, 66, 16))\n        self.label_GB_00_02_Precision.setObjectName(\"label_GB_00_02_Precision\")\n\n        ####\n        self.GB_01_Coordinate = QtWidgets.QGroupBox(MainWindow)\n        self.GB_01_Coordinate.setGeometry(QtCore.QRect(15, 160, 186, 131))\n        self.GB_01_Coordinate.setObjectName(\"GB_01_Coordinate\")\n\n        self.DP_01_01_X = QtWidgets.QDoubleSpinBox(self.GB_01_Coordinate)\n        self.DP_01_01_X.setGeometry(QtCore.QRect(15, 25, 86, 22))\n        self.DP_01_01_X.setObjectName(\"SP_01_01_X\")\n        self.DP_01_01_X.setMaximum(999999)\n        self.DP_01_01_X.setMinimum(-999999)\n        self.DP_01_01_X.setDecimals(4)\n        self.DP_01_01_X.setToolTip(\"The X value of the coordinate\" + \"\\n\"\n                                   \"the default value is calculed\" + \"\\n\"\n                                   \"by the X center BoundBox\") \n        self.DP_01_01_X.valueChanged.connect(self.on_DP_01_01_X)\n\n        self.DP_01_02_Y = QtWidgets.QDoubleSpinBox(self.GB_01_Coordinate)\n        self.DP_01_02_Y.setGeometry(QtCore.QRect(15, 60, 86, 22))\n        self.DP_01_02_Y.setObjectName(\"SP_01_01_Y\")\n        self.DP_01_02_Y.setMaximum(999999)\n        self.DP_01_02_Y.setMinimum(-999999)\n        self.DP_01_02_Y.setDecimals(4)\n        self.DP_01_02_Y.setToolTip(\"The Y value of the coordinate\" + \"\\n\"\n                                   \"the default value is calculed\" + \"\\n\"\n                                   \"by the Y center BoundBox\") \n        self.DP_01_02_Y.valueChanged.connect(self.on_DP_01_02_Y)\n\n        self.DP_01_03_Z = QtWidgets.QDoubleSpinBox(self.GB_01_Coordinate)\n        self.DP_01_03_Z.setGeometry(QtCore.QRect(15, 95, 86, 22))\n        self.DP_01_03_Z.setObjectName(\"SP_01_01_Z\")\n        self.DP_01_03_Z.setMaximum(999999)\n        self.DP_01_03_Z.setMinimum(-999999)\n        self.DP_01_03_Z.setDecimals(4)\n        self.DP_01_03_Z.setToolTip(\"The Z value of the coordinate\" + \"\\n\"\n                                   \"the default value is calculed\" + \"\\n\"\n                                   \"by the Z BoundBox minimum value\") \n        self.DP_01_03_Z.valueChanged.connect(self.on_DP_01_03_Z)\n\n        self.Label_GB_01_01_X = QtWidgets.QLabel(self.GB_01_Coordinate)\n        self.Label_GB_01_01_X.setGeometry(QtCore.QRect(115, 30, 66, 13))\n        self.Label_GB_01_01_X.setObjectName(\"Label_GB_01_01_X\")\n\n        self.Label_GB_01_02_Y = QtWidgets.QLabel(self.GB_01_Coordinate)\n        self.Label_GB_01_02_Y.setGeometry(QtCore.QRect(115, 65, 66, 13))\n        self.Label_GB_01_02_Y.setObjectName(\"Label_GB_01_02_Y\")\n\n        self.Label_GB_01_03_Z = QtWidgets.QLabel(self.GB_01_Coordinate)\n        self.Label_GB_01_03_Z.setGeometry(QtCore.QRect(115, 100, 66, 13))\n        self.Label_GB_01_03_Z.setObjectName(\"Label_GB_01_03_Z\")\n\n        ####\n        self.GB_03_Options = QtWidgets.QGroupBox(MainWindow)\n        self.GB_03_Options.setGeometry(QtCore.QRect(15, 300, 186, 71))\n        self.GB_03_Options.setObjectName(\"GB_03_Options\")\n\n        self.RB_03_00_BSpline = QtWidgets.QRadioButton(self.GB_03_Options)\n        self.RB_03_00_BSpline.setGeometry(QtCore.QRect(10, 20, 71, 18))\n        self.RB_03_00_BSpline.setChecked(True)\n        self.RB_03_00_BSpline.setToolTip(\"BSpline\")\n        self.RB_03_00_BSpline.setObjectName(\"RB_03_00_BSpline\")\n\n        self.RB_03_01_Wire = QtWidgets.QRadioButton(self.GB_03_Options)\n        self.RB_03_01_Wire.setGeometry(QtCore.QRect(100, 20, 71, 18))\n        self.RB_03_01_Wire.setToolTip(\"Wire\")\n        self.RB_03_01_Wire.setObjectName(\"RB_03_01_Wire\")\n\n        self.CB_03_00_Points = QtWidgets.QCheckBox(self.GB_03_Options)\n        self.CB_03_00_Points.setGeometry(QtCore.QRect(10, 45, 71, 18))\n        self.CB_03_00_Points.setToolTip(\"Create one Points in all coordinates\")\n        self.CB_03_00_Points.setObjectName(\"CB_03_00_Points\")\n\n        self.CB_03_01_Reverse = QtWidgets.QCheckBox(self.GB_03_Options)\n        self.CB_03_01_Reverse.setGeometry(QtCore.QRect(100, 45, 71, 18))\n        self.CB_03_01_Reverse.setToolTip(\"Reverse the direction\" + \"\\n\"\n                                         \"Default = counter clockwise\")\n        self.CB_03_01_Reverse.setObjectName(\"CB_03_01_Reverse\")\n\n        self.CB_03_02_Update = QtWidgets.QCheckBox(self.GB_03_Options)\n        self.CB_03_02_Update.setGeometry(QtCore.QRect(170, 45, 18, 18))\n        self.CB_03_02_Update.setObjectName(\"CB_03_02_Update\")\n        self.CB_03_02_Update.setToolTip(\"Display the progress of the operation in the 3D view\")\n\n        ####\n        self.GB_02_Command = QtWidgets.QGroupBox(MainWindow)\n        self.GB_02_Command.setGeometry(QtCore.QRect(15, 380, 186, 61))\n        self.GB_02_Command.setObjectName(\"GB_02_Command\")\n\n        self.PB_02_01_Ok = QtWidgets.QPushButton(self.GB_02_Command)\n        self.PB_02_01_Ok.setGeometry(QtCore.QRect(100, 25, 75, 23))\n        self.PB_02_01_Ok.setObjectName(\"GB_02_01_Ok\")\n        self.PB_02_01_Ok.setToolTip(\"Button Ok\" + \"\\n\"\n                                    \"If on error is created\" + \"\\n\"\n                                    \"the button is coloured in red\" + \"\\n\"\n                                    \"if not the button is coloured in green\")\n        self.PB_02_01_Ok.clicked.connect(self.on_PB_02_01_Ok)\n\n        self.PB_02_02_Quit = QtWidgets.QPushButton(self.GB_02_Command)\n        self.PB_02_02_Quit.setGeometry(QtCore.QRect(10, 25, 75, 23))\n        self.PB_02_02_Quit.setObjectName(\"GB_02_01_Quit\")\n        self.PB_02_02_Quit.setToolTip(\"Quit FCSpring On Surface\")\n        self.PB_02_02_Quit.clicked.connect(self.on_PB_Quit_clicked)\n\n#        section progressBar 1 Green\n        self.progressBar_1_Green = QtWidgets.QProgressBar(MainWindow)\n        self.progressBar_1_Green.setGeometry(QtCore.QRect(210, 30, 30, 411))\n        self.progressBar_1_Green.setValue(0)\n        self.progressBar_1_Green.setOrientation(QtCore.Qt.Vertical)\n        self.progressBar_1_Green.setAlignment(QtCore.Qt.AlignCenter)\n        self.progressBar_1_Green.setObjectName(\"progressBar_1_Green\")\n        self.progressBar_1_Green.setToolTip(\"If the coordinate is erroneous the progressBar is coloured in red\")\n        self.progressBar_1_Green.setStyleSheet(\"QProgressBar {color:black; }\"\n                                               \"QProgressBar:chunk {background-color: #00FF00;}\") # modify the progressBar color \n\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n        MainWindow.setWindowFlags(PySide2.QtCore.Qt.WindowStaysOnTopHint)        # PySide2 cette fonction met la fenetre en avant\n\n    def retranslateUi(self, MainWindow):\n        MainWindow.setWindowTitle(__title__+\" (\"+__version__+\", \"+__date__+\")\")\n        self.label_00_Title.setText(__title__+\" (\"+__version__+\", \"+__date__+\")\")\n\n        self.GB_00_Configuration.setTitle(\"Configuration\")\n        self.Label_GB_00_01_Pas.setText(\"Pas\")\n        self.label_GB_00_02_Hauteur.setText(\"Heigth\")\n        self.label_GB_00_02_Precision.setText(\"Precision\")\n\n        self.GB_01_Coordinate.setTitle(\"Coordinate Begin\")\n        self.Label_GB_01_01_X.setText(\"X\")\n        self.Label_GB_01_02_Y.setText(\"Y\")\n        self.Label_GB_01_03_Z.setText(\"Z\")\n\n        self.GB_03_Options.setTitle(\"Options\")\n        self.RB_03_00_BSpline.setText(\"BSpline\")\n        self.RB_03_01_Wire.setText(\"Wire\")\n        self.CB_03_00_Points.setText(\"Points\")\n        self.CB_03_01_Reverse.setText(\"Reverse\")\n\n        self.GB_02_Command.setTitle(\"Options\")\n        self.GB_02_Command.setTitle(\"Command\")\n        self.PB_02_01_Ok.setText(\"Ok\")\n        self.PB_02_02_Quit.setText(\"Quit\")\n\n    def on_DS_GB_00_01_Pas(self, value):\n        self.Pas = value\n        self.DS_GB_00_01_Pas.setStyleSheet(\"QDoubleSpinBox {background-color: QPalette.Base}\")\n\n    def on_DS_GB_00_02_Hauteur(self, value):\n        self.Hauteur = value\n        self.DS_GB_00_02_Hauteur.setStyleSheet(\"QDoubleSpinBox {background-color: QPalette.Base}\")\n\n    def on_SP_GB_00_03_Precision(self, value):\n        self.Precision = value\n        self.steps = (360.0 / self.Precision)\n        self.SP_GB_00_03_Precision.setStyleSheet(\"QSpinBox {background-color: QPalette.Base}\")\n\n    def on_DP_01_01_X(self, value):\n        self.coor_X = value\n\n    def on_DP_01_02_Y(self, value):\n        self.coor_Y = value\n\n    def on_DP_01_03_Z(self, value):\n        self.coor_Z = value\n\n    def on_PB_02_01_Ok(self):\n        global lineLength\n        global noPass\n        global sel\n        global depart\n        global arrivee\n        global detectFace\n        global objet\n\n        try:\n            if (self.Pas != 0) and (self.Hauteur != 0) and (self.Precision != 0) and (detectFace == 1):\n                chrono(0)\n                noPass     = 0    # switch 0=nopass\n                #sel = FreeCADGui.Selection.getSelection()\n                objetName  = sel[0].Name\n                objetLabel = sel[0].Label\n                objet      = sel[0].Shape\n                z          = 0.0\n                compteur   = 0\n\n                lineDirectrice = Draft.makeWire([FreeCAD.Vector(0.0, 0.0, 0.0),FreeCAD.Vector(lineLength , 0.0, 0.0)])\n                #print(lineDirectrice.Name)\n                if self.CB_03_02_Update.isChecked():\n                    FreeCADGui.ActiveDocument.getObject(lineDirectrice.Name).Visibility = True\n                else:                    \n                    FreeCADGui.ActiveDocument.getObject(lineDirectrice.Name).Visibility = False\n\n                App.ActiveDocument.recompute()\n\n                pl=FreeCAD.Placement()\n                points = []\n        \n                self.progressBar_1_Green.setValue(0)\n                progressMax = (self.Precision * int(self.Hauteur / self.Pas) + 1)\n                self.progressBar_1_Green.setMaximum(progressMax)\n                \n                for sp in range(int(self.Hauteur / self.Pas) + 1):    #nombre de tours\n                    for i in range(0, (360*1000), int(self.steps*1000)):                       #\n                        if self.CB_03_01_Reverse.isChecked():\n                            i = -float(i/1000)                ##Reverse\n                        else:\n                            i = float(i/1000)                 ##Normal\n\n                        compteur += 1\n\n                        pl=App.Placement(App.Vector(self.coor_X, self.coor_Y, z + self.coor_Z), App.Rotation(i,0.0,0.0), App.Vector(0,0,0))\n                        lineDirectrice.Placement = pl\n                        z += (self.Pas / self.Precision)\n                \n                        if z > self.Hauteur:\n                            break\n                \n                        line   = lineDirectrice.Shape\n                        intersection = objet.common(line)    # only for solid object not for face\n                    \n                        try:\n                            coorIntersec = intersection.Vertexes[1].Point\n                            points += [FreeCAD.Vector(coorIntersec[0],coorIntersec[1],coorIntersec[2])]\n                            if self.CB_03_00_Points.isChecked():\n                                Draft.makePoint(coorIntersec[0],coorIntersec[1],coorIntersec[2])\n                        except Exception:\n                            self.progressBar_1_Green.setStyleSheet(\"QProgressBar {color:black; }\"\n                                                \"QProgressBar:chunk {background-color: #FF0000;}\") # modify the progressBar color \n                            self.progressBar_1_Green.setValue(progressMax)\n\n                        ####progressBar\n                        self.progressBar_1_Green.setStyleSheet(\"QProgressBar {color:black; }\"\n                                              \"QProgressBar:chunk {background-color: green;}\")     # modify the progressBar color \n                        self.progressBar_1_Green.setValue(compteur)\n                        ####progressBar\n        \n                        if self.CB_03_02_Update.isChecked():\n                            Gui.updateGui()\n                            App.ActiveDocument.recompute()\n                \n                try:\n                    App.ActiveDocument.removeObject(lineDirectrice.Name)\n                except Exception:\n                    None\n\n                if len(points) != 0:\n                    ##Bspline\n                    if self.RB_03_00_BSpline.isChecked():\n                        BSpline = Draft.makeBSpline(points,closed=False)\n                        #BSpline.Label = objetLabel + \"_BSpline\"\n                        App.ActiveDocument.ActiveObject.Label = objetLabel + \"_BSpline\"\n                        #self.longueurFil =\n                    ##Wire\n                    if self.RB_03_01_Wire.isChecked():\n                        Wire = Draft.makeWire(points,closed=False)\n                        #Wire.Label = objetLabel + \"_Wire\"\n                        App.ActiveDocument.ActiveObject.Label = objetLabel + \"_Wire\"\n                        #self.longueurFil = \n                    self.PB_02_01_Ok.setStyleSheet(\"QPushButton {background-color: green;\\n\"\n                                                   \"border:2px solid rgb( 0, 115,0);}\")\n                else:\n                    self.PB_02_01_Ok.setText(\"K-O\")\n                    self.PB_02_01_Ok.setStyleSheet(\"QPushButton {background-color: red;\\n\"\n                                                   \"border:2px solid rgb(115, 0, 0);}\")\n\n            else:\n                self.PB_02_01_Ok.setStyleSheet(\"QPushButton {background-color: red;\\n\"\n                                               \"border:2px solid rgb(115, 0, 0);}\")\n                if (self.Pas == 0):\n                    self.DS_GB_00_01_Pas.setStyleSheet(\"QDoubleSpinBox {border:2px solid rgb(115, 0, 0);}\")\n                if (self.Hauteur == 0):\n                    self.DS_GB_00_02_Hauteur.setStyleSheet(\"QDoubleSpinBox {border:2px solid rgb(115, 0, 0);}\")\n                if (self.Precision == 0):\n                    self.SP_GB_00_03_Precision.setStyleSheet(\"QSpinBox {border:2px solid rgb(115, 0, 0);}\")\n                \n            FreeCAD.Console.PrintMessage(\"Pas        : \" + str(self.Pas) + \"\\n\")\n            FreeCAD.Console.PrintMessage(\"Hauteur    : \" + str(self.Hauteur) + \"\\n\")\n            FreeCAD.Console.PrintMessage(\"Precision  : \" + str(self.Precision) + \"\\n\")\n            FreeCAD.Console.PrintMessage(\"Coordinate : \" + str(len(points)) + \"\\n\")\n            #FreeCAD.Console.PrintMessage(\"Length     : \" + str(self.longueurFil) + \"\\n\")\n            FreeCAD.Console.PrintMessage(\"coor_X     : \" + str(self.coor_X) + \"\\n\")\n            FreeCAD.Console.PrintMessage(\"coor_Y     : \" + str(self.coor_Y) + \"\\n\")\n            FreeCAD.Console.PrintMessage(\"coor_Z     : \" + str(self.coor_Z) + \"\\n\")\n            chrono(1)\n            FreeCAD.Console.PrintMessage(\"______________________\" + \"\\n\")\n            points = []\n\n        except Exception:\n            self.PB_02_01_Ok.setStyleSheet(\"QSpinBox {background-color: red;\\n\"\n                                           \"border:2px solid rgb(115, 0, 0);}\")\n\n        App.ActiveDocument.recompute()\n        noPass = 1    # switch 1 = pass\n\n        ####################################################################\n        \n    def on_PB_Quit_clicked(self):\n        FreeCADGui.Selection.removeObserver(s)   # Uninstalls resident function (desactivated for read after LeftDock RightDock)\n        self.window.hide()                       # hide the window and close the macro\n        FreeCAD.Console.PrintMessage(\"Quit \" + __title__ + \"\\n\\n\")\n\n##############################################################################\nclass SelObserver:\n    def addSelection(self,document, object, element, position):  # Selection\n        global ui\n        global lineLength\n        global noPass\n        global sel\n        global detectFace\n        global objet\n\n        sel = \"\"\n        ui.progressBar_1_Green.setValue(0)\n        ui.PB_02_01_Ok.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\") # origin system\n        ui.PB_02_01_Ok.setText(\"Ok\")\n        ui.DS_GB_00_01_Pas.setStyleSheet(\"QDoubleSpinBox {background-color: QPalette.Base}\")\n        ui.DS_GB_00_02_Hauteur.setStyleSheet(\"QDoubleSpinBox {background-color: QPalette.Base}\")\n        ui.SP_GB_00_03_Precision.setStyleSheet(\"QSpinBox {background-color: QPalette.Base}\")\n        ui.Label_GB_01_01_X.setText(\"X\")\n        ui.Label_GB_01_02_Y.setText(\"Y\")\n        ui.Label_GB_01_03_Z.setText(\"Z\")\n\n        detectFace = 0\n\n        if (noPass == 1):\n            try:\n                selEx = FreeCADGui.Selection.getSelectionEx()\n                if (noPass == 1) and (hasattr(selEx[0].SubObjects[0],\"Surface\")):\n                    detectFace = 1\n    \n                    ui.DP_01_01_X.setValue(0.0)\n                    ui.DP_01_02_Y.setValue(0.0)\n                    ui.DP_01_03_Z.setValue(0.0)\n        \n                    sel = FreeCADGui.Selection.getSelection()\n        \n                    boundBoxLZ   = sel[0].Shape.BoundBox.ZLength         # Length z boundBox rectangle\n                    ####\n                    boundBoxLL   = sel[0].Shape.BoundBox.DiagonalLength  # Length Diagonal rectangle\n                    ####\n                    boundBoxZMin = sel[0].Shape.BoundBox.ZMin            # coordonate ZMin\n                    ui.Label_GB_01_03_Z.setText(\"Z (\"+str(round(boundBoxZMin,4))+\")\")\n                    ####\n                    boundBoxCenter = sel[0].Shape.BoundBox.Center        # boundBox Center\n                    ####\n        \n                    ui.Label_GB_01_01_X.setText(\"X BBCenter\")\n                    ui.Label_GB_01_02_Y.setText(\"Y BBCenter\")\n                    ui.Label_GB_01_03_Z.setText(\"Z Lowermost\")\n        \n                    ui.DP_01_01_X.setValue(boundBoxCenter[0])   # BBcenter X\n                    ui.DP_01_02_Y.setValue(boundBoxCenter[1])   # BBcenter Y\n                    ui.DP_01_03_Z.setValue(boundBoxZMin)        # point le plus bas\n        \n                    self.Hauteur = boundBoxLZ\n                    ui.DS_GB_00_02_Hauteur.setValue(self.Hauteur)\n                    lineLength = boundBoxLL\n            except Exception:\n                None\n##############################################################################\n\ns=SelObserver()\nFreeCADGui.Selection.addObserver(s) # install the function resident mode\n\nMainWindow = QtWidgets.QWidget()    #PySide2\nui = Ui_MainWindow()\nui.setupUi(MainWindow)\nMainWindow.show()",
    "url": "https://wiki.freecad.org/Macro_FCSpring_On_Surface",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=FCSpring_On_Surface",
    "version": "00.01",
    "license": "",
    "date": "2024/01/15",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\FCSpring_On_Surface.png",
    "icon_source": "https://wiki.freecad.org/images/3/38/FCSpring_On_Surface.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Geodesic Dome",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro creates a parametric geodesic dome shell. The dome radius and the frequency parameter will be set at creation time.<br /><br />Macro version: 02.00<br />Last modified: 2019-03-24<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/File:Macro_Geodesic_Dome.svg\">ToolBar Icon</a><br />Author: Ulrich Brammer, DeepSOIC, galou<br /> ",
    "comment": "This macro creates a parametric geodesic dome shell. The dome radius and the frequency parameter will be set at creation time.",
    "code": "# ************************************************************************\n# * Copyright (c)2015 Ulrich Brammer <ulrich1a[at]users.sourceforge.net> *\n# *                                                                      *\n# * This file is a supplement to the FreeCAD CAx development system.     *\n# *                                                                      *\n# * This program is free software; you can redistribute it and/or modify *\n# * it under the terms of the GNU Lesser General Public License (LGPL)   *\n# * as published by the Free Software Foundation; either version 2 of    *\n# * the License, or (at your option) any later version.                  *\n# * for detail see the LICENCE text file.                                *\n# *                                                                      *\n# * This software is distributed in the hope that it will be useful,     *\n# * but WITHOUT ANY WARRANTY; without even the implied warranty of       *\n# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *\n# * GNU Library General Public License for more details.                 *\n# *                                                                      *\n# * You should have received a copy of the GNU Library General Public    *\n# * License along with this macro; if not, write to the Free Software    *\n# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 *\n# * USA                                                                  *\n# *                                                                      *\n# ************************************************************************\n\n\nimport math\nimport sys\n\nfrom PySide import QtCore, QtGui\n\nimport FreeCAD as app\nimport FreeCADGui as gui\nimport Part\n\n\ndef makeDomeShape(domeRad, ny):\n    #semi-global variables\n    a = 0 #Strutlength of underlying icosahedron:\n    icoFaces = [] # collects faces of the underlying icosahedron\n    domeFaces = [] # collects the faces of the geodesic dome\n\n    def makeFreqFaces(fPt, sPt, thPt, ny = 1):\n        # makes the geodesic dome faces out of the points of an\n        # icosahedron triangle\n        b = a/ny # length of frequent triangles\n        # definition of direction vectors\n        growVec = (sPt - fPt)\n        # growVec = (fPt - sPt)\n        growVec.multiply(1 / ny)\n        crossVec = (thPt - sPt)\n        # crossVec = (sPt - thPt)\n        crossVec.multiply(1 / ny)\n\n        for k in range(ny):\n            kThirdPt = fPt + growVec * (k + 0)\n            dThirdPt = app.Vector(kThirdPt.x, kThirdPt.y, kThirdPt.z)\n            dThirdPt = dThirdPt.normalize().multiply(domeRad)\n            kSecPt = fPt + growVec * (k + 1)\n            dSecPt = app.Vector(kSecPt.x, kSecPt.y, kSecPt.z)\n            dSecPt = dSecPt.normalize().multiply(domeRad)\n            # thirdEdge = Part.makeLine(kSecPt, kThirdPt)\n            # thirdEdge = Part.makeLine(dSecPt, dThirdPt)\n            for l in range(k + 1):\n                firstPt = kSecPt + crossVec *(l + 1)\n                dFirstPt = firstPt.normalize().multiply(domeRad)\n                secPt = kSecPt + crossVec *(l + 0)\n                dSecPt = secPt.normalize().multiply(domeRad)\n                thirdPt = kThirdPt + crossVec *(l + 0)\n                dThirdPt = thirdPt.normalize().multiply(domeRad)\n                #thirdEdge = Part.makeLine(secPt, thirdPt)\n                thirdEdge = Part.makeLine(dSecPt, dThirdPt)\n                # Part.show(thirdEdge)\n                if l > 0:\n                    # What to do here?\n                    #secEdge = Part.makeLine(oThirdPt,thirdPt)\n                    secEdge = Part.makeLine(doThirdPt, dThirdPt)\n                    # Part.show(secEdge)\n                    #thirdEdge = Part.makeLine(secPt, thirdPt)\n                    #thirdEdge = Part.makeLine(dSecPt, dThirdPt)\n                    # Part.show(thirdEdge)\n                    triWire = Part.Wire([firstEdge, secEdge, thirdEdge])\n                    # Part.show(triWire)\n                    triFace = Part.Face(triWire)\n                    domeFaces.append(triFace)\n                    #Part.show(triFace)\n\n                oThirdPt = thirdPt\n                doThirdPt = oThirdPt.normalize().multiply(domeRad)\n                # oFirstPt = firstPt\n                #firstEdge = Part.makeLine(thirdPt,firstPt)\n                firstEdge = Part.makeLine(dThirdPt, dFirstPt)\n                oFirstEdge = firstEdge\n                #secEdge = Part.makeLine(firstPt,secPt)\n                secEdge = Part.makeLine(dFirstPt,dSecPt)\n                #Part.show(firstEdge)\n                #Part.show(secEdge)\n                #Part.show(thirdEdge)\n                triWire = Part.Wire([firstEdge, secEdge, thirdEdge])\n                triFace = Part.Face(triWire)\n                domeFaces.append(triFace)\n                #Part.show(triFace)\n\n    a = (4 * domeRad) / math.sqrt(2 * math.sqrt(5) + 10)\n\n    # icoAngle: angle of vertices of icosahedron points\n    # not a north or south pole\n    icoAngle = math.atan(0.5)\n\n    icoLat = domeRad * math.sin(icoAngle)\n    latRad = domeRad * math.cos(icoAngle)\n    ang36 = math.radians(36)\n\n    # Calculation all points of the icosahedron\n    icoPts = []\n    icoPts.append(app.Vector(0, 0, domeRad))\n\n    for i in range(10):\n        icoCos = latRad * math.cos(i * ang36)\n        icoSin = latRad * math.sin(i * ang36)\n        if i % 2 == 0:\n            icoPts.append(app.Vector(icoSin, icoCos, icoLat))\n        else:\n            icoPts.append(app.Vector(icoSin, icoCos, -icoLat))\n\n    icoPts.append(app.Vector(0, 0, -domeRad))\n\n    # making the faces of the icosahedron\n    thirdPt = icoPts[9]\n    thirdEdge = Part.makeLine(icoPts[0], thirdPt)\n    for i in range(5):\n        j = i * 2 + 1\n        firstEdge = Part.makeLine(thirdPt, icoPts[j])\n        secEdge = Part.makeLine(icoPts[j], icoPts[0])\n        triWire = Part.Wire([firstEdge, secEdge, thirdEdge])\n        triFace = Part.Face(triWire)\n        icoFaces.append(triFace)\n        # Part.show(triFace)\n        makeFreqFaces(icoPts[j], icoPts[0], thirdPt, ny)\n\n        thirdEdge = Part.makeLine(icoPts[0], icoPts[j])\n        thirdPt = icoPts[j]\n\n    thirdPt = icoPts[9]\n    secPt = icoPts[10]\n    thirdEdge = Part.makeLine(secPt,thirdPt)\n\n    for i in range(10):\n        j = i + 1\n        firstEdge = Part.makeLine(thirdPt, icoPts[j])\n        secEdge = Part.makeLine(icoPts[j], secPt)\n        triWire = Part.Wire([firstEdge, secEdge, thirdEdge])\n        triFace = Part.Face(triWire)\n        icoFaces.append(triFace)\n        #Part.show(triFace)\n        makeFreqFaces(icoPts[j], secPt, thirdPt, ny)\n\n        thirdPt = secPt\n        secPt = icoPts[j]\n        thirdEdge = Part.makeLine(secPt, thirdPt)\n\n    thirdPt = icoPts[10]\n    thirdEdge = Part.makeLine(icoPts[11], thirdPt)\n    for i in range(5):\n        j = i * 2 + 2\n        firstEdge = Part.makeLine(thirdPt, icoPts[j])\n        secEdge = Part.makeLine(icoPts[j], icoPts[11])\n        triWire = Part.Wire([firstEdge, secEdge, thirdEdge])\n        triFace = Part.Face(triWire)\n        icoFaces.append(triFace)\n        #Part.show(triFace)\n        makeFreqFaces(icoPts[j], icoPts[11], thirdPt, ny)\n\n        thirdEdge = Part.makeLine(icoPts[11], icoPts[j])\n        thirdPt = icoPts[j]\n\n    # Shell of a corresponding icosahedron\n    newShell = Part.Shell(icoFaces)\n    #Part.show(newShell)\n\n    # Shell of the geodesic dome\n    #domeShell = Part.Shell(domeFaces)\n    #Part.show(domeShell)\n    return Part.Shell(domeFaces)\n\n    # Shere with radius of geodesic dome for debugging purposes\n    # testSphere = Part.makeSphere(domeRad)\n    #Part.show(testSphere)\n\ndef tr(context, text):\n    try:\n        _encoding = QtGui.QApplication.UnicodeUTF8\n        return QtGui.QApplication.translate(context, text, None, _encoding)\n    except AttributeError:\n        return QtGui.QApplication.translate(context, text, None)\n\n\ndef say(s):\n    app.Console.PrintMessage(str(s) + '\\n')\n\n\nclass Ui_Dialog:\n    def setupUi(self, Dialog):\n        Dialog.setObjectName(\"GeodesicDome\")\n        self.dia = Dialog\n        self.gridLayoutWidget = QtGui.QWidget(Dialog)\n        self.gridLayoutWidget.setObjectName(\"gridLayoutWidget\")\n        self.gridLayout = QtGui.QGridLayout(self.gridLayoutWidget)\n        #self.gridLayout.setContentsMargins(0, 0, 0, 0)\n        self.gridLayout.setObjectName(\"gridLayout\")\n\n        self.labelHelp = QtGui.QLabel(self.gridLayoutWidget)\n        self.labelHelp.setObjectName('labelHelp')\n        self.gridLayout.addWidget(self.labelHelp, 0, 0, 1, 2)\n\n        self.labelDomeRadius = QtGui.QLabel(self.gridLayoutWidget)\n        self.labelDomeRadius.setObjectName('labelDomeRadius')\n        self.gridLayout.addWidget(self.labelDomeRadius, 1, 0)\n        fui = gui.UiLoader()\n        self.lineEditRadius = fui.createWidget('Gui::InputField')\n        self.lineEditRadius.setObjectName('lineEditRadius')\n        self.gridLayout.addWidget(self.lineEditRadius, 1, 1)\n\n        self.labelFrequency = QtGui.QLabel(self.gridLayoutWidget)\n        self.labelFrequency.setObjectName('labelFrequency')\n        self.gridLayout.addWidget(self.labelFrequency, 2, 0)\n        self.lineEditFreq = QtGui.QLineEdit(self.gridLayoutWidget)\n        self.lineEditFreq.setObjectName('lineEditFreq')\n        self.gridLayout.addWidget(self.lineEditFreq, 2, 1)\n\n        self.labelType = QtGui.QLabel(self.gridLayoutWidget)\n        self.labelType.setObjectName('labelType')\n        self.gridLayout.addWidget(self.labelType, 3, 0)\n        self.typesWidget = QtGui.QWidget(self.gridLayoutWidget)\n        layoutType = QtGui.QVBoxLayout(self.typesWidget)\n        self.radioSolid = QtGui.QRadioButton()\n        self.radioShell = QtGui.QRadioButton()\n        self.radioWireframe = QtGui.QRadioButton()\n        self.radioVertices = QtGui.QRadioButton()\n        layoutType.addWidget(self.radioSolid)\n        layoutType.addWidget(self.radioShell)\n        layoutType.addWidget(self.radioWireframe)\n        layoutType.addWidget(self.radioVertices)\n        self.radioSolid.setChecked(True)\n        self.gridLayout.addWidget(self.typesWidget, 3, 1)\n\n        self.buttonBox = QtGui.QDialogButtonBox(self.gridLayoutWidget)\n        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)\n        self.buttonBox.setStandardButtons \\\n            (QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)\n        self.buttonBox.setObjectName(\"buttonBox\")\n        self.gridLayout.addWidget(self.buttonBox, 4, 1)\n\n        self.retranslateUi(Dialog)\n        self.buttonBox.accepted.connect(self.makeSomething)\n        self.buttonBox.rejected.connect(self.makeNothing)\n\n    def retranslateUi(self, Dialog):\n        Dialog.setWindowTitle(tr('GeodesicDome', 'Geodesic Dome Creator'))\n        self.labelDomeRadius.setText(tr('GeodesicDome', 'Dome Radius'))\n        self.labelFrequency.setText(tr('GeodesicDome',\n                                       'Frequency Parameter\\n(Integer between 1 to 10)'))\n        self.labelHelp.setText(tr('GeodesicDome',\n                                  'This Macro creates \\na full geodesic dome shell.\\nX-Y-symmetry plane \\nfor even frequencies'))\n        self.labelType.setText(tr('GeodesicDome', 'Type'))\n        self.radioSolid.setText(tr('GeodesicDome', 'Solid'))\n        self.radioShell.setText(tr('GeodesicDome', 'Shell'))\n        self.radioWireframe.setText(tr('GeodesicDome', 'Wireframe'))\n        self.radioVertices.setText(tr('GeodesicDome', 'Vertices'))\n\n    def makeSomething(self):\n        say('Accepted! Dome radius: {} with frequency {}'.format(\n           self.lineEditRadius.property(\"text\"),\n           int(self.lineEditFreq.text())))\n\n        doc = app.activeDocument()\n        if doc is None:\n            doc = app.newDocument()\n        theDome = GeodesicDome(doc).host\n        theDome.Radius = app.Units.Quantity(self.lineEditRadius.property('text'))\n        theDome.FrequencyParameter = int(self.lineEditFreq.text())\n        if self.radioSolid.isChecked():\n            theDome.ShapeType = 'Solid'\n        elif self.radioShell.isChecked():\n            theDome.ShapeType = 'Shell'\n        elif self.radioWireframe.isChecked():\n            theDome.ShapeType = 'Wireframe'\n        elif self.radioVertices.isChecked():\n            theDome.ShapeType = 'Vertices'\n\n        self.dia.close()\n        doc.recompute()\n\n    def makeNothing(self):\n        say('Rejected!')\n        self.dia.close()\n\n\ndef showDialog():\n    d = QtGui.QWidget()\n    d.ui = Ui_Dialog()\n    d.ui.setupUi(d)\n    d.ui.lineEditFreq.setText('2')\n    d.ui.lineEditRadius.setProperty('text', '2 m')\n\n    d.show()\n\n\nclass GeodesicDome:\n    def __init__(self, doc):\n        host = doc.addObject('Part::FeaturePython', 'GeoDome')\n        self.host = host\n        host.Proxy = self\n\n        VPGeodesicDome(host.ViewObject)\n\n        host.addProperty('App::PropertyLength', 'Radius', 'Geodesic Dome', '')\n        host.addProperty('App::PropertyInteger', 'FrequencyParameter', 'Geodesic Dome', 'Frequency Parameter (integer, 1 to 10). If even, the dome is symmetric against XY plane.')\n        host.addProperty('App::PropertyEnumeration', 'ShapeType', 'Geodesic Dome', '')\n        host.ShapeType = ['Solid', 'Shell', 'Wireframe', 'Vertices']\n\n    def execute(self, host):\n        shell = makeDomeShape(host.Radius.getValueAs('mm'), host.FrequencyParameter)\n        if host.ShapeType == 'Solid':\n            host.Shape = Part.Solid(shell)\n        elif host.ShapeType == 'Shell':\n            host.Shape = shell\n        elif host.ShapeType == 'Wireframe':\n            host.Shape = Part.Compound(shell.Edges)\n        elif host.ShapeType == 'Vertices':\n            host.Shape = Part.Compound(shell.Vertexes)\n        else:\n            assert(False)\n\n    def __getstate__(self):\n        return None\n\n    def __setstate__(self, state):\n        return None\n\n\nclass VPGeodesicDome:\n    def __init__(self, host):\n        host.Proxy = self\n\n    def __getstate__(self):\n        return None\n\n    def __setstate__(self, state):\n        return None\n",
    "url": "https://wiki.freecad.org/Macro_Geodesic_Dome",
    "raw_code_url": "https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/master/ParametricObjectCreation/geodesic_dome/geodesic_dome.py",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2019-03-24",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Ulrich Brammer, DeepSOIC, galou",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Geodesic_Dome.svg",
    "icon_source": "https://wiki.freecad.org//images/5/55/Macro_Geodesic_Dome.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Guitar fretboard",
    "on_wiki": true,
    "on_git": false,
    "desc": "Create Guitar fretboard.<br />Guitar Fretboard Maker (Macro), Python script is unbelievable to make complex form....<br />This macro creates a conical compound (or not) multiscale (or not) fretboard with nut and fret slot or zero fret slot to export to CAM software<br /><br />Macro version: 0.4<br />Last modified: 2020-01-09<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/b/be/Macro_Guitar_fretboard.png\">ToolBar Icon</a><br />Author: ryback08, jsiddall<br /> ",
    "comment": "Create Guitar fretboard.",
    "code": "# -*- coding: utf-8 -*-\n\n# Form implementation generated from reading ui file 'dialog.ui'\n#\n# Created: Sat Jan 14 00:33:37 2012\n#      by: PyQt4 UI code generator 4.9\n#      \n# WARNING! All changes made in this file will be lost!\n#\n#\n###################################### FREECAD Macro - Draw fretboard guitar #############################################\n# ressource :                                                                                                            #\n# Freecad dialog creation : http://sourceforge.net/apps/mediawiki/free-cad/index.php?title=Dialog_creation               #\n# Topological data scripting : http://sourceforge.net/apps/mediawiki/free-cad/index.php?title=Topological_data_scripting #\n# Fret slot theory : http://www.jpbourgeois.org/guitar/frets.htm                                                         #\n#                                                                                                                        #\n# For personal use only and / or non-profit use                                                                          #\n# (C)2012 By LEPINE Florent                                                                                              #\n# (C)2020 By Jeff Siddall                                                                                                #\n# V0.1  -  2012/03/18                                                                                                    #\n# V0.2  -  2018/01/25 : PySide                                                                                           #\n# V0.3  -  2019/07/03 : Adaptation for 0.18                                                                              #\n# V0.4  -  2020/01/08 : Major refactor to add multiscale frets and zerofret (Jeff Siddall)                               #\n# Special thanks to FreeCAD team                                                                                         #\n#                                                                                                                        #\n##########################################################################################################################\n#                                                                                                                        #\n#  ### English ###                                                                                                       #\n#  This macro creates a conical compound (or not) multiscale (or not) fretboard with nut and fret slot to export to      #\n#  CAM software                                                                                                          #\n#                                                                                                                        #\n#  ### Francais ###                                                                                                      #\n#  Cette macro creer une touche a radius progressif (ou pas) avec les defonces du sillet et l'emplacement des frettes    #\n#  afin d'etre exporter dans un module de parcourt d'outil CAM                                                           #\n#                                                                                                                        #\n##########################################################################################################################\n#                                                                                                                        #\n#  ### Extra Notes ###                                                                                                   #\n#  All Y-axis measurements are relative to fretboard centerline                                                          #\n#  Origin is middle of nut/zero fret                                                                                     #\n#                                                                                                                        #\n##########################################################################################################################\n\n\n\nfrom PySide import QtCore, QtGui\nimport FreeCAD, Part, math\nfrom FreeCAD import Base, Vector\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    _fromUtf8 = lambda s: s\n\n\n\n   ################################################################################################\n   #########                                begin functions                                ########\n   ################################################################################################\n\n# Function to return the X-value for a given fret\ndef fretx(fret, scalelen, offset):\n    xvalue = (scalelen * (1 - (0.5 ** (float(fret) / 12)))) + offset\n\n    return(xvalue)\n\n\n# Function to return the neck edge Y-value for a given X value\ndef edgey(xvalue, nutwidth, edgetan):\n    yvalue = (xvalue * edgetan) + (nutwidth / 2)\n\n    return(yvalue)\n\n\n# Function to return the fret X-axis crossing value for a given fret\ndef fretxcross(fret, scalelen1, scalelen2, perpscalediff):\n    offset = perpscalediff / 2\n    fret1x = fretx(fret, scalelen1, offset)   \n    fret2x = fretx(fret, scalelen2, -offset)\n    xcross = (fret1x + fret2x) / 2\n\n    return(xcross)\n\n\n# Function to return the fret angle tangent for a given fret\ndef frettan(fret, scalelen1, scalelen2, perpscalediff, nutwidth, edgetan):\n    offset = perpscalediff / 2\n    fret1x = fretx(fret, scalelen1, offset)   \n    fret2x = fretx(fret, scalelen2, -offset)\n    tanval = (fret2x - fret1x) / (nutwidth + (edgetan * (fret2x + fret1x)))\n\n    return(tanval)\n\n\n\n   ################################################################################################\n   ######### begin of dialog box definition / debut de la definition de la boite de dialogue ######\n   ################################################################################################\n\n\nclass Ui_Dialog(object):\n    def setupUi(self, Dialog):\n        Dialog.setObjectName(_fromUtf8(\"Dialog\"))\n        Dialog.resize(600, 491)\n        self.label_zerofret = QtGui.QLabel(Dialog)\n        self.label_zerofret.setGeometry(QtCore.QRect(10, 10, 431, 24))\n        self.label_zerofret.setToolTip(_fromUtf8(\"Use a zero fret instead of a nut when checked\"))\n        self.label_zerofret.setWhatsThis(_fromUtf8(\"\"))\n        self.label_zerofret.setObjectName(_fromUtf8(\"label_zerofret\"))\n        self.checkBox_zerofret = QtGui.QCheckBox(Dialog)\n        self.checkBox_zerofret.setGeometry(QtCore.QRect(460, 10, 51, 24))\n        self.checkBox_zerofret.setWhatsThis(_fromUtf8(\"\"))\n        self.checkBox_zerofret.setObjectName(_fromUtf8(\"checkBox_zerofret\"))\n        self.label_scalelen1 = QtGui.QLabel(Dialog)\n        self.label_scalelen1.setGeometry(QtCore.QRect(10, 30, 431, 24))\n        self.label_scalelen1.setToolTip(_fromUtf8(\"\"))\n        self.label_scalelen1.setWhatsThis(_fromUtf8(\"\"))\n        self.label_scalelen1.setObjectName(_fromUtf8(\"label_scalelen1\"))\n        self.lineEdit_scalelen1 = QtGui.QLineEdit(Dialog)\n        self.lineEdit_scalelen1.setGeometry(QtCore.QRect(460, 30, 51, 24))\n        self.lineEdit_scalelen1.setWhatsThis(_fromUtf8(\"\"))\n        self.lineEdit_scalelen1.setObjectName(_fromUtf8(\"lineEdit_scalelen1\"))\n        self.label_scalelen2 = QtGui.QLabel(Dialog)\n        self.label_scalelen2.setGeometry(QtCore.QRect(10, 50, 431, 24))\n        self.label_scalelen2.setToolTip(_fromUtf8(\"\"))\n        self.label_scalelen2.setWhatsThis(_fromUtf8(\"\"))\n        self.label_scalelen2.setObjectName(_fromUtf8(\"label_scalelen2\"))\n        self.lineEdit_scalelen2 = QtGui.QLineEdit(Dialog)\n        self.lineEdit_scalelen2.setGeometry(QtCore.QRect(460, 50, 51, 24))\n        self.lineEdit_scalelen2.setWhatsThis(_fromUtf8(\"\"))\n        self.lineEdit_scalelen2.setObjectName(_fromUtf8(\"lineEdit_scalelen2\"))\n        self.label_nutwidth = QtGui.QLabel(Dialog)\n        self.label_nutwidth.setGeometry(QtCore.QRect(10, 130, 431, 24))\n        self.label_nutwidth.setToolTip(_fromUtf8(\"Width of center of outside strings measured perpendicular to the neck where the middle of the nut/zero fret crosses the neck centerline.\"))\n        self.label_nutwidth.setObjectName(_fromUtf8(\"label_nutwidth\"))\n        self.lineEdit_nutwidth = QtGui.QLineEdit(Dialog)\n        self.lineEdit_nutwidth.setGeometry(QtCore.QRect(460, 130, 51, 24))\n        self.lineEdit_nutwidth.setObjectName(_fromUtf8(\"lineEdit_nutwidth\"))\n        self.lineEdit_nutradius = QtGui.QLineEdit(Dialog)\n        self.lineEdit_nutradius.setGeometry(QtCore.QRect(460, 190, 51, 24))\n        self.lineEdit_nutradius.setObjectName(_fromUtf8(\"lineEdit_nutradius\"))\n        self.label_nutradius = QtGui.QLabel(Dialog)\n        self.label_nutradius.setGeometry(QtCore.QRect(10, 190, 431, 24))\n        self.label_nutradius.setToolTip(_fromUtf8(\"Measured where the middle of the nut/zero fret crosses the neck centerline.  To convert to mm from inches multiply by 25.4.  Ex: 7.5 in = 191 mm.\"))\n        self.label_nutradius.setObjectName(_fromUtf8(\"label_nutradius\"))\n        self.lineEdit_perpfret = QtGui.QLineEdit(Dialog)\n        self.lineEdit_perpfret.setGeometry(QtCore.QRect(460, 110, 51, 24))\n        self.lineEdit_perpfret.setObjectName(_fromUtf8(\"lineEdit_perpfret\"))\n        self.label_perpfret = QtGui.QLabel(Dialog)\n        self.label_perpfret.setGeometry(QtCore.QRect(10, 110, 431, 24))\n        self.label_perpfret.setToolTip(_fromUtf8(\"\"))\n        self.label_perpfret.setObjectName(_fromUtf8(\"label_perpfret\"))\n        self.lineEdit_bridgewidth = QtGui.QLineEdit(Dialog)\n        self.lineEdit_bridgewidth.setGeometry(QtCore.QRect(460, 150, 51, 24))\n        self.lineEdit_bridgewidth.setObjectName(_fromUtf8(\"lineEdit_bridgewidth\"))\n        self.label_bridgewidth = QtGui.QLabel(Dialog)\n        self.label_bridgewidth.setGeometry(QtCore.QRect(10, 150, 431, 24))\n        self.label_bridgewidth.setToolTip(_fromUtf8(\"Width of center of outside strings measured perpendicular to the neck where the middle of the bridge crosses the neck centerline at the saddles.\"))\n        self.label_bridgewidth.setObjectName(_fromUtf8(\"label_bridgewidth\"))\n        self.lineEdit_bridgeradius = QtGui.QLineEdit(Dialog)\n        self.lineEdit_bridgeradius.setGeometry(QtCore.QRect(460, 210, 51, 24))\n        self.lineEdit_bridgeradius.setObjectName(_fromUtf8(\"lineEdit_bridgeradius\"))\n        self.label_bridgeradius = QtGui.QLabel(Dialog)\n        self.label_bridgeradius.setGeometry(QtCore.QRect(10, 210, 431, 24))\n        self.label_bridgeradius.setToolTip(_fromUtf8(\"Measured at neck centerline at saddles. To convert to mm from inches multiply by 25.4.  Ex: 25 in = 635 mm.\"))\n        self.label_bridgeradius.setObjectName(_fromUtf8(\"label_bridgeradius\"))\n        self.label_thicknessboard = QtGui.QLabel(Dialog)\n        self.label_thicknessboard.setGeometry(QtCore.QRect(10, 90, 431, 24))\n        self.label_thicknessboard.setToolTip(_fromUtf8(\"\"))\n        self.label_thicknessboard.setObjectName(_fromUtf8(\"label_thicknessboard\"))\n        self.lineEdit_thicknessboard = QtGui.QLineEdit(Dialog)\n        self.lineEdit_thicknessboard.setGeometry(QtCore.QRect(460, 90, 51, 24))\n        self.lineEdit_thicknessboard.setObjectName(_fromUtf8(\"lineEdit_thicknessboard\"))\n        self.label_nfret = QtGui.QLabel(Dialog)\n        self.label_nfret.setGeometry(QtCore.QRect(10, 70, 431, 24))\n        self.label_nfret.setToolTip(_fromUtf8(\"\"))\n        self.label_nfret.setObjectName(_fromUtf8(\"label_nfret\"))\n        self.lineEdit_nfret = QtGui.QLineEdit(Dialog)\n        self.lineEdit_nfret.setGeometry(QtCore.QRect(460, 70, 51, 24))\n        self.lineEdit_nfret.setObjectName(_fromUtf8(\"lineEdit_nfret\"))\n        self.label_fretslotdepth = QtGui.QLabel(Dialog)\n        self.label_fretslotdepth.setGeometry(QtCore.QRect(10, 270, 431, 24))\n        self.label_fretslotdepth.setToolTip(_fromUtf8(\"\"))\n        self.label_fretslotdepth.setObjectName(_fromUtf8(\"label_fretslotdepth\"))\n        self.lineEdit_fretslotdepth = QtGui.QLineEdit(Dialog)\n        self.lineEdit_fretslotdepth.setGeometry(QtCore.QRect(460, 270, 51, 24))\n        self.lineEdit_fretslotdepth.setObjectName(_fromUtf8(\"lineEdit_fretslotdepth\"))\n        self.lineEdit_fretslotwidth = QtGui.QLineEdit(Dialog)\n        self.lineEdit_fretslotwidth.setGeometry(QtCore.QRect(460, 290, 51, 24))\n        self.lineEdit_fretslotwidth.setObjectName(_fromUtf8(\"lineEdit_fretslotwidth\"))\n        self.label_fretslotwidth = QtGui.QLabel(Dialog)\n        self.label_fretslotwidth.setGeometry(QtCore.QRect(10, 290, 431, 24))\n        self.label_fretslotwidth.setToolTip(_fromUtf8(\"\"))\n        self.label_fretslotwidth.setObjectName(_fromUtf8(\"label_fretslotwidth\"))\n        self.label_fretslotmargin = QtGui.QLabel(Dialog)\n        self.label_fretslotmargin.setGeometry(QtCore.QRect(10, 310, 431, 24))\n        self.label_fretslotmargin.setToolTip(_fromUtf8(\"\"))\n        self.label_fretslotmargin.setObjectName(_fromUtf8(\"label_fretslotmargin\"))\n        self.lineEdit_fretslotmargin = QtGui.QLineEdit(Dialog)\n        self.lineEdit_fretslotmargin.setGeometry(QtCore.QRect(460, 310, 51, 24))\n        self.lineEdit_fretslotmargin.setObjectName(_fromUtf8(\"lineEdit_fretslotmargin\"))\n        self.label_nutslotwidth = QtGui.QLabel(Dialog)\n        self.label_nutslotwidth.setGeometry(QtCore.QRect(10, 350, 431, 24))\n        self.label_nutslotwidth.setToolTip(_fromUtf8(\"Nut thickness.  Not used when zerofret is selected.\"))\n        self.label_nutslotwidth.setObjectName(_fromUtf8(\"label_nutslotwidth\"))\n        self.lineEdit_nutslotwidth = QtGui.QLineEdit(Dialog)\n        self.lineEdit_nutslotwidth.setGeometry(QtCore.QRect(460, 350, 51, 24))\n        self.lineEdit_nutslotwidth.setObjectName(_fromUtf8(\"lineEdit_nutslotwidth\"))\n        self.label_nutslotdepth = QtGui.QLabel(Dialog)\n        self.label_nutslotdepth.setGeometry(QtCore.QRect(10, 370, 431, 24))\n        self.label_nutslotdepth.setToolTip(_fromUtf8(\"Bottom of nut slot is flat\"))\n        self.label_nutslotdepth.setObjectName(_fromUtf8(\"label_nutslotdepth\"))\n        self.lineEdit_nutslotdepth = QtGui.QLineEdit(Dialog)\n        self.lineEdit_nutslotdepth.setGeometry(QtCore.QRect(460, 370, 51, 24))\n        self.lineEdit_nutslotdepth.setObjectName(_fromUtf8(\"lineEdit_nutslotdepth\"))\n        self.lineEdit_lastfretlen = QtGui.QLineEdit(Dialog)\n        self.lineEdit_lastfretlen.setGeometry(QtCore.QRect(460, 170, 51, 24))\n        self.lineEdit_lastfretlen.setObjectName(_fromUtf8(\"lineEdit_lastfretlen\"))\n        self.label_lastfretlen = QtGui.QLabel(Dialog)\n        self.label_lastfretlen.setGeometry(QtCore.QRect(10, 170, 431, 24))\n        self.label_lastfretlen.setToolTip(_fromUtf8(\"\"))\n        self.label_lastfretlen.setObjectName(_fromUtf8(\"label_lastfretlen\"))\n        self.lineEdit_lengthbeforenut = QtGui.QLineEdit(Dialog)\n        self.lineEdit_lengthbeforenut.setGeometry(QtCore.QRect(460, 390, 51, 24))\n        self.lineEdit_lengthbeforenut.setObjectName(_fromUtf8(\"lineEdit_lengthbeforenut\"))\n        self.label_lengthbeforenut = QtGui.QLabel(Dialog)\n        self.label_lengthbeforenut.setGeometry(QtCore.QRect(10, 390, 431, 24))\n        self.label_lengthbeforenut.setToolTip(_fromUtf8(\"\"))\n        self.label_lengthbeforenut.setObjectName(_fromUtf8(\"label_lengthbeforenut\"))\n        self.label_stringmargin1 = QtGui.QLabel(Dialog)\n        self.label_stringmargin1.setGeometry(QtCore.QRect(10, 230, 431, 24))\n        self.label_stringmargin1.setToolTip(_fromUtf8(\"Distance from edge of fretboard measured perpendicular to neck centerline for scale length 1\"))\n        self.label_stringmargin1.setObjectName(_fromUtf8(\"label_stringmargin1\"))\n        self.lineEdit_stringmargin1 = QtGui.QLineEdit(Dialog)\n        self.lineEdit_stringmargin1.setGeometry(QtCore.QRect(460, 230, 51, 24))\n        self.lineEdit_stringmargin1.setObjectName(_fromUtf8(\"lineEdit_stringmargin1\"))\n        self.label_stringmargin2 = QtGui.QLabel(Dialog)\n        self.label_stringmargin2.setGeometry(QtCore.QRect(10, 250, 431, 24))\n        self.label_stringmargin2.setToolTip(_fromUtf8(\"Distance from edge of fretboard measured perpendicular to neck centerline for scale length 2\"))\n        self.label_stringmargin2.setObjectName(_fromUtf8(\"label_stringmargin2\"))\n        self.lineEdit_stringmargin2 = QtGui.QLineEdit(Dialog)\n        self.lineEdit_stringmargin2.setGeometry(QtCore.QRect(460, 250, 51, 24))\n        self.lineEdit_stringmargin2.setObjectName(_fromUtf8(\"lineEdit_stringmargin2\"))\n        self.OK = QtGui.QPushButton(Dialog)\n        self.OK.setGeometry(QtCore.QRect(263, 450, 75, 32))\n        self.OK.setObjectName(_fromUtf8(\"OK\"))\n        self.label_mm_01 = QtGui.QLabel(Dialog)\n        self.label_mm_01.setGeometry(QtCore.QRect(520, 30, 30, 24))\n        self.label_mm_01.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_01.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_01.setObjectName(_fromUtf8(\"label_mm_01\"))\n        self.label_mm_02 = QtGui.QLabel(Dialog)\n        self.label_mm_02.setGeometry(QtCore.QRect(520, 90, 30, 24))\n        self.label_mm_02.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_02.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_02.setObjectName(_fromUtf8(\"label_mm_02\"))\n        self.label_mm_03 = QtGui.QLabel(Dialog)\n        self.label_mm_03.setGeometry(QtCore.QRect(520, 170, 30, 24))\n        self.label_mm_03.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_03.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_03.setObjectName(_fromUtf8(\"label_mm_03\"))\n        self.label_mm_04 = QtGui.QLabel(Dialog)\n        self.label_mm_04.setGeometry(QtCore.QRect(520, 130, 30, 24))\n        self.label_mm_04.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_04.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_04.setObjectName(_fromUtf8(\"label_mm_04\"))\n        self.label_mm_05 = QtGui.QLabel(Dialog)\n        self.label_mm_05.setGeometry(QtCore.QRect(520, 270, 30, 24))\n        self.label_mm_05.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_05.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_05.setObjectName(_fromUtf8(\"label_mm_05\"))\n        self.label_mm_06 = QtGui.QLabel(Dialog)\n        self.label_mm_06.setGeometry(QtCore.QRect(520, 290, 30, 24))\n        self.label_mm_06.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_06.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_06.setObjectName(_fromUtf8(\"label_mm_06\"))\n        self.label_mm_07 = QtGui.QLabel(Dialog)\n        self.label_mm_07.setGeometry(QtCore.QRect(520, 310, 30, 24))\n        self.label_mm_07.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_07.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_07.setObjectName(_fromUtf8(\"label_mm_07\"))\n        self.label_mm_08 = QtGui.QLabel(Dialog)\n        self.label_mm_08.setGeometry(QtCore.QRect(520, 350, 30, 24))\n        self.label_mm_08.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_08.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_08.setObjectName(_fromUtf8(\"label_mm_08\"))\n        self.label_mm_09 = QtGui.QLabel(Dialog)\n        self.label_mm_09.setGeometry(QtCore.QRect(520, 370, 30, 24))\n        self.label_mm_09.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_09.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_09.setObjectName(_fromUtf8(\"label_mm_09\"))\n        self.label_mm_10 = QtGui.QLabel(Dialog)\n        self.label_mm_10.setGeometry(QtCore.QRect(520, 390, 30, 24))\n        self.label_mm_10.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_10.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_10.setObjectName(_fromUtf8(\"label_mm_10\"))\n        self.label_mm_11 = QtGui.QLabel(Dialog)\n        self.label_mm_11.setGeometry(QtCore.QRect(520, 150, 30, 24))\n        self.label_mm_11.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_11.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_11.setObjectName(_fromUtf8(\"label_mm_11\"))\n        self.label_mm_12 = QtGui.QLabel(Dialog)\n        self.label_mm_12.setGeometry(QtCore.QRect(520, 50, 30, 24))\n        self.label_mm_12.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_12.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_12.setObjectName(_fromUtf8(\"label_mm_12\"))\n        self.label_mm_13 = QtGui.QLabel(Dialog)\n        self.label_mm_13.setGeometry(QtCore.QRect(520, 230, 30, 24))\n        self.label_mm_13.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_13.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_13.setObjectName(_fromUtf8(\"label_mm_13\"))\n        self.label_mm_14 = QtGui.QLabel(Dialog)\n        self.label_mm_14.setGeometry(QtCore.QRect(520, 190, 80, 24))\n        self.label_mm_14.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_14.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_14.setObjectName(_fromUtf8(\"label_mm_14\"))\n        self.label_mm_15 = QtGui.QLabel(Dialog)\n        self.label_mm_15.setGeometry(QtCore.QRect(520, 210, 80, 24))\n        self.label_mm_15.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_15.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_15.setObjectName(_fromUtf8(\"label_mm_15\"))\n        self.label_mm_16 = QtGui.QLabel(Dialog)\n        self.label_mm_16.setGeometry(QtCore.QRect(520, 250, 80, 24))\n        self.label_mm_16.setToolTip(_fromUtf8(\"\"))\n        self.label_mm_16.setWhatsThis(_fromUtf8(\"\"))\n        self.label_mm_16.setObjectName(_fromUtf8(\"label_mm_16\"))\n\n        self.dialog = Dialog  ### Add to close windows at end of macro\n\n\n\n        self.retranslateUi(Dialog)\n        QtCore.QObject.connect(self.OK,QtCore.SIGNAL(\"pressed()\"),self.createFretboard)    ###### See Freecad doc - connect pushbuton #####\n        QtCore.QMetaObject.connectSlotsByName(Dialog)\n        Dialog.setTabOrder(self.checkBox_zerofret, self.lineEdit_scalelen1)\n        Dialog.setTabOrder(self.lineEdit_scalelen1, self.lineEdit_scalelen2)\n        Dialog.setTabOrder(self.lineEdit_scalelen2, self.lineEdit_nfret)\n        Dialog.setTabOrder(self.lineEdit_nfret, self.lineEdit_thicknessboard)\n        Dialog.setTabOrder(self.lineEdit_thicknessboard, self.lineEdit_perpfret)\n        Dialog.setTabOrder(self.lineEdit_perpfret, self.lineEdit_nutwidth)\n        Dialog.setTabOrder(self.lineEdit_nutwidth, self.lineEdit_bridgewidth)\n        Dialog.setTabOrder(self.lineEdit_bridgewidth, self.lineEdit_lastfretlen)\n        Dialog.setTabOrder(self.lineEdit_lastfretlen, self.lineEdit_nutradius)\n        Dialog.setTabOrder(self.lineEdit_nutradius, self.lineEdit_bridgeradius)\n        Dialog.setTabOrder(self.lineEdit_bridgeradius, self.lineEdit_stringmargin1)\n        Dialog.setTabOrder(self.lineEdit_stringmargin1, self.lineEdit_stringmargin2)\n        Dialog.setTabOrder(self.lineEdit_stringmargin2, self.lineEdit_fretslotdepth)\n        Dialog.setTabOrder(self.lineEdit_fretslotdepth, self.lineEdit_fretslotwidth)\n        Dialog.setTabOrder(self.lineEdit_fretslotwidth, self.lineEdit_fretslotmargin)\n        Dialog.setTabOrder(self.lineEdit_fretslotmargin, self.lineEdit_nutslotwidth)\n        Dialog.setTabOrder(self.lineEdit_nutslotwidth, self.lineEdit_nutslotdepth)\n        Dialog.setTabOrder(self.lineEdit_nutslotdepth, self.lineEdit_lengthbeforenut)\n        Dialog.setTabOrder(self.lineEdit_lengthbeforenut, self.OK)\n\n\n\n\n    def retranslateUi(self, Dialog):\n        Dialog.setWindowTitle(_fromUtf8(\"Multiscale Compound Fretboard Maker\"))\n        self.label_zerofret.setText(_fromUtf8(\"Use zero fret - Utilisez z\" + chr(233) + \"ro frette\"))\n        self.checkBox_zerofret.setChecked(True)\n        self.label_scalelen1.setText(_fromUtf8(\"Scale Length 1 - Diapason 1\"))\n        self.lineEdit_scalelen1.setText(_fromUtf8(\"864\"))\n        self.label_scalelen2.setText(_fromUtf8(\"Scale Length 2 - Diapason 2\"))\n        self.lineEdit_scalelen2.setText(_fromUtf8(\"940\"))\n        self.label_nutwidth.setText(_fromUtf8(\"Nut outer string width\"))\n        self.lineEdit_nutwidth.setText(_fromUtf8(\"38\"))\n        self.label_nutradius.setText(_fromUtf8(\"Radius at nut - Rayon au sillet\"))\n        self.lineEdit_nutradius.setText(_fromUtf8(\"191\"))\n        self.label_perpfret.setText(_fromUtf8(\"Perpendicular fret - Frette perpendiculaire\"))\n        self.lineEdit_perpfret.setText(_fromUtf8(\"7\"))\n        self.label_bridgewidth.setText(_fromUtf8(\"Bridge outer string width\"))\n        self.lineEdit_bridgewidth.setText(_fromUtf8(\"72\"))\n        self.label_bridgeradius.setText(_fromUtf8(\"Radius at bridge - Rayon au pont\"))\n        self.lineEdit_bridgeradius.setText(_fromUtf8(\"635\"))\n        self.label_thicknessboard.setText(_fromUtf8(\"Board thickness - Epaisseur de touche\"))\n        self.lineEdit_thicknessboard.setText(_fromUtf8(\"6.4\"))\n        self.label_nfret.setText(_fromUtf8(\"No. frets - No. de frettes\"))\n        self.lineEdit_nfret.setText(_fromUtf8(\"20\"))\n        self.label_fretslotdepth.setText(_fromUtf8(\"Depth of fret slot - Pronfondeur rainure de frette\"))\n        self.lineEdit_fretslotdepth.setText(_fromUtf8(\"2.0\"))\n        self.label_fretslotwidth.setText(_fromUtf8(\"Width of fret slot - Largeur rainure de frette\"))\n        self.lineEdit_fretslotwidth.setText(_fromUtf8(\"0.6\"))\n        self.label_fretslotmargin.setText(_fromUtf8(\"Fret slot margin - Marge de fente de frette\"))\n        self.lineEdit_fretslotmargin.setText(_fromUtf8(\"3.0\"))\n        self.label_nutslotwidth.setText(_fromUtf8(\"Width of nut slot - largeur du sillet\"))\n        self.lineEdit_nutslotwidth.setText(_fromUtf8(\"3.1\"))\n        self.label_nutslotdepth.setText(_fromUtf8(\"Depth of nut slot - profondeur du sillet\"))\n        self.lineEdit_nutslotdepth.setText(_fromUtf8(\"3.0\"))\n        self.label_lastfretlen.setText(_fromUtf8(\"Length after last fret - D\" + chr(233) + \"port apr\" + chr(232) + \"s la derni\" + chr(232) + \"re frette\"))\n        self.lineEdit_lastfretlen.setText(_fromUtf8(\"10.0\"))\n        self.label_lengthbeforenut.setText(_fromUtf8(\"Length before zero fret/nut - D\" + chr(233) + \"port avant le sillet\"))\n        self.lineEdit_lengthbeforenut.setText(_fromUtf8(\"6.4\"))\n        self.label_stringmargin1.setText(_fromUtf8(\"String margin 1 - Marge de cha\" + chr(238) + \" ne 1\"))\n        self.lineEdit_stringmargin1.setText(_fromUtf8(\"4.1\"))\n        self.label_stringmargin2.setText(_fromUtf8(\"String margin 2 - Marge de cha\" + chr(238) + \" ne 2\"))\n        self.lineEdit_stringmargin2.setText(_fromUtf8(\"5.1\"))\n        self.OK.setText(_fromUtf8(\"Create\"))\n        self.label_mm_01.setText(_fromUtf8(\"mm\"))\n        self.label_mm_02.setText(_fromUtf8(\"mm\"))\n        self.label_mm_03.setText(_fromUtf8(\"mm\"))\n        self.label_mm_04.setText(_fromUtf8(\"mm\"))\n        self.label_mm_05.setText(_fromUtf8(\"mm\"))\n        self.label_mm_06.setText(_fromUtf8(\"mm\"))\n        self.label_mm_07.setText(_fromUtf8(\"mm\"))\n        self.label_mm_08.setText(_fromUtf8(\"mm\"))\n        self.label_mm_09.setText(_fromUtf8(\"mm\"))\n        self.label_mm_10.setText(_fromUtf8(\"mm\"))\n        self.label_mm_11.setText(_fromUtf8(\"mm\"))\n        self.label_mm_12.setText(_fromUtf8(\"mm\"))\n        self.label_mm_13.setText(_fromUtf8(\"mm\"))\n        self.label_mm_14.setText(_fromUtf8(\"mm\"))\n        self.label_mm_15.setText(_fromUtf8(\"mm\"))\n        self.label_mm_16.setText(_fromUtf8(\"mm\"))\n\n\n    ############################################################################################\n    ######### end of dialog box definition / fin de la definition de la boite de dialogue ######\n    ############################################################################################\n\n\n    def createFretboard(self):\n        try:\n            #################################################################\n            ####### first we check if valid numbers have been entered #######\n            #################################################################\n            scalelen1 = float(self.lineEdit_scalelen1.text())\t\t\t                # diapason\n            scalelen2 = float(self.lineEdit_scalelen2.text())\t\t\t                # diapason\n            nutradius = float(self.lineEdit_nutradius.text())\t\t\t\t            # radius de la touche au sillet\n            bridgewidth = float(self.lineEdit_bridgewidth.text())\t\t\t            # largeur de la touche a la derniere frette\n            bridgeradius = float(self.lineEdit_bridgeradius.text())\t\t\t            # radius de la touche a la derniere frette\n            thicknessboard = float(self.lineEdit_thicknessboard.text())\t\t            # epaisseur de la touche\n            nfret = int(self.lineEdit_nfret.text())                                     # nombre de frettes\n            perpfret = float(self.lineEdit_perpfret.text())                             # perpendicular fret\n            fretslotdepth = float(self.lineEdit_fretslotdepth.text())\t\t            # profondeur du solt des frettes\n            fretslotwidth = float(self.lineEdit_fretslotwidth.text())                   # epaisseur du slot des frettes\n            fretmargin = float(self.lineEdit_fretslotmargin.text())                     # deport du slot des frettes par rapport au bord\n            lastfretlen = float(self.lineEdit_lastfretlen.text())                       # espace entre la derniere frette et la fin de la touche\n            lengthbeforenut = float(self.lineEdit_lengthbeforenut.text())\t            # espace restant avant le sillet\n            stringmargin1 = float(self.lineEdit_stringmargin1.text())                   # string margin\n            stringmargin2 = float(self.lineEdit_stringmargin2.text())                   # string margin\n            nutwidth = float(self.lineEdit_nutwidth.text())\t\t\t                    # largeur de la touche au sillet\n            nutslotwidth = float(self.lineEdit_nutslotwidth.text())                     # longueur du sille\n            nutslotdepth = float(self.lineEdit_nutslotdepth.text())                     # profondeur du sillet\n\n\n        except ValueError:\n            print( \"Error! values must be valid numbers!\")\n            return None\n\n\n        else:\n            if self.checkBox_zerofret.checkState() == 0:\n                zerofret = 0\n                nutslotwidth = float(nutslotwidth)\n            else:\n                zerofret = 1\n                nutslotwidth = 0.0\n\n            ##### convert all value in float #####\n            scalelen1 = float(scalelen1)\n            scalelen2 = float(scalelen2)\n            nutwidth = float(nutwidth)\n            nutradius = float(nutradius)\n            bridgewidth = float(bridgewidth)\n            bridgeradius = float(bridgeradius)\n            thicknessboard = float(thicknessboard)\n            nfret = float(nfret)\n            perpfret = float(perpfret)\n            fretslotdepth = float(fretslotdepth)\n            fretslotwidth = float(fretslotwidth)\n            fretmargin = float(fretmargin)\n            nutslotdepth = float(nutslotdepth)\n            lastfretlen = float(lastfretlen)\n            lengthbeforenut = float(lengthbeforenut)\n            stringmargin1 = float(stringmargin1)\n            stringmargin2 = float(stringmargin2)\n            print( \"OK, all values are good, let's go\")\n\n\n            #####################################################################\n            ######     calculate first/last/perpendicular fret values      ######\n            #####################################################################\n\n            perplen1 = fretx(perpfret, scalelen1, 0)                                    # see formule to calculate fret length\n            perplen2 = fretx(perpfret, scalelen2, 0)\n            perpscalediff = perplen2 - perplen1\n            halfperpscalediff = perpscalediff / 2\n            fbwidthdiff = bridgewidth - nutwidth\n            edgetan = fbwidthdiff / ((scalelen1 + scalelen2) / 2) / 2                   # half of fbwidthdiff is on each side of fretboard\n            zerofrettan = frettan(0, scalelen1, scalelen2, perpscalediff, nutwidth, edgetan)\n            endfrettan = frettan(nfret, scalelen1, scalelen2, perpscalediff, nutwidth, edgetan)\n\n\n            ########################################################################\n            print(\"1 - Create fretboard bottom\")\n            ########################################################################\n\n\n            ########                   Fretboard Vector                       ######\n            vnb1x = fretx(0, scalelen1, halfperpscalediff) - (zerofrettan * stringmargin1) # use fret angle and X value of the zero fret to find new X value with stringmargin\n            vnb1y = edgey(vnb1x, nutwidth, edgetan) + stringmargin1                     # use new X value to find the Y value\n            vnb1 = Vector(vnb1x, vnb1y, 0)\n\n            vbb1x = fretx(nfret, scalelen1, halfperpscalediff) - (endfrettan * stringmargin1) + lastfretlen\n            #vbb1x = fretx(nfret, scalelen1, halfperpscalediff)\n            vbb1y = edgey(vbb1x, nutwidth, edgetan) + stringmargin1\n            vbb1 = Vector(vbb1x, vbb1y, 0)\n\n            vbb2x = fretx(nfret, scalelen2, -halfperpscalediff) + (endfrettan * stringmargin2) + lastfretlen\n            #vbb2x = fretx(nfret, scalelen2, -halfperpscalediff) \n            vbb2y = -edgey(vbb2x, nutwidth, edgetan) - stringmargin2\n            vbb2 = Vector(vbb2x, vbb2y, 0)\n\n            vnb2x = fretx(0, scalelen2, -halfperpscalediff) + (zerofrettan * stringmargin2)\n            vnb2y = -edgey(vnb2x, nutwidth, edgetan) - stringmargin2\n            vnb2 = Vector(vnb2x, vnb2y, 0)\n\n\n            ########                      Nut Vector                          ######\n            adjnutslotwidth = nutslotwidth / math.cos(math.atan(zerofrettan))           # if nut slot is on an angle its X values need to be corrected\n            nutx = -(lengthbeforenut + adjnutslotwidth)                                 # nut is a linear negative x shift\n            vbnb1x = vnb1x + nutx                                                       # add to the end of the fretboard\n            vbnb1y = edgey(vbnb1x, nutwidth, edgetan) + stringmargin1\n            vbnb1 = Vector(vbnb1x, vbnb1y, 0)\n\n            vbnb2x = vnb2x + nutx\n            vbnb2y = -edgey(vbnb2x, nutwidth, edgetan) - stringmargin2\n            vbnb2 = Vector(vbnb2x, vbnb2y, 0)\n\n            ########                         Draw                             ######\n            pointslist = [vbnb1,vnb1,vbb1,vbb2,vnb2,vbnb2,vbnb1]\n            fretboardwire = Part.makePolygon(pointslist)\n            #Part.show(fretboardwire)\n            fretboardbottom = Part.Face(fretboardwire)\n            #Part.show(fretboardbottom)\n            fbextrude=fretboardbottom.extrude(Vector(0,0,thicknessboard*2))\n            #Part.show(fbextrude)\n\n            ########################################################################\n            print(\"2 - Create fretboard top (radius)\")\n            ########################################################################\n\n            ########################  radius at nut   ##############################\n            # the fretboard top must extend beyond the nut to ensure there is no clipping\n            # so calculate the values for the end of the fretboard relative to the nut\n            radslope = (bridgeradius - nutradius) / ((scalelen1 + scalelen2) / 2)       # Find the slope of the compound radius\n            minx = min(vbnb1x, vbnb2x)                                                  # position the end of the fretboard top at the minimum X value\n            cn1rad = nutradius + (minx * radslope)                                      # Calculate the correct radius for the end of the fretboard\n            cn1 = Part.makeCircle(cn1rad, Vector(minx, 0, -cn1rad + thicknessboard), Vector(1,0,0), 70, 110)\n            #Part.show(cn1)\n\n            ################## radius at bridge - rayon au pont #####################\n            cn2 = Part.makeCircle(bridgeradius, Vector(((scalelen1 + scalelen2) / 2), 0, -bridgeradius + thicknessboard), Vector(1,0,0), 70, 110)\n            #Part.show(cn2)\n\n            ################## face of 2 radius - assemblage des 2 radius ###########\n            compradius = Part.makeRuledSurface(cn1, cn2)\n            #Part.show(compradius)\n            ftextrude=compradius.extrude(Vector(0,0,-(thicknessboard * 2)))\n            #Part.show(ftextrude)\n\n\n            ########################################################################\n            print(\"3 - Regroup fretboard bottom & top\")\n            ########################################################################\n            cleanfretboard = ftextrude.common(fbextrude)\n            #Part.show(cleanfretboard)\n\n            if zerofret:\n                ########################################################################\n                print(\"4 - Skipping nut because zerofret was selected\")\n                print(\"5 - Skipping nut because zerofret was selected\")\n                ########################################################################\n\n            else:\n                ########################################################################\n                print(\"4 - Make nut\")\n                ########################################################################\n                ########                      Nut Vector                          ######\n                vnt1x = -(bridgewidth * zerofrettan)                                    # nut crosses centerline at x=0, y=0 and nut slot needs to be wider than fretboard (i.e.: bridgewidth)\n                vnt1 = Vector(vnt1x, bridgewidth, thicknessboard)\n                vnt2 = Vector(-vnt1x, -bridgewidth, thicknessboard)\n                vnt3x = -vnt1x - adjnutslotwidth\n                vnt3 = Vector(vnt3x, -bridgewidth, thicknessboard)\n                vnt4x = vnt1x - adjnutslotwidth\n                vnt4 = Vector(vnt4x, bridgewidth, thicknessboard)\n\n                ########                     Draw nut                             ######\n                pointslist = [vnt1,vnt2,vnt3,vnt4,vnt1]\n                nutwire = Part.makePolygon(pointslist)\n                nutface = Part.Face(nutwire)\n                nutextrude=nutface.extrude(Vector(0,0,-nutslotdepth))\n                #Part.show(nutextrude)\n\n                ########################################################################\n                print(\"5 - Add nut\")\n                ########################################################################\n                fretboardnut = cleanfretboard.cut(nutextrude)\n                #Part.show(fretboardnut)\n \n\n            ########################################################################\n            print(\"6 - Add \" + str(int(nfret)) + \" frets\")\n            ########################################################################\n\n\n            #####################################################################\n            ##############   Radius on fretboard - depth fret slot   ############\n            #####################################################################\n            fretslotradius=compradius.extrude(Vector(0,0,-fretslotdepth))          # radius (top of fretboard) minus fret slot depth \n\n\n            #####################################################################\n            ##############   outline fretboard - margin fret slot    ############\n            #####################################################################\n            vnb1fs = Vector(vbnb1x, (vbnb1y - fretmargin), 0)                           # use the fretboard dimensions as a starting point since the same slope will be used\n            vbb1fs = Vector(vbb1x, (vbb1y - fretmargin), 0)\n            vbb2fs = Vector(vbb2x, (vbb2y + fretmargin), 0)\n            vnb2fs = Vector(vbnb2x, (vbnb2y + fretmargin), 0)\n            pointslistfs = [vnb1fs,vbb1fs,vbb2fs,vnb2fs,vnb1fs]\n            fretboardwirefs = Part.makePolygon(pointslistfs)\n            #Part.show(fretboardwirefs)\n            fretboardbottomfs = Part.Face(fretboardwirefs)\n            #Part.show(fretboardbottomfs)\n            fbextrudefs=fretboardbottomfs.extrude(Vector(0,0,thicknessboard*2))    # fretboardbottom with margin\n            #Part.show(fbextrudefs)\n\n            i=0\n            incnfret = 0\n\n            if (zerofret):\n                incnfret = -1                                                           # use a zero fret if enabled\n\n\n            while (incnfret < nfret):                                                   # draw all frets\n                incnfret = incnfret + 1                 \n                incxcross = fretxcross(incnfret, scalelen1, scalelen2, perpscalediff)\n                incfrettan = frettan(incnfret, scalelen1, scalelen2, perpscalediff, nutwidth, edgetan)\n                incfretangle = math.atan(incfrettan)\n\n                print(\"      Fret \" + str(incnfret) + \": \" + str(round(incxcross,2)) + \" mm at \" + str(round(math.degrees(incfretangle),1)) + \" degrees\")\n\n                adjfretslotwidth = fretslotwidth/math.cos(incfretangle) / 2             # adjust for fret slot being on an angle\n\n                #####################################################################\n                ##############             Fret slot ne X                ############\n                #####################################################################         \n\n                # make slots much larger than required (i.e.: twice the bridgewidth) initially, then cut later\n                fretend1x = incxcross - (incfrettan * bridgewidth)\n                fretend2x = incxcross + (incfrettan * bridgewidth)\n                vnfs1 = Vector((fretend1x - adjfretslotwidth), bridgewidth, 0)\n                vnfs2 = Vector((fretend1x + adjfretslotwidth), bridgewidth, 0)\n                vnfs3 = Vector((fretend2x + adjfretslotwidth), -bridgewidth, 0)\n                vnfs4 = Vector((fretend2x - adjfretslotwidth), -bridgewidth, 0)\n                pointslistvnfs = [vnfs1,vnfs2,vnfs3,vnfs4,vnfs1]\n                nslotwire = Part.makePolygon(pointslistvnfs)\n                nslotextrude = Part.Face(nslotwire)\n                 \n                while (i < 1 ):\n                    i = i + 1  \n                    nslot = nslotextrude.extrude(Vector(0,0,thicknessboard*2))\n                else:\n                    nslot2 = nslotextrude.extrude(Vector(0,0,thicknessboard*2))\n                    nslot = nslot.fuse(nslot2) \n                \n            else:\n\n                nslot3 = fbextrudefs.common(nslot)                                      # assembling all part (radius, bottom and fret)\n                nslot4 = fretslotradius.common(nslot3)\n\n                if zerofret:\n                    nslot5 = cleanfretboard.cut(nslot4)    \n                else:\n                    nslot5 = fretboardnut.cut(nslot4)    \n\n                #Part.show(fretboardfinal)\n                objet_fretboard = App.ActiveDocument.addObject(\"Part::Feature\",\"Fretboard\")\n                objet_fretboard.Shape = nslot5\n\n                print(\"End of fretboard\")\n\n                  \n            ########################################################################\n            print(\"6 - Add Scale Length\")\n            ########################################################################\n            Plane_scale_length = Part.makePlane(thicknessboard * 2 , (bridgewidth + (stringmargin1 + stringmargin2)), Vector(((scalelen1 + scalelen2) / 2), ((bridgewidth / 2) + ((stringmargin1 + stringmargin2) /2)),0), Vector(1,0,0)) #makePlane(length,width,[start_pnt,dir_normal])\n            #Part.show (Plane_scale_length)\n            objet_diapason = App.ActiveDocument.addObject(\"Part::Feature\",\"Scale/Diapason\")\n            objet_diapason.Shape = Plane_scale_length\n\n\n            ###### close windows when macro is done #####\n            self.dialog.hide()\n\n\nclass Fretboard():\n    if App.ActiveDocument is None :                                                     # create new document called 'Fretboard' if no document is open\n        doc = App.newDocument(\"Fretboard\")\n    dialog = QtGui.QWidget() \n    dialog.ui = Ui_Dialog()\n    dialog.ui.setupUi(dialog)\n    dialog.show()",
    "url": "https://wiki.freecad.org/Macro_Guitar_fretboard",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2020-01-09",
    "src_filename": "",
    "filename_from_url": "",
    "author": "ryback08, jsiddall",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Guitar_fretboard.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/b/be/Macro_Guitar_fretboard.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Guitar Nut",
    "on_wiki": true,
    "on_git": false,
    "desc": "Create <a rel=\"nofollow\" class=\"external text\" href=\"https://wikipedia.org/wiki/Guitar#Nut\">guitar nuts</a>.<br />FreeCAD macro that will create complex guitar nut shapes.<br />Specifically it can create a nut with the bottom of the string slots at the desired height above a fretboard of the desired radius. The diameter of each string is configurable and the slots can be configured to account for the width needed to prevent binding. See the <a href=\"#Usage\">Usage</a> section for more details.<br /><br />Macro version: 0.1<br />Last modified: 2020-01-27<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/9/94/Macro_Guitar_Nut.png\">ToolBar Icon</a><br />Author: jsiddall<br /> ",
    "comment": "This macro creates a guitar/bass nut",
    "code": "# FreeCAD Guitar Nut Macro\n# This macro creates a guitar/bass nut with conical slots at the\n# desired spacing and diameter to export to CAM software \n\n__Name__ = 'Guitar Nut'\n__Comment__ = 'This macro creates a guitar/bass nut'\n__Author__ = 'Jeff Siddall'\n__Version__ = '0.1'\n__Date__ = '2020-01-27'\n__License__ = 'GPL-3.0-or-later'\n__Web__ = ''\n__Wiki__ = ''\n__Icon__ = 'https://wiki.freecad.org/images/9/94/Macro_Guitar_Nut.png'\n__Help__ = 'Macro file must be edited with the desired nut parameters before use'\n__Status__ = 'Beta'\n__Requires__ = ''\n__Communication__ = ''\n__Files__ = ''\n\nimport FreeCAD, Part, math\nfrom FreeCAD import Base, Vector\n\nclass Nut():\n    if App.ActiveDocument is None:\n        # Create new document called \"Nut\" if there is no open document\n        doc = App.newDocument(\"Nut\")\n\n# Enter desired values below\n# Unless specified, units are mm\nequalcenters = 0 # If equalcenters = 1 then the spacing of the strings is equal; if 0 then the space between the strings is equal\nstrings = 5 # Number of strings\n\n# Always enter values below with a decimal point, even if that means adding \".0\" on the end!\nlength = 49.0 # Nut length (neck width); 38.1 mm = 1.5\", 41.275 = 1-5/8\"\nwidth = 6.350 # Nut width; 3.175 mm = 1/8\"; 6.35 mm = 1/4\"\nfretboardmaxheight = 6.350 # Maximum fretboard height above the bottom of the nut slot; 6.35 mm = 1/4\"\nradius = 184.15 # Fretboard radius; 184.15 mm = 7.25\"; 304.8 = 12\"; 406.4 mm = 16\"\n# List of string thicknesses, starting at bottom string, separated by commas, enclosed in square brackets\n# Bottom string 1.143 mm = 0.045\" \n# 1.651 mm = 0.065\"\n# 2.159 mm = 0.085\"\n# Top string on a 4 string 2.667 mm = 0.105\"\n# Top string on a 5 string 3.175 mm = 0.125\"\nstringthickness = [1.143, 1.651, 2.159, 2.667, 3.175] # 5 string bass, 45-125/ 4 string bass 45-105\n#stringthickness = [3.175, 2.667, 2.159, 1.651, 1.143] # Reverse string, 5 string bass, 45-125/ 4 string bass 45-105\n#stringthickness = [0.254, 0.3302, 0.4318, 0.6604, 0.9144, 1.1684] # 6 string guitar, 10-46\nstringheight = 1.1938 # Height of bottom of strings above fretboard; 1.1938 mm = 0.047\" or the height of a typical medium/jumbo fret\nslotmargin = 0.05 # extra slot width on each side of the string; 0.05 mm = 0.00197\"\noverhang = 3.0 # Distance from edge of each outside string to end of nut\nbreakangle = 14.0 # Angle of the nut slot in degrees; this should be greater than the actual string angle to ensure the string only contacts at the leading edge of the nut\nslotradincrease = 0.2 # How much bigger the radius of the end of the slot is than the face\nslotdepthfactor = 1.3 # Factor to control how deep the slots should be.  Values greater than 1 create deeper slots than default.\ntoparcoffsetfactor = 1.8 # Factor to control how far off-center the nut top arc is.  Adjust as required.\n# End of user configuration variables\n# Do not make any changes below this line!\n\nstringindex = 0 # Start at the bottom string\nstringspacing = 0\n\n# Find the centers of the outside strings\n# Bottom string\ncenter1 = (length / 2) - overhang - (stringthickness[0] / 2)\n\n# Top string\ncenter2 = -((length / 2) - overhang - (stringthickness[strings - 1] / 2))\n\n# Outside string values\noutsidestringradiusdiff = (stringthickness[strings - 1] - stringthickness[0]) / 2\noutsidestringavgradius = (stringthickness[strings - 1] + stringthickness[0]) / 2 / 2\ncenterspacing = center1 - center2\n\n# Find the string spacings for both spacing models\nif equalcenters:\n    # Calculate the correct spacing for equal spaced strings\n    stringspacing = centerspacing / (strings - 1)\n\nelse:\n    # Calculate the space between strings\n    totalstringwidth = 0\n    stringindex1 = 0\n    while (stringindex1 < strings):\n        totalstringwidth = totalstringwidth + stringthickness[stringindex1]\n        stringindex1 = stringindex1 + 1\n\n    stringspacing = (centerspacing - totalstringwidth + (2 * outsidestringavgradius)) / (strings - 1)\n\nprint(\"Creating nut blank\")\n# Height is much larger than needed but will be cut down with the \"common\" operation later\nnutshape = Part.makeBox(width, length, ((fretboardmaxheight + stringheight) * 2), Vector(-width, -(length / 2), 0))\n\nprint(\"Creating nut top surface\")\n# Make a sphere to shape the top of the nut, which should pass through  each string center\n# Because the thickness of the strings varies, the Y-position of the sphere needs to be compensated\n# The fretboard \"z\" portion is:\nfretboardz = radius - (((radius ** 2) - ((centerspacing / 2) ** 2)) ** 0.5)\n\n# The formula to calculate the effective radius of the center of outside strings is:\n# r^2 = z^2 + y^2\n# r^2 = ((r - (outsidestringradiusdiff + fretboardz))^2) + ((centerspacing/2)^2)\n# r^2 = r^2 - 2r*(outsidestringradiusdiff + fretboardz) + ((outsidestringradiusdiff + fretboardz)^2) + (centerspacing^2)\n# 2r*(outsidestringradiusdiff + fretboardz) = ((outsidestringradiusdiff + fretboardz)^2) + (centerspacing^2)\n# r  = ((outsidestringradiusdiff + fretboardz)/2) + ((centerspacing^2)/(2*(outsidestringradiusdiff + fretboardz)))\nnutradius = ((abs(outsidestringradiusdiff / 4) + fretboardz) / 2) + (((centerspacing / 2) ** 2) / (2 * (abs(outsidestringradiusdiff / 4) + fretboardz)))\n\n# The center of the arc of the nut radius must also be offset\n# This formula was derived empirically so might nead adjusting\nyoffset = -centerspacing / 2 * toparcoffsetfactor * (outsidestringradiusdiff / (2 * outsidestringavgradius)) * (1 - (nutradius / radius))\n\ntop = Part.makeSphere(nutradius, Vector(0, yoffset, (-nutradius + fretboardmaxheight + stringheight + (outsidestringavgradius * slotdepthfactor) + slotmargin)))\n\nnutshape = nutshape.common(top)\n\ncumulativestringwidth = 0 # Add up the amount of string thickness for equal spacing\n\n# Build the slots\nwhile (stringindex < strings):\n    print(\"Creating slot for string \" + str(stringindex))\n    ypos = 0\n\n    if equalcenters:\n        # For equal centers move each string over by the fixed amount of stringspacing\n        ypos = center1 - (stringindex * stringspacing)\n\n    else:\n        # For equal spacing adjust for the thickness of each string\n\n        # Add up the cumulative string thickness\n        if stringindex == 0:\n            # For the first string the thickness is already included in center1 so don't add anything\n            cumulativestringwidth = 0\n\n        else:\n            # Add half the previous string and half this string\n            cumulativestringwidth = cumulativestringwidth + (stringthickness[stringindex] / 2) + (stringthickness[stringindex - 1] / 2)\n\n        ypos = center1 - (stringindex * stringspacing) - cumulativestringwidth\n\n    zstartpos = (((radius ** 2) - (ypos ** 2)) ** 0.5) - radius + fretboardmaxheight + stringheight + (stringthickness[stringindex] / 2) + slotmargin # Cartesian coordinate formula: z = sqrt(r^2 - y^2)\n    # calculate the end of the slot based on the string break angle \n    zendpos = zstartpos - (math.tan(math.radians(breakangle)) * width)\n\n    slotstartrad = (stringthickness[stringindex] / 2) + slotmargin\n    slotendrad = slotstartrad + slotradincrease\n\n    # Make the string slot as 2 circles offset in the Z axis to create the break angle, then made into a face, then extruded up to allow the slot to protrude to the nut surface\n    slotstart = Part.makeCircle(slotstartrad, Vector(0, ypos, zstartpos), Vector(1, 0, 0), 180, 360)\n    slotend = Part.makeCircle(slotendrad, Vector(-width, ypos, zendpos), Vector(1, 0, 0), 180, 360)\n    slotbottom = Part.makeRuledSurface(slotstart, slotend)\n    slotextrude = slotbottom.extrude(Vector(0, 0, ((fretboardmaxheight + stringheight) * 2)))\n\n    nutshape = nutshape.cut(slotextrude)\n    stringindex = stringindex + 1\n\nnut = App.ActiveDocument.addObject(\"Part::Feature\",\"Nut\")\nnut.Shape = nutshape\nprint(\"Finished creating nut\")",
    "url": "https://wiki.freecad.org/Macro_Guitar_Nut",
    "raw_code_url": "",
    "wiki": "",
    "version": "0.1",
    "license": "",
    "date": "2020-01-27",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Jeff Siddall",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Guitar_Nut.png",
    "icon_source": "https://wiki.freecad.org/images/9/94/Macro_Guitar_Nut.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Half turn stairs",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro creates a Stair with left or right turn in the defined high. The design of the stairs are defined in stairs.dat file (You must copy the data in the wiki page). The step-high of the stair is calculated from the high of the stair.<br /><br />Macro version: 1.0<br />Last modified: 2016-10-17<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/b/b8/Half_turn_stairs.png\">ToolBar Icon</a><br />Author: Berner<br /> ",
    "comment": "This macro creates a Stair with left or right turn in the defined high. The design of the stairs are defined in stairs.dat file (You must copy the data in the wiki page). The step-high of the stair is calculated from the high of the stair.",
    "code": "# -*- coding: utf-8 -*-\n#\n# Half_turn_stairs Macro runs with Freecad 0.17\n#\n# Author: Berner and Forum\n#\n# This macro creates a half turn stair from tupels of x,y,z \n# the tupels used to create a dwire for every stair.\n# The dwire is extruded, so it give with 18 stairs the total rise \n#\n# A sample file with parameters is in stairs.dat\n#\n# created a wire with coordinate x y z separated (in the file)\n#Sample: (delete # on lines without comments)\n# Stair 0\n#0.0 -240.0 0.0 0.0 0.0 0.0 1000.0 0.0 0.0 1000.0 -240.0 0.0\n# Stair 1\n#0.0 0.0 0.0 0.0 240.0 0.0 1000.0 240.0 0.0 1000.0 0.0 0.0\n#. . . .\n\nfrom __future__ import unicode_literals\nfrom FreeCAD import Base\nimport Draft, Part\n\nApp.Console.PrintMessage(\"Half_turn_stairs-Macro\\n\")\n# Get location of user macros\np=FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")\npath = p.GetString(\"MacroPath\")\ndataset = path + \"/stairs.dat\"                          # path and name of file.txt\ndocname = App.ActiveDocument.Name                       # Name of active document\n \ndebug='n' # Debug Values on Console\nrise = 3100.0 # Geschosshoehe Total Rise\n\nleft_right=\"l\"  # turn stairs left or left_right\n# GUI\n\nfrom PySide import QtGui\n(rise, ok) = QtGui.QInputDialog.getDouble(\n\t\tQtGui.QWidget(), 'Total Rise / Geschosshoehe', 'Total Rise /  Geschosshoehe', 2000, 0, 3100, 4)\nif ok:\n left_right = QtGui.QInputDialog.getText(None, \"left_right\", \"Turn Left or Right l/r\")[0]\nif debug == 'y': FreeCAD.Console.PrintMessage(\"rise=\"+str(rise) + \" \" + str(ok) + \"\\n\" )\nif debug == 'y': FreeCAD.Console.PrintMessage(\"left_right=\"+str(left_right) + \" \" + str(ok) + \"\\n\" )\n# End Gui\nstep=float(rise/18)  # Treppensteigung / Step_high\n\n# functions\ndef objnames():  # List object names\n doc = FreeCAD.ActiveDocument\n objs = FreeCAD.ActiveDocument.Objects\n names=''  #list of objectnames\n labels='' # list of objectlabels \n for obj in objs:\n    a = obj.Name                                             # list the Name  of the object  (not modifiable)\n    b = obj.Label                                            # list the Label of the object  (modifiable)\n    try:\n        c = obj.LabelText                                    # list the LabeText of the text (modifiable)\n        names=names+str(a)+\" \"\n        labels=labels+str(b)+\" \"\n    except:\n        names=names+str(a)+\" \"\n        labels=labels+str(b)+\" \"\n return names\n if debug == 'y': App.Console.PrintMessage(\"Names=\"+str(names) +\"\\n\"+\"Labels=\"+ str(labels) + \"\\n\")\n# end functions\n\nfile = open(dataset, \"r\") # open the file read\ni = 0 #line counter\nline = file.readline()\nwhile(line != ''):    # read number of lines\n   if line[0:1] != \"#\" and len(line) >0:\n    i = i + 1\n    if debug == \"y\": App.Console.PrintMessage(\"Parameter-Line\" + str(i) + \" \" + line + \"\\n\")\n   line = file.readline() \nfile.close()\nnumlines=i  # number of parameter-lines\nif debug == \"y\": App.Console.PrintMessage(\"Number of Parameter-Lines =\" + str(numlines) + \"\\n\")\nfile = open(dataset, \"r\")                                  # open the file read\nwire = []\nX=Y=Z = 0.0\nif left_right == \"r\": \n i = 0 #line counter\nelse:\n i = numlines \nline = file.readline()\nwhile(line != ''):\n    num_words = len(line.split())\n    num_tupel = num_words // 3\n    if debug == \"y\": App.Console.PrintMessage(str(num_words) + \"\\n\")\n    if debug == \"y\": App.Console.PrintMessage(str(num_tupel) + \"\\n\")\n    if line[0:1] == \"#\" or num_words != (num_tupel * 3):\n     if num_words != (num_tupel * 3):\n      App.Console.PrintMessage(\"Error on Inputfile line \" + str(i) + \"\\n\")\n      App.Console.PrintMessage(\"Only \" + str(num_words) + \" of multiple of 3 Words\\n\")\n    else:\n     if line[0:1] == \"#\": \n      num_words = 0   #  ignore comment\n     if debug == \"y\": App.Console.PrintMessage(line + \"\\n\")\n     coordinates = line.split()\n     if debug == \"y\": App.Console.PrintMessage(str(coordinates) + \" \" + str(num_words) + \" \" + str(num_tupel)+ str(type(num_words)) + \"\\n\")\n     if num_words > 0:\n      data=\"\"  # generate statement\n      printline=\"App.Console.PrintMessage(\" # generate variable for PrintMessage (debug)\n      for x in range(1, num_tupel + 1):\n       data=data + \"X\" + str(x) + \",Y\" + str(x) + \",Z\" + str(x)\n       printline=printline + \"str(X\" + str(x) + \") + ' ' + \" + \"str(Y\" + str(x) + \") + ' ' + \" + \"str(Z\" + str(x) + \") + ' '\"\n       if x < num_tupel: \n        data=data + \",\"\n        printline=printline + \" + \"\n      data=data + \" = coordinates\" \n      printline=printline + \")\\n\"\n      if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n      if debug == \"y\": App.Console.PrintMessage(printline + \"\\n\")\n      # X1,Y1,Z1,X2,Y2,Z2,X3,Y3,Z3,X4,Y4,Z4 = coordinates\n      exec(data) # coordinates to variables\n      if debug == \"y\": exec(printline) # output input file\n      #App.Console.PrintMessage(str(X1) + \" \" + str(Y1) + \" \" +str(Z1) + \"\\n\")\n      px=\"\"\n      pn=\"\" # names of generated variables\n      for x in range(1, num_tupel +1):\n       if x < num_tupel:\n        pn=pn + \"p\" + str(x) + \",\"\n       else:\n        pn=pn + \"p\" + str(x)\n       data = \"Z\" + str(x) + \" = \" + str(i * step)  # Korrektur z= 0.0 auf aktuelle step\n       if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n       exec(data)\n       px=\"p\" + str(x) + \"= FreeCAD.Vector(float(X\" + str(x) + \"),float(Y\" + str(x) + \"),float(Z\" + str(x) + \"))\" \n       if debug == \"y\": App.Console.PrintMessage(px + \"\\n\")\n       exec(px)\n      if debug == \"y\": App.Console.PrintMessage(pn + \"\\n\")\n      #p1 = FreeCAD.Vector(float(X1),float(Y1),float(Z1))\n      #p2 = FreeCAD.Vector(float(X2),float(Y2),float(Z2))\n      #p3 = FreeCAD.Vector(float(X3),float(Y3),float(Z3))\n      #p4 = FreeCAD.Vector(float(X4),float(Y4),float(Z4))\n      data=\"Draft.makeWire([\" + pn + \"],closed=True)\"\n      if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n      exec(data)\n      #Draft.makeWire([p1,p2,p3,p4,p5],closed=True)\n      if left_right == \"r\": \n       i = i + 1\n      else:\n       i = i -1\n    line = file.readline() \nfile.close()\n#\n# List all objects of the document\nnames = objnames()    # list objectnames\nApp.Console.PrintMessage(\"names=\"+str(names) +\"\\n\")\n#extrude\nextr=\"\" # suffix for continues Extrude in commands\nextrnames=\"Box Cut\" #names of source object, because not consitend nameings in freecad\nj=len(names.split())\nn=0 #counter\nif left_right == \"r\": \n l1 = 0\n l2 = j\n step = 1\nelse:\n l1 = j\n l2 = -1\n step = -1\nfor x in range(l1, l2, step):\n w=str(names.split(\" \")[x])\n if w[0:4] == \"Wire\":\n  if debug == 'y':  App.Console.PrintMessage(\"w=\"+str(w) +\"\\n\")\n  data = 'f = FreeCAD.getDocument(docname).addObject(\"Part::Extrusion\",\"Extrude' + str(extr)+ '\")'\n  if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n  exec(data)\n  data = 'f = App.getDocument(docname).getObject(\"Extrude' + str(extr) + '\")'\n  if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n  exec(data)\n  data = 'f.Base = App.getDocument(docname).getObject(\"' + str(w) + '\")'\n  if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n  exec(data)\n  data = 'f.DirMode = str(\"Custom\")'\n  if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n  exec(data)\n  data = 'f.Dir = App.Vector(0.000000000000000, 0.000000000000000, 1.000000000000000)'\n  if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n  exec(data)\n  data = 'f.DirLink = None'\n  if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n  exec(data)\n  data = 'f.LengthFwd = 180.000000000000000'\n  if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n  exec(data)\n  data = 'f.LengthRev = 0.000000000000000'\n  if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n  exec(data)\n  data = 'f.Solid = True'\n  if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n  exec(data)\n  data = 'f.Reversed = False'\n  if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n  exec(data)\n  data = 'f.Symmetric = False'\n  if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n  exec(data)\n  data = 'f.TaperAngle = 0.000000000000000'\n  if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n  exec(data)\n  data = 'f.TaperAngleRev = 0.000000000000000'\n  if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n  exec(data)\n # data = 'App.getDocument(docname).Extrude' + str(extr) + '.Placement=App.Placement(App.Vector(0,0,360), #App.Rotation(App.Vector(0,0,1),0), App.Vector(0,0,0))'\n  #if debug == \"y\": App.Console.PrintMessage(data + \"\\n\")\n  #exec(data)\n  n = n + 1\n  extr = str(\"%03d\" % n)  # count extrude suffix\n  extrnames=extrnames + \" Extrude\" + str(\"%03d\" % x)\n#\nFreeCAD.ActiveDocument.recompute()\n",
    "url": "https://wiki.freecad.org/Macro_Half_turn_stairs",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2016-10-17",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Berner",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Half_turn_stairs.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/b/b8/Half_turn_stairs.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Half-Hull Model",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro generates both three dimensional half-hull and full-hull models from a series of 2D line drawings.<br />This macro makes simple models of the hulls of boats and ships. It is intended to aid people modeling or designing hulls by providing the hull surface in a straight forward and timely fashion so they can avoid the time consuming full process.<br /><br />Macro version: 1.0<br />Last modified: 2016-01-25<br />FreeCAD version: &lt;= 0.16<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/4/44/Macro_Half_Hull_Model.png\">ToolBar Icon</a><br />Author: Piffpoof<br /> ",
    "comment": "This macro generates both three dimensional half-hull and full-hull models from a series of 2D line drawings.",
    "code": "<html>\r\n<head>\r\n\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf8\">\r\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n\t<title>...</title>\r\n\t<style type=\"text/css\">\r\n\t\t.erisime_engellenmis {\r\n\t\t\tfont-family: Arial, Helvetica, sans-serif;\r\n\t\t\tfont-size: 32px;\r\n\t\t\tfont-weight: bold;\r\n\t\t\tcolor: #0000FF;\r\n\t\t\ttext-decoration: none;\r\n\t\t\ttext-align: center;\r\n\t\t\tborder-right-width: 1px;\r\n\t\t\tborder-left-width: 1px;\r\n\t\t\tborder-right-style: none;\r\n\t\t\tborder-left-style: none;\r\n\t\t\tborder-right-color: #0000FF;\r\n\t\t\tborder-left-color: #0000FF;\r\n\t\t\tborder-top-width: 1px;\r\n\t\t\tborder-top-style: none;\r\n\t\t\tborder-top-color: #0000FF;\r\n\t\t\tborder-bottom-width: 1px;\r\n\t\t\tborder-bottom-style: none;\r\n\t\t\tborder-bottom-color: #0000FF;\r\n\t\t}\r\n\r\n\t\t.yazi1 {\r\n\t\t\tfont-family: Georgia, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 12px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #666666;\r\n\t\t\ttext-decoration: none;\r\n\t\t}\r\n\r\n\t\t.yazi2 {\r\n\t\t\tfont-family: Georgia, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 12px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #6565FF;\r\n\t\t\ttext-decoration: none;\r\n\t\t}\r\n\r\n\t\t.yazi3 {\r\n\t\t\tfont-family: Georgia, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 10px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #BB65FF;\r\n\t\t\ttext-decoration: none;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t}\r\n\r\n\t\t.yazi2_1 {\r\n\t\t\tfont-family: Verdana, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 12px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #6565FF;\r\n\t\t\ttext-decoration: none;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t}\r\n\r\n\t\t.yazi2_2 {\r\n\t\t\tfont-family: Verdana, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 12px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #00005C;\r\n\t\t\ttext-decoration: none;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t}\r\n\r\n\t\t.yazi3_1 {\r\n\t\t\tfont-family: Verdana, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 10px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #BB65FF;\r\n\t\t\ttext-decoration: none;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t}\r\n\r\n\t\t.yazi4_1 {\r\n\t\t\tfont-family: Verdana, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 10px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #444444;\r\n\t\t\ttext-decoration: none;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t}\r\n\r\n\t\t.yazi5_1 {\r\n\t\t\tfont-family: Verdana, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 35px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #FF0000;\r\n\t\t\ttext-decoration: none;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t}\r\n\r\n\t\t.yazi6_1 {\r\n\t\t\tfont-family: Verdana, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 25px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #FF0000;\r\n\t\t\ttext-decoration: none;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t}\r\n\r\n\t\ta.link:link {\r\n\t\t\tfont-family: Georgia, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 11px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #0000FF;\r\n\t\t\ttext-decoration: underline;\r\n\t\t}\r\n\r\n\t\ta.link:active {\r\n\t\t\tfont-family: Georgia, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 11px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #0000FF;\r\n\t\t\ttext-decoration: underline;\r\n\t\t}\r\n\r\n\t\ta.link:visited {\r\n\t\t\tfont-family: Georgia, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 11px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #0000FF;\r\n\t\t\ttext-decoration: underline;\r\n\t\t}\r\n\r\n\t\ta.link:hover {\r\n\t\t\tfont-family: Georgia, \"Times New Roman\", Times, serif;\r\n\t\t\tfont-size: 11px;\r\n\t\t\tline-height: 140%;\r\n\t\t\tfont-weight: normal;\r\n\t\t\tcolor: #BB65FF;\r\n\t\t\ttext-decoration: none;\r\n\t\t}\r\n\r\n\t\t.alticizgili_genisliktd {\r\n\t\t\theight: 100%;\r\n\t\t\twidth: 100%;\r\n\t\t\tpadding-top: 20px;\r\n\t\t\tborder-bottom-width: 1px;\r\n\t\t\tborder-bottom-style: dotted;\r\n\t\t\tborder-bottom-color: #DDCCFE;\r\n\t\t\tpadding-bottom: 10px;\r\n\t\t\ttext-align: center;\r\n\t\t}\r\n\r\n\t\t.genisliktd {\r\n\t\t\theight: 100%;\r\n\t\t\twidth: 100%;\r\n\t\t\tpadding-top: 20px;\r\n\t\t\ttext-align: center;\r\n\t\t}\r\n\r\n\t\t.genisliktdbaslik {\r\n\t\t\theight: 100%;\r\n\t\t\twidth: 100%;\r\n\t\t\tpadding-top: 20px;\r\n\t\t\ttext-align: left;\r\n\t\t\tborder-bottom-width: 5px;\r\n\t\t\tborder-bottom-style: solid;\r\n\t\t\tborder-bottom-color: #DDCCFE;\r\n\t\t}\r\n\t</style>\r\n\r\n</head>\r\n\r\n<body onselectstart=\"return false\" bgcolor=\"aliceblue\">\r\n\t<div>\r\n\r\n\t\t<table border=\"0\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\" width=\"1024\" height=\"100%\">\r\n\t\t\t<tr>\r\n\t\t\t\t<td class=\"alticizgili_genisliktd\">\r\n<br><br><br> <span class=\"yazi2_2\">pastebin.com, 08/03/2012 tarihli ve 2012/27976 Say\u0131l\u0131 Ankara CBS karar\u0131yla eri\u015fime engellenmi\u015ftir.</span><br><br><span class=\"yazi3_1\">pastebin.com, 08/03/2012 has been blocked by the decision dated 2012/27976 and numbered 08/03/2012 of Ankara CBS.</span><br><br><br>\n<a class=\"link\" target=\"_blank\" href=\"http://www.ihbarweb.org.tr\">-http://www.ihbarweb.org.tr</a>\r\n</td>\r\n</tr>\r\n\r\n</table>\r\n</div>\r\n</body>\r\n\r\n</html>\r\n",
    "url": "https://wiki.freecad.org/Macro_Half-Hull_Model",
    "raw_code_url": "http://pastebin.com/raw/tZMpUi6F",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2016-01-25",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Piffpoof",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Half_Hull_Model.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/4/44/Macro_Half_Hull_Model.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Honeycomb",
    "on_wiki": true,
    "on_git": false,
    "desc": "Create a fully parametric feature Python Honeycomb object, compatible in and outside of Part Design<br /><br />Macro version: 0.2024.08.27<br />FreeCAD version: Python 3 versions<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/File:Macro_Honeycomb.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Create a fully parametric feature Python Honeycomb object, compatible in and outside of Part Design",
    "code": "# -*- coding: utf-8 -*-\n__version__ = \"0.2024.08.27\"\n\n#Honeycomb macro -- creates a feature python parametric honeycomb object for Part Design workbench\n#2021, by <TheMarkster> LGPL2.1 or later\nimport FreeCAD, FreeCADGui, Part\nclass Honeycomb:\n    def __init__(self,obj):\n        obj.addExtension(\"Part::AttachExtensionPython\")\n        obj.addProperty(\"App::PropertyFloat\",\"Radius\",\"Honeycomb\",\"Circumradius of the hexagons\").Radius = 1\n        obj.addProperty(\"App::PropertyFloat\",\"Separation\",\"Honeycomb\",\"Separation between hexagons\").Separation = .5\n        obj.addProperty(\"App::PropertyFloat\",\"Length\",\"Honeycomb\",\"Length of grid\").Length = 10\n        obj.addProperty(\"App::PropertyFloat\",\"Width\",\"Honeycomb\", \"Width of grid\").Width = 15\n        obj.addProperty(\"App::PropertyFloat\",\"Height\",\"Honeycomb\",\"Height of grid\").Height = 3\n        obj.addProperty(\"App::PropertyBool\",\"EllipticalGrid\",\"Honeycomb\",\"If True, make an elliptical grid of minor diameter = Width, Major Diameter = Length\").EllipticalGrid = True\n        obj.addProperty(\"App::PropertyFloatConstraint\",\"XAdjust\",\"Honeycomb\",\"Adjust hexagons in the X direction\").XAdjust = (0,-10e4,10e4,.1)\n        obj.addProperty(\"App::PropertyFloatConstraint\",\"YAdjust\",\"Honeycomb\",\"Adjust hexagons in the Y direction\").YAdjust = (0,-10e4,10e4,.1)\n        obj.addProperty(\"App::PropertyFloat\",\"BorderOffset\",\"Honeycomb\",\"Offset for border (0 = no border) -1 for inward offset\").BorderOffset = 1\n        obj.addProperty(\"App::PropertyFloatConstraint\",\"BorderHeightOffset\",\"Honeycomb\",\"Height Offset for border (0 = same as Height)\").BorderHeightOffset = (0.1,-10e4,10e4,.1)\n        obj.addProperty(\"App::PropertyLink\",\"Profile\",\"Honeycomb\",\"Profile, e.g. sketch, to use in place of hexagon, should have radius = 1, centered on origin\")\n        obj.addProperty(\"App::PropertyInteger\",\"CountXAdjust\",\"Honeycomb\",\"default: 0 -- amount to add to number of hexagons on X axis\")\n        obj.addProperty(\"App::PropertyInteger\",\"CountYAdjust\",\"Honeycomb\",\"default: 0 -- amount to add to number of hexagons on Y axis\")\n        obj.addProperty(\"App::PropertyString\",\"Version\",\"Honeycomb\",\"Version of macro this object was created with\").Version = __version__\n        obj.addProperty(\"App::PropertyBool\",\"SquareGrid\",\"Honeycomb\",\"If true, make a square grid instead of hexagon grid\").SquareGrid = False\n        obj.setEditorMode(\"Placement\",0)\n        obj.Proxy = self\n        self.fpName = obj.Name\n\n    def makeHexagon(self,radius,origin):\n        '''makes a hexagon based on radius and origin, returns it as a wire\n        unless a profile is linked to Profile property'''\n        fp = FreeCAD.ActiveDocument.getObject(self.fpName)\n        if hasattr(fp,\"Profile\") and fp.Profile:\n            profile = fp.Profile\n            if not hasattr(profile,\"Shape\"):\n                raise Exception(\"Invalid profile\\n\")\n            shp = profile.Shape.copy()\n            shp.Placement.move(origin)\n            shp.scale(radius,origin)\n            return shp\n        else:\n            sin60 = 0.8660254037844386\n            tups = [(-1,0,0),(-.5,sin60,0),(.5,sin60,0),(1,0,0),(.5,-sin60,0),(-.5,-sin60,0),(-1,0,0)]\n            pts = [FreeCAD.Vector(tup).add(origin) for tup in tups]\n            poly = Part.makePolygon(pts).scale(radius,origin)\n            return poly\n\n\n    def makeCross(self,radius,origin):\n        '''makes cross based on radius and origin, returns it as a wire\n        unless a profile is linked to Profile property'''\n        fp = FreeCAD.ActiveDocument.getObject(self.fpName)\n        if hasattr(fp,\"Profile\") and fp.Profile:\n            profile = fp.Profile\n            if not hasattr(profile,\"Shape\"):\n                raise Exception(\"Invalid profile\\n\")\n            shp = profile.Shape.copy()\n            shp.Placement.move(origin)\n            shp.scale(radius,origin)\n            face = Part.makeFace(shp,\"Part::FaceMakerBullseye\")\n            return face\n        else:\n            tups = [(-1,-1,0),(1,-1,0),(1,1,0),(1,1,0),(-1,1,0),(-1,-1,0)]\n            pts = [FreeCAD.Vector(tup).add(origin) for tup in tups]\n            poly = Part.makePolygon(pts).scale(radius,origin)\n            face = Part.makeFace(poly, \"Part::FaceMakerBullseye\")\n            #Part.show(face,'face\"')\n            return face\n\n    def makeCrossGrid(self, fp):\n        #face = self.makeCross(1, FreeCAD.Vector(0,0,0))\n\n        yInt = (2 * fp.Radius+fp.Separation)\n        xInt = (2 * fp.Radius+fp.Separation)\n        firstX = 0\n        firstY = 0\n        countX = round(fp.Width/xInt) + 1\n        countY = round(fp.Length/yInt) + 1\n        if hasattr(fp,\"CountXAdjust\"):\n            countX += fp.CountXAdjust\n            countY += fp.CountYAdjust\n        vectors = []\n        for xx in range(-1,int(countX)):\n            for yy in range(-1,int(countY)):\n                vectors.append(FreeCAD.Vector(firstX + xx * xInt, firstY + yy * yInt, 0)+FreeCAD.Vector(fp.XAdjust,fp.YAdjust,0))\n        array = [self.makeCross(fp.Radius, v) for v in vectors]\n        #crosses = Part.makeCompound(array)\n        crosses = Part.makeCompound(array)\n\n        cross_faces = crosses.extrude(FreeCAD.Vector(0,0,1)).removeSplitter()\n        #cross_faces = Part.makeFace(crosses,\"Part::FaceMakerCheese\")\n       # rect = Part.makePolygon()\n        #Part.show(cross_faces, \"cross_faces\")\n        solid = self.handleElliptical(fp, cross_faces)\n        return solid\n\n\n\n    def makeHoneycomb(self,fp):\n        tan15 = 0.2679491924311227\n        sin60 = 0.8660254037844386\n        yInt = (2 * fp.Radius + fp.Separation - tan15 * fp.Radius)\n        xInt = (2 * sin60 * (fp.Radius * 2 + fp.Separation - tan15 * fp.Radius))\n        array2XPos = (sin60 * (fp.Radius * 2 + fp.Separation - tan15 * fp.Radius))\n        array2YPos = yInt / 2.0\n        firstX = fp.Radius\n        firstY = fp.Radius\n        countX = round(fp.Width/xInt) + 1\n        countY = round(fp.Length/yInt) + 1\n        if hasattr(fp,\"CountXAdjust\"):\n            countX += fp.CountXAdjust\n            countY += fp.CountYAdjust\n        vectors = []\n        for xx in range(-1,int(countX)):\n            for yy in range(-1,int(countY)):\n                vectors.append(FreeCAD.Vector(firstX + xx * xInt, firstY + yy * yInt, 0)+FreeCAD.Vector(fp.XAdjust,fp.YAdjust,0))\n        array = [self.makeHexagon(fp.Radius, v) for v in vectors]\n        array.extend([self.makeHexagon(fp.Radius, v  + FreeCAD.Vector(array2XPos,array2YPos,0)) for v in vectors[:-int(countY+1)]])\n        hexagons = Part.makeCompound(array)\n        hex_faces = Part.makeFace(hexagons,\"Part::FaceMakerCheese\")\n        solid = self.handleElliptical(fp, hex_faces)\n        return solid\n\n\n    def handleElliptical(self, fp, hex_faces):\n        if not fp.EllipticalGrid:\n            rectTups = [(0,0,0),(fp.Width,0,0),(fp.Width,fp.Length,0),(0,fp.Length,0),(0,0,0)]\n            rect_pts = [FreeCAD.Vector(tup) + FreeCAD.Vector(-fp.Radius,0,0) for tup in rectTups]\n            rect = Part.makePolygon(rect_pts)\n            rect_face = Part.makeFace(rect,\"Part::FaceMakerCheese\")\n            cut = rect_face.cut(hex_faces)\n            cut.translate(-cut.BoundBox.Center)\n            if hasattr(cut,\"Face1\"):\n                normal = cut.Face1.normalAt(0,0).normalize()\n            else:\n                normal = FreeCAD.Vector(0,0,1)\n            cut = cut.extrude(normal * fp.Height)\n            if fp.BorderOffset == 0:\n                return cut\n            else:\n                border = rect_face.makeOffset2D(fp.BorderOffset, join=2, fill=True)\n                border.translate(-border.BoundBox.Center)\n                border = border.extrude(border.Face1.normalAt(0,0).normalize()*(fp.Height + fp.BorderHeightOffset))\n                fuse = border.fuse(cut)\n                return fuse\n        else:\n            if fp.Width >= fp.Length:\n                ellipse = Part.Ellipse(FreeCAD.Vector(0,0,0),fp.Width/2,fp.Length/2).toShape()\n            else:\n                ellipse = Part.Ellipse(FreeCAD.Vector(0,0,0),fp.Length/2,fp.Width/2)\n                plm = FreeCAD.Placement()\n                plm.Rotation = FreeCAD.Rotation(FreeCAD.Vector(0,0,1),90)\n                ellipse.rotate(plm)\n                ellipse = ellipse.toShape()\n            ellipse_face = Part.makeFace(ellipse,\"Part::FaceMakerCheese\")\n            hex_faces.translate(ellipse_face.BoundBox.Center - hex_faces.BoundBox.Center + FreeCAD.Vector(fp.XAdjust, fp.YAdjust, 0))\n            cut = ellipse_face.cut(hex_faces)\n            if hasattr(cut,\"Face1\"):\n                normal = cut.Face1.normalAt(0,0).normalize()\n            else:\n                normal = FreeCAD.Vector(0,0,1)\n            cut = cut.extrude(normal * fp.Height)\n            if fp.BorderOffset == 0:\n                return cut\n            else:\n                if fp.Width >= fp.Length:\n                    ellipse_offset = Part.Ellipse(FreeCAD.Vector(0,0,0),fp.Width / 2 + fp.BorderOffset, fp.Length / 2 + fp.BorderOffset).toShape()\n                else:\n                    ellipse_offset = Part.Ellipse(FreeCAD.Vector(0,0,0),fp.Length / 2 + fp.BorderOffset, fp.Width / 2 + fp.BorderOffset)\n                    ellipse_offset.rotate(plm)\n                    ellipse_offset = ellipse_offset.toShape()\n                ellipse_offset_face = Part.makeFace(ellipse_offset,\"Part::FaceMakerCheese\")\n                if fp.BorderOffset > 0:\n                    border = ellipse_offset_face.cut(ellipse_face)\n                else:\n                    border = ellipse_face.cut(ellipse_offset_face)\n                border = border.extrude(border.Face1.normalAt(0,0).normalize()*(fp.Height + fp.BorderHeightOffset))\n                fuse = border.fuse(cut)\n                return fuse\n\n    def execute(self,fp):\n        if not hasattr(fp, \"SquareGrid\"):\n            fp.addProperty(\"App::PropertyBool\",\"SquareGrid\",\"Honeycomb\",\"Whether to make honeycomb grid or square grid\").SquareGrid = False\n        shape = self.makeHoneycomb(fp) if not fp.SquareGrid else self.makeCrossGrid(fp)\n        fp.positionBySupport()\n        shape.Placement = fp.Placement\n\n       #shape.transformShape(fp.Placement.inverse().toMatrix(), True)\n        if hasattr(fp,\"AddSubShape\"):\n            fp.AddSubShape = shape\n        if hasattr(fp,\"BaseFeature\") and fp.BaseFeature:\n            full_shape = shape.fuse(fp.BaseFeature.Shape)\n            full_shape.transformShape(fp.Placement.inverse().toMatrix(),True)\n            fp.Shape = full_shape\n        else:\n            fp.Shape = shape\n\n\nclass HoneycombVP:\n\n    def __init__(self, obj):\n        '''Set this object to the proxy object of the actual view provider'''\n        obj.Proxy = self\n\n    def attach(self, obj):\n        '''Setup the scene sub-graph of the view provider, this method is mandatory'''\n        self.Object = obj.Object\n\n    def updateData(self, fp, prop):\n        '''If a property of the handled feature has changed we have the chance to handle this here'''\n        # fp is the handled feature, prop is the name of the property that has changed\n        pass\n\n    def getDisplayModes(self,obj):\n        '''Return a list of display modes.'''\n        modes=[]\n        modes.append(\"Flat Lines\")\n        return modes\n\n    def getDefaultDisplayMode(self):\n        '''Return the name of the default display mode. It must be defined in getDisplayModes.'''\n        return \"Flat Lines\"\n\n    def setDisplayMode(self,mode):\n        '''Map the display mode defined in attach with those defined in getDisplayModes.\\\n           Since they have the same names nothing needs to be done. This method is optional'''\n        return mode\n\n    def onChanged(self, vp, prop):\n        '''Here we can do something when a single property got changed'''\n        #FreeCAD.Console.PrintMessage(\"Change property: \" + str(prop) + \"\"+chr(10))\n\n    def claimChildren(self):\n        return []\n\n    def setupContextMenu(self, vobj, menu):\n        pass\n\n    def setEdit(self,vp,modNum):\n        pass\n\n    def onDelete(self, vobj, subelements):\n        if hasattr(vobj.Object,\"_Body\") and vobj.Object._Body: #do this only when the object is in a PD body\n            #need to ensure the next feature in the tree's BaseFeature property points to our BaseFeature\n            solids = [feat for feat in vobj.Object._Body.Group if feat.isDerivedFrom(\"PartDesign::Feature\") and feat.BaseFeature == vobj.Object]\n            if len(solids) == 1: #found previous solid feature\n                solids[0].BaseFeature = vobj.Object.BaseFeature\n        return True\n\n    def getIcon(self):\n        '''Return the icon in XPM format which will appear in the tree view. This method is\\\n               optional and if not defined a default icon is shown.'''\n        XPM = '''\n/* XPM */\nstatic char *_634945598709[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 223 2 \",\n\"   c #03F603F602CA\",\n\".  c #099C099C0429\",\n\"X  c #042F042F0A0A\",\n\"o  c #0AD20AD20B7D\",\n\"O  c #11DE11DE0269\",\n\"+  c #1A191A190606\",\n\"@  c #13E913E90C8D\",\n\"#  c #1BF71BF70A78\",\n\"$  c #0375037513DB\",\n\"%  c #08C908C91212\",\n\"&  c #038403841D1C\",\n\"*  c #14D514D51394\",\n\"=  c #1CDC1CDC1252\",\n\"-  c #147B147B1D50\",\n\";  c #19B619B61927\",\n\":  c #23F923F9042F\",\n\">  c #2B6B2B6B03E4\",\n\",  c #20A020A00D0D\",\n\"<  c #3400340004D2\",\n\"1  c #3B6E3B6E09A3\",\n\"2  c #22BC22BC1CEA\",\n\"3  c #292929291A9B\",\n\"4  c #378D378D1A70\",\n\"5  c #0429042922C6\",\n\"6  c #0C4C0C4C2464\",\n\"7  c #080808082928\",\n\"8  c #1B1B1B1B2444\",\n\"9  c #177717772848\",\n\"0  c #20E120E12222\",\n\"q  c #2626262627A7\",\n\"w  c #2BB72BB72BA0\",\n\"e  c #3131313123A4\",\n\"r  c #3A3A3A3A2379\",\n\"t  c #23E423E43252\",\n\"y  c #2B2B2B2B33C1\",\n\"u  c #390539053467\",\n\"i  c #33B433B43B7B\",\n\"p  c #390E390E3A3A\",\n\"a  c #482848280666\",\n\"s  c #56225622056C\",\n\"d  c #5F095F090B0B\",\n\"f  c #4747474719C4\",\n\"g  c #5CF65CF6167D\",\n\"h  c #537853781DD5\",\n\"j  c #6BEB6BEB02C3\",\n\"k  c #674267420909\",\n\"l  c #76767676095F\",\n\"z  c #69D769D71482\",\n\"x  c #65A565A51DDE\",\n\"c  c #753475341C9D\",\n\"v  c #78AB78AB1DB7\",\n\"b  c #535253522020\",\n\"n  c #459A459A3CE7\",\n\"m  c #1D1D1D1D4202\",\n\"M  c #297F297F4BF6\",\n\"N  c #3B3B3B3B403F\",\n\"B  c #262626265757\",\n\"V  c #3737373757D7\",\n\"C  c #448444844444\",\n\"Z  c #464646464948\",\n\"A  c #515151514F4F\",\n\"S  c #54A954A951A7\",\n\"D  c #61E261E25D5D\",\n\"F  c #4CCD4CCD6464\",\n\"G  c #5DDE5DDE7373\",\n\"H  c #640E640E62B8\",\n\"J  c #606060606A6A\",\n\"K  c #717171716C6C\",\n\"L  c #68A868A87939\",\n\"P  c #797979797676\",\n\"I  c #7DFD7DFD7BBB\",\n\"U  c #858585850AB5\",\n\"Y  c #890989090848\",\n\"T  c #98179817065C\",\n\"R  c #9A199A190B4B\",\n\"E  c #85858585114C\",\n\"W  c #8585858519B3\",\n\"Q  c #8A8A8A8A1798\",\n\"!  c #919091901111\",\n\"~  c #929292921980\",\n\"^  c #A34DA34D0909\",\n\"/  c #AE0DAE0D0C2C\",\n\"(  c #B6B5B6B50157\",\n\")  c #B413B4130D8E\",\n\"_  c #BC28BC280B54\",\n\"`  c #A3A2A3A210DE\",\n\"'  c #AC11AC111178\",\n\"]  c #B80DB80D1515\",\n\"[  c #BA79BA792727\",\n\"{  c #BFBFBFBF3838\",\n\"}  c #C3C3C3C30505\",\n\"|  c #CE4DCE4D0182\",\n\" . c #C4B3C4B30AAB\",\n\".. c #CBFECBFE0A71\",\n\"X. c #D4BFD4BF0317\",\n\"o. c #DCF6DCF603E9\",\n\"O. c #D5D5D5D50BE1\",\n\"+. c #DC14DC1409D1\",\n\"@. c #C419C4191212\",\n\"#. c #CE4DCE4D1515\",\n\"$. c #C9C9C9C91B9C\",\n\"%. c #DBDBDBDB1495\",\n\"&. c #E4D0E4D003A1\",\n\"*. c #EC35EC350303\",\n\"=. c #E387E3870A0A\",\n\"-. c #ED97ED9709ED\",\n\";. c #F54BF54B0317\",\n\":. c #FE79FE790364\",\n\">. c #F3DDF3DD0873\",\n\",. c #FF69FF690934\",\n\"<. c #E2E2E2E21293\",\n\"1. c #E539E53919C4\",\n\"2. c #F3F2F3F21616\",\n\"3. c #F474F4741BDC\",\n\"4. c #C645C6452626\",\n\"5. c #DD87DD87234E\",\n\"6. c #DFDEDFDE2E2E\",\n\"7. c #C9C8C9C83535\",\n\"8. c #C706C70638F9\",\n\"9. c #D8D7D8D735E0\",\n\"0. c #E423E4232666\",\n\"q. c #F453F45323B4\",\n\"w. c #F5F5F5F52C2C\",\n\"e. c #EC96EC963636\",\n\"r. c #F5F5F5F53ABB\",\n\"t. c #8B8B8B8B4A4A\",\n\"y. c #BA39BA394606\",\n\"u. c #BBBBBBBB56AC\",\n\"i. c #8A0A8A0A77F8\",\n\"p. c #969696967171\",\n\"a. c #AFAFAFAF71F2\",\n\"s. c #BABABABA7434\",\n\"d. c #CBCACBCA4949\",\n\"f. c #D983D9834CA2\",\n\"g. c #CB4BCB4B5454\",\n\"h. c #DB5BDB5B5252\",\n\"j. c #F84CF84C4FFA\",\n\"k. c #C747C7476A6A\",\n\"l. c #D555D55569EA\",\n\"z. c #D514D5146BAB\",\n\"x. c #C646C64675B5\",\n\"c. c #CDCDCDCD7979\",\n\"v. c #D353D3537575\",\n\"b. c #DD53DD537E92\",\n\"n. c #E2E2E2E26C6C\",\n\"m. c #E565E5657E7E\",\n\"M. c #585858589919\",\n\"N. c #787878788606\",\n\"B. c #777777779191\",\n\"V. c #7B7B7B7BB737\",\n\"C. c #89DF89DF84DA\",\n\"Z. c #8AF18AF18AF1\",\n\"A. c #922092208D70\",\n\"S. c #88328832953F\",\n\"D. c #952795279502\",\n\"F. c #999999999C46\",\n\"G. c #B8B8B8B88B8B\",\n\"H. c #A1A1A1A198EE\",\n\"J. c #BABABABA9898\",\n\"K. c #8FE58FE5A7FD\",\n\"L. c #A3A3A3A3A2CD\",\n\"P. c #A7A7A7A7A8A8\",\n\"I. c #ADE0ADE0ABAB\",\n\"U. c #B272B272AF6F\",\n\"Y. c #BBBBBBBBAAAA\",\n\"T. c #A8A8A8A8B60B\",\n\"R. c #B6F6B6F6B620\",\n\"E. c #BCBCBCBCB986\",\n\"W. c #CC0BCC0B8383\",\n\"Q. c #C706C7068949\",\n\"!. c #DB30DB3087B2\",\n\"~. c #C9C9C9C99999\",\n\"^. c #D7D7D7D796EC\",\n\"/. c #DC0EDC0E9595\",\n\"(. c #E83DE83D8BE1\",\n\"). c #E1E1E1E19696\",\n\"_. c #C6C6C6C6A650\",\n\"`. c #DCDCDCDCA0A0\",\n\"'. c #CBF6CBF6B1B1\",\n\"]. c #C35CC35CB8EB\",\n\"[. c #E928E928A8A8\",\n\"{. c #EEEEEEEEBBBB\",\n\"}. c #94949494C6C6\",\n\"|. c #ADADADADC8C8\",\n\" X c #BD12BD12C6C6\",\n\".X c #BDBDBDBDD353\",\n\"XX c #AFAFAFAFFCFC\",\n\"oX c #B8B8B8B8FCFC\",\n\"OX c #C5C5C5C5C444\",\n\"+X c #CB5DCB5DC355\",\n\"@X c #C2C2C2C2CA74\",\n\"#X c #CDF2CDF2CC83\",\n\"$X c #DBDBDBDBC5C5\",\n\"%X c #DD76DD76C5F8\",\n\"&X c #C848C848D655\",\n\"*X c #D4F9D4F9D3D3\",\n\"=X c #D8D8D8D8D6D6\",\n\"-X c #D3D3D3D3DB5B\",\n\";X c #DBFBDBFBDD1C\",\n\":X c #E464E464CACA\",\n\">X c #F4F4F4F4C4C4\",\n\",X c #EEEEEEEED353\",\n\"<X c #E73CE73CD8D8\",\n\"1X c #E4A4E4A4DD9D\",\n\"2X c #C646C646E666\",\n\"3X c #D959D959E767\",\n\"4X c #CDCDCDCDF3F3\",\n\"5X c #C29DC29DFCC5\",\n\"6X c #D871D871F82A\",\n\"7X c #DC5CDC5CFD52\",\n\"8X c #E5E5E5E5E476\",\n\"9X c #E5E5E5E5EAEA\",\n\"0X c #EBCEEBCEECCF\",\n\"qX c #F1F1F1F1E464\",\n\"wX c #F4C9F4C9ECEC\",\n\"eX c #E6E6E6E6F5F5\",\n\"rX c #ED0CED0CF6B6\",\n\"tX c #E564E564FD49\",\n\"yX c #EC9CEC9CFE0D\",\n\"uX c #F30FF30FF348\",\n\"iX c #FAA4FAA4F5CA\",\n\"pX c #F624F624FE14\",\n\"aX c None\",\n/* pixels */\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXpXyX6X7X7X7XyXpXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXpX3X%X/.b.b.m.m.b.b.b.m.m.m.b.b.`.$X7XpXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXtX%X!.(.!.f.%.o.o.&.>.,.:.,.,.>.&.o.o.5.f.v.(.!.:XtXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXpX=X)./.f.X.*.,.,.,.,.,.,.,.,.,.,.,.,.,.,.:.:.,.,.*.X.f./.).1XiXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXpX:X[.l.X.:.:.:.:.,.,.-.=.) ) ` ` ` ` ` ' ) ) =.-.,.,.,.:.,.,.| l.[.:XpXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaX1X[.d.&.,.:.,.:.=. ./ / R ..f 2 6 & & & 5 & 2 e ..) / /  .-.,.,.:.,.&.g.[.8XaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXpX{.k.*.:.,.,.-. ._ E 4 & t o >.' Z C C C C C C C x ,.d q & 4 Y ) ..;.,.,.:.&.x.{.pXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXwX$X| :.,.,.-...^ ; 6 w p u C.V T :.>X,X,X,X,X,X,X>X:. .w C.u p w 6 0 / ..-.,.,.,.| $XrXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXqXJ.;.,.,.>.O.! 5 ; w D #XaXaXaXiX- ;.*.8.7.7.7.7.8.X.:.X #XaXaXaX+XS w ; 5 R O.,.,.:.>.~.qXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXwXu.:.,.,.;.) 5 = 2 I.aXaXaXaXaXaXaXV.} *.o.&.o.o.o.o.&.:.B pXaXaXaXaXaXiXL.0 ; 5 _ >.,.,.:.u.qXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXiXy.:.,.,.*.@.E 6 #XpXaXaXaXaXaXaXaXaX(.:.f 7 7 7 7 7 7 & ,.j.aXaXaXaXaXaXaXaXaX].* 0 _ *.,.,.:.y.iXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXpXa.:.,.,.:.& ) :.iXaXaXaXaXaXaXaXaXaX6X:.,.  n p u u u n    .:.2XaXaXaXaXaXaXaXaXaXiX:.:.& :.,.,.:.a.aXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaX&X:.,.,.,.$ X   :.o.aXaXaXaXaXaXaXaXaX_ :.  0XaXiXaXaXaXaXiX  :.| aXaXaXaXaXaXaXaXaX] :.    $ :.,.,.:..XaXaXaXaXaXaXaX\",\n\"aXaXaXaXpX&.,.,.:.o X uXS.a :.a.aXaXaXaXaXaXaX.X:./ 7 aXaXaXaXaXaXaXaXG j :.J.aXaXaXaXaXaXaX&X:._ 5 iX% % :.,.,.=.pXaXaXaXaXaXaX\",\n\"aXaXaXaXu.:.,.,., $ 9XaXuX  ,.,.XX5X5X5X5X5XoX%.,.O 0XaXaXaXaXaXaXaXaXuX. ,.-.XX5XoX5X5XoXoX%.:.. 9XaX9X$ # ,.,.:.y.aXaXaXaXaXaX\",\n\"aXaXaXtX-.,.,. .  ;XaXaXaX@X: ,.q.q.q.q.q.q.q.:.< N.pXaXaXaXaXaXaXaXaXaXP.: ,.q.q.q.q.q.q.q.:.1 G aXaXaX;X  ) ,.,.;.7XaXaXaXaXaX\",\n\"aXaXaXW.:.,.,.: #XaXaXaXaXpX/ :.c c v v v c x ,.( 9XaXaXaXaXaXaXaXaXaXaXrXR :.W ~ ~ ~ ~ ~ W :.T 8XaXaXaXaX#X: :.,.:.c.aXaXaXaXaX\",\n\"aXaXaX$.:.,.( F aXaXaXaXaX].;./ # @ @ # # # @ l ;.~.aXaXaXaXaXaXaXaXaXaX#X*.) + , , # # , # R *.].aXaXaXaXaXF / ,.:.#.aXaXaXaXaX\",\n\"aXaX7X*.,.,.< -XaXaXaXaXpX9.:.> R.R.R.R.R.R.R.+ :.0.yXaXaXaXaXaXaXaXaXpX9.,.< R.U.U.U.R.U.R.: ,.6.pXaXaXaXaX-X> ,.,.*.3XaXaXaXaX\",\n\"aXaX#X:.,.:.N pXaXaXaXaXW.;.k L aXaXaXaXaXaXaXD.s :.k.aXaXaXaXaXaXaXaX~.;.j J aXaXiXaXiXiXaXN.s :.x.aXaXaXaXaXM :.,.:.'.aXaXaXaX\",\n\"aXaX^.:.,.;.V.aXaXaXaXtX1.:.. ;XaXaXaXaXaXaXaXrX$ o.&.6XaXaXaXaXaXaXeX0.,.O *XaXaXaXaXaXaXaX8XX *.1.tXaXaXaXaX}.&.,.:.W.aXaXaXaX\",\n\"aXaX^.:.,.*.s.n.n.n.n.l.,.j D.aXaXaXaXaXaXaXaXaXK.s ,.l.!.b.!.b.b.!.l.,.j Z.aXaXaXaXaXaXaXaXaXD.k :.l.^.^.^.^.~.| ,.:.v.aXaXaXaX\",\n\"aXaXW.:.,.*.&.&.&.&.&.*.,.M aXaXaXaXaXaXaXaXaXaXaXV *.*.<.=.=.<.<.=.&.,.m iXaXaXaXaXaXaXaXaXaXaXm *.*.6.0.%.5.5...,.:.v.aXaXaXaX\",\n\"aXaXG.:.,.,.U Y U U U U :.p.aXaXaXaXaXaXaXaXaXaXaXH.*.R E U E U E E Y :.i.aXaXaXaXaXaXaXaXaXaXaXA.*.R E E E E W =.,.:.x.aXaXaXaX\",\n\"aXaXS.,.,.:.n M i i p $ o.3.9XaXaXaXaXaXaXaXaXaXrXr.>.@ y t t t t y $ *.r.eXaXaXaXaXaXaXaXaXaXyXj.:., 8 9 9 9 t ,.,.:.i.aXaXaXaX\",\n\"aXaXK.&.,.:.y.L.L.L.P.J k :.c.aXaXaXaXaXaXaXaXaX~.:.Y H D.A.A.A.A.D.H U :.~.aXaXaXaXaXaXaXaXaX~.:.T J i.I I P t.:.,.;.B.aXaXaXaX\",\n\"aXaX-XY ,.:.<.rXaXaXaXaXw _ &.<XaXaXaXaXaXaXaX8Xo.X.- aXaXaXaXaXaXaXiX8 | o.1XaXaXaXaXaXaXaX9Xo.X.- aXpXaXiXpXj.:.,.( |.aXaXaXaX\",\n\"aXaXaX= ,.,.:._.aXaXaXaXP.> :.g.tXyXrXrXrXrXyXx.:.s N.aXaXaXaXaXaXaXaXS.s :.x.tXyXyXyXyXyXtXW.:.k L aXaXaXaX$X;.,.,.a pXaXaXaXaX\",\n\"aXaXaXB | ,.:.X.<XaXaXaXaXu } ,.Y.'.'.'.'.'.].>.} q aXaXaXaXaXaXaXaXaXpXw } ;. X+X+X+X+X+XOX*.} q aXaXaXaXrX$.:.,.o.9 aXaXaXaXaX\",\n\"aXaXaX@X> ,.,.:.k.pXaXaXaX3X> ,.O.+.+.+.+.+.O.,.>  XaXaXaXaXaXaXaXaXaXaX X> :.o.=.=.=.=.=.+.:.> T.aXaXaXpX_.:.,.:.j K.aXaXaXaXaX\",\n\"aXaXaXaX; o.,.,.:.+XpXaXaXwX;.*.q r r r r 4 q *.&.wXaXaXaXaXaXaXaXaXaXaXiXo.-.f b h h b b f -.| iXaXaXpX;X;.,.,.o.* aXaXaXaXaXaX\",\n\"aXaXaXaX;X  *.,.,.:.#XiXaXs.:.d ; ; ; ; * ; ; s :.s.aXaXaXaXaXaXaXaXaXaXG.:.j ; ; ; ; * ; ; l :.J.aXaX3X*.,.,.;.  D.aXaXaXaXaXaX\",\n\"aXaXaXaXaXt @ ;.,.,.,.Y.rX;.>.o iXaXiXaXaXpXpXo >.;.eXaXaXaXaXaXaXaXaXeX;.>.o aXiXaXpXaXaXpXo ;.*.iX4X*.:.,.:.g o aXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXX 4 :.,.,.,.^ :.  -XaXaXaXaXaXaXaX-X  :.[ aXaXaXaXaXaXaXaX[ :.  @XaXaXaXaXaXaXaXT.o :.T :.,.,.:.Q   pXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXiX. 3 :.,.,.:.O.t pXaXaXaXaXaXaXaXaX& ..:.5XaXiXaXaXaXaX5X,.O.$ aXaXaXaXaXaXaXaXaX7 } :.,.,.:.c   0XaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaX9X  - ,.,.,.,.-.@..XaXaXaXaXaXaXaX0XO ,.<.#.#.#.#.#.#.<.,.O 0XaXaXaXaXaXaXaX5X[ -.;.,.,.:.r . =XaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaX;XX = _ :.,.,.;.2.4.G.6XaXaXaXaXaXM.;.:.;.;.;.;.;.;.;.*.M.aXaXaXaXaXtXY.[ 3.;.,.,.:.-.2 . ;XaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaX*Xw : 3 ,.,.,.,.;.2.w.4.Q.2XrXpXh.:.e y y w w w y 3 :.l.aXaX5X_.8.0.3.;.,.,.:.,.g > X *XaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaX*XF.X 1 g ,.:.,.,.,.-.1.e.e.{ O./ 2 q 8 m m m 8 ; _ #.7.9.e.3.*.,.,.:.:.:.W 4 @ K OXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXwXE.S o a f #.:.:.:.:.,.:.&.>.=. . . .@.@.@. ._ -.-.*.-.,.,.:.:.,.=.x f # w E.8XpXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXpX=XI.A $ 1 h c _ :.,.,.:.,.:.,.,.:.:.,.,.:.,.,.,.:.,.,.:.O.W b a @ p I.].aXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaX#XH.P 0 @ 1 g g v ` #.-.:.:.:.:.,.:.:.,.>.O.) W g g a , % H L.E.aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX9XP.D.P N $ * < a k k z z z z z z z k a 1 = $ y H D.F.*XaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX8XR.Z.Z.Z.H A N t 8 8 9 8 w i Z D I Z.C.I.*XaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXiX;XOXI.H.A.A.A.A.F.I.E.=XuXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\",\n\"aXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaX\"\n};\n'''\n        return XPM\n\n    def __getstate__(self):\n        '''When saving the document this object gets stored using Python's json module.\\\n               Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\\\n               to return a tuple of all serializable objects or None.'''\n        return None\n\n    def __setstate__(self,state):\n        '''When restoring the serialized object from document we have the chance to set some internals here.\\\n               Since no data were serialized nothing needs to be done here.'''\n        return None\n\n\n\nif __name__ == \"__main__\":\n\n    import os\n    import FreeCAD, FreeCADGui, Part\n    if \".FCMacro\" in __file__ and not os.path.exists(__file__.replace(\".FCMacro\",\".py\")):\n        current = __file__\n        new_name = current.replace(\".FCMacro\", \".py\")\n        with open(new_name, \"w\") as new_file:\n            with open(__file__, \"r\") as current_file:\n                new_file.write(current_file.read())\n        FreeCAD.Console.PrintWarning(\"A new file has been created named Honeycomb.py in order for Honeycomb objects to work when you reload a document containing a Honeycomb object.\\n\")\n    import Honeycomb\n    import importlib\n    importlib.reload(Honeycomb)\n\n    doc = FreeCAD.ActiveDocument if FreeCAD.ActiveDocument else FreeCAD.newDocument()\n    body=FreeCADGui.ActiveDocument.ActiveView.getActiveObject(\"pdbody\")\n    if body:\n        fp = doc.addObject(\"PartDesign::FeatureAdditivePython\",\"Honeycomb\")\n    else:\n        fp = doc.addObject(\"Part::FeaturePython\",\"HoneyComb\")\n    Honeycomb.Honeycomb(fp)\n    Honeycomb.HoneycombVP(fp.ViewObject)\n    # selx = FreeCADGui.Selection.getSelection()\n    # if selx:\n    #     profile = selx[0]\n    #     if hasattr(profile,\"Shape\"):\n    #         fp.Profile = profile\n\n    if body:\n        body.addObject(fp)\n\n    if not hasattr(fp,\"Version\") or fp.Version != __version__:\n        FreeCAD.Console.PrintError(f\"Version mismatch.  Version of Honeycomb.py is outdated.  New version is {__version__}.  You can delete Honeycomb.py from your macro folder, delete the newly created Honeycomb object, and re-run Honeycomb.FCMacro to recreate a new version.  Then save your file and restart FreeCAD to complete the update.\\n\")\n",
    "url": "https://wiki.freecad.org/Macro_Honeycomb",
    "raw_code_url": "https://gist.github.com/mwganson/97d185ac2114701b26d3da47dccc9f7a/raw/46b27ad36991a460e9772ddb5e73b3115a1329be/Honeycomb.py",
    "wiki": "",
    "version": "0.2024.08.27",
    "license": "",
    "date": null,
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Honeycomb.svg",
    "icon_source": "https://wiki.freecad.org//images/b/b1/Macro_Honeycomb.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "ImportAirfoil",
    "on_wiki": true,
    "on_git": false,
    "desc": "Macro for Airfoil coordinates import.<br /><br />Macro version: 1.0.0<br />Last modified: 2022-01-08<br />FreeCAD version: 0.18.4 and above<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/3/37/ImportAirfoil.svg\">ToolBar Icon</a><br />Author: Milo\u0161 Petra\u0161inovi\u0107<br /> ",
    "comment": "Airfoil import macro",
    "code": "# Airfoil import macro\n# After selecting the file with the coordinates of the airfoil\n# data processing and modeling of the airfoil are performed.\n# It is possible, using simple dialog, to scale the airfoil, rotate, \n# translate in the plane, translate along the span, select the plane and \n# the main axis, as well as turn the geometry into a sketch. It is possible\n# to import coordinates saved in the most commonly used formats.\n# Airfoil import is based on:\n#  https://github.com/VAZMFB/Python-importAirfoil\n# Author: Milos D. Petrasinovic <mpetrasinovic@mas.bg.ac.rs>\n# Structural Analysis of Flying Vehicles\n# Faculty of Mechanical Engineering, University of Belgrade\n# Department of Aerospace Engineering, Flying structures\n# https://vazmfb.com\n# Belgrade, 2022\n# \n# --------------------\n#\n# Copyright (C) 2022 Milos Petrasinovic <info@vazmfb.com>\n# \n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU Lesser General Public License as \n# published by the Free Software Foundation, either version 3 of the \n# License, or (at your option) any later version.\n#  \n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU Lesser General Public License for more details.\n#  \n# You should have received a copy of the GNU Lesser General Public License\n# along with this program.  If not, see <https://www.gnu.org/licenses/>.\n#\n# --------------------\n#\n# Based on:\n# Airfoil Import and Scale 2.1.2\n# (c) quick61\n#\n# --------------------\n\n__Name__ = 'ImportAirfoil'\n__Comment__ = 'Airfoil import macro'\n__Author__ = 'Milos Petrasinovic <mpetrasinovic@mas.bg.ac.rs>'\n__Version__ = '1.0.0'\n__Date__ = '2022-01-06'\n__License__ = 'GPL-3.0-or-later'\n__Web__ = 'https://github.com/VAZMFB/FreeCAD-ImportAirfoil'\n__Wiki__ = 'https://wiki.freecadweb.org/Macro_ImportAirfoil'\n__Icon__ = 'https://wiki.freecad.org/images/3/37/ImportAirfoil.svg'\n__Help__ = 'Run the macro program and follow the instructions!'\n__Status__ = 'stable'\n__Requires__ = 'Freecad >= 0.19'\n__Communication__ = 'https://github.com/VAZMFB/FreeCAD-ImportAirfoil/issues/'\n__Files__ = 'ImportAirfoil.svg'\n\nimport FreeCAD as App\nfrom PySide import QtCore, QtGui\nfrom PySide.QtGui import QFileDialog, QLineEdit, QRadioButton, QMessageBox \nimport Draft, importAirfoilDAT\nimport numpy as np\nimport subprocess\nimport sys\nimport os\nimport re\n\nglobal filename\nglobal nameFile\n\nmsgBox = QtGui.QMessageBox()\nmsgBox.setWindowTitle(\"ImportAirfoil\")\nmsgBox.setText(\"In the next window, select the file with the coordinates of the airfoil.\")\nmsgBox.exec_()\n\ntry:\n    filename, filefilter = QtGui.QFileDialog.getOpenFileName(QtGui.qApp.activeWindow(), 'Select the file with the coordinates:', '*.dat;*.txt;*.af')\nexcept Exception:\n    param = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")\n    path = param.GetString(\"MacroPath\", \"\") + \"/\"\n    filename, filefilter = QFileDialog.getOpenFileName(None, \"Select the file with the coordinates:\", path, \"*.dat;*.txt;*.af\")\n\nnameFile = filename.split(\"/\")[-1][:-4]\n\nclass DrawAP():\n    def __init__(self):\n        self.dialog = None\n        self.lt = 0\n        self.alpha = 0\n        self.h0 = 0\n        self.plane = None\n        self.mirror = None\n        self.dh = 0\n        self.dv = 0\n        self.db = 0\n        self.sketch = None\n\n        # Dialog window\n        self.dialog = QtGui.QDialog()\n        self.dialog.resize(350, 100)\n        self.dialog.setWindowTitle(\"ImportAirfoil\")\n        la = QtGui.QVBoxLayout(self.dialog)\n        tx = QtGui.QLabel(\"Length of airfoil chord [mm]:\")\n        la.addWidget(tx)\n        self.lt = QtGui.QLineEdit(\"1000\")\n        la.addWidget(self.lt)\n        tx = QtGui.QLabel(\"The angle of rotation [deg]:\")\n        la.addWidget(tx)\n        self.alpha = QtGui.QLineEdit(\"0\")\n        la.addWidget(self.alpha)\n        tx = QtGui.QLabel(\"The relative position of the axis of rotation [% of chord]:\")\n        la.addWidget(tx)\n        self.h0 = QtGui.QLineEdit(\"25\")\n        la.addWidget(self.h0)\n        tx = QtGui.QLabel(\"Plane selection [XY = 1, YZ = 2, ZX = 3]:\")\n        la.addWidget(tx)\n        self.plane = QtGui.QLineEdit(\"1\")\n        la.addWidget(self.plane)\n        tx = QtGui.QLabel(\"Vertical mirroring [NO = 0, YES = 1]:\")\n        la.addWidget(tx)\n        self.mirror = QtGui.QLineEdit(\"0\")\n        la.addWidget(self.mirror)\n        tx = QtGui.QLabel(\"Change axis [NO = 0, YES = 1]:\")\n        la.addWidget(tx)\n        self.flip = QtGui.QLineEdit(\"0\")\n        la.addWidget(self.flip)\n        tx = QtGui.QLabel(\"Translation along the horizontal axis [mm]:\")\n        la.addWidget(tx)\n        self.dh = QtGui.QLineEdit(\"0\")\n        la.addWidget(self.dh)\n        tx = QtGui.QLabel(\"Translation along the vertical axis [mm]:\")\n        la.addWidget(tx)\n        self.dv = QtGui.QLineEdit(\"0\")\n        la.addWidget(self.dv)\n        tx = QtGui.QLabel(\"Translation along the span [mm]:\")\n        la.addWidget(tx)\n        self.db = QtGui.QLineEdit(\"0\")\n        la.addWidget(self.db)\n        tx = QtGui.QLabel(\"Create a Sketch [NO = 0, YES = 1]:\")\n        la.addWidget(tx)\n        self.sketch = QtGui.QLineEdit(\"0\")\n        la.addWidget(self.sketch)\n\n        # Add OK / Cancel buttons\n        okBox = QtGui.QDialogButtonBox(self.dialog)\n        okBox.setOrientation(QtCore.Qt.Horizontal)\n        okBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel",
    "url": "https://github.com/VAZMFB/FreeCAD-ImportAirfoil",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_ImportAirfoil",
    "version": "1.0.0",
    "license": "",
    "date": "2022-01-06",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Milos Petrasinovic <mpetrasinovic@mas.bg.ac.rs>",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\ImportAirfoil.svg",
    "icon_source": "https://wiki.freecad.org/images/3/37/ImportAirfoil.svg",
    "xpm": "",
    "other_files": [
      "ImportAirfoil.svg"
    ],
    "parsed": true
  },
  {
    "name": "Intersection",
    "on_wiki": true,
    "on_git": false,
    "desc": "Finds the intersection between 2 or 3 selected edges / faces.<br /><br />Macro version: 2024.10.17<br />Last modified: 2024-10-17<br />FreeCAD version: 0.19 or later<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/images/e/e7/Intersection_Icon.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Finds the intersection between 2 or 3 selected edges / faces.",
    "code": "__version__ = \"2024.10.17\"\n__title__ = \"Intersection\"\n__author__ = \"<TheMarkster> 2021\"\n__license__ = \"LGPL 2.1\"\n__doc__ = \"Find the intersection of 2 or 3 faces/edges\"\n__usage__ = '''Select 2 faces or edges in the 3d view and run the macro'''\nfrom PySide import QtGui,QtCore\nimport FreeCAD, FreeCADGui, Part\nimport os\n\nGui = FreeCADGui\nApp = FreeCAD\n#intersection macro, (c) 2022, by <TheMarkster>\n#Full documentation on github at https://github.com/mwganson/intersection\nclass Intersection:\n    def __init__(self,obj):\n        obj.Proxy = self\n        obj.addProperty(\"App::PropertyVector\",\"Center\",\"Intersection\",\"Center of Mass of intersection result\")\n        obj.addProperty(\"App::PropertyBool\",\"EnableLogging\",\"Intersection\",\"Enable log messages\").EnableLogging = False\n        obj.addProperty(\"App::PropertyEnumeration\",\"ObjectOrder\",\"Intersection\",\"Order of evaluation\").ObjectOrder =\\\n                [\"1,2,3\",\"1,3,2\",\"2,1,3\",\"2,3,1\",\"3,1,2\",\"3,2,1\",\"1,2\",\"2,1\",\"1,3\",\"3,1\",\"3,2\",\"2,3\"]\n        obj.addProperty(\"App::PropertyLinkSub\",\"Object1\",\"Intersection\",\"First intersection object\")\n        obj.addProperty(\"App::PropertyLinkSub\",\"Object2\",\"Intersection\",\"Second intersection object\")\n        obj.addProperty(\"App::PropertyLinkSub\",\"Object3\",\"Intersection\",\"Optional 3rd object\")\n        obj.addProperty(\"App::PropertyBool\",\"HasIntersection\",\"Intersection\",\"If intersection is found this will be True\")\n        obj.addProperty(\"App::PropertyBool\",\"CheckVertexIntersection\",\"Intersection\",\\\n    \"When there are 3 objects and the intersection of the first 2 is a vertex, set this True \\\n    to require that the vertex lies on the 3rd face or edge\\n\").CheckVertexIntersection = False\n        obj.addProperty(\"App::PropertyBool\",\"ResetOnRecompute\",\"Intersection\",\"Reset shape to null at the start of each recompute\").ResetOnRecompute = True\n        obj.addProperty(\"App::PropertyFloatConstraint\",\"Tolerance\",\"Intersection\",\"Tolerance, default: 0.01 mm\").Tolerance = (0.01,0,float(\"inf\"),.01)\n        obj.addProperty(\"App::PropertyString\",\"Type\",\"Intersection\",\"Type of the intersection object or None\").Type=\"None\"\n        obj.addProperty(\"App::PropertyString\",\"Version\",\"Intersection\").Version = __version__\n        obj.addProperty(\"App::PropertyEnumeration\",\"Trimming\",\"Intersection\",\"If Trimmed, then the intersection edge is attempted to be trimmed to surfaces\\n\\\n    If the intersection does not lie on the surface/edge, then it will not be considered an intersection in Trimmed mode.\").Trimming = \\\n    [\"Untrimmed\",\"Trimmed\"]\n        obj.setEditorMode(\"HasIntersection\",1) #readonly\n        obj.setEditorMode(\"Version\",1)\n        obj.setEditorMode(\"Type\",1)\n        self.fpName = obj.Name\n        self.editingMode = False\n\n    def log(self,fp,msg):\n        if fp.EnableLogging:\n            FreeCAD.Console.PrintLog(msg)\n\n    def validate(self, fp, propName):\n        prop = getattr(fp,propName)\n        if not prop:\n            return\n        prop1 = prop[1]\n        if not prop1:\n            obj = prop[0]\n            if len(obj.Shape.Faces) == 1:\n                prop1 = \"Face1\" if not obj.isDerivedFrom(\"PartDesign::Plane\") else \"Plane\"\n            elif len(obj.Shape.Edges) == 1:\n                prop1 = \"Edge1\" if not obj.isDerivedFrom(\"PartDesign::Line\") else \"Line\"\n            elif len(obj.Shape.Vertexes) == 1:\n                prop1 = \"Vertex1\" if not obj.isDerivedFrom(\"PartDesign::Point\") else \"Point\"\n                FreeCAD.Console.PrintWarning(\"Intersection: Vertex objects not supported\\n\")\n            else:\n                return\n            setattr(fp,propName,(obj,prop1))\n\n    def execute(self,fp):\n        if fp.ResetOnRecompute:\n            fp.Shape = Part.Shape()\n        self.validate(fp,\"Object1\")\n        self.validate(fp,\"Object2\")\n        self.validate(fp,\"Object3\")\n        shape = self.findIntersection(fp)\n        if not shape.isNull():\n            fp.Shape = self.makeShapeType(fp,shape)\n        fp.Type = self.getIntersectionType(fp,fp.Shape)\n        try:\n            fp.Shape.check()\n            fp.HasIntersection = not fp.Shape.isNull()\n        except:\n            fp.HasIntersection = False\n            fp.Shape = Part.Shape()\n\n    def makeShapeType(self,fp,shp):\n        if fp.Trimming == \"Untrimmed\":\n            return shp\n        if fp.Trimming == \"Trimmed\":\n            obj1,obj2,obj3 = self.getOrderedObjectShapes(fp)\n\n            common = shp.common(obj1) if obj1 and not obj1.isNull() else shp\n            common = common.common(obj2) if obj2 and not obj2.isNull() else common\n            common = common.common(obj3) if obj3 and  not obj3.isNull() else common\n            return common\n\n    def getIntersectionType(self,fp,shp):\n        if hasattr(shp,\"Compound1\") and hasattr(shp.Compound1,\"Edge1\"):\n            fp.Center = shp.Compound1.Edge1.CenterOfGravity\n            return shp.Compound1.Edge1.Curve.TypeId\n        if hasattr(shp,\"Surface\"):\n            fp.Center = shp.Surface.Position\n            return shp.Surface.TypeId\n        if hasattr(shp,\"Vertex1\"):\n            fp.Center = shp.Vertex1.Point\n            return shp.Vertex1.ShapeType\n        if not shp:\n            fp.Center = FreeCAD.Vector()\n            return \"None\"\n        if hasattr(shp,\"isNull\") and shp.isNull():\n            fp.Center = FreeCAD.Vector()\n            return \"Null shape\"\n        return shp.ShapeType\n\n    def getIntersectionShape(self,fp,intersection):\n        \"\"\"return geometry / list as shape\"\"\"\n        shape = Part.Shape()\n        #self.log(fp,f\"Intersection macro: intersection = {intersection}\\n\")\n        if intersection:\n            self.log(fp,f\"getintshp(): intersection = {intersection}\\n\")\n            intObj = intersection #can be [point,point...] or line or [bspline,bspline...]\n            if isinstance(intObj,list):\n                self.log(fp,f\"getintshp(): intObj is list\\n\")\n                shapes = [sh.toShape() for sh in intObj]\n                self.log(fp,f\"getintshp(): shapes = {shapes}\\n\")\n                shape = Part.makeCompound(shapes) if len(shapes)>1 else shapes[0]\n            elif isinstance(intObj,tuple):\n                self.log(fp,f\"getintshp(): intersection is a tuple\\n\")\n                shapes = [sh.toShape() for sh in intObj[0]]\n                self.log(fp,f\"getintshp(): shapes = {shapes}\\n\")\n                shape = Part.makeCompound(shapes) if len(shapes) > 1 else shapes[0] if shapes else Part.Shape()\n            else:\n                shape = intersection.toShape() if hasattr(intersection,\"toShape\") else Part.Shape()\n        self.log(fp,f\"getintshp():(after) shape = {shape}\\n\")\n        return shape\n\n    def getOrderedObjectShapes(self,fp):\n        \"\"\"gets the shapes user has set for the Object links according to the order in fp.ObjectOrder\"\"\"\n        obj,sub = fp.Object1 if fp.Object1 else (None, None)\n        s1 = Part.getShape(obj, sub[0]) if obj else None\n        obj,sub = fp.Object2 if fp.Object2 else (None, None)\n        s2 = Part.getShape(obj, sub[0]) if obj else None\n        obj,sub = fp.Object3 if fp.Object3 else (None, None)\n        s3 = Part.getShape(obj, sub[0]) if obj else None\n\n        orders = [(s1,s2,s3),(s1,s3,s2),(s2,s1,s3),(s2,s3,s1),(s3,s1,s2),(s3,s2,s1),\\\n        (s1,s2,None),(s2,s1,None),(s1,s3,None),(s3,s1,None),(s3,s2,None),(s2,s3,None)]\n        s1,s2,s3 = orders[fp.getEnumerationsOfProperty(\"ObjectOrder\").index(fp.ObjectOrder)]\n        return (s1,s2,s3)\n\n\n    def findIntersection(self,fp):\n        if not fp.Object1 or not fp.Object2:\n            return Part.Shape()\n        try:\n            s1,s2,s3 = self.getOrderedObjectShapes(fp)\n        except Exception as ex:\n            FreeCAD.Console.PrintError(f\"{ex}\")\n            return Part.Shape()\n        c1 = s1.Curve if hasattr(s1,\"Curve\") else s1.Surface if hasattr(s1,\"Surface\") else None\n        c2 = s2.Curve if hasattr(s2,\"Curve\") else s2.Surface if hasattr(s2,\"Surface\") else None\n        c3 = s3.Curve if hasattr(s3,\"Curve\") else s3.Surface if hasattr(s3,\"Surface\") else None\n        if not bool(c1 != None and c2 != None):\n            FreeCAD.Console.PrintError(\"First 2 shapes in the shape order have to be valid shapes, neither can null or empty\\n\")\n            return Part.Shape()\n        intersection = c1.intersect(c2, fp.Tolerance)\n        if not intersection:\n            self.log(fp,\"No intersection, trying c2 -> c1 instead of c1 -> c2\\n\")\n            intersection = c2.intersect(c1, fp.Tolerance)\n            intersection = self.getIntersectionShape(fp,intersection)\n        if not intersection:\n            self.log(fp,\"No intersection between c1 and c2\\n\")\n            return Part.Shape()\n        intersection = self.trimEdgeToSurfaces(fp,intersection,s1,s2)\n        shape = self.getIntersectionShape(fp, intersection)\n        if shape.isNull():\n            self.log(fp,\"No intersection shape\\n\")\n            return Part.Shape()\n        if not c3: #success with first 2 objects, no third object\n            self.log(fp,f\"checking shape = {shape} and s2 = {s2} \\n\")\n            shape = self.checkVertexIntersection(fp, shape, s2)\n            if shape.isNull():\n                self.log(fp,\"check vertex intersection returned null shape\\n\")\n                return shape #shape was not inside c2\n            else:\n                shape = self.checkVertexIntersection(fp, shape, s1)\n                self.log(fp,f\"shape.isNull() = {shape.isNull()} after checking vertex with s1 {s1}\\n\")\n                return shape\n        c4 = shape.Curve if hasattr(shape,\"Curve\") else shape.Surface if hasattr(shape,\"Surface\") else None\n        if not c4: #intersection at vertex found, now check against c3, c2, and c1\n            return self.checkAllVertexIntersections(fp, shape, s1, s2, s3)\n        #intersection was not a vertex, so must be an edge\n        #c4 is the curve result, c3 is the surface/curve of Object3\n        self.log(fp,f\"checking c3.intersect(c4,fp.Tolerance) {c3}.intersect({c4},fp.Tolerance)\\n\")\n        intersection = c3.intersect(c4,fp.Tolerance) if c4 else None\n        self.log(fp,f\"intersection = {intersection}\\n\")\n        if not intersection:\n            return Part.Shape()\n        return self.getIntersectionShape(fp,intersection)\n\n    def checkVertexIntersection(self, fp, shp, s3):\n        \"\"\"shp is a vertex shape inside a compound, s3 is an object, either a Curve or a Surface to test shp\n            for intersection with.  Returns the vertex if it intersects with s3, or a null shape if not.\"\"\"\n        if not fp.CheckVertexIntersection:\n            return shp\n        if shp.isNull():\n                self.log(fp,\"ckvtx: shp is null\\n\")\n                return shp\n        self.log(fp,f\"checkVertexIntersection(): shp = {shp}, s3 = {s3}\\n\")\n        if not hasattr(shp,\"Face1\") and not hasattr(shp,\"Edge1\") and not hasattr(shp,\"Plane\") and not hasattr(shp,\"Line\") and hasattr(shp,\"Vertex1\"):\n            msgs = [f\"shp {shp} is a vertex, pt = {v.Point}\\n\" for v in s3.Vertexes]\n            for msg in msgs:\n                self.log(fp,msg)\n            verts = [v for v in shp.Vertexes if v.distToShape(s3)[0] <= fp.Tolerance]\n            if not verts:\n                self.log(fp,f\"ckvtxint: no points out of {len(s3.Vertexes)} found on {s3}\\n\")\n            for v in verts:\n                self.log(fp,f\"ckvtxint: {v.Point} is on {s3}\\n\")\n            comp = Part.makeCompound(verts) if verts else Part.Shape()\n            self.log(fp,f\"comp.check(True) = {comp.check(True)}\\n\")\n            return comp\n        else: #was not a vertex\n            self.log(fp,f\"{shp} was Not a vertex\\n\")\n            return shp\n\n    def trimEdgeToSurfaces(self,fp,curve,surface1,surface2):\n        \"\"\"return from intersect() is sometimes a line, but the line extends beyond the face.\n        this seeks to trim the line/curve to the confines of thos surfaces\"\"\"\n        self.log(fp,f\"trim(): curve = {curve}, surface1 = {surface1}, surface2 = {surface2}\\n\")\n        return curve\n\n    def checkAllVertexIntersections(self, fp, shp, s1, s2, s3):\n        shape = self.checkVertexIntersection(fp, shp, s3)\n        if shape.isNull():\n            return shape\n        else:\n            shape = self.checkVertexIntersection(fp, shape,s2)\n            if shape.isNull():\n                return shape\n            else:\n                return self.checkVertexIntersection(fp, shape,s1)\n\n    def editFaces(self):\n        from PySide import QtGui\n        fp = FreeCAD.ActiveDocument.getObject(self.fpName)\n        if not FreeCADGui.Control.activeDialog():\n            panel = TaskEditLinkSubPanel(fp,[\"Object1\",\"Object2\",\"Object3\"],\"Faces/Edges\")\n            FreeCADGui.Control.showDialog(panel)\n            self.editingMode = True #tells execute() not to hide the linked object\n        else:\n            self.editingMode=False\n            FreeCAD.Console.PrintError(\"Another task dialog is active.  Close that one and try again.\\n\")\n\n\n\nclass TaskEditLinkSubPanel: #simple editor for App::PropertyLinkSub\n    def __init__(self, obj, linkSubNames, subNames,):\n        self.obj = obj\n        self.subNames = subNames\n        self.linkSubNames = linkSubNames #list of property names\n        self.linkObjs = []\n        self.subObjects = []\n        for ii,lsn in enumerate(self.linkSubNames):\n            if lsn:\n                atr = getattr(self.obj,self.linkSubNames[ii])\n                if atr and len(atr) == 2:\n                    self.linkObjs.append(atr[0])\n                    self.subObjects.append(atr[1])\n        self.obj.Proxy.log(self.obj, f\"linkObjs = {self.linkObjs}, subObjects = {self.subObjects}\\n\")\n        self.form = QtGui.QWidget()\n        self.label1 = QtGui.QLabel(\"Select the \"+self.subNames+\" subobjects to use and click OK.\\nThe ones already being utilized have been selected for you.\")\n        layout=QtGui.QHBoxLayout()\n        layout.addWidget(self.label1)\n        self.form.setLayout(layout)\n        self.form.setWindowTitle('Edit '+self.subNames)\n        FreeCADGui.Selection.clearSelection()\n        for ii,linkObj in enumerate(self.linkObjs):\n            for f in self.subObjects[ii]:\n                FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Name,linkObj.Name,f)\n        self.obj.Proxy.editingMode = True\n\n    def reject(self):\n        FreeCADGui.Control.closeDialog()\n        fp = self.obj\n        self.obj.Proxy.editingMode = False\n        FreeCADGui.activeDocument().resetEdit()\n        FreeCAD.ActiveDocument.recompute()\n\n    def accept(self):\n        FreeCADGui.ActiveDocument.resetEdit()\n        FreeCADGui.Control.closeDialog()\n        fp = self.obj\n        if not fp: #user deleted or closed document perhaps\n            return\n        selx = FreeCADGui.Selection.getSelectionEx()\n        if not selx:\n            FreeCAD.Console.PrintWarning(\"Nothing selected, leaving \"+self.linkObj.Name+\" unmodified.\")\n            return\n        subobjects = []\n        for s in selx:\n            if s.HasSubObjects:\n                for en in s.SubElementNames:\n                    subobjects.append((s.Object,en))\n            else:\n                if s.Object.isDerivedFrom(\"PartDesign::Plane\"):\n                    subobjects.append((s.Object,\"Plane\"))\n                elif s.Object.isDerivedFrom(\"PartDesign::Line\"):\n                    subobjects.append((s.Object,\"Line\"))\n                elif not hasattr(s.Object,\"Shape\"):\n                    FreeCAD.Console.PrintWarning(f\"Skipping {s.Object.Label}\\n\")\n                    continue\n                elif len(s.Object.Shape.Faces) == 1:\n                    subobjects.append((s.Object,\"Face1\"))\n                elif len(s.Object.Shape.Edges) == 1:\n                    subobjects.append((s.Object,\"Edge1\"))\n        if len(subobjects) > 3 or len(subobjects) == 0:\n            FreeCAD.Console.PrintError(\"Selection Error, select 1, 2, or 3 objects\\n\")\n            raise Exception(\"Invalid selection\\n\")\n        else:\n            for linkSubName in self.linkSubNames:\n                setattr(self.obj, linkSubName, None)\n            for ii,subobject in enumerate(subobjects):\n                setattr(self.obj,self.linkSubNames[ii], subobject)\n        if hasattr(fp,\"_Body\") and fp._Body and self.linkObj not in fp._Body.Group:\n            fp._Body.Group += [self.linkObj]\n        if hasattr(fp.Proxy,\"editingMode\"):\n            fp.Proxy.editingMode = False\n        FreeCAD.ActiveDocument.recompute()\n\n\nclass IntersectionVP:\n\n    def __init__(self, obj):\n        '''Set this object to the proxy object of the actual view provider'''\n        obj.Proxy = self\n\n    def setEdit(self,vobj,modNum):\n        #FreeCAD.Console.PrintMessage(\"modNum = \"+str(modNum)+\"\\n\")\n        if modNum == 0:\n            vobj.Object.Proxy.editFaces()\n            return True\n        elif modNum == 3: #color per face\n            FreeCADGui.runCommand('Part_ColorPerFace',0)\n            return True\n\n    def attach(self, obj):\n        '''Setup the scene sub-graph of the view provider, this method is mandatory'''\n        self.Object = obj.Object\n\n    def updateData(self, fp, prop):\n        '''If a property of the handled feature has changed we have the chance to handle this here'''\n        # fp is the handled feature, prop is the name of the property that has changed\n        #FreeCAD.Console.PrintMessage(prop+\" is now \"+str(getattr(fp,prop))+chr(10))\n        if prop == \"HasIntersection\":\n            fp.ViewObject.signalChangeIcon()\n    def getDisplayModes(self,obj):\n        '''Return a list of display modes.'''\n        modes=[]\n        modes.append(\"Flat Lines\")\n        return modes\n\n    def getDefaultDisplayMode(self):\n        '''Return the name of the default display mode. It must be defined in getDisplayModes.'''\n        return \"Flat Lines\"\n\n    def setDisplayMode(self,mode):\n        '''Map the display mode defined in attach with those defined in getDisplayModes.\\\n                Since they have the same names nothing needs to be done. This method is optional'''\n        return mode\n\n    def onChanged(self, vp, prop):\n        '''Here we can do something when a single property got changed'''\n        pass\n\n    def onDelete(self, vobj, subelements):\n        return True\n\n    def getIcon(self):\n        '''Return the icon in XPM format which will appear in the tree view. This method is\\\n                optional and if not defined a default icon is shown.'''\n        xpm =__xpm__\n        fp = self.Object\n        color = \"None\" if fp.HasIntersection else \"red\"\n        fp.ViewObject.LineColor = (1.,0.,0.) if not fp.HasIntersection else (0.,0.,1.)\n        fp.ViewObject.PointColor = (1.,.5,0.) if not fp.HasIntersection else (0.,1.,1.)\n        return xpm.replace(\"None\",color)\n\n    def __getstate__(self):\n        '''When saving the document this object gets stored using Python's json module.\\\n                Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\\\n                to return a tuple of all serializable objects or None.'''\n        return None\n\n    def __setstate__(self,state):\n        '''When restoring the serialized object from document we have the chance to set some internals here.\\\n                Since no data were serialized nothing needs to be done here.'''\n        return None\n\n\n\ndef findHome(fp, datum1=None):\n    \"\"\"find a home for fp, either in a Part or a Body, if one is active\n       or in same container as datum1 if none are active\"\"\"\n    foundHome = False\n    body=FreeCADGui.ActiveDocument.ActiveView.getActiveObject(\"pdbody\")\n    part=FreeCADGui.ActiveDocument.ActiveView.getActiveObject(\"part\")\n    if body:\n        body.Group=body.Group+[fp]\n        foundHome = True\n    if not foundHome and datum1:\n        parent = None\n        if datum1.Parents:\n            parent=datum1.Parents[0][0] #put in same body as Object1\n        if parent and parent.TypeId == \"App::Part\":\n            part = parent\n            if not foundHome:\n                for obj in parent.Group:\n                    if obj.TypeId == \"PartDesign::Body\":\n                        if datum1 in obj.Group:\n                            obj.Group += [fp]\n                            foundHome = True\n        elif parent and parent.TypeId == \"PartDesign::Body\":\n            if not body and not foundHome:\n                parent.Group += [fp]\n                foundHome = True\n        if not foundHome:\n            if part:\n                part.Group += [fp]\n    return foundHome\n\ndef makeObject(FP):\n\n    doc = FreeCAD.ActiveDocument\n    if doc:\n        fp = doc.addObject(\"Part::FeaturePython\",\"Intersection\")\n        if FP:\n            FP.Intersection(fp)\n            FP.IntersectionVP(fp.ViewObject)\n        else:\n            Intersection(fp)\n            IntersectionVP(fp.ViewObject)\n        fp.ViewObject.PointSize = 7\n        fp.ViewObject.LineWidth = 7\n        foundHome = findHome(fp) #puts in part/body if one is active\n        doc.recompute()\n        sel = FreeCADGui.Selection.getSelectionEx()\n        subobjects = []\n        for s in sel:\n            if s.HasSubObjects:\n                for en in s.SubElementNames:\n                    subobjects.append((s.Object,en))\n            else:\n                if s.Object.isDerivedFrom(\"PartDesign::Plane\"):\n                    subobjects.append((s.Object,\"Plane\"))\n                elif s.Object.isDerivedFrom(\"PartDesign::Line\"):\n                    subobjects.append((s.Object,\"Line\"))\n                elif not hasattr(s.Object,\"Shape\"):\n                    FreeCAD.Console.PrintWarning(f\"Skipping {s.Object.Label}\\n\")\n                    continue\n                elif len(s.Object.Shape.Faces) == 1:\n                    subobjects.append((s.Object,\"Face1\"))\n                elif len(s.Object.Shape.Edges) == 1:\n                    subobjects.append((s.Object,\"Edge1\"))\n        if len(subobjects) > 3 or len(subobjects) == 0:\n            FreeCAD.Console.PrintError(\"Selection Error, select 1, 2, or 3 objects\\n\")\n            raise Exception(\"Invalid selection\\n\")\n        else:\n            fp.Object1 = subobjects[0] if len(subobjects) >= 1 else None\n            fp.Object2 = subobjects[1] if len(subobjects) >= 2 else None\n            fp.Object3 = subobjects[2] if len(subobjects) == 3 else None\n            if not foundHome:\n                findHome(fp,fp.Object1[0]) #put fp in same body as first selected object\n        doc.recompute()\n\ndef write_file():\n    current = __file__\n    new_name = current.replace(\".FCMacro\", \".py\")\n    with open(new_name, \"w\") as new_file:\n        with open(__file__, \"r\") as current_file:\n            new_file.write(current_file.read())\n\nif __name__ == \"__main__\":\n\n    if \".FCMacro\" in __file__ and not os.path.exists(__file__.replace(\".FCMacro\",\".py\")):\n        write_file()\n        new_name = __file__.replace(\".FCMacro\", \".py\")\n        FreeCAD.Console.PrintWarning(f\"A new file has been created named {new_name} in order for the feature python objects to work when you reload a document containing one of them.\\n\")\n    import importlib\n    import Intersection\n    importlib.reload(Intersection)\n\n    if __version__ > Intersection.__version__:\n        write_file() #update .py file with new version (only needed for versions < 022 / 1.0)\n        importlib.reload(Intersection)\n        FreeCAD.Console.PrintMessage(f\"Intersection.py has been updated to version {__version__}\\n\")\n    elif __version__ < Intersection.__version__:\n        FreeCAD.Console.PrintError(f\"version of existing Intersection.py file ({Intersection.__version__}) is greater than current version ({__version__}) update skipped\\n\")\n\n    makeObject(Intersection)\n\n#icon for addon manager to put on toolbar\n__xpm__ =\"\"\"/* XPM */\nstatic char * _632119818831[] = {\n\"64 64 147 2 \",\n\"   c #74596C\",\n\".  c #787573\",\n\"X  c #E70000\",\n\"o  c #E80000\",\n\"O  c #F10000\",\n\"+  c #EC1112\",\n\"@  c #EC1119\",\n\"#  c #ED221A\",\n\"$  c #EC1226\",\n\"%  c None\",\n\"&  c #EC1229\",\n\"*  c #F21C24\",\n\"=  c #ED2123\",\n\"-  c #ED2229\",\n\";  c #ED1C51\",\n\":  c #ED214E\",\n\">  c #ED2255\",\n\",  c #EC1172\",\n\"<  c #ED2179\",\n\"1  c #8B7E5A\",\n\"2  c #BEA736\",\n\"3  c #BBA438\",\n\"4  c #BBAA3C\",\n\"5  c #C7AD1B\",\n\"6  c #C8AD1A\",\n\"7  c #D5AB1F\",\n\"8  c #C5AD22\",\n\"9  c #C9B22B\",\n\"0  c #C6B030\",\n\"q  c #E4D316\",\n\"w  c #F5E707\",\n\"e  c #FFEF00\",\n\"r  c #F9ED0C\",\n\"t  c #FFF200\",\n\"y  c #FFFA00\",\n\"u  c #F7EB13\",\n\"i  c #F3E71E\",\n\"p  c #F3E91C\",\n\"a  c #CEC62F\",\n\"s  c #D5C42C\",\n\"d  c #E9DD36\",\n\"f  c #E4D43A\",\n\"g  c #E6DB3D\",\n\"h  c #E8DE39\",\n\"j  c #EFE526\",\n\"k  c #ECE32D\",\n\"l  c #F0E525\",\n\"z  c #EAE034\",\n\"x  c #B28B4B\",\n\"c  c #AC8F51\",\n\"v  c #A78F5C\",\n\"b  c #B3A344\",\n\"n  c #BCB541\",\n\"m  c #A7A35C\",\n\"M  c #ADA859\",\n\"N  c #8B8768\",\n\"B  c #928F6C\",\n\"V  c #969366\",\n\"C  c #9B9662\",\n\"Z  c #9C9862\",\n\"A  c #93936B\",\n\"S  c #8C8A70\",\n\"D  c #A39363\",\n\"F  c #97BD60\",\n\"G  c #C7BC68\",\n\"H  c #D7D25F\",\n\"J  c #DBD25D\",\n\"K  c #E3D948\",\n\"L  c #E1D94B\",\n\"P  c #E0D750\",\n\"I  c #FFF544\",\n\"U  c #FFF54D\",\n\"Y  c #FFF653\",\n\"T  c #FFF65C\",\n\"R  c #D6CF6A\",\n\"E  c #D7D162\",\n\"W  c #D9D063\",\n\"Q  c #D3CC73\",\n\"!  c #FFF768\",\n\"~  c #FFF873\",\n\"^  c #FFF87C\",\n\"/  c #12009D\",\n\"(  c #2D008C\",\n\")  c #360886\",\n\"_  c #250D93\",\n\"`  c #241D9F\",\n\"'  c #21249E\",\n\"]  c #2F279B\",\n\"[  c #332E97\",\n\"{  c #0C0DA9\",\n\"}  c #1315A4\",\n\"|  c #1E1CA1\",\n\" . c #4F4E87\",\n\".. c #545285\",\n\"X. c #585682\",\n\"o. c #035ACB\",\n\"O. c #156CC2\",\n\"+. c #61B69C\",\n\"@. c #37C4B6\",\n\"#. c #4EC1B0\",\n\"$. c #0BAAE2\",\n\"%. c None\",\n\"&. c #30CBC0\",\n\"*. c #36CDC8\",\n\"=. c #00EAFF\",\n\"-. c #00F3FF\",\n\";. c cyan\",\n\":. c #BDBB91\",\n\">. c #BFBF9D\",\n\",. c #B7B7A6\",\n\"<. c #BFB7A0\",\n\"1. c #BCBDA3\",\n\"2. c #B5B7AC\",\n\"3. c #BCB6AE\",\n\"4. c #B7B9AE\",\n\"5. c #BCBAAC\",\n\"6. c #B6AFBA\",\n\"7. c #AFB2BE\",\n\"8. c #B4B6B5\",\n\"9. c #BAB6B4\",\n\"0. c #B3B4BB\",\n\"q. c #B9B4B8\",\n\"w. c #C0BC8A\",\n\"e. c #C4BE9D\",\n\"r. c #C1BBA1\",\n\"t. c #C0C095\",\n\"y. c #FFF882\",\n\"u. c #FFF98B\",\n\"i. c #FFF994\",\n\"p. c #FFF99A\",\n\"a. c #C6C2A1\",\n\"s. c #FFFAA5\",\n\"d. c #FFFAAB\",\n\"f. c #FFFBB4\",\n\"g. c #FFFBBD\",\n\"h. c #AAADC6\",\n\"j. c #B3AFC8\",\n\"k. c #AEB1C4\",\n\"l. c #B2B6C2\",\n\"z. c #FFFBC3\",\n\"x. c #FFFCCB\",\n\"c. c #FFFCD4\",\n\"v. c #FFFDDA\",\n\"b. c #FFFDE2\",\n\"n. c #FFFEEC\",\n\"m. c #FFFEF2\",\n\"M. c none\",\n/* pixels */\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e t e I M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e t t t I M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e t t t t U M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e t t t t e Y M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.t t t t t t e T M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e t d e.y t t e T M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e y l j.Q y t t t ! M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e t l q.3.Q y t t t ! M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e y l q.e.5.R y t t e ~ M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e t l q.e.e.3.R t t t t ~ M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e y l q.e.e.e.3.W y t t e ^ M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e t l q.e.e.e.e.3.J y t t e y.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e y l q.e.e.e.e.e.3.J y t t t u.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e t l q.e.e.e.e.e.e.9.J y t t e u.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e t j q.e.e.e.e.r.e.e.3.P y t t t i.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.t y j q.e.t.e.e.e.e.r.t.q.P t t t t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e t l q.e.e.e.e.e.e.a.e.e.r.L y t t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e t l q.e.e.e.e.e.e.e.e.e.e.q.L t t t e s.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.t y l q.e.e.e.e.e.e.e.e.e.1.0.P t t t t t d.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e t l q.r.r.r.e.r.G 8 0 0 0 2 q y t t t t e f.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.b.t w 3 0 0 0 0 0 0 0 0 0 0 0 0 0 2 q y t t t t t e f.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.e t t t t t t w 3 0 0 0 0 0 0 0 0 0 0 0 0 0 2 q y y E h.z t t e g.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.e t t t t t t t t t t t y w 3 0 0 0 0 0 0 9 b B V V V Z S a y y H 8.0.z t t t z.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.e t t t t t t t t t e t t t u l.w.5 7 F -.=.=.-.*.x C Z Z D Z S a y y H 4.>.8.k t t t x.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"t t t t t t t t t t 7.>.>.>.,.1.5.:.6 7 F -.=.=.-.*.x Z Z Z Z Z S a y y E 4.>.>.h.k y t e x.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"t t t t t >.1.>.>.t.,.1.1.>.>.>.1.:.5 7 F ;.$.( ' }  .M Z Z Z Z S a y y H 4.>.>.>.8.j y t e c.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"t t e t y k.>.>.1.>.>.>.>.t.>.>.1.:.5 7 F ;.$.( ` ` } ..M Z Z Z S a y y H 4.>.>.>.>.0.j t t t v.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.e t t t t l.>.>.>.>.>.>.>.>.>.1.:.5 7 F ;.$.) | ] [ { ..M Z Z S a y y H 4.>.>.>.>.>.7.l t t t b.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.e e t t t k.>.>.>.>.>.>.>.>.1.:.5 9 4 Z . { } ' ` | } X.M Z S a y y H 4.>.>.>.>.>.>.0.p t t e b.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.e t t t y k.>.>.>.>.a.>.>.1.t.5 9 4 A M . } _ O.;.=.=.-.#.v a y y H 4.>.>.>.>.>.>.>.0.p t t e n.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.e t t t t h.>.>.>.>.t.1.1.:.5 9 4 A Z m . / O.;.=.=.-.&.1 s y y E 4.>.>.>.>.>.>.>.>.7.u t t t y % & % % % % % % % % % M.\",\n\"M.M.M.M.M.e t t t t k.>.>.1.a.t.1.:.5 9 4 A Z Z m   o.;.=.-.-.&.N s y y H 4.>.>.>.>.>.>.>.>.1.0.u t t y % % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.e t t t t 7.>.>.>.>.1.:.5 9 4 A Z Z Z c +.-.=.=.-.&.N s y y H 4.>.>.>.>.1.1.,.>.>.>.0.r y y % % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.e t t t t h.>.>.>.1.:.5 9 4 A Z Z Z c +.-.=.=.-.&.1 s y y E 8.,.>.,.0.j t t t t t t t t y % % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.t t t t t 2.,.t.1.:.6 9 4 A Z Z C Z Z Z C v v D S a y t t t t t t t t t t t t t t t t y % % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.t t t t r 4.1.1.e.5 9 4 A Z C V V V V V B 9 y t t t t t t t t t t e t t t t e b.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.e t t t r 2.1.w.5 9 2 V C B n y t t t t t t t t t t t t t t t e g.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.e t t t u l.:.5 2 s y t t t t t t t t t t e t t t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.m.e t t t t t t t t t t t t t t t t y L q.q.L t t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.m.e t t t t t t t t t t t d q.e.e.e.e.e.9.L y t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.n.e t t t y i 9.<.e.e.e.e.e.e.e.e.e.e.9.L t t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.t p 3.e.e.e.e.e.e.e.e.e.e.e.9.L t t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.t t j q.e.e.e.e.e.e.e.e.e.e.9.L y t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % M.M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.e t t j q.e.e.e.e.e.e.e.e.e.9.L t t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.t t t t k q.e.e.e.e.e.e.e.e.9.L y t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.x.t t t k q.e.e.e.e.e.e.e.9.L y t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.z.e t t z q.e.e.e.e.e.e.q.L t t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.g.e t y h q.e.e.e.e.e.9.L y e p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.f.e t t g q.e.e.e.e.9.L y t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.f.t t y h 2.e.e.e.9.L t t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.d.t t t L 9.e.e.9.L y t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.s.e t y d 2.e.9.L y t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.p.t t t d <.0.L t t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.p.t t y g 6.P y t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.i.t t t f f t t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.u.t t t t t t p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.u.e t t t e p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % % % M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.y.e t t e p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % % % M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.^ t t e p.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.% % % % % % % M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\",\n\"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\"\n};\"\"\"",
    "url": "https://wiki.freecad.org/Macro_Intersection",
    "raw_code_url": "https://gist.github.com/mwganson/acf6d419ee0d3b5636ea82221846d758/raw/dff80f8b50d83312e936104f6b062b88279add64/Intersection.py",
    "wiki": "",
    "version": "2024.10.17",
    "license": "",
    "date": "2024-10-17",
    "src_filename": "",
    "filename_from_url": "",
    "author": "<TheMarkster> 2021",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Intersection_Icon.svg",
    "icon_source": "https://wiki.freecadweb.org/images/e/e7/Intersection_Icon.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Line Length",
    "on_wiki": true,
    "on_git": false,
    "desc": "Create a line giving as an argument the XYZ coordinates, length, and angle. The new line is created in the real coordinate of object, not in the coordinate of the Body.<br /><span style=\"background-color: #ffeeee\">(Command line, paste this complete macro in the Python console)</span>.<br /><br />Macro version: 02.00<br />Last modified: 2014-08-08<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/b/bd/Macro_Line_Length.png\">ToolBar Icon</a><br />Author: mario52<br /> ",
    "comment": "Create a line giving as an argument the XYZ coordinates, length, and angle. The new line is created in the real coordinate of object, not in the coordinate of the Body.",
    "code": "# -*- coding: utf-8 -*-\n# cr\u00e9er une ligne avec une coordonn\u00e9e une longueur et un angle sur le plan X Y\n# create line with coordinate length and angle to plane X Y\nimport FreeCAD, FreeCADGui, Draft\nfrom math import cos, sin, radians\n#from FreeCAD import Base\n \ndef line_length(x1 = 0.0, y1 = 0.0, z1 = 0.0, length = 10.0, angle = 0.0):\n    x2 = x1 + (length * cos(radians(angle)))\n    y2 = y1 + (length * sin(radians(angle)))\n    z2 = z1 #+ ()\n    Draft.makeWire([FreeCAD.Vector(x1,y1,z1),FreeCAD.Vector(x2,y2,z2)])\n\n#Example:\n#x1 = 0.0          # Edit coordinate x1 origin\n#y1 = 0.0          # Edit coordinate y1 origin\n#z1 = 0.0          # Edit coordinate z1 origin\n#length = 50.0       # Edit length\n#angle  = 45.0       # Edit angle plane XY\n \n#line_length(x1, y1, z1, length, angle)",
    "url": "https://wiki.freecad.org/Macro_Line_Length",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-08-08",
    "src_filename": "",
    "filename_from_url": "",
    "author": "mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Line_Length.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/b/bd/Macro_Line_Length.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Loft",
    "on_wiki": true,
    "on_git": false,
    "desc": "Creates a loft with wires selected. Specially written for easy lofting with lines generated by the <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/Macro_Texture\">Macro Texture</a> (but may be suitable and used for common lofts)<br /><br />Macro version: 00.04<br />Last modified: 2019-07-03<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/2/29/FCCreaLoft.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Create a loft with a list of wire (specially created for Macro FCTexture)",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2016 2017 2018 2019 <mario52>                           *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#Macro_FCCreaLoft 09/02/2016 03/07/2019\n#\n#OS: Windows 8                                  #OS: Windows 10\n#Word size of OS: 64-bit                        #Word size of OS: 64-bit\n#Word size of FreeCAD: 64-bit                   #Word size of FreeCAD: 64-bit\n#Version: 0.15.4671 (Git)                       #Version: 0.19.17171 (Git)\n#Branch: releases/FreeCAD-0-15                  #Build type: Release\n#Hash: 244b3aef360841646cbfe80a1b225c8b39c8380c #Branch: master\n#Python version: 2.7.8                          #Hash: d19470a9711ea604f3ca6c93e46afadf64d5bb87\n#Qt version: 4.8.6                              #Python version: 3.6.6\n#Coin version: 4.0.0a                           #Qt version: 5.6.2\n#OCC version: 6.8.0.oce-0.17                    #Coin version: 4.0.0a\n#                                               #OCC version: 7.3.0\n\n__title__    = \"FCCreaLoft\"\n__author__   = \"mario52\"\n__url__      = \"http://www.freecadweb.org/index-fr.html\"\n__version__  = \"00.04\"\n__date__     = \"03/07/2019 \"\n\n__Comment__  = \"Create a loft with a list of wire (specially created for Macro FCTexture)\"\n__Web__      = \"https://forum.freecadweb.org/\"\n__Wiki__     = \"https://www.freecadweb.org/wiki/Macro_Loft\"\n__Icon__     = \"/usr/lib/freecad/Mod/plugins/icons/FCCreaLoft\"\n__IconW__    = \"C:/Users/YourUserName/AppData/Roaming/FreeCAD/\"\n__Help__     = \"start the macro and follow the instructions\"\n__Status__   = \"stable\"\n__Requires__ = \"FreeCAD all\"\n\ntry:\n    import PyQt4\n    from PyQt4 import QtGui ,QtCore\n    from PyQt4.QtGui import *\n    from PyQt4.QtCore import *\nexcept Exception:\n    import PySide\n    from PySide import QtGui ,QtCore\n    from PySide.QtGui import *\n    from PySide.QtCore import *\n \nimport Draft, Part, FreeCAD, math, PartGui, FreeCADGui, FreeCAD\nfrom math import sqrt, pi, sin, cos, asin\nfrom FreeCAD import Base\nimport FreeCAD\nApp = FreeCAD\n\nimport sys\nglobal verPython ; verPython = sys.version_info.major\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\nclass Ui_MainWindow(object):\n    def __init__(self):\n        #self.path        = FreeCAD.ConfigGet(\"AppHomePath\")\n        self.path        = FreeCAD.ConfigGet(\"UserAppData\")\n        self.compt_Oject = -1                                                                         #\n        self.loftObject  = []\n        self.doc         = FreeCAD.ActiveDocument\n        self.saut        = 1                                                                          #\n        self.selectionObjects = FreeCADGui.Selection.getSelection()                                   # Select an object or primitive getSelection()\n\n\n    def setupUi(self, MainWindow):\n        global verPython\n        self.window = MainWindow\n        MainWindow.setObjectName(_fromUtf8(\"MainWindow\"))\n        MainWindow.resize(373, 301)\n        self.centralwidget = QtGui.QWidget(MainWindow)\n        self.centralwidget.setObjectName(_fromUtf8(\"centralwidget\"))\n\n        self.PB_01_Sort = QtGui.QPushButton(self.centralwidget)\n        self.PB_01_Sort.setGeometry(QtCore.QRect(290, 70, 70, 23))\n        self.PB_01_Sort.setObjectName(_fromUtf8(\"PB_01_Sort\"))\n        self.PB_01_Sort.setToolTip(u\"Sort the datas.\")\n        self.PB_01_Sort.clicked.connect(self.on_PB_01_Sort_clicked)                                   #connection pushButton\n\n        self.PB_02_Reverse = QtGui.QPushButton(self.centralwidget)\n        self.PB_02_Reverse.setGeometry(QtCore.QRect(290, 100, 70, 23))\n        self.PB_02_Reverse.setObjectName(_fromUtf8(\"PB_02_Reverse\"))\n        self.PB_02_Reverse.setToolTip(u\"Reverse the datas.\")\n        self.PB_02_Reverse.clicked.connect(self.on_PB_02_Reverse_clicked)                             #connection pushButton\n\n        self.PB_03_Reset = QtGui.QPushButton(self.centralwidget)\n        self.PB_03_Reset.setGeometry(QtCore.QRect(290, 130, 70, 23))\n        self.PB_03_Reset.setObjectName(_fromUtf8(\"PB_03_Reset\"))\n        self.PB_03_Reset.setToolTip(u\"Upgrade the datas selecteds or reset the datas in original list.\"+\"\\n\"+\n                                      \"Or upgrade the new selections in the macro\")\n        self.PB_03_Reset.clicked.connect(self.on_PB_03_Reset_clicked)                                 #connection pushButton\n\n        self.PB_06_SelectAll = QtGui.QPushButton(self.centralwidget)\n        self.PB_06_SelectAll.setGeometry(QtCore.QRect(290, 160, 70, 23))\n        self.PB_06_SelectAll.setObjectName(_fromUtf8(\"PB_06_SelectAll\"))\n        self.PB_06_SelectAll.setToolTip(\"Select all objects in the 3DView.\")\n        self.PB_06_SelectAll.clicked.connect(self.on_PB_06_SelectAll_clicked)                         #connection pushButton\n\n        self.SB_01_Saut = QtGui.QSpinBox(self.centralwidget)\n        self.SB_01_Saut.setGeometry(QtCore.QRect(290, 190, 70, 23))\n        self.SB_01_Saut.setMinimum(1.0)\n        self.SB_01_Saut.setMaximum(10000.0)\n        self.SB_01_Saut.setSingleStep(self.saut)\n        self.SB_01_Saut.setToolTip(u\"Works all or jump x lines.\"+\"\\n\"+\n                                    \"By default all (1)\")\n        self.SB_01_Saut.setObjectName(_fromUtf8(\"doubleSpinBox_1\"))\n        self.SB_01_Saut.valueChanged.connect(self.on_SB_01_Saut_valueChanged)                         #connect on def \"on_SB_01_Saut_valueChanged\"\n\n        self.PB_04_Quit = QtGui.QPushButton(self.centralwidget)\n        self.PB_04_Quit.setGeometry(QtCore.QRect(290, 220, 70, 23))\n        self.PB_04_Quit.setObjectName(_fromUtf8(\"PB_04_Quit\"))\n        self.PB_04_Quit.setToolTip(u\"Quit the macro.\")\n        self.PB_04_Quit.clicked.connect(self.on_PB_04_Quit_clicked)                                    #connection pushButton\n\n        self.CB_01_Progress = QtGui.QCheckBox(self.centralwidget)                                      # create object QRadioButton in groupBox\n        self.CB_01_Progress.setGeometry(QtCore.QRect(290, 250, 81, 17))                                # coordinates position\n        self.CB_01_Progress.setObjectName(_fromUtf8(\"CB_01_Progress\"))                                 # name of object\n        self.CB_01_Progress.setChecked(True)                                                           # Check by default True or False\n        self.CB_01_Progress.setToolTip(\"Used to view the conduct of operations in 3D display\")\n#        self.CB_01_Progress.clicked.connect(self.on_CB_01_Progress_clicked)                           # connect on def \"on_checkBox_1_clicked\"\n\n        self.progressBar = QtGui.QProgressBar(self.centralwidget)\n        self.progressBar.setGeometry(QtCore.QRect(10, 40, 351, 23))\n        self.progressBar.setAlignment(QtCore.Qt.AlignCenter)\n        self.progressBar.setValue(0)\n        self.progressBar.setObjectName(_fromUtf8(\"progressBar\"))\n\n        self.textEdit_01 = QtGui.QTextEdit(self.centralwidget)\n        self.textEdit_01.setGeometry(QtCore.QRect(10, 72, 271, 193))\n        self.textEdit_01.setObjectName(_fromUtf8(\"textEdit_01\"))\n#        self.textEdit_01.textChanged.connect(self.on_textEdit_01_Pressed)                             # connect on def \"on_textEdit_01_Pressed\"\n\n        self.PB_05_Launch = QtGui.QPushButton(self.centralwidget)\n        self.PB_05_Launch.setGeometry(QtCore.QRect(10, 270, 351, 23))\n        self.PB_05_Launch.setObjectName(_fromUtf8(\"PB_04_Launch\"))\n        self.PB_05_Launch.setToolTip(u\"Launch the loft.\"+\"\\n\"+\n                                       \"Are displayed the number of selections\"+\"\\n\"+\n                                       \"and the number real Loft if Jump x lines is used\")\n        self.PB_05_Launch.clicked.connect(self.on_PB_05_Launch_clicked) #connection pushButton\n\n        self.label = QtGui.QLabel(self.centralwidget)\n        self.label.setGeometry(QtCore.QRect(140, 10, 81, 20))\n        font = QtGui.QFont()\n        font.setPointSize(14)\n        self.label.setFont(font)\n        self.label.setObjectName(_fromUtf8(\"label\"))\n        MainWindow.setCentralWidget(self.centralwidget)\n\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n        self.selectionObjects = FreeCADGui.Selection.getSelection()                                    # Select an object or primitive getSelection()\n        if len(self.selectionObjects) != 0:\n            for selection in self.selectionObjects:                                                    # sort\n                self.loftObject.append(selection.Name)                                                 # sort\n                if verPython < 3:\n                    self.textEdit_01.append(unicode(selection.Name))\n                else:\n                    self.textEdit_01.append(selection.Name)\n                self.PB_05_Launch.setText(\"Launch the Lofting ( \"+str(len(self.loftObject))+\" )\")\n        else:\n            self.textEdit_01.setText(\"Select object list , and click the Upgrade button for validate the entries in the macro\")\n\n    def retranslateUi(self, MainWindow):\n        try:\n            MainWindow.setWindowFlags(PyQt4.QtCore.Qt.WindowStaysOnTopHint)                            # PyQt4 cette fonction met la fen\u00eatre en avant\n        except Exception:\n            MainWindow.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint)                           # PySide cette fonction met la fen\u00eatre en avant\n        MainWindow.setWindowTitle(\"FCCreaLoft (\" + __version__ + \" - \" + __date__ + \")\")\n        self.PB_01_Sort.setText(\"Sort\")\n        self.PB_02_Reverse.setText(\"Reverse\")\n\n        if len(self.selectionObjects) == 0:\n            self.PB_03_Reset.setText(\"Upgrade\")\n        else:\n            self.PB_03_Reset.setText(\"Reset\")\n\n        self.PB_04_Quit.setText(\"Quit\")\n        self.CB_01_Progress.setText(\"View Progr.\")\n        self.PB_06_SelectAll.setText(\"Select all\")\n        self.PB_05_Launch.setText(\"Launch the Lofting ( \"+str(len(self.loftObject))+\" )\")\n        self.label.setText(\"CreaLoft\")\n\n    def on_PB_01_Sort_clicked(self):  # \n        global verPython\n        if len(self.loftObject) != 0:\n            self.textEdit_01.clear()\n            self.loftObject.sort()                                                                     # sort\n            for nom in self.loftObject:\n                if verPython < 3:\n                    self.textEdit_01.append(unicode(nom))\n                else:\n                    self.textEdit_01.append(nom)\n            self.PB_01_Sort.setEnabled(False)\n        else:\n            App.Console.PrintMessage(\"No data to sort, select objects\"+\"\\n\")\n            self.textEdit_01.clear()\n            self.textEdit_01.setText(\"No data to sort,\"+\"\\n\"+\n                                     \"select objects and click the button Upgrade\")\n        self.PB_05_Launch.setText(\"Launch the Lofting ( \"+str(len(self.loftObject))+\" )\")\n#        App.Console.PrintMessage(\"Sort\"+\"\\n\")\n\n    def on_PB_02_Reverse_clicked(self):  # \n        global verPython\n        if len(self.loftObject) != 0:\n            self.textEdit_01.setText(\"\")\n            self.textEdit_01.clear()\n            self.loftObject.reverse()\n            for nom in self.loftObject:\n                if verPython < 3:\n                    self.textEdit_01.append(unicode(nom))\n                else:\n                    self.textEdit_01.append(nom)\n        else:\n            App.Console.PrintMessage(\"No data to reverse, select objects\"+\"\\n\")\n            self.textEdit_01.clear()\n            self.textEdit_01.setText(\"No data to reverse,\"+\"\\n\"+\n                                     \"select objects and click the button Upgrade\")\n        self.PB_05_Launch.setText(\"Launch the Lofting ( \"+str(len(self.loftObject))+\" )\")\n#        App.Console.PrintMessage(\"Reverse\"+\"\\n\")\n\n    def on_PB_03_Reset_clicked(self):  # \n        global verPython\n        self.textEdit_01.clear()\n        self.loftObject[:]  = []\n        self.compt_Oject = -1                                                                          #\n        self.PB_01_Sort.setEnabled(True)\n        self.selectionObjects = FreeCADGui.Selection.getSelection()                                    # Select an object or primitive getSelection()\n#        App.Console.PrintMessage(\"Number objects \" + str(len(self.selectionObjects)) + \"\\n\")\n\n        for selection in self.selectionObjects:                                                        # sort\n            self.loftObject.append(selection.Name)                                                     # sort\n        for nom in self.loftObject:\n            if verPython < 3:\n                self.textEdit_01.append(unicode(nom))\n            else:\n                self.textEdit_01.append(nom)\n\n        if len(self.loftObject) == 0:\n            App.Console.PrintMessage(\"No data to reset or upgrade, select objects\"+\"\\n\")\n            self.textEdit_01.clear()\n            self.textEdit_01.setText(\"No data to reset or upgrade,\"+\"\\n\"+\n                                     \"select objects and click the button Upgrade\")\n            self.PB_03_Reset.setText(\"Upgrade\")\n        else:\n            self.PB_03_Reset.setText(\"Reset\")\n        self.saut = 1\n        self.SB_01_Saut.setValue(1)\n        self.PB_05_Launch.setText(\"Launch the Lofting ( \"+str(len(self.loftObject))+\" )\")\n#        App.Console.PrintMessage(\"Reset\"+\"\\n\")\n\n    def on_PB_06_SelectAll_clicked(self):  # \n        try:\n            self.loftObject[:]  = []\n            self.compt_Oject = -1                                                                          #\n            self.PB_01_Sort.setEnabled(True)\n            for obj in FreeCAD.ActiveDocument.Objects:\n                objName = obj.Name\n                obj = App.ActiveDocument.getObject(objName)\n                Gui.Selection.addSelection(obj)\n                self.loftObject.append(objName)\n                self.textEdit_01.append(objName)\n            self.textEdit_01.append(\"Number object(s) : \" + str(len(self.loftObject)))\n            self.PB_05_Launch.setText(\"Launch the Lofting ( \"+str(len(self.loftObject))+\" )\")\n        except Exception:\n            self.textEdit_01.append(\"No data to select.\")\n#        App.Console.PrintMessage(\"on_PB_06_SelectAll\"+\"\\n\")\n\n    def on_SB_01_Saut_valueChanged(self,value):  # \n        self.saut = value                                                                              #\n        traite = len(self.selectionObjects) / self.saut\n        self.PB_05_Launch.setText(\"Launch the Lofting ( \"+str(len(self.loftObject))+\" ) ( \"+str(traite)+\" )\")\n#        App.Console.PrintMessage(\"Saut \"+str(self.saut)+\"  \"+str(traite)+\"\\r\\n\")\n        \n    def on_PB_04_Quit_clicked(self):  # \n        FreeCAD.Console.PrintMessage(\"Fin FCCreLoft\"+\"\\n\")\n        self.window.hide()\n\n    def on_PB_05_Launch_clicked(self):  # \n        if len(self.loftObject) != 0:\n            try:\n                self.progressBar.setMaximum(len(self.loftObject))\n                for selection in (self.loftObject):                                                     #\n                    self.compt_Oject += 1                                                               #\n                    if (self.compt_Oject >= 1) and (self.compt_Oject % self.saut == 0):\n                        lofts = self.doc.addObject('Part::RuledSurface', 'Ruled Surface')               # create loft\n        \n                        lofts.Curve1=(self.doc.getObject(self.loftObject[self.compt_Oject-self.saut]),[''])\n                        lofts.Curve2=(self.doc.getObject(self.loftObject[self.compt_Oject  ]),[''])\n\n                        if self.CB_01_Progress.isChecked():\n                            self.progressBar.setValue(self.compt_Oject)\n                            self.doc.recompute()\n                            Gui.updateGui()                                                             # rafraichi l'ecran\n                \n                self.doc.recompute()\n                self.compt_Oject = -1\n                self.textEdit_01.clear()\n                self.textEdit_01.setText(\"Creation finished successfully\"+\"\\n\"+\n                                         str(len(self.loftObject))+\" objects lofted\"+\"\\n\\n\"+\n                                         \"Select other object list , and click the Upgrade button for validate the entries in the macro\")\n                self.loftObject  = []\n                self.PB_01_Sort.setEnabled(True)\n                self.PB_03_Reset.setText(\"Upgrade\")\n                self.progressBar.setValue(0)\n            except Exception:\n                self.textEdit_01.setText(\"End of an error\"+\"\\n\")\n                App.Console.PrintMessage(\"End of an error\")\n        else:\n            App.Console.PrintMessage(\"No data to launch, select objects\"+\"\\n\"+\"Or click reset for upgrade the new selection\"+\"\\n\")\n            self.textEdit_01.clear()\n            self.textEdit_01.setText(\"No data to launch,\"+\"\\n\"+\n                                     \"select objects and click the button Upgrade\")\n        self.PB_05_Launch.setText(\"Launch the Lofting \")\n\n\nMainWindow = QtGui.QMainWindow()\nui = Ui_MainWindow()\nui.setupUi(MainWindow)\nMainWindow.show()\n\n",
    "url": "https://forum.freecadweb.org/",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/c477f892233d6abe02df5e97af828ff4/raw/d633193c577e8257ef458b8c1824d1047c3c6613/Macro_FCCreaLoft.FCMacro",
    "wiki": "https://www.freecadweb.org/wiki/Macro_Loft",
    "version": "00.04",
    "license": "",
    "date": "03/07/2019 ",
    "src_filename": "",
    "filename_from_url": "",
    "author": "mario52",
    "icon": "/usr/lib/freecad/Mod/plugins/icons/FCCreaLoft",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Texture",
    "on_wiki": true,
    "on_git": false,
    "desc": "Creates a 3D image from an 8 bit (256 color) BMP image.<br />In other words, it allows one to build a 3D project very easily from a bitmap image using grayscale (256 shades of gray).<br />If one 32 bit BMP image is selected, the image is represented in points.<br />The <b>FCCreaLoft Macro Loft</b> macro is used to automate the multi loft operation.<br /><br />Macro version: 0.15<br />Last modified: 2025/01/04<br />FreeCAD version: 0.18 and more<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecad.org/wiki/images/9/90/FCTexture.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Creates a 3D image from an 8 bit (256 color) BMP image.",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2014 2015 2016 2017 2018 2019 2020 2021 2025 <mario52>  *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU  General Public License (GPL)           *\n*   as published by the Free Software Foundation; either version 3 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU General Public License     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#OS: Windows 10 (10.0)                          #OS: Ubuntu 20.10 (KDE/plasma) \n#Word size of OS: 64-bit                        #Word size of OS: 64-bit \n#Word size of FreeCAD: 64-bit                   #Word size of FreeCAD: 64-bit \n#Version: 0.19.23546 (Git)                      #Version: 0.19.23578 (Git) \n#Build type: Release                            #AppImage Build type: Release \n#Branch: master                                 #Branch: master \n#Hash: 6b017f9a16b15b0e628c8d874c4058442dee5548 #Hash: 50c3cbf00579dc4941ca743c25720d016b0453ce \n#Python version: 3.6.8                          #Python version: 3.8.6 \n#Qt version: 5.12.1                             #Qt version: 5.12.5 \n#Coin version: 4.0.0a                           #Coin version: 4.0.0 OCC \n#OCC version: 7.3.0                             #version: 7.4.0\n#Locale: French/Mars (fr_MA)                    #Locale: French/Mars (fr_MA)\n#\n# pour faire une texture de votre image, l'image doit etre en 256 niveaux de gris (N/B)\n# une image de 16 millons de couleurs fait l'objet d'une autre procedure d'affichage\n# http://forum.freecadweb.org/viewtopic.php?f=24&t=5893&sid=c5f8d32c22e1d1a883741b70b1fea2dc\n# ver 0.7 03/09/2014 PyQt4 and PySide 0.8 16/03/2016 0.9 12/12/2016 0.10 24/12/2016 \n# ver 0.11 2019/07/03 Py3, ver 0.12 2019/08/04, 0.13 2020/04/17 Layout\n# ver 0.13b 2020/12/30 try: time.clock() and time.process_time()\n# ver 0.14 2021/01/06 new2 path name process accept point in path file colored caracter xyz add search upgrade\n# ver 0.14b 2021/01/ Coordinare and Stretching in TAB for screen 15\"; 0.14c add \"Gui.SendMsgToActiveView(\"ViewFit\")\"; 0.14d replace PySide2 by PySide\n# ver 0.15 2025/01/04 delette alreferences to PySide and QtWidgets , chrono by chrisb\n#\n__title__   = \"FCTexture\"\n__author__  = \"Mario52\"\n__url__     = \"https://www.freecadweb.org/\"\n__Wiki__    = \"https://wiki.freecad.org/Macro_Texture\"\n__version__ = \"0.15\"\n__date__    = \"2025/01/04\"    #YYYY/MM/DD\n#\n#\nimport PySide\ntry:\n    from PySide import QtWidgets\n    from PySide.QtWidgets import *\nexcept Exception:\n    None\nfrom PySide import QtGui , QtCore\nfrom PySide.QtGui import *\nfrom PySide.QtCore import *\n#\n#\ntry:\n    import webbrowser\nexcept Exception:\n    None\n\nimport Draft, Part, FreeCAD, math, PartGui, FreeCADGui, FreeCAD\nfrom math import sqrt, pi, sin, cos, asin\nfrom FreeCAD import Base\nGui = FreeCADGui\n\nimport Points\n\nimport os, sys\nimport os.path\n \n#### Detect version macro ####19-12-2024#######################################\nglobal switchVesionMacroSearch#; switchVesionMacroSearch = False\ntry:\n    def versionSearch():\n        import urllib\n        from urllib import request\n\n        contentPage = request.urlopen(\"https://wiki.freecad.org/Macro_Texture\").readlines()\n\n        for i in contentPage:\n            if \"ctEven macro-version\" in str(i):\n                versionDetect = (str(i).split(\">\")[1].split(\"\\\\\")[0])\n            if \"ctEven macro-date\" in str(i):\n                dateDetect = (str(i).split(\">\")[1].split(\"\\\\\")[0])\n            try:\n                if (len(versionDetect) != 0) and (len(dateDetect) != 0):\n                    break\n            except Exception:\n                None\n        try:\n            if (versionDetect == __version__) and (dateDetect == __date__):\n                None\n            else:\n                msg = (\"New version availlable : \" + \"\\n\" + \n                    str(versionDetect) + \":\" + str(dateDetect) + \"\\n\" + \n                    \"You can install with AddonManager\")\n                FreeCAD.Console.PrintMessage(\"your actual version    : \" + str(__version__) + \" : \" + str(__date__) + \"\\n\")\n                FreeCAD.Console.PrintMessage(\"new version availlable : \" + str(versionDetect) + \" : \" + str(dateDetect) + \"\\n\")\n                diag = QMessageBox(QMessageBox.Information, 'New Version', msg)\n                diag.setWindowModality(QtCore.Qt.ApplicationModal)\n                diag.exec_()\n        except Exception:\n            None\n        return versionDetect, dateDetect\n\n    switchVesionMacroSearch = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switchVesionMacroSearch\")\n    if switchVesionMacroSearch == 0:\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchVesionMacroSearch\", switchVesionMacroSearch)\n    if switchVesionMacroSearch == True:\n        versionSearch()\nexcept Exception:\n    FreeCAD.Console.PrintMessage(\"Failed to establish a connection\" + \"\\n\")\n#### Detect version macro ####19-12-2024#######################################\n\n####chrono################\n####\nimport time\nglobal endTime   ; endTime   = 0.0\nglobal startTime ; startTime = 0.0\ndef chrono(mode = True, allDoc = False, typeTime = True, valElapsed = 0):    # single chronometer\n#def chrono(mode = True, allDoc = True, typeTime = True, valElapsed = 2):      # original measure chrisb macro\n    ##\"https://forum.freecadweb.org/viewtopic.php?p=510691#p510691\"\n    global startTime    # mode = True\n    global endTime      # mode = False\n\n    ####\n    #__author__  = \"chrisb\" __version__ = \"00.01\" __date__    = \"2021/01/16\"\n    #mode       : (default True) : True  = start the chronometer\n    #mode       :                : False = stop the chronometer and give the result display with print(chrono(0))\n    #allDoc     : (default True) : True  = touch all objects in the document and active the App.ActiveDocument.recompute()\n    #           :                : False = None\n    #typeTime   : (default True) : True  = measure real time\n    #           :                : False = measure process time, ignore sleep, count each processor\n    #valElapsed :                : 0 = return the value elapsed by: \"00:00:01.517\"       by string()\n    #           :                : 1 = return the value elapsed by: \"1.5174349999997503\" by string()\n    #           : (default 2)    : 2 = return the value elapsed by: \"00:00:01.517\" + \"\\n\" + \"1.5174349999997503\" by string()\n    ####\n\n    try:\n        if allDoc == True:\n            # # touch everything, may be commented out for detailed tests:\n            for obj in FreeCAD.ActiveDocument.Objects:\n               obj.touch()\n    \n        if typeTime == True:\n            # measure real time\n            timeFn = time.perf_counter\n        else:\n            # measure process time, ignore sleep, count each processor\n            timeFn = time.process_time\n    \n        if mode == True:\n            startTime = timeFn()\n            # measure recompute\n            if allDoc == True:\n                App.ActiveDocument.recompute()\n        else:\n            endTime = timeFn()\n            elapsed = (endTime - startTime)\n            elapsedComplete = str('{:02d}:{:02d}:{:06.3f}'.format(int(elapsed) // 3600, (int(elapsed) % 3600 // 60), elapsed % 60))\n\n            if str(valElapsed) == \"0\":     # \"00:00:01.517\"\n                return elapsedComplete\n            elif str(valElapsed) == \"1\":   # \"1.5174349999997503\"\n                return str(elapsed)\n            else:                          # \"00:00:01.517\" + \"1.5174349999997503\"\n                return elapsedComplete + \"\\n\" + str(elapsed)\n    \n            #print('{:02d}:{:02d}:{:05.2f}'.format(int(elapsed) // 3600, (int(elapsed) % 3600 // 60), elapsed % 60))\n            #print(endTime - startTime)\n    except Exception:\n        None\n####\n####chrono################\n\ndef errorDialog(msg):\n    diag = QMessageBox(QMessageBox.Critical,u\"Error Message\",msg )\n    diag.setWindowModality(QtCore.Qt.ApplicationModal)\n    diag.exec_()\n \nglobal verPython ; verPython = sys.version_info.major\n\ndef decobit(b0 = 0, b1 = 0, b2 = 0, b3 = 0):\n    global verPython\n    if verPython < 3:    # Python < 3\n        b0 = ord(b0)\n        b1 = ord(b1)\n        if b2 == 0:\n            return b0 + (b1*256)\n        else:\n            b2 = ord(b2)\n            b3 = ord(b3)\n            return b0 + (b1*256) + (b2*65536) + (b3*16777216)\n    else:                # Python > 3\n        b0 = int(ord(chr(b0)))\n        b1 = int(ord(chr(b1)))\n        if b2 == 0:\n            return b0 + (b1*256)\n        else:\n            b2 = int(ord(chr(b2)))\n            b3 = int(ord(chr(b3)))\n            return b0 + (b1*256) + (b2*65536) + (b3*16777216)\n\n#### Configuration ###########################################\nglobal SingleStep   ; SingleStep   = 1.0\n#### Configuration ###########################################\n\nglobal position_X   ; position_X   = 0.0\nglobal position_Y   ; position_Y   = 0.0\nglobal position_Z   ; position_Z   = 0.0\nglobal etirement_X  ; etirement_X  = 1.0\nglobal etirement_Y  ; etirement_Y  = 1.0\nglobal etirement_Z  ; etirement_Z  = 1.0\nglobal modeBrut     ; modeBrut     = 0\nglobal modeColor    ; modeColor    = 0\nglobal ecreter      ; ecreter      = 20\nglobal avecLigne    ; avecLigne    = 1\nglobal typeligne    ; typeligne    = 0\nglobal nuance       ; nuance       = 0\nglobal inversion_X  ; inversion_X  = 0\nglobal inversion_Y  ; inversion_Y  = 0\nglobal inversion_Z  ; inversion_Z  = 0\nglobal plan         ; plan         = 0\nglobal fond         ; fond         = 0\nglobal bits_pixel   ; bits_pixel   = 0\nglobal tailleDonnees; tailleDonnees= 0\nglobal fileCoordasc ; fileCoordasc = 0\nglobal fileCoordpcd ; fileCoordpcd = 0\nglobal ecreterFond  ; ecreterFond  = 0\nglobal switchContour; switchContour= 0\nglobal valueFilter  ; valueFilter  = 0\n\n#\nglobal pathFile     ; pathFile     = \"\"\nglobal path\n#path  = FreeCAD.ConfigGet(\"AppHomePath\")\n#path  = FreeCAD.ConfigGet(\"UserAppData\")\n#path  = \"your path\"\nparam = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")# macro path\npath = param.GetString(\"MacroPath\",\"\") + \"/\"                        # macro path\npath = path.replace(\"\\\\\",\"/\")\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n \nclass Ui_MainWindow(object):\n \n    def __init__(self, MainWindow):\n        self.window = MainWindow\n        global path\n        global pathFile\n        global position_X\n        global position_Y\n        global position_Z\n        global etirement_X\n        global etirement_Y\n        global etirement_Z\n        global modeBrut\n        global modeColor\n        global ecreter\n        global typeligne\n        global nuance\n        global avecLigne\n        global inversion_X\n        global inversion_Y\n        global inversion_Z\n        global plan\n        global fond\n        global bits_pixel\n        global tailleDonnees\n        global valueFilter\n        global SingleStep \n\n        MainWindow.setObjectName(_fromUtf8(__title__))\n#        MainWindow.resize(300, 600)\n#        MainWindow.setMinimumSize(QtCore.QSize(241, 624))\n#        MainWindow.setMaximumSize(QtCore.QSize(241, 624))\n        self.centralWidget = QWidget(MainWindow)\n\n        self.groupBox = QGroupBox()\n        self.groupBox_01 = QWidget()\n\n        self.LB_01_Coor_X = QLabel()\n        \n        self.DS_01_Coor_X = QDoubleSpinBox()\n        self.DS_01_Coor_X.setDecimals(7)\n        self.DS_01_Coor_X.setMinimum(-9999999.0)\n        self.DS_01_Coor_X.setMaximum(9999999.99)\n        self.DS_01_Coor_X.setSingleStep(SingleStep)\n        self.DS_01_Coor_X.setSuffix(u\" mm\")\n        self.DS_01_Coor_X.valueChanged.connect(self.on_DS_01_Coor_X_valueChanged)\n \n        self.LB_02_Coor_Y = QLabel()\n        \n        self.DS_02_Coor_Y = QDoubleSpinBox()\n        self.DS_02_Coor_Y.setDecimals(7)\n        self.DS_02_Coor_Y.setMinimum(-9999999.0)\n        self.DS_02_Coor_Y.setMaximum(9999999.99)\n        self.DS_02_Coor_Y.setSingleStep(SingleStep)\n        self.DS_02_Coor_Y.setSuffix(\" mm\")\n        self.DS_02_Coor_Y.valueChanged.connect(self.on_DS_02_Coor_Y_valueChanged)\n \n        self.LB_03_Coor_Z = QLabel()\n        \n        self.DS_03_Coor_Z = QDoubleSpinBox()\n        self.DS_03_Coor_Z.setDecimals(7)\n        self.DS_03_Coor_Z.setMinimum(-9999999.0)\n        self.DS_03_Coor_Z.setMaximum(9999999.99)\n        self.DS_03_Coor_Z.setSingleStep(SingleStep)\n        self.DS_03_Coor_Z.setSuffix(u\" mm\")\n        self.DS_03_Coor_Z.valueChanged.connect(self.on_DS_03_Coor_Z_valueChanged)\n        ####\n\n        self.groupBox_02 = QWidget()\n \n        self.LB_01_Stretch_X = QLabel()\n        \n        self.DS_01_Stretch_X = QDoubleSpinBox()\n        self.DS_01_Stretch_X.setDecimals(7)\n        self.DS_01_Stretch_X.setMinimum(-9999999.0)\n        self.DS_01_Stretch_X.setMaximum(9999999.99)\n        self.DS_01_Stretch_X.setSingleStep(SingleStep)\n        self.DS_01_Stretch_X.setSuffix(u\" mm\")\n        self.DS_01_Stretch_X.valueChanged.connect(self.on_DS_01_Stretch_X_valueChanged)\n \n        self.LB_02_Stretch_Y = QLabel()\n        \n        self.DS_02_Stretch_Y = QDoubleSpinBox()\n        self.DS_02_Stretch_Y.setDecimals(7)\n        self.DS_02_Stretch_Y.setMinimum(-9999999.0)\n        self.DS_02_Stretch_Y.setMaximum(9999999.99)\n        self.DS_02_Stretch_Y.setSingleStep(SingleStep)\n        self.DS_02_Stretch_Y.setSuffix(u\" mm\")\n        self.DS_02_Stretch_Y.valueChanged.connect(self.on_DS_02_Stretch_Y_valueChanged)\n \n        self.LB_03_Stretch_Z = QLabel()\n        \n        self.DS_03_Stretch_Z = QDoubleSpinBox()\n        self.DS_03_Stretch_Z.setDecimals(7)\n        self.DS_03_Stretch_Z.setMinimum(-9999999.0)\n        self.DS_03_Stretch_Z.setMaximum(9999999.99)\n        self.DS_03_Stretch_Z.setSingleStep(SingleStep)\n        self.DS_03_Stretch_Z.setSuffix(u\" mm\")\n        self.DS_03_Stretch_Z.valueChanged.connect(self.on_DS_03_Stretch_Z_valueChanged)\n        ####\n\n        self.groupBox_03 = QGroupBox()\n \n        self.CB_01_Axis_X = QCheckBox()\n        self.CB_01_Axis_X.clicked.connect(self.on_CB_01_Axis_X_clicked)\n \n        self.CB_02_Axis_Y = QCheckBox()\n        self.CB_02_Axis_Y.clicked.connect(self.on_CB_02_Axis_Y_clicked)\n\n        self.CB_03_Axis_Z = QCheckBox()\n        self.CB_03_Axis_Z.clicked.connect(self.on_CB_03_Axis_Z_clicked)\n        ####\n\n        self.groupBox_04 = QGroupBox()\n\n        self.RB_01_Wire = QRadioButton()\n        self.RB_01_Wire.setChecked(True)\n        self.RB_01_Wire.setIcon(QtGui.QIcon.fromTheme(\"Draft\",QtGui.QIcon(\":/icons/Draft_Wire.svg\")))\n        self.RB_01_Wire.clicked.connect(self.on_RB_01_Wire_clicked)\n \n        self.RB_02_BSpline = QRadioButton()\n        self.RB_02_BSpline.setIcon(QtGui.QIcon.fromTheme(\"Draft\",QtGui.QIcon(\":/icons/Draft_BSpline.svg\")))\n        self.RB_02_BSpline.clicked.connect(self.on_RB_02_BSpline_clicked)\n \n        self.RB_03_PointsCloud = QRadioButton()\n        self.RB_03_PointsCloud.setIcon(QtGui.QIcon.fromTheme(\"Draft\",QtGui.QIcon(\":/icons/PointsWorkbench.svg\")))\n        self.RB_03_PointsCloud.clicked.connect(self.on_RB_03_PointsCloud_clicked)\n\n        self.RB_04_Points = QRadioButton()\n        self.RB_04_Points.setIcon(QtGui.QIcon.fromTheme(\"Draft\",QtGui.QIcon(\":/icons/Draft_Point.svg\")))\n        self.RB_04_Points.clicked.connect(self.on_RB_04_Points_clicked)\n \n        self.CB_01_Nuance = QCheckBox()\n        self.CB_01_Nuance.setEnabled(False)\n        self.CB_01_Nuance.clicked.connect(self.on_CB_01_Nuance_clicked)\n        ####\n\n        self.groupBox_05 = QGroupBox()\n \n        self.RB_01_Photo = QRadioButton()\n        self.RB_01_Photo.setChecked(True)\n        self.RB_01_Photo.clicked.connect(self.on_RB_01_Photo_clicked)\n \n        self.RB_02_PLan = QRadioButton()\n        self.RB_02_PLan.clicked.connect(self.on_RB_02_PLan_clicked)\n        ####\n \n        self.groupBox_06 = QGroupBox()\n\n        self.CB_01_Pcd = QCheckBox()\n        self.CB_01_Pcd.clicked.connect(self.on_CB_01_Pcd_clicked)\n \n        self.CB_02_Asc = QCheckBox()\n        self.CB_02_Asc.clicked.connect(self.on_CB_02_Asc_clicked)\n        ####\n\n        self.groupBox_07 = QGroupBox()\n\n#        section horizontalSlider \n        self.horizontalSlider = QSlider()\n        self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal)\n        self.horizontalSlider.setMaximum(255)\n        self.horizontalSlider.setMinimum(0)\n        self.horizontalSlider.setSliderPosition(0)\n        self.horizontalSlider.setPageStep(1)\n        self.horizontalSlider.setInvertedAppearance(False)\n        self.horizontalSlider.valueChanged.connect(self.on_horizontal_slider)\n \n        self.SP_01_Height = QSpinBox()\n        self.SP_01_Height.setMinimum(0)\n        self.SP_01_Height.setMaximum(255)\n        self.SP_01_Height.setValue(0)\n        self.SP_01_Height.setSuffix(u\" height\")\n        self.SP_01_Height.valueChanged.connect(self.on_SP_01_Height_valueChanged)\n\n        self.LB_01_Mode_Raw = QLabel()\n \n        self.CB_01_Mode_Raw = QCheckBox()\n        self.CB_01_Mode_Raw.setAutoFillBackground(False)\n        self.CB_01_Mode_Raw.clicked.connect(self.on_CB_01_Mode_Raw_clicked)\n \n        self.CB_02_Contour = QCheckBox()\n        self.CB_02_Contour.clicked.connect(self.on_CB_02_Contour_clicked)\n \n        self.SP_02_Contour = QSpinBox()\n        self.SP_02_Contour.setMinimum(0)\n        self.SP_02_Contour.setMaximum(20)\n        self.SP_02_Contour.setEnabled(False)\n        self.SP_02_Contour.setValue(0)\n        self.SP_02_Contour.setSuffix(u\"/2 Contour\")\n        self.SP_02_Contour.valueChanged.connect(self.on_SP_02_Contour_valueChanged)\n\n        self.LB_03_Capping = QLabel()\n        \n        self.CB_03_White = QCheckBox()\n        self.CB_03_White.clicked.connect(self.on_CB_03_White_clicked)\n        \n        self.SP_03_Capping = QSpinBox()\n        self.SP_03_Capping.setMinimum(0)\n        self.SP_03_Capping.setMaximum(20)\n        self.SP_03_Capping.setValue(20)\n        self.SP_03_Capping.setSuffix(u\" Capping\")\n        self.SP_03_Capping.valueChanged.connect(self.on_SP_03_Capping_valueChanged)\n\n        ####\n \n        self.groupBox_08 = QGroupBox()\n\n        self.LB_01_File = QLabel()\n\n        self.PBA_progressBar = QProgressBar()\n        self.PBA_progressBar.setValue(0)\n        self.PBA_progressBar.setVisible(True)\n        self.PBA_progressBar.setOrientation(QtCore.Qt.Horizontal)\n        self.PBA_progressBar.setAlignment(QtCore.Qt.AlignCenter)\n\n        self.PB_01_File_Launch = QPushButton()\n        self.PB_01_File_Launch.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogOkButton)))\n        self.PB_01_File_Launch.clicked.connect(self.on_PB_01_File_Launch_clicked) # load file\n\n        self.PB_02_Help = QPushButton()\n        self.PB_02_Help.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_MessageBoxQuestion)))\n        self.PB_02_Help.clicked.connect(self.on_PB_02_Help_clicked)               # help\n \n        self.PB_03_Quit = QPushButton()\n        self.PB_03_Quit.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogCloseButton)))\n        self.PB_03_Quit.clicked.connect(self.on_PB_03_Quit_clicked)               # quit\n \n        #### layout ###################################################\n        self.gridLayout_000 = QGridLayout(self.centralWidget)\n        self.gridLayout_000.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_00 = QGridLayout(self.groupBox)\n        self.gridLayout_00.setContentsMargins(10, 10, 10, 10)\n        ####\n        self.tabWidget = QTabWidget() #Tab\n        ####\n        self.tabWidget.addTab(self.groupBox_01, \"Coordinate\")\n        self.gridLayout_01 = QGridLayout(self.groupBox_01)\n        self.gridLayout_01.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_01.addWidget(self.LB_01_Coor_X, 0, 0, 1, 1)\n        self.gridLayout_01.addWidget(self.DS_01_Coor_X, 0, 1, 1, 1)\n        self.gridLayout_01.addWidget(self.LB_02_Coor_Y, 1, 0, 1, 1)\n        self.gridLayout_01.addWidget(self.DS_02_Coor_Y, 1, 1, 1, 1)\n        self.gridLayout_01.addWidget(self.LB_03_Coor_Z, 2, 0, 1, 1)\n        self.gridLayout_01.addWidget(self.DS_03_Coor_Z, 2, 1, 1, 1)\n        ####\n        self.tabWidget.addTab(self.groupBox_02, \"Stretching\")\n        self.gridLayout_02 = QGridLayout(self.groupBox_02)\n        self.gridLayout_02.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_02.addWidget(self.LB_01_Stretch_X, 0, 0, 1, 1)\n        self.gridLayout_02.addWidget(self.DS_01_Stretch_X, 0, 1, 1, 1)\n        self.gridLayout_02.addWidget(self.LB_02_Stretch_Y, 1, 0, 1, 1)\n        self.gridLayout_02.addWidget(self.DS_02_Stretch_Y, 1, 1, 1, 1)\n        self.gridLayout_02.addWidget(self.LB_03_Stretch_Z, 2, 0, 1, 1)\n        self.gridLayout_02.addWidget(self.DS_03_Stretch_Z, 2, 1, 1, 1)\n        ####\n        self.gridLayout_00.addWidget(self.tabWidget, 0, 0, 1, 2)\n        ####\n        self.gridLayout_03 = QGridLayout(self.groupBox_03)\n        self.gridLayout_03.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_03.addWidget(self.CB_01_Axis_X, 0, 0, 1, 1)\n        self.gridLayout_03.addWidget(self.CB_02_Axis_Y, 0, 1, 1, 1)\n        self.gridLayout_03.addWidget(self.CB_03_Axis_Z, 0, 2, 1, 1)\n        self.gridLayout_00.addWidget(self.groupBox_03, 2, 0, 1, 2)\n        ####\n        self.gridLayout_04 = QGridLayout(self.groupBox_04)\n        self.gridLayout_04.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_04.addWidget(self.RB_01_Wire, 0, 0, 1, 1)\n        self.gridLayout_04.addWidget(self.RB_02_BSpline, 0, 1, 1, 1)\n        self.gridLayout_04.addWidget(self.RB_03_PointsCloud, 0, 2, 1, 1)\n        self.gridLayout_04.addWidget(self.RB_04_Points, 1, 0, 1, 1)\n        self.gridLayout_04.addWidget(self.CB_01_Nuance, 1, 1, 1, 1)\n        self.gridLayout_00.addWidget(self.groupBox_04, 3, 0, 1, 2)\n        ####\n        self.gridLayout_05 = QGridLayout(self.groupBox_05)\n        self.gridLayout_05.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_05.addWidget(self.RB_01_Photo, 0, 0, 1, 1)\n        self.gridLayout_05.addWidget(self.RB_02_PLan, 0, 1, 1, 1)\n        self.gridLayout_00.addWidget(self.groupBox_05, 4, 0, 1, 1)\n        ##\n        self.gridLayout_06 = QGridLayout(self.groupBox_06)\n        self.gridLayout_06.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_06.addWidget(self.CB_01_Pcd, 0, 0, 1, 1)\n        self.gridLayout_06.addWidget(self.CB_02_Asc, 0, 1, 1, 1)\n        self.gridLayout_00.addWidget(self.groupBox_06, 4, 1, 1, 1)\n        ####\n        self.gridLayout_07 = QGridLayout(self.groupBox_07)\n        self.gridLayout_07.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_07.addWidget(self.horizontalSlider, 0, 0, 1, 3)\n        self.gridLayout_07.addWidget(self.SP_01_Height, 0, 3, 1, 1)\n        self.gridLayout_07.addWidget(self.LB_01_Mode_Raw, 1, 0, 1, 1)\n        self.gridLayout_07.addWidget(self.CB_01_Mode_Raw, 1, 1, 1, 1)\n        self.gridLayout_07.addWidget(self.CB_02_Contour, 1, 2, 1, 1)\n        self.gridLayout_07.addWidget(self.SP_02_Contour, 1, 3, 1, 1)\n        self.gridLayout_07.addWidget(self.LB_03_Capping, 2, 0, 1, 1)\n        self.gridLayout_07.addWidget(self.CB_03_White, 2, 1, 1, 1)\n        self.gridLayout_07.addWidget(self.SP_03_Capping, 2, 3, 1, 1)\n        self.gridLayout_00.addWidget(self.groupBox_07, 5, 0, 1, 2)\n        ####\n        self.gridLayout_08 = QGridLayout(self.groupBox_08)\n        self.gridLayout_08.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_08.addWidget(self.LB_01_File, 0, 0, 1, 3)\n        self.gridLayout_08.addWidget(self.PBA_progressBar, 1, 0, 1, 3)\n        self.gridLayout_08.addWidget(self.PB_01_File_Launch, 2, 0, 1, 1)\n        self.gridLayout_08.addWidget(self.PB_02_Help, 2, 1, 1, 1)\n        self.gridLayout_08.addWidget(self.PB_03_Quit, 2, 2, 1, 1)\n        self.gridLayout_00.addWidget(self.groupBox_08, 6, 0, 1, 2)\n        self.gridLayout_000.addWidget(self.groupBox, 0, 0, 1, 1)\n        #### layout ###################################################\n\n        MainWindow.setCentralWidget(self.centralWidget)\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n        MainWindow.setWindowTitle(u\"FCTexture\")\n        MainWindow.setWindowIcon(QtGui.QIcon(path+'FCTexture.png'))\n        MainWindow.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)   # PySide cette fonction met la fenetre en avant\n\n        self.groupBox.setTitle(u\"ver : \" + __version__ + \" : \" + __date__ + \" (rmu)\")\n        ####\n        self.DS_01_Coor_X.setToolTip(u\"Coordinate placement Axis X.\")\n        self.LB_01_Coor_X.setText(u\"Coordinate  <font color=\"\"#a40000\"\"> <b> X </b> </font> <img src=:/icons/Std_CoordinateSystem.svg  height=\"\"18\"\" width=\"\"18\"\" align=top>\")#middle bottom \n        self.DS_02_Coor_Y.setToolTip(u\"Coordinate placement Axis Y.\")\n        self.LB_02_Coor_Y.setText(u\"Coordinate  <font color=\"\"#4e9a06\"\"> <b> Y </b> </font> <img src=:/icons/Std_CoordinateSystem.svg  height=\"\"18\"\" width=\"\"18\"\" align=top>\")#middle bottom \n        self.DS_03_Coor_Z.setToolTip(u\"Coordinate placement Axis Z.\")\n        self.LB_03_Coor_Z.setText(u\"Coordinate  <font color=\"\"#204a87\"\"> <b> Z </b> </font> <img src=:/icons/Std_CoordinateSystem.svg  height=\"\"18\"\" width=\"\"18\"\" align=top>\")#middle bottom \n        ####\n        self.DS_01_Stretch_X.setToolTip(u\"Stretching Axis X.\")\n        self.LB_01_Stretch_X.setText(u\"<html> <body> Stretching <font color=\"\"#a40000\"\"> <b> X </b> </font> </body> </html>\" )\n        self.DS_02_Stretch_Y.setToolTip(u\"Stretching Axis Y.\")\n        self.LB_02_Stretch_Y.setText(u\"<html> <body> Stretching <font color=\"\"#4e9a06\"\"> <b> Y </b> </font> </body> </html>\" )\n        self.DS_03_Stretch_Z.setToolTip(u\"Stretching Axis Z.\")\n        self.LB_03_Stretch_Z.setText(u\"<html> <body> Stretching <font color=\"\"#204a87\"\"> <b> Z </b> </font> </body> </html>\" )\n\n        ####\n        self.groupBox_03.setTitle(u\"Inversion\")\n        self.CB_01_Axis_X.setText(u\"Axis X\")\n        self.CB_01_Axis_X.setToolTip(u\"Axis X\")\n        self.CB_01_Axis_X.setStyleSheet(\"QCheckBox {color : #a40000; font: bold}\")  # couleur du texte et gras\n        self.CB_02_Axis_Y.setText(u\"Axis Y\")\n        self.CB_02_Axis_Y.setToolTip(u\"Axis Y\")\n        self.CB_02_Axis_Y.setStyleSheet(\"QCheckBox {color : #4e9a06; font: bold}\")  # couleur du texte et gras\n        self.CB_03_Axis_Z.setText(u\"Axis Z\")\n        self.CB_03_Axis_Z.setToolTip(u\"Axis Z\")\n        self.CB_03_Axis_Z.setStyleSheet(\"QCheckBox {color : #204a87; font: bold}\")  # couleur du texte et gras\n        ####\n        self.groupBox_04.setTitle(u\"Mode 8 Bits\")\n        self.RB_01_Wire.setText(u\"Wire\")\n        self.RB_01_Wire.setToolTip(u\"Make a Wire\")\n        self.RB_02_BSpline.setText(u\"BSpline\")\n        self.RB_02_BSpline.setToolTip(u\"Make a BSpline\")\n        self.RB_03_PointsCloud.setToolTip(u\"Make a Cloud points\")\n        self.RB_03_PointsCloud.setText(u\"Cloud\")\n        self.RB_04_Points.setText(u\"Point\")\n        self.RB_04_Points.setToolTip(u\"Make a Point (the procedure can be long)\")\n        self.CB_01_Nuance.setText(u\"Nuance\")\n        self.CB_01_Nuance.setToolTip(u\"To display items in mode photo with shade of gray 20 or 256 shades of gray if Raw mode is set 255\")\n        ####\n        self.groupBox_05.setTitle(u\"Mode 32 bits\")\n        self.RB_01_Photo.setText(u\"Photo\")\n        self.RB_01_Photo.setToolTip(u\"The photo mode is automatically activated when a 32-bit image is detected.\" + \"\\n\"\n                                      u\"(the procedure can be long)\")\n        self.RB_02_PLan.setText(u\"Plan\")\n        self.RB_02_PLan.setToolTip(u\"The plan mode is possible when a 32-bit image and ignore the background of the plan.\" + \"\\n\"\n                                      u\"(the procedure can be long)\")\n        ##\n        self.groupBox_06.setTitle(u\"File\")\n        self.CB_01_Pcd.setText(u\".pcd\")\n        self.CB_01_Pcd.setToolTip(u\"Save the coordinates in file format OriginalName.bmp.pcd\" + \"\\n\"\n                                       u\"The function Contour in not availlable with this pcd format\" + \"\\n\"\n                                       u\"\"\n                                       u\"Version saved : ascii .PCD v0.7\")\n        self.CB_02_Asc.setText(u\".asc\")\n        self.CB_02_Asc.setToolTip(u\"Save the coordinates in a file OriginalName.bmp.asc\" + \"\\n\"\n                                       u\"The are in format : X Y Z without comma\")\n        ####\n        self.groupBox_07.setTitle(u\"Capping (10 mm)\")\n        self.groupBox_07.setToolTip(u\"This function work only with the W/B mode\" + \"\\n\"\n                                    u\"The title group give the real height of the shape\" + \"\\n\"\n                                    u\"Ex: Capping (10 mm)\")\n        self.LB_01_Mode_Raw.setText(u\"Raw mode\")\n        self.horizontalSlider.setToolTip(u\"This function work only with mode Raw 20\" + \"\\n\"\n                                         u\"The title group give the real height of the shape\" + \"\\n\"\n                                         u\"Ex: 1 to 255\")\n        self.CB_01_Mode_Raw.setText(\"20\")\n        self.CB_01_Mode_Raw.setToolTip(u\"Raw mode 256 colors or 20 colors\")\n        self.LB_03_Capping.setText(u\"Capping\")\n        self.SP_01_Height.setToolTip(u\"This function work only with mode Raw 20\" + \"\\n\"\n                                      u\"The title group give the real height of the shape\" + \"\\n\"\n                                      u\"Ex: 1 to 255\")\n        self.CB_03_White.setText(u\"White\")\n        self.CB_03_White.setToolTip(u\"Capping color White or Black\")\n        self.CB_02_Contour.setToolTip(u\"Check for activate the Contour SP_03_Capping\")\n        self.SP_02_Contour.setToolTip(u\"Contour /2 = 1 mm /2 on the height axis Z\")\n        self.SP_03_Capping.setToolTip(u\"Capping [20 to 0 (white) normal mode] or [255 to 0 (white) Raw mode]\")\n        ####\n        self.groupBox_08.setTitle(u\"Command\")\n        self.LB_01_File.setText(u\"File : \")\n        self.LB_01_File.setToolTip(u\"Gives informations about the file (Bits_pixel, Size data, Length, Height)\")\n#        self.PBA_progressBar.setToolTip(_translate(\"MainWindow\", \" \", None))\n        self.PB_01_File_Launch.setText(u\"File and launch\")\n        self.PB_01_File_Launch.setToolTip(u\"Load the file and launch the process\")\n        self.PB_02_Help.setText(u\"Help\")\n        self.PB_02_Help.setStyleSheet(\"QToolTip { color: #ffffff; background-color: #204a87; border-color: #ffffff; border-width:2px; border-style:solid; border-radius:0px }\");\n        self.PB_02_Help.setToolTip(u\"Display the Wiki page in the FreeCAD browser\" + \"\\n\\n\"\n                                   u\"For change the parameter disponible: go to Tools > Edit parameter...\" + \"\\n\\n\"\n                                   u\"__The global step on spinBox :__\" + \"\\n\"\n                                   u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__ + \" > SingleStep\" + \"\\n\"\n                                   u\"Adjust the value desired (1.0 by default)\" + \"\\n\\n\"\n                                   u\"__For search if the macro is upraded :__\" + \"\\n\"\n                                   u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__ + \" > switchVesionMacroSearch\" + \"\\n\"\n                                   u\"Adjust the switchVesionMacroSearch to True (False by default)\" + \"\\n\")\n        self.PB_03_Quit.setText(u\"Quit\")\n        self.PB_03_Quit.setToolTip(u\"Quit FCTexture\")\n\n    def on_DS_01_Coor_X_valueChanged(self,value):\n        global position_X\n        position_X = value\n \n    def on_DS_02_Coor_Y_valueChanged(self,value):\n        global position_Y\n        position_Y = value\n \n    def on_DS_03_Coor_Z_valueChanged(self,value):\n        global position_Z\n        position_Z = value\n \n    def on_DS_01_Stretch_X_valueChanged(self,value):\n        global etirement_X\n        etirement_X = value\n \n    def on_DS_02_Stretch_Y_valueChanged(self,value):\n        global etirement_Y\n        etirement_Y = value\n \n    def on_DS_03_Stretch_Z_valueChanged(self,value):\n        global etirement_Z\n        etirement_Z = value\n \n    def on_horizontal_slider(self, value):\n        global modeBrut\n        global ecreter\n        global valueFilter\n        if modeBrut == 0:\n            valueFilter = float(value)\n            self.SP_01_Height.setValue(value)\n            self.groupBox_07.setTitle(\"Height (\"+str(valueFilter)+\" mm)\")\n        else:\n            valueFilter = 0.0\n            self.horizontalSlider.setSliderPosition(0)\n            self.SP_01_Height.setValue(0)\n\n    def on_SP_01_Height_valueChanged(self, value):\n        global modeBrut\n        global ecreter\n        global valueFilter\n        if modeBrut == 0:\n            valueFilter = float(value)\n            self.horizontalSlider.setValue(value)\n            self.groupBox_07.setTitle(\"Height (\"+str(valueFilter)+\" mm)\")\n        else:\n            valueFilter = 0.0\n            self.horizontalSlider.setSliderPosition(0)\n            self.SP_01_Height.setValue(0)\n\n    def on_CB_01_Mode_Raw_clicked(self):\n        global modeBrut\n        global ecreter\n        global valueFilter\n        valueFilter = 0.0\n        self.horizontalSlider.setSliderPosition(0)\n\n        if self.CB_01_Mode_Raw.isChecked():\n            modeBrut = 1                              # if checked mode brut = 255 colors\n            self.SP_03_Capping.setMaximum(255)\n            self.groupBox_07.setTitle(\"Capping (255 mm)\")\n            self.CB_01_Mode_Raw.setText(\"255\")\n            self.SP_02_Contour.setMaximum(255)\n            self.SP_02_Contour.setSuffix(u\" Contour\")\n            self.SP_02_Contour.setToolTip(u\"Contour = 1 mm on the height axis Z\")\n            self.SP_01_Height.setEnabled(False)\n            if  self.CB_03_White.isChecked():         # if Black\n                self.SP_03_Capping.setValue(0)\n                ecreter  = 0\n            else:\n                self.SP_03_Capping.setValue(255)\n                ecreter  = 255\n        else:\n            modeBrut = 0                              # if nochecked White mode brut = 20 colors\n            self.SP_03_Capping.setMaximum(20)\n            self.groupBox_07.setTitle(\"Capping (10 mm)\")\n            self.CB_01_Mode_Raw.setText(\"20\")\n            self.SP_02_Contour.setMaximum(20)\n            self.SP_02_Contour.setSuffix(u\"/2 Contour\")\n            self.SP_02_Contour.setToolTip(u\"Contour /2 = 1 mm /2 on the height axis Z\")\n            self.SP_01_Height.setEnabled(True)\n            if  self.CB_03_White.isChecked():         # if Black\n                self.SP_03_Capping.setValue(0)\n                ecreter  = 0\n            else:\n                self.SP_03_Capping.setValue(20)       # if White\n                ecreter  = 20\n\n    def on_CB_03_White_clicked(self):                 # if checked ecreter Black else White\n        global modeColor\n        global ecreter\n        global valueFilter\n        valueFilter = 0.0\n        self.horizontalSlider.setSliderPosition(0)\n\n        if self.CB_03_White.isChecked():\n            modeColor = 1                             # if checked mode Black\n            self.CB_03_White.setText(\"Black\")\n            self.SP_03_Capping.setValue(0)\n        else:\n            modeColor = 0                             # if nochecked mode White\n            self.CB_03_White.setText(\"White\")\n            if self.CB_01_Mode_Raw.isChecked():\n                self.SP_03_Capping.setValue(255)\n                self.SP_02_Contour.setSuffix(u\" Contour\")\n                self.SP_02_Contour.setToolTip(u\"Contour = 1 mm on the height axis Z\")\n            else:\n                self.SP_03_Capping.setValue(20)\n                self.SP_02_Contour.setSuffix(u\"/2 Contour\")\n                self.SP_02_Contour.setToolTip(u\"Contour /2 = 1 mm /2 on the height axis Z\")\n\n    def on_SP_03_Capping_valueChanged(self,value):    # ecreter\n        global ecreter\n        global valueFilter\n        valueFilter = 0.0\n        self.horizontalSlider.setSliderPosition(0)\n        ecreter = value\n\n    def on_CB_02_Contour_clicked(self):\n        global switchContour\n        global ecreterFond\n        global valueFilter\n        global fileCoordpcd\n        valueFilter = 0.0\n        self.horizontalSlider.setSliderPosition(0)\n\n        self.CB_01_Pcd.setChecked(False)\n        fileCoordpcd = 0\n\n        if self.CB_02_Contour.isChecked():\n            switchContour = 1\n            self.SP_02_Contour.setEnabled(True)\n            if self.CB_01_Mode_Raw.isChecked():\n                self.SP_03_Capping.setValue(255)\n                self.SP_02_Contour.setSuffix(u\" Contour\")\n                self.SP_02_Contour.setToolTip(u\"Contour = 1 mm on the height axis Z\")\n            else:\n                self.SP_03_Capping.setValue(20)\n                self.SP_02_Contour.setSuffix(u\"/2 Contour\")\n                self.SP_02_Contour.setToolTip(u\"Contour /2 = 1 mm /2 on the height axis Z\")\n        else:\n            switchContour = 0\n            ecreterFond = 0\n            self.SP_02_Contour.setValue(0)\n            self.SP_02_Contour.setEnabled(False)\n            if self.CB_01_Mode_Raw.isChecked():\n                self.SP_02_Contour.setSuffix(u\" Contour\")\n                self.SP_02_Contour.setToolTip(u\"Contour = 1 mm on the height axis Z\")\n            else:\n                self.SP_02_Contour.setSuffix(u\"/2 Contour\")\n                self.SP_02_Contour.setToolTip(u\"Contour /2 = 1 mm /2 on the height axis Z\")\n\n    def on_SP_02_Contour_valueChanged(self,value):    # ecreter Fond\n        global ecreterFond\n        ecreterFond = value\n\n    def on_RB_04_Points_clicked(self):                # if checked then mode point N/B\n        global avecLigne\n        avecLigne = 0\n        self.CB_01_Nuance.setEnabled(True)\n        self.CB_02_Contour.setEnabled(True)\n \n    def on_RB_01_Wire_clicked(self):                  # if checked then 0=makeWire N/B\n        global typeligne\n        global avecLigne\n        typeligne = 0\n        avecLigne = 1\n        self.CB_01_Nuance.setChecked(False)\n        self.CB_01_Nuance.setEnabled(False)\n        self.CB_02_Contour.setEnabled(True)\n\n    def on_RB_02_BSpline_clicked(self):               # if no checked then 1=BSpline N/B\n        global typeligne\n        global avecLigne\n        global switchContour\n        global ecreterFond\n        typeligne = 1\n        avecLigne = 1\n        switchContour = 0\n        ecreterFond = 0\n        self.CB_01_Nuance.setChecked(False)\n        self.CB_01_Nuance.setEnabled(False)\n        self.CB_02_Contour.setEnabled(False)\n        self.CB_02_Contour.setChecked(False)\n        self.SP_02_Contour.setValue(0)\n        self.SP_02_Contour.setEnabled(False)\n        if self.CB_01_Mode_Raw.isChecked():\n            self.SP_02_Contour.setSuffix(u\" Contour\")\n            self.SP_02_Contour.setToolTip(u\"Contour = 1 mm on the height axis Z\")\n        else:\n            self.SP_02_Contour.setSuffix(u\"/2 Contour\")\n            self.SP_02_Contour.setToolTip(u\"Contour /2 = 1 mm /2 on the height axis Z\")\n\n    def on_RB_03_PointsCloud_clicked(self):           # Cloud points\n        global typeligne\n        global avecLigne\n        typeligne = 2\n        ecreterFond = 0\n        self.CB_01_Nuance.setChecked(False)\n        self.CB_01_Nuance.setEnabled(False)\n        self.CB_02_Contour.setEnabled(True)\n\n    def on_CB_01_Axis_X_clicked(self):                # if checked inverse X\n        global inversion_X\n        if self.CB_01_Axis_X.isChecked():\n            inversion_X  = 1\n        else:\n            inversion_X  = 0\n \n    def on_CB_02_Axis_Y_clicked(self):                # if checked inverse Y\n        global inversion_Y\n        if self.CB_02_Axis_Y.isChecked():\n            inversion_Y  = 1\n        else:\n            inversion_Y  = 0\n \n    def on_CB_03_Axis_Z_clicked(self):                # if checked inverse Z\n        global inversion_Z\n        if self.CB_03_Axis_Z.isChecked():\n            inversion_Z  = 1\n        else:\n            inversion_Z  = 0\n \n    def on_RB_01_Photo_clicked(self):                 # if checked then Photo colors\n        global plan\n        plan = 0\n \n    def on_RB_02_PLan_clicked(self):                  # if checked then Plan colors\n        global plan\n        global modeBrut\n        global ecreter\n        plan = 1\n        modeBrut = 1                                  # if checked mode brut = 255 colors\n        ecreter  = 255\n        self.SP_03_Capping.setMaximum(255)\n        self.SP_03_Capping.setValue(255)\n        self.CB_03_White.setText(\"White\")\n        self.CB_01_Mode_Raw.setText(\"255\")\n        self.CB_01_Mode_Raw.setChecked(True)\n\n    def on_CB_01_Nuance_clicked(self):                # if checked fond Black else White\n        global nuance\n        if self.CB_01_Nuance.isChecked():\n            nuance = 1                                # if checked Nuance ok\n        else:\n            nuance = 0                                # if nochecked Nuance Ko\n \n    def on_PB_03_Quit_clicked(self):\n        FreeCAD.Console.PrintMessage(\"End FCTexture\"+\"\\n\")\n        self.window.hide()\n \n    def on_PB_02_Help_clicked(self):\n        try:\n            webbrowser.open(\"https://wiki.freecad.org/Macro_Texture\")\n            App.Console.PrintMessage(\"https://wiki.freecad.org/Macro_Texture\" + \"\\n\")\n        except Exception:\n            App.Console.PrintMessage(u\"Not access to Web\")\n\n    def on_CB_01_Pcd_clicked(self):                   # pcd\n        global fileCoordpcd\n        if self.CB_02_Contour.isChecked():\n            self.CB_01_Pcd.setChecked(False)\n        else:\n            if self.CB_01_Pcd.isChecked():\n                fileCoordpcd = 1                      # if checked file pcd ok\n            else:\n                fileCoordpcd = 0                      # if nochecked file pcd Ko\n\n    def on_CB_02_Asc_clicked(self):                   # Asc\n        global fileCoordasc\n        if self.CB_02_Asc.isChecked():\n            fileCoordasc = 1                          # if checked file asc ok\n        else:\n            fileCoordasc = 0                          # if nochecked file asc Ko\n        \n    def on_PB_01_File_Launch_clicked(self):\n        global path\n        global pathFile\n        global position_X\n        global position_Y\n        global position_Z\n        global etirement_X\n        global etirement_Y\n        global etirement_Z\n        global modeBrut\n        global modeColor\n        global ecreter\n        global typeligne\n        global avecLigne\n        global inversion_X\n        global inversion_Y\n        global inversion_Z\n        global plan\n        global fond\n        global bits_pixel\n        global tailleDonnees\n        global fileCoordasc\n        global fileCoordpcd\n        global ecreterFond\n        global switchContour\n        global valueFilter\n \n#        Configuration FCTexture\n#        FreeCAD.Console.PrintMessage(\"position_X  : \"+str(position_X)+\"\\n\")\n#        FreeCAD.Console.PrintMessage(\"position_Y  : \"+str(position_Y)+\"\\n\")\n#        FreeCAD.Console.PrintMessage(\"position_Z  : \"+str(position_Z)+\"\\n\")\n#        FreeCAD.Console.PrintMessage(\"etirement_X : \"+str(etirement_X)+\"\\n\")\n#        FreeCAD.Console.PrintMessage(\"etirement_Y : \"+str(etirement_Y)+\"\\n\")\n#        FreeCAD.Console.PrintMessage(\"etirement_Z : \"+str(etirement_Z)+\"\\n\")\n#        FreeCAD.Console.PrintMessage(\"ecreter     : \"+str(ecreter)+\"\\n\")\n#        FreeCAD.Console.PrintMessage(\"wire        : \"+str(avecLigne)+\"\\n\")\n#        FreeCAD.Console.PrintMessage(\"typeligne   : \"+str(typeligne)+\"\\n\")\n#        FreeCAD.Console.PrintMessage(\"point       : \"+str(avecLigne)+\"\\n\")\n#        FreeCAD.Console.PrintMessage(\"inversion_X : \"+str(inversion_X)+\"\\n\")\n#        FreeCAD.Console.PrintMessage(\"inversion_Y : \"+str(inversion_Y)+\"\\n\")\n#        FreeCAD.Console.PrintMessage(\"inversion_Z : \"+str(inversion_Z)+\"\\n\")\n#        FreeCAD.Console.PrintMessage(\"plan        : \"+str(plan)+\"\\n\")\n#        FreeCAD.Console.PrintMessage(\"fond        : \"+str(fond)+\"\\n\")\n \n        doc = FreeCAD.ActiveDocument\n        if doc == None:\n            doc = FreeCAD.newDocument()\n\n        self.PB_01_File_Launch.setStyleSheet(\"QPushButton {background-color: QPalette.Base}\") # origin system\n        self.LB_01_File.setText(\"File :\")\n        OpenName = \"\"\n\n        OpenName, Filter = QFileDialog.getOpenFileName(None, \"Read an image file\", pathFile, \"*.bmp\")# PySide\n        try:\n            if OpenName != \"\":\n                FreeCAD.ActiveDocument.openTransaction(\"FCTexture \")# memorise les actions (avec annuler restore)\n                SaveName = OpenName\n                \n                ####new2\n                pathFile      = os.path.dirname(SaveName) + \"/\"  #= C:/Provisoire400/\n                formatFichier = os.path.splitext(SaveName)[1]    #= .png\n                SaveName      = os.path.splitext(SaveName)[0]    #= /home/kubuntu/.FreeCAD/Macro/Texture_007_H #= C:/Provisoire400/image3D\n                SaveNameformatFichier = SaveName + formatFichier #= C:/Provisoire400/image3D.png\n                ####new2\n                FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/FCTexture\").SetString(\"Path\",pathFile)\n                ####new\n                \n                OpenName = SaveNameformatFichier\n                chrono(1)\n\n                FreeCAD.Console.PrintMessage(\"Read the file \"+OpenName+\"\\n\")\n                f = open(OpenName, \"rb\")\n                length = os.path.getsize(OpenName)\n                                 # decode header file\n                bytes = f.read(2)# Signature du fichier. BM=Bitmap windows, BA= Bitmap\n    #            FreeCAD.Console.PrintMessage(str(bytes[0]) + str(bytes[1])+\"\\n\")\n                bytes = f.read(4)# Taille totale du fichier en octets\n                bytes = f.read(4)# Champ reserve\n \n                bytes = f.read(4)# Adresse de la zone de definition de l image\n                adresse = decobit(bytes[0],bytes[1],bytes[2],bytes[3])\n    #            FreeCAD.Console.PrintMessage(str(adresse)+\" adresse \"+\"\\n\")\n \n                bytes = f.read(4)# Taille en octets de l'en-tete BITMAPINFOHEADER\n                entete = decobit(bytes[0],bytes[1],bytes[2],bytes[3])\n    #            FreeCAD.Console.PrintMessage(str(entete)+\" entete \"+\"\\n\")\n \n                bytes = f.read(4)# Largeur de l image en pixels\n                Largeur = decobit(bytes[0],bytes[1],bytes[2],bytes[3])\n    #            FreeCAD.Console.PrintMessage(str(Largeur)+\" Largeur \"+\"\\n\")\n \n                bytes = f.read(4)# Hauteur de l image en pixels\n                hauteur = decobit(bytes[0],bytes[1],bytes[2],bytes[3])\n    #            FreeCAD.Console.PrintMessage(str(hauteur)+\" hauteur \"+\"\\n\")\n \n                bytes = f.read(2)# Nombre de plans\n                plans = decobit(bytes[0],bytes[1])\n    #            FreeCAD.Console.PrintMessage(str(plans)+\" plans \"+\"\\n\")\n                bytes = f.read(2)# Nombre de bits par pixel\n                bits_pixel = decobit(bytes[0],bytes[1])\n                FreeCAD.Console.PrintMessage(str(bits_pixel)+\" bits_pixel \"+\"\\n\")\n                bytes = f.read(4)# Type de compression : 0=pas de compression,1=compresse a 8 bits par pixel, 2=4bits par pixel.\n \n                bytes = f.read(4)# Taille en octets des donnees de l image\n                tailleDonnees = decobit(bytes[0],bytes[1],bytes[2],bytes[3])\n    #            FreeCAD.Console.PrintMessage(str(tailleDonnees)+\" tailleDonnees \"+\"\\n\")\n \n                bytes = f.read(4)# Resolution horizontale en pixels par metre\n                bytes = f.read(4)# Resolution verticale en pixels par metre\n \n                bytes = f.read(4)# Nombre de couleurs dans l image : 0=maximum possible. Si une palette est utilisee, ce nombre indique le nombre de couleurs de la palette\n                couleurs = decobit(bytes[0],bytes[1],bytes[2],bytes[3])\n#                try:\n#                    ## Grayscale 8-bit bitmaps saved by Photoshop have no palette, so couleurs = 0 (BITMAPINFOHEADER.biClrUsed = 0). \n#                    ## https://gist.github.com/mario52a/262317bc7d8555885b0e\n#                    ## tester ave un fichier Photoshop\n#                    ##if Photoshop: #detection Photoshop\n#                    if couleurs == 0: couleurs = 1 << bits_pixel\n#                except Exception:\n#                    None\n    #            FreeCAD.Console.PrintMessage(str(couleurs)+\" couleurs \"+\"\\n\")\n \n                bytes = f.read(4)# Nombre de couleurs importantes. 0= toutes importantes\n \n                self.LB_01_File.setText(\"File: \"+str(bits_pixel)+\":bits \" +str(tailleDonnees)+\":data (\"+str(Largeur)+\" x \"+str(hauteur)+\")\")\n                Gui.updateGui()                                        # rafraichi l'ecran\n \n                f.seek(adresse, 0) # seek(position, 0=defaut 1=a la position courante 2=a partir de la fin du fichier)\n \n                coor_X   = 0.0\n                coor_Y   = 0.0\n                coor_Z   = 0.0\n\n        ###########256 couleurs debut#####################################\n                if couleurs == 256:\n                    completion = Largeur % 4\n                    ii = 0\n\n                    pnts = []\n                    points = []\n                    pointsCloud = []\n                    del pnts[:]\n                    del points[:]\n                    del pointsCloud[:]\n                    import Points\n                    pointsCloud = Points.Points()\n\n##                    contourLineG = []                                                  # ligne du bord gauche\n##                    del contourLineG[:]                                                # ligne du bord gauche\n##                    contourLineD = []                                                  # ligne du bord droit\n##                    del contourLineD[:]                                                # ligne du bord droit\n\n                    self.PBA_progressBar.setMaximum(tailleDonnees)\n\n                    for Y in range(tailleDonnees):\n                        self.PBA_progressBar.setValue(Y)\n\n                        ii += 1\n                        try:\n                            bytes = ord(f.read(1))\n                            pnts.append(str(bytes))\n                        except Exception:\n                            None\n                        try:\n                            if ((ii % Largeur) == 0) and (completion > 0):\n                                if completion == 3:\n                                    bytes = (f.read(1))\n                                    Y += 1\n                                elif completion == 2:\n                                    bytes = (f.read(2))\n                                    Y += 2\n                                elif completion == 1:\n                                    bytes = (f.read(3))\n                                    Y += 3\n                                ii = 0\n                        except Exception:\n                            None\n \n                    f.close()\n                    ii = 0\n\n                    ####################################################################### pour asc\n                    if fileCoordasc != 0:\n                        mypath  = OpenName + \".asc\"\n                        file_asc = open(mypath,\"w\") #  save coordinates OpenName.asc\n                    ####################################################################### pour pcd\n                    # .PCD v.7 - Point Cloud Data file format # http://pointclouds.org/documentation/tutorials/pcd_file_format.php\n                    # for save PCD format # \n                    if fileCoordpcd != 0:\n                        mypath  = OpenName + \".pcd\"\n                        file_pcd = open(mypath,\"w\") #  save coordinates OpenName.pcd             # pour fichier PCD \n                        file_pcd.write(\"# .PCD v0.7 - Point Cloud Data file format\" + \"\\n\")      # .PCD v0.7 - Point Cloud Data file format\n                        file_pcd.write(\"VERSION .7\" + \"\\n\")                                      # VERSION 0.7\n                        file_pcd.write(\"FIELDS x y z rgb\" + \"\\n\")                                # FIELDS x y z rgb\n                        file_pcd.write(\"SIZE 4 4 4 4\"+\"\\n\")                                      # SIZE 4\n                        file_pcd.write(\"TYPE F F F F\"+\"\\n\")                                      # F F F F\n                        file_pcd.write(\"COUNT 1 1 1 1\"+\"\\n\")                                     # COUNT 1 1 1 1\n                        file_pcd.write(\"WIDTH \" + str(Largeur) + \"\\n\")                           # WIDTH 640\n                        file_pcd.write(\"HEIGHT \" + str(hauteur) + \"\\n\")                          # HEIGHT 480\n                        file_pcd.write(\"VIEWPOINT 0 0 0 1 0 0 0\" + \"\\n\")                         # VIEWPOINT 0 0 0 1 0 0 0\n                        file_pcd.write(\"POINTS \" + str( Largeur * hauteur) + \"\\n\")               # POINTS 307200\n                        file_pcd.write(\"DATA ascii\" + \"\\n\")                                      # DATA ascii\n                    ####################################################################### pour pcd\n\n                    if modeBrut == 0:\n                        ecreterFond = self.SP_02_Contour.value()\n                        ecreterFond = (float(ecreterFond)/2)\n                        self.SP_02_Contour.setSuffix(u\"/2 Contour\")\n                    else:\n                        ecreterFond = self.SP_02_Contour.value()\n                        self.SP_02_Contour.setSuffix(u\" Contour\")\n\n                    if switchContour == 0:\n                        ecreterFond = 1000\n\n                    if self.CB_03_Axis_Z.isChecked():\n                        ecreterFond = (-ecreterFond)\n\n                    self.PBA_progressBar.setMaximum(hauteur)\n\n                    FreeCAD.ActiveDocument.openTransaction(\"FCTexture\")    # memorise les actions (avec annuler restore)\n                    #FreeCAD.ActiveDocument.commitTransaction()         # restore les actions  (avec annuler restore)\n                    #FreeCAD.ActiveDocument.abortTransaction()          # abandonne les actions(avec annuler restore)\n\n                    for Y in range(hauteur):\n                        self.PBA_progressBar.setValue(Y)\n\n##                        switchLine = 0                                                 # switch lignes bords gauche droit\n\n                        for X in range(Largeur):\n\n                            if X > Largeur:\n                                del points[:]\n                            else:\n                                if modeBrut == 0:\n                                    if  float(pnts[ii])  > 247:  # 20        Filter\n                                        pnts[ii] = \"10\"\n                                    elif float(pnts[ii]) > 234:  # 19\n                                        pnts[ii] = \"9.5\"\n                                    elif float(pnts[ii]) > 221:  # 18\n                                        pnts[ii] = \"9\"\n                                    elif float(pnts[ii]) > 208:  # 17\n                                        pnts[ii] = \"8.5\"\n                                    elif float(pnts[ii]) > 195:  # 16\n                                        pnts[ii] = \"8\"\n                                    elif float(pnts[ii]) > 182:  # 15\n                                        pnts[ii] = \"7.5\"\n                                    elif float(pnts[ii]) > 169:  # 14\n                                        pnts[ii] = \"7\"\n                                    elif float(pnts[ii]) > 156:  # 13\n                                        pnts[ii] = \"6.5\"\n                                    elif float(pnts[ii]) > 143:  # 12\n                                        pnts[ii] = \"6\"\n                                    elif float(pnts[ii]) > 130:  # 11\n                                        pnts[ii] = \"5.5\"\n                                    elif float(pnts[ii]) > 117:  # 10\n                                        pnts[ii] = \"5\"\n                                    elif float(pnts[ii]) > 104:  # 9\n                                        pnts[ii] = \"4.5\"\n                                    elif float(pnts[ii]) > 91:   # 8\n                                        pnts[ii] = \"4\"\n                                    elif float(pnts[ii]) > 78:   # 7\n                                        pnts[ii] = \"3.5\"\n                                    elif float(pnts[ii]) > 65:   # 6\n                                        pnts[ii] = \"3\"\n                                    elif float(pnts[ii]) > 52:   # 5\n                                        pnts[ii] = \"2.5\"\n                                    elif float(pnts[ii]) > 39:   # 4\n                                        pnts[ii] = \"2\"\n                                    elif float(pnts[ii]) > 26:   # 3\n                                        pnts[ii] = \"1.5\"\n                                    elif float(pnts[ii]) > 13:   # 2\n                                        pnts[ii] = \"1\"\n                                    elif float(pnts[ii]) > 1:    # 1\n                                        pnts[ii] = \"0.5\"\n                                    else :\n                                        pnts[ii] = \"0\"           # 0\n\n                                if modeBrut == 0:                                 # ecreter 20 colors\n                                    if modeColor == 0:\n                                        if float(pnts[ii]) > ((ecreter + 1) / 2): # ecreter White\n                                            pnts[ii] = str((ecreter + 1) / 2)\n                                    else:\n                                        if float(pnts[ii]) < ((ecreter + 1) / 2): # ecreter Black\n                                            pnts[ii] = str((ecreter + 1) / 2)\n                                else:                                             # ecreter 255 colors\n                                    if modeColor == 0:\n                                        if float(pnts[ii]) > ecreter:             # ecreter White\n                                            pnts[ii] = str(ecreter)\n                                    else:\n                                        if float(pnts[ii]) < ecreter:             # ecreter Black\n                                            pnts[ii] = str(ecreter)\n\n                                if (valueFilter != 0.0) and (modeBrut == 0):\n                                    pnts[ii] = str( float(pnts[ii]) * (valueFilter/10.0))\n\n                                coor_X = (X * etirement_X) + position_X\n                                coor_Y = (Y * etirement_Y) + position_Y\n                                coor_Z = (float(pnts[ii]) * etirement_Z) + position_Z\n\n                                if inversion_X > 0:\n                                    coor_X = (-coor_X)\n                                if inversion_Y > 0:\n                                    coor_Y = (-coor_Y)\n                                if inversion_Z > 0:\n                                    coor_Z = (-coor_Z)\n\n                                if (coor_Z != ecreterFond):                                  # ici pour contour\n                                    try:\n                                        if typeligne == 2:                                   # 2=cloud\n                                            pointsCloud.addPoints([FreeCAD.Vector(coor_X,coor_Y,coor_Z)])\n                                            points += [FreeCAD.Vector(coor_X,coor_Y,coor_Z)] # (pour remplir)\n                                        if avecLigne == 1:                                   # 1=Ligne 0=point 2=cloud\n                                            points += [FreeCAD.Vector(coor_X,coor_Y,coor_Z)]\n                                        elif avecLigne == 0:                                 # 0=point\n                                            if nuance == 1:                                  # 1 = nuance\n                                                a = Draft.makePoint(coor_X,coor_Y,coor_Z)\n                                                FreeCADGui.activeDocument().getObject(a.Label).PointColor = (coor_Z*0.00392157,coor_Z*0.00392157,coor_Z*0.00392157)\n                                            else:\n                                                Draft.makePoint(coor_X,coor_Y,coor_Z)\n\n                                        ################################################################### pour asc\n                                        if fileCoordasc != 0:\n                                            file_asc.write(str(coor_X)+\" \"+str(coor_Y)+\" \"+str(coor_Z)+\"\\n\")\n                                        ################################################################### pour pcd\n                                        if fileCoordpcd != 0:\n                                            pcdColor = 0.0 #(pcdColor_r) + (pcdColor_v*256) + (pcdColor_b*65536) # pour un champ\n                                            file_pcd.write(str(coor_X) + \" \" + str(coor_Y) + \" \" + str(coor_Z) + \" \" + str(pcdColor)+\"\\n\")                    #\n                                        ################################################################### pour pcd\n\n                                    except Exception:\n                                        try:\n                                            file_asc.close()                                           # essais if error detected to write ... or not the file is closed\n                                        except Exception:\n                                            None\n                                        FreeCAD.Console.PrintError(\"Not ActiveDocument detected \"+\"\\n\")# errorDialog(\"Not ActiveDocument detected\")\n                                        break\n\n                                elif (len(points) > 0):\n\n                                    if ((avecLigne == 1) and (len(points) != 0)) or (typeligne == 2):\n                                        ###cree la ligne jusque la base###############################\n                                        if points[0].z != 0.0:\n                                            points.insert(0,points[0])\n                                            points[0].z = 0.0\n                                            pointsCloud.addPoints([points[0]])\n                                        if points[-1].z != 0.0:\n                                            points.append(FreeCAD.Vector(points[-1].x,points[-1].y,points[-1].z))\n                                            points[-1].z = 0.0\n                                            pointsCloud.addPoints([points[-1]])\n                                        ###cree la ligne jusque la base###############################\n\n                                        if (points[0] != points[-1]):\n                                            if (typeligne == 0):                         # 0=makeWire\n                                                Draft.makeWire(points,closed=False,face=False,support=None)\n                                            elif typeligne == 1:\n                                                Draft.makeBSpline(points,closed=False)   # 1=makeBSpline\n\n##                                        if switchLine == 0:                            # ligne du bord gauche droit\n##                                            switchLine = 1                             # ligne du bord gauche droit\n##                                            contourLineG.append(points[0])             # ligne du bord gauche\n##                                            contourLineD.append(points[-1])            # ligne du bord droit\n\n                                    del points[:]\n\n                                ii += 1\n                        try:\n                            if (avecLigne == 1) and (len(points) != 0) and (typeligne != 2):\n\n##                                if switchLine == 0:                                    # ligne du bord gauche droit\n##                                    switchLine = 1                                     # ligne du bord gauche droit\n##                                    contourLineG.append(points[0])                     # ligne du bord gauche\n##                                    contourLineD.append(points[-1])                    # ligne du bord droit\n\n                                if typeligne == 0:                                       # 0=makeWire\n                                    Draft.makeWire(points,closed=False,face=False,support=None)\n                                else:\n                                    Draft.makeBSpline(points,closed=False)               # 1=makeBSpline\n                        except Exception:\n                            FreeCAD.Console.PrintError(\"Not ActiveDocument detected \"+\"\\n\") #errorDialog(\"Not ActiveDocument detected\")\n                            break\n\n                        del points[:]\n\n##                    Draft.makeWire(contourLineG,closed=False,face=False,support=None)  # ligne du bord gauche\n##                    del contourLineG[:]                                                # ligne du bord gauche\n##                    Draft.makeWire(contourLineD,closed=False,face=False,support=None)  # ligne du bord droit\n##                    del contourLineD[:]                                                # ligne du bord droit\n\n                    if typeligne == 2:\n                        Points.show(pointsCloud)\n\n\n#                        #### Create nurbs surface#####################################\n#                        ## ok avec Version: 0.20.2.29177 +426 (Git)\n#                        import ReverseEngineering as Reen\n#                        # create an approximating nurbs surface with smoothing algorithm\n#                        ptss = App.ActiveDocument.Points.Points\n#                        s = Reen.approxSurface(Points=ptss, UDegree=4, VDegree=4, NbUPoles=16, NbVPoles=16, Smooth=True, Weight=0.1, Grad=0.5,Bend=0.2, Iterations=5, Correction=True, PatchFactor=1.2)\n#                        Part.show(s.toShape())\n#                        App.ActiveDocument.recompute()\n#                        # create an approximating nurbs surface with smoothing algorithm\n\n\n#                        #### Create Mesh #############################################\n                        #http://forum.freecadweb.org/viewtopic.php?f=13&t=12796&start=10\n#                        import ReverseEngineering as Reen\n#                        mesh=Reen.triangulate(pointsCloud, 10000, 8.0)\n#                        import Mesh\n#                        Mesh.show(mesh)\n\n                    if fileCoordasc != 0:\n                        file_asc.close()      # pour asc\n\n                    if fileCoordpcd != 0:\n                        file_pcd.close()      # pour pcd\n\n                    if (valueFilter != 0.0):\n#                        global ui            # appel\n                        ff = ui\n                        ff.on_CB_01_Mode_Raw_clicked()\n                        valueFilter = 0\n\n        ##256 couleurs fin#####################################\n        #\n        ###########16 millions couleurs debut###########################\n                elif bits_pixel == 32:  #if couleurs == 0:     # 16 millions couleurs  pour 32 bits mode 1 bit\n \n                    if adresse == 138:                         # mode 2 bits\n                        bytes = (f.read(1))\n \n                    completion = Largeur % 4\n                    ii = 0\n                    ic = 0\n                    r_color = 0.0\n                    v_color = 0.0\n                    b_color = 0.0\n                    pnts = []\n                    points = []\n                    del pnts[:]\n                    del points[:]\n \n                    self.PBA_progressBar.setMaximum(tailleDonnees)\n                    for Y in range(tailleDonnees):\n                        self.PBA_progressBar.setValue(Y)\n\n                        ii = 0\n                        for ic in range(3):\n                            ii += 1\n                            try:\n                                bytes = ord(f.read(1))\n                                pnts.append(str(bytes))\n                            except Exception:\n                                None\n                        f.read(1)\n                        ii += 1\n                        try:\n                            if ((ii % Largeur) == 0) and (completion > 0):\n                                if completion == 3:\n                                    bytes = ord(f.read(1))\n                                    Y += 1\n                                elif completion == 2:\n                                    bytes = ord(f.read(2))\n                                    Y += 2\n                                elif completion == 1:\n                                    bytes = ord(f.read(3))\n                                    Y += 3\n                        except Exception:\n                            None\n \n                    f.close()\n                    ii = 0\n                    self.PBA_progressBar.setMaximum(hauteur)\n\n                    if fileCoordasc != 0:\n                        mypath = OpenName + \".asc\"\n                        file_asc = open(mypath,\"w\")                                      # save coordinates OpenName.asc\n\n                    ####################################################################### pour pcd\n                    # .PCD v.7 - Point Cloud Data file format\n                    # for save PCD format # \n                    if fileCoordpcd != 0:\n                        mypath  = OpenName + \".pcd\"\n                        file_pcd = open(mypath,\"w\") #  save coordinates OpenName.pcd             # pour fichier PCD #http://pointclouds.org/documentation/tutorials/pcd_file_format.php\n                        file_pcd.write(\"# .PCD v0.7 - Point Cloud Data file format\" + \"\\n\")      # .PCD v0.7 - Point Cloud Data file format\n                        file_pcd.write(\"VERSION .7\" + \"\\n\")                                      # VERSION 0.7\n                        file_pcd.write(\"FIELDS x y z rgb\" + \"\\n\")                                # FIELDS x y z rgb\n                        file_pcd.write(\"SIZE 4 4 4 4\"+\"\\n\")                                      # SIZE 4\n                        file_pcd.write(\"TYPE F F F F\"+\"\\n\")                                      # F F F F\n                        file_pcd.write(\"COUNT 1 1 1 1\"+\"\\n\")                                     # COUNT 1 1 1 1\n                        file_pcd.write(\"WIDTH \" + str(Largeur) + \"\\n\")                           # WIDTH 640\n                        file_pcd.write(\"HEIGHT \" + str(hauteur) + \"\\n\")                          # HEIGHT 480\n                        file_pcd.write(\"VIEWPOINT 0 0 0 1 0 0 0\" + \"\\n\")                         # VIEWPOINT 0 0 0 1 0 0 0\n                        file_pcd.write(\"POINTS \" + str( Largeur * hauteur) + \"\\n\")               # POINTS 307200\n                        file_pcd.write(\"DATA ascii\" + \"\\n\")                                      # DATA ascii\n                    ####################################################################### pour pcd\n\n                    for Y in range(hauteur):\n                        self.PBA_progressBar.setValue(Y)\n\n                        for X in range(Largeur):\n\n                            if X > Largeur:\n                                del points[:]\n                            else:\n \n                                coor_X = (X * etirement_X) + position_X\n                                coor_Y = (Y * etirement_Y) + position_Y\n                                coor_Z = (    etirement_Z) + position_Z\n \n                                if inversion_X > 0:\n                                    coor_X = (-coor_X)\n                                if inversion_Y > 0:\n                                    coor_Y = (-coor_Y)\n                                if inversion_Z > 0:\n                                    coor_Z = (-coor_Z)\n                                b_color = float(pnts[ii])*0.00392157        ; pcdColor_b = int(pnts[ii])*65536 # a partir du \";\" encodage pour PCD\n                                ii += 1\n                                v_color = float(pnts[ii])*0.00392157        ; pcdColor_v = int(pnts[ii])*256   # a partir du \";\" encodage pour PCD\n                                ii += 1\n                                r_color = float(pnts[ii])*0.00392157        ; pcdColor_r = int(pnts[ii])       # a partir du \";\" encodage pour PCD\n                                ii += 1\n\n                                try:\n                                    if plan == 0:                                                                               # 0=Photo\n                                        a = Draft.makePoint(coor_X,coor_Y,coor_Z)                                               # ok pour 32 bits mode\n                                        FreeCADGui.activeDocument().getObject(a.Label).PointColor = (r_color,v_color,b_color)\n                                    else:                                                                                       # 1=Plan\n                                        if modeColor == 0:                                                                      # white background\n                                            if (r_color < (ecreter*0.00392157)) and (r_color < (ecreter*0.00392157)) and (r_color < (ecreter*0.00392157)): # ecreter White\n                                                a = Draft.makePoint(coor_X,coor_Y,coor_Z)\n                                                FreeCADGui.activeDocument().getObject(a.Label).PointColor = (r_color,v_color,b_color)\n                                        else:                                                                                   # black background\n                                            if (r_color > (ecreter*0.00392157)) and (r_color > (ecreter*0.00392157)) and (r_color > (ecreter*0.00392157)): # ecreter Black\n                                                a = Draft.makePoint(coor_X,coor_Y,coor_Z)\n                                                FreeCADGui.activeDocument().getObject(a.Label).PointColor = (r_color,v_color,b_color)\n\n                                    ################################################################### pour asc\n                                    if fileCoordasc != 0:\n                                        file_asc.write(str(coor_X)+\" \"+str(coor_Y)+\" \"+str(coor_Z)+\"\\n\")\n                                    ################################################################### pour pcd\n                                    if fileCoordpcd != 0:\n                                        pcdColor = (pcdColor_r) + (pcdColor_v*256) + (pcdColor_b*65536) # pour un champ (pas teste avec FreeCAD)\n                                        file_pcd.write(str(coor_X) + \" \" + str(coor_Y) + \" \" + str(coor_Z) + \" \" + str(pcdColor)+\"\\n\")                    #\n                                    ################################################################### pour pcd\n\n                                except Exception:\n                                    try:\n                                        file_asc.close()\n                                    except Exception:\n                                        None\n                                    FreeCAD.Console.PrintError(\"Not ActiveDocument detected \"+\"\\n\")\n                                    break\n                        del points[:]\n                    if fileCoordasc != 0:\n                        try:\n                            file_asc.close()      # pour asc\n                        except Exception:\n                            None\n\n                    if fileCoordpcd != 0:\n                        try:\n                            file_pcd.close()      # pour pcd\n                        except Exception:\n                            None\n\n        ###########16 millions couleurs fin#####################################\n                else:\n                    FreeCAD.Console.PrintError(\"Bits_pixel \"+str(bits_pixel)+\" unrecognized format\"+\"\\n\")\n\n                FreeCAD.Console.PrintWarning(\"Wait i recompute :\"+\"\\n\")\n                Gui.updateGui()                                        # rafraichi l'ecran\n                App.ActiveDocument.recompute()\n \n                self.PB_01_File_Launch.setStyleSheet(\"QPushButton {background-color: green}\")                 # This function gives a color button\n\n                print(chrono(0))\n\n                Gui.SendMsgToActiveView(\"ViewFit\")\n                FreeCAD.Console.PrintMessage(\"_End Work_____________\"+\"\\n\")\n \n        except Exception:\n            self.PB_01_File_Launch.setStyleSheet(\"QPushButton {background-color: red}\")                       # This function gives a color button\n            FreeCAD.Console.PrintMessage(\"Error in reading the file \"+OpenName+\"\\n\")\n            errorDialog(u\"Error in reading the file \"+OpenName)\n        self.PBA_progressBar.setValue(0)\n\n#read parameter\nFreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"Version\",__version__ + \" (\" + __date__ + \")\")# \npathFile = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/FCTexture\").GetString(\"Path\")\nif pathFile == \"\":\n    pathFile = path\n    #write parameter\n    FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros\" + __title__).SetString(\"Path\",pathFile)\n####\nSingleStepC = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetFloat(\"SingleStep\")\nif SingleStepC == 0:\n    FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetFloat(\"SingleStep\",SingleStep)\nelse:\n    SingleStep = SingleStepC\n##################################################################################################\n\nMainWindow = QMainWindow()\nui = Ui_MainWindow(MainWindow)\nMainWindow.show()\n",
    "url": "https://wiki.freecad.org/Macro_Texture",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/262317bc7d8555885b0e/raw/f18613c8bfd142e644ba79fc8dd34a5f72282f18/Macro%2520FCTexture.FCMacro",
    "wiki": "https://wiki.freecad.org/Macro_Texture",
    "version": "0.15",
    "license": "",
    "date": "2025/01/04",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\FCTexture.png",
    "icon_source": "https://www.freecad.org/wiki/images/9/90/FCTexture.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Place Image",
    "on_wiki": true,
    "on_git": false,
    "desc": "Creates an ImagePlane and aligns it to an existing Draft Rectangle.<br /><br />Macro version: 0.1<br />Last modified: 2023-01-30<br />Author: heda<br /> ",
    "comment": "Aligns ImagePlane to existing draft rectangle",
    "code": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n# ***************************************************************************\n# *   Copyright (c) 2023 heda <heda @ freecad forum>                        *\n# *                                                                         *\n# *   This file is part of the FreeCAD CAx development system.              *\n# *                                                                         *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU Lesser General Public License (LGPL)    *\n# *   as published by the Free Software Foundation; either version 2 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENCE text file.                                 *\n# *                                                                         *\n# *   This program is distributed in the hope that it will be useful,       *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU Library General Public License for more details.                  *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with this program; if not, write to the Free Software   *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\n\n__Name__ = 'Place_Image'\n__Comment__ = 'Aligns ImagePlane to existing draft rectangle'\n__Author__ = 'heda @ fc-forum'\n__Version__ = '0.1'\n__Date__ = '2023-01-30'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = ''\n__Wiki__ = 'https://wiki.freecadweb.org/Macro_Place_Image'\n__Icon__ = ''\n__Help__ = 'Select rectangle, run macro and image is placed.'\n__Status__ = 'Stable'\n__Requires__ = 'tested on FreeCAD v0.20'\n__Communication__ = 'forum'\n__Files__ = ''\n\n\n__doc__ = \"\"\"\nWorks as intended on XY-plane.\nWhen out of XY-plane, not so much.\nFeel free to improve the placement logic.\n\"\"\"\n\n\nfrom pathlib import Path as pyPath\nfrom PySide.QtGui import QMessageBox, QFileDialog\n\nimport Draft\nimport FreeCAD as App\nimport FreeCADGui as Gui\n\ndoc = App.ActiveDocument\nsel = Gui.Selection.getSelection()\nrect = None\n\ndef message(msg):\n    QMessageBox.information(None, __Name__, msg)\n\nif sel:\n    sel, *_ = sel\n    if hasattr(sel, 'Proxy') and isinstance(sel.Proxy, Draft.Rectangle):\n        rect = sel\n    else:\n        message('Sorry, selected object needs to be a draft rectangle.')\nelse:\n    message('No selection, select a draft rectangle.')\n\nif rect:\n    rname = rect.Name\n    picformats = '*.png *.bmp *.jpg *.jpeg'\n    pic, _ = QFileDialog.getOpenFileName(None, 'Select Image',\n                                         '', f'Images ({picformats})')\n    if pic:\n        picname = pyPath(pic).stem.replace(' ', '_')\n        imp = doc.addObject('Image::ImagePlane', picname)\n        imp.ImageFile = pic\n\n        imp.setExpression('XSize', f'{rname}.Length')\n        imp.setExpression('YSize', f'{rname}.Height')\n        imp.setExpression('.Placement.Base.x',\n                          f'{rname}.Placement.Base.x + XSize / 2')\n        imp.setExpression('.Placement.Base.y',\n                          f'{rname}.Placement.Base.y + YSize / 2')\n        imp.setExpression('.Placement.Base.z',\n                          f'{rname}.Placement.Base.z - 0.1 mm')\n        imp.setExpression('.Placement.Rotation.Angle',\n                          f'{rname}.Placement.Rotation.Angle')\n        imp.setExpression('.Placement.Rotation.Axis',\n                          f'{rname}.Placement.Rotation.Axis')\n\n        rect.ViewObject.Visibility = False\n        rect.setExpression('.Label2',  f'<<{picname}>>')\n        doc.recompute()\n        print('placed image successfully')",
    "url": "https://wiki.freecad.org/Macro_Place_Image",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_Place_Image",
    "version": "0.1",
    "license": "",
    "date": "2023-01-30",
    "src_filename": "",
    "filename_from_url": "",
    "author": "heda @ fc-forum",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Points to Splines",
    "on_wiki": true,
    "on_git": false,
    "desc": "Creates splines from Points object sections.<br /><br />Macro version: 0.1<br />Last modified: 2024-10-23<br />Author: heda<br /> ",
    "comment": "Aligns 2 (or more) objects by bounding box..",
    "code": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n# ***************************************************************************\n# *   Copyright (c) 2024 heda <heda @ freecad forum>                        *\n# *                                                                         *\n# *   This file is part of the FreeCAD CAx development system.              *\n# *                                                                         *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU Lesser General Public License (LGPL)    *\n# *   as published by the Free Software Foundation; either version 2 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENCE text file.                                 *\n# *                                                                         *\n# *   This program is distributed in the hope that it will be useful,       *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU Library General Public License for more details.                  *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with this program; if not, write to the Free Software   *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\n\n__Name__ = 'Macro_Points_to_Splines'\n__Comment__ = 'Aligns 2 (or more) objects by bounding box..'\n__Author__ = 'heda @ fc-forum'\n__Version__ = '0.1'\n__Date__ = '2024-10-23'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = ''\n__Wiki__ = 'https://wiki.freecadweb.org/Macro_Points_to_Splines'\n__Icon__ = ''\n__Help__ = 'Select and launch.'\n__Status__ = 'functional'\n__Requires__ = 'tested on FreeCAD v0.21'\n__Communication__ = ''\n__Files__ = ''\n\n__doc__ = \"\"\"\n\npoints obj to draft-spline (or draft-wire)\nbecause a draft-spline is gui-editable allowing\nfor fine-tuning by hand once created\n\nselect a points-object and run the macro\n\nuseful when reverse engineering meshes.\nmake sections from a mesh-obj and\nrun the macro on the resulting points-object.\nsections are assumed to be in the orthogonal system (xyz aligned).\nif not, it will not give usable results (or crash)\n\nthe orientation of the splines are neither checked, nor touched,\ntherefore reversing orientation could be needed\nif it turns out that the generated splines\nhave different orientations.\n\ndefaults:\n- merge close vertices < 0.1% (of total length)\n- decimate 1x (as in no decimation)\n- starting point (of created spline)\n  a) as given after removal of duplicate points\n  b) x/y/z with min/max\n- closed\n- not making a face\n- spline (as opposed to a wire)\n\n\nthe code is by no means written for speed,\nit has an abundance of castings back and forth,\nas well as doing the same calculations multiple times.\nanyone is free to improve as they wish.\n\nif one wants to simplify a spline without distorting it,\ninkscape has tools for that.\njust export the spline as svg,\nopen in inkscape and run simplify (ctrl+L) on the path.\ncan then be reimported to fc as a sanitized path.\n\n\"\"\"\n\nfrom enum import Enum # there is a StrEnum, but not until py 3.11\nfrom collections import deque\n\nimport numpy as np\n\nimport FreeCAD as App\nimport FreeCADGui as Gui\nfrom FreeCAD.Plot import Plot\n\nimport Part\nimport Draft\n\nfrom PySide import QtCore, QtGui, QtWidgets\n\nROUND_TO = 3 # decimals, meaning micro-meter significance\nVector = App.Vector\n\nQtW = QtWidgets\nQt = QtCore.Qt\nQMsgBox = QtW.QMessageBox\nQDlgBtnBox = QtW.QDialogButtonBox\n\ndoc = App.ActiveDocument\n\nclass FCType(Enum):\n    PointsObj = 'Points::Feature'\n\n\nclass Settings:\n    merge_close = 0.1\n    decimate = 1\n    keep_original = True\n    direction = 'y'\n    minmax = 'max'\n    spline = True\n    closed = True\n    make_face = False\n\n\ndef plot_hist(normed, which='?', limit=0.1/100):\n    plt = Plot.plt\n    tpl = 'Wire #{} (open) has {} edges / {} below limit'\n    label = tpl.format(which, len(normed), sum(normed < limit))\n    plt.hist(normed, label=label, alpha=0.5)\n    fig, ax = plt.gcf(), plt.gca()\n    \n    ax.set_xlabel('Normed edge lengths')\n    ax.set_ylabel('Count')\n    ax.legend()\n    fig.tight_layout()\n    ymin, ymax = ax.get_ylim()\n    ax.vlines([limit], ymin, ymax, linestyle='--')\n    plt.get_current_fig_manager().set_window_title('Before merging close points')\n    fig.show()\n\n\ndef points2array(points):\n    return np.array([list(v) for v in points])\n\ndef array2points(array):\n    return [Vector(*p) for p in array]\n\n\ndef remove_duplicates(points):\n    # utilize occt auto-magical removal of duplicate points\n    return [vtx.Point for vtx in Part.makePolygon(points).Vertexes]\n\n\ndef extract_clusters(points):\n    # assumes that sections are clustered in smaller to larger plane pos, and\n    # in order, with start of a cluster at an arbitrary angle in the plane\n    # which they appear to be in the limited testing done\n    # the assumption is fragile, but cpu-cycle friendly\n    d = dict()\n    idx = list()\n    for col in range(3):\n        uq, uqn = np.unique(points[:, col], return_counts=True)\n        idx.append(uqn)\n        d[len(uqn)] = col\n    \n    dmin = min(d)\n    normal = d.get(dmin)\n\n    if dmin == 1:\n        return [points], normal\n\n    else:\n        ij = np.zeros(dmin + 1, dtype=int)\n        ij[1:] = idx[normal]\n        ij = ij.cumsum()\n\n        return [points[i:j, :] for i, j in zip(ij[:-1], ij[1:])], normal\n\n\nclass ndeque(deque):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        \n    def drop_nth(self, n):\n        self.rotate(-n)\n        self.popleft()\n        self.rotate(n)\n        \n    def get_first_three(self):\n        # no native support of slicing deque's\n        return self[0], self[1], self[2]\n\n\ndef merge_close_verts(nbr, points, limit):\n    # limit here is the threshold distance\n    # this is a rather naive algorithm, could be made differently...\n    start_len = len(points)\n    \n    rr = ndeque(points + points[:2] + [False])\n    rotate = True\n    \n    while rotate:\n        rr.rotate(-1)\n        if rr[2] is False:\n            rotate = False\n            continue\n\n        p1, p2, p3 = rr.get_first_three()\n        l12, l23 = (p1-p2).Length, (p2-p3).Length\n        \n        no_touch = l12 > limit and l23 > limit\n        if no_touch:\n            continue\n        \n        remove_center = l12 < limit and l23 < limit\n        if remove_center:\n            rr.drop_nth(1)\n            rr.rotate(1)\n            continue\n\n        move_left = l12 < l23\n        if move_left:\n            new_point = p1 + (p2 - p1)/2\n            rr[0] = new_point\n        else:\n            new_point = p3 + (p2 - p3)/2\n            rr[2] = new_point\n\n        rr.drop_nth(1)\n        rr.rotate(1)\n\n    _ = [rr.popleft() for i in range(3)]\n    msg = 'merging close verts on wire #{} - removed {} points of {}'     \n    print(msg.format(nbr, start_len - len(rr), start_len))\n    \n    return list(rr)\n    \n\ndef remove_smallest_edge(array):\n    def chord_lengths(array):\n        # work with a closed one\n        array = np.vstack((array, array[0]))\n        diff = np.diff(array, axis=0)\n        return np.sqrt( (diff**2).sum(axis=1) )\n        \n    cl = chord_lengths(array)\n    shortest = np.argmin(cl)\n    shortest = -1 if shortest == len(array) else shortest\n    p1, p2, p3 = array[shortest - 1], array[shortest], array[shortest + 1]\n    l12, l23 = p2 - p1, p2 - p3\n    array[shortest - 1] += l12 / 2\n    array[shortest + 1] += l23 / 2\n    mask = list(range(len(array)))\n    _ = mask.pop(shortest)\n    array = array[mask]\n    return array\n\n    \ndef decimation(points, factor):\n    \"\"\"\n    decimate (as in just removing points) is a blunt instrument,\n    can do fairly well though when using splines.\n    best used when there is an abundance of points\n    \"\"\"\n    remainder = len(points) % factor\n    if remainder:\n        array = points2array(points)\n        for i in range(remainder):\n            array = remove_smallest_edge(array)\n        points = array2points(array)\n    \n    return points[::factor]\n    \n\ndef rotate(points, column, fcn):\n    fcn = np.argmin if fcn == 'min' else np.argmax\n    array = points2array(points)\n    idx = fcn(array[:, column])\n    return points[idx:] + points[:idx]\n    \n\ndef normalize_chords(array):\n    # uses an open wire\n    diff = np.diff(array, axis=0)\n    cl = np.sqrt( (diff**2).sum(axis=1) )\n    cls = cl.sum()\n    return cls, cl / cls\n    \n\ndef make_splines(pobj, sts):\n    print('* in making splines')\n    pts = pobj.Points.Points\n    start_pts = len(pts)\n\n    pts = remove_duplicates(pts)\n    msg = 'verts after removing dups: {} of {}'\n    print(msg.format(len(pts), start_pts))\n\n    pts = points2array(pts).round(ROUND_TO)\n    clusters, normal = extract_clusters(pts)\n    ndir = {0:'yz', 1:'xz', 2:'xy'}.get(normal)\n    msg = 'found {} sections in {}-plane'\n    print(msg.format(len(clusters), ndir))\n\n    # make sure clusters are open\n    for i, c in enumerate(clusters):\n        closed = round( (c[0] - c[-1]).sum(), ROUND_TO) == 0\n        if closed:\n            clusters[i] = clusters[i][:-1]\n    \n    ol, nc = zip(*(normalize_chords(c) for c in clusters))\n    \n    limit = sts.merge_close / 100\n\n    # make the plot, makes for some redundant cpu-cycles\n    for i, c in enumerate(nc):\n        plot_hist(c, i, limit)\n\n    clusters = [array2points(c) for c in clusters]\n    \n    if sts.merge_close > 0:\n        cit = tuple(clusters)\n        for i, items in enumerate(zip(cit, ol, nc)):\n            ci, oli, nci = items\n            dirty1 = sum(nci < limit) > 0\n            closed = ci[0] - ci[-1]\n            dirty2 = closed.Length / oli < limit\n            if any((dirty1, dirty2)):\n                clusters[i] = merge_close_verts(i, ci, limit * oli)\n            else:\n                msg = 'Wire #{} has no close vertices to merge with given criterias'\n                print(msg.format(i))\n                \n    \n    if sts.decimate > 1:\n        cit = tuple(clusters)\n        for i, ci in enumerate(cit):\n            clusters[i] = decimation(ci, sts.decimate)\n\n\n    if not sts.keep_original:\n        column = dict(x=0, y=1, z=2).get(sts.direction)\n        cit = tuple(clusters)\n        for i, ci in enumerate(cit):\n            clusters[i] = rotate(ci, column, sts.minmax)\n\n\n    maker = Draft.makeBSpline if sts.spline else Draft.makeWire        \n    w = [maker(c, closed=sts.closed, face=sts.make_face)\n         for c in clusters]\n    doc.recompute()\n\n    \n\ndef infoDialog(msg):\n    icon = QMsgBox.Information\n    d = QMsgBox(icon, 'Points to Splines', msg)\n    d.exec_()\n\n\nclass Dialog(QtW.QDialog):\n\n    def __init__(self, pobj=None, defaults=None):\n        super().__init__()\n        self.setWindowTitle('Points to Splines')\n        self.makeUI(defaults)\n        self.pobj = pobj\n        self.open()\n\n    def makeUI(self, ds):\n        outer = QtW.QVBoxLayout(self)\n\n        dupBox = QtW.QHBoxLayout()\n        tip = ('0.0 % leaves the spline points untouched.\\n'\n               'Percent limit of total cordal length of points\\n'\n               'for which a point is considered duplicate and removed.\\nThe '\n               'neighbouring point is relocated to the midpoint of the two.')\n        dupLabel = QtW.QLabel('Merge Close:')\n        dupLabel.setToolTip(tip)\n        dupBox.addWidget(dupLabel)\n        merge_close = self.merge_close = QtW.QDoubleSpinBox()\n        merge_close.setRange(0, 5)\n        merge_close.setSuffix('%')\n        merge_close.setDecimals(1)\n        merge_close.setSingleStep(0.1)\n        merge_close.setValue(ds.merge_close)\n        merge_close.setToolTip(tip)\n        dupBox.addWidget(merge_close)\n        \n        outer.addLayout(dupBox)\n\n        decBox = QtW.QHBoxLayout()\n        tip = '1x leaves the spline points untouched.'\n        decLabel = QtW.QLabel('Decimate:')\n        decLabel.setToolTip(tip)\n        decBox.addWidget(decLabel)\n        decimate = self.decimate = QtW.QSpinBox()\n        decimate.setRange(1, 10)\n        decimate.setSuffix('x')\n        decimate.setValue(ds.decimate)\n        decimate.setToolTip(tip)\n        decBox.addWidget(decimate)\n        \n        outer.addLayout(decBox)\n        \n        gBox = QtW.QGroupBox('Indicate start point')\n        gvBox = QtW.QVBoxLayout()\n\n        cb = self.cb = QtW.QCheckBox('Use as given')\n        cb.setToolTip('Uncheck to use x/y/z & min/max.')\n        cb.setChecked(ds.keep_original)\n        cb.toggled.connect(self.toggled_keep_original)\n        gvBox.addWidget(cb)\n        \n        xyz = self.xyz = QtW.QButtonGroup()\n        tmpBox = QtW.QHBoxLayout()\n        for s in 'xyz':\n            rb = QtW.QRadioButton(s)\n            rb.setEnabled(not ds.keep_original)\n            xyz.addButton(rb)\n            tmpBox.addWidget(rb)\n        xyz.buttons()[1].setChecked(True)\n        gvBox.addLayout(tmpBox)\n        \n        minmax = self.minmax = QtW.QButtonGroup()\n        tmpBox = QtW.QHBoxLayout()\n        for s in ('min', 'max'):\n            rb = QtW.QRadioButton(s)\n            rb.setEnabled(not ds.keep_original)\n            minmax.addButton(rb)\n            tmpBox.addWidget(rb)\n        rb.setChecked(True)\n        gvBox.addLayout(tmpBox)\n\n        gBox.setLayout(gvBox)\n        outer.addWidget(gBox)\n        \n        hbox = QtW.QHBoxLayout()\n        spline = self.spline = QtW.QCheckBox('Spline')\n        spline.setChecked(ds.spline)\n        hbox.addWidget(spline)\n        closed = self.closed = QtW.QCheckBox('Closed')\n        closed.setChecked(ds.closed)\n        hbox.addWidget(closed)\n        make_face = self.make_face = QtW.QCheckBox('Make Face')\n        make_face.setChecked(ds.make_face)\n        hbox.addWidget(make_face)\n        outer.addLayout(hbox)\n        \n        \n        CancelOk = QDlgBtnBox(QDlgBtnBox.Cancel | QDlgBtnBox.Ok)\n        CancelOk.accepted.connect(self.accept)\n        CancelOk.rejected.connect(self.close)\n        \n        outer.addWidget(CancelOk)\n        self.setLayout(outer)\n\n    def toggled_keep_original(self):\n        enabled = not self.cb.isChecked()\n        _ = [b.setEnabled(enabled) for b in self.xyz.buttons()]\n        _ = [b.setEnabled(enabled) for b in self.minmax.buttons()]\n        \n        \n    def getSettings(self):\n        sts = Settings()\n\n        sts.merge_close = self.merge_close.value()\n        sts.decimate = self.decimate.value()\n        sts.keep_original = self.cb.isChecked()\n        sts.direction = self.xyz.checkedButton().text()\n        sts.minmax = self.minmax.checkedButton().text()\n        sts.spline = self.spline.isChecked()\n        sts.closed = self.closed.isChecked()\n        sts.make_face = self.make_face.isChecked()\n        \n        return sts\n        \n\n    def accept(self):\n        self.close()\n        make_splines(self.pobj, self.getSettings())\n\n        \n\nsel = Gui.Selection.getSelection()\nif len(sel) > 0:\n    # take the first points object\n    for obj in sel:\n        if obj.TypeId == FCType.PointsObj.value:\n            dlg = Dialog(obj, Settings())\n            break\n\nelse:\n    infoDialog('Please select one Points-object\\nand rerun macro.')\n",
    "url": "https://wiki.freecad.org/Macro_Points_to_Splines",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_Points_to_Splines",
    "version": "0.1",
    "license": "",
    "date": "2024-10-23",
    "src_filename": "",
    "filename_from_url": "",
    "author": "heda @ fc-forum",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Polyhedrons",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro creates parametric polyhedrons: tetrahedron, hexahedron, octahedron, dodecahedron, icosahedron, icosahedron_truncated<br />Parameters radius and side can be adjusted.<br /><br />Macro version: 01.02<br />Last modified: 2020-01-10<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/a/a4/Dodecahedron.svg\">ToolBar Icon</a><br />Author: Eddy Verlinden, Genk, Belgium<br /> ",
    "comment": "This macro creates parametric polyhedrons.",
    "code": "# ***************************************************************************\n# *   Copyright (c) 2019  Eddy Verlinden , Genk Belgium   (eddyverl)        *   \n# *                                                                         *\n# *   This file is part of the FreeCAD CAx development system.              *\n# *                                                                         *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU Lesser General Public License (LGPL)    *\n# *   as published by the Free Software Foundation; either version 2 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENCE text file.                                 *\n# *                                                                         *\n# *   FreeCAD is distributed in the hope that it will be useful,            *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU Lesser General Public License for more details.                   *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with FreeCAD; if not, write to the Free Software        *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\n\n\n__Title__   = \"Macro_Polyhedrons\"\n__Author__  = \"Eddy Verlinden\"\n__Version__ = \"01.04\"\n__Date__    = \"2020-02-25\"\n__Comment__ = \"This macro creates parametric polyhedrons.\"\n\n\n# version 1.04 (2020-02-25)\n# correction : value of the side of icosahedron-truncated \n\n# ver 01.03 (2020-01-15) :\n# => added geodesic spheres\n# => some additions to the dialog\n\n# ver 01.02 (2020-01-10) \n#  => first release\n\nimport FreeCAD,FreeCADGui\nimport Part\nimport math\nimport sys, time\nfrom PySide import QtGui, QtCore\nfrom FreeCAD import Base\n\n\ndef horizontal_regular_polygon_vertexes(sidescount,radius,z, startangle = 0):\n    vertexes = []\n    if radius != 0 :\n        for i in range(0,sidescount+1):\n            angle = 2 * math.pi * i / sidescount + math.pi + startangle\n            vertex = (radius * math.cos(angle), radius * math.sin(angle), z)\n            vertexes.append(vertex)\n    else:\n        vertex = (0,0,z)\n        vertexes.append(vertex)\n    return vertexes\n\n       \n# ===========================================================================    \n    \nclass Tetrahedron:\n        # == basics ==\n        #R = z / 4 * sqrt(6)\n        #ro = z / 12 * sqrt(6)    -->   ro = R / 3\n        #z = 4 * R / sqrt(6)\n        #h = z / 3 * sqrt(6) = 4 * R / sqrt(6) /3 * sqrt(6) = 4 * R / 3  = ro + R \n        #radius at level = z / 2 / cos(30) = (4 * R / sqrt(6)) / 2 / sqrt(3) * 2 = 4 * R / (sqrt(6) * sqrt(3))= 4 * R / (3 * sqrt(2)\n        \n    radiusvalue = 0  \n      \n    def __init__(self, obj, radius=5):\n        obj.addProperty(\"App::PropertyLength\",\"Radius\",\"Tetrahedron\",\"Radius of the tetrahedron\").Radius=radius\n        obj.addProperty(\"App::PropertyLength\",\"Side\",\"Tetrahedron\",\"Sidelength of the tetrahedron\")\n        obj.Proxy = self\n\n        \n    def execute (self,obj):\n\n        radius = float(obj.Radius)\n        if (radius != self.radiusvalue):\n            obj.Side = radius * 4 / math.sqrt(6)\n            self.radiusvalue = radius\n        else:\n            self.radiusvalue = float(obj.Side * math.sqrt(6) / 4)\n            obj.Radius = self.radiusvalue\n            radius = self.radiusvalue\n            \n        faces = []        \n        vertexes_bottom = horizontal_regular_polygon_vertexes(3,4*radius/3/math.sqrt(2),- radius / 3)\n        vertexes_top    = horizontal_regular_polygon_vertexes(1,0,radius)\n        \n        for i in range(3):\n            vertexes_side=[vertexes_bottom[i],vertexes_bottom[i+1],vertexes_top[0],vertexes_bottom[i]]\n            polygon_side=Part.makePolygon(vertexes_side)\n            faces.append(Part.Face(polygon_side))\n\n        polygon_bottom=Part.makePolygon(vertexes_bottom)\n        \n        faces.append(Part.Face(polygon_bottom))\n        shell = Part.makeShell(faces)\n        solid = Part.makeSolid(shell)\n        obj.Shape = solid\n        \n\n\n\n# ===========================================================================    \n\nclass Hexahedron: \n \n    radiusvalue = 0  \n    \n    def __init__(self, obj, radius=5):\n        obj.addProperty(\"App::PropertyLength\",\"Radius\",\"Hexahedron\",\"Radius of the hexahedron\").Radius=radius\n        obj.addProperty(\"App::PropertyLength\",\"Side\",\"Hexahedron\",\"Sidelength of the hexahedron\")\n        obj.Proxy = self\n\n    def execute(self, obj):\n            \n        radius = float(obj.Radius) \n        if (radius != self.radiusvalue):\n            side = radius * 2 / math.sqrt(3)\n            obj.Side = side\n            self.radiusvalue = radius\n        else:\n            self.radiusvalue = obj.Side / 2 * math.sqrt(3)\n            obj.Radius = self.radiusvalue\n            radius = self.radiusvalue\n            side = obj.Side       \n             \n        faces = []\n        vertexes_bottom = horizontal_regular_polygon_vertexes(4,math.sqrt(side ** 2 / 2),- side/2, math.pi/4)\n        vertexes_top    = horizontal_regular_polygon_vertexes(4,math.sqrt(side ** 2 / 2), side/2, math.pi/4)\n\n        for i in range(4):\n            vertexes_side=[vertexes_bottom[i],vertexes_bottom[i+1],vertexes_top[i+1],vertexes_top[i],vertexes_bottom[i]]\n            polygon_side=Part.makePolygon(vertexes_side)\n            faces.append(Part.Face(polygon_side))\n\n        polygon_bottom=Part.makePolygon(vertexes_bottom)\n        faces.append(Part.Face(polygon_bottom))\n        \n        polygon_top=Part.makePolygon(vertexes_top)\n        faces.append(Part.Face(polygon_top))\n\n        shell = Part.makeShell(faces)\n        solid = Part.makeSolid(shell)\n        obj.Shape = solid        \n        \n# ===========================================================================    \n\nclass Octahedron: \n    # Z = R * sqrt(2)   \n    radiusvalue = 0  \n    \n    def __init__(self, obj, radius=5):\n        obj.addProperty(\"App::PropertyLength\",\"Radius\",\"Octahedron\",\"Radius of the octahedron\").Radius=radius\n        obj.addProperty(\"App::PropertyLength\",\"Side\",\"Octahedron\",\"Sidelength of the octahedron\")\n        obj.Proxy = self\n  \n    def execute (self,obj):\n\n        radius = float(obj.Radius)\n        if (radius != self.radiusvalue):\n            obj.Side = radius * math.sqrt(2)\n            self.radiusvalue = radius\n        else:\n            self.radiusvalue = float(obj.Side / math.sqrt(2))\n            obj.Radius = self.radiusvalue\n            radius = self.radiusvalue \n\n        faces = []\n        vertexes_middle = horizontal_regular_polygon_vertexes(4,radius,0)\n        vertexes_bottom = horizontal_regular_polygon_vertexes(1,0,-radius)\n        vertexes_top    = horizontal_regular_polygon_vertexes(1,0,radius)\n\n        for i in range(4):\n            vertexes_side=[vertexes_middle[i],vertexes_middle[i+1],vertexes_top[0],vertexes_middle[i]]\n            polygon_side=Part.makePolygon(vertexes_side)\n            faces.append(Part.Face(polygon_side))\n\n        for i in range(4):\n            vertexes_side=[vertexes_middle[i],vertexes_middle[i+1],vertexes_bottom[0],vertexes_middle[i]]\n            polygon_side=Part.makePolygon(vertexes_side)\n            faces.append(Part.Face(polygon_side))\n\n        shell = Part.makeShell(faces)\n        solid = Part.makeSolid(shell)\n        obj.Shape = solid\n\n\n\n# ===========================================================================    \n    \nclass Dodecahedron:\n    \n    radiusvalue = 0  \n   \n    def __init__(self, obj, radius=5):\n        obj.addProperty(\"App::PropertyLength\",\"Radius\",\"Dodecahedron\",\"Radius of the dodecahedron\").Radius=radius\n        obj.addProperty(\"App::PropertyLength\",\"Side\",\"Dodecahedron\",\"Sidelength of the dodecahedron\")\n        obj.Proxy = self\n    \n\n    def execute (self,obj):\n        \n        angleribs = 121.717474411\n        anglefaces = 116.565051177\n\n        radius = float(obj.Radius)\n        if (radius != self.radiusvalue):\n            obj.Side = 4 * radius /  (math.sqrt(3) * ( 1 + math.sqrt(5)))\n            self.radiusvalue = radius\n        else:\n            self.radiusvalue = float(obj.Side * (math.sqrt(3) * ( 1 + math.sqrt(5))) / 4)\n            obj.Radius = self.radiusvalue\n            radius = self.radiusvalue\n            \n        faces = []\n        z = 4 * radius /  (math.sqrt(3) * ( 1 + math.sqrt(5)))\n        r = z/2 * math.sqrt((25 + (11 * math.sqrt(5)))/10)\n        # int sphere r is height / 2\n\n        h2 = z * math.sin(angleribs/180 * math.pi)\n\n        #height of the side-tips\n        radius1 = z / 2 / math.sin(36 * math.pi / 180)\n        h5h = (radius1 + radius1 * math.cos(36 * math.pi / 180))   * math.sin(anglefaces * math.pi / 180) #height of the tops\n\n        radius2 = radius1 - z * math.cos(angleribs * math.pi / 180 )\n\n        r=(h2 + h5h)/2  # XXX to make it fit!\n\n\n\n\n        vertexes_bottom = horizontal_regular_polygon_vertexes(5,radius1,-r)\n        vertexes_low = horizontal_regular_polygon_vertexes(5,radius2, -r + h2)\n        vertexes_high = horizontal_regular_polygon_vertexes(5,radius2, -r + h5h,  math.pi/5)\n        vertexes_top = horizontal_regular_polygon_vertexes(5,radius1, r, math.pi/5)\n\n        polygon_bottom = Part.makePolygon(vertexes_bottom)\n        face_bottom = Part.Face(polygon_bottom)\n        faces.append(face_bottom)\n\n        polygon_top = Part.makePolygon(vertexes_top)\n        face_top = Part.Face(polygon_top)\n        faces.append(face_top)\n\n        for i in range(5):\n            vertexes_side=[vertexes_bottom[i],vertexes_bottom[i+1],vertexes_low[i+1],vertexes_high[i],vertexes_low[i], vertexes_bottom[i] ]\n            polygon_side=Part.makePolygon(vertexes_side)\n            faces.append(Part.Face(polygon_side))\n\n        for i in range(5):\n            #vertexes_side=[vertexes_top[i],vertexes_top[i+1],vertexes_high[i+1],vertexes_high2[i], vertexes_high[i],vertexes_top[i] ]\n            vertexes_side=[vertexes_top[i],vertexes_top[i+1],vertexes_high[i+1],vertexes_low[i+1],vertexes_high[i],vertexes_top[i] ]\n            polygon_side=Part.makePolygon(vertexes_side)\n            faces.append(Part.Face(polygon_side))\n\n        shell = Part.makeShell(faces)\n        solid = Part.makeSolid(shell)\n        obj.Shape = solid\n\n\n# ===========================================================================    \n\nclass Icosahedron:\n    \n    radiusvalue = 0  \n\n    def __init__(self, obj, radius=5):\n        obj.addProperty(\"App::PropertyLength\",\"Radius\",\"Icosahedron\",\"Radius of the icosahedron\").Radius=radius\n        obj.addProperty(\"App::PropertyLength\",\"Side\",\"Icosahedron\",\"Sidelength of the icosahedron\")\n        obj.Proxy = self\n\n\n    def execute (self,obj):\n\n        radius = float(obj.Radius)\n        if (radius != self.radiusvalue):\n            obj.Side = 4*radius / math.sqrt(10 + 2 * math.sqrt(5))\n            self.radiusvalue = radius\n        else:\n            self.radiusvalue = float(obj.Side * math.sqrt(10 + 2 * math.sqrt(5)) / 4)\n            obj.Radius = self.radiusvalue\n            radius = self.radiusvalue\n            \n\n        z = 4*radius / math.sqrt(10 + 2 * math.sqrt(5))\n        anglefaces = 138.189685104\n        r = z/12 * math.sqrt(3) * (3 + math.sqrt(5))\n\n\n        #radius of a pentagon with the same side\n        radius2 = z / math.sin(36 * math.pi/180)/2\n        #height of radius2 in the sphere\n\n        angle = math.acos(radius2/radius)\n        height = radius * math.sin(angle)\n\n        faces = []\n\n        vertex_bottom = (0,0,-radius)\n        vertexes_low = horizontal_regular_polygon_vertexes(5,radius2, -height)\n        vertexes_high = horizontal_regular_polygon_vertexes(5,radius2, height, math.pi/5)\n        vertex_top = (0,0,radius)\n\n\n        for i in range(5):\n            vertexes_side=[vertex_bottom,vertexes_low[i],vertexes_low[i+1], vertex_bottom]\n            polygon_side=Part.makePolygon(vertexes_side)\n            faces.append(Part.Face(polygon_side))\n\n        for i in range(5):\n            vertexes_side=[vertexes_low[i],vertexes_low[i+1],vertexes_high[i],vertexes_low[i] ]\n            polygon_side=Part.makePolygon(vertexes_side)\n            faces.append(Part.Face(polygon_side))\n            vertexes_side=[vertexes_high[i],vertexes_high[i+1],vertexes_low[i+1],vertexes_high[i] ]\n            polygon_side=Part.makePolygon(vertexes_side)\n            faces.append(Part.Face(polygon_side))\n\n        for i in range(5):\n            vertexes_side=[vertex_top,vertexes_high[i],vertexes_high[i+1],vertex_top ]\n            polygon_side=Part.makePolygon(vertexes_side)\n            faces.append(Part.Face(polygon_side))\n\n        shell = Part.makeShell(faces)\n        solid = Part.makeSolid(shell)\n        obj.Shape = solid\n   \n\n\n# ===========================================================================    \n\nclass Icosahedron_truncated:\n    \n    radiusvalue = 0  \n\n    def __init__(self, obj, radius=5):\n        obj.addProperty(\"App::PropertyLength\",\"Radius\",\"Icosahedron_truncated\",\"Radius (of the base-icosahedron)\").Radius=radius\n        obj.addProperty(\"App::PropertyLength\",\"Side\",\"Icosahedron_truncated\",\"Sidelength of the truncated icosahedron\")\n        obj.Proxy = self\n\n    def execute (self,obj):\n\n        radius = float(obj.Radius)\n        if (radius != self.radiusvalue):\n            obj.Side = 4*radius / math.sqrt(10 + 2 * math.sqrt(5)) / 3\n            self.radiusvalue = radius\n        else:\n            self.radiusvalue = float(obj.Side * math.sqrt(10 + 2 * math.sqrt(5)) / 4) * 3\n            obj.Radius = self.radiusvalue\n            radius = self.radiusvalue\n            \n        z = 4*radius / math.sqrt(10 + 2 * math.sqrt(5))\n        anglefaces = 138.189685104\n        r = z/12 * math.sqrt(3) * (3 + math.sqrt(5))\n\n        #radius of a pentagon with the same side\n        radius2 = z / math.sin(36 * math.pi/180)/2\n\n        #height of radius2 in the sphere\n        angle = math.acos(radius2/radius)\n        height = radius * math.sin(angle)\n\n        faces = []\n\n        vertex_bottom = (0,0,-radius)\n        vertexes_low = horizontal_regular_polygon_vertexes(5,radius2, -height)\n        vertexes_high = horizontal_regular_polygon_vertexes(5,radius2, height,  -math.pi/5)\n        vertex_top = (0,0,radius)\n\n        vertexes_bottom = []\n        vertexes_top = []\n\n        for i in range(6):\n            new_vertex = ((vertex_bottom[0]+vertexes_low[i][0])/3 , (vertex_bottom[1]+vertexes_low[i][1])/3 , vertex_bottom[2]-(vertex_bottom[2]-vertexes_low[i][2])/3)\n            vertexes_bottom.append(new_vertex)\n        polygon_side=Part.makePolygon(vertexes_bottom)\n        faces.append(Part.Face(polygon_side))\n\n        for i in range(6):\n            new_vertex = ((vertex_top[0]+vertexes_high[i][0])/3 , (vertex_top[1]+vertexes_high[i][1])/3 , vertex_top[2]-(vertex_top[2]-vertexes_high[i][2])/3)\n            vertexes_top.append(new_vertex)\n        polygon_side=Part.makePolygon(vertexes_top)\n        faces.append(Part.Face(polygon_side))\n\n        pg6_bottom = []\n        for i in range(5):\n            vertex1=vertexes_bottom[i]\n            vertex2=vertexes_bottom[i+1]\n            vertex3=(vertexes_bottom[i+1][0] + (vertexes_low[i+1][0] - vertexes_bottom[i+1][0])/2, vertexes_bottom[i+1][1] + (vertexes_low[i+1][1] - vertexes_bottom[i+1][1])/2, (vertexes_low[i+1][2] + vertexes_bottom[i+1][2])/2)\n            vertex4=((vertexes_low[i+1][0]*2 +vertexes_low[i][0])/3, (vertexes_low[i+1][1]*2 +vertexes_low[i][1])/3, -height)\n            vertex5=((vertexes_low[i+1][0]+vertexes_low[i][0]*2)/3, (vertexes_low[i+1][1] +vertexes_low[i][1]*2)/3, -height)\n            vertex6=(vertexes_bottom[i][0] + (vertexes_low[i][0] - vertexes_bottom[i][0])/2, vertexes_bottom[i][1] + (vertexes_low[i][1] - vertexes_bottom[i][1])/2, (vertexes_low[i][2] + vertexes_bottom[i][2])/2)\n            vertexes = [vertex1,vertex2,vertex3,vertex4,vertex5,vertex6,vertex1]\n            pg6_bottom.append(vertexes)\n            polygon_side=Part.makePolygon(vertexes)\n            faces.append(Part.Face(polygon_side))\n\n        pg6_top = []\n        for i in range(5):\n            vertex1=vertexes_top[i]\n            vertex2=vertexes_top[i+1]\n            vertex3=(vertexes_top[i+1][0] + (vertexes_high[i+1][0] - vertexes_top[i+1][0])/2, vertexes_top[i+1][1] + (vertexes_high[i+1][1] - vertexes_top[i+1][1])/2, (vertexes_high[i+1][2] + vertexes_top[i+1][2])/2)\n            vertex4=((vertexes_high[i+1][0]*2 +vertexes_high[i][0])/3, (vertexes_high[i+1][1]*2 +vertexes_high[i][1])/3, height)\n            vertex5=((vertexes_high[i+1][0]+vertexes_high[i][0]*2)/3, (vertexes_high[i+1][1] +vertexes_high[i][1]*2)/3, height)\n            vertex6=(vertexes_top[i][0] + (vertexes_high[i][0] - vertexes_top[i][0])/2, vertexes_top[i][1] + (vertexes_high[i][1] - vertexes_top[i][1])/2, (vertexes_high[i][2] + vertexes_top[i][2])/2)\n            vertexes = [vertex1,vertex2,vertex3,vertex4, vertex5,vertex6,vertex1]\n            pg6_top.append(vertexes)\n            polygon_side=Part.makePolygon(vertexes)\n            faces.append(Part.Face(polygon_side))\n\n        pg6_low = []\n        for i in range(5):\n            vertex1 = pg6_bottom[i][3]\n            vertex2 = pg6_bottom[i][4]\n            vertex3 = ((vertexes_low[i][0]*2 + vertexes_high[i+1][0])/3,(vertexes_low[i][1]*2 + vertexes_high[i+1][1])/3, (vertexes_low[i][2]*2 + vertexes_high[i+1][2])/3)\n            vertex4 = ((vertexes_low[i][0] + vertexes_high[i+1][0]*2)/3,(vertexes_low[i][1] + vertexes_high[i+1][1]*2)/3, (vertexes_low[i][2] + vertexes_high[i+1][2]*2)/3)\n            vertex5 = ((vertexes_low[i+1][0] + vertexes_high[i+1][0]*2)/3,(vertexes_low[i+1][1] + vertexes_high[i+1][1]*2)/3, (vertexes_low[i+1][2] + vertexes_high[i+1][2]*2)/3)\n            vertex6 = ((vertexes_low[i+1][0]*2 + vertexes_high[i+1][0])/3,(vertexes_low[i+1][1]*2 + vertexes_high[i+1][1])/3, (vertexes_low[i+1][2]*2 + vertexes_high[i+1][2])/3)\n            vertexes = [vertex1,vertex2,vertex3,vertex4, vertex5,vertex6,vertex1]\n            pg6_low.append(vertexes)\n            polygon_side=Part.makePolygon(vertexes)\n            faces.append(Part.Face(polygon_side))\n\n        pg6_high = []\n        for i in range(5):\n            vertex1 = pg6_top[i][3]\n            vertex2 = pg6_top[i][4]\n            vertex3 = pg6_low[i-1][4]\n            vertex4 = pg6_low[i-1][5]\n            vertex5 = pg6_low[i][2]\n            vertex6 = pg6_low[i][3]\n            vertexes = [vertex1,vertex2, vertex3, vertex4,vertex5,vertex6 ,vertex1]\n            pg6_high.append(vertexes)\n            polygon_side=Part.makePolygon(vertexes)\n            faces.append(Part.Face(polygon_side))\n\n        for i in range(5):\n            vertex1 = pg6_top[i][4]\n            vertex2 = pg6_top[i][5]\n            vertex3 = pg6_high[i-1][6]\n            vertex4 = pg6_high[i-1][5]\n            vertex5 = pg6_low[i-1][4]\n            vertexes = [vertex1,vertex2, vertex3,vertex4,vertex5,vertex1]\n            polygon_side=Part.makePolygon(vertexes)\n            faces.append(Part.Face(polygon_side))\n\n        for i in range(5):\n            vertex1 = pg6_bottom[i][4]\n            vertex2 = pg6_bottom[i][5]\n            vertex3 = pg6_low[i-1][6]\n            vertex4 = pg6_low[i-1][5]\n            vertex5 = pg6_high[i][4]\n            vertexes = [vertex1,vertex2, vertex3,vertex4,vertex5, vertex1]\n            polygon_side=Part.makePolygon(vertexes)\n            faces.append(Part.Face(polygon_side))\n\n\n        shell = Part.makeShell(faces)\n        solid = Part.makeSolid(shell)\n        obj.Shape = solid\n\n\n\n# ===========================================================================    \n\ndef geodesic_radius2side(radius, div):\n    # approximative experience values! Not all sides are equal!\n    dictsides = {\"2\":618.034, \"3\":412.41, \"4\":312.87,\"5\":245.09,\"6\":205.91,\"7\":173.53,\"8\":152.96,\"9\":135.96,\"10\":121.55}\n    div = int(round(div))\n    if div < 0:\n        return 0\n    if div == 1:\n        return radius * 4 / math.sqrt(10 + 2 * math.sqrt(5))\n    elif div <= 10:\n        factor = dictsides[str(div)]\n        return radius * factor / 1000\n\ndef geodesic_side2radius(side, div):\n    # approximative experience values!  Not all sides are equal!\n    dictsides = {\"2\":618.034, \"3\":412.41, \"4\":312.87,\"5\":245.09,\"6\":205.91,\"7\":173.53,\"8\":152.96,\"9\":135.96,\"10\":121.55}\n    div = int(round(div))\n    if div < 0:\n        return 0\n    if div == 1:\n        return side / 4 * math.sqrt(10 + 2 * math.sqrt(5))\n    elif div <= 10:\n        factor = dictsides[str(div)]\n        return side * 1000 / factor\n\n\n# =========================================================================== \n\nclass Geodesic_sphere:\n    \n    radiusvalue = 0  \n    divided_by = 2\n\n\n    def __init__(self, obj, radius=5, div=2):\n        obj.addProperty(\"App::PropertyLength\",\"Radius\",\"Geodesic\",\"Radius of the sphere\").Radius=radius\n        obj.addProperty(\"App::PropertyLength\",\"Side\",\"Geodesic\",\"Sidelength of the triangles (approximative!)\")\n        obj.addProperty(\"App::PropertyInteger\",\"DividedBy\",\"Geodesic\",\"The sides of the icosahedron are divided in x\").DividedBy = div\n\n        obj.Proxy = self\n\n    \n    def geodesic_divide_triangles(self,vertex1, vertex2, vertex3, faces):\n        \n        vector1 = (Base.Vector(vertex2) - Base.Vector(vertex1)) / self.divided_by\n        vector2 = (Base.Vector(vertex3) - Base.Vector(vertex2)) / self.divided_by\n\n        icosaPt={}\n        \n        icosaPt[str(1)] = Base.Vector(vertex1) \n          \n        for level in range(self.divided_by):\n            l1 = level + 1\n            icosaPt[str(l1*10+1)] = icosaPt[str(1)]+ vector1 * (l1)\n\n            for pt in range(level+1):\n                icosaPt[str(l1*10+2+pt)] = icosaPt[str(l1*10+1)] + vector2 *(pt+1)\n                    \n        \n        for level in range(self.divided_by):\n\n            for point in range(level+1):\n                vertex1x = icosaPt[str(level*10+1+point)].normalize().multiply(self.radiusvalue)\n                vertex2x = icosaPt[str(level*10+11+point)].normalize().multiply(self.radiusvalue)\n                vertex3x = icosaPt[str(level*10+12+point)].normalize().multiply(self.radiusvalue)\n                polygon = Part.makePolygon([vertex1x,vertex2x,vertex3x, vertex1x])\n                faces.append(Part.Face(polygon))\n\n            for point in range(level):\n                vertex1x = icosaPt[str(level*10+1+point)].normalize().multiply(self.radiusvalue)\n                vertex2x = icosaPt[str(level*10+2+point)].normalize().multiply(self.radiusvalue)\n                vertex3x = icosaPt[str(level*10+12+point)].normalize().multiply(self.radiusvalue)\n                polygon = Part.makePolygon([vertex1x,vertex2x,vertex3x, vertex1x])\n                faces.append(Part.Face(polygon))\n      \n        return faces\n\n         \n\n    def execute (self,obj):\n\n        obj.DividedBy = int(round(obj.DividedBy))\n        if obj.DividedBy <= 0:\n            obj.DividedBy = 1\n                    \n            \n        radius = float(obj.Radius)\n        if radius != self.radiusvalue or obj.DividedBy != self.divided_by:\n            self.divided_by = obj.DividedBy\n            obj.Side = geodesic_radius2side(radius, self.divided_by)\n            self.radiusvalue = radius\n        else:\n            self.radiusvalue = geodesic_side2radius(obj.Side,self.divided_by)\n            obj.Radius = self.radiusvalue\n            radius = self.radiusvalue\n            \n        self.divided_by = obj.DividedBy   \n\n        z = 4*radius / math.sqrt(10 + 2 * math.sqrt(5))\n        anglefaces = 138.189685104\n        r = z/12 * math.sqrt(3) * (3 + math.sqrt(5))\n\n\n        #radius of a pentagram with the same side\n        radius2 = z / math.sin(36 * math.pi/180)/2\n        \n        #height of radius2 in the sphere\n        angle = math.acos(radius2/radius)\n        height = radius * math.sin(angle)\n\n        faces = []\n\n        vertex_bottom = (0,0,-radius)\n        vertexes_low = horizontal_regular_polygon_vertexes(5,radius2, -height)\n        vertexes_high = horizontal_regular_polygon_vertexes(5,radius2, height, math.pi/5)\n        vertex_top = (0,0,radius)\n        \n        for i in range(5):\n            faces = self.geodesic_divide_triangles(vertex_bottom,vertexes_low[i+1],vertexes_low[i],faces)\n\n        \n        for i in range(5):\n            faces = self.geodesic_divide_triangles(vertexes_high[i],vertexes_low[i+1],vertexes_low[i],faces)\n            faces = self.geodesic_divide_triangles(vertexes_low[i+1],vertexes_high[i+1],vertexes_high[i],faces)\n\n        for i in range(5):\n            faces = self.geodesic_divide_triangles(vertex_top,vertexes_high[i],vertexes_high[i+1],faces)\n\n        \n        shell = Part.makeShell(faces)\n        solid = Part.makeSolid(shell)\n        obj.Shape = solid        \n \n\n# =========================================================================== \n\nclass ViewProviderBox:\n    \n    obj_name = \"polyhedron\"\n    \n    def __init__(self, obj, obj_name):\n        self.obj_name = obj_name\n        obj.Proxy = self\n\n    def attach(self, obj):\n        return\n\n    def updateData(self, fp, prop):\n        return\n\n    def getDisplayModes(self,obj):\n        return \"As Is\"\n        \n    def getDefaultDisplayMode(self):\n        return \"As Is\"\n\n    def setDisplayMode(self,mode):\n        return \"As Is\"\n\n    def onChanged(self, vobj, prop):\n        pass\n        \n    def getIcon(self):\n        return \"\"\"\n        /* XPM */\n        static char * xpm[] = {\n\"32 32 9 1\",\n\"   c None\",\n\".  c #010050\",\n\"+  c #000641\",\n\"@  c #04036A\",\n\"#  c #00019A\",\n\"$  c #272687\",\n\"%  c #3E3EA2\",\n\"&  c #4C4BBF\",\n\"*  c #6466FC\",\n\"                                \",\n\"                                \",\n\"                                \",\n\"              @###@$%           \",\n\"           @#####@&**&          \",\n\"         @#####@&******%        \",\n\"       @#####@%*********%       \",\n\"      @###@@$%***********&      \",\n\"     +@@$****%*************     \",\n\"     &********&************&    \",\n\"     *********%************$+   \",\n\"     *********&************+.   \",\n\"    %**********%***********+.+  \",\n\"    &**********%**********%..+  \",\n\"    &***********&*********+..   \",\n\"    &***********%&********+..   \",\n\"    ***********&@#@@$$%&&*+..   \",\n\"    ***********@#########+..+   \",\n\"    **********$##########...+   \",\n\"    +********%###########...+   \",\n\"    ++$*****&############...+   \",\n\"    +..+&***@############...    \",\n\"     +..++*$#############..+    \",\n\"      +...+@#############..     \",\n\"       +...+@############.+     \",\n\"         ...+@##########@       \",\n\"          +..+@#######@         \",\n\"           +..+@####@           \",\n\"            ++++.@.             \",\n\"                                \",\n\"                                \",\n\"                                \"};\n        \"\"\"\n        \n    def __getstate__(self):\n        return None\n\n    def __setstate__(self,state):\n        return None\n        \n        \n# ===========================================================================  \n\ndef msgbox(s):\n    msg = QtGui.QMessageBox()\n    msg.setIcon(QtGui.QMessageBox.Information)\n    msg.setText(s)\n    msg.setWindowTitle(\"Message\")\n    msg.setStandardButtons(QtGui.QMessageBox.Ok )\n    retval = msg.exec_()\n\n\n# =========================================================================== \n\n\n\nclass polyhedron_dialog(QtGui.QWidget):\n    \n    polyhedronname = \"\"\n\n    def __init__(self):\n        super(polyhedron_dialog, self).__init__()\n\n        self.initUI()\n\n    def initUI(self):\n        grid = QtGui.QGridLayout()\n\n        button = QtGui.QPushButton('Cancel')\n        button.setStyleSheet(\"color:blue\")\n        grid.addWidget(button, 10, 3)\n        button.clicked.connect(self.cancel_method)\n        button2 = QtGui.QPushButton('OK')\n        button2.setStyleSheet(\"color:blue\")\n        grid.addWidget(button2, 10, 5)\n        button2.clicked.connect(self.slot_method)\n\n        self.listBox = QtGui.QListWidget(self)\n        grid.addWidget(self.listBox, 0, 3)\n        self.listBox.addItem(\"tetrahedron\")\n        self.listBox.addItem(\"hexahedron\")\n        self.listBox.addItem(\"octahedron\")\n        self.listBox.addItem(\"dodecahedron\")\n        self.listBox.addItem(\"icosahedron\")\n        self.listBox.addItem(\"icosahedron-truncated\")\n        self.listBox.addItem(\"geodesic-sphere\")\n        self.listBox.itemClicked.connect(self.listwidgetclicked)\n\n        grid.addWidget(QtGui.QLabel('radius :'), 3, 2)\n        self.radius = QtGui.QLineEdit(\"5\")\n        self.radius.setStyleSheet(\"background : white; font-weight:bold; padding-left:10px\")\n        grid.addWidget(self.radius,3,3)\n\n        grid.addWidget(QtGui.QLabel('or sidelength:'), 3, 4)\n        self.side = QtGui.QLineEdit()\n        self.side.setStyleSheet(\"background : white; font-weight:bold; padding-left:10px\")\n        grid.addWidget(self.side, 3,5)\n\n        self.warning = QtGui.QLineEdit()\n        self.warning.setStyleSheet(\"color : red\")\n        grid.addWidget(self.warning, 5,3)\n\n\n        self.setLayout(grid)\n        self.move(500, 350)\n        self.setWindowTitle('Polyhedrons as FreeCad-Part')\n        self.show()\n    \n    def listwidgetclicked(self, item):\n        self.polyhedronname = format(item.text())\n        self.warning.clear()\n\n\n    def slot_method(self):\n        if self.listBox.selectedItems() == []:\n            self.warning.setText(\"Select a type!\")\n            return\n\n\n        if (str(self.radius.text()))== \"\":\n            radius = 0\n        else:\n            radius = float(str(self.radius.text()))\n\n        if (str(self.side.text()))== \"\":\n            side = 0\n        else:\n            side = float(str(self.side.text()))\n\n        if radius == 0 and side == 0 :\n            self.warning.setText(\"INPUT ERROR! No radius nor side!\")\n            return    \n            \n        if radius != 0 and side != 0 :\n            self.warning.setText(\"INPUT ERROR! Only One value allowed!\")\n            return\n        else :   \n            if FreeCAD.ActiveDocument == None:\n                FreeCAD.newDocument() \n                      \n            obj=FreeCAD.ActiveDocument.addObject(\"Part::FeaturePython\",self.listBox.currentItem().text())\n\n            if self.listBox.currentItem().text() == \"tetrahedron\":\n                if radius==0:\n                    radius = side / 4 * math.sqrt(6)\n                Tetrahedron(obj, radius)\n            elif self.listBox.currentItem().text() == \"hexahedron\":\n                if radius == 0:\n                    radius = side * 2 / math.sqrt(3)\n                Hexahedron(obj, radius)\n            elif self.listBox.currentItem().text() == \"octahedron\":\n                if radius == 0:\n                    radius = side / math.sqrt(2)\n                Octahedron(obj, radius)\n            elif self.listBox.currentItem().text() == \"dodecahedron\":\n                if radius == 0:\n                    radius = side / 4 *  math.sqrt(3) * (1 + math.sqrt(5))\n                Dodecahedron(obj, radius)\n            elif self.listBox.currentItem().text() == \"icosahedron\":\n                if radius == 0:\n                    radius = side / 4 * math.sqrt(10 + 2 * math.sqrt(5))\n                Icosahedron(obj, radius)\n            elif self.listBox.currentItem().text() == \"icosahedron-truncated\":\n                if radius == 0:\n                    radius = side / 4 * math.sqrt(10 + 2 * math.sqrt(5)) * 3\n                Icosahedron_truncated(obj,radius)\n            elif self.listBox.currentItem().text() == \"geodesic-sphere\":\n                if radius == 0:\n                    radius = side / 2 * math.sqrt(10 + 2 * math.sqrt(5))\n                Geodesic_sphere(obj,radius)  \n                                  \n            obj.ViewObject.Proxy=0\n            ViewProviderBox(obj.ViewObject, self.listBox.item)\n            FreeCAD.ActiveDocument.recompute()\n            FreeCADGui.SendMsgToActiveView(\"ViewFit\")                \n\n        self.close()\n\n    def cancel_method(self):\n        self.close()\n\n\nmainaction = polyhedron_dialog()",
    "url": "https://wiki.freecad.org/Macro_Polyhedrons",
    "raw_code_url": "",
    "wiki": "",
    "version": "01.04",
    "license": "",
    "date": "2020-02-25",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Eddy Verlinden",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Dodecahedron.svg",
    "icon_source": "https://wiki.freecad.org/images/a/a4/Dodecahedron.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Pyramid",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro creates a parametric pyramid. The radiuses and the height will be set at creation time similar to Part Cone. All parameters can be adjusted. It is possible to create pyramids with a perfect tip.<br /><br />Macro version: 01.01<br />Last modified: 2019-11-10<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/4/46/Pyramidicon.svg\">ToolBar Icon</a><br />Author: Eddy Verlinden, Genk, Belgium<br /> ",
    "comment": "This macro creates a parametric pyramid.",
    "code": "# ***************************************************************************\n# *   Copyright (c) 2019  Eddy Verlinden                                    *   \n# *                                                                         *\n# *   This file is part of the FreeCAD CAx development system.              *\n# *                                                                         *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU Lesser General Public License (LGPL)    *\n# *   as published by the Free Software Foundation; either version 2 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENCE text file.                                 *\n# *                                                                         *\n# *   FreeCAD is distributed in the hope that it will be useful,            *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU Lesser General Public License for more details.                   *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with FreeCAD; if not, write to the Free Software        *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\n\n__Title__   = \"Macro_Pyramid\"\n__Author__  = \"Eddy Verlinden\"\n__Version__ = \"01.02\"\n__Date__    = \"2021-01-09\"\n__Comment__ = \"This macro creates a parametric pyramid.\"\n\nimport sys\nimport FreeCAD,FreeCADGui\nimport Part\nimport math\n\n\n\ndef create(obj_name):\n    obj=FreeCAD.ActiveDocument.addObject(\"Part::FeaturePython\",obj_name) \n    fpo = Pyramid(obj)\n    ViewProviderBox(obj.ViewObject)  \n    FreeCAD.ActiveDocument.recompute()\n    return fpo\n\n\ndef horizontal_regular_polygon_vertexes(sidescount,radius,z, startangle = 0):\n    vertexes = []\n    if radius != 0 :\n        for i in range(0,sidescount+1):\n            angle = 2 * math.pi * i / sidescount + math.pi + startangle\n            vertex = (radius * math.cos(angle), radius * math.sin(angle), z)\n            vertexes.append(vertex)\n    else:\n        vertex = (0,0,z)\n        vertexes.append(vertex)\n    return vertexes\n\n\ndef horizontal_regular_pyramid_vertexes(sidescount,radius,z, startangle = 0):\n    vertexes = []\n    odd = 0\n    if (sidescount % 2) == 0:\n        odd = 1\n    if radius != 0 :\n        for i in range(0,sidescount+1):\n            angle = 2 * math.pi * i / sidescount + (math.pi * (odd/sidescount + 1/2)) + startangle * math.pi / 180\n            vertex = (radius * math.cos(angle), radius * math.sin(angle), z)\n            vertexes.append(vertex)\n    else:\n        vertex = (0,0,z)\n        vertexes.append(vertex)\n    return vertexes\n\n# =========================================================================== \n\nclass Pyramid:\n \n    radius1value = 0\n    radius2value = 0\n    sidescountvalue = 0\n    side1value = 0\n    side2value = 0\n    anglez = 0\n\n    def __init__(self, obj, sidescount = 5,radius_bottom = 2 , radius_top = 4, height = 10, angz = 0):\n        obj.addProperty(\"App::PropertyLength\",\"Radius1\",\"Pyramid\",\"Radius of the pyramid\").Radius1=radius_bottom\n        obj.addProperty(\"App::PropertyLength\",\"Radius2\",\"Pyramid\",\"Radius of the pyramid\").Radius2=radius_top\n        obj.addProperty(\"App::PropertyLength\",\"Height\",\"Pyramid\",\"Height of the pyramid\").Height = height\n        obj.addProperty(\"App::PropertyInteger\",\"Sidescount\",\"Pyramid\",\"Sidescount of the pyramid\").Sidescount = sidescount\n        obj.addProperty(\"App::PropertyLength\",\"Sidelength1\",\"Pyramid\",\"Sidelength1 of the pyramid\")\n        obj.addProperty(\"App::PropertyLength\",\"Sidelength2\",\"Pyramid\",\"Sidelength2 of the pyramid\")\n        obj.addProperty(\"App::PropertyAngle\",\"Z_rotation\",\"Pyramid\",\"alfa angle around Z\").Z_rotation = angz\n\n        obj.Proxy = self\n\n        \n    def execute (self,obj):\n              \n        sidescount = int(obj.Sidescount)\n        angle = 2 * math.pi / sidescount\n        radius_bottom = float(obj.Radius1)\n        radius_top = float(obj.Radius2)\n        sidelength_top = float(obj.Sidelength2)\n        sidelength_bottom = float(obj.Sidelength1)\n        height = float(obj.Height)\n        anglez = float(obj.Z_rotation)\n\n        if radius_bottom != self.radius1value or sidescount != self.sidescountvalue:\n            obj.Sidelength1 = radius_bottom * math.sin(angle/2) * 2\n            self.radius1value = radius_bottom\n            self.side1value = float(obj.Sidelength1)\n        elif sidelength_bottom != self.side1value:\n            self.radius1value = float(obj.Sidelength1 / 2) / math.sin(angle/2) \n            obj.Radius1 = self.radius1value\n            radius_bottom = self.radius1value\n            self.side1value = float(obj.Sidelength1)\n\n        if radius_top != self.radius2value or sidescount != self.sidescountvalue: \n            obj.Sidelength2 = radius_top * math.sin(angle/2) * 2\n            self.radius2value = float(radius_top)\n            self.side2value = float(obj.Sidelength2)\n        elif sidelength_top != self.side2value:\n            self.radius2value = float(obj.Sidelength2 / 2) / math.sin(angle/2) \n            obj.Radius2 = self.radius2value\n            radius_top = self.radius2value\n            self.side2value = float(obj.Sidelength2)\n            \n        self.sidescountvalue = sidescount\n        faces = []\n        if radius_bottom == 0 and radius_top == 0:\n            FreeCAD.Console.PrintMessage(\"Both radiuses are zero\" + \"\\n\")\n        else:\n            vertexes_bottom = horizontal_regular_pyramid_vertexes(sidescount,radius_bottom,0     ,anglez)\n            vertexes_top    = horizontal_regular_pyramid_vertexes(sidescount,radius_top   ,height,anglez)\n\n            if radius_bottom != 0:\n                polygon_bottom = Part.makePolygon(vertexes_bottom)\n                face_bottom = Part.Face(polygon_bottom)\n                faces.append(face_bottom)\n            if radius_top != 0:    \n                polygon_top = Part.makePolygon(vertexes_top)\n                face_top = Part.Face(polygon_top)\n                faces.append(face_top)\n\n            for i in range(sidescount):            \n                if radius_top == 0:\n                    vertexes_side=[vertexes_bottom[i],vertexes_bottom[i+1],vertexes_top[0],vertexes_bottom[i]]\n                elif radius_bottom == 0:\n                    vertexes_side=[vertexes_bottom[0],vertexes_top[i+1],vertexes_top[i],vertexes_bottom[0]]\n                else:\n                    vertexes_side=[vertexes_bottom[i],vertexes_bottom[i+1],vertexes_top[i+1],vertexes_top[i],vertexes_bottom[i]]\n                polygon_side=Part.makePolygon(vertexes_side)\n                faces.append(Part.Face(polygon_side))\n\n            shell = Part.makeShell(faces)   \n            solid = Part.makeSolid(shell)\n            obj.Shape = solid        \n            \n\n# ===========================================================================    \n\nclass ViewProviderBox:\n    def __init__(self, obj):\n        obj.Proxy = self\n\n    def attach(self, obj):\n        return\n\n    def updateData(self, fp, prop):\n        return\n\n    def getDisplayModes(self,obj):\n        return \"As Is\"\n        \n    def getDefaultDisplayMode(self):\n        return \"As Is\"\n\n    def setDisplayMode(self,mode):\n        return \"As Is\"\n\n    def onChanged(self, vobj, prop):\n        pass\n        \n    def getIcon(self):\n        return \"\"\"\n        /* XPM */\n        static char * xpm[] = {\n        \"32 32 9 1\",\n        \" \tc None\",\n        \".\tc #01035E\",\n        \"+\tc #0F0C1D\",\n        \"@\tc #4849B7\",\n        \"#\tc #5F5E61\",\n        \"$\tc #6567FE\",\n        \"%\tc #8E9192\",\n        \"&\tc #A5A6A4\",\n        \"*\tc #FBFEFA\",\n        \"                                \",\n        \"                                \",\n        \"                        #       \",\n        \"                       +#       \",\n        \"                     &++#       \",\n        \"                    #+++%       \",\n        \"                   ++.@+&       \",\n        \"                 &++.$++&       \",\n        \"                %++@$$++&       \",\n        \"               #++@$$@++&       \",\n        \"             &+++@$$$@++&       \",\n        \"            %+.+@$$$$+.+&       \",\n        \"           #+.+@$$$$$+.+&       \",\n        \"         &+..+@$$$$$@+.+&       \",\n        \"        &+..+@$$$$$$@+.+&       \",\n        \"       #+..+@$$$$$$$+..+&       \",\n        \"      +..++@$$$$$$$$+..+&       \",\n        \"    %+++++++@$$$$$$@+..+&       \",\n        \"   #++++...+++@$$$$.+..+&       \",\n        \"    +........+++@$$+...+&       \",\n        \"    &+.........+++.+...+        \",\n        \"     #+...........++...+        \",\n        \"      #+...........++..+        \",\n        \"       +............+..+        \",\n        \"       &++...........+.+        \",\n        \"         %+++........+++        \",\n        \"           &#++.......++        \",\n        \"              #++..+++++&       \",\n        \"                %++#%           \",\n        \"                                \",\n        \"                                \",\n        \"                                \"};\n        \"\"\"\n    def __getstate__(self):\n        return None\n\n    def __setstate__(self,state):\n        return None\n       \n# ===========================================================================    \n\nif FreeCAD.ActiveDocument == None:\n    FreeCAD.newDocument()\n\ncreate (\"Pyramid\")\nFreeCADGui.SendMsgToActiveView(\"ViewFit\")",
    "url": "https://wiki.freecad.org/Macro_Pyramid",
    "raw_code_url": "",
    "wiki": "",
    "version": "01.02",
    "license": "",
    "date": "2021-01-09",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Eddy Verlinden",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Pyramidicon.svg",
    "icon_source": "https://wiki.freecad.org/images/4/46/Pyramidicon.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Repro Wire",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro create on duplicate to wire subObject ... selected. (Compatible with Body)<br />(include in FreeCAD since 0.19 version&#160;: Menu \u2192 Part \u2192 Create a copy)<br /><br />Macro version: 00.04<br />Last modified: 2020-03-14<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/a/a3/Macro_ReproWire.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Compatible with FreeCAD 0.17 0.18 and more",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\nimport codecs   #https://docs.python.org/2/howto/unicode.html\nimport Part,Draft\n\n#24/10/2015, 22/09/2018, 03/07/2019, 14/03/2020\n\n__title__   = \"Macro_ReproWire\"\n__author__  = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__Wiki__    = \"https://www.freecadweb.org/wiki/Macro_Repro_Wire\"\n__version__ = \"00.04\"\n__date__    = \"2020/03/14\"    #YYYY/MM/DD\n__Comment__ = \"Compatible with FreeCAD 0.17 0.18 and more\"\n\nglobal objectPlacementAngle ; objectPlacementAngle = \"\"\ndef objectRealPlacement3D(obj):\n    global objectPlacementAngle\n    try:\n        objectPlacement      = obj.Shape.Placement\n        #### \n        objectPlacementBase  = FreeCAD.Vector(objectPlacement.Base)\n        ####\n        objectWorkCenter     = objectPlacementBase\n        ####\n        objectPlacementAngle = objectPlacement.Rotation.toEuler()\n\n        if hasattr(obj, \"getGlobalPlacement\"):\n            globalPlacement       = obj.getGlobalPlacement()\n            globalPlacementBase   = FreeCAD.Vector(globalPlacement.Base)\n            objectRealPlacement3D = globalPlacementBase.add(objectWorkCenter).sub(objectPlacementBase)\n            objectPlacementAngle  = globalPlacement.Rotation.toEuler()\n        else:\n            objectRealPlacement3D = objectWorkCenter\n\n        return objectRealPlacement3D\n    except Exception:\n        return FreeCAD.Vector(0.0, 0.0, 0.0)\n\nsel = Gui.Selection.getSelection()\ns   = Gui.Selection.getSelectionEx()\n\ntry:\n    if len(sel) != 0:\n            print( \"Object(s) : \", len(sel), \" , SubObject(s) : \", len(s))\n            i2 = ii2 = -1 \n            for i in s:\n                i2 += 1\n                ii2 = -1\n                try:\n                    FreeCADGui.Selection.getSelectionEx()[i2].SubObjects[ii2]\n                    for ii in i.SubElementNames:\n                        placementOrigine = objectRealPlacement3D(FreeCAD.ActiveDocument.getObject(i.ObjectName))# search the original Placement\n                        ii2 += 1\n                        Part.show(FreeCADGui.Selection.getSelectionEx()[i2].SubObjects[ii2].copy())   # create repro shape subObject\n                        print( i2+1 ,\"/\", ii2+1 ,\"/\", len(s) ,\" \", i.ObjectName ,\" \", ii)             # display the info SubObject\n                        a = App.ActiveDocument.ActiveObject\n                        a.Placement.Base = placementOrigine\n                        a.Placement.Rotation = App.Rotation(objectPlacementAngle[0], objectPlacementAngle[1], objectPlacementAngle[2])\n                        #    object Name  / original object Name / SubObject Name\n                        a.Label = a.Name + \" \" + i.ObjectName + \" \" + ii                              # Label for the repro shape\n                        try:\n                            FreeCADGui.activeDocument().activeObject().LineColor  = (1.0,0.0,0.0)     # give LineColor\n                            FreeCADGui.activeDocument().activeObject().PointColor = (1.0,0.0,0.0)     # give PointColor\n                            FreeCADGui.activeDocument().activeObject().ShapeColor = (1.0,0.0,0.0)     # give ShapeColor\n                        except Exception:\n                            None\n                except Exception:\n#                    print( \"Not SubObject\")\n                    placementOrigine = objectRealPlacement3D(FreeCAD.ActiveDocument.getObject(sel[i2].Name))# search the original Placement\n                    Part.show(sel[i2].Shape)                                                          # create repro shape object\n                    print( i2+1 ,\"/\", ii2+1 ,\"/\", len(s) ,\" \", sel[i2].Name)                          # display the info SubObject\n                    a = App.ActiveDocument.ActiveObject\n                    a.Placement.Base = placementOrigine\n                    a.Placement.Rotation = App.Rotation(objectPlacementAngle[0], objectPlacementAngle[1], objectPlacementAngle[2])\n                    #        object Name  /  original object Name\n                    a.Label =a.Name + \" \" +  sel[i2].Name                                             # Label for the repro shape\n                    try:\n                        FreeCADGui.activeDocument().activeObject().LineColor  = (1.0,0.0,0.0)         # give LineColor\n                        FreeCADGui.activeDocument().activeObject().PointColor = (1.0,0.0,0.0)         # give PointColor\n                        FreeCADGui.activeDocument().activeObject().ShapeColor = (1.0,0.0,0.0)         # give ShapeColor\n                    except Exception:\n                        None\n                try:\n                    SubElement = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0]\n                    print( FreeCADGui.Selection.getSelectionEx()[0].SubElementNames[0], \" : \", SubElement.normalAt(0,0)) # ok Vector pour face\n                except Exception:\n                    None\n                    \n            FreeCAD.ActiveDocument.recompute()\n    else :\n        FreeCAD.Console.PrintError(\"Select one object\" + \"\\n\")\nexcept Exception:\n    FreeCAD.Console.PrintError(\"Unexpected error\" + \"\\n\")",
    "url": "https://wiki.freecad.org/Macro_Repro_Wire",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_Repro_Wire",
    "version": "00.04",
    "license": "",
    "date": "2020/03/14",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_ReproWire.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/a/a3/Macro_ReproWire.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Site From Contours",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro allows you to select a series of objects containing level contours and create an Arch Site from them. The contours can be grouped in any number of objects, and don't need to form closed wires. All this will be taken care of by the macro. Internally, one bspline will be created from each contour, then ruled surfaces will be created between the contours, then these ruled surfaces will be united in a shell object, and finally an Arch Site will be created using this shell as its Terrain.<br /><br />Macro version: 1.0<br />Last modified: 2018-08-30<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/File:Macro_Site_From_Contours.png\">ToolBar Icon</a><br />Author: yorik<br /> ",
    "comment": "This macro allows you to select a series of objects containing level contours and create an Arch Site from them. The contours can be grouped in any number of objects, and don't need to form closed wires. All this will be taken care of by the macro. Internally, one bspline will be created from each contour, then ruled surfaces will be created between the contours, then these ruled surfaces will be united in a shell object, and finally an Arch Site will be created using this shell as its Terrain.",
    "code": "# This macro builds an Arch Site object out of different level curves.\n# It doesn't matter how many object contain the curves or if they\n# are connected into wires or not.\n\nimport FreeCAD,FreeCADGui,Part,Draft,DraftGeomUtils,Arch\n\n# first build a list of edges from selected objects\n\nedges = []\nfor obj in FreeCADGui.Selection.getSelection():\n    edges.extend(obj.Shape.Edges)\n\n# sort our edges into connected wires\n\nwires = DraftGeomUtils.findWires(edges)\n\n# build a bspline for each wire\n\nbsplines = []\nfor wire in wires:\n    points = []\n    for vert in wire.Vertexes:\n        points.append(vert.Point)\n    bspline = Draft.makeBSpline(points)\n    bsplines.append(bspline)\n\n# hide the bsplines\n\nfor bspline in bsplines:\n    bspline.ViewObject.hide()\n\n# sort the bsplines by elevation (we use the z of their first point to sort)\n\nbsplines.sort(key=lambda b: b.Points[0].z)\n\n# build one ruled surface from each pair of bsplines\n\nruledsurfaces = []\nfor i in range(len(bsplines)-1):\n    ruled = FreeCAD.ActiveDocument.addObject('Part::RuledSurface', 'TerrainSection')\n    ruled.Curve1 = (bsplines[i],[''])\n    ruled.Curve2 = (bsplines[i+1],[''])\n    ruledsurfaces.append(ruled)\n\n# hide the ruled surfaces\n\nfor ruled in ruledsurfaces:\n    ruled.ViewObject.hide()\n\n# at this stade we need to recompute to build all the shapes before getting the faces\n\nFreeCAD.ActiveDocument.recompute()\n\n# make a shell object out of all the ruled surfaces\n\nfaces = []\nfor ruled in ruledsurfaces:\n    faces.extend(ruled.Shape.Faces)\nshell = Part.Shell(faces)\nterrain = FreeCAD.ActiveDocument.addObject('Part::Feature', 'Terrain')\nterrain.Shape = shell\n\n# make a site object using our shell as terrain\n\nsite = Arch.makeSite()\nsite.Terrain = terrain\n\n# recompute one last time\n\nFreeCAD.ActiveDocument.recompute()",
    "url": "https://wiki.freecad.org/Macro_Site_From_Contours",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2018-08-30",
    "src_filename": "",
    "filename_from_url": "",
    "author": "yorik",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Site_From_Contours.png",
    "icon_source": "https://wiki.freecad.org//images/d/d3/Macro_Site_From_Contours.png?20190704172250",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Solid Sweep",
    "on_wiki": true,
    "on_git": false,
    "desc": "Creates a solid by sweeping a profile from a trajectory.<br /><br />Macro version: 1.0<br />Last modified: 2011-12-03<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/6/6d/Macro_Solid_Sweep.png\">ToolBar Icon</a><br />Author: Normandc<br /> ",
    "comment": "Creates a solid by sweeping a profile from a trajectory.",
    "code": "import Part, FreeCAD, math, PartGui, FreeCADGui\nfrom FreeCAD import Base\n\n# get the selected objects, with first selection for the trajectory and second for the section\ns = FreeCADGui.Selection.getSelection()\ntry:\n     shape1=s[0].Shape\n     shape2=s[1].Shape\nexcept:\n     print \"Wrong selection\"\n\ntraj = Part.Wire([shape1])\nsection = Part.Wire([shape2])\n\n# create Part objec in the current document\nmyObject=App.ActiveDocument.addObject(\"Part::Feature\",\"Sweep\")\n\n# variable makeSolid = 1 to create solid, 0 to create surfaces\nmakeSolid = True #1\nisFrenet = True #1\n\n# create a 3D shape and assigh it to the current document\nSweep = Part.Wire(traj).makePipeShell([section],makeSolid,isFrenet)\nmyObject.Shape = Sweep",
    "url": "https://wiki.freecad.org/Macro_Solid_Sweep",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2011-12-03",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Normandc",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Solid_Sweep.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/6/6d/Macro_Solid_Sweep.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Stairs",
    "on_wiki": true,
    "on_git": false,
    "desc": "Creates a stair helix. Create your stair nosing, select your object and launch the macro<br /><br />Macro version: 00.05<br />Last modified: 2023-08-11<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/a/a3/Macro_Stairs.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Creates a stair helix. Create your stair nosing, select your object and launch the macro",
    "code": "# Select your object(s) give :\n#     head marche\n#     number objects for 1 turn\n#     radius (axe to object)\n#     number turns\n# the original object is not modify\n# Macro_Stairs.FCMacro\n# \n#01/03/2015 2019/07/24\nimport FreeCAD, Draft, Part\n\n__title__   = \"CircularStair\"\n__author__  = \"Mario52\"\n__date__    = \"2023/08/11\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__wiki__    = \"https://www.freecadweb.org/wiki/Macro_Stairs\"\n__version__ = \"00.05\"\n\n############## Modify here ####################\nHmarche  = 5  # head marche\nnombre   = 5  # number objects for 1 turn\nrayon    = 20  # radius (axe to object)\ntours    = 2  # nomber turns pitch \ncloner   = 1   # 1=clone    0=copy\ncylindre = 1   # 1=create cylinder  0=not cylinder\ndegres   = 360  # number of degrees  (default 360)\n###############################################\n\n\ntry:\n    sel = FreeCADGui.Selection.getSelection()[0]\n\n    vecligne=[FreeCAD.Vector(0.0,0.0,0.0),FreeCAD.Vector(rayon,0.0,0.0)]   # vector for line directrice\n    ligne = Draft.makeWire(vecligne,closed=False,face=False,support=None)  # creation de la ligne de base\n    FreeCAD.ActiveDocument.openTransaction(\"Stair: Line\")    # memorise les actions (avec annuler restore)\n\n    coor_X = coor_Y = coor_Z = 0.0\n    for i0 in range(tours):\n        for i in range(0,degres,(int(degres/nombre))):                                  # boucle principale 0 to 360 degrees\n            FreeCAD.ActiveDocument.openTransaction(\"Stair:\" + str(i0) + \"/\" + str(i))    # memorise les actions (avec annuler restore)\n\n            FreeCAD.ActiveDocument.getObject(ligne.Name).Placement=App.Placement(App.Vector(0,0,coor_Z), App.Rotation(App.Vector(0,0,1),i), App.Vector(0,0,0))\n            try:\n                a = ligne.Shape.Edges[0].Vertexes[1]       # fin de la ligne\n                coor_X = (a.Point.x)\n                coor_Y = (a.Point.y)\n            except Exception:\n                a = ligne.End         \n                coor_X = (ligne.End.x)                      # fin de la ligne X\n                coor_Y = (ligne.End.y)                      # fin de la ligne Y\n    \n            if cloner == 1:\n                obj=Draft.clone(sel)\n            else:\n                obj = Draft.scale(sel,delta=App.Vector(1, 1, 1),center=App.Vector(),copy=True,legacy=True)\n            try:\n                for io in range(len(obj)):\n                    obj[io].Placement=App.Placement(App.Vector(coor_X,coor_Y,coor_Z), App.Rotation(i,0,0), App.Vector(0,0,0))\n            except Exception:\n                obj.Placement=App.Placement(App.Vector(coor_X,coor_Y,coor_Z), App.Rotation(i,0,0), App.Vector(0,0,0))\n    \n            coor_Z += Hmarche\n    App.ActiveDocument.removeObject(ligne.Name)                            # remove ligne de base directrice\n    \n    # create cylinder\n    if cylindre == 1:\n        FreeCAD.ActiveDocument.openTransaction(\"Stair: Cylinder\")    # memorise les actions (avec annuler restore)\n        App.ActiveDocument.addObject(\"Part::Cylinder\",\"Cylinder\")\n        App.ActiveDocument.ActiveObject.Label = \"Cylindre\"\n        FreeCAD.ActiveDocument.ActiveObject.Height = (Hmarche * nombre * tours)    # heigth of cylinder\n        FreeCAD.ActiveDocument.ActiveObject.Radius = (rayon)                       # radius of cylinder\n    \n    FreeCAD.ActiveDocument.recompute()\nexcept Exception:\n    App.Console.PrintError(u\"Select the stair treads\")",
    "url": "https://wiki.freecad.org/Macro_Stairs",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_Stairs",
    "version": "00.05",
    "license": "",
    "date": "2023/08/11",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Stairs.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/a/a3/Macro_Stairs.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Triangle AH",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro create one triangle creates a triangle by giving the head angle and the height of the triangle. The new triangle is created in the real coordinate.<br /><span style=\"background-color: #ffeeee\">(Command line, paste this complete macro in the Python console)</span>.<br /><br />Macro version: 00.03<br />Last modified: 2019/07/02<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/4/41/Macro_Triangle_AH.png\">ToolBar Icon</a><br />Author: mario52<br /> ",
    "comment": "This macro create one triangle creates a triangle by giving the head angle and the height of the triangle. The new triangle is created in the real coordinate.",
    "code": "__title__   = \"triangleAH\"\n__author__  = \"Mario52\"\n__version__ = \"00.03\"\n__date__    = \"2019/07/02\"\n# Give angle and on choice : height or base or hypo\nfrom math import cos, sin, tan, degrees, radians, sqrt\nimport Draft, Part\ndef triangleAH(angle, height=0.0, base=0.0, hypo=0.0):\n    def line_length(x1 = 0.0, y1 = 0.0, z1 = 0.0, length = 10.0, angle2 = 0.0):  # search coordinates\n        x2 = x1 + (length * cos(radians(angle2)))\n        y2 = y1 + (length * sin(radians(angle2)))\n        z2 = z1 #+ ()\n        return x2,y2,z2                                                          # return coordinates (xyz) to point\n \n    x0 = y0 = z0 = 0.0\n    angle = float(angle)\n    height = float(height)\n    base = float(base)\n    if base != 0:\n        height = ( (base/2) / (tan(radians(angle/2))) )                          # imposing base and calculate height\n    if hypo != 0:\n        height = hypo * (cos(radians(angle/2)))                                  # imposing hypo and calculate height \n    else:\n        hypo = height / cos(radians(angle/2))                                    # calculate hypotenuse\n    if base==0:                                                                  # base of triangle\n        base = (tan(radians(angle/2) ) * height) * 2                             # calculate base\n    a0 = line_length(x1=x0,y1=y0,z1=z0,length=height,angle2=0 )                  # coord height of triangle\n    a0 = line_length(x1=x0,y1=y0,z1=z0,length=0, angle2 = angle )                # point 0 (begin vertex)\n    a  = line_length(x1=a0[0],y1=a0[1],z1=a0[2],length= hypo, angle2=-(angle/2)) #\n    b  = line_length(a[0],a[1],a[2],length= (abs(a[1])*2), angle2=90.0)          # base of triangle = (abs(a[1])*2)\n    ##\n    print()\n    print(\"angle theet : \", angle)\n    print(\"angles base : (\", (180.0-angle)/2.0,\"),(\",(180-angle)/2.0,\")\")\n    print(\"height      : \", height)\n    print(\"base        : \", base)\n    print(\"hypotenuse  : \", hypo)\n    print(\"surface     : \", (base * height) / 2.0)\n    print(\"_________________________\")\n    Draft.makeWire([FreeCAD.Vector(a0),FreeCAD.Vector(a),FreeCAD.Vector(b)],closed=True,face=True,support=None) # create triangle\n    App.ActiveDocument.recompute()\n\n#Example\n#triangleAH(angle=90, height=10)\n#triangleAH(90, 10)\n#triangleAH(45, hypo=10)",
    "url": "https://wiki.freecad.org/Macro_Triangle_AH",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.03",
    "license": "",
    "date": "2019/07/02",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Triangle_AH.png",
    "icon_source": "https://wiki.freecad.org/images/4/41/Macro_Triangle_AH.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "WireXYZ",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro creates a wire (or points) with the coordinates extracted from a file. The coordinates X Y Z are separated by a space.<br /><span style=\"background-color: #ffeeee\">(Command line, paste this complete macro in the Python console)</span>.<br /><br />Macro version: 0.3<br />Last modified: 2020-10-16<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/0/0a/Macro_WireXYZ.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "This macro creates a wire (or points) with the coordinates extracted from a file. The coordinates X Y Z are separated by a space.",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n# created a wire with coordinate x y z separated (in the file without coma)\n__title__= \"Macro_WireXYZ\"\n__author__= \"Mario52\"\n__date__= \"2020/10/16\"\n__version__= \"00.03\"\n##\n#EX:\n#0 0 0\n#10 10 10\n#15 20 25\n#. . . .\n\nfrom FreeCAD import Base\nimport Draft, Part\n\n## path for Windows    : C:\\yourPath\\cloud.asc (create one error in Python (cause, the \"\\\" is a command syntax in Python)\n## replace \"\\\" by \"/\"  result : C:/yourPath/cloud.asc \n## or replace the \"\\\" by \"\\\\\" result : C:\\\\yourPath\\\\cloud.asc \n\nfichier = \"C:\\\\yourPath\\\\cloud.asc\"                          # path and name of file.txt\n\nfile = open(fichier, \"r\")                                  # open the file read\nwire = []\nX=Y=Z = 0.0\n\nfor ligne in file:\n    coordinates = ligne.split()\n    try:                                                        # for format PCD ignore the header\n        X,Y,Z = coordinates                                     # separate the coordinates\n#        Draft.makePoint(float(X),float(Y),float(Z))            # create points (uncomment for use)\n        print(X,\" \",Y,\" \",Z)\n        wire.append(FreeCAD.Vector(float(X),float(Y),float(Z))) # append the coordinates\n    except Exception:\n        None\nfile.close()\nDraft.makeWire(wire,closed=False,face=False,support=None)   # create the wire open\n#Draft.makeWire(wire,closed=True,face=False,support=None)   # create the wire closed (uncomment for use)\n\n#Draft.makeBSpline(wire,closed=False,face=False,support=None)# create the BSpline open (uncomment for use)\n#Draft.makeBSpline(wire,closed=True,face=False,support=None)# create the BSpline open (uncomment for use)\n\nApp.ActiveDocument.recompute()",
    "url": "https://wiki.freecad.org/Macro_WireXYZ",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.03",
    "license": "",
    "date": "2020/10/16",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_WireXYZ.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/0/0a/Macro_WireXYZ.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Align Object BoundBox Center",
    "on_wiki": true,
    "on_git": false,
    "desc": "Aligns 2 (or more) objects by the center of their bounding boxes.<br /><br />Macro version: 0.2<br />Last modified: 2024-11-10<br />Author: heda<br /> ",
    "comment": "Aligns 2 (or more) objects by bounding box",
    "code": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n# ***************************************************************************\n# *   Copyright (c) 2024 heda <heda @ freecad forum>                        *\n# *                                                                         *\n# *   This file is part of the FreeCAD CAx development system.              *\n# *                                                                         *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU Lesser General Public License (LGPL)    *\n# *   as published by the Free Software Foundation; either version 2 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENCE text file.                                 *\n# *                                                                         *\n# *   This program is distributed in the hope that it will be useful,       *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU Library General Public License for more details.                  *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with this program; if not, write to the Free Software   *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\n\n__Name__ = 'Macro_Align_Object_BoundBox_Center'\n__Comment__ = 'Aligns 2 (or more) objects by bounding box'\n__Author__ = 'heda @ fc-forum'\n__Version__ = '0.2'\n__Date__ = '2024-11-10'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = ''\n__Wiki__ = 'https://wiki.freecad.org/Macro_Align_Object_BoundBox_Center'\n__Icon__ = ''\n__Help__ = 'Select and launch.'\n__Status__ = 'functional'\n__Requires__ = 'tested on FreeCAD v0.21'\n__Communication__ = ''\n__Files__ = ''\n\n\n__doc__ = \"\"\"\nselect 2 or more objects and run macro.\nfirst object is reference, and all subsequent\nselections will get a placement that has the\ncentre at same location as the reference object.\n\nundo transaction is commented out,\nsince it moves the object back twice...\n\"\"\"\n\n\nimport FreeCAD as App\nimport FreeCADGui as Gui\n\ndoc = App.ActiveDocument\nsel = Gui.Selection.getSelection()\n\ndef getBBox(obj):\n    if hasattr(obj, 'Shape'):\n        return obj.Shape.BoundBox\n    elif hasattr(obj.'ViewObject'):\n        return obj.ViewObject.getBoundingBox()\n    else:\n        return None\n\nif len(sel) > 1:\n\n    ref, *moves = sel\n    refbb = getBBox(ref)\n    msg_skip = 'could not find bbox for {}, skipping...)'\n    if refbb:\n        # doc.openTransaction('Bbox align objects')\n        moved = list()\n        for move in moves:\n            movebb = getBBox(move)\n            if movebb:\n                vec = refbb.Center - movebb.Center\n                move.Placement.Base = move.Placement.Base + vec\n                moved.append(move)\n            else:\n                print(msg_skip.format(move.Label))\n        doc.recompute()\n        # doc.commitTransaction()\n        if moved:\n            txt = [obj.Label for obj in moved]\n            print('moved {} to {}'.format(', '.join(txt), ref.Label))\n        else:\n            print('could not move any objects')\n    else:\n        print('could not find bbox for ref-obj, bailing...')",
    "url": "https://wiki.freecad.org/Macro_Align_Object_BoundBox_Center",
    "raw_code_url": "",
    "wiki": "https://wiki.freecad.org/Macro_Align_Object_BoundBox_Center",
    "version": "0.2",
    "license": "",
    "date": "2024-11-10",
    "src_filename": "",
    "filename_from_url": "",
    "author": "heda @ fc-forum",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Align Object to View",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro aligns the selected object to the current View.<br /><br />Macro version: 0.1<br />Last modified: 2015-01-16<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/f/f4/Macro_Align_Object_to_View.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "This macro aligns the selected object to the current View.",
    "code": "# This macro place your object selected to the position ActiveView (camera)\n# extact FCCamera\n# 16/01/2015\n\n__title__  =\"Align Object to View\"\n__author__ = \"Mario52\"\n__date__   = \"16/01/2015\"\n__version__= \"0.1\"\n\nimport pivy\nfrom pivy import coin\n\nsel = FreeCADGui.Selection.getSelection()\nNameelement = sel[0].Name\nApp.Console.PrintMessage(str(Nameelement)+\"\\n\")\n\npl = FreeCAD.Placement()\npl.Rotation = FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation()\npl.Base = FreeCAD.Vector(0.0,0.0,0.0)\n\nApp.ActiveDocument.getObject(Nameelement).Placement=pl",
    "url": "https://wiki.freecad.org/Macro_Align_Object_to_View",
    "raw_code_url": "",
    "wiki": "",
    "version": "0.1",
    "license": "",
    "date": "16/01/2015",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Align_Object_to_View.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/f/f4/Macro_Align_Object_to_View.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "ArrayCopy",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro copies the selected object several times, on an array grid You can define the number of rows and columns and the distance between them.<br /><br />Macro version: 1.0<br />Last modified: 2014-05-04<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/9/9d/Macro_ArrayCopy.png\">ToolBar Icon</a><br />Author: Yorik<br /> ",
    "comment": "This macro copies the selected object several times, on an array grid You can define the number of rows and columns and the distance between them.",
    "code": "import FreeCAD, FreeCADGui, Part\nfrom PySide import QtGui,QtCore\n \ndef proceed():\n    try:\n        u = (int(l1.text()),float(l2.text()))   \n        v = (int(l3.text()),float(l4.text()))\n    except:\n        FreeCAD.Console.PrintError(\"Wrong input! Only numbers allowed...\\n\")\n    sel = FreeCADGui.Selection.getSelection()\n    if sel:\n        sel = sel[0]\n        name = sel.Name   \n        shape = sel.Shape\n        for column in range(u[0]):\n            for row in range(v[0]):\n                if (column != 0) or (row != 0):\n                    delta = FreeCAD.Vector(column*u[1],row*v[1],0)   \n                    newshape = sel.Shape.copy()\n                    newshape.translate(delta)\n                    newobject = FreeCAD.ActiveDocument.addObject(\"Part::Feature\",name)\n                    newobject.Shape = newshape\n    else:\n        FreeCAD.Console.PrintError(\"Error: One object must be selected\")\n    hide()\n \ndef hide():\n    dialog.hide()\n \ndialog = QtGui.QDialog()\ndialog.resize(200,300)\ndialog.setWindowTitle(\"Array\")\nla = QtGui.QVBoxLayout(dialog)\nt1 = QtGui.QLabel(\"number of columns\")\nla.addWidget(t1)\nl1 = QtGui.QLineEdit()\nla.addWidget(l1)\nt2 = QtGui.QLabel(\"distance between columns\")\nla.addWidget(t2)\nl2 = QtGui.QLineEdit()\nla.addWidget(l2)\nt3 = QtGui.QLabel(\"number of rows\")\nla.addWidget(t3)\nl3 = QtGui.QLineEdit()\nla.addWidget(l3)\nt4 = QtGui.QLabel(\"distance between rows\")   \nla.addWidget(t4)\nl4 = QtGui.QLineEdit()\nla.addWidget(l4)\nokbox = QtGui.QDialogButtonBox(dialog)\nokbox.setOrientation(QtCore.Qt.Horizontal)\nokbox.setStandardButtons(QtGui.QDialogButtonBox.Cancel",
    "url": "https://wiki.freecad.org/Macro_ArrayCopy",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-05-04",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Yorik",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_ArrayCopy.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/9/9d/Macro_ArrayCopy.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Bevel",
    "on_wiki": true,
    "on_git": false,
    "desc": "Bevel selected vertices of solid objects, parametric, compatible with Part Design<br /><br />Macro version: 0.2022.04.06b<br />Last modified: 2022-04-06<br />FreeCAD version: Python 3 versions<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/File:bevel.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Bevel selected vertices of solid objects, parametric, compatible with Part Design",
    "code": "# -*- coding: utf-8 -*-\n__version__ = \"0.2022.04.06b\"\n#__version__ = \"0.2022.04.06b\"\n#__title__ = \"Bevel Macro\"\n#__author__ = \"<TheMarkster> 2021\"\n#__license__ = \"LGPL 2.1\"\n#__doc__ = \"Bevel the selected vertices of an object.\"\n#__usage__ = '''Select the vertices or the entire object and activate the tool, modify properties as desired'''\n#import Part, FreeCADGui, FreeCAD\n#from PySide import QtGui,QtCore\n#BASENAME = \"bevel\"\n#\n#class Bevel:\n#    def __init__(self,obj):\n#        obj.addProperty(\"App::PropertyLength\",\"Length\",\"Bevel\",\"distance from vertex to point along edge to be removed\").Length = 1\n#        obj.addProperty(\"App::PropertyLinkSub\",\"Vertices\",\"Bevel\",\"Selected vertices to be beveled\")\n#        obj.addProperty(\"App::PropertyString\", \"Version\", \"Bevel\", \"version this object was created with\").Version = __version__\n#        obj.addProperty(\"App::PropertyBool\",\"EditVertices\",\"Bevel\",\"Trigger, toggle to bring up vertex editor\").EditVertices = False\n#        obj.addProperty(\"App::PropertyBool\",\"UseAllVertices\",\"Bevel\",\"use all vertices of this object\").UseAllVertices = False\n#        if not hasattr(obj,\"Refine\"):\n#            obj.addProperty(\"App::PropertyBool\",\"Refine\", \"Bevel\", \"refine feature\").Refine = False\n#        obj.addProperty(\"App::PropertyBool\",\"FilletEdges\",\"Bevel\", \"whether to fillet the edges created with the bevel\").FilletEdges = False\n#        obj.addProperty(\"App::PropertyBool\",\"FilletAllEdges\",\"Bevel\", \"whether to fillet all the edges\").FilletAllEdges = False\n#        obj.addProperty(\"App::PropertyFloatConstraint\", \"FilletRadius\",\"Bevel\",\"radius of fillets in mm\").FilletRadius = (.1,0.001,10e17,.1)\n#        obj.addProperty(\"App::PropertyBool\",\"ClaimChildren\",\"Bevel\",\"whether to claim children in the tree\").ClaimChildren = True\n#        self.editingMode = False\n#        self.fpName = obj.Name\n#        obj.Proxy = self\n#\n#    def onChanged(self,fp,prop):\n#        if prop == \"EditVertices\" and fp.EditVertices == True:\n#            t = QtCore.QTimer()\n#            t.singleShot(50, self.editVertices) #avoid warning message about selection changing while committing data\n#            fp.EditVertices = False\n#\n#    def editVertices(self):\n#        fp = FreeCAD.ActiveDocument.getObject(self.fpName)\n#        if not fp.Vertices:\n#            return\n#        object = fp.Vertices[0]\n#        if not object:\n#            return\n#        if not FreeCADGui.Control.activeDialog():\n#            panel = TaskEditLinkSubPanel(fp,\"Vertices\",\"Vertex\")\n#            FreeCADGui.Control.showDialog(panel)\n#            self.editingMode = True #tells execute() not to hide the linked object\n#            if fp.UseAllVertices:\n#                FreeCAD.Console.PrintWarning(\"Use All Vertices property is True, which overrides the Vertices property.  You must set it to False in order to use only selected vertices.\\n\")\n#        else:\n#            self.editingMode=False\n#            FreeCAD.Console.PrintError(\"Another task dialog is active.  Close that one and try again.\\n\")\n#\n#    def execute(self,fp):\n#        if not fp.Vertices:\n#            return\n#        vertices = []\n#        object = fp.Vertices[0]\n#        solid = len(object.Shape.Solids) > 0\n#        mapped = {}\n#        insideLofts = []\n#        outsideLofts = []\n#        if not fp.UseAllVertices:\n#            for vname in fp.Vertices[1]:\n#                if vname != '':\n#                    vertices.append(getattr(object.Shape,vname))\n#        else:\n#            for ii in range(0,len(object.Shape.removeSplitter().Vertexes)):\n#                name = \"Vertex\"+str(ii+1)\n#                vertices.append(getattr(object.Shape.removeSplitter(),name))\n#        for vert in vertices:\n#            shape_pts = []\n#            for edge in object.Shape.removeSplitter().Edges:\n#                hasCurve = False\n#                for edge_vert in edge.Vertexes:\n#                    if edge_vert.Point.isEqual(vert.Point,1e-7):\n#                        #this is an edge containing a selected vertex\n#                        if edge.Curve.TypeId != \"Part::GeomLine\":\n#                            hasCurve = True #we'll skip this edge\n#                        else:\n#                            hasCurve = False\n#                        other_vert = self.getOtherVertex(edge_vert, edge)\n#                        if other_vert:\n#                            dir = edge_vert.Point.sub(other_vert.Point).normalize()\n#                            #line = Part.makeLine(edge_vert.Point,edge_vert.Point.sub(dir.multiply(fp.Length)))\n#                            mid = edge_vert.Point.sub(dir.multiply(fp.Length)) #point along edge fp.Length distance from selected vertex\n#                            if not hasCurve:\n#                                shape_pts.append(mid)\n#            if solid:\n#                if len(shape_pts) >= 3:\n#                    mapped[vert] = shape_pts\n#            else:\n#                if len(shape_pts) >= 2:\n#                    mapped[vert] = shape_pts\n#        for k,val in mapped.items():\n#            if not val:\n#                FreeCAD.Console.PrintError(\"Error making bevel\\n\")\n#                return\n#            pts = self.sortPoints(val)\n#            pts.append(val[0])\n#            if len(pts) > 2:\n#                poly = Part.makePolygon(pts)\n#                loft = Part.makeLoft([k,poly],solid)\n#                if not solid:\n#                    loft = loft.reversed() if not bool(loft.Face1.normalAt(0,0) == object.Shape.Face1.normalAt(0,0)) else loft\n#                if object.Shape.cut(loft).isInside(k.Point,.01,True):\n#                    insideLofts.append(loft)\n#                else:\n#                    outsideLofts.append(loft)\n#            else:\n#                FreeCAD.Console.PrintError(\"Error making bevel\\n\")\n#                return\n#        #handle inside corners by fusing those lofts instead of cutting\n#        #test for this by fusing and checking if the volume has increased\n#        origShape = object.Shape.removeSplitter()\n#        if len(outsideLofts)>1:\n#            outsideFusion = Part.Shape(outsideLofts[0]).fuse(outsideLofts[1:])\n#        elif len(outsideLofts) == 1:\n#            outsideFusion = outsideLofts[0]\n#        else:\n#            outsideFusion = Part.Shape()\n#        if len(insideLofts)>1:\n#            insideFusion = Part.Shape(insideLofts[0]).fuse(insideLofts[1:])\n#        elif len(insideLofts) == 1:\n#            insideFusion = insideLofts[0]\n#        else:\n#            insideFusion = Part.Shape()\n#        try:\n#            if not outsideFusion.isNull():\n#                shape = object.Shape.cut(outsideFusion)\n#            else:\n#                shape = object.Shape\n#            if not insideFusion.isNull():\n#                shape = shape.fuse(insideFusion)\n#        except:\n#            FreeCAD.Console.PrintError(\"Error making boolean\\n\")\n#            shape = object.Shape\n#        if len(insideLofts) + len(outsideLofts) == 0:\n#            ## don't warn about not making any bevels if user is filleting all edges\n#            if hasattr(fp,\"FilletAllEdges\") and not fp.FilletAllEdges:\n#                FreeCAD.Console.PrintWarning(\"No bevels were made.\\n\")\n#        if fp.Refine and not shape.isNull():\n#            shape = shape.removeSplitter()\n#        if not insideFusion.isNull() and not outsideFusion.isNull():\n#            fusion = insideFusion.fuse(outsideFusion)\n#        elif not insideFusion.isNull():\n#            fusion = insideFusion\n#        elif not outsideFusion.isNull():\n#            fusion = outsideFusion\n#        if not fusion.isNull():\n#            fusion = fusion.removeSplitter()\n#        if shape and bool(fp.FilletEdges or bool(hasattr(fp,\"FilletAllEdges\"))and fp.FilletAllEdges):\n#            if fp.Refine or len(insideLofts) == 0:\n#                if hasattr(fp,\"FilletAllEdges\") and fp.FilletAllEdges:\n#                    common = shape.Edges\n#                else:\n#                    common = self.findCommonEdges(shape, fusion)\n#                if common:\n#                    try:\n#                        shape2 = shape.makeFillet(fp.FilletRadius, common)\n#                        shape = shape2 #only get here if makeFillet succeeded\n#                    except:\n#                        FreeCAD.Console.PrintError(\"Failed to make fillet, skipping\\n\")\n#            else:\n#                FreeCAD.Console.PrintMessage(\"Refine = True required for Fillet Edges option if there are inside corners, else FreeCAD will sometimes hang.  Skipping fillet.\\n\")\n#        if hasattr(fp,\"BaseFeature\") and hasattr(fp,\"AddSubShape\"):\n#            if fp.BaseFeature and not shape.isNull():\n#                fp.AddSubShape = shape.common(fp.BaseFeature.Shape)\n#            else:\n#                fp.AddSubShape = shape\n#        fp.Shape = shape if shape else Part.Shape()\n#        if not self.editingMode:\n#            object.ViewObject.Visibility = False if shape else True\n#\n#    def sortPoints(self,pts):\n#        \"\"\" sortPoints(pts)\n#            sort pts, a list of vectors, according to distance from one point to the next\n#            pts[0] is taken first, then the nearest point to it is placed at pts[1]\n#            then pts[1] is used to find the nearest point to it and placed at pts[2], and so on\n#        \"\"\"\n#        newList = [pts[0]]\n#        for ii in range(0, len(pts)):\n#            newList.extend([self.nearestPoint(newList[ii],pts,newList)])\n#        return newList\n#\n#    def nearestPoint(self, pt, pts, exclude):\n#        \"\"\" nearestPoint(pt, pts, exclude)\n#            pt is a vector, pts a list of vectors\n#            exlude is a list of vectors to exclude from process\n#            return nearest point to pt in pts and not in exclude\"\"\"\n#        if len(pts) == 0: #should never happen\n#            raise Exception(\"Error: nearestPoint() pts length = 0\\n\")\n#        nearest = pts[0]\n#        d = 10**100\n#        for p in pts:\n#            if p in exclude:\n#                continue\n#            dis = pt.distanceToPoint(p)\n#            if dis < d:\n#                d = dis\n#                nearest = p\n#        return nearest\n#\n#    def getOtherVertex(self,v0,edge):\n#        '''get the other vertex from this edge of which v0 is one vertex'''\n#        for v in edge.Vertexes:\n#            if not v.Point.isEqual(v0.Point,1e-7):\n#                return v\n#        return None #not found\n#\n#    def findCommonEdges(self, shape1, shape2):\n#        '''find the common edges of 2 shapes, return them as a list of edges of shape1'''\n#        common = []\n#        for edge in shape1.Edges:\n#            for edge2 in shape2.Edges:\n#                if self.isSameEdge(edge,edge2) and edge not in common:\n#                    common.append(edge)\n#        return common\n\n#    def isSameEdge(self, edge1, edge2):\n#        '''compare 2 edges.  They are the same if their vertices are within tolerance distance of each other 1e-7'''\n#        equals = 0\n#        if edge1.Vertex1.Point.isEqual(edge2.Vertex1.Point, 1e-7) or edge1.Vertex1.Point.isEqual(edge2.Vertex2.Point, 1e-7):\n#            equals += 1\n#        if edge1.Vertex2.Point.isEqual(edge2.Vertex1.Point, 1e-7) or edge1.Vertex2.Point.isEqual(edge2.Vertex2.Point, 1e-7):\n#            equals += 1\n#        return True if equals == 2 else False\n\n#class TaskEditLinkSubPanel: #simple editor for App::PropertyLinkSub\n#    def __init__(self, obj, linkSubName, subNames,):\n#        self.obj = obj\n#        self.subNames = subNames\n#        self.linkSubName = linkSubName #entire LinkSub property\n#        self.linkObj = getattr(self.obj,linkSubName)[0]\n#        self.subObjects = getattr(self.obj,linkSubName)[1]\n#        self.form = QtGui.QWidget()\n#        self.label1 = QtGui.QLabel(\"Select the \"+self.subNames+\" subobjects to use and click OK.\\nThe ones already being utilized have been selected for you.\")\n#        layout=QtGui.QHBoxLayout()\n#        layout.addWidget(self.label1)\n#        self.form.setLayout(layout)\n#        self.form.setWindowTitle('Edit '+self.subNames)\n#        self.obj.ViewObject.Visibility = False\n#        self.linkObj.ViewObject.Visibility = True\n#        FreeCADGui.Selection.clearSelection()\n#        for f in self.subObjects:\n#            FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Name,self.linkObj.Name,f)\n#        self.obj.Proxy.editingMode = True\n#\n#    def reject(self):\n#        FreeCADGui.Control.closeDialog()\n#        fp = self.obj\n#        self.linkObj.ViewObject.Visibility = False\n#        fp.ViewObject.Visibility = True\n#        self.obj.Proxy.editingMode = False #self.obj.Proxy is the Bevel class object (self in that class)\n#        FreeCADGui.activeDocument().resetEdit()\n#        FreeCAD.ActiveDocument.recompute()\n#\n#    def accept(self):\n#        FreeCADGui.ActiveDocument.resetEdit()\n#        FreeCADGui.Control.closeDialog()\n#        fp = self.obj\n#        if not fp: #user deleted or closed document perhaps\n#            return\n#        selx = FreeCADGui.Selection.getSelectionEx()\n#        if not selx:\n#            FreeCAD.Console.PrintWarning(\"Nothing selected, leaving \"+self.linkObj.Name+\" unmodified.\")\n#            return\n#        seNames = [sen for sen in selx[0].SubElementNames if self.subNames in sen]\n#        setattr(self.obj,self.linkSubName,(selx[0].Object,seNames)) #allow user to select diffent object\n#        self.linkObj = selx[0].Object\n#        if hasattr(fp,\"_Body\") and fp._Body and self.linkObj not in fp._Body.Group:\n#            fp._Body.Group += [self.linkObj]\n#            if not self.linkObj.isDerivedFrom(\"PartDesign::Feature\"):\n#               fp.ClaimChildren = True\n#        self.linkObj.ViewObject.Visibility = False\n#        fp.ViewObject.Visibility = True\n#        if hasattr(fp.Proxy,\"editingMode\"):\n#            fp.Proxy.editingMode = False\n#        FreeCAD.ActiveDocument.recompute()\n#\n#\n#class BevelVP:\n#\n#    def __init__(self, obj):\n#        '''Set this object to the proxy object of the actual view provider'''\n#        obj.Proxy = self\n#\n#    def attach(self, obj):\n#        '''Setup the scene sub-graph of the view provider, this method is mandatory'''\n#        self.Object = obj.Object\n#\n#    def updateData(self, fp, prop):\n#        '''If a property of the handled feature has changed we have the chance to handle this here'''\n#        # fp is the handled feature, prop is the name of the property that has changed\n#        pass\n#\n#    def getDisplayModes(self,obj):\n#        '''Return a list of display modes.'''\n#        modes=[]\n#        modes.append(\"Flat Lines\")\n#        return modes\n#\n#    def setEdit(self,vobj,modNum):\n#        if modNum == 0:\n#            vobj.Object.Proxy.editVertices()\n#            return True\n#        elif modNum == 3:\n#            FreeCADGui.runCommand('Part_ColorPerFace',0)\n#            return True\n#\n#    def getDefaultDisplayMode(self):\n#        '''Return the name of the default display mode. It must be defined in getDisplayModes.'''\n#        return \"Flat Lines\"\n \n#    def setDisplayMode(self,mode):\n#        '''Map the display mode defined in attach with those defined in getDisplayModes.\\\n#                Since they have the same names nothing needs to be done. This method is optional'''\n#        return mode\n#\n#    def onChanged(self, vp, prop):\n#        '''Here we can do something when a single property got changed'''\n#        #FreeCAD.Console.PrintMessage(\"Change property: \" + str(prop) + \"\"+chr(10))\n#\n#    def claimChildren(self):\n#        if self.Object.ClaimChildren and self.Object.Vertices and not self.Object.Shape.isNull():\n#            return [self.Object.Vertices[0]]\n#        else:\n#            return []\n#\n#    def onDelete(self, vobj, subelements):\n#        if vobj.Object.Vertices:\n#            vobj.Object.Vertices[0].ViewObject.Visibility = True\n#        if hasattr(vobj.Object,\"_Body\"): #do this only when the object is in a PD body\n#            #need to ensure the next feature in the tree's BaseFeature property points to our BaseFeature\n#            solids = [feat for feat in vobj.Object._Body.Group if feat.isDerivedFrom(\"PartDesign::Feature\") and feat.BaseFeature == vobj.Object]\n#            if len(solids) == 1: #found previous solid feature\n#                solids[0].BaseFeature = vobj.Object.BaseFeature\n#        return True\n#\n#    def getIcon(self):\n#        '''Return the icon in XPM format which will appear in the tree view. This method is\\\n#                optional and if not defined a default icon is shown.'''\n#        return '''\n#/* XPM */\n#static char *a1ua2_q91uc[] = {\n#/* columns rows colors chars-per-pixel */\n#\"64 64 208 2 \",\n#\"   c #772C3F\",\n#\".  c #743F50\",\n#\"X  c #644956\",\n#\"o  c #5B5B77\",\n#\"O  c #6E5472\",\n#\"+  c #725674\",\n#\"@  c #900F17\",\n#\"#  c #BE0102\",\n#\"$  c #A60F14\",\n#\"%  c #B51414\",\n#\"&  c #B81C22\",\n#\"*  c #8D2635\",\n#\"=  c #B7252D\",\n#\"-  c #BE2F38\",\n#\";  c #AE323B\",\n#\":  c #B53239\",\n#\">  c #D40B12\",\n#\",  c #D71318\",\n#\"<  c #F90608\",\n#\"1  c #F00E14\",\n#\"2  c #EB1217\",\n#\"3  c #EF121A\",\n#\"4  c #EB181E\",\n#\"5  c #F31217\",\n#\"6  c #F2151C\",\n#\"7  c #F7161C\",\n#\"8  c #FA161C\",\n#\"9  c #CB1B21\",\n#\"0  c #DC1C23\",\n#\"q  c #E31C24\",\n#\"w  c #ED1C24\",\n#\"e  c #F11A21\",\n#\"r  c #D7262D\",\n#\"t  c #CF2B32\",\n#\"y  c #CB2C36\",\n#\"u  c #DB2932\",\n#\"i  c #E3212B\",\n#\"p  c #883B4B\",\n#\"a  c #98394B\",\n#\"s  c #BB2F41\",\n#\"d  c #AB3B4B\",\n#\"f  c #CB3D49\",\n#\"g  c #83425A\",\n#\"h  c #9E4758\",\n#\"j  c #BD404A\",\n#\"k  c #AE4A51\",\n#\"l  c #AD525E\",\n#\"z  c #BC5159\",\n#\"x  c #A45B69\",\n#\"c  c #B75E68\",\n#\"v  c #896379\",\n#\"b  c #BB6567\",\n#\"n  c #BD787A\",\n#\"m  c #D5464C\",\n#\"M  c #D44D53\",\n#\"N  c #CC5458\",\n#\"B  c #D05158\",\n#\"V  c #E74B51\",\n#\"C  c #E74C53\",\n#\"Z  c #F4555D\",\n#\"A  c #FA5358\",\n#\"S  c #FB545C\",\n#\"D  c #DA5C60\",\n#\"F  c #F35B63\",\n#\"G  c #FB5B62\",\n#\"H  c #C06F72\",\n#\"J  c #DB6F72\",\n#\"K  c #DC7276\",\n#\"L  c #E56766\",\n#\"P  c #3E5C8A\",\n#\"I  c #4E648D\",\n#\"U  c #5A6B95\",\n#\"Y  c #4D729D\",\n#\"T  c #597195\",\n#\"R  c #5B759C\",\n#\"E  c #6E6E8A\",\n#\"W  c #7C718B\",\n#\"Q  c #6C7893\",\n#\"!  c #667C9B\",\n#\"~  c #6B7D9D\",\n#\"^  c #727A98\",\n#\"/  c #4A6FA4\",\n#\"(  c #4D74A8\",\n#\")  c #5C78A2\",\n#\"_  c #527BB3\",\n#\"`  c #577EB9\",\n#\"'  c #587FBA\",\n#\"]  c #846F80\",\n#\"[  c #9A7B8D\",\n#\"{  c #A87286\",\n#\"}  c #6C819E\",\n#\"|  c #4E85BA\",\n#\" . c #5383BB\",\n#\".. c #5D83BB\",\n#\"X. c #5D84BB\",\n#\"o. c #6E84A3\",\n#\"O. c #6888AA\",\n#\"+. c #6E88AE\",\n#\"@. c #7588A5\",\n#\"#. c #7B8BA5\",\n#\"$. c #7389A9\",\n#\"%. c #7B90AE\",\n#\"&. c #6084B9\",\n#\"*. c #698AB9\",\n#\"=. c #738FB2\",\n#\"-. c #728EB9\",\n#\";. c #6390B4\",\n#\":. c #7991B4\",\n#\">. c #7491BB\",\n#\",. c #7A95BC\",\n#\"<. c #4C8AC2\",\n#\"1. c #568EC7\",\n#\"2. c #5C8BC3\",\n#\"3. c #5490CB\",\n#\"4. c #6B9CC2\",\n#\"5. c #7499C1\",\n#\"6. c #7E9BC4\",\n#\"7. c #7AA1CB\",\n#\"8. c #7DA7D2\",\n#\"9. c #79AAD5\",\n#\"0. c #7EAAD5\",\n#\"q. c #89899E\",\n#\"w. c #94879C\",\n#\"e. c #A1889B\",\n#\"r. c #8895AA\",\n#\"t. c #9E95AD\",\n#\"y. c #8095B2\",\n#\"u. c #8C9BB5\",\n#\"i. c #8B9EBA\",\n#\"p. c #9B9EB8\",\n#\"a. c #A59AAE\",\n#\"s. c #96A0AE\",\n#\"d. c #8DA1BC\",\n#\"f. c #92A2BC\",\n#\"g. c #9AA6B8\",\n#\"h. c #A4ADBA\",\n#\"j. c #A9B1BF\",\n#\"k. c #B1B6BE\",\n#\"l. c #B5B8BF\",\n#\"z. c #C68A8B\",\n#\"x. c #DB8689\",\n#\"c. c #C49EA0\",\n#\"v. c #DA9FA1\",\n#\"b. c #C4A6A7\",\n#\"n. c #D0AEAE\",\n#\"m. c #D2BABA\",\n#\"M. c #E0A1A3\",\n#\"N. c #E8B1B1\",\n#\"B. c #839FC7\",\n#\"V. c #829FC8\",\n#\"C. c #84A1CA\",\n#\"Z. c #94A5C1\",\n#\"A. c #97A9C4\",\n#\"S. c #96AAC5\",\n#\"D. c #9AAAC2\",\n#\"F. c #9BAECC\",\n#\"G. c #97B2CF\",\n#\"H. c #82A6D1\",\n#\"J. c #84A9D3\",\n#\"K. c #84AED9\",\n#\"L. c #8FB4D0\",\n#\"P. c #9EB2D1\",\n#\"I. c #9BBCDA\",\n#\"U. c #A2AEC2\",\n#\"Y. c #A3B1C6\",\n#\"T. c #A5B2CA\",\n#\"R. c #AEB9CA\",\n#\"E. c #B4B9C2\",\n#\"W. c #B4BECC\",\n#\"Q. c #A2B5D4\",\n#\"!. c #A5B9D6\",\n#\"~. c #A7BAD8\",\n#\"^. c #A8BCDA\",\n#\"/. c #BAC0CA\",\n#\"(. c #BCC3CC\",\n#\"). c #ACC0DE\",\n#\"_. c #B8C3D3\",\n#\"`. c #BBC4D1\",\n#\"'. c #9BC4E4\",\n#\"]. c #A5C6E5\",\n#\"[. c #ABC4E3\",\n#\"{. c #A8CAEA\",\n#\"}. c #C3C6CB\",\n#\"|. c #CCCCCF\",\n#\" X c #D2CBCB\",\n#\".X c #DDCFCF\",\n#\"XX c #C3CAD3\",\n#\"oX c #CDCCD1\",\n#\"OX c #C7CED8\",\n#\"+X c #CDD0D7\",\n#\"@X c #CCD2DC\",\n#\"#X c #D4D4D5\",\n#\"$X c #DAD7D7\",\n#\"%X c #D2D6DC\",\n#\"&X c #DDDCDC\",\n#\"*X c #D8DBE1\",\n#\"=X c #DEE0E4\",\n#\"-X c #DEECEB\",\n#\";X c #E2E3E3\",\n#\":X c #E5E8EA\",\n#\">X c #EBECEC\",\n#\",X c #F4EEEC\",\n#\"<X c #F3F1EE\",\n#\"1X c #EAF4F3\",\n#\"2X c #F3F3F2\",\n#\"3X c #F8F6F4\",\n#\"4X c #F3FCFC\",\n#\"5X c none\",\n#/* pixels */\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X<X&X%XXX#X2X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X:X=X%XOX`.W.R.Y.A.i.Z.R.`.%X3X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X>X%X@XXX`.R.Y.f.i.:.+.,.6.6.V.V.>.%.D.`.OX*X2X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X2XR.u.y.$.+.6.6.V.V.C.C.V.V.V.V.V.C.V.V.-.%.g.`.@X;X2X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X2XW.-.V.V.C.C.V.V.V.V.V.V.V.V.V.V.V.V.V.V.C.V.V.>.$.g.XX*X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X3X(.-.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.B.B.B.V.V.V.V.V.C.6.>.! $X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X4X}.-.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.B.B.V.V.V.V.V.V.V.V.V.H.X ,X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X|.*.V.V.V.V.V.V.V.V.V.V.B.V.V.V.V.V.V.V.B.V.V.V.V.V.C.V.V.V.C.~ k 5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X|.-.V.V.V.V.V.B.V.V.V.V.V.B.V.V.V.V.V.V.V.B.B.V.V.B.V.V.V.V.V.C.K.@ b.5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X}.,.V.V.V.V.V.B.B.V.V.V.V.B.B.V.V.V.V.V.V.V.V.B.B.V.V.V.V.V.V.V.V.C.E % ;X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X X,.6.C.V.V.V.V.V.V.V.V.V.V.B.B.B.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.C.8.@ ; 5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5Xz.^ C.V.B.V.V.V.B.B.V.V.V.V.B.B.V.V.V.V.V.V.V.V.V.B.V.V.V.V.V.V.B.B.B.J.+ # b 5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X4XM x 8.V.V.V.V.V.B.B.V.V.V.V.B.B.V.V.V.V.V.V.V.V.B.B.V.V.V.V.B.V.B.B.B.C.5.$ % b.5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X XV C =.C.V.V.V.V.B.B.V.V.V.V.V.V.V.V.V.V.V.V.V.V.B.V.V.V.V.V.B.B.V.B.B.B.K.. # : $X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5Xn S S v H.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.B.B.B.V.V.V.V.V.B.V.V.V.C.=.R g $ b 3X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X>XM F F B 5.C.B.V.V.V.V.V.V.V.B.B.B.B.B.B.V.V.V.V.B.V.V.V.V.V.V.B.B.V.V.C.=.) X. .O * z.5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5Xm.A F F S W C.B.V.V.V.V.V.V.V.B.B.V.B.B.V.V.V.V.B.B.V.V.V.V.V.V.B.B.V.C.,.) ..&.&.2.U   oX5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5XH Z F F G z 7.C.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.B.C.6.R X.&.&.&.&.&. .o 5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X1Xm F F F F A o.V.V.C.C.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.C.V.R X.&.&.&.&.&.&.&.P 5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5Xb.S F F F F Z ] o.6.V.V.V.V.C.V.V.V.V.V.V.V.V.V.V.V.V.V.V.C.V.V.C.C.C.T &.&.&.&.&.&.&.&.&.P 5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5Xb F F F S z d.[.[.u.#.~ 6.C.C.V.C.C.V.V.V.V.C.C.V.V.V.V.V.C.C.H.0.J.T &.&.&.&.&.&.&.&.&.&.P 5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X-XV F G V [ ^.^.^.^.^.^.^.u.#.~ ,.C.C.V.V.V.V.C.C.H.H.0.0.9.;.^ v h . 2.&.&.&.&.&.&.&.&.&.&.P 5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5Xc.S A c D.!.~.^.~.~.^.^.^.!.Q.!.f.%.o.,.C.0.0.4.o.W v h ; 9 i i q 6 o 2.&.&.&.&.&.&.&.&.&.&.P 5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5XN M e.T.!.^.~.~.~.~.~.~.~.^.^.^.Q.Q.Q.d.^ d : y u u i q q 4 e e e ,  .&.&.&.&.&.&.&.&.&.&.&.P 5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X Xx a.P.^.^.~.~.~.~.~.~.~.~.~.~.~.^.^.^.Q.G.; 1 4 e e e w e w w w 8 a 1.&.&.&.&.&.&.&.&.&.&.&.P 5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5Xl.p.^.^.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.^.[.t.0 e w w w w w w w w 5 I 2.&.&.&.&.&.&.&.&.&.&.&.P 5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5XE.^.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.].{ 2 w w w w w w w e 9 | &.&.&.&.&.&.&.&.&.&.&.&.P 5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5Xl.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.^.I.z 5 w w w w w w 7 p 1.&.&.&.&.&.&.&.&.&.&.&.&.P 5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5Xl.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.).A.y 6 w w w w w 5 U X.&.&.&.&.&.&.&.&.&.&.&.&.P 5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5Xl.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.[.w.q e w w w e 9 <.&.&.&.&.&.&.&.&.&.&.&.&.&.I 5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5Xl.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.{.x 3 w w w 7 g 1.&.&.&.&.&.&.&.&.&.&.&.&...#.5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5Xl.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.'.- 6 w w 5 Y &.&.&.&.&.&.&.&.&.&.&.&.&._ }.5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5Xl.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.^.L., e e & 3.&.&.&.&.&.&.&.&.&.&.&.&.&.I 5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5Xl.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.^.[.q.< 8 O 2.&.&.&.&.&.&.&.&.&.&.&.&...r.5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5Xl.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.^.].x < ( &.&.&.&.&.&.&.&.&.&.&.&.&.( #X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5Xl.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.^.!.p 2.&.&.&.&.&.&.&.&.&.&.&.&...T 4X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5Xk.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.[.Q X.&.&.&.&.&.&.&.&.&.&.&.&...s.5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X|.F.^.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.).o...&.&.&.&.&.&.&.&.&.&.&.&./ ;X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X2Xj.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.).} ..&.&.&.&.&.&.&.&.&.&.&...! 5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X&XD.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.).} ..&.&.&.&.&.&.&.&.&.&.&.` h.5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5XXXF.^.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.).} ..&.&.&.&.&.&.&.&.&.&.&./ ;X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5XE.P.^.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.).} ..&.&.&.&.&.&.&.&.&.&...! 5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X2XU.Q.^.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.).} ..&.&.&.&.&.&.&.&.&.&._ k.5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X&XA.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.).} ..&.&.&.&.&.&.&.&.&.../ ,X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5XE.Q.^.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.).} ..&.&.&.&.&.&.&.&.....r.5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5Xs.~.^.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.).} ..&.&.&.&.&.&.&.&.' @.5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5Xu.^.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.).} ..&.&.&.&.&.&.&.` o.5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X&XZ.^.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.^.^.[.O.2.&.&.&.&.&.&.' o.2X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X4X/.P.^.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.^.{.w.= o 1.&.&.&.&.' o.:X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X2Xj.u.~.~.^.~.~.~.~.~.~.~.~.~.^.~.^.[.A.x u 4 r a _ 2.&.' o.=X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X:X*X(.U.i.~.~.^.~.~.~.~.~.~.~.).'.[ f 0 6 w 7 q s +  .O.%X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X:X*X@X/.Y.f.Q.~.^.~.~.^.].p.c t 1 6 3 3 > , r l #.OX5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X;X%XXX_.T.Z.Q.^.F.{ j > 0 u m D K x.x.M.N. X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X;X+X(._.T.t.b L J x.v.m..X:X4X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X;X(.n.$X1X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\",\n#\"5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X\"\n#};\n#'''\n \n#    def __getstate__(self):\n#        '''When saving the document this object gets stored using Python's json module.\\\n#                Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\\\n#                to return a tuple of all serializable objects or None.'''\n#        return None\n \n#    def __setstate__(self,state):\n#        '''When restoring the serialized object from document we have the chance to set some internals here.\\\n#                Since no data were serialized nothing needs to be done here.'''\n#        return None\n\n\n\n############\n#if __name__ == \"__main__\":\n#    FreeCAD.Console.PrintMessage(\"Please run \"+BASENAME+\".FCMacro rather than this file.\\n\")\n############\n\n#CODE_ENDS_HERE\n\n\ndef getBody(feature):\n    doc = FreeCAD.ActiveDocument\n    bodies = [obj for obj in doc.Objects if obj.TypeId == \"PartDesign::Body\"]\n    for bod in bodies:\n        if feature in bod.Group:\n            return bod\n    return None\n\ndef makeObject(BV):\n    doc = FreeCAD.ActiveDocument\n    body=None\n    selobjs = FreeCADGui.Selection.getSelectionEx()\n    if doc:\n        doc.openTransaction(\"Create Bevel\"+\"s\" if len(selobjs) > 1 else \"\")\n\n        if selobjs:\n            for selobj in selobjs:\n                body = getBody(selobj.Object)\n                if body:\n                    bevel = body.newObject(\"PartDesign::FeatureAdditivePython\",\"Bevel\")\n                else:\n                    bevel = doc.addObject(\"Part::FeaturePython\",\"Bevel\")\n                BV.Bevel(bevel)\n                BV.BevelVP(bevel.ViewObject)\n                if body:\n                    bevel.ClaimChildren = False #do not claim children in Part Design to preserve the linear tree\n                if selobj.HasSubObjects:\n                    verts = [name for name in selobj.SubElementNames if not \"Edge\" in name and not \"Face\" in name]\n                    if verts:\n                        bevel.Vertices = (selobj.Object,verts)\n                    else:\n                        FreeCAD.Console.PrintWarning(\"No vertices among selected subobjects, using all vertices.\\n\")\n                        bevel.Vertices = (selobj.Object, \"\")\n                        bevel.UseAllVertices = True\n                else:\n                    bevel.Vertices = (selobj.Object, \"\")\n                    bevel.UseAllVertices = True\n        else:\n            FreeCAD.Console.PrintMessage(\"No object selected to bevel.\\n\")\n        doc.commitTransaction()\n\nBASENAME = \"bevel\"\n\n\n\ndef writeFile():\n    with open(py_file,\"w\") as outfile:\n        for line in code.splitlines():\n            if \"#CODE_ENDS_HERE\" in line:\n                break\n            if line.startswith('#'):\n                if line == \"# -*- coding: utf-8 -*-\":\n                    line = \"#\" + line\n                outfile.write(line[1:]+\"\\n\") #skip first character (#)\n\n\n\n############\n#if __name__ == \"__main__\":\n#    makeObject(None)\n#    raise Exception(\"quick exit for testing/debugging\")\n############\n\nif __name__ == \"__main__\":\n    import os\n    fin = open(__file__, 'r')\n    code = fin.read()\n    fin.close()\n    version = code.splitlines()[1][16:]\n    real_path = os.path.realpath(__file__)\n    dir_path = os.path.dirname(real_path)\n    py_file = real_path.replace(\".FCMacro\",\".py\").replace('Bevel','bevel')\n    bHasFile = os.path.exists(py_file)\n    noImport = False #user elects not to save import file\n\n    if not bHasFile:\n        from PySide import QtCore,QtGui\n        window = QtGui.QApplication.activeWindow()\n        items = [\"Yes, go ahead and create the file.\", \"No, do not create the file.\",\"Cancel\"]\n        caption = \"In order for \"+BASENAME+\" objects to be parametric after saving and reloading file\\n\\\nwe need to create another file on this computer.  File to be created will be: \\n\\n\"+py_file+\"\\n\\n\\\nThis makes it available to the system upon restarting FreeCAD and loading documents containing the \\n\\\n\"+BASENAME+\" feature python objects.  May we proceed?\\n\\n\"\n        item,ok = QtGui.QInputDialog.getItem(window,\"One time installation\",caption,items)\n        if ok and item == items[0]:\n            writeFile()\n            QtGui.QMessageBox.information(window,\"Success\",\"File successfully created.  Please note: if you uninstall \"+BASENAME+\" macro you need to manually remove this file, too.\\n\")\n        else:\n            new_lines = []\n            for line in code.splitlines():\n                if line.startswith('#'):\n                    if \"CODE_ENDS_HERE\" in line:\n                        break\n                    if line == \"# -*- coding: utf-8 -*-\":\n                        new_lines.append(line+\"\\n\")\n                        continue\n                    new_lines.append(line[1:]+\"\\n\")\n            code = \"\".join(new_lines)\n\n            #credit to Mila Nautikus for his answer to a question on stackoverflow, which I modified here\n            #in this example the filename is bevel.py\n            #https://stackoverflow.com/questions/5362771/how-to-load-a-module-from-code-in-a-string\n\n            ##########\n            import sys, importlib\n            my_name = 'bevel' #filename = bevel.py, so this must be 'bevel'\n            my_spec = importlib.util.spec_from_loader(my_name, loader=None)\n\n            bevel = importlib.util.module_from_spec(my_spec)\n\n            exec(code, bevel.__dict__)\n            sys.modules['bevel'] = bevel\n            makeObject(bevel)\n            noImport = True\n\n    if not noImport: #don't never use no double negatives\n\n        import bevel as BV\n        import addonmanager_utilities as utils\n\n        if BV.__version__ != __version__:\n            writeFile()\n            from PySide import QtCore,QtGui\n            window = QtGui.QApplication.activeWindow()\n            mbox = QtGui.QMessageBox()\n            mbox.setWindowTitle(BASENAME+\" updated\")\n\n            mbox.setText(BASENAME+\".py has been updated to version \"+__version__+\". \\\nYou must restart FreeCAD for the new changes to take effect and to use the macro.\")\n            mbox.setIcon(mbox.Warning)\n            mbox.setStandardButtons(mbox.Ok | mbox.Cancel)\n            mbox.setDefaultButton(mbox.Cancel)\n            okBtn = mbox.button(QtGui.QMessageBox.StandardButton.Ok)\n            cancelBtn = mbox.button(QtGui.QMessageBox.StandardButton.Cancel)\n            okBtn.setText(\"Restart now\")\n            cancelBtn.setText(\"Restart later\")\n            ret = mbox.exec_()\n            if ret == mbox.Ok:\n                QtCore.QTimer.singleShot(1000, utils.restart_freecad)\n        else:\n            makeObject(BV)",
    "url": "https://wiki.freecad.org/Macro_Bevel",
    "raw_code_url": "https://gist.github.com/mwganson/25ee4dc925c8bcf1182bd9979025ed2d/raw/db5e9ecdba031bc743a9bd1e3a39e257ee523abc/Bevel.FCMacro",
    "wiki": "",
    "version": "0.2022.04.06b",
    "license": "",
    "date": "2022-04-06",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Bevel.svg",
    "icon_source": "https://wiki.freecad.org//images/a/a2/Bevel.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Center Align Objects with Faces or Edges",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro Aligns Objects through Faces or Edges constraints. These tools are now included in the <a rel=\"nofollow\" class=\"external text\" href=\"https://github.com/easyw/Manipulator\">Manipulator Workbench</a>. Install this workbench for the latest updates on these tools.<br /><br />Macro version: 1.5.3<br />Last modified: 2017-10-01<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/e/ee/Macro_Center_Align_Objects_with_Faces_or_Edges.svg\">ToolBar Icon</a><br /><a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/3/3d/Manipulator_Mover.svg\">Mover-icon</a><br /><a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/1/10/Manipulator_Caliper.svg\">Caliper-icon</a><br />Author: easyw-fc<br /> ",
    "comment": "This macro Aligns Objects through Faces or Edges constraints. These tools are now included in the Manipulator Workbench. Install this workbench for the latest updates on these tools.",
    "code": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#****************************************************************************\n#*                                                                          *\n#*  Copyright (c) 2017                                                      *\n#*  Maurice easyw@katamail.com                                              *\n#*                                                                          *\n#*   code partially based on:                                               *\n#*                                                                          *\n# evolution of Macro_CenterFace                                             *\n# some part of Macro WorkFeature                                            *\n# and assembly2                                                             *\n#                                                                           *\n# center objs faces/closed_edges to first obj face/closed_edge              *\n#                                                                           *\n#  (C) Maurice easyw-fc 2016                                                *\n#    This program is free software; you can redistribute it and/or modify   *\n#    it under the terms of the GNU Library General Public License (LGPL)    *\n#    as published by the Free Software Foundation; either version 2 of      *\n#    the License, or (at your option) any later version.                    *\n#    for detail see the LICENCE text file.                                  *\n#****************************************************************************\n\n\n__title__   = \"Center Faces of Parts\"\n__author__  = \"maurice\"\n__url__     = \"kicad stepup\"\n__version__ = \"1.5.3\" #undo alignment for App::Part hierarchical objects\n__date__    = \"10.2017\"\n\ntesting=False #true for showing helpers\ntesting2=False #true for showing helpers\n\n## todo\n#  better Gui with icons\n## done case: invert normal and standard when already aligned planes\n## done works for Bodys on FC 0.17\n##\n\n\n## import statements\n\nimport FreeCAD, FreeCADGui, Draft, Part, DraftTools, DraftVecUtils\nfrom FreeCAD import Base\nimport sys\nfrom PySide import QtCore, QtGui\n\n\n##--------------------------------------------------------------------------------------\n\ndef a_clear_console():\n    #clearing previous messages\n    mw=FreeCADGui.getMainWindow()\n    c=mw.findChild(QtGui.QPlainTextEdit, \"Python console\")\n    c.clear()\n    r=mw.findChild(QtGui.QTextEdit, \"Report view\")\n    r.clear()\n\n#if not Mod_ENABLED:\na_clear_console()\n\nfrom sys import platform as _platform\n\n# window GUI dimensions parameters\nif _platform == \"linux\" or _platform == \"linux2\":\n   # linux\n   pt_lnx=True\n   sizeXmin=110;sizeYmin=34+34\n   sizeX=342;sizeY=252-22+34 #516 #536\n   sizeXright=172;sizeYright=536 #556\nelse:\n    sizeXmin=110;sizeYmin=34\n    sizeX=342;sizeY=252-22 #482#502\n    sizeXright=172;sizeYright=502#522\nif _platform == \"darwin\":\n    pt_osx=True\n##   # MAC OS X\n##elif _platform == \"win32\":\n##   # Windows\n#sizeXmin=172;sizeYmin=30+34\nsizeXMax=487 #487\nbtn_sizeX=32;btn_sizeY=32;\nchkb_sizeX=20;chkb_sizeY=20;\nbtn_sm_sizeX=20;btn_sm_sizeY=20;\nbtn_md_sizeX=26;btn_md_sizeY=26;\n\ndef close_aligner():\n    #def closeEvent(self, e):\n    ALGDockWidget.close()\n    #self.setWindowState(QtCore.Qt.WindowActive)\n    doc=FreeCAD.ActiveDocument\n    if doc is not None:\n        FreeCAD.setActiveDocument(doc.Name)\n    #FreeCAD.ActiveDocument=FreeCAD.getDocument(doc.Label)\n    #FreeCADGui.ActiveDocument=FreeCADGui.getDocument(doc.Label)\n\ndef Alg_undock():\n    ALGDockWidget.setFloating(True)  #undock\n    ALGDockWidget.resize(sizeX,sizeY)\n    ALGDockWidget.activateWindow()\n    ALGDockWidget.raise_()\n    #AlgWidget.resize(QtCore.QSize(300,100).expandedTo(AlgWidget.maximumSize())) # sets size of the widget\n    #AlgWidget.setFloating(False)  #dock\n    #say (\"now!\")\n\ndef Alg_minimz():\n    #clear_console()\n    ALGDockWidget.setFloating(True)  #undock\n    # AlgWidget.hide();\n    # AlgWidget.setWindowState(QtCore.Qt.WindowMinimized)\n    #AlgWidget.resize(500, 500)\n    ALGDockWidget.resize(sizeXmin,sizeYmin)\n    ALGDockWidget.activateWindow()\n    ALGDockWidget.raise_()\n\n\n####################################\n# embedded button images\nimport base64\n# \"b64_data\" is a variable containing your base64 encoded jpeg\n\ncloseW_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0IgogICBoZWlnaHQ9IjY0IgogICBpZD0ic3ZnMiIKICAgdmVyc2lvbj0iMS4xIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ4LjUgcjEwMDQwIgogICBzb2RpcG9kaTpkb2NuYW1lPSJlZGl0X0NhbmNlbC5zdmciCiAgIHZpZXdCb3g9IjAgMCA2NCA2NCI+CiAgPGRlZnMKICAgICBpZD0iZGVmczQiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODc5IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODgxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg4MyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWYyOTI5O3N0b3Atb3BhY2l0eToxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg2OSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODcxIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWYyOTI5O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg3MyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4NjkiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODc1IgogICAgICAgeDE9Ii00NSIKICAgICAgIHkxPSIxMDQ0LjM2MjIiCiAgICAgICB4Mj0iLTU1IgogICAgICAgeTI9Ijk5NC4zNjIxOCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjg2NjQ3NzI3LDAsMCwwLjg2NjQ3NzM5LDczLjY1MzQwOSwxMzYuMzAzOTEpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODc5IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg3NyIKICAgICAgIHgxPSItNDUiCiAgICAgICB5MT0iMTA0NC4zNjIyIgogICAgICAgeDI9Ii01NSIKICAgICAgIHkyPSI5OTQuMzYyMTgiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44NjY0NzcyNywwLDAsMC44NjY0NzczOSw3My42NTM0MDksMTM2LjMwMzkxKSIgLz4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjYuNTU3NzM4IgogICAgIGlua3NjYXBlOmN4PSI1MC4yNzE5NTgiCiAgICAgaW5rc2NhcGU6Y3k9IjMyLjkwMDkyNCIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTU5OCIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI4MzYiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjAiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjI3IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjAiCiAgICAgaW5rc2NhcGU6c25hcC1nbG9iYWw9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOnNuYXAtbm9kZXM9InRydWUiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMTE1MjEiCiAgICAgICBlbXBzcGFjaW5nPSIyIgogICAgICAgZG90dGVkPSJmYWxzZSIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTciPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciIKICAgICBpZD0ibGF5ZXIxIgogICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTk4OC4zNjIxOCkiPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMyODAwMDA7c3Ryb2tlLXdpZHRoOjE2O3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gMTMsMTAwMS4zNjIyIDM4LjEyNSwzOC4xMjUiCiAgICAgICBpZD0icGF0aDMwMDIiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMjgwMDAwO3N0cm9rZS13aWR0aDoxNjtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJNIDUxLjEyNSwxMDAxLjM2MjIgMTMsMTAzOS40ODcyIgogICAgICAgaWQ9InBhdGgzMDAyLTYiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZWYyOTI5O3N0cm9rZS13aWR0aDoxMjtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICBkPSJtIDEzLDEwMDEuMzYyMiAzOC4xMjUsMzguMTI1IgogICAgICAgaWQ9InBhdGgzMDAyLTciCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZWYyOTI5O3N0cm9rZS13aWR0aDoxMjtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICBkPSJNIDUxLjEyNSwxMDAxLjM2MjIgMTMsMTAzOS40ODcyIgogICAgICAgaWQ9InBhdGgzMDAyLTYtNSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOnVybCgjbGluZWFyR3JhZGllbnQzODc3KTtzdHJva2Utd2lkdGg6ODtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICBkPSJtIDEzLDEwMDEuMzYyMiAzOC4xMjUsMzguMTI1IgogICAgICAgaWQ9InBhdGgzMDAyLTctNiIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOnVybCgjbGluZWFyR3JhZGllbnQzODc1KTtzdHJva2Utd2lkdGg6ODtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICBkPSJNIDUxLjEyNSwxMDAxLjM2MjIgMTMsMTAzOS40ODcyIgogICAgICAgaWQ9InBhdGgzMDAyLTYtNS0yIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgPC9nPgo8L3N2Zz4K\n\"\"\"\nun_dock_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpvc2I9Imh0dHA6Ly93d3cub3BlbnN3YXRjaGJvb2sub3JnL3VyaS8yMDA5L29zYiIKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIHZlcnNpb249IjEuMCIKICAgeD0iMC4wMDAwMDAwIgogICB5PSIwLjAwMDAwMDAiCiAgIHdpZHRoPSI2NCIKICAgaGVpZ2h0PSI2NCIKICAgaWQ9InN2ZzExMzAwIgogICBzb2RpcG9kaTp2ZXJzaW9uPSIwLjMyIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ4LjQgcjk5MzkiCiAgIHNvZGlwb2RpOmRvY25hbWU9InVuLWRvY2suc3ZnIj4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGE2NiI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGUgLz4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5Db3JleSBXb29kd29ydGg8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICAgIDxjYzpsaWNlbnNlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS8yLjAvIiAvPgogICAgICAgIDxkYzpzb3VyY2U+aHR0cDovL2ppbW1hYy5tdXNpY2hhbGwuY3o8L2RjOnNvdXJjZT4KICAgICAgICA8ZGM6Y3JlYXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkpha3ViIFN0ZWluZXI8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNyZWF0b3I+CiAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICA8cmRmOkJhZz4KICAgICAgICAgICAgPHJkZjpsaT5uZXc8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5pbnNlcnQ8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT53aW5kb3c8L3JkZjpsaT4KICAgICAgICAgIDwvcmRmOkJhZz4KICAgICAgICA8L2RjOnN1YmplY3Q+CiAgICAgIDwvY2M6V29yaz4KICAgICAgPGNjOkxpY2Vuc2UKICAgICAgICAgcmRmOmFib3V0PSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS8yLjAvIj4KICAgICAgICA8Y2M6cGVybWl0cwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3dlYi5yZXNvdXJjZS5vcmcvY2MvUmVwcm9kdWN0aW9uIiAvPgogICAgICAgIDxjYzpwZXJtaXRzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9EaXN0cmlidXRpb24iIC8+CiAgICAgICAgPGNjOnJlcXVpcmVzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9Ob3RpY2UiIC8+CiAgICAgICAgPGNjOnJlcXVpcmVzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9BdHRyaWJ1dGlvbiIgLz4KICAgICAgICA8Y2M6cGVybWl0cwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3dlYi5yZXNvdXJjZS5vcmcvY2MvRGVyaXZhdGl2ZVdvcmtzIiAvPgogICAgICAgIDxjYzpyZXF1aXJlcwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3dlYi5yZXNvdXJjZS5vcmcvY2MvU2hhcmVBbGlrZSIgLz4KICAgICAgPC9jYzpMaWNlbnNlPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjEiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIyNTYwIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGlkPSJiYXNlIgogICAgIGlua3NjYXBlOnpvb209IjUuNjU2ODU0MiIKICAgICBpbmtzY2FwZTpjeD0iLTIuMzI3NTAwNSIKICAgICBpbmtzY2FwZTpjeT0iMTkuMzY5NDQxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOSIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTkiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMTEzMDAiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOnNuYXAtbm9kZXM9ImZhbHNlIgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMzAxNiIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8ZGVmcwogICAgIGlkPSJkZWZzMyI+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQ2MzMiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzMzMzMzO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDQ2MjkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMzMzMzMzM7c3RvcC1vcGFjaXR5OjA7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNDYzMSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MzIiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDQ2MjQiCiAgICAgICAgIG9mZnNldD0iMC4wMDAwMDAwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZmZmO3N0b3Atb3BhY2l0eToxIiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDQ2MjYiCiAgICAgICAgIG9mZnNldD0iMS4wMDAwMDAwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZDNkN2NmO3N0b3Atb3BhY2l0eToxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTA2MCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDUwMzEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTIuNzc0Mzg5LDAsMCwxLjk2OTcwNiwxMTIuNzYyMywtODcyLjg4NTQpIgogICAgICAgY3g9IjYwNS43MTQyOSIKICAgICAgIGN5PSI0ODYuNjQ3ODkiCiAgICAgICBmeD0iNjA1LjcxNDI5IgogICAgICAgZnk9IjQ4Ni42NDc4OSIKICAgICAgIHI9IjExNy4xNDI4NiIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NTA2MCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOmJsYWNrO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDUwNjIiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOmJsYWNrO3N0b3Atb3BhY2l0eTowOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDUwNjQiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ1MDYwIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50NTAyOSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjc3NDM4OSwwLDAsMS45Njk3MDYsLTE4OTEuNjMzLC04NzIuODg1NCkiCiAgICAgICBjeD0iNjA1LjcxNDI5IgogICAgICAgY3k9IjQ4Ni42NDc4OSIKICAgICAgIGZ4PSI2MDUuNzE0MjkiCiAgICAgICBmeT0iNDg2LjY0Nzg5IgogICAgICAgcj0iMTE3LjE0Mjg2IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MDQ4Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6YmxhY2s7c3RvcC1vcGFjaXR5OjA7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTA1MCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3A1MDU2IgogICAgICAgICBvZmZzZXQ9IjAuNSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6YmxhY2s7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjpibGFjaztzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3A1MDUyIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTA0OCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUwMjciCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi43NzQzODksMCwwLDEuOTY5NzA2LC0xODkyLjE3OSwtODcyLjg4NTQpIgogICAgICAgeDE9IjMwMi44NTcxNSIKICAgICAgIHkxPSIzNjYuNjQ3ODkiCiAgICAgICB4Mj0iMzAyLjg1NzE1IgogICAgICAgeTI9IjYwOS41MDUwNyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MTI1MTIiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZmZmO3N0b3Atb3BhY2l0eToxLjAwMDAwMDAiCiAgICAgICAgIG9mZnNldD0iMC4wMDAwMDAwIgogICAgICAgICBpZD0ic3RvcDEyNTEzIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmNTIwO3N0b3Atb3BhY2l0eTowLjg5MTA4OTA4IgogICAgICAgICBvZmZzZXQ9IjAuNTAwMDAwMDAiCiAgICAgICAgIGlkPSJzdG9wMTI1MTciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmYzMDA7c3RvcC1vcGFjaXR5OjAuMDAwMDAwMCIKICAgICAgICAgb2Zmc2V0PSIxLjAwMDAwMDAiCiAgICAgICAgIGlkPSJzdG9wMTI1MTQiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0ODE2Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM0NjVhNDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwLjAwMDAwMDAiCiAgICAgICAgIGlkPSJzdG9wNDgxOCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxLjAwMDAwMDAiCiAgICAgICAgIGlkPSJzdG9wNDgyMCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQ4MDgiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAwMDAwO3N0b3Atb3BhY2l0eToxLjAwMDAwMDAiCiAgICAgICAgIG9mZnNldD0iMC4wMDAwMDAwIgogICAgICAgICBpZD0ic3RvcDQ4MTAiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjAuMDAwMDAwMCIKICAgICAgICAgb2Zmc2V0PSIxLjAwMDAwMDAiCiAgICAgICAgIGlkPSJzdG9wNDgxMiIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MzItNSIKICAgICAgIG9zYjpwYWludD0iZ3JhZGllbnQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZmZmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAuMDAwMDAwMCIKICAgICAgICAgaWQ9InN0b3AzODM0IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZDNkN2NmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEuMDAwMDAwMCIKICAgICAgICAgaWQ9InN0b3AzODM2IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDgwOCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDEzNzIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS45NDU3MzQsMCwwLDAuNjI3Mjc0LC05LjYyODQ1NSwyNC4yNTkyMSkiCiAgICAgICBjeD0iMTcuMzY4MzExIgogICAgICAgY3k9IjI1LjY4MTk0MiIKICAgICAgIGZ4PSIxNy4zNjgzMTEiCiAgICAgICBmeT0iMjUuNjgxOTQyIgogICAgICAgcj0iMTEuNzk5ODQ1IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODMyLTUiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyMjY3IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDMuMjUzOTM1LDAsMCwzLjI5NTQ1MTcsLTE2LjM2NDA3NCwtMjQuNTQ2OTQzKSIKICAgICAgIHgxPSIxMy44MTczOTkiCiAgICAgICB5MT0iOC42NjQ3ODI1IgogICAgICAgeDI9IjE3Ljg4MDY4IgogICAgICAgeTI9IjIxLjc2NzU3OCIgLz4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTA2MCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDUwMjktOCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjc3NDM4OSwwLDAsMS45Njk3MDYsLTE4OTEuNjMzLC04NzIuODg1NCkiCiAgICAgICBjeD0iNjA1LjcxNDI5IgogICAgICAgY3k9IjQ4Ni42NDc4OSIKICAgICAgIGZ4PSI2MDUuNzE0MjkiCiAgICAgICBmeT0iNDg2LjY0Nzg5IgogICAgICAgcj0iMTE3LjE0Mjg2IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ1MDYwIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50NTAzMS0yIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0yLjc3NDM4OSwwLDAsMS45Njk3MDYsMTEyLjc2MjMsLTg3Mi44ODU0KSIKICAgICAgIGN4PSI2MDUuNzE0MjkiCiAgICAgICBjeT0iNDg2LjY0Nzg5IgogICAgICAgZng9IjYwNS43MTQyOSIKICAgICAgIGZ5PSI0ODYuNjQ3ODkiCiAgICAgICByPSIxMTcuMTQyODYiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDUwNDgiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQxMTIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi43NzQzODksMCwwLDEuOTY5NzA2LC0xODkyLjE3OSwtODcyLjg4NTQpIgogICAgICAgeDE9IjMwMi44NTcxNSIKICAgICAgIHkxPSIzNjYuNjQ3ODkiCiAgICAgICB4Mj0iMzAyLjg1NzE1IgogICAgICAgeTI9IjYwOS41MDUwNyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDYzMyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQ2MzUiCiAgICAgICB4MT0iNTguNDQ2OTY4IgogICAgICAgeTE9IjU4Ljc3NjU0NiIKICAgICAgIHgyPSIzMy43NTQ1NTkiCiAgICAgICB5Mj0iMTIuNDYxMDUxIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDUwNDgiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQ5IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNzc0Mzg5LDAsMCwxLjk2OTcwNiwtMTg5Mi4xNzksLTg3Mi44ODU0KSIKICAgICAgIHgxPSIzMDIuODU3MTUiCiAgICAgICB5MT0iMzY2LjY0Nzg5IgogICAgICAgeDI9IjMwMi44NTcxNSIKICAgICAgIHkyPSI2MDkuNTA1MDciIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDUwNjAiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzMDUxIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNzc0Mzg5LDAsMCwxLjk2OTcwNiwtMTg5MS42MzMsLTg3Mi44ODU0KSIKICAgICAgIGN4PSI2MDUuNzE0MjkiCiAgICAgICBjeT0iNDg2LjY0Nzg5IgogICAgICAgZng9IjYwNS43MTQyOSIKICAgICAgIGZ5PSI0ODYuNjQ3ODkiCiAgICAgICByPSIxMTcuMTQyODYiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDUwNjAiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzMDUzIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0yLjc3NDM4OSwwLDAsMS45Njk3MDYsMTEyLjc2MjMsLTg3Mi44ODU0KSIKICAgICAgIGN4PSI2MDUuNzE0MjkiCiAgICAgICBjeT0iNDg2LjY0Nzg5IgogICAgICAgZng9IjYwNS43MTQyOSIKICAgICAgIGZ5PSI0ODYuNjQ3ODkiCiAgICAgICByPSIxMTcuMTQyODYiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4MzItNSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNTUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMy4yNTM5MzUsMCwwLDMuMjk1NDUxNywtMTYuMzY0MDc0LC0yNC41NDY5NDMpIgogICAgICAgeDE9IjEzLjgxNzM5OSIKICAgICAgIHkxPSI4LjY2NDc4MjUiCiAgICAgICB4Mj0iMTcuODgwNjgiCiAgICAgICB5Mj0iMjEuNzY3NTc4IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ1MDQ4IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA1NyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjc3NDM4OSwwLDAsMS45Njk3MDYsLTE4OTIuMTc5LC04NzIuODg1NCkiCiAgICAgICB4MT0iMzAyLjg1NzE1IgogICAgICAgeTE9IjM2Ni42NDc4OSIKICAgICAgIHgyPSIzMDIuODU3MTUiCiAgICAgICB5Mj0iNjA5LjUwNTA3IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ1MDYwIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzA1OSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjc3NDM4OSwwLDAsMS45Njk3MDYsLTE4OTEuNjMzLC04NzIuODg1NCkiCiAgICAgICBjeD0iNjA1LjcxNDI5IgogICAgICAgY3k9IjQ4Ni42NDc4OSIKICAgICAgIGZ4PSI2MDUuNzE0MjkiCiAgICAgICBmeT0iNDg2LjY0Nzg5IgogICAgICAgcj0iMTE3LjE0Mjg2IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ1MDYwIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzA2MSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMi43NzQzODksMCwwLDEuOTY5NzA2LDExMi43NjIzLC04NzIuODg1NCkiCiAgICAgICBjeD0iNjA1LjcxNDI5IgogICAgICAgY3k9IjQ4Ni42NDc4OSIKICAgICAgIGZ4PSI2MDUuNzE0MjkiCiAgICAgICBmeT0iNDg2LjY0Nzg5IgogICAgICAgcj0iMTE3LjE0Mjg2IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ0NjMzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA2MyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjU4LjQ0Njk2OCIKICAgICAgIHkxPSI1OC43NzY1NDYiCiAgICAgICB4Mj0iMzMuNzU0NTU5IgogICAgICAgeTI9IjEyLjQ2MTA1MSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTA0OCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwODMiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi43NzQzODksMCwwLDEuOTY5NzA2LC0xODkyLjE3OSwtODcyLjg4NTQpIgogICAgICAgeDE9IjMwMi44NTcxNSIKICAgICAgIHkxPSIzNjYuNjQ3ODkiCiAgICAgICB4Mj0iMzAyLjg1NzE1IgogICAgICAgeTI9IjYwOS41MDUwNyIgLz4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTA2MCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMwODUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi43NzQzODksMCwwLDEuOTY5NzA2LC0xODkxLjYzMywtODcyLjg4NTQpIgogICAgICAgY3g9IjYwNS43MTQyOSIKICAgICAgIGN5PSI0ODYuNjQ3ODkiCiAgICAgICBmeD0iNjA1LjcxNDI5IgogICAgICAgZnk9IjQ4Ni42NDc4OSIKICAgICAgIHI9IjExNy4xNDI4NiIgLz4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTA2MCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMwODciCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTIuNzc0Mzg5LDAsMCwxLjk2OTcwNiwxMTIuNzYyMywtODcyLjg4NTQpIgogICAgICAgY3g9IjYwNS43MTQyOSIKICAgICAgIGN5PSI0ODYuNjQ3ODkiCiAgICAgICBmeD0iNjA1LjcxNDI5IgogICAgICAgZnk9IjQ4Ni42NDc4OSIKICAgICAgIHI9IjExNy4xNDI4NiIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDYzMyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwODkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSI1OC40NDY5NjgiCiAgICAgICB5MT0iNTguNzc2NTQ2IgogICAgICAgeDI9IjMzLjc1NDU1OSIKICAgICAgIHkyPSIxMi40NjEwNTEiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDUwNDgiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDkxIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNzc0Mzg5LDAsMCwxLjk2OTcwNiwtMTg5Mi4xNzksLTg3Mi44ODU0KSIKICAgICAgIHgxPSIzMDIuODU3MTUiCiAgICAgICB5MT0iMzY2LjY0Nzg5IgogICAgICAgeDI9IjMwMi44NTcxNSIKICAgICAgIHkyPSI2MDkuNTA1MDciIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDUwNjAiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzMDkzIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNzc0Mzg5LDAsMCwxLjk2OTcwNiwtMTg5MS42MzMsLTg3Mi44ODU0KSIKICAgICAgIGN4PSI2MDUuNzE0MjkiCiAgICAgICBjeT0iNDg2LjY0Nzg5IgogICAgICAgZng9IjYwNS43MTQyOSIKICAgICAgIGZ5PSI0ODYuNjQ3ODkiCiAgICAgICByPSIxMTcuMTQyODYiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDUwNjAiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzMDk1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0yLjc3NDM4OSwwLDAsMS45Njk3MDYsMTEyLjc2MjMsLTg3Mi44ODU0KSIKICAgICAgIGN4PSI2MDUuNzE0MjkiCiAgICAgICBjeT0iNDg2LjY0Nzg5IgogICAgICAgZng9IjYwNS43MTQyOSIKICAgICAgIGZ5PSI0ODYuNjQ3ODkiCiAgICAgICByPSIxMTcuMTQyODYiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4MzItNSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwOTciCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMy4yNTM5MzUsMCwwLDMuMjk1NDUxNywtMTYuMzY0MDc0LC0yNC41NDY5NDMpIgogICAgICAgeDE9IjEzLjgxNzM5OSIKICAgICAgIHkxPSI4LjY2NDc4MjUiCiAgICAgICB4Mj0iMTcuODgwNjgiCiAgICAgICB5Mj0iMjEuNzY3NTc4IiAvPgogIDwvZGVmcz4KICA8ZwogICAgIGlkPSJnMzA2NSIKICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMS4wMjA0MzMzLC0xLjgwNzcwODgpIj4KICAgIDxnCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjg1NzM3NSwwLDAsMC44NTczNzUsNi41OTQ2MDc4LDYuNjgwMDQxMikiCiAgICAgICBpZD0iZzMwNDAiPgogICAgICA8ZwogICAgICAgICBpZD0iZzQ2NDMiPgogICAgICAgIDxnCiAgICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4wMjg0NDcxMiwwLDAsMC4wMTg4NjY2NSw2MS44NTY3MDYsNTkuMjAwODI2KSIKICAgICAgICAgICBpZD0iZzUwMjItMiIKICAgICAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmUiPgogICAgICAgICAgPHJlY3QKICAgICAgICAgICAgIHN0eWxlPSJvcGFjaXR5OjAuNDAyMDYxODU7Y29sb3I6IzAwMDAwMDtmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzMDgzKTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MTttYXJrZXI6bm9uZTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgICAgICAgIGlkPSJyZWN0NDE3My0xIgogICAgICAgICAgICAgd2lkdGg9IjEzMzkuNjMzNSIKICAgICAgICAgICAgIGhlaWdodD0iNDc4LjM1NzE4IgogICAgICAgICAgICAgeD0iLTE1NTkuMjUyMyIKICAgICAgICAgICAgIHk9Ii0xNTAuNjk2ODUiIC8+CiAgICAgICAgICA8cGF0aAogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIHN0eWxlPSJvcGFjaXR5OjAuNDAyMDYxODU7Y29sb3I6IzAwMDAwMDtmaWxsOnVybCgjcmFkaWFsR3JhZGllbnQzMDg1KTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MTttYXJrZXI6bm9uZTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgICAgICAgIGQ9Im0gLTIxOS42MTg3NiwtMTUwLjY4MDM4IGMgMCwwIDAsNDc4LjMzMDc5IDAsNDc4LjMzMDc5IDE0Mi44NzQxNjYsMC45MDA0NSAzNDUuNDAwMjIsLTEwNy4xNjk2NiAzNDUuNDAwMTQsLTIzOS4xOTYxNzUgMCwtMTMyLjAyNjUzNyAtMTU5LjQzNjgxNiwtMjM5LjEzNDU5NSAtMzQ1LjQwMDE0LC0yMzkuMTM0NjE1IHoiCiAgICAgICAgICAgICBpZD0icGF0aDUwNTgtMCIKICAgICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjYyIgLz4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjIgogICAgICAgICAgICAgaWQ9InBhdGg1MDE4LTUiCiAgICAgICAgICAgICBkPSJtIC0xNTU5LjI1MjMsLTE1MC42ODAzOCBjIDAsMCAwLDQ3OC4zMzA3OSAwLDQ3OC4zMzA3OSAtMTQyLjg3NDIsMC45MDA0NSAtMzQ1LjQwMDIsLTEwNy4xNjk2NiAtMzQ1LjQwMDIsLTIzOS4xOTYxNzUgMCwtMTMyLjAyNjUzNyAxNTkuNDM2OCwtMjM5LjEzNDU5NSAzNDUuNDAwMiwtMjM5LjEzNDYxNSB6IgogICAgICAgICAgICAgc3R5bGU9Im9wYWNpdHk6MC40MDIwNjE4NTtjb2xvcjojMDAwMDAwO2ZpbGw6dXJsKCNyYWRpYWxHcmFkaWVudDMwODcpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxO21hcmtlcjpub25lO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlIiAvPgogICAgICAgIDwvZz4KICAgICAgICA8cmVjdAogICAgICAgICAgIGlkPSJyZWN0MzgxOC04IgogICAgICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2ZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDMwODkpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojOGQ4ZDhkO3N0cm9rZS13aWR0aDoxLjgwNDk5OTk1O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDttYXJrZXI6bm9uZTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgICAgICB5PSIxMC4zMzAxOCIKICAgICAgICAgICB4PSIxMC4zODIzMjEiCiAgICAgICAgICAgcnk9IjEuNDExOTg0OSIKICAgICAgICAgICByeD0iMS4yODY1ODAzIgogICAgICAgICAgIGhlaWdodD0iNTIuMzQ1MDAxIgogICAgICAgICAgIHdpZHRoPSI1Mi4zNDUwMDEiIC8+CiAgICAgICAgPHJlY3QKICAgICAgICAgICBpZD0icmVjdDQ5NjItNyIKICAgICAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtmaWxsOm5vbmU7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjEuODA0OTk5OTU7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO21hcmtlcjpub25lO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgICAgIHk9IjEyLjEzNTE4IgogICAgICAgICAgIHg9IjEyLjE4NzMyMiIKICAgICAgICAgICByeT0iMCIKICAgICAgICAgICByeD0iMCIKICAgICAgICAgICBoZWlnaHQ9IjQ4LjczNTAwMSIKICAgICAgICAgICB3aWR0aD0iNDguNzM1MDAxIiAvPgogICAgICA8L2c+CiAgICA8L2c+CiAgICA8ZwogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC44NTczNzUsMCwwLDAuODU3Mzc1LDQuMDA4NDg0OSw0LjExNjg4NjQpIgogICAgICAgaWQ9ImczMDMxIj4KICAgICAgPGcKICAgICAgICAgaWQ9ImcxNDYiCiAgICAgICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuNCwwKSI+CiAgICAgICAgPGcKICAgICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjAyODQ0NzEyLDAsMCwwLjAxODg2NjY1LDUzLjAwNjk0NSw1MC42NjA3NTcpIgogICAgICAgICAgIGlkPSJnNTAyMiIKICAgICAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmUiPgogICAgICAgICAgPHJlY3QKICAgICAgICAgICAgIHN0eWxlPSJvcGFjaXR5OjAuNDAyMDYxODU7Y29sb3I6IzAwMDAwMDtmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzMDkxKTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MTttYXJrZXI6bm9uZTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgICAgICAgIGlkPSJyZWN0NDE3MyIKICAgICAgICAgICAgIHdpZHRoPSIxMzM5LjYzMzUiCiAgICAgICAgICAgICBoZWlnaHQ9IjQ3OC4zNTcxOCIKICAgICAgICAgICAgIHg9Ii0xNTU5LjI1MjMiCiAgICAgICAgICAgICB5PSItMTUwLjY5Njg1IiAvPgogICAgICAgICAgPHBhdGgKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBzdHlsZT0ib3BhY2l0eTowLjQwMjA2MTg1O2NvbG9yOiMwMDAwMDA7ZmlsbDp1cmwoI3JhZGlhbEdyYWRpZW50MzA5Myk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjE7bWFya2VyOm5vbmU7dmlzaWJpbGl0eTp2aXNpYmxlO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGUiCiAgICAgICAgICAgICBkPSJtIC0yMTkuNjE4NzYsLTE1MC42ODAzOCBjIDAsMCAwLDQ3OC4zMzA3OSAwLDQ3OC4zMzA3OSAxNDIuODc0MTY2LDAuOTAwNDUgMzQ1LjQwMDIyLC0xMDcuMTY5NjYgMzQ1LjQwMDE0LC0yMzkuMTk2MTc1IDAsLTEzMi4wMjY1MzcgLTE1OS40MzY4MTYsLTIzOS4xMzQ1OTUgLTM0NS40MDAxNCwtMjM5LjEzNDYxNSB6IgogICAgICAgICAgICAgaWQ9InBhdGg1MDU4IgogICAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjIiAvPgogICAgICAgICAgPHBhdGgKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2MiCiAgICAgICAgICAgICBpZD0icGF0aDUwMTgiCiAgICAgICAgICAgICBkPSJtIC0xNTU5LjI1MjMsLTE1MC42ODAzOCBjIDAsMCAwLDQ3OC4zMzA3OSAwLDQ3OC4zMzA3OSAtMTQyLjg3NDIsMC45MDA0NSAtMzQ1LjQwMDIsLTEwNy4xNjk2NiAtMzQ1LjQwMDIsLTIzOS4xOTYxNzUgMCwtMTMyLjAyNjUzNyAxNTkuNDM2OCwtMjM5LjEzNDU5NSAzNDUuNDAwMiwtMjM5LjEzNDYxNSB6IgogICAgICAgICAgICAgc3R5bGU9Im9wYWNpdHk6MC40MDIwNjE4NTtjb2xvcjojMDAwMDAwO2ZpbGw6dXJsKCNyYWRpYWxHcmFkaWVudDMwOTUpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxO21hcmtlcjpub25lO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlIiAvPgogICAgICAgIDwvZz4KICAgICAgICA8cmVjdAogICAgICAgICAgIGlkPSJyZWN0MzgxOCIKICAgICAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzMDk3KTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzhkOGQ4ZDtzdHJva2Utd2lkdGg6MS44MDQ5OTk5NTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7bWFya2VyOm5vbmU7dmlzaWJpbGl0eTp2aXNpYmxlO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGUiCiAgICAgICAgICAgeT0iMS43OTAxMTE0IgogICAgICAgICAgIHg9IjEuNTMyNTYzMSIKICAgICAgICAgICByeT0iMS40MTE5ODQ5IgogICAgICAgICAgIHJ4PSIxLjI4NjU4MDMiCiAgICAgICAgICAgaGVpZ2h0PSI1Mi4zNDUwMDEiCiAgICAgICAgICAgd2lkdGg9IjUyLjM0NTAwMSIgLz4KICAgICAgICA8cmVjdAogICAgICAgICAgIGlkPSJyZWN0NDk2MiIKICAgICAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtmaWxsOm5vbmU7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjEuODA0OTk5OTU7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO21hcmtlcjpub25lO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgICAgIHk9IjMuNTk1MTExNCIKICAgICAgICAgICB4PSIzLjMzNzU2MyIKICAgICAgICAgICByeT0iMCIKICAgICAgICAgICByeD0iMCIKICAgICAgICAgICBoZWlnaHQ9IjQ4LjczNTAwMSIKICAgICAgICAgICB3aWR0aD0iNDguNzM1MDAxIiAvPgogICAgICA8L2c+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K\n\"\"\"\nminimize_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB3aWR0aD0iNjRweCIKICAgaGVpZ2h0PSI2NHB4IgogICBpZD0ic3ZnMjk4NSIKICAgdmVyc2lvbj0iMS4xIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ4LjQgcjk5MzkiCiAgIHNvZGlwb2RpOmRvY25hbWU9Im1pbmltaXplLnN2ZyI+CiAgPGRlZnMKICAgICBpZD0iZGVmczI5ODciIC8+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjUuMDk2ODMxMiIKICAgICBpbmtzY2FwZTpjeD0iLTU5Ljk3Mjg4NSIKICAgICBpbmtzY2FwZTpjeT0iMTYuMTkzNDEzIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIKICAgICBzaG93Z3JpZD0idHJ1ZSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMjU2MCIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMzYxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOSIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTkiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIKICAgICBpbmtzY2FwZTpzbmFwLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1ub2Rlcz0iZmFsc2UiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMjk4NyIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEyOTkwIj4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzp0aXRsZSAvPgogICAgICAgIDxkYzpjcmVhdG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W3lvcmlrdmFuaGF2cmVdPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjcmVhdG9yPgogICAgICAgIDxkYzp0aXRsZT5BcmNoX1NlY3Rpb25QbGFuZV9UcmVlPC9kYzp0aXRsZT4KICAgICAgICA8ZGM6ZGF0ZT4yMDExLTEyLTA2PC9kYzpkYXRlPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL0FyY2gvUmVzb3VyY2VzL2ljb25zL0FyY2hfU2VjdGlvblBsYW5lX1RyZWUuc3ZnPC9kYzppZGVudGlmaWVyPgogICAgICAgIDxkYzpyaWdodHM+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEIExHUEwyKzwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cmlnaHRzPgogICAgICAgIDxjYzpsaWNlbnNlPmh0dHBzOi8vd3d3LmdudS5vcmcvY29weWxlZnQvbGVzc2VyLmh0bWw8L2NjOmxpY2Vuc2U+CiAgICAgICAgPGRjOmNvbnRyaWJ1dG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W2Fncnlzb25dIEFsZXhhbmRlciBHcnlzb248L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciI+CiAgICA8cGF0aAogICAgICAgc29kaXBvZGk6dHlwZT0ic3RhciIKICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2ZpbGw6Izk5OTk5OTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6IzRkNGQ0ZDtzdHJva2Utd2lkdGg6MS41NzQ4ODIyNztzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7bWFya2VyOm5vbmU7dmlzaWJpbGl0eTp2aXNpYmxlO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIKICAgICAgIGlkPSJwYXRoMjk5NyIKICAgICAgIHNvZGlwb2RpOnNpZGVzPSIzIgogICAgICAgc29kaXBvZGk6Y3g9IjIyIgogICAgICAgc29kaXBvZGk6Y3k9IjE3LjA5MDkwOCIKICAgICAgIHNvZGlwb2RpOnIxPSIyMC40MzI1MTIiCiAgICAgICBzb2RpcG9kaTpyMj0iMTAuMjE2MjU3IgogICAgICAgc29kaXBvZGk6YXJnMT0iMi4wOTQzOTUxIgogICAgICAgc29kaXBvZGk6YXJnMj0iMy4xNDE1OTI3IgogICAgICAgaW5rc2NhcGU6ZmxhdHNpZGVkPSJ0cnVlIgogICAgICAgaW5rc2NhcGU6cm91bmRlZD0iMCIKICAgICAgIGlua3NjYXBlOnJhbmRvbWl6ZWQ9IjAiCiAgICAgICBkPSJtIDExLjc4Mzc0NCwzNC43ODU5ODMgMCwtMzUuMzkwMTQ5NjMgMzAuNjQ4NzY4LDE3LjY5NTA3NDYzIHoiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLDAuNTk3OTI3MDMsMS4xNDcyNDA3LDAsMTIuMzkyNjE0LDIxLjYwNjM2NCkiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9IjMuMDU0Mjg1NyIgLz4KICA8L2c+Cjwvc3ZnPgo=\n\"\"\"\nBbox_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI4NjAiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9IkJCb3guc3ZnIgogICBpbmtzY2FwZTpvdXRwdXRfZXh0ZW5zaW9uPSJvcmcuaW5rc2NhcGUub3V0cHV0LnN2Zy5pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzMjg2MiI+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQxNDciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZDNkN2NmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNDE0OSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDQxNTEiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MTIxIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6Izg4OGE4NTtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDQxMjMiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNiYWJkYjY7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3A0MTI1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzM3NyI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzM3OSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmFmZjJiO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzMzgxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmFhMDA7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUyODY4IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMzc3LTEiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzMDk1LTYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS4wMzUyNzg1LDAuMjM5MTEwMDgsLTAuNDkxMjE5OTMsMi4xMjY4NDI0LC04My4wMjA1NjYsLTIxMC4xOTU5NSkiCiAgICAgICBjeD0iMTM1LjM4MzMzIgogICAgICAgY3k9Ijk3LjM2OTU2OCIKICAgICAgIGZ4PSIxMzUuMzgzMzMiCiAgICAgICBmeT0iOTcuMzY5NTY4IgogICAgICAgcj0iMTkuNDY3NDM2IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzc3LTEiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDMzNzktMSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmFmZjJiO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzMzgxLTAiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmYWEwMDtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMTQ0IgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50NDEwOCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwwLjY5ODUyOTQsMCwyMDIuODI4NjMpIgogICAgICAgY3g9IjIyNS4yNjQwMiIKICAgICAgIGN5PSI2NzIuNzk3MzYiCiAgICAgICBmeD0iMjI1LjI2NDAyIgogICAgICAgZnk9IjY3Mi43OTczNiIKICAgICAgIHI9IjM0LjM0NTE4OCIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzE0NCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzE0NiIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMTQ4IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzk2MCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwNDEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSIzNy43NTgxNzEiCiAgICAgICB5MT0iNTcuMzAxMzI3IgogICAgICAgeDI9IjIxLjg2MDQ2MiIKICAgICAgIHkyPSIyMi42MTU0MTIiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM5NjAiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYmFiZGI2O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzk2MiIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM5NjQiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGZpbHRlcgogICAgICAgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImZpbHRlcjM5ODAiCiAgICAgICB4PSItMC4yOTI5NDEzMyIKICAgICAgIHdpZHRoPSIxLjU4NTg4MjciCiAgICAgICB5PSItMC40NDI0MjA1NyIKICAgICAgIGhlaWdodD0iMS44ODQ4NDExIj4KICAgICAgPGZlR2F1c3NpYW5CbHVyCiAgICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgICAgc3RkRGV2aWF0aW9uPSI0LjQ4NjIzMDQiCiAgICAgICAgIGlkPSJmZUdhdXNzaWFuQmx1cjM5ODIiIC8+CiAgICA8L2ZpbHRlcj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDEyMSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQxMjciCiAgICAgICB4MT0iMTAwLjUzODI4IgogICAgICAgeTE9IjEyMy4yMDU4NiIKICAgICAgIHgyPSI5MC4yNzA4MjgiCiAgICAgICB5Mj0iOTMuNzk0MTM2IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0idHJhbnNsYXRlKC04MCwtODApIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ0MTQ3IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NDE1MyIKICAgICAgIHgxPSIxMjguMjI3NjMiCiAgICAgICB5MT0iMTIzLjU2OTQzIgogICAgICAgeDI9IjEyMy41MDAxOCIKICAgICAgIHkyPSI4OC4yNTMzNzIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTgwLC04MCkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MzYtMCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNjNGEwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzgzOC0yIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmNlOTRmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4NDAtNSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4MzYtMCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwNDEtNSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjM3Ljc1ODE3MSIKICAgICAgIHkxPSI1Ny4zMDEzMjciCiAgICAgICB4Mj0iMjEuODYwNDYyIgogICAgICAgeTI9IjIyLjYxNTQxMiIgLz4KICAgIDxmaWx0ZXIKICAgICAgIHN0eWxlPSJjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM6c1JHQiIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJmaWx0ZXIzOTgwLTMiCiAgICAgICB4PSItMC4yOTI5NDEzMyIKICAgICAgIHdpZHRoPSIxLjU4NTg4MjciCiAgICAgICB5PSItMC40NDI0MjA1NyIKICAgICAgIGhlaWdodD0iMS44ODQ4NDExIj4KICAgICAgPGZlR2F1c3NpYW5CbHVyCiAgICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgICAgc3RkRGV2aWF0aW9uPSI0LjQ4NjIzMDQiCiAgICAgICAgIGlkPSJmZUdhdXNzaWFuQmx1cjM5ODItMyIgLz4KICAgIDwvZmlsdGVyPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaWQ9ImJhc2UiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6em9vbT0iMy42MDQwMDM5IgogICAgIGlua3NjYXBlOmN4PSI1NS4zNTg1MzQiCiAgICAgaW5rc2NhcGU6Y3k9IjY3Ljg2MTQxMiIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE1MzYiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODAxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6b2JqZWN0LXBhdGhzPSJmYWxzZSIKICAgICBpbmtzY2FwZTpzbmFwLW5vZGVzPSJ0cnVlIgogICAgIGlua3NjYXBlOm9iamVjdC1ub2Rlcz0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIgogICAgIGlua3NjYXBlOnNuYXAtZ2xvYmFsPSJmYWxzZSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQzMDA0IgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTI4NjUiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlIC8+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bWW9yaWsgdmFuIEhhdnJlXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6dGl0bGU+QXJjaF9TcGFjZV9UcmVlPC9kYzp0aXRsZT4KICAgICAgICA8ZGM6ZGF0ZT4yMDEzLTA3LTE2PC9kYzpkYXRlPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL0FyY2gvUmVzb3VyY2VzL2ljb25zL0FyY2hfU3BhY2VfVHJlZS5zdmc8L2RjOmlkZW50aWZpZXI+CiAgICAgICAgPGRjOnJpZ2h0cz4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkZyZWVDQUQgTEdQTDIrPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpyaWdodHM+CiAgICAgICAgPGNjOmxpY2Vuc2U+aHR0cHM6Ly93d3cuZ251Lm9yZy9jb3B5bGVmdC9sZXNzZXIuaHRtbDwvY2M6bGljZW5zZT4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bYWdyeXNvbl0gQWxleGFuZGVyIEdyeXNvbjwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y29udHJpYnV0b3I+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIj4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO3N0cm9rZTpub25lIgogICAgICAgZD0iTSA1LDUzIDI5LDQzIDU5LDQ5IDM5LDU5IHoiCiAgICAgICBpZD0icGF0aDMwMDYiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50NDEyNyk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmUiCiAgICAgICBkPSJNIDI5LDQgNSwxNCA1LDUzIDI5LDQzIHoiCiAgICAgICBpZD0icGF0aDM4ODYiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQ0MTUzKTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSIKICAgICAgIGQ9Im0gMjksNCAwLDM5IDMwLDYgMCwtMzkgeiIKICAgICAgIGlkPSJwYXRoMzg4OCIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2JhYmRiNjtzdHJva2Utd2lkdGg6MiIKICAgICAgIGQ9Ik0gMjguMDIzMDMsNS40ODU1NzEgNiwxNC42NTMxNjQgNiw1MS41MjAyNSAyOC4wMjMwMyw0Mi4zNTI2NiB6IgogICAgICAgaWQ9InBhdGgzODg2LTQiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZmZmZmZmO3N0cm9rZS13aWR0aDoyIgogICAgICAgZD0ibSAzMC4wNzU2LDUuMTkwOTM4IC0wLjAwNiwzNi45OTg4MTIgMjcuOTE4OTgsNS40NDUwNiAwLjA3NjMsLTM2Ljc4NzIyMyB6IgogICAgICAgaWQ9InBhdGgzODg4LTciCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO3N0cm9rZTpub25lIgogICAgICAgZD0iTSA1LDE0IDI5LDQgNTksMTAgMzksMjAgeiIKICAgICAgIGlkPSJwYXRoMzAwNi0zIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzJlMzQzNjtzdHJva2Utd2lkdGg6NjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6NiwgMTI7c3Ryb2tlLWRhc2hvZmZzZXQ6My42MDAwMDAwMDAwMDAwMDAwOSIKICAgICAgIGQ9Im0gNSw1MyAzNCw2IgogICAgICAgaWQ9InBhdGgzOTE3IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMmUzNDM2O3N0cm9rZS13aWR0aDo2O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTo2LCAxMjtzdHJva2UtZGFzaG9mZnNldDozLjYiCiAgICAgICBkPSJtIDI1LDQ0IDM0LDUiCiAgICAgICBpZD0icGF0aDM5MTctMiIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMyZTM0MzY7c3Ryb2tlLXdpZHRoOjY7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5OjYsIDEyO3N0cm9rZS1kYXNob2Zmc2V0OjMuNjAwMDAwMDAwMDAwMDAwMDkiCiAgICAgICBkPSJtIDI1LDUgMzQsNiIKICAgICAgIGlkPSJwYXRoMzkxNy0xIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMmUzNDM2O3N0cm9rZS13aWR0aDo2O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTo2LCAxMjtzdHJva2UtZGFzaG9mZnNldDozLjYiCiAgICAgICBkPSJtIDU5LDExIDAsMzgiCiAgICAgICBpZD0icGF0aDM5MTctMjciCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMmUzNDM2O3N0cm9rZS13aWR0aDo2O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTo2LCAxMjtzdHJva2UtZGFzaG9mZnNldDozLjYwMDAwMDAwMDAwMDAwMDA5IgogICAgICAgZD0iTSA0MCw1OSA1OSw0OSIKICAgICAgIGlkPSJwYXRoMzkxNy0wIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzJlMzQzNjtzdHJva2Utd2lkdGg6NjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6NiwgMTI7c3Ryb2tlLWRhc2hvZmZzZXQ6My42MDAwMDAwMDAwMDAwMDAwOSIKICAgICAgIGQ9Ik0gNSwxNSAyNSw1IgogICAgICAgaWQ9InBhdGgzOTE3LTkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMmUzNDM2O3N0cm9rZS13aWR0aDo2O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTo2LCAxMjtzdHJva2UtZGFzaG9mZnNldDozLjYiCiAgICAgICBkPSJNIDUsMTUgNSw1MyIKICAgICAgIGlkPSJwYXRoMzkxNy0zIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzJlMzQzNjtzdHJva2Utd2lkdGg6NjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6NiwgMTI7c3Ryb2tlLWRhc2hvZmZzZXQ6My42MDAwMDAwMDAwMDAwMDAwOSIKICAgICAgIGQ9Ik0gNSw1MyAyNSw0NCIKICAgICAgIGlkPSJwYXRoMzkxNy02MCIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5OjYsIDEyO3N0cm9rZS1kYXNob2Zmc2V0OjMuNjAwMDAwMDAwMDAwMDAwMDkiCiAgICAgICBkPSJtIDI1LDQ0IDM0LDUiCiAgICAgICBpZD0icGF0aDM5MTctMi03IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2ZmZmZmZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6NiwgMTI7c3Ryb2tlLWRhc2hvZmZzZXQ6My42MDAwMDAwMDAwMDAwMDAwOSIKICAgICAgIGQ9Ik0gNSw1MyAyNSw0NCIKICAgICAgIGlkPSJwYXRoMzkxNy02MC0zIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICA8ZwogICAgICAgaWQ9Imc0MDM1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS4yMTI3MjY0LDAsMCwxLjIxMjcyNjQsLTg1LjQ0MzU2Miw5LjE0OTA5NDUpIgogICAgICAgc3R5bGU9InN0cm9rZTojMmUzNDM2Ij4KICAgICAgPGNpcmNsZQogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjYzODk0NzksMCwwLDAuNjM5NDAzNTIsNzkuMTUxMTg4LC02LjYyMTMzMjMpIgogICAgICAgICBpZD0icGF0aDQwNDItMTIiCiAgICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQ0MDQxKTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzJlMzQzNjtzdHJva2Utd2lkdGg6My4xMjkwMzAyMztzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowIgogICAgICAgICBjeD0iMjcuNjQxNDQ3IgogICAgICAgICBjeT0iMzkuOTU4MzciCiAgICAgICAgIHI9IjIwLjk1NjA3NCIgLz4KICAgICAgPGNpcmNsZQogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iMzMuODUyMjAzIgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iMzMuODUyMjAzIgogICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL2ppbW1hYy94aW1pYW5fYXJ0L2ljb25zL25hdXRpbHVzL3N1c2U5My9zdG9ja19uZXctMTYucG5nIgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjEyNTU1NDIsMC4xMjM0MzgxOCwtMC4xOTI3MjE0NSwwLjE3OTc3NDU4LDEwOS4xODQ3LC0xNS4yNjA5MjIpIgogICAgICAgICBpZD0icGF0aDEyNTExLTc3IgogICAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtkaXNwbGF5OmJsb2NrO3Zpc2liaWxpdHk6dmlzaWJsZTtmaWxsOiNmZmZmZmY7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOiMyZTM0MzY7c3Ryb2tlLXdpZHRoOjEuMjUwMDAwMjQ7bWFya2VyOm5vbmU7ZmlsdGVyOnVybCgjZmlsdGVyMzk4MCkiCiAgICAgICAgIGN4PSI1NSIKICAgICAgICAgY3k9IjEyNSIKICAgICAgICAgcj0iMTQuMzc1IiAvPgogICAgICA8Y2lyY2xlCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuNTcyNjI2MzQsMCwwLDAuNTcyNjI2MzUsODEuMTcxNzgsLTMuODgxMjE1NykiCiAgICAgICAgIGlkPSJwYXRoNDA0Mi0wIgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZmZmZmZmO3N0cm9rZS13aWR0aDozLjQ5MjY3OTEyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjAiCiAgICAgICAgIGN4PSIyNy42NDE0NDciCiAgICAgICAgIGN5PSIzOS45NTgzNyIKICAgICAgICAgcj0iMjAuOTU2MDc0IiAvPgogICAgICA8Y2lyY2xlCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuNjY4MDY0MDgsMCwwLDAuNjY4MDY0MDcsNzguNTMzNzQyLC03LjY5NDc1MTQpIgogICAgICAgICBpZD0icGF0aDQwNDItMyIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzJlMzQzNjtzdHJva2Utd2lkdGg6Mi45OTM3MjQ4MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowIgogICAgICAgICBjeD0iMjcuNjQxNDQ3IgogICAgICAgICBjeT0iMzkuOTU4MzciCiAgICAgICAgIHI9IjIwLjk1NjA3NCIgLz4KICAgIDwvZz4KICAgIDxnCiAgICAgICBpZD0iZzQwMzUtNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMzY5OTU4OSwwLDAsMS4zNjk5NTg5LC0xMDEuMjczMzYsNS4wNTE3OTk2KSI+CiAgICAgIDxjaXJjbGUKICAgICAgICAgcj0iMjAuOTU2MDc0IgogICAgICAgICBjeT0iMzkuOTU4MzciCiAgICAgICAgIGN4PSIyNy42NDE0NDciCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuNjM4OTQ3OSwwLDAsMC42Mzk0MDM1Miw3OS4xNTExODgsLTYuNjIxMzMyMykiCiAgICAgICAgIGlkPSJwYXRoNDA0Mi0xMi01IgogICAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50NDA0MS01KTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzMwMmIwMDtzdHJva2Utd2lkdGg6My4xMjkwMzAyMztzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowIiAvPgogICAgICA8Y2lyY2xlCiAgICAgICAgIHI9IjE0LjM3NSIKICAgICAgICAgY3k9IjEyNSIKICAgICAgICAgY3g9IjU1IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iMzMuODUyMjAzIgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iMzMuODUyMjAzIgogICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL2ppbW1hYy94aW1pYW5fYXJ0L2ljb25zL25hdXRpbHVzL3N1c2U5My9zdG9ja19uZXctMTYucG5nIgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjEyNTU1NDIsMC4xMjM0MzgxOCwtMC4xOTI3MjE0NSwwLjE3OTc3NDU4LDEwOS4xODQ3LC0xNS4yNjA5MjIpIgogICAgICAgICBpZD0icGF0aDEyNTExLTc3LTYiCiAgICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6YmxvY2s7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6I2ZmZmZmZjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MS4yNTAwMDAyNDttYXJrZXI6bm9uZTtmaWx0ZXI6dXJsKCNmaWx0ZXIzOTgwLTMpIiAvPgogICAgICA8Y2lyY2xlCiAgICAgICAgIHI9IjIwLjk1NjA3NCIKICAgICAgICAgY3k9IjM5Ljk1ODM3IgogICAgICAgICBjeD0iMjcuNjQxNDQ3IgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjU3MjYyNjM0LDAsMCwwLjU3MjYyNjM1LDgxLjE3MTc4LC0zLjg4MTIxNTcpIgogICAgICAgICBpZD0icGF0aDQwNDItMC02IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZmNlOTRmO3N0cm9rZS13aWR0aDozLjQ5MjY3OTEyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjAiIC8+CiAgICAgIDxjaXJjbGUKICAgICAgICAgcj0iMjAuOTU2MDc0IgogICAgICAgICBjeT0iMzkuOTU4MzciCiAgICAgICAgIGN4PSIyNy42NDE0NDciCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuNjY4MDY0MDgsMCwwLDAuNjY4MDY0MDcsNzguNTMzNzQyLC03LjY5NDc1MTQpIgogICAgICAgICBpZD0icGF0aDQwNDItMy0xIgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMzAyYjAwO3N0cm9rZS13aWR0aDoyLjk5MzcyNDgyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjAiIC8+CiAgICA8L2c+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzJlMzQzNjtzdHJva2Utd2lkdGg6NjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6NiwgMTI7c3Ryb2tlLWRhc2hvZmZzZXQ6My42MDAwMDAwMDAwMDAwMDAwOSIKICAgICAgIGQ9Im0gNDAsMjEgMCwzOCIKICAgICAgIGlkPSJwYXRoMzkxNy02MiIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMyZTM0MzY7c3Ryb2tlLXdpZHRoOjY7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5OjYsIDEyO3N0cm9rZS1kYXNob2Zmc2V0OjMuNjAwMDAwMDAwMDAwMDAwMDkiCiAgICAgICBkPSJNIDQwLDIxIDYxLDEwIgogICAgICAgaWQ9InBhdGgzOTE3LTYxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzJlMzQzNjtzdHJva2Utd2lkdGg6NjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6NiwgMTI7c3Ryb2tlLWRhc2hvZmZzZXQ6My42MDAwMDAwMDAwMDAwMDAwOSIKICAgICAgIGQ9Im0gNSwxNSAzNSw2IgogICAgICAgaWQ9InBhdGgzOTE3LTYiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZmZmZmZmO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTo2LCAxMjtzdHJva2UtZGFzaG9mZnNldDozLjYwMDAwMDAwMDAwMDAwMDA5IgogICAgICAgZD0ibSA1LDE1IDM1LDYiCiAgICAgICBpZD0icGF0aDM5MTctNi05IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2ZmZmZmZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6NiwgMTI7c3Ryb2tlLWRhc2hvZmZzZXQ6My42MDAwMDAwMDAwMDAwMDAwOSIKICAgICAgIGQ9Ik0gNDAsMjEgNjEsMTAiCiAgICAgICBpZD0icGF0aDM5MTctNjEtOSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5OjYsIDEyO3N0cm9rZS1kYXNob2Zmc2V0OjMuNjAwMDAwMDAwMDAwMDAwMDkiCiAgICAgICBkPSJtIDQwLDIxIDAsMzgiCiAgICAgICBpZD0icGF0aDM5MTctNjItMSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5OjYsIDEyO3N0cm9rZS1kYXNob2Zmc2V0OjMuNiIKICAgICAgIGQ9Ik0gNSwxNSA1LDUzIgogICAgICAgaWQ9InBhdGgzOTE3LTMtOSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5OjYsIDEyO3N0cm9rZS1kYXNob2Zmc2V0OjMuNjAwMDAwMDAwMDAwMDAwMDkiCiAgICAgICBkPSJNIDUsMTUgMjUsNSIKICAgICAgIGlkPSJwYXRoMzkxNy05LTIiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZmZmZmZmO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTo2LCAxMjtzdHJva2UtZGFzaG9mZnNldDozLjYwMDAwMDAwMDAwMDAwMDA5IgogICAgICAgZD0iTSA0MCw1OSA1OSw0OSIKICAgICAgIGlkPSJwYXRoMzkxNy0wLTEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZmZmZmZmO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTo2LCAxMjtzdHJva2UtZGFzaG9mZnNldDozLjYwMDAwMDAwMDAwMDAwMDA5IgogICAgICAgZD0ibSA1LDUzIDM0LDYiCiAgICAgICBpZD0icGF0aDM5MTctMjgiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5OjYsIDEyO3N0cm9rZS1kYXNob2Zmc2V0OjMuNiIKICAgICAgIGQ9Im0gNTksMTEgMCwzOCIKICAgICAgIGlkPSJwYXRoMzkxNy0yNy02IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2ZmZmZmZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6NiwgMTI7c3Ryb2tlLWRhc2hvZmZzZXQ6My42MDAwMDAwMDAwMDAwMDAwOSIKICAgICAgIGQ9Im0gMjUsNSAzNCw2IgogICAgICAgaWQ9InBhdGgzOTE3LTEtMyIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgPC9nPgo8L3N2Zz4K\n\"\"\"\nMass_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI5ODUiCiAgIHZlcnNpb249IjEuMSIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45Mi4wIHIxNTI5OSIKICAgc29kaXBvZGk6ZG9jbmFtZT0iTWFzcy5zdmciPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMyOTg3Ij4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc3MyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM4ODhhODU7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzNzc1IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZDNkN2NmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzc3NyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3OTQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZDNkN2NmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzc5NiIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM3OTgiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzNzk0IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg2NyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjMyLjcxNDc0OCIKICAgICAgIHkxPSIyNy4zOTgzNTIiCiAgICAgICB4Mj0iMzguOTk3NzI2IgogICAgICAgeTI9IjMuNjUyMzEyNSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45Mjg5NjkzMSwwLDAsMC44MDE0NTcxMywxLjg0MDcxNzcsNC40NDMyMjUyKSIKICAgICAgIHNwcmVhZE1ldGhvZD0icmVmbGVjdCIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc5NC04Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmYjQwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzNzk2LTUiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmVhMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzc5OC04IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjIzLjg0ODY4NiIKICAgICAgIHgyPSI2Mi42NTIzNyIKICAgICAgIHkxPSIyMy44NDg2ODYiCiAgICAgICB4MT0iMTUuMTg0OTcxIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjAyNjU1NjgsMCwwLDAuOTE0OTA2MjYsLTMuMjM2NzA2LC0xLjgwMjcwMzIpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODg2IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzc5NC04IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzk0LTEiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZiNDAwO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM3OTYtMiIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZWEwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzNzk4LTIiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMjMuODQ4Njg2IgogICAgICAgeDI9IjYyLjY1MjM3IgogICAgICAgeTE9IjIzLjg0ODY4NiIKICAgICAgIHgxPSIxNS4xODQ5NzEiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMDI2NTU2OCwwLDAsMC45MTQ5MDYyNiwtMy4yMzY3MDYsLTEuODAyNzAzMikiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4ODYtMCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM3OTQtMSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzc3MyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3NzkiCiAgICAgICB4MT0iNTcuNzI0MzUiCiAgICAgICB5MT0iMzQuNDMwNDAxIgogICAgICAgeDI9IjUwLjYyMDM4IgogICAgICAgeTI9IjIzLjkzMzY4IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4MzYtMCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MDEtMSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9Ii0xOCIKICAgICAgIHkxPSIxOCIKICAgICAgIHgyPSItMjIiCiAgICAgICB5Mj0iNSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgzNi0wIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2M0YTAwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODM4LTIiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmY2U5NGY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg0MC01IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjkuNjg3NSIKICAgICBpbmtzY2FwZTpjeD0iMzIiCiAgICAgaW5rc2NhcGU6Y3k9IjMyIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIKICAgICBzaG93Z3JpZD0idHJ1ZSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTUzNiIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI4MDEiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy15PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIgogICAgIGlua3NjYXBlOnNuYXAtZ2xvYmFsPSJmYWxzZSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQyOTk3IgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTI5OTAiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlIC8+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5beW9yaWt2YW5oYXZyZV08L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNyZWF0b3I+CiAgICAgICAgPGRjOnRpdGxlPkFyY2hfU2l0ZV9UcmVlPC9kYzp0aXRsZT4KICAgICAgICA8ZGM6ZGF0ZT4yMDExLTEyLTA2PC9kYzpkYXRlPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL0FyY2gvUmVzb3VyY2VzL2ljb25zL0FyY2hfU2l0ZV9UcmVlLnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8Y2M6bGljZW5zZT5odHRwczovL3d3dy5nbnUub3JnL2NvcHlsZWZ0L2xlc3Nlci5odG1sPC9jYzpsaWNlbnNlPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlthZ3J5c29uXSBBbGV4YW5kZXIgR3J5c29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2ZpbGw6I2QzZDdjZjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6IzJlMzQzNjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7bWFya2VyOm5vbmU7dmlzaWJpbGl0eTp2aXNpYmxlO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIKICAgICAgIGQ9Ik0gMyw0MSAyOSw1MyAyOSw2MSAzLDQ5IHoiCiAgICAgICBpZD0icGF0aDM5MDQiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzNzc5KTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6IzJlMzQzNjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7bWFya2VyOm5vbmU7dmlzaWJpbGl0eTp2aXNpYmxlO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIKICAgICAgIGQ9Ik0gNjEsMTEgNjEsMzUgMjksNjEgMjksNTMgNDAuNzc0NzQzLDEzLjkzOTU4IHoiCiAgICAgICBpZD0icGF0aDM4NjkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM4NjcpO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMmUzNDM2O3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICBkPSJNIDM1LDMgMjMsMTMgMTcsMjkgMyw0MSAyOSw1MyA0MC42ODMyNSw0MC4yMDgyNDkgNDksMjMgNjEsMTEgeiIKICAgICAgIGlkPSJwYXRoMzc2MyIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZDNkN2NmO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJNIDMwLjk4MjY1OCw1My43OTc3MjQgMzEsNTYuODA5MTA0IDU4Ljk4MjY1OCwzNC4wNTIwMjUgbCAwLC0xOC4xODQ5MzQgLTguMzEyMTUzLDguMzIzNjY5IC04LjM0NjgzNiwxNy4xMjEzOTMgeiIKICAgICAgIGlkPSJwYXRoMjk5OSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2ZmZmZmZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgZD0iTSA1LjAxMDU1NDYsNDQuMTY5MzY5IDQuOTkwOTU5Myw0Ny43MDYzOCAyNy4wMTY4MTgsNTcuODgzMDU1IDI2Ljk3NTQ2Miw1NC4yNzk0NDEgeiIKICAgICAgIGlkPSJwYXRoMzAwMSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjIiAvPgogICAgPGcKICAgICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDI2LjE5OTI4MywtMjcuNzQxOTM2KSIKICAgICAgIGlkPSJnMzgyNy0xIj4KICAgICAgPGcKICAgICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMzEuMzIyMTMxLDQwLjU3MDI4OSkiCiAgICAgICAgIGlkPSJnMzc5Ny05Ij4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzJlMjkwMDtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIGlkPSJwYXRoNDI1MC03MSIKICAgICAgICAgICBkPSJNIC0yNi4xNTYyMDQsNS41ODI2MjYgQSA4Ljk5MzgxOCw4Ljk5MzQwNzcgMC4wMjA0MjI4MyAxIDEgLTEyLjQ5Mzc5MywxNy4yODIyNDEgOC45OTM4MTgsOC45OTM0MDc3IDAuMDIwNDIyODMgMSAxIC0yNi4xNTYyMDQsNS41ODI2MjYgWiIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM4MDEtMSk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNmY2U5NGY7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5NTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgICBpZD0icGF0aDQyNTAtNy0zIgogICAgICAgICAgIGQ9Ik0gLTI0LjYzMzU4OCw2Ljg5MzU4OCBBIDYuOTk5OTk5Nyw3LjAwMDAwMDEgMCAxIDEgLTE0LDE2IDYuOTk5OTk5Nyw3LjAwMDAwMDEgMCAwIDEgLTI0LjYzMzU4OCw2Ljg5MzU4OCBaIiAvPgogICAgICA8L2c+CiAgICA8L2c+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2ZmZmZmZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgZD0iTSA2LjY1OTQyMDQsNDAuNDY3ODYxIDE4LjY5NTQ3NiwzMC4xNjYzMjMgMjQuNjk3OTUsMTQuMTkyNjUxIDM1LjU3MDIzNyw1LjI3ODEyMyA1Ny4xNTMyOTUsMTEuOTA5MzIxIDQ3LjM1NjcxMSwyMS43NzAzNDIgMzguOTg3NDIzLDM5LjA3MTE2NiAyOC40NzIzNDIsNTAuNTM4MDA1IHoiCiAgICAgICBpZD0icGF0aDMwMDMiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjY2MiIC8+CiAgPC9nPgo8L3N2Zz4K\n\"\"\"\nNormal_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI5ODAiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9Ik5vcm1hbC1VcC5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMyOTgyIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NDAyOCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A0MDMwIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNDAzMiIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3OTQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAwMDAwO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM3OTYiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjA7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzc5OCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4NjQiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM4NjYiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcxYjJmODtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg2OCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAyNzk1O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfej0iNjQgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMzIgOiAyMS4zMzMzMzMgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMjk4OCIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgwLC00KSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM3NjciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzczIgogICAgICAgeDE9IjIyLjExNjUxNiIKICAgICAgIHkxPSI1NS43MTc1MTgiCiAgICAgICB4Mj0iMTcuMzI4NTQ3IgogICAgICAgeTI9IjIxLjMxMTM0IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3NjciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzQ2NWE0O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzc2OSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM3NzEiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTQpIgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzc3NyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3ODMiCiAgICAgICB4MT0iNTMuODk2NzYzIgogICAgICAgeTE9IjUxLjE3OTc4NyIKICAgICAgIHgyPSI0Ny41MDIyMzUiCiAgICAgICB5Mj0iMjEuODM3NDIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc3NyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzNzc5IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzQ2NWE0O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzc4MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM3OTQiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzODAwIgogICAgICAgY3g9IjEiCiAgICAgICBjeT0iNDUiCiAgICAgICBmeD0iMSIKICAgICAgIGZ5PSI0NSIKICAgICAgIHI9IjQxIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjkzMzQ4MjEzLC0yLjI5MDUyNzZlLTgsMCwwLjI4Njg3NTczLDAuMDY2NTE3NTEsMzIuMDkwNTkyKSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM2LTAtNi05LTciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYTQwMDAwO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzgzOC0yLTctMy04IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWYyOTI5O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg0MC01LTUtMS02IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgzNi0wLTYtOTItNCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODM4LTItNy0wNi04IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWYyOTI5O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg0MC01LTUtOC03IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgzNi0wLTYtOTItNC02Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2E0MDAwMDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4MzgtMi03LTA2LTgtNyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2VmMjkyOTtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4NDAtNS01LTgtNy01IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgzNi0wLTYtOTItNC02MiI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODM4LTItNy0wNi04LTkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNlZjI5Mjk7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODQwLTUtNS04LTctMSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MzYtMC02LTkyLTQtMCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODM4LTItNy0wNi04LTYiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNlZjI5Mjk7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODQwLTUtNS04LTctMiIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4MzYtMC02LTkyLTQtMiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MDEtMS0zLTE0LTAtOSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9Ii0xOCIKICAgICAgIHkxPSIxOCIKICAgICAgIHgyPSItMjIiCiAgICAgICB5Mj0iNSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC43NjM0MjQzOSwwLDAsMC43NTc1MDQyNSwtNC41OTYzODksMi43NTI1NjM3KSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgzNi0wLTYtOTItNC0yIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2E0MDAwMDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4MzgtMi03LTA2LTgtMCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2VmMjkyOTtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4NDAtNS01LTgtNy0yMyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQwMjgiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MDM0IgogICAgICAgeDE9IjM4IgogICAgICAgeTE9IjU3IgogICAgICAgeDI9IjI2IgogICAgICAgeTI9IjI2IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQwMjgiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MDQwIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzgiCiAgICAgICB5MT0iNTciCiAgICAgICB4Mj0iMjYiCiAgICAgICB5Mj0iMjYiIC8+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSIzLjQyNTA0ODUiCiAgICAgaW5rc2NhcGU6Y3g9IjI3LjkxMjY0NiIKICAgICBpbmtzY2FwZTpjeT0iMzguNTI4MjM2IgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9Imc0NTI3IgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpncmlkLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxNTM2IgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjgwMSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOnNuYXAtYmJveD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6c25hcC1ub2Rlcz0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIj4KICAgIDxpbmtzY2FwZTpncmlkCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBpZD0iZ3JpZDI5OTEiCiAgICAgICBlbXBzcGFjaW5nPSIyIgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiCiAgICAgICBzbmFwdmlzaWJsZWdyaWRsaW5lc29ubHk9InRydWUiIC8+CiAgPC9zb2RpcG9kaTpuYW1lZHZpZXc+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhMjk4NSI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGU+PC9kYzp0aXRsZT4KICAgICAgICA8ZGM6Y3JlYXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPltqbWF1c3RwY108L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNyZWF0b3I+CiAgICAgICAgPGRjOnRpdGxlPlRyZWVfUGFydF9QbGFuZV9QYXJhbWV0cmljPC9kYzp0aXRsZT4KICAgICAgICA8ZGM6ZGF0ZT4yMDEzLTAzLTEzPC9kYzpkYXRlPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL1BhcnQvR3VpL1Jlc291cmNlcy9pY29ucy9UcmVlX1BhcnRfUGxhbmVfUGFyYW1ldHJpYy5zdmc8L2RjOmlkZW50aWZpZXI+CiAgICAgICAgPGRjOnJpZ2h0cz4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkZyZWVDQUQgTEdQTDIrPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpyaWdodHM+CiAgICAgICAgPGNjOmxpY2Vuc2U+aHR0cHM6Ly93d3cuZ251Lm9yZy9jb3B5bGVmdC9sZXNzZXIuaHRtbDwvY2M6bGljZW5zZT4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bYWdyeXNvbl0gQWxleGFuZGVyIEdyeXNvbjwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y29udHJpYnV0b3I+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIj4KICAgIDxnCiAgICAgICBpZD0iZzQwMzYiCiAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLC02KSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI2Mi4wMzA4OCIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI2Mi4wMzA4OCI+CiAgICAgIDxwYXRoCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzI0MCIKICAgICAgICAgZD0iTSA4LDQ2IDM3LDU2IDU2LDI5IDI3LDIxIHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiM3MjlmY2Y7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMjQwLTIiCiAgICAgICAgIGQ9Im0gMTEuMyw0NSAyNSw4LjcgMTYuNSwtMjMuNiAtMjUsLTYuOCB6IgogICAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50NDA0MCk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgIDwvZz4KICAgIDxnCiAgICAgICBpZD0iZzQ1MjciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjE1MTA3NjcxLC0wLjAyNjYzODksMC4wMjY2Mzg5LDAuMTUxMDc2NzEsLTMwMy4wNzUwNiwtMTg0LjcwMDk3KSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI3Ni43Njk5OTciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNzYuNzY5OTk3Ij4KICAgICAgPGcKICAgICAgICAgaWQ9Imc0NTUwIgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgtMC41MjQ4NjYzOCwtMC43MDQwODM0MSwwLjg0NDMwNTYyLC0wLjM1OTM1MzA5LDEzNDAuNjYyOCwzNjM0LjI3OTMpIj4KICAgICAgICA8cGF0aAogICAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMyODAwMDA7c3Ryb2tlLXdpZHRoOjYyLjAzODI1Mzc4O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIGQ9Im0gMTc1OS42NTEzLDE3NjMuMzMxMyAxMzkuNTg2MSwxMTUuNjYzIgogICAgICAgICAgIGlkPSJwYXRoNjM5NyIKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojY2MwMDAwO3N0cm9rZS13aWR0aDozMS4wMTkxMjY4OTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgICBkPSJtIDE3NTkuNjUxMywxNzYzLjMzMTMgMTM5LjU4NjEsMTE1LjY2MyIKICAgICAgICAgICBpZD0icGF0aDYzOTctNSIKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZWYyOTI5O3N0cm9rZS13aWR0aDoxNS41MDk1NjM0NTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgICBkPSJtIDE3NTMuMTQyOCwxNzY3Ljc3MjEgOTIuNjA1NCw3Ni43MzQyIDQ2Ljk4MDYsMzguOTI4OCIKICAgICAgICAgICBpZD0icGF0aDYzOTctNS0wIgogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2MiIC8+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBzdHlsZT0iZmlsbDojY2MwMDAwO3N0cm9rZTojMjgwMDAwO3N0cm9rZS13aWR0aDoxNS41MDk1NjM0NTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6MzIuMjAwMDAwNzY7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgICBkPSJtIDE4NTguMTgxOCwxOTA1Ljc4MzEgYyAtMS44MDkxLC0zMi44MTE5IDQ3Ljc3MTQsLTY3LjQ0NjkgNzUuNjczNywtNjUuNzY5NCBsIDE5LjY2NTQsODkuNTgzMiB6IgogICAgICAgICAgIGlkPSJwYXRoNjQ3NS0zIgogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjIiAvPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2VmMjkyOTtzdHJva2Utd2lkdGg6MTUuNTA5NTYzNDU7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjMyLjIwMDAwMDc2O3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgZD0ibSAxODc1LjQ3ODYsMTg5NS4zMDA5IGMgMy41OSwtMTMuNzczNiAyNi45MDI4LC0zMy4zNTUgNDYuMDg2OSwtMzguNjM3OCBsIDEyLjA5MSw1Mi43Nzg1IHoiCiAgICAgICAgICAgaWQ9InBhdGg2NDc1LTYtMiIKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjYyIgLz4KICAgICAgPC9nPgogICAgPC9nPgogIDwvZz4KPC9zdmc+Cg==\n\"\"\"\nNormal_Inv_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI5ODAiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9Ik5vcm1hbC1Eb3duLnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiCiAgIHZlcnNpb249IjEuMSI+CiAgPGRlZnMKICAgICBpZD0iZGVmczI5ODIiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MDI4Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzIwNGE4NztzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDQwMzAiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3A0MDMyIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc5NCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzc5NiIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMDAwMDtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzNzk4IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg2NCI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg2NiIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODY4IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUyOTg4IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTQpIgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzc2NyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3NzMiCiAgICAgICB4MT0iMjIuMTE2NTE2IgogICAgICAgeTE9IjU1LjcxNzUxOCIKICAgICAgIHgyPSIxNy4zMjg1NDciCiAgICAgICB5Mj0iMjEuMzExMzQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc2NyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMzNDY1YTQ7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzNzY5IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzc3MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtNCkiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzNzc3IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc4MyIKICAgICAgIHgxPSI1My44OTY3NjMiCiAgICAgICB5MT0iNTEuMTc5Nzg3IgogICAgICAgeDI9IjQ3LjUwMjIzNSIKICAgICAgIHkyPSIyMS44Mzc0MiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzc3Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzIwNGE4NztzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM3NzkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMzNDY1YTQ7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzNzgxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzc5NCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM4MDAiCiAgICAgICBjeD0iMSIKICAgICAgIGN5PSI0NSIKICAgICAgIGZ4PSIxIgogICAgICAgZnk9IjQ1IgogICAgICAgcj0iNDEiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTMzNDgyMTMsLTIuMjkwNTI3NmUtOCwwLDAuMjg2ODc1NzMsMC4wNjY1MTc1MSwzMi4wOTA1OTIpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MzYtMC02LTktNyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODM4LTItNy0zLTgiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNlZjI5Mjk7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODQwLTUtNS0xLTYiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM2LTAtNi05Mi00Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2E0MDAwMDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4MzgtMi03LTA2LTgiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNlZjI5Mjk7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODQwLTUtNS04LTciIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM2LTAtNi05Mi00LTYiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYTQwMDAwO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzgzOC0yLTctMDYtOC03IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWYyOTI5O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg0MC01LTUtOC03LTUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM2LTAtNi05Mi00LTYyIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2E0MDAwMDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4MzgtMi03LTA2LTgtOSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2VmMjkyOTtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4NDAtNS01LTgtNy0xIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgzNi0wLTYtOTItNC0wIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2E0MDAwMDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4MzgtMi03LTA2LTgtNiIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2VmMjkyOTtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4NDAtNS01LTgtNy0yIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzgzNi0wLTYtOTItNC0yIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgwMS0xLTMtMTQtMC05IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iLTE4IgogICAgICAgeTE9IjE4IgogICAgICAgeDI9Ii0yMiIKICAgICAgIHkyPSI1IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjc2MzQyNDM5LDAsMCwwLjc1NzUwNDI1LC00LjU5NjM4OSwyLjc1MjU2MzcpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM2LTAtNi05Mi00LTIiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYTQwMDAwO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzgzOC0yLTctMDYtOC0wIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWYyOTI5O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg0MC01LTUtOC03LTIzIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDAyOCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwMzQiCiAgICAgICB4MT0iMzgiCiAgICAgICB5MT0iNTciCiAgICAgICB4Mj0iMjYiCiAgICAgICB5Mj0iMjYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDAyOCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwNDAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSIzOCIKICAgICAgIHkxPSI1NyIKICAgICAgIHgyPSIyNiIKICAgICAgIHkyPSIyNiIgLz4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjMuNDI1MDQ4NSIKICAgICBpbmtzY2FwZTpjeD0iMjcuOTEyNjQ2IgogICAgIGlua3NjYXBlOmN5PSIzOC41MjgyMzYiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iZzQ1NTkiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE1MzYiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODAxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6c25hcC1iYm94PSJmYWxzZSIKICAgICBpbmtzY2FwZTpzbmFwLW5vZGVzPSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMjk5MSIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEyOTg1Ij4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzp0aXRsZT48L2RjOnRpdGxlPgogICAgICAgIDxkYzpjcmVhdG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W2ptYXVzdHBjXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6dGl0bGU+VHJlZV9QYXJ0X1BsYW5lX1BhcmFtZXRyaWM8L2RjOnRpdGxlPgogICAgICAgIDxkYzpkYXRlPjIwMTMtMDMtMTM8L2RjOmRhdGU+CiAgICAgICAgPGRjOnJlbGF0aW9uPmh0dHA6Ly93d3cuZnJlZWNhZHdlYi5vcmcvd2lraS9pbmRleC5waHA/dGl0bGU9QXJ0d29yazwvZGM6cmVsYXRpb24+CiAgICAgICAgPGRjOnB1Ymxpc2hlcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkZyZWVDQUQ8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnB1Ymxpc2hlcj4KICAgICAgICA8ZGM6aWRlbnRpZmllcj5GcmVlQ0FEL3NyYy9Nb2QvUGFydC9HdWkvUmVzb3VyY2VzL2ljb25zL1RyZWVfUGFydF9QbGFuZV9QYXJhbWV0cmljLnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8Y2M6bGljZW5zZT5odHRwczovL3d3dy5nbnUub3JnL2NvcHlsZWZ0L2xlc3Nlci5odG1sPC9jYzpsaWNlbnNlPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlthZ3J5c29uXSBBbGV4YW5kZXIgR3J5c29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPGcKICAgICAgIGlkPSJnNDAzNiIKICAgICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTYpIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjYyLjAzMDg4IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjYyLjAzMDg4Ij4KICAgICAgPHBhdGgKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMjQwIgogICAgICAgICBkPSJNIDgsNDYgMzcsNTYgNTYsMjkgMjcsMjEgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzcyOWZjZjtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8cGF0aAogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMyNDAtMiIKICAgICAgICAgZD0ibSAxMS4zLDQ1IDI1LDguNyAxNi41LC0yMy42IC0yNSwtNi44IHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQ0MDQwKTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgPC9nPgogICAgPGcKICAgICAgIGlkPSJnNDUyNyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMTUxMDc2NzEsLTAuMDI2NjM4OSwwLjAyNjYzODksMC4xNTEwNzY3MSwtMzAzLjA3NTA2LC0xODQuNzAwOTcpIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9Ijc2Ljc2OTk5NyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI3Ni43Njk5OTciPgogICAgICA8cGF0aAogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDYzOTciCiAgICAgICAgIGQ9Im0gMTkzMS42NzI0LDE1ODIuMDIwNyAtMjQuMzkwOSwxMzkuODQ0MSIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzI4MDAwMDtzdHJva2Utd2lkdGg6NTQuODk4NTU5NTc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI2Mi4wMzA4OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjYyLjAzMDg4IiAvPgogICAgICA8cGF0aAogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDYzOTctNSIKICAgICAgICAgZD0ibSAxOTMxLjY3MjQsMTU4Mi4wMjA3IC0yNC4zOTA5LDEzOS44NDQxIgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojY2MwMDAwO3N0cm9rZS13aWR0aDoyNy40NDkyNzk3OTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjYyLjAzMDg4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNjIuMDMwODgiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDYzOTctNS0wIgogICAgICAgICBkPSJtIDE5MjQuNTA2OSwxNTc5LjAzMzkgLTE2LjE4MTcsOTIuNzc2NiAtOC4yMDkyLDQ3LjA2NzUiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNlZjI5Mjk7c3Ryb2tlLXdpZHRoOjEzLjcyNDYzOTg5O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNjIuMDMwODgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI2Mi4wMzA4OCIgLz4KICAgICAgPGcKICAgICAgICAgaWQ9Imc0NTU5Ij4KICAgICAgICA8ZwogICAgICAgICAgIGlkPSJnNDU2MyIKICAgICAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSgtOC40MDg2OTgyLDE5MDUuODMxNywxNzQxLjE4NjMpIgogICAgICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI2Mi4wMzA4OCIKICAgICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNjIuMDMwODgiPgogICAgICAgICAgPHBhdGgKICAgICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjYyIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDY0NzUtMyIKICAgICAgICAgICAgIGQ9Im0gMTg2My4xMTQ5LDE3MDIuNTg0OCBjIDI2Ljc1MzcsLTEzLjA2NDggODIuMDE5NCw5LjM5NzggOTUuMjQ4LDI5LjY0NjIgbCAtNjUuMzEzOSw0Ni4wMzgxIHoiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojY2MwMDAwO3N0cm9rZTojMjgwMDAwO3N0cm9rZS13aWR0aDoxMy43MjQ2Mzk4OTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6MzIuMjAwMDAwNzY7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2MiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGg2NDc1LTYtMiIKICAgICAgICAgICAgIGQ9Im0gMTg4MS4wNDM2LDE3MTAuOTk2NCBjIDEzLjUxMzQsLTIuNDIxOSA0Mi4yODIyLDYuOTU1NiA1Ni44MTE1LDE4LjU2NDQgbCAtMzguMjE1LDI3LjQ3OTIgeiIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNlZjI5Mjk7c3Ryb2tlLXdpZHRoOjEzLjcyNDYzOTg5O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDozMi4yMDAwMDA3NjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICAgIDwvZz4KICAgICAgPC9nPgogICAgPC9nPgogIDwvZz4KPC9zdmc+Cg==\n\"\"\"\nPlanes_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI5ODAiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9IlBsYW5lcy5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMyOTgyIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NDAyOCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A0MDMwIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNDAzMiIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3OTQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAwMDAwO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM3OTYiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjA7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzc5OCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4NjQiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM4NjYiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcxYjJmODtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg2OCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAyNzk1O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfej0iNjQgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMzIgOiAyMS4zMzMzMzMgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMjk4OCIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgwLC00KSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM3NjciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzczIgogICAgICAgeDE9IjIyLjExNjUxNiIKICAgICAgIHkxPSI1NS43MTc1MTgiCiAgICAgICB4Mj0iMTcuMzI4NTQ3IgogICAgICAgeTI9IjIxLjMxMTM0IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3NjciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzQ2NWE0O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzc2OSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM3NzEiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTQpIgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzc3NyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3ODMiCiAgICAgICB4MT0iNTMuODk2NzYzIgogICAgICAgeTE9IjUxLjE3OTc4NyIKICAgICAgIHgyPSI0Ny41MDIyMzUiCiAgICAgICB5Mj0iMjEuODM3NDIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc3NyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzNzc5IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzQ2NWE0O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzc4MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM3OTQiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzODAwIgogICAgICAgY3g9IjEiCiAgICAgICBjeT0iNDUiCiAgICAgICBmeD0iMSIKICAgICAgIGZ5PSI0NSIKICAgICAgIHI9IjQxIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjkzMzQ4MjEzLC0yLjI5MDUyNzZlLTgsMCwwLjI4Njg3NTczLDAuMDY2NTE3NTEsMzIuMDkwNTkyKSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM2LTAtNi05LTciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYTQwMDAwO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzgzOC0yLTctMy04IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWYyOTI5O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg0MC01LTUtMS02IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgzNi0wLTYtOTItNCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODM4LTItNy0wNi04IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWYyOTI5O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg0MC01LTUtOC03IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzgzNi0wLTYtOTItNC02IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgwMS0xLTMtMTQtMC0zIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iLTE4IgogICAgICAgeTE9IjE4IgogICAgICAgeDI9Ii0yMiIKICAgICAgIHkyPSI1IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjc2MzQyNDM5LDAsMCwwLjc1NzUwNDI1LC00LjU5NjM4OSwyLjc1MjU2MzcpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM2LTAtNi05Mi00LTYiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYTQwMDAwO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzgzOC0yLTctMDYtOC03IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWYyOTI5O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg0MC01LTUtOC03LTUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODM2LTAtNi05Mi00LTYyIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgwMS0xLTMtMTQtMC0zNSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9Ii0xOCIKICAgICAgIHkxPSIxOCIKICAgICAgIHgyPSItMjIiCiAgICAgICB5Mj0iNSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC43NjM0MjQzOSwwLDAsMC43NTc1MDQyNSwtNC41OTYzODksMi43NTI1NjM3KSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgzNi0wLTYtOTItNC02MiI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODM4LTItNy0wNi04LTkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNlZjI5Mjk7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODQwLTUtNS04LTctMSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4MzYtMC02LTkyLTQtMCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MDEtMS0zLTE0LTAtMzYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSItMTgiCiAgICAgICB5MT0iMTgiCiAgICAgICB4Mj0iLTIyIgogICAgICAgeTI9IjUiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNzYzNDI0MzksMCwwLDAuNzU3NTA0MjUsLTQuNTk2Mzg5LDIuNzUyNTYzNykiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MzYtMC02LTkyLTQtMCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODM4LTItNy0wNi04LTYiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNlZjI5Mjk7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODQwLTUtNS04LTctMiIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4MzYtMC02LTkyLTQtMiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MDEtMS0zLTE0LTAtOSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9Ii0xOCIKICAgICAgIHkxPSIxOCIKICAgICAgIHgyPSItMjIiCiAgICAgICB5Mj0iNSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC43NjM0MjQzOSwwLDAsMC43NTc1MDQyNSwtNC41OTYzODksMi43NTI1NjM3KSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgzNi0wLTYtOTItNC0yIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2E0MDAwMDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4MzgtMi03LTA2LTgtMCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2VmMjkyOTtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4NDAtNS01LTgtNy0yMyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQwMjgiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MDM0IgogICAgICAgeDE9IjM4IgogICAgICAgeTE9IjU3IgogICAgICAgeDI9IjI2IgogICAgICAgeTI9IjI2IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQwMjgiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MDQwIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzgiCiAgICAgICB5MT0iNTciCiAgICAgICB4Mj0iMjYiCiAgICAgICB5Mj0iMjYiIC8+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI1LjE0MDY0NTUiCiAgICAgaW5rc2NhcGU6Y3g9IjY0LjA0NTU1OSIKICAgICBpbmtzY2FwZTpjeT0iLTMuNjMzMDI4MyIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE1MzYiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODAxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6c25hcC1iYm94PSJmYWxzZSIKICAgICBpbmtzY2FwZTpzbmFwLW5vZGVzPSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMjk5MSIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEyOTg1Ij4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzp0aXRsZSAvPgogICAgICAgIDxkYzpjcmVhdG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W2ptYXVzdHBjXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6dGl0bGU+VHJlZV9QYXJ0X1BsYW5lX1BhcmFtZXRyaWM8L2RjOnRpdGxlPgogICAgICAgIDxkYzpkYXRlPjIwMTMtMDMtMTM8L2RjOmRhdGU+CiAgICAgICAgPGRjOnJlbGF0aW9uPmh0dHA6Ly93d3cuZnJlZWNhZHdlYi5vcmcvd2lraS9pbmRleC5waHA/dGl0bGU9QXJ0d29yazwvZGM6cmVsYXRpb24+CiAgICAgICAgPGRjOnB1Ymxpc2hlcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkZyZWVDQUQ8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnB1Ymxpc2hlcj4KICAgICAgICA8ZGM6aWRlbnRpZmllcj5GcmVlQ0FEL3NyYy9Nb2QvUGFydC9HdWkvUmVzb3VyY2VzL2ljb25zL1RyZWVfUGFydF9QbGFuZV9QYXJhbWV0cmljLnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8Y2M6bGljZW5zZT5odHRwczovL3d3dy5nbnUub3JnL2NvcHlsZWZ0L2xlc3Nlci5odG1sPC9jYzpsaWNlbnNlPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlthZ3J5c29uXSBBbGV4YW5kZXIgR3J5c29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPGcKICAgICAgIGlkPSJnNDAzNiIKICAgICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTYpIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjYyLjI3MDMyOSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI2Mi4yNzAzMjkiPgogICAgICA8cGF0aAogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMyNDAiCiAgICAgICAgIGQ9Ik0gOCw0NiAzNyw1NiA1NiwyOSAyNywyMSB6IgogICAgICAgICBzdHlsZT0iZmlsbDojNzI5ZmNmO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzI0MC0yIgogICAgICAgICBkPSJtIDExLjMsNDUgMjUsOC43IDE2LjUsLTIzLjYgLTI1LC02LjggeiIKICAgICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDQwNDApO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICA8L2c+CiAgICA8ZwogICAgICAgaWQ9ImczMTUwIgogICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNTguODMwNDkzLDM3LjI4MjkzNCkiPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMxMzAiCiAgICAgICAgIGQ9Ik0gOCw0NiAzNyw1NiIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzI4MDAwMDtzdHJva2Utd2lkdGg6NjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMxMzAtMiIKICAgICAgICAgZD0iTSA4LDQ2IDM3LDU2IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZWYyOTI5O3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICA8L2c+CiAgICA8ZwogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsLTEsOTYsMTI5KSIKICAgICAgIGlkPSJnMzE1MC04Ij4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMTMwLTkiCiAgICAgICAgIGQ9Ik0gMTAsNTEgMjksNzgiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMyODAwMDA7c3Ryb2tlLXdpZHRoOjY7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMTMwLTItNyIKICAgICAgICAgZD0iTSAxMCw1MSAyOSw3OCIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2VmMjkyOTtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPC9nPgogICAgPGcKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuNTYxMzc4NywxLjU2NDE4MjNlLTgsMCwwLjU2NTc2OTcyLDg5LjA3ODYzNiw2My44NDE4NSkiCiAgICAgICBpZD0iZzM4MjctMS0zLTkyLTEiPgogICAgICA8ZwogICAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgzMS4zMjIxMzEsNDAuNTcwMjg5KSIKICAgICAgICAgaWQ9ImczNzk3LTktNS02Ni03Ij4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6I2VmMjkyOTtzdHJva2U6IzI4MDAwMDtzdHJva2Utd2lkdGg6My41NDg4MDUyNDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIGlkPSJwYXRoNDI1MC03MS02LTQ5LTIiCiAgICAgICAgICAgZD0iTSAtMjYuMTE4MjIxLDUuNjY0MzM0NyBBIDguOTM3OTc5Myw4Ljg2ODA3NzQgMCAxIDEgLTEyLjU0MDYzNCwxNy4yMDA5MDYgOC45Mzc5NzkzLDguODY4MDc3NCAwIDEgMSAtMjYuMTE4MjIxLDUuNjY0MzM0NyBaIiAvPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzgwMS0xLTMtMTQtMC0zKTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2VmMjkyOTtzdHJva2Utd2lkdGg6My41NDg4MDQyODtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIGlkPSJwYXRoNDI1MC03LTMtMi01LTciCiAgICAgICAgICAgZD0ibSAtMjMuNDAyMjcsNy45NzQ0ODU4IGEgNS4zNDM5NzA2LDUuMzAyNTI5OCAwIDEgMSA4LjExNzk0LDYuODk4MTQ1MiA1LjM0Mzk3MDYsNS4zMDI1Mjk4IDAgMCAxIC04LjExNzk0LC02Ljg5ODE0NTIgeiIgLz4KICAgICAgPC9nPgogICAgPC9nPgogICAgPGcKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuNTYxMzc4NywxLjU2NDE4MjNlLTgsMCwwLjU2NTc2OTcyLDExOC4yNDgxNCwyMS41NTg5MTYpIgogICAgICAgaWQ9ImczODI3LTEtMy05Mi0xLTIiPgogICAgICA8ZwogICAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgzMS4zMjIxMzEsNDAuNTcwMjg5KSIKICAgICAgICAgaWQ9ImczNzk3LTktNS02Ni03LTciPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICBzdHlsZT0iZmlsbDojZWYyOTI5O3N0cm9rZTojMjgwMDAwO3N0cm9rZS13aWR0aDozLjU0ODgwNTI0O3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgaWQ9InBhdGg0MjUwLTcxLTYtNDktMi0wIgogICAgICAgICAgIGQ9Ik0gLTI2LjExODIyMSw1LjY2NDMzNDcgQSA4LjkzNzk3OTMsOC44NjgwNzc0IDAgMSAxIC0xMi41NDA2MzQsMTcuMjAwOTA2IDguOTM3OTc5Myw4Ljg2ODA3NzQgMCAxIDEgLTI2LjExODIyMSw1LjY2NDMzNDcgWiIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM4MDEtMS0zLTE0LTAtMzUpO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZWYyOTI5O3N0cm9rZS13aWR0aDozLjU0ODgwNDI4O3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgaWQ9InBhdGg0MjUwLTctMy0yLTUtNy05IgogICAgICAgICAgIGQ9Im0gLTIzLjQwMjI3LDcuOTc0NDg1OCBhIDUuMzQzOTcwNiw1LjMwMjUyOTggMCAxIDEgOC4xMTc5NCw2Ljg5ODE0NTIgNS4zNDM5NzA2LDUuMzAyNTI5OCAwIDAgMSAtOC4xMTc5NCwtNi44OTgxNDUyIHoiIC8+CiAgICAgIDwvZz4KICAgIDwvZz4KICAgIDxnCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjU2MTM3ODcsMS41NjQxODIzZS04LDAsMC41NjU3Njk3Miw2MC4wNzg2MzYsNTMuODQxODUpIgogICAgICAgaWQ9ImczODI3LTEtMy05Mi0xLTYiPgogICAgICA8ZwogICAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgzMS4zMjIxMzEsNDAuNTcwMjg5KSIKICAgICAgICAgaWQ9ImczNzk3LTktNS02Ni03LTEiPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICBzdHlsZT0iZmlsbDojZWYyOTI5O3N0cm9rZTojMjgwMDAwO3N0cm9rZS13aWR0aDozLjU0ODgwNTI0O3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgaWQ9InBhdGg0MjUwLTcxLTYtNDktMi04IgogICAgICAgICAgIGQ9Ik0gLTI2LjExODIyMSw1LjY2NDMzNDcgQSA4LjkzNzk3OTMsOC44NjgwNzc0IDAgMSAxIC0xMi41NDA2MzQsMTcuMjAwOTA2IDguOTM3OTc5Myw4Ljg2ODA3NzQgMCAxIDEgLTI2LjExODIyMSw1LjY2NDMzNDcgWiIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM4MDEtMS0zLTE0LTAtMzYpO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZWYyOTI5O3N0cm9rZS13aWR0aDozLjU0ODgwNDI4O3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgaWQ9InBhdGg0MjUwLTctMy0yLTUtNy03IgogICAgICAgICAgIGQ9Im0gLTIzLjQwMjI3LDcuOTc0NDg1OCBhIDUuMzQzOTcwNiw1LjMwMjUyOTggMCAxIDEgOC4xMTc5NCw2Ljg5ODE0NTIgNS4zNDM5NzA2LDUuMzAyNTI5OCAwIDAgMSAtOC4xMTc5NCwtNi44OTgxNDUyIHoiIC8+CiAgICAgIDwvZz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo=\n\"\"\"\nPlanes_Centers_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI5ODAiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9IlBsYW5lcy1DZW50ZXJzLnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiCiAgIHZlcnNpb249IjEuMSI+CiAgPGRlZnMKICAgICBpZD0iZGVmczI5ODIiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MDI4Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzIwNGE4NztzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDQwMzAiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3A0MDMyIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc5NCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzc5NiIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMDAwMDtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzNzk4IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg2NCI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg2NiIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODY4IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUyOTg4IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTQpIgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzc2NyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3NzMiCiAgICAgICB4MT0iMjIuMTE2NTE2IgogICAgICAgeTE9IjU1LjcxNzUxOCIKICAgICAgIHgyPSIxNy4zMjg1NDciCiAgICAgICB5Mj0iMjEuMzExMzQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc2NyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMzNDY1YTQ7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzNzY5IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzc3MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtNCkiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzNzc3IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc4MyIKICAgICAgIHgxPSI1My44OTY3NjMiCiAgICAgICB5MT0iNTEuMTc5Nzg3IgogICAgICAgeDI9IjQ3LjUwMjIzNSIKICAgICAgIHkyPSIyMS44Mzc0MiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzc3Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzIwNGE4NztzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM3NzkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMzNDY1YTQ7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzNzgxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzc5NCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM4MDAiCiAgICAgICBjeD0iMSIKICAgICAgIGN5PSI0NSIKICAgICAgIGZ4PSIxIgogICAgICAgZnk9IjQ1IgogICAgICAgcj0iNDEiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTMzNDgyMTMsLTIuMjkwNTI3NmUtOCwwLDAuMjg2ODc1NzMsMC4wNjY1MTc1MSwzMi4wOTA1OTIpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MzYtMC02LTktNyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODM4LTItNy0zLTgiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNlZjI5Mjk7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODQwLTUtNS0xLTYiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM2LTAtNi05Mi00Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2E0MDAwMDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4MzgtMi03LTA2LTgiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNlZjI5Mjk7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODQwLTUtNS04LTciIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM2LTAtNi05Mi00LTYiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYTQwMDAwO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzgzOC0yLTctMDYtOC03IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWYyOTI5O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg0MC01LTUtOC03LTUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM2LTAtNi05Mi00LTYyIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2E0MDAwMDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4MzgtMi03LTA2LTgtOSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2VmMjkyOTtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4NDAtNS01LTgtNy0xIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgzNi0wLTYtOTItNC0wIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2E0MDAwMDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4MzgtMi03LTA2LTgtNiIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2VmMjkyOTtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4NDAtNS01LTgtNy0yIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzgzNi0wLTYtOTItNC0yIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgwMS0xLTMtMTQtMC05IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iLTE4IgogICAgICAgeTE9IjE4IgogICAgICAgeDI9Ii0yMiIKICAgICAgIHkyPSI1IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjc2MzQyNDM5LDAsMCwwLjc1NzUwNDI1LC00LjU5NjM4OSwyLjc1MjU2MzcpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM2LTAtNi05Mi00LTIiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYTQwMDAwO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzgzOC0yLTctMDYtOC0wIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWYyOTI5O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg0MC01LTUtOC03LTIzIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDAyOCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwMzQiCiAgICAgICB4MT0iMzgiCiAgICAgICB5MT0iNTciCiAgICAgICB4Mj0iMjYiCiAgICAgICB5Mj0iMjYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDAyOCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwNDAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSIzOCIKICAgICAgIHkxPSI1NyIKICAgICAgIHgyPSIyNiIKICAgICAgIHkyPSIyNiIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzgzNi0wLTYtOTItNC0yIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50OTE0IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNzYzNDI0MzksMCwwLDAuNzU3NTA0MjUsLTQuNTk2Mzg5LDIuNzUyNTYzNykiCiAgICAgICB4MT0iLTE4IgogICAgICAgeTE9IjE4IgogICAgICAgeDI9Ii0yMiIKICAgICAgIHkyPSI1IiAvPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaWQ9ImJhc2UiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6em9vbT0iNC41NDA1MzgzIgogICAgIGlua3NjYXBlOmN4PSI1Mi43MjQyMDkiCiAgICAgaW5rc2NhcGU6Y3k9IjEyLjM1ODM0NCIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE1MzYiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODAxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6c25hcC1iYm94PSJmYWxzZSIKICAgICBpbmtzY2FwZTpzbmFwLW5vZGVzPSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMjk5MSIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEyOTg1Ij4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzp0aXRsZT48L2RjOnRpdGxlPgogICAgICAgIDxkYzpjcmVhdG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W2ptYXVzdHBjXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6dGl0bGU+VHJlZV9QYXJ0X1BsYW5lX1BhcmFtZXRyaWM8L2RjOnRpdGxlPgogICAgICAgIDxkYzpkYXRlPjIwMTMtMDMtMTM8L2RjOmRhdGU+CiAgICAgICAgPGRjOnJlbGF0aW9uPmh0dHA6Ly93d3cuZnJlZWNhZHdlYi5vcmcvd2lraS9pbmRleC5waHA/dGl0bGU9QXJ0d29yazwvZGM6cmVsYXRpb24+CiAgICAgICAgPGRjOnB1Ymxpc2hlcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkZyZWVDQUQ8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnB1Ymxpc2hlcj4KICAgICAgICA8ZGM6aWRlbnRpZmllcj5GcmVlQ0FEL3NyYy9Nb2QvUGFydC9HdWkvUmVzb3VyY2VzL2ljb25zL1RyZWVfUGFydF9QbGFuZV9QYXJhbWV0cmljLnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8Y2M6bGljZW5zZT5odHRwczovL3d3dy5nbnUub3JnL2NvcHlsZWZ0L2xlc3Nlci5odG1sPC9jYzpsaWNlbnNlPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlthZ3J5c29uXSBBbGV4YW5kZXIgR3J5c29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPGcKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuNTYxMzc4NywxLjU2NDE4MjNlLTgsMCwwLjU2NTc2OTcyLDI1LjA3ODYzNiwxOS44NDE4NSkiCiAgICAgICBpZD0iZzM4MjctMS0zLTkyLTEtNCIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI2MC42ODgwNzYiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNjAuNjg4MDc2Ij4KICAgICAgPGcKICAgICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMzEuMzIyMTMxLDQwLjU3MDI4OSkiCiAgICAgICAgIGlkPSJnMzc5Ny05LTUtNjYtNy0zIj4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6I2VmMjkyOTtzdHJva2U6IzI4MDAwMDtzdHJva2Utd2lkdGg6My41NDg4MDUyNDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIGlkPSJwYXRoNDI1MC03MS02LTQ5LTItMiIKICAgICAgICAgICBkPSJNIC0yNi4xMTgyMjEsNS42NjQzMzQ3IEEgOC45Mzc5NzkzLDguODY4MDc3NCAwIDEgMSAtMTIuNTQwNjM0LDE3LjIwMDkwNiA4LjkzNzk3OTMsOC44NjgwNzc0IDAgMSAxIC0yNi4xMTgyMjEsNS42NjQzMzQ3IFoiIC8+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQ5MTQpO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZWYyOTI5O3N0cm9rZS13aWR0aDozLjU0ODgwNDI4O3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgaWQ9InBhdGg0MjUwLTctMy0yLTUtNy02IgogICAgICAgICAgIGQ9Im0gLTIzLjQwMjI3LDcuOTc0NDg1OCBhIDUuMzQzOTcwNiw1LjMwMjUyOTggMCAxIDEgOC4xMTc5NCw2Ljg5ODE0NTIgNS4zNDM5NzA2LDUuMzAyNTI5OCAwIDAgMSAtOC4xMTc5NCwtNi44OTgxNDUyIHoiIC8+CiAgICAgIDwvZz4KICAgIDwvZz4KICAgIDxnCiAgICAgICBpZD0iZzQwMzYiCiAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLC02KSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI2MC42ODgwNzYiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNjAuNjg4MDc2Ij4KICAgICAgPHBhdGgKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMjQwIgogICAgICAgICBkPSJNIDgsNDYgMzcsNTYgNTYsMjkgMjcsMjEgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzcyOWZjZjtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8cGF0aAogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMyNDAtMiIKICAgICAgICAgZD0ibSAxMS4zLDQ1IDI1LDguNyAxNi41LC0yMy42IC0yNSwtNi44IHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQ0MDQwKTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgPC9nPgogICAgPGcKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDAuNTMyODkzNjgsOS44MzA0OTI4LC02LjkwMTIzODMpIgogICAgICAgaWQ9ImczMTUwLTMiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNjAuNjg4MDc2IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjYwLjY4ODA3NiI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzEzMC02IgogICAgICAgICBkPSJNIDIyLDM2IFYgNzMiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMyODAwMDA7c3Ryb2tlLXdpZHRoOjY7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMTMwLTItMSIKICAgICAgICAgZD0iTSAyMiwzNiBWIDczIgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZWYyOTI5O3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICA8L2c+CiAgICA8ZwogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC41NjEzNzg3LDEuNTY0MTgyM2UtOCwwLDAuNTY1NzY5NzIsMjUuMDc4NjM2LC0xNy4xNTgxNSkiCiAgICAgICBpZD0iZzM4MjctMS0zLTkyLTEtNyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI2MC42ODgwNzYiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNjAuNjg4MDc2Ij4KICAgICAgPGcKICAgICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMzEuMzIyMTMxLDQwLjU3MDI4OSkiCiAgICAgICAgIGlkPSJnMzc5Ny05LTUtNjYtNy01Ij4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6I2VmMjkyOTtzdHJva2U6IzI4MDAwMDtzdHJva2Utd2lkdGg6My41NDg4MDUyNDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIGlkPSJwYXRoNDI1MC03MS02LTQ5LTItOSIKICAgICAgICAgICBkPSJNIC0yNi4xMTgyMjEsNS42NjQzMzQ3IEEgOC45Mzc5NzkzLDguODY4MDc3NCAwIDEgMSAtMTIuNTQwNjM0LDE3LjIwMDkwNiA4LjkzNzk3OTMsOC44NjgwNzc0IDAgMSAxIC0yNi4xMTgyMjEsNS42NjQzMzQ3IFoiIC8+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzODAxLTEtMy0xNC0wLTkpO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZWYyOTI5O3N0cm9rZS13aWR0aDozLjU0ODgwNDI4O3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgaWQ9InBhdGg0MjUwLTctMy0yLTUtNy0yIgogICAgICAgICAgIGQ9Im0gLTIzLjQwMjI3LDcuOTc0NDg1OCBhIDUuMzQzOTcwNiw1LjMwMjUyOTggMCAxIDEgOC4xMTc5NCw2Ljg5ODE0NTIgNS4zNDM5NzA2LDUuMzAyNTI5OCAwIDAgMSAtOC4xMTc5NCwtNi44OTgxNDUyIHoiIC8+CiAgICAgIDwvZz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo=\n\"\"\"\nCenters_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzMwNTIiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9IkNlbnRlcnMuc3ZnIgogICBpbmtzY2FwZTpvdXRwdXRfZXh0ZW5zaW9uPSJvcmcuaW5rc2NhcGUub3V0cHV0LnN2Zy5pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzMzA1NCI+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MTIiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzQ2NWE0O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzgxNCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4MTYiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MDMyIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcxYjJmODtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A0MDM0IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAyNzk1O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDQwMzYiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3o9IjY0IDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjMyIDogMjEuMzMzMzMzIDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTMwNjAiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMzNzciCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzNzA1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBjeD0iMTQ4Ljg4MzMzIgogICAgICAgY3k9IjgxLjg2OTU2OCIKICAgICAgIGZ4PSIxNDguODgzMzMiCiAgICAgICBmeT0iODEuODY5NTY4IgogICAgICAgcj0iMTkuNDY3NDM2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjYyNDQ2NjksLTAuMDUxMzY3ODMsMC4wNDM0NTUyMSwwLjk5OTMxMzIsLTEwMi45OTAzMyw3LjcwNDA0MzgpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzc3Ij4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzMzc5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM0YmZmNTQ7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDMzODEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwYjgwMDtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMjA2IgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzcwMyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgY3g9IjEzNS4zODMzMyIKICAgICAgIGN5PSI5Ny4zNjk1NjgiCiAgICAgICBmeD0iMTM1LjM4MzMzIgogICAgICAgZnk9Ijk3LjM2OTU2OCIKICAgICAgIHI9IjE5LjQ2NzQzNiIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44NzkwNDY4NCwwLjIyNTAzNzksLTAuNDE3MDkwOTcsMi4wMDE2NzI4LDU2LjczNzUxLC0xMjcuOTk4ODMpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTk5Ij4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzMjAxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmYWZmMmI7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDMyMDMiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmYWEwMDtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMzc3IgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzY5MiIKICAgICAgIGN4PSI0NS44ODMzMjciCiAgICAgICBjeT0iMjguODY5NTY4IgogICAgICAgZng9IjQ1Ljg4MzMyNyIKICAgICAgIGZ5PSIyOC44Njk1NjgiCiAgICAgICByPSIxOS40Njc0MzYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzIwNiI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzIwOCIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmFmZjJiO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzMjEwIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmFhMDA7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDAzMiIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDQwMzAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS4yNjAxNjQsLTAuMDUxMzY3ODMsMC4wMzM3MDk5NSwwLjk5OTMxMzIsLTQzLjEzOTc4MSw3LjIwNDQwNzcpIgogICAgICAgY3g9IjE0OC44ODMzMyIKICAgICAgIGN5PSI4MS44Njk1NjgiCiAgICAgICBmeD0iMTQ4Ljg4MzMzIgogICAgICAgZnk9IjgxLjg2OTU2OCIKICAgICAgIHI9IjE5LjQ2NzQzNiIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzgzNi0wLTYtOTItNC02IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgwMS0xLTMtMTQtMC0zIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iLTE4IgogICAgICAgeTE9IjE4IgogICAgICAgeDI9Ii0yMiIKICAgICAgIHkyPSI1IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjc2MzQyNDM5LDAsMCwwLjc1NzUwNDI1LC0wLjk4NzY3NTI0LC0zMi41NTEzNjUpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM2LTAtNi05Mi00LTYiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYTQwMDAwO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzgzOC0yLTctMDYtOC03IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWYyOTI5O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg0MC01LTUtOC03LTUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODEyIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgxOCIKICAgICAgIHgxPSIzMS4xNjgxODQiCiAgICAgICB5MT0iNTkuMDA4NjcxIgogICAgICAgeDI9IjI2LjU3MDMyNCIKICAgICAgIHkyPSI0NC4wMDgxNTIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjguMDc4MjkyOSIKICAgICBpbmtzY2FwZTpjeD0iMTcuMTM0OTc1IgogICAgIGlua3NjYXBlOmN5PSIyOC42ODg4NiIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJnMzc5Ny05LTUtNjYtNyIKICAgICBzaG93Z3JpZD0idHJ1ZSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTUzNiIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI4MDEiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy15PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIgogICAgIGlua3NjYXBlOnNuYXAtZ2xvYmFsPSJ0cnVlIgogICAgIHNob3dndWlkZXM9InRydWUiCiAgICAgaW5rc2NhcGU6Z3VpZGUtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTpzbmFwLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1ub2Rlcz0iZmFsc2UiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMzAwMSIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEzMDU3Ij4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzp0aXRsZT48L2RjOnRpdGxlPgogICAgICAgIDxkYzpjcmVhdG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W2ptYXVzdHBjXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6dGl0bGU+UGFydF9Qb2ludF9QYXJhbWV0cmljPC9kYzp0aXRsZT4KICAgICAgICA8ZGM6ZGF0ZT4yMDEzLTAzLTA1PC9kYzpkYXRlPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL1BhcnQvR3VpL1Jlc291cmNlcy9pY29ucy9QYXJ0X1BvaW50X1BhcmFtZXRyaWMuc3ZnPC9kYzppZGVudGlmaWVyPgogICAgICAgIDxkYzpyaWdodHM+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEIExHUEwyKzwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cmlnaHRzPgogICAgICAgIDxjYzpsaWNlbnNlPmh0dHBzOi8vd3d3LmdudS5vcmcvY29weWxlZnQvbGVzc2VyLmh0bWw8L2NjOmxpY2Vuc2U+CiAgICAgICAgPGRjOmNvbnRyaWJ1dG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W2Fncnlzb25dIEFsZXhhbmRlciBHcnlzb248L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciI+CiAgICA8cGF0aAogICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzIwNGE4NztzdHJva2Utd2lkdGg6Ni45MTAwMzk0MjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NC41O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIwLjQiCiAgICAgICBpZD0icGF0aDMwMjQiCiAgICAgICBzb2RpcG9kaTpjeD0iMzAuMDE4NzE5IgogICAgICAgc29kaXBvZGk6Y3k9IjUyLjA4NTM1NCIKICAgICAgIHNvZGlwb2RpOnJ4PSI4LjA0NjI1NDIiCiAgICAgICBzb2RpcG9kaTpyeT0iOC4wNzcyMDE4IgogICAgICAgZD0ibSAzOC4wNjQ5NzMsNTIuMDg1MzU0IGEgOC4wNDYyNTQyLDguMDc3MjAxOCAwIDEgMSAtMTYuMDkyNTA4LDAgOC4wNDYyNTQyLDguMDc3MjAxOCAwIDEgMSAxNi4wOTI1MDgsMCB6IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC44Njk5NzAwNSwwLDAsMC44NjY2MzY3Nyw1LjkxMDQ2ODksLTEzLjExMjk3NykiIC8+CiAgICA8cGF0aAogICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6dXJsKCNsaW5lYXJHcmFkaWVudDM4MTgpO3N0cm9rZS13aWR0aDoyLjMwMzM0NjYzO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0LjU7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MjAuNCIKICAgICAgIGlkPSJwYXRoMzAyNC0zIgogICAgICAgc29kaXBvZGk6Y3g9IjMwLjAxODcxOSIKICAgICAgIHNvZGlwb2RpOmN5PSI1Mi4wODUzNTQiCiAgICAgICBzb2RpcG9kaTpyeD0iOC4wNDYyNTQyIgogICAgICAgc29kaXBvZGk6cnk9IjguMDc3MjAxOCIKICAgICAgIGQ9Im0gMzguMDY0OTczLDUyLjA4NTM1NCBhIDguMDQ2MjU0Miw4LjA3NzIwMTggMCAxIDEgLTE2LjA5MjUwOCwwIDguMDQ2MjU0Miw4LjA3NzIwMTggMCAxIDEgMTYuMDkyNTA4LDAgeiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuODY5OTcwMDUsMCwwLDAuODY2NjM2NzcsNS45MTA0Njg5LC0xMy4xMTI5NzcpIiAvPgogICAgPGcKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuNTYxMzc4NywxLjU2NDE4MjNlLTgsMCwwLjU2NTc2OTcyLDIzLjI0ODE0MywyMi41NTg5MTYpIgogICAgICAgaWQ9ImczODI3LTEtMy05Mi0xIj4KICAgICAgPGcKICAgICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMzEuMzIyMTMxLDQwLjU3MDI4OSkiCiAgICAgICAgIGlkPSJnMzc5Ny05LTUtNjYtNyI+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgIHN0eWxlPSJmaWxsOiNlZjI5Mjk7c3Ryb2tlOiNhNDAwMDA7c3Ryb2tlLXdpZHRoOjMuNTQ4ODA1MjQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgICAgICBpZD0icGF0aDQyNTAtNzEtNi00OS0yIgogICAgICAgICAgIGQ9Ik0gLTIyLjUwOTUwNywtMjkuNjM5NTk0IEEgOC45Mzc5NzkzLDguODY4MDc3NCAwIDEgMSAtOC45MzE5MjA1LC0xOC4xMDMwMjMgOC45Mzc5NzkzLDguODY4MDc3NCAwIDEgMSAtMjIuNTA5NTA3LC0yOS42Mzk1OTQgeiIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM4MDEtMS0zLTE0LTAtMyk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNlZjI5Mjk7c3Ryb2tlLXdpZHRoOjMuNTQ4ODA0Mjg7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgICAgICBpZD0icGF0aDQyNTAtNy0zLTItNS03IgogICAgICAgICAgIGQ9Im0gLTE5Ljc5MzU1NiwtMjcuMzI5NDQzIGEgNS4zNDM5NzA2LDUuMzAyNTI5OCAwIDEgMSA4LjExNzkzOSw2Ljg5ODE0NSA1LjM0Mzk3MDYsNS4zMDI1Mjk4IDAgMCAxIC04LjExNzkzOSwtNi44OTgxNDUgeiIgLz4KICAgICAgPC9nPgogICAgPC9nPgogIDwvZz4KPC9zdmc+Cg==\n\"\"\"\nX_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzMwMDAiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9IlgtYXhpcy5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMzMDAyIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzM5MyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMzk1IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzM5NyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMzOTMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzk5IgogICAgICAgeDE9IjE5NDIuNzM4MiIKICAgICAgIHkxPSIxOTM0Ljc1NiIKICAgICAgIHgyPSIxODA5LjUwMjEiCiAgICAgICB5Mj0iMTU0Ny40MTM1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjk4NjU3ODExLDAsMCwwLjk5OTIyMDc4LDM3MDYuODY1OCwtMi42ODExNjk3KSIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUzMDA4IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMzkzLTciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzk5LTEiCiAgICAgICB4MT0iMTY2OS43MzE0IgogICAgICAgeTE9IjE3MjYuMDU4NSIKICAgICAgIHgyPSIyMDY3LjE3MDIiCiAgICAgICB5Mj0iMTcyNi4wNTg1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTg2NTc4MTEsMCwwLDAuOTk5MjIwNzgsMjAuMTI5MjUxLC0yLjY4MTE2OTcpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzkzLTciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAzZGRkO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDMzOTUtNCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzYzOWVmMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMzk3LTAiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzkzLTEiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzM5NS03IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzM5Ny00IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjkuNjg3NSIKICAgICBpbmtzY2FwZTpjeD0iMzIiCiAgICAgaW5rc2NhcGU6Y3k9IjMyIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImczNDA1IgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpncmlkLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxNTM2IgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjgwMSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOnNuYXAtYmJveD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6c25hcC1ub2Rlcz0idHJ1ZSIKICAgICBpbmtzY2FwZTpzbmFwLWdsb2JhbD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQyOTkwIgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIj4KICAgIDxnCiAgICAgICBpZD0iZzM0MDUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjEzNjkzNjUsMCwwLDAuMTM2OTM2NSwtMjIyLjIxNzU0LC0yMDMuMzY1MTIpIj4KICAgICAgPGcKICAgICAgICAgaWQ9ImczMTYwIgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCg4LjE4MTAyMjcsMCwwLDguMTgxMDIyNywxNzE2LjA5NDcsMTYwNi4xODAzKSIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9Ijc2Ljc2OTk5NyIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9Ijc2Ljc2OTk5NyI+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBpZD0icGF0aDMxNjIiCiAgICAgICAgICAgZD0ibSAxNS41OTA1NTEsMTEuNzYzNzggNy45MzcwMDgsMTEuNjU3NDggSCAxNy4zOTc2MzggTCAxMi4wNDcyNDQsMTUuNjI1OTg1IDYuNzY3NzE2NSwyMy40MjEyNiBIIDAuNjAyMzYyMiBMIDguNTAzOTM2OSwxMS43NjM3OCAwLjg4NTgyNjc2LDAuNjAyMzYyMjIgSCA3LjA1MTE4MSBMIDEyLjA0NzI0NCw3LjkzNzAwOCAxNy4wNDMzMDcsMC42MDIzNjIyMiBoIDYuMTY1MzU0IHoiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6I2ZmMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6I2Q0MDAwMDtzdHJva2Utd2lkdGg6MS4xNjkyOTEzOHB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgPC9nPgogICAgICA8ZwogICAgICAgICBpZD0iZzQ1MjciCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMTAzMjYxMSwtMC4xOTQ1MzQ2OSwwLjE5NDUzNDY5LDEuMTAzMjYxMSwtNTkwLjQ3NDU3LDEzNi4yOTc4KSIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9Ijc2Ljc2OTk5NyIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9Ijc2Ljc2OTk5NyI+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIgogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgaWQ9InBhdGg2Mzk3IgogICAgICAgICAgIGQ9Im0gMTc1OS42NTEzLDE3NjMuMzMxMyAxMzkuNTg2MSwxMTUuNjYzIgogICAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMyODAwMDA7c3Ryb2tlLXdpZHRoOjYyLjAzODI1Mzc4O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgIGlkPSJwYXRoNjM5Ny01IgogICAgICAgICAgIGQ9Im0gMTc1OS42NTEzLDE3NjMuMzMxMyAxMzkuNTg2MSwxMTUuNjYzIgogICAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNjYzAwMDA7c3Ryb2tlLXdpZHRoOjMxLjAxOTEyNjg5O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgIGlkPSJwYXRoNjM5Ny01LTAiCiAgICAgICAgICAgZD0ibSAxNzUzLjE0MjgsMTc2Ny43NzIxIDEzOS41ODYsMTE1LjY2MyIKICAgICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZWYyOTI5O3N0cm9rZS13aWR0aDoxNS41MDk1NjM0NTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjYyIKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgIGlkPSJwYXRoNjQ3NS0zIgogICAgICAgICAgIGQ9Im0gMTg1OC4xODE4LDE5MDUuNzgzMSBjIC0xLjgwOTEsLTMyLjgxMTkgNDcuNzcxNCwtNjcuNDQ2OSA3NS42NzM3LC02NS43Njk0IGwgMTkuNjY1NCw4OS41ODMyIHoiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6I2NjMDAwMDtzdHJva2U6IzI4MDAwMDtzdHJva2Utd2lkdGg6MTUuNTA5NTYzNDU7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjMyLjIwMDAwMDc2O3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2MiCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICBpZD0icGF0aDY0NzUtNi0yIgogICAgICAgICAgIGQ9Im0gMTg3NS40Nzg2LDE4OTUuMzAwOSBjIDMuNTksLTEzLjc3MzYgMjYuOTAyOCwtMzMuMzU1IDQ2LjA4NjksLTM4LjYzNzggbCAxMi4wOTEsNTIuNzc4NSB6IgogICAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNlZjI5Mjk7c3Ryb2tlLXdpZHRoOjE1LjUwOTU2MzQ1O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDozMi4yMDAwMDA3NjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8L2c+CiAgICA8L2c+CiAgPC9nPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTUzMjQiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlIC8+CiAgICAgICAgPGNjOmxpY2Vuc2UKICAgICAgICAgICByZGY6cmVzb3VyY2U9IiIgLz4KICAgICAgICA8ZGM6ZGF0ZT5Nb24gT2N0IDEwIDEzOjQ0OjUyIDIwMTEgKzAwMDA8L2RjOmRhdGU+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bd21heWVyXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8ZGM6cHVibGlzaGVyPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICAgIDxkYzppZGVudGlmaWVyPkZyZWVDQUQvc3JjL01vZC9EcmFmdC9SZXNvdXJjZXMvaWNvbnMvRHJhZnRfUm90YXRlLnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmVsYXRpb24+aHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZy93aWtpL2luZGV4LnBocD90aXRsZT1BcnR3b3JrPC9kYzpyZWxhdGlvbj4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bYWdyeXNvbl0gQWxleGFuZGVyIEdyeXNvbjwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y29udHJpYnV0b3I+CiAgICAgICAgPGRjOmRlc2NyaXB0aW9uPkFuIGFycm93IGluIGEgY2lyY3VsYXIgc2hhcGUgd2l0aCB0aGUgaGVhZCBjdXJ2aW5nIHRvd2FyZHMgdGhlIHRhaWw8L2RjOmRlc2NyaXB0aW9uPgogICAgICAgIDxkYzpzdWJqZWN0PgogICAgICAgICAgPHJkZjpCYWc+CiAgICAgICAgICAgIDxyZGY6bGk+YXJyb3c8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5jdXJ2ZWQ8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5yZWZyZXNoPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+cm90YXRlPC9yZGY6bGk+CiAgICAgICAgICA8L3JkZjpCYWc+CiAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KPC9zdmc+Cg==\n\"\"\"\nY_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzMwMDAiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9IlktYXhpcy5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiCiAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iQzpcQ2FkXFByb2dldHRpX0tcM0QtRnJlZUNhZC10b29sc1xpY29ucy1uZXdcWS1heGlzLnBuZyIKICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9Ijc2Ljc2OTk5NyIKICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9Ijc2Ljc2OTk5NyI+CiAgPGRlZnMKICAgICBpZD0iZGVmczMwMDIiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzkzIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzIwNGE4NztzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDMzOTUiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMzk3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzM5MyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMzOTkiCiAgICAgICB4MT0iMTk0Mi43MzgyIgogICAgICAgeTE9IjE5MzQuNzU2IgogICAgICAgeDI9IjE4MDkuNTAyMSIKICAgICAgIHkyPSIxNTQ3LjQxMzUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuOTg2NTc4MTEsMCwwLDAuOTk5MjIwNzgsMzcwNi44NjU4LC0yLjY4MTE2OTcpIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3o9IjY0IDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjMyIDogMjEuMzMzMzMzIDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTMwMDgiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMzOTMtNyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMzOTktMSIKICAgICAgIHgxPSIxNjY5LjczMTQiCiAgICAgICB5MT0iMTcyNi4wNTg1IgogICAgICAgeDI9IjIwNjcuMTcwMiIKICAgICAgIHkyPSIxNzI2LjA1ODUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45ODY1NzgxMSwwLDAsMC45OTkyMjA3OCwyMC4xMjkyNTEsLTIuNjgxMTY5NykiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMzOTMtNyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDNkZGQ7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzM5NS00IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNjM5ZWYwO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDMzOTctMCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMzOTMtMSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMzk1LTciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMzk3LTQiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHBhdHRlcm4KICAgICAgIHk9IjAiCiAgICAgICB4PSIwIgogICAgICAgaGVpZ2h0PSI2IgogICAgICAgd2lkdGg9IjYiCiAgICAgICBwYXR0ZXJuVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9IkVNRmhiYXNlcGF0dGVybiIgLz4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjkuNjg3NSIKICAgICBpbmtzY2FwZTpjeD0iMTQuNCIKICAgICBpbmtzY2FwZTpjeT0iMTguODQ1MjMxIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImczNDA1IgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpncmlkLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxNTM2IgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjgwMSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOnNuYXAtYmJveD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6c25hcC1ub2Rlcz0idHJ1ZSIKICAgICBpbmtzY2FwZTpzbmFwLWdsb2JhbD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQyOTkwIgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIj4KICAgIDxnCiAgICAgICBpZD0iZzM0MDUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjEzNjkzNjUsMCwwLDAuMTM2OTM2NSwtMjIyLjIxNzU0LC0yMDMuMzY1MTIpIj4KICAgICAgPHRleHQKICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZToyNjguNTc1MTAzNzZweDtsaW5lLWhlaWdodDoxMjUlO2ZvbnQtZmFtaWx5OidEZWphVnUgU2Fucyc7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonRGVqYVZ1IFNhbnMgQm9sZCc7bGV0dGVyLXNwYWNpbmc6MHB4O3dvcmQtc3BhY2luZzowcHg7ZGlzcGxheTppbmxpbmU7ZmlsbDojMDA4MDAwO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMDA1NTAwO3N0cm9rZS13aWR0aDoxMC4wMjM3MzUwNTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICB4PSIxNzUwLjc1NDgiCiAgICAgICAgIHk9IjE4MTYuOTA2MSIKICAgICAgICAgaWQ9InRleHQ0MTk5IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNzYuNzY5OTk3IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNzYuNzY5OTk3IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDAuOTkwNDg4NTQsMS4wMDk2MDI4KSI+PHRzcGFuCiAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICBpZD0idHNwYW40MjAxIgogICAgICAgICAgIHg9IjE3NTAuNzU0OCIKICAgICAgICAgICB5PSIxODE2LjkwNjEiCiAgICAgICAgICAgc3R5bGU9InN0cm9rZTojMDA1NTAwO3N0cm9rZS13aWR0aDoxMC4wMjM3MzUwNTtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSI+WTwvdHNwYW4+PC90ZXh0PgogICAgICA8ZwogICAgICAgICBpZD0iZzQ1NjciCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuODc5NTY2ODEsMCwwLDAuODk2NTQwNDgsMjA1LjQ1MDExLDI0Ny44NDU4MikiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI3Ni43Njk5OTciCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI3Ni43Njk5OTciPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICBzdHlsZT0iZmlsbDojOGFlMjM0O2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTojMTcyYTA0O3N0cm9rZS13aWR0aDoxNS43NzM2MTg3cHg7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgZD0ibSAxOTg0LjMwMjIsMTY1My45NDMxIGMgMTQuNjA1MiwyMS42MTU3IDcuNTk0Nyw1Ny44MzY2IC03LjU5NDcsNjQuODQ3MSAtMTUuNzczNiw3LjAxMDUgLTMyLjEzMTUsNy4wMTA1IC00Ni43MzY3LC0xNS4xODk0IC0xNC42MDUyLC0yMi4xOTk5IC0xOS44NjMsLTUwLjgyNjEgLTcuNTk0NywtNjQuMjYyOSAxMi4yNjg0LC0xNC4wMjEgNDcuMzIwOSwtNy41OTQ3IDYxLjkyNjEsMTQuNjA1MiB6IgogICAgICAgICAgIGlkPSJwYXRoNDUyMyIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6IzczZDIxNjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6IzE3MmEwNDtzdHJva2Utd2lkdGg6MTUuNzczNjE4N3B4O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIGQ9Im0gMTk4NC4zMDIyLDE3MTEuNzc5NyBjIDE1Ljc3MzYsLTIyLjE5OTkgMCwtODAuMDM2NSAtNDYuNzM2NywtODAuMDM2NSBoIDkzLjQ3MzMgeiIKICAgICAgICAgICBpZD0icGF0aDQ1MzEiIC8+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM4YWUyMzQ7c3Ryb2tlLXdpZHRoOjE1Ljc3MzYxODdweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIGQ9Im0gMTk2OS4xMTI4LDE2NDYuMzQ4NCBoIDUzLjc0NzEiCiAgICAgICAgICAgaWQ9InBhdGg0NTMzIiAvPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMTcyYTA0O3N0cm9rZS13aWR0aDoxNS43NzM2MTg3cHg7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgZD0ibSAxOTg0LjMwMjIsMTcxMS43Nzk3IGMgMTUuMTg5NCwtMjEuNjE1NyAwLC03OS40NTIzIC00Ni43MzY3LC03OS40NTIzIGggOTIuODg5MSB6IgogICAgICAgICAgIGlkPSJwYXRoNDUzNSIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzE3MmEwNDtzdHJva2Utd2lkdGg6NjEuOTI2MDU1OTFweDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgICBkPSJtIDE3MzYuMDEzOCwxNzk4LjI0MjUgMjAxLjU1MTcsLTExNS42NzMyIgogICAgICAgICAgIGlkPSJwYXRoNDUzNyIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzczZDIxNjtzdHJva2Utd2lkdGg6MzAuOTYzMDI3OTVweDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgICBkPSJtIDE3MzYuMDEzOCwxNzk4LjI0MjUgMjAxLjU1MTcsLTExNS42NzMyIgogICAgICAgICAgIGlkPSJwYXRoNDUzOSIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzhhZTIzNDtzdHJva2Utd2lkdGg6MTUuNzczNjE4N3B4O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIGQ9Im0gMTczMy4wOTI3LDE3OTEuMjMyIDIwMS41NTE4LC0xMTUuNjczMiIKICAgICAgICAgICBpZD0icGF0aDQ1NDEiIC8+CiAgICAgIDwvZz4KICAgIDwvZz4KICA8L2c+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhNTMyNCI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGUgLz4KICAgICAgICA8Y2M6bGljZW5zZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iIiAvPgogICAgICAgIDxkYzpkYXRlPk1vbiBPY3QgMTAgMTM6NDQ6NTIgMjAxMSArMDAwMDwvZGM6ZGF0ZT4KICAgICAgICA8ZGM6Y3JlYXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlt3bWF5ZXJdPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjcmVhdG9yPgogICAgICAgIDxkYzpyaWdodHM+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEIExHUEwyKzwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cmlnaHRzPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL0RyYWZ0L1Jlc291cmNlcy9pY29ucy9EcmFmdF9Sb3RhdGUuc3ZnPC9kYzppZGVudGlmaWVyPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlthZ3J5c29uXSBBbGV4YW5kZXIgR3J5c29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgICA8ZGM6ZGVzY3JpcHRpb24+QW4gYXJyb3cgaW4gYSBjaXJjdWxhciBzaGFwZSB3aXRoIHRoZSBoZWFkIGN1cnZpbmcgdG93YXJkcyB0aGUgdGFpbDwvZGM6ZGVzY3JpcHRpb24+CiAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICA8cmRmOkJhZz4KICAgICAgICAgICAgPHJkZjpsaT5hcnJvdzwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmN1cnZlZDwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPnJlZnJlc2g8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5yb3RhdGU8L3JkZjpsaT4KICAgICAgICAgIDwvcmRmOkJhZz4KICAgICAgICA8L2RjOnN1YmplY3Q+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgo8L3N2Zz4K\n\"\"\"\nZ_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzMwMDAiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9IlotQXhpcy5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMzMDAyIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzM5MyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMzk1IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzM5NyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMzOTMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzk5IgogICAgICAgeDE9IjE5NDIuNzM4MiIKICAgICAgIHkxPSIxOTM0Ljc1NiIKICAgICAgIHgyPSIxODA5LjUwMjEiCiAgICAgICB5Mj0iMTU0Ny40MTM1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjk4NjU3ODExLDAsMCwwLjk5OTIyMDc4LDM3MDYuODY1OCwtMi42ODExNjk3KSIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUzMDA4IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMzkzLTciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzk5LTEiCiAgICAgICB4MT0iMTY2OS43MzE0IgogICAgICAgeTE9IjE3MjYuMDU4NSIKICAgICAgIHgyPSIyMDY3LjE3MDIiCiAgICAgICB5Mj0iMTcyNi4wNTg1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTg2NTc4MTEsMCwwLDAuOTk5MjIwNzgsMjAuMTI5MjUxLC0yLjY4MTE2OTcpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzkzLTciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAzZGRkO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDMzOTUtNCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzYzOWVmMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMzk3LTAiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzkzLTEiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzM5NS03IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzM5Ny00IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjkuNjg3NSIKICAgICBpbmtzY2FwZTpjeD0iMTQuNCIKICAgICBpbmtzY2FwZTpjeT0iMzIiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iZzM0MDUiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE1MzYiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODAxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6c25hcC1iYm94PSJmYWxzZSIKICAgICBpbmtzY2FwZTpzbmFwLW5vZGVzPSJ0cnVlIgogICAgIGlua3NjYXBlOnNuYXAtZ2xvYmFsPSJmYWxzZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIj4KICAgIDxpbmtzY2FwZTpncmlkCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBpZD0iZ3JpZDI5OTAiCiAgICAgICBlbXBzcGFjaW5nPSIyIgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiCiAgICAgICBzbmFwdmlzaWJsZWdyaWRsaW5lc29ubHk9InRydWUiIC8+CiAgPC9zb2RpcG9kaTpuYW1lZHZpZXc+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPGcKICAgICAgIGlkPSJnMzQwNSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMTM2OTM2NSwwLDAsMC4xMzY5MzY1LC0yMjIuMjE3NTQsLTIwMy4zNjUxMikiPgogICAgICA8dGV4dAogICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjI3MS41MjU4Nzg5MXB4O2xpbmUtaGVpZ2h0Ojc2Ljk5OTk5ODA5JTtmb250LWZhbWlseTpTYW5zOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J1NhbnMgQm9sZCc7dGV4dC1hbGlnbjpzdGFydDtsZXR0ZXItc3BhY2luZzowcHg7d29yZC1zcGFjaW5nOjBweDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxMC4xMzM4Nzc3NTtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICB4PSIxODA0LjE2IgogICAgICAgICB5PSIxODAyLjQ2NjIiCiAgICAgICAgIGlkPSJ0ZXh0NDQ5OSIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9Ijc2Ljc3MDE0OSIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9Ijc2Ljc3MDE0OSI+PHRzcGFuCiAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICBpZD0idHNwYW40NDk3IgogICAgICAgICAgIHg9IjE4MDQuMTYiCiAgICAgICAgICAgeT0iMTgwMi40NjYyIgogICAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6MjcxLjUyNTg3ODkxcHg7bGluZS1oZWlnaHQ6NzYuOTk5OTk4MDklO2ZvbnQtZmFtaWx5OlNhbnM7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonU2FucyBCb2xkJzt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtmaWxsOiMwMDAwZmY7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEwLjEzMzg3Nzc1O3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiPlo8L3RzcGFuPjwvdGV4dD4KICAgICAgPGcKICAgICAgICAgaWQ9Imc0NTE5IgogICAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLC0xMzEuNDQ3NzkpIgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNzYuNzcwMTQ5IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNzYuNzcwMTQ5Ij4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgaWQ9InBhdGg2NDE5IgogICAgICAgICAgIGQ9Im0gMTc3NS4wMDY1LDE3NjEuODU0MSAzMS4wMTkxLDE1OS4wMzY2IgogICAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjYyLjAzODI1Mzc4O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICBpZD0icGF0aDY0MTktNiIKICAgICAgICAgICBkPSJtIDE3NzUuMDA2NSwxNzYxLjg1NDEgMzEuMDE5MSwxNTkuMDM2NiIKICAgICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMzQ2NWE0O3N0cm9rZS13aWR0aDozMS4wMTkxMjY4OTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgaWQ9InBhdGg2NDE5LTYtMiIKICAgICAgICAgICBkPSJtIDE3NjcuMjUxNywxNzYxLjg1NDEgMzEuMDE5MSwxNTkuMDM2NiIKICAgICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoxNS41MDk1NjM0NTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjYyIKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgIGlkPSJwYXRoNjQ3NSIKICAgICAgICAgICBkPSJtIDE4MjEuNTM1MiwxNzMyLjkzODMgYyAtMTYuMDMyNiwyOS4yNTkyIC03Ny41NDc4LDM2LjE0NDcgLTEwMC44MTIyLDIxLjY4NjggbCAzMS4wMTkxLC04Ni43NDcyIHoiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6IzM0NjVhNDtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MTUuNTA5NTYzNDU7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjMyLjIwMDAwMDc2O3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2MiCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICBpZD0icGF0aDY0NzUtNiIKICAgICAgICAgICBkPSJtIDE4MDAuNzYzMywxNzMzLjg2NzcgYyAtMTAuNTA2NCwxMC4yNDY1IC00MS4yMDQ0LDE2LjMxMzQgLTYwLjY0NzgsMTEuOTMxIGwgMTcuODg1OSwtNTEuMzI4NSB6IgogICAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjE1LjUwOTU2MzQ1O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDozMi4yMDAwMDA3NjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8L2c+CiAgICA8L2c+CiAgPC9nPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTUzMjQiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlIC8+CiAgICAgICAgPGNjOmxpY2Vuc2UKICAgICAgICAgICByZGY6cmVzb3VyY2U9IiIgLz4KICAgICAgICA8ZGM6ZGF0ZT5Nb24gT2N0IDEwIDEzOjQ0OjUyIDIwMTEgKzAwMDA8L2RjOmRhdGU+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bd21heWVyXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8ZGM6cHVibGlzaGVyPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICAgIDxkYzppZGVudGlmaWVyPkZyZWVDQUQvc3JjL01vZC9EcmFmdC9SZXNvdXJjZXMvaWNvbnMvRHJhZnRfUm90YXRlLnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmVsYXRpb24+aHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZy93aWtpL2luZGV4LnBocD90aXRsZT1BcnR3b3JrPC9kYzpyZWxhdGlvbj4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bYWdyeXNvbl0gQWxleGFuZGVyIEdyeXNvbjwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y29udHJpYnV0b3I+CiAgICAgICAgPGRjOmRlc2NyaXB0aW9uPkFuIGFycm93IGluIGEgY2lyY3VsYXIgc2hhcGUgd2l0aCB0aGUgaGVhZCBjdXJ2aW5nIHRvd2FyZHMgdGhlIHRhaWw8L2RjOmRlc2NyaXB0aW9uPgogICAgICAgIDxkYzpzdWJqZWN0PgogICAgICAgICAgPHJkZjpCYWc+CiAgICAgICAgICAgIDxyZGY6bGk+YXJyb3c8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5jdXJ2ZWQ8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5yZWZyZXNoPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+cm90YXRlPC9yZGY6bGk+CiAgICAgICAgICA8L3JkZjpCYWc+CiAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KPC9zdmc+Cg==\n\"\"\"\nUndo_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjkwLjAwMDAwMCIKICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjkwLjAwMDAwMCIKICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS9qaW1tYWMvRGVza3RvcC93aS1maS5wbmciCiAgIHdpZHRoPSI0OHB4IgogICBoZWlnaHQ9IjQ4cHgiCiAgIGlkPSJzdmcxMTMwMCIKICAgc29kaXBvZGk6dmVyc2lvbj0iMC4zMiIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45Mi4wIHIxNTI5OSIKICAgc29kaXBvZGk6ZG9jbmFtZT0iVW5kby5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMzIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MjMyNiI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMjMyOCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AyMzMwIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MjMxNiI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNjNGEwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMjMxOCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2M0YTAwMDtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AyMzIwIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MjMwOCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNlZGQ0MDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMjMxMCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2VkZDQwMDtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AyMzEyIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50ODY2MiI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wODY2NCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMDAwMDtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3A4NjY2IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50ODY2MiIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDg2NjgiCiAgICAgICBjeD0iMjQuODM3MTI2IgogICAgICAgY3k9IjM2LjQyMTEyNyIKICAgICAgIGZ4PSIyNC44MzcxMjYiCiAgICAgICBmeT0iMzYuNDIxMTI3IgogICAgICAgcj0iMTUuNjQ0NzM3IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjAwMDAwMCwwLjAwMDAwMCwwLjAwMDAwMCwwLjUzNjcyMywtNi4yMjcyNjVlLTE0LDE2Ljg3MzA2KSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyMTg3IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyMTg5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDIxOTEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MDsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyMTg3IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MTc2NCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMS44MTM0NzFlLTE2LC0xLjE3MTkyNiwtMS4xNzE5MjYsMS44MTM0NzFlLTE2LDQ2LjE3NDQwLDU0LjEwMTExKSIKICAgICAgIHgxPSIxNy4wNjA4MDYiCiAgICAgICB5MT0iMTEuMzk1MDIiCiAgICAgICB4Mj0iMTIuNjI0MzM3IgogICAgICAgeTI9IjEyLjU4Mzc2OSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MjMwOCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDIzMTQiCiAgICAgICB4MT0iMjYuNSIKICAgICAgIHkxPSIzNC4yNSIKICAgICAgIHgyPSIyNi4yNSIKICAgICAgIHkyPSI0My41NzE4MzEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MjMxNiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDIzMjIiCiAgICAgICB4MT0iMjYuNSIKICAgICAgIHkxPSIzNC4yNSIKICAgICAgIHgyPSIyNi4yNSIKICAgICAgIHkyPSI0My41NzE4MzEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MjMyNiIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDIzMzIiCiAgICAgICBjeD0iMTUuMDk0MDMiCiAgICAgICBjeT0iMTMuMjgyNzIxIgogICAgICAgZng9IjE1LjA5NDAzIgogICAgICAgZnk9IjEzLjI4MjcyMSIKICAgICAgIHI9IjEwLjE2NDY2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjQ5NjAzMSwtMS4xNTE5MDVlLTE2LDEuMDYxNzU2ZS0xNiwyLjMwMDY4OSwtMjUuMTI0MDIsLTE3LjgyNjM2KSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgc3Ryb2tlPSIjYzRhMDAwIgogICAgIGZpbGw9IiNlZGQ0MDAiCiAgICAgaWQ9ImJhc2UiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjAuMjU0OTAxOTYiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjgiCiAgICAgaW5rc2NhcGU6Y3g9IjI0IgogICAgIGlua3NjYXBlOmN5PSIyNCIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgc2hvd2dyaWQ9ImZhbHNlIgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9ImZhbHNlIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iODkxIgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9Ijg2NCIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iMjkxIgogICAgIGlua3NjYXBlOndpbmRvdy15PSI2OCIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIwIiAvPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTQiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5KYWt1YiBTdGVpbmVyPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjcmVhdG9yPgogICAgICAgIDxkYzpzb3VyY2U+aHR0cDovL2ppbW1hYy5tdXNpY2hhbGwuY3o8L2RjOnNvdXJjZT4KICAgICAgICA8Y2M6bGljZW5zZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvMi4wLyIgLz4KICAgICAgICA8ZGM6dGl0bGU+PC9kYzp0aXRsZT4KICAgICAgICA8ZGM6c3ViamVjdD4KICAgICAgICAgIDxyZGY6QmFnPgogICAgICAgICAgICA8cmRmOmxpPmVkaXQ8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT51bmRvPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+cmV2ZXJ0PC9yZGY6bGk+CiAgICAgICAgICA8L3JkZjpCYWc+CiAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICA8L2NjOldvcms+CiAgICAgIDxjYzpMaWNlbnNlCiAgICAgICAgIHJkZjphYm91dD0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvMi4wLyI+CiAgICAgICAgPGNjOnBlcm1pdHMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly93ZWIucmVzb3VyY2Uub3JnL2NjL1JlcHJvZHVjdGlvbiIgLz4KICAgICAgICA8Y2M6cGVybWl0cwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3dlYi5yZXNvdXJjZS5vcmcvY2MvRGlzdHJpYnV0aW9uIiAvPgogICAgICAgIDxjYzpyZXF1aXJlcwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3dlYi5yZXNvdXJjZS5vcmcvY2MvTm90aWNlIiAvPgogICAgICAgIDxjYzpyZXF1aXJlcwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3dlYi5yZXNvdXJjZS5vcmcvY2MvQXR0cmlidXRpb24iIC8+CiAgICAgICAgPGNjOnBlcm1pdHMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly93ZWIucmVzb3VyY2Uub3JnL2NjL0Rlcml2YXRpdmVXb3JrcyIgLz4KICAgICAgICA8Y2M6cmVxdWlyZXMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly93ZWIucmVzb3VyY2Uub3JnL2NjL1NoYXJlQWxpa2UiIC8+CiAgICAgIDwvY2M6TGljZW5zZT4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIj4KICAgIDxwYXRoCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgtMS40ODk3MzYsMC4wMDAwMDAsMC4wMDAwMDAsLTEuMDAxMjUyLDYwLjYwNDM2LDc1LjMxMjYwKSIKICAgICAgIGQ9Ik0gNDAuNDgxODYzIDM2LjQyMTEyNyBBIDE1LjY0NDczNyA4LjM5Njg5MzUgMCAxIDEgIDkuMTkyMzg4NSwzNi40MjExMjcgQSAxNS42NDQ3MzcgOC4zOTY4OTM1IDAgMSAxICA0MC40ODE4NjMgMzYuNDIxMTI3IHoiCiAgICAgICBzb2RpcG9kaTpyeT0iOC4zOTY4OTM1IgogICAgICAgc29kaXBvZGk6cng9IjE1LjY0NDczNyIKICAgICAgIHNvZGlwb2RpOmN5PSIzNi40MjExMjciCiAgICAgICBzb2RpcG9kaTpjeD0iMjQuODM3MTI2IgogICAgICAgaWQ9InBhdGg4NjYwIgogICAgICAgc3R5bGU9Im9wYWNpdHk6MC4xNDExNzY0Nztjb2xvcjojMDAwMDAwO2ZpbGw6dXJsKCNyYWRpYWxHcmFkaWVudDg2NjgpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO21hcmtlcjpub25lO21hcmtlci1zdGFydDpub25lO21hcmtlci1taWQ6bm9uZTttYXJrZXItZW5kOm5vbmU7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgIHNvZGlwb2RpOnR5cGU9ImFyYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0ib3BhY2l0eToxO2NvbG9yOiMwMDAwMDA7ZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MjMxNCk7ZmlsbC1vcGFjaXR5OjEuMDtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6dXJsKCNsaW5lYXJHcmFkaWVudDIzMjIpO3N0cm9rZS13aWR0aDoxLjAwMDAwMDEyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO21hcmtlcjpub25lO21hcmtlci1zdGFydDpub25lO21hcmtlci1taWQ6bm9uZTttYXJrZXItZW5kOm5vbmU7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmJsb2NrO292ZXJmbG93OnZpc2libGUiCiAgICAgICBkPSJNIDkuNTgyNDQxLDQ1LjAzNDM2OSBDIDQ5LjYwODI0OSw0Ni4zNTU1MDkgNDMuMjgyNDA1LDEyLjI5MzU1IDIyLjQ2MjQxMSwxMi40OTc2NSBMIDIyLjQ2MjQxMSwzLjEyMjIzOTYgTCA1LjgxMzkyOTgsMTcuNzA4ODE5IEwgMjIuNDYyNDExLDMzLjAwNjM0OSBDIDIyLjQ2MjQxMSwzMy4wMDYzNDkgMjIuNDYyNDExLDIzLjMzNzk2OSAyMi40NjI0MTEsMjMuMzM3OTY5IEMgMzYuNTI1NTIxLDIyLjc1MTk5OSA0MC42Mzk5MzksNDQuNzcwNTQ5IDkuNTgyNDQxLDQ1LjAzNDM2OSB6ICIKICAgICAgIGlkPSJwYXRoMTQzMiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiCiAgICAgICBpZD0icGF0aDIxNzciCiAgICAgICBkPSJNIDMxLjAzMjI4MSwzOS4zMTU1MTkgQyA0Mi43NTUzOCwzMy4yMzU4OTIgMzkuMjIwMDczLDEzLjA4NzQ4OSAyMS40NDg3MDEsMTMuNTQ5OTU5IEwgMjEuNDQ4NzAxLDUuNDUwODY3OCBDIDIxLjQ0ODcwMSw1LjQ1MDg2NzggNy40MDA5NjI4LDE3LjcxNDU4OSA3LjQwMDk2MjgsMTcuNzE0NTg5IEwgMjEuNDQ4NzAxLDMwLjY1ODYxNyBDIDIxLjQ0ODcwMSwzMC42NTg2MTcgMjEuNDQ4NzAxLDIyLjM4MDk3OSAyMS40NDg3MDEsMjIuMzgwOTc5IEMgMzYuMjg4NTUxLDIyLjAzMjcwOSAzNS42MDg2MTEsMzUuMTM4NTc5IDMxLjAzMjI4MSwzOS4zMTU1MTkgeiAiCiAgICAgICBzdHlsZT0ib3BhY2l0eTowLjY5ODg2MzYxO2NvbG9yOiMwMDAwMDA7ZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTp1cmwoI2xpbmVhckdyYWRpZW50MTc2NCk7c3Ryb2tlLXdpZHRoOjAuOTk5OTk5NztzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjttYXJrZXI6bm9uZTttYXJrZXItc3RhcnQ6bm9uZTttYXJrZXItbWlkOm5vbmU7bWFya2VyLWVuZDpub25lO3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjE7dmlzaWJpbGl0eTp2aXNpYmxlO2Rpc3BsYXk6YmxvY2s7b3ZlcmZsb3c6dmlzaWJsZSIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0ib3BhY2l0eTowLjUxMTM2MzY0O2NvbG9yOiMwMDAwMDA7ZmlsbDp1cmwoI3JhZGlhbEdyYWRpZW50MjMzMik7ZmlsbC1vcGFjaXR5OjEuMDtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjttYXJrZXI6bm9uZTttYXJrZXItc3RhcnQ6bm9uZTttYXJrZXItbWlkOm5vbmU7bWFya2VyLWVuZDpub25lO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgIGQ9Ik0gNi42MjkxMjYxLDE3LjY4Mjc5NyBMIDEyLjI4NTk4LDIzLjA3NDQ4NiBDIDE4LjU2MTU1MywyMi44OTc3MDkgMTUuNzMzMTI2LDE2LjcxMDUyNSAyNi45NTg0NDYsMTMuNjE2OTMzIEwgMjIuMDA4Njk5LDEyLjk5ODIxNCBMIDIxLjkyMDMxLDQuMzM2MTU2MiBMIDYuNjI5MTI2MSwxNy42ODI3OTcgeiAiCiAgICAgICBpZD0icGF0aDIzMjQiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjYyIgLz4KICA8L2c+Cjwvc3ZnPgo=\n\"\"\"\nMove_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI5NjMiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9Ik1vdmUuc3ZnIgogICBpbmtzY2FwZTpvdXRwdXRfZXh0ZW5zaW9uPSJvcmcuaW5rc2NhcGUub3V0cHV0LnN2Zy5pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzMjk2NSI+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMzNTQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjE1N2M3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDMzNTYiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM2ZGFhZmY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzM1OCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfej0iNjQgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMzIgOiAyMS4zMzMzMzMgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMjk3MSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLC0xLjQ1MDAwMDEsMS40NzA1ODgyLDAsLTE1LjA1ODgyLDkxLjQ1KSIKICAgICAgIHkyPSIzNi4wNzk5OTgiCiAgICAgICB4Mj0iMjEuNjg5NjUzIgogICAgICAgeTE9IjI5LjI3OTk5OSIKICAgICAgIHgxPSI1Ni4xNzI0MDkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwMzYiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODk3IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzYuMDc5OTk4IgogICAgICAgeDI9IjIxLjY4OTY1MyIKICAgICAgIHkxPSIyOS4yNzk5OTkiCiAgICAgICB4MT0iNTYuMTcyNDA5IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLC0wLjU4MDAwMDAzLDAuNTg4MjM1MjcsMCwxMy4xNzY0NzEsMzguMzc5OTk5KSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzkxOC0zIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1LTYiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTctNyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzIwNGE4NztzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODk5LTUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzYuMDc5OTk4IgogICAgICAgeDI9IjIxLjY4OTY1MyIKICAgICAgIHkxPSIyOS4yNzk5OTkiCiAgICAgICB4MT0iNTYuMTcyNDA5IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjU4MDAwMDAzLDAsMCwwLjU4ODIzNTI3LDI1LjYyMDAwMSwxMy4xNzY0NzEpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDI5LTYiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtMiIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg5NS02LTIiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTctNy05IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTktNS0xIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjM2LjA3OTk5OCIKICAgICAgIHgyPSIyMS42ODk2NTMiCiAgICAgICB5MT0iMjkuMjc5OTk5IgogICAgICAgeDE9IjU2LjE3MjQwOSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMCwtMC41ODAwMDAwMywwLjU4ODIzNTI3LDAsMTMuMTc2NDcxLDM4LjM3OTk5OSkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM5MTgtMCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtOSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg5NS05Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODk3LTMiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OS02IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNTQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMCwtMC41ODAwMDAwMywwLjU4ODIzNTI3LDAsMTMuMTc2NDcxLDM4LjM3OTk5OSkiCiAgICAgICB4MT0iNDUuNDgyNzU0IgogICAgICAgeTE9IjExLjU5OTk5OSIKICAgICAgIHgyPSItMjMuNDgyNzU5IgogICAgICAgeTI9IjUyLjQwMDAwMiIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTIiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTU2IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjU4MDAwMDAzLDAsMCwwLjU4ODIzNTI3LDM4LjM3OTk5OSwxMy4xNzY0NzEpIgogICAgICAgeDE9IjMxLjY4OTY1MSIKICAgICAgIHkxPSItMi4wMDAwMDA3IgogICAgICAgeDI9Ii05LjY4OTY1NjMiCiAgICAgICB5Mj0iNjYiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNTgiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC41ODAwMDAwMywwLDAsMC41ODgyMzUyNywyNS42MjAwMDEsMTMuMTc2NDcxKSIKICAgICAgIHgxPSItOS42ODk2NTYzIgogICAgICAgeTE9Ii0yLjAwMDAwMDciCiAgICAgICB4Mj0iMzEuNjg5NjUxIgogICAgICAgeTI9IjY2IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTkiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTYwIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAsMC41ODAwMDAwMywwLjU4ODIzNTI3LDAsMTMuMTc2NDcxLDI1LjYyMDAwMSkiCiAgICAgICB4MT0iLTIzLjQ4Mjc1OSIKICAgICAgIHkxPSIxMS41OTk5OTkiCiAgICAgICB4Mj0iNDUuNDgyNzU0IgogICAgICAgeTI9IjUyLjQwMDAwMiIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS05IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzkzNiIKICAgICAgIHgxPSIyMCIKICAgICAgIHkxPSIxMiIKICAgICAgIHgyPSI0NCIKICAgICAgIHkyPSI1MiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTkiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTQ0IgogICAgICAgeDE9IjIwIgogICAgICAgeTE9IjEyIgogICAgICAgeDI9IjQ0IgogICAgICAgeTI9IjUyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI5LjY4NzUiCiAgICAgaW5rc2NhcGU6Y3g9IjMyIgogICAgIGlua3NjYXBlOmN5PSIzMiIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE1MzYiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODAxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6c25hcC1nbG9iYWw9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQzMDA5IgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMzAxMSIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIKICAgICAgIHNwYWNpbmd4PSIxNiIKICAgICAgIHNwYWNpbmd5PSIxNiIKICAgICAgIGVtcGNvbG9yPSIjZmYwMDAwIgogICAgICAgZW1wb3BhY2l0eT0iMC4yNTA5ODAzOSIKICAgICAgIGNvbG9yPSIjZmYwMDAwIgogICAgICAgb3BhY2l0eT0iMC4xMjU0OTAyIgogICAgICAgb3JpZ2lueD0iMCIKICAgICAgIG9yaWdpbnk9IjAiIC8+CiAgPC9zb2RpcG9kaTpuYW1lZHZpZXc+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPHJlY3QKICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzOTM2KTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSIKICAgICAgIGlkPSJyZWN0MzEyNiIKICAgICAgIHdpZHRoPSIxMiIKICAgICAgIGhlaWdodD0iNiIKICAgICAgIHg9IjI2IgogICAgICAgeT0iMjkiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNTEuMjAwMDU4IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjUxLjIwMDA1OCIgLz4KICAgIDxyZWN0CiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50Mzk0NCk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmUiCiAgICAgICBpZD0icmVjdDMxMjYtMiIKICAgICAgIHdpZHRoPSI2IgogICAgICAgaGVpZ2h0PSIxMS45OTk5OTkiCiAgICAgICB4PSIyOSIKICAgICAgIHk9IjI2IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjUxLjIwMDA1OCIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI1MS4yMDAwNTgiIC8+CiAgICA8ZwogICAgICAgaWQ9Imc0MzUxIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL21vdmUucG5nIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjYuNTU5MTU2NCIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI2LjU1OTE1NjQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjEzNzgxMzMsMCwwLDAuMTM3ODEzMywtMjIxLjM5Njk5LC0xMzguMzUyNzUpIiAvPgogICAgPHBhdGgKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzE1NCk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgIGQ9Im0gMzcsMjggMCwtMTUgNiwwIC0xMSwtMTAgLTExLDEwIDYsMCAwLDE1IgogICAgICAgaWQ9InBhdGgzMzQzIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjUxLjIwMDA1OCIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI1MS4yMDAwNTgiIC8+CiAgICA8cGF0aAogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgIGQ9Ik0gMzUsMjkgMzUsMTEgMzcuODMxMjU5LDExIDMyLDUuNzAyNjkzNyAyNi4xNjg3NDEsMTEgMjksMTEgMjksMjkiCiAgICAgICBpZD0icGF0aDMzNDMtMiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjYyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI1MS4yMDAwNTgiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNTEuMjAwMDU4IiAvPgogICAgPHBhdGgKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzE1OCk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgIGQ9Im0gMzcsMzcgMTQsMCAwLDYgMTAsLTExIC0xMCwtMTEgMCw2IC0xNCwwIgogICAgICAgaWQ9InBhdGgzMzQzLTMiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNTEuMjAwMDU4IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjUxLjIwMDA1OCIgLz4KICAgIDxwYXRoCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgZD0ibSAzNSwzNSAxOCwwIDAsMi44MzEyNTkgTCA1OC4yOTczMDYsMzIgNTMsMjYuMTY4NzQxIDUzLDI5IDM0LDI5IgogICAgICAgaWQ9InBhdGgzMzQzLTItNSIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjYyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI1MS4yMDAwNTgiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNTEuMjAwMDU4IiAvPgogICAgPHBhdGgKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzE1Nik7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgIGQ9Im0gMjcsMzcgLTE0LDAgMCw2IC0xMCwtMTEgMTAsLTExIDAsNiAxNCwwIgogICAgICAgaWQ9InBhdGgzMzQzLTMtMiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjYyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI1MS4yMDAwNTgiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNTEuMjAwMDU4IiAvPgogICAgPHBhdGgKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICBkPSJNIDI5LDM1IDExLDM1IDExLDM3LjgzMTI1OSA1LjcwMjY5NCwzMiAxMSwyNi4xNjg3NDEgMTEsMjkgMzAsMjkiCiAgICAgICBpZD0icGF0aDMzNDMtMi01LTciCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNTEuMjAwMDU4IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjUxLjIwMDA1OCIgLz4KICAgIDxwYXRoCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDMxNjApO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICBkPSJtIDM3LDM2IDAsMTUgNiwwIC0xMSwxMCAtMTEsLTEwIDYsMCAwLC0xNSIKICAgICAgIGlkPSJwYXRoMzM0My0wIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjUxLjIwMDA1OCIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI1MS4yMDAwNTgiIC8+CiAgICA8cGF0aAogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgIGQ9Im0gMzUsMzQgMCwxOSAyLjgzMTI1OSwwIEwgMzIsNTguMjk3MzA2IDI2LjE2ODc0MSw1MyAyOSw1MyAyOSwzNCIKICAgICAgIGlkPSJwYXRoMzM0My0yLTYiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNTEuMjAwMDU4IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjUxLjIwMDA1OCIgLz4KICA8L2c+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhNTAwNiI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGU+PC9kYzp0aXRsZT4KICAgICAgICA8Y2M6bGljZW5zZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iIiAvPgogICAgICAgIDxkYzpkYXRlPk1vbiBPY3QgMTAgMTM6NDQ6NTIgMjAxMSArMDAwMDwvZGM6ZGF0ZT4KICAgICAgICA8ZGM6Y3JlYXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlt3bWF5ZXJdPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjcmVhdG9yPgogICAgICAgIDxkYzpyaWdodHM+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEIExHUEwyKzwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cmlnaHRzPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL0RyYWZ0L1Jlc291cmNlcy9pY29ucy9EcmFmdF9Nb3ZlLnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmVsYXRpb24+aHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZy93aWtpL2luZGV4LnBocD90aXRsZT1BcnR3b3JrPC9kYzpyZWxhdGlvbj4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bYWdyeXNvbl0gQWxleGFuZGVyIEdyeXNvbjwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y29udHJpYnV0b3I+CiAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICA8cmRmOkJhZz4KICAgICAgICAgICAgPHJkZjpsaT5hcnJvdzwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPm1vdmU8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5hcnJvd3M8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5jb21wYXNzPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+Y3Jvc3M8L3JkZjpsaT4KICAgICAgICAgIDwvcmRmOkJhZz4KICAgICAgICA8L2RjOnN1YmplY3Q+CiAgICAgICAgPGRjOmRlc2NyaXB0aW9uPkZvdXIgZXF1YWxseSBzaXplZCBhcnJvdyBoZWFkcyBhdCA5MMKwIHRvIGVhY2hvdGhlciwgYWxsIGpvaW5lZCBhdCB0aGUgdGFpbDwvZGM6ZGVzY3JpcHRpb24+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgo8L3N2Zz4K\n\"\"\"\nMove_Green_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI5NjMiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9Ik1vdmUtZ3JlZW4uc3ZnIgogICBpbmtzY2FwZTpvdXRwdXRfZXh0ZW5zaW9uPSJvcmcuaW5rc2NhcGUub3V0cHV0LnN2Zy5pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzMjk2NSI+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMzNTQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjE1N2M3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDMzNTYiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM2ZGFhZmY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzM1OCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfej0iNjQgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMzIgOiAyMS4zMzMzMzMgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMjk3MSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLC0xLjQ1MDAwMDEsMS40NzA1ODgyLDAsLTE1LjA1ODgyLDkxLjQ1KSIKICAgICAgIHkyPSIzNi4wNzk5OTgiCiAgICAgICB4Mj0iMjEuNjg5NjUzIgogICAgICAgeTE9IjI5LjI3OTk5OSIKICAgICAgIHgxPSI1Ni4xNzI0MDkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwMzYiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODk3IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzYuMDc5OTk4IgogICAgICAgeDI9IjIxLjY4OTY1MyIKICAgICAgIHkxPSIyOS4yNzk5OTkiCiAgICAgICB4MT0iNTYuMTcyNDA5IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLC0wLjU4MDAwMDAzLDAuNTg4MjM1MjcsMCwxMy4xNzY0NzEsMzguMzc5OTk5KSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzkxOC0zIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1LTYiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTctNyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzIwNGE4NztzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODk5LTUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzYuMDc5OTk4IgogICAgICAgeDI9IjIxLjY4OTY1MyIKICAgICAgIHkxPSIyOS4yNzk5OTkiCiAgICAgICB4MT0iNTYuMTcyNDA5IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjU4MDAwMDAzLDAsMCwwLjU4ODIzNTI3LDI1LjYyMDAwMSwxMy4xNzY0NzEpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDI5LTYiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtMiIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg5NS02LTIiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTctNy05IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTktNS0xIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjM2LjA3OTk5OCIKICAgICAgIHgyPSIyMS42ODk2NTMiCiAgICAgICB5MT0iMjkuMjc5OTk5IgogICAgICAgeDE9IjU2LjE3MjQwOSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMCwtMC41ODAwMDAwMywwLjU4ODIzNTI3LDAsMTMuMTc2NDcxLDM4LjM3OTk5OSkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM5MTgtMCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtOSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg5NS05Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODk3LTMiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OS02IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNTQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMCwtMC41ODAwMDAwMywwLjU4ODIzNTI3LDAsMTMuMTc2NDcxLDM4LjM3OTk5OSkiCiAgICAgICB4MT0iNDUuNDgyNzU0IgogICAgICAgeTE9IjExLjU5OTk5OSIKICAgICAgIHgyPSItMjMuNDgyNzU5IgogICAgICAgeTI9IjUyLjQwMDAwMiIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTIiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTU2IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjU4MDAwMDAzLDAsMCwwLjU4ODIzNTI3LDM4LjM3OTk5OSwxMy4xNzY0NzEpIgogICAgICAgeDE9IjMxLjY4OTY1MSIKICAgICAgIHkxPSItMi4wMDAwMDA3IgogICAgICAgeDI9Ii05LjY4OTY1NjMiCiAgICAgICB5Mj0iNjYiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNTgiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC41ODAwMDAwMywwLDAsMC41ODgyMzUyNywyNS42MjAwMDEsMTMuMTc2NDcxKSIKICAgICAgIHgxPSItOS42ODk2NTYzIgogICAgICAgeTE9Ii0yLjAwMDAwMDciCiAgICAgICB4Mj0iMzEuNjg5NjUxIgogICAgICAgeTI9IjY2IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTkiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTYwIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAsMC41ODAwMDAwMywwLjU4ODIzNTI3LDAsMTMuMTc2NDcxLDI1LjYyMDAwMSkiCiAgICAgICB4MT0iLTIzLjQ4Mjc1OSIKICAgICAgIHkxPSIxMS41OTk5OTkiCiAgICAgICB4Mj0iNDUuNDgyNzU0IgogICAgICAgeTI9IjUyLjQwMDAwMiIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS05IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzkzNiIKICAgICAgIHgxPSIyMCIKICAgICAgIHkxPSIxMiIKICAgICAgIHgyPSI0NCIKICAgICAgIHkyPSI1MiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTkiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTQ0IgogICAgICAgeDE9IjIwIgogICAgICAgeTE9IjEyIgogICAgICAgeDI9IjQ0IgogICAgICAgeTI9IjUyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8ZmlsdGVyCiAgICAgICBzdHlsZT0iY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOnNSR0I7IgogICAgICAgaW5rc2NhcGU6bGFiZWw9IkNvbG9yIFNoaWZ0IgogICAgICAgaWQ9ImZpbHRlcjg1NSI+CiAgICAgIDxmZUNvbG9yTWF0cml4CiAgICAgICAgIHR5cGU9Imh1ZVJvdGF0ZSIKICAgICAgICAgdmFsdWVzPSIyNzQiCiAgICAgICAgIHJlc3VsdD0iY29sb3IxIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDg1MSIgLz4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0ic2F0dXJhdGUiCiAgICAgICAgIHZhbHVlcz0iMC42IgogICAgICAgICByZXN1bHQ9ImNvbG9yMiIKICAgICAgICAgaWQ9ImZlQ29sb3JNYXRyaXg4NTMiIC8+CiAgICA8L2ZpbHRlcj4KICAgIDxmaWx0ZXIKICAgICAgIHN0eWxlPSJjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM6c1JHQjsiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iQ29sb3IgU2hpZnQiCiAgICAgICBpZD0iZmlsdGVyODYxIj4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0iaHVlUm90YXRlIgogICAgICAgICB2YWx1ZXM9IjI3NCIKICAgICAgICAgcmVzdWx0PSJjb2xvcjEiCiAgICAgICAgIGlkPSJmZUNvbG9yTWF0cml4ODU3IiAvPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICB0eXBlPSJzYXR1cmF0ZSIKICAgICAgICAgdmFsdWVzPSIwLjYiCiAgICAgICAgIHJlc3VsdD0iY29sb3IyIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDg1OSIgLz4KICAgIDwvZmlsdGVyPgogICAgPGZpbHRlcgogICAgICAgc3R5bGU9ImNvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpzUkdCOyIKICAgICAgIGlua3NjYXBlOmxhYmVsPSJDb2xvciBTaGlmdCIKICAgICAgIGlkPSJmaWx0ZXI4NjciPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICB0eXBlPSJodWVSb3RhdGUiCiAgICAgICAgIHZhbHVlcz0iMjc0IgogICAgICAgICByZXN1bHQ9ImNvbG9yMSIKICAgICAgICAgaWQ9ImZlQ29sb3JNYXRyaXg4NjMiIC8+CiAgICAgIDxmZUNvbG9yTWF0cml4CiAgICAgICAgIHR5cGU9InNhdHVyYXRlIgogICAgICAgICB2YWx1ZXM9IjAuNiIKICAgICAgICAgcmVzdWx0PSJjb2xvcjIiCiAgICAgICAgIGlkPSJmZUNvbG9yTWF0cml4ODY1IiAvPgogICAgPC9maWx0ZXI+CiAgICA8ZmlsdGVyCiAgICAgICBzdHlsZT0iY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOnNSR0I7IgogICAgICAgaW5rc2NhcGU6bGFiZWw9IkNvbG9yIFNoaWZ0IgogICAgICAgaWQ9ImZpbHRlcjg3MyI+CiAgICAgIDxmZUNvbG9yTWF0cml4CiAgICAgICAgIHR5cGU9Imh1ZVJvdGF0ZSIKICAgICAgICAgdmFsdWVzPSIyNzQiCiAgICAgICAgIHJlc3VsdD0iY29sb3IxIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDg2OSIgLz4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0ic2F0dXJhdGUiCiAgICAgICAgIHZhbHVlcz0iMC42IgogICAgICAgICByZXN1bHQ9ImNvbG9yMiIKICAgICAgICAgaWQ9ImZlQ29sb3JNYXRyaXg4NzEiIC8+CiAgICA8L2ZpbHRlcj4KICAgIDxmaWx0ZXIKICAgICAgIHN0eWxlPSJjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM6c1JHQjsiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iQ29sb3IgU2hpZnQiCiAgICAgICBpZD0iZmlsdGVyODc5Ij4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0iaHVlUm90YXRlIgogICAgICAgICB2YWx1ZXM9IjI3NCIKICAgICAgICAgcmVzdWx0PSJjb2xvcjEiCiAgICAgICAgIGlkPSJmZUNvbG9yTWF0cml4ODc1IiAvPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICB0eXBlPSJzYXR1cmF0ZSIKICAgICAgICAgdmFsdWVzPSIwLjYiCiAgICAgICAgIHJlc3VsdD0iY29sb3IyIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDg3NyIgLz4KICAgIDwvZmlsdGVyPgogICAgPGZpbHRlcgogICAgICAgc3R5bGU9ImNvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpzUkdCOyIKICAgICAgIGlua3NjYXBlOmxhYmVsPSJDb2xvciBTaGlmdCIKICAgICAgIGlkPSJmaWx0ZXI4ODUiPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICB0eXBlPSJodWVSb3RhdGUiCiAgICAgICAgIHZhbHVlcz0iMjc0IgogICAgICAgICByZXN1bHQ9ImNvbG9yMSIKICAgICAgICAgaWQ9ImZlQ29sb3JNYXRyaXg4ODEiIC8+CiAgICAgIDxmZUNvbG9yTWF0cml4CiAgICAgICAgIHR5cGU9InNhdHVyYXRlIgogICAgICAgICB2YWx1ZXM9IjAuNiIKICAgICAgICAgcmVzdWx0PSJjb2xvcjIiCiAgICAgICAgIGlkPSJmZUNvbG9yTWF0cml4ODgzIiAvPgogICAgPC9maWx0ZXI+CiAgICA8ZmlsdGVyCiAgICAgICBzdHlsZT0iY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOnNSR0I7IgogICAgICAgaW5rc2NhcGU6bGFiZWw9IkNvbG9yIFNoaWZ0IgogICAgICAgaWQ9ImZpbHRlcjg5MSI+CiAgICAgIDxmZUNvbG9yTWF0cml4CiAgICAgICAgIHR5cGU9Imh1ZVJvdGF0ZSIKICAgICAgICAgdmFsdWVzPSIyNzQiCiAgICAgICAgIHJlc3VsdD0iY29sb3IxIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDg4NyIgLz4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0ic2F0dXJhdGUiCiAgICAgICAgIHZhbHVlcz0iMC42IgogICAgICAgICByZXN1bHQ9ImNvbG9yMiIKICAgICAgICAgaWQ9ImZlQ29sb3JNYXRyaXg4ODkiIC8+CiAgICA8L2ZpbHRlcj4KICAgIDxmaWx0ZXIKICAgICAgIHN0eWxlPSJjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM6c1JHQjsiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iQ29sb3IgU2hpZnQiCiAgICAgICBpZD0iZmlsdGVyODk3Ij4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0iaHVlUm90YXRlIgogICAgICAgICB2YWx1ZXM9IjI3NCIKICAgICAgICAgcmVzdWx0PSJjb2xvcjEiCiAgICAgICAgIGlkPSJmZUNvbG9yTWF0cml4ODkzIiAvPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICB0eXBlPSJzYXR1cmF0ZSIKICAgICAgICAgdmFsdWVzPSIwLjYiCiAgICAgICAgIHJlc3VsdD0iY29sb3IyIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDg5NSIgLz4KICAgIDwvZmlsdGVyPgogICAgPGZpbHRlcgogICAgICAgc3R5bGU9ImNvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpzUkdCOyIKICAgICAgIGlua3NjYXBlOmxhYmVsPSJDb2xvciBTaGlmdCIKICAgICAgIGlkPSJmaWx0ZXI5MDMiPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICB0eXBlPSJodWVSb3RhdGUiCiAgICAgICAgIHZhbHVlcz0iMjc0IgogICAgICAgICByZXN1bHQ9ImNvbG9yMSIKICAgICAgICAgaWQ9ImZlQ29sb3JNYXRyaXg4OTkiIC8+CiAgICAgIDxmZUNvbG9yTWF0cml4CiAgICAgICAgIHR5cGU9InNhdHVyYXRlIgogICAgICAgICB2YWx1ZXM9IjAuNiIKICAgICAgICAgcmVzdWx0PSJjb2xvcjIiCiAgICAgICAgIGlkPSJmZUNvbG9yTWF0cml4OTAxIiAvPgogICAgPC9maWx0ZXI+CiAgICA8ZmlsdGVyCiAgICAgICBzdHlsZT0iY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOnNSR0I7IgogICAgICAgaW5rc2NhcGU6bGFiZWw9IkNvbG9yIFNoaWZ0IgogICAgICAgaWQ9ImZpbHRlcjkwOSI+CiAgICAgIDxmZUNvbG9yTWF0cml4CiAgICAgICAgIHR5cGU9Imh1ZVJvdGF0ZSIKICAgICAgICAgdmFsdWVzPSIyNzQiCiAgICAgICAgIHJlc3VsdD0iY29sb3IxIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDkwNSIgLz4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0ic2F0dXJhdGUiCiAgICAgICAgIHZhbHVlcz0iMC42IgogICAgICAgICByZXN1bHQ9ImNvbG9yMiIKICAgICAgICAgaWQ9ImZlQ29sb3JNYXRyaXg5MDciIC8+CiAgICA8L2ZpbHRlcj4KICAgIDxmaWx0ZXIKICAgICAgIHN0eWxlPSJjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM6c1JHQjsiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iQ29sb3IgU2hpZnQiCiAgICAgICBpZD0iZmlsdGVyOTE1Ij4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0iaHVlUm90YXRlIgogICAgICAgICB2YWx1ZXM9IjI3NCIKICAgICAgICAgcmVzdWx0PSJjb2xvcjEiCiAgICAgICAgIGlkPSJmZUNvbG9yTWF0cml4OTExIiAvPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICB0eXBlPSJzYXR1cmF0ZSIKICAgICAgICAgdmFsdWVzPSIwLjYiCiAgICAgICAgIHJlc3VsdD0iY29sb3IyIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDkxMyIgLz4KICAgIDwvZmlsdGVyPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaWQ9ImJhc2UiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6em9vbT0iOS42ODc1IgogICAgIGlua3NjYXBlOmN4PSIzMiIKICAgICBpbmtzY2FwZTpjeT0iMzIiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpncmlkLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxNTM2IgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjgwMSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOnNuYXAtZ2xvYmFsPSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMzAwOSIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICAgIDxpbmtzY2FwZTpncmlkCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBpZD0iZ3JpZDMwMTEiCiAgICAgICBlbXBzcGFjaW5nPSIyIgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiCiAgICAgICBzbmFwdmlzaWJsZWdyaWRsaW5lc29ubHk9InRydWUiCiAgICAgICBzcGFjaW5neD0iMTYiCiAgICAgICBzcGFjaW5neT0iMTYiCiAgICAgICBlbXBjb2xvcj0iI2ZmMDAwMCIKICAgICAgIGVtcG9wYWNpdHk9IjAuMjUwOTgwMzkiCiAgICAgICBjb2xvcj0iI2ZmMDAwMCIKICAgICAgIG9wYWNpdHk9IjAuMTI1NDkwMiIKICAgICAgIG9yaWdpbng9IjAiCiAgICAgICBvcmlnaW55PSIwIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIj4KICAgIDxyZWN0CiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzkzNik7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7ZmlsdGVyOnVybCgjZmlsdGVyODU1KSIKICAgICAgIGlkPSJyZWN0MzEyNiIKICAgICAgIHdpZHRoPSIxMiIKICAgICAgIGhlaWdodD0iNiIKICAgICAgIHg9IjI2IgogICAgICAgeT0iMjkiIC8+CiAgICA8cmVjdAogICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM5NDQpO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO2ZpbHRlcjp1cmwoI2ZpbHRlcjg2MSkiCiAgICAgICBpZD0icmVjdDMxMjYtMiIKICAgICAgIHdpZHRoPSI2IgogICAgICAgaGVpZ2h0PSIxMS45OTk5OTkiCiAgICAgICB4PSIyOSIKICAgICAgIHk9IjI2IiAvPgogICAgPGcKICAgICAgIGlkPSJnNDM1MSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9tb3ZlLnBuZyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI2LjU1OTE1NjQiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNi41NTkxNTY0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4xMzc4MTMzLDAsMCwwLjEzNzgxMzMsLTIyMS4zOTY5OSwtMTM4LjM1Mjc1KSIKICAgICAgIHN0eWxlPSJmaWx0ZXI6dXJsKCNmaWx0ZXI4NjcpIiAvPgogICAgPHBhdGgKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzE1NCk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtmaWx0ZXI6dXJsKCNmaWx0ZXI4NzMpIgogICAgICAgZD0ibSAzNywyOCAwLC0xNSA2LDAgLTExLC0xMCAtMTEsMTAgNiwwIDAsMTUiCiAgICAgICBpZD0icGF0aDMzNDMiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIgLz4KICAgIDxwYXRoCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO2ZpbHRlcjp1cmwoI2ZpbHRlcjg3OSkiCiAgICAgICBkPSJNIDM1LDI5IDM1LDExIDM3LjgzMTI1OSwxMSAzMiw1LjcwMjY5MzcgMjYuMTY4NzQxLDExIDI5LDExIDI5LDI5IgogICAgICAgaWQ9InBhdGgzMzQzLTIiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIgLz4KICAgIDxwYXRoCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDMxNTgpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7ZmlsdGVyOnVybCgjZmlsdGVyODg1KSIKICAgICAgIGQ9Im0gMzcsMzcgMTQsMCAwLDYgMTAsLTExIC0xMCwtMTEgMCw2IC0xNCwwIgogICAgICAgaWQ9InBhdGgzMzQzLTMiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIgLz4KICAgIDxwYXRoCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO2ZpbHRlcjp1cmwoI2ZpbHRlcjg5MSkiCiAgICAgICBkPSJtIDM1LDM1IDE4LDAgMCwyLjgzMTI1OSBMIDU4LjI5NzMwNiwzMiA1MywyNi4xNjg3NDEgNTMsMjkgMzQsMjkiCiAgICAgICBpZD0icGF0aDMzNDMtMi01IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiIC8+CiAgICA8cGF0aAogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzMTU2KTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO2ZpbHRlcjp1cmwoI2ZpbHRlcjg5NykiCiAgICAgICBkPSJtIDI3LDM3IC0xNCwwIDAsNiAtMTAsLTExIDEwLC0xMSAwLDYgMTQsMCIKICAgICAgIGlkPSJwYXRoMzM0My0zLTIiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIgLz4KICAgIDxwYXRoCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO2ZpbHRlcjp1cmwoI2ZpbHRlcjkwMykiCiAgICAgICBkPSJNIDI5LDM1IDExLDM1IDExLDM3LjgzMTI1OSA1LjcwMjY5NCwzMiAxMSwyNi4xNjg3NDEgMTEsMjkgMzAsMjkiCiAgICAgICBpZD0icGF0aDMzNDMtMi01LTciCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIgLz4KICAgIDxwYXRoCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDMxNjApO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7ZmlsdGVyOnVybCgjZmlsdGVyOTA5KSIKICAgICAgIGQ9Im0gMzcsMzYgMCwxNSA2LDAgLTExLDEwIC0xMSwtMTAgNiwwIDAsLTE1IgogICAgICAgaWQ9InBhdGgzMzQzLTAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIgLz4KICAgIDxwYXRoCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO2ZpbHRlcjp1cmwoI2ZpbHRlcjkxNSkiCiAgICAgICBkPSJtIDM1LDM0IDAsMTkgMi44MzEyNTksMCBMIDMyLDU4LjI5NzMwNiAyNi4xNjg3NDEsNTMgMjksNTMgMjksMzQiCiAgICAgICBpZD0icGF0aDMzNDMtMi02IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiIC8+CiAgPC9nPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTUwMDYiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgICAgPGNjOmxpY2Vuc2UKICAgICAgICAgICByZGY6cmVzb3VyY2U9IiIgLz4KICAgICAgICA8ZGM6ZGF0ZT5Nb24gT2N0IDEwIDEzOjQ0OjUyIDIwMTEgKzAwMDA8L2RjOmRhdGU+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bd21heWVyXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8ZGM6cHVibGlzaGVyPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICAgIDxkYzppZGVudGlmaWVyPkZyZWVDQUQvc3JjL01vZC9EcmFmdC9SZXNvdXJjZXMvaWNvbnMvRHJhZnRfTW92ZS5zdmc8L2RjOmlkZW50aWZpZXI+CiAgICAgICAgPGRjOnJlbGF0aW9uPmh0dHA6Ly93d3cuZnJlZWNhZHdlYi5vcmcvd2lraS9pbmRleC5waHA/dGl0bGU9QXJ0d29yazwvZGM6cmVsYXRpb24+CiAgICAgICAgPGRjOmNvbnRyaWJ1dG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W2Fncnlzb25dIEFsZXhhbmRlciBHcnlzb248L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICAgIDxkYzpzdWJqZWN0PgogICAgICAgICAgPHJkZjpCYWc+CiAgICAgICAgICAgIDxyZGY6bGk+YXJyb3c8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5tb3ZlPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+YXJyb3dzPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+Y29tcGFzczwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmNyb3NzPC9yZGY6bGk+CiAgICAgICAgICA8L3JkZjpCYWc+CiAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICAgIDxkYzpkZXNjcmlwdGlvbj5Gb3VyIGVxdWFsbHkgc2l6ZWQgYXJyb3cgaGVhZHMgYXQgOTDCsCB0byBlYWNob3RoZXIsIGFsbCBqb2luZWQgYXQgdGhlIHRhaWw8L2RjOmRlc2NyaXB0aW9uPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KPC9zdmc+Cg==\n\"\"\"\nMove_Brown_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI5NjMiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9Ik1vdmUtYnJvd24uc3ZnIgogICBpbmtzY2FwZTpvdXRwdXRfZXh0ZW5zaW9uPSJvcmcuaW5rc2NhcGUub3V0cHV0LnN2Zy5pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzMjk2NSI+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMzNTQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjE1N2M3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDMzNTYiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM2ZGFhZmY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzM1OCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfej0iNjQgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMzIgOiAyMS4zMzMzMzMgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMjk3MSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLC0xLjQ1MDAwMDEsMS40NzA1ODgyLDAsLTE1LjA1ODgyLDkxLjQ1KSIKICAgICAgIHkyPSIzNi4wNzk5OTgiCiAgICAgICB4Mj0iMjEuNjg5NjUzIgogICAgICAgeTE9IjI5LjI3OTk5OSIKICAgICAgIHgxPSI1Ni4xNzI0MDkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwMzYiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODk3IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzYuMDc5OTk4IgogICAgICAgeDI9IjIxLjY4OTY1MyIKICAgICAgIHkxPSIyOS4yNzk5OTkiCiAgICAgICB4MT0iNTYuMTcyNDA5IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLC0wLjU4MDAwMDAzLDAuNTg4MjM1MjcsMCwxMy4xNzY0NzEsMzguMzc5OTk5KSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzkxOC0zIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1LTYiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTctNyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzIwNGE4NztzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODk5LTUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzYuMDc5OTk4IgogICAgICAgeDI9IjIxLjY4OTY1MyIKICAgICAgIHkxPSIyOS4yNzk5OTkiCiAgICAgICB4MT0iNTYuMTcyNDA5IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjU4MDAwMDAzLDAsMCwwLjU4ODIzNTI3LDI1LjYyMDAwMSwxMy4xNzY0NzEpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDI5LTYiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtMiIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg5NS02LTIiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTctNy05IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTktNS0xIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjM2LjA3OTk5OCIKICAgICAgIHgyPSIyMS42ODk2NTMiCiAgICAgICB5MT0iMjkuMjc5OTk5IgogICAgICAgeDE9IjU2LjE3MjQwOSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMCwtMC41ODAwMDAwMywwLjU4ODIzNTI3LDAsMTMuMTc2NDcxLDM4LjM3OTk5OSkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM5MTgtMCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtOSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg5NS05Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODk3LTMiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OS02IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNTQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMCwtMC41ODAwMDAwMywwLjU4ODIzNTI3LDAsMTMuMTc2NDcxLDM4LjM3OTk5OSkiCiAgICAgICB4MT0iNDUuNDgyNzU0IgogICAgICAgeTE9IjExLjU5OTk5OSIKICAgICAgIHgyPSItMjMuNDgyNzU5IgogICAgICAgeTI9IjUyLjQwMDAwMiIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTIiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTU2IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjU4MDAwMDAzLDAsMCwwLjU4ODIzNTI3LDM4LjM3OTk5OSwxMy4xNzY0NzEpIgogICAgICAgeDE9IjMxLjY4OTY1MSIKICAgICAgIHkxPSItMi4wMDAwMDA3IgogICAgICAgeDI9Ii05LjY4OTY1NjMiCiAgICAgICB5Mj0iNjYiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNTgiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC41ODAwMDAwMywwLDAsMC41ODgyMzUyNywyNS42MjAwMDEsMTMuMTc2NDcxKSIKICAgICAgIHgxPSItOS42ODk2NTYzIgogICAgICAgeTE9Ii0yLjAwMDAwMDciCiAgICAgICB4Mj0iMzEuNjg5NjUxIgogICAgICAgeTI9IjY2IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTkiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTYwIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAsMC41ODAwMDAwMywwLjU4ODIzNTI3LDAsMTMuMTc2NDcxLDI1LjYyMDAwMSkiCiAgICAgICB4MT0iLTIzLjQ4Mjc1OSIKICAgICAgIHkxPSIxMS41OTk5OTkiCiAgICAgICB4Mj0iNDUuNDgyNzU0IgogICAgICAgeTI9IjUyLjQwMDAwMiIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS05IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzkzNiIKICAgICAgIHgxPSIyMCIKICAgICAgIHkxPSIxMiIKICAgICAgIHgyPSI0NCIKICAgICAgIHkyPSI1MiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTkiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTQ0IgogICAgICAgeDE9IjIwIgogICAgICAgeTE9IjEyIgogICAgICAgeDI9IjQ0IgogICAgICAgeTI9IjUyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8ZmlsdGVyCiAgICAgICBzdHlsZT0iY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOnNSR0I7IgogICAgICAgaW5rc2NhcGU6bGFiZWw9IkNvbG9yIFNoaWZ0IgogICAgICAgaWQ9ImZpbHRlcjkxMjEiPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICB0eXBlPSJodWVSb3RhdGUiCiAgICAgICAgIHZhbHVlcz0iMTg1IgogICAgICAgICByZXN1bHQ9ImNvbG9yMSIKICAgICAgICAgaWQ9ImZlQ29sb3JNYXRyaXg5MTE3IiAvPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICB0eXBlPSJzYXR1cmF0ZSIKICAgICAgICAgdmFsdWVzPSIwLjgxNzcwOCIKICAgICAgICAgcmVzdWx0PSJjb2xvcjIiCiAgICAgICAgIGlkPSJmZUNvbG9yTWF0cml4OTExOSIgLz4KICAgIDwvZmlsdGVyPgogICAgPGZpbHRlcgogICAgICAgc3R5bGU9ImNvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpzUkdCOyIKICAgICAgIGlua3NjYXBlOmxhYmVsPSJDb2xvciBTaGlmdCIKICAgICAgIGlkPSJmaWx0ZXI5MTI3Ij4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0iaHVlUm90YXRlIgogICAgICAgICB2YWx1ZXM9IjE4NSIKICAgICAgICAgcmVzdWx0PSJjb2xvcjEiCiAgICAgICAgIGlkPSJmZUNvbG9yTWF0cml4OTEyMyIgLz4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0ic2F0dXJhdGUiCiAgICAgICAgIHZhbHVlcz0iMC44MTc3MDgiCiAgICAgICAgIHJlc3VsdD0iY29sb3IyIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDkxMjUiIC8+CiAgICA8L2ZpbHRlcj4KICAgIDxmaWx0ZXIKICAgICAgIHN0eWxlPSJjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM6c1JHQjsiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iQ29sb3IgU2hpZnQiCiAgICAgICBpZD0iZmlsdGVyOTEzMyI+CiAgICAgIDxmZUNvbG9yTWF0cml4CiAgICAgICAgIHR5cGU9Imh1ZVJvdGF0ZSIKICAgICAgICAgdmFsdWVzPSIxODUiCiAgICAgICAgIHJlc3VsdD0iY29sb3IxIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDkxMjkiIC8+CiAgICAgIDxmZUNvbG9yTWF0cml4CiAgICAgICAgIHR5cGU9InNhdHVyYXRlIgogICAgICAgICB2YWx1ZXM9IjAuODE3NzA4IgogICAgICAgICByZXN1bHQ9ImNvbG9yMiIKICAgICAgICAgaWQ9ImZlQ29sb3JNYXRyaXg5MTMxIiAvPgogICAgPC9maWx0ZXI+CiAgICA8ZmlsdGVyCiAgICAgICBzdHlsZT0iY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOnNSR0I7IgogICAgICAgaW5rc2NhcGU6bGFiZWw9IkNvbG9yIFNoaWZ0IgogICAgICAgaWQ9ImZpbHRlcjkxMzkiPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICB0eXBlPSJodWVSb3RhdGUiCiAgICAgICAgIHZhbHVlcz0iMTg1IgogICAgICAgICByZXN1bHQ9ImNvbG9yMSIKICAgICAgICAgaWQ9ImZlQ29sb3JNYXRyaXg5MTM1IiAvPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICB0eXBlPSJzYXR1cmF0ZSIKICAgICAgICAgdmFsdWVzPSIwLjgxNzcwOCIKICAgICAgICAgcmVzdWx0PSJjb2xvcjIiCiAgICAgICAgIGlkPSJmZUNvbG9yTWF0cml4OTEzNyIgLz4KICAgIDwvZmlsdGVyPgogICAgPGZpbHRlcgogICAgICAgc3R5bGU9ImNvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpzUkdCOyIKICAgICAgIGlua3NjYXBlOmxhYmVsPSJDb2xvciBTaGlmdCIKICAgICAgIGlkPSJmaWx0ZXI5MTQ1Ij4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0iaHVlUm90YXRlIgogICAgICAgICB2YWx1ZXM9IjE4NSIKICAgICAgICAgcmVzdWx0PSJjb2xvcjEiCiAgICAgICAgIGlkPSJmZUNvbG9yTWF0cml4OTE0MSIgLz4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0ic2F0dXJhdGUiCiAgICAgICAgIHZhbHVlcz0iMC44MTc3MDgiCiAgICAgICAgIHJlc3VsdD0iY29sb3IyIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDkxNDMiIC8+CiAgICA8L2ZpbHRlcj4KICAgIDxmaWx0ZXIKICAgICAgIHN0eWxlPSJjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM6c1JHQjsiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iQ29sb3IgU2hpZnQiCiAgICAgICBpZD0iZmlsdGVyOTE1MSI+CiAgICAgIDxmZUNvbG9yTWF0cml4CiAgICAgICAgIHR5cGU9Imh1ZVJvdGF0ZSIKICAgICAgICAgdmFsdWVzPSIxODUiCiAgICAgICAgIHJlc3VsdD0iY29sb3IxIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDkxNDciIC8+CiAgICAgIDxmZUNvbG9yTWF0cml4CiAgICAgICAgIHR5cGU9InNhdHVyYXRlIgogICAgICAgICB2YWx1ZXM9IjAuODE3NzA4IgogICAgICAgICByZXN1bHQ9ImNvbG9yMiIKICAgICAgICAgaWQ9ImZlQ29sb3JNYXRyaXg5MTQ5IiAvPgogICAgPC9maWx0ZXI+CiAgICA8ZmlsdGVyCiAgICAgICBzdHlsZT0iY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOnNSR0I7IgogICAgICAgaW5rc2NhcGU6bGFiZWw9IkNvbG9yIFNoaWZ0IgogICAgICAgaWQ9ImZpbHRlcjkxNTciPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICB0eXBlPSJodWVSb3RhdGUiCiAgICAgICAgIHZhbHVlcz0iMTg1IgogICAgICAgICByZXN1bHQ9ImNvbG9yMSIKICAgICAgICAgaWQ9ImZlQ29sb3JNYXRyaXg5MTUzIiAvPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICB0eXBlPSJzYXR1cmF0ZSIKICAgICAgICAgdmFsdWVzPSIwLjgxNzcwOCIKICAgICAgICAgcmVzdWx0PSJjb2xvcjIiCiAgICAgICAgIGlkPSJmZUNvbG9yTWF0cml4OTE1NSIgLz4KICAgIDwvZmlsdGVyPgogICAgPGZpbHRlcgogICAgICAgc3R5bGU9ImNvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpzUkdCOyIKICAgICAgIGlua3NjYXBlOmxhYmVsPSJDb2xvciBTaGlmdCIKICAgICAgIGlkPSJmaWx0ZXI5MTYzIj4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0iaHVlUm90YXRlIgogICAgICAgICB2YWx1ZXM9IjE4NSIKICAgICAgICAgcmVzdWx0PSJjb2xvcjEiCiAgICAgICAgIGlkPSJmZUNvbG9yTWF0cml4OTE1OSIgLz4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0ic2F0dXJhdGUiCiAgICAgICAgIHZhbHVlcz0iMC44MTc3MDgiCiAgICAgICAgIHJlc3VsdD0iY29sb3IyIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDkxNjEiIC8+CiAgICA8L2ZpbHRlcj4KICAgIDxmaWx0ZXIKICAgICAgIHN0eWxlPSJjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM6c1JHQjsiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iQ29sb3IgU2hpZnQiCiAgICAgICBpZD0iZmlsdGVyOTE2OSI+CiAgICAgIDxmZUNvbG9yTWF0cml4CiAgICAgICAgIHR5cGU9Imh1ZVJvdGF0ZSIKICAgICAgICAgdmFsdWVzPSIxODUiCiAgICAgICAgIHJlc3VsdD0iY29sb3IxIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDkxNjUiIC8+CiAgICAgIDxmZUNvbG9yTWF0cml4CiAgICAgICAgIHR5cGU9InNhdHVyYXRlIgogICAgICAgICB2YWx1ZXM9IjAuODE3NzA4IgogICAgICAgICByZXN1bHQ9ImNvbG9yMiIKICAgICAgICAgaWQ9ImZlQ29sb3JNYXRyaXg5MTY3IiAvPgogICAgPC9maWx0ZXI+CiAgICA8ZmlsdGVyCiAgICAgICBzdHlsZT0iY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOnNSR0I7IgogICAgICAgaW5rc2NhcGU6bGFiZWw9IkNvbG9yIFNoaWZ0IgogICAgICAgaWQ9ImZpbHRlcjkxNzUiPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICB0eXBlPSJodWVSb3RhdGUiCiAgICAgICAgIHZhbHVlcz0iMTg1IgogICAgICAgICByZXN1bHQ9ImNvbG9yMSIKICAgICAgICAgaWQ9ImZlQ29sb3JNYXRyaXg5MTcxIiAvPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICB0eXBlPSJzYXR1cmF0ZSIKICAgICAgICAgdmFsdWVzPSIwLjgxNzcwOCIKICAgICAgICAgcmVzdWx0PSJjb2xvcjIiCiAgICAgICAgIGlkPSJmZUNvbG9yTWF0cml4OTE3MyIgLz4KICAgIDwvZmlsdGVyPgogICAgPGZpbHRlcgogICAgICAgc3R5bGU9ImNvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpzUkdCOyIKICAgICAgIGlua3NjYXBlOmxhYmVsPSJDb2xvciBTaGlmdCIKICAgICAgIGlkPSJmaWx0ZXI5MTgxIj4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0iaHVlUm90YXRlIgogICAgICAgICB2YWx1ZXM9IjE4NSIKICAgICAgICAgcmVzdWx0PSJjb2xvcjEiCiAgICAgICAgIGlkPSJmZUNvbG9yTWF0cml4OTE3NyIgLz4KICAgICAgPGZlQ29sb3JNYXRyaXgKICAgICAgICAgdHlwZT0ic2F0dXJhdGUiCiAgICAgICAgIHZhbHVlcz0iMC44MTc3MDgiCiAgICAgICAgIHJlc3VsdD0iY29sb3IyIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDkxNzkiIC8+CiAgICA8L2ZpbHRlcj4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjkuNjg3NSIKICAgICBpbmtzY2FwZTpjeD0iMzIiCiAgICAgaW5rc2NhcGU6Y3k9IjMyIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIKICAgICBzaG93Z3JpZD0idHJ1ZSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTUzNiIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI4MDEiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy15PSItOCIKICAgICBpbmtzY2FwZTpzbmFwLWdsb2JhbD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIj4KICAgIDxpbmtzY2FwZTpncmlkCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBpZD0iZ3JpZDMwMDkiCiAgICAgICBlbXBzcGFjaW5nPSIyIgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiCiAgICAgICBzbmFwdmlzaWJsZWdyaWRsaW5lc29ubHk9InRydWUiIC8+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQzMDExIgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIgogICAgICAgc3BhY2luZ3g9IjE2IgogICAgICAgc3BhY2luZ3k9IjE2IgogICAgICAgZW1wY29sb3I9IiNmZjAwMDAiCiAgICAgICBlbXBvcGFjaXR5PSIwLjI1MDk4MDM5IgogICAgICAgY29sb3I9IiNmZjAwMDAiCiAgICAgICBvcGFjaXR5PSIwLjEyNTQ5MDIiCiAgICAgICBvcmlnaW54PSIwIgogICAgICAgb3JpZ2lueT0iMCIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciI+CiAgICA8cmVjdAogICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM5MzYpO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO2ZpbHRlcjp1cmwoI2ZpbHRlcjkxMjEpIgogICAgICAgaWQ9InJlY3QzMTI2IgogICAgICAgd2lkdGg9IjEyIgogICAgICAgaGVpZ2h0PSI2IgogICAgICAgeD0iMjYiCiAgICAgICB5PSIyOSIgLz4KICAgIDxyZWN0CiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50Mzk0NCk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7ZmlsdGVyOnVybCgjZmlsdGVyOTEyNykiCiAgICAgICBpZD0icmVjdDMxMjYtMiIKICAgICAgIHdpZHRoPSI2IgogICAgICAgaGVpZ2h0PSIxMS45OTk5OTkiCiAgICAgICB4PSIyOSIKICAgICAgIHk9IjI2IiAvPgogICAgPGcKICAgICAgIGlkPSJnNDM1MSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9tb3ZlLnBuZyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI2LjU1OTE1NjQiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNi41NTkxNTY0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4xMzc4MTMzLDAsMCwwLjEzNzgxMzMsLTIyMS4zOTY5OSwtMTM4LjM1Mjc1KSIKICAgICAgIHN0eWxlPSJmaWx0ZXI6dXJsKCNmaWx0ZXI5MTMzKSIgLz4KICAgIDxwYXRoCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDMxNTQpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7ZmlsdGVyOnVybCgjZmlsdGVyOTEzOSkiCiAgICAgICBkPSJtIDM3LDI4IDAsLTE1IDYsMCAtMTEsLTEwIC0xMSwxMCA2LDAgMCwxNSIKICAgICAgIGlkPSJwYXRoMzM0MyIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjYyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0LjE2ODM4OTgiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IiAvPgogICAgPHBhdGgKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7ZmlsdGVyOnVybCgjZmlsdGVyOTE0NSkiCiAgICAgICBkPSJNIDM1LDI5IDM1LDExIDM3LjgzMTI1OSwxMSAzMiw1LjcwMjY5MzcgMjYuMTY4NzQxLDExIDI5LDExIDI5LDI5IgogICAgICAgaWQ9InBhdGgzMzQzLTIiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIgLz4KICAgIDxwYXRoCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDMxNTgpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7ZmlsdGVyOnVybCgjZmlsdGVyOTE1MSkiCiAgICAgICBkPSJtIDM3LDM3IDE0LDAgMCw2IDEwLC0xMSAtMTAsLTExIDAsNiAtMTQsMCIKICAgICAgIGlkPSJwYXRoMzM0My0zIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiIC8+CiAgICA8cGF0aAogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtmaWx0ZXI6dXJsKCNmaWx0ZXI5MTU3KSIKICAgICAgIGQ9Im0gMzUsMzUgMTgsMCAwLDIuODMxMjU5IEwgNTguMjk3MzA2LDMyIDUzLDI2LjE2ODc0MSA1MywyOSAzNCwyOSIKICAgICAgIGlkPSJwYXRoMzM0My0yLTUiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIgLz4KICAgIDxwYXRoCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDMxNTYpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7ZmlsdGVyOnVybCgjZmlsdGVyOTE2MykiCiAgICAgICBkPSJtIDI3LDM3IC0xNCwwIDAsNiAtMTAsLTExIDEwLC0xMSAwLDYgMTQsMCIKICAgICAgIGlkPSJwYXRoMzM0My0zLTIiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIgLz4KICAgIDxwYXRoCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO2ZpbHRlcjp1cmwoI2ZpbHRlcjkxNjkpIgogICAgICAgZD0iTSAyOSwzNSAxMSwzNSAxMSwzNy44MzEyNTkgNS43MDI2OTQsMzIgMTEsMjYuMTY4NzQxIDExLDI5IDMwLDI5IgogICAgICAgaWQ9InBhdGgzMzQzLTItNS03IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiIC8+CiAgICA8cGF0aAogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzMTYwKTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO2ZpbHRlcjp1cmwoI2ZpbHRlcjkxNzUpIgogICAgICAgZD0ibSAzNywzNiAwLDE1IDYsMCAtMTEsMTAgLTExLC0xMCA2LDAgMCwtMTUiCiAgICAgICBpZD0icGF0aDMzNDMtMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjYyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0LjE2ODM4OTgiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IiAvPgogICAgPHBhdGgKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7ZmlsdGVyOnVybCgjZmlsdGVyOTE4MSkiCiAgICAgICBkPSJtIDM1LDM0IDAsMTkgMi44MzEyNTksMCBMIDMyLDU4LjI5NzMwNiAyNi4xNjg3NDEsNTMgMjksNTMgMjksMzQiCiAgICAgICBpZD0icGF0aDMzNDMtMi02IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiIC8+CiAgPC9nPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTUwMDYiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgICAgPGNjOmxpY2Vuc2UKICAgICAgICAgICByZGY6cmVzb3VyY2U9IiIgLz4KICAgICAgICA8ZGM6ZGF0ZT5Nb24gT2N0IDEwIDEzOjQ0OjUyIDIwMTEgKzAwMDA8L2RjOmRhdGU+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bd21heWVyXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8ZGM6cHVibGlzaGVyPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICAgIDxkYzppZGVudGlmaWVyPkZyZWVDQUQvc3JjL01vZC9EcmFmdC9SZXNvdXJjZXMvaWNvbnMvRHJhZnRfTW92ZS5zdmc8L2RjOmlkZW50aWZpZXI+CiAgICAgICAgPGRjOnJlbGF0aW9uPmh0dHA6Ly93d3cuZnJlZWNhZHdlYi5vcmcvd2lraS9pbmRleC5waHA/dGl0bGU9QXJ0d29yazwvZGM6cmVsYXRpb24+CiAgICAgICAgPGRjOmNvbnRyaWJ1dG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W2Fncnlzb25dIEFsZXhhbmRlciBHcnlzb248L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICAgIDxkYzpzdWJqZWN0PgogICAgICAgICAgPHJkZjpCYWc+CiAgICAgICAgICAgIDxyZGY6bGk+YXJyb3c8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5tb3ZlPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+YXJyb3dzPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+Y29tcGFzczwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmNyb3NzPC9yZGY6bGk+CiAgICAgICAgICA8L3JkZjpCYWc+CiAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICAgIDxkYzpkZXNjcmlwdGlvbj5Gb3VyIGVxdWFsbHkgc2l6ZWQgYXJyb3cgaGVhZHMgYXQgOTDCsCB0byBlYWNob3RoZXIsIGFsbCBqb2luZWQgYXQgdGhlIHRhaWw8L2RjOmRlc2NyaXB0aW9uPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KPC9zdmc+Cg==\n\"\"\"\nhelp_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0IgogICBoZWlnaHQ9IjY0IgogICBpZD0ic3ZnNjM2MSIKICAgc29kaXBvZGk6dmVyc2lvbj0iMC4zMiIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMC40OC41IHIxMDA0MCIKICAgc29kaXBvZGk6ZG9jbmFtZT0iaGVscC1icm93c2VyLnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiCiAgIHZlcnNpb249IjEuMSI+CiAgPGRlZnMKICAgICBpZD0iZGVmczMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyNDMxIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AyNDMzIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYjhiOGI4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDI0MzUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyMTY0NCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMjE2NDYiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjA7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMjE2NDgiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyMTY0NCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDIxNjUwIgogICAgICAgY3g9IjI1LjEyNSIKICAgICAgIGN5PSIzNi43NSIKICAgICAgIGZ4PSIyNS4xMjUiCiAgICAgICBmeT0iMzYuNzUiCiAgICAgICByPSIxNS43NSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMC41OTUyMzgsMCwxNC44NzUpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDI5MzMiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDI5MzUiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzljYmNkZTtzdG9wLW9wYWNpdHk6MSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyOTM3IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODciIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyOTMzIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MjIwNyIKICAgICAgIGN4PSIyNi41NDQzMjEiCiAgICAgICBjeT0iMjguNDU4NzI1IgogICAgICAgZng9IjI2LjU0NDMyMSIKICAgICAgIGZ5PSIyOC40NTg3MjUiCiAgICAgICByPSIyMi4zNzYxMTYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS4yMzgzNDIsMC4wMDU5NTQ4NSwtMC4wMDY1MDc3NiwxLjM1MTI3MiwtNi45OTI1MTMsLTkuNzQ0ODQyKSIgLz4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MjQzMSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDI0MzciCiAgICAgICBjeD0iLTE5LjUxNTYzOCIKICAgICAgIGN5PSIxNi44NTU2NjMiCiAgICAgICBmeD0iLTE5LjUxNTYzOCIKICAgICAgIGZ5PSIxNi44NTU2NjMiCiAgICAgICByPSI4Ljc1MzY0MyIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoNC40NDU5OTEsMCwwLDYuODY2NSw2Ny4yNTA3MSwtMTA0LjY2NzkpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM3ODAiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzg2IgogICAgICAgeDE9IjQxLjY0Mjg1NyIKICAgICAgIHkxPSI1OC43ODU3MTMiCiAgICAgICB4Mj0iMjIuMzU3MTQzIgogICAgICAgeTI9IjcuMzU3MTQyOSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzgwIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM0NjVhNDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM3ODIiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjA7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzc4NCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpbmtzY2FwZTpndWlkZS1iYm94PSJ0cnVlIgogICAgIHNob3dndWlkZXM9InRydWUiCiAgICAgaWQ9ImJhc2UiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjUuNjU2ODU0MiIKICAgICBpbmtzY2FwZTpjeD0iOTIuMDU4NTM5IgogICAgIGlua3NjYXBlOmN5PSI0OC4yNzgzNDQiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxNjAwIgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjgzNyIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iMCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iMjciCiAgICAgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9InRydWUiCiAgICAgZmlsbD0iI2RlYjg4NyIKICAgICBzdHJva2U9IiMyMDRhODciCiAgICAgYm9yZGVybGF5ZXI9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgaWQ9IkdyaWRGcm9tUHJlMDQ2U2V0dGluZ3MiCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBvcmlnaW54PSIwcHgiCiAgICAgICBvcmlnaW55PSIwcHgiCiAgICAgICBzcGFjaW5neD0iMXB4IgogICAgICAgc3BhY2luZ3k9IjFweCIKICAgICAgIGNvbG9yPSIjNzE3MWNkIgogICAgICAgZW1wY29sb3I9IiM3YjdiYzMiCiAgICAgICBvcGFjaXR5PSIwLjEyMTU2ODYzIgogICAgICAgZW1wb3BhY2l0eT0iMC41MzcyNTQ5IgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTQiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPkhlbHAgQnJvd3NlcjwvZGM6dGl0bGU+CiAgICAgICAgPGRjOmRhdGU+MjAwNS0xMS0wNjwvZGM6ZGF0ZT4KICAgICAgICA8ZGM6Y3JlYXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlR1b21hcyBLdW9zbWFuZW48L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNyZWF0b3I+CiAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICA8cmRmOkJhZz4KICAgICAgICAgICAgPHJkZjpsaT5oZWxwPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+YnJvd3NlcjwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmRvY3VtZW50YXRpb248L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5kb2NzPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+bWFuPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+aW5mbzwvcmRmOmxpPgogICAgICAgICAgPC9yZGY6QmFnPgogICAgICAgIDwvZGM6c3ViamVjdD4KICAgICAgICA8Y2M6bGljZW5zZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvMi4wLyIgLz4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5KYWt1YiBTdGVpbmVyLCBBbmRyZWFzIE5pbHNzb248L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICAgIDxkYzpzb3VyY2U+aHR0cDovL3RpZ2VydC5jb208L2RjOnNvdXJjZT4KICAgICAgPC9jYzpXb3JrPgogICAgICA8Y2M6TGljZW5zZQogICAgICAgICByZGY6YWJvdXQ9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzIuMC8iPgogICAgICAgIDxjYzpwZXJtaXRzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9SZXByb2R1Y3Rpb24iIC8+CiAgICAgICAgPGNjOnBlcm1pdHMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly93ZWIucmVzb3VyY2Uub3JnL2NjL0Rpc3RyaWJ1dGlvbiIgLz4KICAgICAgICA8Y2M6cmVxdWlyZXMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly93ZWIucmVzb3VyY2Uub3JnL2NjL05vdGljZSIgLz4KICAgICAgICA8Y2M6cmVxdWlyZXMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly93ZWIucmVzb3VyY2Uub3JnL2NjL0F0dHJpYnV0aW9uIiAvPgogICAgICAgIDxjYzpwZXJtaXRzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9EZXJpdmF0aXZlV29ya3MiIC8+CiAgICAgICAgPGNjOnJlcXVpcmVzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9TaGFyZUFsaWtlIiAvPgogICAgICA8L2NjOkxpY2Vuc2U+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciIKICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLDE2KSI+CiAgICA8cGF0aAogICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgc3R5bGU9ImZpbGw6IzcyOWZjZjtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6Mi4wNjg5NjU0NDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICBpZD0icGF0aDI5OTIiCiAgICAgICBzb2RpcG9kaTpjeD0iMzIiCiAgICAgICBzb2RpcG9kaTpjeT0iMzIiCiAgICAgICBzb2RpcG9kaTpyeD0iMzAiCiAgICAgICBzb2RpcG9kaTpyeT0iMzAiCiAgICAgICBkPSJNIDYyLDMyIEEgMzAsMzAgMCAxIDEgMiwzMiAzMCwzMCAwIDEgMSA2MiwzMiB6IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC45NjY2NjY2NywwLDAsMC45NjY2NjY2NywxLjA2NjY2NjYsLTE0LjkzMzMzMykiIC8+CiAgICA8cGF0aAogICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM3ODYpO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoyLjIyMjIyMjMzO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgIGlkPSJwYXRoMjk5Mi0zIgogICAgICAgc29kaXBvZGk6Y3g9IjMyIgogICAgICAgc29kaXBvZGk6Y3k9IjMyIgogICAgICAgc29kaXBvZGk6cng9IjMwIgogICAgICAgc29kaXBvZGk6cnk9IjMwIgogICAgICAgZD0iTSA2MiwzMiBBIDMwLDMwIDAgMSAxIDIsMzIgMzAsMzAgMCAxIDEgNjIsMzIgeiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuOSwwLDAsMC45LDMuMTk5OTk5NiwtMTIuOCkiIC8+CiAgICA8cGF0aAogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS42ODU3NzYyLDAsMCwxLjY1NjYzODQsNjYuNTUzNzY0LC0xNC4zNTU3OSkiCiAgICAgICBzdHlsZT0iZm9udC1zaXplOjM0LjE1MzIyODc2cHg7Zm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDtsaW5lLWhlaWdodDoxMjUlO3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtmaWxsOnVybCgjcmFkaWFsR3JhZGllbnQyNDM3KTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MS4xOTY3ODUwOTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxO2ZvbnQtZmFtaWx5OkJpdHN0cmVhbSBWZXJhIFNhbnMiCiAgICAgICBkPSJtIC0yMC4yNSw1LjY2MTU4MzggYyAtMS4wNTkwMTksMi42M2UtNSAtMi4xNDc2MzcsMC4xMjMyMzU2IC0zLjI4MTI1LDAuMzQzNzUgLTEuMTMyOTI1LDAuMjIwNDI4MyAtMi4wMDk0MTMsMC41Mzc1MTI1IC0zLjM3OTI1MSwxIC0wLjAxMDM3LC0wLjAwMTIxIC0wLjAyMDg4LC0wLjAwMTIxIC0wLjAzMTI1LDAgLTAuMDEyMDQsMC4wMDg2MSAtMC4wMjI2NCwwLjAxOTIxNCAtMC4wMzEyNSwwLjAzMTI1IC0wLjAxMjA0LDAuMDA4NjEgLTAuMDIyNjQsMC4wMTkyMTQgLTAuMDMxMjUsMC4wMzEyNSAtMC4wMDEyLDAuMDEwMzcgLTAuMDAxMiwwLjAyMDg4IDAsMC4wMzEyNSAtMC4wMDEyLDAuMDEwMzcgLTAuMDAxMiwwLjAyMDg4IDAsMC4wMzEyNSBsIDAsNS4xNTYyNTAyIGMgLTAuMDAxMiwwLjAxMDM3IC0wLjAwMTIsMC4wMjA4OCAwLDAuMDMxMjUgLTAuMDAxMiwwLjAxMDM3IC0wLjAwMTIsMC4wMjA4OCAwLDAuMDMxMjUgMC4wMDg2LDAuMDEyMDQgMC4wMTkyMSwwLjAyMjY0IDAuMDMxMjUsMC4wMzEyNSAwLjAwODYsMC4wMTIwNCAwLjAxOTIxLDAuMDIyNjQgMC4wMzEyNSwwLjAzMTI1IDAuMDEwMzcsMC4wMDEyIDAuMDIwODgsMC4wMDEyIDAuMDMxMjUsMCAwLjAxMDM3LDAuMDAxMiAwLjAyMDg4LDAuMDAxMiAwLjAzMTI1LDAgMC4wMTAzNywwLjAwMTIgMC4wMjA4OCwwLjAwMTIgMC4wMzEyNSwwIDAuMDEwMzcsMC4wMDEyIDAuMDIwODgsMC4wMDEyIDAuMDMxMjUsMCAxLjE0MjQzOCwtMC43MTkwNDMgMS44NjI2MDMsLTEuMjY3MTM4IDIuOTEwNTAxLC0xLjYyNSAxLjA0ODE0MSwtMC4zNjg3NTYgMi4wNDMxMTYsLTAuNTYyNDc5IDIuOTM3NSwtMC41NjI1IDAuOTQ5MjE4LDIuMWUtNSAxLjY0NDkyNSwwLjIxMDU0NSAyLjE1NjI1LDAuNjI1IDAuNTA4NzIzLDAuNDAyMDkgMC43ODEyMzgsMC45ODMwNCAwLjc4MTI1LDEuNzE4NzUgLTEwZS02LDAuNDgwNjU3IC0wLjE0NDE4OCwwLjk1MTQxIC0wLjQzNzUsMS40Mzc1IC0wLjI4Mjk5MSwwLjQ4NzAxNiAtMC43NDAyNjUsMS4yNDM5MTEgLTEuMzc1LDEuODA3MTY2IEwgLTIwLjkzNzUsMTYuNzUgYyAtMS4yMDE0NTksMS4wODA0OSAtMS43Nzk1MTYsMS45OTEwMjIgLTIuMTY1MjczLDIuNzE4NzUgLTAuMzgzMTEzLDAuNzExNDQ2IC0wLjM1OTc2OSwxLjIzMTY1NiAtMC4zNTk3NjksMi4xNDk4MzIgbCAwLDAuODEyNSBjIC0wLjAwMTIsMC4wMTAzNyAtMC4wMDEyLDAuMDIwODggMCwwLjAzMTI1IC0wLjAwMTIsMC4wMTAzNyAtMC4wMDEyLDAuMDIwODggMCwwLjAzMTI1IDAuMDA4NiwwLjAxMjA0IDAuMDE5MjEsMC4wMjI2NCAwLjAzMTI1LDAuMDMxMjUgMC4wMDg2LDAuMDEyMDQgMC4wMTkyMSwwLjAyMjY0IDAuMDMxMjUsMC4wMzEyNSAwLjAxMDM3LDAuMDAxMiAwLjAyMDg4LDAuMDAxMiAwLjAzMTI1LDAgMC4wMTAzNywwLjAwMTIgMC4wMjA4OCwwLjAwMTIgMC4wMzEyNSwwIGwgNS42ODEyOTIsLTAuMDI4MyBjIDAuMDEwMzcsMC4wMDEyIDAuMDIwODgsMC4wMDEyIDAuMDMxMjUsMCAwLjAxMDM3LDAuMDAxMiAwLjAyMDg4LDAuMDAxMiAwLjAzMTI1LDAgMC4wMTIwNCwtMC4wMDg2IDAuMDIyNjQsLTAuMDE5MjEgMC4wMzEyNSwtMC4wMzEyNSAwLjAxMjA0LC0wLjAwODYgMC4wMjI2NCwtMC4wMTkyMSAwLjAzMTI1LC0wLjAzMTI1IDAuMDAxMiwtMC4wMTAzNyAwLjAwMTIsLTAuMDIwODggMCwtMC4wMzEyNSAwLjAwMTIsLTAuMDEwMzcgMC4wMDEyLC0wLjAyMDg4IDAsLTAuMDMxMjUgbCAwLC0wLjc1IGMgLTEuMWUtNSwtMC40NjgxOTYgMC4xNDgzNywtMC41NzY4ODUgMC4zNzUsLTAuOTY1Mjg2IDAuMjIyMjk1LC0wLjM5MTI4NCAwLjcwODA3MywtMC45NTAzNTkgMS40Njg3NSwtMS42MjUgbCAxLjA2MjUsLTAuOTM3NSBjIDEuMDY2NTg4LC0wLjk4MjMxIDEuODMwNjU5LC0xLjg4NDY1NCAyLjI4MTI1LC0yLjc1IDAuNDQ5MjY5LC0wLjg3NDA0NiAwLjY4NzQ4MiwtMi4wODY4MzYgMC42ODc1LC0zLjE4MjE2NiAtMS44ZS01LC0yLjEyNjI2NSAtMC43NDM3NjksLTMuNzM0MDI3OCAtMi4yMTg3NSwtNC44NDM3NTAyIC0xLjQ3NTE5NywtMS4xMjEwMjUyIC0zLjYwNjI0LC0xLjY4NzQ3MzcgLTYuMzc1LC0xLjY4NzQ5NiB6IgogICAgICAgaWQ9InBhdGgxNTU0IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY3NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gMjcsMjcgMTAsMCAwLDEwIC0xMCwwIHoiCiAgICAgICBpZD0icGF0aDM3ODgiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogIDwvZz4KPC9zdmc+Cg==\n\"\"\"\nConfirm_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0IgogICBoZWlnaHQ9IjY0IgogICBpZD0ic3ZnMjk4NSIKICAgdmVyc2lvbj0iMS4xIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjkyLjAgcjE1Mjk5IgogICBzb2RpcG9kaTpkb2NuYW1lPSJDb25maXJtLnN2ZyI+CiAgPGRlZnMKICAgICBpZD0iZGVmczI5ODciPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzc0Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzRlOWEwNjtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM3NzYiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM4YWUyMzQ7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzNzc4IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDA4MiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM5MjItMCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMC41NjA5MTI2NCwtMC40OTg2NDYsMC40ODAzNTE3OSwtMC41ODIyNzUzOSwtMTc3Ljg5ODEzLDI2OS4xNTYzNSkiCiAgICAgICB4MT0iMTAuMzg3IgogICAgICAgeTE9IjQ1My43Nzg3NSIKICAgICAgIHgyPSI1Ni4zMTk0MTIiCiAgICAgICB5Mj0iNDgzLjk5NTI0IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MDgyIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3A0MDg0IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM0ZTlhMDY7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wNDA4NiIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojOGFlMjM0O3N0b3Atb3BhY2l0eToxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzc3NCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3ODAiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iLTIiCiAgICAgICB4Mj0iMjYiCiAgICAgICB5Mj0iLTI2IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM3NzQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyOTk5IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iLTIiCiAgICAgICB4Mj0iMjYiCiAgICAgICB5Mj0iLTI2IiAvPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaWQ9ImJhc2UiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6em9vbT0iOS42ODc1IgogICAgIGlua3NjYXBlOmN4PSIzMiIKICAgICBpbmtzY2FwZTpjeT0iMzIiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iZzI5OTUiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE1MzYiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODAxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQyOTgzIgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTI5OTAiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIgogICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsNDgpIj4KICAgIDxnCiAgICAgICBpZD0iZzI5OTUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjIyNTI2ODMsMCwwLDEuMjI1MjY4MywtNi4zMDE0MTc5LDIuNDMzMDg5MSkiPgogICAgICA8cGF0aAogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDA4OCIKICAgICAgICAgZD0ibSAxNS40ODA3NiwtMjEuMjQ2NTc2IDEwLjUxOTIzOSwxMC41MTkyMzIgMjEuMDM4NDc0LC0yMS4wMzg0NjQgNy44ODk0MjgsNy44ODk0MjQgTCAyNS45OTk5OTksNS4wNTE1MDY1IDcuNTkxMzMxMiwtMTMuMzU3MTUyIHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQyOTk5KTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzE3MmEwNDtzdHJva2Utd2lkdGg6MS42MzIyOTUzNztzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNTAuOTQzNTEyIgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNTAuOTQzNTEyIiAvPgogICAgICA8cGF0aAogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2MiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzAwNCIKICAgICAgICAgZD0iTSA5Ljk1MTA5NzgsLTEzLjM1MDQwMyAxNS40Nzc4MjIsLTE4Ljg4OTYyOCAyNiwtOC40Mzc1NTgzIDQ3LjAzMTg1NSwtMjkuNDQ4NTczIDUyLjU3MTA4LC0yMy44NzI1ODEgMjYsMi43MzUyNjYyIHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM4YWUyMzQ7c3Ryb2tlLXdpZHRoOjEuNjMyMjk1NDk7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjUwLjk0MzUxMiIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjUwLjk0MzUxMiIgLz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo=\n\"\"\"\nCenter_Align_b64=\\\n\"\"\"\nPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB3aWR0aD0iMTM2LjUzMzM0IgogICBoZWlnaHQ9IjEzNi41MzMzNCIKICAgdmlld0JveD0iMCAwIDEyNy45OTk5OSAxMjgiCiAgIGlkPSJzdmc0MjE2IgogICB2ZXJzaW9uPSIxLjEiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9IkNlbnRlci1BbGlnbi5zdmciPgogIDxkZWZzCiAgICAgaWQ9ImRlZnM0MjE4IiAvPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI0LjU0MTAxNTQiCiAgICAgaW5rc2NhcGU6Y3g9IjY4LjI2NjY3IgogICAgIGlua3NjYXBlOmN5PSI2OC4yNjY2NyIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJmYWxzZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE1MzYiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODAxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIKICAgICB1bml0cz0icHgiCiAgICAgd2lkdGg9IjI1LjRweCIgLz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGE0MjIxIj4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzp0aXRsZSAvPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZwogICAgIGlua3NjYXBlOmxhYmVsPSJDYWxxdWUgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIgogICAgIGlkPSJsYXllcjEiCiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtOTI0LjM2MjIpIj4KICAgIDxlbGxpcHNlCiAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7ZmlsbDojZmZjYzAwO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBpZD0icGF0aDMzNDEiCiAgICAgICBjeD0iNTguOTc0NjQ4IgogICAgICAgY3k9Ijk5Ni4yODc4NCIKICAgICAgIHJ4PSI1OC4wODIzNCIKICAgICAgIHJ5PSIzMi40NTA4NjMiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNDUuNDUwMDg1IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQ1LjQ1MDA4NSIgLz4KICAgIDxlbGxpcHNlCiAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7ZmlsbDojYjNiM2IzO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBpZD0icGF0aDMzNDMiCiAgICAgICBjeD0iNTguMjY5MTgiCiAgICAgICBjeT0iOTk2LjI4Nzg0IgogICAgICAgcng9IjUxLjkwOTE4NCIKICAgICAgIHJ5PSIyNi45ODMxNTIiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNDUuNDUwMDg1IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQ1LjQ1MDA4NSIgLz4KICAgIDxyZWN0CiAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7ZmlsbDojMDAwMGZmIgogICAgICAgaWQ9InJlY3QzMzQ3IgogICAgICAgd2lkdGg9IjU4Ljc4Nzc5NiIKICAgICAgIGhlaWdodD0iMzkuMDM1MDk1IgogICAgICAgeD0iMjguMTY5ODM2IgogICAgICAgeT0iOTc2LjA2NDg4IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQ1LjQ1MDA4NSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0NS40NTAwODUiIC8+CiAgICA8cmVjdAogICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO2ZpbGw6I2IzYjNiMyIKICAgICAgIGlkPSJyZWN0MzM0OSIKICAgICAgIHdpZHRoPSI0Ni4wODk2MyIKICAgICAgIGhlaWdodD0iMjguMjE4MTQyIgogICAgICAgeD0iMzQuMjgzNzgzIgogICAgICAgeT0iOTgxLjIzODM0IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQ1LjQ1MDA4NSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0NS40NTAwODUiIC8+CiAgICA8cmVjdAogICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO2ZpbGw6I2ZmZmZmZiIKICAgICAgIGlkPSJyZWN0MzM3MCIKICAgICAgIHdpZHRoPSIxMS43NTc1NTkiCiAgICAgICBoZWlnaHQ9IjEyLjIyNzg2MSIKICAgICAgIHg9IjUxLjIxNDY3MiIKICAgICAgIHk9Ijk4OS43MDM2NyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0NS40NTAwODUiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNDUuNDUwMDg1IiAvPgogICAgPHJlY3QKICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtmaWxsOiNmZmZmZmYiCiAgICAgICBpZD0icmVjdDMzNzIiCiAgICAgICB3aWR0aD0iMS40MTA5MDciCiAgICAgICBoZWlnaHQ9IjAuNDcwMzAyMzQiCiAgICAgICB4PSI1NC41MDY3MzciCiAgICAgICB5PSI5OTcuNjk4NjciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNDUuNDUwMDg1IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQ1LjQ1MDA4NSIgLz4KICAgIDxlbGxpcHNlCiAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7ZmlsbDojZmYwMDAwO3N0cm9rZS13aWR0aDowO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgaWQ9InBhdGg0MTc0IgogICAgICAgY3g9IjU3LjA2NjA1MSIKICAgICAgIGN5PSI5OTUuOTgyNzMiCiAgICAgICByeD0iMS43ODUwMzAyIgogICAgICAgcnk9IjEuNzE2MTU2MSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0NS40NTAwODUiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNDUuNDUwMDg1IiAvPgogICAgPHBhdGgKICAgICAgIHNvZGlwb2RpOnR5cGU9InN0YXIiCiAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7ZmlsbDojMDA4MDAwO3N0cm9rZS13aWR0aDowO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgaWQ9InBhdGg0MTc2IgogICAgICAgc29kaXBvZGk6c2lkZXM9IjMiCiAgICAgICBzb2RpcG9kaTpjeD0iLTE1MS43NTg0NyIKICAgICAgIHNvZGlwb2RpOmN5PSItMjIuMTE4NjQ1IgogICAgICAgc29kaXBvZGk6cjE9IjQuOTUzNTA2IgogICAgICAgc29kaXBvZGk6cjI9IjIuNDc2NzUzIgogICAgICAgc29kaXBvZGk6YXJnMT0iMC41MTkxNDYxMSIKICAgICAgIHNvZGlwb2RpOmFyZzI9IjEuNTY2MzQzNyIKICAgICAgIGlua3NjYXBlOmZsYXRzaWRlZD0iZmFsc2UiCiAgICAgICBpbmtzY2FwZTpyb3VuZGVkPSIwIgogICAgICAgaW5rc2NhcGU6cmFuZG9taXplZD0iMCIKICAgICAgIGQ9Im0gLTE0Ny40NTc2MiwtMTkuNjYxMDE4IC00LjI4OTgyLDAuMDE5MSAtNC4yODk4MiwwLjAxOTEgMi4xMjgzNywtMy43MjQ2NDMgMi4xMjgzNywtMy43MjQ2NDQgMi4xNjE0NSwzLjcwNTU0MyB6IgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci14PSItMC4wMzUxNDYwNDUiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9Ii00LjU2OTE4NyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDMuMTg3MTkzNywwLDAsMy43MTgzOTI2LDU0MS4xMzAwNywxMDI2LjY5NDUpIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQ1LjQ1MDA4NSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0NS40NTAwODUiIC8+CiAgICA8cGF0aAogICAgICAgc29kaXBvZGk6dHlwZT0ic3RhciIKICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtvcGFjaXR5OjE7ZmlsbDojZmYwMDAwO3N0cm9rZS13aWR0aDowO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgaWQ9InBhdGg0MTc2LTMiCiAgICAgICBzb2RpcG9kaTpzaWRlcz0iMyIKICAgICAgIHNvZGlwb2RpOmN4PSItMTUxLjc1ODQ3IgogICAgICAgc29kaXBvZGk6Y3k9Ii0yMi4xMTg2NDUiCiAgICAgICBzb2RpcG9kaTpyMT0iNC45NTM1MDYiCiAgICAgICBzb2RpcG9kaTpyMj0iMi40NzY3NTMiCiAgICAgICBzb2RpcG9kaTphcmcxPSIwLjUxOTE0NjExIgogICAgICAgc29kaXBvZGk6YXJnMj0iMS41NjYzNDM3IgogICAgICAgaW5rc2NhcGU6ZmxhdHNpZGVkPSJmYWxzZSIKICAgICAgIGlua3NjYXBlOnJvdW5kZWQ9IjAiCiAgICAgICBpbmtzY2FwZTpyYW5kb21pemVkPSIwIgogICAgICAgZD0ibSAtMTQ3LjQ1NzYyLC0xOS42NjEwMTggLTQuMjg5ODIsMC4wMTkxIC00LjI4OTgyLDAuMDE5MSAyLjEyODM3LC0zLjcyNDY0MyAyLjEyODM3LC0zLjcyNDY0NCAyLjE2MTQ1LDMuNzA1NTQzIHoiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9Ii0yLjQxMzE1OTQiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9Ii04LjQwODk3MzUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLDMuMzY2NTM3NSwtMy45Mjc2MjY5LDAsMjEuMjk1NjE2LDE1MDUuNjY5MykiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNDUuNDUwMDg1IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQ1LjQ1MDA4NSIgLz4KICAgIDxyZWN0CiAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7b3BhY2l0eToxO2ZpbGw6IzAwODAwMDtzdHJva2Utd2lkdGg6MDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgIGlkPSJyZWN0NDE5NSIKICAgICAgIHdpZHRoPSIxMC40NzA1NTUiCiAgICAgICBoZWlnaHQ9IjM1Ljg0MDI4MiIKICAgICAgIHg9IjUxLjg4NjY5MiIKICAgICAgIHk9Ijk1My4zOTMwNyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0NS40NTAwODUiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNDUuNDUwMDg1IiAvPgogICAgPHJlY3QKICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtvcGFjaXR5OjE7ZmlsbDojZmYwMDAwO3N0cm9rZS13aWR0aDowO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgaWQ9InJlY3Q0MTk3IgogICAgICAgd2lkdGg9IjM1LjUwNzgyOCIKICAgICAgIGhlaWdodD0iMTAuMjc1NzUiCiAgICAgICB4PSI2My42Nzc2NSIKICAgICAgIHk9Ijk5MC43NDg1NCIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0NS40NTAwODUiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNDUuNDUwMDg1IiAvPgogICAgPHRleHQKICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjQ4LjcwNjMwNjQ2cHg7bGluZS1oZWlnaHQ6MTI1JTtmb250LWZhbWlseTonRGVqYVZ1IFNhbnMnOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J0RlamFWdSBTYW5zIEJvbGQnO2xldHRlci1zcGFjaW5nOjBweDt3b3JkLXNwYWNpbmc6MHB4O2Rpc3BsYXk6aW5saW5lO2ZpbGw6IzAwODAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MS44MTgwMDg3OHB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICB4PSIzLjI2NzQ2MzciCiAgICAgICB5PSI5NjguOTg5NzUiCiAgICAgICBpZD0idGV4dDQxOTkiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNDUuNDUwMDg1IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQ1LjQ1MDA4NSI+PHRzcGFuCiAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgIGlkPSJ0c3BhbjQyMDEiCiAgICAgICAgIHg9IjMuMjY3NDYzNyIKICAgICAgICAgeT0iOTY4Ljk4OTc1IgogICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjEuODE4MDA4NzhweCI+WTwvdHNwYW4+PC90ZXh0PgogICAgPHRleHQKICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjQ4LjcwNjMwMjY0cHg7bGluZS1oZWlnaHQ6MTI1JTtmb250LWZhbWlseTonRGVqYVZ1IFNhbnMnOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J0RlamFWdSBTYW5zIEJvbGQnO2xldHRlci1zcGFjaW5nOjBweDt3b3JkLXNwYWNpbmc6MHB4O2Rpc3BsYXk6aW5saW5lO2ZpbGw6I2ZmMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MS44MTgwMDg2NnB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICB4PSI5MC42ODA2MzQiCiAgICAgICB5PSIxMDUxLjQzNjIiCiAgICAgICBpZD0idGV4dDQxOTktNCIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0NS40NTAwODUiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNDUuNDUwMDg1Ij48dHNwYW4KICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgaWQ9InRzcGFuNDIwMS05IgogICAgICAgICB4PSI5MC42ODA2MzQiCiAgICAgICAgIHk9IjEwNTEuNDM2MiIKICAgICAgICAgc3R5bGU9InN0cm9rZS13aWR0aDoxLjgxODAwODY2cHgiPlg8L3RzcGFuPjwvdGV4dD4KICA8L2c+Cjwvc3ZnPgo=\n\"\"\"\n###############################################\n\n\n##############################################################\nglobal initial_placement, last_selection\nglobal moving, rotating\nglobal objs_moved, plc_moved\n\n\n#init\ninitial_placement = FreeCAD.Placement(App.Vector(0,0,0), App.Rotation(0,0,0), App.Vector(0,0,0)) #Placement [Pos=(0,0,0), Yaw-Pitch-Roll=(0,0,0)]\nmoving = [] #[App.Vector(0,0,0)]\nrotating = [] #[0, App.Vector(0,0,0), App.Vector(0,0,0)]\nobjs_moved = []\nplc_moved = []\n#Draft.rotate(objs[j],-rot_angle,rot_center,rot_axis)\n#rotating=[rot_angle,rot_center,rot_axis]\n\nlast_selection = []\n\n#################################################################\n\ndef say(msg):\n    FreeCAD.Console.PrintMessage(msg)\n    FreeCAD.Console.PrintMessage('\\n')\n\ndef sayw(msg):\n    FreeCAD.Console.PrintWarning(msg)\n    FreeCAD.Console.PrintWarning('\\n')\n\ndef sayerr(msg):\n    FreeCAD.Console.PrintError(msg)\n    FreeCAD.Console.PrintWarning('\\n')\n\ndef make_string(input):\n    if (sys.version_info > (3, 0)):  #py3\n        if isinstance(input, str):\n            return input\n        else:\n            input =  input.encode('utf-8')\n            return input\n    else:  #py2\n        if type(input) == unicode:\n            input =  input.encode('utf-8')\n            return input\n        else:\n            return input\n\nsayw(\"Aligner version \"+str(__version__))\n\n# Form implementation generated from reading ui file 'C:\\Cad\\Progetti_K\\3D-FreeCad-tools\\icons-new\\align-tool-docked-v1.2.ui'\n#\n# Created: Sun Oct 01 10:20:00 2017\n#      by: pyside-uic 0.2.15 running on PySide 1.2.2\n#\n# WARNING! All changes made in this file will be lost!\n\n#from PySide import QtCore, QtGui\n\n###############################################################################################################\n### new dock widget\n### add def link inside class\n#    def link(self, linkStr):\n#        QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr))\n\n#class Ui_DockWidget(object):\n#    def link(self, linkStr):\n#        #QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr))\n#        try:\n#            QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr))  #workaround Qt5 waiting for PySide2\n#        except:\n#            #QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr.fromLocalFile()))\n#            pass\n#class Ui_DockWidget(object):\nclass Ui_DockWidget(object):\n    def setupUi(self, DockWidget):\n        DockWidget.setObjectName(\"DockWidget\")\n        DockWidget.resize(344, 252)\n        icon = QtGui.QIcon()\n        icon.addPixmap(QtGui.QPixmap(\"Center-Align.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        DockWidget.setWindowIcon(icon)\n        DockWidget.setLayoutDirection(QtCore.Qt.LeftToRight)\n        DockWidget.setToolTip(\"Align tool:\\nCtrl+Click to add selection\")\n        DockWidget.setFloating(True)\n        DockWidget.setFeatures(QtGui.QDockWidget.DockWidgetFloatable|QtGui.QDockWidget.DockWidgetMovable)\n        DockWidget.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea|QtCore.Qt.RightDockWidgetArea)\n        self.dockWidgetContents = QtGui.QWidget()\n        self.dockWidgetContents.setObjectName(\"dockWidgetContents\")\n        self.horizontalLayoutWidget = QtGui.QWidget(self.dockWidgetContents)\n        self.horizontalLayoutWidget.setGeometry(QtCore.QRect(5, 0, 100, 36))\n        self.horizontalLayoutWidget.setObjectName(\"horizontalLayoutWidget\")\n        self.horizontalLayout_2 = QtGui.QHBoxLayout(self.horizontalLayoutWidget)\n        self.horizontalLayout_2.setSpacing(2)\n        self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)\n        self.horizontalLayout_2.setObjectName(\"horizontalLayout_2\")\n        self.dock_float = QtGui.QPushButton(self.horizontalLayoutWidget)\n        self.dock_float.setMaximumSize(QtCore.QSize(28, 28))\n        self.dock_float.setText(\"\")\n        icon1 = QtGui.QIcon()\n        icon1.addPixmap(QtGui.QPixmap(\"un_dock.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.dock_float.setIcon(icon1)\n        self.dock_float.setIconSize(QtCore.QSize(16, 16))\n        self.dock_float.setObjectName(\"dock_float\")\n        self.horizontalLayout_2.addWidget(self.dock_float)\n        self.dock_minimize = QtGui.QPushButton(self.horizontalLayoutWidget)\n        self.dock_minimize.setMaximumSize(QtCore.QSize(28, 28))\n        self.dock_minimize.setText(\"\")\n        icon2 = QtGui.QIcon()\n        icon2.addPixmap(QtGui.QPixmap(\"minimize.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.dock_minimize.setIcon(icon2)\n        self.dock_minimize.setIconSize(QtCore.QSize(24, 24))\n        self.dock_minimize.setObjectName(\"dock_minimize\")\n        self.horizontalLayout_2.addWidget(self.dock_minimize)\n        self.close = QtGui.QPushButton(self.horizontalLayoutWidget)\n        self.close.setMaximumSize(QtCore.QSize(28, 28))\n        self.close.setText(\"\")\n        icon3 = QtGui.QIcon()\n        icon3.addPixmap(QtGui.QPixmap(\"closeW.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.close.setIcon(icon3)\n        self.close.setIconSize(QtCore.QSize(24, 24))\n        self.close.setObjectName(\"close\")\n        self.horizontalLayout_2.addWidget(self.close)\n        self.ReferenceGroup = QtGui.QGroupBox(self.dockWidgetContents)\n        self.ReferenceGroup.setGeometry(QtCore.QRect(6, 40, 183, 136))\n        self.ReferenceGroup.setObjectName(\"ReferenceGroup\")\n        self.gridLayoutWidget_8 = QtGui.QWidget(self.ReferenceGroup)\n        self.gridLayoutWidget_8.setGeometry(QtCore.QRect(5, 25, 172, 36))\n        self.gridLayoutWidget_8.setObjectName(\"gridLayoutWidget_8\")\n        self.gridLayout_10 = QtGui.QGridLayout(self.gridLayoutWidget_8)\n        self.gridLayout_10.setSpacing(2)\n        self.gridLayout_10.setContentsMargins(0, 0, 0, 0)\n        self.gridLayout_10.setObjectName(\"gridLayout_10\")\n        self.rbMass = QtGui.QRadioButton(self.gridLayoutWidget_8)\n        self.rbMass.setMinimumSize(QtCore.QSize(64, 32))\n        self.rbMass.setToolTip(\"Center of\\n\"\n\"Mass\")\n        self.rbMass.setText(\"\")\n        icon4 = QtGui.QIcon()\n        icon4.addPixmap(QtGui.QPixmap(\"Mass.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.rbMass.setIcon(icon4)\n        self.rbMass.setIconSize(QtCore.QSize(26, 26))\n        self.rbMass.setObjectName(\"rbMass\")\n        self.gridLayout_10.addWidget(self.rbMass, 0, 2, 1, 1)\n        self.rbBBox = QtGui.QRadioButton(self.gridLayoutWidget_8)\n        self.rbBBox.setMinimumSize(QtCore.QSize(64, 32))\n        self.rbBBox.setToolTip(\"Center of\\n\"\n\"Boundig Box\")\n        self.rbBBox.setText(\"\")\n        icon5 = QtGui.QIcon()\n        icon5.addPixmap(QtGui.QPixmap(\"Bbox.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.rbBBox.setIcon(icon5)\n        self.rbBBox.setIconSize(QtCore.QSize(26, 26))\n        self.rbBBox.setChecked(True)\n        self.rbBBox.setObjectName(\"rbBBox\")\n        self.gridLayout_10.addWidget(self.rbBBox, 0, 0, 1, 1)\n        spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)\n        self.gridLayout_10.addItem(spacerItem, 0, 1, 1, 1)\n        self.gridLayoutWidget_13 = QtGui.QWidget(self.ReferenceGroup)\n        self.gridLayoutWidget_13.setGeometry(QtCore.QRect(5, 80, 172, 36))\n        self.gridLayoutWidget_13.setObjectName(\"gridLayoutWidget_13\")\n        self.gridLayout_15 = QtGui.QGridLayout(self.gridLayoutWidget_13)\n        self.gridLayout_15.setSpacing(2)\n        self.gridLayout_15.setContentsMargins(0, 0, 0, 0)\n        self.gridLayout_15.setObjectName(\"gridLayout_15\")\n        self.rbNormal = QtGui.QRadioButton(self.gridLayoutWidget_13)\n        self.rbNormal.setMinimumSize(QtCore.QSize(64, 32))\n        self.rbNormal.setToolTip(\"Alignment Normal\")\n        self.rbNormal.setText(\"\")\n        icon6 = QtGui.QIcon()\n        icon6.addPixmap(QtGui.QPixmap(\"Normal-Up.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.rbNormal.setIcon(icon6)\n        self.rbNormal.setIconSize(QtCore.QSize(26, 26))\n        self.rbNormal.setChecked(True)\n        self.rbNormal.setObjectName(\"rbNormal\")\n        self.gridLayout_15.addWidget(self.rbNormal, 0, 0, 1, 1)\n        self.rbNormal_Inv = QtGui.QRadioButton(self.gridLayoutWidget_13)\n        self.rbNormal_Inv.setMinimumSize(QtCore.QSize(64, 32))\n        self.rbNormal_Inv.setToolTip(\"Alignment Normal\\n\"\n\"Inverted\")\n        self.rbNormal_Inv.setText(\"\")\n        icon7 = QtGui.QIcon()\n        icon7.addPixmap(QtGui.QPixmap(\"Normal-Down.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.rbNormal_Inv.setIcon(icon7)\n        self.rbNormal_Inv.setIconSize(QtCore.QSize(26, 26))\n        self.rbNormal_Inv.setChecked(False)\n        self.rbNormal_Inv.setObjectName(\"rbNormal_Inv\")\n        self.gridLayout_15.addWidget(self.rbNormal_Inv, 0, 1, 1, 1)\n        spacerItem1 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)\n        self.gridLayout_15.addItem(spacerItem1, 0, 2, 1, 1)\n        self.AlignGroup = QtGui.QGroupBox(self.dockWidgetContents)\n        self.AlignGroup.setGeometry(QtCore.QRect(185, 40, 151, 136))\n        self.AlignGroup.setObjectName(\"AlignGroup\")\n        self.gridLayoutWidget_10 = QtGui.QWidget(self.AlignGroup)\n        self.gridLayoutWidget_10.setGeometry(QtCore.QRect(10, 20, 137, 102))\n        self.gridLayoutWidget_10.setObjectName(\"gridLayoutWidget_10\")\n        self.gridLayout_12 = QtGui.QGridLayout(self.gridLayoutWidget_10)\n        self.gridLayout_12.setSpacing(2)\n        self.gridLayout_12.setContentsMargins(0, 0, 0, 0)\n        self.gridLayout_12.setObjectName(\"gridLayout_12\")\n        self.cbX = QtGui.QCheckBox(self.gridLayoutWidget_10)\n        self.cbX.setMinimumSize(QtCore.QSize(47, 32))\n        self.cbX.setMaximumSize(QtCore.QSize(64, 128))\n        self.cbX.setToolTip(\"center on X\")\n        self.cbX.setText(\"\")\n        icon8 = QtGui.QIcon()\n        icon8.addPixmap(QtGui.QPixmap(\"Xaxis.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.cbX.setIcon(icon8)\n        self.cbX.setIconSize(QtCore.QSize(16, 16))\n        self.cbX.setChecked(True)\n        self.cbX.setObjectName(\"cbX\")\n        self.gridLayout_12.addWidget(self.cbX, 0, 2, 1, 1)\n        self.rbCenters = QtGui.QRadioButton(self.gridLayoutWidget_10)\n        self.rbCenters.setMinimumSize(QtCore.QSize(64, 32))\n        self.rbCenters.setToolTip(\"Align Centers\")\n        self.rbCenters.setText(\"\")\n        icon9 = QtGui.QIcon()\n        icon9.addPixmap(QtGui.QPixmap(\"Centers.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.rbCenters.setIcon(icon9)\n        self.rbCenters.setIconSize(QtCore.QSize(26, 26))\n        self.rbCenters.setChecked(False)\n        self.rbCenters.setObjectName(\"rbCenters\")\n        self.gridLayout_12.addWidget(self.rbCenters, 0, 0, 1, 1)\n        spacerItem2 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)\n        self.gridLayout_12.addItem(spacerItem2, 0, 1, 1, 1)\n        self.rbPlanes = QtGui.QRadioButton(self.gridLayoutWidget_10)\n        self.rbPlanes.setMinimumSize(QtCore.QSize(64, 32))\n        self.rbPlanes.setToolTip(\"Align Planes\")\n        self.rbPlanes.setText(\"\")\n        icon10 = QtGui.QIcon()\n        icon10.addPixmap(QtGui.QPixmap(\"Planes.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.rbPlanes.setIcon(icon10)\n        self.rbPlanes.setIconSize(QtCore.QSize(26, 26))\n        self.rbPlanes.setChecked(False)\n        self.rbPlanes.setObjectName(\"rbPlanes\")\n        self.gridLayout_12.addWidget(self.rbPlanes, 1, 0, 1, 1)\n        self.rbPlanesCenters = QtGui.QRadioButton(self.gridLayoutWidget_10)\n        self.rbPlanesCenters.setMinimumSize(QtCore.QSize(64, 32))\n        self.rbPlanesCenters.setToolTip(\"Align Centers & Planes\")\n        self.rbPlanesCenters.setText(\"\")\n        icon11 = QtGui.QIcon()\n        icon11.addPixmap(QtGui.QPixmap(\"Planes-Centers.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.rbPlanesCenters.setIcon(icon11)\n        self.rbPlanesCenters.setIconSize(QtCore.QSize(26, 26))\n        self.rbPlanesCenters.setChecked(True)\n        self.rbPlanesCenters.setObjectName(\"rbPlanesCenters\")\n        self.gridLayout_12.addWidget(self.rbPlanesCenters, 2, 0, 1, 1)\n        self.cbY = QtGui.QCheckBox(self.gridLayoutWidget_10)\n        self.cbY.setMinimumSize(QtCore.QSize(47, 32))\n        self.cbY.setMaximumSize(QtCore.QSize(64, 128))\n        self.cbY.setToolTip(\"center on Y\")\n        self.cbY.setText(\"\")\n        icon12 = QtGui.QIcon()\n        icon12.addPixmap(QtGui.QPixmap(\"Yaxis.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.cbY.setIcon(icon12)\n        self.cbY.setIconSize(QtCore.QSize(16, 16))\n        self.cbY.setChecked(True)\n        self.cbY.setObjectName(\"cbY\")\n        self.gridLayout_12.addWidget(self.cbY, 1, 2, 1, 1)\n        self.cbZ = QtGui.QCheckBox(self.gridLayoutWidget_10)\n        self.cbZ.setMinimumSize(QtCore.QSize(47, 32))\n        self.cbZ.setMaximumSize(QtCore.QSize(64, 128))\n        self.cbZ.setToolTip(\"center on Z\")\n        self.cbZ.setText(\"\")\n        icon13 = QtGui.QIcon()\n        icon13.addPixmap(QtGui.QPixmap(\"Zaxis.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.cbZ.setIcon(icon13)\n        self.cbZ.setIconSize(QtCore.QSize(16, 16))\n        self.cbZ.setChecked(True)\n        self.cbZ.setObjectName(\"cbZ\")\n        self.gridLayout_12.addWidget(self.cbZ, 2, 2, 1, 1)\n        spacerItem3 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)\n        self.gridLayout_12.addItem(spacerItem3, 1, 1, 1, 1)\n        spacerItem4 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)\n        self.gridLayout_12.addItem(spacerItem4, 2, 1, 1, 1)\n        self.Label_Align_Gui = QtGui.QLabel(self.dockWidgetContents)\n        self.Label_Align_Gui.setGeometry(QtCore.QRect(115, 0, 231, 41))\n        self.Label_Align_Gui.setToolTip(\"Ctrl+Click to select\\n\"\n\"Faces/Planes or Edges/Axis\\n\"\n\"First selection is the Reference\")\n        self.Label_Align_Gui.setObjectName(\"Label_Align_Gui\")\n        self.gridLayoutWidget_6 = QtGui.QWidget(self.dockWidgetContents)\n        self.gridLayoutWidget_6.setGeometry(QtCore.QRect(5, 175, 328, 46))\n        self.gridLayoutWidget_6.setObjectName(\"gridLayoutWidget_6\")\n        self.gridLayout_13 = QtGui.QGridLayout(self.gridLayoutWidget_6)\n        self.gridLayout_13.setSpacing(2)\n        self.gridLayout_13.setContentsMargins(0, 0, 0, 0)\n        self.gridLayout_13.setObjectName(\"gridLayout_13\")\n        self.Help_Align = QtGui.QPushButton(self.gridLayoutWidget_6)\n        self.Help_Align.setMinimumSize(QtCore.QSize(60, 36))\n        self.Help_Align.setMaximumSize(QtCore.QSize(64, 64))\n        self.Help_Align.setText(\"\")\n        icon14 = QtGui.QIcon()\n        icon14.addPixmap(QtGui.QPixmap(\"help.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.Help_Align.setIcon(icon14)\n        self.Help_Align.setIconSize(QtCore.QSize(24, 24))\n        self.Help_Align.setCheckable(False)\n        self.Help_Align.setChecked(False)\n        self.Help_Align.setObjectName(\"Help_Align\")\n        self.gridLayout_13.addWidget(self.Help_Align, 0, 4, 1, 1)\n        self.Move = QtGui.QPushButton(self.gridLayoutWidget_6)\n        self.Move.setMinimumSize(QtCore.QSize(60, 36))\n        self.Move.setMaximumSize(QtCore.QSize(64, 64))\n        self.Move.setText(\"\")\n        icon15 = QtGui.QIcon()\n        icon15.addPixmap(QtGui.QPixmap(\"Move.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.Move.setIcon(icon15)\n        self.Move.setIconSize(QtCore.QSize(24, 24))\n        self.Move.setCheckable(False)\n        self.Move.setChecked(False)\n        self.Move.setObjectName(\"Move\")\n        self.gridLayout_13.addWidget(self.Move, 0, 2, 1, 1)\n        self.Align = QtGui.QPushButton(self.gridLayoutWidget_6)\n        self.Align.setMinimumSize(QtCore.QSize(60, 36))\n        self.Align.setMaximumSize(QtCore.QSize(64, 64))\n        self.Align.setText(\"\")\n        self.Align.setIcon(icon)\n        self.Align.setIconSize(QtCore.QSize(28, 28))\n        self.Align.setCheckable(False)\n        self.Align.setChecked(False)\n        self.Align.setObjectName(\"Align\")\n        self.gridLayout_13.addWidget(self.Align, 0, 0, 1, 1)\n        self.Undo_Align = QtGui.QPushButton(self.gridLayoutWidget_6)\n        self.Undo_Align.setMinimumSize(QtCore.QSize(60, 36))\n        self.Undo_Align.setMaximumSize(QtCore.QSize(64, 64))\n        self.Undo_Align.setText(\"\")\n        icon16 = QtGui.QIcon()\n        icon16.addPixmap(QtGui.QPixmap(\"Undo.png\"), QtGui.QIcon.Normal, QtGui.QIcon.Off)\n        self.Undo_Align.setIcon(icon16)\n        self.Undo_Align.setIconSize(QtCore.QSize(24, 24))\n        self.Undo_Align.setCheckable(False)\n        self.Undo_Align.setChecked(False)\n        self.Undo_Align.setObjectName(\"Undo_Align\")\n        self.gridLayout_13.addWidget(self.Undo_Align, 0, 3, 1, 1)\n        DockWidget.setWidget(self.dockWidgetContents)\n\n###############################################################################################################\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(closeW_b64))\n        self.close.setIconSize(QtCore.QSize(btn_sm_sizeX,btn_sm_sizeY))\n        self.close.setIcon(QtGui.QIcon(pm))\n        self.close.clicked.connect(close_aligner)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(minimize_b64))\n        self.dock_minimize.setIconSize(QtCore.QSize(btn_sm_sizeX,btn_sm_sizeY))\n        self.dock_minimize.setIcon(QtGui.QIcon(pm))\n        self.dock_minimize.clicked.connect(Alg_minimz)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(un_dock_b64))\n        self.dock_float.setIconSize(QtCore.QSize(btn_sm_sizeX,btn_sm_sizeY))\n        self.dock_float.setIcon(QtGui.QIcon(pm))\n        self.dock_float.clicked.connect(Alg_undock)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(Bbox_b64))\n        self.rbBBox.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY)) #chkb_sizeX,chkb_sizeY))\n        self.rbBBox.setIcon(QtGui.QIcon(pm))\n        self.rbBBox.clicked.connect(self.setReference)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(Mass_b64))\n        self.rbMass.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))\n        self.rbMass.setIcon(QtGui.QIcon(pm))\n        self.rbMass.clicked.connect(self.setReference)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(Normal_b64))\n        self.rbNormal.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))\n        self.rbNormal.setIcon(QtGui.QIcon(pm))\n        self.rbNormal.clicked.connect(self.setNormal)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(Normal_Inv_b64))\n        self.rbNormal_Inv.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))\n        self.rbNormal_Inv.setIcon(QtGui.QIcon(pm))\n        self.rbNormal_Inv.clicked.connect(self.setNormal)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(Planes_b64))\n        self.rbPlanes.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))\n        self.rbPlanes.setIcon(QtGui.QIcon(pm))\n        #self.rbPlanes.clicked.connect(AlignOn)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(Planes_Centers_b64))\n        self.rbPlanesCenters.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))\n        self.rbPlanesCenters.setIcon(QtGui.QIcon(pm))\n        #self.rbPlanesCenters.clicked.connect(AlignOn)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(Centers_b64))\n        self.rbCenters.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))\n        self.rbCenters.setIcon(QtGui.QIcon(pm))\n        #self.rbCenters.clicked.connect(AlignOn)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(X_b64))\n        self.cbX.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))\n        self.cbX.setIcon(QtGui.QIcon(pm))\n        #self.cbX.clicked.connect(onAxis)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(Y_b64))\n        self.cbY.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))\n        self.cbY.setIcon(QtGui.QIcon(pm))\n        #self.cbY.clicked.connect(onAxis)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(Z_b64))\n        self.cbZ.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))\n        self.cbZ.setIcon(QtGui.QIcon(pm))\n        #self.cbZ.clicked.connect(onAxis)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(Center_Align_b64))\n        self.Align.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))\n        self.Align.setIcon(QtGui.QIcon(pm))\n        self.Align.clicked.connect(self.onAlign)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(Move_b64))\n        self.Move.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))\n        self.Move.setIcon(QtGui.QIcon(pm))\n        self.Move.clicked.connect(self.onMove)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(Undo_b64))\n        self.Undo_Align.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))\n        self.Undo_Align.setIcon(QtGui.QIcon(pm))\n        self.Undo_Align.clicked.connect(self.onUndo)\n        pm = QtGui.QPixmap()\n        pm.loadFromData(base64.b64decode(help_b64))\n        self.Help_Align.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))\n        self.Help_Align.setIcon(QtGui.QIcon(pm))\n        self.Help_Align.clicked.connect(self.onHelp)\n\n###############################################################################################################\n        self.retranslateUi(DockWidget)\n        QtCore.QMetaObject.connectSlotsByName(DockWidget)\n\n\n\n## retraslateUi Qt5 compatibility #############################################################################################################\n    def retranslateUi(self, DockWidget):\n        DockWidget.setWindowTitle(\"Align tool\")\n        self.dock_float.setToolTip(\"expand\")\n        self.dock_minimize.setToolTip(\"minimize\")\n        self.close.setToolTip(\"close\")\n        self.Move.setToolTip(\"Move selected\")\n        self.Align.setToolTip(\"Align objects\\nFirst object is the Reference\")\n        self.Help_Align.setToolTip(\"Help tips\")\n        self.Undo_Align.setToolTip(\"Undo last Alignment\")\n        self.Label_Align_Gui.setText(\"<b>Ctrl+Click to add selection:<br>Planes/Faces and Edges/Axis</b>\")\n        self.ReferenceGroup.setTitle(\"Reference\")\n        self.AlignGroup.setTitle(\"Align on\")\n\n### ------------------------------------------------------------------------------------ ###\n### ---------code to be inserted and remove from new generation------------------------- ###\n### ------------------------------------------------------------------------------------ ###\n\n  ## NB!!! comment the line      ##self.config_ini_Lbl.setText(\"<b>TextLabel</b>\")\n###############################################################################################################\n# widgets connected functions\n    def setReference(self):\n        if self.rbBBox.isChecked():\n            say(\"centering on Bounding Boxes\")\n            type=0\n        else:\n            say(\"centering on Center of Mass\")\n            type=1\n##\n    def setNormal(self):\n        if self.rbNormal.isChecked():\n            normal=0\n            say(\"Align on NormalAt\")\n        else:\n            say(\"Align on Inverted NormalAt\")\n            normal=1\n##\n    def onAlign(self):\n        say(\"Align clicked\")\n        normal=0;type=0;mode=0\n        if self.rbNormal_Inv.isChecked():\n            say(\"Align Normal Inverted\")\n            normal=1\n        if self.rbBBox.isChecked():\n            say(\"centering on Bounding Boxes\")\n        else:\n            say(\"centering on Center of Mass\")\n            type=1\n        if self.rbPlanesCenters.isChecked():\n            say(\"Centering and aligning Planes\")\n        elif self.rbCenters.isChecked():\n            say(\"Centering Faces/Edges\")\n            mode=1\n        else:\n            say(\"Aligning Planes\")\n            mode=2\n        cx=0;cy=0;cz=0\n        if self.cbX.isChecked():\n            cx=1\n        if self.cbY.isChecked():\n            cy=1\n        if self.cbZ.isChecked():\n            cz=1\n        Align(normal,type,mode,cx,cy,cz)\n##\n\n    def onMove(self):\n        say(\"Move clicked\")\n        Move()\n##\n    def onUndo(self):\n        say(\"Undo clicked\")\n        Undo()\n##\n    def onHelp(self):\n        msg=\"\"\"<b>Align Tool</b><br>\n        <b>Ctrl+Clik</b> to add selection:<br>\n        select Faces, Planes, Edges and Axis<br>\n        then click the <i>'Align'</i> button<br>\n        <i>Note:</i><br>The <b>first Selection</b> is the\n        Reference for Aligning<br>\n        <br>Use <i>'Move'</i> button to move a signle object<br>\n        <br><b>Align Tool</b> works with <b>Part</b>, <b>App::Part</b> and <b>Body</b> objects\n        <b>Version:</b> \n        \"\"\"+__version__\n        QtGui.qApp.restoreOverrideCursor()\n        res=''\n        QtGui.qApp.restoreOverrideCursor()\n        res = QtGui.QMessageBox.question(None,\"Help\",msg,QtGui.QMessageBox.Ok)\n##\n\n###############################################################################################################\ndef Alg_centerOnScreen (widg):\n    '''centerOnScreen()\n    Centers the window on the screen.'''\n    # sayw(widg.width());sayw(widg.height())\n    # sayw(widg.pos().x());sayw(widg.pos().y())\n    resolution = QtGui.QDesktopWidget().screenGeometry()\n    xp=(resolution.width() / 2) - sizeXMax/2 # - (KSUWidget.frameSize().width() / 2)\n    yp=(resolution.height() / 2) - sizeY/2 # - (KSUWidget.frameSize().height() / 2))\n    # xp=widg.pos().x()-sizeXMax/2;yp=widg.pos().y()#+sizeY/2\n    widg.setGeometry(xp, yp, sizeXMax, sizeY)\n##\n\ndef Alg_singleInstance():\n    app = QtGui.qApp\n\n    for i in app.topLevelWidgets():\n        if i.objectName() == \"Aligner\":\n            i.deleteLater()\n        else:\n            pass\n    t=FreeCADGui.getMainWindow()\n    dw=t.findChildren(QtGui.QDockWidget)\n    #print str(dw)\n    for i in dw:\n        #say str(i.objectName())\n        if str(i.objectName()) == \"Aligner\": #\"kicad StepUp 3D tools\":\n            i.deleteLater()\n        else:\n            pass\n##\n\ndef Alg_checkInstance():\n    app = QtGui.qApp\n\n    foundAlg=False\n    for i in app.topLevelWidgets():\n        if i.objectName() == \"Aligner\":\n            foundAlg=True\n        else:\n            pass\n    t=FreeCADGui.getMainWindow()\n    dw=t.findChildren(QtGui.QDockWidget)\n    #print str(dw)\n    for i in dw:\n        #say str(i.objectName())\n        if str(i.objectName()) == \"Aligner\": #\"kicad StepUp 3D tools\":\n            foundAlg=True\n        else:\n            pass\n    return foundAlg\n##\n\n##############################################################\n\ndoc=FreeCAD.ActiveDocument\n\nAlg_singleInstance()\n\nALGDockWidget = QtGui.QDockWidget()          # create a new dckwidget\nALGDockWidget.ui = Ui_DockWidget()   #Ui_AlignDockWidget()           # myWidget_Ui()             # load the Ui script\nALGDockWidget.ui.setupUi(ALGDockWidget) # setup the ui\n#ui = Ui_AlignDockWidget()\n#ui.setupUi(AlignDockWidget)\n#AlignDockWidget.show()\n\nALGDockWidget.setObjectName(\"Aligner\")\n\nALGDockWidget.setFloating(True)  #undock\nALGDockWidget.resize(sizeX,sizeY)\nALGDockWidget.activateWindow()\nALGDockWidget.raise_()\n\n#ALGDockWidget.show()\n\nALGDockWidget.setFeatures( QtGui.QDockWidget.DockWidgetMovable | QtGui.QDockWidget.DockWidgetFloatable) #|QtGui.QDockWidget.DockWidgetClosable )\n\nif ALGDockWidget.style().metaObject().className()== \"QStyleSheetStyle\":\n    ALGDockWidget.setStyleSheet('QPushButton {border-radius: 0px; padding: 1px 2px;}')\n\nALGmw = FreeCADGui.getMainWindow()                 # PySide # the active qt window, = the freecad window since we are inside it\nALGmw.addDockWidget(QtCore.Qt.RightDockWidgetArea,ALGDockWidget)\n#ALGDockWidget.show()\nAlg_undock()\n\n### ------------------------------------------------------------------------------------ ###\n\n\ndef Undo():\n    say('Undo')\n    global initial_placement, last_selection\n    global moving, rotating\n    global objs, objs_plc\n    global objs_moved, plc_moved\n\n    if len(last_selection) == 1:\n        obj = last_selection[0].Object\n        say ('last selection: ' + obj.Name)\n        obj.Placement.Base =initial_placement\n        #obj.Placement = initial_placement\n        FreeCAD.ActiveDocument.recompute()\n        objs = []\n        last_selection = []\n    elif len (objs) > 1:\n        say ('Moving: ' + str(moving))\n        say ('Rotating: ' + str(rotating))\n        #sayerr(len(objs_moved))\n        i=0\n        for o in objs_moved:\n            #sayerr (o.Name)\n            #sayerr (plc_moved[i])\n            o.Placement = plc_moved[i]\n            i=i+1\n            \n        objs = []\n        last_selection = []\n        objs_moved = []\n        plc_moved = []\n        FreeCAD.ActiveDocument.recompute()\n    \ndef Move():\n    global initial_placement, last_selection\n    global objs, objs_plc\n    \n    say('Move')\n    selection = [s for s in FreeCADGui.Selection.getSelectionEx() if s.Document == FreeCAD.ActiveDocument ]\n    if len(selection) == 1:\n        objs = []\n        last_selection = selection\n        say('Move2')\n        PartMover( FreeCADGui.activeDocument().activeView(), selection[0].Object )\n        say('starting '+str(initial_placement))\n    else:\n        PartMoverSelectionObserver()\n\nclass PartMover:\n    global initial_placement\n    \n    def __init__(self, view, obj):\n        global initial_placement\n        self.obj = obj\n        self.initialPosition = self.obj.Placement.Base\n        initial_placement = self.initialPosition\n        #sayw('init '+str(initial_placement))\n        self.copiedObject = False\n        self.view = view\n        self.callbackMove = self.view.addEventCallback(\"SoLocation2Event\",self.moveMouse)\n        self.callbackClick = self.view.addEventCallback(\"SoMouseButtonEvent\",self.clickMouse)\n        self.callbackKey = self.view.addEventCallback(\"SoKeyboardEvent\",self.KeyboardEvent)\n    def moveMouse(self, info):\n        newPos = self.view.getPoint( *info['Position'] )\n        # debugPrint(5, 'new position %s' % str(newPos))\n        self.obj.Placement.Base = newPos\n    def removeCallbacks(self):\n        self.view.removeEventCallback(\"SoLocation2Event\",self.callbackMove)\n        self.view.removeEventCallback(\"SoMouseButtonEvent\",self.callbackClick)\n        self.view.removeEventCallback(\"SoKeyboardEvent\",self.callbackKey)\n    def clickMouse(self, info):\n        global initial_placement\n        # debugPrint(4, 'clickMouse info %s' % str(info))\n        if info['Button'] == 'BUTTON1' and info['State'] == 'DOWN':\n            if not info['ShiftDown'] and not info['CtrlDown']:\n                say('releasing obj')\n                FreeCAD.ActiveDocument.recompute()\n                #sayw('releasing\\ninitial p: '+ str( initial_placement ))\n                #sayw('final p: '+str(self.obj.Placement.Base))\n                self.removeCallbacks()\n            elif info['ShiftDown']: #copy object\n                self.obj = duplicateImportedPart( self.obj )\n                self.copiedObject = True\n            elif info['CtrlDown']:\n                azi   =  ( numpy.random.rand() - 0.5 )*numpy.pi*2\n                ela   =  ( numpy.random.rand() - 0.5 )*numpy.pi\n                theta =  ( numpy.random.rand() - 0.5 )*numpy.pi\n                axis = azimuth_and_elevation_angles_to_axis( azi, ela )\n                self.obj.Placement.Rotation.Q = quaternion( theta, *axis )\n\n    def KeyboardEvent(self, info):\n        # debugPrint(4, 'KeyboardEvent info %s' % str(info))\n        if info['State'] == 'UP' and info['Key'] == 'ESCAPE':\n            if not self.copiedObject:\n                self.obj.Placement.Base = self.initialPosition\n            else:\n                FreeCAD.ActiveDocument.removeObject(self.obj.Name)\n            self.removeCallbacks()\n\nclass PartMoverSelectionObserver:\n     def __init__(self):\n         FreeCADGui.Selection.addObserver(self)\n         FreeCADGui.Selection.removeSelectionGate()\n     def addSelection( self, docName, objName, sub, pnt ):\n         # debugPrint(4,'addSelection: docName,objName,sub = %s,%s,%s' % (docName, objName, sub))\n         FreeCADGui.Selection.removeObserver(self)\n         obj = FreeCAD.ActiveDocument.getObject(objName)\n         view = FreeCADGui.activeDocument().activeView()\n         PartMover( view, obj )\n\n# class MovePartCommand:\n#     say('Move')\n#     def Activated(self):\n#         selection = [s for s in FreeCADGui.Selection.getSelectionEx() if s.Document == FreeCAD.ActiveDocument ]\n#         if len(selection) == 1:\n#             say('Move2')\n#             PartMover( FreeCADGui.activeDocument().activeView(), selection[0].Object )\n#         else:\n#             PartMoverSelectionObserver()\n\n#FreeCADGui.addCommand('assembly2_movePart', MovePartCommand())\n            \ndef duplicateImportedPart( part ):\n    nameBase = part.Label\n    while nameBase[-1] in '0123456789' and len(nameBase) > 0:\n        nameBase = nameBase[:-1]\n    try:\n        newObj = FreeCAD.ActiveDocument.addObject(\"Part::FeaturePython\", findUnusedObjectName(nameBase))\n    except UnicodeEncodeError:\n        safeName = findUnusedObjectName('import_')\n        newObj = FreeCAD.ActiveDocument.addObject(\"Part::FeaturePython\", safeName)\n        newObj.Label = findUnusedLabel( nameBase )\n    newObj.addProperty(\"App::PropertyFile\",    \"sourceFile\",    \"importPart\").sourceFile = part.sourceFile\n    newObj.addProperty(\"App::PropertyFloat\", \"timeLastImport\",\"importPart\").timeLastImport =  part.timeLastImport\n    newObj.setEditorMode(\"timeLastImport\",1)\n    newObj.addProperty(\"App::PropertyBool\",\"fixedPosition\",\"importPart\").fixedPosition = False# part.fixedPosition\n    newObj.addProperty(\"App::PropertyBool\",\"updateColors\",\"importPart\").updateColors = getattr(part,'updateColors',True)\n    newObj.Shape = part.Shape.copy()\n    for p in part.ViewObject.PropertiesList: #assuming that the user may change the appearance of parts differently depending on their role in the assembly.\n        if hasattr(newObj.ViewObject, p) and p not in ['DiffuseColor','Proxy']:\n            setattr(newObj.ViewObject, p, getattr( part.ViewObject, p))\n    newObj.ViewObject.DiffuseColor = copy.copy( part.ViewObject.DiffuseColor )\n    newObj.Proxy = Proxy_importPart()\n    newObj.ViewObject.Proxy = ImportedPartViewProviderProxy()\n    newObj.Placement.Base = part.Placement.Base\n    newObj.Placement.Rotation = part.Placement.Rotation\n    return newObj    \n\ndef recurse_node(obj,plcm,scl):\n    sayerr(obj.Name)\n    if \"App::Part\" in obj.TypeId or \"Body\" in obj.TypeId or \"Compound\" in obj.TypeId:\n        for o in obj.Group:\n            #sayerr(o.Name)\n            if \"App::Part\" in o.TypeId  or \"Body\" in o.TypeId or \"Compound\" in o.TypeId:\n                #sayerr(o.Name)#+\" * \"+obj.Name)\n                new_plcm=get_node_plc(o,obj)\n                recurse_node(o,new_plcm,scl)\n            else:\n                if \"Sketcher\" not in o.TypeId:\n                    simple_cpy_plc(o,plcm)\n                    scl.append(FreeCAD.ActiveDocument.ActiveObject)\n##\n\ndef get_top_level (obj):\n    lvl=10000\n    for ap in obj.InListRecursive:\n        if len(ap.InListRecursive) < lvl:\n            top = ap\n            lvl = len(ap.InListRecursive)\n    return top\n\ndef get_sorted_list (obj):\n    lvl=10000\n    completed=0\n    listUs=obj.InListRecursive\n    #sayerr('unsorted')\n    #for p in listUs:\n    #    print p.Label\n    listUsName=[]\n    for o in obj.InListRecursive:\n        listUsName.append(o.Name)\n    listS=[]\n    i=0\n    #for i, ap in enumerate(listUs):\n    #    top=ap\n    #    if len(ap.InListRecursive) < lvl:\n    #        lvl = len(ap.InListRecursive)\n    #    for ap2 in listUs[(i + 1):]:\n    #        if len(ap2.InListRecursive) < lvl:\n    #            top = ap2\n    #            lvl = len(ap2.InListRecursive)\n    #    listS.append(top)\n    sayw(listUsName)\n    i=0\n    while len (listUsName) > 0:\n        for apName in listUsName:\n            #apName=listUsName[i]\n            ap=FreeCAD.ActiveDocument.getObject(apName)\n            if len(ap.InListRecursive) < lvl:\n                lvl = len(ap.InListRecursive)\n                top = ap\n                topName = ap.Name\n        listS.append(top)\n        #print topName\n        idx=listUsName.index(topName)\n        #sayw(idx)\n        listUsName.pop(idx)\n        lvl=10000\n        #sayerr(listUsName)\n      \n    return listS\n##\n\ndef reset_prop_shapes(obj):\n\n    s=obj.Shape\n    #say('resetting props #2')\n    r=[]\n    t=s.copy()\n    for i in t.childShapes():\n        c=i.copy()\n        c.Placement=t.Placement.multiply(c.Placement)\n        r.append((i,c))\n\n    w=t.replaceShape(r)\n    w.Placement=FreeCAD.Placement()\n    Part.show(w)\n    #say(w)\n    #\n    #FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.Part__Feature.ShapeColor\n    #FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.Part__Feature.LineColor\n    #FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.Part__Feature.PointColor\n    #FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.Part__Feature.DiffuseColor\n    FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor\n    FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor\n    FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor\n    FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor\n    new_label=obj.Label\n    FreeCAD.ActiveDocument.removeObject(obj.Name)\n    FreeCAD.ActiveDocument.recompute()\n    FreeCAD.ActiveDocument.ActiveObject.Label=new_label\n    rstObj=FreeCAD.ActiveDocument.ActiveObject\n    #say(rstObj)\n    #\n\n    return rstObj\n\ndef Align(normal,type,mode,cx,cy,cz):\n    global initial_placement, last_selection\n    global objs, objs_plc\n    global moving, rotating\n    global objs_moved, plc_moved\n    objs = [] ; objs_plc = []\n    objs_moved = [] ; plc_moved = []\n    \n    \n    #cx = 1  # center x -> 1  \n    #cy = 1  # center y -> 1 \n    #cz = 1  # center z -> 1 \n    say(str(cx)+str(cy)+str(cz))\n    create_points=False\n    use_bb = True #align center based on bounding boxes or center of mass\n    if type==1:\n        use_bb = False #align center based on bounding boxes or center of mass\n\n    sel = FreeCADGui.Selection.getSelection()\n    selEx = FreeCADGui.Selection.getSelectionEx()\n    if len(selEx) < 2 and not testing:\n        return\n    last_selection = []\n    say(\"number of objects: \"+ str(len(selEx)))\n    objs = [selobj.Object for selobj in selEx]\n    #k=0\n    for o in objs:\n        say ('obj: ' + o.Name)\n        objs_plc.append(o.Placement) #.Base)\n        say ('Placement: ' + str(o.Placement)) #.Base))\n        moving.append([App.Vector(0,0,0)])\n        rotating.append([0, App.Vector(0,0,0), App.Vector(0,0,0)])\n        #k=k+1\n        \n    def edgeToVector(edge):\n        \"\"\" Return a vector from an edge or a Part.line.\n        \"\"\"\n        if isinstance(edge,Part.Shape):\n            return edge.Vertexes[-1].Point.sub(edge.Vertexes[0].Point)\n        elif isinstance(edge,Part.Line):\n            return edge.EndPoint.sub(edge.StartPoint)\n        else:\n            sayw(\"Error in edgeToVector(edge) : not a good type of input\" + str(type(edge)))\n            return None    \n\n    def centerLinePoint(edge,info=0):\n        \"\"\" Return the center point of the Line.\n        \"\"\"\n        center = None\n        #VVector_A=edge.valueAt( 0.0 )\n        Vector_A = edge.Vertexes[0].Point\n        if info != 0:\n            say(\"Origin of line selected is : \"+str(Vector_A)) \n        #Vector_B=edge.valueAt( edge.Length )\n        Vector_B = edge.Vertexes[-1].Point\n        if info != 0:\n            say(\"End of line selected is : \"+str(Vector_B)) \n        Vector_MidPoint = Vector_B + Vector_A\n        center = Vector_MidPoint.multiply(0.5)\n        if info != 0:\n            say(\"Center of line selected is : \"+str(center)) \n        return center\n    \n    def object_alignEdges():\n        \"\"\" \n        Align the Edge(s) from selected object(s) to the last Edge selected.\n        - Click first to select an Edge of an object or several Edges from several objects. \n        - Click second to select an Edge to align to.\n    \n        NB:\n        The center of rotation is the center of the bounbing box if possible or \n        the center of the Edge.\n        \n        if the Edge of the object selected is already aligned to the last one,\n        a rotation of 180 deg is applied to the object.\n        In this case the Axis of rotation is Z vector : Base.Vector(0, 0, 1)\n        \n        Two clicks will rotate by 180 deg.\n        \"\"\"\n        msg=verbose\n    \n        error_msg =\\\n        \"INCORRECT Object(s) Selection :\\n\" +\\\n        \"You Must Select at least two(2) Edges (from two objects) !\\n\" +\\\n        \"All Edges will be aligned to the last one !\"\n        \n        Selection = get_SelectedObjectsWithParent(info=msg, printError=False)\n        m_actDoc=get_ActiveDocument(info=1)\n        Selection2 = Gui.Selection.getSelectionEx(m_actDoc.Name)\n        \n        try:\n            SelectedObjects = Selection\n            Number_of_Edges  = SelectedObjects[1]\n            if msg!=0:\n                print_msg(\"Number_of_Edges=\" + str(Number_of_Edges))\n                \n            if Number_of_Edges >= 2 :\n                Edge_List = SelectedObjects[4]\n                if msg != 0:\n                    print_msg(\" Edge_List=\" + str(Edge_List))\n                \n                # Get the Reference Edge : last of the selected\n                Ref_Edge_dict = Edge_List[-1]\n                for Selected_Edge, Parent_Edge in Ref_Edge_dict.iteritems():\n                    Edge_ref = Selected_Edge\n    \n                del Edge_List[-1]\n                            \n                for Selected_Edge_dict in Edge_List:\n                    if msg != 0:\n                        print_msg(\"Selected_Edge_dict = \" + str(Selected_Edge_dict))\n                    for Selected_Edge, Parent_Edge in Selected_Edge_dict.iteritems():\n                        if msg != 0:\n                            print_msg(\"Selected_Edge = \" + str(Selected_Edge))\n                            print_msg(\"Parent = \" + str(Parent_Edge))\n                        try:                        \n                            Edge_Point = Parent_Edge.Shape.BoundBox.Center\n                        except:\n                            Edge_Point = centerLinePoint(Selected_Edge,info=0)\n                        \n                        if msg != 0:\n                            print_point(Edge_Point, msg=\"Edge_Point = \")\n                        Edge = Selected_Edge\n                        \n                        if colinearEdges(Edge, Edge_ref, info=msg , tolerance=1e-12):\n                            rot_axis = Base.Vector(0, 0, 1).cross(edgeToVector(Edge))\n                            rot_center = Edge_Point\n                            rot_angle = 180. + m_angleAlignEdges\n                            Draft.rotate(Parent_Edge,rot_angle,rot_center,rot_axis)\n                        else:\n                            m_angle, m_angle_rad = angleBetween(Edge,Edge_ref)\n                            print_msg(\"m_angle = \" + str(m_angle))\n                            rot_axis = edgeToVector(Edge).cross(edgeToVector(Edge_ref))\n                            print_msg(\"rot_axis = \" + str(rot_axis))\n                            rot_center = Edge_Point\n                            rot_angle = m_angle + m_angleAlignEdges\n                            Draft.rotate(Parent_Edge,rot_angle,rot_center,rot_axis)\n                # Reset the selection changed by Draft.rotate \n                reset_SelectedObjects(Selection2, info=0)\n            else:\n                sayerr(error_msg)                          \n        except:\n            sayerr(error_msg)\n    \n    \n    def angleBetween(e1, e2):\n        \"\"\" Return the angle (in degrees) between 2 edges.\n        \"\"\"\n        if isinstance(e1,Part.Edge) and isinstance(e2,Part.Edge):\n            # Create the Vector for first edge\n            v1 = e1.Vertexes[-1].Point\n            v2 = e1.Vertexes[0].Point\n            ve1 = v1.sub(v2)\n            # Create the Vector for second edge\n            v3 = e2.Vertexes[-1].Point\n            v4 = e2.Vertexes[0].Point\n            ve2 = v3.sub(v4)\n        elif isinstance(e1,Base.Vector) and isinstance(e2,Base.Vector):\n            ve1 = e1\n            ve2 = e2\n        elif isinstance(e1,Part.Edge) and isinstance(e2,Base.Vector):\n            v1 = e1.Vertexes[-1].Point\n            v2 = e1.Vertexes[0].Point\n            ve1 = v1.sub(v2)\n            ve2 = e2\n        elif isinstance(e1,Base.Vector) and  isinstance(e2,Part.Edge):\n            ve1 = e1\n            v3 = e2.Vertexes[-1].Point\n            v4 = e2.Vertexes[0].Point\n            ve2 = v3.sub(v4)   \n        else:\n            return\n        \n        angle = ve1.getAngle(ve2)\n        import math\n        return math.degrees(angle), angle\n        \n    def colinearVectors(A, B, C, info=0, tolerance=1e-12):\n        \"\"\" Return true if the 3 points are aligned.\n        \"\"\"\n        Vector_1 = B - A\n        Vector_2 = C - B\n        #if info != 0:\n        #    print_point(Vector_1, msg=\"Vector_1 : \")\n        #    print_point(Vector_2, msg=\"Vector_2 : \")\n        Vector_3 = Vector_1.cross(Vector_2)\n        #if info != 0:\n        #    print_point(Vector_3, msg=\"Vector_1.cross(Vector_2) : \")\n            \n        if abs(Vector_3.x) <= tolerance and abs(Vector_3.y) <= tolerance and abs(Vector_3.z) <= tolerance:\n            if info != 0:\n                sayw(\"Colinear Vectors !\")\n            return True\n        else:\n            if info != 0:\n                sayw(\"NOT Colinear Vectors !\")\n            return False\n        return \n    \n    coords = []\n    normals = []\n    coordPs = []\n    sEdge = []\n    j = 0\n    p0 =  FreeCAD.Placement (FreeCAD.Vector(0,0,0), FreeCAD.Rotation(0,0,0), FreeCAD.Vector(0,0,0))\n    # .BoundBox.Center\n    #align faces\n    if (len(selEx) > 1) and (len(selEx)==len(sel)):\n        #s = obj.Shape\n        last_selection = [] #removing old Move object\n        top_level_obj=[]\n        \n        for i in range (len(selEx)):\n            top_level_obj.append('none')\n        for fc in selEx:\n            say (\"j= \"+str(j))\n            say(\"len selEx \"+str(len(selEx)))\n            s=fc\n            #selectedEdge = FreeCADGui.Selection.getSelectionEx()[j].SubObjects[0] # select one element SubObjects    \n            if (selEx[j].Object.TypeId == 'PartDesign::Plane'): #Datum plane with super Placement #(selEx[j].Object.TypeId == 'App::Plane') or :\n                ##print norm\n                pad=0\n                edge_op=0\n                f1=selEx[j].Object.Shape.Faces[0]\n                App.ActiveDocument.addObject(\"Part::Circle\",\"testCircle\")\n                App.ActiveDocument.testCircle.Radius=2.000\n                App.ActiveDocument.testCircle.Angle0=0.000\n                App.ActiveDocument.testCircle.Angle1=360.000\n                App.ActiveDocument.testCircle.Placement=f1.Placement\n                f=Part.Face(Part.Wire(App.ActiveDocument.testCircle.Shape.Edges[0]))\n                Part.show(f)\n                fName= FreeCAD.ActiveDocument.ActiveObject.Name\n                s = FreeCAD.ActiveDocument.getObject(fName)\n                App.ActiveDocument.removeObject(App.ActiveDocument.testCircle.Name)\n                FreeCAD.ActiveDocument.recompute()\n                #stop\n                sayerr(str(s.Placement))\n                s.Label = 'single-copy-absolute-placement'\n                #f.Placement = s.Placement\n                say(\"Label : \"+ make_string(sel[j].Label))     # extract the Label\n                say(\"Name  : \"+ str(sel[j].Name))     # extract the Name\n                say( \"Center Face Binder \"+str(0)+\" \"+str(f.Faces[0].CenterOfMass)) # Vector center mass to face\n                say( \"Center Face Binder bb \"+str(0)+\" \"+str(f.Faces[0].BoundBox.Center)) # Vector center mass to face\n            elif (selEx[j].Object.TypeId == 'App::Plane') and ('XY' in selEx[j].Object.Name or 'XZ' in selEx[j].Object.Name or 'YZ' in selEx[j].Object.Name): #Origin Planes\n                pad=0\n                edge_op=0\n                shape = Part.Shape()\n                shape.Placement = selEx[j].Object.Placement #selEx[j].Object.superPlacement.multiply(selEx[j].Object.Placement)\n                #sayerr(selEx[j].Object.superPlacement)\n                #sayw(selEx[j].Object.Placement)\n                #sayerr(selEx[j].Object.superPlacement.multiply(selEx[j].Object.Placement))\n                App.ActiveDocument.addObject(\"Part::Circle\",\"testCircle\")\n                App.ActiveDocument.testCircle.Radius=2.000\n                App.ActiveDocument.testCircle.Angle0=0.000\n                App.ActiveDocument.testCircle.Angle1=360.000\n                App.ActiveDocument.testCircle.Placement=shape.Placement\n                sayw(App.ActiveDocument.testCircle.Placement)\n                f=Part.Face(Part.Wire(App.ActiveDocument.testCircle.Shape.Edges[0]))\n                Part.show(f)\n                #f.Placement=App.ActiveDocument.testCircle.Placement\n                sayerr(f.Placement)\n                App.ActiveDocument.removeObject(App.ActiveDocument.testCircle.Name)\n                FreeCAD.ActiveDocument.recompute()\n                fName= FreeCAD.ActiveDocument.ActiveObject.Name\n                s = FreeCAD.ActiveDocument.getObject(fName)\n                #f.Placement=shape.Placement\n                s.Placement=f.Placement\n                #f1=f.copy()\n                #Part.show(f1)\n                FreeCAD.ActiveDocument.ActiveObject.Label='Testing-'+str(j)\n                sayerr(str(s.Placement))\n                s.Label = 'single-copy-absolute-placement'\n                say(\"Label : \"+ make_string(sel[j].Label))     # extract the Label\n                say(\"Name  : \"+ str(sel[j].Name))     # extract the Name\n                say( \"Center Face Binder \"+str(0)+\" \"+str(f.Faces[0].CenterOfMass)) # Vector center mass to face\n                say( \"Center Face Binder bb \"+str(0)+\" \"+str(f.Faces[0].BoundBox.Center)) # Vector center mass to face            \n            elif (selEx[j].Object.TypeId == 'App::Line') or (selEx[j].Object.TypeId == 'PartDesign::Line'):\n                FreeCAD.ActiveDocument.addObject(\"Part::Plane\",\"TempAxis\")\n                FreeCAD.ActiveDocument.TempAxis.Length=5.000\n                FreeCAD.ActiveDocument.TempAxis.Width=5.000\n                FreeCAD.ActiveDocument.TempAxis.Placement=selEx[j].Object.Placement\n                FreeCAD.ActiveDocument.TempAxis.Label='TempAxis'\n                FreeCAD.ActiveDocument.recompute()\n                fp = FreeCAD.ActiveDocument.TempAxis.Shape.Faces[0].Edges[1]\n                pad=0\n                edge_op=2\n                f=fp.copy()\n                Part.show(f)\n                #stop\n                FreeCAD.ActiveDocument.removeObject(\"TempAxis\")\n                FreeCAD.ActiveDocument.recompute()\n                fName= FreeCAD.ActiveDocument.ActiveObject.Name\n                s = FreeCAD.ActiveDocument.getObject(fName)\n                s.Placement = f.Placement\n                sayerr(str(f.Placement))\n                s.Label = 'single-copy-absolute-placement'\n                #f.Placement = s.Placement\n                say(\"Label : \"+ make_string(sel[j].Label))     # extract the Label\n                say(\"Name  : \"+ str(sel[j].Name))     # extract the Name\n                say( \"Center Face Binder \"+str(0)+\" \"+str(f.CenterOfMass)) # Vector center mass to face\n                say( \"Center Face Binder bb \"+str(0)+\" \"+str(f.BoundBox.Center)) # Vector center mass to face\n            else:\n                try:\n                    selectedEdge = selEx[j].SubObjects[0] # select one element SubObjects    \n                except:\n                    sayerr('select only Faces or closed Edges')\n                    return\n                sEdge.append(selectedEdge)\n                pad=0\n                edge_op=0\n                if str(fc.SubObjects[0])[1:5] != \"Face\": #edge\n                    # try:                        \n                    #     Edge_Point = centerLinePoint(selectedEdge,info=1)\n                    # except:\n                    #     stop\n                    try:\n                        sayerr(str(selectedEdge.Placement))\n                        wire = Part.Wire(selectedEdge)\n                        #sayw(str(wire.Placement))\n                        e = selectedEdge\n                        f = Part.Face(wire)\n                    except: # edge not closed\n                        wire = Part.Wire(selectedEdge)\n                        f = wire\n                        edge_op=1\n                        #sayerr('edge not closed to be managed')\n                        Edge_Point = centerLinePoint(selectedEdge,info=0)\n                        #reply = QtGui.QMessageBox.information(None,\"info\", \"edge(s) non closed are not managed atm\\n\")\n                        #stop\n                    #Part.show(fw)\n                    Part.show(f)\n                    #stop\n                    #f.Placement=selectedEdge.Placement\n                    fName= FreeCAD.ActiveDocument.ActiveObject.Name\n                    s = FreeCAD.ActiveDocument.getObject(fName)\n                    #sayerr(str(f.Placement))\n                    s.Placement = f.Placement\n                    s.Label = 'single-copy-absolute-placement-edge'\n                    #stop\n                    #f.Placement = s.Placement\n                    pad=1\n                    #FreeCAD.ActiveDocument.recompute()\n                    say(\"Label : \"+ make_string(sel[j].Label))     # extract the Label\n                    say(\"Name  : \"+ str(sel[j].Name))     # extract the Name\n                    if edge_op==0:\n                        say( \"Center Face Binder \"+str(0)+\" \"+str(f.Faces[0].CenterOfMass)) # Vector center mass to face\n                        say( \"Center Face Binder bb \"+str(0)+\" \"+str(f.Faces[0].BoundBox.Center)) # Vector center mass to face\n                    else:\n                        say( \"Center Face Binder \"+str(0)+\" \"+str(f.CenterOfMass)) # Vector center mass to face\n                        say( \"Center Face Binder bb \"+str(0)+\" \"+str(f.BoundBox.Center)) # Vector center mass to face\n                else: #face\n                    pad=0\n                    f=fc.SubObjects[0].Faces[0].copy()\n                    Part.show(f)\n                    fName= FreeCAD.ActiveDocument.ActiveObject.Name\n                    s = FreeCAD.ActiveDocument.getObject(fName)\n                    s.Placement = f.Placement\n                    sayerr(str(f.Placement))\n                    s.Label = 'single-copy-absolute-placement'\n                    #f.Placement = s.Placement\n                    say(\"Label : \"+ make_string(sel[j].Label))     # extract the Label\n                    say(\"Name  : \"+ str(sel[j].Name))     # extract the Name\n                    say( \"Center Face Binder \"+str(0)+\" \"+str(f.Faces[0].CenterOfMass)) # Vector center mass to face\n                    say( \"Center Face Binder bb \"+str(0)+\" \"+str(f.Faces[0].BoundBox.Center)) # Vector center mass to face\n            # LineColor\n            ob = fc.Object\n            #print ob.Placement\n            ## pOriginal=ob.Placement\n            pOriginal=f.Placement\n            s.Placement=p0\n            #stop\n            ##ob.Placement=p0\n            #say('resetting props #2')\n            #sh=ob.Shape\n            sh=s.Shape\n            r=[]\n            t=sh.copy()\n            for i in t.childShapes():\n                c=i.copy()\n                c.Placement=t.Placement.multiply(c.Placement)\n                r.append((i,c))\n            acpy=t.replaceShape(r)\n            acpy.Placement=FreeCAD.Placement()\n            if hasattr(ob,'InListRecursive'):\n                lrl=len(ob.InListRecursive)\n                for o in ob.InListRecursive:\n                    say(o.Name)\n                inverted=True\n                if len(ob.InList):\n                    top_level_obj[j] = get_top_level(ob)\n                    #sayerr(top_level_obj[j].Label)\n                    listSorted=get_sorted_list (ob)\n                    #for p in listSorted:\n                    #    print p.Name\n                    #print listSorted, ' Sorted; Top ', top_level_obj[j]\n                    #stop\n                    for i in range (0,lrl):\n                        if hasattr(listSorted[i],'Placement'):\n                            #if 'Plane' not in ob.InListRecursive[i].TypeId:\n                            if listSorted[i].hasExtension(\"App::GeoFeatureGroupExtension\"):\n                                acpy.Placement=acpy.Placement.multiply(listSorted[i].Placement)\n            say(acpy.Placement)\n            #acpy.Placement=acpy.Placement.multiply(pOriginal)\n            if pad == 0: #note making wire from edge already resets the original placement\n                acpy.Placement=acpy.Placement.multiply(pOriginal)\n            s.Placement = acpy.Placement\n            ##ob.Placement = pOriginal\n            #stop\n            f.Placement = s.Placement\n            #stop\n        \n            red   = 1.0  # 1 = 255\n            green = 0.0  #\n            blue  = 0.0  #\n            if create_points:\n                if pad==0:\n                    if use_bb:\n                        Draft.makePoint(f.Faces[0].BoundBox.Center.x,f.Faces[0].BoundBox.Center.y,f.Faces[0].BoundBox.Center.z) # create a point\n                    else:\n                        Draft.makePoint(f.Faces[0].CenterOfMass.x,f.Faces[0].CenterOfMass.y,f.Faces[0].CenterOfMass.z) # create a point\n                    FreeCADGui.activeDocument().activeObject().PointColor = (red, green, blue)\n                else:\n                    if use_bb:\n                        Draft.makePoint(f.Faces[0].BoundBox.Center.x,f.Faces[0].CenterOfMass.y,f.Faces[0].CenterOfMass.z) # create a point\n                    else:\n                        Draft.makePoint(f.Faces[0].CenterOfMass.x,f.Faces[0].CenterOfMass.y,f.Faces[0].CenterOfMass.z) # create a point\n                    FreeCADGui.activeDocument().activeObject().PointColor = (red, green, blue)            \n            if pad==0:\n                if use_bb:\n                    if edge_op == 0:\n                        coordNx = f.Faces[0].BoundBox.Center.x\n                        coordNy = f.Faces[0].BoundBox.Center.y\n                        coordNz = f.Faces[0].BoundBox.Center.z\n                        coordP  = f.Faces[0].BoundBox.Center\n                    else:\n                        coordNx = f.BoundBox.Center.x\n                        coordNy = f.BoundBox.Center.y\n                        coordNz = f.BoundBox.Center.z\n                        coordP  = f.BoundBox.Center\n                else:\n                    if edge_op == 0:\n                        coordNx = f.Faces[0].CenterOfMass.x\n                        coordNy = f.Faces[0].CenterOfMass.y\n                        coordNz = f.Faces[0].CenterOfMass.z\n                        coordP  = f.Faces[0].CenterOfMass\n                    else:\n                        coordNx = f.CenterOfMass.x\n                        coordNy = f.CenterOfMass.y\n                        coordNz = f.CenterOfMass.z\n                        coordP  = f.CenterOfMass\n            else:\n                if use_bb:\n                    if edge_op == 0:\n                        coordNx = f.Faces[0].BoundBox.Center.x\n                        coordNy = f.Faces[0].BoundBox.Center.y\n                        coordNz = f.Faces[0].BoundBox.Center.z\n                        coordP  = f.Faces[0].BoundBox.Center\n                    else:\n                        coordNx = f.BoundBox.Center.x\n                        coordNy = f.BoundBox.Center.y\n                        coordNz = f.BoundBox.Center.z\n                        coordP  = f.BoundBox.Center\n                else:\n                    if edge_op == 0:\n                        coordNx = f.Faces[0].CenterOfMass.x\n                        coordNy = f.Faces[0].CenterOfMass.y\n                        coordNz = f.Faces[0].CenterOfMass.z\n                        coordP  = f.Faces[0].CenterOfMass\n                    else:\n                        coordNx = f.CenterOfMass.x\n                        coordNy = f.CenterOfMass.y\n                        coordNz = f.CenterOfMass.z\n                        coordP  = f.CenterOfMass\n            coords.append ([coordNx,coordNy,coordNz])\n            coordPs.append (coordP)\n            #norm = f.Shape.Faces[0].normalAt(0,0)\n            if j==0:\n                if normal==1: #inverted\n                    if edge_op == 0:\n                        norm = f.Faces[0].normalAt(0,0)*-1\n                    elif edge_op == 1:\n                        norm = f.Vertex1.Point - f.Vertex2.Point\n                    else:\n                        norm = f.Vertex2.Point - f.Vertex1.Point\n                else:\n                    if edge_op == 0:\n                        norm = f.Faces[0].normalAt(0,0)\n                    elif edge_op == 1:\n                        norm = f.Vertex2.Point - f.Vertex1.Point\n                    else:\n                        norm = f.Vertex1.Point - f.Vertex2.Point\n                        #norm = e.normalAt(0)\n            else:\n                if edge_op == 0:\n                    norm = f.Faces[0].normalAt(0,0)\n                else:\n                    norm = f.Vertex2.Point - f.Vertex1.Point\n                    #norm = e.normalAt(0)\n            #else:\n            #    norm = f.Shape.Faces[0].normalAt(0,0)        \n            say (norm)\n            normals.append (norm)\n            if not testing:\n                FreeCAD.ActiveDocument.removeObject(fName)\n            else:\n                say('testing')\n                #stop\n            if j>0:\n                pos=App.Vector(-coords[j][0]+coords[0][0],-coords[j][1]+coords[0][1],-coords[j][2]+coords[0][2])\n                ## objs[j].Placement.move(pos)\n                m_angle, m_angle_rad = angleBetween(normals[0],normals[j])\n                say (m_angle)\n                Origin = Base.Vector(0, 0, 0)\n                copl=0\n                if colinearVectors(normals[0], Origin, normals[j], info=1, tolerance=1e-12):\n                    rot_axis = Base.Vector(0, 0, 1).cross(normals[0])\n                    if rot_axis==FreeCAD.Vector (0.0, 0.0, 0.0):\n                        rot_axis=Base.Vector(0, 1, 0).cross(normals[0])\n                    rot_center = coordPs[j]\n                    if normal==1:\n                        rot_angle = 180. # + m_angleAlignFaces\n                    else:\n                        rot_angle=0.\n                    copl=1\n                    #Draft.rotate(Parent_Plane,rot_angle,rot_center,rot_axis)\n                else:\n                    #m_angle, m_angle_rad = angleBetween(Plane_Normal,Plane_Normal_ref)\n                    rot_axis = normals[0].cross(normals[j])\n                    rot_center = coordPs[j]\n                    rot_angle = m_angle # + m_angleAlignFaces\n                    #Draft.rotate(Parent_Plane,rot_angle,rot_center,rot_axis)\n                #rot_axis = normals[0].cross(normals[j])\n                #rot_center = coordPs[j]\n                #rot_angle = m_angle # + m_angleAlignFaces\n                sayw(\"axis,center,angle\")\n                say(rot_axis)\n                say(rot_center)\n                say(rot_angle)\n                \n                object_added=0\n                if not testing2:\n                    #print 'not testing2, mode  ', mode, ' rot_angle ',rot_angle\n                    if rot_angle!=0: # and rot_axis!=FreeCAD.Vector (0.0, 0.0, 0.0):\n                        if mode==0 or mode==2:\n                            if rot_axis!=FreeCAD.Vector (0.0, 0.0, 0.0):\n                                if top_level_obj[j] != 'none':\n                                    o = top_level_obj[j]\n                                else:\n                                    o = objs[j] \n                                #sayerr(o.Name+' '+o.Label+' '+str(o.Placement)+' rotation')\n                                objs_moved.append(o)\n                                plc_moved.append(o.Placement)\n                                object_added=1\n                                ##Draft.rotate(o,-rot_angle,rot_center,rot_axis)\n                                shape = Part.Shape()\n                                shape.Placement = o.Placement\n                                shape.rotate(DraftVecUtils.tup(rot_center), DraftVecUtils.tup(rot_axis), -rot_angle)\n                                o.Placement = shape.Placement\n                                rotating[j] = [rot_angle,rot_center,rot_axis]\n                                say(\"Rotated   \"+o.Label+\"  : angle \"+str(-rot_angle)+\" center \"+str(rot_center)+\" axis \"+str(rot_axis))\n                            else:\n                                rotating[j] = [0, App.Vector(0,0,0), App.Vector(0,0,0)]\n                    else:\n                        rotating[j] = [0, App.Vector(0,0,0), App.Vector(0,0,0)]\n            ##align centers\n            if j>0:\n                pos=App.Vector((-coords[j][0]+coords[0][0])*cx,(-coords[j][1]+coords[0][1])*cy,(-coords[j][2]+coords[0][2])*cz)\n                if mode==0 or mode==1:\n                    #objs[j].Placement.move(pos)\n                    if object_added==0:\n                        if top_level_obj[j] != 'none':\n                            o = top_level_obj[j]\n                        else:\n                            o = objs[j] \n                        objs_moved.append(o)\n                        plc_moved.append(o.Placement)\n                        #sayerr(o.Name+' '+o.Label+' '+str(o.Placement)+' centers')\n                        object_added=1\n                    if not testing2:\n                        o.Placement.move(pos)\n                    moving[j] = pos\n                    say(\"Moved   \"+o.Label+\"  : \"+str(coordNx-coords[0][0])+\" \"+str(coordNy-coords[0][1])+\" \"+str(coordNz-coords[0][2]))\n                    if mode==1:\n                        rotating[j] = [0, App.Vector(0,0,0), App.Vector(0,0,0)]\n                else:\n                    moving[j] = App.Vector(0,0,0)\n\n            object_added=0\n            j=j+1\n    \n    FreeCAD.ActiveDocument.recompute()\n    #for obj in objs:\n    for obj in FreeCAD.ActiveDocument.Objects:\n        FreeCADGui.Selection.removeSelection(obj)\n    \n    # except:\n    #     App.Console.PrintError( \"select a face\"+\"\\n\")\n\n",
    "url": "https://wiki.freecad.org/Macro_Center_Align_Objects_with_Faces_or_Edges",
    "raw_code_url": "https://raw.githubusercontent.com/easyw/FreeCAD_Macros/master/Align%20Objects/CenterAlignObjectswFacesEdges.py",
    "wiki": "",
    "version": "1.5.3",
    "license": "",
    "date": "10.2017",
    "src_filename": "",
    "filename_from_url": "",
    "author": "maurice",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Center_Align_Objects_with_Faces_or_Edges.svg",
    "icon_source": "https://www.freecadweb.org/wiki/images/e/ee/Macro_Center_Align_Objects_with_Faces_or_Edges.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "CloneConvert",
    "on_wiki": true,
    "on_git": false,
    "desc": "Creates a Clone/Copy/Compound of the object(s) and then converted into a chosen position and size (<i>inch, mm, m, \u00b5m</i>...) or free. The base object is recognized in <i>mm</i> (FreeCAD base).<br /><br />Macro version: 00.16<br />Last modified: 2025-01-06<br />FreeCAD version: \u22650.18<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/0/0a/Macro_CloneConvert.png\">ToolBar Icon</a><br />Author: mario52<br /> ",
    "comment": "This macro creates Clone or Copy or Compound of object(s)",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2014 2015 2016 2017 2018 2019 2020 2021 2022 <mario52>  *\n*                 2025                                                    *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*   http://www.freecadweb.org/wiki/index.php?title=Macro_FCCircularText   *\n*           WARNING! All changes in this file will be lost and            *\n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n# CloneConvert.FCMacro\n# Cree un clone ou une copie de l'objet ou des objets selectionne(s) et le met e l'echelle de la grandeur choisie\n# utilisation : lancer CloneConvert selectionnez un objet choisissez la grandeur et cliquez sur OK\n# \n# Creates a clone of one copy the selected object and updates the selected size range\n# use: start CloneConvert select an object choose the size and click OK\n#\n#OS: Windows 10 (10.0)\n#Word size of OS: 64-bit\n#Word size of FreeCAD: 64-bit\n#Version: 0.19.21280 (Git)\n#Build type: Release\n#Branch: master\n#Hash: 6f3160db3e88733536c7eaf97ad7d6ebd21baccd\n#Python version: 3.6.8\n#Qt version: 5.12.1\n#Coin version: 4.0.0a\n#OCC version: 7.3.0\n#Locale: French/Mars (fr_MA)\n#\n# ver 0.3 31/07/2014 PyQt4 + PySide\n# ver 0.4 25/07/2015 ajout rotation\n# ver 0.5 26/07/2015 correction rotation plusieurs objets Copy\n# ver 0.6 26/01/2016 correction placement avec plusieurs objets Copy\n# ver 0.7 30/01/2016 reecriture du code avec Placement et ajout Increment et de boutons\n# ver 0.8 31/01/2016 clique 2 fois pour mettre les valeurs a zero (en cas de modifications reinitialisait )\n# ver 0.9 14/06/2016 ajout du bouton nombre de copies et optimisation des labels\n# ver 0.10 07/06/2017 modifie Draft... pour copie ne faisait plus de copie a l'echelle ?? remplace par Part...Shape!\n# ver 0.11 30/03/2018 ajout d'un checkBox choix clone unique avec plusieurs objets ou clones separes\n# ver 0.12 01/06/2019 adapte pour 0.19 et correction \"Copy:legacy=True\" et ShapeColor .....\n# ver 0.13 15/09/2019 remplace le signe grec micro par \"um\", remplace tous \"_translate(\"MainWindow\", \"mm\", None)\" par \"mm\" et commente ligne \"text.encode('utf-8')\"\n# ver 0.14 2020/05/20 GridLayout PySide2 ajoute \".ActiveDocument.ActiveObject.recompute()\" ligne 909 causait une erreur dans FC 0.19\n# ver 0.15 2020/06/06 icon\n# ver 0.16 2025/01/06 remplace PySide2 to PySide augmente mini et maxi efface toutes les reference a PySide, PySide2 et QtWidgets et correction clone\n# \n\n__title__   = \"CloneConvert\"\n__author__  = \"mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__version__ = \"00.16\"\n__date__    = \"2025/01/06\"    #YYYY/MM/DD\n\n__Comment__ = \"This macro creates Clone or Copy or Compound of object(s)\"\n__Web__     = \"http://www.freecadweb.org/\"\n__Wiki__    = \"http://www.freecadweb.org/wiki/index.php?title=Macro_CloneConvert\"\n__Icon__    = \"https://wiki.freecadweb.org/images/0/0a/Macro_CloneConvert.png\"\n__Help__    = \"start the macro and follow the instructions\"\n__Status__  = \"stable\"\n__Requires__= \"0.19\"\n__Communication__ = \"http://www.freecadweb.org/wiki/index.php?title=User:Mario52\"\n\n# icon fromTheme by FreeCAD\n\nhelpIcon = [\n\"24 24 4 1\",\n\"   c None\",\n\".  c #016AC5\",\n\"+  c #F8F8FF\",\n\"@  c #FFFFFF\",\n\"........................\",\n\".++++++++++++++++++++++.\",\n\".++++++++++++++++++++++.\",\n\".++..................++.\",\n\".++..................++.\",\n\".++......@@@@@@......++.\",\n\".++.....@@@@@@@@.....++.\",\n\".++.....@@@..@@@.....++.\",\n\".++.....@@....@@.....++.\",\n\".++.....@@....@@.....++.\",\n\".++...........@@.....++.\",\n\".++..........@@@.....++.\",\n\".++.........@@@......++.\",\n\".++........@@@.......++.\",\n\".++........@@........++.\",\n\".++........@@........++.\",\n\".++..................++.\",\n\".++........@@........++.\",\n\".++........@@........++.\",\n\".++..................++.\",\n\".++..................++.\",\n\".++++++++++++++++++++++.\",\n\".++++++++++++++++++++++.\",\n\"........................\"]\n\nvalidIcon = [\n\"24 24 3 1\",\n\"   c None\",\n\".  c #4E9A06\",\n\"+  c #FFFFFF\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                  .     \",\n\"                 .+.    \",\n\"                .+.+.   \",\n\"               .+...+.  \",\n\"              .+.....+. \",\n\"     .       .+.......+.\",\n\"    .+.     .+.......+. \",\n\"   .+.+.   .+.......+.  \",\n\"  .+...+. .+.......+.   \",\n\" .+.....+.+.......+.    \",\n\".+.......+.......+.     \",\n\" .+.............+.      \",\n\"  .+...........+.       \",\n\"   .+.........+.        \",\n\"    .+.......+.         \",\n\"     .+.....+.          \",\n\"      .+...+.           \",\n\"       .+.+.            \",\n\"        .+.             \",\n\"         .              \",\n\"                        \"]\nquitIcon = [\n\"24 24 3 1\",\n\"   c None\",\n\".  c #FFFFFF\",\n\"+  c #CC0000\",\n\"          ....          \",\n\"++++++++++....++++++++++\",\n\"+.......++....++.......+\",\n\"+.......++....++.......+\",\n\"+.......++....++.......+\",\n\"+...++++++....++++++...+\",\n\"+...++++++....++++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+......................+\",\n\"+......................+\",\n\"+......................+\",\n\"++++++++++++++++++++++++\"]\n\nresetIcon = [\n\"24 24 3 1\",\n\"   c None\",\n\".  c #3465A4\",\n\"+  c #888A85\",\n\"                        \",\n\"      ........          \",\n\"     .++++++++.         \",\n\"    .++..+....+.  ..... \",\n\"    .+.. .+....+. .+++. \",\n\"    .+.   .+....+..+.+. \",\n\"    ...    .+....+.+.+. \",\n\"            .+....+..+. \",\n\"             .+......+. \",\n\"              .+.....+. \",\n\"               .+....+. \",\n\"  ......        .+...+. \",\n\"  .++++.         .++++. \",\n\"  .+...+.        ...... \",\n\"  .+....+.              \",\n\"  .+.....+.             \",\n\"  .+......+.            \",\n\"  .+..+....+.           \",\n\"  .+.+.+....+.    ...   \",\n\"  .+.+..+....+.   .+.   \",\n\"  .+++. .+....+. ..+.   \",\n\"  .....  .+....+..++.   \",\n\"          .++++++++.    \",\n\"           ........     \"]\n\n#\nimport PySide\ntry:\n    from PySide import QtWidgets\n    from PySide.QtWidgets import *\nexcept Exception:\n    None\nfrom PySide import QtGui , QtCore\nfrom PySide.QtGui import *\nfrom PySide.QtCore import *\n#import PySide.QtXml\n\nGui = FreeCADGui\nApp = FreeCAD\n\nglobal ui         ; ui         = \"\"\nglobal sourisPass ; sourisPass = 0\n\nimport Draft, Part, FreeCAD, math, PartGui, FreeCADGui\nfrom math import sqrt, pi, sin, cos, asin\nfrom FreeCAD import Base\nfrom decimal import *\nfrom Draft import *\nfrom FreeCAD import Vector, Rotation, Placement, Console\nimport FreeCADGui\n#### geometry\nglobal setMainWindowMoveX; #setMainWindowMoveX= 0        # position X macro window\nglobal setMainWindowMoveY; #setMainWindowMoveY= 0        # position Y macro window\nglobal setFrameWindowSizeX #setFrameWindowSizeX=0        # dimension X macro window\nglobal setFrameWindowSizeY #setFrameWindowSizeY=0        # dimension Y macro window\n#\nsetMainWindowMoveX = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"setMainWindowMoveX\")\nsetMainWindowMoveY = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"setMainWindowMoveY\")\nsetFrameWindowSizeX= FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"setFrameWindowSizeX\")\nsetFrameWindowSizeY= FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"setFrameWindowSizeY\")\n#### geometry\n\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QApplication.translate(context, text, disambig)\n\nglobal surface     ; surface     = 0.0\nglobal volume_     ; volume_     = 0.0\nglobal boundBox_   ; boundBox_   = 0.0\nglobal boundBoxLX  ; boundBoxLX  = 0.0\nglobal boundBoxLY  ; boundBoxLY  = 0.0\nglobal boundBoxLZ  ; boundBoxLZ  = 0.0\nglobal boundBox_S  ; boundBox_S  = \"\"\nglobal uniteM_X    ; uniteM_X    = 1.0\nglobal uniteM_Y    ; uniteM_Y    = 1.0\nglobal uniteM_Z    ; uniteM_Z    = 1.0\nglobal uniteM      ; uniteM      = 1.0\nglobal uniteMs     ; uniteMs     = \"mm\"   # default mm\nglobal placement_X ; placement_X = 0.0\nglobal placement_Y ; placement_Y = 0.0\nglobal placement_Z ; placement_Z = 0.0\nglobal Yaw_Z       ; Yaw_Z       = 0.0\nglobal Pitch_Y     ; Pitch_Y     = 0.0\nglobal Roll_X      ; Roll_X      = 0.0\nglobal copyNumber  ; copyNumber  = 1\nglobal copyUnique  ; copyUnique  = 0\n\nglobal switchP     ; switchP     = 0\nglobal switchA     ; switchA     = 0\nglobal switchS     ; switchS     = 0\n\nglobal sel         ; sel         = \"\"\nglobal cloneCopy   ; cloneCopy   = 1\n\nglobal a ; a = \"\"\n\nglobal path\n##path###########################################################################\n#path = FreeCAD.ConfigGet(\"AppHomePath\")\n#path = FreeCAD.ConfigGet(\"UserAppData\")\n#path = \"your path\"\nparam = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")# macro path\npath = param.GetString(\"MacroPath\",\"\") + \"/\"                        # macro path\npath = path.replace(\"\\\\\",\"/\")\n#App.Console.PrintMessage(str(\"Path for the icons : \") + path + \"\\n\" + __title__ + \" : \" +__version__ + \" \" + __date__ + \"\\n\")\n#################################################################################\n\n## icon freeCAD Theme\n\nclass Ui_MainWindow(object):\n\n    def __init__(self, MainWindow):\n        global path\n        global uniteMs\n\n        self.path   = path\n        self.window = MainWindow\n        MainWindow.setObjectName(_fromUtf8(\"MainWindow\"))\n#        MainWindow.resize(230, 549)\n#        MainWindow.setMinimumSize(QtCore.QSize(230, 549))\n#        MainWindow.setMaximumSize(QtCore.QSize(230, 549))\n\n        #### geometry\n        global setMainWindowMoveX\n        global setMainWindowMoveY\n        global setFrameWindowSizeX\n        global setFrameWindowSizeY\n        #\n        MainWindow.setGeometry(setMainWindowMoveX, setMainWindowMoveY, setFrameWindowSizeX, setFrameWindowSizeY)\n        #### geometry\n\n        self.centralWidget = QWidget(MainWindow)\n        self.centralWidget.setObjectName(_fromUtf8(\"centralWidget\"))\n\n        self.label = QLabel()\n        font = QtGui.QFont()\n        font.setPointSize(12)\n        self.label.setFont(font)\n        self.label.setAlignment(QtCore.Qt.AlignCenter)\n\n        self.groupBox_00 = QGroupBox()\n        self.groupBox = QGroupBox()\n\n        self.radioButton = QRadioButton()\n        self.radioButton.setChecked(True)\n        self.radioButton.setIcon(QtGui.QIcon.fromTheme(\"close\",QtGui.QIcon(\":/icons/Draft_Clone.svg\")))\n        self.radioButton.clicked.connect(self.on_radioButton_clicked)     #connection radioButton mode clone\n\n        self.checkBox_00 = QCheckBox()\n        self.checkBox_00.setChecked(False)\n\n        self.radioButton_2 = QRadioButton()\n        self.radioButton_2.setIcon(QtGui.QIcon.fromTheme(\"close\",QtGui.QIcon(\":/icons/Part_Transformed_Copy.svg\")))\n        self.radioButton_2.clicked.connect(self.on_radioButton_2_clicked) #connection radioButton_2 mode copy\n\n        self.radioButton_3 = QRadioButton()\n        self.radioButton_3.setIcon(QtGui.QIcon.fromTheme(\"close\",QtGui.QIcon(\":/icons/Part_Compound.svg\")))\n        self.radioButton_3.clicked.connect(self.on_radioButton_3_clicked) #connection radioButton_3 mode compount\n\n        self.checkBox = QCheckBox()\n        self.checkBox.setChecked(True)\n\n        self.groupBox_Translate = QGroupBox()\n\n        self.label_2 = QLabel()\n#        self.label_2.setStyleSheet(\"QLabel {color : #aa0000}\")\n\n        self.doubleSpinBox = QDoubleSpinBox()\n        self.doubleSpinBox.setDecimals(8)\n        self.doubleSpinBox.setMinimum(-10000000.0)\n        self.doubleSpinBox.setMaximum(10000000.0)\n        self.doubleSpinBox.setSingleStep(1.0)\n        self.doubleSpinBox.setProperty(\"value\", 0.0)\n        self.doubleSpinBox.valueChanged.connect(self.on_doubleSpinBox_valueChanged) #connection doubleSpinBox\n\n        self.label_3 = QLabel()\n#        self.label_3.setStyleSheet(\"QLabel {color : #00aa00}\")\n\n        self.doubleSpinBox_2 = QDoubleSpinBox()\n        self.doubleSpinBox_2.setDecimals(8)\n        self.doubleSpinBox_2.setMinimum(-10000000.0)\n        self.doubleSpinBox_2.setMaximum(10000000.0)\n        self.doubleSpinBox_2.setSingleStep(1.0)\n        self.doubleSpinBox_2.setProperty(\"value\", 0.0)\n        self.doubleSpinBox_2.valueChanged.connect(self.on_doubleSpinBox_2_valueChanged) #connection doubleSpinBox_2\n\n        self.label_4 = QLabel()\n#        self.label_4.setStyleSheet(\"QLabel {color : #0000aa}\")\n\n        self.doubleSpinBox_3 = QDoubleSpinBox()\n        self.doubleSpinBox_3.setDecimals(8)\n        self.doubleSpinBox_3.setMinimum(-10000000.0)\n        self.doubleSpinBox_3.setMaximum(10000000.0)\n        self.doubleSpinBox_3.setSingleStep(1.0)\n        self.doubleSpinBox_3.setProperty(\"value\", 0.0)\n        self.doubleSpinBox_3.valueChanged.connect(self.on_doubleSpinBox_3_valueChanged) #connection doubleSpinBox_3\n\n        self.pushButton_5 = QPushButton()\n        self.pushButton_5.clicked.connect(self.on_pushButton_5_clicked)   # connect on def \"on_pushButton_5_clicked\"\n\n        self.groupBox_2 = QGroupBox()\n\n        self.comboBox = QComboBox()\n        self.comboBox.setMinimumContentsLength(0)\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        self.comboBox.addItem(_fromUtf8(\"\"))\n        QtCore.QObject.connect(self.comboBox, QtCore.SIGNAL(\"currentIndexChanged(QString)\"), self.SIGNAL_comboBox_Changed)\n \n        self.groupBox_3 = QGroupBox()\n \n        self.doubleSpinBox_4 = QDoubleSpinBox()\n        self.doubleSpinBox_4.setDecimals(8)\n        self.doubleSpinBox_4.setMinimum(-1000000)\n        self.doubleSpinBox_4.setMaximum(1000000.0)\n        self.doubleSpinBox_4.setSingleStep(1.0)\n        self.doubleSpinBox_4.setProperty(\"value\", 1.0)\n        self.doubleSpinBox_4.valueChanged.connect(self.on_doubleSpinBox_4_valueChanged) #connection doubleSpinBox_4\n\n        self.doubleSpinBox_5 = QDoubleSpinBox()\n        self.doubleSpinBox_5.setDecimals(8)\n        self.doubleSpinBox_5.setMinimum(-1000000)\n        self.doubleSpinBox_5.setMaximum(1000000.0)\n        self.doubleSpinBox_5.setSingleStep(1.0)\n        self.doubleSpinBox_5.setProperty(\"value\", 1.0)\n        self.doubleSpinBox_5.valueChanged.connect(self.on_doubleSpinBox_5_valueChanged) #connection doubleSpinBox_5\n\n        self.doubleSpinBox_6 = QDoubleSpinBox()\n        self.doubleSpinBox_6.setDecimals(8)\n        self.doubleSpinBox_6.setMinimum(-1000000)\n        self.doubleSpinBox_6.setMaximum(1000000.0)\n        self.doubleSpinBox_6.setSingleStep(1.0)\n        self.doubleSpinBox_6.setProperty(\"value\", 1.0)\n        self.doubleSpinBox_6.valueChanged.connect(self.on_doubleSpinBox_6_valueChanged) #connection doubleSpinBox_6\n\n        self.label_5 = QLabel()\n        self.label_6 = QLabel()\n        self.label_7 = QLabel()\n\n        self.pushButton_6 = QPushButton()\n        self.pushButton_6.clicked.connect(self.on_pushButton_6_clicked) # connect on def \"on_pushButton_6_clicked\"\n\n        self.pushButton_3 = QPushButton(self.groupBox_3)\n        self.pushButton_3.clicked.connect(self.on_pushButton03_clicked) #connection pushButton03 \"...\" align YZ to X\n\n        self.groupBox_4 = QGroupBox(self.centralWidget)\n\n        self.doubleSpinBox_7 = QDoubleSpinBox()\n        self.doubleSpinBox_7.setDecimals(8)\n        self.doubleSpinBox_7.setMinimum(-360.0)\n        self.doubleSpinBox_7.setMaximum(360.0)\n        self.doubleSpinBox_7.valueChanged.connect(self.on_doubleSpinBox_7_valueChanged) #connection doubleSpinBox_7\n\n        self.doubleSpinBox_8 = QDoubleSpinBox()\n        self.doubleSpinBox_8.setDecimals(8)\n        self.doubleSpinBox_8.setMinimum(-360.0)\n        self.doubleSpinBox_8.setMaximum(360.0)\n        self.doubleSpinBox_8.valueChanged.connect(self.on_doubleSpinBox_8_valueChanged) #connection doubleSpinBox_8\n\n        self.doubleSpinBox_9 = QDoubleSpinBox()\n        self.doubleSpinBox_9.setDecimals(8)\n        self.doubleSpinBox_9.setMinimum(-360.0)\n        self.doubleSpinBox_9.setMaximum(360.0)\n        self.doubleSpinBox_9.valueChanged.connect(self.on_doubleSpinBox_9_valueChanged) #connection doubleSpinBox_9\n\n        self.groupBox_5 = QGroupBox()\n        self.groupBox_6 = QGroupBox()\n\n        self.SpinBox = QSpinBox()\n        self.SpinBox.setMaximum(1000000)\n        self.SpinBox.setProperty(\"value\", 1)\n        self.SpinBox.valueChanged.connect(self.on_SpinBox_valueChanged) #connection SpinBox\n\n        self.label_8 = QLabel()\n        self.label_9 = QLabel()\n        self.label_10 = QLabel()\n\n        self.pushButton_4 = QPushButton()\n        self.pushButton_4.clicked.connect(self.on_pushButton_4_clicked) # connect on def \"on_pushButton_4_clicked\"\n\n        self.lineEdit = QLineEdit()\n        self.lineEdit.setText(\"Form\")\n\n        self.pushButton_2 = QPushButton()\n        self.pushButton_2.setIcon(QtGui.QIcon(QtGui.QPixmap(quitIcon))) # icone dans une variable \n        self.pushButton_2.clicked.connect(self.on_pushButton02_clicked) #connection pushButton02 \"Quitter\"\n\n        self.pushButton = QPushButton()\n        self.pushButton.setIcon(QtGui.QIcon(QtGui.QPixmap(resetIcon)))  # icone dans une variable \n        self.pushButton.clicked.connect(self.on_pushButton00_clicked)   #connection pushButton00 \"Reset\"\n\n        self.pushButton_1 = QPushButton()\n        self.pushButton_1.setStyleSheet(\"QPushButton {background-color: Base}\")\n        self.pushButton_1.setIcon(QtGui.QIcon(QtGui.QPixmap(validIcon)))# icone dans une variable \n        self.pushButton_1.clicked.connect(self.on_pushButton01_clicked) #connection pushButton01 \"OK\"\n\n        self.PB_Help = QPushButton()\n        self.PB_Help.setIcon(QtGui.QIcon(QtGui.QPixmap(helpIcon)))      # icone dans une variable \n        self.PB_Help.clicked.connect(self.on_PB_Help)                   #\n\n        #### gridLayout debut ####################\n        gridLayout_00 = QGridLayout(self.centralWidget)\n        gridLayout_00.addWidget(self.groupBox_00)\n        gridLayout_01 = QGridLayout(self.groupBox_00)\n        ####\n        gridLayout_Tittle = QGridLayout(self.label)\n        gridLayout_Tittle.setContentsMargins(2, 2, 2, 2)\n        gridLayout_01.addWidget(self.label, 0, 0, 1, 2)\n        ####\n        self.gridLayout_Mode = QGridLayout(self.groupBox)\n        self.gridLayout_Mode.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_Mode.addWidget(self.radioButton, 0, 0, 1, 1)\n        self.gridLayout_Mode.addWidget(self.checkBox_00, 0, 1, 1, 1)\n        self.gridLayout_Mode.addWidget(self.radioButton_2, 1, 0, 1, 1)\n        self.gridLayout_Mode.addWidget(self.radioButton_3, 1, 1, 1, 1)\n        self.gridLayout_Mode.addWidget(self.checkBox, 1, 2, 1, 1)\n        gridLayout_01.addWidget(self.groupBox, 1, 0, 1, 2)\n        ####\n        self.gridLayout_Translate = QGridLayout(self.groupBox_Translate)\n        self.gridLayout_Translate.addWidget(self.label_2, 0, 0, 1, 1)\n        self.gridLayout_Translate.addWidget(self.pushButton_5, 0, 1, 1, 1)\n        self.gridLayout_Translate.addWidget(self.doubleSpinBox, 0, 2, 1, 1)\n        self.gridLayout_Translate.addWidget(self.label_3, 1, 0, 1, 1)\n        self.gridLayout_Translate.addWidget(self.doubleSpinBox_2, 1, 2, 1, 1)\n        self.gridLayout_Translate.addWidget(self.label_4, 2, 0, 1, 1)\n        self.gridLayout_Translate.addWidget(self.doubleSpinBox_3, 2, 2, 1, 1)\n        gridLayout_01.addWidget(self.groupBox_Translate, 2, 0, 1, 2)\n        ####\n        self.gridLayout_Rotation = QGridLayout(self.groupBox_4)\n        self.gridLayout_Rotation.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_Rotation.addWidget(self.label_8, 0, 0, 1, 1)\n        self.gridLayout_Rotation.addWidget(self.pushButton_4, 0, 1, 1, 1)\n        self.gridLayout_Rotation.addWidget(self.doubleSpinBox_7, 0, 2, 1, 1)\n        self.gridLayout_Rotation.addWidget(self.label_9, 1, 0, 1, 1)\n        self.gridLayout_Rotation.addWidget(self.doubleSpinBox_8, 1, 2, 1, 1)\n        self.gridLayout_Rotation.addWidget(self.label_10, 2, 0, 1, 1)\n        self.gridLayout_Rotation.addWidget(self.doubleSpinBox_9, 2, 2, 1, 1)\n        gridLayout_01.addWidget(self.groupBox_4, 3, 0, 1, 2)\n        ####\n        self.gridLayout_Scale = QGridLayout(self.groupBox_2)\n        self.gridLayout_Scale.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_Scale.addWidget(self.comboBox, 0, 0, 1, 1)\n        gridLayout_01.addWidget(self.groupBox_2, 4, 0, 1, 1)\n        ####\n        self.gridLayout_NumberCopy = QGridLayout(self.groupBox_5)\n        self.gridLayout_NumberCopy.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_NumberCopy.addWidget(self.SpinBox, 0, 0, 1, 1)\n        gridLayout_01.addWidget(self.groupBox_5, 4, 1, 1, 1)\n        ####\n        self.gridLayout_ScaleFree = QGridLayout(self.groupBox_3)\n        self.gridLayout_ScaleFree.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_ScaleFree.addWidget(self.label_5, 0, 0, 1, 1)\n        self.gridLayout_ScaleFree.addWidget(self.pushButton_3, 0, 1, 1, 1)\n        self.gridLayout_ScaleFree.addWidget(self.doubleSpinBox_4, 0, 2, 1, 1)\n        self.gridLayout_ScaleFree.addWidget(self.label_6, 1, 0, 1, 1)\n        self.gridLayout_ScaleFree.addWidget(self.doubleSpinBox_5, 1, 2, 1, 1)\n        self.gridLayout_ScaleFree.addWidget(self.label_7, 2, 0, 1, 1)\n        self.gridLayout_ScaleFree.addWidget(self.doubleSpinBox_6, 2, 2, 1, 1)\n        gridLayout_01.addWidget(self.groupBox_3, 5, 0, 1, 2)\n        ####\n        self.gridLayout_Command = QGridLayout(self.groupBox_6)\n        self.gridLayout_Command.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_Command.addWidget(self.pushButton_6, 0, 0, 1, 1)\n        self.gridLayout_Command.addWidget(self.lineEdit, 0, 1, 1, 3)\n        self.gridLayout_Command.addWidget(self.pushButton_2, 1, 0, 1, 1)\n        self.gridLayout_Command.addWidget(self.pushButton, 1, 1, 1, 1)\n        self.gridLayout_Command.addWidget(self.pushButton_1, 1, 2, 1, 1)\n        self.gridLayout_Command.addWidget(self.PB_Help, 1, 3, 1, 1)\n        gridLayout_01.addWidget(self.groupBox_6, 6, 0, 1, 2)\n        #### gridLayout fin ####################\n\n        MainWindow.setCentralWidget(self.centralWidget)\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n        _translate = QtCore.QCoreApplication.translate\n        MainWindow.setWindowTitle(_translate(\"MainWindow\", __title__, None))\n        MainWindow.setWindowIcon(QtGui.QIcon(_fromUtf8(self.path + \"Macro_CloneConvert.png\")))  # change l'icone de la fenetre principale\n        MainWindow.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)                       # cette fonction met la fenetre en avant\n\n        self.groupBox_00.setTitle(_translate(\"MainWindow\", \"ver : \" + __version__ + \" : \" + __date__, None))\n        self.label.setText(_translate(\"MainWindow\", \"Clone Convert\", None))\n        self.groupBox.setTitle(_translate(\"MainWindow\", \"Mode\", None))\n        ####\n        self.radioButton.setText(_translate(\"MainWindow\", \"Clone\", None))\n        self.radioButton.setToolTip(_translate(\"MainWindow\", \"Create a clone of the object(s)\", None))\n        self.checkBox_00.setText(_translate(\"MainWindow\", \"Unique\", None))\n        self.checkBox_00.setToolTip(_translate(\"MainWindow\", \"If checked and multiple object selected\" + \"\\n\"\n                                                             \"the clone created is one unique object\" + \"\\n\"\n                                                             \"or the 'Comp'ound object is created without\" + \"\\n\"\n                                                             \"modification or attach to the original(s) object(s)\", None))\n        self.radioButton_2.setText(_translate(\"MainWindow\", \"Copy\", None))\n        self.radioButton_2.setToolTip(_translate(\"MainWindow\", \"Create a copy of the object(s)\", None))\n        self.radioButton_3.setText(_translate(\"MainWindow\", \"Comp.\", None))\n        self.radioButton_3.setToolTip(_translate(\"MainWindow\", \"Create a compount of the object(s)\" + \"\\n\"\n                                                               \"If the checkBox 'Unique' is checked\" + \"\\n\"\n                                                               \"the compound is created in 1 object and not touch the original(s) object(s)\" + \"\\n\"\n                                                               \"if not the compound is one normal system compound\", None))\n        self.checkBox.setText(_translate(\"MainWindow\", \"Increm.\", None))\n        self.checkBox.setToolTip(_translate(\"MainWindow\", \"Apply incremental changes to object Placement (Defaut)\\n\"+\n                                                          \"If this is not checked the Placement begin in coordinates 0,0,0 of FreeCAD\\n\"+\n                                                          \"In case a compound Placement information is [0,0,0] the Placement begin in the position of object\\n\"+\n                                                          \"If the real location is away from the base coordinates 0,0,0 use the ValueAt() button\\n\"\n                                                          \"for the real Placement of the subObject selected Face, Wire, Line ....\", None))\n        ####\n        self.groupBox_Translate.setTitle(_translate(\"MainWindow\", \"Translate\", None))\n        self.label_2.setText(\"<html> <body> <text=\"\"#000000\"\"> Coordinate <FONT COLOR=\"\"#aa0000\"\"> X </font> </body> </html>\" )\n        self.pushButton_5.setToolTip(_translate(\"MainWindow\", \"Align the YZ coordinates values to X value  \\n Two click reset the coordinates values to 0.0\", None))\n        self.pushButton_5.setText(_translate(\"MainWindow\", \"Align YZ ...\", None))\n        self.doubleSpinBox.setToolTip(_translate(\"MainWindow\", \"Place the new object to the X coordinate \", None))\n        self.doubleSpinBox.setSuffix(_translate(\"MainWindow\", \" mm\", None))\n        self.label_3.setText(\"<html> <body> <text=\"\"#000000\"\"> Coordinate <FONT COLOR=\"\"#00aa00\"\"> Y </font> </body> </html>\" )\n        self.doubleSpinBox_2.setToolTip(_translate(\"MainWindow\", \"Place the new object to the Y coordinate\", None))\n        self.doubleSpinBox_2.setSuffix(_translate(\"MainWindow\", \" mm\", None))\n        self.label_4.setText(\"<html> <body> <text=\"\"#000000\"\"> Coordinate <FONT COLOR=\"\"#0000aa\"\"> Z </font> </body> </html>\" )\n        self.doubleSpinBox_3.setToolTip(_translate(\"MainWindow\", \"Place the new object to the Z coordinate\", None))\n        self.doubleSpinBox_3.setSuffix(_translate(\"MainWindow\", \" mm\", None))\n        ####\n        self.groupBox_4.setTitle(_translate(\"MainWindow\", \"Rotation\", None))\n#        self.label_8.setText(_translate(\"MainWindow\", \"Yaw ( Z )\", None))\n        self.label_8.setText(\"<html> <body> <text=\"\"#000000\"\"> Yaw (  <FONT COLOR=\"\"#0000aa\"\"> Z </font>  <text=\"\"#000000\"\"> ) </body> </html>\" )\n        self.pushButton_4.setToolTip(_translate(\"MainWindow\", \"Align the YX degrees values to Z value \\n Two click reset the rotations values to 0.0\", None))\n        self.pushButton_4.setText(_translate(\"MainWindow\", \"Align YX ...\", None))\n        self.doubleSpinBox_7.setSuffix(_translate(\"MainWindow\", \" Deg\", None))\n        self.doubleSpinBox_7.setToolTip(_translate(\"MainWindow\", \"Rotation of Yaw ( Axis Z )\", None))\n#        self.label_9.setText(_translate(\"MainWindow\", \"Pitch ( Y )\", None))\n        self.label_9.setText(\"<html> <body> <text=\"\"#000000\"\"> Pitch (  <FONT COLOR=\"\"#00aa00\"\"> Y </font>  <text=\"\"#000000\"\"> ) </body> </html>\" )\n        self.doubleSpinBox_8.setSuffix(_translate(\"MainWindow\", \" Deg\", None))\n        self.doubleSpinBox_8.setToolTip(_translate(\"MainWindow\", \"Rotation of Pitch ( Axis Y )\", None))\n#        self.label_10.setText(_translate(\"MainWindow\", \"Roll ( X )\", None))\n        self.label_10.setText(\"<html> <body> <text=\"\"#000000\"\"> Roll (  <FONT COLOR=\"\"#aa0000\"\"> X </font>  <text=\"\"#000000\"\"> ) </body> </html>\" )\n        self.doubleSpinBox_9.setSuffix(_translate(\"MainWindow\", \" Deg\", None))\n        self.doubleSpinBox_9.setToolTip(_translate(\"MainWindow\", \"Rotation of Roll ( Axis X )\", None))\n        ####\n        self.groupBox_2.setTitle(_translate(\"MainWindow\", \"Scale predefined\", None))\n        self.comboBox.setToolTip(_translate(\"MainWindow\", \"Convert your object to . . .\", None))\n        self.comboBox.setCurrentIndex(6)\n        self.comboBox.setItemText(0, \"km\")         #km #        = 1000000\n        self.comboBox.setItemText(1, \"hm\")         #hm #        = 100000\n        self.comboBox.setItemText(2, \"dam\")        #dam#        = 10000\n        self.comboBox.setItemText(3, \"m\")          #m  #        = 1000\n        self.comboBox.setItemText(4, \"dm\")         #dm #        = 100\n        self.comboBox.setItemText(5, \"cm\")         #cm #        = 10\n        self.comboBox.setItemText(6, \"mm\")         #mm #        = 1        #####\n        self.comboBox.setItemText(7, \"um\")         #um # micro  = 0.001\n        self.comboBox.setItemText(8, \"nm\")         #nm # nano   = 0.000001\n        self.comboBox.setItemText(9, \"inch\")       #in # inch  pouce    = 25.400\n        self.comboBox.setItemText(10, \"link\")      #lk # link  chainon  = 201.168\n        self.comboBox.setItemText(11, \"foot\")      #ft # foot  pied     = 304.800\n        self.comboBox.setItemText(12, \"yard\")      #yd # yard  verge    = 914.400\n        self.comboBox.setItemText(13, \"perch\")     #rd # rod ou perch   perche   = 5029.200\n        self.comboBox.setItemText(14, \"chain\")     #ch # chain chaine   = 20116.800\n        self.comboBox.setItemText(15, \"furlong\")   #fur# furlong        = 201168\n        self.comboBox.setItemText(16, \"mile\")      #mi # mile           = 1609344\n        self.comboBox.setItemText(17, \"league\")    #lea# league lieue   = 4828032\n        self.comboBox.setItemText(18, \"nautique\")  #nmi# mile nautique  = 1852000\n        self.comboBox.setToolTip(_translate(\"MainWindow\",u\"Select unit. . .\", None))\n        ####\n        self.groupBox_5.setTitle(_translate(\"MainWindow\", \"Number copy\", None))\n        self.SpinBox.setToolTip(_translate(\"MainWindow\", \"Number copy of original\", None))\n        ####\n        self.groupBox_3.setTitle(_translate(\"MainWindow\", \"Scale free\", None))\n        self.label_5.setText(_translate(\"MainWindow\", \"Scale X\", None))\n        self.pushButton_3.setToolTip(_translate(\"MainWindow\", \"Align the YZ scale values to X scale value  \\n Two click reset the scales values to 1.0\", None))\n        self.pushButton_3.setText(_translate(\"MainWindow\", \"Align YZ ...\", None))\n        self.doubleSpinBox_4.setToolTip(_translate(\"MainWindow\", \"Scale free X multiplied by ...\\nIf the value is negative the object result is reverted in X axis\", None))\n        self.label_6.setText(_translate(\"MainWindow\", \"Scale Y\", None))\n        self.doubleSpinBox_5.setToolTip(_translate(\"MainWindow\", \"Scale free Y multiplied by ...\\n\"+\n                                                                 \"If the value is negative the object result is reverted in Y axis\", None))\n        self.label_7.setText(_translate(\"MainWindow\", \"Scale Z\", None))\n        self.doubleSpinBox_6.setToolTip(_translate(\"MainWindow\", \"Scale free Z multiplied by ...\\n\"+\n                                                                 \"If the value is negative the object result is reverted in Z axis\", None))\n        ####\n        self.groupBox_6.setTitle(_translate(\"MainWindow\", \"Command\", None))\n        self.pushButton_6.setToolTip(_translate(\"MainWindow\", \"Give the valueAt() the subObject selected Face, Wire, Line ...\\n\"+\n                                                \"This option is useful in case a compound Placement information [0,0,0]\\n\"+\n                                                \"and its real location is away from the base coordinates 0,0,0\\n\"+\n                                                \"(gives no provide information about the tilt of the object)\", None))\n        self.pushButton_6.setText(_translate(\"MainWindow\", \"ValueAt()\", None))\n        ##\n        self.pushButton_2.setToolTip(_translate(\"MainWindow\", \"Quit the macro\", None))\n        self.pushButton_2.setText(_translate(\"MainWindow\", \"Quit\", None))\n        self.pushButton.setToolTip(_translate(\"MainWindow\", \"Reset the values\", None))\n        self.pushButton.setText(_translate(\"MainWindow\", \"Reset\", None))\n        self.pushButton_1.setToolTip(_translate(\"MainWindow\", \"Ok for Convert Copy or Compount\", None))\n        self.pushButton_1.setText(_translate(\"MainWindow\", \"Ok\", None))\n        self.PB_Help.setText(_translate(\"MainWindow\", \"Help\"))\n\n    def SIGNAL_comboBox_Changed(self,text):\n        global uniteM_X\n        global uniteM_Y\n        global uniteM_Z\n        global uniteM\n        global uniteMs\n\n        if text == \"km\":        #        = 1000000\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1000000.0\n            uniteMs= \"km\"\n        elif text == \"hm\":      #        = 100000\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 100000.0\n            uniteMs= \"hm\"\n        elif text == \"dam\":     #        = 10000\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 10000.0\n            uniteMs= \"dam\"\n        elif text == \"m\":       #        = 1000\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1000.0\n            uniteMs= \"m\"\n        elif text == \"dm\":      #        = 100\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 100.0\n            uniteMs= \"dm\"\n        elif text == \"cm\":      #        = 10\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 10.0\n            uniteMs= \"cm\"\n        elif text == \"mm\":      #        = 1  ###############################\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1.0\n            uniteMs= \"mm\"\n        elif text == \"um\":      #        = 1000\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1.0/1000.0\n            uniteMs= \"um\"\n        elif text == \"nm\":      #        = 1000000\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1.0/1000000.0\n            uniteMs= u\"nm\"\n        elif text == \"inch\":    # inch   = 25.400\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 25.400\n            uniteMs= \"in\"\n        elif text == \"link\":    # link   = 201.168\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 201.168\n            uniteMs= \"lk\"\n        elif text == \"foot\":    # foot   = 304.800\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 304.800\n            uniteMs= \"ft\"\n        elif text == \"yard\":    # yard   = 914.400\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 914.400\n            uniteMs= \"yd\"\n        elif text == \"perch\":   #rd # rod   perche    = 5029.200\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 5029.200\n            uniteMs= \"rd\"\n        elif text == \"chain\":   # chain  = 20116.800\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 20116.800\n            uniteMs= \"ch\"\n        elif text == \"furlong\": # furlong= 201168\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 201168\n            uniteMs= \"fur\"\n        elif text == \"mile\":     # mile   = 1609344\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1609344\n            uniteMs= \"mi\"\n        elif text == \"league\":   # league = 4828032\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 4828032\n            uniteMs= \"lea\"\n        elif text == \"nautique\": # nautique = 1852000\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1852000\n            uniteMs= \"nmi\"\n        else:                    # mm = 1\n            uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1.0 \n            uniteMs= \"mm\"\n\n        self.doubleSpinBox_4.setProperty(\"value\", uniteM_X)\n        self.doubleSpinBox_5.setProperty(\"value\", uniteM_Y)\n        self.doubleSpinBox_6.setProperty(\"value\", uniteM_Z)\n\n    def on_radioButton_clicked(self):                    # if checked then mode clone\n        global cloneCopy\n\n        cloneCopy = 1\n\n    def on_radioButton_2_clicked(self):                  # if checked then mode copy\n        global cloneCopy\n\n        cloneCopy = 0\n\n    def on_radioButton_3_clicked(self):                  # if checked then mode compount\n        global cloneCopy\n\n        cloneCopy = 2\n\n    def on_doubleSpinBox_valueChanged(self,value):       # doubleSpinbox X\n        global placement_X\n        global switchP\n\n        switchP     = 0\n        placement_X = value\n\n    def on_doubleSpinBox_2_valueChanged(self,value):     # doubleSpinbox Y \n        global placement_Y\n        global switchP\n\n        switchP     = 0\n        placement_Y = value\n\n    def on_doubleSpinBox_3_valueChanged(self,value):     #  doubleSpinbox Z\n        global placement_Z\n        global switchP\n\n        switchP     = 0\n        placement_Z = value\n\n    def on_doubleSpinBox_4_valueChanged(self,value):     # doubleSpinbox free X\n        global uniteM_X\n        global switchS\n\n        switchS  = 0\n        uniteM_X = value\n        if uniteM_X == 0:\n            uniteM_X = 1\n\n    def on_doubleSpinBox_5_valueChanged(self,value):     # doubleSpinbox free Y \n        global uniteM_Y\n        global switchS\n\n        switchS  = 0\n        uniteM_Y = value\n        if uniteM_Y == 0:\n            uniteM_Y = 1\n\n    def on_doubleSpinBox_6_valueChanged(self,value):     #  doubleSpinbox free Z\n        global uniteM_Z\n        global switchS\n\n        switchS  = 0\n        uniteM_Z = value\n        if uniteM_Z == 0:\n            uniteM_Z = 1\n\n    def on_doubleSpinBox_7_valueChanged(self,value):     # doubleSpinBox_7  Yaw ( Z )\n        global Yaw_Z\n        global switchA\n\n        switchA  = 0\n        Yaw_Z = value\n\n    def on_doubleSpinBox_8_valueChanged(self,value):     # doubleSpinBox_8 Pitch ( Y )\n        global Pitch_Y\n        global switchA\n\n        switchA  = 0\n        Pitch_Y = value\n\n    def on_doubleSpinBox_9_valueChanged(self,value):     # doubleSpinBox_9 Roll ( X )\n        global Roll_X\n        global switchA\n\n        switchA  = 0\n        Roll_X = value\n\n    def on_SpinBox_valueChanged(self,value):             # SpinBox Number copy\n        global copyNumber\n\n        copyNumber = value\n\n    def on_pushButton_5_clicked(self):                   # Bouton ... (align) placement\n        global placement_X\n        global placement_Y\n        global placement_Z\n        global switchP\n\n        if switchP == 0:\n            placement_Y = placement_Z = placement_X\n            switchP = 1\n        else:\n            placement_Y = placement_Z = placement_X = 0.0\n            switchP = 0\n\n        self.doubleSpinBox.setProperty(\"value\", placement_X)\n        self.doubleSpinBox_2.setProperty(\"value\", placement_Y)\n        self.doubleSpinBox_3.setProperty(\"value\", placement_Z)\n\n    def on_pushButton_6_clicked(self):                    # valueAt() placement detected\n        try:\n            sel = FreeCADGui.Selection.getSelection()\n            App.Console.PrintMessage(str(sel[0].Placement) +\"\\r\\n\")\n            selectionObjects = FreeCADGui.Selection.getSelectionEx()   # Select an object or sub object getSelectionEx\n            edge = selectionObjects[0].SubObjects[0]\n            try:\n                self.lineEdit.setText(str(edge.valueAt(0,0))) # face\n                self.pushButton_6.setText(_translate(\"MainWindow\", \"ValueAt(0,0)\", None))\n                App.Console.PrintMessage(str(edge.valueAt(0,0)) +\"\\r\\n\")\n            except Exception:\n                self.lineEdit.setText(str(edge.valueAt(0)))   # fil\n                self.pushButton_6.setText(_translate(\"MainWindow\", \"ValueAt(0)\", None))\n                App.Console.PrintMessage(str(edge.valueAt(0)) +\"\\r\\n\")\n        except Exception:\n            self.pushButton_6.setText(_translate(\"MainWindow\", \"ValueAt()\", None))\n            App.Console.PrintError(\"Select one subObject, Face, Wire, Line ...\"+\"\\r\\n\")\n        App.Console.PrintMessage(\"____________________________________\"+\"\\r\\n\")\n        \n    def on_pushButton_4_clicked(self):                   # Bouton ... (align) rotation\n        global Yaw_Z\n        global Pitch_Y\n        global Roll_X\n        global switchA\n\n        if switchA == 0:\n            Pitch_Y = Roll_X = Yaw_Z\n            switchA = 1\n        else:\n            Pitch_Y = Roll_X = Yaw_Z = 0.0\n            switchA = 0\n\n        self.doubleSpinBox_7.setProperty(\"value\", Yaw_Z)\n        self.doubleSpinBox_8.setProperty(\"value\", Pitch_Y)\n        self.doubleSpinBox_9.setProperty(\"value\", Roll_X)\n\n    def on_pushButton03_clicked(self):                   # Bouton ... (align) uniteM\n        global uniteM_X\n        global uniteM_Y\n        global uniteM_Z\n        global switchS\n        global uniteM\n        global uniteMs\n\n        if switchS == 0:\n            uniteM_Y = uniteM_Z = uniteM_X\n            switchS = 1\n        else:\n            uniteM_Y = uniteM_Z = uniteM_X = 1.0\n            switchS = 0\n\n        self.doubleSpinBox_4.setProperty(\"value\", uniteM_X)\n        self.doubleSpinBox_5.setProperty(\"value\", uniteM_Y)\n        self.doubleSpinBox_6.setProperty(\"value\", uniteM_Z)\n\n    def on_pushButton00_clicked(self):                   # Bouton Reset\n        global sel\n        global uniteM_X\n        global uniteM_Y\n        global uniteM_Z\n        global uniteM\n        global uniteMs\n        global placement_X\n        global placement_Y\n        global placement_Z\n        global cloneCopy\n        global Yaw_Z\n        global Pitch_Y\n        global Roll_X\n        global copyNumber\n\n        sel         = \"\"\n\n        self.pushButton_1.setToolTip(\"Ok for Convert or copy\")\n        self.pushButton_1.setStyleSheet(\"QPushButton {background-color: Base}\")\n\n        self.radioButton.setChecked(True)\n        cloneCopy = 1\n\n        self.comboBox.setCurrentIndex(6)\n        self.doubleSpinBox.setProperty(\"value\",   0.0) # coordinates\n        self.doubleSpinBox_2.setProperty(\"value\", 0.0)\n        self.doubleSpinBox_3.setProperty(\"value\", 0.0)\n        self.checkBox.setChecked(True)\n\n        placement_X = placement_Y = placement_Z = 0.0\n\n        self.doubleSpinBox_4.setProperty(\"value\", 1.0) # scale\n        self.doubleSpinBox_5.setProperty(\"value\", 1.0)\n        self.doubleSpinBox_6.setProperty(\"value\", 1.0)\n \n        self.doubleSpinBox_7.setProperty(\"value\", 0.0) # angles\n        self.doubleSpinBox_8.setProperty(\"value\", 0.0)\n        self.doubleSpinBox_9.setProperty(\"value\", 0.0)\n\n        self.SpinBox.setProperty(\"value\", 1)           # number copy\n        copyNumber  = 1\n\n        uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1.0\n        uniteMs= \"mm\"\n        uniteM = 1\n        self.lineEdit.setText(\"\")\n \n    def on_pushButton01_clicked(self):                  # Bouton OK\n        global sel\n        global surface\n        global volume_\n        global boundBox\n        global boundBoxLX\n        global boundBoxLY\n        global boundBoxLZ\n        global boundBox_S\n        global uniteM_X\n        global uniteM_Y\n        global uniteM_Z\n        global uniteM\n        global uniteMs\n        global placement_X\n        global placement_Y\n        global placement_Z\n        global sel\n        global Yaw_Z\n        global Pitch_Y\n        global Roll_X\n        global copyNumber\n        global copyUnique\n\n        sel = FreeCADGui.Selection.getSelection()   \n\n        if len(sel) != 0:\n\n            FreeCAD.ActiveDocument.openTransaction(\"FCCConvert\")    # memorise les actions (avec annuler restore)\n            #FreeCAD.ActiveDocument.commitTransaction()         # restore les actions  (avec annuler restore)\n            #FreeCAD.ActiveDocument.abortTransaction()          # abandonne les actions(avec annuler restore)\n\n            self.pushButton_1.setToolTip(_translate(\"MainWindow\", \"Ok for Convert or copy\", None))\n            self.pushButton_1.setStyleSheet(\"QPushButton {background-color: Base}\")\n            FreeCADGui.updateGui()                                 # rafraichi l'ecran\n\n             # boundinbox (dimensions hors tout)\n            try:\n                boundBox_ = sel[0].Shape.BoundBox # pour 1 seul objet, (le premier)\n                boundBoxLX = boundBox_.XLength\n                boundBoxLY = boundBox_.YLength\n                boundBoxLZ = boundBox_.ZLength\n            except:\n                boundBox_  = 0.0\n                boundBoxLX = 0.0\n                boundBoxLY = 0.0\n                boundBoxLZ = 0.0\n                boundBox_S = \"\"\n\n             # volume de tous les objets\n            volume_ = 0.0\n            try:\n                for i in range(len(sel)):\n                    volume_ += sel[i].Shape.Volume\n            except:\n                volume_ = 0.0\n\n             # surface de tous les objets\n            surface = 0.0\n            try:\n                for i in range(len(sel)):\n                    surface += sel[i].Shape.Area\n            except:\n                surface = 0.0\n\n            boundBox_S = \"[X: \"+str(boundBoxLX)+\" mm] x [Y: \"+str(boundBoxLY)+\" mm] x [Z:\"+str(boundBoxLZ)+\" mm]\"\n            App.Console.PrintMessage(\"Original boundBox : \"+boundBox_S+\"\\r\\n\")\n            App.Console.PrintMessage(\"Original volume_  : \"+str(volume_)+\" mm3 (\"+str(len(sel))+\" element(s))\"+\"\\r\\n\")\n            App.Console.PrintMessage(\"Original surface  : \"+str(surface)+\" mm2 (\"+str(len(sel))+\" element(s))\"+\"\\r\\n\")\n            App.Console.PrintMessage(\"- - - - - - - - - -\"+\"\\r\\n\")\n\n            try:\n                obj = comptName = \"\"\n                import Draft\n\n                for copies in range(1,copyNumber+1): ##### Boucle copies Debut ###########################\n\n                    if copyNumber > 1:\n                        comptName = str(copies)\n\n                    if cloneCopy == 1:       # clone ok clone object and stay solidaris \n                        if self.checkBox_00.isChecked():       # create clone unique with all object Ok\n                            mess = \"Clone\"\n                            obj=Draft.clone(sel)\n                            try:\n                                obj.Scale = (uniteM_X, uniteM_Y, uniteM_Z)\n                            except Exception:\n                                try:\n                                    FreeCAD.ActiveDocument.getObject(obj.Name).Length.Value      = (sel[0].Length.Value * uniteM_X)\n                                    FreeCAD.ActiveDocument.getObject(obj.Name).Thickness.Value   = (sel[0].Thickness.Value * uniteM_Y)\n                                    FreeCAD.ActiveDocument.getObject(obj.Name).Width.Value       = (sel[0].Width.Value * uniteM_Z)\n                                except Exception:\n                                    None\n\n                            if self.checkBox.isChecked(): # if checkbox is checked then .... increment\n                                obj.Placement=App.Placement(App.Vector(placement_X,placement_Y,placement_Z), App.Rotation(Yaw_Z,Pitch_Y,Roll_X), App.Vector(0,0,0)).multiply(App.activeDocument().getObject(obj.Name).Placement) # increment\n                            else:\n                                obj.Placement=App.Placement(App.Vector(placement_X,placement_Y,placement_Z), App.Rotation(Yaw_Z,Pitch_Y,Roll_X), App.Vector(0,0,0))\n                            oL = obj.Label[:5] + \" \" + comptName + \" \" +  obj.Label[6:]\n                            obj.Label = oL\n                        else:                                  # create clone object separated\n                            mess = \"Clone\"\n                            for i in range(len(sel)):\n                                obj=Draft.clone(sel[i])\n\n                                try:\n                                    obj.Scale = (uniteM_X, uniteM_Y, uniteM_Z)\n                                except Exception:\n                                    try:\n                                        FreeCAD.ActiveDocument.getObject(obj.Name).Length.Value      = (sel[i].Length.Value * uniteM_X)\n                                        FreeCAD.ActiveDocument.getObject(obj.Name).Thickness.Value   = (sel[i].Thickness.Value * uniteM_Y)\n                                        FreeCAD.ActiveDocument.getObject(obj.Name).Width.Value       = (sel[i].Width.Value * uniteM_Z)\n                                    except Exception:\n                                        None\n\n                                if self.checkBox.isChecked(): # if checkbox is checked then .... increment\n                                    obj.Placement=App.Placement(App.Vector(placement_X,placement_Y,placement_Z), App.Rotation(Yaw_Z,Pitch_Y,Roll_X), App.Vector(0,0,0)).multiply(App.activeDocument().getObject(sel[i].Name).Placement) # increment\n                                else:\n                                    obj.Placement=App.Placement(App.Vector(placement_X,placement_Y,placement_Z), App.Rotation(Yaw_Z,Pitch_Y,Roll_X), App.Vector(0,0,0))\n                                oL = obj.Label[:5] + \" \" + comptName + \" \" +  obj.Label[6:]\n                                obj.Label = oL\n                                obj.touch()  # recompute l'objet\n                            if len(sel) > 1:\n                                obj = \"\"\n\n                    if cloneCopy == 0:       # copy ok copy object not touch original\n                        mess = \"Copy \"\n                        for i in range(len(sel)):\n                            obj = Draft.scale(sel[i],App.Vector(uniteM_X, uniteM_Y, uniteM_Z),center=App.Vector(0,0,0),copy=True)\n                            if self.checkBox.isChecked(): # if checkbox is checked then .... increment\n                                obj.Placement=App.Placement(App.Vector(placement_X,placement_Y,placement_Z), App.Rotation(Yaw_Z,Pitch_Y,Roll_X), App.Vector(0,0,0)).multiply(App.activeDocument().getObject(obj.Name).Placement) # increment\n                            else:\n                                obj.Placement=App.Placement(App.Vector(placement_X,placement_Y,placement_Z), App.Rotation(Yaw_Z,Pitch_Y,Roll_X), App.Vector(0,0,0))\n\n                            obj2 = Part.show(obj.Shape)\n\n                            FreeCADGui.activeDocument().activeObject().LineColor  = sel[i].ViewObject.LineColor\n                            FreeCADGui.activeDocument().activeObject().PointColor = sel[i].ViewObject.PointColor\n                            FreeCADGui.activeDocument().activeObject().ShapeColor = sel[i].ViewObject.ShapeColor\n\n                            App.ActiveDocument.ActiveObject.Label = \"Copy \" + comptName + \" of \" + sel[i].Label\n                            App.ActiveDocument.removeObject(obj.Name)\n                            obj = App.ActiveDocument.ActiveObject\n                    if cloneCopy == 2:     # compound ok\n                        liste = []\n                        if self.checkBox_00.isChecked():       # create clone unique with all object not touch originalOk\n                            mess = \"Block \"\n                            for i in sel:\n                                ### Begin command Part_SimpleCopy   # duplicate the original object\n                                __shape = Part.getShape(App.ActiveDocument.getObject(i.Name),'',needSubElement=False,refine=False)\n                                App.ActiveDocument.addObject('Part::Feature',i.Label).Shape=__shape\n                                duplicate = App.ActiveDocument.ActiveObject\n                                #App.ActiveDocument.ActiveObject.recompute()\n                                liste.append(App.ActiveDocument.getObject(duplicate.Name))\n                                ### End command Part_SimpleCopy\n                            objori = Draft.makeBlock(liste) # create Block other method compound\n                            objori.Label = mess + \"_\" + str(len(liste))\n                            App.ActiveDocument.ActiveObject.recompute()\n                            for i in liste:\n                                App.ActiveDocument.removeObject(i.Name)\n                                App.ActiveDocument.recompute()\n                        else:\n                            mess = \"Compount \"  # ne modifie pas les originaux\n                            for i in sel:\n                                liste.append(App.ActiveDocument.getObject(i.Name))\n\n                            objori = App.activeDocument().addObject(\"Part::Compound\",\"Compound\")\n                            App.activeDocument().Compound.Links = liste\n                            App.ActiveDocument.recompute()\n\n                        obj = App.ActiveDocument.addObject('Part::Scale','Scale')\n                        obj.Base = App.ActiveDocument.getObject(objori.Name)\n                        obj.Uniform = False\n                        obj.UniformScale = 1.0\n                        obj.XScale = uniteM_X\n                        obj.YScale = uniteM_Y\n                        obj.ZScale = uniteM_Z\n                        App.ActiveDocument.getObject(objori.Name).Visibility = False\n                        App.ActiveDocument.ActiveObject.recompute()\n                        #####\n\n                        if self.checkBox.isChecked():                           # if checkbox is checked then .... increment\n                            obj.Placement=App.Placement(App.Vector(placement_X,placement_Y,placement_Z), App.Rotation(Yaw_Z,Pitch_Y,Roll_X), App.Vector(0,0,0)).multiply(App.activeDocument().getObject(obj.Name).Placement) # increment\n                        else:\n                            obj.Placement=App.Placement(App.Vector(placement_X,placement_Y,placement_Z), App.Rotation(Yaw_Z,Pitch_Y,Roll_X), App.Vector(0,0,0))\n                        obj.Label = mess + \" \" + comptName + \" of \" + obj.Label\n\n                        try:\n                            obj.Label = mess + \"_\" + obj.Label               # renamme the original object\n                        except Exception:\n                            None\n#                    try:                                                    # optional delette the original objects \n#                        App.activeDocument().removeObject(objori.Name)\n#                        for i in liste:\n#                            App.activeDocument().removeObject(i.Name)\n#                    except:\n#                        None\n                    ##### Boucle copies Fin ###########################\n\n                FreeCAD.ActiveDocument.recompute()\n\n                 # boundinbox (dimensions hors tout)\n\n                try:\n                    boundBox_ = obj.Shape.BoundBox\n                    boundBoxLX = boundBox_.XLength\n                    boundBoxLY = boundBox_.YLength\n                    boundBoxLZ = boundBox_.ZLength\n                except:\n                    boundBox_  = 0.0\n                    boundBoxLX = 0.0\n                    boundBoxLY = 0.0\n                    boundBoxLZ = 0.0\n\n                 # volume\n                volume_ = 0.0\n                try:\n                    volume_ = obj.Shape.Volume\n                except Exception:\n                    try:\n                        for i in range(len(obj)):\n                            volume_ += obj[i].Shape.Volume\n                    except Exception:\n                        volume_ = 0.0\n\n                 # surface\n                surface = 0.0\n                try:\n                    surface = obj.Shape.Area\n                except:\n                    try:\n                        for i in range(len(obj)):\n                            surface += obj[i].Shape.Area\n                    except Exception:\n                        surface = 0.0\n\n                try:\n                    App.Console.PrintMessage(obj.Label+\"\\r\\n\")\n                except Exception:\n                    App.Console.PrintMessage(\"\\r\\n\")\n\n                App.Console.PrintMessage(\"Convert mm in ' \"+uniteMs+\" ' (1 \"+uniteMs+\" = \"+str(uniteM)+\" mm)\"+\"\\r\\n\")\n                App.Console.PrintMessage(mess + \" boundBox_X  : \"+str(boundBoxLX)+\" mm\"+\"\\r\\n\")\n                App.Console.PrintMessage(mess + \" boundBox_Y  : \"+str(boundBoxLY)+\" mm\"+\"\\r\\n\")\n                App.Console.PrintMessage(mess + \" boundBox_Z  : \"+str(boundBoxLZ)+\" mm\"+\"\\r\\n\")\n                App.Console.PrintMessage(mess + \" volume      : \"+str(volume_)+\" mm3 (\"+str(len(sel))+\" element(s))\"+\"\\r\\n\")#\n                App.Console.PrintMessage(mess + \" surface     : \"+str(surface)+\" mm2 (\"+str(len(sel))+\" element(s))\"+\"\\r\\n\")#\n\n                App.Console.PrintMessage(\"___________________\"+\"\\r\\n\")\n                self.pushButton_1.setStyleSheet(\"QPushButton {background-color: green}\")\n\n            except Exception:\n                FreeCAD.Console.PrintError(\"Error interne\"+\"\\r\\n\")\n        else:\n            self.pushButton_1.setStyleSheet(\"QPushButton {background-color: red}\")#red\n            self.pushButton_1.setToolTip(\"Not object selected for Convert or copy\")\n            FreeCAD.Console.PrintError(\"Select an object\"+\"\\r\\n\")   #App.Console.PrintMessage\n            sel = \"\"\n\n    def on_pushButton02_clicked(self):                   # Bouton Quitter\n        #### geometry\n        global setMainWindowMoveX\n        global setMainWindowMoveY\n        global setFrameWindowSizeX\n        global setFrameWindowSizeY\n        #\n        positionWindowXY = MainWindow.geometry()\n        setMainWindowMoveX  = positionWindowXY.x()\n        setMainWindowMoveY  = positionWindowXY.y()\n        positionWindowXY = MainWindow.size()\n        setFrameWindowSizeX = positionWindowXY.width()\n        setFrameWindowSizeY = positionWindowXY.height()\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"setMainWindowMoveX\",  setMainWindowMoveX)      # setMainWindowMoveX\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"setMainWindowMoveY\",  setMainWindowMoveY)      # setMainWindowMoveY\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"setFrameWindowSizeX\", setFrameWindowSizeX)     # setFrameWindowSizeX\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"setFrameWindowSizeY\", setFrameWindowSizeY)     # setFrameWindowSizeY\n        #### geometry\n\n        App.Console.PrintMessage(\"End CloneConvert\\r\\n\")\n        self.window.hide()\n\n    def on_PB_Help(self): # \n        try:\n            import webbrowser\n            webbrowser.open(\"http://www.freecadweb.org/wiki/index.php?title=Macro_CloneConvert\")\n            App.Console.PrintMessage(\"http://www.freecadweb.org/wiki/index.php?title=Macro_CloneConvert\" + \"\\n\")\n        except Exception:\n            None\n\nFreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"Version\",__version__ + \" (\" + __date__ + \")\")# \nsel = FreeCADGui.Selection.getSelection()\n\nMainWindow = QMainWindow()\nui = Ui_MainWindow(MainWindow)\n#ui.setupUi(MainWindow)\nMainWindow.show()\n",
    "url": "http://www.freecadweb.org/",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/9f2f2f6144e1307a048f1840ef99300c/raw/fb76b3c728c1c7cd085e87f5d6d223d9f79bb574/Macro_CloneConvert.FCMacro",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_CloneConvert",
    "version": "00.16",
    "license": "",
    "date": "2025/01/06",
    "src_filename": "",
    "filename_from_url": "",
    "author": "mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_CloneConvert.png",
    "icon_source": "https://wiki.freecadweb.org/images/0/0a/Macro_CloneConvert.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Connect And Sweep",
    "on_wiki": true,
    "on_git": false,
    "desc": "<span style=\"background-color:#ff0000; color:#ffffff;\">New version GUI modifyed for the HD dpi (QGridLayout) run only FC version 0.18 and more (PySide2 Qt5)</span> <br /> <br /> This macro easily creates a connection between two objects, an object and a point or between two points or on wire selected (the center of the objects are the starting and ending points of the sweep) can be selected form a configurable ellipse polygon circle.<br />A discretize function is available to create marker points configurable for cutting lines in section or cutting with a dimension on point is created to all coordinates.<br />A Duplicate face or wire feature for use with the Sweep and Loft operation<br />Sweep and Loft operation directly with the macro.<br />Centring the beam on face<br /><br /><br />Macro version: 0.13<br />Last modified: 2024-07-21<br />FreeCAD version: 0.18 and more<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/c/c9/Macro_Connect_And_Sweep.png\">ToolBar Icon</a><br /><br />Author: Mario52<br /> ",
    "comment": "This macro connect 2 objects (boundingBox center) or one object (boundingBox center) and one point or two points selected one wire selected (straight)",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2016 2017 2018 2019 2020 2024 <mario52>                 *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#Macro_Connect_And_Sweep.FCMacro\n# This macro is based to the microelly2 code see \"http://forum.freecadweb.org/viewtopic.php?t=7029#p56746\"\n#\n#05/04/2019 Py3, 26/06/2019, 23/12/2019 discretize, 2020/01/06 sweep et outils, 2020/01/09 centrage sur face, 2020/02/13 Layout rmu\n#2020/02/22 try:except Error Dialog, 05/07/2020 icon, 21/07/2024 del WebGui, \n#\n#OS: Windows 10 build 19045                                 #OS: Windows 10 (10.0)                         #OS: Windows 10 (10.0)\n#Word size of FreeCAD: 64-bit                               #Word size of OS: 64-bit                       #Word size of OS: 64-bit\n#Version: 0.22.0dev.38079 (Git)                             #Word size of FreeCAD: 64-bit                  #Word size of FreeCAD: 64-bit\n#Build type: Release                                        #Version: 0.19.16993 (Git)                     #Version: 0.19.18990 (Git)\n#Branch: main                                               #Build type: Release                           #Build type: Release\n#Hash: de508e437d13e7eb35baffceea496fb9107888cb             #Branch: master                                #Branch: master\n#Python 3.11.9, Qt 5.15.13, Coin 4.0.2, Vtk 9.2.6, OCC 7.7.2#Hash: 5ea062f6699666b2f284f6a52105acf20828b481#Hash: e499f384240196c415f207520bfbcb8df9d1b0d2\n#Locale: French/Mars (fr_MA)                                #Python version: 3.6.8                         #Python version: 3.6.8\n#                                                           #Qt version: 5.12.1                            #Qt version: 5.12.1\n#                                                           #Coin version: 4.0.0a                          #Coin version: 4.0.0a\n#                                                           #OCC version: 7.3.0                            #OCC version: 7.3.0\n#\n#\n__title__   = \"Macro_Connect_And_Sweep\"\n__author__  = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__Wiki__    = \"http://www.freecadweb.org/wiki/index.php?title=Macro_Connect_And_Sweep\"\n__version__ = \"00.13\"\n__date__    = \"2024/07/21\" #YYYY/MM/DD\n__Comment__ = \"This macro connect 2 objects (boundingBox center) or one object (boundingBox center) and one point or two points selected one wire selected (straight)\"\n__Help__    = \"Start the macro select 2 objects choice the form and validate\"\n#\n#### Section Icones ####\n## icon fromTheme by FreeCAD\n## base64 easyw-fc method\n## https://forum.freecadweb.org/viewtopic.php?f=9&t=24742&start=100#p363271\nimport base64\n\nCenterTop_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAE8AAAAxCAYAAACbHPQ3AAACvklEQVRo3u2bT3LaMBTGnzzcoTfqgk7T3sNyI7NLKF2Uku5sAc49GvJn0Rv1FOoCSGVbcq1nSZaJ3oyHUbCt7/30PUk4QPK8EhADFYnvDsuCdrb7vvcm4eWL6hVKWVDIF1V0niuHhuy+UeCd3Tdl1wXrPBmsXOa+oyjp9OAJEFAUae11jFjkFRQl1UIkjLnfqnCemsFTKSIkmMHN2bEqZiHPKYT8A0kM3cfYvZ0phNMaMDm8whO/3+lH8+Wb1EpbDmzCKOff1cDf/3l9v35PHDgVNOfw5ORUZTs0seb1Kpjy3zD9dYE7zXl7YRfaWusGxtxvTfipzHQuz19WYW5VVOBsijVz5krZt0rj6PCaonTiQ4DYB2DJs842AEAixHFixh7lfN0Sw55XtXPkLYjrQ9cXe24DLOfrzvuUPDvmeALXPGeQ8/iH9gg2RYYUKm2qHAAA2PW+s211tQ0ZmkqnDloTGN9mSnCD5jy586mA0w22DuQZHN9m9uD1GbWpRTOnJjAVwOStlCtG+7lcrZXt1Mu1b/n2WjCEwH/AML12SF+utWGuQ5ft9dPXi5nvsLkkEAMdXh9J7XbZRcGLzhviPOwcbnIdpVvviQmROM8L7bzdxx8X4yBsLjMY9J8pYX00bQUhwmlOKOd9eVxKI7bpmYj/o7/rNsrcvCwYfQD6eI6ne643VHsnPIyw7LA0gjOG80wBZ4elMQe082SA+6vN5BYJWXPTDN43yWcxKiHjLBj/h2ZhkywAe2SHW424+nnjLBhtvSpwxxxw+RNKubDjvDuFqJDK1L4+kqbcWlFVn+7any4exoXoUpNVeDqxvkH60mAdXp8EXID03Z9TeCaJYZJzcc8g4ZkmPSR8zrEz4XkTlv66qbXvP/+0ej/w+BXc0b8Z2k5+OhGfJEd4Ed7kYibibx6j80ZxHkC0Hjb+AskPXAE8rckuAAAAAElFTkSuQmCC\n\"\"\"\nCenterRigth_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAE8AAAAxCAYAAACbHPQ3AAACv0lEQVRo3u2bzXKbMBDHF4Z36BO1h3bq9j0QwuRWu+mhqZNbDEh5j8Rtc+kT5SnUA8aWkfgQSAKDdobxyMar3Z//Wn0w9pKEMnDWy3yHwMGrtf0jamx3/WyR8JIbeoKyf0SQ3FCnPFMKVVHfIuCV6tOpOqc8TnUlWH6Yt1nARl6o7D/+HKaq1x+d763LdZ1QYNw9fLsR3rXBavNXB3OdUO25BFMBpqKgJp/8+6o+JwOvDdjQxKrfl/VnGmQAwDRDu2tI+JavQHpn1AvfYhwlyOp9kso4jvJk4NqDNbQ8OfYrQrzTFpNvClzyejsauLY4mkaH0rAdulRJP4mBrP+OD00WEx9rCbAaqwqPYMrgsgxpBdjqL43GmW2nqDbTFuhQnWlwcUyN+OVz8D682ZkwZMN1ieYvebgOjd2f8nCdOsCADVirMEtHMszi0Y9KX72Hbfzn+3yK1/s3YAyAAYMsiyDLiiVLlmM7O4w5WoxzyHJcCzFwiM7meecdRhUY345x7uCJ9Q4EQCW0sq1lb2vz+H6MRwWMAeQEA46O0JjGmpd//jUfyf17B55XDFuMCWBMAADO4Oq3Z0N+VluSsCk9g0sV/HvLqW939aIbkoM/ZudTBpeTuLENAOAzVhRHlSs6bIXiauKy5V+WSwmsmDhiaRy9lyrRYQtkVfxyZLUTgOo0SrF1vxHKgND4om1sh0FWuxPMuVgJUAYOAMBDKGXDoN1LVLmZJAzVWAldQ4TS06t25UWHjRCALMipgZPFXQXX1O49Ycgu9CICJKt7Y8W+61XGwRt62XSaTFCYFrmFqXTC8MIw1boCpV/qVVcFbGyCsRSDdnhdEjAB0nZ/RuGpJNYnORM+JwlPNekhZqs0HI+k7J73hM/fLtpPXx+0+rN5iDD6YaiY/PWYe4bh4Dl4V2ej/5XAKW+pyrP7fGBe9h9FZTXwd2PQzwAAAABJRU5ErkJggg==\n\"\"\"\nCenterLeft_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAE8AAAAxCAYAAACbHPQ3AAACzElEQVRo3u2bTXbTMBDHx3m+Q08EC/oI3MOWbHdHSlgQWnaNZZl70EC7gBNxCrFI3Po71sdITqJ5zwultvSfn0eakfwaZFkpwJuSLTwCi/C2D/Hkv43d6yOvZdlN+QJs+xBDdlN6eO1IOveIcrbmVdF37lEnBa8OpD49L9lCMbFQSbMSqluFaLb7bGq/23df9SL9+Ys7eBidplmJButYfzZhhjYGmQJM1umhPuu/Y4MMXQHTdaz9fN942CBDAJXdmRiBthlxeD2pDzWY61EdFcj2fbOJvD5wJsWqwOxC3BjTtMAClz2vnYE7pmNsdqCUKkNlSH7dFZI+uYfWp6mutQKoozVIEi6Fj+UEILB7ipUk5nYrJl/2xR1JpU9rYzNDOWGIP1fo05Sx2Mo0zq83Sj74w9CR6YwOb47JwZb2xaWC6/NBNvpCIdQzp86zcxxHdqzJkccYAcYICBD7Ou/NP+dRwwpqphT6/fnySpWEFsAKagwieqkSBK87DGzRDA79F3JRmNBinvDqSwK2yKIgAABAKT8KzRYw7b1tH0jcRXwALqdAyQGawB1La82jlAOlHIJgP3Xh75XzNe8FnG6Ev/+mOm11XpmtEsLmQQRCqdL/xu5Ovkiu+0B/3dotVVwBLHgy2rahfSHEfpGceg0tshjXWP8VMCFewen4Qna30s8rH0kFb93uMEjMgJdJoy1jfHnXAGelzpuTVQBlwNWhGSiS5TJZ3BLKl/ddp3YrK/B4mQKJ8wPAfAK4Ia1q2Vw7YZDdqgOrTyQGuLH2MXB9utETxtAVP3YB8uU9ajKJo3w/dpQPJoxKR2P2PK6MaAiiKDdagZYfhqOuDRjLbGkwDm+KAxggbY+HCk/GMRXnMPqcJTxZp3XM1tJwOJKy+/U/+vmp0f7x8bvR/mweIjgvkrvOn475j94enod3chYK/z+PPvKcRJ7d7wPnZf8Biy09F4GwYRYAAAAASUVORK5CYII=\n\"\"\"\nCenterBottom_b64=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAE8AAAAxCAYAAACbHPQ3AAACyUlEQVRo3u2bS27bMBCGSUF3yI26aBHnHnqR3tpNFm3trfXsPeI0XeRGOQW7MKRSEmWJw5eccAAhkMORZj7+M6JoGG+3NUPeQBZ4BB6eh+fheXjePDzDFjLHC5XT1x9K/tu/T+7g3RqsuevZhBmuBZhs0lPX5D83DRJTauYN4xowE0nNTZCJe2JKK6Y3iZ9XEni01BrsxKAVnihoW8BcxKQN3jBI19BsxIcJUYOXfxvPLH1dFzhTsQafBdxUbKIcrL9h0NfHReCKPL16vvR/puM0Co+fMZlgCK06KEWeIkIr5yqEqi/QVa66jQfsqh8aL1tICbTqc6U6Xf05sFWusqprwfJlvrbyDZnCtgpT3JKZ8s9IiRhi3Rj+3LTJ5AQuW/Lnu1KQGSlXs4SB5mJlV6UsgWVXZGDfLDPfT/1OsoJZ3QyVVUMJ8SlTe/CgPR/iZ8vHlh+4bMv7Xx+m/KC5hEhpCcAMj4f62PGTVl72sudm7PABVHcQ51aR/rjBuZan7S0DnIu9BSYChxBCAWOXJilzpOf9qMleO5aOE/lBfJb68Zae9/0ck6L3AEmTYuQPVh4PsNrcnvr4mIdi6D5PClTVpANpbJFcbQ43AVEmzhZcVZMpeAxBj/S8m5jR4Vj+SSZzQH3EfiJolxwEYztgrAM5HKOsvPS8G0GsNscVKu44G/e4bPPeX21vGENLnneofjiOgk2ed07fMPiY+Fhn84nznpCH59o3BkRBiYK3YfXDEQzO2cZAG5wocP4znUnw124asnhiVQ3HcW58i7ZNiL3dLVJtLXi6JYPlwpSi8Zf37l6qwOqGXsp1DfBU+hzGcveM40KPohv6v+eNHxjr/Q0LxtybBpKk12juoQKIVjZDoyiX9KAjBcbRyckENr+33f3xQP4h8jahetzreSLd4yg6+d+eAc1/AaSyzmNed155TpSHkJce1P4BKzoCYWDV5uEAAAAASUVORK5CYII=\n\"\"\"\nMacro_Connect_And_Sweep_LL=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAE8AAAAxCAYAAACbHPQ3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AYLECQ6qRNY5wAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAC1ElEQVRo3u2aW3LbIBSGjzTaQ3eUmTpN9uGLLvjRuTw4sR+DYsnZR5M2nemOugr6oEtVjBAI0JUzw8iyEfzn4xxAkh2EUgLWWplrEQwAHn7ZzA6eJwoGbdPacxP28nWvdP321+Mw4KFtWgIzBU4VVlN7JmB6OlNWFqwIMFmn69qsfq8LpDA8XVHXBEzVMfp6Vn+6QHpEcqNC14/xBiKUlkecHy+ic1EPDX2am5+qbbM0FCDbaFBOWxqUKDiTwNqAxIu9tCZXBZTQfEiJRJ+PvYBjgaR18LKj000yXuyZ4IZmLICiEF0AAnoKlJ/ZafoA+vrSWzJtrIzhX+eZH9mHUdwtFDrx4qm/tK12PhZwdYPdBNIlJNt+qBZWZ7ra7rrQwVBXz9iCEf0cX9TJanctuGYf4uunbrcqczDXRl17X7RuVZyrP506F4bptCJvTuYRovf9TxAkxkWfTn6+Feru3RWrLxt5Q0rb12/Pk4HT5IuNvKEtGFOIvqoP4Y978/e2dOem7z1NtU8Pfuf3tlOx4OOel7Y6H4YCBB93/7YUN89g5gFmGRPaS6a56kuPD0NPN4cLqEO0QmfvCwYLVBtxfYITGWxP9ya9aM9/zzpPbg//iSy+19mXilX1VXUP4t6WFpPcHi4E92EsHbID63Uh1H+/uxBaPdcZjTJRpgIuh6ce+0kSQgJB3lSQifFfKXG73IEj16minmDiCgA7NgzsTritXiKPLbYO5LG2vlh0HaU0cNtKI/A3ce3vznodK4demoZ5a045iztOB4+Jfn8Rrrv5vmvn2znKrl/HhiOvsvwR6IDelQQEiNQChAHRWNqyRmqMxos8LWk7VUvPETcIXAsoqj1vyh6XEAJzLgUwQkgJTvTa2UfeeoW55zxzVits5zwAOL8hKXB2zqPAnd+QhScLjnfesGCM9390ut6HrJYYCMmOxV5fpDjLpZ3z2pqWpypztb+Llze/0WHnggAAAABJRU5ErkJggg==\n\"\"\"\nMacro_Connect_And_Sweep_LR=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAE8AAAAxCAYAAACbHPQ3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AYLECQBGBixwwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAC2ElEQVRo3u2ZXXKbMBDHhYezdaZOk57DBmzwYxznIY55NGAg96jTpmfqKeiDEcFCAgnvCuNoZzREjpD++2MXfWAFQVYQY71sYhAYeNIW7V2wvmwdgvffXy66f/X3GR1osMqEda3wLoXV1R80zGCVVcBkwYHCkwGm6rSoz/rvKn3SlFUBhAavC9ilEcLezxuvL8i26JOGV/RYqERTMbTgA+/9VO+bp4GC5GmII5f4QVZdo/LKmgoPGwIcJrA+IKPpS0MTC4oHDnWpwooMPp4HAccDyepoyw6RqQKdyELjgbs24wHsA1EBXkHaCj9NN6TrvqHKSRsvY2gbAjaWrfZkN6PYRVCd0XQ73PasPvhYwIkeNgZI4VIlvtv2nsKvdl873ZIY0BepCcP/sxktMEztk66oGzM4bB/MeR4WvFuIOkxf7KGdShJX71iFZdL2GswuWubtQuP6ZLFI0cc4HDxQv0zkYcFLfrzejKMYvpjIg4a3/P10U9GH5cOkKE57Pbawg4vaXVrqe2eMwgMH1bcwbRfvTyYvu9NWfNi3eF9/TvP3rwTnALOKB/By0kyDYQ0+ltIO43C/4wi5PqM6B12qiEDpEgcFDuthS3239Y6nwdOH3ZlI+juEQSz66/rqujHGUl7nsWLSh11D8BDG0wH5YMFOVbzjuiG0XtchmhdlusGV8NRj2Ds+lg6ErU7RdpKJKwEslNLF9pWmy/Ja/i8lxPMS8TiZTzw3ho88vlgRyFDYXi66QiUNUOa5MUkzv/pbZJbjxODnTtnPULqt9e0fenpVE4RlfVYs9UNR14nhIk84yK/H3jD1UGyCaARA7ne203IMz8Ksm+MkGhQs1TIn9zvhoqXtlz6SMiZ9JFUQU85LlvutdVpM5AksfwvOriZtJc2ZR631asKYzyMzYbREnwiciTwJcK1pi/XtYMyFAqNr6vwtUPuG8dVtPovOrtx33my2N++8nvYfI8m7sS3TiAMAAAAASUVORK5CYII=\n\"\"\"\nMacro_Connect_And_Sweep_TL=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAE8AAAAxCAYAAACbHPQ3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AYLECMS0+dm2gAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAC10lEQVRo3u2bz3KbMBDGdxneoc/Uf+lzxBiMcgx2DmmcYyAO4OdonLozfTl6IJrIGASIlRAuO6MD2Ja+/fmThCQbr6+fCphDKRwABKqyz2+Asj7bi/M/OibfM+l1Z+chAlCUfV4K2Ofs5F71PVTtDSkcGOIHOJV6tDpv4cWQZ6W4PGOw8GIrnOctYul1jzGPoBsIYERgNoe3iCHLmTI4MnhVR4nXHKYtruPBwWU5Gxfe1KIKTBWgg4hAVcqBt/v9sQoAwNJLABFh6SXK+ow4z1smVjmPA2u6TrOwUz3oecngFUaars4FLp8n3bU5wCpYMVzdjU89xDyqIGnhIQIUpZER9C+Zi7+funfVX7f0zuNP3DTZFL267cvVY+t7/NfbxmGi7rWmOtMfj9I6T+pIQ/Dfx2kZHtd0N2gD1pZYX9h17Yn36trzO05wrpxtR8H+DtI0eHfcjvfhiuCtJOFIdZzoADOSauAgVTS4Zty2JQQ2xJXNIF+utr01OabB+a/RKODqQFZ1yHqH/gkDPrZ8dt/PhQSHCCjbo6grOEQnWjnA4BCN47wmcLZGnba6HIyPeTZDq9PZBZrgPKo9/fNvLDisQc/5gTjb0pZSs5jLfIYxYAh6kG1J0Z0LiLF6W2s9g+ATho6yelufTUzGzjCqjU8xxByevz2M85x3yeHMrlPPZXbegHCReImx2/nGxFNr79vW7LwhzqOqiO/qhr8384ShGsnXnxcDpy2Xudva4Dyxu16C+8QcmoYiZyzLT7m7kq9tEQHYcdNpTWh7EYMdN+bWtiLA+Mv03CdqrppB26NKm5g2ITZB6zFh0G8osuNdgzg7f5hdB67MQf45DMO00PuN3teIsslx6vq0w6sTaANECk1G4DWJNQ2SWgMylhr9B9DT53vp6zd/7ibTnnF4fRJTSU5HnVbC65v0kKB2tJHnPNXkhsLUActaeGMkb82uyrwlNUev+AeAWxFWDD2nCwAAAABJRU5ErkJggg==\n\"\"\"\nMacro_Connect_And_Sweep_TR=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAE8AAAAxCAYAAACbHPQ3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AYLECIu5ZMrHAAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAACvElEQVRo3u2aW3KbMBSGjzJeW2d6ibuOmHsea7sPaZzH2AiM9xGn7pq6CvrgGguQZAldAIUzo7HBIP3n45cEwujh4bWEKTrFHQCCj1IOxaPW+u4m/yg4DyEAV8qhSJjbhyIBgPYxKsUp5y28LRT7M6Rin8DC25oe89wPEiQJWDXQYrEtXYYlsn9yXg8xQwg5mRgrL535Ouk8z9/ZuUCet3P+CSPPo9Y+30/px+5j8D0x+DMr4r+/sK/ep78W4Ikf63s7yPdx9d2683iw+oBXltWAd92QGPtYEGe6xs9sfhtY8PaDLZDSjVTrvEbUoAgQcMbFLI9rxyAT3fZWcmKJiZ9Pa4/cp9reBVwgOOEg309LeWgbTsJLyfEo/O88bFxD17a03arQRAdvy6rYCl6bPLDiDoy429LwmqJsA7sF0hRAGjjhJalsvmmJCY9LLcs6QEyEqiU8tgFm802ntsIgrU3KYZDKL0nh+/YVbIocUtC00XIQqitIAWdRBVKp24bH5aDB6dZ5AYeziAWPvUZPXrHwuAIz7xaqzqS9nDXT3Hf73CswVIEUfoeB758//JJTGODap/CEUbs/f18Ze++gc8Kgleh9RVmWEjgvxNxt5oSRfnuugRt7mMphWkk2Bc8F15nMZXKeQnDfYdh8v4FxYK0tXXlNzlNxXu9jUZRba2v39RcAAMS/1+add2nMhTCRy9RtdcMjbe2C+8gcdHVZYeeNGaBJ7cxn2+S0ln4eHGIhIzmttdbNdR4JcPtlfO4jNTfNYP1W5SLGhBBT0AxPGPxFweT0kyFumH/apoE756C/LRTHeSl+RZ8ooobkOLv6pODRBA4BYl+apOGxxNoGOQQNKEnyzv+Sev38xP398Y/eJGy3ZxSeTGJdkjNR5yDhySatEn0CM74k1UxOFeZQYFmBN5bkpyWpCd444x8+MBrlUkwPVAAAAABJRU5ErkJggg==\n\"\"\"\nMacro_Connect_And_Sweep_CE=\\\n\"\"\"\niVBORw0KGgoAAAANSUhEUgAAAE8AAAAxCAYAAACbHPQ3AAADA0lEQVRo3u2bQXabMBCGBx5n6I2ySRq39zAIyK523UXtJLsYJHqPxmmy6Y16CXVhY8sgZElIQiTMe7xYsYX++fhHQjgJ8ryiMIVWhK4H3D7Fwrbsex8SXn5XHaFsn2LI76rJebYc6rP7BoFXu2/MrvPWeSxYtswneJLOFLV9iSDLhr1V2V7/7BZ39Q/o309i0G8/BtMe+QTLxPlcwox8AcZN+iruhNF1Tvb3tkFGQwHrm1izP2882yAjAGoY2lqQ8IppyY5LJWGuhBpqkOcaPHIeT7RJsfKu7Aa5vV4b0xTaApe/rQYBxwPZ1CGqDiXn0Z5VW9y0hWSv5qBRQ7NK9ro601oD7KM1SFNCbYMrS80dAg0AAj15aVpZv9jG5jyTbrMZtU4eRGfw2MFlwXW5oStKnT6SLmfLuLhZa1380FS5jj10cgo/Srna0B66KNexAFR1X0R73Auo9tUZS1efi37aZZv++W7NDWWZQFkmQIEeX9uMrlxKjNzsMN5jpAhDiVEnxMhn8UFw2mFccsHp9ubwOaw4GG70F7gwRdh/eOz0Uwu+yADvSxwhojZVfN5wS7iGxhtfe2+r06/PPlW1r4m8MEGAkgM0arBs8e0G0IudRUPVNX0D3274OhJ8aXvW57EFtfx5cKhNvZ/yaotelswVux/9isrmwObmZHs2ZoAi7ZikwjYAQEjpfpJUOZLdsjXJig7Zz5k4VMZiI9ktW+9hkgKlJ3DN/toLRrJbApntrxyZ3beA8qKqkDeuq7XXubTyi0sgVXrWtnaTXIuRgegLtIsGOQDkgQMACOK4oP3EPHBcufAUnJpWUmWQxMXxp/EFI9ktWgJ4In0Dx9PdBCdqay8YvCN+bgMkswcni4ToqHWwET8vpBaTeF7sc5sX3AUjmM8Lo3eu1Zdu1zUB2wpXGozDk0nABkjX41mFp5KYTnI2zuklPNWk+4SrqeHwSMrtH4bOf387a//6+mj0fC4fPgz+MLSd/Hhi+g5jgjfBG11EdPqfx8l5gzjP7fcK7yv+AxcwYgOsAbMUAAAAAElFTkSuQmCC\n\"\"\"\n\narrowUp = [\n\"24 24 3 1\",\n\" \tc None\",\n\".\tc #4e9a06\",\n\"+\tc #FFFFFF\",\n\"         ......         \",\n\"      .....+......      \",\n\"     ......+.......     \",\n\"    ......+++.......    \",\n\"   .......+++........   \",\n\"  .......+++++........  \",\n\" ........+++++......... \",\n\" .......+++++++........ \",\n\" .......+++++++........ \",\n\"........+++++++.........\",\n\".......+++++++++........\",\n\".......+++++++++........\",\n\"......+++++++++++.......\",\n\"......+++++++++++.......\",\n\".....+++++++++++++......\",\n\" ....+++++++++++++..... \",\n\" ...+++...+++...+++.... \",\n\" ...+.....+++.....+.... \",\n\"  ........+++.........  \",\n\"   .......+++........   \",\n\"    ......+++.......    \",\n\"     .....+++......     \",\n\"      ....+++.....      \",\n\"         ......         \"]\n\n#### Section Icones ####\n\n####\ntry:\n    import webbrowser\nexcept Exception:\n    None\ntry:\n    def errorDialog(msg):\n        import PySide\n        from PySide import QtGui\n        import sys, os\n        diag = QtGui.QMessageBox(QtGui.QMessageBox.Critical,u\"Error FreeCAD Version\",msg )\n        diag.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint) # PySide #cette fonction met la fenetre en avant\n        diag.setStyleSheet(\"QLabel {color : #ffffff; background-color : #FF3300;  font: bold}\")\n        FreeCAD.Console.PrintMessage(\"https://gist.githubusercontent.com/mario52a/3ec67a3711202dab69592ce53b938924/raw/5adea7e9362849fa04d28e5a4065cd4129ea707a/Macro_Connect_And_Sweep.FCMacro\" + \"\\n\\n\")\n        diag.exec_()\n        diag.setStyleSheet(\"Base\")\n        quit(\"None\")\n    \n    if int(FreeCAD.Version()[1]) < 18:      # Version de FreeCAD\n        errorDialog(\"This version \" + __title__ + \" work with the FreeCAD 0.18 or higher. \" + \"\\n\"\n                    \"PySide2 Qt version: 5\" + \"\\n\"\n                    \"See the page (Report view) for copy the link of the precedent version. \" + \"\\n\")\n#\nexcept Exception:\n    None\n####\n\n\nimport PySide2\nfrom PySide2 import (QtWidgets, QtCore, QtGui)\nfrom PySide2.QtWidgets import (QWidget, QApplication, QSlider, QGraphicsView, QGraphicsScene, QVBoxLayout, QStyle)\nfrom PySide2.QtGui import (QPainter, QColor, QIcon)\nfrom PySide2.QtSvg import *\nimport PySide2.QtXml\n\n######import for WebPage\n#import WebGui\n#from PySide2 import  QtUiTools, QtNetwork\n#from PySide2.QtCore import QUrl\n######import for WebPage\n\nimport Draft, Part, FreeCAD, math, PartGui, FreeCADGui\nimport DraftVecUtils\nfrom math import sqrt, pi, sin, cos, asin\nfrom FreeCAD import Base\n#import time\n#time.sleep(0.1)\n\nApp = FreeCAD\n\nglobal ui    ; ui     = \"\"\n\nglobal path\n##path###########################################################################\n#path = FreeCAD.ConfigGet(\"AppHomePath\")\n#path = FreeCAD.ConfigGet(\"UserAppData\")\n#path = \"your path\"\nparam = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")# macro path\npath = param.GetString(\"MacroPath\",\"\") + \"/\"                        # macro path\npath = path.replace(\"\\\\\",\"/\")\n#App.Console.PrintMessage(str(\"Path for the icons : \") + path + \"\\n\" + __title__ + \" : \" +__version__ + \" \" + __date__ + \"\\n\")\n#################################################################################\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\n####nouveau objectRealPlacement3D#######################################################################\n####return objectRealPlacement3DX, objectPlacementAngle (avec bbox = \"BB\")\ndef objectRealPlacement3D(obj, mode = 0, bbox = \"\" ):   #obj : object, mode : 0=Base, 1=BoundBox.Center, 2=CenterOfMass\n    try:\n        try:\n            objectPlacement  = obj.Shape.Placement\n        except Exception:\n            objectPlacement  = obj.Placement\n        objectPlacementBase  = FreeCAD.Vector(objectPlacement.Base)\n        objectPlacementAngle = objectPlacement.Rotation.toEuler()\n\n        #### \n        if   mode == 0:    # 0=Base\n            objectWorkCenter     = objectPlacementBase\n        elif mode == 1:    # 1=BoundBox.Center\n            objectBoundBoxCenter = FreeCAD.Vector(obj.Shape.BoundBox.Center)\n            objectWorkCenter     = objectBoundBoxCenter\n        elif mode == 2:    # 2=CenterOfMass\n            try:\n                objectCenterOfMass   = FreeCAD.Vector(obj.Shape.CenterOfMass)\n            except Exception:\n                objectCenterOfMass   = FreeCAD.Vector(0.0, 0.0, 0.0)\n            objectWorkCenter     = objectCenterOfMass\n        ####\n\n        if hasattr(obj, \"getGlobalPlacement\"):\n            globalPlacement        = obj.getGlobalPlacement()\n            globalPlacementBase    = FreeCAD.Vector(globalPlacement.Base)\n\n            if bbox != \"BB\":\n                objectRealPlacement3DX = globalPlacementBase.add(objectWorkCenter).sub(objectPlacementBase)\n            else:\n                objectRealPlacement3DX = globalPlacementBase.sub(objectWorkCenter)#mode=0 adapte pour BBox + Centerpoints\n\n            objectPlacementAngle   = globalPlacement.Rotation.toEuler()\n        else:\n            objectRealPlacement3DX = objectWorkCenter\n            objectPlacementAngle   = obj.Placement.Rotation.toEuler()\n\n        #print(objectRealPlacement3DX,\" : \", objectPlacementAngle)\n        if bbox != \"BB\":\n            return objectRealPlacement3DX, objectPlacementAngle\n        else:\n            return objectRealPlacement3DX\n        \n    except Exception:\n        return FreeCAD.Vector(0.0, 0.0, 0.0), (0.0, 0.0, 0.0)\n####nouveau objectRealPlacement3D#######################################################################\n\nclass Ui_MainWindow(object):\n    global path\n\n    def __init__(self):\n        global path\n        self.path                  = path\n        self.Polyline_Number_Faces = 3\n        self.Polyline_CirCon       = 5.0\n        self.Rectangle_X           = 5.0\n        self.Rectangle_Y           = 3.0\n        self.Circle_Radius         = 1.0\n        self.Circle_Radius_Sbs     = 0.5\n        self.Circle_Diameter       = self.Circle_Radius * 2.0\n        self.Thickness             = 0.0\n        self.FcSweep               = \"\"\n        self.FcSweepS              = \"\"\n        self.Forme                 = \"\"\n        self.FormeSubtract         = \"\"\n        self.cutFcSweep            = \"\"\n        self.ligne                 = \"\"\n        self.sweepForme            = \"\"\n        self.discretize            = 1.0\n#01        self.nameL                 = []   # contener en attente\n        self.CASweep               = \"\"   # conteneur dossier\n        self.ElementName           = \"\"\n        self.sweepFace             = \"\"\n        self.sweepFaceName         = \"\"\n        self.selectForDuplicate    = []\n        size_ecran = QtWidgets.QDesktopWidget().screenGeometry()  # donne les dimensions de l'ecran\n        self.orgWidth =  size_ecran.width()\n        self.orgHeight = size_ecran.height()\n\n    def setupUi(self, MainWindow):\n        self.window = MainWindow\n\n        MainWindow.resize(360, 570)\n        #MainWindow.setGeometry(50, 50, 360, 570)\n#        MainWindow.move(900,115)\n\n        self.centralwidget = QtWidgets.QWidget(MainWindow)\n######################################################################\n\n        #### #Titre\n        self.widget = QtWidgets.QWidget(self.centralwidget)\n\n        grid = QtWidgets.QGridLayout(self.centralwidget)\n        grid.addWidget(self.widget)\n        \n        ####\n        self.label = QtWidgets.QLabel()\n        font = QtGui.QFont()\n        font.setPointSize(12)\n        self.label.setFont(font)\n\n        self.PB_Help = QtWidgets.QPushButton()\n        self.PB_Help.setToolTip(_fromUtf8(\"Help on line  \" + __version__ + \"  \" + __date__ + \" rmu\"))\n        self.PB_Help.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_MessageBoxQuestion)))\n        self.PB_Help.clicked.connect(self.on_PB_Help) ###\n\n        grid.addWidget(self.widget, 0, 0, 1, 2) #linge, colonne, ligne case, nombre de cases)\n        grid01 = QtWidgets.QGridLayout(self.widget)\n        grid01.addWidget(self.label, 0, 0)\n        grid01.addWidget(self.PB_Help, 0, 1)\n        #### #Titre\n\n        #### #Mode\n        self.GBox_00 = QtWidgets.QGroupBox()\n\n        self.RB_01_BBox_Oject = QtWidgets.QRadioButton()\n        #self.RB_01_BBox_Oject.setChecked(True)\n        self.RB_01_BBox_Oject.clicked.connect(self.on_RB_00_Mode_clicked)\n        \n        self.RB_03_Subo_Subo = QtWidgets.QRadioButton()\n        self.RB_03_Subo_Subo.setChecked(True)#\n        self.RB_03_Subo_Subo.clicked.connect(self.on_RB_00_Mode_clicked)\n\n        self.RB_02_BBox_Subo = QtWidgets.QRadioButton()\n        #self.RB_02_BBox_Subo.setChecked(True)\n        self.RB_02_BBox_Subo.clicked.connect(self.on_RB_00_Mode_clicked)\n\n        self.label_Info = QtWidgets.QLabel()\n        # ####\n\n        grid.addWidget(self.GBox_00, 1, 0, 1, 2) #linge, colonne, ligne case, nombre de cases)\n        grid02 = QtWidgets.QGridLayout(self.GBox_00)\n\n        grid02.addWidget(self.RB_01_BBox_Oject, 0, 0)\n        grid02.addWidget(self.RB_02_BBox_Subo, 1, 0)\n        grid02.addWidget(self.RB_03_Subo_Subo, 0, 1)\n        #### #Mode\n\n        #### #Forme\n        self.GBox_02_ = QtWidgets.QGroupBox()\n\n        self.DS_Polyline_CirCon = QtWidgets.QDoubleSpinBox()\n        self.DS_Polyline_CirCon.setDecimals(3)\n        self.DS_Polyline_CirCon.setMinimum(0.00001)\n        self.DS_Polyline_CirCon.setMaximum(999999.999999)\n        self.DS_Polyline_CirCon.setValue(self.Polyline_CirCon)\n        self.DS_Polyline_CirCon.valueChanged.connect(self.on_DS_Polyline_CirCon) ###\n\n        self.SB_Polyline_Number_Faces = QtWidgets.QSpinBox()\n        self.SB_Polyline_Number_Faces.setPrefix(_fromUtf8(\"\"))\n        self.SB_Polyline_Number_Faces.setMinimum(3)\n        self.SB_Polyline_Number_Faces.setMaximum(999999)\n        self.SB_Polyline_Number_Faces.setValue(self.Polyline_Number_Faces )\n        self.SB_Polyline_Number_Faces.valueChanged.connect(self.on_SB_Polyline_Number_Faces) ###\n\n        self.RB_Polyline = QtWidgets.QRadioButton()\n        self.RB_Polyline.setChecked(True)\n        self.RB_Polyline.setIcon(QtGui.QIcon.fromTheme(\"refresh\",QtGui.QIcon(\":/icons/Draft_Polygon.svg\")))\n        self.RB_Polyline.clicked.connect(self.on_RB_Polyline_clicked)\n\n        self.CB_Insc_Circon = QtWidgets.QCheckBox()\n        self.CB_Insc_Circon.setEnabled(True)\n        self.CB_Insc_Circon.setText(_fromUtf8(\"Polygon Circumscribed\"))\n        self.CB_Insc_Circon.clicked.connect(self.on_CB_Insc_Circon_clicked)\n\n        self.DS_Rectangle_X = QtWidgets.QDoubleSpinBox()\n        self.DS_Rectangle_X.setDecimals(3)\n        self.DS_Rectangle_X.setDecimals(3)\n        self.DS_Rectangle_X.setMinimum(0.00001)\n        self.DS_Rectangle_X.setMaximum(999999.999999)\n        self.DS_Rectangle_X.setValue(self.Rectangle_X)\n        self.DS_Rectangle_X.valueChanged.connect(self.on_DS_Rectangle_X) ###\n\n        self.DS_Rectangle_Y = QtWidgets.QDoubleSpinBox()\n        self.DS_Rectangle_Y.setDecimals(3)\n        self.DS_Rectangle_Y.setDecimals(3)\n        self.DS_Rectangle_Y.setMinimum(0.00001)\n        self.DS_Rectangle_Y.setMaximum(999999.999999)\n        self.DS_Rectangle_Y.setValue(self.Rectangle_Y)\n        self.DS_Rectangle_Y.valueChanged.connect(self.on_DS_Rectangle_Y) ###\n\n        self.RB_Rectangle = QtWidgets.QRadioButton()\n        self.RB_Rectangle.setIcon(QtGui.QIcon.fromTheme(\"refresh\",QtGui.QIcon(\":/icons/Draft_Rectangle.svg\")))\n        self.RB_Rectangle.clicked.connect(self.on_RB_Rectangle_clicked)\n\n        self.RB_Ellipse = QtWidgets.QRadioButton()\n        self.RB_Ellipse.setIcon(QtGui.QIcon.fromTheme(\"refresh\",QtGui.QIcon(\":/icons/Draft_Ellipse.svg\")))\n        self.RB_Ellipse.clicked.connect(self.on_RB_Ellipse_clicked)\n\n        self.DS_Circle_Radius = QtWidgets.QDoubleSpinBox()\n        self.DS_Circle_Radius.setDecimals(3)\n        self.DS_Circle_Radius.setMinimum(0.00001)\n        self.DS_Circle_Radius.setMaximum(999999.999999)\n        self.DS_Circle_Radius.setValue(self.Circle_Radius)\n        self.DS_Circle_Radius.valueChanged.connect(self.on_DS_Circle_Radius) ###\n\n        self.DS_Circle_Diameter = QtWidgets.QDoubleSpinBox()\n        self.DS_Circle_Diameter.setDecimals(3)\n        self.DS_Circle_Diameter.setMinimum(0.00001)\n        self.DS_Circle_Diameter.setMaximum(999999.999999)\n        self.DS_Circle_Diameter.setValue(self.Circle_Diameter)\n        self.DS_Circle_Diameter.valueChanged.connect(self.on_DS_Circle_Diameter) ###\n\n        self.RB_Circle = QtWidgets.QRadioButton()\n        self.RB_Circle.setIcon(QtGui.QIcon.fromTheme(\"refresh\",QtGui.QIcon(\":/icons/Draft_Circle.svg\")))\n        self.RB_Circle.clicked.connect(self.on_RB_Circle_clicked)\n\n        self.RB_Line = QtWidgets.QRadioButton()\n        self.RB_Line.setIcon(QtGui.QIcon.fromTheme(\"refresh\",QtGui.QIcon(\":/icons/Draft_Line.svg\")))\n        self.RB_Line.clicked.connect(self.on_RB_Line_clicked)\n\n        self.CB_Solid = QtWidgets.QCheckBox()\n        self.CB_Solid.setChecked(True)\n        self.CB_Solid.clicked.connect(self.on_CB_Solid_clicked)\n\n        self.label_Pipe = QtWidgets.QLabel()\n\n        self.DS_Pipe = QtWidgets.QDoubleSpinBox()\n        self.DS_Pipe.setDecimals(3)\n        self.DS_Pipe.setMinimum(0.00001)\n        self.DS_Pipe.setMaximum(999999.999999)\n        self.DS_Pipe.setValue(self.Thickness)\n        self.DS_Pipe.valueChanged.connect(self.on_DS_Pipe) ###\n\n        grid.addWidget(self.GBox_02_, 2, 0, 1, 2) #linge, colonne, ligne case, nombre de cases)\n        self.grid03 = QtWidgets.QGridLayout(self.GBox_02_)\n        self.grid03.addWidget(self.CB_Insc_Circon, 0, 1)\n        self.grid03.addWidget(self.RB_Polyline, 1, 0)\n        self.grid03.addWidget(self.DS_Polyline_CirCon,1, 1)\n        self.grid03.addWidget(self.SB_Polyline_Number_Faces, 1, 2)\n        self.grid03.addWidget(self.RB_Rectangle, 2, 0)\n        self.grid03.addWidget(self.DS_Rectangle_X, 2, 1)\n        self.grid03.addWidget(self.DS_Rectangle_Y, 2, 2)\n        self.grid03.addWidget(self.RB_Ellipse, 3, 0)\n        self.grid03.addWidget(self.RB_Circle, 4, 0)\n        self.grid03.addWidget(self.DS_Circle_Radius, 4, 1)\n        self.grid03.addWidget(self.DS_Circle_Diameter, 4, 2)\n        self.grid03.addWidget(self.RB_Line, 5, 0)\n        self.grid03.addWidget(self.CB_Solid, 6, 0)\n        self.grid03.addWidget(self.label_Pipe, 7, 0)\n        self.grid03.addWidget(self.DS_Pipe, 7, 1)\n        #### #Forme\n\n        #### #Graphique\n        self.GBox_07_ = QtWidgets.QGroupBox()\n        self.GBox_07_.setVisible(False)\n#        self.GBox_07_.setVisible(True)\n\n        self.RB_Top_Left = QtWidgets.QRadioButton()\n        self.RB_Top_Left.setLayoutDirection(QtCore.Qt.RightToLeft)\n        iconRotate = QtGui.QPixmap(arrowUp).transformed(QtGui.QTransform().rotate(-45), QtCore.Qt.SmoothTransformation)#Rotation\n        self.RB_Top_Left.setIconSize(QtCore.QSize(24, 24))\n        self.RB_Top_Left.setIcon(iconRotate)\n        self.RB_Top_Left.clicked.connect(self.on_RB_Image_clicked)\n\n        self.RB_Center_Top = QtWidgets.QRadioButton()\n        iconRotate = QtGui.QPixmap(arrowUp).transformed(QtGui.QTransform().rotate(0), QtCore.Qt.SmoothTransformation)#Rotation\n        self.RB_Center_Top.setIcon(iconRotate)\n        self.RB_Center_Top.clicked.connect(self.on_RB_Image_clicked)\n\n        self.RB_Top_Rigth = QtWidgets.QRadioButton()\n        iconRotate = QtGui.QPixmap(arrowUp).transformed(QtGui.QTransform().rotate(45), QtCore.Qt.SmoothTransformation)#Rotation\n        self.RB_Top_Rigth.setIconSize(QtCore.QSize(24, 24))\n        self.RB_Top_Rigth.setIcon(iconRotate)\n        self.RB_Top_Rigth.clicked.connect(self.on_RB_Image_clicked)\n\n        self.RB_Center_Left = QtWidgets.QRadioButton()\n        self.RB_Center_Left.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_ArrowLeft))) #\n        iconRotate = QtGui.QPixmap(arrowUp).transformed(QtGui.QTransform().rotate(-90), QtCore.Qt.SmoothTransformation)#Rotation\n        self.RB_Center_Left.setIcon(iconRotate)\n        self.RB_Center_Left.setLayoutDirection(QtCore.Qt.RightToLeft)\n        self.RB_Center_Left.clicked.connect(self.on_RB_Image_clicked)\n\n        self.RB_Center_Right = QtWidgets.QRadioButton()\n        self.RB_Center_Right.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_ArrowRight))) #\n        iconRotate = QtGui.QPixmap(arrowUp).transformed(QtGui.QTransform().rotate(90), QtCore.Qt.SmoothTransformation)#Rotation\n        self.RB_Center_Right.setIcon(iconRotate)\n        self.RB_Center_Right.clicked.connect(self.on_RB_Image_clicked)\n\n        self.RB_Low_Left = QtWidgets.QRadioButton()\n        self.RB_Low_Left.setLayoutDirection(QtCore.Qt.RightToLeft)\n        iconRotate = QtGui.QPixmap(arrowUp).transformed(QtGui.QTransform().rotate(225), QtCore.Qt.SmoothTransformation)#Rotation\n        self.RB_Low_Left.setIconSize(QtCore.QSize(24, 24))\n        self.RB_Low_Left.setIcon(iconRotate)\n        self.RB_Low_Left.clicked.connect(self.on_RB_Image_clicked)\n\n        self.RB_Center_Bottom = QtWidgets.QRadioButton()\n        self.RB_Center_Bottom.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_ArrowDown))) #\n        iconRotate = QtGui.QPixmap(arrowUp).transformed(QtGui.QTransform().rotate(180), QtCore.Qt.SmoothTransformation)#Rotation\n        self.RB_Center_Bottom.setIcon(iconRotate)\n        self.RB_Center_Bottom.clicked.connect(self.on_RB_Image_clicked)\n        \n        self.RB_Low_Rigth = QtWidgets.QRadioButton()\n        iconRotate = QtGui.QPixmap(arrowUp).transformed(QtGui.QTransform().rotate(135), QtCore.Qt.SmoothTransformation)#Rotation\n        self.RB_Low_Rigth.setIconSize(QtCore.QSize(24, 24))\n        self.RB_Low_Rigth.setIcon(iconRotate)\n        self.RB_Low_Rigth.clicked.connect(self.on_RB_Image_clicked)\n\n        self.RB_Center = QtWidgets.QRadioButton()\n        self.RB_Center.setStyleSheet(\"\")\n        self.RB_Center.setChecked(True)\n        self.RB_Center.setChecked(True)\n        self.RB_Center.clicked.connect(self.on_RB_Image_clicked)\n\n        ####Screen Graphic BitMap\n        ##https://doc.qt.io/qtforpython/PySide2/QtCore/Qt.html\n        self.graphicsView = QtWidgets.QGraphicsView()\n        pic = QtGui.QPixmap()\n        pic.loadFromData(base64.b64decode(Macro_Connect_And_Sweep_CE))\n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))                        # png (bmp)\n        self.graphicsView.setScene(self.scene)\n        ####Screen Graphic BitMap\n\n###########################\n#        ####Screen Graphic SVG\n#        self.graphicsView = QtWidgets.QGraphicsView()\n#        pic = PySide2.QtSvg.QGraphicsSvgItem(path + \"FreeCAD.svg\")    # svg\n#        self.scene = QtWidgets.QGraphicsScene()\n#        self.scene.addItem(pic)\n#        self.graphicsView.setScene(self.scene)\n#        ####Screen Graphic SVG\n########################### PySide2.QtCore.\n\n        grid.addWidget(self.GBox_07_, 2, 2, 1, 3) #linge, colonne, ligne case, nombre de cases)\n        grid04 = QtWidgets.QGridLayout(self.GBox_07_)\n        grid04.addWidget(self.RB_Top_Left, 1, 0)\n        grid04.addWidget(self.RB_Center_Top, 1, 1)\n        grid04.addWidget(self.RB_Top_Rigth, 1, 2)\n        grid04.addWidget(self.RB_Center, 2, 1)\n        grid04.addWidget(self.RB_Center_Left, 3, 0)\n        grid04.addWidget(self.graphicsView, 3, 1)\n        grid04.addWidget(self.RB_Center_Right, 3, 2)\n        grid04.addWidget(self.RB_Low_Left, 4, 0)\n        grid04.addWidget(self.RB_Center_Bottom, 4, 1)\n        grid04.addWidget(self.RB_Low_Rigth, 4, 2)\n        #### #Graphique\n\n# # tabWidget ####\n        ##\n        self.GBox_06_ = QtWidgets.QGroupBox()\n\n        self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)\n        self.tabWidget.setTabPosition(QtWidgets.QTabWidget.North)\n        self.tabWidget.setTabShape(QtWidgets.QTabWidget.Rounded)\n\n        self.TAB_Discretize = QtWidgets.QWidget()\n\n####################\n        self.DS_Discretize = QtWidgets.QDoubleSpinBox()\n        ####                                            # Doit demarrer en \"Spinbox\" !!\n#        self.DS_Discretize.setMinimum(0.000001)        # DoubleSpinBox\n#        self.DS_Discretize.setMaximum(999999.99999)    # DoubleSpinBox\n#        self.DS_Discretize.setDecimals(3)              # DoubleSpinBox\n        ####\n        self.DS_Discretize.setSuffix(\" Sec\")            # nombre de Sections\n        self.DS_Discretize.setMinimum(1)                # SpinBox\n        self.DS_Discretize.setMaximum(999999)           # SpinBox\n        self.DS_Discretize.setDecimals(0)               # SpinBox\n        self.discretize = int(self.discretize)          # SpinBox\n        ####\n        self.DS_Discretize.setValue(self.discretize)\n        self.DS_Discretize.valueChanged.connect(self.on_DS_Discretize) ###\n####################\n\n        self.CB_Discretize = QtWidgets.QCheckBox()\n        self.CB_Discretize.clicked.connect(self.on_CB_Discretize_clicked)\n\n        self.CB_Reverse = QtWidgets.QCheckBox()\n        self.CB_Reverse.setEnabled(False)\n        self.CB_Reverse.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_BrowserReload))) #\n        self.CB_Reverse.clicked.connect(self.on_CB_Reverse)\n\n        self.PB_Del_Points = QtWidgets.QPushButton()\n        self.PB_Del_Points.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogCancelButton))) #\n        self.PB_Del_Points.clicked.connect(self.on_PB_Del_Points) ###\n\n        self.PB_Discretize = QtWidgets.QPushButton()\n        self.PB_Discretize.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton))) #\n        self.PB_Discretize.clicked.connect(self.on_PB_Discretize) ###\n\n        self.tabWidget.addTab(self.TAB_Discretize, \"\")\n        ##\n# # Tab_Face ####\n        ##\n        self.Tab_Face = QtWidgets.QWidget()\n\n        self.PB_Reset_Face = QtWidgets.QPushButton()\n        self.PB_Reset_Face.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogResetButton))) #\n        self.PB_Reset_Face.clicked.connect(self.on_PB_Reset_Sweep) ###\n\n        self.PB_Visibility = QtWidgets.QPushButton()\n        self.PB_Visibility.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_FileDialogListView))) #\n        self.PB_Visibility.clicked.connect(self.on_PB_Visibility) ###\n\n        self.PB_Create_Face = QtWidgets.QPushButton()\n        self.PB_Create_Face.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton))) #\n        self.PB_Create_Face.clicked.connect(self.on_PB_Create_Face) ###\n        self.tabWidget.addTab(self.Tab_Face, \"\")\n\n        \n        self.tabWidget.addTab(self.Tab_Face, \"\")\n        ##\n# # Tab_Sweep ####\n        ##\n        self.Tab_Sweep = QtWidgets.QWidget()\n        \n        self.PB_Reset_Sweep = QtWidgets.QPushButton()\n        self.PB_Reset_Sweep.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogResetButton))) #\n        self.PB_Reset_Sweep.clicked.connect(self.on_PB_Reset_Sweep) ###\n\n        self.PB_Del_Sweep = QtWidgets.QPushButton()\n        self.PB_Del_Sweep.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogCancelButton))) #\n        self.PB_Del_Sweep.clicked.connect(self.on_PB_Del_Sweep) ###\n\n        self.PB_Sweep = QtWidgets.QPushButton()\n        self.PB_Sweep.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton))) #\n        self.PB_Sweep.clicked.connect(self.on_PB_Sweep) ###\n\n        self.CB_Solid_Sweep = QtWidgets.QCheckBox(self.Tab_Sweep)\n        #self.CB_Solid_Sweep.clicked.connect(self.on_CB_Solid_Sweep)\n\n        self.CB_Frenet_Sweep = QtWidgets.QCheckBox()\n        #self.CB_Frenet_Sweep.clicked.connect(self.on_CB_Frenet_Sweep)\n        \n        self.tabWidget.addTab(self.Tab_Sweep, \"\")\n        ##\n# # Tab_Loft ####\n        ##\n        self.Tab_Loft = QtWidgets.QWidget()\n        \n        self.PB_Reset_Loft = QtWidgets.QPushButton()\n        self.PB_Reset_Loft.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogResetButton))) #\n        self.PB_Reset_Loft.clicked.connect(self.on_PB_Reset_Sweep) ###\n\n        self.PB_Del_Loft = QtWidgets.QPushButton()\n        self.PB_Del_Loft.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogCancelButton))) #\n        self.PB_Del_Loft.clicked.connect(self.on_PB_Del_Sweep) ###\n\n        self.PB_Loft = QtWidgets.QPushButton()\n        self.PB_Loft.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton))) #\n        self.PB_Loft.clicked.connect(self.on_PB_Loft) ###\n\n        self.CB_Solid_Loft = QtWidgets.QCheckBox()\n        #self.CB_Solid_Loft.clicked.connect(self.on_CB_Solid_Loft)\n\n        self.CB_Ruled_Loft = QtWidgets.QCheckBox()\n        #self.CB_Ruled_Loft.clicked.connect(self.on_CB_Ruled_Loft)\n\n        \n        self.CB_Closed_Loft = QtWidgets.QCheckBox()\n        #self.CB_Closed_Loft.clicked.connect(self.on_CB_Closed_Loft)\n        \n        self.tabWidget.addTab(self.Tab_Loft, \"\")\n\n        grid.addWidget(self.GBox_06_, 4, 0, 1, 2)     #linge, colonne, ligne case, nombre de cases)\n        gridBox = QtWidgets.QGridLayout(self.GBox_06_)\n\n        gridBox.addWidget(self.tabWidget, 4, 0, 1, 2) #linge, colonne, ligne case, nombre de cases)\n        grid05 = QtWidgets.QGridLayout(self.TAB_Discretize)\n        grid05.addWidget(self.DS_Discretize, 0, 0)\n        grid05.addWidget(self.CB_Discretize, 0, 1)\n        grid05.addWidget(self.CB_Reverse, 0, 2)\n        grid05.addWidget(self.PB_Del_Points, 1, 0)\n        grid05.addWidget(self.PB_Discretize, 1, 1)\n\n        gridBox.addWidget(self.tabWidget, 4, 0, 1, 2) #linge, colonne, ligne case, nombre de cases)\n        grid06 = QtWidgets.QGridLayout(self.Tab_Face)\n        grid06.addWidget(self.PB_Reset_Face, 0, 0)\n        grid06.addWidget(self.PB_Visibility, 0, 1)\n        grid06.addWidget(self.PB_Create_Face, 0, 2)\n\n        gridBox.addWidget(self.tabWidget, 4, 0, 1, 2) #linge, colonne, ligne case, nombre de cases)\n        grid07 = QtWidgets.QGridLayout(self.Tab_Sweep)\n        grid07.addWidget(self.PB_Reset_Sweep, 0, 0)\n        grid07.addWidget(self.PB_Del_Sweep, 0, 1)\n        grid07.addWidget(self.PB_Sweep, 0, 2)\n        grid07.addWidget(self.CB_Solid_Sweep, 1, 0)\n        grid07.addWidget(self.CB_Frenet_Sweep, 1, 1)\n\n        gridBox.addWidget(self.tabWidget, 4, 0, 1, 2) #linge, colonne, ligne case, nombre de cases)\n        grid08 = QtWidgets.QGridLayout(self.Tab_Loft)\n        grid08.addWidget(self.PB_Reset_Loft, 0, 0)\n        grid08.addWidget(self.PB_Del_Loft, 0, 1)\n        grid08.addWidget(self.PB_Loft, 0, 2)\n        grid08.addWidget(self.CB_Solid_Loft, 1, 0)\n        grid08.addWidget(self.CB_Ruled_Loft, 1, 1)\n        grid08.addWidget(self.CB_Closed_Loft, 1, 2)\n        #### #Tab\n        ####\n# # Sortie ####\n        ####\n        #### #Sortie\n        self.GBox_05_ = QtWidgets.QGroupBox()\n\n        self.PB_Del_Last_Line = QtWidgets.QPushButton()\n        self.PB_Del_Last_Line.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogCancelButton))) #\n        self.PB_Del_Last_Line.clicked.connect(self.on_PB_Del_Last_Line) ###\n\n        self.PB_Quit = QtWidgets.QPushButton()\n        ##https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html\n        ##https://doc.qt.io/qt-5/qstyle.html#StandardPixmap-enum\n        self.PB_Quit.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogCloseButton))) #PySide2 Qt5\n        self.PB_Quit.clicked.connect(self.on_PB_Quit) ###\n\n        self.PB_Create = QtWidgets.QPushButton()\n        self.PB_Create.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton))) #\n        self.PB_Create.clicked.connect(self.on_PB_Create) ###\n\n        grid.addWidget(self.GBox_05_, 5, 0, 1, 2) #linge, colonne, ligne case, nombre de cases)\n        grid09 = QtWidgets.QGridLayout(self.GBox_05_)\n        grid09.addWidget(self.PB_Quit, 0, 0)\n        grid09.addWidget(self.PB_Del_Last_Line, 0, 1)\n        grid09.addWidget(self.PB_Create, 0, 2)\n        #### #Sortie\n\n        #### #Info\n        self.frame = QtWidgets.QFrame()\n        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)\n        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)\n\n        grid.addWidget(self.frame, 6, 0, 1, 3)            #ligne, colonne) frame in centralwidget\n        frame01 = QtWidgets.QGridLayout(self.frame)\n        frame01.addWidget(self.label_Info, 0, 0)\n        #### #Info\n\n        MainWindow.setCentralWidget(self.centralwidget)\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n        _translate = QtCore.QCoreApplication.translate\n        MainWindow.setWindowTitle(_fromUtf8(\"Connect and Sweep (\" + __version__ + \") rmu\")) #\" \" + __date__ + \n        MainWindow.setWindowIcon(QtGui.QIcon(_fromUtf8(self.path+'Macro_Connect_And_Sweep.png')))  # change l'icone de la fenetre principale\n        MainWindow.setWindowFlags(PySide2.QtCore.Qt.WindowStaysOnTopHint)         # PySide2 cette fonction met la fenetre en avant\n\n        self.label.setText(_translate(\"MainWindow\", \"Connect And Sweep\"))\n#        self.PB_Help.setText(_fromUtf8(\"Help\"))\n\n        self.GBox_00.setTitle(_translate(\"MainWindow\", \"Mode\"))\n        self.RB_01_BBox_Oject.setText(_translate(\"MainWindow\", \"1 : Object + Object\"))\n        self.RB_01_BBox_Oject.setToolTip(_fromUtf8(\"Create the connection to BoundBox center\"+\"\\n\"\n                                                   \"Center first object selected to center second Object selected\"+\"\\n\\n\"\n                                                   \"If one error of selection is detected the mode change to the mode 3\"+\"\\n\"\n                                                   \"and the radio button mode 3 is colored in orange to warn you\"+\"\\n\"))\n        self.RB_02_BBox_Subo.setText(_translate(\"MainWindow\", \"2 : Object + S_Object\"))\n        self.RB_02_BBox_Subo.setToolTip(_fromUtf8(\"Create the connection to BoundBox center\"+\"\\n\"\n                                           \"the first selection = Object (BoundBox center)\"+\"\\n\"\n                                           \"the second selection  = SubObject (BoundBox center of the SubObject)\"+\"\\n\\n\"\n                                           \"Example: if one line is selected center BoundingBox of the line is the center of line\"+\"\\n\"\n                                           \"if one circle is selected center BoundingBox of the circle is the center of circle\"+\"\\n\\n\"\n                                           \"If one error of selection is detected the mode change to the mode 3\"+\"\\n\"\n                                           \"and the radio button mode 3 is colored in orange to warn you\"+\"\\n\"))\n        self.RB_03_Subo_Subo.setText(_translate(\"MainWindow\", \"3 : S_Object + S_Object\"))\n        self.RB_03_Subo_Subo.setToolTip(_fromUtf8(\"Create the connection to BoundBox center\"+\"\\n\"\n                                           \"the first selection  = SubObject (BoundBox center of the first SubObject)\"+\"\\n\"\n                                           \"the second selection = SubObject (BoundBox center of the second SubObject)\"+\"\\n\"\n                                           \"the SubObject can be: \"+\"\\n\"\n                                           \"Line, wire, edge, face \"+\"\\n\\n\"\n                                           \"PS: If only one line is selected the object created follow the DIRECTION of the line or curve\"+\"\\n\"\n                                           \"If one circle is selected, one line of length 0 is created\"+\"\\n\"\n                                           \"(the points are in point 0 and point 360 and are in the same place.)\"))\n        self.label_Info.setText(_translate(\"MainWindow\", __version__ + \"  \" + __date__ + \" rmu\"))\n        self.label_Info.setToolTip(_fromUtf8(\"Information of the wire selected :\" + \"\\n\"\n                                             \"Number of points created : Length of the wire\"))\n\n        self.GBox_02_.setTitle(_translate(\"MainWindow\", \"Sweep Forme\"))\n        self.SB_Polyline_Number_Faces.setSuffix(_translate(\"MainWindow\", \" num\"))\n        self.SB_Polyline_Number_Faces.setToolTip(_fromUtf8(\"Enter number faces\"))\n        self.DS_Polyline_CirCon.setSuffix(_translate(\"MainWindow\", \" Cir mm\"))\n        self.DS_Polyline_CirCon.setToolTip(_fromUtf8(\"Radius polygon\"))\n        self.RB_Polyline.setText(_translate(\"MainWindow\", \"Polygone\"))\n        self.CB_Insc_Circon.setText(_translate(\"MainWindow\", \"Polygon Circumscribed\"))\n        self.CB_Insc_Circon.setToolTip(_fromUtf8(\"Circumscribed by default, if checked then Inscribed\"))\n        self.DS_Rectangle_Y.setSuffix(_translate(\"MainWindow\", \" H mm\"))\n        self.DS_Rectangle_Y.setToolTip(_fromUtf8(\"Rectangle Height\"))\n        self.DS_Rectangle_X.setSuffix(_translate(\"MainWindow\", \" L mm\"))\n        self.DS_Rectangle_X.setToolTip(_fromUtf8(\"Rectangle Length\"))\n        self.RB_Rectangle.setText(_translate(\"MainWindow\", \"Rectangle\"))\n        self.RB_Ellipse.setText(_translate(\"MainWindow\", \"Ellipse\"))\n        self.DS_Circle_Diameter.setSuffix(_translate(\"MainWindow\", \" d mm\"))\n        self.DS_Circle_Diameter.setToolTip(_fromUtf8(\"Diameter of circle\"))\n        self.DS_Circle_Radius.setSuffix(_translate(\"MainWindow\", \" r mm\"))\n        self.DS_Circle_Radius.setToolTip(_fromUtf8(\"Radius of circle\"))\n        self.RB_Circle.setText(_translate(\"MainWindow\", \"Circle\"))\n        self.RB_Line.setText(_translate(\"MainWindow\", \"Line\"))\n        self.CB_Solid.setText(_translate(\"MainWindow\", \"Solid\"))\n        self.CB_Solid.setToolTip(_fromUtf8(\"Create solid checked by default\"+\"\\n\"\n                                           \"If is not checked then is pipe empty (Shell)\"+\"\\n\"\n                                           \"If thickness is not 0 the Solid checkBox is checked automatically\"))\n        self.label_Pipe.setText(_translate(\"MainWindow\", \"Pipe\"))\n        self.DS_Pipe.setToolTip(_translate(\"MainWindow\", \"thickness of pipe\"))\n        self.DS_Pipe.setSuffix(_translate(\"MainWindow\", \" Thickness\"))\n        self.DS_Pipe.setToolTip(_fromUtf8(\"Thickness of pipe\"+\"\\n\"\n                                          \"If thickness = 0 the object is solid and not pipe\"+\"\\n\"\n                                          \"If thickness is larger than a dimension of the object,\"+\"\\n\"\n                                          \"thickness is ignored\"+\"\\n\"\n                                          \"If this function is used with a Line the LineWidth is affected.\"))\n\n        self.GBox_07_.setTitle(_translate(\"MainWindow\", \"Corner point position (on X Y Axis)\"))\n        self.RB_Top_Left.setText(_translate(\"MainWindow\", \"Top Left\"))\n        self.RB_Top_Left.setToolTip(_fromUtf8(\"The selected point is in the upper left corner\"+\"\\n\"\n                                              \"The selection order can reverse the form\"+\"\\n\"\n                                              \"Select the objects from the smallest to the largest coordinated\"))\n        self.RB_Center_Top.setText(_translate(\"MainWindow\", \"Center Top\"))\n        self.RB_Center_Top.setToolTip(_fromUtf8(\"The selected point is the center face Top of the beam\"))\n        self.RB_Top_Rigth.setText(_translate(\"MainWindow\", \"Top Rigth\"))\n        self.RB_Top_Rigth.setToolTip(_fromUtf8(\"The selected point is in the upper rigth corner\"+\"\\n\"\n                                               \"The selection order can reverse the form\"+\"\\n\"\n                                               \"Select the objects from the smallest to the largest coordinated\"))\n        self.RB_Center_Left.setText(_translate(\"MainWindow\", \"Center Left\"))\n        self.RB_Center_Left.setToolTip(_fromUtf8(\"The selected point is the center face Left of the beam\"))\n        self.RB_Center_Right.setText(_translate(\"MainWindow\", \"Center Right\"))\n        self.RB_Center_Right.setToolTip(_fromUtf8(\"The selected point is the center face Right of the beam\"))\n        self.RB_Low_Left.setText(_translate(\"MainWindow\", \"Low Left\"))\n        self.RB_Low_Left.setToolTip(_fromUtf8(\"The selected point is in the low left corner\"+\"\\n\"\n                                              \"The selection order can reverse the form\"+\"\\n\"\n                                              \"Select the objects from the smallest to the largest coordinated\"))\n        self.RB_Center_Bottom.setText(_translate(\"MainWindow\", \"Center Bottom\"))\n        self.RB_Center_Bottom.setToolTip(_fromUtf8(\"The selected point is the center face Bottom of the beam\"))\n        self.RB_Low_Rigth.setText(_translate(\"MainWindow\", \"Low Rigth\"))\n        self.RB_Low_Rigth.setToolTip(_fromUtf8(\"The selected point is in the low rigth corner\"+\"\\n\"\n                                               \"The selection order can reverse the form\"+\"\\n\"\n                                               \"Select the objects from the smallest to the largest coordinated\"))\n        self.RB_Center.setText(_translate(\"MainWindow\", \"Center\"))\n        self.RB_Center.setToolTip(_fromUtf8(\"The selected point is in the center of forme\"))\n\n        self.GBox_06_.setTitle(_translate(\"MainWindow\", \"Options\"))\n        self.DS_Discretize.setSuffix(_translate(\"MainWindow\", \" sec\"))\n        self.DS_Discretize.setToolTip(_fromUtf8(\"Enter number cut\"))\n        self.CB_Discretize.setText(_translate(\"MainWindow\", \"Sections\")) #Dimension\n        self.CB_Discretize.setToolTip(_fromUtf8(\"Check this checkBox for choice:\" + \"\\n\"\n                                                \"Section   (Sec) : the line is cut in x egual sections\" + \"\\n\"\n                                                \"Dimension (mm)  : the line is cut in x parts with the dimension request\"))\n        self.CB_Reverse.setText(_translate(\"MainWindow\", \"Reverse\"))\n        self.CB_Reverse.setToolTip(_fromUtf8(\"Check for reverse the order points created\" + \"\\n\"\n                                             \"only with the Dimension (mm) option\"))\n        self.PB_Del_Points.setText(_translate(\"MainWindow\", \"Del last Points\"))\n        self.PB_Del_Points.setToolTip(_fromUtf8(\"Delete the last package of points created\"))\n        self.PB_Discretize.setText(_translate(\"MainWindow\", \"Process Discretize\"))\n        self.PB_Discretize.setToolTip(_fromUtf8(\"Process the operation creation of points\" + \"\\n\"\n                                                \"after discretize\"))\n        self.tabWidget.setTabText(self.tabWidget.indexOf(self.TAB_Discretize), _translate(\"MainWindow\", \"Discretize Line\"))\n\n        self.PB_Reset_Face.setText(_translate(\"MainWindow\", \"Reset\"))\n        self.PB_Reset_Face.setToolTip(_fromUtf8(\"Reset the selection(s) for the Sweep, Loft, Face, Edge or\" + \"\\n\"\n                                                \"Duplicate operation BUT not delette the object created\"))\n        self.PB_Visibility.setText(_translate(\"MainWindow\", \"Visibility\"))\n        self.PB_Visibility.setToolTip(_fromUtf8(\"Restore the visibility\" + \"\\n\"\n                                                \"on the all object selected for create a Duplicate button\" + \"\\n\"\n                                                \"The button is active for the duplicate objects until\" + \"\\n\"\n                                                \"the creation of Sweep (Button)\" + \"\\n\"\n                                                \"If the duplication is not used (empty) this button can be used\" + \"\\n\"\n                                                \"for hide/display the object selected (only the object selcted)\"))\n        self.PB_Create_Face.setText(_translate(\"MainWindow\", \"Create Face\"))\n        self.PB_Create_Face.setToolTip(_fromUtf8(\"Create a Face or Edge on S_obect selected\" + \"\\n\"\n                                                 \"The original object used for create a face or duplicate\" + \"\\n\"\n                                                 \"is made hidden to access easily on new object created\" + \"\\n\"\n                                                 \"This function are used by the Sweep tools button\"))\n        self.tabWidget.setTabText(self.tabWidget.indexOf(self.Tab_Face), _translate(\"MainWindow\", \"Duplicate F/W\"))\n\n        self.PB_Reset_Sweep.setText(_translate(\"MainWindow\", \"Reset\"))\n        self.PB_Reset_Sweep.setToolTip(_fromUtf8(\"Reset the selection(s) for the Sweep, Loft, Face, Edge or\" + \"\\n\"\n                                                 \"Duplicate operation BUT not delette the object created\"))\n        self.PB_Del_Sweep.setText(_translate(\"MainWindow\", \"Del last Sweep\"))\n        self.PB_Del_Sweep.setToolTip(_fromUtf8(\"Delette the last object created\" + \"\\n\"\n                                               \"Sweep, Loft, Edge or Face\"))\n        self.PB_Sweep.setText(_translate(\"MainWindow\", \"Create Sweep\"))\n        self.PB_Sweep.setToolTip(_fromUtf8(\"Create a sweep with the face(s) created and the path selected\" + \"\\n\"\n                                           \"For create the sweep:\" + \"\\n\"\n                                           \"create first the face(s) with the Duplicate button\" + \"\\n\"\n                                           \"Using this button delette the listing of the names memorised\" + \"\\n\"\n                                           \"with the Duplicate button\"))\n        self.CB_Solid_Sweep.setText(_translate(\"MainWindow\", \"Solid\"))\n        self.CB_Solid_Sweep.setToolTip(_fromUtf8(\"Check for create a Solid Sweep\"))\n        self.CB_Frenet_Sweep.setText(_translate(\"MainWindow\", \"Frenet\"))\n        self.CB_Frenet_Sweep.setToolTip(_fromUtf8(\"Check for create a Frenet Sweep\"))\n        self.tabWidget.setTabText(self.tabWidget.indexOf(self.Tab_Sweep), _translate(\"MainWindow\", \"Sweep\"))\n\n        self.PB_Reset_Loft.setText(_translate(\"MainWindow\", \"Reset\"))\n        self.PB_Reset_Loft.setToolTip(_fromUtf8(\"Reset the selection(s) for the Sweep, Loft, Face, Edge or\" + \"\\n\"\n                                                \"Duplicate operation BUT not delette the object created\"))\n        self.PB_Del_Loft.setText(_translate(\"MainWindow\", \"Del last Loft\"))\n        self.PB_Del_Loft.setToolTip(_fromUtf8(\"Delette the last object created\" + \"\\n\"\n                                              \"Sweep, Loft, Edge or Face\"))\n        self.PB_Loft.setText(_translate(\"MainWindow\", \"Create Loft\"))\n        self.PB_Loft.setToolTip(_fromUtf8(\"Create a loft with the face(s) created\" + \"\\n\"\n                                           \"For create the loft:\" + \"\\n\"\n                                           \"create first the face(s) with the Duplicate button\" + \"\\n\"\n                                           \"Using this button delette the listing of the names memorised\" + \"\\n\"\n                                           \"with the Duplicate button\"))\n        self.CB_Solid_Loft.setText(_translate(\"MainWindow\", \"Solid\"))\n        self.CB_Solid_Loft.setToolTip(_fromUtf8(\"Check for create a Solid Loft\"))\n        self.CB_Ruled_Loft.setText(_translate(\"MainWindow\", \"Ruled\"))\n        self.CB_Ruled_Loft.setToolTip(_fromUtf8(\"Check for create a Ruled Loft\"))\n        self.CB_Closed_Loft.setText(_translate(\"MainWindow\", \"Closed\"))\n        self.CB_Closed_Loft.setToolTip(_fromUtf8(\"Check for create a Closed Loft\"))\n        self.tabWidget.setTabText(self.tabWidget.indexOf(self.Tab_Loft), _translate(\"MainWindow\", \"Loft\"))\n\n        self.GBox_05_.setTitle(_translate(\"MainWindow\", \"Command\"))\n        self.PB_Create.setText(_translate(\"MainWindow\", \"Create Solid\"))\n        self.PB_Create.setToolTip(_fromUtf8(\"Create the sweep or line\"))\n        self.PB_Del_Last_Line.setText(_translate(\"MainWindow\", \"Del last Line\"))\n        self.PB_Del_Last_Line.setToolTip(_fromUtf8(\"If the last form is not in the right direction\" + \"\\n\"\n                                                   \"you can delete it easily\"))\n        self.PB_Quit.setText(_translate(\"MainWindow\", \"Quit\"))\n        self.PB_Quit.setToolTip(_fromUtf8(\"Quit Connect And Sweep\"))\n\n\n    def on_PB_Help(self): # \n        try:\n            webbrowser.open(__Wiki__)\n            App.Console.PrintMessage(__Wiki__ + \"\\n\")\n        except Exception:\n            App.Console.PrintMessage(u\"Not access\")\n\n    def colorThickness(self,value):    # 0= couleur de Base , 1= couleur rouge\n        global ui\n\n        if (self.Thickness != 0.0):\n            if value != 0:\n                ############### font and color modified\n                self.Thickness = 0.0\n                self.DS_Pipe.setValue(self.Thickness)\n                palette = QtGui.QPalette()\n                brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))\n                brush.setStyle(QtCore.Qt.SolidPattern)\n                palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)\n                font = QtGui.QFont()\n                font.setBold(True)\n                font.setWeight(75)\n                self.DS_Pipe.setPalette(palette)    # DSpinbox\n                self.DS_Pipe.setFont(font)          # DSpinbox\n                App.Console.PrintWarning(\"Thickness aborded\" + \"\\n\")\n                self.label_Info.setText(_fromUtf8(\"Thickness aborded\"))\n                self.label_Info.setStyleSheet(\"QLabel {color : #ffffff; background-color : #FF3300;}\")\n                ############### font and color modified\n            else:\n                ############### font and color base\n                palette = QtGui.QPalette()\n                brush = QtGui.QBrush(QtGui.QColor(\"Base\"))\n                brush.setStyle(QtCore.Qt.SolidPattern)\n                palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)\n                font = QtGui.QFont()\n                font.setBold(False)\n                self.DS_Pipe.setPalette(palette)    # DSpinbox\n                self.DS_Pipe.setFont(font)          # DSpinbox\n                ###############\n\n    def on_RB_00_Mode_clicked(self):\n\n        self.RB_01_BBox_Oject.setStyleSheet(\"background-color: QPalette.Base\")# origin system\n        self.RB_02_BBox_Subo.setStyleSheet(\"background-color: QPalette.Base\") # origin system\n        self.RB_03_Subo_Subo.setStyleSheet(\"background-color: QPalette.Base\") # origin system\n\n    def on_SB_Polyline_Number_Faces(self,value):\n\n        self.Polyline_Number_Faces = value\n\n    def on_DS_Circle_Radius(self,value):\n\n        self.Circle_Radius   = value\n        self.Circle_Diameter = self.Circle_Radius * 2.0\n        self.DS_Circle_Diameter.setValue(self.Circle_Diameter)\n\n    def on_DS_Circle_Diameter(self,value):\n\n        self.Circle_Diameter = value\n        self.Circle_Radius   = self.Circle_Diameter / 2.0\n        self.DS_Circle_Radius.setValue(self.Circle_Radius)\n\n    def on_DS_Polyline_CirCon(self,value):\n\n        self.Polyline_CirCon = value\n\n    def on_DS_Rectangle_X(self,value):\n\n        self.Rectangle_X = value\n\n    def on_DS_Rectangle_Y(self,value):\n\n        if value > self.Rectangle_X:\n            value = self.Rectangle_X\n            self.DS_Rectangle_Y.setValue(value)\n        self.Rectangle_Y = value\n\n    def on_DS_Pipe(self,value):\n        global ui\n\n        self.Thickness = value\n        if self.Thickness != 0.0:\n            self.CB_Solid.setChecked(True)\n            self.PB_Create.setText(\"Create Solid\")\n            self.CB_Solid.setText(_fromUtf8(\"Solid\"))\n            if   self.RB_Polyline.isChecked():\n                self.PB_Create.setText(_fromUtf8(\"Create Pipe Polyline\"))\n            elif self.RB_Rectangle.isChecked():\n                self.PB_Create.setText(_fromUtf8(\"Create Pipe Rectangle\"))\n            elif self.RB_Ellipse.isChecked():\n                self.PB_Create.setText(_fromUtf8(\"Create Pipe Ellipse\"))\n            elif self.RB_Circle.isChecked():\n                self.PB_Create.setText(_fromUtf8(\"Create Pipe Circle\"))\n            elif self.RB_Line.isChecked():\n                self.PB_Create.setText(_fromUtf8(\"Create Width Line\"))\n        else:\n            self.CB_Solid.setChecked(True)\n            if   self.RB_Polyline.isChecked():\n                self.PB_Create.setText(_fromUtf8(\"Create Solid Polyline\"))\n            elif self.RB_Rectangle.isChecked():\n                self.PB_Create.setText(_fromUtf8(\"Create Solid Rectangle\"))\n            elif self.RB_Ellipse.isChecked():\n                self.PB_Create.setText(_fromUtf8(\"Create Solid Ellipse\"))\n            elif self.RB_Circle.isChecked():\n                self.PB_Create.setText(_fromUtf8(\"Create Solid Circle\"))\n            elif self.RB_Line.isChecked():\n                self.PB_Create.setText(_fromUtf8(\"Create Line\"))\n        ff = ui\n        ff.colorThickness(0)\n\n    def on_CB_Insc_Circon_clicked(self):\n\n        if self.CB_Insc_Circon.isChecked():\n            self.DS_Polyline_CirCon.setSuffix(\" Ins mm\")\n            self.CB_Insc_Circon.setText(_fromUtf8(\"Polygon Inscribed\"))\n        else:\n            self.DS_Polyline_CirCon.setSuffix(\" Cir mm\")\n            self.CB_Insc_Circon.setText(_fromUtf8(\"Polygon Circumscribed\"))\n\n    def on_CB_Solid_clicked(self):\n        global ui\n\n        if self.CB_Solid.isChecked():\n            self.PB_Create.setText(\"Create Solid\")\n            self.CB_Solid.setText(_fromUtf8(\"Solid\"))\n        else:\n            self.PB_Create.setText(\"Create Empty (Shell)\")\n            self.CB_Solid.setText(_fromUtf8(\"Shell\"))\n        if self.Thickness != 0.0:\n            self.CB_Solid.setChecked(True)\n            ui.on_DS_Pipe(self.Thickness)\n\n    def on_RB_Polyline_clicked(self):\n        global ui\n\n        self.GBox_07_.setVisible(False)\n        MainWindow.resize(QtCore.QSize(360, 570))\n        FreeCADGui.updateGui()                                 # rafraichi l'ecran\n        MainWindow.resize(QtCore.QSize(360, 570))\n\n        if self.RB_Polyline.isChecked():\n            ui.on_DS_Pipe(self.Thickness)\n            self.DS_Circle_Radius.setVisible(True)\n            self.DS_Circle_Diameter.setVisible(True)\n            self.label_Pipe.setText(_fromUtf8(\"Pipe\"))\n\n    def on_RB_Rectangle_clicked(self):\n        global ui\n\n        ui.on_DS_Pipe(self.Thickness)\n\n        MainWindow.resize(750, 570)\n        self.GBox_07_.setVisible(True)\n\n        self.grid03.addWidget(self.DS_Rectangle_X, 2, 1)\n        self.grid03.addWidget(self.DS_Rectangle_Y, 2, 2)\n        self.DS_Rectangle_X.setSuffix(\" L mm\")\n        self.DS_Rectangle_Y.setSuffix(\" H mm\")\n        self.DS_Rectangle_X.setToolTip(_fromUtf8(\"Rectangle Length\"))\n        self.DS_Rectangle_Y.setToolTip(_fromUtf8(\"Rectangle Height\"))\n        self.label_Pipe.setText(_fromUtf8(\"Pipe\"))\n\n    def on_RB_Ellipse_clicked(self):\n        global ui\n\n        ui.on_DS_Pipe(self.Thickness)\n\n        MainWindow.resize(750, 570)\n        self.GBox_07_.setVisible(True)\n\n        self.grid03.addWidget(self.DS_Rectangle_X, 3, 1)\n        self.grid03.addWidget(self.DS_Rectangle_Y, 3, 2)\n        self.DS_Rectangle_X.setSuffix(\" R mm\")\n        self.DS_Rectangle_Y.setSuffix(\" r mm\")\n        self.DS_Rectangle_X.setToolTip(_fromUtf8(\"Ellipse MajorRadius\"))\n        self.DS_Rectangle_Y.setToolTip(_fromUtf8(\"Ellipse MinorRadius\"))\n        self.label_Pipe.setText(_fromUtf8(\"Pipe\"))\n\n    def on_RB_Image_clicked(self):\n\n        pic = QtGui.QPixmap()\n        if self.RB_Top_Left.isChecked():\n            pic.loadFromData(base64.b64decode(Macro_Connect_And_Sweep_TL))\n        elif self.RB_Top_Rigth.isChecked():\n            pic.loadFromData(base64.b64decode(Macro_Connect_And_Sweep_TR))\n        elif self.RB_Low_Left.isChecked():\n            pic.loadFromData(base64.b64decode(Macro_Connect_And_Sweep_LL))\n        elif self.RB_Low_Rigth.isChecked():\n            pic.loadFromData(base64.b64decode(Macro_Connect_And_Sweep_LR))\n        elif self.RB_Center.isChecked():\n            pic.loadFromData(base64.b64decode(Macro_Connect_And_Sweep_CE))\n        elif self.RB_Center_Top.isChecked():      # center dessus poutrelle\n            pic.loadFromData(base64.b64decode(CenterTop_b64))\n        elif self.RB_Center_Right.isChecked():    # Rectangle Center_Right\n            pic.loadFromData(base64.b64decode(CenterRigth_b64))\n        elif self.RB_Center_Left.isChecked():     # Rectangle Center Left\n            pic.loadFromData(base64.b64decode(CenterLeft_b64))\n        elif self.RB_Center_Bottom.isChecked():   # Rectangle Center Bottom\n            pic.loadFromData(base64.b64decode(CenterBottom_b64))\n        else:\n            pic.loadFromData(base64.b64decode(Macro_Connect_And_Sweep_CE))\n        self.scene = QtWidgets.QGraphicsScene()\n        self.scene.addPixmap(QtGui.QPixmap(pic))\n        self.graphicsView.setScene(self.scene)\n        \n    def on_RB_Circle_clicked(self):\n        global ui\n\n        self.GBox_07_.setVisible(False)\n        MainWindow.resize(QtCore.QSize(360, 570))\n        FreeCADGui.updateGui()                                 # rafraichi l'ecran\n        MainWindow.resize(QtCore.QSize(360, 570))\n\n        if self.RB_Circle.isChecked():\n            ui.on_DS_Pipe(self.Thickness)\n            self.label_Pipe.setText(_fromUtf8(\"Pipe\"))\n\n    def on_RB_Line_clicked(self):\n        global ui\n\n        self.GBox_07_.setVisible(False)\n        MainWindow.resize(QtCore.QSize(360, 570))\n        FreeCADGui.updateGui()                                 # rafraichi l'ecran\n        MainWindow.resize(QtCore.QSize(360, 570))\n\n        if self.RB_Line.isChecked():\n            ui.on_DS_Pipe(self.Thickness)\n            self.label_Pipe.setText(_fromUtf8(\"Line\"))\n\n    def on_DS_Discretize(self, value): \n\n        if self.CB_Discretize.isChecked():\n            self.discretize = float(value)\n        else:\n            self.discretize = int(value)\n        self.DS_Discretize.setValue(self.discretize)\n\n    def on_CB_Discretize_clicked(self):\n\n        if self.CB_Discretize.isChecked():\n            self.DS_Discretize.setMinimum(0.000001)\n            self.DS_Discretize.setMaximum(999999)\n            self.DS_Discretize.setDecimals(3)\n            self.DS_Discretize.setSuffix(\" mm\")\n            self.DS_Discretize.setValue(float(self.discretize))\n            self.CB_Discretize.setText(_fromUtf8(\"Dimension\"))\n            self.CB_Reverse.setEnabled(True)\n        else:\n            self.DS_Discretize.setMinimum(1)\n            self.DS_Discretize.setMaximum(999999)\n            self.DS_Discretize.setDecimals(0)\n            self.DS_Discretize.setSuffix(\" Sec\")\n            self.discretize = int(self.discretize)\n            self.CB_Discretize.setText(_fromUtf8(\"Sections\"))\n            self.CB_Reverse.setEnabled(False)\n            self.CB_Reverse.setChecked(False)\n        self.DS_Discretize.setValue(self.discretize)\n\n    def on_CB_Reverse(self):\n        None\n\n    def on_PB_Del_Points(self): \n\n        try:\n            FreeCAD.ActiveDocument.getObject(self.CASweep.Name).removeObjectsFromDocument()\n            FreeCAD.ActiveDocument.removeObject(self.CASweep.Name)\n#01            for de in self.nameL:\n#01                FreeCAD.ActiveDocument.removeObject(de)\n#01            del self.nameL[:]\n        except Exception:\n            None\n\n    def on_PB_Discretize(self): \n\n        try:\n            selD = FreeCADGui.Selection.getSelectionEx()\n            longueur = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0].Length\n            subElementName = Gui.Selection.getSelectionEx()[0].SubElementNames[0]\n            self.CASweep = App.activeDocument().addObject(\"App::DocumentObjectGroup\",\"CASweep_\" + subElementName)\n#01            self.nameL  = []\n#01            del self.nameL[:]\n            if self.CB_Discretize.isChecked():\n                if self.CB_Reverse.isChecked():        #reverse\n                    debutLine   = selD[0].SubObjects[0].Edges[0].Vertexes[0].Point\n                    finLine     = selD[0].SubObjects[0].Edges[0].Vertexes[1].Point\n                    lineReverse = Part.LineSegment(finLine, debutLine).toShape()\n                    Part.show(lineReverse)\n                    lineReverse = Part.LineSegment(finLine, debutLine).toShape()\n                    pointsDirection = lineReverse.discretize(Distance = self.discretize)           # distance en mm reverse\n                    FreeCAD.ActiveDocument.removeObject(App.ActiveDocument.ActiveObject.Name)\n                else:                                  #Forward\n                    pointsDirection = selD[0].SubObjects[0].discretize(Distance = self.discretize) # distance en mm nomal\n            else:\n                pointsDirection = selD[0].SubObjects[0].discretize(self.discretize + 1)            # nombre de coupes\n\n            for i in pointsDirection:\n                point = Draft.makePoint(i)\n                FreeCADGui.ActiveDocument.getObject(point.Name).PointColor = (1.0,0.0,0.0)\n                self.CASweep.addObject(point)  # conteneur dossier points\n#01                self.nameL.append(point.Name)\n            FreeCAD.ActiveDocument.recompute()\n#01            self.label_Info.setText(_fromUtf8(\"Number points : \" + str(len(pointsDirection)) + \" ; Length wire : \" + str(round(longueur,3))))\n        except Exception:\n            App.Console.PrintError(\"Error Discretize !\" + \"\\n\")\n            self.label_Info.setText(_fromUtf8(\"Error Discretize !\"))\n            self.label_Info.setStyleSheet(\"QLabel {color : #ffffff; background-color : #FF3300;}\")\n\n        FreeCAD.ActiveDocument.recompute()\n\n    def on_PB_Create_Face(self): \n\n        try:\n            sel = FreeCADGui.Selection.getSelection()\n            self.ElementName = FreeCADGui.Selection.getSelection()[0].Name\n            subElementName   = Gui.Selection.getSelectionEx()[0].SubElementNames[0]\n            try:    \n                Gui.runCommand('Part_ElementCopy',0)        #ici pour la FC 0.19 et + use the FC feature\n            except Exception :\n                Part.show(FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0].copy())                            # create repro shape subObject\n                try:\n                    if (str(sel[0].InList[0]) == \"<body object>\") or (str(sel[0].InList[0]) == \"<Part object>\"):\n                        objectRealPlacement3DX, objectPlacementAngle = objectRealPlacement3D(FreeCAD.ActiveDocument.getObject(self.ElementName))# search the original Placement\n                        a = App.ActiveDocument.ActiveObject #ici avec la FC 0.18\n                        a.Placement = App.Placement(App.Vector(objectRealPlacement3DX), App.Rotation(objectPlacementAngle[0], objectPlacementAngle[1], objectPlacementAngle[2]), App.Vector(0,0,0))\n                    else:\n                        None\n                except Exception:\n                    None\n\n            App.ActiveDocument.ActiveObject.Label = App.ActiveDocument.ActiveObject.Label + \"_\" + subElementName\n            FreeCADGui.activeDocument().getObject(self.ElementName).Visibility = False\n\n            try:\n                FreeCADGui.activeDocument().activeObject().LineColor  = (1.0,0.0,0.0)     # give LineColor\n                FreeCADGui.activeDocument().activeObject().PointColor = (1.0,0.0,0.0)     # give PointColor\n                FreeCADGui.activeDocument().activeObject().ShapeColor = (1.0,0.0,0.0)     # give ShapeColor\n            except Exception:\n                None\n\n            if self.ElementName in self.selectForDuplicate:\n                None\n            else:\n                self.selectForDuplicate.append(self.ElementName)\n            FreeCAD.ActiveDocument.recompute()\n\n            self.PB_Reset_Sweep.setText(_fromUtf8(\"Reset \" + str(len(self.selectForDuplicate))))\n            self.PB_Reset_Loft.setText(_fromUtf8(\"Reset \" + str(len(self.selectForDuplicate))))\n            self.PB_Reset_Face.setText(_fromUtf8(\"Reset \" + str(len(self.selectForDuplicate))))\n            self.PB_Visibility.setStyleSheet(\"background-color: white;\\n\"\n                                             \"border:2px solid rgb(115, 210, 22);\")  # bord white and green\n            self.PB_Reset_Sweep.setStyleSheet(\"background-color: white;\\n\"\n                                              \"border:2px solid rgb(115, 210, 22);\") # bord white and green\n            self.PB_Reset_Loft.setStyleSheet(\"background-color: white;\\n\"\n                                             \"border:2px solid rgb(115, 210, 22);\")  # bord white and green\n            self.PB_Reset_Face.setStyleSheet(\"background-color: white;\\n\"\n                                             \"border:2px solid rgb(115, 210, 22);\")  # bord white and green\n\n        except Exception:\n            None\n        App.ActiveDocument.recompute()\n\n    def on_PB_Visibility(self): # after created face\n\n        try:\n            if len(self.selectForDuplicate) == 0:\n                self.ElementName = FreeCADGui.Selection.getSelection()[0].Name\n                if FreeCADGui.activeDocument().getObject(self.ElementName).Visibility == True:\n                    FreeCADGui.activeDocument().getObject(self.ElementName).Visibility = False\n                else:\n                    FreeCADGui.activeDocument().getObject(self.ElementName).Visibility = True\n            else:\n                for visible in self.selectForDuplicate:\n                    if FreeCADGui.activeDocument().getObject(visible).Visibility == True:\n                        FreeCADGui.activeDocument().getObject(visible).Visibility = False\n                    else:\n                        FreeCADGui.activeDocument().getObject(visible).Visibility = True\n        except Exception:\n            None\n\n    def on_PB_Reset_Sweep(self): # Sweep or Duplicate or Face or Loft (self.selectForDuplicate)\n\n        for visible in self.selectForDuplicate:    #restore the visible objects\n            FreeCADGui.activeDocument().getObject(visible).Visibility = True\n        self.selectForDuplicate = []\n        self.PB_Reset_Sweep.setText(_fromUtf8(\"Reset\"))\n        self.PB_Reset_Loft.setText(_fromUtf8(\"Reset\"))\n        self.PB_Reset_Face.setText(_fromUtf8(\"Reset\"))\n        self.PB_Visibility.setStyleSheet(\"Base\")\n        self.PB_Reset_Sweep.setStyleSheet(\"Base\")\n        self.PB_Reset_Loft.setStyleSheet(\"Base\")\n        self.PB_Reset_Face.setStyleSheet(\"Base\")\n\n    def on_PB_Del_Sweep(self): \n\n        try:\n            FreeCAD.ActiveDocument.removeObject(self.sweepFaceName)\n        except Exception:\n            None\n\n    def on_PB_Sweep(self): # \n\n        try:\n            selForSweep     = FreeCADGui.Selection.getSelection()\n            subElementSweep = Gui.Selection.getSelectionEx()[len(selForSweep)-1].SubElementNames[0]\n            #if (selForSweep[0].Shape.ShapeType == \"Face\"):\n            #else:\n            #    print(\"Error selection : \",selForSweep[0].Shape.ShapeType,\" \",selForSweep[1].Shape.ShapeType)\n            if len(selForSweep) > 1:\n                sweepFace          = FreeCAD.ActiveDocument.addObject('Part::Sweep','Sweep')\n                self.sweepFaceName = sweepFace.Name\n                sweepFace.Sections = [FreeCAD.ActiveDocument.getObject(o.Name) for o in selForSweep[:-1]]\n                sweepFace.Spine    = FreeCAD.ActiveDocument.getObject(selForSweep[-1].Name),[subElementSweep]\n\n                if self.CB_Solid_Sweep.isChecked():\n                    sweepFace.Solid    = True\n                else:\n                    sweepFace.Solid    = False\n                if self.CB_Frenet_Sweep.isChecked():\n                    sweepFace.Frenet   = True\n                else:\n                    sweepFace.Frenet   = False\n\n                sweepFace.Label    = selForSweep[0].Label + \"_\" + selForSweep[-1].Name\n                for visible in self.selectForDuplicate:    #restore the visible objects\n                    FreeCADGui.activeDocument().getObject(visible).Visibility = True\n                self.selectForDuplicate = []\n\n                self.PB_Reset_Sweep.setText(_fromUtf8(\"Reset \" + str(len(self.selectForDuplicate))))\n                self.PB_Reset_Loft.setText(_fromUtf8(\"Reset \" + str(len(self.selectForDuplicate))))\n                self.PB_Reset_Face.setText(_fromUtf8(\"Reset \" + str(len(self.selectForDuplicate))))\n                self.PB_Visibility.setStyleSheet(\"background-color: white;\\n\"\n                                                 \"border:2px solid rgb(115, 210, 22);\")  # bord white and green\n                self.PB_Reset_Sweep.setStyleSheet(\"background-color: white;\\n\"\n                                                  \"border:2px solid rgb(115, 210, 22);\") # bord white and green\n                self.PB_Reset_Loft.setStyleSheet(\"background-color: white;\\n\"\n                                                 \"border:2px solid rgb(115, 210, 22);\")  # bord white and green\n                self.PB_Reset_Face.setStyleSheet(\"background-color: white;\\n\"\n                                                 \"border:2px solid rgb(115, 210, 22);\")  # bord white and green\n        except Exception:\n            try:\n                FreeCAD.ActiveDocument.removeObject(self.sweepFaceName)\n            except Exception:\n                None\n        App.ActiveDocument.recompute()\n\n    def on_PB_Loft(self):\n\n        try:\n            selForLoft     = FreeCADGui.Selection.getSelection()\n            subElementSweep = Gui.Selection.getSelectionEx()[len(selForLoft)-1].SubElementNames[0]\n            #if (selForLoft[0].Shape.ShapeType == \"Face\"):\n            #else:\n            #    print(\"Error selection : \",selForLoft[0].Shape.ShapeType,\" \",selForLoft[1].Shape.ShapeType)\n            if len(selForLoft) > 1:\n                loftFace          = FreeCAD.ActiveDocument.addObject('Part::Loft','Loft')\n                self.sweepFaceName = loftFace.Name\n                loftFace.Sections = [FreeCAD.ActiveDocument.getObject(o.Name) for o in selForLoft]\n\n                if self.CB_Solid_Loft.isChecked():\n                    loftFace.Solid    = True\n                else:\n                    loftFace.Solid    = False\n\n                if self.CB_Ruled_Loft.isChecked():\n                    loftFace.Ruled    = True\n                else:\n                    loftFace.Closed    = False\n\n                if self.CB_Closed_Loft.isChecked():\n                    loftFace.Closed    = True\n                else:\n                    loftFace.Closed    = False\n\n                loftFace.Label    = selForLoft[0].Label + \"_\" + selForLoft[-1].Name\n                for visible in self.selectForDuplicate:    #restore the visible objects\n                    FreeCADGui.activeDocument().getObject(visible).Visibility = True\n                self.selectForDuplicate = []\n\n                self.PB_Reset_Sweep.setText(_fromUtf8(\"Reset \" + str(len(self.selectForDuplicate))))\n                self.PB_Reset_Loft.setText(_fromUtf8(\"Reset \" + str(len(self.selectForDuplicate))))\n                self.PB_Reset_Face.setText(_fromUtf8(\"Reset \" + str(len(self.selectForDuplicate))))\n                self.PB_Visibility.setStyleSheet(\"background-color: white;\\n\"\n                                                 \"border:2px solid rgb(115, 210, 22);\")  # bord white and green\n                self.PB_Reset_Sweep.setStyleSheet(\"background-color: white;\\n\"\n                                                  \"border:2px solid rgb(115, 210, 22);\") # bord white and green\n                self.PB_Reset_Loft.setStyleSheet(\"background-color: white;\\n\"\n                                                 \"border:2px solid rgb(115, 210, 22);\")  # bord white and green\n                self.PB_Reset_Face.setStyleSheet(\"background-color: white;\\n\"\n                                                 \"border:2px solid rgb(115, 210, 22);\")  # bord white and green\n        except Exception:\n            try:\n                FreeCAD.ActiveDocument.removeObject(self.sweepFaceName)\n            except Exception:\n                None\n        App.ActiveDocument.recompute()\n\n    def on_PB_Quit(self):                        # Quit\n\n        App.Console.PrintMessage(str(\"Fin Connect And Sweep \")+\"\\n\")\n        self.window.hide()\n\n    def on_PB_Del_Last_Line(self):               # Del Last Line\n\n        self.label_Info.setStyleSheet(\"QPalette.Base\")         # origin system\n        self.label_Info.setText(_fromUtf8( __version__ + \"  \" + __date__ + \" rmu\"))\n        try:\n            FreeCAD.ActiveDocument.getObject(self.FcSweep.Name).removeObjectsFromDocument()\n            FreeCAD.ActiveDocument.removeObject(self.FcSweep.Name)\n        except Exception:\n            self.PB_Del_Last_Line.setText(_fromUtf8(\"?\"))\n            None\n\n    def on_PB_Create(self):                      # Create\n        try:\n            if len(Gui.Selection.getSelection()) >= 1:\n\n                self.label_Info.setStyleSheet(\"QPalette.Base\")         # origin system\n                self.label_Info.setText(_fromUtf8( __version__ + \"  \" + __date__ + \" rmu\"))\n\n                if self.RB_01_BBox_Oject.isChecked(): # Obj Obj\n                    boundBox_0 = Gui.Selection.getSelection()[0].Shape.BoundBox.Center       # Object 1 is Object BBox\n                    boundBox_0 = boundBox_0.add(objectRealPlacement3D(Gui.Selection.getSelection()[0],0,\"BB\"))####\n                    try:\n                        boundBox_1 = Gui.Selection.getSelection()[1].Shape.BoundBox.Center       # Object 2 is Object BBox\n                        boundBox_1 = boundBox_1.add(objectRealPlacement3D(Gui.Selection.getSelection()[1],0,\"BB\"))####\n                    except Exception:\n                        self.RB_03_Subo_Subo.setChecked(True)\n                        self.RB_03_Subo_Subo.setStyleSheet(\"background-color: #f57900 \")\n                        FreeCAD.Console.PrintError(\"Bad selection or 1 object selected instead 2 in mode BBox Obj Obj\"+\"\\n\"\n                                                   \"mode changed to mode 3 BBox SObj. SObj. \"+\"\\n\")\n                    #print(\"1\")\n\n                elif self.RB_02_BBox_Subo.isChecked(): # Obj SObj\n                    boundBox_0 = Gui.Selection.getSelection()[0].Shape.BoundBox.Center       # Object 2 is Object BBox\n                    boundBox_0 = boundBox_0.add(objectRealPlacement3D(Gui.Selection.getSelection()[0],0,\"BB\"))####\n                    try:\n                        boundBox_1 = Gui.Selection.getSelectionEx()[1].SubObjects[0].BoundBox.Center         # object 1 is subObject BBCenter\n                        boundBox_1 = boundBox_1.add(objectRealPlacement3D(Gui.Selection.getSelection()[1],0,\"BB\"))# \n                    except Exception:\n                        self.RB_03_Subo_Subo.setChecked(True)\n                        self.RB_03_Subo_Subo.setStyleSheet(\"background-color: #f57900 \")\n                        FreeCAD.Console.PrintError(\"Bad selection or 1 object selected instead 2 in mode BBox Obj SObj\"+\"\\n\"\n                                                   \"mode changed to mode 3 BBox SObj. SObj. \"+\"\\n\")\n                    #print(\"2\")\n\n                if self.RB_03_Subo_Subo.isChecked(): # SObj SObj\n                    boundBox_0 = Gui.Selection.getSelectionEx()[0].SubObjects[0].BoundBox.Center         # object 1 is subObject BBCenter\n                    boundBox_0 = boundBox_0.add(objectRealPlacement3D(Gui.Selection.getSelection()[0],0,\"BB\"))# \n                    #print(\"11\")\n                    try:\n                        boundBox_1 = Gui.Selection.getSelectionEx()[0].SubObjects[1].BoundBox.Center         # object 2 is subObject BBCenter\n                        boundBox_1 = boundBox_1.add(objectRealPlacement3D(Gui.Selection.getSelection()[0],0,\"BB\"))# \n                        #print(\"12\")\n                    except Exception:\n                        try:\n                            boundBox_1 = Gui.Selection.getSelectionEx()[1].SubObjects[0].BoundBox.Center         # object 2 is subObject BBCenter\n                            boundBox_1 = boundBox_1.add(objectRealPlacement3D(Gui.Selection.getSelection()[1],0,\"BB\"))# \n                            #print(\"13\")\n                        except Exception:\n                            try:\n                                originalPosition_01 = objectRealPlacement3D(Gui.Selection.getSelection()[0],0,\"BB\")\n                                originalPosition_02 = objectRealPlacement3D(Gui.Selection.getSelection()[0],0,\"BB\")\n\n                                points = Gui.Selection.getSelectionEx()[0].SubObjects[0].Edges[0].discretize(3)   # single object (Line)\n                                boundBox_0 = originalPosition_01.add(points[0])\n                                boundBox_1 = originalPosition_02.add(points[2])\n                                #print(\"14\")\n                            except Exception:\n                                App.Console.PrintMessage(\"Error selection SObj SObj\" + \"\\n\")# \n                                self.label_Info.setText(_fromUtf8(\"Error selection SObj SObj\"))\n                                self.label_Info.setStyleSheet(\"QLabel {color : #ffffff; background-color : #FF3300;}\")\n                                \n                try:\n                    points=[FreeCAD.Vector(boundBox_0),FreeCAD.Vector(boundBox_1)]              # coordinates\n                    self.ligne = Draft.makeWire(points,closed=False,face=False,support=None)    # create line directrice\n                    self.ligne.Label = \"Line_Master\"\n\n                    App.Console.PrintMessage(\"Object 0  : \" + str(boundBox_0) + \"\\n\")    # coordinates displayed\n                    App.Console.PrintMessage(\"Object 1  : \" + str(boundBox_1) + \"\\n\")    # coordinates displayed\n                    self.label_Info.setText(_fromUtf8(\"Object 0 : \" + str(boundBox_0) + \" Object 1 : \" + str(boundBox_1)))\n                    try:\n                        direction = boundBox_1.sub(boundBox_0)\n                        App.Console.PrintMessage(\"Direction : \" + str(direction) + \"\\n\") # direction displayed\n                    except Exception:\n                        None                   \n                    try:\n                        App.Console.PrintMessage(\"Distance point to point : \" + str(DraftVecUtils.dist(boundBox_0, boundBox_1)) + \"\\n\")# length point to point\n                        self.label_Info.setText(_fromUtf8(\"Distance point to point : \" + str(DraftVecUtils.dist(boundBox_0, boundBox_1))))\n                    except Exeption:\n                        None\n                    App.Console.PrintMessage(\"_______________________\" + \"\\n\")#\n    \n                    ##### create Line\n                    #self.PB_Del_Last_Line.setEnabled(True)\n                    if self.RB_Line.isChecked():\n                        if (self.Thickness != 0.0):\n                            FreeCADGui.ActiveDocument.getObject(self.ligne.Name).LineWidth = self.Thickness\n                            self.ligne.Label = \"Line_Master_\" + str(self.Thickness)\n                        #self.PB_Del_Last_Line.setEnabled(False)\n                        #self.PB_Del_Last_Line.setText(_fromUtf8(\"!\"))\n                        App.ActiveDocument.recompute()\n    \n                    else:\n                        ##### section camera view get origin\n                        OriginOrientation = FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation()\n                        ##### section camera alignement to points\n                        v=boundBox_1.sub(boundBox_0)\n                        r=App.Rotation(App.Vector(0,0,1),v)\n                        FreeCADGui.ActiveDocument.ActiveView.setCameraOrientation(r.Q)\n                    \n                        ##### create Placement\n                        pl = \"\"\n                        pl = FreeCAD.Placement()\n                        pl.Rotation.Q = (r.Q[0],r.Q[1],r.Q[2],r.Q[3])\n                        pl.Base = FreeCAD.Vector(boundBox_0[0],boundBox_0[1],boundBox_0[2])\n            \n                        ##### create Polyline\n                        if self.RB_Polyline.isChecked():\n                            if self.Polyline_CirCon == 0: self.Polyline_CirCon = 1.0\n                            if self.CB_Insc_Circon.isChecked():\n                                self.Forme = Draft.makePolygon(self.Polyline_Number_Faces ,radius=self.Polyline_CirCon,inscribed=True,placement=pl,face=False,support=None)    # Draft\n                            else:\n                                self.Forme = Draft.makePolygon(self.Polyline_Number_Faces ,radius=self.Polyline_CirCon,inscribed=False,placement=pl,face=False,support=None)   # Draft\n                            self.Forme.Placement = pl\n                            ##### tube a soustraire Polyline\n                            if (self.Thickness != 0.0) and (self.Thickness < self.Polyline_CirCon):\n                                if self.CB_Insc_Circon.isChecked():\n                                    self.FormeSubtract = Draft.makePolygon(self.Polyline_Number_Faces ,radius=(self.Polyline_CirCon-self.Thickness),inscribed=True,placement=pl,face=False,support=None)    # Draft\n                                else:\n                                    self.FormeSubtract = Draft.makePolygon(self.Polyline_Number_Faces ,radius=(self.Polyline_CirCon-self.Thickness),inscribed=False,placement=pl,face=False,support=None)   # Draft\n                                self.FormeSubtract.Placement = pl\n                            else:\n                                ff = ui\n                                ff.colorThickness(1)\n                            ##### tube a soustraire Polyline\n                            self.PB_Del_Last_Line.setText(_fromUtf8(\"Del Polygon\"))\n                        ##### create Rectangle\n                        elif self.RB_Rectangle.isChecked():\n        \n                            XS = self.Rectangle_X-(self.Thickness * 2)\n                            YS = self.Rectangle_Y-(self.Thickness * 2)\n        \n                            if self.RB_Center.isChecked():\n                                self.Forme = Draft.makeRectangle(length=self.Rectangle_X,height=self.Rectangle_Y,placement=App.Placement(App.Vector(-(self.Rectangle_X/2),-(self.Rectangle_Y/2),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(self.Forme.Placement) # increment and centrage\n                                ##### tube a soustraire Rectangle centre\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeRectangle(length=XS,height=YS,placement=App.Placement(App.Vector(-((XS)/2),-((YS)/2),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Rectangle centre\n                            elif self.RB_Top_Left.isChecked():\n                                self.Forme = Draft.makeRectangle(length=self.Rectangle_X,height=self.Rectangle_Y,placement=App.Placement(App.Vector((0.0),-(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(self.Forme.Placement) # increment Top_Left\n                                ##### tube a soustraire Rectangle Top_Left\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeRectangle(length=XS,height=YS,placement=App.Placement(App.Vector((self.Thickness),-(self.Rectangle_Y-self.Thickness),(0.0)), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Rectangle Top_Left\n                            elif self.RB_Top_Rigth.isChecked():\n                                self.Forme = Draft.makeRectangle(length=self.Rectangle_X,height=self.Rectangle_Y,placement=App.Placement(App.Vector(-(self.Rectangle_X),-(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(self.Forme.Placement) # increment Top_Rigth\n                                ##### tube a soustraire Rectangle Top_Rigth\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeRectangle(length=XS,height=YS,placement=App.Placement(App.Vector(-(self.Rectangle_X-self.Thickness),-(self.Rectangle_Y-self.Thickness),(0.0)), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Rectangle Top_Rigth\n                            elif self.RB_Low_Left.isChecked():\n                                self.Forme = Draft.makeRectangle(length=self.Rectangle_X,height=self.Rectangle_Y,placement=App.Placement(App.Vector(0.0,0.0,0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(self.Forme.Placement) # increment Low_Left\n                                ##### tube a soustraire Rectangle Low_Left\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeRectangle(length=XS,height=YS,placement=App.Placement(App.Vector((self.Thickness),(self.Thickness),(0.0)), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Rectangle Low_Left\n                            elif self.RB_Low_Rigth.isChecked():\n                                self.Forme = Draft.makeRectangle(length=self.Rectangle_X,height=self.Rectangle_Y,placement=App.Placement(App.Vector(-(self.Rectangle_X),0.0,0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(self.Forme.Placement) # increment Low_Rigth\n                                ##### tube a soustraire Rectangle Low_Rigth\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    XS = self.Rectangle_X-(self.Thickness * 2)\n                                    YS = self.Rectangle_Y-(self.Thickness * 2)\n                                    self.FormeSubtract = Draft.makeRectangle(length=XS,height=YS,placement=App.Placement(App.Vector(-(self.Rectangle_X-self.Thickness),(self.Thickness),(0.0)), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Rectangle Low_Rigth\n                            elif self.RB_Center_Top.isChecked():      # center dessus poutrelle\n                                self.Forme = Draft.makeRectangle(length=self.Rectangle_X,height=self.Rectangle_Y,placement=App.Placement(App.Vector(-(self.Rectangle_X/2.0),-(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(self.Forme.Placement) # increment Top_Left\n                                ##### tube a soustraire Rectangle  center dessus poutrelle\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeRectangle(length=XS,height=YS,placement=App.Placement(App.Vector(-(self.Rectangle_X/2.0)+(self.Thickness),-((self.Rectangle_Y)-self.Thickness),(0.0)), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Rectangle center dessus poutrelle\n                            elif self.RB_Center_Right.isChecked():    # Rectangle Center_Right\n                                self.Forme = Draft.makeRectangle(length=self.Rectangle_X,height=self.Rectangle_Y,placement=App.Placement(App.Vector(-(self.Rectangle_X),-(self.Rectangle_Y/2.0),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(self.Forme.Placement) # increment Top_Rigth\n                                ##### tube a soustraire Rectangle Center_Rigth\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeRectangle(length=XS,height=YS,placement=App.Placement(App.Vector(-(self.Rectangle_X-self.Thickness),-((self.Rectangle_Y/2.0)-self.Thickness),(0.0)), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Rectangle Center_Rigth\n                            elif self.RB_Center_Left.isChecked():     # Rectangle Center Left\n                                self.Forme = Draft.makeRectangle(length=self.Rectangle_X,height=self.Rectangle_Y,placement=App.Placement(App.Vector(0.0,-(self.Rectangle_Y/2.0),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(self.Forme.Placement) # increment Low_Left\n                                ##### tube a soustraire Rectangle Center Left\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeRectangle(length=XS,height=YS,placement=App.Placement(App.Vector((self.Thickness),-(self.Rectangle_Y/2.0)+(self.Thickness),(0.0)), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Rectangle Center Left\n                            elif self.RB_Center_Bottom.isChecked():   # Rectangle Center Bottom\n                                self.Forme = Draft.makeRectangle(length=self.Rectangle_X,height=self.Rectangle_Y,placement=App.Placement(App.Vector(-(self.Rectangle_X/2.0),(0.0),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(self.Forme.Placement) # increment Low_Rigth\n                                ##### tube a soustraire Rectangle Center Bottom\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    XS = self.Rectangle_X-(self.Thickness * 2)\n                                    YS = self.Rectangle_Y-(self.Thickness * 2)\n                                    self.FormeSubtract = Draft.makeRectangle(length=XS,height=YS,placement=App.Placement(App.Vector(-(self.Rectangle_X/2.0) + self.Thickness,(self.Thickness),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Rectangle Center Bottom\n                            self.PB_Del_Last_Line.setText(_fromUtf8(\"Del Rectangle\"))\n        \n                        ##### create Ellipse\n                        elif self.RB_Ellipse.isChecked():\n                            if self.Rectangle_X == 0: self.Rectangle_X = 1.0\n                            if self.Rectangle_Y == 0: self.Rectangle_Y = 1.0\n        \n                            XS = self.Rectangle_X-(self.Thickness )\n                            YS = self.Rectangle_Y-(self.Thickness )\n        \n                            if self.RB_Center.isChecked():\n                                self.Forme = Draft.makeEllipse(self.Rectangle_X,self.Rectangle_Y,placement=pl,face=False,support=None)    \n                                self.Forme.Placement = pl # centrage\n                                ##### tube a soustraire Ellipse centre\n                                if (self.Thickness != 0.0) and ((self.Thickness) < self.Rectangle_X) and ((self.Thickness) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeEllipse(XS,YS,placement=pl,face=False,support=None) \n                                    self.FormeSubtract.Placement.Rotation = App.Rotation(0.0,0.0,0.0)\n                                    self.FormeSubtract.Placement = pl\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Ellipse centre\n                            elif self.RB_Top_Left.isChecked():\n                                self.Forme = Draft.makeEllipse(self.Rectangle_X,self.Rectangle_Y,placement=App.Placement(App.Vector((self.Rectangle_X),-(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(self.Forme.Placement) # increment Top_Left\n                                ##### tube a soustraire Ellipse Top_Left\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeEllipse(XS,YS,placement=App.Placement(App.Vector((self.Rectangle_X),-(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Ellipse Top_Left\n                            elif self.RB_Top_Rigth.isChecked():\n                                self.Forme = Draft.makeEllipse(self.Rectangle_X,self.Rectangle_Y,placement=App.Placement(App.Vector(-(self.Rectangle_X),-(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(self.Forme.Placement) # increment Top_Rigth\n                                ##### tube a soustraire Ellipse Top_Rigth\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeEllipse(XS,YS,placement=App.Placement(App.Vector(-(self.Rectangle_X),-(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Ellipse Top_Rigth\n                            elif self.RB_Low_Left.isChecked():\n                                self.Forme = Draft.makeEllipse(self.Rectangle_X,self.Rectangle_Y,placement=App.Placement(App.Vector((self.Rectangle_X),(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(self.Forme.Placement) # increment Low_Left\n                                ##### tube a soustraire Ellipse Low_Left\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeEllipse(XS,YS,placement=App.Placement(App.Vector((self.Rectangle_X),(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Ellipse Low_Left\n                            elif self.RB_Low_Rigth.isChecked():\n                                self.Forme = Draft.makeEllipse(self.Rectangle_X,self.Rectangle_Y,placement=App.Placement(App.Vector(-(self.Rectangle_X),(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(self.Forme.Placement) # increment Low_Rigth\n                                ##### tube a soustraire Ellipse Low_Rigth\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeEllipse(XS,YS,placement=App.Placement(App.Vector(-(self.Rectangle_X),(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Ellipse Low_Rigth\n                            elif self.RB_Center_Top.isChecked():\n                                self.Forme = Draft.makeEllipse(self.Rectangle_X,self.Rectangle_Y,placement=App.Placement(App.Vector((self.Rectangle_X),-(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(App.Placement(App.Vector(0.0,-(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0,0,0))) # centrage Bord superieur\n                                ##### tube a soustraire Ellipse Top_Center\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeEllipse(XS,YS,placement=App.Placement(App.Vector(0.0,-(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Ellipse Top_Center\n                            elif self.RB_Center_Bottom.isChecked():\n                                self.Forme = Draft.makeEllipse(self.Rectangle_X,self.Rectangle_Y,placement=App.Placement(App.Vector(0.0,0.0,0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(App.Placement(App.Vector(0.0,(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0,0,0))) # centrage Bord superieur\n                                ##### tube a soustraire Ellipse Bas_Center\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeEllipse(XS,YS,placement=App.Placement(App.Vector(0.0,(self.Rectangle_Y),0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Ellipse Bas_Center\n                            elif self.RB_Center_Left.isChecked():\n                                self.Forme = Draft.makeEllipse(self.Rectangle_X,self.Rectangle_Y,placement=App.Placement(App.Vector((self.Rectangle_X),0.0,0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(self.Forme.Placement) # increment Left_Center\n                                ##### tube a soustraire Ellipse Left_Center\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeEllipse(XS,YS,placement=App.Placement(App.Vector((self.Rectangle_X),0.0,0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Ellipse Left_Center\n                            elif self.RB_Center_Right.isChecked():\n                                self.Forme = Draft.makeEllipse(self.Rectangle_X,self.Rectangle_Y,placement=App.Placement(App.Vector(-(self.Rectangle_X),0.0,0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                self.Forme.Placement = pl.multiply(self.Forme.Placement) # increment Rigth_Center\n                                ##### tube a soustraire Ellipse Rigth_Center\n                                if (self.Thickness != 0.0) and ((self.Thickness*2) < self.Rectangle_X) and ((self.Thickness*2) < self.Rectangle_Y):\n                                    self.FormeSubtract = Draft.makeEllipse(XS,YS,placement=App.Placement(App.Vector(-(self.Rectangle_X),0.0,0.0), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)),face=False,support=None)\n                                    self.FormeSubtract.Placement = pl.multiply(self.FormeSubtract.Placement)\n                                else:\n                                    ff = ui\n                                    ff.colorThickness(1)\n                                ##### tube a soustraire Ellipse Rigth_Center\n                            self.PB_Del_Last_Line.setText(_fromUtf8(\"Del Ellipse\"))\n\n                        ##### create Circle\n                        elif self.RB_Circle.isChecked():\n                            if self.Circle_Radius == 0: self.Circle_Radius = 1.0\n                            self.Forme = Draft.makeCircle(radius=self.Circle_Radius,placement=pl,face=False,support=None)\n                            self.Forme.Placement = pl\n                            ##### tube a soustraire Circle\n                            if (self.Thickness != 0.0) and (self.Thickness < self.Circle_Radius):\n                                self.Circle_Radius_Sbs = self.Circle_Radius - (self.Thickness)\n                                self.FormeSubtract = Draft.makeCircle(radius=self.Circle_Radius_Sbs,placement=pl,face=False,support=None)\n                                self.FormeSubtract.Placement = pl\n                            else:\n                                ff = ui\n                                ff.colorThickness(1)\n                            ##### tube a soustraire Circle\n                            self.PB_Del_Last_Line.setText(_fromUtf8(\"Del Circle\"))\n                            \n                        ##### create sweep self.Forme externe to line \n                        self.sweepForme = App.ActiveDocument.addObject('Part::Sweep','Sweep_Externe_')\n                        self.sweepForme.Sections=[App.ActiveDocument.getObject(self.Forme.Name), ]\n                        self.sweepForme.Spine=(App.ActiveDocument.getObject(self.ligne.Name))\n                        if (self.CB_Solid.isChecked()) or (self.Thickness != 0.0):\n                            self.sweepForme.Solid=True\n                        else:\n                            self.sweepForme.Solid=False\n                        self.sweepForme.Frenet=True\n        \n                        ##### create sweep self.FormeSubtract interne to line \n                        if self.Thickness != 0.0:\n                            self.sweepFormeS = App.ActiveDocument.addObject('Part::Sweep','Sweep_Substract_')\n                            self.sweepFormeS.Sections=[App.ActiveDocument.getObject(self.FormeSubtract.Name), ]\n                            self.sweepFormeS.Spine=(App.ActiveDocument.getObject(self.ligne.Name))\n                            self.sweepFormeS.Solid=True\n        \n                        ##### Contener\n                        self.FcSweep = App.ActiveDocument.addObject(\"App::DocumentObjectGroup\",\"FcSweep\")    \n                        self.FcSweep.addObject(self.sweepForme)\n                        self.FcSweep.addObject(self.ligne)\n                        self.FcSweep.addObject(self.Forme)\n        \n                        ##### tube soustraction\n                        if self.Thickness != 0.0:\n                            ### cut object\n                            self.cutFcSweep = App.activeDocument().addObject(\"Part::Cut\",\"Pipe\")\n                            self.cutFcSweep.Base = self.sweepForme\n                            self.cutFcSweep.Tool = self.sweepFormeS\n                            self.cutFcSweep.Label = \"Pipe\"\n        \n                            self.FcSweep.addObject(self.sweepFormeS)  # Contener\n                            self.FcSweep.addObject(self.FormeSubtract)# Contener\n                            self.FcSweep.addObject(self.cutFcSweep)   # Contener\n                            App.ActiveDocument.recompute()\n                        ##### tube soustraction\n        \n                        ##### renamme ObjectGroup\n                        if self.RB_Line.isChecked():\n                            None\n                        else:\n                            if self.RB_Polyline.isChecked():\n                                if self.CB_Insc_Circon.isChecked():\n                                    self.FcSweep.Label = \"Polyline_r_=_\" + str(self.Polyline_CirCon) + \"_F_=_\" + str(self.Polyline_Number_Faces)+ \"_I\"\n                                    if (self.Thickness != 0.0):\n                                        self.FcSweep.Label = \"Pipe_Polyline_r_=_\" + str(self.Polyline_CirCon) + \"_F_=_\" + str(self.Polyline_Number_Faces) + \"_Th_=_\"  + str(self.Thickness) + \"_I\"\n                                else:\n                                    self.FcSweep.Label = \"Polyline_r_=_\" + str(self.Polyline_CirCon) + \"_F_=_\" + str(self.Polyline_Number_Faces)+ \"_C\"\n                                    if (self.Thickness != 0.0):\n                                        self.FcSweep.Label = \"Pipe_Polyline_r_=_\" + str(self.Polyline_CirCon) + \"_F_=_\" + str(self.Polyline_Number_Faces) + \"_Th_=_\"  + str(self.Thickness) + \"_C\"\n        \n                            elif self.RB_Rectangle.isChecked():\n                                self.FcSweep.Label = \"Rectangle_X_=_\" + str(self.Rectangle_X) + \"_Y_=_\" + str(self.Rectangle_Y)\n                                if (self.Thickness != 0.0):\n                                    self.FcSweep.Label = \"Pipe_Rectangle_X_=_\" + str(self.Rectangle_X) + \"_Y_=_\" + str(self.Rectangle_Y) + \"_Th_=_\"  + str(self.Thickness)\n                                    None\n                            elif self.RB_Ellipse.isChecked():\n                                self.FcSweep.Label = \"Ellipse_X_=_\" + str(self.Rectangle_X) + \"_Y_=_\" + str(self.Rectangle_Y)\n                                if (self.Thickness != 0.0):\n                                    self.FcSweep.Label = \"Pipe_Ellipse_X_=_\" + str(self.Rectangle_X) + \"_Y_=_\" + str(self.Rectangle_Y) + \"_Th_=_\"  + str(self.Thickness)\n                                    None\n                            elif self.RB_Circle.isChecked():\n                                self.FcSweep.Label = \"Circle_r_=_\" + str(self.Circle_Radius)\n                                if (self.Thickness != 0.0):\n                                    self.FcSweep.Label = \"Pipe_Circle_r_=_\" + str(self.Circle_Radius) + \"_Th_=_\" + str(self.Thickness)\n        \n                        ##### renamme sweep\n                        self.ligne.Label = \"Line_Master_\" + self.ligne.Name\n                        self.Forme.Label = \"Forme_\" + self.Forme.Name\n        \n                        FreeCADGui.ActiveDocument.getObject(self.ligne.Name).Visibility = False\n                        FreeCADGui.ActiveDocument.getObject(self.Forme.Name).Visibility = False\n                        \n                        if (self.Thickness != 0.0):\n                            self.FormeSubtract.Label = \"Subtract_\" + self.FormeSubtract.Name\n                            FreeCADGui.ActiveDocument.getObject(self.FormeSubtract.Name).Visibility = False\n                            App.Console.PrintMessage(\"Thickness             : \" + str(self.Thickness) + \"\\n\")# Thickness\n                            self.label_Info.setText(_fromUtf8(\"Thickness : \" + str(self.Thickness)))\n    \n                        App.ActiveDocument.recompute()\n        \n                        App.Console.PrintMessage(\"_______________________\" + \"\\n\")#\n    \n                        ##### section camera origin view restitute\n                        FreeCADGui.ActiveDocument.ActiveView.setCameraOrientation(OriginOrientation)\n                    \n                    if   self.RB_Polyline.isChecked():\n                        self.PB_Del_Last_Line.setText(_fromUtf8(\"Delete last Polyline\"))\n                    elif self.RB_Rectangle.isChecked():\n                        self.PB_Del_Last_Line.setText(_fromUtf8(\"Delete last Rectangle\"))\n                    elif self.RB_Ellipse.isChecked():\n                        self.PB_Del_Last_Line.setText(_fromUtf8(\"Delete last Ellipse\"))\n                    elif self.RB_Circle.isChecked():\n                        self.PB_Del_Last_Line.setText(_fromUtf8(\"Delete last Circle\"))\n                    elif self.RB_Line.isChecked():\n                        self.PB_Del_Last_Line.setText(_fromUtf8(\"Delete last Line\"))\n\n                except Exception:\n                    App.Console.PrintError(\" Error Selection !!\" + \"\\n\")\n                    self.label_Info.setText(_fromUtf8(\" Error Selection !!\"))\n                    self.label_Info.setStyleSheet(\"QLabel {color : #ffffff; background-color : #FF3300;}\")\n\n            else:\n                App.Console.PrintError(\"Select two objects (\"+str(len(Gui.Selection.getSelection()))+\" object(s) selected)\"+\"\\n\")\n                App.Console.PrintError(\"or straight line, edge and mode 3:SObj. + SObj.\"+\"\\n\")\n                App.Console.PrintError(\"_______________________________________________\"+\"\\n\")\n                self.label_Info.setText(_fromUtf8(\"Select one or two objects (\"+str(len(Gui.Selection.getSelection()))+\" object(s) selected)\"))\n                self.label_Info.setStyleSheet(\"QLabel {color : #ffffff; background-color : #FF3300;}\")\n\n        except Exception:\n            App.Console.PrintError(\" Error Selection !!!\" + \"\\n\")\n            self.label_Info.setText(_fromUtf8(\" Error Selection !!!\"))\n            self.label_Info.setStyleSheet(\"QLabel {color : #ffffff; background-color : #FF3300;}\")\n\n#####################################\nFreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"Version\",__version__ + \" (\" + __date__ + \")\")# \n\nMainWindow = QtWidgets.QMainWindow()\nMainWindow.setObjectName(\"__title__\")          # macro internal Name\nui = Ui_MainWindow()\nui.setupUi(MainWindow)\nMainWindow.show()\n\n",
    "url": "https://wiki.freecad.org/Macro_Connect_And_Sweep",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/3ec67a3711202dab69592ce53b938924/raw/984cd58c1d64dd391062025cfa82a698c7268e66/Macro_Connect_And_Sweep.FCMacro",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_Connect_And_Sweep",
    "version": "00.13",
    "license": "",
    "date": "2024/07/21",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Connect_And_Sweep.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/c/c9/Macro_Connect_And_Sweep.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Express Placement",
    "on_wiki": true,
    "on_git": false,
    "desc": "Display and quickly edit a selected object's placement coordinates directly or via expressions.<br /><br />Macro version: 1.0<br />Last modified: 2023-08-01<br />FreeCAD version: Created and tested in 0.21<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://raw.githubusercontent.com/screeneroner/fc-express-placement/master/fc-express-placement.FCMacro\">Express Placement</a><br />Author: screeneroner<br /> ",
    "comment": "FreeCAD GUI addon that allow quick editing X,Y,Z coordinates of the selected object",
    "code": "# -*- coding: utf-8 -*-\n__Name__ = \"Express Placement\"\n__Comment__ = \"FreeCAD GUI addon that allow quick editing X,Y,Z coordinates of the selected object\"\n__Author__ = \"screeneroner\"\n__Version__ = \"1.0\"\n__Date__ = \"2023-08-01\"\n__License__ = \"GPL-3.0\"\n__Web__ = \"https://wiki.freecad.org/Macro_Express_Placement\"\n__Wiki__ = \"https://wiki.freecad.org/Macro_Express_Placement\"\n__Icon__ = \"https://wiki.freecad.org/images/8/8f/Std_AxisCross_example.svg\"\n__Help__ = \"Display and quickly edit selected object placement coordinates directly or via expressions\"\n__Status__ = \"Working\"\n__Requires__ = \"FreeCAD >= 0.19\"\n__Communication__ = \"https://forum.freecad.org/memberlist.php?mode=viewprofile&u=60629\"\n#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n\n''' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThis macro is free software: you can redistribute it and/or modify it under the terms of the  \nversion 3 GNU General Public License as published by the Free Software Foundation. \n \nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY without even  \nthe implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \nSee the GNU General Public License for more details (https://www.gnu.org/licenses/gpl-3.0.html) \n \nWARNING TO USERS AND MODIFIERS \n \nThis script contains \"Buy me a coffee\" links to honor the author's hard work and dedication in creating \nall the features present in this code. Removing or altering these links not only violates the GPL license \nbut also disregards the significant effort put into making this script valuable for the community. \n \nIf you find value in this script and would like to show appreciation to the author, \nkindly consider visiting the site below and treating the author to a few cups of coffee: \n                           https://www.buymeacoffee.com/screeneroner \nYour honor and gratitude is greatly appreciated.\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ''' \n\n\nimport FreeCADGui as Gui\nimport FreeCAD as App\nfrom PySide import QtGui, QtCore\n\n# Define a function to create and display a table\ndef create_table():\n    # Function to update the table with the selected object's data\n    def update_table_with_selected_object():\n        # Clear the table first\n        clear_table()\n\n        # Get the selected objects\n        selection = Gui.Selection.getSelection()\n        # If there's exactly one selected object\n        if len(selection) == 1:\n            selected_obj = selection[0]\n            selected_object = selected_obj\n            # Ensure the object isn't a spreadsheet\n            if str(selected_obj.TypeId) != \"Spreadsheet::Sheet\":\n                # Populate the table with the object's placement data\n                populate_table_with_placement(selected_obj)\n                # Store the selected object on the table widget\n                table_widget.selected_object = selected_obj\n\n    # Function to populate the table with an object's placement data\n    def populate_table_with_placement(selected_obj):\n        # Clear the table first\n        clear_table()\n    \n        # Get the object's placement\n        placement = selected_obj.Placement\n        # Update each row of the table with the object's placement data\n        for row in range(3):  # Limit to 3 instead of row_count\n            value_widget = QtGui.QTableWidgetItem()\n            value_widget.setText(str(getattr(placement.Base, [\"x\", \"y\", \"z\"][row])))\n            table_widget.setItem(row, 0, value_widget)\n    \n        # Get the object's properties\n        properties_list = selected_obj.ExpressionEngine\n        # If the object has properties\n        if properties_list is not None:\n            # For each property that involves placement\n            for prop in properties_list:\n                if prop[0] in [\".Placement.Base.x\", \".Placement.Base.y\", \".Placement.Base.z\"]:\n                    # Get the attribute's name\n                    attribute = prop[0].split(\".\")[-1]\n                    # Set the corresponding cell's value\n                    expression_label = QtGui.QTableWidgetItem()\n                    expression_label.setText(prop[1])\n                    table_widget.setItem([\"x\", \"y\", \"z\"].index(attribute), 1, expression_label)\n    \n        # Add the new row with the support data\n        support_label_widget = QtGui.QLabel(\" \")\n        support_link_widget = QtGui.QLabel( u'\\u2615' + '  <a href=\"https://www.buymeacoffee.com/screeneroner\">Buy me a coffee</a>  ')\n        support_link_widget.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)\n        support_link_widget.setTextFormat(QtCore.Qt.RichText)\n        support_link_widget.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)\n        support_link_widget.setOpenExternalLinks(True)\n                \n        table_widget.setCellWidget(3, 0, support_label_widget)\n        table_widget.setCellWidget(3, 1, support_link_widget)\n    \n        # Adjust the height of each row\n        header = table_widget.horizontalHeader()\n        header.setFixedHeight(24)  \n        for row in range(row_count):\n            table_widget.setRowHeight(row, 18)\n\n\n\n    # Function to clear the table\n    def clear_table():\n        for row in range(row_count):\n            for col in range(column_count):\n                table_widget.takeItem(row, col)\n\n    # Function to update the selected object's placement values based on edits to the table\n    def update_values(row):\n        item = table_widget.item(row, 0)\n        if item is not None:\n            # Get the edited text\n            edited_text = item.text()\n            # Get the label of the value that was edited\n            value_label = [\"x\", \"y\", \"z\"][row]\n            # Get the selected object\n            selected_obj = table_widget.selected_object\n            # Get the object's placement\n            placement = selected_obj.Placement\n\n            # If the edited text is not empty\n            if edited_text != \"\":\n                try:\n                    # Try to convert the edited text to a float\n                    edited_value = float(edited_text)\n                    # Update the corresponding placement value\n                    if value_label == \"x\":\n                        placement.Base.x = edited_value\n                    elif value_label == \"y\":\n                        placement.Base.y = edited_value\n                    elif value_label == \"z\":\n                        placement.Base.z = edited_value\n                except ValueError:\n                    # If the text can't be converted to a float, print an error message\n                    print(\"Invalid value entered. The value must be a valid number.\")\n\n                # Update the object's placement\n                selected_obj.Placement = placement\n\n                # Recompute the document to reflect the changes\n                App.ActiveDocument.recompute()\n                # print(f\"Updated value: {edited_value} in row {row}, column 0\")\n\n                # Reselect the object to refresh the table data\n                reselect_object(selected_obj)\n\n    # Function to update the selected object's expression values based on edits to the table\n    def update_expression(row):\n        item = table_widget.item(row, 1)\n        if item is not None:\n            # Get the edited text\n            edited_text = item.text()\n            # Get the label of the expression that was edited\n            expression_label = [\"x\", \"y\", \"z\"][row]\n            # Get the selected object\n            selected_obj = table_widget.selected_object\n            # Get the attribute's name\n            attribute = f\".Placement.Base.{expression_label}\"\n\n            # Update the attribute's expression\n            selected_obj.setExpression(attribute, edited_text if edited_text != \"\" else None)\n\n            # Recompute the document to reflect the changes\n            App.ActiveDocument.recompute()\n            # print(f\"Updated expression: {edited_text} in row {row}, column 1\")\n\n            # Reselect the object to refresh the table data\n            reselect_object(selected_obj)\n\n    # Function to reselect an object\n    def reselect_object(selected_obj):\n        # Clear the current selection\n        Gui.Selection.clearSelection()\n        # Add the selected object to the selection\n        Gui.Selection.addSelection(selected_obj)\n\n    # Define the table's dimensions\n    row_count = 4\n    column_count = 2\n\n    # Create the table widget\n    table_widget = QtGui.QTableWidget(row_count, column_count)\n    table_widget.setHorizontalHeaderLabels([\"Value\", \"Expression\"])\n    table_widget.setVerticalHeaderLabels([\"x\", \"y\", \"z\", \" \"])\n\n    # Left align the headers\n    header = table_widget.horizontalHeader()\n    header.setDefaultAlignment(QtCore.Qt.AlignLeft)\n\n    # Adjust columns to contents\n    table_widget.setSizeAdjustPolicy(QtGui.QAbstractScrollArea.AdjustToContents)\n    table_widget.resizeColumnsToContents()\n    table_widget.resizeRowsToContents()\n\n    table_widget.setShowGrid(False)\n\n    # Assign a delegate to handle cell edits\n    delegate = QtGui.QItemDelegate()\n    table_widget.setItemDelegate(delegate)\n\n    # Connect signals to handle cell edits\n    delegate.commitData.connect(lambda: update_values(table_widget.currentRow()) if table_widget.currentColumn() == 0 else None)\n    delegate.closeEditor.connect(\n        lambda: update_expression(table_widget.currentRow()) if table_widget.currentColumn() == 1 else None\n    )\n\n    # Define a class to observe selection changes\n    class SelectionObserver:\n        # When an object is selected, update the table\n        def addSelection(self, doc, obj, sub, pnt):\n            update_table_with_selected_object()\n\n        # When an object is deselected, update the table\n        def removeSelection(self, doc, obj, sub):\n            update_table_with_selected_object()\n\n    # Create an instance of the observer class\n    selection_observer = SelectionObserver()\n    # Add the observer to the selection\n    Gui.Selection.addObserver(selection_observer)\n\n    # Update the table with the currently selected object's data\n    update_table_with_selected_object()\n\n    # Make the last column stretch to fill the remaining space\n    table_widget.horizontalHeader().setStretchLastSection(True)\n\n    # Get the main window\n    mainWindow = Gui.getMainWindow()\n\n    # Check if the dock widget already exists\n    dock_widget = mainWindow.findChild(QtGui.QDockWidget, \"ExpressPlacementWidget\")\n\n    # If the dock widget does not exist, create it\n    if dock_widget is None:\n        dock_widget = QtGui.QDockWidget(\"Express Placement\")\n        dock_widget.setObjectName(\"ExpressPlacementWidget\")  # Assign an object name to the dock widget\n        mainWindow.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dock_widget)\n\n    # Set the dock widget's widget to the table\n    dock_widget.setWidget(table_widget)\n    # Make sure the dock widget is visible\n    dock_widget.setVisible(True)\n\n# Create and display the table\ncreate_table()\n",
    "url": "https://wiki.freecad.org/Macro_Express_Placement",
    "raw_code_url": "",
    "wiki": "https://wiki.freecad.org/Macro_Express_Placement",
    "version": "1.0",
    "license": "",
    "date": "2023-08-01",
    "src_filename": "",
    "filename_from_url": "",
    "author": "screeneroner",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Std_AxisCross_example.svg",
    "icon_source": "https://wiki.freecad.org/images/8/8f/Std_AxisCross_example.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FlattenWire",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro flattens draft wires that are not planar to their median Z coordinate<br /><br />Macro version: 1.1<br />Last modified: 2021-10-27<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/2/2f/Macro_FlattenWire.png\">ToolBar Icon</a><br />Author: Yorik<br /> ",
    "comment": "This macro flattens draft wires that are not planar to their median Z coordinate",
    "code": "import FreeCAD\nobj = FreeCAD.ActiveDocument.ActiveObject\nz = 0\nfor p in obj.Points: z += p.z\nz = z/len(obj.Points)\nnewpoints = []\nfor p in obj.Points: newpoints.append(FreeCAD.Vector(p.x, p.y, z))\nobj.Points = newpoints",
    "url": "https://wiki.freecad.org/Macro_FlattenWire",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2021-10-27",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Yorik",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_FlattenWire.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/2/2f/Macro_FlattenWire.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FlattenWire3Points",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro flattens draft wires that are not planar on a plane defined by 3 points.<br /> To use this macro, select first 3 vertices from a single Draft Wire.<br /><br />Macro version: 1.0<br />Last modified: 2016-02-06<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/1/1e/Macro_FlattenWire3Points.png\">ToolBar Icon</a><br />Author: Yorik<br /> ",
    "comment": "This macro flattens draft wires that are not planar on a plane defined by 3 points.",
    "code": "import FreeCAD,FreeCADGui,Draft\n \n # check selection\n sel = FreeCADGui.Selection.getSelectionEx()\n ok = True\n if len(sel) != 1:\n    FreeCAD.Console.PrintError(\"Please select 3 vertices from one Draft wire\\n\")\n    ok = False\n sel = sel[0]\n if Draft.getType(sel.Object) not in [\"Wire\",\"BSpline\"]:\n    FreeCAD.Console.PrintError(\"Please select 3 vertices from one Draft wire\\n\")\n    ok = False\n if len(sel.SubElementNames) != 3:\n    FreeCAD.Console.PrintError(\"Please select 3 vertices from one Draft wire\\n\")\n    ok = False\n for e in sel.SubElementNames:\n    if not \"Vertex\" in e:\n        FreeCAD.Console.PrintError(\"Please select 3 vertices from one Draft wire\\n\")\n        ok = False\n \n if ok:\n    # define a plane\n    p1 = getattr(sel.Object.Shape,sel.SubElementNames[0]).Point\n    p2 = getattr(sel.Object.Shape,sel.SubElementNames[1]).Point\n    p3 = getattr(sel.Object.Shape,sel.SubElementNames[2]).Point\n    p4 = p2.sub(p1).cross(p3.sub(p1))\n    \n    # project wire points\n    points = []\n    for p in sel.Object.Points:\n        points.append(p.projectToPlane(p1,p4))\n    sel.Object.Points = points",
    "url": "https://wiki.freecad.org/Macro_FlattenWire3Points",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2016-02-06",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Yorik",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_FlattenWire3Points.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/1/1e/Macro_FlattenWire3Points.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "HealArcs",
    "on_wiki": true,
    "on_git": false,
    "desc": "Sometimes arcs are transformed into BSplines, for example when scale operations have been applied to them. This macro recreates valid arcs from them. Useful before exporting to dxf. Useful before exporting to dxf.<br /><br />Macro version: 0.1<br />Last modified: 2011-09-24<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/5/5a/Macro_HealArcs.png\">ToolBar Icon</a><br />Author: Yorik<br /> ",
    "comment": "Sometimes arcs are transformed into BSplines, for example when scale operations have been applied to them. This macro recreates valid arcs from them. Useful before exporting to dxf. Useful before exporting to dxf.",
    "code": "try:\n    import DraftGeomUtils as fcgeo\nexcept:\n    from draftlibs import fcgeo\nimport FreeCAD,FreeCADGui,Part\n\nsel = FreeCADGui.Selection.getSelection()\nif not sel:\n    FreeCAD.Console.PrintWarning(\"Select something first!\")\nelse:\n    removeList = []\n    for obj in sel:\n        ed = obj.Shape.Edges[0]\n        arc = fcgeo.arcFromSpline(ed)\n        if arc:\n            Part.show(arc)\n            removeList.append(obj.Name)\n    FreeCAD.ActiveDocument.recompute()\n    print(\"removing\", removeList)\n    for n in removeList:\n        FreeCAD.ActiveDocument.removeObject(n)",
    "url": "https://wiki.freecad.org/Macro_HealArcs",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2011-09-24",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Yorik",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_HealArcs.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/5/5a/Macro_HealArcs.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "JointWire",
    "on_wiki": true,
    "on_git": false,
    "desc": "<span style=\"background-color: #ff0000\">!!! This macro needs to be corrected.&#160;!!!</span><br />This macro allow to find and joint all non connected edge to the closest non connected one using a line. It take a shape matrix in entry ([shape1, shape2, ...])<br /><br />Macro version: 1.0<br />Last modified: 2011-08-24<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/b/bb/Macro_JointWire.png\">ToolBar Icon</a><br />Author: Tremblou<br /> ",
    "comment": "!!! This macro needs to be corrected.&#160;!!!",
    "code": "def findWires(edges):\n    def verts(shape):\n                return [shape.Vertexes[0].Point,shape.Vertexes[-1].Point]\n        def group(shapes):\n                shapesIn = shapes[:]\n                pointTst = []\n        pointOut =[]\n        for s in shapesIn :\n            pointTst=pointTst+[s.Vertexes[0].Point]\n            pointTst=pointTst+[s.Vertexes[-1].Point]\n        print pointTst               \n        changed = False\n                for s in shapesIn:\n                        if len(s.Vertexes) < 2:\n                print \"one vertex, its a circle, just add\"\n                        else:                             \n                                for v in verts(s):\n                    twoDot=0\n                                        for vv in pointTst:\n                                                if v == vv:\n                            twoDot=twoDot+1                           \n                        if v==vv and twoDot==2 :                   \n                            changed = True\n                            print \"found matching vert\"\n                            break\n                                    if twoDot<2:\n                        print \"didn't find any matching vert...\"\n                        pointOut.append(v)\n         print \"Dots non connected\", pointOut\n                return(changed,pointOut)\n    def joint(point):\n        for p in range(len(point)/2) :\n            print point\n            deltI=Part.Vertex(100,100,100).Point\n            pos=1\n            for pp in range(len(point)-1) :\n                print \"position:\",pp+1\n                if len(point)-1>1:\n                    deltN=(point[0]-point[pp+1])\n                    if deltN.Length<deltI.Length:\n                        deltI=deltN\n                        pos=pp+1\n                        print \"changement\",pos\n                else:\n                    pos=1   \n            print \"points a joindre\",point[0],point[pos]\n            if point[0]!=point[pos]:\n                Part.show(Part.makePolygon([point[0],point[pos]]))\n            else:\n                print \"WARNING les points ont la meme valeurs \"\n            point.pop(0)\n            point.pop(pos-1)\n        point=0 #to have a return normally void\n        return(point)\n    working = True\n        edgeSet = edges\n    result = group(edgeSet)\n        working = result[0]\n        edgeSet = result[1]\n    joint(result[1])\n        return result[1]",
    "url": "https://wiki.freecad.org/Macro_JointWire",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2011-08-24",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Tremblou",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_JointWire.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/b/bb/Macro_JointWire.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "MatrixTransform",
    "on_wiki": true,
    "on_git": false,
    "desc": "Applies linear transformation to a shape, defined by a 3x3 matrix. It is possible to: apply non-linear scaling to a shape, shear a shape, rotate a shape.<br /><span style=\"background-color:#ff0000; color:#ffff00;\">This macro is composed of 2 macro: <b>MatrixTransform.FCMacro</b> (launcher) and <b>MatrixTransform.py</b> (executor).</span><br />The <b>.FCMacro</b> is installed with AddonManager you must install the <b>.py</b> macro manually.<br />Link of th two macros:<br /><a rel=\"nofollow\" class=\"external text\" href=\"https://github.com/DeepSOIC/FreeCAD-Macros/raw/master/MatrixTransform/MatrixTransform.FCMacro\">MatrixTransform.FCMacro</a> (launcher)<br /><a rel=\"nofollow\" class=\"external text\" href=\"https://github.com/DeepSOIC/FreeCAD-Macros/raw/master/MatrixTransform/MatrixTransform.py\">MatrixTransform.py</a> (executor)<br /><br />Macro version: 1.1<br />Last modified: 2024-12-09<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/d/db/Macro_MatrixTransform.png\">ToolBar Icon</a><br />Author: DeepSOIC<br /> ",
    "comment": "Applies linear transformation to a shape, defined by a 3x3 matrix. It is possible to: apply non-linear scaling to a shape, shear a shape, rotate a shape.",
    "code": "#***************************************************************************\n#*                                                                         *\n#*   Copyright (c) 2015 - Victor Titov (DeepSOIC)                          *\n#*                                               <vv.titov@gmail.com>      *  \n#*                                                                         *\n#*   This program is free software; you can redistribute it and/or modify  *\n#*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n#*   as published by the Free Software Foundation; either version 2 of     *\n#*   the License, or (at your option) any later version.                   *\n#*   for detail see the LICENCE text file.                                 *\n#*                                                                         *\n#*   This program is distributed in the hope that it will be useful,       *\n#*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n#*   GNU Library General Public License for more details.                  *\n#*                                                                         *\n#*   You should have received a copy of the GNU Library General Public     *\n#*   License along with this program; if not, write to the Free Software   *\n#*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n#*   USA                                                                   *\n#*                                                                         *\n#***************************************************************************\n\n__title__=\"Macro MatrixTransform\"\n__author__ = \"DeepSOIC\"\n__doc__ = '''\nMacro MatrixTransform.\nDistorts geometry according to vector transformation defined by the matrix.\n\nMatrix is defined by three vectors:\n       v1x   v2x   v3x                  \nM = (  v1y   v2y   v3y )                  \n       v1z   v2z   v3z                  \nHere, v1,v2,v3 are vectors that can be defined in properties. They correspond\nto new directions of what was originally X,Y,Z axes.\n\nexmaple matrices:\n\nNo transformation:\n1  0  0\n0  1  0\n0  0  1\n\nnon-uniform scaling:\nscaleX    0      0\n   0   scaleY    0\n   0      0   scaleZ\n\nshearing (operation that makes regular text into italic; assuming text is in XY\nplane):\n1  shear  0\n0    1    0\n0    0    1\n('shear' coefficient defines the amount of shearing. 0 is no shearing. 1 makes\nthe text italic by 45 degrees. -1 shears in backslash-like fashion.)\n\n\nInstruciotns:\nSelect the object to be sheared, then run the macro. A new object will be\ncreated, with shear matrix filled in by default. Edit values of v1, v2, v3 to\nchange the behavior.\n\nWarning. All geometry is converted to B-splines, even if it doesn't have to.\nThis can cause all sorts of trouble. Use only if absolutely necessary.\n'''\n\nimport MatrixTransform\nMatrixTransform.run()\n",
    "url": "https://wiki.freecad.org/Macro_MatrixTransform",
    "raw_code_url": "https://raw.githubusercontent.com/DeepSOIC/FreeCAD-Macros/master/MatrixTransform/MatrixTransform.FCMacro",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2024-12-09",
    "src_filename": "",
    "filename_from_url": "",
    "author": "DeepSOIC",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_MatrixTransform.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/d/db/Macro_MatrixTransform.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "MoveToOrigin",
    "on_wiki": true,
    "on_git": false,
    "desc": "Moves the selected location of an object to the Origin.<br /> This macro translates the <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/Placement\">Placement</a> of an object so that a selected location becomes its new origin. This may be useful when imported objects from other formats like STL or STEP are inconveniently located for further processing by FreeCAD.<br /><br />Macro version: 00.02<br />Last modified: 2021-07-07<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/File:Centericon.png\">ToolBar Icon</a><br />Author: Edwilliams16<br /> ",
    "comment": "Moves the selected location of an object to the Origin.",
    "code": "__Title__    = \"MoveToOrigin\"\n__Author__   = \"edwilliams16\"\n__Version__  = \"00.02\"\n__Date__     = \"2021.7.7\"\ndebug = False\n'''Usage:\nThis macro will adjust the placement of a shape to place a selected feature at the origin.\nOne vertex:  - to origin\nOne line segment - midpoint to origin\nOne circle - center to origin\nOne arc of circle - center to origin\nOne face - CG of face to origin\nThree vertices - center of circle through vertices to origin\nShape - CG of shape to origin\n\nIf the shape is a BaseFeature inside a body, the base feature's placement in the body is adjusted.\n'''\n# Version 0.01  Original\n# Version 0.02 - now handles objects in nested part containers\n\ndef circumcenter(A, B, C):\n    '''Return the circumcenter of three 3D vertices'''\n    a2 = (B - C).Length**2\n    b2 = (C - A).Length**2\n    c2 = (A - B).Length**2\n    if a2 * b2 * c2 == 0.0:\n        print('Three vertices must be distinct')\n        return\n    alpha = a2 * (b2 + c2 - a2)\n    beta = b2 * (c2 + a2 - b2)\n    gamma = c2 * (a2 + b2 - c2)\n    return (alpha*A + beta * B + gamma * C)/(alpha + beta + gamma)\n\ndef centerofmass(subshapes):\n    mass =0.0\n    moment = App.Vector(0, 0, 0)\n    for sh in subshapes:\n        mass += sh.Volume\n        moment += sh.Volume * sh.CenterOfMass\n    return moment/mass  \n\ndef globalCG(obj, removeLocalOffset=True):\n    '''Find COM of object in global coordinates\n      remove local offset per https://forum.freecadweb.org/viewtopic.php?t=27821'''\n    gpl = obj.getGlobalPlacement()\n    pl = obj.Placement\n    rpl= gpl.multiply(pl.inverse())\n    if removeLocalOffset:\n        return rpl.multVec(obj.Shape.CenterOfMass)\n    else:\n        return gpl.multVec(obj.Shape.CenterOfMass)\n\n\n\ndef globalGCGHierarchy(obj):\n    ''' Compute global COM of an object hierarchy'''\n    volume= 0\n    moment = App.Vector(0., 0., 0.)\n    def wrappedGCG(obj): \n        nonlocal volume, moment\n        if hasattr(obj, 'Shape'):\n            shape = obj.Shape\n            if hasattr(shape, 'CenterOfMass'):\n                print(f'{obj.Name}  {vectorRound(globalCG(obj, True), nDec)}')\n                volume += shape.Volume\n                moment += globalCG(obj, True).multiply(shape.Volume)\n            else:\n                for obj1 in obj.OutList:\n                    if hasattr(obj1, 'Shape'):\n                        wrappedGCG(obj1)\n    wrappedGCG(obj)\n    return (volume, moment)\n\ndef vectorRound(v, n):\n    '''Round the output of App.Vector v to n dec places'''\n    return App.Vector(round(v.x, n), round(v.y, n), round(v.z, n))\n  \nisGlobal = False\nnDec = 3\nselt = Gui.Selection.getSelectionEx()\nif len(selt) != 1:\n    print('Select one vertex, edge or object\\nor three vertices for center of circle')\n    shift = App.Vector(0, 0, 0)  # bail and do nothing  \nelse:\n    sel = selt[0]\n    if sel.HasSubObjects:\n        vv = sel.SubObjects\n        if len(vv) ==3 and vv[0].ShapeType == 'Vertex' and   vv[1].ShapeType == 'Vertex' and vv[2].ShapeType == 'Vertex':\n            shift = circumcenter(vv[0].Point, vv[1].Point, vv[2].Point)\n            if debug: print('Three Vertices')\n        elif len(vv) == 1: \n            selected = sel.SubObjects[0]\n            if selected.ShapeType == 'Vertex':\n                shift = selected.Point\n                if debug: print('One vertex')\n            elif selected.ShapeType == 'Edge':\n                if selected.Curve.TypeId == 'Part::GeomCircle':    #circles and arcs\n                     shift = selected.Curve.Center\n                     if debug: print('One arc')      \n                elif selected.Curve.TypeId == 'Part::GeomLine':\n                    shift = (selected.valueAt(selected.FirstParameter) + selected.valueAt(selected.LastParameter))/2 # mid-point\n                    if debug: print('One line')\n                else:\n                    print(f'edge is {selected.Curve.TypeId} not handled')\n                    shift = App.Vector(0, 0, 0)  # bail and do nothing\n            elif selected.ShapeType == 'Face':\n                shift = selected.CenterOfMass #center of face\n                if debug: print('One face')\n            else:\n                print(f'ShapeType {selected.ShapeType} not handled')\n                shift = App.Vector(0, 0, 0)  # bail and do nothing\n        else:\n            print('Wrong number of Selections')\n            shift = App.Vector(0, 0, 0)  # bail and do nothing\n    else:\n        if debug: print(f'ObjectName is {sel.ObjectName}')\n        #if sel.ObjectName[0:11] == 'BaseFeature':\n        if hasattr(sel.Object, 'Shape'):\n            if debug: print('One solid')\n            shape = sel.Object.Shape\n            if shape.ShapeType == 'Solid' or shape.ShapeType == 'Shell':\n                shift = shape.CenterOfMass\n            elif shape.ShapeType == 'Compound' or shape.ShapeType == 'CompSolid':\n                #shift = centerofmass(shape.SubShapes)\n                vol, mom = globalGCGHierarchy(sel.Object)\n                shift = mom.multiply(1./vol)  # global!\n                isGlobal = True\n            #more cases?\n            else:\n                print(f'Object ShapeType {sel.Object.Shape.ShapeType} not handled')\n                shift = App.Vector(0, 0, 0)  # bail and do nothing                \n        else:\n            print(f'{sel.ObjectName} is not a shape')\n            shift = App.Vector(0, 0, 0)  # bail and do nothing\n            \n\n\npl = App.ActiveDocument.getObject(sel.ObjectName).Placement\ngpl = App.ActiveDocument.getObject(sel.ObjectName).getGlobalPlacement()\ngplr = gpl.multiply(pl.inverse())\nif isGlobal:\n    shift = gplr.inverse().multVec(shift) # global shift in LCS\nprint(f'Shift = {vectorRound(shift,nDec)}')\nlocorigin = gplr.inverse().multVec(App.Vector(0., 0., 0.)) #global origin in LCS\nApp.ActiveDocument.openTransaction('Undo Move to Origin')\nApp.ActiveDocument.getObject(sel.ObjectName).Placement.move(locorigin-shift)\nApp.ActiveDocument.commitTransaction()\nApp.ActiveDocument.recompute()",
    "url": "https://wiki.freecad.org/Macro_MoveToOrigin",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.02",
    "license": "",
    "date": "2021.7.7",
    "src_filename": "",
    "filename_from_url": "",
    "author": "edwilliams16",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Centericon.png",
    "icon_source": "https://wiki.freecad.org//images/8/8a/Centericon.png?20210619192700",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "MultiCuts",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro improves boolean cut hierarchy by automatic labeling and using copies for cut.<br /><br />Macro version: 1.0<br />Last modified: 2022-08-15<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/0/02/MultiCuts.png\">ToolBar Icon</a><br />Author: Dprojects<br /> ",
    "comment": "This macro improves boolean cut hierarchy by automatic labeling and using copies for cut.",
    "code": "__Title__=\"multiCuts\"\n__Author__ = \"Dprojects\"\n__Version__ = \"1.0\"\n__Date__    = \"2022-08-15\"\n__Comment__ = \"\"\n__Web__ = \"https://github.com/dprojects/Woodworking\"\n__Wiki__ = \"https://wiki.freecadweb.org/Macro_multiCuts\"\n__Icon__  = \"https://wiki.freecad.org/images/0/02/MultiCuts.png\"\n__IconW__  = \"https://wiki.freecad.org/images/0/02/MultiCuts.png\"\n__Help__ = \"select base object and next objects to cut the base\"\n__Status__ = \"stable\"\n__Requires__ = \"freecad 0.20.29177\"\n__Communication__ = \"http://www.freecadweb.org/wiki/index.php?title=User:Dprojects\"\n\n# ####################################################################\n#\n# This macro allows to create multi bool cut operation at \n# selected objects. First selected object should be the base \n# element and all other selected will cut the base. The copies will \n# be created for cut, so the objects tree not change. Also there is \n# automatic labeling for better cut hierarchy look. This macro has \n# been created for special request \n# https://forum.freecadweb.org/viewtopic.php?f=31&t=70941 \n# but is also available at Woodworking workbench.\n#\n# Certified platform:\n# \n# OS: Ubuntu 22.04 LTS (XFCE/xubuntu)\n# Word size of FreeCAD: 64-bit\n# Version: 0.20.29177 (Git) AppImage\n# Build type: Release\n# Branch: (HEAD detached at 0.20)\n# Hash: 68e337670e227889217652ddac593c93b5e8dc94\n# Python 3.9.13, Qt 5.12.9, Coin 4.0.0, Vtk 9.1.0, OCC 7.5.3\n# Locale: English/United States (en_US)\n# Installed mods: \n#  * Woodworking 0.20.29177\n#\n# https://github.com/dprojects/Woodworking\n#\n# MIT License\n# \n# Copyright (c) 2022 Darek L github.com/dprojects\n# \n# Permission is hereby granted, free of charge, to any \n# person obtaining a copy of this software and associated \n# documentation files (the \"Software\"), to deal in the \n# Software without restriction, including without limitation \n# the rights to use, copy, modify, merge, publish, distribute, \n# sublicense, and/or sell copies of the Software, and to permit \n# persons to whom the Software is furnished to do so, subject \n# to the following conditions:\n# \n# The above copyright notice and this permission notice shall \n# be included in all copies or substantial portions of the Software.\n# \n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, \n# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES \n# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \n# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT \n# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, \n# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n# DEALINGS IN THE SOFTWARE.\n# \n# ####################################################################\n\nimport FreeCAD, FreeCADGui\n\n\ndef multiCuts(iObjects):\n\n\tcuts = []\n\t\n\ti = 0\n\tfor o in iObjects:\n\t\t\n\t\ti = i + 1\n\t\t\n\t\tif i == 1:\n\t\t\tbase = o\n\t\t\tbaseName = str(base.Name)\n\t\t\tbaseLabel = str(base.Label)\n\t\t\tcontinue\n\n\t\tcopy = FreeCAD.ActiveDocument.copyObject(o)\n\t\tcopy.Label = \"copy, \" + o.Label\n\t\t\n\t\tcutName = baseName + str(i-1)\n\t\tcut = FreeCAD.ActiveDocument.addObject(\"Part::Cut\", cutName)\n\t\tcut.Base = base\n\t\tcut.Tool = copy\n\t\tcut.Label = \"Cut \" + str(i-1) + \", \" + baseLabel\n\t\t\n\t\tFreeCAD.activeDocument().recompute()\n\t\t\n\t\tbase = cut\n\t\tcuts.append(cut)\n\t\t\n\tcut.Label = \"Cut, \" + baseLabel\n\n\treturn cuts\n\n# ####################################################################\n# main\n# ####################################################################\n\nmultiCuts(FreeCADGui.Selection.getSelection())\nFreeCADGui.Selection.clearSelection()\n\n# ####################################################################",
    "url": "https://github.com/dprojects/Woodworking",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_multiCuts",
    "version": "1.0",
    "license": "",
    "date": "2022-08-15",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Dprojects",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\MultiCuts.png",
    "icon_source": "https://wiki.freecad.org/images/0/02/MultiCuts.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Overlap",
    "on_wiki": true,
    "on_git": false,
    "desc": "Boolean tool in between <a href=\"/Part_Fuse\" title=\"Part Fuse\">Part Fuse</a> and <a href=\"/Part_Common\" title=\"Part Common\">Part Common</a>. Parametric.<br /><br />Macro version: 0.2<br />Last modified: 2018-08-31<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/a/ac/Macro_Overlap.png\">ToolBar Icon</a><br />Author: DeepSOIC<br /> ",
    "comment": "Extension of Part Common boolean operation",
    "code": "#***************************************************************************\n#*                                                                         *\n#*   Copyright (c) 2016 - Victor Titov (DeepSOIC)                          *\n#*                                               <vv.titov@gmail.com>      *  \n#*                                                                         *\n#*   This program is free software; you can redistribute it and/or modify  *\n#*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n#*   as published by the Free Software Foundation; either version 2 of     *\n#*   the License, or (at your option) any later version.                   *\n#*   for detail see the LICENCE text file.                                 *\n#*                                                                         *\n#*   This program is distributed in the hope that it will be useful,       *\n#*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n#*   GNU Library General Public License for more details.                  *\n#*                                                                         *\n#*   You should have received a copy of the GNU Library General Public     *\n#*   License along with this program; if not, write to the Free Software   *\n#*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n#*   USA                                                                   *\n#*                                                                         *\n#***************************************************************************\n\n__Title__ = \"Macro Overlap\"\n__Author__ = \"DeepSOIC\"\n__Version__ = \"0.2\"\n__Date__    = \"31/08/2018\"\n\n__Comment__ = \"Extension of Part Common boolean operation\"\n__Web__ = \"http://forum.freecadweb.org/viewtopic.php?f=8&t=17755\"\n__Wiki__ = \"http://www.freecadweb.org/wiki/index.php?title=Macro_Boolean_Overlap\"\n__Status__ = \"experimental\"\n__Requires__ = \"freecad 0.17.8053 with OCC 6.9.0+\"\n__Communication__ = \"http://www.freecadweb.org/wiki/index.php?title=User:DeepSOIC\" \n__Help__ = '''\nMacro Overlap.\nRequires FreeCAD v0.17.8053+ and OCC 6.9.0+\n\nInstructions:\nSelect three or more shapes to compute Overlap between. A single compound will do, too.\nThen, run this macro. Parametric Overlap object is created.\n'''\n\nif __name__ == \"__main__\": #being run as a macro\n    import MacroOverlap\n    MacroOverlap.run()\n\nimport FreeCAD as App\nif App.GuiUp:\n    import FreeCADGui as Gui\nimport Part\n\ndef makeOverlapFeature():\n    '''makeOverlapFeature(): makes a Overlap parametric feature object. Returns the new object.'''\n    selfobj = App.ActiveDocument.addObject(\"Part::FeaturePython\",\"Overlap\")\n    Overlap(selfobj)\n    ViewProviderOverlap(selfobj.ViewObject)\n    return selfobj\n\nclass Overlap:\n    \"The Overlap feature object\"\n    def __init__(self,selfobj):\n        selfobj.addProperty(\"App::PropertyLinkList\",\"Objects\",\"Overlap\",\"Input shape\")\n        selfobj.addProperty(\"App::PropertyInteger\", \"OverlapIndex\", \"Overlap\", \"minimum overlap order to output\")\n        selfobj.OverlapIndex = 2\n        selfobj.Proxy = self\n\n    def execute(self,selfobj):\n        import BOPTools\n        import BOPTools.Utils as Utils\n        from BOPTools.GeneralFuseResult import GeneralFuseResult\n        \n        list_of_shapes = [obj.Shape for obj in selfobj.Objects]\n        if len(list_of_shapes) == 1 and list_of_shapes[0].ShapeType == \"Compound\":\n            list_of_shapes = list_of_shapes[0].childShapes()\n\n        list_of_shapes = Utils.upgradeToAggregateIfNeeded(list_of_shapes)\n        pieces, map = list_of_shapes[0].generalFuse(list_of_shapes[1:])\n        gr = GeneralFuseResult(list_of_shapes, (pieces,map))\n        gr.explodeCompounds()\n        gr.splitAggregates()\n        pieces_to_keep = []\n        for piece in gr.pieces:\n            if len(gr.sourcesOfPiece(piece)) >= selfobj.OverlapIndex:\n                pieces_to_keep.append(piece)\n        selfobj.Shape = BOPTools.ShapeMerge.mergeShapes(pieces_to_keep)\n\nclass ViewProviderOverlap:\n    def __init__(self,vobj):\n        vobj.Proxy = self\n       \n    def getIcon(self):\n        return \":/icons/Part_Overlap.svg\"\n\n    def attach(self, vobj):\n        self.ViewObject = vobj\n        self.Object = vobj.Object\n  \n    def setEdit(self,vobj,mode):\n        return False\n    \n    def unsetEdit(self,vobj,mode):\n        return\n\n    def __getstate__(self):\n        return None\n\n    def __setstate__(self,state):\n        return None\n\n    def claimChildren(self):\n        return self.Object.Objects\n        \n    def onDelete(self, feature, subelements): # subelements is a tuple of strings\n        try:\n            for f in self.Object.Objects:\n                f.ViewObject.show()\n        except Exception as err:\n            App.Console.PrintError(\"Error in onDelete: \" + err.message)\n        return True\n\nclass CommandMacroOverlap:\n    \"Command to create Overlap feature\"\n    def GetResources(self):\n        return {'Pixmap'  : \":/icons/Part_Overlap.svg\",\n                'MenuText': \"Overlap\",\n                'Accel': \"\",\n                'ToolTip': \"Macro_Overlap: boolean overlap. Collects space filled by at least 2 shapes.\"}\n\n    def Activated(self):\n        run()\n    def IsActive(self):\n        if App.ActiveDocument:\n            return True\n        else:\n            return False\n\nif App.GuiUp and __name__ != \"__main__\":\n    Gui.addCommand(\"Macro_Overlap\", CommandMacroOverlap())\n\ndef run():\n    sel = Gui.Selection.getSelectionEx()\n    try:\n        if len(sel) < 1:\n            raise Exception(\"Select two shapes to compute Overlap between, first! Then run this macro.\")\n        try:\n            App.ActiveDocument.openTransaction(\"Macro Overlap\")\n            selfobj = makeOverlapFeature()\n            selfobj.Objects = [it.Object for it in sel]\n            for f in selfobj.Objects:\n                f.ViewObject.hide()\n            \n            selfobj.Proxy.execute(selfobj)\n        finally:\n            App.ActiveDocument.commitTransaction()\n    except Exception as err:\n        from PySide import QtGui\n        mb = QtGui.QMessageBox()\n        mb.setIcon(mb.Icon.Warning)\n        mb.setText(err.message)\n        mb.setWindowTitle(\"Macro Overlap\")\n        mb.exec_()",
    "url": "http://forum.freecadweb.org/viewtopic.php?f=8&t=17755",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_Boolean_Overlap",
    "version": "0.2",
    "license": "",
    "date": "31/08/2018",
    "src_filename": "",
    "filename_from_url": "",
    "author": "DeepSOIC",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Overlap.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/a/ac/Macro_Overlap.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Parametric Defeaturing",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro is similar to the <a href=\"/Part_Defeaturing\" title=\"Part Defeaturing\">defeaturing tool</a> in the <a href=\"/Part_Workbench\" title=\"Part Workbench\">Part Workbench</a>, but it's parametric and it also works in <a href=\"/PartDesign_Workbench\" title=\"PartDesign Workbench\">PartDesign</a>. To use: select the faces of the features you wish to remove from the model and run the macro. Faces are used in defeaturing, not edges or vertices. The faces used may be edited later and the object will rebuild itself automatically.<br /> <p>Parametric is generally a good thing in 3D modeling, but because defeaturing relies upon face names: Face1, Face2, etc. it is vulnerable to topological naming issues and might break if changes are made to the original source object being defeatured when those changes result in the face names getting renumbered. Defeaturing is also a somewhat finicky process, not guaranteed to always succeed.<br /> </p><p>Full documentation can be found on github: <a rel=\"nofollow\" class=\"external text\" href=\"https://github.com/mwganson/parametric_defeaturing\">Parametric Defeaturing</a>.<br /><br /><br />Macro version: 0.2021.10.10.rev2<br />Last modified: 2021-10-10.rev2<br />FreeCAD version: python 3 versions<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/File:parametric_defeaturing.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> </p> ",
    "comment": "This macro is similar to the defeaturing tool in the Part Workbench, but it's parametric and it also works in PartDesign. To use: select the faces of the features you wish to remove from the model and run the macro. Faces are used in defeaturing, not edges or vertices. The faces used may be edited later and the object will rebuild itself automatically.",
    "code": "# -*- coding: utf-8 -*-\n__version__ = \"0.2021.10.10.rev2\"\n#__version__ = \"0.2021.10.10.rev2\"\n#__title__ = \"Parametric Defeaturing Macro\"\n#__author__ = \"<TheMarkster> 2021\"\n#__license__ = \"LGPL 2.1\"\n#__doc__ = \"Parametric Defeaturing inside and outside Part Design.\"\n#__usage__ = '''Select the faces to defeature and activate the tool'''\n#import Part, FreeCADGui, FreeCAD\n#from PySide import QtGui,QtCore\n#BASENAME = \"parametric_defeaturing\"\n#\n#class ParametricDefeaturing:\n#    def __init__(self,obj):\n#        obj.addProperty(\"App::PropertyLinkSub\",\"Faces\",\"ParametricDefeaturing\",\"Selected faces to be defeatured\")\n#        obj.addProperty(\"App::PropertyString\", \"Version\", \"ParametricDefeaturing\", \"version this object was created with\").Version = __version__\n#        if not hasattr(obj,\"Refine\"):\n#            obj.addProperty(\"App::PropertyBool\",\"Refine\", \"ParametricDefeaturing\", \"refine feature\").Refine = False\n#        obj.addProperty(\"App::PropertyBool\",\"ClaimChildren\",\"ParametricDefeaturing\",\"whether to claim children in the tree\").ClaimChildren = True\n#        obj.addProperty(\"App::PropertyBool\",\"EditFaces\",\"ParametricDefeaturing\",\"[Trigger] brings up face editing dialog\").EditFaces = False\n#        obj.addProperty(\"App::PropertyBool\",\"DefeaturingSuccess\",\"ParametricDefeaturing\",\"If True, defeaturing succeeded\").DefeaturingSuccess = False\n#        obj.Proxy = self\n#        self.fpName = obj.Name\n#        self.editingMode = False\n#\n#    def onChanged(self, fp, prop):\n#        if prop == \"EditFaces\" and fp.EditFaces == True:\n#            t = QtCore.QTimer()\n#            t.singleShot(50, self.editFaces) #avoid warning message about selection changing while committing data\n#            fp.EditFaces = False\n#\n#    def getEditDialog(self):\n#        return self.editFaces\n#\n#    def editFaces(self):\n#        from PySide import QtGui\n#        fp = FreeCAD.ActiveDocument.getObject(self.fpName)\n#        if not fp.Faces:\n#            return\n#        object = fp.Faces[0]\n#        if not object:\n#            return\n#        if not FreeCADGui.Control.activeDialog():\n#            panel = TaskEditLinkSubPanel(fp,\"Faces\",\"Face\")\n#            FreeCADGui.Control.showDialog(panel)\n#            self.editingMode = True #tells execute() not to hide the linked object\n#        else:\n#            self.editingMode=False\n#            FreeCAD.Console.PrintError(\"Another task dialog is active.  Close that one and try again.\\n\")\n#\n#    def execute(self,fp):\n#        if not fp.Faces:\n#            return\n#        fp.DefeaturingSuccess = True\n#        faces = []\n#        object = fp.Faces[0]\n#        for fname in fp.Faces[1]:\n#            faces.append(getattr(object.Shape,fname))\n#        shape = object.Shape.defeaturing(faces)\n#        if shape.Volume == object.Shape.Volume:\n#            FreeCAD.Console.PrintError(\"Defeaturing failed.\\n\")\n#            fp.DefeaturingSuccess = False\n#        if fp.Refine:\n#            shape = shape.removeSplitter()\n#        if hasattr(fp,\"BaseFeature\") and hasattr(fp,\"AddSubShape\"):\n#            if fp.BaseFeature and not shape.isNull():\n#                pattern_shape = shape.fuse(fp.BaseFeature.Shape)\n#                if fp.Refine:\n#                    pattern_shape = pattern_shape.removeSplitter()\n#                fp.AddSubShape = pattern_shape\n#            else:\n#                fp.AddSubShape = shape\n#        fp.Shape = shape if shape and fp.DefeaturingSuccess else Part.Shape()\n#        if not self.editingMode:\n#            object.ViewObject.Visibility = True if not fp.DefeaturingSuccess else False\n#\n#class TaskEditLinkSubPanel: #simple editor for App::PropertyLinkSub\n#    def __init__(self, obj, linkSubName, subNames,):\n#        self.obj = obj\n#        self.subNames = subNames\n#        self.linkSubName = linkSubName #entire LinkSub property\n#        self.linkObj = getattr(self.obj,linkSubName)[0]\n#        self.subObjects = getattr(self.obj,linkSubName)[1]\n#        self.form = QtGui.QWidget()\n#        self.label1 = QtGui.QLabel(\"Select the \"+self.subNames+\" subobjects to use and click OK.\\nThe ones already being utilized have been selected for you.\")\n#        layout=QtGui.QHBoxLayout()\n#        layout.addWidget(self.label1)\n#        self.form.setLayout(layout)\n#        self.form.setWindowTitle('Edit '+self.subNames)\n#        self.obj.ViewObject.Visibility = False\n#        self.linkObj.ViewObject.Visibility = True\n#        FreeCADGui.Selection.clearSelection()\n#        for f in self.subObjects:\n#            FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Name,self.linkObj.Name,f)\n#        self.obj.Proxy.editingMode = True\n#\n#    def reject(self):\n#        FreeCADGui.Control.closeDialog()\n#        fp = self.obj\n#        self.linkObj.ViewObject.Visibility = False\n#        fp.ViewObject.Visibility = True\n#        self.obj.Proxy.editingMode = False\n#        FreeCADGui.activeDocument().resetEdit()\n#        FreeCAD.ActiveDocument.recompute()\n#\n#    def accept(self):\n#        FreeCADGui.ActiveDocument.resetEdit()\n#        FreeCADGui.Control.closeDialog()\n#        fp = self.obj\n#        if not fp: #user deleted or closed document perhaps\n#            return\n#        selx = FreeCADGui.Selection.getSelectionEx()\n#        if not selx:\n#            FreeCAD.Console.PrintWarning(\"Nothing selected, leaving \"+self.linkObj.Name+\" unmodified.\")\n#            return\n#        seNames = [sen for sen in selx[0].SubElementNames if self.subNames in sen]\n#        setattr(self.obj,self.linkSubName,(selx[0].Object,seNames)) #allow user to select diffent object\n#        self.linkObj = selx[0].Object\n#        if hasattr(fp,\"_Body\") and fp._Body and self.linkObj not in fp._Body.Group:\n#            fp._Body.Group += [self.linkObj]\n#            if not self.linkObj.isDerivedFrom(\"PartDesign::Feature\"):\n#               fp.ClaimChildren = True\n#        self.linkObj.ViewObject.Visibility = False\n#        fp.ViewObject.Visibility = True\n#        if hasattr(fp.Proxy,\"editingMode\"):\n#            fp.Proxy.editingMode = False\n#        FreeCAD.ActiveDocument.recompute()\n#\n#class ParametricDefeaturingVP:\n#    def __init__(self, obj):\n#        '''Set this object to the proxy object of the actual view provider'''\n#        obj.Proxy = self\n#    def attach(self, obj):\n#        '''Setup the scene sub-graph of the view provider, this method is mandatory'''\n#        self.Object = obj.Object\n#\n#    def updateData(self, fp, prop):\n#        '''If a property of the handled feature has changed we have the chance to handle this here'''\n#        # fp is the handled feature, prop is the name of the property that has changed\n#        if prop == \"DefeaturingSuccess\":\n#            fp.ViewObject.signalChangeIcon()\n#\n#    def getDisplayModes(self,obj):\n#        '''Return a list of display modes.'''\n#        modes=[]\n#        modes.append(\"Flat Lines\")\n#        return modes\n \n#    def getDefaultDisplayMode(self):\n#        '''Return the name of the default display mode. It must be defined in getDisplayModes.'''\n#        return \"Flat Lines\"\n \n#    def setDisplayMode(self,mode):\n#        '''Map the display mode defined in attach with those defined in getDisplayModes.\\\n#                Since they have the same names nothing needs to be done. This method is optional'''\n#        return mode\n \n#    def onChanged(self, vp, prop):\n#        '''Here we can do something when a single property got changed'''\n#        #FreeCAD.Console.PrintMessage(\"Change property: \" + str(prop) + \"\"+chr(10))\n\n#    def claimChildren(self):\n#        if self.Object.ClaimChildren and self.Object.Faces and not self.Object.Shape.isNull():\n#            return [self.Object.Faces[0]] #the object itself, not a face\n#        else:\n#            return []\n#\n#    def setEdit(self,vobj,modNum):\n#        #FreeCAD.Console.PrintMessage(\"modNum = \"+str(modNum)+\"\\n\")\n#        if modNum == 0:\n#            vobj.Object.Proxy.editFaces()\n#            return True\n#        elif modNum == 3: #color per face\n#            FreeCADGui.runCommand('Part_ColorPerFace',0)\n#            return True\n#\n#    def onDelete(self, vobj, subelements):\n#        if vobj.Object.Faces:\n#            vobj.Object.Faces[0].ViewObject.Visibility = True\n#            if not vobj.Object.Faces[0].isDerivedFrom(\"PartDesign::Feature\"):\n#                if hasattr(vobj.Object,\"_Body\") and vobj.Object._Body:\n#                    grp = vobj.Object._Body.Group\n#                    grp.remove(vobj.Object.Faces[0])\n#                    vobj.Object._Body.Group = grp\n#        #ensure next feature's BaseFeature property points to our BaseFeature object\n#        if hasattr(vobj.Object,\"_Body\"):\n#            solids = [sol for sol in vobj.Object._Body.Group if sol.isDerivedFrom(\"PartDesign::Feature\") and sol.BaseFeature == vobj.Object]\n#            for solid in solids: #leave open possibility for multiple objects using the same BaseFeature\n#                solid.BaseFeature = vobj.Object.BaseFeature\n#        return True\n#\n#    def getIcon(self):\n#        '''Return the icon in XPM format which will appear in the tree view. This method is\\\n#                optional and if not defined a default icon is shown.'''\n#        xpm ='''\n#/* XPM */\n#static char *_633719960957[] = {\n#/* columns rows colors chars-per-pixel */\n#\"64 64 193 2 \",\n#\"   c #008D00480049\",\n#\".  c #0B2300B800C4\",\n#\"X  c #070707070808\",\n#\"o  c #0A500A0A0AAE\",\n#\"O  c #126800720072\",\n#\"+  c #1C1C00000000\",\n#\"@  c #0F0F0F0F1010\",\n#\"#  c #121212A41380\",\n#\"$  c #151516161818\",\n#\"%  c #1B1B1B9C1D1D\",\n#\"&  c #242400000000\",\n#\"*  c #2B5E00000000\",\n#\"=  c #323200000000\",\n#\"-  c #3B3B00000000\",\n#\";  c #1D731EC920CA\",\n#\":  c #1F1E212022A2\",\n#\">  c #215323222558\",\n#\",  c #272628C22AF7\",\n#\"<  c #2D2C2EAE3171\",\n#\"1  c #2D2C30303231\",\n#\"2  c #33B336363A3A\",\n#\"3  c #35B538F83C7C\",\n#\"4  c #39B93A3A3ABA\",\n#\"5  c #438300000000\",\n#\"6  c #4BE500000000\",\n#\"7  c #511100000000\",\n#\"8  c #5B5B00000000\",\n#\"9  c #626200000000\",\n#\"0  c #6CAC00000000\",\n#\"q  c #741E00000000\",\n#\"w  c #7C5C00000000\",\n#\"e  c #39383C914141\",\n#\"r  c #3D7D41004545\",\n#\"t  c #448447464B4B\",\n#\"y  c #49094D4C5292\",\n#\"u  c #4E1A521E5689\",\n#\"i  c #570159585CB1\",\n#\"p  c #547D5B8C63AC\",\n#\"a  c #57015EB468BE\",\n#\"s  c #58585F5F6868\",\n#\"d  c #5BB0610B6666\",\n#\"f  c #5BFE62E26B5A\",\n#\"g  c #5B5B66D874E6\",\n#\"h  c #5E086A6A7822\",\n#\"j  c #60A9671D6E49\",\n#\"k  c #67926A3F6CC1\",\n#\"l  c #642E6B1572BD\",\n#\"z  c #68E86EEF7635\",\n#\"x  c #620C6E6D7BFC\",\n#\"c  c #6665711B7CD1\",\n#\"v  c #6D3973737A68\",\n#\"b  c #7271727172F2\",\n#\"n  c #717176F77D7C\",\n#\"m  c #84C400000000\",\n#\"M  c #8CF300000000\",\n#\"N  c #939300000000\",\n#\"B  c #9C1C00000000\",\n#\"V  c #A44E00000000\",\n#\"C  c #ABAB00000000\",\n#\"Z  c #BC2600000000\",\n#\"A  c #C51100000000\",\n#\"S  c #CBFE00000000\",\n#\"D  c #D29200000000\",\n#\"F  c #DB7B00000000\",\n#\"G  c #E5E500000000\",\n#\"H  c #ED4200000000\",\n#\"J  c #F37C00000000\",\n#\"K  c #FFD300000000\",\n#\"L  c #666673D38323\",\n#\"P  c #6B6B76CC83D8\",\n#\"I  c #6C417AA58B0B\",\n#\"U  c #75877C5783DF\",\n#\"Y  c #792F7EC78517\",\n#\"T  c #75757E7E8888\",\n#\"R  c #69BE7D7C9494\",\n#\"E  c #7BBB81008787\",\n#\"W  c #7BC482388A40\",\n#\"Q  c #6EEE81019515\",\n#\"!  c #72728282952E\",\n#\"~  c #7ACF873195EA\",\n#\"^  c #723285049ADA\",\n#\"/  c #676781D7A34D\",\n#\"(  c #68688282A3A3\",\n#\")  c #64CA82B5AE47\",\n#\"_  c #73738A8AA727\",\n#\"`  c #7A138E27A33C\",\n#\"'  c #7F7E9292A7A7\",\n#\"]  c #7DFD9393AC00\",\n#\"[  c #66CD861FB149\",\n#\"{  c #68688786B2B2\",\n#\"}  c #6B018A5DB55A\",\n#\"|  c #6E148EF2BB13\",\n#\" . c #721C8F39B7B7\",\n#\".. c #6F37912CBD20\",\n#\"X. c #71B5936ABF45\",\n#\"o. c #7A4F95BFBC66\",\n#\"O. c #7D7D9864B851\",\n#\"+. c #744B962FC1F0\",\n#\"@. c #76C39907C3C2\",\n#\"#. c #7AD09C0DC5BF\",\n#\"$. c #7D379F13C8C8\",\n#\"%. c #7F07A0DAC9A1\",\n#\"&. c #826C86F18C76\",\n#\"*. c #863089338CE1\",\n#\"=. c #83838A89933D\",\n#\"-. c #89898E8E9595\",\n#\";. c #8D8D92929797\",\n#\":. c #8ADF93939D47\",\n#\">. c gray58\",\n#\",. c #931297179C71\",\n#\"<. c #959599389DDD\",\n#\"1. c #99D99DBDA2A2\",\n#\"2. c #93939C9CA841\",\n#\"3. c #84129B29B408\",\n#\"4. c #83A39C9CBBFB\",\n#\"5. c #9D47A277A87D\",\n#\"6. c #89C9A2E2BDBD\",\n#\"7. c #9BF0A6A6B409\",\n#\"8. c #A565A7E7AB2B\",\n#\"9. c #A464A8A8AD2D\",\n#\"0. c #A7E7AE2DB5F5\",\n#\"q. c #AF66B268B66C\",\n#\"w. c #A6A5B1B1BF3F\",\n#\"e. c #B333B434B5B5\",\n#\"r. c #B37FB61BBA53\",\n#\"t. c #BB10BB65BC11\",\n#\"y. c #82C29E1DC382\",\n#\"u. c #88879F9FC0C0\",\n#\"i. c #842EA12EC5FE\",\n#\"p. c #8BC6A441C425\",\n#\"a. c #8DE2A8FDC51A\",\n#\"s. c #83ECA401CB5C\",\n#\"d. c #8B3FA700CAD9\",\n#\"f. c #8C61AA29CE4D\",\n#\"g. c #953FAA29C59A\",\n#\"h. c #93ADAC78CC18\",\n#\"j. c #9999AE64CBA6\",\n#\"k. c #9494B1B0CFCF\",\n#\"l. c #9C9CB1F1CDCD\",\n#\"z. c #8CFEAC8FD1B4\",\n#\"x. c #9304AF3DD1B4\",\n#\"c. c #9548B2B2D453\",\n#\"v. c #9B90B523D442\",\n#\"b. c #9F05B8EBD73C\",\n#\"n. c #9696B68BDA04\",\n#\"m. c #98EEB7B7DA2E\",\n#\"M. c #9CADBC93DDBD\",\n#\"N. c #AA17B56BC4E8\",\n#\"B. c #A261B4B3CF4E\",\n#\"V. c #ADACBA86C962\",\n#\"C. c #B862BD67C26C\",\n#\"Z. c #B1DCBDE7CDA2\",\n#\"A. c #A1A1B6B6D27C\",\n#\"S. c #A56EBA17D525\",\n#\"D. c #AC08BD8ED577\",\n#\"F. c #A2A2BE61DCE6\",\n#\"G. c #AA09BEFED9D8\",\n#\"H. c #B6B6C140CBCA\",\n#\"J. c #A3C8C0BFDF96\",\n#\"K. c #ACB9C2A8DCE9\",\n#\"L. c #B372C241D655\",\n#\"P. c #B424C568DC18\",\n#\"I. c #B837C7C7DB5B\",\n#\"U. c #B8F8C7C7DC1B\",\n#\"Y. c #BBA1CA7DDDDC\",\n#\"T. c #A5A5C2FBE119\",\n#\"R. c #AB08C5E0E240\",\n#\"E. c #AED2C8EDE408\",\n#\"W. c #B4C6CBAFE491\",\n#\"Q. c #BBBACE8BE48A\",\n#\"!. c #BDBDD17BE73B\",\n#\"~. c #BDBDD305E91B\",\n#\"^. c #C3C3C426C44D\",\n#\"/. c #C61BC71CC91E\",\n#\"(. c #C6C6C8C8CB8B\",\n#\"). c #CBE5CBFECC32\",\n#\"_. c #CA74CE22D2D2\",\n#\"`. c #D413D453D494\",\n#\"'. c #D72CD92EDB30\",\n#\"]. c #DC9EDC9EDC9E\",\n#\"[. c #C1C1CECDE0DF\",\n#\"{. c #C392D362E624\",\n#\"}. c #C3CFD662EA83\",\n#\"|. c #C8C8D756E968\",\n#\" X c #CCA4DC51ED76\",\n#\".X c #DCDCDEDEE0E0\",\n#\"XX c #D190DEFEEE0D\",\n#\"oX c #D311E120EFAF\",\n#\"OX c #DB85E690F29C\",\n#\"+X c #E4A0E4BBE4D0\",\n#\"@X c #EC00EC16EC32\",\n#\"#X c #F4ADF4ADF4AD\",\n#\"$X c none\",\n#/* pixels */\n#\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X#X].r.;.l d v &.1.q.(..X#X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X+X^.1.v p p p p p p p p p p p p p j n ;.8.H.`.+X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X@X_.0.W d p p p p d x ~ O.a.m.a.3.` ! L h a p p p p p p p f c &.1.q.(.].$X$X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X$X#X'.r.;.l p p p p p f Q ] 6.m.M.M.M.M.M.M.M.M.M.M.M.M.k.6.] ` L x f p p p p p p p p f U ;.9.C.`.@X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X.Xt.1.v p p p p p f Q ` 6.m.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.c.a.3.` ! L g p p p p p p p p f $X$X\",\n#\"$X$X$X@X/.5.E d p p p p d c ^ 3.a.M.b.M.M.J.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.m.f.Q p p p p p p $X$X\",\n#\"$X$Xf p p p p p g R ] a.M.M.M.M.M.M.M.F.T.T.T.T.T.T.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.] x p p p p g / p p $X$X\",\n#\"$X$Xp p p p p p p a f x ! 3.m.M.M.M.F.J.T.R.R.R.J.J.T.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.m.M.M.M.M.3.x p p p p g / | ..+.p p $X$X\",\n#\"$X$Xp p c.6.] I p p p p p p p f h Q ' N.W.~.~.~.W.R.T.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.m.M.M.O.L p p p p g / ..+...+.X.X.p p $X$X\",\n#\"$X$Xp p M.M.M.M.M.m.h.6.` L a p d l U ~ <.7.<.7.H.K.R.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.6.L d d p p g / ..+.......+...X.X.p p $X$X\",\n#\"$X$Xp p M.M.M.M.M.M.M.M.M.M.M.M.v.j.7.9.0.z   y 5.W v l x ! O.c.M.M.M.M.J.M.M.M.4.L p p p p h R ....+.+.+.+.| +.| +.+.| p p #X$X\",\n#\"$X$Xp p M.M.M.M.M.M.M.M.M.M.J.T.E.Q.}.XXW     u C.:.n f p d d d f l P ` a.3.L d s a p h R +.+.X...+.....| +.+.| | +.+.| p p $X$X\",\n#\"$X$Xp p M.M.M.M.M.M.M.M.M.M.T.E.Q.}.XX=.      d  X~.R.b.p.' I f f g l l l l z l P _ @.@.+.+.X.X.+...+...+.| +.| +.} +.+.p p $X$X\",\n#\"$X$Xp p M.M.M.M.M.M.m.M.J.T.E.W.}.XXW   . 9   k  X~.W.T.J.J.R.R.K.J.g.2.E E 3.d.d.d.s.$.$.#.+.+.+...+...+.| | +.} +.+.+.p p $X$X\",\n#\"$X$Xp p M.M.M.m.M.m.M.M.T.E.W.}. XY   . Z B   v  X~.W.E.E.W.W.Q.Q.!.~.~.1.,.F.S.S.v.v.h.f.s.y.#.+...X.X...............+.p p $X$X\",\n#\"$X$Xp p M.M.m.m.m.M.M.F.R.W.}. XY   . Z K M   E oX|.~.!.!.!.~.|.|. XoXoXq.q.Q.Y.W.U.G.G.S.v.h.d.y.@.o.X.| ..| | ..} +...p p $X$X\",\n#\"$X$Xp p M.M.m.m.m.m.J.T.W.{. XU   . Z K K m   =.OXXX X}.|. XY.2.n u 4 > # o % > e p =.V.W.L.D.v.h.i.#.+.X.| ..| | | +.+.p p $X$X\",\n#\"$X$Xp p M.M.n.m.M.M.R.W.{. Xn   . Z K K K q   ,.OXOXoX5.p >             .               < Y P.P.S.c.d.y.o...| ..| | ....p p $X$X\",\n#\"$X$Xp p M.M.m.M.F.K.W.~. Xn   . A K K K K 0   1.5.u o       & 9 M Z F J K K K J D V 0 &     $ W Y.D.l.d.y.o.X.| | } | +.p p #X$X\",\n#\"$X$Xp p M.M.m.M.F.W.{. Xn   . A K K K K K 9   o     . 7 V G K K K K K K K K K K K K K K S 7     e D.L.v.d.o.X.X.| | +.| p p $X$X\",\n#\"$X$Xp p M.J.M.F.W.!. Xv   . A K K K K K K 8     5 V J K K K K K K K K K K K K K K K K K K K A *   > N.L.v.p.o.X.| } +.+.p p $X$X\",\n#\"$X$Xp p F.R.F.W.!. Xz   . A K K K K K K K D M F K K K K K K K K K K K K K K K K K K K K K K K J 6   ; D.D.j.i.o.| } +.+.p p $X$X\",\n#\"$X$Xd d T.E.W.Q. Xz   . A K K K K K K K K K K K K K K K K K K K K K K J D S F F J K K K K K K K K 7   3 I.S.d.y...} ..+.p p $X$X\",\n#\"$X$Xf l E.~.Q. Xl   O A K K K K K K K K K K K K K K K K K K K Z q - +           . = w G K K K K K J *   U P.l.i...[ +...p p $X$X\",\n#\"$X$Xj v W.}. Xl   . S K K K K K K K K K K K K K K K K K C 8 .         > 4 e e 2 $     . q J K K K K S   # L.S.a.#.} +.+.p p $X$X\",\n#\"$X$Xl Y ~. Xl   O S K K K K K K K K K K K K K K K H m +     X r W V.oXoXq.q.Y.!.Y.N.f o   - H K K K K 8   n L.h.%.} ....p p $X$X\",\n#\"$X$Xz W }.U     V K K K K K K K K K K K K K K H 9 .   . e 2._.|.{.!.}.}.2.,.S.K.D.D.[.Z.<   5 K K K K S   , U.A.p.{ | +.p p $X$X\",\n#\"$X$Xz E }.Y       - N H K K K K K K K K K K K N   X d Z.XX}.Q.E.K.J.W.W.E U f.f.h.j.S.P.U.>   B K K K K &   N.S.h.{ +.+.p p $X$X\",\n#\"$X$Xl U ~.}.Z.n :     . 8 Z K K K K K K K K K H . X _.oX|.Q.G.F.v.c.T.T.l l %.4.@.u.g.S.U.7.  & K K K K 0   =.G.h.[ | | p p $X$X\",\n#\"$X$Xl c W.~.W.{.|.7.i o     + q F K K K K K K K q   i XX{.E.F.x.k.f.J.M.d d X.@. .o.y.j.D._.,   F K K K B   j D.j.[ +.+.p p $X$X\",\n#\"$X$Xd j R.E.F.E.W.Q.}.{.=.e       - B J K K K K J O . Z.{.K.b.z.z.%.M.M.p p +.+.} } o.p.A.Y.p   C K K K Z   y P.h.[ +.| p p $X$X\",\n#\"$X$Xa d T.R.c.m.F.G.P.Y.[.|.Z.v ;     . 8 Z K K K m   y {.P.b.x.s.%.M.M.p p ..+.[ } X.4.l.U.l   B K K K S   e P.j.[ +.+.p p $X$X\",\n#\"$X$Xp p M.M.z.z.x.c.b.F.K.E.Q.Q.|.7.u o     & w F J O   N.W.G.c.z.%.M.M.p p +.+.} }  .y.l.U.d   V K K K D   e L.j.) ..+.p p $X$X\",\n#\"$X$Xp p M.M.%.z.s.d.f.x.x.A.F.R.P.Q.{.Y.=.2       - 5   r {.K.c.z.%.M.n.p p +...} } o.u.B.U.y   Z K K K A   y L.j.[ +.| p p $X$X\",\n#\"$X$Xp p M.M.s.s.%.s.z.s.z.z.z.n.b.F.K.P.Q.}.V.z %         7.P.b.z.%.M.M.p p +.| [ } o.a.S.Y.$ . J K K K C   p D.h.) | +.p p $X$X\",\n#\"$X$Xp p M.M.%.$.%.%.%.%.%.%.s.z.f.h.v.b.G.K.W.Q.}.5.u o   f K.v.z.%.M.M.p p +.+.{  .4.j.L.7.  - K K K K m   U D.g.) +.+.p p $X$X\",\n#\"$X$Xp p M.M.%.%.%.%.%.%.%.%.%.%.s.s.f.z.c.c.S.G.P.W.!.I.:.S.S.x.d.$.M.M.p p +.+.}  .u.A.P.y   M K K K K 5   2.D.p.) X.| p p $X$X\",\n#\"$X$Xp p M.M.%.%.$.$.$.$.%.$.$.$.%.%.%.%.s.f.f.x.v.A.D.K.G.F.v.f.s.#.M.M.p p X.o. .y.j.D.N.  O J K K K J . o L.B.u.) X.+.p p $X$X\",\n#\"$X$Xp p M.M.#.#.#.$.#.$.#.$.$.#.#.#.#.#.y.$.s.s.f.f.x.k.x.x.f.%.#.#.M.M.a p +.#.4.p.B.U.t   m K K K K C   r P.g.4.) X.X.p p $X$X\",\n#\"$X$Xp p M.M.$.#.#.#.#.#.#.#.#.#.#.#.#.@.#.#.#.#.#.%.i.s.s.s.%.%.#.@.M.M.p s #.s.u.B.P.T   & J K K K K 7   =.D.g.o.| X.X.p p $X$X\",\n#\"$X$Xp p m.M.#.#.#.#.@.#.@.@.#.#.#.#.@.#.@.@.+.#.@.#.#.#.#.#.@.@.@.@.M.M.f g i.h.j.D.w.X   A K K K K F   # L.S.x.i.+.| ) p p $X$X\",\n#\"$X$Xp p M.M.$.#.@.@.#.#.@.#.@.@.@.+.@.@.@.@.@.@.@.@.@.@.@.@.+.+.+.@.M.J.l v j.F.Z.N.% . w K K K K K 9   l W.A.d.+.R a p p Y $X$X\",\n#\"$X$Xp p M.M.s.%.$.+.+.@.@.+.@.@.+.+.+.@.+.@.+.+.+.+.+.+.+.+.+.+.+.@.M.T.n &.S.W.V.:   8 K K K K K S   # L.K.g.! f p p &.(.$X$X$X\",\n#\"$X$Xp p M.M.M.M.M.m.x.z.s.%.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+...+.+.@.#.R.E.*.2.Y.N.>   6 K K K K K J -   Y Z.<.U j l 1.+X$X$X$X$X$X\",\n#\"$X$Xp p Q ] p.c.M.m.M.M.M.m.M.n.z.f.i.@.+.+.+.+.+.+.+.+.X.+.+.o.#.s.W.~.1.q.2.#   6 J K K K K K q   < q.<.*.*.e.+X#X#X$X$X$X$X$X\",\n#\"$X$XW p p p p p p L ( O.f.n.M.M.M.M.M.M.M.n.z.%.+.+.+.+...+.#.%.f.x.{. Xr.k     q J K K K K K C . X 5.9.8./..X+X@X@X#X$X$X$X$X$X\",\n#\"$X$X$X#X'.q.,.U d d d i p d d L ` O.f.n.M.M.M.M.n.M.m.n.z.%.s.f.l.G. XZ.<   . V K K K K K K S .   &.).'.].].].+X@X#X#X$X$X$X$X$X\",\n#\"$X$X$X$X$X#X#X#X+X).q.<.W l p p p p p p g R ] p.z.M.M.m.M.T.R.E.!.{.n X   = S K K K K K K S .   b .X].].].].+X+X@X#X#X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X#X#X@X+X.X'.`.`.H.e.<.*.b j p p p p p p h ^ O.k.J.~. X1   . M J K K K K K K Z . . k +X.X].].].].+X@X#X#X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X#X#X#X@X+X].'.`.).^.^.^.t.8.<.*.b h p a p f f v -.N.,   0 K K K K K K K N     b +X+X.X+X].+X@X#X#X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X#X#X@X@X+X].].`.`.).).^.^.t.t.e.e.8.>.&.Y Y &.1.<.o . Z K K K K H 6   X >.@X+X+X+X+X@X@X#X#X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X#X#X#X@X+X+X].'.`.`.).).).^.^.^.^.t.^.^./.).).*.  O H K K V O   % t.@X@X@X@X@X#X#X#X$X$X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X#X#X#X@X@X@X+X].].'.'.`.`.`.`.`.`.].].+X@Xi   5 C *     k @X#X#X#X#X#X#X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X#X#X#X#X#X@X@X@X@X+X+X+X+X+X@X@X@X@X,       4 ).#X#X#X$X#X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X#X$X#X#X#X#X#X#X#X$X#X`.@ 4 e.$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n#\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\"\n#};\n#'''\n#        if self.Object.DefeaturingSuccess:\n#            return xpm\n#        else:\n#            return xpm.replace('none','red')\n \n#    def __getstate__(self):\n#        '''When saving the document this object gets stored using Python's json module.\\\n#                Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\\\n#                to return a tuple of all serializable objects or None.'''\n#        return None\n \n#    def __setstate__(self,state):\n#        '''When restoring the serialized object from document we have the chance to set some internals here.\\\n#                Since no data were serialized nothing needs to be done here.'''\n#        return None\n\n\n\n############\n#if __name__ == \"__main__\":\n#    FreeCAD.Console.PrintMessage(\"Please run \"+BASENAME+\".FCMacro rather than this file.\\n\")\n############\n\n#CODE_ENDS_HERE\n\n\ndef getBody(feature):\n    doc = FreeCAD.ActiveDocument\n    bodies = [obj for obj in doc.Objects if obj.TypeId == \"PartDesign::Body\"]\n    for bod in bodies:\n        if feature in bod.Group:\n            return bod\n    return None\n\ndef makeObject(PD):\n    doc = FreeCAD.ActiveDocument\n    body=None\n    selobjs = FreeCADGui.Selection.getSelectionEx()\n    if doc:\n        doc.openTransaction(\"Create ParametricDefeaturing\"+\"s\" if len(selobjs) > 1 else \"\")\n\n        if selobjs:\n            for selobj in selobjs:\n                body = getBody(selobj.Object)\n                if body:\n\n                    parametric_defeaturing = body.newObject(\"PartDesign::FeatureAdditivePython\",\"ParametricDefeaturing\")\n                else:\n                    parametric_defeaturing = doc.addObject(\"Part::FeaturePython\",\"ParametricDefeaturing\")\n                PD.ParametricDefeaturing(parametric_defeaturing)\n                PD.ParametricDefeaturingVP(parametric_defeaturing.ViewObject)\n                if body:\n                    parametric_defeaturing.ClaimChildren = False\n\n                if selobj.HasSubObjects:\n                    faces = [name for name in selobj.SubElementNames if not \"Vertex\" in name and not \"Edge\" in name]\n                    if faces:\n                        parametric_defeaturing.Faces = (selobj.Object,faces)\n                    else:\n                        FreeCAD.Console.PrintError(\"No faces among selected subobjects.  Defeaturing only works on faces.\\n\")\n                        doc.removeObject(parametric_defeaturing.Name)\n\n                else:\n                    FreeCAD.Console.PrintError(\"No faces selected.  Defeaturing only works on faces.\\n\")\n                    doc.removeObject(parametric_defeaturing.Name)\n        else:\n            FreeCAD.Console.PrintMessage(\"No object selected to defeature.\\n\")\n        doc.commitTransaction()\n\nBASENAME = \"parametric_defeaturing\"\n\n\n\ndef writeFile():\n    with open(py_file,\"w\") as outfile:\n        for line in code.splitlines():\n            if \"#CODE_ENDS_HERE\" in line:\n                break\n            if line.startswith('#'):\n                if line == \"# -*- coding: utf-8 -*-\":\n                    line = \"#\" + line\n                outfile.write(line[1:]+\"\\n\") #skip first character (#)\n\n\n\n############\n#if __name__ == \"__main__\":\n#    makeObject(None)\n#    raise Exception(\"quick exit for testing/debugging\")\n############\n\nif __name__ == \"__main__\":\n    import os\n    fin = open(__file__, 'r')\n    code = fin.read()\n    fin.close()\n    version = code.splitlines()[1][16:]\n    real_path = os.path.realpath(__file__)\n    dir_path = os.path.dirname(real_path)\n    py_file = real_path.replace(\".FCMacro\",\".py\").replace('Parametric_Defeaturing','parametric_defeaturing')\n    bHasFile = os.path.exists(py_file)\n    noImport = False #user elects not to save import file\n\n    if not bHasFile:\n        from PySide import QtCore,QtGui\n        window = QtGui.QApplication.activeWindow()\n        mb = QtGui.QMessageBox()\n        mb.setWindowTitle(BASENAME+\" setup\")\n        mb.setIcon(mb.Information)\n        mb.setStandardButtons(mb.Ok | mb.Cancel)\n        mb.setDefaultButton(mb.Cancel)\n        okBtn = mb.button(QtGui.QMessageBox.StandardButton.Ok)\n        cancelBtn = mb.button(QtGui.QMessageBox.StandardButton.Cancel)\n        okBtn.setText(\"Create file\")\n        cancelBtn.setText(\"Do not create file\")\n        caption = \"In order for \"+BASENAME+\" objects to be parametric after saving and reloading file\\n\\\nwe need to create another file on this computer.  File to be created will be: \\n\\n\"+py_file+\"\\n\\n\\\nThis makes it available to the system upon restarting FreeCAD and loading documents containing the \\\n\"+BASENAME+\" feature python objects.  Create file now?\\n\\n\"\n        mb.setText(caption)\n        ret = mb.exec_()\n        if ret == mb.Ok:\n            writeFile()\n            QtGui.QMessageBox.information(window,\"Success\",\"File successfully created.  Please note: if you uninstall \"+BASENAME+\" macro you need to manually remove \"+py_file+\", too.\\n\")\n        else:\n            new_lines = []\n            for line in code.splitlines():\n                if line.startswith('#'):\n                    if \"CODE_ENDS_HERE\" in line:\n                        break\n                    if line == \"# -*- coding: utf-8 -*-\":\n                        new_lines.append(line+\"\\n\")\n                        continue\n                    new_lines.append(line[1:]+\"\\n\")\n            code = \"\".join(new_lines)\n\n            #credit to Mila Nautikus for his answer to a question on stackoverflow, which I modified here\n            #in this example the filename is parametric_defeaturing.py\n            #https://stackoverflow.com/questions/5362771/how-to-load-a-module-from-code-in-a-string\n\n            ##########\n            import sys, importlib\n            my_name = 'parametric_defeaturing' #filename = parametric_defeaturing.py, so this must be 'parametric_defeaturing'\n            my_spec = importlib.util.spec_from_loader(my_name, loader=None)\n\n            parametric_defeaturing = importlib.util.module_from_spec(my_spec)\n\n            exec(code, parametric_defeaturing.__dict__)\n            sys.modules['parametric_defeaturing'] = parametric_defeaturing\n            makeObject(parametric_defeaturing)\n            noImport = True\n\n    if not noImport: #don't never use no double negatives\n\n        import parametric_defeaturing as PD\n        import addonmanager_utilities as utils\n\n        if PD.__version__ != __version__:\n            writeFile()\n            from PySide import QtCore,QtGui\n            window = QtGui.QApplication.activeWindow()\n            mbox = QtGui.QMessageBox()\n            mbox.setWindowTitle(BASENAME+\" updated\")\n\n            mbox.setText(BASENAME+\".py has been updated to version \"+__version__+\". \\\nYou must restart FreeCAD for the new changes to take effect and to use the macro.\")\n            mbox.setIcon(mbox.Warning)\n            mbox.setStandardButtons(mbox.Ok | mbox.Cancel)\n            mbox.setDefaultButton(mbox.Cancel)\n            okBtn = mbox.button(QtGui.QMessageBox.StandardButton.Ok)\n            cancelBtn = mbox.button(QtGui.QMessageBox.StandardButton.Cancel)\n            okBtn.setText(\"Restart now\")\n            cancelBtn.setText(\"Restart later\")\n            ret = mbox.exec_()\n            if ret == mbox.Ok:\n                QtCore.QTimer.singleShot(1000, utils.restart_freecad)\n        else:\n            makeObject(PD)",
    "url": "https://wiki.freecad.org/Macro_Parametric_Defeaturing",
    "raw_code_url": "https://gist.github.com/mwganson/0d55a5c51b1d6ff488b7a2f62bf50656/raw/140e9118deb955981a1ea499778cbf2521818e40/parametric_defeaturing.FCMacro",
    "wiki": "",
    "version": "0.2021.10.10.rev2",
    "license": "",
    "date": "2021-10-10.rev2",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Parametric_defeaturing.svg",
    "icon_source": "https://wiki.freecad.org//images/f/fa/Parametric_defeaturing.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Perpendicular To Wire",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro positions an object perpendicularly to the selected wire.<br /><br />Macro version: 00.03<br />Last modified: 2020-03-31<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/0/0c/Macro_Perpendicular_To_Wire.png\">ToolBar Icon</a>.<br />Author: Mario52<br /> ",
    "comment": "This macro positions an object perpendicularly to the selected wire.",
    "code": "# -*- coding: utf-8 -*-\n__title__   = \"Macro Perpendicular To Wire\"\n__author__  = \"Mario52\"\n__url__     = \"https://wiki.freecadweb.org/Macro_Perpendicular_To_Wire\"\n__version__ = \"00.03\"\n__date__    = \"31/03/2020\"\n\nimport Draft, Part\n\ntry:\n    sel = FreeCADGui.Selection.getSelection()                               # Select an object\n    \n    lineSelected = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0]   # first object the Path object or SubObjects\n    myCircle     = sel[1]                                                   # second object\n    \n    pointsDirection  = []\n    \n    pointsDirection = lineSelected.discretize(Number=500)                   # discretize the path line first selection\n    \n    v=pointsDirection[0].sub(pointsDirection[1])                            # avec vecteurs 1 et 2 (direction debut ligne)\n    r=App.Rotation(App.Vector(0,0,1),v)\n    \n    pl=FreeCAD.Placement()                                                  # placement object\n    pl.Rotation.Q = r.Q\n    pl.Base = pointsDirection[0]\n    myCircle.Placement = pl\n    \n    del pointsDirection[:]\n    FreeCAD.ActiveDocument.recompute()\nexcept Exception:\n    print( \"Select two objects. 1:The path 2:The object to align\" )",
    "url": "https://wiki.freecad.org/Macro_Perpendicular_To_Wire",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.03",
    "license": "",
    "date": "31/03/2020",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Perpendicular_To_Wire.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/0/0c/Macro_Perpendicular_To_Wire.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Remove parametric history",
    "on_wiki": true,
    "on_git": false,
    "desc": "This will remove all parametric associativity from an object, leaving it as a \"dumb\" shape<br /><br />Macro version: 1.0<br />Last modified: 2011-08-01<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/b/b7/Macro_Remove_parametric_history.png\">ToolBar Icon</a><br />Author: Yorik<br /> ",
    "comment": "This will remove all parametric associativity from an object, leaving it as a \"dumb\" shape",
    "code": "originalObject = FreeCAD.ActiveDocument.ActiveObject\nnewShape = originalObject.Shape.copy()\nnewName = FreeCAD.ActiveDocument.ActiveObject.Name\nFreeCAD.ActiveDocument.removeObject(newName)\nnewObject = FreeCAD.ActiveDocument.addObject(\"Part::Feature\",newName)\nnewObject.Shape = newShape",
    "url": "https://wiki.freecad.org/Macro_Remove_parametric_history",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2011-08-01",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Yorik",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Remove_parametric_history.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/b/b7/Macro_Remove_parametric_history.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Rotate To Point",
    "on_wiki": true,
    "on_git": false,
    "desc": "Macro to rotate an object on itself with the axis of rotation the: boundbox center, center of mass, direction of wire, or last point clicked. You must save in a file all coordinate worked and save it in a file \"Coordinate [(0.06,1.30,0.0),(85.0,0.0,0.0)],\" or in a complete macro with different options (Create serial image) for create one animation, increase/decrease, pause, yoyo ....<br /><br />Macro version: 00.11<br />Last modified: 2022/10/17<br />FreeCAD version: 0.19 and more<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/d/d1/Macro_Rotate_To_Point.svg\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Macro to rotate an object on itself with the axis of rotation the: boundbox center, center of mass, direction of wire, or last point clicked. You must save in a file all coordinate worked and save it in a file \"Coordinate [(0.06,1.30,0.0),(85.0,0.0,0.0)],\" or in a complete macro with different options (Create serial image) for create one animation, increase/decrease, pause, yoyo ....",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2017 2018 2019 2020 2021 2022 <mario52>                 *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#\n#\n#OS: Windows 10 Version 2009\n#Word size of FreeCAD: 64-bit\n#Version: 0.21.30492 (Git)\n#Build type: Release\n#Branch: master\n#Hash: b4578fb3eae842eb510a1bc055d07d369a67ce94\n#Python 3.8.13, Qt 5.15.4, Coin 4.0.0, Vtk 9.1.0, OCC 7.6.3\n#Locale: French/Mars (fr_Ma)\n#\n#\n__title__   = \"Rotate_To_Point\"\n__author__  = \"Mario52\"\n__url__     = \"https://www.freecadweb.org/\"\n__Wiki__    = \"https://www.freecadweb.org/wiki/Macro_Rotate_To_Point\"\n__version__ = \"00.11\"\n__date__    = \"2022/10/17\"  #YYYY/MM/DD\n#\n#\nimport PySide2\nfrom PySide2 import (QtWidgets, QtCore, QtGui)\nfrom PySide2.QtWidgets import *\nfrom PySide2.QtCore import *\nfrom PySide2.QtGui import *\nfrom PySide2.QtWidgets import QComboBox\n#from PySide2.QtWidgets import (QWidget, QApplication, QSlider, QGraphicsView, QGraphicsScene, QVBoxLayout, QStyle, QListWidget)\n#from PySide2.QtCore import QDate\n#from PySide2.QtGui import (QPainter, QColor, QIcon, QBrush, QPalette)\nfrom PySide2.QtSvg import *\n\nimport unicodedata\nimport re\nimport operator\nfrom operator import itemgetter, attrgetter, methodcaller    # pour sort \n\nimport Draft, Part, PartGui, FreeCADGui, FreeCAD\nfrom FreeCAD import Base\nimport DraftVecUtils\nimport time, os\n\nGui = FreeCADGui\nApp = FreeCAD\n\nglobal ui            ; ui             = \"\"\nglobal sourisPass    ; sourisPass     = 0\nglobal positionMouse ; positionMouse  = \"\"\n\nglobal selM          ; selM           = \"\"\nglobal originalObject; originalObject = \"\"\nglobal myObject      ; myObject       = \"\"\nglobal myObjectName  ; myObjectName   = \"\"\nglobal myObjectLabel ; myObjectLabel  = \"\"\n\nglobal originalPlacement; originalPlacement = \"\"\nglobal valeur        ; valeur         = 0.0\n\nglobal posX          ; posX           = 0.0\nglobal posY          ; posY           = 0.0\nglobal posZ          ; posZ           = 0.0\n\nglobal rotAngleX     ; rotAngleX      = 0.0\nglobal rotAngleY     ; rotAngleY      = 0.0\nglobal rotAngleZ     ; rotAngleZ      = 0.0\n\nglobal axisX         ; axisX          = 0.0\nglobal axisY         ; axisY          = 0.0\nglobal axisZ         ; axisZ          = 0.0\n\nglobal posFollow     ; posFollow      = []\nglobal compPosFollow ; compPosFollow  = 0\n\nglobal saveOnDisk    ; saveOnDisk     = []\nglobal saveListView  ; saveListView   = \"\"\nglobal memorySelected; memorySelected = []\nglobal countMemory   ; countMemory    = 0\nglobal duplicate_Memory ;duplicate_Memory = []\nglobal duplicate_View; duplicate_View = []\n\nglobal s             ; s               = \"\"\n\n##path###########################################################################\nglobal path, path2                                                  #\n#path  = FreeCAD.ConfigGet(\"AppHomePath\")                           # path FreeCAD installation\n#path  = FreeCAD.ConfigGet(\"UserAppData\")                           # path FreeCAD User data\n#path  = \"your path\"                                                # your directory path\nparam = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")# macro path\npath = param.GetString(\"MacroPath\",\"\") + \"/\"                        # macro path\npath = path.replace(\"\\\\\",\"/\")                                       # convert the \"\\\" to \"/\"\n#print( \"Path for the icons : \" , path  )                            # \n#################################################################################\n\nglobal pathFile\n#### Configuration begin ##############################################################\npathFile = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__ ).GetString(\"setLastPath\")\nif pathFile == \"\":\n    pathFile = path\n    FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"setLastPath\",pathFile)\n####\nFreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"Version\",__version__ + \" (\" + __date__ + \")\")\nglobal switchZoomOnCilck\nswitchZoomOnCilck = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switchZoomOnCilck\")\nif switchZoomOnCilck == 0:\n    FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchZoomOnCilck\", switchZoomOnCilck)\n#### Configuration end   ##############################################################\n\n#### wiki help page ####\nimport WebGui\n\n#def on_PB_Help(self): # \n#    WebGui.openBrowser(\"http://www.freecadweb.org/wiki/index.php?title=xxxx\")\n#    App.Console.PrintMessage(\"http://www.freecadweb.org/wiki/index.php?title=xxxx\" + \"\\n\")\n#### wiki help page ####\n\n#### Detect version macro ###########################################\nglobal switchVersionMacroSearch#; switchVersionMacroSearch = False\ntry:\n    def versionSearch():\n        import urllib\n        import requests\n        contentPage = requests.get(\"https://wiki.freecadweb.org/Macro_\" + __title__).text\n        for i in contentPage.split(\"\\n\"):            # list page to line\n            if \"ctEven macro-version\" in i:\n                versionDetect = (i.split(\">\")[1])\n            if \"ctEven macro-date\" in i:\n                dateDetect = (i.split(\">\")[1])\n            try:\n                if (len(versionDetect) != 0) and (len(dateDetect) != 0):\n                    break\n            except Exception:\n                None\n        try:\n            if (versionDetect == __version__) and (dateDetect == __date__):\n                None\n            else:\n                msg = (\"New version availlable : \" + \"\\n\" + \n                      str(versionDetect) + \" : \" + str(dateDetect) + \"\\n\" + \n                      \"You can install with AddonManager\")\n                FreeCAD.Console.PrintMessage(\"your actual version    : \" + str(__version__) + \" : \" + str(__date__) + \"\\n\")\n                FreeCAD.Console.PrintMessage(\"new version availlable : \" + str(versionDetect) + \" : \" + str(dateDetect) + \"\\n\")\n                diag = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Information, 'New Version', msg)\n                diag.setWindowModality(QtCore.Qt.ApplicationModal)\n                diag.exec_()\n        except Exception:\n            None\n        return versionDetect, dateDetect\nexcept Exception:\n    FreeCAD.Console.PrintMessage(\"Failed to establish a connection\" + \"\\n\")\n#### Detect version macro ###########################################\n\nswitchVersionMacroSearch = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switchVersionMacroSearch\")\n\nif switchVersionMacroSearch == 0:\n    FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchVersionMacroSearch\", switchVersionMacroSearch)\nif switchVersionMacroSearch == True:\n    versionSearch()\n#### Detect version macro ###########################################\n\n\nQuit_Icon = [\n\"24 24 3 1\",\n\" \tc None\",\n\".\tc #FFFFFF\",\n\"+\tc #CC0000\",\n\"          ....          \",\n\"++++++++++....++++++++++\",\n\"+.......++....++.......+\",\n\"+.......++....++.......+\",\n\"+.......++....++.......+\",\n\"+...++++++....++++++...+\",\n\"+...++++++....++++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+......................+\",\n\"+......................+\",\n\"+......................+\",\n\"++++++++++++++++++++++++\"\n]\n\nboundBox_Center_Icon = [\n\"24 24 8 1\",\n\" \tc None\",\n\".\tc #284871\",\n\"+\tc #234C86\",\n\"@\tc #314B64\",\n\"#\tc #EF2929\",\n\"$\tc #4A74A4\",\n\"%\tc #4478AD\",\n\"&\tc #4E9A06\",\n\"                        \",\n\"           #            \",\n\"           #            \",\n\"           #            \",\n\"      &&&&&#            \",\n\"      &    #&&&&&&&     \",\n\"     &    +#..   &&     \",\n\"    &&&&&+%#%%. & &     \",\n\"    &  ++&&&&&&&  &     \",\n\"    &  +$$$$$$&+@ &     \",\n\"    & +%$$$$$$&+@ &     \",\n\"####&###$$$$$+&+####### \",\n\"    & +%$$$$++&+@ &     \",\n\"    & +%$$$+++&+@ &     \",\n\"    &  +$$++++&@  &     \",\n\"    &   ++++++&@  &     \",\n\"    &    @@@@@&   &     \",\n\"    &      #  &  &      \",\n\"    &&&&&  #  &&&       \",\n\"         &&&&&&         \",\n\"           #            \",\n\"           #            \",\n\"           #            \",\n\"                        \"\n]\n\ncenterMass_Icon = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #000100\",\n\"+\tc #CD0000\",\n\"@\tc #6B6014\",\n\"#\tc #B0A22C\",\n\"$\tc #D5B716\",\n\"%\tc #E9D235\",\n\"&\tc #F7E66C\",\n\"*\tc #FBF4BC\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"         ......         \",\n\"       ..#%%%%#..       \",\n\"      .@&&&%%%%%@.      \",\n\"     .@&**&%%%%%%@.     \",\n\"     .&***&%%%%%%%.     \",\n\"    .#&**&%%+%%%%%#.    \",\n\"    .%&&&%%++%%%$$%.    \",\n\"    .%%%%+++++$$$$$.    \",\n\"    .%%%%%+++++$$$$.    \",\n\"    .%%%%$$++$$$$$$.    \",\n\"    .#%$$$$+$$$$$$#.    \",\n\"     .%$$$$$$$$$$%.     \",\n\"     .@%$$$$$$$$$@.     \",\n\"      .@%$$$$$$%@.      \",\n\"       ..#$$$$#..       \",\n\"         ......         \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\npoint_Clicked_Icon = [\n\"24 24 7 1\",\n\" \tc None\",\n\".\tc #730000\",\n\"+\tc #9F0000\",\n\"@\tc #E90000\",\n\"#\tc #C39F03\",\n\"$\tc #ECD309\",\n\"%\tc #FBE851\",\n\"                        \",\n\"         #####          \",\n\"        #%%%%%#         \",\n\"       #%%%%%%$#        \",\n\"      #%%%%%$$$$#       \",\n\"      #%%%%$$$$$#       \",\n\"      #%%%+.$$$$#       \",\n\"      #%%%++.$$$#       \",\n\"       #%%+@+.$#        \",\n\"       #%%+@@+.#        \",\n\"        ##+@@@+.        \",\n\"          +@@@@+.       \",\n\"          +@@@@@+.      \",\n\"          +@@@@@@+.     \",\n\"          +@@@@@@@..    \",\n\"          +@@@@@@@@..   \",\n\"          +@@@@@@@@@..  \",\n\"          +@@@@@@+....  \",\n\"          +@@@@@+       \",\n\"          +@@++@@.      \",\n\"          +@+. .@@.     \",\n\"          ++.   .@.     \",\n\"                .+..    \",\n\"                 ..     \"\n]\n\naxis_X_Icon = [\n\"24 24 6 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"+\tc #A40000\",\n\"@\tc #EE2A2A\",\n\"#\tc #729FCF\",\n\"$\tc #B9BCB5\",\n\"           $$   $$$$    \",\n\"          $$$$  $  $    \",\n\"         $$$$$$   $     \",\n\"         $$$$$$  $      \",\n\"        $$$$$$$$ $$$    \",\n\"          $$$$          \",\n\"          $$$$          \",\n\"          $$$$          \",\n\"          $$$$          \",\n\"          $$$$    $$  $$\",\n\"         $$##$$   $$  $$\",\n\" .  .    $####$     $$$ \",\n\"  ...    +####$     $$  \",\n\"  ..    +@####$$    $   \",\n\" . ... +@@@+$$$$$  $$   \",\n\"      +@@@+  $$$$$      \",\n\"     +@@@+    $$$$$     \",\n\"  +++@@@+      $$$$$$$  \",\n\"  +@@@@+        $$$$$$  \",\n\"  +@@@+          $$$$$  \",\n\"  +++++          $$$$$  \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\naxis_Y_Icon = [\n\"24 24 7 1\",\n\" \tc None\",\n\".\tc #030303\",\n\"+\tc #4E9A06\",\n\"@\tc #729FCF\",\n\"#\tc #B9BCB5\",\n\"$\tc #BABDB6\",\n\"%\tc #8AE134\",\n\"           $$   ####    \",\n\"          $$$$  #  #    \",\n\"         $$$$$$   #     \",\n\"         $$$$$$  #      \",\n\"        $$$$$$$$ ###    \",\n\"          $$$$          \",\n\"          $$$$          \",\n\"          $$$$          \",\n\"          $$$$          \",\n\"          $$$$    ..  ..\",\n\"         $$@@$$   ..  ..\",\n\" #  #    $@@@@$     ... \",\n\"  ###    $@@@@+     ..  \",\n\"  ##    $$@@@@%+    .   \",\n\" # ### $$$$$+%%%+  ..   \",\n\"      $$$$$  +%%%+      \",\n\"     $$$$$    +%%%+     \",\n\"  $$$$$$$      +%%%+++  \",\n\"  $$$$$$        +%%%%+  \",\n\"  $$$$$          +%%%+  \",\n\"  $$$$$          +++++  \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\naxis_Z_Icon = [\n\"24 24 6 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"+\tc #204A87\",\n\"@\tc #1D89B6\",\n\"#\tc #729FCF\",\n\"$\tc #B9BCB5\",\n\"           ++    ...    \",\n\"          +@@+     .    \",\n\"         +@@@@+   .     \",\n\"         +@@@@+  .      \",\n\"        +++@@+++ ...    \",\n\"          +@@+          \",\n\"          +@@+          \",\n\"          +@@+          \",\n\"          +@@+          \",\n\"          +@@+    $$  $$\",\n\"         ++##++   $$  $$\",\n\" $  $    +####+     $$$ \",\n\"  $$$    $####$     $$  \",\n\"  $$    $$####$$    $   \",\n\" $ $$$ $$$$$$$$$$  $$   \",\n\"      $$$$$  $$$$$      \",\n\"     $$$$$    $$$$$     \",\n\"  $$$$$$$      $$$$$$$  \",\n\"  $$$$$$        $$$$$$  \",\n\"  $$$$$          $$$$$  \",\n\"  $$$$$          $$$$$  \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\ndirection_Icon = [\n\"24 24 6 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"+\tc #A40000\",\n\"@\tc #EE2A2A\",\n\"#\tc #565854\",\n\"$\tc #729FCF\",\n\"                        \",\n\"                        \",\n\"                 +++++  \",\n\"                  +@@+  \",\n\"                 +@@@+  \",\n\"                +@@@++  \",\n\"               +@@@+ +  \",\n\"              +@@@+     \",\n\"             +@@@+      \",\n\"            +@@@+       \",\n\"           +@@@+        \",\n\"          +@@@+         \",\n\"         +@@@+          \",\n\"        +@@@+           \",\n\"       +@@@+            \",\n\"      +@@@+             \",\n\"   + +@@@+              \",\n\"   ++@@@+               \",\n\"   +@@@+                \",\n\"   +@@+                 \",\n\"   +++++                \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\n\nfollow_Icon = [\n\"24 24 3 1\",\n\" \tc None\",\n\".\tc #A40000\",\n\"+\tc #EE2A2A\",\n\"                        \",\n\"                        \",\n\"       .                \",\n\"      ..                \",\n\"     .++.               \",\n\"    .+++.               \",\n\" . .+++++.              \",\n\" ..+++..+.              \",\n\" .+++. .++.             \",\n\" .++.   .+.             \",\n\" .....  .++.            \",\n\"         .+.      ..... \",\n\"         .++.      .++. \",\n\"          .+.     .+++. \",\n\"          .++.   .+++.. \",\n\"           .+.  .+++. . \",\n\"           .++..+++.    \",\n\"            .+.+++.     \",\n\"            .++++.      \",\n\"             .++.       \",\n\"             ...        \",\n\"              .         \",\n\"                        \",\n\"                        \"\n]\n\npoint_Icon = [\n\"24 24 8 1\",\n\" \tc None\",\n\".\tc #000100\",\n\"+\tc #B0A22C\",\n\"@\tc #E9D235\",\n\"#\tc #6B6014\",\n\"$\tc #F7E66C\",\n\"%\tc #FBF4BC\",\n\"&\tc #D5B716\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"         ......         \",\n\"       ..+@@@@+..       \",\n\"      .#$$$@@@@@#.      \",\n\"     .#$%%$@@@@@@#.     \",\n\"     .$%%%$@@@@@@@.     \",\n\"    .+$%%$@@@@@@@@+.    \",\n\"    .@$$$@@@@@&&&&&.    \",\n\"    .@@@@@@@&&&&&&&.    \",\n\"    .@@@@@&&&&&&&&&.    \",\n\"    .@@@@&&&&&&&&&&.    \",\n\"    .+@@&&&&&&&&&&+.    \",\n\"     .@&&&&&&&&&&&.     \",\n\"     .#&&&&&&&&&&#.     \",\n\"      .#&&&&&&&&#.      \",\n\"       ..+&&&&+..       \",\n\"         ......         \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\napply_Icon = [\n\"24 24 3 1\",\n\" \tc None\",\n\".\tc #4E9A06\",\n\"+\tc #FFFFFF\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                  .     \",\n\"                 .+.    \",\n\"                .+.+.   \",\n\"               .+...+.  \",\n\"              .+.....+. \",\n\"     .       .+.......+.\",\n\"    .+.     .+.......+. \",\n\"   .+.+.   .+.......+.  \",\n\"  .+...+. .+.......+.   \",\n\" .+.....+.+.......+.    \",\n\".+.......+.......+.     \",\n\" .+.............+.      \",\n\"  .+...........+.       \",\n\"   .+.........+.        \",\n\"    .+.......+.         \",\n\"     .+.....+.          \",\n\"      .+...+.           \",\n\"       .+.+.            \",\n\"        .+.             \",\n\"         .              \",\n\"                        \"\n]\n\nquit_Icon = [\n\"24 24 3 1\",\n\" \tc None\",\n\".\tc #FFFFFF\",\n\"+\tc #CC0000\",\n\"          ....          \",\n\"++++++++++....++++++++++\",\n\"+.......++....++.......+\",\n\"+.......++....++.......+\",\n\"+.......++....++.......+\",\n\"+...++++++....++++++...+\",\n\"+...++++++....++++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+......................+\",\n\"+......................+\",\n\"+......................+\",\n\"++++++++++++++++++++++++\"\n]\n\nsave_Icon = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #A30500\",\n\"+\tc #5D5F5C\",\n\"@\tc #3967A0\",\n\"#\tc #4B9A00\",\n\"$\tc #7E9BBD\",\n\"%\tc #A9ABA8\",\n\"&\tc #C7C9C6\",\n\"*\tc #DCDEDB\",\n\"                        \",\n\"      @@@@@             \",\n\"    @@$$$$$@            \",\n\"    @$$$$$$$@           \",\n\"   @@@@@@$@$$@          \",\n\"         @$@@@          \",\n\"    +%&&&@$@@@@&%%%     \",\n\"    +*@@@$@@@@@@@@&%    \",\n\"   +%*@@@@@@@@@@@@*&+   \",\n\"   +***@@@@@@@@@@***+   \",\n\"  +%***&@@@@@@@@&****+  \",\n\"  +****&&@@@@@@&&****+  \",\n\"  +***&&&&@@@@&&&&***+  \",\n\" +%***&&&&&@@&&&&&****+ \",\n\" +***&&&&&&&&&&&&&&***+ \",\n\" %********************+ \",\n\" %********************+ \",\n\" %&&&&&&&&&&&&&&&&&&&&+ \",\n\" %&%%%%%%%%%%%%%%%%%%%+ \",\n\" %&%%%%%%%%%%%%%%%%%%%+ \",\n\" %&%&&&%%%%%%%@%%#%%.%+ \",\n\" %%%%%%%%%%%%%%%%%%%%%+ \",\n\" ++++++++++++++++++++++ \",\n\"                        \"\n]\n\nclear_Icon = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #000200\",\n\"+\tc #8B0606\",\n\"@\tc #875209\",\n\"#\tc #E3383A\",\n\"$\tc #C19916\",\n\"%\tc #C4A163\",\n\"&\tc #E2C928\",\n\"*\tc #E4D05A\",\n\"   @@@                  \",\n\"  @%%%@                 \",\n\"  @%*@@                 \",\n\"  @%@*%@                \",\n\"   @%$$%@               \",\n\"   @%%$%%@              \",\n\"    @%$$$*@             \",\n\"     @$**+++            \",\n\"     @*%+##+.           \",\n\"      ++##+*$           \",\n\"      +#++****$         \",\n\"      ++****&**$        \",\n\"       &**&*&&&*$       \",\n\"       &*&&&*&$&*$      \",\n\"       $*&*&$&&$$*$     \",\n\"       $*&$&*$*&*$*$    \",\n\"        *&$$&&$&&&&*$   \",\n\"        $*&$&**$$**@    \",\n\"        $*&$&****&$     \",\n\"         $*$***$$@      \",\n\"         $***$@ @       \",\n\"          $@$@          \",\n\"            @           \",\n\"                        \"\n]\n\ndelete_Icon = [\n\"24 24 3 1\",\n\" \tc None\",\n\".\tc #A40000\",\n\"+\tc #EE2A2A\",\n\"                        \",\n\"                        \",\n\"       .         .      \",\n\"      .+.       .+.     \",\n\"     .+++.     .+++.    \",\n\"    .+++++.   .+++++.   \",\n\"   .+++++++. .+++++++.  \",\n\"    .+++++++.+++++++.   \",\n\"     .+++++++++++++.    \",\n\"      .+++++++++++.     \",\n\"       .+++++++++.      \",\n\"        .+++++++.       \",\n\"       .+++++++++.      \",\n\"      .+++++++++++.     \",\n\"     .+++++++++++++.    \",\n\"    .+++++++.+++++++.   \",\n\"   .+++++++. .+++++++.  \",\n\"    .+++++.   .+++++.   \",\n\"     .+++.     .+++.    \",\n\"      .+.       .+.     \",\n\"       .         .      \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\nmemo_Allume_Icon = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #4F514E\",\n\"+\tc #635D41\",\n\"@\tc #676966\",\n\"#\tc #848784\",\n\"$\tc #888A87\",\n\"%\tc #E9D312\",\n\"&\tc #FEEE4D\",\n\"*\tc #FDFFFC\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"         %%%%%%         \",\n\"        %%&&&&%%        \",\n\"       %%&&&&&&%%       \",\n\"      %%&&&**&&&%%      \",\n\"     %%&&&****&&&%%     \",\n\"     %&&&******&&&%     \",\n\"     %&&&******&&&%     \",\n\"     %&&&******&&&%     \",\n\"     %%&&&****&&&%%     \",\n\"      %%&&&**&&&%%      \",\n\"       %%&&&&&&%%       \",\n\"        %%%&&%%%        \",\n\"         .%%%%+         \",\n\"         @.....         \",\n\"         ..#$$@         \",\n\"         @@....         \",\n\"         ..$$$@         \",\n\"         @@....         \",\n\"          $$$$          \",\n\"                        \"\n]\n\nmemo_Eteint_Icon = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"+\tc #204A87\",\n\"@\tc #555753\",\n\"#\tc #4F514E\",\n\"$\tc #635D41\",\n\"%\tc #676966\",\n\"&\tc #848784\",\n\"*\tc #888A87\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"         ......         \",\n\"        ........        \",\n\"       ..........       \",\n\"      ............      \",\n\"     ....+.+.+.+...     \",\n\"     ...+.+.+.++...     \",\n\"     ...@......@...     \",\n\"     ...@......@...     \",\n\"     ....@....@....     \",\n\"      ....@..@....      \",\n\"       ...@..@...       \",\n\"        ..@..@..        \",\n\"         #@..@$         \",\n\"         %#####         \",\n\"         ##&**%         \",\n\"         %%####         \",\n\"         ##***%         \",\n\"         %%####         \",\n\"          ****          \",\n\"                        \"\n]\n\norigin_Icon = [\n\"24 24 14 1\",\n\" \tc None\",\n\".\tc #EF2929\",\n\"+\tc #A40000\",\n\"@\tc #DDDFDC\",\n\"#\tc #888A85\",\n\"$\tc #DDDEDB\",\n\"%\tc #DCDEDB\",\n\"&\tc #DCDEDC\",\n\"*\tc #DBDDDA\",\n\"=\tc #BABDB6\",\n\"-\tc #555753\",\n\";\tc #729FCF\",\n\">\tc #3465A4\",\n\",\tc #8191AA\",\n\"                        \",\n\"                        \",\n\"           .+           \",\n\"          ..++          \",\n\"         ....++         \",\n\"        .....+++        \",\n\"       ....@#++++       \",\n\"      ....@@@#++++      \",\n\"     ....@@@@@#++++     \",\n\"    ....@@@@$@@#++++    \",\n\"   ....@@@$@@%@@#++++   \",\n\"  ....@@@@@@@@%@@#++++  \",\n\"  ...@@@%%%%&%%*@@#+++  \",\n\"  ..@@@@@@@@@@@@@@@#++  \",\n\"   #@@=#---@@=====@#    \",\n\"   #@@=#---@@;>>>;@#    \",\n\"   #@@,#---@@;>>>;@#    \",\n\"   #@@,#---@@;>>>;@#    \",\n\"   #@@=#---@@-----@#    \",\n\"   #@@=#---@@@@@@@@#    \",\n\"   #@@=##--@@@@@@@@#    \",\n\"   #################    \",\n\"                        \",\n\"                        \"\n]\n\nzero_Icon = [\n\"24 24 6 1\",\n\" \tc None\",\n\".\tc #CC0000\",\n\"+\tc #000000\",\n\"@\tc #BABDB6\",\n\"#\tc #4E9A06\",\n\"$\tc #204A87\",\n\"           ..           \",\n\"           ..           \",\n\"           ..           \",\n\"           ..           \",\n\"           ..           \",\n\"           ..           \",\n\"           ..           \",\n\"   ++@     ..@     ++@  \",\n\"  ++++@   +..+@   ++++@ \",\n\" ++@ ++@ ++..++@ ++@ ++@\",\n\" +@   +@ +@.. +@ +@   +@\",\n\"######+@###$$#+@######+@\",\n\"######+@###$$#+@######+@\",\n\" ++@ ++@ ++..++@ ++@ ++@\",\n\"  ++++ +  ++++ +  ++++  \",\n\"   ++ ++   ++ ++   ++   \",\n\"      +    .. +         \",\n\"     ++    ..++         \",\n\"    ++     ..+          \",\n\"           ..           \",\n\"           ..           \",\n\"           ..           \",\n\"           ..           \",\n\"           ..           \"\n]\n\nreset_Icon = [\n\"24 24 3 1\",\n\" \tc None\",\n\".\tc #3465A4\",\n\"+\tc #888A85\",\n\"                        \",\n\"      ........          \",\n\"     .++++++++.         \",\n\"    .++..+....+.  ..... \",\n\"    .+.. .+....+. .+++. \",\n\"    .+.   .+....+..+.+. \",\n\"    ...    .+....+.+.+. \",\n\"            .+....+..+. \",\n\"             .+......+. \",\n\"              .+.....+. \",\n\"               .+....+. \",\n\"  ......        .+...+. \",\n\"  .++++.         .++++. \",\n\"  .+...+.        ...... \",\n\"  .+....+.              \",\n\"  .+.....+.             \",\n\"  .+......+.            \",\n\"  .+..+....+.           \",\n\"  .+.+.+....+.    ...   \",\n\"  .+.+..+....+.   .+.   \",\n\"  .+++. .+....+. ..+.   \",\n\"  .....  .+....+..++.   \",\n\"          .++++++++.    \",\n\"           ........     \"\n]\n\ncode_Python_Icon = [\n\"24 24 3 1\",\n\" \tc None\",\n\".\tc #3B7AAC\",\n\"+\tc #EDD400\",\n\"                        \",\n\"  ++++++++++++++++++++. \",\n\"  +                   . \",\n\"  +                   . \",\n\"  +     .....         . \",\n\"  +    . .....        . \",\n\"  +    ....... +      . \",\n\"  +        ... +++    . \",\n\"  +   ........ ++++   . \",\n\"  +  ......... +++++  . \",\n\"  + .........  ++++++ . \",\n\"  + .......   +++++++ . \",\n\"  + ......  +++++++++ . \",\n\"  +  ..... +++++++++  . \",\n\"  +   .... ++++++++   . \",\n\"  +    ... +++        . \",\n\"  +      . +++++++    . \",\n\"  +        +++++ +    . \",\n\"  +         +++++     . \",\n\"  +                   . \",\n\"  +                   . \",\n\"  +                   . \",\n\"  +.................... \",\n\"                        \"\n]\n\ncode_FC_Icon = [\n\"24 24 5 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"+\tc #CB0208\",\n\"@\tc #204A86\",\n\"#\tc #BABDB6\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"@@@    @@@    @@@    @@@\",\n\"@        @    @        @\",\n\"@   ++#  @    @   ++#  @\",\n\"@  ++++# @    @  ++++# @\",\n\"@ ++# ++#@    @ ++# ++#@\",\n\"@ +#   +#@    @ +#   +#@\",\n\"@ +#   +#@    @ +#   +#@\",\n\"@ +#   +#@    @ +#   +#@\",\n\"@ ++# ++#@    @ ++# ++#@\",\n\"@  ++++  @    @  ++++  @\",\n\"@   ++   @    @   ++   @\",\n\"@        @    @        @\",\n\"@        @    @        @\",\n\"@@@    @@@  . @@@    @@@\",\n\"           ..           \",\n\"           .            \",\n\"          ..            \",\n\"         ..             \",\n\"                        \"\n]\n\nrotate_Icon = [\n\"24 24 4 1\",\n\" \tc None\",\n\".\tc #000100\",\n\"+\tc #000201\",\n\"@\tc #6695BF\",\n\"                        \",\n\"       ++++++++         \",\n\"      +@@@@@@@@+        \",\n\"     +@@......@@++      \",\n\"    +@@.@@@@@@.@@@+ ++  \",\n\"   +@@.@@++++@@.@@@+@+  \",\n\"  +@@.@@+    +@@.@@@@+  \",\n\" +@@.@@+      +@@.@@@+  \",\n\" +@.@@+        +@@.@@@+ \",\n\" +@.@+       ++@@@@@@@+ \",\n\" +@.@+        ++@@@@@@+ \",\n\" +@.@+          +++@@@+ \",\n\" +@.@+            +++++ \",\n\" +@.@+                  \",\n\" +@.@@+                 \",\n\" +@@.@@+      +++       \",\n\"  +@@.@@+     +@+       \",\n\"   +@@.@@+++++@@+       \",\n\"    +@@.@@@@@@@@+       \",\n\"     +@@.....@@+        \",\n\"      +@@@@@@@++        \",\n\"       +++++++          \",\n\"                        \",\n\"                        \"\n]\n\ntranslate_Icon = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #000100\",\n\"+\tc #000407\",\n\"@\tc #6694BF\",\n\"#\tc #6D92BE\",\n\"$\tc #6A93C5\",\n\"%\tc #6795C0\",\n\"&\tc #6F93C0\",\n\"*\tc #6896C1\",\n\"                        \",\n\"                        \",\n\"          ..            \",\n\"          .@.           \",\n\"          .@@..         \",\n\"          .@@@@.        \",\n\"          .@@@@@.       \",\n\" ..........@@@@@@.      \",\n\"  +**&%%&@&@@@@@@@.     \",\n\" .............+@@@$..   \",\n\"  +@@@@@@@@@@@@@@@@@@.  \",\n\" ..........+@@@@@@@@@@. \",\n\"  +@@@@@@@@@@@@@@@@@@+  \",\n\" ........+@@@@@@@@@++   \",\n\"  +@@@@@@@@@@@@@@@.     \",\n\" ..........@@@@@@.      \",\n\"          .@@@@@.       \",\n\"          .@@@@.        \",\n\"          .@@..         \",\n\"          .@.           \",\n\"          ..            \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\nOnClickApply_Icon = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #910000\",\n\"+\tc #F20001\",\n\"@\tc #54595E\",\n\"#\tc #4B9A00\",\n\"$\tc #8A8C89\",\n\"%\tc #B0B2AE\",\n\"&\tc #FED758\",\n\"*\tc #DFE1DC\",\n\"                        \",\n\"        ..              \",\n\"        .......         \",\n\"         ....++         \",\n\"         .+.+++         \",\n\"      ....+++++         \",\n\"      $.+++++++%%%%     \",\n\"     **$.++++++***&&    \",\n\"    %***$.+++++&*&&&    \",\n\"    *****$.++++&&&&*    \",\n\"   %******$.+++&&&**%   \",\n\"   *******&$.++&&&&**   \",\n\"   ***&&&&&&$.+&&&&&&&  \",\n\"  %*******&&&$.&&&&**%  \",\n\"  *********&&&$&&&****  \",\n\"  ********&&&&&&&&&***% \",\n\" %*******&&&*&&&*&&&**% \",\n\" %%%%%%%%&&%%%&%%%&&%%$ \",\n\" %%%$%%%%%%%%%&%@%#%+%$ \",\n\" %%%$$%%%%%%%%&%%%%%%%$ \",\n\" %%%%%%%%%%%%%&%%%%%%%$ \",\n\" $%%%%%%%%%%%%%%%%%%%%$ \",\n\"  @@@@@@@@@@@@@@@@@@@@@ \",\n\"                        \"\n]\n\nnormalWork_Icon = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #565854\",\n\"+\tc #555753\",\n\"@\tc #2E3436\",\n\"#\tc #FFFFFF\",\n\"$\tc #FCE94F\",\n\"%\tc #FEFEFE\",\n\"&\tc #EDD400\",\n\"*\tc #BABDB6\",\n\"                        \",\n\" ...................... \",\n\" .                    . \",\n\" . +++++ +++++        . \",\n\" .                    . \",\n\" .                    . \",\n\" . +++++ +++++        . \",\n\" .                    . \",\n\" .                    . \",\n\" . +++++ +++++        . \",\n\" .                    . \",\n\" .                    . \",\n\" ...................... \",\n\"                        \",\n\"                        \",\n\"         @@@@@@@@@@@@@@@\",\n\"         @#$$#########%@\",\n\"         @#&&###@@@#@@%@\",\n\"         @%&&%########%@\",\n\"         @#**#########%@\",\n\"         @@@@@@@@@@@@@@@\",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\nPointCenter_Icon = [\n\"24 24 8 1\",\n\" \tc None\",\n\".\tc #CC0000\",\n\"+\tc #CB0007\",\n\"@\tc #363C3C\",\n\"#\tc #666768\",\n\"$\tc #999E9D\",\n\"%\tc #C2C4C0\",\n\"&\tc #E3E5E1\",\n\"                        \",\n\"        @@@@@@@         \",\n\" .    @@$%&&&%#@@   .   \",\n\"  .  @%&&&%%%&&&%@ .    \",\n\"   .@&&$#@@@@@$%&&.     \",\n\"   @.%#@       @#.&@    \",\n\"  @&&.@         .#&&@   \",\n\" @$&#@           @#&$@  \",\n\" @&%@             @%&@  \",\n\"@#&$    ++  ++     $&#@ \",\n\"@$&#    ++++++     #&$@ \",\n\"@$&@     ++++      @&$@ \",\n\"@$&@     ++++      @&$@ \",\n\"@#&#    ++++++     #&#@ \",\n\" @&$    ++  ++     $&@  \",\n\" @%&              @&%@  \",\n\"  @&@            @$&@   \",\n\"  @%&.          .#&%@   \",\n\"   @.&@@      @@$.%@    \",\n\"   .@%&&%@@@@@%&&%.     \",\n\"  .  @#%&&&&&&&$#@ .    \",\n\" .    @@#$$$$$#@@   .   \",\n\"        @@@@@@@         \",\n\"                        \"\n]\n\npositif_Icon = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #213B07\",\n\"+\tc #3B6212\",\n\"@\tc #487415\",\n\"#\tc #5AA713\",\n\"$\tc #66BB14\",\n\"%\tc #6FC31C\",\n\"&\tc #7ACE23\",\n\"*\tc #80D82B\",\n\"                        \",\n\"                        \",\n\"         ++++++         \",\n\"         +****+         \",\n\"         +****+         \",\n\"         +****+         \",\n\"         +****+         \",\n\"         +****+         \",\n\"         +****+         \",\n\"  ++++++++****++++++++  \",\n\"  +******************+  \",\n\"  +******************+  \",\n\"  +******************+  \",\n\"  +******************+  \",\n\"  ++++++++****++++++++  \",\n\"         +****+         \",\n\"         +****+         \",\n\"         +****+         \",\n\"         +****+         \",\n\"         +****+         \",\n\"         +****+         \",\n\"         ++++++         \",\n\"                        \",\n\"                        \"\n]\n\nnegatif_Icon = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #000100\",\n\"+\tc #3C0406\",\n\"@\tc #680A0D\",\n\"#\tc #7B0B13\",\n\"$\tc #B00206\",\n\"%\tc #C40D0D\",\n\"&\tc #D7171A\",\n\"*\tc #EA2525\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"  @@@@@@@@@@@@@@@@@@@@  \",\n\"  @******************@  \",\n\"  @******************@  \",\n\"  @******************@  \",\n\"  @******************@  \",\n\"  @@@@@@@@@@@@@@@@@@@@  \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \"\n]\n\ncopy_Icon = [\n\"24 24 7 1\",\n\" \tc None\",\n\".\tc #2E3436\",\n\"+\tc #888A85\",\n\"@\tc #C5C8C4\",\n\"#\tc #E8EAE7\",\n\"$\tc #EDF0ED\",\n\"%\tc #F2F5F1\",\n\"                        \",\n\" .................      \",\n\" .@@@@@@@@@@@@@@@.      \",\n\" .@$$$$$$$$$$$$$%.      \",\n\" .@$+++................ \",\n\" .@$$$#.@@@@@@@@@@@@@@. \",\n\" .@$+++.@$$$$$$$$$$$$$. \",\n\" .@$$$#.@$++++++++++$$. \",\n\" .@$+++.@$$$$$$$$$$$$$. \",\n\" .@$$$#.@#++++++++++$$. \",\n\" .@$+++.@$$$$$$$$$$$$$. \",\n\" .@$$$$.@#++++++++++$$. \",\n\" .@$$$$.@$$$$$$$$$$$$$. \",\n\" .@$+++.@#++++++++++$$. \",\n\" .@$$$$.@$$$$$$$$$$$$$. \",\n\" .@$+++.@$$$$$$$$$$$$$. \",\n\" .@$$$$.@$++++++++++$$. \",\n\" .@$$$$.@$$$$$$$$$$$$$. \",\n\" .@$$$$.@$++++++++++#$. \",\n\" .@@@@@.@$$$$$$$$$###$. \",\n\" .......@$$$$$$$%%###$. \",\n\"       .@@@@@@@@@@@@@@. \",\n\"       ................ \",\n\"                        \"\n]\n\nzoom_View_Icon = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #303436\",\n\"+\tc #EF2B29\",\n\"@\tc #3066A6\",\n\"#\tc #757774\",\n\"$\tc #6D9FD0\",\n\"%\tc #A9ABA8\",\n\"&\tc #DDDFDC\",\n\"*\tc #FFFFFF\",\n\"                        \",\n\"                        \",\n\"  ....................  \",\n\"  .&&&&&&&&&&&&&&&&&&.  \",\n\"  .&@@@@@****@@@@@@@&.  \",\n\"  .&@@@@**$$**@@@@@@&.  \",\n\"  .&@@@**$$$$**@@@@@&.  \",\n\"  .&@@@*$$**$$*@@@@@&.  \",\n\"  .&@@@*$$**$$*@@@@@&.  \",\n\"  .&@@@*$$$$$$*@@@@@&.  \",\n\"  .&@@@**$$$$**@@@@@&.  \",\n\"  .&@@@@**$$**+@@@@@&.  \",\n\"  .&@@@@@****+++@@@@&.  \",\n\"  .&@@@@@@@@@@+++@@@&.  \",\n\"  .&@@@@@@@@@@@+++@@&.  \",\n\"  .&@@@@@@@@@@@@+++@&.  \",\n\"  .&&&&&&&&&&&&&&+++&.  \",\n\"  ................+++.  \",\n\"       &&######&&  ++   \",\n\"      &#%%####%%#&      \",\n\"      &##%%%%%%##&      \",\n\"       &########&       \",\n\"        &&&&&&&&        \",\n\"                        \"\n]\n\nglobal objectPlacementAngle ; objectPlacementAngle = \"\"\ndef objectRealPlacement3D(obj):\n    global objectPlacementAngle\n    try:\n        objectPlacement      = obj.Shape.Placement\n        #### \n        objectPlacementBase  = FreeCAD.Vector(objectPlacement.Base)\n        ####\n        objectWorkCenter     = objectPlacementBase\n        ####\n        objectPlacementAngle = objectPlacement.Rotation.toEuler()\n\n        if hasattr(obj, \"getGlobalPlacement\"):\n            globalPlacement       = obj.getGlobalPlacement()\n            globalPlacementBase   = FreeCAD.Vector(globalPlacement.Base)\n            objectRealPlacement3D = globalPlacementBase.add(objectWorkCenter).sub(objectPlacementBase)\n            objectPlacementAngle  = globalPlacement.Rotation.toEuler()\n        else:\n            objectRealPlacement3D = objectWorkCenter\n\n        return objectRealPlacement3D\n    except Exception:\n        return FreeCAD.Vector(0.0, 0.0, 0.0)\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n        \nclass Ui_MainWindow(object):\n    def __init__(self ):\n        global path, path2\n        self.window = MainWindow\n        self.path = path\n        self.countOpenTransaction = 0\n        self.setFrameWindowSizeX = 400\n        self.setFrameWindowSizeY = 500\n        self.setMainWindowMoveX  = 900\n        self.setMainWindowMoveY  = 100\n        self.restore_Values = []\n        self.vueActive = FreeCADGui.ActiveDocument.ActiveView\n        self.click = self.vueActive.addEventCallback(\"SoMouseButtonEvent\",self.souris)\n\n    def souris(self,info):\n        global sourisPass\n        if (info[\"Button\"] == \"BUTTON1\") and (info[\"State\"] == \"DOWN\"):\n            #time.sleep(0.02)\n            sourisPass = 0\n            #print(\"ok\")\n\n    def setupUi(self, MainWindow):\n        self.window = MainWindow\n        MainWindow.setObjectName(_fromUtf8(\"MainWindow\"))\n        global saveListView\n        global switchZoomOnCilck\n\n        self.setFrameWindowSizeX = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"setFrameWindowSizeX\")\n        if self.setFrameWindowSizeX == 0:\n            self.setFrameWindowSizeX = 400\n        self.setFrameWindowSizeY = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"setFrameWindowSizeY\")\n        if self.setFrameWindowSizeY == 0:\n            self.setFrameWindowSizeY = 500\n        self.setMainWindowMoveX = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"setMainWindowMoveX\")\n        if self.setMainWindowMoveX == 0:\n            self.setMainWindowMoveX = 900\n        self.setMainWindowMoveY = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"setMainWindowMoveY\")\n        if self.setMainWindowMoveY == 0:\n            self.setMainWindowMoveY = 100\n\n#        MainWindow.setMinimumSize(QtCore.QSize(330, 10))\n#        MainWindow.setMaximumSize(QtCore.QSize(330, 330))\n#        MainWindow.setStyleSheet(\"background-color: rgb(50, 50, 50);\")  \n\n        MainWindow.resize(self.setFrameWindowSizeX, self.setFrameWindowSizeY)\n        MainWindow.move(self.setMainWindowMoveX, self.setMainWindowMoveY)\n\n        self.centralwidget = QtWidgets.QWidget(MainWindow)\n        self.centralwidget.setObjectName(_fromUtf8(\"centralwidget\"))\n\n        self.groupBox_Cadre = QtWidgets.QGroupBox()\n\n        ####scrollArea###############\n        grid = QtWidgets.QGridLayout()\n        self.centralwidget.setLayout(grid)\n        ####\n        self.scrollArea = QtWidgets.QScrollArea(self.centralwidget)    # cadre scrollarea contenant le widget GUI\n        self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)\n        self.scrollArea.setWidgetResizable(True)\n        grid.addWidget(self.scrollArea, 0, 0)\n        self.vbox = QtWidgets.QVBoxLayout()\n        self.scrollArea.setLayout(self.vbox)\n        ####\n        self.scrollAreaWidgetContents_2 = QtWidgets.QWidget()          #widget contenant le GUI\n        self.vbox.addWidget(self.scrollAreaWidgetContents_2)\n        self.vbox = QtWidgets.QVBoxLayout()\n        self.scrollAreaWidgetContents_2.setLayout(self.vbox)\n        ####scrollArea###############\n\n        ####\n        self.groupBox_Position = QtWidgets.QGroupBox()\n        self.groupBox_Position.setEnabled(False)\n\n        self.CB_Position = QtWidgets.QCheckBox()\n        self.CB_Position.setIcon(QtGui.QIcon(QtGui.QPixmap(translate_Icon))) #icone dans une variable \n        self.CB_Position.clicked.connect(self.on_CB_Position)\n\n        ####\n        self.label_Timer = QtWidgets.QLCDNumber()\n        self.label_Timer.setSegmentStyle(QLCDNumber.Outline)   # Filled  Flat\n        self.label_Timer.setDigitCount(12)\n        ####\n#        self.label_Timer = QtWidgets.QLabel()\n#        self.label_Timer.setAlignment(Qt.AlignRight)\n        self.timeFn = time.perf_counter\n        self.startTime = self.timeFn()\n        ## https://doc.qt.io/qtforpython-5/PySide2/QtCore/QTimer.html#detailed-description\n        self.timer = QTimer()\n        ##self.timer.setInterval(1)\n        self.timer.timeout.connect(self.on_displayTime)\n        self.timer.start()\n        ####\n\n        self.groupBox_Axis_Rotation = QtWidgets.QGroupBox()\n\n        self.groupBox_Axis = QtWidgets.QGroupBox()\n        self.groupBox_Axis.setEnabled(False)\n\n        self.RB_Bond_Box_Center = QtWidgets.QRadioButton()\n        self.RB_Bond_Box_Center.setChecked(True)\n        self.RB_Bond_Box_Center.setIcon(QtGui.QIcon(QtGui.QPixmap(boundBox_Center_Icon))) #icone dans une variable \n        self.RB_Bond_Box_Center.clicked.connect(self.on_RB_CenterRot)\n\n        self.RB_Center_Mass = QtWidgets.QRadioButton()\n        self.RB_Center_Mass.setIcon(QtGui.QIcon(QtGui.QPixmap(centerMass_Icon))) # icone dans une variable \n        self.RB_Center_Mass.clicked.connect(self.on_RB_CenterRot)\n\n        self.RB_Point_Clicked = QtWidgets.QRadioButton()\n        self.RB_Point_Clicked.setIcon(QtGui.QIcon(QtGui.QPixmap(point_Clicked_Icon))) # icone dans une variable \n        self.RB_Point_Clicked.clicked.connect(self.on_RB_CenterRot)\n\n        ####\n        self.groupBox_Rotation = QtWidgets.QGroupBox()\n        self.groupBox_Rotation.setEnabled(False)\n\n        self.RB_Rotation_0 = QtWidgets.QRadioButton()    # factice pour bouton invisible\n        self.RB_Rotation_0.setVisible(False)\n#        self.RB_Rotation_0.clicked.connect(self.on_RB_Rotation_0)\n\n        self.RB_Rotation_X = QtWidgets.QRadioButton()\n        self.RB_Rotation_X.setChecked(True)\n        self.RB_Rotation_X.setIcon(QtGui.QIcon(QtGui.QPixmap(axis_Z_Icon))) # icone dans une variable \n        self.RB_Rotation_X.clicked.connect(self.on_RB_Rotation_X)\n\n        self.RB_Rotation_Y = QtWidgets.QRadioButton()\n        self.RB_Rotation_Y.setIcon(QtGui.QIcon(QtGui.QPixmap(axis_Y_Icon))) # icone dans une variable \n        self.RB_Rotation_Y.clicked.connect(self.on_RB_Rotation_Y)\n#        self.RB_Angle_Y.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))  # Bold\n#        self.RB_Angle_Y.setStyleSheet(\"color : #008700\")                         # Color text\n\n        self.RB_Rotation_Z = QtWidgets.QRadioButton()\n        self.RB_Rotation_Z.setIcon(QtGui.QIcon(QtGui.QPixmap(axis_X_Icon))) # icone dans une variable \n        self.RB_Rotation_Z.clicked.connect(self.on_RB_Rotation_Z)\n\n        self.RB_Direction_D = QtWidgets.QRadioButton()\n        self.RB_Direction_D.setIcon(QtGui.QIcon(QtGui.QPixmap(direction_Icon))) # icone dans une variable \n        self.RB_Direction_D.clicked.connect(self.on_RB_Direction_D)\n\n        self.RB_Follow_The_Path_F = QtWidgets.QRadioButton()\n        self.RB_Follow_The_Path_F.setEnabled(False)\n        self.RB_Follow_The_Path_F.setIcon(QtGui.QIcon(QtGui.QPixmap(follow_Icon))) # icone dans une variable \n        self.RB_Follow_The_Path_F.clicked.connect(self.on_RB_Follow_The_Path_F)\n        ####\n\n        self.groupBox_Pos_Mouse = QtWidgets.QGroupBox()\n        self.groupBox_Pos_Mouse.setEnabled(False)\n\n        self.DS_Pos_Mouse_X = QtWidgets.QDoubleSpinBox()\n        self.DS_Pos_Mouse_X.setMinimum(-999999.9)\n        self.DS_Pos_Mouse_X.setMaximum(99999999.9)\n        self.DS_Pos_Mouse_X.setDecimals(6)\n        self.DS_Pos_Mouse_X.setSuffix(\" X\")\n        self.DS_Pos_Mouse_X.valueChanged.connect(self.on_DS_Pos_Mouse_X)\n\n        self.DS_Pos_Mouse_Y = QtWidgets.QDoubleSpinBox()\n        self.DS_Pos_Mouse_Y.setMinimum(-999999.9)\n        self.DS_Pos_Mouse_Y.setMaximum(99999999.9)\n        self.DS_Pos_Mouse_Y.setDecimals(6)\n        self.DS_Pos_Mouse_Y.setSuffix(\" Y\")\n        self.DS_Pos_Mouse_Y.valueChanged.connect(self.on_DS_Pos_Mouse_Y)\n\n        self.DS_Pos_Mouse_Z = QtWidgets.QDoubleSpinBox()\n        self.DS_Pos_Mouse_Z.setMinimum(-999999.9)\n        self.DS_Pos_Mouse_Z.setMaximum(99999999.9)\n        self.DS_Pos_Mouse_Z.setDecimals(6)\n        self.DS_Pos_Mouse_Z.setSuffix(\" Z\")\n        self.DS_Pos_Mouse_Z.valueChanged.connect(self.on_DS_Pos_Mouse_Z)\n\n        ####\n        self.groupBox_Work = QtWidgets.QGroupBox()\n        self.groupBox_Work.setEnabled(False)\n\n#        self.SC_Slider_Bar = QtWidgets.QSlider()\n#        self.SC_Slider_Bar.setMinimum(0.0)\n#        self.SC_Slider_Bar.setMaximum(359.0)\n#        self.SC_Slider_Bar.setValue(0.0)\n#        self.SC_Slider_Bar.setSliderPosition(0)\n#        self.SC_Slider_Bar.setOrientation(QtCore.Qt.Horizontal)\n#        self.SC_Slider_Bar.valueChanged.connect(self.on_SC_Slider_Bar)\n\n        self.CB_View = QtWidgets.QCheckBox()\n        self.CB_View.setIcon(QtGui.QIcon(QtGui.QPixmap(zoom_View_Icon))) #icone dans une variable \n        self.CB_View.setChecked(switchZoomOnCilck)\n        self.CB_View.clicked.connect(self.on_CB_View)\n\n        self.PB_Point = QtWidgets.QPushButton()\n        self.PB_Point.setIcon(QtGui.QIcon(QtGui.QPixmap(point_Icon))) # icone dans une variable \n        self.PB_Point.clicked.connect(self.on_CB_Point)\n\n        self.PB_PointCenter = QtWidgets.QPushButton()\n        self.PB_PointCenter.setIcon(QtGui.QIcon(QtGui.QPixmap(PointCenter_Icon))) # icone dans une variable \n        self.PB_PointCenter.clicked.connect(self.on_PB_PointCenter)\n\n        self.CBox_View = QtWidgets.QComboBox()\n        #QtCore.QObject.connect(self.CBox_View, QtCore.SIGNAL(\"currentIndexChanged(QString)\"), self.on_CBox_View)\n        QtCore.QObject.connect(self.CBox_View, QtCore.SIGNAL(\"activated(QString)\"), self.on_CBox_View)\n\n        self.CBox_Impost = QtWidgets.QComboBox()\n        self.CBox_Impost.setCurrentIndex(5)\n        self.CBox_Impost.setMaxVisibleItems(17)\n        for i in range(17):    # number item\n            self.CBox_Impost.addItem(\"\")\n        QtCore.QObject.connect(self.CBox_Impost, QtCore.SIGNAL(\"currentIndexChanged(QString)\"), self.on_CBox_Impost)\n\n        self.CBox_Memory = QtWidgets.QComboBox()\n        #self.CBox_Memory.addItem(\"\")\n        self.CBox_Memory.setDuplicatesEnabled(True) #False\n        #QtCore.QObject.connect(self.CBox_Memory, QtCore.SIGNAL(\"currentIndexChanged(QString)\"), self.on_CBox_Memory)\n        QtCore.QObject.connect(self.CBox_Memory, QtCore.SIGNAL(\"activated(QString)\"), self.on_CBox_Memory)\n\n        self.PB_Negatif = QtWidgets.QPushButton()\n        self.PB_Negatif.setIcon(QtGui.QIcon(QtGui.QPixmap(negatif_Icon))) # icone dans une variable \n        self.PB_Negatif.clicked.connect(self.on_PB_Negatif_clicked)\n\n        self.DS_Value_Angle_Dimension = QtWidgets.QDoubleSpinBox()\n        self.DS_Value_Angle_Dimension.setMinimum(-360.0)\n        self.DS_Value_Angle_Dimension.setMaximum(360.0)\n        self.DS_Value_Angle_Dimension.setSuffix(\" Degrees\")\n        self.DS_Value_Angle_Dimension.setDecimals(5)\n        self.DS_Value_Angle_Dimension.valueChanged.connect(self.on_DS_Value_Angle_Dimension)\n\n        self.PB_Apply = QtWidgets.QPushButton()\n        self.PB_Apply.setAutoRepeat(True)\n        self.PB_Apply.setIcon(QtGui.QIcon(QtGui.QPixmap(apply_Icon))) # icone dans une variable \n        self.PB_Apply.clicked.connect(self.on_PB_Apply_clicked)\n\n        self.LE_Increment = QtWidgets.QLineEdit()\n        self.LE_Increment.setReadOnly(True)\n        self.LE_Increment.setText(str(0.0))\n        #self.LE_Increment.returnPressed.connect(self.on_LE_Increment_Pressed)\n        self.LE_Increment.textChanged.connect(self.on_LE_Increment_Pressed)\n\n        self.label_00 = QtWidgets.QLabel()\n#        self.label_00.setStyleSheet(\"color : #ffffff; background-color: red; font: bold 11px;\")   # white red bold\n\n        self.groupBox_Data = QtWidgets.QGroupBox()\n        self.groupBox_Data.setEnabled(False)\n\n        self.TE_Memorize = QtWidgets.QListView()\n        saveListView = QtGui.QStandardItemModel()\n        self.TE_Memorize.setModel(saveListView)\n        self.TE_Memorize.setSelectionRectVisible(True)#\n        self.TE_Memorize.setAlternatingRowColors(True)#\n        self.TE_Memorize.setStyleSheet(\"alternate-background-color:#fdeeee;\")\n        self.TE_Memorize.clicked[QtCore.QModelIndex].connect(self.on_TE_Clicked)\n\n        self.PB_ClearMemo = QtWidgets.QPushButton()\n        self.PB_ClearMemo.setIcon(QtGui.QIcon(QtGui.QPixmap(clear_Icon))) # icone dans une variable \n        self.PB_ClearMemo.clicked.connect(self.on_PB_ClearMemo)\n\n        self.PB_Delete_Line_Memory = QtWidgets.QPushButton()\n        self.PB_Delete_Line_Memory.setIcon(QtGui.QIcon(QtGui.QPixmap(delete_Icon))) # icone dans une variable \n        self.PB_Delete_Line_Memory.clicked.connect(self.on_PB_Delete_Line_Memory)\n\n        self.CB_On_Click_Apply = QtWidgets.QCheckBox()\n        self.CB_On_Click_Apply.setIcon(QtGui.QIcon(QtGui.QPixmap(OnClickApply_Icon))) # icone dans une variable \n        self.CB_On_Click_Apply.clicked.connect(self.on_CB_On_Click_Apply)\n\n        self.PB_Memorize = QtWidgets.QPushButton()\n        self.PB_Memorize.setIcon(QtGui.QIcon(QtGui.QPixmap(memo_Eteint_Icon))) # icone dans une variable \n        self.PB_Memorize.clicked.connect(self.on_PB_Memorize)\n\n        self.PB_Save_Memorize = QtWidgets.QPushButton()\n        self.PB_Save_Memorize.setIcon(QtGui.QIcon(QtGui.QPixmap(save_Icon))) # icone dans une variable \n        self.PB_Save_Memorize.clicked.connect(self.on_PB_Save_Memorize)\n\n        self.CB_DataInMacro = QtWidgets.QCheckBox()\n        self.CB_DataInMacro.setIcon(QtGui.QIcon(QtGui.QPixmap(code_Python_Icon))) # icone dans une variable \n        self.CB_DataInMacro.clicked.connect(self.On_CB_DataInMacro)\n\n        self.PB_Clip_Board = QtWidgets.QPushButton()\n        self.PB_Clip_Board.setIcon(QtGui.QIcon(QtGui.QPixmap(copy_Icon))) # icone dans une variable \n        self.PB_Clip_Board.clicked.connect(self.on_PB_Clip_Board)\n        ####\n\n        self.groupBox_Command = QtWidgets.QGroupBox()\n\n        self.PB_Quit = QtWidgets.QPushButton()\n        self.PB_Quit.setIcon(QtGui.QIcon(QtGui.QPixmap(quit_Icon))) # icone dans une variable \n        self.PB_Quit.clicked.connect(self.on_PB_Quit_clicked)\n\n        self.PB_Original = QtWidgets.QPushButton()\n        self.PB_Original.setIcon(QtGui.QIcon(QtGui.QPixmap(origin_Icon))) # icone dans une variable \n        self.PB_Original.clicked.connect(self.on_PB_Original_clicked)\n\n        self.PB_Zero = QtWidgets.QPushButton()\n        self.PB_Zero.setIcon(QtGui.QIcon(QtGui.QPixmap(zero_Icon))) # icone dans une variable \n        self.PB_Zero.clicked.connect(self.on_PB_Zero_clicked)\n\n        self.PB_Reset = QtWidgets.QPushButton()\n        self.PB_Reset.setIcon(QtGui.QIcon(QtGui.QPixmap(reset_Icon))) # icone dans une variable \n        self.PB_Reset.clicked.connect(self.on_PB_Reset_clicked)\n\n        #### Gridlayout Header\n        self.gridLayout_00_00 = QtWidgets.QGridLayout() #self.centralwidget\n        self.gridLayout_00_00.setContentsMargins(10, 10, 10, 10)#Gauche Haut Droit Bas\n        #### Gridlayout Header\n        #### Gridlayout BEGIN\n        ####\n        self.grid_00_00_00 = QtWidgets.QGridLayout(self.groupBox_Position)\n        self.grid_00_00_00.setContentsMargins(10, 10, 10, 10)\n        self.grid_00_00_00.addWidget(self.CB_Position, 0, 0, 1, 1)\n        self.grid_00_00_00.addWidget(self.label_Timer, 0, 1, 1, 1)\n        self.vbox.addWidget(self.groupBox_Position)      # scrollArea\n        ####\n        self.grid_00_00_AR = QtWidgets.QGridLayout(self.groupBox_Axis_Rotation) # groupe axis+rotation\n        self.grid_00_00_AR.setContentsMargins(10, 10, 10, 10)\n        #\n        self.grid_00_01_00 = QtWidgets.QGridLayout(self.groupBox_Rotation)\n        self.grid_00_01_00.setContentsMargins(10, 10, 10, 10)\n        self.grid_00_01_00.addWidget(self.RB_Bond_Box_Center, 0, 0, 1, 1)\n        self.grid_00_01_00.addWidget(self.RB_Center_Mass, 1, 0, 1, 1)\n        self.grid_00_01_00.addWidget(self.RB_Point_Clicked, 2, 0, 1, 1)\n        self.grid_00_00_AR.addWidget(self.groupBox_Rotation, 0, 0, 1, 1)\n        #\n        self.grid_00_02_00 = QtWidgets.QGridLayout(self.groupBox_Axis)\n        self.grid_00_02_00.setContentsMargins(10, 10, 10, 10)\n        self.grid_00_02_00.addWidget(self.RB_Rotation_X, 0, 0, 1, 1)\n        self.grid_00_02_00.addWidget(self.RB_Rotation_Y, 1, 0, 1, 1)\n        self.grid_00_02_00.addWidget(self.RB_Rotation_Z, 2, 0, 1, 1)\n        self.grid_00_02_00.addWidget(self.RB_Direction_D, 3, 0, 1, 1)\n        self.grid_00_02_00.addWidget(self.RB_Follow_The_Path_F, 4, 0, 1, 1)\n        self.grid_00_00_AR.addWidget(self.groupBox_Axis, 0, 1, 1, 1)\n        self.vbox.addWidget(self.groupBox_Axis_Rotation)      # scrollArea\n        ####\n        self.grid_00_03_00 = QtWidgets.QGridLayout(self.groupBox_Pos_Mouse)\n        self.grid_00_03_00.setContentsMargins(10, 10, 10, 10)\n        self.grid_00_03_00.addWidget(self.DS_Pos_Mouse_X, 0, 0, 1, 1)\n        self.grid_00_03_00.addWidget(self.DS_Pos_Mouse_Y, 0, 1, 1, 1)\n        self.grid_00_03_00.addWidget(self.DS_Pos_Mouse_Z, 0, 2, 1, 1)\n        self.vbox.addWidget(self.groupBox_Pos_Mouse)      # scrollArea\n        ####\n        self.grid_00_044_00 = QtWidgets.QGridLayout(self.groupBox_Work)\n        self.grid_00_044_00.setContentsMargins(10, 10, 10, 10)\n        self.grid_00_044_00.addWidget(self.CB_View, 0, 0, 1, 1)\n        self.grid_00_044_00.addWidget(self.PB_Point, 0, 1, 1, 1)\n        self.grid_00_044_00.addWidget(self.PB_PointCenter, 0, 2, 1, 1)\n        #\n        self.grid_00_044_00.addWidget(self.CBox_View, 1, 0, 1, 1)\n        self.grid_00_044_00.addWidget(self.CBox_Impost, 1, 1, 1, 1)\n        self.grid_00_044_00.addWidget(self.CBox_Memory, 1, 2, 1, 1)\n        #\n        self.grid_00_044_00.addWidget(self.PB_Negatif, 2, 0, 1, 1)\n        self.grid_00_044_00.addWidget(self.DS_Value_Angle_Dimension, 2, 1, 1, 1)\n        self.grid_00_044_00.addWidget(self.PB_Apply, 2, 2, 1, 1)\n        #\n        self.grid_00_044_00.addWidget(self.LE_Increment, 3, 0, 1, 3)\n        self.grid_00_044_00.addWidget(self.label_00, 4, 0, 1, 3)\n        self.vbox.addWidget(self.groupBox_Work)      # scrollArea\n        ####\n        self.grid_00_044b_00 = QtWidgets.QGridLayout(self.groupBox_Data)\n        self.grid_00_044b_00.setContentsMargins(10, 10, 10, 10)\n        self.grid_00_044b_00.addWidget(self.TE_Memorize, 0, 0, 1, 4)\n        self.grid_00_044b_00.addWidget(self.PB_ClearMemo, 1, 0, 1, 1)\n        self.grid_00_044b_00.addWidget(self.PB_Delete_Line_Memory, 1, 1, 1, 1)\n        self.grid_00_044b_00.addWidget(self.CB_On_Click_Apply, 1, 2, 1, 1)\n        self.grid_00_044b_00.addWidget(self.PB_Memorize, 1, 3, 1, 1)\n        self.grid_00_044b_00.addWidget(self.PB_Save_Memorize, 2, 0, 1, 1)\n        self.grid_00_044b_00.addWidget(self.CB_DataInMacro, 2, 1, 1, 1)\n        self.grid_00_044b_00.addWidget(self.PB_Clip_Board, 2, 3, 1, 1)\n        self.vbox.addWidget(self.groupBox_Data)      # scrollArea\n        ####\n        self.grid_00_08_00 = QtWidgets.QGridLayout(self.groupBox_Command)\n        self.grid_00_08_00.setContentsMargins(10, 10, 10, 10)\n        self.grid_00_08_00.addWidget(self.PB_Quit, 0, 0, 1, 1)\n        self.grid_00_08_00.addWidget(self.PB_Original, 0, 1, 1, 1)\n        self.grid_00_08_00.addWidget(self.PB_Zero, 0, 2, 1, 1)\n        self.grid_00_08_00.addWidget(self.PB_Reset, 0, 3, 1, 1)\n        grid.addWidget(self.groupBox_Command, 1, 0)\n        ####\n        self.gridLayout_00_00.addLayout(self.vbox, 0, 0)\n        self.gridLayout_00_00.addLayout(self.grid_00_08_00, 1, 0)\n        ###########################################################scrollArea\n        self.scrollArea.setWidget(self.scrollAreaWidgetContents_2)\n        ###########################################################scrollArea\n        #### Gridlayout END\n\n        MainWindow.setCentralWidget(self.centralwidget)\n\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n        global path\n        global myObjectName\n\n        MainWindow.setWindowFlags(PySide2.QtCore.Qt.WindowStaysOnTopHint)        # this function turns the front window (stay to hint)\n        MainWindow.setWindowIcon(QtGui.QIcon(self.path+u\"Macro_Rotate_To_Point.png\")) # change l'icone de la fenetre principale\n        MainWindow.setWindowTitle(__title__ + \" (\" + __version__ + \" : \" + __date__ + \" (rmu))\")\n\n        _translate = QtCore.QCoreApplication.translate\n        ####\n        self.groupBox_Position.setTitle(_translate(\"MainWindow\", \"[ 1 ] Position or Rotation\"))\n        self.groupBox_Position.setToolTip(_translate(\"MainWindow\", \"First choice Position or Rotation\"))\n        self.CB_Position.setText(_translate(\"MainWindow\", \"Check for Translation\"))\n        self.CB_Position.setToolTip(_translate(\"MainWindow\", \"Check for move the object to axis choice X, Y or Z\"))\n#        self.label_Timer.setText(_translate(\"MainWindow\", \"Time\"))\n        self.label_Timer.setToolTip(_translate(\"MainWindow\", \"Give the elapsed time\"))\n        ####\n        self.groupBox_Axis_Rotation.setTitle(_translate(\"MainWindow\", \"[ 2 ] Translation Rotation\"))\n        self.groupBox_Axis_Rotation.setToolTip(_translate(\"MainWindow\", \"Second choice Axis, Translation or Rotation\"+\"\\n\"\n                                                          \"(All change mode Axis, reset the degrees value to 0.0)\"))\n        self.groupBox_Rotation.setTitle(_translate(\"MainWindow\", \"Point Rotation\"))\n        self.RB_Bond_Box_Center.setText(_translate(\"MainWindow\", \"Bounbox Center\"))\n        self.RB_Bond_Box_Center.setToolTip(_translate(\"MainWindow\", \"Point rotation on BoundBox Center\"))\n        self.RB_Center_Mass.setText(_translate(\"MainWindow\", \"Center of Mass\"))\n        self.RB_Center_Mass.setToolTip(_translate(\"MainWindow\", \"Point rotation on Center Mass\"+\"\\n\"\n                                                  \"If the Center Mass is not availlable the spin is colored\"))\n        self.RB_Point_Clicked.setText(_translate(\"MainWindow\", \"Point clicked\"))\n        self.RB_Point_Clicked.setToolTip(_translate(\"MainWindow\", \"Point rotation on Point Mouse clicked on the object\"+\"\\n\"\n                                         \"If twoo points are clicked, the second point is used for axis rotation\"+\"\\n\"\n                                         \"The point axis rotation Can be changed during the work as long as the object is selected\"+\"\\n\"\n                                         \"For this press the CTRL KEY and click the new point rotation\"))\n        ####\n        self.groupBox_Axis.setTitle(_translate(\"MainWindow\", \"Axis Rotation\"))\n        self.RB_Rotation_X.setText(_translate(\"MainWindow\", \"Rotation(Z) Yaw\"))\n        self.RB_Rotation_X.setToolTip(_translate(\"MainWindow\", \"Rotation on Axis Yaw (Z)\"))\n        self.RB_Rotation_Y.setText(_translate(\"MainWindow\", \"Rotation(Y) Pitch\"))\n        self.RB_Rotation_Y.setToolTip(_translate(\"MainWindow\", \"Rotation on Axis Pitch (Y)\"))\n        self.RB_Rotation_Z.setText(_translate(\"MainWindow\", \"Rotation(X) Roll\"))\n        self.RB_Rotation_Z.setToolTip(_translate(\"MainWindow\", \"Rotation on Axis Roll (X)\"))\n        self.RB_Direction_D.setText(_translate(\"MainWindow\", \"Rotation(D) on Direction\"))\n        self.RB_Direction_D.setToolTip(_translate(\"MainWindow\", \"Rotation or Translation on Direction\" + \"\\n\"\n                                                                \"For use the Direction option:\" + \"\\n\"\n                                                                \"Select First: the object to Rotate/Translate\" + \"\\n\"\n                                                                \"Second: the path: Line, Wire or Edge\"))\n        self.RB_Follow_The_Path_F.setText(_translate(\"MainWindow\", \"Follow the path\"))\n        self.RB_Follow_The_Path_F.setToolTip(_translate(\"MainWindow\", \"Translation on Follow the path\" + \"\\n\"\n                                                                \"For use the Follow option:\" + \"\\n\"\n                                                                \"Select First: the object to Follow check (Rotate/Translate)\" + \"\\n\"\n                                                                \"Second: the path: Line, Wire or Edge\"))\n        ####\n        self.groupBox_Work.setTitle(_translate(\"MainWindow\", \"[ 3 ] Work ()\"))\n        self.groupBox_Work.setToolTip(_translate(\"MainWindow\", \"Third, good work\"))\n        self.groupBox_Pos_Mouse.setTitle(_translate(\"MainWindow\", \"Coordinates on Point clicked\"))\n        self.groupBox_Pos_Mouse.setToolTip(_translate(\"MainWindow\", \"Position click mouse modification possible only with mode Point clicked\"))\n        self.DS_Pos_Mouse_X.setToolTip(_translate(\"MainWindow\", \"Position click mouse X\" + \"\\n\" +\n                                       \"modification only with mode Point clicked\"))\n        self.DS_Pos_Mouse_Y.setToolTip(_translate(\"MainWindow\", \"Position click mouse Y\" + \"\\n\" +\n                                       \"modification only with mode Point clicked\"))\n        self.DS_Pos_Mouse_Z.setToolTip(_translate(\"MainWindow\", \"Position click mouse Z\" + \"\\n\" +\n                                       \"modification only with mode Point clicked\"))\n        ####\n        self.CB_View.setText(_translate(\"MainWindow\", \"View\"))\n        self.CB_View.setToolTip(_translate(\"MainWindow\", \"If checked restitute the associated view on object selected\"))\n        self.PB_Point.setText(_translate(\"MainWindow\", \"Point\"))\n        self.PB_Point.setToolTip(_translate(\"MainWindow\", \"Create one point to visualise the point rotation\"))\n        self.PB_PointCenter.setText(_translate(\"MainWindow\", \"Center\"))\n        self.PB_PointCenter.setToolTip(_translate(\"MainWindow\", \"Create one point on center face, circle \"))\n        self.LE_Increment.setToolTip(_translate(\"MainWindow\", \"Display the original Data + the modification\"))\n        #\n        #self.CBox_View.setItemText(0,_translate(\"MainWindow\",  \"0\"))\n        self.CBox_View.setToolTip(_translate(\"MainWindow\", \"Memorize the view associate with the Object worked\" + \"\\n\"\n                                             \"For automate the zoom on object clicked, see:\" + \"\\n\\n\"\n                                             \"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__ + \" > switchZoomOnCilck\" + \"\\n\"\n                                             \"and check the 'switchZoomOnCilck' option on True and restart \" + __title__ + \"\\n\\n\"\n                                             \"If you choice the object with this box\" + \"\\n\" \n                                             \"the latest configuration of the object is automatically returned\"))\n\n        self.CBox_Impost.setCurrentIndex(6)\n        self.CBox_Impost.setMaxVisibleItems(17)\n        self.CBox_Impost.setItemText(0, \"0.0001\")\n        self.CBox_Impost.setItemText(1, \"0.001\")\n        self.CBox_Impost.setItemText(2, \"0.01\")\n        self.CBox_Impost.setItemText(3, \"0.1\")\n        self.CBox_Impost.setItemText(4, \"0.5\")\n        self.CBox_Impost.setItemText(5, \"0\")\n        self.CBox_Impost.setItemText(6, \"1\")\n        self.CBox_Impost.setItemText(7, \"5\")\n        self.CBox_Impost.setItemText(8, \"10\")\n        self.CBox_Impost.setItemText(9, \"20\")\n        self.CBox_Impost.setItemText(10, \"30\")\n        self.CBox_Impost.setItemText(11, \"40\")\n        self.CBox_Impost.setItemText(12, \"45\")\n        self.CBox_Impost.setItemText(13, \"60\")\n        self.CBox_Impost.setItemText(14, \"90\")\n        self.CBox_Impost.setItemText(15, \"120\")\n        self.CBox_Impost.setItemText(16, \"180\")\n        self.CBox_Impost.setToolTip(_translate(\"MainWindow\", \"Value standard imposted\"))\n        #\n        self.CBox_Memory.setItemText(0,_translate(\"MainWindow\",  \"0\"))\n        self.CBox_Memory.setToolTip(_translate(\"MainWindow\", \"Value used memorized\"))\n        #\n        self.DS_Value_Angle_Dimension.setToolTip(_translate(\"MainWindow\", \"Enter the modification\"))\n        self.PB_Negatif.setText(_translate(\"MainWindow\", \"Invert\"))\n        self.PB_Apply.setToolTip(_translate(\"MainWindow\", \"Apply the modification\"))\n        self.PB_Apply.setText(_translate(\"MainWindow\", \"Apply\"))\n        self.label_00.setText(_translate(\"MainWindow\", \" Select one Object or give one value Angle/Dimension\"))\n        self.label_00.setStyleSheet(\"color : #ffffff; background-color: red; font: bold 11px;\")   # white red bold\n        #self.label_00.setToolTip(\"Display the modification Axis and Rotation or Position\")\n        ####\n        self.groupBox_Data.setTitle(_translate(\"MainWindow\", \"Data to save\"))\n        self.PB_ClearMemo.setText(_translate(\"MainWindow\", \"Clear\"))\n        self.PB_ClearMemo.setToolTip(_translate(\"MainWindow\", \"Clear the memo data\" + \"\\n\"\n                                                              \"The Reset button is not actif for this option\"))\n        self.PB_Delete_Line_Memory.setText(_translate(\"MainWindow\", \"Delete\"))\n        self.PB_Delete_Line_Memory.setToolTip(_translate(\"MainWindow\", \"Delete the line selected\"))\n        self.CB_On_Click_Apply.setText(_translate(\"MainWindow\", \"Memo on click\"))\n        self.CB_On_Click_Apply.setToolTip(_translate(\"MainWindow\", \"Memorize the coordinates on all Click Apply button\"))\n        self.PB_Memorize.setText(_translate(\"MainWindow\", \"Memorize\"))\n        self.PB_Memorize.setToolTip(_translate(\"MainWindow\", \"Memorize the placement displayed\"))\n        self.PB_Save_Memorize.setText(_translate(\"MainWindow\", \"Save\"))\n        self.PB_Save_Memorize.setToolTip(_translate(\"MainWindow\", \"Save the memorized placement\" + \"\\n\"\n                                                    \"Format to save : [Placement.Base], [Placement.Rotation.toEuler]\" + \"\\n\"\n                                                    \"Ex: ['Body001',(0.08,0.14,-1.5),(2.0,0.0,0.0)] with the extension: .CoorInfo\" + \"\\n\"\n                                                    \"If the file exist, the data is saved in Append (adding) mode\" + \"\\n\"\n                                                    \"If the CheckBox is checked for a Macro the file is saved in Write mode\"))\n        self.CB_DataInMacro.setText(_translate(\"MainWindow\", \"Macro\"))\n        self.CB_DataInMacro.setToolTip(_translate(\"MainWindow\", \"If checked, the coordinate is saved in Python code (complete macro) in your Macro directory\" + \"\\n\"\n                                                                \"Actual : \" + path + \"\\n\"\n                                                                \"Select the object and run the macro\" + \"\\n\"\n                                                                \"\\t\" + \"The macro saved has various options :\" + \"\\n\"\n                                                                \"\\t\" + \" (Q)uit, (D)ecrease, (I)ncrease, (P)ause, (S)tep, (M)emo\" + \"\\n\"\n                                                                \"If this is not checked, the data hare saved in coordinate mode\" + \"\\n\"\n                                                                \"\\t\" + \"Ex: ['Body001',(0.08,0.14,-1.5),(2.0,0.0,0.0)] with the ext: .CoorInfo\" + \"\\n\"))\n        self.PB_Clip_Board.setText(_translate(\"MainWindow\", \"Copy\"))\n        self.PB_Clip_Board.setToolTip(_translate(\"MainWindow\", \"Copy the data in the clip Board\" + \"\\n\"\n                                                               \"on Rotate_To_Point format\" + \"\\n\"\n                                                               \"['Body001',(0.08,0.14,-1.5),(2.0,0.0,0.0)]\"))\n        ####\n        self.groupBox_Command.setTitle(_translate(\"MainWindow\", \"Command\"))\n        self.PB_Quit.setText(_translate(\"MainWindow\", \"Quit\"))\n        self.PB_Quit.setToolTip(_translate(\"MainWindow\", \"Quite the macro\"))\n        self.PB_Original.setText(_translate(\"MainWindow\", \"Original\"))\n        self.PB_Original.setToolTip(_translate(\"MainWindow\", \"Move the object to the original position\"))\n        self.PB_Reset.setText(_translate(\"MainWindow\", \"Reset\"))\n        self.PB_Reset.setToolTip(_translate(\"MainWindow\", \"Reset the complete data macro\"))\n        self.PB_Zero.setText(_translate(\"MainWindow\", \"0,0,0\"))\n        self.PB_Zero.setToolTip(_translate(\"MainWindow\", \"Move the object to the base coordinates 0, 0, 0\"))\n\n    def on_displayTime(self):\n        ##https://forum.freecadweb.org/viewtopic.php?p=623962#p623962\n        ##measure the time elapsed for a recompute\n        ##chrisb\n        endTime = self.timeFn()\n        elapsed = (endTime - self.startTime)\n        self.elapsedComplete = str('{:02d}:{:02d}:{:06.3f}'.format(int(elapsed) // 3600, (int(elapsed) % 3600 // 60), elapsed % 60))\n        self.label_Timer.display(self.elapsedComplete)\n\n    def on_DS_Pos_Mouse_X(self,val):\n        global positionMouse\n        global axisX\n\n        positionMouse = [val, positionMouse[1], positionMouse[2]]\n        axisX = positionMouse[0]\n        self.DS_Pos_Mouse_X.setValue(axisX)\n\n    def on_DS_Pos_Mouse_Y(self,val):\n        global positionMouse\n        global axisY\n\n        positionMouse = [positionMouse[0], val, positionMouse[2]]\n        axisY = positionMouse[1]\n        self.DS_Pos_Mouse_Y.setValue(axisY)\n\n    def on_DS_Pos_Mouse_Z(self,val):\n        global positionMouse\n        global axisZ\n\n        positionMouse = [positionMouse[0], positionMouse[1], val]\n        axisZ = positionMouse[2]\n        self.DS_Pos_Mouse_Z.setValue(axisZ)\n\n#    def on_SC_Slider_Bar(self,val):\n#        global ui\n#        global valeur\n#        global myObject\n#\n#        if (myObject != \"\") and (self.CB_On_Click_Apply.isChecked()):\n#            valeur = val\n#            self.DS_Value_Angle_Dimension.setValue(1)\n#            self.SC_Slider_Bar.setValue(valeur)\n#            ui.on_PB_Apply_clicked()\n#\n##            if self.CB_On_Click_Apply.isChecked():\n##                ui.on_PB_Apply_clicked()\n##        else:\n##            self.DS_Value_Angle_Dimension.setValue(0.0)\n##            self.SC_Slider_Bar.setValue(0.0)\n\n    def on_PB_Delete_Line_Memory(self):    #self.TE_Memorize    #QListView\n        global countMemory\n        global saveOnDisk\n\n        self.model = model = QtGui.QStandardItemModel()\n        try:\n            self.PB_Delete_Line_Memory.setStyleSheet(\"Base\")\n            lineSelected = self.TE_Memorize.selectionModel().selectedRows()[0].row()\n            #textLigne = self.TE_Memorize.selectionModel().currentIndex().data() # affiche la ligne selectionnee\n            self.TE_Memorize.model().removeRow(lineSelected)\n            del saveOnDisk[lineSelected]\n            countMemory -= 1\n            self.PB_Memorize.setText(\"Memo (\" + str(countMemory) + \")\")\n        except Exception:\n            self.PB_Delete_Line_Memory.setStyleSheet(\"background-color: rgb(255, 0, 0)\")\n\n    def on_TE_Clicked(self, index):    # click dans la fenetre des donnees\n        global saveOnDisk\n        global saveListView\n        global memorySelected        \n\n####ori colore la ligne######\n#        item = saveListView.itemFromIndex(index)\n#        item.setBackground(QtGui.QBrush(QtGui.QColor(\"#ef1919\")))\n#        if (item.index().row()) in memorySelected:\n##            memorySelected.remove(item.index().row())\n#            baseBackground = self.TE_Memorize.palette().color(QPalette.Window)\n#            item.setBackground(QtGui.QBrush(QtGui.QColor(baseBackground)))\n#        else:\n#            memorySelected.append(item.index().row())\n##        print(memorySelected)\n####ori colore la ligne######\n\n        item = saveListView.itemFromIndex(index)\n        memorySelected = []\n        memorySelected.append(item.index().row())\n\n    def on_PB_PointCenter(self):\n        global objectPlacementAngle\n\n        try:\n            sel = FreeCADGui.Selection.getSelection()\n            placementOrigine = objectRealPlacement3D(FreeCAD.ActiveDocument.getObject(sel[0].Name))# search the original Placement\n            Part.show(FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0].copy())               # create repro shape subObject\n            a = App.ActiveDocument.ActiveObject\n            a.Placement.Base = placementOrigine\n            a.Placement.Rotation = App.Rotation(objectPlacementAngle[0], objectPlacementAngle[1], objectPlacementAngle[2])\n            point = Draft.makePoint(a.Shape.BoundBox.Center)\n            App.ActiveDocument.ActiveObject.recompute()\n            #App.ActiveDocument.ActiveObject.touch()\n            App.ActiveDocument.ActiveObject.purgeTouched()\n        except Exception:\n            self.PB_PointCenter.setStyleSheet(\"background-color: red\")\n        try:\n            App.ActiveDocument.removeObject(a.Name)\n        except Exception:\n            None\n\n    def on_PB_Memorize(self):    # memorize the position\n        global myObject\n        global myObjectName\n        global saveOnDisk\n        global saveListView\n        global countMemory\n        global valeur\n\n#        if (valeur != 0):\n        self.PB_Memorize.setIcon(QtGui.QIcon(QtGui.QPixmap(memo_Allume_Icon))) # icone dans une variable \n        countMemory += 1\n        xPB = str(myObject.Placement.Base[0])\n        yPB = str(myObject.Placement.Base[1])\n        zPB = str(myObject.Placement.Base[2])\n        xPR = str(myObject.Placement.Rotation.toEuler()[0])\n        yPR = str(myObject.Placement.Rotation.toEuler()[1])\n        zPR = str(myObject.Placement.Rotation.toEuler()[2])\n        #####\n        #           #myObjectName , [(3.7,0.0,41.8),          (0.0,3.0,0.0)],\n        #           #nomObjet     , Placement.Base ,          Placement.Rotation.toEuler()\n        dummy = '[\"' + str(myObjectName) + '\",' + \"(\"+xPB+\",\"+yPB+\",\"+zPB+\"),(\"+xPR+\",\"+yPR+\",\"+zPR+\")],\"\n        ####\n        saveOnDisk.append(dummy)\n        self.PB_Memorize.setText(\"Memo (\" + str(countMemory) + \")\")\n        self.PB_Memorize.setStyleSheet(\"background-color: rgb(188, 245, 169)\"); # bouton\n        self.PB_Delete_Line_Memory.setStyleSheet(\"Base\")\n        item = QtGui.QStandardItem(dummy)\n        saveListView.appendRow(item)\n#        else:\n#            self.PB_Memorize.setStyleSheet(\"background-color: #ff0000;\")\n#            self.PB_Memorize.setIcon(QtGui.QIcon(QtGui.QPixmap(memo_Eteint_Icon))) # icone dans une variable \n\n    def on_PB_Save_Memorize(self):  # Save_Memorize in macro file\n        global pathFile\n        global saveOnDisk\n        global countMemory\n        global path\n\n        if countMemory != 0:\n            if self.CB_DataInMacro.isChecked():\n                SaveName, Filter = PySide2.QtWidgets.QFileDialog.getSaveFileName(None, \"Save a file FCMacro\", path, \"FCMacro (*.FCMacro);;Python (*.py)\")   # PySide2\n#                nomMacro = FreeCAD.ActiveDocument.Name\n#                SaveName, Filter = PySide2.QtWidgets.QFileDialog.getSaveFileName(None, \"Save a file FCMacro\", path + nomMacro, \"(*.FCMacro);;Python (*.py)\") # dans \"FreeCAD/Macro/\" PySide2\n            else:\n                SaveName, Filter = PySide2.QtWidgets.QFileDialog.getSaveFileName(None, \"Save a file CoorInfo\", pathFile, \"CoorInfo (*.CoorInfo);;Ascii (*.asc);;TXT (*.txt)\")   # PySide2\n        \n            if SaveName == \"\":                                                            # if the name file are not selected then Abord process\n                App.Console.PrintMessage(\"Process aborted\"+\"\\n\")\n            else:                                                                         # if the name file are selected or created then \n                ####new2\n                pathFile      = os.path.dirname(SaveName) + \"/\"  #= C:/Provisoire400/\n                formatFichier = os.path.splitext(SaveName)[1]    #= .png\n                SaveName      = os.path.splitext(SaveName)[0]    #= /home/kubuntu/.FreeCAD/Macro/Texture_007_H #= C:/Provisoire400/image3D\n                SaveNameformatFichier = SaveName + formatFichier #= C:/Provisoire400/image3D.png\n                ####new2\n                \n                ######## sauve le dernier chemin utilise si n'est pas une macro########\n                if self.CB_DataInMacro.isChecked():\n                    None\n                else:\n                    FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"setLastPath\",pathFile)\n                ######## sauve le dernier chemin utilise si n'est pas une macro########\n\n                App.Console.PrintMessage(\"Registration of \"+SaveNameformatFichier+\"\\n\")\n                try:\n                    if self.CB_DataInMacro.isChecked():\n                        file = open(SaveNameformatFichier, 'w') #'w'write\n                    else:\n                        file = open(SaveNameformatFichier, 'a') #'a'append\n                    try:\n                        #### macro first section begin\n                        if self.CB_DataInMacro.isChecked():\n                            file.write(\"# -*- coding: utf-8 -*-\" + \"\\n\")\n                            file.write(\"##\" + \"\\n\")\n                            try:\n                                nameAuthor = str(unicodedata.normalize('NFD', __author__).encode('ascii','ignore'))\n                            except Exception: nameAuthor = \"Sir X\"\n                            try:\n                                file.write(\"##Animation ver 0.2 2022/09/15 #YYYY/MM/DD\" + \"\\n\")\n                                file.write(\"##Created by   : \" + __title__ + \" : \" + __version__ + \":\" + __date__ + \"  : \" + nameAuthor + \"\\n\")\n                                file.write(\"##Document     : \" + FreeCAD.ActiveDocument.Name + \"\\n\")\n                                #file.write(\"##Date         : \" + str(QDate.currentDate().toString()) + \"\\n\")           # mer. mars 3 2021\n                                file.write(\"##Date         : \" + str(QDate.currentDate().toString(\"yyyy/MM/dd\")) + \"    # yyyy/MM/dd\" + \"\\n\")\n                                file.write(\"##Object(First): \" + str(FreeCADGui.Selection.getSelection()[0].Name) + \"\\n\")\n                                file.write(\"##Coordinates  : \" + str(countMemory) + \"\\n\")\n                                file.write(\"##\" + \"\\n\")\n                            except Exception: None\n                            file.write(\"import Draft, Part\" + \"\\n\")\n                            file.write(\"import PySide2\" + \"\\n\")\n                            file.write(\"from pivy import coin\" + \"\\n\")\n                            file.write(\"import time, os\" + \"\\n\")\n                            file.write(\"\" + \"\\n\")\n                            file.write(\"import FreeCAD, FreeCADGui\" + \"\\n\")\n                            file.write(\"App = FreeCAD\" + \"\\n\")\n                            file.write(\"Gui = FreeCADGui\" + \"\\n\")\n                            file.write(\"\" + \"\\n\")\n                            file.write(\"global Document; Document = \" + chr(34) + FreeCAD.ActiveDocument.Name + chr(34) + \"\\n\")\n                            file.write(\"global xxData  ; xxData   = [] \" + \"\\n\")\n                            file.write(\"global xxKey   ; xxKey    = \" + chr(34) + chr(34) + \"\\n\")\n                            file.write(\"global v, o, c\" + \"\\n\")\n                            file.write(\"global vitesse ; vitesse  = 0.02\" + \"\\n\")\n                            file.write(\"\" + \"\\n\")\n                            file.write(\"global animation ; animation  = 0\" + \"\\n\")\n                            file.write(\"global countImage; countImage = 0\" + \"\\n\")\n                            file.write(\"global pathImage ; pathImage  = \" + chr(34) + chr(34) + \"\\n\")\n                            file.write(\"\" + \"\\n\")\n                            file.write(\"global sizeX\" + \"\\n\")\n                            file.write(\"global sizeY\" + \"\\n\")\n                            file.write(\"global jumpingImage\" + \"\\n\")\n                            file.write(\"global switchCountZero\" + \"\\n\")\n                            file.write(\"global createPoint\" + \"\\n\")\n                            file.write(\"global switchYoYo; switchYoYo = 0\" + \"\\n\")\n                            file.write(\"\" + \"\\n\")\n                            file.write(\"#### Config Begin ####\" + \"\\n\")\n                            file.write(\"####\" + \"\\n\")\n                            file.write(\"sizeX = 640            # size X of image    640 VGA\" + \"\\n\")\n                            file.write(\"sizeY = 480            # size Y of image    480 VGA\" + \"\\n\")\n                            file.write(\"jumpingImage    = 1    # jump the image to ...\" + \"\\n\")\n                            file.write(\"switchCountZero = 1    # if 0 and jumpingImage = 5 the counter follow the jump ex: image1 image6 image11 image16 ...\" + \"\\n\")\n                            file.write(\"                       # if 1 and jumpingImage = 5 the counter is incremented normally ex: image1 image2 image3 ...\" + \"\\n\")\n                            file.write('createPoint     = 0    # 0=not point 1=create point (on base) # used by \"S\" :Step to Step' + \"\\n\")\n                            file.write(\"####\" + \"\\n\")\n                            file.write(\"#### Config End   ####\" + \"\\n\")\n                            file.write(\"\" + \"\\n\")\n                            file.write('####path#########################################################################' + \"\\n\")\n                            file.write('global path          ; path          = \"\"                            #' + \"\\n\")\n                            file.write('param = FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macro\")# macro path' + \"\\n\")\n                            file.write('path = param.GetString(u\"MacroPath\",\"\") + \"/\"                        # macro path' + \"\\n\")\n                            file.write('#path  = \"your path\"                                                 # your directory path' + \"\\n\")\n                            file.write('path = path.replace(u\"' + chr(92) + chr(92) + '\",\"/\")                                       # convert the \"\\\" to \"/\"' + \"\\n\")\n                            file.write('#################################################################################' + \"\\n\")\n                            file.write(\"\" + \"\\n\")\n                            file.write(\"def help():\" + \"\\n\")\n                            file.write(\"    global xxData\" + \"\\n\")\n                            file.write(\"    global Document\" + \"\\n\")\n                            file.write('    App.Console.PrintMessage(\"__' + FreeCAD.ActiveDocument.Name + '__\"+\"' + chr(92) + 'n\")' + \"\\n\")\n                            file.write('    App.Console.PrintMessage(\"__\" + str(len(xxData)) + \" Coordinates__\"+\"' + chr(92) + 'n\")' + \"\\n\")\n                            file.write('    App.Console.PrintMessage(\"Type Key Q to Quit\"+\"' + chr(92) + 'n\")' +  \"\\n\")\n                            file.write('    App.Console.PrintMessage(\"Type Key A to Create serial image for create Animate GIF\"+\"' + chr(92) + 'n\")' + \"\\n\")\n                            file.write('    App.Console.PrintMessage(\"Type Key D to Decrease speed\"+\"' + chr(92) + 'n\")' +  \"\\n\")\n                            file.write('    App.Console.PrintMessage(\"Type Key I to Increase speed\"+\"' + chr(92) + 'n\")' +  \"\\n\")\n                            file.write('    App.Console.PrintMessage(\"Type Key P to Pause/Continue or key RETURN or ESCAPE\"+\"' + chr(92) + 'n\")' +  \"\\n\")\n                            file.write('    App.Console.PrintMessage(\"Type Key S to Step by Step (key RETURN or ESCAPE to continue)\"+\"' + chr(92) + 'n\")' +  \"\\n\")\n                            file.write('    App.Console.PrintMessage(\"Type Key V to ReVerse\"+\"' + chr(92) + 'n\")' +  \"\\n\")\n                            file.write('    App.Console.PrintMessage(\"Type Key Y to YoYo\"+\"' + chr(92) + 'n\")' +  \"\\n\")\n                            file.write('    App.Console.PrintMessage(\"Type Key M for this message\"+\"' + chr(92) + 'n\")' +  \"\\n\")\n                            file.write('    App.Console.PrintError(\"For use this options click mouse in the 3D view and type the key desidered\"+\"' + chr(92) + 'n\")' +  \"\\n\")\n                            file.write('    App.Console.PrintMessage(\"____________________________\"+\"' + chr(92) + 'n\")' +  \"\\n\")\n                            file.write('\\n')\n                            ####\n                            file.write('class ViewObserver:' +  \"\\n\")\n                            file.write('    def logPosition(self, info):' +  \"\\n\")\n                            file.write('        global xxKey' +  \"\\n\")\n                            file.write('        global v, o, c' +  \"\\n\")\n                            file.write('        global vitesse' +  \"\\n\")\n                            file.write('        global animation' +  \"\\n\")\n                            file.write('        global path' +  \"\\n\")\n                            file.write('        global pathImage' +  \"\\n\")\n                            file.write('        global Document' +  \"\\n\")\n                            file.write('        global countImage' +  \"\\n\")\n                            file.write('        global switchYoYo' +  \"\\n\")\n                            file.write('        global xxData' +  \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('        xxKey = info[\"Key\"].upper()' +  \"\\n\")\n                            file.write('        if xxKey in \"QVIDPSAYM\" or xxKey == \"RETURN\" or xxKey == \"PAD_ENTER\" or xxKey == \"ESCAPE\":' +  \"\\n\")\n                            file.write('            if (xxKey == \"Q\"):                        # Quit' +  \"\\n\")\n                            file.write('                v.removeEventCallback(\"SoKeyboardEvent\",c)' +  \"\\n\")\n                            file.write('                FreeCAD.Console.PrintMessage(\"End \" + Document + \"' + chr(92) + 'n\")' +  \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('            if (xxKey == \"ESCAPE\"):                   # Reset' +  \"\\n\")\n                            file.write('                vitesse = 0.02' +  \"\\n\")\n                            file.write('                switchYoYo = 0' +  \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('            if (xxKey == \"I\"):                        # Increase' +  \"\\n\")\n                            file.write('                vitesse -= 0.01' +  \"\\n\")\n                            file.write('                if vitesse <= 0:' +  \"\\n\")\n                            file.write('                    vitesse = 0' +  \"\\n\")\n                            file.write('                    App.Console.PrintMessage(\"Speed maximum\"+\"' + chr(92) + 'n\")' +  \"\\n\")\n                            file.write('                else:' +  \"\\n\")\n                            file.write('                    App.Console.PrintMessage(str(vitesse)+\"' + chr(92) + 'n\")' +  \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('            if (xxKey == \"D\"):                        # Decrease' +  \"\\n\")\n                            file.write('                vitesse += 0.01' +  \"\\n\")\n                            file.write('                App.Console.PrintMessage(str(vitesse)+\"' + chr(92) + 'n\")' +  \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('            if (xxKey == \"V\"):                        # ReVerse' +  \"\\n\")\n                            file.write('                xxData.reverse()' +  \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('            if (xxKey == \"A\"):                        # Animation' +  \"\\n\")\n                            file.write('                animation = 1' +  \"\\n\")\n                            file.write('                if not os.path.exists(path + Document + \"_Image\"):' +  \"\\n\")\n                            file.write('                    #os.makedirs(path + Document + \"_Image\")' +  \"\\n\")\n                            file.write('                    pathImage = os.mkdir(path + Document + \"_Image\")' +  \"\\n\")\n                            file.write('                else:' +  \"\\n\")\n                            file.write('                    pathImage = path + Document + \"_Image\" + \"/\"' +  \"\\n\")\n                            file.write('                countImage = 0' +  \"\\n\")\n                            file.write('                App.Console.PrintMessage(\"Animation image (i wait the first image to begin)\" + \"' + chr(92) + 'n\")' + \"\\n\")\n                            file.write('                App.Console.PrintMessage(\"(Type Escape to abord)\" + \"' + chr(92) + 'n\")' + \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('            if (xxKey == \"Y\"):                        # Animation' +  \"\\n\")\n                            file.write('                switchYoYo = 1' +  \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('            if (xxKey == \"M\"):                        # Help memo' +  \"\\n\")\n                            file.write('                help()' +  \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('##Begin of data file' + \"\\n\")\n                            file.write('xxData = [' + \"\\n\")\n                        #### macro first section end\n                        #### section save data\n                        for i in saveOnDisk:\n                            file.write(i + \"\\n\")\n                        #### section save data\n                        #### macro second section begin\n                        if self.CB_DataInMacro.isChecked():\n                            file.write(']' + \"\\n\")\n                            file.write('##End of data file' + \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('try:' + \"\\n\")\n                            file.write('    v = Gui.activeDocument().activeView()' + \"\\n\")\n                            file.write('    o = ViewObserver()' + \"\\n\")\n                            file.write('    c = v.addEventCallback(\"SoKeyboardEvent\",o.logPosition)' + \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('    help()      #help message' + \"\\n\")\n                            file.write('    switchImage = 0' + \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('    ##Loop' + \"\\n\")\n                            file.write('    while xxKey != \"Q\":' + \"\\n\")\n                            file.write('        comptCoordinate = -1  # coordinte 0 to ...x' + \"\\n\")\n                            file.write('        if (switchYoYo != 0):' + \"\\n\")\n                            file.write('            xxData.reverse()' + \"\\n\")\n                            file.write('            switchImage = 0' + \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('        for p in xxData:' + \"\\n\")\n                            file.write('            #if (xxKey == \"Q\"): break # Quit the loop after finish the complete loop (commented by default: if used quit the loop as is)' + \"\\n\")\n                            file.write('            comptCoordinate += 1' + \"\\n\")\n                            file.write('            ##         p[1]=Coordinate x,y,z;  p[2]=Rotation angle x (Roll), y (Pitch), z (Yaw)' + \"\\n\")\n                            file.write('            px = float(p[1][0]);    rx = float(p[2][0])' + \"\\n\")\n                            file.write('            py = float(p[1][1]);    ry = float(p[2][1])' + \"\\n\")\n                            file.write('            pz = float(p[1][2]);    rz = float(p[2][2])' + \"\\n\")\n                            file.write('            App.ActiveDocument.getObject(p[0]).Placement=App.Placement(App.Vector(px,py,pz), App.Rotation(rx,ry,rz), App.Vector(0,0,0))' + \"\\n\")\n                            file.write('            Gui.updateGui()                                            # rafraichi l''ecran' + \"\\n\")\n                            file.write('            time.sleep(vitesse)' + \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('            if xxKey == \"P\":                                           # Pause' + \"\\n\")\n                            file.write('                xxKey = \"\"' + \"\\n\")\n                            file.write('                comptLoop = 0' + \"\\n\")\n                            file.write('                while xxKey != \"P\":' + \"\\n\")\n                            file.write('                    if xxKey == \"RETURN\" or xxKey == \"PAD_ENTER\" or xxKey == \"ESCAPE\": break' + \"\\n\")\n                            file.write('                    comptLoop += 1' + \"\\n\")\n                            file.write('                    if comptLoop > 50000:' + \"\\n\")\n                            file.write('                        comptLoop = 0' + \"\\n\")\n                            file.write('                        App.Console.PrintError(\"You is in mode Pause : Type P or RETURN or ESCAPE to continue\" + \"' + chr(92) + 'n\")' + \"\\n\")\n                            file.write('                    Gui.updateGui()                                    # rafraichi l''ecran' + \"\\n\")\n                            file.write('                xxKey = \"\"' + \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('            if xxKey == \"S\":                                           # Step by Step' + \"\\n\")\n                            file.write('                App.Console.PrintMessage(str(App.ActiveDocument.getObject(p[0]).Placement) + \" #(\" + str(comptCoordinate) + \")\" + \"' + chr(92) + 'n\")' + \"\\n\")\n                            file.write('                ####' + \"\\n\")\n                            file.write('                if createPoint == 1:' + \"\\n\")\n                            file.write('                    point = Draft.makePoint(App.ActiveDocument.getObject(p[0]).Placement.Base)   # create point to Placement.Base' + \"\\n\")\n                            file.write('                    Draft.autogroup(point)                             #' + \"\\n\")\n                            file.write('                    FreeCAD.ActiveDocument.recompute()                 #' + \"\\n\")\n                            file.write('                ####' + \"\\n\")\n                            file.write('                xxKey = \"\"' + \"\\n\")\n                            file.write('                while xxKey != \"S\":' + \"\\n\")\n                            file.write('                    if xxKey == \"RETURN\" or xxKey == \"PAD_ENTER\" or xxKey == \"ESCAPE\": break' + \"\\n\")\n                            file.write('                    xxKey = \"\"' + \"\\n\")\n                            file.write('                    Gui.updateGui()                                    # rafraichi l''ecran' + \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('            #### Save image begin' + \"\\n\")\n                            file.write('            if (comptCoordinate <= len(xxData)) and (animation == 1):  # section save image' + \"\\n\")\n                            file.write('                if comptCoordinate == 0:' + \"\\n\")\n                            file.write('                    switchImage += 1' + \"\\n\")\n                            file.write('                if (switchImage > 1) or (xxKey == \"ESCAPE\") or (switchYoYo != 0 and (countImage >= ((len(xxData)*2)-1)/jumpingImage)):' + \"\\n\")\n                            file.write('                    animation = 0; switchImage = 0' + \"\\n\")\n                            file.write('                    App.Console.PrintMessage(\"Image Format : [\" + str(sizeX) + \"px x \" + str(sizeY) + \"px]\" + \"' + chr(92) + 'n\")' + \"\\n\")\n                            file.write('                    App.Console.PrintMessage(\"saved in \" + pathImage + \"' + chr(92) + 'n\" + \"' + chr(92) + 'n\")' + \"\\n\")\n                            file.write('                    if (xxKey == \"ESCAPE\"):                   # Escape' + \"\\n\")\n                            file.write('                        App.Console.PrintMessage(\"Save image Aborded with : \" + str(countImage) + \" images saved\" + \"' + chr(92) + 'n\")' + \"\\n\")\n                            file.write('                        countImage = 0' + \"\\n\")\n                            file.write('                        xxKey = \"\"' + \"\\n\")\n                            file.write('                if (switchImage == 1) and (comptCoordinate % jumpingImage == 0):' + \"\\n\")\n                            file.write('                    countImage += 1' + \"\\n\")\n                            file.write('                    if switchCountZero == 0:' + \"\\n\")\n                            file.write('                        Gui.activeDocument().activeView().saveImage(pathImage + Document + str(comptCoordinate + 1)+\".png\",sizeX, sizeY,\"Current\")' + \"\\n\")\n                            file.write('                        App.Console.PrintMessage(str(comptCoordinate + 1) + \" of \" + str(len(xxData)) + \"' + chr(92) + 'n\")' + \"\\n\")\n                            file.write('                    else:' + \"\\n\")\n                            file.write('                        Gui.activeDocument().activeView().saveImage(pathImage + Document + str(countImage)+\".png\",sizeX, sizeY,\"Current\")' + \"\\n\")\n                            file.write('                        App.Console.PrintMessage(str(countImage) + \" of \" + str(int(len(xxData) / jumpingImage)) + \"(*)\" + \"' + chr(92) + 'n\")' + \"\\n\")\n                            file.write('            #### Save image end' + \"\\n\")\n                            file.write('' + \"\\n\")\n                            file.write('except Exception:' + \"\\n\")\n                            file.write('    FreeCAD.Console.PrintError(\"' + chr(92) + 'n\"+\"Not document open, or not object selected\" + \"' + chr(92) + 'n\")' + \"\\n\")\n                            file.write('    try:' + \"\\n\")\n                            file.write('         v.removeEventCallback(\"SoKeyboardEvent\",c)' + \"\\n\")\n                            file.write('    except Exception:' + \"\\n\")\n                            file.write('        None' + \"\\n\")\n                            file.write('' + \"\\n\")\n                        #### macro second section end\n\n                    except Exception:\n                        self.label_00.setStyleSheet(\"color : #ffffff; background-color: red; font: bold 11px;\")   # white red bold\n                        self.label_00.setText(\" Error write file\")\n#                        App.Console.PrintError(\"Error write file \"+\"\\n\")\n                    finally:\n                        file.close()\n                except Exception:\n                    self.label_00.setStyleSheet(\"color : #ffffff; background-color: red; font: bold 11px;\")   # white red bold\n                    self.label_00.setText(\" Error Write file \" + SaveName)\n#                    App.Console.PrintError(\"Error Write file \" + SaveName+\"\\n\")\n    #### save macro end\n\n    def on_PB_ClearMemo(self):\n        global saveOnDisk\n        global saveListView\n        global countMemory\n        global memorySelected\n\n        try:\n            model = saveListView = QtGui.QStandardItemModel()\n            self.TE_Memorize.model().removeRows(0, countMemory)# model.rowCount()\n            saveOnDisk     = []\n            self.TE_Memorize.setModel(saveListView)\n            countMemory    = 0\n            memorySelected = []\n            self.PB_Memorize.setText(\"Memo\")\n            self.PB_Memorize.setStyleSheet(\"Base\")\n            self.PB_Memorize.setIcon(QtGui.QIcon(QtGui.QPixmap(memo_Eteint_Icon))) # icone dans une variable \n        except Exception:\n            None\n\n    def on_CB_On_Click_Apply(self):\n\n        if self.CB_On_Click_Apply.isChecked():\n            self.CB_On_Click_Apply.setIcon(QtGui.QIcon(QtGui.QPixmap(normalWork_Icon))) # icone dans une variable \n            self.CB_On_Click_Apply.setText(u\"Memo on demand\")\n            self.CB_On_Click_Apply.setToolTip(u\"Memorize the coordinates on demand\")\n            self.PB_Memorize.setIcon(QtGui.QIcon(QtGui.QPixmap(memo_Allume_Icon))) # icone dans une variable \n            self.groupBox_Data.setEnabled(True)\n        else:\n            self.CB_On_Click_Apply.setIcon(QtGui.QIcon(QtGui.QPixmap(OnClickApply_Icon))) # icone dans une variable \n            self.CB_On_Click_Apply.setText(u\"Memo on click\")\n            self.CB_On_Click_Apply.setToolTip(u\"Memorize the coordinates on all Click Apply button\")\n\n    def On_CB_DataInMacro(self):\n\n        if self.CB_DataInMacro.isChecked():\n            self.CB_DataInMacro.setIcon(QtGui.QIcon(QtGui.QPixmap(code_FC_Icon))) # icone dans une variable \n            self.CB_DataInMacro.setText(u\"Coordinate\")\n            self.PB_Save_Memorize.setText(\"Save (wr)\")\n            self.PB_Save_Memorize.setToolTip(\"The file is open in mode Write\" + \"\\n\"\n                                             \"If the file exist, the file is crushed\" + \"\\n\"\n                                             \"\")\n        else:\n            self.CB_DataInMacro.setIcon(QtGui.QIcon(QtGui.QPixmap(code_Python_Icon))) # icone dans une variable \n            self.CB_DataInMacro.setText(u\"Macro\")\n            self.PB_Save_Memorize.setText(\"Save (ap)\")\n            self.PB_Save_Memorize.setToolTip(\"The file is open in mode Append\" + \"\\n\"\n                                             \"If the file exist, the the data hare adding in the file\" + \"\\n\"\n                                             \"\")\n\n    def on_PB_Clip_Board(self):\n        global saveOnDisk\n\n        memo = QtWidgets.QApplication.clipboard()\n        memo.clear(mode=memo.Clipboard )\n        txt = \"\"\n        for i in range(len(saveOnDisk)):\n            txt += saveOnDisk[i] + \"\\n\"\n        memo.setText(txt, mode = memo.Clipboard)\n        txt = \"\"\n\n    def on_DS_Value_Angle_Dimension(self,val):\n        global valeur\n        global myObject\n        global posX, posY, posZ\n        global rotAngleX, rotAngleY, rotAngleZ\n        global axisX, axisY, axisZ\n        global posFollow\n\n        valeur = val\n        if (myObject == \"\") or (valeur == 0):\n            self.PB_Memorize.setIcon(QtGui.QIcon(QtGui.QPixmap(memo_Eteint_Icon))) # icone dans une variable \n            self.DS_Value_Angle_Dimension.setValue(0.0)\n            self.DS_Value_Angle_Dimension.setStyleSheet(\"background-color: rgb(250, 88, 88)\")\n#            self.SC_Slider_Bar.setValue(0.0)\n            None\n        else:\n            self.PB_Memorize.setIcon(QtGui.QIcon(QtGui.QPixmap(memo_Allume_Icon))) # icone dans une variable \n            self.DS_Value_Angle_Dimension.setStyleSheet(\"Base\")\n            self.PB_Memorize.setStyleSheet(\"Base\")\n#            self.SC_Slider_Bar.setValue(valeur)\n            if self.CB_Position.isChecked():                 # translate\n\n                if self.RB_Rotation_X.isChecked():\n                    posX = valeur\n                    posY = posZ = 0.0\n                    self.LE_Increment.setText(str(round(myObject.Placement.Base[0],4) + valeur))\n                elif self.RB_Rotation_Y.isChecked():\n                    posY = valeur\n                    posX = posZ = 0.0\n                    self.LE_Increment.setText(str(round(myObject.Placement.Base[1],4) + valeur))\n                elif self.RB_Rotation_Z.isChecked():\n                    posZ = valeur\n                    posX = posY = 0.0\n                    self.LE_Increment.setText(str(round(myObject.Placement.Base[2],4) + valeur))\n                elif (self.RB_Direction_D.isChecked()) or (self.RB_Follow_The_Path_F.isChecked()):\n                    posZ = valeur\n                    posX = posY = 0.0\n                    xD = str(round(myObject.Placement.Base[0],4))\n                    yD = str(round(myObject.Placement.Base[1],4))\n                    zD = str(round(myObject.Placement.Base[2],4))\n                    self.LE_Increment.setText(\"(\" + xD + \", \" + yD + \", \" + zD + \")\")\n\n                    if self.RB_Follow_The_Path_F.isChecked():\n                        selectedEdge = FreeCADGui.Selection.getSelectionEx()                               # Select an object or sub object getSelectionEx\n                        try:\n                            posFollow = selectedEdge[1].SubObjects[0].discretize(Distance=abs(valeur))     # 1 object, 1 object ou subObject\n                        except Exception:\n                            try:\n                                posFollow = selectedEdge[0].SubObjects[1].discretize(Distance=abs(valeur)) # 1 object avec son subobject\n                            except Exception:\n                                print(\"stop\")\n                        xD = str(round(myObject.Placement.Base[0],4))\n                        yD = str(round(myObject.Placement.Base[1],4))\n                        zD = str(round(myObject.Placement.Base[2],4))\n                        self.LE_Increment.setText(\"(\" + xD + \", \" + yD + \", \" + zD + \")\")\n\n                self.label_00.setText(\"[Pos=(\" + str(round(myObject.Placement.Base[0],2))+\" , \" + \n                                                 str(round(myObject.Placement.Base[1],2))+\" , \" + \n                                                 str(round(myObject.Placement.Base[2],2))+\")] \" +\n                                      \"[Axis=(\"+ str(round(axisX,2)) + \" , \" + str(round(axisY,2)) + \" , \" + str(round(axisZ,2)) + \")]\")\n                self.label_00.setStyleSheet(\"font: 11px;\")\n\n            else:                                            # rotation\n\n                if self.RB_Rotation_X.isChecked():\n                    rotAngleX = valeur\n                    rotAngleY = rotAngleZ = 0.0\n                    self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[0],4) + valeur))\n                elif self.RB_Rotation_Y.isChecked():\n                    rotAngleY = valeur\n                    rotAngleZ = rotAngleX = 0.0\n                    self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[1],4) + valeur))\n                elif self.RB_Rotation_Z.isChecked():\n                    rotAngleZ = valeur\n                    rotAngleX = rotAngleY = 0.0\n                    self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[2],4) + valeur))\n                elif self.RB_Direction_D.isChecked():\n                    rotAngleZ = valeur\n                    rotAngleX = rotAngleY = 0.0\n                    xD = str(round(myObject.Placement.Rotation.toEuler()[0],4))\n                    yD = str(round(myObject.Placement.Rotation.toEuler()[1],4))\n                    zD = str(round(myObject.Placement.Rotation.toEuler()[2],4))\n                    self.LE_Increment.setText(\"(\" + xD + \", \" + yD + \", \" + zD + \")\")\n\n                self.label_00.setText(\"[Rot=(\" + str(round(rotAngleX,2)) + \" , \" + str(round(rotAngleY,2)) + \" , \" + str(round(rotAngleZ,2)) + \")] \" +\n                                      \"[Axis=(\"+ str(round(axisX,2)) + \" , \" + str(round(axisY,2)) + \" , \" + str(round(axisZ,2)) + \")]\")\n                self.label_00.setStyleSheet(\"font: 11px;\")\n\n            if valeur < 0:\n                self.PB_Negatif.setIcon(QtGui.QIcon(QtGui.QPixmap(positif_Icon))) # icone dans une variable \n            else:\n                self.PB_Negatif.setIcon(QtGui.QIcon(QtGui.QPixmap(negatif_Icon))) # icone dans une variable \n\n    def on_PB_Negatif_clicked(self):\n        global valeur\n\n        if valeur < 0:\n            self.PB_Negatif.setIcon(QtGui.QIcon(QtGui.QPixmap(negatif_Icon))) # icone dans une variable \n        else:\n            self.PB_Negatif.setIcon(QtGui.QIcon(QtGui.QPixmap(positif_Icon))) # icone dans une variable \n\n        self.DS_Value_Angle_Dimension.setValue(-valeur)    # !?\n\n    def restitue_Values(self, switch):  #, switch 0 = read configuration, 1 = write configuration\n        global posX, posY, posZ\n        global rotAngleX, rotAngleY, rotAngleZ\n        global axisX, axisY, axisZ\n\n        if switch == 0:\n            a = self.CB_Position.isChecked()\n            b = self.RB_Bond_Box_Center.isChecked()\n            c = self.RB_Center_Mass.isChecked()\n            d = self.RB_Point_Clicked.isChecked()\n            e = self.RB_Rotation_X.isChecked()\n            f = self.RB_Rotation_Y.isChecked()\n            g = self.RB_Rotation_Z.isChecked()\n            h = self.RB_Direction_D.isChecked()\n            i = self.RB_Follow_The_Path_F.isChecked()\n            j = self.DS_Value_Angle_Dimension.value()\n            return  [a, b, c, d, e, f, g, h, i, j, posX, posY, posZ, rotAngleX, rotAngleY, rotAngleZ, axisX, axisY, axisZ]\n\n    def on_CBox_View(self, text):  # memory view on object worked\n        global ui\n        global duplicate_View\n        global sourisPass\n        global myObjectName\n        global myObjectLabel\n        global switchZoomOnCilck\n\n        global originalObject\n        global myObject\n        global sel   \n        global selM\n        global posX, posY, posZ\n        global rotAngleX, rotAngleY, rotAngleZ\n        global axisX, axisY, axisZ\n\n        if text == \"Empty\":\n            #duplicate_View = sorted(list(set(duplicate_View))) # trie et tire les doublons\n            duplicate_View = sorted(duplicate_View, key=itemgetter(0)) # sort\n            try:          # supprime les doublons apres avoir ete trie (sorted)\n                doublon = 1\n                while doublon < len(duplicate_View):\n                    if (duplicate_View[doublon][0] == duplicate_View[doublon-1][0]):\n                        del duplicate_View[doublon-1]\n                        doublon -= 1\n                    doublon += 1\n            except Exception:\n                None\n            self.CBox_View.blockSignals(True)\n            self.CBox_View.clear()\n            for i in range(len(duplicate_View)):    # copie les noms tries dans ComboBox_View\n                self.CBox_View.addItem(duplicate_View[i][0])\n                self.CBox_View.blockSignals(False)\n                duplicate_View[i] = duplicate_View[i] + self.restitue_Values(0) # copy options used\n        else:\n            for i in range(len(duplicate_View)):\n                if text == duplicate_View[i][0]:\n                    sourisPass = 1\n                    Gui.Selection.clearSelection()\n                    originalObject = myObject = sel = selM = \"\"\n                    Gui.Selection.addSelection(App.ActiveDocument.getObject(duplicate_View[i][0]))\n                    originalObject = myObject = sel = selM = App.ActiveDocument.getObject(duplicate_View[i][0])\n                    myObjectLabel = sel.Label\n\n                    if switchZoomOnCilck == 1:\n                        Gui.ActiveDocument.ActiveView.setCamera(duplicate_View[i][1])    #restore previously stored camera settings\n\n                    myObjectName = duplicate_View[i][0]\n                    self.groupBox_Work.setTitle(u\"Work (\" + myObjectName + \" : \" + myObjectLabel +\")\")\n                    ####\n                    self.CB_Position.setChecked(duplicate_View[i][2])    #restore previously stored options settings\n                    self.RB_Bond_Box_Center.setChecked(duplicate_View[i][3])\n                    self.RB_Center_Mass.setChecked(duplicate_View[i][4])\n                    self.RB_Point_Clicked.setChecked(duplicate_View[i][5])\n                    self.RB_Rotation_X.setChecked(duplicate_View[i][6])\n                    self.RB_Rotation_Y.setChecked(duplicate_View[i][7])\n                    self.RB_Rotation_Z.setChecked(duplicate_View[i][8])\n                    self.RB_Direction_D.setChecked(duplicate_View[i][9])\n                    self.RB_Follow_The_Path_F.setChecked(duplicate_View[i][10])\n                    self.DS_Value_Angle_Dimension.setValue(duplicate_View[i][11])\n                    ##\n                    posX      = duplicate_View[i][12]\n                    posY      = duplicate_View[i][13]\n                    posZ      = duplicate_View[i][14]\n                    rotAngleX = duplicate_View[i][15]\n                    rotAngleY = duplicate_View[i][16]\n                    rotAngleZ = duplicate_View[i][17]\n                    axisX     = duplicate_View[i][18]\n                    axisY     = duplicate_View[i][19]\n                    axisZ     = duplicate_View[i][20]\n                    ####\n\n    def on_CBox_Impost(self,text):  # value length and degrees\n\n        if self.CB_Position.isChecked():\n            self.CBox_Impost.setCurrentIndex(5)\n            self.CBox_Impost.setItemText(0, \"0.0001\")\n            self.CBox_Impost.setItemText(1, \"0.001\")\n            self.CBox_Impost.setItemText(2, \"0.01\")\n            self.CBox_Impost.setItemText(3, \"0.1\")\n            self.CBox_Impost.setItemText(4, \"0.5\")\n            self.CBox_Impost.setItemText(5, \"0\")\n            self.CBox_Impost.setItemText(6, \"1\")\n            self.CBox_Impost.setItemText(7, \"5\")\n            self.CBox_Impost.setItemText(8, \"10\")\n            self.CBox_Impost.setItemText(9, \"25\")\n            self.CBox_Impost.setItemText(10, \"50\")\n            self.CBox_Impost.setItemText(11, \"100\")\n            self.CBox_Impost.setItemText(12, \"250\")\n            self.CBox_Impost.setItemText(13, \"500\")\n            self.CBox_Impost.setItemText(14, \"1000\")\n            self.CBox_Impost.setItemText(15, \"5000\")\n            self.CBox_Impost.setItemText(16, \"10000\")\n        else:\n            self.CBox_Impost.setCurrentIndex(5)\n            self.CBox_Impost.setItemText(0, \"0.0001\")\n            self.CBox_Impost.setItemText(1, \"0.001\")\n            self.CBox_Impost.setItemText(2, \"0.01\")\n            self.CBox_Impost.setItemText(3, \"0.1\")\n            self.CBox_Impost.setItemText(4, \"0.5\")\n            self.CBox_Impost.setItemText(5, \"0\")\n            self.CBox_Impost.setItemText(6, \"1\")\n            self.CBox_Impost.setItemText(7, \"5\")\n            self.CBox_Impost.setItemText(8, \"10\")\n            self.CBox_Impost.setItemText(9, \"20\")\n            self.CBox_Impost.setItemText(10, \"30\")\n            self.CBox_Impost.setItemText(11, \"40\")\n            self.CBox_Impost.setItemText(12, \"45\")\n            self.CBox_Impost.setItemText(13, \"60\")\n            self.CBox_Impost.setItemText(14, \"90\")\n            self.CBox_Impost.setItemText(15, \"120\")\n            self.CBox_Impost.setItemText(16, \"180\")\n        self.DS_Value_Angle_Dimension.setProperty(\"value\", text)\n\n    def on_CBox_Memory(self,text):  # memory the value sort and delete duplicate\n        global duplicate_Memory\n\n        self.DS_Value_Angle_Dimension.setValue(float(text))\n        duplicate_Memory.append(float(text))\n        duplicate_Memory = sorted(list(set(duplicate_Memory))) # sort\n        self.CBox_Memory.blockSignals(True)\n        self.CBox_Memory.clear()\n        for i in range(len(duplicate_Memory)):\n            self.CBox_Memory.addItem(str(duplicate_Memory[i]))\n            self.CBox_Memory.blockSignals(False)\n\n    def on_LE_Increment_Pressed(self,text):\n        None\n\n    def on_PB_Apply_clicked(self):\n        global ui\n        global valeur\n        global selM\n        global myObject\n        global myObjectName\n        global myObjectLabel\n        global duplicate_View\n\n        global posX, posY, posZ\n        global rotAngleX, rotAngleY, rotAngleZ\n        global axisX, axisY, axisZ\n        global posFollow\n        global compPosFollow\n\n        if (myObject == \"\") or (valeur == 0):\n            self.label_00.setStyleSheet(\"color : #ffffff; background-color: red; font: bold 11px;\")   # white red bold\n            self.label_00.setText(\" Select one Object or give one value Angle/Dimension\")\n#            FreeCAD.Console.PrintError(\"Select one Object or give one value Angle/Dimension\" + \"\\n\")\n            self.PB_Memorize.setIcon(QtGui.QIcon(QtGui.QPixmap(memo_Eteint_Icon))) # icone dans une variable \n            if valeur == 0:\n                self.DS_Value_Angle_Dimension.setStyleSheet(\"background-color: rgb(250, 88, 88)\")\n        else:\n            self.PB_Memorize.setIcon(QtGui.QIcon(QtGui.QPixmap(memo_Allume_Icon))) # icone dans une variable \n\n            #Gui.ActiveDocument.ActiveView.setCamera(camera)    #restore previously stored camera settings\n            camera = Gui.ActiveDocument.ActiveView.getCamera() #store camera settings to 'cam'\n            duplicate_View.append([myObjectName, camera])\n\n            self.on_CBox_View(\"Empty\")\n            self.on_CBox_Memory(self.DS_Value_Angle_Dimension.value())\n\n            if self.CB_Position.isChecked():                 # section translate\n                try:\n                    self.countOpenTransaction += 1\n                    FreeCAD.ActiveDocument.openTransaction(\"RTP T (\" + str(self.countOpenTransaction) + \") : \" + myObjectName + \" : \" + myObjectLabel + \" (\" + str(valeur) +\" mm)\")    # memorise les actions (avec annuler restore)\n\n                    if (self.RB_Direction_D.isChecked()) or (self.RB_Follow_The_Path_F.isChecked()):      # direction\n                        try:\n                            selectedEdge = FreeCADGui.Selection.getSelectionEx()[1].SubObjects[0]         # select one element and axis second object (2 selections)\n                        except Exception:\n                            try:\n                                selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[1]     # select one element and axis same object   (2 selections)\n                            except Exception:\n                                None\n                                try:\n                                    selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0] # select one element and axis same object   (1 selection)\n                                except Exception:\n                                    None\n\n                        pointsTrajet = []\n                        ####\n                        pointsTrajet  = selectedEdge.discretize(Distance = 1.0)                       # discretize the element for calculate the direction\n                        direction = pointsTrajet[1].sub(pointsTrajet[0])                              # search the direction line or sub\n                        ####\n                        if self.RB_Follow_The_Path_F.isChecked():                                         # Path\n                            if valeur > 0:\n                                compPosFollow += 1\n                                if compPosFollow > len(posFollow)-1:\n                                    compPosFollow = 0\n                            else:\n                                compPosFollow -= 1\n                                if compPosFollow < 0:\n                                    compPosFollow = len(posFollow)-1\n                            selM.Placement.Base=App.Vector(posFollow[compPosFollow][0], posFollow[compPosFollow][1], posFollow[compPosFollow][2])\n                        else:\n                            selM.Placement.Base = myObject.Placement.Base + App.Vector(direction).scale(valeur, valeur, valeur)\n                    else:\n                        selM.Placement = App.Placement(App.Vector(posX, posY, posZ), App.Rotation(0.0,0.0,0.0), App.Vector(0.0,0.0,0.0)).multiply(App.ActiveDocument.getObject(myObjectName).Placement)\n\n                    myObject = selM\n\n                    if self.RB_Rotation_X.isChecked():\n                        self.LE_Increment.setText(str(round(myObject.Placement.Base[0],4)))\n                    elif self.RB_Rotation_Y.isChecked():\n                        self.LE_Increment.setText(str(round(myObject.Placement.Base[1],4)))\n                    elif self.RB_Rotation_Z.isChecked():\n                        self.LE_Increment.setText(str(round(myObject.Placement.Base[2],4)))\n                    elif (self.RB_Direction_D.isChecked()) or (self.RB_Follow_The_Path_F.isChecked()):\n                        xD = str(round(myObject.Placement.Base[0],4))\n                        yD = str(round(myObject.Placement.Base[1],4))\n                        zD = str(round(myObject.Placement.Base[2],4))\n                        self.LE_Increment.setText(\"(\" + xD + \", \" + yD + \", \" + zD + \")\")\n                    self.label_00.setText(\"[Pos=(\" + str(round(myObject.Placement.Base[0],2))+\" , \" + \n                                                     str(round(myObject.Placement.Base[1],2))+\" , \" + \n                                                     str(round(myObject.Placement.Base[2],2))+\")] \" +\n                                          \"[Axis=(\"+ str(round(axisX,2)) + \" , \" + str(round(axisY,2)) + \" , \" + str(round(axisZ,2)) + \")]\")\n                except Exception:\n                    self.label_00.setStyleSheet(\"color : #ffffff; background-color: red; font: bold 11px;\")   # white red bold\n                    self.label_00.setText(\" Select 2 elements 1:object, 2:the direction or path\")\n\n            else:                                            # section rotation\n                if self.RB_Direction_D.isChecked():          # direction\n                    self.countOpenTransaction += 1\n                    FreeCAD.ActiveDocument.openTransaction(\"RTP D (\" + str(self.countOpenTransaction) + \") : \" + myObjectName + \" : \" + myObjectLabel + \" (\" + str(valeur) +\" mm)\")    # memorise les actions (avec annuler restore)\n                    try:\n                        selectedEdge = FreeCADGui.Selection.getSelectionEx()[1].SubObjects[0]         # select one element and axis second object (2 selections)\n                    except Exception:\n                        try:\n                            selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[1]     # select one element and axis same object   (2 selections)\n                        except Exception:\n                            try:\n                                selectedEdge = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0] # select one element and axis same object   (1 selection)\n                            except Exception:\n                                None\n                    try:\n                        direction = selectedEdge.Vertexes[1].Point.sub(selectedEdge.Vertexes[0].Point)# search the direction line or sub\n                    except Exception:\n                        try:\n                            direction = objectRotation.Vertexes[0].Point\n                        except Exception:\n                            direction = App.Vector(0.0,0.0,0.0)\n                    selM.Placement = App.Placement(App.Vector(0.0,0.0,0.0), App.Rotation(App.Vector(direction), valeur), App.Vector(axisX, axisY, axisZ)).multiply(App.ActiveDocument.getObject(myObjectName).Placement)\n                else:\n                    self.countOpenTransaction += 1\n                    FreeCAD.ActiveDocument.openTransaction(\"RTP R (\" + str(self.countOpenTransaction) + \") : \" + myObjectName + \" : \" + myObjectLabel + \" (\" + str(valeur) +\" deg)\")    # memorise les actions (avec annuler restore)\n                    selM.Placement = App.Placement(App.Vector(0.0,0.0,0.0), App.Rotation(rotAngleX, rotAngleY, rotAngleZ), App.Vector(axisX, axisY, axisZ)).multiply(App.ActiveDocument.getObject(myObjectName).Placement) # other method\n                myObject = selM\n\n                if self.RB_Rotation_X.isChecked():\n                    self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[0],4)))\n                elif self.RB_Rotation_Y.isChecked():\n                    self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[1],4)))\n                elif self.RB_Rotation_Z.isChecked():\n                    self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[2],4)))\n                elif self.RB_Direction_D.isChecked():\n                    xD = str(round(myObject.Placement.Rotation.toEuler()[0],4))\n                    yD = str(round(myObject.Placement.Rotation.toEuler()[1],4))\n                    zD = str(round(myObject.Placement.Rotation.toEuler()[2],4))\n                    self.LE_Increment.setText(\"(\" + xD + \", \" + yD + \", \" + zD + \")\")\n\n                self.label_00.setText(\"[Rot=(\" + str(round(myObject.Placement.Rotation.toEuler()[0],2)) + \" , \" +\n                                                 str(round(myObject.Placement.Rotation.toEuler()[1],2)) + \" , \" + \n                                                 str(round(myObject.Placement.Rotation.toEuler()[2],2)) + \")] \" +\n                                      \"[Axis=(\"+ str(round(axisX,2))+\" , \"+ str(round(axisY,2))+\" , \"+ str(round(axisZ,2))+\")]\")\n            if self.CB_On_Click_Apply.isChecked():\n                self.on_PB_Memorize()\n#            FreeCAD.ActiveDocument.recompute()\n\n    def on_RB_Rotation_0(self):\n        None\n\n    def on_RB_Rotation_X(self):\n        global myObject\n\n        if self.CB_Position.isChecked():              \n            self.LE_Increment.setText(str(round(myObject.Placement.Base[0],4)))                  # pos X\n        else:\n            self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[0],4)))    # yaw = Z\n        self.DS_Value_Angle_Dimension.setValue(0.0)\n\n    def on_RB_Rotation_Y(self):\n        global myObject\n\n        if self.CB_Position.isChecked():              \n            self.LE_Increment.setText(str(round(myObject.Placement.Base[1],4)))                  # pos Y\n        else:\n            self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[1],4)))    # pitch= Y\n        self.DS_Value_Angle_Dimension.setValue(0.0)\n\n    def on_RB_Rotation_Z(self):\n        global myObject\n\n        if self.CB_Position.isChecked():              \n            self.LE_Increment.setText(str(round(myObject.Placement.Base[2],4)))                  #  pos Z\n        else:\n            self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[2],4)))    # roll = X\n        self.DS_Value_Angle_Dimension.setValue(0.0)\n\n    def on_RB_Direction_D(self):\n        global myObject\n\n        if self.CB_Position.isChecked():              \n            xD = str(round(myObject.Placement.Base[0],4))\n            yD = str(round(myObject.Placement.Base[1],4))\n            zD = str(round(myObject.Placement.Base[2],4))\n        else:\n            xD = str(round(myObject.Placement.Rotation.toEuler()[0],4))\n            yD = str(round(myObject.Placement.Rotation.toEuler()[1],4))\n            zD = str(round(myObject.Placement.Rotation.toEuler()[2],4))\n        self.LE_Increment.setText(\"(\" + xD + \", \" + yD + \", \" + zD + \")\")\n        self.DS_Value_Angle_Dimension.setValue(0.0)\n\n    def on_RB_Follow_The_Path_F(self):\n        global myObject\n\n        if self.CB_Position.isChecked():              \n            xD = str(round(myObject.Placement.Base[0],4))\n            yD = str(round(myObject.Placement.Base[1],4))\n            zD = str(round(myObject.Placement.Base[2],4))\n\n            self.LE_Increment.setText(\"(\" + xD + \", \" + yD + \", \" + zD + \")\")\n            self.DS_Value_Angle_Dimension.setValue(0.0)\n\n    def on_RB_CenterRot(self):                                # zero\n        global myObject\n        global selM\n        global positionMouse\n        global axisX, axisY, axisZ\n        \n        try:\n            if hasattr(selM, \"Shape\"):\n                sel = selM.Shape\n            elif hasattr(selM, \"Mesh\"):         # upgrade with wmayer thanks #http://forum.freecadweb.org/viewtopic.php?f=13&t=22331\n                sel = selM.Mesh\n            elif hasattr(selM, \"Points\"):\n                sel = selM.Points\n            myObject = sel\n\n            self.groupBox_Pos_Mouse.setEnabled(False)\n            if self.RB_Bond_Box_Center.isChecked():           # axis\n                axisX = myObject.BoundBox.Center.x\n                axisY = myObject.BoundBox.Center.y\n                axisZ = myObject.BoundBox.Center.z\n                self.label_00.setToolTip(\"Axis BoundBox.Center\")\n                self.RB_Center_Mass.setStyleSheet(\"Base\")\n            elif self.RB_Center_Mass.isChecked():\n                try:\n                    axisX = myObject.CenterOfMass.x\n                    axisY = myObject.CenterOfMass.y\n                    axisZ = myObject.CenterOfMass.z\n                    self.label_00.setToolTip(\"Axis Center Of Mass\")\n                except Exception:   # case Mesh.MeshObject\n                    self.RB_Bond_Box_Center.setChecked(True)\n                    self.RB_Center_Mass.setStyleSheet(\"background-color: rgb(250, 88, 88)\")\n            elif self.RB_Point_Clicked.isChecked():\n                axisX = positionMouse[0]\n                axisY = positionMouse[1]\n                axisZ = positionMouse[2]\n                self.groupBox_Pos_Mouse.setEnabled(True)\n                self.label_00.setToolTip(\"Point Mouse\")\n\n        except Exception:\n            self.label_00.setStyleSheet(\"color : #ffffff; background-color: red; font: bold 11px;\")   # white red bold\n            self.label_00.setText(\"Error CenterRot_0\")\n##            FreeCAD.Console.PrintError(\"Error CenterRot_0\" + \"\\n\" + \"or Bad selection\" + \"\\n\")\n\n    def on_CB_Position(self):\n        global myObject\n        global posX, posY, posZ\n        global axisX, axisY, axisZ\n        global ui\n\n        self.on_CBox_Impost(\"\")\n        #self.RB_Follow_The_Path_F.setEnabled(False)\n        if self.CB_Position.isChecked():\n            self.groupBox_Position.setToolTip(u\"Choice first : Translation or Rotation\")\n            self.CB_Position.setText(u\"Check for Rotation\")\n            self.CB_Position.setToolTip(u\"Rotate the object to axis choice X, Y, Z or D\")\n            self.CB_Position.setIcon(QtGui.QIcon(QtGui.QPixmap(rotate_Icon))) #icone dans une variable \n\n            self.RB_Follow_The_Path_F.setEnabled(True)\n            self.DS_Value_Angle_Dimension.setMinimum(-999999999.999999999)\n            self.DS_Value_Angle_Dimension.setMaximum(999999999.999999999)\n            self.DS_Value_Angle_Dimension.setSuffix(\" mm\")\n\n            self.RB_Rotation_X.setIcon(QtGui.QIcon(QtGui.QPixmap(axis_X_Icon))) # icone dans une variable \n            self.RB_Rotation_Z.setIcon(QtGui.QIcon(QtGui.QPixmap(axis_Z_Icon))) # icone dans une variable \n            self.groupBox_Rotation.setEnabled(False)\n            self.RB_Bond_Box_Center.setChecked(True)\n\n#            self.SC_Slider_Bar.setMinimum(-1000)\n#            self.SC_Slider_Bar.setMaximum(1000)\n#            self.DS_Value_Angle_Dimension.setMinimum(-1000)\n#            self.DS_Value_Angle_Dimension.setMaximum(1000)\n\n            self.groupBox_Axis.setTitle(\"Axis Translation\")\n            self.RB_Rotation_Z.setText(\"Translation Z \")          # translate change the title\n            self.RB_Rotation_Y.setText(\"Translation Y \")\n            self.RB_Rotation_X.setText(\"Translation X \")\n            self.RB_Direction_D.setText(\"Translation D \")\n\n            try:\n                self.label_00.setText(\"[Pl.Base=(\" + str(round(myObject.Placement.Base[0],2)) + \" , \" + \n                                                 str(round(myObject.Placement.Base[1],2)) + \" , \" + \n                                                 str(round(myObject.Placement.Base[2],2)) + \")] \" +\n                                      \"[Axis=(\"+ str(round(axisX,2)) + \" , \" + str(round(axisY,2)) + \" , \" + str(round(axisZ,2)) + \")]\")\n                if self.RB_Rotation_X.isChecked():\n                    self.LE_Increment.setText(str(round(myObject.Placement.Base[0],4)))\n                elif self.RB_Rotation_Y.isChecked():\n                    self.LE_Increment.setText(str(round(myObject.Placement.Base[1],4)))\n                elif self.RB_Rotation_Z.isChecked():\n                    self.LE_Increment.setText(str(round(myObject.Placement.Base[2],4)))\n                elif (self.RB_Direction_D.isChecked()) or (self.RB_Follow_The_Path_F.isChecked()):\n                    xD = str(round(myObject.Placement.Base[0],4))\n                    yD = str(round(myObject.Placement.Base[1],4))\n                    zD = str(round(myObject.Placement.Base[2],4))\n                    self.LE_Increment.setText(\"(\" + xD + \", \" + yD + \", \" + zD + \")\")\n            except Exception:\n                self.label_00.setStyleSheet(\"color : #ffffff; background-color: red; font: bold 11px;\")   # white red bold\n                self.label_00.setText(\"Error Position_0 or Bad selection\")\n##                FreeCAD.Console.PrintError(\"Error Position_0\" + \"\\n\" + \"or Bad selection\" + \"\\n\")\n        else:\n            if self.RB_Follow_The_Path_F.isChecked():\n                self.RB_Rotation_X.setChecked(True)\n            self.DS_Value_Angle_Dimension.setMinimum(-360.0)\n            self.DS_Value_Angle_Dimension.setMaximum(360.0)\n            self.DS_Value_Angle_Dimension.setSuffix(\" Degrees\")\n            self.RB_Rotation_Z.setIcon(QtGui.QIcon(QtGui.QPixmap(axis_X_Icon))) # icone dans une variable \n            self.RB_Rotation_X.setIcon(QtGui.QIcon(QtGui.QPixmap(axis_Z_Icon))) # icone dans une variable \n            self.CB_Position.setIcon(QtGui.QIcon(QtGui.QPixmap(translate_Icon))) #icone dans une variable \n            self.CB_Position.setText(u\"Check for Translation\")\n            self.CB_Position.setToolTip(u\"Check for move the object to axis choice X, Y, Z D or Follow\")\n            self.groupBox_Rotation.setEnabled(True)\n#            self.SC_Slider_Bar.setMinimum(0.0)\n#            self.SC_Slider_Bar.setMaximum(359.0)\n#            self.DS_Value_Angle_Dimension.setMinimum(0.0)\n#            self.DS_Value_Angle_Dimension.setMaximum(359.0)\n            self.groupBox_Axis.setTitle(\"Axis Rotation\")\n            self.RB_Rotation_Z.setText(\"Rotation(X) Roll\")      # rotation change the title\n            self.RB_Rotation_Y.setText(\"Rotation(Y) Pitch\")\n            self.RB_Rotation_X.setText(\"Rotation(Z) Yaw\")\n            self.RB_Direction_D.setText(\"Rotation(D) on Direction\")\n            self.RB_Follow_The_Path_F.setEnabled(False)\n            try:\n                self.label_00.setText(\"[Rot=(\" + str(round(myObject.Placement.Rotation.toEuler()[0],2)) + \" , \" +\n                                                 str(round(myObject.Placement.Rotation.toEuler()[1],2)) + \" , \" + \n                                                 str(round(myObject.Placement.Rotation.toEuler()[2],2)) + \")] \" +\n                                      \"[Axis=(\"+str(round(axisX,2))+\" , \"+ str(round(axisY,2))+\" , \"+ str(round(axisZ,2))+\")]\")\n                if self.RB_Rotation_X.isChecked():\n                    self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[0],4)))\n                elif self.RB_Rotation_Y.isChecked():\n                    self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[1],4)))\n                elif self.RB_Rotation_Z.isChecked():\n                    self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[2],4)))\n                elif self.RB_Direction_D.isChecked():\n                    xD = str(round(myObject.Placement.Rotation.toEuler()[0],4))\n                    yD = str(round(myObject.Placement.Rotation.toEuler()[1],4))\n                    zD = str(round(myObject.Placement.Rotation.toEuler()[2],4))\n                    self.LE_Increment.setText(\"(\" + xD + \", \" + yD + \", \" + zD + \")\")\n            except Exception:\n                self.label_00.setStyleSheet(\"color : #ffffff; background-color: red; font: bold 11px;\")   # white red bold\n                self.label_00.setText(\"Error Position_1 or Bad selection\")\n#                FreeCAD.Console.PrintError(\"Error Position_0\" + \"\\n\" + \"or Bad selection\" + \"\\n\")\n\n        self.DS_Value_Angle_Dimension.setValue(0.0)\n\n    def on_CB_View(self):   # state CB view\n        global switchZoomOnCilck\n\n        if self.CB_View.isChecked():\n            switchZoomOnCilck = True\n        else:\n            switchZoomOnCilck = False\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchZoomOnCilck\", switchZoomOnCilck)\n\n    def on_CB_Point(self):\n        global ui\n        global myObject\n        global selM\n        global myObjectName\n        global positionMouse\n\n        if hasattr(selM, \"Shape\"):\n            sel = selM.Shape\n        elif hasattr(selM, \"Mesh\"):         # upgrade with wmayer thanks #http://forum.freecadweb.org/viewtopic.php?f=13&t=22331\n            sel = selM.Mesh\n        elif hasattr(selM, \"Points\"):\n            sel = selM.Points\n        myObject = sel\n\n        if self.RB_Bond_Box_Center.isChecked():           # axis\n            point = Draft.makePoint(myObject.BoundBox.Center.x, myObject.BoundBox.Center.y, myObject.BoundBox.Center.z)\n            point.ViewObject.PointColor = (1.0,0.0,0.0)\n            point.Label = \"Point_BoundBox_Center\"\n            self.RB_Center_Mass.setStyleSheet(\"Base\")\n        elif self.RB_Center_Mass.isChecked():\n            try:\n                point = Draft.makePoint(myObject.CenterOfMass.x, myObject.CenterOfMass.y, myObject.CenterOfMass.z)\n                point.ViewObject.PointColor = (0.0,1.0,0.0)\n                point.Label = \"Point_CenterOfMass\"\n            except Exception:   # case Mesh.MeshObject\n                self.RB_Bond_Box_Center.setChecked(True)\n                self.RB_Center_Mass.setStyleSheet(\"background-color: rgb(250, 88, 88)\")\n        elif self.RB_Point_Clicked.isChecked():\n            point = Draft.makePoint(positionMouse[0], positionMouse[1], positionMouse[2])\n            point.ViewObject.PointColor = (0.0,0.0,1.0)\n            point.Label = \"Point_positionMouse\"\n        Gui.Selection.addSelection(App.ActiveDocument.getObject(myObjectName))\n        FreeCAD.ActiveDocument.recompute()\n#        ui.on_RB_CenterRot()\n\n    def on_PB_Zero_clicked(self):\n        global myObject\n        global selM\n\n        if (myObject != \"\"):\n            try:\n                self.countOpenTransaction += 1\n                FreeCAD.ActiveDocument.openTransaction(\"RTP Z 0,0,0 zero (\" + str(self.countOpenTransaction) + \")\")    # memorise les actions (avec annuler restore)\n                #FreeCAD.ActiveDocument.commitTransaction()         # restore les actions  (avec annuler restore)\n                #FreeCAD.ActiveDocument.abortTransaction()          # abandonne les actions(avec annuler restore)\n\n                myObject = selM\n                pl = App.Placement(App.Vector(0.0,0.0,0.0), App.Rotation(0.0, 0.0, 0.0), App.Vector(0.0, 0.0, 0.0))\n                myObject.Placement = pl\n\n                if self.RB_Rotation_X.isChecked():\n                    self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[0],4)))\n                elif self.RB_Rotation_Y.isChecked():\n                    self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[1],4)))\n                elif self.RB_Rotation_Z.isChecked():\n                    self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[2],4)))\n                elif self.RB_Direction_D.isChecked():\n                    xD = str(round(myObject.Placement.Rotation.toEuler()[0],4))\n                    yD = str(round(myObject.Placement.Rotation.toEuler()[1],4))\n                    zD = str(round(myObject.Placement.Rotation.toEuler()[2],4))\n                    self.LE_Increment.setText(\"(\" + xD + \", \" + yD + \", \" + zD + \")\")\n\n                self.label_00.setText(\"[Rot=(\" +str(round(myObject.Placement.Rotation.toEuler()[0],2))+\" , \"+str(round(myObject.Placement.Rotation.toEuler()[1],2))+\" , \"+ str(round(myObject.Placement.Rotation.toEuler()[2],2))+\")] \"+\n                                      \"[Axis=(\"+str(round(myObject.Placement.Base.x,2))+\" , \"+ str(round(myObject.Placement.Base.y,2))+\" , \"+ str(round(myObject.Placement.Base.z,2))+\")]\")\n\n                self.DS_Value_Angle_Dimension.setValue(0.0)\n                self.LE_Increment.setText(str(0.0))\n\n                #FreeCAD.ActiveDocument.recompute()\n                Gui.activeDocument().activeView().viewTop()\n                Gui.SendMsgToActiveView(\"ViewFit\")\n\n            except Exception:\n                self.label_00.setStyleSheet(\"color : #ffffff; background-color: red; font: bold 11px;\")   # white red bold\n                self.label_00.setText(\"Error Zero_0 or Bad selection\")\n#                FreeCAD.Console.PrintError(\"Error Zero_0\" + \"\\n\" + \"or Bad selection\" + \"\\n\")\n        else:\n            self.label_00.setStyleSheet(\"color : #ffffff; background-color: red; font: bold 11px;\")   # white red bold\n            self.label_00.setText(\" Select one Object or give one value Angle/Dimension\")\n#            FreeCAD.Console.PrintError(\"Select one Object or give one value Angle/Dimension\" + \"\\n\")\n\n    def on_PB_Original_clicked(self):\n        global ui\n        global myObject\n        global myObjectName\n        global selM\n        global originalPlacement\n        global rotAngleX, rotAngleY, rotAngleZ\n        global axisX, axisY, axisZ\n\n        if (myObject != \"\"):\n            try:\n                self.countOpenTransaction += 1\n                FreeCAD.ActiveDocument.openTransaction(\"RTP O Origin (\" + str(self.countOpenTransaction) + \") : \" + myObjectName)    # memorise les actions (avec annuler restore)\n\n                rotAngleX  = rotAngleY = rotAngleZ = 0.0\n                selM.Placement = originalPlacement \n                if hasattr(selM, \"Shape\"):\n                    sel = selM.Shape\n                elif hasattr(selM, \"Mesh\"):         # upgrade with wmayer thanks #http://forum.freecadweb.org/viewtopic.php?f=13&t=22331\n                    sel = selM.Mesh\n                elif hasattr(selM, \"Points\"):\n                    sel = selM.Points\n                myObject = sel\n                self.DS_Value_Angle_Dimension.setValue(0.0)\n\n                if self.RB_Rotation_X.isChecked():\n                    self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[0],4)))    # yaw Z\n                elif self.RB_Rotation_Y.isChecked():\n                    self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[1],4)))    # pitch Y\n                elif self.RB_Rotation_Z.isChecked():\n                    self.LE_Increment.setText(str(round(myObject.Placement.Rotation.toEuler()[2],4)))    # roll Z\n                elif self.RB_Direction_D.isChecked():\n                    xD = str(round(myObject.Placement.Rotation.toEuler()[0],4))\n                    yD = str(round(myObject.Placement.Rotation.toEuler()[1],4))\n                    zD = str(round(myObject.Placement.Rotation.toEuler()[2],4))\n                ui.on_RB_CenterRot()\n                self.label_00.setText(\"[Rot=(\" +str(round(myObject.Placement.Rotation.toEuler()[0],2))+\" , \"+str(round(myObject.Placement.Rotation.toEuler()[1],2))+\" , \"+ str(round(myObject.Placement.Rotation.toEuler()[2],2))+\")] \"+\n                                              \"[Axis=(\"+str(round(axisX,2))+\" , \"+ str(round(axisY,2))+\" , \"+ str(round(axisZ,2))+\")]\")\n                #FreeCAD.ActiveDocument.recompute()\n            except Exception:\n                self.label_00.setStyleSheet(\"color : #ffffff; background-color: red; font: bold 11px;\")   # white red bold\n                self.label_00.setText(\"Error Original_0 or Bad selection\")\n#                FreeCAD.Console.PrintError(\"Error Original_0\" + \"\\n\" + \"or Bad selection\" + \"\\n\")\n        else:\n            self.label_00.setStyleSheet(\"color : #ffffff; background-color: red; font: bold 11px;\")   # white red bold\n            self.label_00.setText(\" Select one Object or give one value Angle/Dimension\")\n#            FreeCAD.Console.PrintError(\"Select one Object or give one value Angle/Dimension\" + \"\\n\")\n\n    def on_PB_Reset_clicked(self, resetAll = 0):\n        global ui\n        global originalObject\n        global myObject\n        global myObjectName\n        global selectedEdge\n        global selM\n        global duplicate_Memory\n        global duplicate_View\n        global switchZoomOnCilck\n        global valeur\n        global posX, posY, posZ\n        global rotAngleX, rotAngleY, rotAngleZ\n        global axisX, axisY, axisZ\n        global countMemory\n\n        try:\n            for obj in FreeCAD.ActiveDocument.Objects:         # deslectionne\n                FreeCADGui.Selection.removeSelection(obj)\n        except Exception:\n            None\n\n        countMemory = 0\n        ui.on_PB_ClearMemo()\n\n        originalObject = myObject = myObjectName = selM = \"\"\n        posX = posY = posZ = rotAngleX = rotAngleY = rotAngleZ = 0.0\n        axisX = axisY = axisZ = 0.0\n        valeur  = 0.0\n\n        self.DS_Value_Angle_Dimension.setStyleSheet(\"Base\")\n        self.DS_Value_Angle_Dimension.setValue(valeur)\n        self.DS_Value_Angle_Dimension.setSuffix(\" Degrees\")\n        self.LE_Increment.setText(str(0.0))\n\n        self.CB_Position.setChecked(False)\n        self.CB_Position.setIcon(QtGui.QIcon(QtGui.QPixmap(translate_Icon))) #icone dans une variable \n        self.CB_Position.setText(u\"Check for Translation\")\n        self.CB_Position.setToolTip(u\"Move the object to axis choice X, Y, Z, D or Follow\")\n\n        self.RB_Bond_Box_Center.setChecked(True)\n        self.RB_Center_Mass\n        self.RB_Point_Clicked\n\n        self.groupBox_Axis.setTitle(\"Axis Rotation\")\n        self.RB_Rotation_Z.setText(\"Rotation(X) Roll\")\n        self.RB_Rotation_Y.setText(\"Rotation(Y) Pitch\")\n        self.RB_Rotation_X.setText(\"Rotation(Z) Yaw\")\n        self.RB_Direction_D.setText(\"Rotation(D) on Direction\")\n        self.RB_Follow_The_Path_F.setEnabled(False)\n        self.RB_Follow_The_Path_F.setChecked(False)\n        self.RB_Rotation_X.setChecked(True)\n        self.groupBox_Position.setEnabled(False)\n        self.groupBox_Rotation.setEnabled(False)\n        self.groupBox_Axis.setEnabled(False)\n        self.groupBox_Pos_Mouse.setEnabled(False)\n        self.groupBox_Work.setEnabled(False)\n        self.groupBox_Work.setTitle(\"[ 3 ] Work ()\")\n        self.groupBox_Data.setEnabled(False)\n\n        self.DS_Pos_Mouse_X.setValue(0.0)\n        self.DS_Pos_Mouse_Y.setValue(0.0)\n        self.DS_Pos_Mouse_Z.setValue(0.0)\n\n        if resetAll == 0:\n            self.CB_View.setChecked(False)\n            self.CBox_View.blockSignals(True)\n            self.CBox_View.clear()\n            duplicate_View = []\n\n        duplicate_Memory = []\n        self.CBox_Memory.blockSignals(True)\n        self.CBox_Memory.clear()\n        switchZoomOnCilck = 0\n\n        #self.PB_Point.setEnabled(False)\n        self.PB_PointCenter.setStyleSheet(\"Base\")\n        self.PB_Memorize.setStyleSheet(\"Base\")\n\n        #self.CB_On_Click_Apply.setEnabled(False)\n        self.CB_On_Click_Apply.setChecked(False)\n        Gui.Selection.clearSelection()\n\n        self.label_00.setStyleSheet(\"color : #ffffff; background-color: red; font: bold 11px;\")   # white red bold\n        self.label_00.setText(\" Select one Object or give one value Angle/Dimension\")\n#        FreeCAD.Console.PrintError(\"Select one Object or give one value Angle/Dimension\" + \"\\n\")\n#        FreeCAD.Console.PrintMessage(\"Reset\" + \"\\n\")\n\n    def on_PB_Quit_clicked(self):\n        global ui\n        global s\n        global switchZoomOnCilck\n\n        self.timer.stop()\n        #### geometry\n        self.positionWindowXY = MainWindow.geometry()\n        self.setMainWindowMoveX  = self.positionWindowXY.x()\n        self.setMainWindowMoveY  = self.positionWindowXY.y()\n        self.positionWindowXY = MainWindow.size()\n        self.setFrameWindowSizeX = self.positionWindowXY.width()\n        self.setFrameWindowSizeY = self.positionWindowXY.height()\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"setMainWindowMoveX\",  self.setMainWindowMoveX)      # setMainWindowMoveX\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"setMainWindowMoveY\",  self.setMainWindowMoveY)      # setMainWindowMoveY\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"setFrameWindowSizeX\", self.setFrameWindowSizeX)     # setFrameWindowSizeX\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"setFrameWindowSizeY\", self.setFrameWindowSizeY)     # setFrameWindowSizeY\n        #### geometry\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchZoomOnCilck\", switchZoomOnCilck)\n        try:\n            self.vueActive.removeEventCallback(\"SoMouseButtonEvent\",self.click) # desinstalle la fonction souris\n        except Exception:\n            None\n        try:\n            FreeCADGui.Selection.removeObserver(s)   # Uninstalls resident function (desactivated for read after LeftDock RightDock)\n            self.window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)      # destroy\n            self.window.deleteLater()                                       # destroy\n            self.window.destroy()                                           # destroy\n        except Exception:\n            self.window.hide()                                              # hide the window and close the macro\n        FreeCAD.Console.PrintMessage(\"Quit Rotate_To_Point (Work \" + self.elapsedComplete + \")\\n\")\n\n###################################################################################################\nclass SelObserver:\n    def addSelection(self, document, object, element, position):  # Selection\n        global ui\n        global sourisPass\n        global switchZoomOnCilck\n        \n        global valeur\n        global positionMouse\n        global originalObject\n        global myObject\n        global myObjectName\n        global myObjectLabel\n        global originalPlacement\n        global selM\n\n        global posX, posY, posZ\n        global rotAngleX, rotAngleY, rotAngleZ\n        global axisX, axisY, axisZ\n\n        if sourisPass == 0:                                       # pour un seul passage\n            sourisPass == 1\n            selM = FreeCADGui.Selection.getSelection()[0]         # select object with getSelection()\n            myObjectName = selM.Name\n            myObjectLabel = selM.Label\n\n            if hasattr(selM, \"Shape\"):\n                sel = selM.Shape\n            elif hasattr(selM, \"Mesh\"):         # upgrade with wmayer thanks #http://forum.freecadweb.org/viewtopic.php?f=13&t=22331\n                sel = selM.Mesh\n            elif hasattr(selM, \"Points\"):\n                sel = selM.Points\n\n            if switchZoomOnCilck == 1:\n                ui.on_CBox_View(myObjectName)   # return on zoom on click object selected\n            positionMouse     = position\n            originalObject    = myObject = sel   \n            originalPlacement = sel.Placement\n            #longueur = (myObject.BoundBox.XLength * 0.5)          # pour Axis\n            positionBase = originalObject.Placement.Base          # Placement Vector XYZ\n\n            posX = positionBase.x\n            posY = positionBase.y\n            posZ = positionBase.z\n\n            Yaw   = originalObject.Placement.Rotation.toEuler()[0]                     # decode angle Euler Yaw\n            Pitch = originalObject.Placement.Rotation.toEuler()[1]                     # decode angle Euler Pitch\n            Roll  = originalObject.Placement.Rotation.toEuler()[2]                     # decode angle Euler Roll\n\n            rotAngleX = Yaw\n            rotAngleY = Pitch\n            rotAngleZ = Roll\n            axisX = axisY = axisZ = 0.0\n\n            ui.groupBox_Work.setTitle(u\"[ 3 ] Work (\" + myObjectName + \" : \" + myObjectLabel +\")\")\n            valeur = 0.0\n            ui.DS_Value_Angle_Dimension.setValue(valeur)\n            ui.DS_Value_Angle_Dimension.setStyleSheet(\"background-color: rgb(250, 88, 88)\")\n\n            ui.DS_Pos_Mouse_X.setValue(positionMouse[0])\n            ui.DS_Pos_Mouse_Y.setValue(positionMouse[1])\n            ui.DS_Pos_Mouse_Z.setValue(positionMouse[2])\n\n            ui.on_RB_CenterRot()\n            if ui.CB_Position.isChecked():\n                ui.groupBox_Rotation.setEnabled(False)\n            else:\n                ui.groupBox_Rotation.setEnabled(True)\n\n            ui.groupBox_Position.setEnabled(True)\n            ui.groupBox_Axis.setEnabled(True)\n            ui.groupBox_Work.setEnabled(True)\n            ui.groupBox_Data.setEnabled(True)\n            ui.PB_Memorize.setIcon(QtGui.QIcon(QtGui.QPixmap(memo_Allume_Icon))) # icone dans une variable \n            #ui.groupBox_Pos_Mouse.setEnabled(True)\n            #ui.label_00.setStyleSheet(\"font: bold 11px;\")\n            ui.label_00.setStyleSheet(\"font: 11px;\")\n            ui.label_00.setText(\"[Rot =(\" + str(round(rotAngleX,2))+ \" , \" + str(round(rotAngleY,2)) + \" , \" + str(round(rotAngleZ,2)) + \")] \" +\n                                \"[Axis=(\"+ str(round(axisX,2)) + \" , \" + str(round(axisY,2)) + \" , \" + str(round(axisZ,2)) + \")]\")\n            ui.PB_Memorize.setStyleSheet(\"Base\")\n            ui.PB_PointCenter.setStyleSheet(\"Base\")\n\n    def clearSelection(self,doc):                       # Si clic sur l'ecran, effacer la selection\n        global ui\n        global selM\n        global originalObject\n        global myObject\n        global myObjectName\n        global myObjectLabel\n\n#        ui.on_PB_Reset_clicked(1)\n\n    #def removeSelection(self,doc,obj,sub):             # Effacer l'objet selectionne\n    #    None\n\n###################################################################################################\n\ndoc = FreeCAD.ActiveDocument\nif doc == None:\n    doc = FreeCAD.newDocument()\n\ntry:\n    for obj in FreeCAD.ActiveDocument.Objects:         # deselectionne\n        FreeCADGui.Selection.removeSelection(obj)\nexcept Exception:\n    None\n\ns=SelObserver()\nFreeCADGui.Selection.addObserver(s)                    # installe la fonction en mode resident\n\nif __name__ == \"__main__\":\n    MainWindow = QtWidgets.QMainWindow()\n    MainWindow.setObjectName(\"__title__\")              # macro internal Name\n    ui = Ui_MainWindow()\n    ui.setupUi(MainWindow)\n    MainWindow.show()\n\n",
    "url": "https://wiki.freecad.org/Macro_Rotate_To_Point",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/2fc48333deca5a31e6232c29a9db5e4c/raw/d9419d4bb13e36940eb2f56c3c469ea4182827ee/Macro%2520Rotate%2520To%2520Point.FCMacro",
    "wiki": "https://www.freecadweb.org/wiki/Macro_Rotate_To_Point",
    "version": "00.11",
    "license": "",
    "date": "2022/10/17",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Rotate_To_Point.svg",
    "icon_source": "https://www.freecadweb.org/wiki/images/d/d1/Macro_Rotate_To_Point.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Section",
    "on_wiki": true,
    "on_git": false,
    "desc": "Alternative implementation of <a href=\"/Part_Section\" title=\"Part Section\">Part Section</a> tool (parametric)<br />This macro does the same by extracting the section edges from result of generalFuse (GFA). The result is C1-continuous and has less knots. It is still not terrific for sweeping, but much better than plain Part Section.<br /><br />Macro version: 1.1<br />Last modified: 2018-04-28<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/f/f7/Part_Section.svg\">ToolBar Icon</a><br />Author: DeepSOIC<br /> ",
    "comment": "Alternative implementation of Part Section tool (parametric)",
    "code": "#***************************************************************************\n#*                                                                         *\n#*   Copyright (c) 2016 - Victor Titov (DeepSOIC)                          *\n#*                                               <vv.titov@gmail.com>      *  \n#*                                                                         *\n#*   This program is free software; you can redistribute it and/or modify  *\n#*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n#*   as published by the Free Software Foundation; either version 2 of     *\n#*   the License, or (at your option) any later version.                   *\n#*   for detail see the LICENCE text file.                                 *\n#*                                                                         *\n#*   This program is distributed in the hope that it will be useful,       *\n#*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n#*   GNU Library General Public License for more details.                  *\n#*                                                                         *\n#*   You should have received a copy of the GNU Library General Public     *\n#*   License along with this program; if not, write to the Free Software   *\n#*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n#*   USA                                                                   *\n#*                                                                         *\n#***************************************************************************\n\n__title__=\"Macro Section\"\n__author__ = \"DeepSOIC\"\n__doc__ = '''\nMacro Section.\nAlternative implementation of Part Section tool.\nRequires FreeCAD v0.17+ and OCC 6.9.0+\n\nInstructions:\nFirst of all, save this macro as MacroSection.py, into a location from where it can be imported. FC's standard macro location is the best place to do that.\n\nSelect two shapes to compute section between.\nThen, in Py console:\n\nimport MacroSection\nMacroSection.run()\n\nOR\n\njust run this file as a macro.\n\nParametric Section object is created.\n'''\nif __name__ == \"__main__\": #being run as a macro\n    import MacroSection\n    MacroSection.run()\n\nimport FreeCAD as App\nif App.GuiUp:\n    import FreeCADGui as Gui\nimport Part\n\ndef makeSectionFeature():\n    '''makeSectionFeature(): makes a Section parametric feature object. Returns the new object.'''\n    selfobj = App.ActiveDocument.addObject(\"Part::FeaturePython\",\"Section\")\n    Section(selfobj)\n    ViewProviderSection(selfobj.ViewObject)\n    return selfobj\n\nclass Section:\n    \"The Section feature object\"\n    def __init__(self,selfobj):\n        selfobj.addProperty(\"App::PropertyLink\",\"Base\",\"Section\",\"Input shape\")\n        selfobj.addProperty(\"App::PropertyLink\",\"Tool\",\"Section\",\"Input shape\")\n        selfobj.Proxy = self\n\n    def execute(self,selfobj):\n        import BOPTools\n        import BOPTools.ShapeMerge\n        from BOPTools.Utils import HashableShape\n        \n        if len(selfobj.Base.Shape.Faces) == 0 or len(selfobj.Tool.Shape.Faces) == 0:\n            raise ValueError(\"Shapes must have at least one face each.\")\n        sh1 = Part.Compound(selfobj.Base.Shape.Faces)\n        sh2 = Part.Compound(selfobj.Tool.Shape.Faces)\n        pieces, map = sh1.generalFuse([sh2])\n        pieces = pieces.childShapes()\n        assert(len(pieces) == 2)\n        \n        edges1 = set([HashableShape(edge) for edge in pieces[0].Edges])\n        edges2 = set([HashableShape(edge) for edge in pieces[1].Edges])\n        edges_to_return = list(set.intersection(edges1, edges2))\n        edges_to_return = [edge.Shape for edge in edges_to_return] #convert hashable shapes back to plain shapes\n        print(\"returning {num} edges of total {tot}\".format(num= len(edges_to_return), tot= len(edges1)+len(edges2)))\n        \n        selfobj.Shape = BOPTools.ShapeMerge.mergeWires(edges_to_return)\n\nclass ViewProviderSection:\n    def __init__(self,vobj):\n        vobj.Proxy = self\n       \n    def getIcon(self):\n        return \":/icons/Part_Section.svg\"\n\n    def attach(self, vobj):\n        self.ViewObject = vobj\n        self.Object = vobj.Object\n  \n    def __getstate__(self):\n        return None\n\n    def __setstate__(self,state):\n        return None\n\n    def claimChildren(self):\n        return [self.Object.Base, self.Object.Tool]\n        \n    def onDelete(self, feature, subelements): # subelements is a tuple of strings\n        try:\n            self.Object.Base.ViewObject.show()\n            self.Object.Tool.ViewObject.show()\n        except Exception as err:\n            App.Console.PrintError(\"Error in onDelete: \" + err.message)\n        return True\n\nclass CommandMacroSection:\n    \"Command to create Section feature\"\n    def GetResources(self):\n        return {'Pixmap'  : \":/icons/Part_Section.svg\",\n                'MenuText': \"Section\",\n                'Accel': \"\",\n                'ToolTip': \"Macro_Section: alternative implementation of Part Section tool\"}\n\n    def Activated(self):\n        run()\n    def IsActive(self):\n        if App.ActiveDocument:\n            return True\n        else:\n            return False\n\nif App.GuiUp:\n    Gui.addCommand(\"Macro_Section\", CommandMacroSection())\n\ndef run():\n    sel = Gui.Selection.getSelectionEx()\n    try:\n        if len(sel) != 2:\n            raise Exception(\"Select two shapes to compute section between, first! Then run this macro.\")\n        try:\n            App.ActiveDocument.openTransaction(\"Macro Section\")\n            selfobj = makeSectionFeature()\n            selfobj.Base = sel[0].Object\n            selfobj.Tool = sel[1].Object\n            selfobj.Base.ViewObject.hide()\n            selfobj.Tool.ViewObject.hide()\n            \n            selfobj.Proxy.execute(selfobj)\n        finally:\n            App.ActiveDocument.commitTransaction()\n    except Exception as err:\n        from PySide import QtGui\n        mb = QtGui.QMessageBox()\n        mb.setIcon(mb.Icon.Warning)\n        mb.setText(err.message)\n        mb.setWindowTitle(\"Macro Section\")\n        mb.exec_()",
    "url": "https://wiki.freecad.org/Macro_Section",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2018-04-28",
    "src_filename": "",
    "filename_from_url": "",
    "author": "DeepSOIC",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Part_Section.svg",
    "icon_source": "https://www.freecadweb.org/wiki/images/f/f7/Part_Section.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "SuperWire",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro creates a wire from selected objects (lines and arcs) even where normal wire creation methods (for example the upgrade tool) fail. Attention, you need a recent version of FreeCAD for this to work<br /><br />Macro version: 0.1<br />Last modified: 2012-05-22<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/e/e3/Macro_SuperWire.png\">ToolBar Icon</a><br />Author: Yorik<br /> ",
    "comment": "This macro creates a wire from selected objects (lines and arcs) even where normal wire creation methods (for example the upgrade tool) fail. Attention, you need a recent version of FreeCAD for this to work",
    "code": "import FreeCAD,FreeCADGui,Part\ntry:\n    import DraftGeomUtils as fcgeo\nexcept:\n    from draftlibs import fcgeo\n\nsel = FreeCADGui.Selection.getSelection()\nif not sel:\n   FreeCAD.Console.PrintWarning(\"Select something first!\")\nelse:\n   elist = []\n   for obj in sel:\n       if hasattr(obj,\"Shape\"):\n           elist.append(obj.Shape.Edges[0])\n   wire = fcgeo.superWire(elist)\n   if wire:\n       Part.show(wire)\n   else:\n       FreeCAD.Console.PrintError(\"SuperWire operation failed!\")",
    "url": "https://wiki.freecad.org/Macro_SuperWire",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2012-05-22",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Yorik",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_SuperWire.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/e/e3/Macro_SuperWire.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "WireFilter",
    "on_wiki": true,
    "on_git": false,
    "desc": "Filter wires from sketches, 2D offsets, scales, rearranges wire order<br /><br />Macro version: 0.2023.10.19<br />Last modified: 2022-10-19<br />FreeCAD version: python 3 versions<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/File:Wirefilter.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Filter wires from sketches, 2D offsets, scales, rearranges wire order",
    "code": "# -*- coding: utf-8 -*-\n__version__ = \"0.2023.10.19\"\n#__version__ = \"0.2023.10.19\"\n##WireFilter, 2021, by <TheMarkster> LGPL 2.1 or later\n#import FreeCAD, FreeCADGui, Part, Draft\n#from PySide import QtGui, QtCore, QtWidgets\n#from PySide.QtGui import QColor\n#import time\n#COLORS = [\"red\",\"green\",\"blue\",\"cyan\",\"magenta\",\"yellow\",\"orange\",\"maroon\",\"purple\",\"white\",\\\n#\"chartreuse\", \"navy\",\"teal\",\"pink\",\"black\",\"silver\"]\n#class WireFilter:\n#    def __init__(self, obj):\n#        obj.addExtension(\"Part::AttachExtensionPython\")\n#        obj.addProperty(\"App::PropertyInteger\",\"MaxWires\",\"WireFilter\",\"Maximum number of wires to use (prevents hanging on complex sources)\").MaxWires = 50\n#        obj.addProperty(\"App::PropertyLinkSub\",\"Source\",\"WireFilter\",\"Source of the wires, typically a sketch or a compound of sketches\")\n#        obj.addProperty(\"App::PropertyIntegerList\",\"WireOrder\",\"WireOrder\",\"Order of wires (0 = disable wire)  There is a special editor for this if Edit Wire Order is toggled to True.\")\n#        obj.addProperty(\"App::PropertyBool\",\"ClaimChildren\",\"WireFilter\",\"Whether to claim children in tree view\").ClaimChildren=True\n#        obj.addProperty(\"App::PropertyBool\",\"Colorize\",\"WireFilter\",\"Whether to colorize wires\").Colorize=True\n#        obj.addProperty(\"App::PropertyBool\",\"UsePreselection\",\"WireFilter\",\"Applicable only when subobjects were selected when creating WireFilter object.  If True, only those preselected subojects are used, else if False, all wires are used\").UsePreselection = True\n#        obj.addProperty(\"App::PropertyEnumeration\",\"FaceMaker\",\"WireFilter\",\"FaceMaker class to use to make face or No Face if no face\")\n#        obj.FaceMaker = [\"No Face\",\"Part::FaceMakerBullseye\", \"Part::FaceMakerCheese\",\"Part::FaceMakerSimple\",\"Part::FaceMakerExtrusion\",\"InvertedFace\", \"FilledFace\"]\n#        obj.addProperty(\"App::PropertyFloat\",\"InvertedFaceScale\",\"WireFilter\",\"(InvertedFace Face Maker only) 2D scaling used for creating outer face from which original face is cut\").InvertedFaceScale = 5\n#        obj.addProperty(\"App::PropertyFloat\",\"Offset\",\"Offsetting\",\"2D offset in mm, < 0.0 = offset inwards, 0.0 = no offset, > 0.0 = offset outwards\")\n#        obj.addProperty(\"App::PropertyEnumeration\",\"OffsetJoin\",\"Offsetting\",\"Join method -- Arcs, Tangent, Intersection\")\n#        obj.OffsetJoin = [\"Arcs\",\"Tangent\",\"Intersection\"]\n#        obj.addProperty(\"App::PropertyBool\",\"OffsetFill\",\"Offsetting\", \"Whether to fill offset space (makes a face if true)\").OffsetFill = False\n#        obj.addProperty(\"App::PropertyBool\",\"OffsetOpenResult\",\"Offsetting\",\"Whether to allow open result or to close result\").OffsetOpenResult = False\n#        obj.addProperty(\"App::PropertyBool\",\"OffsetIntersection\",\"Offsetting\",\"Whether to offset child wires/faces independently or collectively\").OffsetIntersection = False\n#        obj.addProperty(\"App::PropertyVector\",\"Scale\",\"Scaling\",\"Scale Factor: if 1,1,1, no scaling is done\").Scale = FreeCAD.Vector(1,1,1)\n#        obj.addProperty(\"App::PropertyString\",\"Version\",\"WireFilter\",\"Version of WireFilter used to create this object.\").Version = __version__\n#        obj.addProperty(\"App::PropertyVector\",\"Normal\",\"WireFilter\",\"Normal of Face1 or Wire1 if no face\").Normal = FreeCAD.Vector(0,0,1)\n#        obj.addProperty(\"App::PropertyBool\",\"FollowSource\",\"WireFilter\",\"If False, source's placement is ignored.\").FollowSource = True\n#        obj.addProperty(\"App::PropertyBool\",\"UseDefault\",\"WireOrder\",\"[Trigger] sets wire order to default [1,2,3,4...] and resets itself to False\").UseDefault = False\n#        obj.addProperty(\"App::PropertyBool\",\"EditWireOrder\",\"WireOrder\",\"[Trigger] opens wire order editor, resets self to False\").EditWireOrder = False\n#        obj.addProperty(\"App::PropertyLink\",\"CompareObject\",\"WireOrder\",\"Object to compare to this wire order in editor\")\n#        obj.addProperty(\"App::PropertyLink\",\"Ghost\",\"WireOrder\",\"Temporary object created while wire order editor is open\")\n#        obj.addProperty(\"App::PropertyBool\",\"HideGhost\",\"WireOrder\",\"Internal use: hide the ghost if comparing wirefilter to itself in wire order dialog\").HideGhost = False\n#        obj.addProperty(\"App::PropertyBool\",\"ReUseGhost\",\"WireOrder\",\"Internal use: whether to reuse same compare object instead of asking.  This is for when using Apply or Accept in dialog\").ReUseGhost = False\n#        obj.setEditorMode(\"Ghost\",2) #hidden\n#        obj.setEditorMode(\"HideGhost\",2)\n#        obj.setEditorMode(\"ReUseGhost\",2)\n#        obj.addProperty(\"App::PropertyBool\",\"FixNormal\",\"WireFilter\",\"[Trigger] Fix Pad or Extrude's custom direction if it can't find the normal correctly.\").FixNormal = False\n#        obj.addProperty(\"App::PropertyFloat\",\"UniformScale\",\"Scaling\",\"Scale the WireFilter uniformly.  Keeps it centered, too.\").UniformScale = 1.0\n#        obj.Proxy = self\n#        self.fpName = obj.Name\n#        self.editingMode = False #wire order editor\n#\n#    def onChanged(self,fp,prop):\n#        if prop == \"WireOrder\":\n#            self.setWireOrder(fp)\n#        elif prop == \"UseDefault\" and fp.UseDefault and hasattr(fp,\"WireOrder\"):\n#            fp.WireOrder = [] #will get set to defaults\n#        elif prop == \"FixNormal\" and fp.FixNormal:\n#            fp.FixNormal = False\n#            self.fixNormal(fp)\n#        elif prop == \"Source\" and hasattr(fp,\"WireOrder\"):\n#            fp.WireOrder = []\n#        elif prop == \"EditWireOrder\" and fp.EditWireOrder:\n#            t = QtCore.QTimer()\n#            t.singleShot(50, self.showWires)\n#        elif prop == \"MaxWires\":\n#            fp.WireOrder = []\n#        elif prop == \"UsePreselection\":\n#            fp.WireOrder = []\n#\n#    def clearColorKeys(self,fp):\n#        for p in fp.PropertiesList:\n#            if \"Wire\" in p and \"Color\" in p:\n#                fp.removeProperty(p)\n#\n#    def setColorKeys(self,fp):\n#        self.clearColorKeys(fp)\n#        if not hasattr(fp,\"ColorKeyCount\"):\n#            return #object made with earlier version of WireFilter macro\n#        for ii in range (1,fp.ColorKeyCount+1):\n#            if not hasattr(fp,\"Wire\"+format(ii,\"03\")+\"Color\"):\n#                fp.addProperty(\"App::PropertyColor\",\"Wire\"+format(ii,\"03\")+\"Color\",\"WireColors\",\"Wire color keys, (some edges may belong to more than one wire\\nin which case the last wire color set takes precedence)\\nHint: select vertex in 3D view so edge colors are viewable.\")\n#                setattr(fp,\"Wire\"+format(ii,\"03\")+\"Color\",self.colorize(fp,Part.Shape(),True,ii))\n#                fp.setEditorMode(\"Wire\"+format(ii,\"03\")+\"Color\",1) # readonly\n#\n#    def fixNormal(self,fp):\n#        '''fixes a Pad or Extrude if it cannot find the correct normal direction for extruding'''\n#        inlist = fp.InList\n#        pads = [obj for obj in inlist if hasattr(obj,\"UseCustomVector\") and bool(obj.TypeId == \"PartDesign::Pad\" or obj.TypeId == \"PartDesign::Pocket\") and obj.Profile and obj.Profile[0] == fp]\n#        if len(pads) != 0:\n#            for pad in pads:\n#                pad.UseCustomVector = True\n#                pad.Direction = fp.Normal\n#                if pad.TypeId == \"PartDesign::Pocket\":\n#                    pad.Direction = fp.Normal * -1\n#        extrudes = [obj for obj in inlist if obj.TypeId == \"Part::Extrusion\" and obj.Base and obj.Base == fp]\n#        if len(extrudes) != 0:\n#            for ext in extrudes:\n#                ext.DirMode = \"Custom\"\n#                ext.Dir = fp.Normal\n#\n#    #borrowed from Draft.Clone scaling code\n#    def scale(self,fp,shp):\n#        m = FreeCAD.Matrix()\n#        if not shp.isNull():\n#            sx,sy,sz = fp.Scale\n#            if not fp.Scale.isEqual(FreeCAD.Vector(1, 1, 1),1e-7):\n#                op = shp.Placement\n#                shp.Placement = FreeCAD.Placement()\n#                m.scale(fp.Scale)\n#                if sx == sy == sz:\n#                    shp.transformShape(m)\n#                else:\n#                    shp = shp.transformGeometry(m)\n#                shp.Placement = op\n#            if not fp.UniformScale == 1.0:\n#                shp.scale(fp.UniformScale,shp.BoundBox.Center)\n#        return shp\n#\n#    def offset(self,fp,shp):\n#        if fp.Offset == 0.0:\n#            return shp\n#        mapped = {\"Arcs\":0,\"Tangent\":1,\"Intersection\":2}\n#        join = mapped[fp.OffsetJoin]\n#        return(shp.makeOffset2D(fp.Offset,join,fp.OffsetFill,fp.OffsetOpenResult,fp.OffsetIntersection))\n#\n#    def setWireOrder(self,fp):\n#        '''user has adjusted WireOrder property.  Pad with 0's if some are missing'''\n#        if fp.Source:\n#            if len(fp.WireOrder) < len(fp.Source[0].Shape.Wires) and len(fp.WireOrder) != 0:\n#                needed = len(fp.Source[0].Shape.Wires) - len(fp.WireOrder)\n#                if needed != len(fp.Source[0].Shape.Wires):\n#                    fp.WireOrder += [0] * needed\n#                else:\n#                    fp.WireOrder = []\n#\n#    def fixWireOrder(self,fp,shp):\n#        '''if length of wires in shape has changed, reset wire order to default'''\n#        if len(fp.WireOrder) != len(shp.Wires):\n#            fp.WireOrder = range(1,len(shp.Wires)+1)\n#            if hasattr(fp,\"MaxWires\") and len(fp.WireOrder) > fp.MaxWires:\n#                fp.WireOrder = fp.WireOrder[:fp.MaxWires]\n#\n#    def isInWire(self,edge,wire):\n#        '''return True if edge is in wire'''\n#        edges = wire.Edges\n#        for e in edges:\n#            if e.isSame(edge) or e.isEqual(edge) or e.isPartner(edge):\n#                return True\n#        return False\n#\n#    def getWireDict(self,shape,maxWires):\n#        '''returns a dictionary of form wire:[list of edge names]'''\n#        edgenames = {}\n#        wire_dict = {}\n#        for ee in range (0,len(shape.Edges)):\n#            edgenames[shape.Edges[ee]] = \"Edge\"+str(ee+1)\n#        wire_count = len(shape.Wires)\n#        if wire_count > maxWires:\n#            wire_count = maxWires\n#        for ww in range(0,wire_count):\n#            wire_dict[ww+1] = []\n#            for k,v in edgenames.items():\n#                if self.isInWire(k, shape.Wires[ww]):\n#                    wire_dict[ww+1] += [v]\n#        return wire_dict\n#\n#    def makeFilledFace(self, fp, shape):\n#        return Part.makeFilledFace(shape.Edges)\n#\n#    def makeInvertedFace(self,fp,wire):\n#        faceOriginal = Part.makeFace(wire,\"Part::FaceMakerBullseye\")\n#        faceOuter = Part.makeFace(faceOriginal.OuterWire,\"Part::FaceMakerCheese\")\n#        offset = faceOuter.scale(fp.InvertedFaceScale, faceOuter.CenterOfGravity)\n#        cut = offset.cut(faceOriginal)\n#        return cut\n#\n#    def wireIsPlanar(self, wire):\n#        '''check if the wire is planar and return true/false'''\n#        import DraftGeomUtils as dgu\n#        return dgu.is_planar(wire)\n#\n#    def color(self, s):\n#        return QColor(s).getRgbF()\n#\n#    def getCL(self):\n#        colors = COLORS\n#        colorNames = QColor.colorNames() #color name strings supported by Qt\n#        colorNames.remove(\"black\") # will be default color for edges if we run out of colors\n#        for c in colorNames:\n#            if not c in colors:\n#                colors.append(c)\n#        cL = [] #color list of tuples, eg. red is (1.0,0.0,0.0,1.0) rgba\n#        colorDuplicates = [] #sometimes the name is different, but the color is the same\n#        for cn in colors:\n#            if not self.color(cn) in cL:\n#                cL.append(self.color(cn))\n#            else:\n#                colorDuplicates.append(cn)\n#        for cd in colorDuplicates:\n#            colors.remove(cd)\n#        return cL\n#\n#    def colorize(self,fp,shape,getColor = False,idx = -1):\n#        '''assign colors to individual wires if Colorize = True'''\n#        cL = self.getCL()\n#        if getColor:\n#            return cL[idx -1]\n#        if not fp.Colorize:\n#            fp.ViewObject.LineColorArray = [self.color(\"black\")]\n#            return\n#        if not len(shape.Wires):\n#            return #no wires\n#        cLArray = self.getColorArray(fp, shape, cL)\n#        fp.ViewObject.LineColorArray = cLArray\n#\n#    def flashAWire(self, fp, idx, reason=None):\n#        red = COLORS.index(\"red\")\n#        blue = COLORS.index(\"blue\")\n#        green = COLORS.index(\"green\")\n#        white = COLORS.index(\"white\")\n#        black = COLORS.index(\"black\")\n#        silver = COLORS.index(\"silver\")\n#        teal = COLORS.index(\"teal\")\n#        yellow = COLORS.index(\"yellow\")\n#        orange = COLORS.index(\"orange\")\n#\n#        num_wires = len(fp.WireOrder)\n#        multiplier = 15 if num_wires < 5 else 5 if num_wires < 10 else 2\n#\n#        if not reason:\n#            colorIndices = []\n#        elif reason == \"selected\":\n#            colorIndices = [black,white,silver]*multiplier\n#        elif reason == \"disabled\":\n#            colorIndices = [red,orange,yellow]*multiplier\n#        elif reason == \"enabled\":\n#            colorIndices = [blue,green,teal]*multiplier\n#\n#        for ii in colorIndices:\n#            self.colorAWire(fp, idx, ii)\n#            time.sleep(.01)\n#            FreeCADGui.updateGui()\n#        self.colorize(fp, fp.Shape)\n#\n#    def colorAWire(self, fp, idx, colorIdx):\n#        cL = self.getCL()\n#        shape = fp.Shape\n#        colors = COLORS\n#        #print(f\"in colorAWire, idx = {idx}, colorIdx = {colorIdx}\")\n#        cLArray = self.getColorArray(fp, shape, cL)\n#        wireDict = self.getWireDict(shape, len(shape.Edges))\n#        for k,vals in enumerate(wireDict.values()):\n#            numbers = [int(val.replace(\"Edge\",\"\"))-1 for val in vals]\n#            #FreeCAD.Console.PrintMessage(f\"Wire{k+1} set to {colors[k]}\\n\")\n#            if k == idx:\n#                for num in numbers:\n#                    cLArray[num] = cL[colorIdx]\n#                    #FreeCAD.Console.PrintMessage(f\"num = {num} cLArray[num] = {cLArray[num]}, cL[colorIdx] = {cL[colorIdx]}\\n\")   \n#        fp.ViewObject.LineColorArray = cLArray\n#\n#    def getColorArray(self, fp, shape, cL):\n#        edgeCount = len(shape.Edges)\n#        if edgeCount > len(cL):\n#            cL = cL+[self.color(\"black\")]*(edgeCount - len(cL)) #extend cL with extra black colors\n#            FreeCAD.Console.PrintWarning(\"Too many wires for the number of colors in the color list, extra wires will all be black\\n\")  \n#        wireDict = self.getWireDict(shape,edgeCount)\n#        colors = COLORS\n#        cLArray = [None]*edgeCount\n#        for k,vals in enumerate(wireDict.values()):\n#            numbers = [int(val.replace(\"Edge\",\"\"))-1 for val in vals]\n#           # FreeCAD.Console.PrintMessage(f\"Wire{k+1} set to {colors[k]}\\n\")\n#            for num in numbers:\n#                cLArray[num] = cL[k]\n#        return cLArray\n#\n#    def execute(self,fp):\n#        if not fp.Source:\n#            return\n#        self.setColorKeys(fp)\n#        shape = fp.Source[0].Shape.copy()\n#\n#        if fp.FollowSource and not shape.isNull():\n#            shape = shape.transformShape(shape.Placement.toMatrix(),True)\n#\n#        wire_count = len(shape.Wires)\n#        if hasattr(fp,\"MaxWires\") and wire_count > fp.MaxWires:\n#            wire_count = fp.MaxWires\n#\n#        if fp.Source[1] and bool(hasattr(fp,\"UsePreselection\") and fp.UsePreselection):\n#            faces = [name for name in fp.Source[1] if \"Face\" in name or \"Wire\" in name]\n#            if len(faces) != 0:\n#                shapes = [getattr(shape,f) for f in faces]\n#                shape = Part.makeCompound(shapes)\n#            else:\n#                #handle edges\n#                edges = [name for name in fp.Source[1] if \"Edge\" in name]\n#                if len(edges) != 0:\n#                    wire_dict = self.getWireDict(shape,fp.MaxWires)\n#                    wire_order = [ww for ww in range(1,wire_count+1)]\n#                    for k in range(1,wire_count+1):\n#                        found = False\n#                        for en in wire_dict[k]: #en = edge names in this wire\n#                            for un in edges: #un = user name, edges user selected\n#                                if en == un:\n#                                    found = True\n#                                    break\n#                            if found:\n#                                break\n#                        if not found:\n#                            wire_order[k-1] = 0\n#                        else:\n#                            wire_order[k-1] = k\n#                    fp.WireOrder = wire_order\n#        wires = shape.Wires\n#        fp.WireOrder = fp.WireOrder[:len(wires)]\n#        if hasattr(fp,\"MaxWires\") and len(wires) > fp.MaxWires:\n#            wires = wires[:fp.MaxWires]\n#            FreeCAD.Console.PrintWarning(\"MaxWires (\"+str(fp.MaxWires)+\") exceeded.  Source has \"+str(len(shape.Wires))+\" wires.  Set MaxWires property higher if you want to use all the wires.\\n\")\n#        self.fixWireOrder(fp,shape)\n#        reordered = [wires[ii-1] for ii in fp.WireOrder if ii != 0]\n#        if len(reordered) == 0:\n#            new_shape = Part.Shape()\n#        elif len(reordered)==1:\n#            new_shape = Part.makeCompound(reordered)\n#        elif len(reordered)>1:\n#            new_shape = Part.makeCompound(reordered)\n#\n#        if fp.FaceMaker != \"No Face\":\n#            if fp.FaceMaker == \"InvertedFace\":\n#                face = self.makeInvertedFace(fp,new_shape)\n#            elif fp.FaceMaker == \"FilledFace\":\n#                face = self.makeFilledFace(fp,new_shape)\n#            else:\n#                face = Part.makeFace(new_shape,fp.FaceMaker)\n#            new_shape = face\n#\n#        fp.positionBySupport()\n#        if fp.FollowSource and not new_shape.isNull():\n#            shape = new_shape.transformShape(shape.Placement.inverse().toMatrix(),True)\n#        elif not fp.FollowSource and not new_shape.isNull():\n#            shape = new_shape.transformShape(shape.Placement.inverse().toMatrix(),True)\n#            shape.Placement = FreeCAD.Placement()\n#\n#        if hasattr(shape,\"Face1\"):\n#            fp.Normal = shape.Face1.normalAt(0,0)\n##            FreeCAD.Console.PrintMessage(\"Normal found at: \"+str(fp.Normal)+\"\\n\")\n#        elif hasattr(shape,\"Wire1\") and self.wireIsPlanar(shape.Wire1) and shape.Wire1.isClosed():\n#            fp.Normal = Part.makeFace(shape.Wire1,\"Part::FaceMakerBullseye\").normalAt(0,0)\n##            FreeCAD.Console.PrintMessage(\"Normal found at: \"+str(fp.Normal)+\"\\n\")\n#        elif len(shape.Wires) != 0:\n#            FreeCAD.Console.PrintWarning(\"Unable to find Normal of Wire1\\n\")\n#\n#        fp.Shape = self.offset(fp,shape)\n#        fp.Shape = self.scale(fp, fp.Shape.copy())\n#\n#        if not hasattr(fp,\"Colorize\"): #object made with earlier version of WireFilter macro\n#            return\n#        else:\n#            self.colorize(fp,fp.Shape)\n#\n#    def getCompareObject(self,fp):\n#        #put objects with same wire count as fp at the top of the list\n#        objs = [o.Label for o in fp.Document.Objects if hasattr(o,\"Shape\")\\\n#and len(o.Shape.Wires) == len(fp.Shape.Wires)\\\n#and o != fp and o != fp.Source[0]]\n#        items = objs\n#        items += [o.Label for o in fp.Document.Objects\\\n#if not o.isDerivedFrom(\"PartDesign::Body\")\\\n#and (o.isDerivedFrom(\"Part::Feature\")\\\n#and o != fp and o != fp.Source[0]\\\n#and o.Label not in objs)]\n#        items += [f\"Self (uses {fp.Source[0].Label})\"]\n#        fp.HideGhost = False\n#        if len(items) == 2:\n#            return fp.Document.getObjectsByLabel(items[0])[0]\n#        elif len(items) == 1:\n#            fp.HideGhost = True\n#            return fp.Source[0]\n#        item,ok = QtGui.QInputDialog.getItem(FreeCADGui.getMainWindow(), \"WireFilter\",\"Pick an item from the list to compare the wires to.\", items, 0)\n#        if ok:\n#            fp.HideGhost = False\n#            if item == f\"Self (uses {fp.Source[0].Label})\":\n#                fp.HideGhost = True\n#                return fp.Source[0]\n#            return fp.Document.getObjectsByLabel(item)[0]\n#        else:\n#            return False\n#\n#    def showWires(self):\n#        '''Show the wire order task panel'''\n#        fp = FreeCAD.ActiveDocument.getObject(self.fpName)\n#        if bool(hasattr(fp,\"UsePreselection\") and fp.UsePreselection) and fp.Source[1]:\n#            FreeCAD.Console.PrintError(\"WireFilter created using subelements of source object.  Create a new WireFilter of this WireFilter to \\\n#edit the wire order\\n\")\n#            return\n#        if len(fp.Shape.Wires) == 0: #no wires to edit\n#            FreeCAD.Console.PrintMessage(\"WireFilter: no wires to edit wire order for\\n\")\n#            return\n#        if not fp.ReUseGhost:\n#            co = self.getCompareObject(fp)\n#        else:\n#            fp.ReUseGhost = False# ask next time unless this is set in dialog\n#            co = fp.CompareObject\n#        if not co:\n#            return\n#        else:\n#            fp.CompareObject = co\n#        wf = fp.Document.addObject(\"Part::FeaturePython\",\"WF_Ghost\")\n#        wf.Label2 = \"(Temporary object that should be automatically deleted when dialog closes)\"\n#        self.putInBody(fp, wf)\n#        WireFilter(wf)\n#        WireFilterVP(wf.ViewObject)\n#        wf.Source = fp.CompareObject\n#        fp.CompareObject.ViewObject.Visibility = False\n#        fp.Ghost = wf\n#        if fp.HideGhost:\n#            fp.Ghost.ViewObject.Visibility = False\n#        fp.Document.recompute()\n#        \n#        if not FreeCADGui.Control.activeDialog():\n#            panel = TaskEditWireOrdersPanel(fp)\n#            FreeCADGui.Control.showDialog(panel)\n#            self.editingMode = True \n#        else:\n#            self.editingMode=False\n#            FreeCAD.Console.PrintError(\"Another task dialog is active.  Close that one and try again.\\n\")\n#            return\n#\n#    def cleanUpWires(self):\n#        '''remove temporary representation of wires being manipulated'''\n#        fp = FreeCAD.ActiveDocument.getObject(self.fpName)\n#        if fp.Ghost:\n#            fp.Ghost.Source[0].ViewObject.Visibility = True if not fp.HideGhost else False\n#            fp.Document.removeObject(fp.Ghost.Name)\n#            fp.Document.recompute()\n#\n#    def putInBody(self, fp, ghost):\n#        '''put the ghost into the same body as its source'''\n#        bodies = [obj for obj in fp.Document.Objects if obj.isDerivedFrom(\"PartDesign::Body\") and fp.CompareObject in obj.Group]\n#        if len(bodies) == 1:\n#            bodies[0].Group += [ghost]\n#        else:\n#            parts = [obj for obj in fp.Document.Objects if obj.TypeId == \"App::Part\" and fp.CompareObject in obj.Group]\n#            if len(parts) == 1:\n#                parts[0].Group += [ghost]\n#\n#class TaskEditWireOrdersPanel: #simple editor for wire orders\n#    def __init__(self, fp):\n#        FreeCADGui.Selection.clearSelection()\n#        self.blockSignals = True\n#        self.fp = fp\n#        self.wireOrder = self.fp.WireOrder\n#        self.form = QtWidgets.QWidget()     \n#        self.layout=QtWidgets.QVBoxLayout()\n#        self.form.setLayout(self.layout)\n#        self.form.setWindowTitle('Edit Wire Order')\n#        self.form.setObjectName(\"TaskEditWireOrdersPanel\")\n#        wireBox = QtWidgets.QHBoxLayout()\n#        self.layout.addLayout(wireBox)\n#        self.wireOrderEdit = QtWidgets.QLineEdit()\n#        self.wireOrderEdit.setPlaceholderText(f\"(Optional) Enter wire order and press OK or Apply. Example: {self.fp.WireOrder}\")\n#        self.wireOrderEdit.setToolTip(\"\\\n#You can use this to directly enter a new wire order rather than using \\n\\\n#the radio buttons.  Enter as a comma separated list of integers.\\n\\\n#Enter 0 to disable a wire.\")\n#        self.wireOrderLabel = QtWidgets.QLabel(f\"Current Wire Order: {fp.WireOrder}\")\n#        wireBox.addWidget(self.wireOrderLabel)\n#        wireBox.addWidget(self.wireOrderEdit)\n#        self.hboxes = []\n#        self.buttonlist = []\n#        self.buttongroups = []\n#        self.enableds = [] #checkboxes to enable/disable wires\n#        self.hboxArea = QtWidgets.QVBoxLayout()\n#        self.scrollArea = QtWidgets.QScrollArea()  # Create a scroll area\n#        scrollWidget = QtWidgets.QWidget()\n#        scrollWidget.setStyleSheet(\"background-color: lightblue;\")\n#        scrollWidget.setLayout(self.hboxArea)\n#        self.scrollArea.setWidgetResizable(True)  # Make the widget inside the scrollable\n#        self.scrollArea.setWidget(scrollWidget)  # Set hboxArea as the widget inside the scroll area\n#        self.layout.addWidget(self.scrollArea)  # Add the scroll area to the main layout\n#        self.makeHBoxes()\n#        hbox = QtWidgets.QHBoxLayout()\n#        self.layout.addLayout(hbox)\n#        self.showWireFilterCheckBox = QtWidgets.QCheckBox(\"Show WireFilter\")\n#        self.showWireFilterCheckBox.setChecked(True)\n#        self.showWireFilterCheckBox.clicked.connect(self.onShowWireFilterCheckBoxClicked)\n#        hbox.addWidget(self.showWireFilterCheckBox)\n#        self.showGhostCheckBox = QtWidgets.QCheckBox(\"Show Ghost\")\n#        self.showGhostCheckBox.setChecked(True)\n#        self.showGhostCheckBox.clicked.connect(self.onShowGhostCheckBoxClicked)\n#        hbox.addWidget(self.showGhostCheckBox)\n#        self.helpRequestedCheckBox = QtWidgets.QCheckBox(\"Show help\")\n#        hbox.addWidget(self.helpRequestedCheckBox)\n#        self.helpRequestedCheckBox.clicked.connect(self.helpRequested)\n#        if len(self.fp.Shape.Wires) < 7 and not 0 in self.wireOrder:\n#            permsTxt = self.getPermsText(bPrev = True)\n#            self.btnPrevPerms = QtWidgets.QPushButton(permsTxt)\n#            self.btnPrevPerms.clicked.connect(self.previousPermutation)\n#            if permsTxt:\n#                hbox.addWidget(self.btnPrevPerms)\n#            permsTxt = self.getPermsText()\n#            self.btnPerms = QtWidgets.QPushButton(permsTxt)\n#            self.btnPerms.clicked.connect(self.nextPermutation)\n#            if permsTxt:\n#                hbox.addWidget(self.btnPerms)\n#        self.helpLabel = QtWidgets.QLabel()\n#        self.setupHelp()\n#\n#        self.fp.Proxy.editingMode = True\n#        self.blockSignals = False\n#\n#    def checkLuminance (self, bg):\n#        \"\"\"check the luminance and return either black or white for foreground color\"\"\"\n#        bgcol = self.fp.Proxy.color(bg)# takes a string and returns a QColor\n#        red, green, blue, alpha = bgcol\n#\n#    # Convert the color components to the sRGB color space\n#        red_srgb = red if red <= 0.04045 else ((red + 0.055) / 1.055) ** 2.4\n#        green_srgb = green if green <= 0.04045 else ((green + 0.055) / 1.055) ** 2.4\n#        blue_srgb = blue if blue <= 0.04045 else ((blue + 0.055) / 1.055) ** 2.4\n#\n#    # Calculate the luminance\n#        lum = 0.2126 * red_srgb + 0.7152 * green_srgb + 0.0722 * blue_srgb\n#        if lum > 0.5:\n#            return \"black\"\n#        else:\n#            return \"white\"\n#\n#    def setupHelp(self):\n#        \"\"\"add a label at the bottom of the panel to provide helpful information.\"\"\"\n#        txt = \"\"\"\n#\n#With this dialog you can edit the wire order in the WireFilter object and you can\n#enable or disable individual wires.  For example, you can make Wire1 of the source\n#object Wire3 of the WireFilter object or you can disable Wire1 in the WireFilter\n#object, in which case Wire2 of the source becomes Wire1 in the WireFilter and so on.\n#\n#Let's suppose you have applied WireFilter to Sketch, which contains 3 wires: Wire1,\n#Wire2, and Wire3.  But you want them reordered in the WireFilter object so that Wire1 \n#becomes Wire3 and Wire3 becomes Wire1.  In this example the wire order needs to be \n#[3,2,1] since Wire3 becomes Wire1, Wire2 remains the same, and Wire1 becomes Wire3.\n#\n#The motivation for reording the wires is to make Part Design Loft and Part Design\n#Sweep with multisections work the way you want them to work if the wires in the sketches\n#are getting crossed or just not connecting to each other in the desired manner.\n#\n#The motivation for disabling some wires could be where you want to reuse the same\n#sketch, but you don't want to use all the wires.  Or you might be making a WireFilter \n#of a face and don't want all the wires in the filter.\n#\n#Push Buttons -- In the left column there are a number of push buttons, one for each \n#wire in the object you are comparing the WireFilter to.  Typically, this object would \n#be the other sketch to be used in a Loft.  If you click one of these push buttons the \n#only effect is that wire gets flashed in the 3D view.  The flashing colors are black, \n#gray, and white, and then after it finishes flashing it reverts back to its original color. \n#That's the only thing the left column buttons do -- they flash the wire that you need \n#to select one of the radio buttons to connect to in the Loft or Sweep.\n#\n#Enabled Checkboxes -- In each row in the 2nd column there is an Enabled checkbox.  This \n#is used to enable or disable that wire in the WireFilter object.  When you disable a \n#wire it will flash through red, yellow, and orange, to indicate to you that it is being \n#disabled.  It's Wire Order value is set to 0.  If that was not the wire you wanted to \n#disable, all you need to do is check the box again to re-enable it.  When being re-enabled, \n#the wire will flash blue, teal, and green.\n#\n#Radio Buttons -- The remainder of the widgets in each row are radio buttons.  These are \n#used to select the mapping for this wire in the compared item, e.g. sketch, to connect to \n#in a Part Design Loft.  When you select one of these radio buttons the indicated wire will \n#flash white, gray, and black.  So, by clicking the push button and the radio button and watching\n#to see which wires flash, then you can know which ones will be connected in the Loft.  Note:\n#if you see asterisks in the labels of the radio buttons it's an indicator that none of the radio \n#buttons in that column have yet been connected to a wire in the compare object.\n#\n#Current Wire Order Label -- This label is at the top left of the form.  It shows the current \n#working wire order.  If it turns red, that indicates there are duplicates in the wire order. \n#For example: [1,1,3] would be red because the 1 is duplicated.  This is normal because you will \n#necessarily have duplicates while you are fiddling with the dialog.  You should not use Apply \n#or OK while this label is red because it will cause some wires to be disabled and you won't be \n#able to re-enabled them without first resetting everything back to default and starting all over\n#again. In the above example [1,1,3] Wire2 will be disabled.\n#\n#Show ghost checkbox\n#The ghost is the colorized version of the object the wirefilter is being compared with.  It's a \n#temporary object that will be deleted when the editor dialog is closed.\n#\n#Previous Permutation, Next Permutation buttons\n#\n#If the WireFilter object has fewer than 7 wires you will get additional permutation buttons. \n#You can use these to try all the various possible wire orders, but only if you haven't disabled \n#any of the wires.  Permutation is a fancy way of saying how the wires are ordered.  The fewer \n#wires you have the fewer possible permutations there are.  For example, if you only have 2 wires, \n#then the permutations are: [1,2] and [2,1].  If you have 3 wires, then you have 6 permutations: \n#[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], and [3,2,1].  The Permutation buttons just allow you \n#to cycle through all the possibilities.  When you get to 7 or more wires, there are too many \n#permutations to reasonably cycle through in this manner, so these buttons are not shown.\n#\n#Reset -- resets the wire order to what it was when you first opened this editor or\n#since the last time you clicked Apply or Restore Defaults.\n#\n#Restore Defaults -- Resets the wire order back to default: [1,2,3...] (Can be undone\n#using FreeCAD's Undo/Redo system.\n#\n#OK -- Accept the current wire order configured in this dialog (or manually entered\n#in the wire order line edit widget) and closes the dialog. (Can be undone.)\n#\n#Cancel -- Cancel any changes made in this dialog since last time you clicked Apply\n#or Restore Defaults and closes dialog.\n#\n#Apply -- Apply changes, but leave the dialog open.  (Can be undone, but you should\n#press Cancel, then Undo, and then open the dialog again if you want to undo.)\n#Note: This function actually clicks OK, and then reopens the dialog for you.\n#\n#Show help -- Brings up this help text when checked.\n#\n#\"\"\"\n#\n#\n#        self.helpLabel.setText(txt)\n#        self.layout.addWidget(self.helpLabel)\n#        self.helpLabel.setVisible(False)\n#\n#    def helpRequested(self):\n#        checked = self.helpRequestedCheckBox.isChecked()\n#        self.helpLabel.setVisible(checked)\n#\n#    def onShowGhostCheckBoxClicked(self):\n#        checked = self.showGhostCheckBox.isChecked()\n#        self.fp.Ghost.ViewObject.Visibility = checked\n#\n#    def onShowWireFilterCheckBoxClicked(self):\n#        checked = self.showWireFilterCheckBox.isChecked()\n#        self.fp.ViewObject.Visibility = checked\n#\n#    def makeHBoxes(self):\n#        def makeTrigger(x,y): return lambda : self.wireBtnClicked(x,y)\n#        def makeEnabled(x): return lambda : self.enabledClicked(x)\n#        buttons = []\n#        for idx,wire in enumerate(self.fp.Shape.Wires):\n#            idx += 1\n#            hbox = QtGui.QHBoxLayout()\n#            btn = QtGui.QPushButton(self.fp.CompareObject.Label+\" \"+str(idx))\n#            btn.setStyleSheet(f\"background-color: {COLORS[idx-1]};color:{self.checkLuminance(COLORS[idx-1])};font-weight:bold;\")\n#            btn.clicked.connect(makeTrigger(idx,self.fp))\n#            btn.setObjectName(btn.text())\n#            buttons.append(btn)\n#            hbox.addWidget(btn)\n#            cb = QtWidgets.QCheckBox(\"Enabled\")\n#            cb.setChecked(True)\n#            cb.setObjectName(f\"Enabled {idx}\")\n#            self.enableds.append(cb)\n#            hbox.addWidget(cb)\n#            cb.clicked.connect(makeEnabled(idx-1))\n#\n#            group = QtGui.QButtonGroup(hbox)\n#            self.buttongroups.append(group)\n#            for idx2,wire2 in enumerate(self.fp.CompareObject.Shape.Wires):\n#                idx2 += 1\n#                btn2 = QtGui.QRadioButton(\"WF \"+str(idx2))\n#                if self.wireOrder[idx -1] == idx2:\n#                    btn2.setChecked(True)\n#                btn2.setStyleSheet(f\"background-color: {COLORS[idx2-1]};color:{self.checkLuminance(COLORS[idx2-1])};font-weight:bold;\")\n#                btn2.clicked.connect(makeTrigger(idx,idx2))\n#                btn2.setObjectName(f\"{idx}_{idx2}\")\n#                hbox.addWidget(btn2)\n#                buttons.append(btn2)\n#                group.addButton(btn2)\n#            self.buttonlist.append(buttons)\n#            buttons = []\n#            self.hboxArea.addLayout(hbox)\n#            if idx % 3 == 0:\n#                divider = QtWidgets.QFrame()\n#                divider.setFrameShape(QtWidgets.QFrame.HLine)\n#                divider.setFrameShadow(QtWidgets.QFrame.Sunken)\n#                self.hboxArea.addWidget(divider)\n#\n#    def nextPermutation(self):\n#        \"\"\"Try the next permutation in the wire order list\"\"\"\n#        if 0 in self.wireOrder:\n#            FreeCAD.Console.PrintMessage(\"WireFilter: 0 in wire order, skipping permutations\\n\")\n#            return\n#        from itertools import permutations\n#        unique_integers = sorted(self.wireOrder)\n##        print(f\"self.wireOrder = {self.wireOrder}\")\n#        # Generate all permutations\n#        all_permutations = list(permutations(unique_integers))\n#        if tuple(self.wireOrder) in all_permutations:\n#            idx = all_permutations.index(tuple(self.wireOrder))\n##            print(f\"idx = {idx}\")\n#            if idx >= len(all_permutations) -1:\n#                idx = -1 #return the first permutation\n#            self.wireOrder = list(all_permutations[idx+1])\n#            self.clicked(QtGui.QDialogButtonBox.Apply)\n#        else:\n#            FreeCAD.Console.PrintMessage(\"WireFilter: current wire order not a valid permutation\\n\")\n#            return\n#\n#    def previousPermutation(self):\n#        \"\"\"Try the previous permutation in the wire order list\"\"\"\n#        if 0 in self.wireOrder:\n#            FreeCAD.Console.PrintMessage(\"WireFilter: 0 in wire order, skipping permutations\\n\")\n#            return\n#        from itertools import permutations\n#        unique_integers = sorted(self.wireOrder)\n##        print(f\"self.wireOrder = {self.wireOrder}\")\n#        # Generate all permutations\n#        all_permutations = list(permutations(unique_integers))\n#        if tuple(self.wireOrder) in all_permutations:\n#            idx = all_permutations.index(tuple(self.wireOrder))\n##            print(f\"idx = {idx}\")\n#            if idx == 0:\n#                idx = len(all_permutations)\n#            self.wireOrder = list(all_permutations[idx-1])\n#            self.clicked(QtGui.QDialogButtonBox.Apply)\n#        else:\n#            FreeCAD.Console.PrintMessage(\"WireFilter: current wire order not a valid permutation\\n\")\n#            return\n#    def getPermsText(self, bPrev = False):\n#        from itertools import permutations\n#        unique_integers = sorted(self.wireOrder)\n#        # Generate all permutations\n#        all_permutations = list(permutations(unique_integers))\n#        if tuple(self.wireOrder) in all_permutations:\n#            idx = all_permutations.index(tuple(self.wireOrder)) + 1\n#            if idx == len(all_permutations):\n#                idx = 0 #return the first permutation\n#            idx += 1\n#            if not bPrev:\n#                return f\"Next Permutation {idx}/{len(all_permutations)}\"\n#            else:\n#                idx -= 2\n#                if idx == 0:\n#                    idx = len(all_permutations)\n#                elif idx == -1:\n#                    idx = len(all_permutations)-1\n#                return f\"Previous Permutation {idx}/{len(all_permutations)}\"             \n#        else:\n#            return \"\"     \n#\n#    def enabledClicked(self, idx):\n#        btn = self.enableds[idx]\n#        checked = btn.isChecked()\n##        print(f\"enabled clicked {idx}, btn = {btn}, checked = {checked}\")\n#        radios = self.buttonlist[idx]\n#        current = 0\n#        for rr,radio in enumerate(radios):\n#            if radio.isChecked():\n#                current = rr\n#        self.wireOrder[idx] = 0 if not checked else current\n#        self.wireOrderLabel.setText(f\"Current Wire Order: {self.wireOrder}\")\n#        reason = \"enabled\" if checked else \"disabled\"\n#        self.fp.Proxy.flashAWire(self.fp,idx,reason)\n#            \n#    def wireBtnClicked(self, row, col):\n#        if col != self.fp: #radio button clicked\n#            btn = self.buttonlist[row-1][col]\n#            pushBtn = self.buttonlist[row-1][0] #left column push button for this row\n##            print(btn.objectName()+\" found\")\n##            print(f\"row,col = {row},{col}\")\n##            print(f\"incoming wire order: {self.wireOrder}\")\n#            old = self.wireOrder[row-1]\n#            new = col\n##            print(f\"old = {old}\")\n##            print(f\"new = {new}\")\n#            self.fp.Proxy.flashAWire(self.fp,new-1,reason=\"selected\")\n#            self.wireOrder[row-1] = new\n#            self.wireOrderLabel.setText(f\"Current Wire Order: {self.wireOrder}\")\n#            wo_stripped = [x for x in self.wireOrder if x != 0]\n#            if self.hasDuplicates():\n#                self.wireOrderLabel.setStyleSheet(\"color:red;\")\n#                self.wireOrderLabel.setText(f\"Current Wire Order: {self.wireOrder}\")\n#                self.markDuplicates()\n#            else:\n#                self.unMarkAll()\n#                self.wireOrderLabel.setStyleSheet(\"color:black;\")\n#            self.fp.Proxy.colorize(self.fp, self.fp.Shape)\n#        else: #one of the left column buttons was clicked\n#            self.fp.Ghost.Proxy.flashAWire(self.fp.Ghost, row-1,reason=\"selected\")\n#\n#    def findDuplicates(self, my_list):\n#        \"\"\"find the subsequent duplicates in a list and return their indices\"\"\"\n#        seen = {}  # A dictionary to store the last seen index of each element\n#        duplicates = []  # List to store the indices of subsequent duplicates\n#        for index, item in enumerate(my_list):\n#            if item == 0:\n#                continue\n#            if item in seen:\n#                # If the item is already in the 'seen' dictionary, it's a duplicate\n#                if seen[item] is not None:\n#                    # Append the index of the subsequent duplicate\n#                    duplicates.append(index)\n#            else:\n#                # If the item is not in 'seen', add it with the current index\n#                seen[item] = index\n#        return duplicates\n#\n#    def unMarkAll(self):\n#        \"\"\"Unmark all pushbuttons as duplicates\"\"\"\n#        btns = [item for sublist in self.buttonlist for item in sublist] #flatten list\n#        for btn in btns:\n#            if \"QRadioButton\" in str(type(btn)):\n#                btn.setText(btn.text().replace(\"*\",\"\"))\n#\n#    def parseRadioButtonObjectName(self, name):\n#        parts = name.split(\"_\")\n#        if len(parts) == 2:\n#            x = int(parts[0])\n#            y = int(parts[1])\n#            return x, y\n#        else:\n#            raise ValueError(\"Input string does not have the expected format\")  \n#\n#    def markDuplicates(self):\n#        self.unMarkAll()\n#        duplicates = self.findDuplicates(self.wireOrder)\n#        all_btns = [item for sublist in self.buttonlist for item in sublist] #flatten list\n#        radio_btns = [b for b in all_btns if \"QRadioButton\" in str(type(b))]\n##        print (f\"radio_btns = {radio_btns}\")\n#        cols = len(self.buttonlist[0])-1\n#        uncheckedColumns = list(range(1,cols+1))\n##        print(f\"uncheckedColumns = {uncheckedColumns}\")\n#        for rb in radio_btns:\n#            r,c = self.parseRadioButtonObjectName(rb.objectName())\n##            print(f\"r,c,rb.text(),rb.isChecked() = {r},{c},{rb.text()},{rb.isChecked()}\")\n#            if rb.isChecked() and c in uncheckedColumns:\n#                uncheckedColumns.remove(c)\n##            print(f\"After parsing: uncheckedColumns = {uncheckedColumns}\")  \n#        uncheckedRadios = []\n#        for rb in radio_btns:\n#            r,c = self.parseRadioButtonObjectName(rb.objectName())\n#            if c in uncheckedColumns:\n#                uncheckedRadios.append(rb)\n#        for btn in uncheckedRadios:\n#            txt = btn.text()\n#            if not \"*\" in txt:\n#                new_txt = \"*\" + txt + \"*\"\n#                btn.setText(new_txt)                       \n#        \n#\n#    def hasDuplicates(self):\n#        \"\"\"Checks if self.wireOrder has duplicate non-zero values\"\"\"\n#        wo_stripped = [x for x in self.wireOrder if x != 0]\n#        if len(wo_stripped) != len(list(set(wo_stripped))):\n#            return True\n#        else:\n#            return False\n#\n#    def reject(self):\n#        FreeCADGui.Control.closeDialog()\n#        FreeCADGui.ActiveDocument.resetEdit()\n#        self.fp.Proxy.editingMode = False #self.fp.Proxy is the fp class object (self in that class)\n#        self.fp.ViewObject.Visibility = True\n#        self.fp.Proxy.cleanUpWires()\n#        FreeCAD.ActiveDocument.recompute()\n#\n#    def accept(self):\n#        if self.hasDuplicates():\n#            FreeCAD.Console.PrintWarning(\"WireFilter: Wire order has duplicate non-zero values\\n\")\n#        self.fp.Document.openTransaction(\"WireFilter:Accept Wire Order Changes\")\n#        wo = self.parseWireOrderEdit()\n#        if wo:\n#            self.fp.WireOrder = wo\n#        else:\n#            self.fp.WireOrder = self.wireOrder\n#        self.fp.Document.commitTransaction()\n#        FreeCADGui.Control.closeDialog()\n#        FreeCADGui.ActiveDocument.resetEdit()\n#        self.fp.Proxy.editingMode = False\n#        if not self.fp: #user deleted or closed document perhaps\n#            return\n#        self.fp.ViewObject.Visibility = True\n#        self.fp.Proxy.cleanUpWires()\n#        FreeCAD.ActiveDocument.recompute()\n#\n#    def parseWireOrderEdit(self):\n#        \"\"\"returns a python list of integers if valid, else None\"\"\"\n#        input_string = self.wireOrderEdit.text()\n#        if not input_string:\n#            return None\n#        else:\n#            if not input_string[0] == \"[\":\n#                input_string = \"[\" + input_string\n#            if not input_string[-1] == \"]\":\n#                input_string = input_string + \"]\"\n#        import ast\n#        try:\n#            # Attempt to parse the input string as a Python literal (list)\n#            parsed_list = ast.literal_eval(input_string)\n#            # Check if the parsed result is a list\n#            if isinstance(parsed_list, list):\n#                # Check if all elements in the list are integers\n#                if all(isinstance(item, int) for item in parsed_list):\n#                    return parsed_list\n#                else:\n#                    FreeCAD.Console.PrintError(\"WireFilter: enter only integers in the list\\n\")\n#                    return None\n#            else:\n#                FreeCAD.Console.PrintError(\"WireFilter: not a valid list in wire order line edit.\")\n#        except (ValueError, SyntaxError):\n#            FreeCAD.Console.PrintError(\"WireFilter: unable to parse list for new wire order.\")\n#            return None\n#\n#    def clicked(self, button):\n#        if button == QtGui.QDialogButtonBox.Reset:\n#            self.reject()\n#            self.fp.ReUseGhost = True\n#            self.fp.ViewObject.Proxy.setEdit(self.fp.ViewObject, 5) #essentially closes and restarts editor\n#        elif button == QtGui.QDialogButtonBox.Apply:\n#            self.fp.Document.openTransaction(\"WireFilter:ApplyChanges\")\n#            self.accept()\n#            self.fp.ReUseGhost = True\n#            self.fp.ViewObject.Proxy.setEdit(self.fp.ViewObject, 5) #essentially closes and restarts editor\n#            self.fp.Document.commitTransaction()\n#        elif button == QtGui.QDialogButtonBox.RestoreDefaults:\n#            self.fp.Document.openTransaction(\"WireFilter:RestoreDefaults\")\n#            self.fp.UseDefault=True\n#            self.reject()\n#            self.fp.ReUseGhost = True\n#            self.fp.ViewObject.Proxy.setEdit(self.fp.ViewObject, 5) #essentially closes and restarts editor\n#            self.fp.Document.commitTransaction()\n#\n#    def getStandardButtons(self):\n#        return int(QtGui.QDialogButtonBox.Ok) | int(QtGui.QDialogButtonBox.Apply)\\\n#         | int(QtGui.QDialogButtonBox.Cancel) | int(QtGui.QDialogButtonBox.Reset)\\\n#         | int(QtGui.QDialogButtonBox.RestoreDefaults)\n#\n#\n#class WireFilterVP:\n#    def __init__(self, obj):\n#        '''Set this object to the proxy object of the actual view provider'''\n#        obj.Proxy = self\n#        self.Object = obj.Proxy.Object\n#\n#    def attach(self,vobj):\n#        self.Object = vobj.Object\n#\n#    def dropObject(self, vp, dropped):\n#        vp.Object.Source = dropped\n#\n#    def canDropObject(self, dropped):\n#        return hasattr(dropped, \"ViewObject\")\n#\n#    def onDelete(self, vobj, subelements):\n#        if vobj.Object.Source:\n#            vobj.Object.Source[0].ViewObject.Visibility = True\n#        return True\n#\n#    def updateData(self, fp, prop):\n#        '''If a property of the handled feature has changed we have the chance to handle this here'''\n#        pass\n#\n#    def getDisplayModes(self,obj):\n#        '''Return a list of display modes.'''\n#        modes=[]\n#        modes.append(\"Flat Lines\")\n#        modes.append(\"Shaded\")\n#        modes.append(\"Wireframe\")\n#        return modes\n#\n#    def claimChildren(self):\n#        fp = self.Object\n#        if fp.Source and fp.ClaimChildren and not fp.Source[0].isDerivedFrom(\"PartDesign::Feature\"):\n#            return [fp.Source[0]]\n#        else:\n#            return[]\n#\n#    def getDefaultDisplayMode(self):\n#        '''Return the name of the default display mode. It must be defined in getDisplayModes.'''\n#        return \"Flat Lines\"\n#\n#    def setDisplayMode(self,mode):\n#        '''Map the display mode defined in attach with those defined in getDisplayModes.\\\n#                Since they have the same names nothing needs to be done. This method is optional'''\n#        return mode\n#\n#    def setupContextMenu(self, vobj, menu):\n#        if vobj.Object.Proxy.editingMode == False:\n#            text = \"Edit Wire Orders\"\n#            mode = 5\n#        else:\n#            text = \"Accept Wire Orders\"\n#            mode = 6\n#        if len(vobj.Object.Shape.Wires) == 0:\n#            text = \"No wires to edit\"\n#            mode = 5\n#        action = menu.addAction(text)\n#        action.triggered.connect(lambda: self.setEdit(vobj,mode))\n#\n#    def setEdit(self,vp,modNum):\n#        if modNum == 3:\n#            FreeCADGui.runCommand('Part_ColorPerFace',0)\n#        elif modNum == 5: #begin edit mode\n#            vp.Object.Proxy.showWires()\n#        elif modNum == 6: #accept changes and end edit mode\n#            vp.Object.Proxy.editingMode = False\n#            vp.Object.Proxy.cleanUpWires()\n#            FreeCADGui.Control.closeDialog()\n#        return False\n#\n#    def onChanged(self, vp, prop):\n#        '''Here we can do something when a single property got changed'''\n#        #FreeCAD.Console.PrintMessage(\"Change property: \" + str(prop) + \"\\n\")\n#        pass\n#\n#    def getIcon(self):\n#        '''Return the icon in XPM format which will appear in the tree view. This method is\\\n#                optional and if not defined a default icon is shown.'''\n#        return \"\"\"\n#/* XPM */\n#static char *a57ib_u2pr2[] = {\n#/* columns rows colors chars-per-pixel */\n#\"64 64 158 2 \",\n#\"   c #AD0E0E\",\n#\".  c #B30C0C\",\n#\"X  c #BC0E0E\",\n#\"o  c #AF1212\",\n#\"O  c #AE1A1A\",\n#\"+  c #B41212\",\n#\"@  c #BB1212\",\n#\"#  c #B41A1A\",\n#\"$  c #B91C1C\",\n#\"%  c #A92B2B\",\n#\"&  c #B32525\",\n#\"*  c #B82323\",\n#\"=  c #B52C2C\",\n#\"-  c #BB2C2C\",\n#\";  c #B53030\",\n#\":  c #BC3535\",\n#\">  c #B53E3E\",\n#\",  c #BB3C3C\",\n#\"<  c #C51414\",\n#\"1  c #CB1616\",\n#\"2  c #C41B1B\",\n#\"3  c #CD1A1A\",\n#\"4  c #D41B1B\",\n#\"5  c #DA1E1E\",\n#\"6  c #C52525\",\n#\"7  c #CB2323\",\n#\"8  c #C72C2C\",\n#\"9  c #CB2B2B\",\n#\"0  c #D12222\",\n#\"q  c #DD2121\",\n#\"w  c #D12A2A\",\n#\"e  c #C03535\",\n#\"r  c #CC3333\",\n#\"t  c #C23D3D\",\n#\"y  c #CB3C3C\",\n#\"u  c #D13333\",\n#\"i  c #D03D3D\",\n#\"p  c #E22424\",\n#\"a  c #E12A2A\",\n#\"s  c #935858\",\n#\"d  c #AA4646\",\n#\"f  c #A04B4B\",\n#\"g  c #AA4D4D\",\n#\"h  c #B54343\",\n#\"j  c #BA4242\",\n#\"k  c #B34E4E\",\n#\"l  c #B94A4A\",\n#\"z  c #AB5252\",\n#\"x  c #A45D5D\",\n#\"c  c #BD5656\",\n#\"v  c #8C7373\",\n#\"b  c #897979\",\n#\"n  c #917272\",\n#\"m  c #9E7B7B\",\n#\"M  c #A76161\",\n#\"N  c #BC6262\",\n#\"B  c #AB7171\",\n#\"V  c #B07878\",\n#\"C  c #C54343\",\n#\"Z  c #CB4343\",\n#\"A  c #C44C4C\",\n#\"S  c #CA4B4B\",\n#\"D  c #D14646\",\n#\"F  c #D04C4C\",\n#\"G  c #C45454\",\n#\"H  c #CC5454\",\n#\"J  c #C65A5A\",\n#\"K  c #CB5C5C\",\n#\"L  c #D05353\",\n#\"P  c #D05B5B\",\n#\"I  c #D95D5D\",\n#\"U  c #C66363\",\n#\"Y  c #CB6464\",\n#\"T  c #CD6B6B\",\n#\"R  c #D16363\",\n#\"E  c #D06A6A\",\n#\"W  c #C37575\",\n#\"Q  c #CE7373\",\n#\"!  c #D27575\",\n#\"~  c #D27B7B\",\n#\"^  c #838383\",\n#\"/  c #898989\",\n#\"(  c #938484\",\n#\")  c #969696\",\n#\"_  c #9D9D9D\",\n#\"`  c #A58585\",\n#\"'  c #AC8080\",\n#\"]  c #A38C8C\",\n#\"[  c #AD8C8C\",\n#\"{  c #B08585\",\n#\"}  c #BF8282\",\n#\"|  c #A09292\",\n#\" . c #A89292\",\n#\".. c #A29D9D\",\n#\"X. c #AB9D9D\",\n#\"o. c #B59797\",\n#\"O. c #A5A4A4\",\n#\"+. c #AAA6A6\",\n#\"@. c #AAAAAA\",\n#\"#. c #B6A3A3\",\n#\"$. c #BBA3A3\",\n#\"%. c #B1ADAD\",\n#\"&. c #BFABAB\",\n#\"*. c #B4B4B4\",\n#\"=. c #BDB1B1\",\n#\"-. c #BDBDBD\",\n#\";. c #CF8E8E\",\n#\":. c #D58484\",\n#\">. c #D88787\",\n#\",. c #D98C8C\",\n#\"<. c #C59393\",\n#\"1. c #D59393\",\n#\"2. c #DA9494\",\n#\"3. c #DC9C9C\",\n#\"4. c #C8A7A7\",\n#\"5. c #D7A7A7\",\n#\"6. c #DEA3A3\",\n#\"7. c #D0A9A9\",\n#\"8. c #DEBCBC\",\n#\"9. c #E0A6A6\",\n#\"0. c #E1AAAA\",\n#\"q. c #E2ACAC\",\n#\"w. c #E2ADAD\",\n#\"e. c #E3B0B0\",\n#\"r. c #E5B4B4\",\n#\"t. c #E7BBBB\",\n#\"y. c #E8BFBF\",\n#\"u. c #C2C2C2\",\n#\"i. c #CDCDCD\",\n#\"p. c #DEC3C3\",\n#\"a. c #D9CCCC\",\n#\"s. c #DFDBDB\",\n#\"d. c #EBC4C4\",\n#\"f. c #ECC9C9\",\n#\"g. c #EDCBCB\",\n#\"h. c #EED0D0\",\n#\"j. c #E0D9D9\",\n#\"k. c #EADBDB\",\n#\"l. c #F0D5D5\",\n#\"z. c #F0D7D7\",\n#\"x. c #F2DADA\",\n#\"c. c #F2DCDC\",\n#\"v. c #F3DDDD\",\n#\"b. c #E2E1E1\",\n#\"n. c #E8E0E0\",\n#\"m. c #EDEDED\",\n#\"M. c #F4E0E0\",\n#\"N. c #F5E3E3\",\n#\"B. c #F7EBEB\",\n#\"V. c #F8EBEB\",\n#\"C. c #F9EFEF\",\n#\"Z. c #F1F1F1\",\n#\"A. c #FAF3F3\",\n#\"S. c #FBF4F4\",\n#\"D. c #FBF6F6\",\n#\"F. c #FCF6F6\",\n#\"G. c #FDF9F9\",\n#\"H. c white\",\n#/* pixels */\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.A.V.M.c.z.h.h.g.g.g.g.h.h.z.c.M.V.A.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.F.B.z.y.6.>.Q T Y K J J J Y T ~ ,.6.t.z.C.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.S.B.x.d.0.>.T A : * # + . . + # * : A T >.9.g.M.V.F.G.H.H.H.H.H.H.H.H.H.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.A.h.0.>.T H S i u w w 0 3 3 3 3 0 w w u y S H T :.q.h.B.H.H.H.H.H.H.H.H.H.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.B.x.9.T t # X < 3 5 q p p p q p p p p q 4 3 < @ $ : Q 9.g.S.G.H.H.H.H.H.H.H.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.C.M.e.~ K Z 9 3 1 1 < < < 7 9 9 r r r 9 3 2 < 1 1 3 3 9 Z J >.e.z.G.H.H.H.H.H.H.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.M.d.Q & $ 1 4 p q 3 < X + & ; , j j , = O + @ < 3 5 q 5 < @ t T e.F.G.H.H.H.H.H.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.A.M.0.T S 6 1 3 3 3 9 Z H E ~ >.2.3.3.3.3.2.>.~ E H y 9 3 1 1 3 8 C ! q.h.G.H.H.H.H.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.M.g.Q # 2 q 4 4 2 # : T 3.d.M.C.F.F.F.S.S.S.A.c.d.3.Y , $ X 4 q 3 < t Y 0.A.H.H.H.H.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.C.r.~ S 2 1 4 7 6 Z Y >.0.g.M.F.G.H.H.H.H.H.H.H.A.M.g.0.>.Y C 9 3 3 3 9 t ~ d.M.G.H.H.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.c.:.= 6 4 4 1 6 : T r.c.V.S.G.H.H.H.H.H.H.H.H.H.H.G.S.C.z.0.~ t X 3 q 3 @ H 2.d.A.H.H.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.F.x.r.Y # 3 5 3 2 C Q 6.x.F.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.A.z.q.Q t 9 4 1 1 y K 3.M.G.H.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.C.r.:.S < 3 4 6 - T y.M.S.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.S.c.q.~ C X 1 q 6 & Q h.F.H.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.M.2.G r 3 1 1 y J 3.M.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.F.z.q.Y $ 7 q 1 + J r.c.S.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.z.Q - 7 q 1 X H 6.g.A.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.A.x.>., 9 4 3 < S ,.y.C.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.A.d.K + 3 p 3 # Q g.B.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.A.0.T Z 1 1 1 y T 6.M.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.A.x.0.H @ 3 q 9 : ,.M.F.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.F.g.3.H @ 1 4 r A >.c.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.C.d.2.S < 1 4 y G 6.A.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.M.g.E . < q w - Q z.H.\",\n#\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.M.r.:.Z < 1 3 S Q r.S.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.A.M.~ o 1 p 0 # Y h.H.\",\n#\"H.H.S.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.k.5.Q y 1 1 2 H ;.8.m.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.S.H.H.H.H.H.H.H.S.>.O 3 p 4 . J g.H.\",\n#\"H.Z.i.*.*.*.*.*.*.*.*.*.*.*.*.*.%. .B , 1 < < k ` X.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.i.m.H.H.H.H.H.H.F.,.& 7 p 3 . G d.G.\",\n#\"H.b.@.^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ n h 4 < @ f ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ O.b.H.H.H.H.H.H.F.2.; 9 p 1 . G y.A.\",\n#\"H.b.@.^ ) O.O.O.O.O.O.O.O.O.O.O.O.O.[ A 5 4 7 N O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.) ^ O.b.H.H.H.H.H.H.S.1.= 6 p 3 . G d.F.\",\n#\"G.b.+./ @.u.u.u.u.u.u.u.u.u.u.u.u.u.4.I p p a ! u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.@./ O.b.H.H.H.H.H.H.S.,.& 7 p 3 . G d.G.\",\n#\"S.j.+./ @.u.*.O.O.O.O.O.O.O.O.O.O.O.[ A 5 5 q N O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.*.u.@./ O.b.H.H.H.H.H.G.C.>.O 3 p 4 + J g.H.\",\n#\"S.j.O./ @.-.O.^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ n > 4 4 0 z ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ _ -.@./ O.b.H.H.H.H.H.F.M.~   < p 0 # U h.H.\",\n#\"S.j.O./ @.-._ ^ ) @.*.*.*.*.*.*.@.X.' j < 3 0 > s m X.@.%.*.*.*.*.*.*.*.*.*.*.*.) ^ _ -.@./ O.b.H.H.H.H.G.M.d.T . < q w : Q z.H.\",\n#\"S.j.O./ @.-._ ^ *.m.m.m.m.m.m.m.n.p.1.C X 1 q 6 % W p.k.m.m.m.m.m.m.m.m.m.m.m.m.-.^ _ -.@./ O.b.H.H.H.H.F.g.3.K @ 1 4 r A >.c.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.S.M.r.J # 3 q 3 # Y r.x.F.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.C.0.T Z 1 1 1 y T 6.M.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.F.h.Q - 7 q 3 @ H 2.d.A.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.G.M.>.: 9 5 1 X S ,.d.C.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.M.2.G r 4 1 1 y Y 3.c.S.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.S.x.r.Y # 3 q 3 # K q.x.S.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.C.y.>.S X 1 5 6 - T t.c.F.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.M.6.T y 2 3 5 6 - ~ h.A.G.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.F.c.r.Y # 3 q 3 @ C >.r.x.C.G.H.H.H.H.H.H.H.u.^ _ -.@./ O.s.C.c.r.! t 9 3 3 3 r G 3.B.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.A.z.>.C 8 3 3 3 9 t T 3.d.B.H.H.H.H.H.H.H.u.^ _ -.@./ ..a.g.2.Y C 6 0 5 1 @ H 3.d.A.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.A.e.Q S 2 3 5 3 @ : Y 2.d.c.M.C.A.S.S.A.-.^ _ -.+.( ` 7.3.J - 2 1 4 q 6 & ~ g.V.G.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.G.x.t.! e 6 3 3 3 7 y A T :.3.r.d.z.g.d.#.^ _ -.o.x g c A r 7 3 4 1 2 S ! q.M.F.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.A.6.J t 2 3 q 4 1 @ $ : J ~ 2.0.3.2.{ b | =.} > # + X 1 4 4 4 2 & Q y.c.G.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.G.z.q.~ A r 3 1 1 3 7 9 y S L P H A l d c Y H 9 3 1 1 1 1 2 8 H ~ q.c.C.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.y.:.A # @ 3 5 p q 4 1 < X X X < 1 4 q q 5 5 p q 3 < * , >.h.B.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.c.y.3.! H y 9 3 1 1 < < < < < 1 4 5 q 5 1 1 3 9 Z K ! 2.d.B.S.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.M.g.3.Y , # . X < 1 1 4 4 4 5 q p 4 X + # , T 3.g.C.F.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.F.B.g.0.,.! Y K H F D y r t h G R H : C T ,.q.g.M.G.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.F.C.M.c.g.q.2.>.~ Y A M v ] &.<.U ~ d.V.A.S.G.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.C.x.d.y.e.6.1.[ ^ _ -.$.V <.k.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.S.A.C.V.M.M.=.^ _ -.@.( +.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ -.S.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.-.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ _ -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-._ ^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.-._ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.u.@._ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @.-.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"S.j.O./ @.u.u.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.u.u.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"G.j.+.^ ) @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.) ^ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"H.b.@.^ ^ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / ^ ^ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"H.m.u.@.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.+.@.@.u.m.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"H.G.m.b.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.b.b.m.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n#\"H.H.H.H.G.S.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.S.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\"\n#};\n\n#            \"\"\"\n#\n#    def __getstate__(self):\n#        '''When saving the document this object gets stored using Python's json module.\\\n#                Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\\\n#                to return a tuple of all serializable objects or None.'''\n#        return None\n#\n#    def __setstate__(self,state):\n#        '''When restoring the serialized object from document we have the chance to set some internals here.\\\n#                Since no data were serialized nothing needs to be done here.'''\n#        return None\n\n\n\n########################################\n#CODE_ENDS_HERE\n\nBASENAME = 'wirefilter'\n\ndef makeObject(WF):\n\n    doc = FreeCAD.ActiveDocument if FreeCAD.ActiveDocument else FreeCAD.newDocument()\n    selobj = FreeCADGui.Selection.getSelectionEx()\n    wf = doc.addObject(\"Part::Part2DObjectPython\",\"WireFilter\")\n    WF.WireFilter(wf)\n    WF.WireFilterVP(wf.ViewObject)\n\n    if selobj:\n        wf.Source = (selobj[0].Object,selobj[0].SubElementNames)\n        if selobj[0].SubElementNames:\n            FreeCAD.Console.PrintMessage(\"WireFilter created using selected subelements.  You should make a WireFilter of this WireFilter if you \\\nwish to edit the wire order.  This is because the numer of elements in the wire order is based on the number \\\nof wires in the original source shape.\\n\")\n        selobj[0].Object.ViewObject.Visibility = False\n        bodies = [obj for obj in doc.Objects if obj.isDerivedFrom(\"PartDesign::Body\") and selobj[0].Object in obj.Group]\n        if len(bodies) == 1:\n            bodies[0].Group += [wf]\n        else:\n            parts = [obj for obj in doc.Objects if obj.TypeId == \"App::Part\" and selobj[0].Object in obj.Group]\n            if len(parts) == 1:\n                parts[0].Group += [wf]\n    else:\n        FreeCAD.Console.PrintMessage(\"WireFilter: No selected object.  Edit the Source property or drop an object on to it.\\n\")\n\n\n\n#################\ndef writeFile():\n    with open(py_file,\"w\") as outfile:\n        for line in code.splitlines():\n            if \"#CODE_ENDS_HERE\" in line:\n                break\n            if line.startswith('#'):\n                if line == \"# -*- coding: utf-8 -*-\":\n                    line = \"#\" + line\n                outfile.write(line[1:]+\"\\n\") #skip first character (#)\n\n\n\n############\n#if __name__ == \"__main__\":\n#    makeObject(None)\n#    raise Exception(\"quick exit for testing/debugging\")\n############\n\nif __name__ == \"__main__\":\n    import os\n    fin = open(__file__, 'r')\n    code = fin.read()\n    fin.close()\n    version = code.splitlines()[1][16:]\n    real_path = os.path.realpath(__file__)\n    dir_path = os.path.dirname(real_path)\n    py_file = real_path.replace(\".FCMacro\",\".py\").replace('WireFilter','wirefilter').replace('Wirefilter','wirefilter')\n    bHasFile = os.path.exists(py_file)\n    noImport = False #user elects not to save import file\n\n    if not bHasFile:\n        from PySide import QtGui\n        window = QtGui.QApplication.activeWindow()\n        mb = QtGui.QMessageBox()\n        mb.setWindowTitle(BASENAME+\" setup\")\n        mb.setIcon(mb.Information)\n        mb.setStandardButtons(mb.Ok)\n        mb.addButton(mb.Cancel)\n        mb.setDefaultButton(mb.Cancel)\n        okBtn = mb.button(QtGui.QMessageBox.StandardButton.Ok)\n        cancelBtn = mb.button(QtGui.QMessageBox.StandardButton.Cancel)\n        okBtn.setText(\"Create file\")\n        cancelBtn.setText(\"Do not create file\")\n        caption = \"In order for \"+BASENAME+\" objects to be parametric after saving and reloading file\\n\\\nwe need to create another file on this computer.  File to be created will be: \\n\\n\"+py_file+\"\\n\\n\\\nThis makes it available to the system upon restarting FreeCAD and loading documents containing the \\\n\"+BASENAME+\" feature python objects.  Create file now?\\n\\n\"\n        mb.setText(caption)\n        ret = mb.exec_()\n        if ret == mb.Ok:\n            writeFile()\n            QtGui.QMessageBox.information(window,\"Success\",\"File successfully created.  Please note: if you uninstall \"+BASENAME+\" macro you need to manually remove \"+py_file+\", too.\\n\")\n        else:\n            new_lines = []\n            for line in code.splitlines():\n                if line.startswith('#'):\n                    if \"CODE_ENDS_HERE\" in line:\n                        break\n                    if line == \"# -*- coding: utf-8 -*-\":\n                        new_lines.append(line+\"\\n\")\n                        continue\n                    new_lines.append(line[1:]+\"\\n\")\n            code = \"\".join(new_lines)\n\n            #credit to Mila Nautikus for his answer to a question on stackoverflow, which I modified here\n            #in this example the filename is pdwrapper.py\n            #https://stackoverflow.com/questions/5362771/how-to-load-a-module-from-code-in-a-string\n\n            ##########\n            import sys, importlib\n            my_name = 'wirefilter' #filename = wirefilter.py, so this must be 'wirefilter'\n            my_spec = importlib.util.spec_from_loader(my_name, loader=None)\n\n            wirefilter = importlib.util.module_from_spec(my_spec)\n\n            exec(code, wirefilter.__dict__)\n            sys.modules['wirefilter'] = wirefilter\n            makeObject(wirefilter)\n            noImport = True\n\n    if not noImport: #don't never use no double negatives\n        import addonmanager_utilities as utils\n        import wirefilter as WF\n        if WF.__version__ != __version__:\n            writeFile()\n            from PySide import QtCore,QtGui\n            window = QtGui.QApplication.activeWindow()\n            mbox = QtGui.QMessageBox()\n            mbox.setWindowTitle(BASENAME+\" updated\")\n\n            mbox.setText(BASENAME+\".py has been updated to version \"+__version__+\". \\\nYou must restart FreeCAD for the new changes to take effect and to use the macro.\")\n            mbox.setIcon(mbox.Warning)\n            mbox.setStandardButtons(mbox.Ok | mbox.Cancel)\n            mbox.setDefaultButton(mbox.Cancel)\n            okBtn = mbox.button(QtGui.QMessageBox.StandardButton.Ok)\n            cancelBtn = mbox.button(QtGui.QMessageBox.StandardButton.Cancel)\n            okBtn.setText(\"Restart now\")\n            cancelBtn.setText(\"Restart later\")\n            ret = mbox.exec_()\n            if ret == mbox.Ok:\n                QtCore.QTimer.singleShot(1000, utils.restart_freecad)\n        else:\n            makeObject(WF)\n\n# icon for addonmanager auto toolbar installation\n__xpm__ = \"\"\"/* XPM */\nstatic char *a57ib_u2pr2[] = {\n\"64 64 158 2 \",\n\"   c #AD0E0E\",\n\".  c #B30C0C\",\n\"X  c #BC0E0E\",\n\"o  c #AF1212\",\n\"O  c #AE1A1A\",\n\"+  c #B41212\",\n\"@  c #BB1212\",\n\"#  c #B41A1A\",\n\"$  c #B91C1C\",\n\"%  c #A92B2B\",\n\"&  c #B32525\",\n\"*  c #B82323\",\n\"=  c #B52C2C\",\n\"-  c #BB2C2C\",\n\";  c #B53030\",\n\":  c #BC3535\",\n\">  c #B53E3E\",\n\",  c #BB3C3C\",\n\"<  c #C51414\",\n\"1  c #CB1616\",\n\"2  c #C41B1B\",\n\"3  c #CD1A1A\",\n\"4  c #D41B1B\",\n\"5  c #DA1E1E\",\n\"6  c #C52525\",\n\"7  c #CB2323\",\n\"8  c #C72C2C\",\n\"9  c #CB2B2B\",\n\"0  c #D12222\",\n\"q  c #DD2121\",\n\"w  c #D12A2A\",\n\"e  c #C03535\",\n\"r  c #CC3333\",\n\"t  c #C23D3D\",\n\"y  c #CB3C3C\",\n\"u  c #D13333\",\n\"i  c #D03D3D\",\n\"p  c #E22424\",\n\"a  c #E12A2A\",\n\"s  c #935858\",\n\"d  c #AA4646\",\n\"f  c #A04B4B\",\n\"g  c #AA4D4D\",\n\"h  c #B54343\",\n\"j  c #BA4242\",\n\"k  c #B34E4E\",\n\"l  c #B94A4A\",\n\"z  c #AB5252\",\n\"x  c #A45D5D\",\n\"c  c #BD5656\",\n\"v  c #8C7373\",\n\"b  c #897979\",\n\"n  c #917272\",\n\"m  c #9E7B7B\",\n\"M  c #A76161\",\n\"N  c #BC6262\",\n\"B  c #AB7171\",\n\"V  c #B07878\",\n\"C  c #C54343\",\n\"Z  c #CB4343\",\n\"A  c #C44C4C\",\n\"S  c #CA4B4B\",\n\"D  c #D14646\",\n\"F  c #D04C4C\",\n\"G  c #C45454\",\n\"H  c #CC5454\",\n\"J  c #C65A5A\",\n\"K  c #CB5C5C\",\n\"L  c #D05353\",\n\"P  c #D05B5B\",\n\"I  c #D95D5D\",\n\"U  c #C66363\",\n\"Y  c #CB6464\",\n\"T  c #CD6B6B\",\n\"R  c #D16363\",\n\"E  c #D06A6A\",\n\"W  c #C37575\",\n\"Q  c #CE7373\",\n\"!  c #D27575\",\n\"~  c #D27B7B\",\n\"^  c #838383\",\n\"/  c #898989\",\n\"(  c #938484\",\n\")  c #969696\",\n\"_  c #9D9D9D\",\n\"`  c #A58585\",\n\"'  c #AC8080\",\n\"]  c #A38C8C\",\n\"[  c #AD8C8C\",\n\"{  c #B08585\",\n\"}  c #BF8282\",\n\"|  c #A09292\",\n\" . c #A89292\",\n\".. c #A29D9D\",\n\"X. c #AB9D9D\",\n\"o. c #B59797\",\n\"O. c #A5A4A4\",\n\"+. c #AAA6A6\",\n\"@. c #AAAAAA\",\n\"#. c #B6A3A3\",\n\"$. c #BBA3A3\",\n\"%. c #B1ADAD\",\n\"&. c #BFABAB\",\n\"*. c #B4B4B4\",\n\"=. c #BDB1B1\",\n\"-. c #BDBDBD\",\n\";. c #CF8E8E\",\n\":. c #D58484\",\n\">. c #D88787\",\n\",. c #D98C8C\",\n\"<. c #C59393\",\n\"1. c #D59393\",\n\"2. c #DA9494\",\n\"3. c #DC9C9C\",\n\"4. c #C8A7A7\",\n\"5. c #D7A7A7\",\n\"6. c #DEA3A3\",\n\"7. c #D0A9A9\",\n\"8. c #DEBCBC\",\n\"9. c #E0A6A6\",\n\"0. c #E1AAAA\",\n\"q. c #E2ACAC\",\n\"w. c #E2ADAD\",\n\"e. c #E3B0B0\",\n\"r. c #E5B4B4\",\n\"t. c #E7BBBB\",\n\"y. c #E8BFBF\",\n\"u. c #C2C2C2\",\n\"i. c #CDCDCD\",\n\"p. c #DEC3C3\",\n\"a. c #D9CCCC\",\n\"s. c #DFDBDB\",\n\"d. c #EBC4C4\",\n\"f. c #ECC9C9\",\n\"g. c #EDCBCB\",\n\"h. c #EED0D0\",\n\"j. c #E0D9D9\",\n\"k. c #EADBDB\",\n\"l. c #F0D5D5\",\n\"z. c #F0D7D7\",\n\"x. c #F2DADA\",\n\"c. c #F2DCDC\",\n\"v. c #F3DDDD\",\n\"b. c #E2E1E1\",\n\"n. c #E8E0E0\",\n\"m. c #EDEDED\",\n\"M. c #F4E0E0\",\n\"N. c #F5E3E3\",\n\"B. c #F7EBEB\",\n\"V. c #F8EBEB\",\n\"C. c #F9EFEF\",\n\"Z. c #F1F1F1\",\n\"A. c #FAF3F3\",\n\"S. c #FBF4F4\",\n\"D. c #FBF6F6\",\n\"F. c #FCF6F6\",\n\"G. c #FDF9F9\",\n\"H. c white\",\n/* pixels */\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.A.V.M.c.z.h.h.g.g.g.g.h.h.z.c.M.V.A.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.F.B.z.y.6.>.Q T Y K J J J Y T ~ ,.6.t.z.C.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.S.B.x.d.0.>.T A : * # + . . + # * : A T >.9.g.M.V.F.G.H.H.H.H.H.H.H.H.H.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.A.h.0.>.T H S i u w w 0 3 3 3 3 0 w w u y S H T :.q.h.B.H.H.H.H.H.H.H.H.H.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.B.x.9.T t # X < 3 5 q p p p q p p p p q 4 3 < @ $ : Q 9.g.S.G.H.H.H.H.H.H.H.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.C.M.e.~ K Z 9 3 1 1 < < < 7 9 9 r r r 9 3 2 < 1 1 3 3 9 Z J >.e.z.G.H.H.H.H.H.H.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.M.d.Q & $ 1 4 p q 3 < X + & ; , j j , = O + @ < 3 5 q 5 < @ t T e.F.G.H.H.H.H.H.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.A.M.0.T S 6 1 3 3 3 9 Z H E ~ >.2.3.3.3.3.2.>.~ E H y 9 3 1 1 3 8 C ! q.h.G.H.H.H.H.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.M.g.Q # 2 q 4 4 2 # : T 3.d.M.C.F.F.F.S.S.S.A.c.d.3.Y , $ X 4 q 3 < t Y 0.A.H.H.H.H.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.C.r.~ S 2 1 4 7 6 Z Y >.0.g.M.F.G.H.H.H.H.H.H.H.A.M.g.0.>.Y C 9 3 3 3 9 t ~ d.M.G.H.H.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.c.:.= 6 4 4 1 6 : T r.c.V.S.G.H.H.H.H.H.H.H.H.H.H.G.S.C.z.0.~ t X 3 q 3 @ H 2.d.A.H.H.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.F.x.r.Y # 3 5 3 2 C Q 6.x.F.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.A.z.q.Q t 9 4 1 1 y K 3.M.G.H.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.C.r.:.S < 3 4 6 - T y.M.S.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.S.c.q.~ C X 1 q 6 & Q h.F.H.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.M.2.G r 3 1 1 y J 3.M.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.F.z.q.Y $ 7 q 1 + J r.c.S.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.z.Q - 7 q 1 X H 6.g.A.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.A.x.>., 9 4 3 < S ,.y.C.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.A.d.K + 3 p 3 # Q g.B.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.A.0.T Z 1 1 1 y T 6.M.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.A.x.0.H @ 3 q 9 : ,.M.F.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.F.g.3.H @ 1 4 r A >.c.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.C.d.2.S < 1 4 y G 6.A.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.M.g.E . < q w - Q z.H.\",\n\"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.M.r.:.Z < 1 3 S Q r.S.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.A.M.~ o 1 p 0 # Y h.H.\",\n\"H.H.S.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.k.5.Q y 1 1 2 H ;.8.m.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.S.H.H.H.H.H.H.H.S.>.O 3 p 4 . J g.H.\",\n\"H.Z.i.*.*.*.*.*.*.*.*.*.*.*.*.*.%. .B , 1 < < k ` X.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.i.m.H.H.H.H.H.H.F.,.& 7 p 3 . G d.G.\",\n\"H.b.@.^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ n h 4 < @ f ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ O.b.H.H.H.H.H.H.F.2.; 9 p 1 . G y.A.\",\n\"H.b.@.^ ) O.O.O.O.O.O.O.O.O.O.O.O.O.[ A 5 4 7 N O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.) ^ O.b.H.H.H.H.H.H.S.1.= 6 p 3 . G d.F.\",\n\"G.b.+./ @.u.u.u.u.u.u.u.u.u.u.u.u.u.4.I p p a ! u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.@./ O.b.H.H.H.H.H.H.S.,.& 7 p 3 . G d.G.\",\n\"S.j.+./ @.u.*.O.O.O.O.O.O.O.O.O.O.O.[ A 5 5 q N O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.*.u.@./ O.b.H.H.H.H.H.G.C.>.O 3 p 4 + J g.H.\",\n\"S.j.O./ @.-.O.^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ n > 4 4 0 z ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ _ -.@./ O.b.H.H.H.H.H.F.M.~   < p 0 # U h.H.\",\n\"S.j.O./ @.-._ ^ ) @.*.*.*.*.*.*.@.X.' j < 3 0 > s m X.@.%.*.*.*.*.*.*.*.*.*.*.*.) ^ _ -.@./ O.b.H.H.H.H.G.M.d.T . < q w : Q z.H.\",\n\"S.j.O./ @.-._ ^ *.m.m.m.m.m.m.m.n.p.1.C X 1 q 6 % W p.k.m.m.m.m.m.m.m.m.m.m.m.m.-.^ _ -.@./ O.b.H.H.H.H.F.g.3.K @ 1 4 r A >.c.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.S.M.r.J # 3 q 3 # Y r.x.F.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.C.0.T Z 1 1 1 y T 6.M.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.F.h.Q - 7 q 3 @ H 2.d.A.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.G.M.>.: 9 5 1 X S ,.d.C.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.M.2.G r 4 1 1 y Y 3.c.S.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.S.x.r.Y # 3 q 3 # K q.x.S.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.C.y.>.S X 1 5 6 - T t.c.F.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.M.6.T y 2 3 5 6 - ~ h.A.G.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.F.c.r.Y # 3 q 3 @ C >.r.x.C.G.H.H.H.H.H.H.H.u.^ _ -.@./ O.s.C.c.r.! t 9 3 3 3 r G 3.B.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.A.z.>.C 8 3 3 3 9 t T 3.d.B.H.H.H.H.H.H.H.u.^ _ -.@./ ..a.g.2.Y C 6 0 5 1 @ H 3.d.A.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.A.e.Q S 2 3 5 3 @ : Y 2.d.c.M.C.A.S.S.A.-.^ _ -.+.( ` 7.3.J - 2 1 4 q 6 & ~ g.V.G.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.G.x.t.! e 6 3 3 3 7 y A T :.3.r.d.z.g.d.#.^ _ -.o.x g c A r 7 3 4 1 2 S ! q.M.F.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.A.6.J t 2 3 q 4 1 @ $ : J ~ 2.0.3.2.{ b | =.} > # + X 1 4 4 4 2 & Q y.c.G.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.G.z.q.~ A r 3 1 1 3 7 9 y S L P H A l d c Y H 9 3 1 1 1 1 2 8 H ~ q.c.C.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.y.:.A # @ 3 5 p q 4 1 < X X X < 1 4 q q 5 5 p q 3 < * , >.h.B.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.c.y.3.! H y 9 3 1 1 < < < < < 1 4 5 q 5 1 1 3 9 Z K ! 2.d.B.S.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.M.g.3.Y , # . X < 1 1 4 4 4 5 q p 4 X + # , T 3.g.C.F.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.F.B.g.0.,.! Y K H F D y r t h G R H : C T ,.q.g.M.G.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.F.C.M.c.g.q.2.>.~ Y A M v ] &.<.U ~ d.V.A.S.G.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.C.x.d.y.e.6.1.[ ^ _ -.$.V <.k.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.G.S.A.C.V.M.M.=.^ _ -.@.( +.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.u.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ -.S.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.-.^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ _ -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-._ ^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.-._ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ _ -.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.u.@._ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @.-.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"S.j.O./ @.u.u.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.u.u.@./ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"G.j.+.^ ) @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.) ^ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"H.b.@.^ ^ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / ^ ^ O.b.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"H.m.u.@.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.+.@.@.u.m.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"H.G.m.b.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.b.b.m.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\",\n\"H.H.H.H.G.S.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.S.G.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.\"\n};\"\"\"",
    "url": "https://wiki.freecad.org/Macro_WireFilter",
    "raw_code_url": "https://gist.github.com/mwganson/0aedd5e9057650d0a1f0483f3cc2fa6c/raw/28575fbb2042790d779bcd293c048a4123f4a771/wirefilter.FCMacro",
    "wiki": "",
    "version": "0.2023.10.19",
    "license": "",
    "date": "2022-10-19",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Wirefilter.svg",
    "icon_source": "https://wiki.freecad.org//images/1/17/Wirefilter.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Colorize",
    "on_wiki": true,
    "on_git": false,
    "desc": "Quickly and easily set the color and transparency of individual faces, edges, and vertices.<br /><br />Macro version: 1.03<br />Last modified: 2023-10-07<br />FreeCAD version: Python3 builds<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/images/d/de/Workbench_Image.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Quickly and easily set the color and transparency of individual faces, edges, and vertices.",
    "code": "# -*- coding: utf-8 -*-\n#Colorize macro, 2021, by <TheMarkster> LGPL2.1 or later\n#Usage: Select subobjects, run macro\n#A color picker dialog will appear\n#Select the color for the selected subobjects.\n#The alpha channel corresponds to the transparency\n# 0 = no transparency, 255 = full transparency\n# first 2 custom colors are the default gray and black\n# used for faces and edges/points\n__icon__ = \"https://wiki.freecad.org/images/d/de/Workbench_Image.svg\"\n__version__ = \"1.03\"\nfrom PySide import QtGui,QtCore\nimport warnings\nwarnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n\nclass ColorDlg (QtGui.QColorDialog):\n    def __init__(self,title,flags):\n        QtGui.QColorDialog.__init__(self)\n        self.title = title\n        self.flags = flags\n\n    def getClr(self, currentColor):\n        current = QtGui.QColor(currentColor[0]*255,currentColor[1]*255,currentColor[2]*255,currentColor[3]*255)\n        self.setCustomColor(0,QtGui.QColor.fromRgb(204,204,204,0)) # gray, default face color\n        self.setCustomColor(2,QtGui.QColor.fromRgb(0,0,0,0)) #black, default line and point color\n        clr = self.getColor(current,None,self.title, self.flags)\n        return clr\n\ndef getIdx(sen):\n    '''get subelement index from sub element name, e.g. from \"Face6\"  we get 5'''\n    if 'Face' in sen or 'Edge' in sen or 'Wire' in sen:\n        val = int(sen[4:])\n    elif 'Vertex' in sen:\n        val = int(sen[6:])\n    return val-1\n\ndef buildDefaultColorArray(color, count):\n    clr = (color[0],color[1],color[2],0.0)\n    return[clr] * count\n\ndef getCurrentColor(obj,subName):\n    idx = getIdx(subName)\n    if \"Face\" in subName:\n        ary = obj.ViewObject.DiffuseColor\n    elif \"Edge\" in subName:\n        ary = obj.ViewObject.LineColorArray\n    elif \"Vertex\" in subName:\n        ary = obj.ViewObject.PointColorArray\n    if len(ary) >= idx:\n        return ary[idx]\n    else:\n        return ary[0]\n\n\ndef setColors():\n    selx = Gui.Selection.getSelectionEx()\n    for sel in selx:\n        if sel.HasSubObjects:\n            defaultColor = QtCore.Qt.gray if \"Face\" in sel.SubElementNames[0] else QtCore.Qt.black\n            currentColor = getCurrentColor(sel.Object,sel.SubElementNames[0])\n            subs = sel.SubElementNames\n            faces = [name for name in subs if \"Face\" in name]\n            edges = [name for name in subs if \"Edge\" in name]\n            vertices = [name for name in subs if \"Vertex\" in name]\n            objname = sel.Object.Name\n            if sel.Object.Name != sel.Object.Label:\n                objname += \" (\"+sel.Object.Label+\")\"\n            dlg = ColorDlg('Colorize v'+__version__+' object: '+objname,QtGui.QColorDialog.ShowAlphaChannel.__or__(QtGui.QColorDialog.DontUseNativeDialog))\n            col = dlg.getClr(currentColor)\n            if not col.isValid(): #user canceled\n                return\n            col = col.getRgbF()\n\n            if faces:\n                dc = sel.Object.ViewObject.DiffuseColor\n                if len(dc) == 1:\n                    dc = buildDefaultColorArray(dc[0], len(sel.Object.Shape.Faces))\n                indices = [getIdx(name) for name in faces]\n                for idx in indices:\n                    dc[idx] = col\n                sel.Object.ViewObject.DiffuseColor = dc\n            if edges:\n                lca = sel.Object.ViewObject.LineColorArray\n                if len(lca) == 1:\n                    lca = buildDefaultColorArray(lca[0], len(sel.Object.Shape.Edges))\n                indices = [getIdx(name) for name in edges]\n                for idx in indices:\n                    lca[idx] = col\n                sel.Object.ViewObject.LineColorArray = lca\n\n            if vertices:\n                pca = sel.Object.ViewObject.PointColorArray\n                if len(pca) == 1:\n                    pca = buildDefaultColorArray(pca[0], len(sel.Object.Shape.Vertexes))\n                indices = [getIdx(name) for name in vertices]\n                for idx in indices:\n                    pca[idx] = col\n                sel.Object.ViewObject.PointColorArray = pca\n\n        else:\n            FreeCAD.Console.PrintError(\"No subobjects selected\\n\")\n\nsetColors()",
    "url": "https://wiki.freecad.org/Macro_Colorize",
    "raw_code_url": "",
    "wiki": "",
    "version": "1.03",
    "license": "",
    "date": "2023-10-07",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Workbench_Image.svg",
    "icon_source": "https://wiki.freecad.org/images/d/de/Workbench_Image.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "EasyReflector",
    "on_wiki": true,
    "on_git": false,
    "desc": "Easily manage textures with this Feature Python object<br /><br />Macro version: 0.2023.12.09<br />Last modified: 2023-12-09<br />FreeCAD version: Python 3 versions<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/File:EasyReflectorIcon.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Easily manage textures with this Feature Python object",
    "code": "# -*- coding: utf-8 -*-\n__version__ = \"0.2023.12.09\"\n__icon__ = \"https://github.com/mwganson/EasyReflector/raw/main/EasyReflectorIcon.svg\"\n#__version__ = \"0.2023.12.09\"\n##EasyReflector macro by TheMarkster\n##based on work by Athanaze at https://github.com/Athanaze/Freecad-easy-reflections\n##\n##do not run this file directly.  Instead run the EasyReflector.FCMacro file.\n##\n#from pivy import coin\n#import FreeCAD, FreeCADGui\n#import os, requests, concurrent.futures\n#from PySide import QtGui, QtCore\n#\n#PATH = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\").GetString(\"MacroPath\")+\"/easy_reflections/\"\n#DEFAULT_FILES = [\"other image file\",\"none\",\"interior.jpg\",\"industrial.jpg\",\"mesh2.jpg\",\"outside.jpg\",\"studio.jpg\",\"workshop.jpg\"]\n#GITHUB_BASE_URL = \"https://github.com/mwganson/EasyReflector/blob/main/easy_reflections/\"\n#GITHUB_RAW_EXTRA = \"?raw=true\"\n#EXPANDED_FILES = DEFAULT_FILES #will add any additional files user has added to Environment property\n#\n## Get a list of all image files in the local directory\n#local_files = [f for f in os.listdir(PATH)] if os.path.exists(PATH) else DEFAULT_FILES\n#\n## Iterate through local files and add their base names to EXPANDED_FILES if not already present\n#for local_file in local_files:\n#    base_name, extension = os.path.splitext(local_file)\n#    fullname = base_name + extension\n#    if fullname not in EXPANDED_FILES and fullname != \"white.jpg\": #aliased to \"none\"\n#        EXPANDED_FILES.append(fullname)\n#\n#class EasyReflector:\n#    def __init__(self, obj):\n#        obj.addProperty(\"App::PropertyString\",\"Version\",\"EasyReflector\",\"Version used to create this object\").Version = __version__\n#        obj.addProperty(\"App::PropertyEnumeration\", \"Environment\",\"EasyReflector\",\"Select Environment (white = None)\")\n#        obj.Environment = EXPANDED_FILES\n#        obj.Environment = \"studio.jpg\"\n#        obj.addProperty(\"App::PropertyLinkList\",\"LinkedObjects\",\"EasyReflector\",\"Objects to apply textures to\")\n#        obj.addProperty(\"App::PropertyFileIncluded\",\"ImageFile\",\"EasyReflector\",\"Image file to use for environment\")\n#        obj.setEditorMode(\"ImageFile\", 2) #hide by default\n#        obj.addProperty(\"App::PropertyBool\",\"Enabled\",\"EasyReflector\",\"Whether texturing is enabled or not\").Enabled=True\n#        obj.Proxy = self\n#\n#    def execute(self,fp):\n#        if not fp.LinkedObjects:\n#            return\n#        self.setEnvironment(fp, fp.Environment)\n#\n#    def onChanged(self,fp,prop):\n#        if not fp:\n#            return\n#        elif prop == \"Environment\":\n#            if fp.Environment == \"other image file\":\n#                fp.setEditorMode(\"ImageFile\", 0) #normal mode\n#            else:\n#                fp.setEditorMode(\"ImageFile\", 2) #hide\n#        elif prop == \"LinkedObjects\":\n#            self.verifyLinkedObjects(fp)\n#\n#    def verifyLinkedObjects(self,fp):\n#        links = fp.LinkedObjects\n#        incompatibles = [\"App::Plane\",\"App::Line\"]\n#        links_to_keep = [obj for obj in links if not obj.TypeId in incompatibles]\n#        links_removed = [obj for obj in links if obj.TypeId in incompatibles]\n#        for lr in links_removed:\n#            FreeCAD.Console.PrintWarning(f\"EasyReflector: {lr.Label} is incompatible \\\n#and has been removed from Linked Objects property.\\n\")\n#        fp.LinkedObjects = links_to_keep\n#\n#    def onDocumentRestored(self, fp):\n#        self.setEnvironment(fp, fp.Environment)\n#\n#    def checkImagesExist(self, fp):\n#        paths = [PATH + (fn if fn != \"none\" else \"white.jpg\") for fn in DEFAULT_FILES[1:]]\n#        for path in paths:\n#            if not os.path.exists(path):\n#                return False\n#        return True\n#\n#    def getPermissionFromUser(self,fp):\n#        msgBox = QtGui.QMessageBox()\n#        msgBox.setWindowTitle(\"EasyReflector\")\n#        msgBox.setIcon(QtGui.QMessageBox.Warning)\n#        msgBox.setText(\"EasyReflector needs to download the texture image files.\")\n#        info = \"These are jpg image files to be used as textures for the reflections. \"\n#        info += \"They will be downloaded from a github repository and placed in \"\n#        info += \"your macros folder in a subfolder named easy_reflections. \"\n#        info += \"You must manually remove these files if you uninstall EasyReflector. \"\n#        info += \"Proceed with download (Yes/No)?\"\n#        msgBox.setInformativeText(info)\n#        msgBox.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)\n#        msgBox.setDefaultButton(QtGui.QMessageBox.No)\n#        ret = msgBox.exec();\n#        return ret == QtGui.QMessageBox.Yes\n#\n#\n#    def downloadImages(self, fp):\n#        if not self.getPermissionFromUser(fp):\n#            return\n#        FreeCAD.Console.PrintMessage(\"Downloading files...\\n\")\n#        os.makedirs(PATH, exist_ok=True)\n#        QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)\n#\n#        def download_file(fn):\n#            if fn == \"none\":\n#                # For \"none\", download the white.jpg file\n#                url = GITHUB_BASE_URL + \"white.jpg\" + GITHUB_RAW_EXTRA\n#            else:\n#                # For other files, download them using their respective names\n#                url = GITHUB_BASE_URL + fn + GITHUB_RAW_EXTRA\n#\n#            try:\n#                response = requests.get(url)\n#                response.raise_for_status()\n#                content = response.content\n#\n#                # Construct the local file path\n#                local_file_path = os.path.join(PATH, fn if fn != \"none\" else \"white.jpg\")\n#\n#                # Save the content to the local file\n#                with open(local_file_path, \"wb\") as file:\n#                    file.write(content)\n#\n#                print(f\"Downloaded '{fn}' from GitHub and saved it as '{local_file_path}'\")\n#            except Exception as e:\n#                print(f\"Failed to download '{fn}' from GitHub: {str(e)}\")\n#\n#        with concurrent.futures.ThreadPoolExecutor() as executor:\n#            executor.map(download_file, DEFAULT_FILES[1:])\n#        QtGui.QApplication.restoreOverrideCursor()\n#\n#    def setEnvironment(self, fp, env):\n#        if not self.checkImagesExist(fp):\n#            self.downloadImages(fp)\n#        tex = coin.SoTexture2()\n#        if env == \"other image file\":\n#            tex.filename = fp.ImageFile\n#        else:\n#            if fp.Environment == \"none\":\n#                tex.filename = PATH + \"white.jpg\"\n#            else:\n#                tex.filename = PATH + fp.Environment\n#        if not fp.Enabled:\n#            tex.filename = PATH + \"white.jpg\"\n#        tc = coin.SoTextureCoordinateEnvironment()\n#        linked = fp.LinkedObjects\n#        if not linked:\n#            return\n#        for link in linked:\n#            rootnode = link.ViewObject.RootNode\n#            child1 = rootnode.getChild(1)\n#            child2 = rootnode.getChild(2)\n#            already_done = \"SoTexture2\" in str(type(child1)) and \"SoTextureCoordinateEnvironment\" in str(type(child2))\n#            if already_done:\n#                rootnode.replaceChild(1, tex)\n#                rootnode.replaceChild(2, tc)\n#            else:\n#                rootnode.insertChild(tex,1)\n#                rootnode.insertChild(tc,2)\n#\n#__XPM__ = \"\"\"\n#/* XPM */\n#static char *_693848802616[] = {\n#/* columns rows colors chars-per-pixel */\n#\"64 64 116 2 \",\n#\"   c #0B650BB10DE1\",\n#\".  c #0DBE0E0B1115\",\n#\"X  c #10200F3813BC\",\n#\"o  c #0F1110011307\",\n#\"O  c #119B125615DD\",\n#\"+  c #143415321A30\",\n#\"@  c #16DB18631CF3\",\n#\"#  c #18E719ED1E46\",\n#\"$  c #141816BF200E\",\n#\"%  c #1650190121ED\",\n#\"&  c #1AD71C552268\",\n#\"*  c #1C2C1EEC286B\",\n#\"=  c #1EAA209824F5\",\n#\"-  c #1E3E212C2A47\",\n#\";  c #211C226F2652\",\n#\":  c #22FA25302AC4\",\n#\">  c #266E28E82D80\",\n#\",  c #29202AC92E23\",\n#\"<  c #238A27013143\",\n#\"1  c #25EA2A833376\",\n#\"2  c #2AFC2D5832DB\",\n#\"3  c #28FE2DD8392C\",\n#\"4  c #2DBA30FC35C9\",\n#\"5  c #2C2C318A3BD9\",\n#\"6  c #319D332E3610\",\n#\"7  c #329E35AD3AA8\",\n#\"8  c #360F39893E28\",\n#\"9  c #3A4A3B303DFF\",\n#\"0  c #2E87359C4292\",\n#\"q  c #305236804275\",\n#\"w  c #329D3954441F\",\n#\"e  c #39C83D7542B6\",\n#\"r  c #359C3D0149AC\",\n#\"t  c #383A3F404BC4\",\n#\"y  c #3D5840CE4552\",\n#\"u  c #3B94420A4CCF\",\n#\"i  c #3DFE44B85143\",\n#\"p  c #4394443145FD\",\n#\"a  c #41C5455C4A4D\",\n#\"s  c #457D49764E74\",\n#\"d  c #4A8E4B894DEA\",\n#\"f  c #409047185373\",\n#\"g  c #45364AC95396\",\n#\"h  c #49CF4E13539E\",\n#\"j  c #46634D2C5AFF\",\n#\"k  c #498B4E115CE4\",\n#\"l  c #4C5050EC55EC\",\n#\"z  c #4E1B53A75A3E\",\n#\"x  c #532953EE55DA\",\n#\"c  c #516955E75A8F\",\n#\"v  c #54EF592D5DCD\",\n#\"b  c #5CE15CE85DE7\",\n#\"n  c #4CE5541362C2\",\n#\"m  c #516355E36259\",\n#\"M  c #55735AE06229\",\n#\"N  c #59DB5E276391\",\n#\"B  c #55875C586A13\",\n#\"V  c #5BDF60CA6600\",\n#\"C  c #5D41629A6980\",\n#\"Z  c #5DA6646471AD\",\n#\"A  c #6278629763D6\",\n#\"S  c #622F66926C3A\",\n#\"D  c #63C169026E62\",\n#\"F  c #6A646B386CE6\",\n#\"G  c #61E0672E71F2\",\n#\"H  c #64C56B4C7396\",\n#\"J  c #69F66E6A73DA\",\n#\"K  c #67006DBD7A69\",\n#\"L  c #68376F227AA8\",\n#\"P  c #6C7471817689\",\n#\"I  c #6DFD73857A79\",\n#\"U  c #72EA7485765A\",\n#\"Y  c #71EF76AD7BFA\",\n#\"T  c #7435794E7EAC\",\n#\"R  c #7B1A7D027F95\",\n#\"E  c #6C5473C880B9\",\n#\"W  c #714177B881DE\",\n#\"Q  c #76367B8C81CE\",\n#\"!  c #797A7E8E844E\",\n#\"~  c #76607DA5882D\",\n#\"^  c #7BCE814A8691\",\n#\"/  c #7E2284438A18\",\n#\"(  c #7FA0880B8BE5\",\n#\")  c #8345841C85C8\",\n#\"_  c #821B86C08BA5\",\n#\"`  c #847189E68E50\",\n#\"'  c #8AFC8C168D68\",\n#\"]  c #85338C479212\",\n#\"[  c #89068ED4935A\",\n#\"{  c #87859080937B\",\n#\"}  c #8A45922294B2\",\n#\"|  c #8EC095939BCA\",\n#\" . c #91BB928693B4\",\n#\".. c #97DD99EA9BD1\",\n#\"X. c #9B909CBB9E2E\",\n#\"o. c #A441A473A55A\",\n#\"O. c #A4D9A778A8FB\",\n#\"+. c #AC79AD21AE40\",\n#\"@. c #B33EB400B547\",\n#\"#. c #B67CB78AB89C\",\n#\"$. c #B6ECB898BA4A\",\n#\"%. c #BC61BCF0BDC0\",\n#\"&. c #C02CC15AC322\",\n#\"*. c #C274C424C54E\",\n#\"=. c #C83FC83FC855\",\n#\"-. c #CC1ACC3CCC9E\",\n#\";. c #D017D0B5D270\",\n#\":. c #D43CD482D4F3\",\n#\">. c #DBAEDBDEDC46\",\n#\",. c #E02EE054E096\",\n#\"<. c #E444E465E4B3\",\n#\"1. c #EBF8EC3AEC69\",\n#\"2. c #F02DF0F6F11C\",\n#\"3. c #F5E1F5F3F61B\",\n#\"4. c #F840F862F891\",\n#\"5. c none\",\n#/* pixels */\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.4.4.5.4.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.4.<.%. .` ) ) ) o.=.2.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.4.;.` c a g c v l a 9 7 6 8 F =.4.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.4.&.S 7 7 w r u l c z h 9 2 > ; # , U :.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.:.F 6 3 3 0 0 0 e f l c z h e 2 , ; @ # 6 @.4.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.3...e - < 3 0 0 0 0 w r f h x c h e 2 , & + o > X.4.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.>.F 2 % * * 1 3 3 0 0 w w r t j z c h e 2 , = O o ; ' 4.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.-.x : & * * * < < 3 0 0 w w w r u h c c h e 2 > = O . & U 3.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.%.d & % * * % * * - < 3 0 0 w r r r t h k z h e 4 , & O . # A 1.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.4.%.p & + $ % * * * % * * < 3 0 0 0 r r r t g z c h y 2 > & O . + x <.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.;.s % O + + + $ % % * % * * - 3 0 0 r r t t t f l c h y 4 > = O   O d :.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.>.v & + O X + O $ $ % * * $ * * < 1 0 0 r t t t u u l c g e 4 - # O   X p -.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.2.U , * $ $ + X O + + $ $ $ * % % * * < 0 q r t t u u i l c h y 4 , # X     9 #.4.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.4.X.7 8 2 = % @ O o O + + $ $ $ % % % * * 3 0 0 t t i t u i l z l e 6 1 # X     6 o.4.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.-.a e y y 5 - = = @ + O O O + $ % % $ % % * - 0 q t u u u r i l c l e 2 > # X     ,  .4.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.3.F > 7 e 8 8 7 1 - = = $ + + X $ $ % % $ $ % * < 3 q r i i i u i g c h e 4 > @ X     : ) 3.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.#.7 : : > , , 3 4 4 - - = = % $ O $ $ $ % $ $ % * < 3 0 r i i i u i g v l e 6 > @ o     & U 3.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.1.V , : = & # # # = > > : : : : * $ + O + $ $ $ $ $ % < 3 0 r i f f u i g c l e , & o o .   @ F <.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.#.6 4 , = # @ O O O + = - : - : : : & $ + + + $ $ $ $ % < 3 0 u f f f i g h 8 > = , 6 7 6 ; @ # b >.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.4.F 4 4 4 : = & @ + O o O + % & - : > , : % + X $ $ $ $ $ & - 3 0 t j g e 7 > : 2 s D P P U A g 7 : b ;.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.,.a 7 7 4 , : = & # @ @ O X X + + & - , 2 > * $ + $ $ + $ $ $ - 3 g w 1 : : > w j Z T ^ Q ! T J N p , b -.5.5.5.5.5.5.5.5.\",\n#\"5.5.4.O.6 7 8 8 4 , ; = # & # @ + O X X + + & > 2 2 : # + $ $ $ + $ 5 j 7 & & : w z C H I Y I I Y T W Y H c 7 v -.5.5.5.5.5.5.5.\",\n#\"5.5.3.A , 6 7 6 7 4 > ; = & & # # @ + X o . O + & 2 2 > & + + $ % g D y & , 8 h M L I T T Q T T W Q Q ! Q J c 4 x <.5.5.5.5.5.5.\",\n#\"5.5.1.7 > 4 6 4 , , > = = % = % # # @ + O O . X + # : 2 2 = $ * B ~ h , 4 u z C H I T Q Q Q Q Q ! Q ! Q Q U S h 2  .4.5.5.5.5.5.\",\n#\"5.5.:., ; 2 4 , = = = = = # = = & & # # + + O X X X @ = > 2 2 S _ l 1 8 h m C Z P D v d s a d v F T Q Q W I S v h e :.5.5.5.5.5.\",\n#\"5.4.@.> # , 6 , = # # = # = = # & & # & # # + + X X . + + 3 U ] h 4 y h v C Z v y 6 , = @ + @ ; 6 h J R T P S c v e _ 4.5.5.5.5.\",\n#\"5.4. .; = ; , 6 = # # # # @ # = & & & & & # # # + + + X # S ` g 4 u l v V z y > @ O O O O O o . X # 9 J T P S c v v l 3.5.5.5.5.\",\n#\"5.4.) + + = ; , - # # # @ # % % & # & # % & # & + + + + h [ g 2 u z v V u , @ o O @ @ O + O O o . o O p Y T D v c N d ,.5.5.5.5.\",\n#\"5.4.' ; . # = ; , # @ @ @ @ # # # & & & & # & # % # # e [ N 6 g z V v e & O + O @ O + + + O O O o . . # v ! P N v v v +.4.5.5.5.\",\n#\"5.4.} y # o # # ; # @ # + @ # # # % # & & & & & % @ > ( P 7 i z v c 8 & + + + + + + + + + + + O O X X X 8 Y T A v M C  .5.5.5.5.\",\n#\"5.4.X.y 6 @ O # # = # @ @ @ @ @ # # # % # # & # # = V ( 8 u v V C h = % + + + + + + X + + X + O + O X . & P ^ J v N D X.4.5.5.5.\",\n#\"5.4.%.6 9 6 @ o # = # # @ @ @ @ # @ @ % # & & & = 7 ( l y c V V z N y - & # + + + + + + + + + O + O X X + D ] I V V D O.4.5.5.5.\",\n#\"5.5.,., ; 8 4 @ # # # # @ O + @ @ @ @ # # # # & - P Y 8 z V C u 7 C J d > % $ + + + + + + + + O O O O O + V ] Q C V D X.4.5.5.5.\",\n#\"5.5.3.x O ; 6 6 # @ # @ @ O @ + @ + @ @ @ @ @ # y { u l C D v 3 < p P Y k , & % $ + + + + + + + + O O O # b } ! D C D X.5.5.5.5.\",\n#\"5.5.4. .O o # 6 6 = # # @ O + + O @ @ O @ @ @ = J C u V C H V i < , h Y Q c 2 & & $ + + + X + + + + O + O b | ^ H C J @.4.5.5.5.\",\n#\"5.5.5.:.6   . @ , 6 ; # @ @ O @ O + O @ @ + @ 6 ` u V D J L W Z f 0 5 N Q ! m 2 & & # + + + + + + + O + # F ..^ J D J ;.5.5.5.5.\",\n#\"5.5.5.4.' O   o O ; 6 ; # O @ @ @ @ O O + + # V R l D P L ^ ( / Z j q e G ! ! N 4 & & # + + + + + + + O # ) [ ^ Y J J 1.5.5.5.5.\",\n#\"5.5.5.5.<.p     . . ; , > @ @ O + O O O O O > ( C C P Y C T ( { / E k r h P ~ Q N 2 & & # + + + + + @ O 5 [ _ ~ Q Y ) 3.5.5.5.5.\",\n#\"5.5.5.5.5.@.6       . # , ; @ O + + + O @ @ e | V P Y Y i V W ( [ ] E n i B T ^ ^ N 6 & & # # + + @ O @ M ! / / ! T +.4.5.5.5.5.\",\n#\"5.5.5.5.5.5.+.6     . . @ , ; @ O + + + O @ v ( J Y R S w u B I ] [ ] ~ B k G Q _ ! N 5 & * & + + + + : ^ D _ / / ! >.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.4.+.9     . o @ , > @ O + O O = Y Y T T R N g 0 u n E _ [ ] ~ Z B L ! ! ! C 4 & & & @ + @ h _ N _ _ _ ` 3.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.4.&.p .   o o O , > # O O O ; ( Y R ^ ^ z c s q r k E / [ } / K Z Y ! _ ! S 5 & & # # 2 / v U _ _ _ $.4.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.4.-.d .   o o o > 2 & O @ 2 ( ! R ^ R 8 p z h 7 0 j H / [ } ( L H Q ~ ! ! A 2 & # : S Y g _ _ ` ` 1.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.>.x o   o o O : 2 & @ 8 } ( / / T : > e c d 0 q g G ^ { } ] E K Q ! ! ! N 5 ; h _ p L ` ` _ @.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.4.4.<.A @   o o o ; 4 & y } ( / _ Y : o = 8 x j q 3 f Z W ] } ] W E Q ! / ! N h / z c _ ] _ ` 1.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.3.F &   . o o ; , p } ( ( _ T , . X = 6 l l w 5 i B W _ } { ~ W Q ^ ^ ^ ` N y ! ` ` ` *.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.3.R ;     o o # p } _ _ _ ! 4 . . . # 4 d z e 5 u m I ( } { ^ W ~ ( ( C 8 P ` ` ` O.4.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.4. .,   . o + 6 { _ _ _ ) e .   . . O 2 a c e 3 r n L ( } } / ~ ^ V 7 J ` ` _ } 1.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.o.,   o O , ) _ _ _ _ N @       o O > y c u 4 w k G ^ _ ^ P d 7 S ` ` ` [ ;.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.#.6   o # T _ ( _ ` Q e .     . o O ; 9 c a 5 0 g m h e , 8 J _ ` ` [ *.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.4.=.9 O @ v _ _ _ ` ( D 3 +     . o o & 8 l a 1 1 & # , a T ` ` ` ] %.4.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.:.p + 6 ) _ _ ] _ _ S e : @ + O O O = 6 8 2 # : w v ( ` ` _ ' @.4.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.,.x : S _ ] _ ] _ _ K m d p p 7 8 8 e a u y c ! ` ` ' _ ' *.4.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.1.F e W _ ` ` ` _ _ ^ P P ^ ` ` ^ Y D D ! ` ] ` ` ` } :.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.1.R v Q _ ` ] ] ` ] ` ` ) ^ ^ ( ( ' ` ` ` ' ` ' ..<.4.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.3. .A Q _ _ ] ` ` ` ` ` { { ` ` ` ' ` _ ` [ &.4.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.4.o.N Y ! _ ` ` ` ` { ` { ` ` ` ` ` ` @.1.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.4.>._ S Y ^ ) ` ) _ _ ` ' _ / [ @.1.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.4.<.+.` U U P Y R ) X.@.>.3.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.4.4.4.3.1.1.4.4.4.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\",\n#\"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.\"\n#};\"\"\"\n#class EasyReflectorVP:\n#    def __init__(self, obj):\n#        '''Set this object to the proxy object of the actual view provider'''\n#        obj.Proxy = self\n#\n#    def doubleClicked(self,vobj):\n#        vobj.Object.Enabled = not vobj.Object.Enabled\n#\n#    def dropObject(self, vp, dropped):\n#        vp.Object.LinkedObjects += [dropped]\n#        vp.Object.LinkedObjects = list(set(vp.Object.LinkedObjects)) #remove duplicates\n#\n#    def canDropObjects(self):\n#        return True\n#\n#    def canDropObject(self, dropped):\n#        return hasattr(dropped, \"ViewObject\")\n#\n#    def attach(self,vobj):\n#        self.Object = vobj.Object\n#        self.standard = coin.SoGroup()\n#        vobj.addDisplayMode(self.standard,\"Standard\")\n#\n#    def onDelete(self, vobj, subelements):\n#        vobj.Object.Enabled = False\n#        vobj.Object.Document.recompute()\n#        return True\n#\n#    def updateData(self, fp, prop):\n#        '''If a property of the handled feature has changed we have the chance to handle this here'''\n#        if prop == \"Environment\":\n#            fp.ViewObject.signalChangeIcon()\n#\n#    def getDisplayModes(self,obj):\n#        '''Return a list of display modes.'''\n#        modes=[\"Standard\"]\n#        return modes\n#\n#    def claimChildren(self):\n#        return[]\n#\n#    def getDefaultDisplayMode(self):\n#        '''Return the name of the default display mode. It must be defined in getDisplayModes.'''\n#        return \"Standard\"\n#\n#    def setDisplayMode(self,mode):\n#        '''Map the display mode defined in attach with those defined in getDisplayModes.\\\n#                Since they have the same names nothing needs to be done. This method is optional'''\n#        return mode\n#\n#    def onChanged(self, vp, prop):\n#        '''Here we can do something when a single property got changed'''\n#        #FreeCAD.Console.PrintMessage(\"Change property: \" + str(prop) + \"\\n\")\n#        pass\n#\n#    def getIcon(self):\n#        '''Return the icon in XPM format which will appear in the tree view. This method is\\\n#                optional and if not defined a default icon is shown.'''\n#        iconTextured = __XPM__\n#\n#        if self.Object.Environment != \"none\" and self.Object.Enabled:\n#            return iconTextured\n#        else:\n#            return None #default app::featurepython icon\n#\n#    def __getstate__(self):\n#        '''When saving the document this object gets stored using Python's json module.\\\n#                Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\\\n#                to return a tuple of all serializable objects or None.'''\n#        return None\n#\n#    def __setstate__(self,state):\n#        '''When restoring the serialized object from document we have the chance to set some internals here.\\\n#                Since no data were serialized nothing needs to be done here.'''\n#        return None\n#\n#CODE_ENDS_HERE\n########################################\n\nBASENAME = 'easyreflector'\n\ndef makeObject(FP):\n\n    doc = FreeCAD.ActiveDocument\n    sel = Gui.Selection.getSelection()\n\n    fp = doc.addObject(\"App::FeaturePython\",\"EasyReflector\")\n    FP.EasyReflector(fp)\n    FP.EasyReflectorVP(fp.ViewObject)\n\n    if len(sel) >= 1:\n        fp.LinkedObjects = sel\n    else:\n        FreeCAD.Console.PrintWarning(\"EasyReflector: nothing selected.  Select an \\\nobject prior to running the macro or drag/drop your object(s) on to it in the \\\ncombo view or edit the Linked Objects property.\\n\")\n\n\n#################\ndef writeFile():\n    with open(py_file,\"w\") as outfile:\n        for line in code.splitlines():\n            if \"#CODE_ENDS_HERE\" in line:\n                break\n            if line.startswith('#'):\n                if line == \"# -*- coding: utf-8 -*-\":\n                    line = \"#\" + line\n                outfile.write(line[1:]+\"\\n\") #skip first character (#)\n\n\n\n############\n#if __name__ == \"__main__\":\n#    makeObject(None)\n#    raise Exception(\"quick exit for testing/debugging\")\n############\n\nif __name__ == \"__main__\":\n    import os\n    fin = open(__file__, 'r')\n    code = fin.read()\n    fin.close()\n    version = code.splitlines()[1][16:]\n    real_path = os.path.realpath(__file__)\n    dir_path = os.path.dirname(real_path)\n    py_file = real_path.replace(\".FCMacro\",\".py\").replace('EasyReflector','easyreflector').replace(\"easyReflector\",\"easyreflector\")\n    bHasFile = os.path.exists(py_file)\n    noImport = False #user elects not to save import file\n\n    if not bHasFile:\n        from PySide import QtGui\n        window = QtGui.QApplication.activeWindow()\n        mb = QtGui.QMessageBox()\n        mb.setWindowTitle(BASENAME+\" setup\")\n        mb.setIcon(mb.Information)\n        mb.setStandardButtons(mb.Ok)\n        mb.addButton(mb.Cancel)\n        mb.setDefaultButton(mb.Cancel)\n        okBtn = mb.button(QtGui.QMessageBox.StandardButton.Ok)\n        cancelBtn = mb.button(QtGui.QMessageBox.StandardButton.Cancel)\n        okBtn.setText(\"Create file\")\n        cancelBtn.setText(\"Do not create file\")\n        caption = \"In order for \"+BASENAME+\" objects to be parametric after saving and reloading file\\n\\\nwe need to create another file on this computer.  File to be created will be: \\n\\n\"+py_file+\"\\n\\n\\\nThis makes it available to the system upon restarting FreeCAD and loading documents containing the \\\n\"+BASENAME+\" feature python objects.  Create file now?\\n\\n\"\n        mb.setText(caption)\n        ret = mb.exec_()\n        if ret == mb.Ok:\n            writeFile()\n            QtGui.QMessageBox.information(window,\"Success\",\"File successfully created.  Please note: if you uninstall \"+BASENAME+\" macro you need to manually remove \"+py_file+\", too.\\n\")\n        else:\n            new_lines = []\n            for line in code.splitlines():\n                if line.startswith('#'):\n                    if \"CODE_ENDS_HERE\" in line:\n                        break\n                    if line == \"# -*- coding: utf-8 -*-\":\n                        new_lines.append(line+\"\\n\")\n                        continue\n                    new_lines.append(line[1:]+\"\\n\")\n            code = \"\".join(new_lines)\n\n            #credit to Mila Nautikus for his answer to a question on stackoverflow, which I modified here\n            #in this example the filename is easyreflector.py\n            #https://stackoverflow.com/questions/5362771/how-to-load-a-module-from-code-in-a-string\n\n            ##########\n            import sys, importlib\n            my_name = BASENAME\n            my_spec = importlib.util.spec_from_loader(my_name, loader=None)\n\n            my_macro = importlib.util.module_from_spec(my_spec)\n\n            exec(code,my_macro.__dict__)\n            sys.modules[BASENAME] = my_macro\n            makeObject(my_macro)\n            noImport = True\n\n    if not noImport: #don't never use no double negatives\n        import addonmanager_utilities as utils\n        try:\n            import easyreflector as FP\n        except:\n            import EasyReflector as FP\n        if FP.__version__ != __version__:\n            writeFile()\n            from PySide import QtCore,QtGui\n            window = QtGui.QApplication.activeWindow()\n            mbox = QtGui.QMessageBox()\n            mbox.setWindowTitle(BASENAME+\" updated\")\n\n            mbox.setText(BASENAME+\".py has been updated to version \"+__version__+\". \\\nYou must restart FreeCAD for the new changes to take effect and to use the macro.\")\n            mbox.setIcon(mbox.Warning)\n            mbox.setStandardButtons(mbox.Ok)\n            mbox.addButton(QtGui.QMessageBox.Cancel)\n            mbox.setDefaultButton(mbox.Cancel)\n            okBtn = mbox.button(QtGui.QMessageBox.StandardButton.Ok)\n            cancelBtn = mbox.button(QtGui.QMessageBox.StandardButton.Cancel)\n            okBtn.setText(\"Restart now\")\n            cancelBtn.setText(\"Restart later\")\n            ret = mbox.exec_()\n            if ret == mbox.Ok:\n                QtCore.QTimer.singleShot(1000, utils.restart_freecad)\n        else:\n            makeObject(FP)\n",
    "url": "https://wiki.freecad.org/Macro_EasyReflector",
    "raw_code_url": "https://gist.github.com/mwganson/aea3c51981c0b994cfd961cf4db56b50/raw/71b325b7c1568e2460beb099f553225a5516fc44/EasyReflector.FCMacro",
    "wiki": "",
    "version": "0.2023.12.09",
    "license": "",
    "date": "2023-12-09",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\EasyReflectorIcon.svg",
    "icon_source": "https://github.com/mwganson/EasyReflector/raw/main/EasyReflectorIcon.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "HiddenAlls",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro hidden all objects in the document (Visibility False).<br /><br />Macro version: 00.01<br />Last modified: 2015-11-12<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/d/d6/Macro_HiddenAlls.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "This macro hidden all objects in the document (Visibility False).",
    "code": "import FreeCAD\n#Macro_HideAllObjects\n__title__=\"Macro_HideAlls\"\n__author__ = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__version__ = \"00.00\"\n__date__    = \"11/11/2015\"\n\ntry:\n    for ShapeNameObj in FreeCAD.ActiveDocument.Objects:   # hidden alls objects\n        #print ShapeNameObj.Name\n        FreeCADGui.ActiveDocument.getObject(ShapeNameObj.Name).Visibility = False\nexcept Exception:\n    None",
    "url": "https://wiki.freecad.org/Macro_HiddenAlls",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.00",
    "license": "",
    "date": "11/11/2015",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_HiddenAlls.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/d/d6/Macro_HiddenAlls.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Texture Objects",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro allows you to temporarily put a texture image on selected objects. To remove the textures, simply close and reopen the document.<br /><br />Macro version: 1.1<br />Last modified: 2023-12-08<br />FreeCAD version: 0.18 and below<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/d/da/Macro_Texture_Objects.png\">ToolBar Icon</a><br />Author: yorik<br /> ",
    "comment": "This macro allows you to temporarily put a texture image on selected objects. To remove the textures, simply close and reopen the document.",
    "code": "import FreeCADGui\nfrom PySide import QtGui\nfrom pivy import coin\n\n# get a jpg filename\njpgfilename = QtGui.QFileDialog.getOpenFileName(QtGui.QApplication.activeWindow(),'Open image file','*.jpg')\n\n# apply textures\nfor obj in FreeCADGui.Selection.getSelection():\n    rootnode = obj.ViewObject.RootNode\n    tex =  coin.SoTexture2()\n    tex.filename = str(jpgfilename[0])\n    rootnode.insertChild(tex,1)",
    "url": "https://wiki.freecad.org/Macro_Texture_Objects",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2023-12-08",
    "src_filename": "",
    "filename_from_url": "",
    "author": "yorik",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Texture_Objects.png",
    "icon_source": "https://wiki.freecad.org/images/d/da/Macro_Texture_Objects.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Toggle Drawstyle",
    "on_wiki": true,
    "on_git": false,
    "desc": "When working with FreeCAD there are times when you want to quickly change the Drawstyle of the object you are working with. This is available through the Drawstyle pull-down menu where any Drawstyle may be selected. This macro makes 2 of the Drawstyles available as a clickable button on a toolbar which the user may click to toggle back and forth between the two Drawstyles. The user can modify the macro code to select which 2 Drawstyles they wish to toggle between. This does not add functionality missing in the Drawstyles pull-down menu, but rather an increased convenience level.<br /><br />Macro version: 2.0<br />Last modified: 2020-02-02<br />FreeCAD version: &gt;=0.17<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/0/0b/Macro_Toggle_Drawstyle.png\">ToolBar Icon</a><br />Author: Piffpoof<br /> ",
    "comment": "When working with FreeCAD there are times when you want to quickly change the Drawstyle of the object you are working with. This is available through the Drawstyle pull-down menu where any Drawstyle may be selected. This macro makes 2 of the Drawstyles available as a clickable button on a toolbar which the user may click to toggle back and forth between the two Drawstyles. The user can modify the macro code to select which 2 Drawstyles they wish to toggle between. This does not add functionality missing in the Drawstyles pull-down menu, but rather an increased convenience level.",
    "code": "# -*- coding: utf-8 -*-\n#\n#\n#\t\t\tMacro: Toggle Draw Style\n#\n# This macros allows the user to switch between different Drawstyles by clicking on\n# the button of a Macro in a toolbar.\n#\n# initial code:\t\ttriplus\n# macro-isation:\tpiffpoof\n#\n# This macro switches (or toggles) between 2 selected styles from the Drawstyle menu.\n# As written the macro toggles between \"WireFrame\" and \"As is\".\n# Immediately below this text is a list of the legal values for the Drawstyle menu.\n# The first 2 lines of executable code are of the form \"DrawstyleA = \" followed by\n# the 2nd line which is of the form \"DrawstyleB = \".\n# These 2 lines specify which of the Drawstyle values the macro will toggle between.\n# Drawstyle \"As is\" is the system default and so is specified as the first drawstyle.\n# The second line specifies which drawstyle will be toggled to and from.\n# Any of the legal values may be used, so if, for example, it is desired to toggle between\n# the Shaded and Points drawstyles, then the 2 lines of code would be modified to be:\n#\n# drawstyleA = \"Shaded\"\n# drawstyleB = \"Points\"\n#\n# but remember that the hash signs ('#') are not to be present on the executable lines.\n#\n###Legal Values for Drawstyle###\n#\n# 0 = \"As is\"\n# 1 = \"Flat lines\"\n# 2 = \"Shaded\n# 3 = \"Wireframe\"\n# 4 = \"Points\"\n# 5 = \"Hidden line\"\n# 6 = \"No shading\"\n#\n################################\n\n# triplus @ 2016, 2020\n# Toggle global display mode\n# ==============================\n\n# 0 = \"As is\"\n# 1 = \"Flat lines\"\n# 2 = \"Shaded\n# 3 = \"Wireframe\"\n# 4 = \"Points\"\n# 5 = \"Hidden line\"\n# 6 = \"No shading\"\n\nstyleA = 0\nstyleB = 3\n\n# ==============================\n\nfrom PySide import QtGui\nimport FreeCADGui as Gui\n\nmw = Gui.getMainWindow()\n\n\nact = {\n    0: mw.findChild(QtGui.QAction, \"Std_DrawStyleAsIs\"),\n    1: mw.findChild(QtGui.QAction, \"Std_DrawStyleFlatLines\"),\n    2: mw.findChild(QtGui.QAction, \"Std_DrawStyleShaded\"),\n    3: mw.findChild(QtGui.QAction, \"Std_DrawStyleWireframe\"),\n    4: mw.findChild(QtGui.QAction, \"Std_DrawStylePoints\"),\n    5: mw.findChild(QtGui.QAction, \"Std_DrawStyleHiddenLine\"),\n    6: mw.findChild(QtGui.QAction, \"Std_DrawStyleNoShading\"),\n}\n\n\nactionA = act[styleA]\nactionB = act[styleB]\n\n\nif actionA.isChecked():\n    actionB.trigger()\nelse:\n    actionA.trigger()",
    "url": "https://wiki.freecad.org/Macro_Toggle_Drawstyle",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2020-02-02",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Piffpoof",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Toggle_Drawstyle.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/0/0b/Macro_Toggle_Drawstyle.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Toggle Drawstyle Optimized",
    "on_wiki": true,
    "on_git": false,
    "desc": "Script optimized for all languages and to object selected or all objects.<br />When working with FreeCAD there are times when you want to quickly change the Drawstyle of the object you are working with. This is available through the Drawstyle pull-down menu where any Drawstyle may be selected. This macro makes 2 of the Drawstyles available as a clickable button on a toolbar which the user may click to toggle back and forth between the two Drawstyles.<br />See also:<br />Toggle global display mode: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/Macro_Toggle_Drawstyle_Optimized#Script_2\">Macro_Toggle_Drawstyle_Optimized_2.FCMacro</a><br />Toggle selected object(s) display mode (changes visible only in global As is (located on View toolbar) display mode): <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/Macro_Toggle_Drawstyle_Optimized#Script_3\">Macro_Toggle_Drawstyle_Optimized_3.FCMacro</a><br /><br />Macro version: 2.0<br />Last modified: 2020-29-01<br />FreeCAD version: 0.17 and above<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/8/8c/Macro_Toggle_Drawstyle_Optimized.png\">ToolBar Icon</a><br />Author: Piffpoof , triplus<br /> ",
    "comment": "Script optimized for all languages and to object selected or all objects.",
    "code": "# triplus @ 2016, 2020\n# Toggle object/global display mode\n# ==============================\n\n# 0 = \"As is\"\n# 1 = \"Flat lines\"\n# 2 = \"Shaded\n# 3 = \"Wireframe\"\n# 4 = \"Points\"\n# 5 = \"Hidden line\"\n# 6 = \"No shading\"\n\nglobalA = 0\nglobalB = 3\n\na = \"Flat Lines\"\nb = \"Shaded\"\nc = \"Wireframe\"\nd = \"Points\"\n\nobjectA = a\nobjectB = c\n\n# ==============================\n\nfrom PySide import QtGui\nimport FreeCADGui as Gui\n\nmw = Gui.getMainWindow()\nsel = Gui.Selection.getSelectionEx()\n\n\nact = {\n    0: mw.findChild(QtGui.QAction, \"Std_DrawStyleAsIs\"),\n    1: mw.findChild(QtGui.QAction, \"Std_DrawStyleFlatLines\"),\n    2: mw.findChild(QtGui.QAction, \"Std_DrawStyleShaded\"),\n    3: mw.findChild(QtGui.QAction, \"Std_DrawStyleWireframe\"),\n    4: mw.findChild(QtGui.QAction, \"Std_DrawStylePoints\"),\n    5: mw.findChild(QtGui.QAction, \"Std_DrawStyleHiddenLine\"),\n    6: mw.findChild(QtGui.QAction, \"Std_DrawStyleNoShading\"),\n}\n\n\ndefault = act[0]\nactionA = act[globalA]\nactionB = act[globalB]\n\n\nif sel:\n    obj = []\n    default.trigger()\n    for s in sel:\n        if s.Object.TypeId == \"App::Link\":\n            if s.Object.LinkedObject not in obj:\n                obj.append(s.Object.LinkedObject)\n        elif s.Object not in obj:\n            obj.append(s.Object)\n        else:\n            pass\n\n    for o in obj:\n        if o.ViewObject.DisplayMode == objectA:\n            o.ViewObject.DisplayMode = objectB\n        else:\n            o.ViewObject.DisplayMode = objectA\nelse:\n    if actionA.isChecked():\n        actionB.trigger()\n    else:\n        actionA.trigger()",
    "url": "https://wiki.freecad.org/Macro_Toggle_Drawstyle_Optimized",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2020-29-01",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Piffpoof , triplus",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Toggle_Drawstyle_Optimized.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/8/8c/Macro_Toggle_Drawstyle_Optimized.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Toggle Visibility",
    "on_wiki": true,
    "on_git": false,
    "desc": "Toggling Hidden/Display all objects not selected.<br />objects that are selected in a document are made visible while objects that are not selected are made invisible.<br />if no objects are selected then all objects are hidden.<br />if all objects are selected then all objects are made visible.<br /><br />Macro version: 00.02<br />Last modified: 2015-11-12<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/4/42/Macro_SelectVisible.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "Toggling Hidden/Display all objects not selected.",
    "code": "import FreeCAD\n# Macro_ToggleSelectedObjectVisibility\n__title__=\"Macro_ToggleSelectedObjectVisibility\"\n__author__ = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__version__ = \"00.02\"\n__date__    = \"12/11/2015\"\n\ntry:\n    compt = 0\n    for ShapeNameObj in FreeCAD.ActiveDocument.Objects:                                   # list alls objet for test if alls hidden\n        if (FreeCADGui.ActiveDocument.getObject(ShapeNameObj.Name).Visibility == False) and (Gui.Selection.isSelected(ShapeNameObj) == False):\n            compt += 1                                                                    # if hidden : compt += 1\n            #print \"False : \",ShapeNameObj.Name\n    if compt == len(FreeCAD.ActiveDocument.Objects):                                      # if (compt = Alls objects hidden) then Visibility = True\n        for ShapeNameObj in FreeCAD.ActiveDocument.Objects:\n            FreeCADGui.ActiveDocument.getObject(ShapeNameObj.Name).Visibility = True      # Visibility = True\n            #print \"True  : \",ShapeNameObj.Name\n        compt = 0\n    else :\n        for ShapeNameObj in FreeCAD.ActiveDocument.Objects:                               # hidde objects not selecteds\n            if Gui.Selection.isSelected(ShapeNameObj) == False:\n                FreeCADGui.ActiveDocument.getObject(ShapeNameObj.Name).Visibility = False # if objects is not selected then Visibility = False (Hidden)\n                #print \"False : \",ShapeNameObj.Name\n            else:\n                FreeCADGui.ActiveDocument.getObject(ShapeNameObj.Name).Visibility = True  # if objects are hidden and selected then Visibility = True and hidden alls objects visibles\n                #print \"True  : \",ShapeNameObj.Name\nexcept Exception:\n    None",
    "url": "https://wiki.freecad.org/Macro_Toggle_Visibility",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.02",
    "license": "",
    "date": "12/11/2015",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_SelectVisible.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/4/42/Macro_SelectVisible.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Toggle Visibility2 1-2",
    "on_wiki": true,
    "on_git": false,
    "desc": "<div style=\"background-color:DarkRed; color:Yellow;\">This macro must be used with <b>Macro Toggle Visibility2 2-2</b></div><br />This is a set of four related macros for managing the visibility of objects in the Object Model (return on original visibility):<br /># objects that are selected in a document are made visible while objects that are not selected are made invisible<br />#*if no objects are selected then all objects are hidden;<br />#*if all objects are selected then all objects are made visible<br /># make all objects visible<br /><br />Macro version: 00.02b<br />Last modified: 2017-07-27<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/d/d7/Macro_SelectVisible2.png\">ToolBar Icon</a><br />Author: openfablab<br /> ",
    "comment": "This macro must be used with Macro Toggle Visibility2 2-2",
    "code": "import FreeCAD\n# \"Macro_Toggle_Visibility2_1-2\" associate with \"Macro_Toggle_Visibility2_2-2\"\n__title__=\"Macro_Toggle_Visibility2_1-2\"\n__author__ = \"openfablab\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__version__ = \"00.02b\"\n__date__    = \"27/07/2017\"\nFreeCAD.actual=[]\ntry: \n    compt = 0\n    for ShapeNameObj in FreeCAD.ActiveDocument.Objects:                                   # list alls objet for test if alls hidden\n        if (FreeCADGui.ActiveDocument.getObject(ShapeNameObj.Name).Visibility == False) and (Gui.Selection.isSelected(ShapeNameObj) == False):\n            compt += 1                                                                    # if hidden : compt += 1\n            #print \"False : \",ShapeNameObj.Name\n        elif Gui.Selection.isSelected(ShapeNameObj) == False:\n            FreeCAD.actual.append(ShapeNameObj.Name)\n            #print \"Actual : \",ShapeNameObj.Name\n    if compt == len(FreeCAD.ActiveDocument.Objects):                                      # if (compt = Alls objects hidden) then Visibility = True\n        for ShapeNameObj in FreeCAD.ActiveDocument.Objects:\n            FreeCADGui.ActiveDocument.getObject(ShapeNameObj.Name).Visibility = True      # Visibility = True\n            #print \"True  : \",ShapeNameObj.Name\n        compt = 0\n    else :\n        for ShapeNameObj in FreeCAD.ActiveDocument.Objects:                               # hidde objects not selecteds\n            if Gui.Selection.isSelected(ShapeNameObj) == False:\n                FreeCADGui.ActiveDocument.getObject(ShapeNameObj.Name).Visibility = False # if objects is not selected then Visibility = False (Hidden)\n                #print \"False : \",ShapeNameObj.Name\n            else:\n                FreeCADGui.ActiveDocument.getObject(ShapeNameObj.Name).Visibility = True  # if objects are hidden and selected then Visibility = True and hidden alls objects visibles\n                #print \"True  : \",ShapeNameObj.Name\nexcept Exception:\n    None",
    "url": "https://wiki.freecad.org/Macro_Toggle_Visibility2_1-2",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.02b",
    "license": "",
    "date": "27/07/2017",
    "src_filename": "",
    "filename_from_url": "",
    "author": "openfablab",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_SelectVisible2.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/d/d7/Macro_SelectVisible2.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Toggle Visibility2 2-2",
    "on_wiki": true,
    "on_git": false,
    "desc": "<div style=\"background-color:DarkRed; color:Yellow;\">This macro must be used with <b>Macro_Toggle_Visibility2_1-2</b></div><br />This macro makes all objects visible respecting the original visible and hidden objects after use the <a href=\"/Macro_Toggle_Visibility2_1-2\" title=\"Macro Toggle Visibility2 1-2\">Macro Toggle Visibility2 1-2</a><br /><br />Macro version: 00.02b<br />Last modified: 2017-07-27<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/e/ec/Macro_VisibleAlls2.png\">ToolBar Icon</a><br />Author: openfablab<br /> ",
    "comment": "This macro must be used with Macro_Toggle_Visibility2_1-2",
    "code": "import FreeCAD\n#original name \"Macro_VisibleAlls\" pratical name \"Macro_Toggle_Visibility2_2-2\" \"Macro_Toggle_Visibility2_1-2\" associate with \"Macro_Toggle_Visibility2_2-2\"\n__title__=\"Macro_DisplayAllObjects2_2-2\"\n__author__ = \"openfablab\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__version__ = \"00.00b\"\n__date__    = \"27/07/2017\"\n\ntry:\n    for ShapeNameObj in FreeCAD.actual:   # displyed alls objects\n        #print ShapeNameObj\n        FreeCADGui.ActiveDocument.getObject(ShapeNameObj).Visibility = True\nexcept Exception:\n    None",
    "url": "https://wiki.freecad.org/Macro_Toggle_Visibility2_2-2",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.00b",
    "license": "",
    "date": "27/07/2017",
    "src_filename": "",
    "filename_from_url": "",
    "author": "openfablab",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_VisibleAlls2.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/e/ec/Macro_VisibleAlls2.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "VisibleAlls",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro display all objects in the document (Visibility True).<br /><br />Macro version: 00.01<br />Last modified: 2015-11-12<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/1/19/Macro_VisibleAlls.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "This macro display all objects in the document (Visibility True).",
    "code": "import FreeCAD\n#Macro_VisibleAlls\n__title__=\"Macro_DisplayAllObjects\"\n__author__ = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__version__ = \"00.00\"\n__date__    = \"11/11/2015\"\n\ntry:\n    for ShapeNameObj in FreeCAD.ActiveDocument.Objects:   # displyed alls objects\n        #print ShapeNameObj.Name\n        FreeCADGui.ActiveDocument.getObject(ShapeNameObj.Name).Visibility = True\nexcept Exception:\n    None",
    "url": "https://wiki.freecad.org/Macro_VisibleAlls",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.00",
    "license": "",
    "date": "11/11/2015",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_VisibleAlls.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/1/19/Macro_VisibleAlls.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Visibility Manager",
    "on_wiki": true,
    "on_git": false,
    "desc": "Use this to manage the visibility of document objects.<br />There are 2 modes of operation: Show All and Show Types.<br />In Show Types mode (the default) you only see a list of the types of objects, e.g. Body, Sketch, Pad, Extrude.<br />Toggling one of the types off/on will set the visibility of all document <p>objects of that type in the active document.<br />In Show All mode (Press Shift key while executing the macro) you see a different checkbox for each and every document object, sorted alphabetically.<br />You can toggle each object's visibility individually.<br /><br />Macro version: 1.06<br />Last modified: 2020-06-18<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/c/c8/Macro_Visibility_Manager.png\">ToolBar Icon</a><br />Author: TheMarkster<br /> </p> ",
    "comment": "Use this to manage the visibility of document objects.",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2019 <TheMarkster>                                 *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License at http://www.gnu.org/licenses     *\n*   for more details.                                                     *\n*                                                                         *\n*   For more information about the GNU Library General Public License     *\n*   write to the Free Software Foundation, Inc., 59 Temple Place,         *\n*   Suite 330, Boston, MA  02111-1307 USA                                 *\n*                                                                         *\n***************************************************************************\n\"\"\"\n\n\"\"\"\nVisibility_Manager Macro\n\nUse this to manage the visibility of document objects.\n\nThere are 2 modes of operation: Show All and Show Types.\n\nIn Show Types mode (the default) you only see a list of the types\nof objects, e.g. Body, Sketch, Pad, Extrude.\n\nToggling one of the types off/on will set the visibility of all document\nobjects of that type in the active document.\n\nIn Show All mode (Press Shift key while executing the macro) you see \na different checkbox for each and every document object, sorted\nalphabetically.  You can toggle each object's visibility individually.\n\n\"\"\"\n\n__title__ = \"Visibility_Manager\"\n__author__ = \"TheMarkster\"\n__url__ = \"\"\n__Wiki__ = \"https://www.freecadweb.org/wiki/Macro_Visibility_Manager\"\n__date__ = \"2020.06.18\"\n__version__ = 1.06\n\nimport FreeCAD\nfrom PySide import QtCore, QtGui\nimport time\n\nclass Dlg(QtGui.QDialog):\n    def __init__(self, bShowAll=False):\n        QtGui.QDialog.__init__(self)\n        self.types={} #dict of types\n        self.showAll = bShowAll\n        self.reload = False\n        self.infoLabel = QtGui.QLabel()\n        self.infoLabel.mousePressEvent = self.label_clicked\n        if self.showAll:\n            self.infoLabel.setText(\"Show All mode\")\n        else:\n            self.infoLabel.setText(\"Show by Type mode\")\n        checkboxLayout = QtGui.QVBoxLayout()\n        self.checkboxes = []\n        widget = QtGui.QWidget() #will hold scroll area\n        checkboxLayout = QtGui.QVBoxLayout()\n        self.addCheckboxes(checkboxLayout)  \n        widget.setLayout(checkboxLayout)\n\n        #Scroll Area Properties\n        scroll = QtGui.QScrollArea()\n        scroll.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)\n        scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)\n        scroll.setWidgetResizable(True)\n        scroll.setWidget(widget)\n        vLayout = QtGui.QVBoxLayout()\n        vLayout.addWidget(scroll)\n\n        #buttons = QtGui.QDialogButtonBox(\n        #    QtGui.QDialogButtonBox.Ok.__or__(QtGui.QDialogButtonBox.Cancel),\n        #    QtCore.Qt.Horizontal, self)\n        buttons = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok, QtCore.Qt.Horizontal,self)\n        buttons.addButton(QtGui.QDialogButtonBox.Cancel)\n        mode_button = buttons.addButton('Switch Mode', QtGui.QDialogButtonBox.ActionRole)\n        mode_button.clicked.connect(self.label_clicked)\n        buttons.accepted.connect(self.accept)\n        buttons.rejected.connect(self.reject)\n        buttons.setCenterButtons(True)\n        layout = QtGui.QVBoxLayout()\n        layout.addWidget(self.infoLabel)\n        layout.addLayout(vLayout)\n        layout.addWidget(buttons)\n        self.setLayout(layout)\n\n    def label_clicked(self, event):\n        self.reload = True\n        self.close()\n        QtGui.QApplication.processEvents()\n        time.sleep(0.1)\n\n    def addCheckboxes (self, cbLayout):\n        objectList = FreeCAD.ActiveDocument.findObjects()\n        objectList.sort(key=lambda x: x.Name, reverse=False)\n        nameList = []\n        for obj in objectList:\n            if not self.nameInList(obj.Name, nameList):\n                nameList.append(obj.Name)\n                self.newType(obj.Name)\n\n        all = QtGui.QCheckBox(\"All\", self)\n        all.setObjectName(\"all\")\n        all.toggled.connect(self.allToggled)\n        cbLayout.addWidget(all)\n        self.checkboxes = [all]\n        for name in nameList:\n            for nn in range(0,len(self.types[name])):\n                objLabel = getattr(FreeCAD.ActiveDocument,self.types[name][nn]).Label\n                objName = self.types[name][nn]\n                if objLabel != objName and self.showAll:\n                    ck = QtGui.QCheckBox(self.types[name][nn]+\" (\"+objLabel+\")\", self)\n                else:\n                    ck = QtGui.QCheckBox(objName,self)\n                ck.setObjectName(objName)\n\n                if getattr(FreeCAD.ActiveDocument,self.types[name][nn]).ViewObject.Visibility:\n                    ck.setCheckState(QtCore.Qt.Checked)\n                else:\n                    ck.setCheckState(QtCore.Qt.Unchecked)\n                if nn != 0 and not self.showAll:\n                    ck.hide()\n                cbLayout.addWidget(ck)\n                self.checkboxes.append(ck)\n    \n    def addToTypes(self, typeName, name):\n        self.types[typeName].append(name)\n\n    def newType(self, typeName):\n        self.types[typeName] = [typeName]\n    \n    def nameInList(self, name, nameList):\n        \"\"\" check if name is in nameList\n            e.g. name = \"Extrude002\"\n            nameList = [\"Extrude\", \"Extrude001\", \"Extrude002\"...]\n        \"\"\"\n        for nl in nameList:\n            if nl in name and nl[:3] == name[:3]:\n                self.addToTypes(nl,name)\n                return True\n        return False\n\n    def allToggled(self):\n        \"\"\"all checkbox was toggled\"\"\"\n        allState = self.checkboxes[0].checkState()\n        for ii in range(1,len(self.checkboxes)):\n            self.checkboxes[ii].setCheckState(allState)\n\n    def accept(self):\n        \"\"\"user clicked Ok\"\"\"\n        self.setWindowOpacity(0.85)\n        self.infoLabel.setText(\"Working...\")\n        if self.showAll:\n            for ii in range(1, len(self.checkboxes)):\n                name = self.checkboxes[ii].objectName()\n                state = self.checkboxes[ii].checkState()\n            \n                if state == QtCore.Qt.Checked:\n                    obj = getattr(FreeCAD.ActiveDocument, name)\n                    if not obj.ViewObject.Visibility:\n                        obj.ViewObject.Visibility = True\n                else:\n                    obj = getattr(FreeCAD.ActiveDocument, name)\n                    if obj.ViewObject.Visibility:\n                        obj.ViewObject.Visibility = False\n                QtGui.QApplication.processEvents()\n                time.sleep(0.01)\n        else: #show type mode\n            for ii in range(1, len(self.checkboxes)):\n                if not self.checkboxes[ii].isVisible():\n                    continue\n                name = self.checkboxes[ii].objectName()\n                state = self.checkboxes[ii].checkState()\n            \n                if state == QtCore.Qt.Checked:\n                    for n in self.types[name]:\n                        obj = getattr(FreeCAD.ActiveDocument, n)\n                        obj.ViewObject.Visibility = True\n                else:\n                    for n in self.types[name]:\n                        obj = getattr(FreeCAD.ActiveDocument, n)\n                        obj.ViewObject.Visibility = False\n                QtGui.QApplication.processEvents()\n                time.sleep(0.01)\n        self.close()\n\n\nshowAll = False\nmodifiers = QtGui.QApplication.keyboardModifiers()\nif modifiers == QtCore.Qt.ShiftModifier:\n    showAll = True\nif FreeCAD.ActiveDocument:\n    dlg = Dlg(showAll)\n    dlg.setWindowTitle(\"Visibility Manager v\"+str(__version__))\n    result = dlg.exec_()\n    while dlg.reload:\n        showAll = not dlg.showAll\n        dlg = Dlg(showAll)\n        dlg.setWindowTitle(\"Visibility Manager v\"+str(__version__))\n        result = dlg.exec_()\nelse:\n    FreeCAD.Console.PrintWarning(\"Visibility Manager v\"+str(__version__)+\": no active document\\n\")",
    "url": "https://wiki.freecad.org/Macro_Visibility_Manager",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/Macro_Visibility_Manager",
    "version": "1.06",
    "license": "",
    "date": "2020.06.18",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Visibility_Manager.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/c/c8/Macro_Visibility_Manager.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "PDWrapper",
    "on_wiki": true,
    "on_git": false,
    "desc": "Encapsulate non-PartDesign solids to work in PartDesign<br /><br />Macro version: 0.2023.08.13<br />Last modified: 2023-08-13<br />FreeCAD version: python 3 versions<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/File:Workbench_PartDesign.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Encapsulate non-PartDesign solids to work in PartDesign",
    "code": "# -*- coding: utf-8 -*-\n__version__ = \"0.2023.08.13\"\n#__version__ = \"0.2023.08.13\"\n## PDWrapper a class to encapsulate non-Part Design objects into a PartDesign::FeaturePython object\n## 2021, by <TheMarkster>\n#\n#DEBUG = False\n#\n#import FreeCAD, FreeCADGui\n#import Part\n#from PySide import QtGui,QtCore\n#\n#class PDWrapper:\n#    def __init__(self,obj):\n#        obj.addProperty(\"App::PropertyBool\",\"EditPlacementAdjustments\",\"PlacementAdjustments\",\"[Command trigger] brings up placement adjustment dialog\").EditPlacementAdjustments=False\n#        obj.addProperty(\"App::PropertyPlacement\",\"TipBasePlacement\",\"PlacementAdjustments\",\"Rotate/Translate Tip Base shape copy, if needed\")\n#        obj.addProperty(\"App::PropertyPlacement\",\"TipToolPlacement\",\"PlacementAdjustments\",\"Rotate/Translate Tip Tool shape copy, if needed\")\n#        obj.addProperty(\"App::PropertyPlacement\",\"PatternBasePlacement\",\"PlacementAdjustments\",\"Rotate/Translate Pattern Base shape copy, if needed\")\n#        obj.addProperty(\"App::PropertyPlacement\",\"PatternToolPlacement\",\"PlacementAdjustments\",\"Rotate/Translate Pattern Tool shape copy, if needed\")\n#        obj.addProperty(\"App::PropertyBool\",\"ShowOffsetProps\",\"UserInterface\",\"Show/Hide properties related to Offsetting\").ShowOffsetProps = False\n#        obj.addProperty(\"App::PropertyBool\",\"ShowScaleProps\",\"UserInterface\",\"Show/Hide properties related to Scaling\").ShowScaleProps = False\n#        obj.addProperty(\"App::PropertyBool\",\"ShowMeshProps\",\"UserInterface\",\"Show/Hide properties related to Meshes\").ShowMeshProps = False\n#        obj.addProperty(\"App::PropertyIntegerConstraint\",\"Enabled\",\"PDWrapper\",\"If False, passes through previous solid feature as tip shape\").Enabled = (1,0,1,1)\n#        obj.addProperty(\"App::PropertyLink\",\"PatternBase\",\"PatternShape\",\"Base shape presented for patterning\")\n#        obj.addProperty(\"App::PropertyBool\",\"UsePatternToolAddSubShape\",\"PatternShape\",\"Use pattern tools addsubshape property in place of Pattern tool's shape in boolean to create pattern shape\").UsePatternToolAddSubShape = False\n#        obj.addProperty(\"App::PropertyFloat\",\"PatternBaseOffset\",\"PatternOffset\",\"Offset Pattern Base shape (0.0 = no offset)\").PatternBaseOffset = 0.0\n#        obj.addProperty(\"App::PropertyFloat\",\"PatternToolOffset\",\"PatternOffset\",\"Offset of Pattern Tool shape\").PatternToolOffset = 0.0\n#        obj.addProperty(\"App::PropertyFloat\",\"PatternShapeOffset\",\"PatternOffset\",\"Offset of Pattern Shape (result of Pattern Boolean operation)\").PatternShapeOffset = 0.0\n#        obj.addProperty(\"App::PropertyFloat\",\"TipShapeOffset\",\"TipOffset\",\"Offset of Tip Shape (result of Tip Boolean operation)\").TipShapeOffset = 0.0\n#        obj.addProperty(\"App::PropertyFloat\",\"TipBaseOffset\",\"TipOffset\",\"Whether to offset Tip Base shape\").TipBaseOffset = 0.0\n#        obj.addProperty(\"App::PropertyFloat\",\"TipToolOffset\",\"TipOffset\",\"Whether to offset Tip Tool shape\").TipToolOffset = 0.0\n#        obj.addProperty(\"App::PropertyBool\",\"TipOffsetIntersection\",\"TipOffset\",\"OCC parameter, might not be yet implemented in FreeCAD\").TipOffsetIntersection=False\n#        obj.addProperty(\"App::PropertyBool\",\"TipOffsetSelfIntersection\",\"TipOffset\",\"OCC parameter, might not be yet implemented in FreeCAD\").TipOffsetSelfIntersection=False\n#        obj.addProperty(\"App::PropertyBool\",\"PatternOffsetIntersection\",\"PatternOffset\",\"OCC parameter, might not be yet implemented in FreeCAD\").PatternOffsetIntersection=False\n#        obj.addProperty(\"App::PropertyBool\",\"PatternOffsetSelfIntersection\",\"PatternOffset\",\"OCC parameter, might not be yet implemented in FreeCAD\").PatternOffsetSelfIntersection=False\n#        obj.addProperty(\"App::PropertyBool\",\"UsePatternBaseAddSubShape\",\"PatternShape\",\"Use pattern base's addsubshape property in place of Pattern base's shape in boolean to create pattern shape\").UsePatternBaseAddSubShape = False\n#        obj.addProperty(\"App::PropertyBool\",\"UseTipBaseAddSubShape\",\"TipShape\",\"Use tip base's addsubshape property in place of Tip Base's shape in boolean to create tip shape\").UseTipBaseAddSubShape = False\n#        obj.addProperty(\"App::PropertyBool\",\"UseTipToolAddSubShape\",\"TipShape\",\"Use tip tool's addsubshape property in place of Tip Tool's shape in boolean to create tip shape\").UseTipToolAddSubShape = False\n#        obj.addProperty(\"App::PropertyLink\",\"PatternTool\",\"PatternShape\",\"Tool used with Pattern Base for creating patten shape to use with patterning\")\n#        obj.addProperty(\"App::PropertyString\",\"PatternOperationDefault\",\"PDWrapper\",\"hidden property holds operation type originally set during creation\")\n#        obj.addProperty(\"App::PropertyString\",\"TipOperationDefault\",\"PDWrapper\",\"hidden property holds operation type originally set during creation\")\n#        obj.addProperty(\"App::PropertyEnumeration\",\"PatternOperation\",\"PatternShape\",\"Operation to make pattern shape from the base and tool -- not used if no tool\").PatternOperation =[\"None\",\"Cut\",\"Fuse\",\"Common\",\"XOR\"]\n#        obj.addProperty(\"App::PropertyLink\",\"LinkedObject\",\"PDWrapper\",\"Object this wrapper is based on -- should normally be a solid based itself on the last item in the body (the tip).\")\n#        obj.addProperty(\"App::PropertyString\",\"Version\",\"PDWrapper\", \"Version used to create this PDWrapper object\").Version = __version__\n#        obj.addProperty(\"App::PropertyString\",\"Body\",\"PDWrapper\",\"Name of body containing this wrapper object\")\n#        obj.addProperty(\"App::PropertyBool\",\"ClaimChildren\",\"PDWrapper\",\"Whether to claim children in tree\").ClaimChildren = True\n#        obj.addProperty(\"App::PropertyLink\",\"TipBase\",\"TipShape\",\"Base shape for making the tip shape for this feature\")\n#        obj.addProperty(\"App::PropertyLink\",\"TipTool\",\"TipShape\",\"Tool shape for making the tip shape for this feature\")\n#        obj.addProperty(\"App::PropertyBool\",\"PatternScaleCut\",\"PatternScale\",\"Whether to cut scaled object from shape or vice versa\").PatternScaleCut = False\n#        obj.addProperty(\"App::PropertyBool\",\"TipScaleCut\",\"TipScale\",\"Whether to cut scaled object from shape or vice versa\").TipScaleCut = False\n#        obj.addProperty(\"App::PropertyBool\",\"TipOffsetCut\",\"TipOffset\",\"Whether to cut offset from shape or vice versa\").TipOffsetCut = False\n#        obj.addProperty(\"App::PropertyEnumeration\",\"TipOffsetMode\",\"TipOffset\",\"3D offset mode: Skin, Pipe, Recto-verso\").TipOffsetMode = [\"Skin\",\"Pipe\",\"Recto-verso\"]\n#        obj.addProperty(\"App::PropertyEnumeration\",\"TipOffsetJoin\",\"TipOffset\",\"3D offset join method: Arcs,Tangent,Intersection\").TipOffsetJoin = [\"Arcs\",\"Tangent\",\"Intersection\"]\n#        obj.addProperty(\"App::PropertyBool\",\"PatternOffsetCut\",\"PatternOffset\",\"Whether to cut offset from shape or vice versa\").PatternOffsetCut = False\n#        obj.addProperty(\"App::PropertyEnumeration\",\"PatternOffsetMode\",\"PatternOffset\",\"3D offset mode: Skin, Pipe, Recto-verso\").PatternOffsetMode = [\"Skin\",\"Pipe\",\"Recto-verso\"]\n#        obj.addProperty(\"App::PropertyEnumeration\",\"PatternOffsetJoin\",\"PatternOffset\",\"3D offset join method: Arcs,Tangent,Intersection\").PatternOffsetJoin = [\"Arcs\",\"Tangent\",\"Intersection\"]\n#        obj.addProperty(\"App::PropertyFloat\",\"TipShapeScale\",\"TipScale\",\"Scale to be applied to tip shape boolean result\").TipShapeScale = 1.0\n#        obj.addProperty(\"App::PropertyFloat\",\"TipBaseScale\",\"TipScale\",\"Scale to be applied to tip base\").TipBaseScale = 1.0\n#        obj.addProperty(\"App::PropertyFloat\",\"TipToolScale\",\"TipScale\",\"Scale to be applied to tip tool\").TipToolScale = 1.0\n#        obj.addProperty(\"App::PropertyFloat\",\"PatternShapeScale\",\"PatternScale\",\"Scale to be applied to pattern shape\").PatternShapeScale = 1.0\n#        obj.addProperty(\"App::PropertyFloat\",\"PatternBaseScale\",\"PatternScale\",\"Scale to be applied to pattern base\").PatternBaseScale = 1.0\n#        obj.addProperty(\"App::PropertyFloat\",\"PatternToolScale\",\"PatternScale\",\"Scale to be applied to pattern tool\").PatternToolScale = 1.0\n#        obj.addProperty(\"App::PropertyVector\",\"TipShapeScaleXYZ\",\"TipScale\",\"Scale to be applied to tip shape boolean result\").TipShapeScaleXYZ = FreeCAD.Vector(1,1,1)\n#        obj.addProperty(\"App::PropertyVector\",\"TipBaseScaleXYZ\",\"TipScale\",\"Scale to be applied to tip base\").TipBaseScaleXYZ = FreeCAD.Vector(1,1,1)\n#        obj.addProperty(\"App::PropertyVector\",\"TipToolScaleXYZ\",\"TipScale\",\"Scale to be applied to tip tool\").TipToolScaleXYZ = FreeCAD.Vector(1,1,1)\n#        obj.addProperty(\"App::PropertyVector\",\"PatternShapeScaleXYZ\",\"PatternScale\",\"Scale to be applied to pattern shape\").PatternShapeScaleXYZ = FreeCAD.Vector(1,1,1)\n#        obj.addProperty(\"App::PropertyVector\",\"PatternBaseScaleXYZ\",\"PatternScale\",\"Scale to be applied to pattern base\").PatternBaseScaleXYZ = FreeCAD.Vector(1,1,1)\n#        obj.addProperty(\"App::PropertyVector\",\"PatternToolScaleXYZ\",\"PatternScale\",\"Scale to be applied to pattern tool\").PatternToolScaleXYZ = FreeCAD.Vector(1,1,1)\n#        obj.addProperty(\"App::PropertyEnumeration\",\"TipOperation\",\"TipShape\",\"Operation to perform with Tip Base and Tip Tool to create feature shape\").TipOperation=[\"Fuse\",\"Cut\",\"Common\",\"XOR\",\"None\"]\n#        if not hasattr(obj,\"Refine\"):\n#            obj.addProperty(\"App::PropertyBool\",\"Refine\",\"PartDesign\",\"Whether to refine shape (removes extra edges\")\n#        obj.addProperty(\"App::PropertyString\",\"Type\",\"PDWrapper\",\"This object type, can be Additive, Subtractive, Common, XOR, None\")\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"MeshTolerance\",\"Mesh\",\"Tolerance when wrapping mesh objects\").MeshTolerance = (0.1,0.001,10000,.1)\n#        obj.addProperty(\"App::PropertyBool\",\"RefineMesh\",\"Mesh\",\"Whether to refine Mesh shape after conversion\").RefineMesh = True\n#        obj.addProperty(\"App::PropertyEnumeration\",\"ShapeManagement\",\"PDWrapper\",\n#\"If Automatic, wrapper manages Tip Base, Tip Tool, Pattern Base, Pattern Tool based on\\n\\\n#its position in the tree and its type and whether the linked object is a Part Design object\\n\\\n#or an outside object. If Manual, user must manage these when the tree changes.\").ShapeManagement = [\"Automatic\",\"Manual\"]\n#        obj.addProperty(\"App::PropertyBool\",\"ShowWarnings\",\"UserInterface\",\"Set to false to disable annoying warning messages\\n\").ShowWarnings=True\n#        obj.ShapeManagement = \"Automatic\"\n#        obj.setEditorMode(\"Type\",1) #readonly\n#        obj.setEditorMode(\"Body\",1) #readonly\n#        obj.setEditorMode(\"Version\",1)\n#        obj.setEditorMode(\"TipOperationDefault\",2) #hidden\n#        obj.setEditorMode(\"PatternOperationDefault\",2)\n#        self.showProps(obj,\"Scale\")\n#        self.showProps(obj,\"Offset\")\n#        self.showProps(obj,\"Mesh\")\n#        obj.Proxy = self\n#        self.bInhibitRecomputes = False\n#        self.editingMode = False #placement adjustment editor\n#        self.fpName = obj.Name\n#        self.tbName = \"\" #ghosts, tb = tip base, etc.\n#        self.ttName = \"\"\n#        self.pbName = \"\"\n#        self.ptName = \"\"\n#        self.pgName = \"\" #pattern ghost\n#        self.positioningGhosts = False\n#\n#    def recompute(self):\n#        t = QtCore.QTimer()\n#        t.singleShot(50, FreeCAD.ActiveDocument.recompute)\n#\n#    def onChanged(self,fp,prop):\n#        if prop == \"MeshTolerance\" or prop == \"RefineMesh\":\n#            self.resetMeshCache(fp)\n#            fp.touch()\n#        elif prop == \"ShowOffsetProps\":\n#            self.bInhibitRecomputes = True\n#            self.showProps(fp,\"Offset\")\n#        elif prop == \"ShowScaleProps\":\n#            self.bInhibitRecomputes = True\n#            self.showProps(fp,\"Scale\")\n#        elif prop == \"ShowMeshProps\":\n#            self.bInhibitRecomputes = True\n#            self.showProps(fp,\"Mesh\")\n#        elif prop == \"EditPlacementAdjustments\" and fp.EditPlacementAdjustments == True:\n#            fp.EditPlacementAdjustments = False\n#            t = QtCore.QTimer()\n#            t.singleShot(50, self.showGhosts)\n#        elif bool(\"Placement\" in prop or \"Offset\" in prop or \"Scale\" in prop) and self.editingMode == True:\n#            if not self.positioningGhosts:\n#                self.positioningGhosts = True\n#                self.positionGhosts(fp,prop)\n#                self.positioningGhosts = False\n#\n#    def positionGhosts(self,fp,prop):\n#        ghost = None\n#        if \"TipBase\" in prop:\n#            ghost = FreeCAD.ActiveDocument.getObject(self.tbName)\n#            plm = getattr(fp,\"TipBasePlacement\")\n#            shp = self.getShape(fp,fp.TipBase,fp.UseTipBaseAddSubShape)\n#            shp = self.scale(fp,shp, fp.TipBaseScale, fp.TipBaseScale != 1.0,fp.TipScaleCut)\n#            shp = self.scaleXYZ(fp.TipBaseScaleXYZ,shp,fp.TipScaleCut)\n#            if fp.TipBaseOffset != 0:\n#                shp = self.offset(fp,shp,fp.TipBaseOffset,\"Tip\")\n#        elif \"TipTool\" in prop:\n#            ghost = FreeCAD.ActiveDocument.getObject(self.ttName)\n#            plm = getattr(fp,\"TipToolPlacement\")\n#            shp = self.getShape(fp,fp.TipTool,fp.UseTipToolAddSubShape)\n#            shp = self.scale(fp,shp, fp.TipToolScale, fp.TipToolScale != 1.0,fp.TipScaleCut)\n#            shp = self.scaleXYZ(fp.TipToolScaleXYZ,shp,fp.TipScaleCut)\n#            if fp.TipToolOffset != 0:\n#                shp = self.offset(fp,shp,fp.TipToolOffset,\"Tip\")\n#        elif \"PatternBase\" in prop:\n#            ghost = FreeCAD.ActiveDocument.getObject(self.pbName)\n#            plm = getattr(fp,\"PatternBasePlacement\")\n#            shp = self.getShape(fp,fp.PatternBase,fp.UsePatternBaseAddSubShape)\n#            shp = self.scale(fp,shp, fp.PatternBaseScale, fp.PatternBaseScale != 1.0,fp.PatternScaleCut)\n#            shp = self.scaleXYZ(fp.PatternBaseScaleXYZ,shp,fp.PatternScaleCut)\n#            if fp.PatternBaseOffset != 0:\n#                shp = self.offset(fp,shp,fp.PatternBaseOffset,\"Pattern\")\n#        elif \"PatternTool\" in prop:\n#            ghost = FreeCAD.ActiveDocument.getObject(self.ptName)\n#            plm = getattr(fp,\"PatternToolPlacement\")\n#            shp = self.getShape(fp,fp.PatternTool,fp.UsePatternToolAddSubShape)\n#            shp = self.scale(fp,shp, fp.PatternToolScale, fp.PatternToolScale != 1.0,fp.PatternScaleCut)\n#            shp = self.scaleXYZ(fp.PatternToolScaleXYZ,shp,fp.PatternScaleCut)\n#            if fp.PatternToolOffset != 0:\n#                shp = self.offset(fp,shp,fp.PatternToolOffset,\"Pattern\")\n#        if not ghost or not plm:\n#            return\n#        if shp and not shp.isNull():\n#            shp = shp.transformShape(plm.toMatrix(), True)\n#        else:\n#            shp = Part.Shape()\n#        ghost.Shape = shp\n#        self.recompute()\n#\n#    def exorciseGhosts(self):\n#        '''remove temporary representation of shapes being manipulated'''\n#        ghosts = [self.tbName,self.ttName,self.pbName,self.ptName,self.pgName]\n#        for ghost in ghosts:\n#            FreeCAD.ActiveDocument.removeObject(ghost)\n#        self.recompute()\n#\n#    def summonGhosts(self):\n#        '''builds/rebuilds ghost objects'''\n#        fp = FreeCAD.ActiveDocument.getObject(self.fpName)\n#        pb = self.getShape(fp,fp.PatternBase,fp.UsePatternBaseAddSubShape)\n#        pt = self.getShape(fp,fp.PatternTool,fp.UsePatternToolAddSubShape)\n#        pb_ghost = FreeCAD.ActiveDocument.addObject(\"Part::Feature\",fp.Name+\"_pb_ghost\")\n#        if pb and not pb.isNull():\n#            pb = pb.transformShape(fp.PatternBasePlacement.toMatrix(), True)\n#            pb_ghost.Shape = pb\n#        else:\n#            pb = Part.Shape()\n#        self.pbName = pb_ghost.Name\n#        pt_ghost = FreeCAD.ActiveDocument.addObject(\"Part::Feature\",fp.Name+\"_pt_ghost\")\n#        if pt and not pt.isNull():\n#            pt = pt.transformShape(fp.PatternToolPlacement.toMatrix(), True)\n#            pt_ghost.Shape = pt\n#        self.ptName = pt_ghost.Name\n#        #pattern ghost will hold shape of pattern shape\n#        pg = Part.Shape()\n#        if hasattr(fp,\"AddSubShape\"):\n#            pg = fp.AddSubShape\n#        pg_ghost = FreeCAD.ActiveDocument.addObject(\"Part::Feature\",fp.Name+\"_pg_ghost\")\n#        self.pgName = pg_ghost.Name\n#        pg_ghost.Shape = pg\n#        tb = self.getShape(fp,fp.TipBase,fp.UseTipBaseAddSubShape)\n#        tt = self.getShape(fp,fp.TipTool,fp.UseTipToolAddSubShape)\n#        tb_ghost = FreeCAD.ActiveDocument.addObject(\"Part::Feature\",fp.Name+\"_tb_ghost\")\n#        if tb and not tb.isNull():\n#            tb = tb.transformShape(fp.TipBasePlacement.toMatrix(), True)\n#        else:\n#            tb = Part.Shape()\n#        tb_ghost.Shape = tb\n#        self.tbName = tb_ghost.Name\n#        tt_ghost = FreeCAD.ActiveDocument.addObject(\"Part::Feature\",fp.Name+\"_tt_ghost\")\n#        if tt and not tt.isNull():\n#            tt = tt.transformShape(fp.TipToolPlacement.toMatrix(), True)\n#        else:\n#            tt = Part.Shape()\n#        tt_ghost.Shape = tt\n#        self.ttName = tt_ghost.Name\n#        tb_ghost.ViewObject.Transparency = 85\n#        tb_ghost.ViewObject.ShapeColor = (0.0,0.0,1.0) #blue\n#        tb_ghost.ViewObject.ShowInTree = False\n#        tt_ghost.ViewObject.Transparency = 85\n#        tt_ghost.ViewObject.ShapeColor = (0.0,1.0,1.0) #teal\n#        tt_ghost.ViewObject.ShowInTree = False\n#        pb_ghost.ViewObject.Transparency = 85\n#        pb_ghost.ViewObject.ShapeColor = (1.0,0.0,1.0) #brown\n#        pb_ghost.ViewObject.ShowInTree = False\n#        pt_ghost.ViewObject.Transparency = 85\n#        pt_ghost.ViewObject.ShapeColor = (1.0,1.0,0.0) #orange\n#        pt_ghost.ViewObject.ShowInTree = False\n#        pt_ghost.ViewObject.Visibility = False\n#        pb_ghost.ViewObject.Visibility = False\n#        pg_ghost.ViewObject.Visibility = False\n#        pg_ghost.ViewObject.ShowInTree = False\n#        ghosts = [obj for obj in FreeCAD.ActiveDocument.Objects if \"_ghost\" in obj.Name]\n#        for ghost in ghosts:\n#            ghost.setEditorMode(\"Placement\",1) #readonly  User must not edit this property, but rather the fp property\n#            ghost.addProperty(\"App::PropertyString\",\"GhostlyMessage\",\"Base\",\"Boo\").GhostlyMessage=\"Edit the PDWrapper's Placement Adjustment property, not this Placement.\"\n#            if not ghost in fp._Body.Group:\n#                fp._Body.Group += [ghost]\n#        self.recompute()\n#\n#    def showGhosts(self):\n#        '''show a temporary representation of the object being manipulated'''\n#        fp = FreeCAD.ActiveDocument.getObject(self.fpName)\n#        if not FreeCADGui.Control.activeDialog():\n#            panel = TaskEditPlacementsPanel(fp)\n#            FreeCADGui.Control.showDialog(panel)\n#            self.editingMode = True \n#        else:\n#            self.editingMode=False\n#            FreeCAD.Console.PrintError(\"Another task dialog is active.  Close that one and try again.\\n\")\n#            return\n#        self.summonGhosts()\n#\n#    def showProps(self,fp,propType):\n#        '''propType is \"Offset\" or \"Scale\"'''\n#        if not hasattr(fp,\"Type\"):\n#            return\n#        bShow = getattr(fp,\"Show\"+propType+\"Props\")\n#        props = [p for p in fp.PropertiesList if propType in p and not \"Show\" in p]\n#        if fp.Type == \"None\":\n#            props = [p for p in props if not \"Pattern\" in p]\n#        modeMap = {True:0,False:2}\n#        for prop in props:\n#            fp.setEditorMode(prop,modeMap[bShow])\n#\n#    def resetMeshCache(self,fp):\n#        meshProps = [prop for prop in fp.PropertiesList if \"_from_mesh\" in prop]\n#        for meshProp in meshProps:\n#            setattr(fp,meshProp,Part.Shape()) #null shape\n#\n#    def getShape(self,fp,link,bUseAddSubShape = False):\n#        '''get the shape of link and return it, if mesh, build shape,cache it, and return it'''\n#        body = FreeCAD.ActiveDocument.getObject(fp.Body) #in case user has selected an object outside the body\n#        if link and not link in body.Group:\n#            body.Group += [link]\n#        if hasattr(link,\"Shape\"):\n#            if hasattr(link,\"AddSubShape\") and bUseAddSubShape:\n#                shp = link.AddSubShape.copy() if link.AddSubShape else Part.Shape()\n#            else:\n#                shp = link.Shape.copy() if link.Shape else Part.Shape()\n#            return shp.copy()\n#        elif hasattr(link,\"Mesh\"):\n#            propName = link.Name+\"_from_mesh\"\n#            fp.ShowMeshProps = True\n#            if hasattr(fp,propName) and not getattr(fp,propName).isNull():\n#                return getattr(fp,propName).copy()\n#            else: #cache the shape so we do not have to rebuild on each access\n#                if not hasattr(fp,propName):\n#                    fp.addProperty(\"Part::PropertyPartShape\",propName)\n#                    fp.setEditorMode(propName,2) #hidden\n#                if len(link.Mesh.getSeparateComponents()) > 1:\n#                    FreeCAD.Console.PrintWarning(f\"{link.Label} has multiple components.  In some cases it will be \\\n#necessary to use Mesh Design workbench Split by components first, and then wrap the component meshes individually.\\n\")\n#                mesh_shape = Part.Shape()\n#                mesh_shape.makeShapeFromMesh(link.Mesh.Topology,fp.MeshTolerance)\n#                shells = mesh_shape.Shells\n#                if fp.RefineMesh:\n#                    solids = [Part.makeSolid(shell).removeSplitter() for shell in shells]\n#                else:\n#                    solids = [Part.makeSolid(shell) for shell in shells]\n#                if len(solids) == 1:\n#                    setattr(fp,propName,solids[0])\n#                elif len(solids) == 0:\n#                    setattr(fp,propName,Part.Shape()) #likely to throw exception\n#                else:\n#                    sh = solids[0]\n#                    sh = sh.multiFuse(solids[1:])\n#                    sh = sh.removeSplitter() if fp.RefineMesh else sh\n#                    setattr(fp,propName,sh)\n#                return getattr(fp,propName).copy()\n#\n#    def placeInBody(self,fp,link):\n#        def checkSolids(link):\n#            if hasattr(link,\"Shape\"):\n#                if len(link.Shape.Solids)>1:\n#                    self.warn(fp,link.Name+\" (\"+link.Label+\") has multiple solids.  Subsequent Part Design operations might fail.\\n\")\n#        body = FreeCAD.ActiveDocument.getObject(fp.Body)\n#        if body and not link in body.Group:\n#            body.Group += [link]\n#            checkSolids(link)\n#\n#    def makeAddSubShape(self,fp):\n#        ''' create addsubshape and return as shape\n#            this is shape used in patterning, for example\n#            when creating a polar pattern this is the shape to copy'''\n#        base = fp.PatternBase if fp.PatternBase else None #null shape\n#        base_shape = self.getShape(fp,base,fp.UsePatternBaseAddSubShape)\n#        base_shape = self.scale(fp,base_shape, fp.PatternBaseScale, fp.PatternBaseScale != 1.0,fp.PatternScaleCut)\n#        base_shape = self.scaleXYZ(fp.PatternBaseScaleXYZ, base_shape,fp.PatternScaleCut)\n#        if fp.PatternBaseOffset != 0:\n#            base_shape = self.offset(fp,base_shape,fp.PatternBaseOffset,\"Pattern\")\n#        tool = fp.PatternTool if fp.PatternTool else None\n#        tool_shape = self.getShape(fp,tool,fp.UsePatternToolAddSubShape)\n#        tool_shape = self.scale(fp,tool_shape, fp.PatternToolScale, fp.PatternToolScale != 1.0,fp.PatternScaleCut)\n#        tool_shape = self.scaleXYZ(fp.PatternToolScaleXYZ, tool_shape, fp.PatternScaleCut)\n#        if fp.PatternToolOffset != 0.0:\n#            tool_shape = self.offset(fp,tool_shape,fp.PatternToolOffset,\"Pattern\")\n#        if not fp.PatternBasePlacement.isIdentity() and not base_shape.isNull():\n#            base_shape = base_shape.transformShape(fp.PatternBasePlacement.toMatrix(), True)\n#        if not fp.PatternToolPlacement.isIdentity() and not tool_shape.isNull():\n#            tool_shape = tool_shape.transformShape(fp.PatternToolPlacement.toMatrix(), True)\n#        op = fp.PatternOperation\n#        if not tool:\n#            return base_shape if base else Part.Shape()\n#        if base and tool:\n#            if op == \"None\":\n#                return tool_shape\n#            elif op == \"Cut\": #cut tool from base\n#                return base_shape.cut(tool_shape)\n#            elif op == \"Fuse\": #all bits\n#                return base_shape.fuse(tool_shape)\n#            elif op == \"Common\": #only bits intersecting\n#                return base_shape.common(tool_shape)\n#            elif op == \"XOR\": #only bits not intersecting\n#                fusion = base_shape.fuse(tool_shape)\n#                common = base_shape.common(tool_shape)\n#                return fusion.cut(common)\n#        if tool:\n#            return tool_shape\n#        elif base:\n#            return base_shape\n#        else:\n#            return fp.LinkedObject.Shape\n#\n#    def restoreDefaults(self,fp):\n#        '''used by manageShape() to restore defaults on enable/disable'''\n#        fp.PatternOperation = fp.PatternOperationDefault\n#        fp.TipOperation = fp.TipOperationDefault\n#\n#    def manageShape(self,fp):\n#        '''used for automatic mode shape management'''\n#        fp.Label2 = \"(\"+fp.LinkedObject.Label+\")\"\n#        if not fp.Enabled:\n#            fp.Label2 = \"*\"+fp.Label2+\"*\"\n#        if fp.ShapeManagement == \"Manual\":\n#            return\n#        if fp.LinkedObject.isDerivedFrom(\"PartDesign::Feature\"):\n#            if fp.Type == \"Additive\":\n#                if fp.Enabled:\n#                    fp.TipBase = fp.LinkedObject.BaseFeature\n#                    fp.TipTool = fp.LinkedObject\n#                    fp.UseTipToolAddSubShape = True\n#                    fp.PatternBase = fp.LinkedObject.BaseFeature\n#                    fp.PatternTool = fp.LinkedObject\n#                    fp.UsePatternToolAddSubShape = True\n#                    if fp.LinkedObject != fp.BaseFeature: #user is re-using a feature from earlier in the tree\n#                        fp.TipBase = fp.BaseFeature\n#                        fp.PatternBase = fp.BaseFeature\n#                    self.restoreDefaults(fp)\n#                else:\n#                    fp.TipBase = fp.BaseFeature\n#                    fp.TipTool = fp.BaseFeature\n#                    fp.TipOperation = \"None\"\n#            elif fp.Type == \"Subtractive\":\n#                if fp.Enabled:\n#                    fp.TipBase = fp.LinkedObject.BaseFeature\n#                    fp.TipTool = fp.LinkedObject\n#                    fp.UseTipToolAddSubShape = True\n#                    fp.PatternBase = fp.LinkedObject.BaseFeature\n#                    fp.PatternTool = fp.LinkedObject\n#                    fp.UsePatternToolAddSubShape = True\n#                    if fp.LinkedObject != fp.BaseFeature: #user is re-using a feature from earlier in the tree\n#                        fp.TipBase = fp.BaseFeature\n#                        fp.PatternBase = fp.BaseFeature\n#                    self.restoreDefaults(fp)\n#                elif not fp.Enabled:\n#                    fp.TipBase = fp.BaseFeature\n#                    fp.TipTool = fp.BaseFeature\n#                    fp.TipOperation = \"None\"\n#            elif fp.Type == \"None\":\n#                if fp.Enabled:\n#                    fp.TipBase = fp.LinkedObject.BaseFeature\n#                    fp.TipTool = fp.LinkedObject.BaseFeature\n#                elif not fp.Enabled:\n#                    fp.TipTool = fp.BaseFeature\n#                    fp.TipBase = fp.BaseFeature\n#\n#        else: #not a PD object\n#            if fp.Type == \"Additive\":\n#                fp.TipBase = fp.BaseFeature\n#                fp.TipTool = fp.LinkedObject\n#            elif fp.Type == \"Subtractive\":\n#                fp.TipBase = fp.BaseFeature\n#                fp.TipTool = fp.LinkedObject\n#            elif fp.Type == \"None\":\n#                fp.TipBase = fp.BaseFeature\n#                fp.TipTool = fp.BaseFeature\n#            if not fp.Enabled:\n#                fp.TipBase = fp.BaseFeature\n#                fp.TipTool = fp.BaseFeature\n#                fp.TipOperation = \"None\"\n#                fp.PatternBase = fp.BaseFeature\n#                fp.PatternTool = fp.BaseFeature\n#                fp.PatternOperation = \"None\"\n#            else:\n#                self.restoreDefaults(fp)\n#\n#    def makeTipShape(self,fp):\n#        shape = Part.Shape()\n#        base_shape = self.getShape(fp,fp.TipBase,fp.UseTipBaseAddSubShape)\n#        base_shape = self.scale(fp,base_shape, fp.TipBaseScale, fp.TipBaseScale != 1.0,fp.TipScaleCut)\n#        base_shape = self.scaleXYZ(fp.TipBaseScaleXYZ, base_shape, fp.TipScaleCut)\n#        tool_shape = self.getShape(fp,fp.TipTool,fp.UseTipToolAddSubShape)\n#        tool_shape = self.scale(fp,tool_shape, fp.TipToolScale, fp.TipToolScale != 1.0,fp.TipScaleCut)\n#        tool_shape = self.scaleXYZ(fp.TipToolScaleXYZ, tool_shape, fp.TipScaleCut)\n#        if base_shape and not fp.TipBasePlacement.isIdentity() and not base_shape.isNull():\n#            base_shape = base_shape.transformShape(fp.TipBasePlacement.toMatrix(), True)\n#        if tool_shape and not fp.TipToolPlacement.isIdentity() and not tool_shape.isNull():\n#            tool_shape = tool_shape.transformShape(fp.TipToolPlacement.toMatrix(), True)\n#        if not tool_shape:\n#            tool_shape = Part.Shape()\n#        if not base_shape:\n#            base_shape = Part.Shape()\n#        if fp.TipToolOffset != 0:\n#            tool_shape = self.offset(fp,tool_shape,fp.TipToolOffset,\"Tip\")\n#        if fp.TipBaseOffset != 0:\n#            base_shape = self.offset(fp,base_shape,fp.TipBaseOffset,\"Tip\")\n#        if fp.TipTool and fp.TipBase:\n#            op = fp.TipOperation\n#            if op == \"Cut\":\n#                cut = base_shape.cut(tool_shape)\n#                shape = cut\n#            elif op == \"Fuse\":\n#                fuse = base_shape.fuse(tool_shape)\n#                shape = fuse\n#            elif op == \"Common\":\n#                common = base_shape.common(tool_shape)\n#                shape = common\n#            elif op == \"XOR\":\n#                fusion = base_shape.fuse(tool_shape)\n#                common = base_shape.common(tool_shape)\n#                cut = fusion.cut(common)\n#                shape = cut\n#            elif op == \"None\":\n#                shape = base_shape\n#        elif fp.TipBase:\n#            shape = base_shape\n#        elif fp.TipTool:\n#            shape = tool_shape\n#        return shape\n#\n#    def execute(self,fp):\n#        if self.bInhibitRecomputes:\n#            self.bInhibitRecomputes = False\n#            return\n#        self.manageShape(fp)\n#        if hasattr(fp,\"Refine1\"):\n#            fp.removeProperty(\"Refine1\") #PD features might already have a Refine feature, but None types will not\n#        if fp.LinkedObject:\n#            self.placeInBody(fp,fp.LinkedObject)\n#\n#        shape = self.makeTipShape(fp)\n#\n#        if fp.TipShapeOffset != 0 and fp.Enabled:\n#            offset = self.offset(fp,shape,fp.TipShapeOffset,\"Tip\")\n#            shape = offset\n#\n#        if not fp.Shape.isNull() and fp.Refine and fp.Enabled:\n#            refined = shape.removeSplitter()\n#            shape = refined\n#\n#        scaled = self.scale(fp,shape,fp.TipShapeScale,bool(fp.Enabled and fp.TipShapeScale != 1.0),fp.TipScaleCut)\n#        scaled = self.scaleXYZ(fp.TipShapeScaleXYZ, scaled, fp.TipScaleCut)\n#        shape = scaled\n#\n#        if not \"None\" in fp.Type:\n#            addsubshape = self.makeAddSubShape(fp)\n#            addSubShape = addsubshape if not fp.Refine else addsubshape.removeSplitter()\n#            addSubShape = self.scale(fp,addSubShape,fp.PatternShapeScale,fp.PatternShapeScale != 1.0,fp.PatternScaleCut)\n#            addSubShape = self.scaleXYZ(fp.PatternShapeScaleXYZ, addSubShape, fp.PatternScaleCut)\n#            if fp.PatternShapeOffset != 0:\n#                addSubShape = self.offset(fp,fp.AddSubShape,fp.PatternShapeOffset,\"Pattern\")\n#            fp.AddSubShape = addsubshape\n#\n#        if len(fp.Shape.Solids)>1:\n#            self.warn(fp,\"PDWrapper shape has multiple solids.  This could cause subsequent operations to fail or produce unexpected results.\\n\")\n#        if not shape.isNull():\n#            shape.transformShape(shape.Placement.toMatrix(), True)\n#        fp.Shape = shape\n#\n#    def debug(self,msg):\n#        if not DEBUG:\n#            return\n#        FreeCAD.Console.PrintMessage(msg+\"\\n\")\n#\n#    def offset(self,fp,shp,factor,tipOrPattern):\n#        '''shp is shape to offset, tipOrPattern is a string = \"Pattern\" or \"Tip\", returns offset shape\n#           if bCut = True, the shp is cut from the offset or vice versa if offset < 0'''\n#        if shp == None or shp.isNull():\n#            return shp\n#        if tipOrPattern == \"Pattern\":\n#            if factor == 0:\n#                return shp\n#            psoTol = 1e-7\n#            psoMode = 0 if fp.PatternOffsetMode == \"Skin\" else 1 if fp.PatternOffsetMode == \"Pipe\" else 2 if fp.PatternOffsetMode == \"Recto-verso\" else -1\n#            psoJoin = 0 if fp.PatternOffsetJoin == \"Arcs\" else 1 if fp.PatternOffsetJoin == \"Tangent\" else 2 if fp.PatternOffsetMode == \"Intersection\" else -1\n#            psoFill = False\n#            if hasattr(fp,\"PatternOffsetIntersection\"):\n#                psoInter = fp.PatternOffsetIntersection\n#            else:\n#                psoInter = False\n#            if hasattr(fp,\"PatternOffsetSelfIntersection\"):\n#                psoSelfInter = fp.PatternOffsetSelfIntersection\n#            else:\n#                psoSelfInter = False\n#            offsetShp = shp.makeOffsetShape(factor,tolerance=psoTol,offsetMode = psoMode, join = psoJoin, fill = psoFill, inter = psoInter, self_inter = psoSelfInter)\n#            if fp.PatternOffsetCut:\n#                if factor < 0:\n#                    return shp.cut(offsetShp)\n#                else:\n#                    return offsetShp.cut(shp)\n#            else:\n#                return offsetShp\n#        elif tipOrPattern == \"Tip\":\n#            if factor == 0:\n#                return shp\n#            tsoTol = 1e-7\n#            tsoMode = 0 if fp.TipOffsetMode == \"Skin\" else 1 if fp.TipOffsetMode == \"Pipe\" else 2 if fp.TipOffsetMode == \"Recto-verso\" else -1\n#            tsoJoin = 0 if fp.TipOffsetJoin == \"Arcs\" else 1 if fp.TipOffsetJoin == \"Tangent\" else 2 if fp.TipOffsetMode == \"Intersection\" else -1\n#            tsoFill = False\n#            if hasattr(fp,\"TipOffsetIntersection\"):\n#                tsoInter = fp.TipOffsetIntersection\n#            else:\n#                tsoInter = False\n#            if hasattr(fp,\"TipOffsetSelfIntersection\"):\n#                tsoSelfInter = fp.TipOffsetSelfIntersection\n#            else:\n#                tsoSelfInter = False\n#            offsetShp = shp.makeOffsetShape(factor,tolerance=tsoTol,offsetMode = tsoMode, join = tsoJoin, fill = tsoFill, inter = tsoInter, self_inter = tsoSelfInter)\n#            if fp.TipOffsetCut:\n#                if factor < 0:\n#                    return shp.cut(offsetShp)\n#                else:\n#                    return offsetShp.cut(shp)\n#            else:\n#                return offsetShp\n#\n##    #borrowed from Draft.Clone scaling code\n#    def scaleXYZ(self,scale,shp,bCut):\n#        if shp:\n#            orig = shp.copy()\n#        m = FreeCAD.Matrix()\n#        if shp and not shp.isNull():\n#            sx,sy,sz = scale\n#            if not scale.isEqual(FreeCAD.Vector(1, 1, 1),1e-7):\n#                op = shp.Placement\n#                shp.Placement = FreeCAD.Placement()\n#                m.scale(scale)\n#                if sx == sy == sz:\n#                    shp.transformShape(m)\n#                else:\n#                    shp = shp.transformGeometry(m)\n#                shp.Placement = op\n#                if bCut:\n#                    if orig.Volume > shp.Volume:\n#                        shp = orig.cut(shp)\n#                    elif shp.Volume > orig.Volume:\n#                        shp = shp.cut(orig)\n#                    else:\n#                        FreeCAD.Console.PrintWarning(\"Unable to determine direction of cut.\\n\")\n#        return shp\n#\n#    def scale(self,fp,shp,factor,bScale,bCut):\n#        '''scale and return shp scaled if bScale = true'''\n#        if not shp or shp.isNull():\n#            return shp\n#        if bScale:\n#            scaleds = [sol.scale(factor,sol.CenterOfMass) for sol in shp.Solids]\n#            if not bCut:\n#                return Part.makeCompound(scaleds)\n#            else: #bCut\n#                unscaleds = [sol for sol in shp.Solids]\n#                cuts = []\n#                for ii in range(0,len(shp.Solids)):\n#                    if factor > 1:\n#                        cuts.append(scaleds[ii].cut(unscaleds[ii]))\n#                    else:\n#                        cuts.append(unscaleds[ii].cut(scaleds[ii]))\n#                return Part.makeCompound(cuts)\n#        else:\n#            return shp\n#\n#    def warn(self,fp,msg):\n#        if fp.ShowWarnings:\n#            FreeCAD.Console.PrintWarning(msg)\n#            FreeCAD.Console.PrintMessage(\"PDWrapper warnings may be suppressed with the ShowWarnings property set to false\\n\")\n#\n#class TaskEditPlacementsPanel: #simple editor for placement adjustments\n#    def __init__(self, fp):\n#        FreeCADGui.Selection.clearSelection()\n#        self.blockSignals = True\n#        self.fp = fp\n#        self.form = QtGui.QWidget()\n#        self.label1 = QtGui.QLabel(\\\n#\"Select which ghosts to show, then edit their\\n\\\n#placement adjustment properties here.\\n\")\n#        layout=QtGui.QVBoxLayout()\n#        layout.addWidget(self.label1)\n#\n#        self.tbCheckBox = QtGui.QCheckBox(\"tip base\")\n#        self.tbCheckBox.setChecked(True)\n#        self.tbCheckBox.stateChanged.connect(self.showTipBase)\n#        self.tbCheckBox.setStyleSheet('QCheckBox {background-color: #A0A0FF;}')\n#        layout.addWidget(self.tbCheckBox)\n#\n#        self.ttCheckBox = QtGui.QCheckBox(\"tip tool\")\n#        self.ttCheckBox.setChecked(True)\n#        self.ttCheckBox.stateChanged.connect(self.showTipTool)\n#        self.ttCheckBox.setStyleSheet('QCheckBox {background-color: #A0FFFF;}')\n#        layout.addWidget(self.ttCheckBox)\n#\n#        self.fpCheckBox = QtGui.QCheckBox(\"tip shape\")\n#        self.fpCheckBox.setChecked(True)\n#        self.fpCheckBox.stateChanged.connect(self.showFp)\n#        layout.addWidget(self.fpCheckBox)\n#\n#        self.pbCheckBox = QtGui.QCheckBox(\"pattern base\")\n#        self.pbCheckBox.setChecked(False)\n#        self.pbCheckBox.stateChanged.connect(self.showPatternBase)\n#        self.pbCheckBox.setStyleSheet('QCheckBox {background-color: #FFA0FF;}')\n#        layout.addWidget(self.pbCheckBox)\n#\n#        self.ptCheckBox = QtGui.QCheckBox(\"pattern tool\")\n#        self.ptCheckBox.setChecked(False)\n#        self.ptCheckBox.stateChanged.connect(self.showPatternTool)\n#        self.ptCheckBox.setStyleSheet('QCheckBox {background-color: #FFFFA0;}')\n#        layout.addWidget(self.ptCheckBox)\n#\n#        self.pgCheckBox = QtGui.QCheckBox(\"pattern shape\")\n#        self.pgCheckBox.setChecked(False)\n#        self.pgCheckBox.stateChanged.connect(self.showPg)\n#        layout.addWidget(self.pgCheckBox)\n#\n#        self.tb_pos_x = QtGui.QDoubleSpinBox()\n#        self.tb_pos_y = QtGui.QDoubleSpinBox()\n#        self.tb_pos_z = QtGui.QDoubleSpinBox()\n#        self.tb_yaw = QtGui.QDoubleSpinBox()\n#        self.tb_roll = QtGui.QDoubleSpinBox()\n#        self.tb_pitch = QtGui.QDoubleSpinBox()\n#        layout.addLayout(self.makeSpinBox(\"tip base position x\",self.tb_pos_x,color=\"#A0A0FF\",default=getattr(self.fp,\"TipBasePlacement\").Base.x))\n#        layout.addLayout(self.makeSpinBox(\"tip base position y\",self.tb_pos_y,color=\"#A0A0FF\",default=getattr(self.fp,\"TipBasePlacement\").Base.y))\n#        layout.addLayout(self.makeSpinBox(\"tip base position z\",self.tb_pos_z,color=\"#A0A0FF\",default=getattr(self.fp,\"TipBasePlacement\").Base.z))\n#        layout.addLayout(self.makeSpinBox(\"tip base yaw\",self.tb_yaw,color=\"#A0A0FF\",default=getattr(self.fp,\"TipBasePlacement\").Rotation.toEuler()[0],min=-360,max=360))\n#        layout.addLayout(self.makeSpinBox(\"tip base pitch\",self.tb_pitch,color=\"#A0A0FF\",default=getattr(self.fp,\"TipBasePlacement\").Rotation.toEuler()[1],min=-360,max=360))\n#        layout.addLayout(self.makeSpinBox(\"tip base roll\",self.tb_roll,color=\"#A0A0FF\",default=getattr(self.fp,\"TipBasePlacement\").Rotation.toEuler()[2],min=-360,max=360))\n#\n#        self.tt_pos_x = QtGui.QDoubleSpinBox()\n#        self.tt_pos_y = QtGui.QDoubleSpinBox()\n#        self.tt_pos_z = QtGui.QDoubleSpinBox()\n#        self.tt_yaw = QtGui.QDoubleSpinBox()\n#        self.tt_roll = QtGui.QDoubleSpinBox()\n#        self.tt_pitch = QtGui.QDoubleSpinBox()\n#        layout.addLayout(self.makeSpinBox(\"tip tool position x\",self.tt_pos_x,color=\"#A0FFFF\",default=getattr(self.fp,\"TipToolPlacement\").Base.x))\n#        layout.addLayout(self.makeSpinBox(\"tip tool position y\",self.tt_pos_y,color=\"#A0FFFF\",default=getattr(self.fp,\"TipToolPlacement\").Base.y))\n#        layout.addLayout(self.makeSpinBox(\"tip tool position z\",self.tt_pos_z,color=\"#A0FFFF\",default=getattr(self.fp,\"TipToolPlacement\").Base.z))\n#        layout.addLayout(self.makeSpinBox(\"tip tool yaw\",self.tt_yaw,color=\"#A0FFFF\",default=getattr(self.fp,\"TipToolPlacement\").Rotation.toEuler()[0],min=-360,max=360))\n#        layout.addLayout(self.makeSpinBox(\"tip tool pitch\",self.tt_pitch,color=\"#A0FFFF\",default=getattr(self.fp,\"TipToolPlacement\").Rotation.toEuler()[1],min=-360,max=360))\n#        layout.addLayout(self.makeSpinBox(\"tip tool roll\",self.tt_roll,color=\"#A0FFFF\",default=getattr(self.fp,\"TipToolPlacement\").Rotation.toEuler()[2],min=-360,max=360))\n#\n#        self.pb_pos_x = QtGui.QDoubleSpinBox()\n#        self.pb_pos_y = QtGui.QDoubleSpinBox()\n#        self.pb_pos_z = QtGui.QDoubleSpinBox()\n#        self.pb_yaw = QtGui.QDoubleSpinBox()\n#        self.pb_roll = QtGui.QDoubleSpinBox()\n#        self.pb_pitch = QtGui.QDoubleSpinBox()\n#        layout.addLayout(self.makeSpinBox(\"pattern base position x\",self.pb_pos_x,color=\"#FFA0FF\",default=getattr(self.fp,\"PatternBasePlacement\").Base.x))\n#        layout.addLayout(self.makeSpinBox(\"pattern base position y\",self.pb_pos_y,color=\"#FFA0FF\",default=getattr(self.fp,\"PatternBasePlacement\").Base.y))\n#        layout.addLayout(self.makeSpinBox(\"pattern base position z\",self.pb_pos_z,color=\"#FFA0FF\",default=getattr(self.fp,\"PatternBasePlacement\").Base.z))\n#        layout.addLayout(self.makeSpinBox(\"pattern base yaw\",self.pb_yaw,color=\"#FFA0FF\",default=getattr(self.fp,\"PatternBasePlacement\").Rotation.toEuler()[0],min=-360,max=360))\n#        layout.addLayout(self.makeSpinBox(\"pattern base pitch\",self.pb_pitch,color=\"#FFA0FF\",default=getattr(self.fp,\"PatternBasePlacement\").Rotation.toEuler()[1],min=-360,max=360))\n#        layout.addLayout(self.makeSpinBox(\"pattern base roll\",self.pb_roll,color=\"#FFA0FF\",default=getattr(self.fp,\"PatternBasePlacement\").Rotation.toEuler()[2],min=-360,max=360))\n#\n#        self.pt_pos_x = QtGui.QDoubleSpinBox()\n#        self.pt_pos_y = QtGui.QDoubleSpinBox()\n#        self.pt_pos_z = QtGui.QDoubleSpinBox()\n#        self.pt_yaw = QtGui.QDoubleSpinBox()\n#        self.pt_roll = QtGui.QDoubleSpinBox()\n#        self.pt_pitch = QtGui.QDoubleSpinBox()\n#        layout.addLayout(self.makeSpinBox(\"pattern tool position x\",self.pt_pos_x,color=\"#FFFFA0\",default=getattr(self.fp,\"PatternToolPlacement\").Base.x))\n#        layout.addLayout(self.makeSpinBox(\"pattern tool position y\",self.pt_pos_y,color=\"#FFFFA0\",default=getattr(self.fp,\"PatternToolPlacement\").Base.y))\n#        layout.addLayout(self.makeSpinBox(\"pattern tool position z\",self.pt_pos_z,color=\"#FFFFA0\",default=getattr(self.fp,\"PatternToolPlacement\").Base.z))\n#        layout.addLayout(self.makeSpinBox(\"pattern tool yaw\",self.pt_yaw,color=\"#FFFFA0\",default=getattr(self.fp,\"PatternToolPlacement\").Rotation.toEuler()[0],min=-360,max=360))\n#        layout.addLayout(self.makeSpinBox(\"pattern tool pitch\",self.pt_pitch,color=\"#FFFFA0\",default=getattr(self.fp,\"PatternToolPlacement\").Rotation.toEuler()[1],min=-360,max=360))\n#        layout.addLayout(self.makeSpinBox(\"pattern tool roll\",self.pt_roll,color=\"#FFFFA0\",default=getattr(self.fp,\"PatternToolPlacement\").Rotation.toEuler()[2],min=-360,max=360))\n#\n#        self.form.setLayout(layout)\n#        self.form.setWindowTitle('Edit Placement Adjustments')\n#        self.fp.Proxy.editingMode = True\n#        self.initialPlacements = {} #save current ghost placements to restore on cancel/reject\n#        plms = [prop for prop in self.fp.PropertiesList if \"Placement\" in prop and not \"Edit\" in prop]\n#        for plm in plms:\n#            self.fp.setEditorMode(plm,1) #readonly mode while editor is open else editor values won't be updated\n#            self.initialPlacements[plm] = getattr(self.fp,plm)\n#        self.blockSignals = False\n#\n#    def valueChanged(self, val):\n#        if hasattr(self,\"blockSignals\") and self.blockSignals:\n#            return\n#        plm = FreeCAD.Placement()\n#        plm.Base.x = self.tb_pos_x.value()\n#        plm.Base.y = self.tb_pos_y.value()\n#        plm.Base.z = self.tb_pos_z.value()\n#        plm.Rotation = FreeCAD.Rotation(self.tb_yaw.value(),self.tb_pitch.value(),self.tb_roll.value())\n#        setattr(self.fp,\"TipBasePlacement\",plm)\n#        plm.Base.x = self.tt_pos_x.value()\n#        plm.Base.y = self.tt_pos_y.value()\n#        plm.Base.z = self.tt_pos_z.value()\n#        plm.Rotation = FreeCAD.Rotation(self.tt_yaw.value(),self.tt_pitch.value(),self.tt_roll.value())\n#        setattr(self.fp,\"TipToolPlacement\",plm)\n#        plm.Base.x = self.pb_pos_x.value()\n#        plm.Base.y = self.pb_pos_y.value()\n#        plm.Base.z = self.pb_pos_z.value()\n#        plm.Rotation = FreeCAD.Rotation(self.pb_yaw.value(),self.pb_pitch.value(),self.pb_roll.value())\n#        setattr(self.fp,\"PatternBasePlacement\",plm)\n#        plm.Base.x = self.pt_pos_x.value()\n#        plm.Base.y = self.pt_pos_y.value()\n#        plm.Base.z = self.pt_pos_z.value()\n#        plm.Rotation = FreeCAD.Rotation(self.pt_yaw.value(),self.pt_pitch.value(),self.pt_roll.value())\n#        setattr(self.fp,\"PatternToolPlacement\",plm)\n#\n#    def makeSpinBox(self,lbl,spinbox,color=\"default\",default=0,min=-float(\"inf\"),max=float(\"inf\")):\n#        '''makes a hbox layout adds the label and the spinbox, returns the layout'''\n#        decimals = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Units\").GetInt(\"Decimals\",2)\n#        vbox = QtGui.QHBoxLayout()\n#        label = QtGui.QLabel(lbl)\n#        if color != \"default\":\n#            label.setStyleSheet('QLabel {background-color: %1;}'.replace('%1',color))\n#        vbox.addWidget(label,0)\n#        spinbox.setValue(default)\n#        spinbox.setMinimum(min)\n#        spinbox.setDecimals(decimals)\n#        spinbox.setMaximum(max)\n#        spinbox.valueChanged.connect(self.valueChanged)\n#        vbox.addWidget(spinbox,1)\n#        return vbox\n#\n#    def showFp(self):\n#        self.fp.ViewObject.Visibility = self.fpCheckBox.isChecked()\n#\n#    def showPg(self):\n#        ghost = FreeCAD.ActiveDocument.getObject(self.fp.Proxy.pgName)\n#        ghost.ViewObject.Visibility = self.pgCheckBox.isChecked()\n#\n#    def showTipBase(self):\n#        ghost = FreeCAD.ActiveDocument.getObject(self.fp.Proxy.tbName)\n#        ghost.ViewObject.Visibility = self.tbCheckBox.isChecked()\n#\n#    def showTipTool(self):\n#        ghost = FreeCAD.ActiveDocument.getObject(self.fp.Proxy.ttName)\n#        ghost.ViewObject.Visibility = self.ttCheckBox.isChecked()\n#\n#    def showPatternBase(self):\n#        ghost = FreeCAD.ActiveDocument.getObject(self.fp.Proxy.pbName)\n#        ghost.ViewObject.Visibility = self.pbCheckBox.isChecked()\n#\n#    def showPatternTool(self):\n#        ghost = FreeCAD.ActiveDocument.getObject(self.fp.Proxy.ptName)\n#        ghost.ViewObject.Visibility = self.ptCheckBox.isChecked()\n#\n#    def reject(self):\n#        FreeCADGui.Control.closeDialog()\n#        self.fp.Proxy.editingMode = False #self.fp.Proxy is the Bevel class object (self in that class)\n#        plms = [prop for prop in self.fp.PropertiesList if \"Placement\" in prop and not \"Edit\" in prop]\n#        for plm in plms:\n#            self.fp.setEditorMode(plm,0) #normal mode when not editing\n#            setattr(self.fp,plm,self.initialPlacements[plm])\n#        FreeCADGui.activeDocument().resetEdit()\n#        self.fp.Proxy.exorciseGhosts()\n#        self.fp.ViewObject.Visibility = True\n#        FreeCAD.ActiveDocument.recompute()\n#\n#    def accept(self):\n#        FreeCADGui.ActiveDocument.resetEdit()\n#        FreeCADGui.Control.closeDialog()\n#        if not self.fp: #user deleted or closed document perhaps\n#            return\n#        self.fp.Proxy.exorciseGhosts()\n#        if hasattr(self.fp.Proxy,\"editingMode\"):\n#            self.fp.Proxy.editingMode = False\n#        plms = [prop for prop in self.fp.PropertiesList if \"Placement\" in prop and not \"Edit\" in prop]\n#        for plm in plms:\n#            self.fp.setEditorMode(plm,0) #normal mode when not editing\n#        self.fp.ViewObject.Visibility = True\n#        FreeCAD.ActiveDocument.recompute()\n#\n#    def getStandardButtons(self):\n#        return int(QtGui.QDialogButtonBox.Ok) | int(QtGui.QDialogButtonBox.Cancel) | int(QtGui.QDialogButtonBox.Reset)\n#\n#    def clicked(self, button):\n#        if button == QtGui.QDialogButtonBox.Reset:\n#            plm = FreeCAD.Placement()\n#            setattr(self.fp,\"TipBasePlacement\",plm)\n#            setattr(self.fp,\"TipToolPlacement\",plm)\n#            setattr(self.fp,\"PatternBasePlacement\",plm)\n#            setattr(self.fp,\"PatternToolPlacement\",plm)\n#            children = self.form.findChildren(QtGui.QDoubleSpinBox)\n#            for child in children:\n#                child.setValue(0)\n#\n#class PDWrapperVP:\n#\n#    def __init__(self, obj):\n#        '''Set this object to the proxy object of the actual view provider'''\n#        obj.Proxy = self\n#\n#    def attach(self, obj):\n#        '''Setup the scene sub-graph of the view provider, this method is mandatory'''\n#        self.Object = obj.Object\n#\n#    def updateData(self, fp, prop):\n#        '''If a property of the handled feature has changed we have the chance to handle this here'''\n#        # fp is the handled feature, prop is the name of the property that has changed\n#        pass\n#\n#    def getDisplayModes(self,obj):\n#        '''Return a list of display modes.'''\n#        modes=[]\n#        modes.append(\"Flat Lines\")\n#        return modes\n#\n#    def getDefaultDisplayMode(self):\n#        '''Return the name of the default display mode. It must be defined in getDisplayModes.'''\n#        return \"Flat Lines\"\n#\n#    def setDisplayMode(self,mode):\n#        '''Map the display mode defined in attach with those defined in getDisplayModes.\\\n#                Since they have the same names nothing needs to be done. This method is optional'''\n#        return mode\n#\n#    def onChanged(self, vp, prop):\n#        '''Here we can do something when a single property got changed'''\n#        #FreeCAD.Console.PrintMessage(\"Change property: \" + str(prop) + \"\"+chr(10))\n#\n#    def claimChildren(self):\n#        if hasattr(self.Object,\"LinkedObject\") and hasattr(self.Object,\"ClaimChildren\") and self.Object.LinkedObject and self.Object.ClaimChildren:\n#            return [self.Object.LinkedObject]\n#        else:\n#            return []\n#\n#    def setupContextMenu(self, vobj, menu):\n#        text = {True:\"Disable %1\",False:\"Enable %1\"}\n#        action = menu.addAction(text[vobj.Object.Enabled].replace(\"%1\",vobj.Object.Label))\n#        action.triggered.connect(lambda: self.setEdit(vobj,0))\n#        if vobj.Object.Proxy.editingMode == False:\n#            text = \"Edit Placement Adjustments\"\n#            mode = 5\n#        else:\n#            text = \"Accept Placement Adjustments\"\n#            mode = 6\n#        action = menu.addAction(text)\n#        action.triggered.connect(lambda: self.setEdit(vobj,mode))\n#\n#    def setEdit(self,vp,modNum):\n#        if modNum == 0:\n#            vp.Object.Enabled = 0 if vp.Object.Enabled else 1\n#            vp.Document.resetEdit()\n#            FreeCAD.ActiveDocument.recompute()\n#        elif modNum == 3:\n#            FreeCADGui.runCommand('Part_ColorPerFace',0)\n#        elif modNum == 5: #begin edit more\n#            vp.Object.Proxy.showGhosts()\n#        elif modNum == 6: #accept changes and end edit mode\n#            vp.Object.Proxy.editingMode = False\n#            vp.Object.Proxy.exorciseGhosts()\n#            FreeCADGui.Control.closeDialog()\n#            plms = [prop for prop in vp.Object.PropertiesList if \"Placement\" in prop and not \"Edit\" in prop]\n#            for plm in plms:\n#               vp.Object.setEditorMode(plm,0) #normal mode when not editing\n#        return False\n#\n#    def onDelete(self, vobj, subelements):\n#        #only remove children from the body if they are claimed and not native PD objects\n#        doc = FreeCAD.ActiveDocument\n#        body = doc.getObject(vobj.Object.Body)\n#        if vobj.Object.LinkedObject and vobj.Object.ClaimChildren:\n#            if vobj.Object.LinkedObject in body.Group:\n#                grp = body.Group\n#                if not vobj.Object.LinkedObject.isDerivedFrom(\"PartDesign::Feature\") \\\n#                and not vobj.Object.LinkedObject.isDerivedFrom(\"Part::Part2DObject\") \\\n#                and not vobj.Object.LinkedObject.isDerivedFrom(\"PartDesign::ShapeBinder\"):\n#                    grp.remove(vobj.Object.LinkedObject)\n#                    body.Group = grp\n#                    vobj.Object.LinkedObject.ViewObject.Visibility = True\n#        #need to ensure the next feature in the tree's BaseFeature property points to our BaseFeature\n#        solids = [feat for feat in body.Group if feat.isDerivedFrom(\"PartDesign::Feature\") and feat.BaseFeature == vobj.Object]\n#        if len(solids) == 1: #found it\n#            solids[0].BaseFeature = vobj.Object.BaseFeature\n#        #need also to set the tip to our object's base feature if our object is the current tip\n#        if hasattr(vobj.Object,\"_Body\") and vobj.Object._Body.Tip == vobj.Object and vobj.Object.BaseFeature:\n#            vobj.Object._Body.Tip = vobj.Object.BaseFeature\n#            vobj.Object.BaseFeature.ViewObject.Visibility = True\n#        if vobj.Object.Proxy.editingMode:\n#            vobj.Object.Proxy.exorciseGhosts()\n#            FreeCADGui.Control.closeDialog()\n#        return True\n#\n#    def getIcon(self):\n#        '''Return the icon in XPM format which will appear in the tree view. This method is\\\n#                optional and if not defined a default icon is shown.'''\n#        XPM = '''\n#/* XPM */\n#static char *_632945370954[] = {\n#/* columns rows colors chars-per-pixel */\n#\"64 64 188 2 \",\n#\"   c #0EB917171E1E\",\n#\".  c #1B1B1F1F1212\",\n#\"X  c #13131A1A1B1B\",\n#\"o  c #299026C00639\",\n#\"O  c #2BAC29290505\",\n#\"+  c #292929290C0C\",\n#\"@  c none\",\n#\"#  c #32322F2F0889\",\n#\"$  c #360330750146\",\n#\"%  c #3D3D36E10303\",\n#\"&  c #347431310A0A\",\n#\"*  c #39A735350B9E\",\n#\"=  c #2F2F33331C1C\",\n#\"-  c #34013400137A\",\n#\";  c #3C9138381212\",\n#\":  c #0B2915482158\",\n#\">  c #0E78191524B4\",\n#\",  c #0E8F199A28A9\",\n#\"<  c #11111A3E2492\",\n#\"1  c #14541D5D28E8\",\n#\"2  c #0E8F1C9D3131\",\n#\"3  c #131320202F2F\",\n#\"4  c #146A22A33207\",\n#\"5  c #1ADA26663474\",\n#\"6  c #191927273838\",\n#\"7  c #19C427FD38E3\",\n#\"8  c #36E13BE62379\",\n#\"9  c #3A803D9A2274\",\n#\"0  c #23232BEB3676\",\n#\"q  c #2E2E39393131\",\n#\"w  c #2C5734093DBD\",\n#\"e  c #31313B3B3939\",\n#\"r  c #47473D3D0000\",\n#\"t  c #393943433636\",\n#\"y  c #4B6B42420000\",\n#\"u  c #4F4F47470808\",\n#\"i  c #53994BE30DD4\",\n#\"p  c #64E559DA0000\",\n#\"a  c #68685F5F1313\",\n#\"s  c #6C6C62E31798\",\n#\"d  c #51514D4D2929\",\n#\"f  c #547E50502BEC\",\n#\"g  c #595855543288\",\n#\"h  c #5D5D5A5A3838\",\n#\"j  c #19592DEE4787\",\n#\"k  c #18582E6E4ACB\",\n#\"l  c #196F30DB4DA3\",\n#\"z  c #1B1B38385D5D\",\n#\"x  c #212131B24545\",\n#\"c  c #2F2F38384242\",\n#\"v  c #31B13A3A43C3\",\n#\"b  c #26663BBC5393\",\n#\"n  c #1E1E3F3F6868\",\n#\"m  c #393946C7499F\",\n#\"M  c #2D2D44045D5D\",\n#\"N  c #277D43EE65BB\",\n#\"B  c #33334F4F6464\",\n#\"V  c #32DD4DF86CC2\",\n#\"C  c #3B3B54D56A6A\",\n#\"Z  c #232348487878\",\n#\"A  c #3B7B55D672F3\",\n#\"S  c #3D3D58587575\",\n#\"D  c #368C58587D27\",\n#\"F  c #403F46C64E4E\",\n#\"G  c #44C44C0B5454\",\n#\"H  c #49494ECE5656\",\n#\"J  c #4BA052515AAF\",\n#\"K  c #51D257575D5D\",\n#\"L  c #696965654646\",\n#\"P  c #6F6F6B6B4D4D\",\n#\"I  c #7B7B78785C5C\",\n#\"U  c #54FF5B046262\",\n#\"Y  c #58575C5B6161\",\n#\"T  c #41415B5B7373\",\n#\"R  c #59D964246A2A\",\n#\"E  c #434361617979\",\n#\"W  c #63E468E86EEE\",\n#\"Q  c #64646A697272\",\n#\"!  c #6DC371717620\",\n#\"~  c #6D6D73737A7A\",\n#\"^  c #70F074747939\",\n#\"/  c #B69994BF0000\",\n#\"(  c #B8B897970000\",\n#\")  c #C5C5A1A10000\",\n#\"_  c #CC5CB6250000\",\n#\"`  c #CDE4B8CF0000\",\n#\"'  c #D3D3BDBD0101\",\n#\"]  c #DD5DC6460101\",\n#\"[  c #E0EFC3D20000\",\n#\"{  c #EDEDD54C0101\",\n#\"}  c #DB80CA7E3E2F\",\n#\"|  c #F7F7E3E33645\",\n#\" . c #92128F8F7878\",\n#\".. c #D6D6C5C54040\",\n#\"X. c #D92EC91E416C\",\n#\"o. c #E0E0CFCF4444\",\n#\"O. c #E9E9D7D74848\",\n#\"+. c #EBC0DAAF4848\",\n#\"@. c #FCFCE9E94F4F\",\n#\"#. c #20FF4AC286A8\",\n#\"$. c #22724D668AE9\",\n#\"%. c #2A4F522D8517\",\n#\"&. c #251651208EC4\",\n#\"*. c #292953538B35\",\n#\"=. c #3E3E5E5E8585\",\n#\"-. c #26B853659157\",\n#\";. c #28F4561A9445\",\n#\":. c #2ACB58DF96F6\",\n#\">. c #2D8E5C7C9B06\",\n#\",. c #30305F5F9E9E\",\n#\"<. c #2F2F60609E9E\",\n#\"1. c #3083609A9F44\",\n#\"2. c #33BA649DA3C4\",\n#\"3. c #37376868A6A6\",\n#\"4. c #38786969A787\",\n#\"5. c #3C966D43AA77\",\n#\"6. c #3F3F7070ACAC\",\n#\"7. c #469C650F85DB\",\n#\"8. c #4AA06BC18DE3\",\n#\"9. c #4BCC6E6E9515\",\n#\"0. c #4B4B71719C9C\",\n#\"q. c #76F77B7B8101\",\n#\"w. c #425872A4AE6A\",\n#\"e. c #4A4A7777AA2A\",\n#\"r. c #535379CFA54F\",\n#\"t. c #58587C7CA3A3\",\n#\"y. c #52FD7D27AB55\",\n#\"u. c #464B766BB13B\",\n#\"i. c #48487777B2B2\",\n#\"p. c #4BAF7B6FB4EC\",\n#\"a. c #50507F62B7B7\",\n#\"s. c #50507F7FB8B8\",\n#\"d. c #5B5B8303ACEC\",\n#\"f. c #5ADB8505B2B2\",\n#\"g. c #5DDE8888B636\",\n#\"h. c #5437834EBACA\",\n#\"j. c #58AE875CBDE8\",\n#\"k. c #5AAB8960BF45\",\n#\"l. c #622F8B24B582\",\n#\"z. c #63638DC0BAED\",\n#\"x. c #68689090B7B7\",\n#\"c. c #6C579454BC91\",\n#\"v. c #5DD88C6AC194\",\n#\"b. c #60BD8F03C366\",\n#\"n. c #64B392BAC628\",\n#\"m. c #6ADC9708C5C5\",\n#\"M. c #6A6A9717C7C7\",\n#\"N. c #68E996C1C949\",\n#\"B. c #6CF59A78CBDC\",\n#\"V. c #72699F83CFC7\",\n#\"C. c #840487078A8A\",\n#\"Z. c #8A8A8BE18C8C\",\n#\"A. c #949496168E0E\",\n#\"S. c #87078C0C9212\",\n#\"D. c #93E9953F95EB\",\n#\"F. c #94EA97419A44\",\n#\"G. c #959599999E9E\",\n#\"H. c #9B709BF19C46\",\n#\"J. c #A7A7A5259313\",\n#\"K. c #9E9EA3A3A6A6\",\n#\"L. c #A37EA3A3A3A3\",\n#\"P. c #A5E5A9E9ADED\",\n#\"I. c #AC7CAC7CAC8C\",\n#\"U. c #BC3CBA3AACAC\",\n#\"Y. c #ADADB0B0B4B4\",\n#\"T. c gray70\",\n#\"R. c #B5B5B8B8BCBC\",\n#\"E. c #BBEBBBEBBBFB\",\n#\"W. c #C8C8C6C6BBBB\",\n#\"Q. c #BCBCBFBFC2C2\",\n#\"!. c gray77\",\n#\"~. c #C670C872CB20\",\n#\"^. c #CC16CC16CC16\",\n#\"/. c #D1D1D0D0C6C6\",\n#\"(. c #CF79D126D27C\",\n#\"). c #D437D437D437\",\n#\"_. c #DB92DA91D2F7\",\n#\"`. c #D6D6D8D8DADA\",\n#\"'. c #DC08DC08DC08\",\n#\"]. c #E4E4E4E4DEDE\",\n#\"[. c #DFDFE1E1E2E2\",\n#\"{. c #E42CE423E3F5\",\n#\"}. c #EBEBEAEAE6E6\",\n#\"|. c #E6E6E7E7E8E8\",\n#\" X c #ECE0ECE0EB5E\",\n#\".X c #F1F1F1F1EEEE\",\n#\"XX c #F466F46FF416\",\n#\"oX c none\",\n#/* pixels */\n#\"oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoXoXoXoXoXoXoX Xg g  XoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoXoXoXoXoXoX Xd @ @ d  XoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoXoXoXoXoX Xf O i i @ d .XoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoXoXoXoX Xf @ i O.+.i @ d }.oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoXoXoX X* @ i O.@.@.+.i @ d  XoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoXoX}.f O @ $ } @.@.@.+.i @ d  XoXoXoXoXoXoXoX[.Y.P.~.|.oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoX Xf @ i $ O $ X.@.@.@.O.i @ d }.oX.XQ.S.U 0 : : : : : 1 v Y q.G.R.`.XXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoX Xf @ u +.} $ @ @ } @.@.@.O.i @ ; e : : :     4 b M x 4 : : : : : : : : 0 G Q S.P.~.|.oXoXoXoXoXoXoXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoX X* @ y ] | @.} $ O $ X.@.@.@.+.i @ o < x V 8.l.V.V.V.V.V.B.z.t.7.A M x , : : : : : : : > c J ~ D.Y.(.XXoXoXoXoXoXoXoX\",\n#\"oXoXoXoX}.f @ @ $ ' { | @.} $ @ $ X.@.@.@.+.i @ = c.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.z.t.8.S M x 3 : : : : : : : : 0 G W R K.oXoX\",\n#\"oXoXoX Xf @ y @ O $ _ { | @.} $ @ $ ..@.@.@.+.i @ 9 c.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.m.f.9.=.B b 6 : : : : : : oXoX\",\n#\"oXoXD.- @ y ] ` @ @ $ _ { | @.} $ @ @ ..@.@.@.+.i @ r c.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.m.A 5 : : :   : < oXoX\",\n#\"oXoXo @ y ( [ { ` $ O $ ` { | @.} $ @ # ..@.@.@.+.i + 9 c.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.m.T 6 : : : : k %.2.: < oXoX\",\n#\"oXoXo O r ( ) [ { ` $ @ $ ` { | @.} $ @ $ ..@.@.@.+.i # 9 c.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.m.A 6 : : : : k %.2.2.2.2.: > oXoX\",\n#\"oXXX  o O r ( ) [ { _ @ @ @ _ { | @.X.$ @ $ ..@.@.@.+.i @ 9 c.V.V.V.V.V.V.V.V.V.V.V.V.V.m.S 7 : : : : l %.2.2.2.2.2.2.2.: > oXoX\",\n#\"oXoX: > 9 @ r / ) [ { _ @ @ $ _ { | @.} $ @ $ ..@.@.@.+.i @ 9 c.V.V.V.V.V.V.V.V.V.N.S 6 : : : : k %.2.2.2.2.2.2.2.2.4.2.: > oXoX\",\n#\"oXoX  : c.9 @ r / ) [ { ' $ @ @ _ { | @.} $ @ @ X.@.@.@.+.i @ # T l.V.V.V.V.N.S 7 : : : : k %.1.2.2.2.2.2.2.2.2.2.2.2.2.: < oXoX\",\n#\"oXoX  : V.m.9 @ r / ) [ { _ $ @ @ _ { | @.} $ @ @ ..@.@.@.+.i @ o   < 4 7 4 : : : : k %.2.3.2.2.2.2.2.2.2.2.2.2.2.2.2.2.: > oXoX\",\n#\"oXoX: < V.V.c.d @ r ( ) [ { ` @ @ @ _ { | @.} $ @ $ X.@.@.@.+.i @ O   : : : : l %.2.2.2.2.2.2.2.2.2.2.2.2.1.2.1.1.2.2.2.: > oXoX\",\n#\"oXoX: > V.V.B.z.9 @ r / ) [ { _ $ @ $ _ { | @.} $ @ @ X.@.@.@.+.i @ ; d.: : 2.2.2.2.2.2.2.2.2.2.2.2.1.2.1.2.2.1.1.2.2.2.: > oXoX\",\n#\"oXXX: > V.V.B.B.c.9 @ r ( ) [ { _ $ @ @ _ { | @.} $ @ $ X.@.@.o.s O @ # : : 2.2.2.2.2.2.2.2.1.2.2.2.1.2.1.2.>.2.1.2.2.2.: < oXoX\",\n#\"oXoX: , V.V.B.B.B.z.9 @ r ( ) ] { _ $ @ @ _ { | @.X.@ @ @ X.o.% @ @ @ @   : 2.2.2.1.2.2.1.2.1.1.1.1.2.>.,.1.2.>.,.,.2.2.: > oXoX\",\n#\"oXXX: , V.V.B.B.N.N.z.t @ r / ) [ { _ $ @ $ _ { | @.} $ @ $ s @ P _.I O . : 2.2.2.1.1.1.2.1.1.1.1.1.2.,.1.1.1.>.>.>.2.2.: > oXoX\",\n#\"oXoX: < V.V.B.N.N.N.m.l.9 O r / ) [ { _ @ @ @ _ { | @.} @ @ @ @ _.oXU.@ o : 2.2.1.1.1.1.1.1.1.1.1.,.>.,.1.>.1.>.2.>.2.2.: < oXoX\",\n#\"oXoX: > V.V.n.n.m.n.n.n.l.9 @ r / ) [ { _ $ @ $ _ { | o.a @ @ @ XXoX.X@ O > 2.2.1.1.1.1.1.,.,.1.>.1.,.>.>.,.>.>.>.>.2.2.: < oXoX\",\n#\"oXoX: > V.V.n.n.n.n.n.n.n.l.9 O r / ) [ { _ $ @ & _ _ r O @ @ * oXoXoXh @ X 2.3.1.1.1.>.,.,.>.>.>.>.,.>.>.>.>.>.>.>.3.2.: > oXoX\",\n#\"oXXX: : V.V.n.n.n.n.n.v.n.n.f.9 @ r / ) [ { _ @ @ @ p @ P _.XXoXoXoXoX .@ + 2.2.,.>.1.,.>.>.>.>.>.>.>.,.>.>.>.>.>.>.2.2.: > oXoX\",\n#\"oXoX: , V.V.n.b.v.n.n.n.v.v.n.g.9 @ r / ) [ { _ $ @ @ @ _.oXoXoXoXoXoX/.@ O 2.2.>.>.>.>.>.>.>.>.>.>.>.>.>.>.:.>.>.>.2.2.: > oXoX\",\n#\"oXoX  : V.V.v.n.v.n.v.v.v.v.v.v.f.9 @ r ( ) [ _ p @ @ @ XXoXoXoXoXoXoXoX; @ >.2.>.>.>.>.>.>.>.>.>.>.>.>.>.:.>.:.:.:.2.2.: < oXoX\",\n#\"oXoX: : V.V.v.v.v.v.v.v.v.v.j.v.k.y.9 @ r ( / r @ @ @ * oXoXoXoXoXoXoXoXL O B 2.>.>.>.>.>.>.>.:.:.:.>.:.:.:.:.:.>.:.2.2.: > oXoX\",\n#\"oXXX: > V.V.k.k.k.k.k.k.k.k.k.k.j.v.d.8 @ r p O P _..XoXoXoXoXoXoXoX{.L $ @ e 2.:.>.:.:.>.:.>.:.:.:.:.>.>.;.:.:.:.:.2.2.: > oXoX\",\n#\"oXoX: > V.V.k.k.k.k.k.k.k.j.j.h.j.j.j.y.9 @ O @ _.oXoXoXoXoXoXoXoXU.* # @ @ @ 2.>.>.>.:.:.:.:.>.;.:.:.;.:.;.;.:.;.:.2.2.: > oXoX\",\n#\"oXoX  > V.V.k.j.k.j.k.k.j.j.h.h.h.h.j.h.y.- O @  ./.oXoXoXoXoXoXW.* @ @ O @ @ D >.;.:.>.:.:.:.:.:.:.;.:.;.;.;.;.;.:.2.2.: < oXoX\",\n#\"oXXX> > V.V.j.h.j.j.h.j.h.h.h.h.j.h.h.h.h.r.$ O @ @ f A.].oXoXXXr + O @ @ O O m :.:.;.:.;.:.;.;.;.;.;.;.;.;.;.;.-.:.2.2.: > oXoX\",\n#\"oXXX: , V.V.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.p.8.m & O @ @ g J.J.* @ @ O @ O @ - ;.;.:.;.:.-.;.:.;.;.;.;.;.;.;.;.-.;.2.2.: > oXoX\",\n#\"oXoX: : V.V.h.h.h.h.h.h.h.h.h.h.h.s.h.p.p.h.h.p.h.h.7.m & @ @ @ & $ @ @ @ @ @ O *.;.;.;.:.:.-.;.;.;.&.;.;.&.-.;.-.-.2.2.: > oXoX\",\n#\"oXoX: , V.V.h.h.h.h.h.h.i.h.h.p.p.h.p.s.h.p.h.p.h.p.h.p.e.E e @ @ @ @ # @ O @ @ N ;.-.:.-.-.-.-.&.;.-.;.&.-.;.&.-.-.2.2.  < oXoX\",\n#\"oXoX: , V.V.i.h.u.h.i.h.h.h.i.h.p.s.p.p.p.p.p.p.e.p.p.p.p.p.p.e.C 8 @ @ @ @ @ @ q :.-.-.-.-.-.-.;.&.&.-.-.-.&.&.-.-.2.2.: > oXoX\",\n#\"oXXX: , V.V.h.p.h.p.p.p.h.i.h.i.p.p.p.p.p.p.p.i.i.i.i.p.i.i.i.i.p.i.x.R o O O O # -.-.-.-.-.-.-.-.-.&.-.-.-.-.&.&.&.2.2.: > oXoX\",\n#\"oXoX: , V.V.h.i.p.p.p.p.p.p.p.p.p.p.p.i.i.p.i.i.i.i.i.i.i.i.u.u.i.i.V.V.:   m # = -.-.-.-.&.&.&.$.&.&.&.-.$.$.-.&.&.2.2.: > oXoX\",\n#\"oXXX: : V.V.i.i.p.p.p.p.i.p.i.i.i.i.i.i.u.u.i.u.i.u.i.w.i.u.u.u.w.u.V.B.: , 3.2.&.-.&.&.&.&.&.&.-.$.-.&.$.&.-.$.$.&.2.2.: < oXoX\",\n#\"oXoX: , V.V.i.i.i.i.u.i.u.u.u.i.i.u.u.u.u.u.u.u.u.w.w.w.u.u.w.w.w.u.V.V.: : 2.2.&.&.&.&.&.&.$.&.$.-.$.&.$.$.$.$.$.&.2.2.: > oXoX\",\n#\"oXXX  > V.V.i.i.i.i.i.u.i.i.w.i.i.i.w.w.w.w.u.6.w.w.w.w.w.w.w.w.6.6.V.V.: : 2.2.&.&.$.&.&.$.&.&.$.$.$.-.$.$.$.$.$.$.2.2.: > oXoX\",\n#\"oXoX: , V.V.i.w.w.i.w.u.w.w.w.w.w.w.w.w.6.u.w.6.w.w.w.5.w.5.w.5.6.6.V.V.: : 3.2.&.&.&.&.$.$.$.$.$.&.$.$.$.$.$.$.$.$.2.2.: > oXoX\",\n#\"oXoX: , V.V.w.w.w.w.w.w.w.w.w.w.w.6.6.w.6.6.6.w.5.w.w.w.5.5.5.w.6.6.B.V.: : 3.2.&.$.$.$.&.$.&.$.$.$.$.$.$.$.$.$.$.&.2.2.: < oXoX\",\n#\"oXXX: > V.V.w.w.w.6.w.w.w.w.6.w.6.6.6.6.6.6.6.6.w.5.4.5.5.5.5.w.5.6.V.V.: : 2.2.$.&.$.$.#.$.$.#.$.#.$.#.#.#.#.;.<.2.2.2.: > oXoX\",\n#\"oXoX  : V.V.w.w.w.5.w.6.5.w.5.w.w.4.w.w.4.w.4.4.w.w.4.4.5.5.4.4.4.4.V.V.: : 2.2.$.$.$.$.$.$.$.#.$.#.$.#.&.:.2.2.2.2.#.6 : 1 oXoX\",\n#\"oXoX: : V.V.5.5.w.5.5.5.5.5.5.5.4.w.4.4.4.4.w.4.4.4.4.4.4.4.4.4.4.3.V.V.: , 2.2.$.#.$.#.#.#.#.#.$.#.$.>.2.2.2.,.n , : : c P.oXoX\",\n#\"oXXX: , V.V.N.v.j.p.w.5.5.4.4.5.3.4.4.3.4.4.4.4.4.4.4.4.3.3.3.3.4.3.V.V.: : 2.2.#.$.#.#.#.#.#.$.;.1.2.3.1.*.k : : : J R.oXoXoXoX\",\n#\"oXoX: : m.V.V.B.V.V.V.B.n.j.h.i.w.4.4.w.4.3.4.4.3.3.4.2.3.2.3.3.3.2.V.B.: , 2.2.#.#.#.#.#.&.:.2.3.2.,.Z 2 : : 0 ^ (.XXoXoXoXoXoX\",\n#\"oXoX: : : > b D 0.g.N.V.V.V.V.V.V.B.n.s.s.u.3.3.2.2.4.3.2.3.2.2.2.2.V.V.: : 2.2.#.$.$.-.2.2.2.2.;.z : : : c C.^.[.|.XXXXoXoXoXoX\",\n#\"oXoXP.R c : : : : : : 4 N 7.e.z.B.V.V.V.V.V.V.m.b.s.p.w.2.2.2.2.2.3.V.V.: : 2.2.$.;.1.2.2.2.#.6 : : < H H.!.^.`.[.|.XXoXoXoXoXoX\",\n#\"oXoXoXoXoX.X~.G.! G 0 : : : : : : x V 9.y.n.V.V.V.V.V.V.V.n.z.p.u.4.V.V.: , 2.2.2.2.2.>.n < : : 5 R L.R.E.~.(._.{. XXXoXoXoXoXoX\",\n#\"oXoXoXoXoXXXXX|.[.`.^.E.F.^ K w , : : : : : < b =.0.p.M.V.V.V.V.V.V.V.V.: , 2.2.2.&.k : : : w ! L.I.T.E.~.(._.[.}..XoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoXXX}.[.`.(.~.!.T.T.I.D.! K v 0 : : : : : : 6 b =.r.v.B.V.V.: : ,.Z , : : 1 H Z.H.I.I.R.W.~.(.`.{.|..XoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoXoXXX X|.'.`.^.~.E.E.T.I.L.H.D.A.^ K F w 1 : : : : : : j V : : : : : w W H.L.I.T.E.W.~.^.`.'.|. XXXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoXoXoXoX.X X{.'._.).^.!.E.R.T.I.I.L.L.H.H.D.Z.! Y F 0 1 : : : : < G Z.I.I.T.E.E.!.^.(.`.'.|. XXXoXoXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoXoXoXoXoXoXoXXX X{.'._.`.(.^.!.!.E.E.T.T.T.T.I.I.I.I.I.F.q.F H I.E.E.!.!.~.(.).'.[.{. X XoXoXoXoXoXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXXXXX X X{.{.'.`.`.).(.^.^.~.~.~.!.~.~.~.^.^.^.).).`.`.'.[.|.}..XXXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXXXXX X X X}.}.].[.].{.].{.{.{.|.}. X X.X.XXXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX\",\n#\"oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX\"\n#};\n#'''\n#        if self.Object.Type == \"Subtractive\":\n#            return XPM.replace(\"none\",\"red\")\n#        else:\n#            return XPM\n \n#    def __getstate__(self):\n#        '''When saving the document this object gets stored using Python's json module.\\\n#                Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\\\n#                to return a tuple of all serializable objects or None.'''\n#        return None\n \n#    def __setstate__(self,state):\n#        '''When restoring the serialized object from document we have the chance to set some internals here.\\\n#                Since no data were serialized nothing needs to be done here.'''\n#        return None\n\n#if __name__ == \"__main__\":\n#    FreeCAD.Console.PrintMessage(\"This file is for import only.  Please run pdwrapper.FCMacro to create object.\\n\")\n\n\n########################################\n#CODE_ENDS_HERE\n\n\nBASENAME = \"pdwrapper\"\n\ndef getTipBase(fromBody,wrapper): #empower the user by letting him select where to put this new wrapper\n    '''return (before feature, new tip)'''\n    from PySide import QtGui\n    def parens(name,label):\n        return name + \" (\"+label+\")\" if label != name else name\n    solids = [ii for ii in fromBody.Group if hasattr(ii,\"Shape\") and len(ii.Shape.Solids) >= 1 and ii.isDerivedFrom(\"PartDesign::Feature\")]\n    if len(solids) == 0:\n        return (None,wrapper) #empty body, so wrapper is new tip\n    else:\n        #BaseFeature, if any, should be first, but if the user wants to try to put this ahead of it let him try it\n        items2 = [\"Beginning of Body\"]+[parens(ss.Name,ss.Label) for ss in solids]\n        default = len(items2)-1\n        window = FreeCADGui.getMainWindow()\n        QtGui.QInputDialog.InputDialogOption = QtGui.QInputDialog.NoButtons\n        item2,ok = QtGui.QInputDialog.getItem(window,\"Set previous feature\",\n\"Select what should come *before* this object in the tree.\\n\\\nCancel will put the new wrapper object last in the tree.\\n\\\nNote: the last item in the tree will be set as the new tip\\n\\\nand made the visible feature in the tree.  You may, of course, \\n\\\nchange this after the wrapper and the wrapped object are placed.\\n\", items2, default, False)\n        if not ok or item2 == items2[-1]:\n            return (solids[-1],wrapper) #put at end of list and make wrapper new tip\n        elif item2 == items2[0]:\n            return (None,solids[-1]) #put at front of body, last solid is new tip\n        else: #user selected neither the first nor the last feature\n              #first -1 because of string as first item\n              #second -1 because we want the last solid to be the new tip\n            return (solids[items2.index(item2)-1],solids[-1])\n\ndef setDefaults(wrapobj):\n    wrapobj.PatternOperationDefault = wrapobj.PatternOperation\n    wrapobj.TipOperationDefault = wrapobj.TipOperation\n\ndef makeObject(PDW):\n    from PySide import QtGui\n    doc = FreeCAD.ActiveDocument\n    body=FreeCADGui.ActiveDocument.ActiveView.getActiveObject(\"pdbody\")\n    if not body:\n        body = getBody(doc)\n\n    if not body:\n        FreeCAD.Console.PrintError(\"No body in active document or user canceled.\\n\")\n    else:\n        if body and doc:\n            doc.openTransaction(\"Create PDWrapper\")\n            selobjs = FreeCADGui.Selection.getSelectionEx()\n            if selobjs:\n                for selobj in selobjs:\n                    if body:\n                        window = FreeCADGui.getMainWindow()\n                        items=[\"Additive\",\"Subtractive\",\"Common (Additive)\",\"Common (Subtractive)\",\"XOR (Additive)\",\"XOR (Subtractive)\",\"None\"]\n                        item,ok = QtGui.QInputDialog.getItem(window,\"Wrapper type\",\n\"Select wrapper type for this object. You can change the operations later, but Additive or \\n\\\nSubtractive can only be chosen now, at the time of object creation, and can't be changed later. \\n\\\nAdditive or Subtractive is required if you want to be able to use the wrapped object in a \\n\\\nPart Design pattern (array) later.\\n \", items, 0, False)\n                        if ok:\n                            if item == items[0]:#Additive\n                                wrapper = doc.addObject(\"PartDesign::FeatureAdditivePython\",\"PDW_Add\")\n                                PDW.PDWrapper(wrapper) #body.newObject would add this to the end each time and make it the new tip\n                                PDW.PDWrapperVP(wrapper.ViewObject) #we'll empower the user to make this decision each time\n                                tipBase,newTip = getTipBase(body,wrapper) #tipBase is previous solid feature or None\n                                body.insertObject(wrapper, tipBase, True) #insert into the body before adding links to avoid scope warnings\n                                body.Tip = newTip #newTip is the last solid in the body, which might be the wrapper, user can always set a new tip\n                                newTip.ViewObject.Visibility = True #make the new tip visible so it is obvious to the user what the body shape looks like\n                                wrapper.TipBase = tipBase #base for the tip shape\n                                wrapper.TipTool = selobj.Object #tool for the tip shape\n                                wrapper.TipOperation = \"Fuse\" #op to perform on base and tool to create tip shape\n                                wrapper.Type = \"Additive\" #for our reference only and to remind user of type selected\n                                wrapper.PatternBase = selobj.Object #base used to create AddSubShape for use in patterns\n                                wrapper.PatternOperation = \"None\" #operation to perform on base and tool to create pattern shape\n                                wrapper.PatternTool = None #tool for pattern shape boolean, if any\n                            elif item == items[1]:#Subtractive\n                                wrapper = doc.addObject(\"PartDesign::FeatureSubtractivePython\",\"PDW_Sub\")\n                                PDW.PDWrapper(wrapper)\n                                PDW.PDWrapperVP(wrapper.ViewObject)\n                                tipBase,newTip = getTipBase(body,wrapper)\n                                body.insertObject(wrapper, tipBase, True)\n                                body.Tip = newTip\n                                newTip.ViewObject.Visibility = True\n                                wrapper.TipBase = tipBase\n                                wrapper.TipOperation = \"Cut\"\n                                wrapper.Type = \"Subtractive\"\n                                wrapper.PatternBase = selobj.Object #also fp.LinkedObject\n                                wrapper.TipTool = selobj.Object\n                                wrapper.PatternOperation = \"None\"\n                                wrapper.PatternTool = None\n                            elif item == items[2]:#Common additive\n                                wrapper = doc.addObject(\"PartDesign::FeatureAdditivePython\",\"PDW_Common_Add\")\n                                PDW.PDWrapper(wrapper)\n                                PDW.PDWrapperVP(wrapper.ViewObject)\n                                tipBase,newTip = getTipBase(body,wrapper)\n                                body.insertObject(wrapper, tipBase, True)\n                                body.Tip = newTip\n                                newTip.ViewObject.Visibility = True\n                                wrapper.TipBase = tipBase\n                                wrapper.TipOperation = \"Common\"\n                                wrapper.Type = \"Additive\"\n                                wrapper.TipTool = selobj.Object\n                                wrapper.PatternTool = selobj.Object\n                                wrapper.PatternBase = wrapper.TipBase\n                                wrapper.PatternOperation = \"Common\"\n                            elif item == items[3]:#Common subtractive\n                                wrapper = doc.addObject(\"PartDesign::FeatureSubtractivePython\",\"PDW_Common_Sub\")\n                                PDW.PDWrapper(wrapper)\n                                PDW.PDWrapperVP(wrapper.ViewObject)\n                                tipBase,newTip = getTipBase(body,wrapper)\n                                body.insertObject(wrapper, tipBase, True)\n                                body.Tip = newTip\n                                newTip.ViewObject.Visibility = True\n                                wrapper.TipBase = tipBase\n                                wrapper.TipOperation = \"Common\"\n                                wrapper.Type = \"Subtractive\"\n                                wrapper.TipTool = selobj.Object\n                                wrapper.PatternTool = selobj.Object\n                                wrapper.PatternBase = wrapper.TipBase\n                                wrapper.PatternOperation = \"Common\"\n                            elif item == items[4]: #XOR additive\n                                wrapper = doc.addObject(\"PartDesign::FeatureAdditivePython\",\"PDW_XOR_Add\")\n                                PDW.PDWrapper(wrapper)\n                                PDW.PDWrapperVP(wrapper.ViewObject)\n                                tipBase,newTip = getTipBase(body,wrapper)\n                                body.insertObject(wrapper, tipBase, True)\n                                body.Tip = newTip\n                                newTip.ViewObject.Visibility = True\n                                wrapper.TipBase = tipBase\n                                wrapper.TipOperation = \"XOR\"\n                                wrapper.Type = \"Additive\"\n                                wrapper.TipTool = selobj.Object\n                                wrapper.PatternBase = wrapper.TipBase\n                                wrapper.PatternOperation = \"XOR\"\n                                wrapper.PatternTool = selobj.Object\n                            elif item == items[5]: #XOR subtractive\n                                wrapper = doc.addObject(\"PartDesign::FeatureSubtractivePython\",\"PDW_XOR_Sub\")\n                                PDW.PDWrapper(wrapper)\n                                PDW.PDWrapperVP(wrapper.ViewObject)\n                                tipBase,newTip = getTipBase(body,wrapper)\n                                body.insertObject(wrapper, tipBase, True)\n                                body.Tip = newTip\n                                newTip.ViewObject.Visibility = True\n                                wrapper.TipBase = tipBase\n                                wrapper.TipOperation = \"XOR\"\n                                wrapper.Type = \"Subtractive\"\n                                wrapper.TipTool = selobj.Object\n                                wrapper.PatternBase = wrapper.TipBase\n                                wrapper.PatternOperation = \"XOR\"\n                                wrapper.PatternTool = selobj.Object\n                            elif item == items[6]: #None ##add object to body, but don't use its shape\n                                wrapper = doc.addObject(\"PartDesign::FeaturePython\",\"PDW_None\")\n                                PDW.PDWrapper(wrapper)\n                                PDW.PDWrapperVP(wrapper.ViewObject)\n                                tipBase,newTip = getTipBase(body,wrapper)\n                                body.insertObject(wrapper, tipBase, True)\n                                body.Tip = newTip\n                                newTip.ViewObject.Visibility = True\n                                wrapper.TipOperation = \"None\"\n                                wrapper.Type = \"None\" #neither additive nor subtractive, so hide these properties\n                                unused = [prop for prop in wrapper.PropertiesList if \"Pattern\" in prop]\n                                for prop in unused:\n                                    wrapper.setEditorMode(prop,2)\n                        else: #cancel\n                            doc.abortTransaction()\n                            return\n                        setDefaults(wrapper) #save default operations for enable/disable\n                        if not selobj.Object in body.Group:\n                            parents = selobj.Object.Parents\n                            if parents:\n                                if selobj.Object in parents[0][0].Group:\n                                    grp = parents[0][0].Group\n                                    grp.remove(selobj.Object)\n                                    parents[0][0].Group = grp\n                                    body.Group += [selobj.Object]\n                                    wrapper.Proxy.warn(wrapper,selobj.Object.Label+\" removed from \"+parents[0][0].Name+\"\\n\")\n                            body.Group += [selobj.Object]\n                        wrapper.Body = body.Name\n                        wrapper.LinkedObject =selobj.Object\n                        if wrapper.Type != \"None\":\n                            wrapper.LinkedObject.ViewObject.Visibility = False\n                        if selobj.Object.isDerivedFrom(\"PartDesign::Feature\"):\n                            wrapper.ClaimChildren = False #preserve linear tree if wrapping a PD object\n                        doc.commitTransaction()\n            else:\n                FreeCAD.Console.PrintError(\"Selection error.  Select an object to add to the active body.\\n\")\n\n\ndef getBody(doc):\n    from PySide import QtGui\n    def parens(name,label):\n        return name + \" (\"+label+\")\" if name != label else name\n    selobj = FreeCADGui.Selection.getSelection() #prefer body containing PD native object being encapsulated\n    if len(selobj) >= 1:\n        sel = selobj[0]\n        if hasattr(sel,\"_Body\"):\n            return sel._Body\n    bodies = [obj for obj in doc.Objects if obj.TypeId == \"PartDesign::Body\"]\n    if len(bodies) == 1:\n        return bodies[0]\n    if len(bodies) == 0:\n        return None\n    items = [parens(ii.Name,ii.Label) for ii in bodies]\n    window = FreeCADGui.getMainWindow()\n    item,ok = QtGui.QInputDialog.getItem(window,\"Choose body\",\n\"Multiple bodies, but none are active, so please select the body to which \\n\\\nthis feature should be added\\n\", items, 0, False)\n    if ok:\n        return bodies[items.index(item)]\n    else:\n        return None\n\n#################\ndef writeFile():\n    with open(py_file,\"w\") as outfile:\n        for line in code.splitlines():\n            if \"#CODE_ENDS_HERE\" in line:\n                break\n            if line.startswith('#'):\n                if line == \"# -*- coding: utf-8 -*-\":\n                    line = \"#\" + line\n                outfile.write(line[1:]+\"\\n\") #skip first character (#)\n\n\n\n############\n#if __name__ == \"__main__\":\n#    makeObject(None)\n#    raise Exception(\"quick exit for testing/debugging\")\n############\n\nif __name__ == \"__main__\":\n    import os\n    fin = open(__file__, 'r')\n    code = fin.read()\n    fin.close()\n    version = code.splitlines()[1][16:]\n    real_path = os.path.realpath(__file__)\n    dir_path = os.path.dirname(real_path)\n    py_file = real_path.replace(\".FCMacro\",\".py\").replace('PDWrapper','pdwrapper').replace('Pdwrapper','pdwrapper')\n    bHasFile = os.path.exists(py_file)\n    noImport = False #user elects not to save import file\n\n    if not bHasFile:\n        from PySide import QtGui\n        window = QtGui.QApplication.activeWindow()\n        mb = QtGui.QMessageBox()\n        mb.setWindowTitle(BASENAME+\" setup\")\n        mb.setIcon(mb.Information)\n        mb.setStandardButtons(mb.Ok | mb.Cancel)\n        mb.setDefaultButton(mb.Cancel)\n        okBtn = mb.button(QtGui.QMessageBox.StandardButton.Ok)\n        cancelBtn = mb.button(QtGui.QMessageBox.StandardButton.Cancel)\n        okBtn.setText(\"Create file\")\n        cancelBtn.setText(\"Do not create file\")\n        caption = \"In order for \"+BASENAME+\" objects to be parametric after saving and reloading file\\n\\\nwe need to create another file on this computer.  File to be created will be: \\n\\n\"+py_file+\"\\n\\n\\\nThis makes it available to the system upon restarting FreeCAD and loading documents containing the \\\n\"+BASENAME+\" feature python objects.  Create file now?\\n\\n\"\n        mb.setText(caption)\n        ret = mb.exec_()\n        if ret == mb.Ok:\n            writeFile()\n            QtGui.QMessageBox.information(window,\"Success\",\"File successfully created.  Please note: if you uninstall \"+BASENAME+\" macro you need to manually remove \"+py_file+\", too.\\n\")\n        else:\n            new_lines = []\n            for line in code.splitlines():\n                if line.startswith('#'):\n                    if \"CODE_ENDS_HERE\" in line:\n                        break\n                    if line == \"# -*- coding: utf-8 -*-\":\n                        new_lines.append(line+\"\\n\")\n                        continue\n                    new_lines.append(line[1:]+\"\\n\")\n            code = \"\".join(new_lines)\n\n            #credit to Mila Nautikus for his answer to a question on stackoverflow, which I modified here\n            #in this example the filename is pdwrapper.py\n            #https://stackoverflow.com/questions/5362771/how-to-load-a-module-from-code-in-a-string\n\n            ##########\n            import sys, importlib\n            my_name = 'pdwrapper' #filename = pdwrapper.py, so this must be 'pdwrapper'\n            my_spec = importlib.util.spec_from_loader(my_name, loader=None)\n\n            pdwrapper = importlib.util.module_from_spec(my_spec)\n\n            exec(code, pdwrapper.__dict__)\n            sys.modules['pdwrapper'] = pdwrapper\n            makeObject(pdwrapper)\n            noImport = True\n\n    if not noImport: #don't never use no double negatives\n\n        import pdwrapper as PDW\n        if PDW.__version__ != __version__:\n            writeFile()\n            from PySide import QtGui\n            window = QtGui.QApplication.activeWindow()\n            QtGui.QMessageBox.information(window,\"Version upated\",BASENAME+\".py has been updated.  You must restart FreeCAD for the new changes to take effect.\")\n        else:\n            makeObject(PDW)",
    "url": "https://wiki.freecad.org/Macro_PDWrapper",
    "raw_code_url": "https://gist.github.com/mwganson/4106e84eeaaf4d6e056cd286cbc39170/raw/addc2f23ca223fd4f3332cfa04f2264ef0ee908b/Pdwrapper.FCMacro",
    "wiki": "",
    "version": "0.2023.08.13",
    "license": "",
    "date": "2023-08-13",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Workbench_PartDesign.svg",
    "icon_source": "https://wiki.freecad.org//images/3/39/Workbench_PartDesign.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "3d Printer Slicer",
    "on_wiki": true,
    "on_git": false,
    "desc": "Export to slicing software for 3D printers. Exports stl file in the same directory as original design file, then opens it in slicing software.<br />This code, when run, will export the currently open design to STL file, and open it in the slicing software that you use. This example is for <b><a rel=\"nofollow\" class=\"external text\" href=\"http://kisslicer.com/\">KISSlicer</a></b>, but can be modified to use <b><a rel=\"nofollow\" class=\"external text\" href=\"http://slic3r.org/\">Slic3r</a></b>, <b><a rel=\"nofollow\" class=\"external text\" href=\"http://wiki.ultimaker.com/Cura\">Cura</a></b>, or any other 3d printer software. It can also be modified slightly to open up CAM software for CNC machines.<br /><br />Macro version: 1.0<br />Last modified: 2013-10-10<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/9/96/Macro_3d_Printer_Slicer.png\">ToolBar Icon</a><br />Author: cae2100<br /> ",
    "comment": "Export to slicing software for 3D printers. Exports stl file in the same directory as original design file, then opens it in slicing software.",
    "code": "import FreeCAD\nimport Mesh\nimport sys\nimport math\nimport os\nimport subprocess\n# some fuctions\ndef getPlacement(quat,vect,obj):\n  if quat[3] > -1  and quat[3] < 1:\n    delta = math.acos(quat[3])*2.0\n    scale = math.sin(delta/2)\n    rx = quat[0]/scale\n    ry = quat[1]/scale\n    rz = quat[2]/scale\n  else:\n    delta = 0\n    rx = 0\n    ry = 0\n    rz = 1\n  info0 = \"translation \"+str(vect.x)+\" \"+str(vect.y)+\" \"+str(vect.z)\n  info1 = \"rotation \"+str(rx)+\" \"+str(ry)+\" \"+str(rz)+\" \"+str(delta)\n  return info0+\" \"+info1\n# some definitions\nplacement = App.Placement(App.Vector(0,0,0),App.Rotation(0,0,0,1))\n# user need to set this directory where slicing software is located\nOutDir = FreeCAD.ActiveDocument.FileName.replace(FreeCAD.ActiveDocument.Label + \".fcstd\", \"\")\nvisible_objs = []\nSLICER = \"/kisslicer location/\"                          # Put your Slicer program location here\nos.chdir(SLICER)\n# Get Objects in document\ndoc = App.ActiveDocument\nobjs = doc.Objects\n# hide all\nfor obj in objs:\n   if obj.ViewObject.isVisible():\n      visible_objs.append(obj)\nfor obj in visible_objs:\n  # get volume\n  volume = obj.Shape.Volume\n  # get Rotation and translation of volume\n  quat = obj.Placement.Rotation.Q\n  vect = obj.Placement.Base\n  pinfo = getPlacement(quat,vect,obj)\n  # reset placement, export it and set at original placement\n  oldPlacement = obj.Placement\n  obj.Placement = placement\n  obj.Placement = oldPlacement   \nstlFile = OutDir+str(doc.Label)+\".stl\"\nMesh.export(visible_objs,stlFile)\nsubprocess.Popen([SLICER + \"KISSlicer\", stlFile])",
    "url": "https://wiki.freecad.org/Macro_3d_Printer_Slicer",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2013-10-10",
    "src_filename": "",
    "filename_from_url": "",
    "author": "cae2100",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_3d_Printer_Slicer.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/9/96/Macro_3d_Printer_Slicer.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "3d Printer Slicer Individual Parts",
    "on_wiki": true,
    "on_git": false,
    "desc": "Export to slicing software for 3D printers based on a similar macro by cae2100. Exports a single stl file for each visible part in the same directory as original design file, then opens it in slicing software.<br />This code, when run, will export the currently open design to several STL files, named after the labels of the parts, and open it in the slicing software that you use. The macro is searching for <b><a rel=\"nofollow\" class=\"external text\" href=\"http://wiki.ultimaker.com/Cura\">Cura</a></b> in the path but you can add any other slicing by changing the string in the macro.<br /><br />Macro version: 1.1<br />Last modified: 2020-10-30<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/images/3/3d/Macro_3d_Printer_Slicer_Individual_Parts.svg\">ToolBar Icon</a><br />Author: WayofWood<br /> ",
    "comment": "Export to slicing software for 3D printers based on a similar macro by cae2100. Exports a single stl file for each visible part in the same directory as original design file, then opens it in slicing software.",
    "code": "import FreeCAD\nimport Mesh\nimport sys\nimport math\nimport os\nimport subprocess\n\nSLICERAPP= \"cura\"\t\t \t\t\t# Put your Slicer program here\n\n# some fuctions\ndef getPlacement(quat,vect,obj):\n  if quat[3] > -1  and quat[3] < 1:\n    delta = math.acos(quat[3])*2.0\n    scale = math.sin(delta/2)\n    rx = quat[0]/scale\n    ry = quat[1]/scale\n    rz = quat[2]/scale\n  else:\n    delta = 0\n    rx = 0\n    ry = 0\n    rz = 1\n  info0 = \"translation \"+str(vect.x)+\" \"+str(vect.y)+\" \"+str(vect.z)\n  info1 = \"rotation \"+str(rx)+\" \"+str(ry)+\" \"+str(rz)+\" \"+str(delta)\n  return info0+\" \"+info1\n# some definitions\nplacement = App.Placement(App.Vector(0,0,0),App.Rotation(0,0,0,1))\n# user need to set this directory where slicing software is located\nOutDir = FreeCAD.ActiveDocument.FileName.replace(\".FCStd\", \"--\")\nvisible_objs = []\n# Get Objects in document\ndoc = App.ActiveDocument\nobjs = doc.Objects\nstlFile = \"\"\nstlFiles = [ SLICERAPP ]\n# hide all\nfor obj in objs:\n   print(obj.Label + \"//\" + obj.TypeId)\n   print(len(obj.InList))\n   if obj.ViewObject.isVisible() and hasattr(obj, 'Shape') and (len(obj.InList) <= 1):\n      visible_objs.append(obj)\nfor obj in visible_objs:\n  stlFile = OutDir+str(obj.Label)+\".stl\"\n  Mesh.export([obj],stlFile)\n  stlFiles.append(stlFile)\n  print (\"Exporting \" + stlFile + \"\\n\")\nprint (\"Calling subprocess: \" + str(stlFiles)+\"\\n\")\nsubprocess.Popen(stlFiles)",
    "url": "https://wiki.freecad.org/Macro_3d_Printer_Slicer_Individual_Parts",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2020-10-30",
    "src_filename": "",
    "filename_from_url": "",
    "author": "WayofWood",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_3d_Printer_Slicer_Individual_Parts.svg",
    "icon_source": "https://wiki.freecadweb.org/images/3/3d/Macro_3d_Printer_Slicer_Individual_Parts.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "3D Printer Workflow",
    "on_wiki": true,
    "on_git": false,
    "desc": "Macro that creates an stl file with perfect rounding, i.e. without visible facets, from selected objects. It also allows to launch programs of your choice. For example to automate the FreeCAD \u2192 Slicer \u2192 printing workflow.<br /> <p>After the creation of the stl file you can, for example, open your slicer with the stl file, switch on your printer, heat the printer bed and, if necessary, trigger additional commands in your home automation.<br /><br />Macro version: 00.02<br />Last modified: 2023-01-21<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/images/b/b4/Macro_3D_Printer_Workflow.png\">ToolBar icon</a><br />Author: 2cv001<br /> </p> ",
    "comment": "Macro that creates an stl file with perfect rounding, i.e. without visible facets, from selected objects. It also allows to launch programs of your choice. For example to automate the FreeCAD \u2192 Slicer \u2192 printing workflow.",
    "code": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# ==================================================================\n# ==================================================================\n# ==                                                              ==\n# ==  Workflow to print with \"stl\" file with perfect rounding     ==\n# ==  and launch others programs                                  ==\n# ==                                                              ==\n# ==================================================================\n# ==================================================================\n__author__ = \"2cv001\"\n__title__   = \"Macro_3D_Printer_Workflow\"\n__date__    = \"2023/02/05\"    #YYYY/MM/DD\n__version__ = __date__\n__icon__    = \"https://wiki.freecadweb.org/images/b/b4/Macro_3D_Printer_Workflow.png\"\n__Wiki__    = \"http://www.freecadweb.org/wiki/Macro_3D_Printer_Workflow\"\n\"\"\"\nMacro that creates an \"stl\" file with perfect rounding\n= without visible facets.\nIt also allows to launch programs of your choice\nFor example to automate the FreeCAD -> Slicer -> printing workflow\n\nPrinciple of smoothing : it modifies the deviation property of the solids before\ngeneration of the stl and then replace the old values\nAt the end, it proposes to launch the stl file which will open for example under\ncura if the stl extension has been associated with cura in your operating system.\n\nLaunching other programs or commands :\nYou can ask it to chain any program or command that you might\ntype in a terminal.\nTo do this, you must change what is in the\n\"parameters that can be changed\" section.\n\nExamples of applications:\n- Turn on the printer and the light (requires for example a controlled socket)\n- Connect octoprint to the printer\n- Start the tray preheating\n- Save your FreeCAD and stl file\n....\n\n\nTested on windows and Linux\n\"\"\"\nimport FreeCAD as App\nimport Mesh\nfrom PySide2 import QtCore, QtWidgets\nimport os, sys, subprocess\nimport time\nimport FreeCADGui as Gui\n\n#================================\n# Parameters that can be changed\n#================================\n\n# Smoothing management\n#--------------------\n\n# deviation : default value that will be displayed in the dialog box.\n# 0.5 is the default value in FreeCad, 0.05 allows a stronger smoothing.\n# 0.01 is perfect from a smoothing point of view.\n# The lower the value, the better the quality,\n# but the larger the size of the stl file\n# the value must be between 0 and 1\ndeviation=0.01\ndoitLancerFichier=True # if True, it will be proposed to launch the stl file.\n                                 # otherwise put False\n\n# Automatic program launch,\n# Automation of the production line\n#------------------------------------------\n\ndelaiMax=10 # if the user enters a delay greater than this value,\n                   # it will be reduced to delaiMax\n\n#To launch programs of your choice\n#------------------------------------------\n#Typically for example a home automation program, \n#turn on your printer or/and a light etc.\n#Use the following syntax by adding after the line \"# insert your lines here\" a line\n#   with this syntax (important: align the [ with the others):\n#  [ ['command to execute', 'param 1', param 2, ] ,'.extension','question to ask', waiting time],\n# Details of the syntax :\n#  'command to execute' : the command you want to execute. \n#  'param 1, param 2,...' : if your program needs parameters. \n#      These parameters will be taken into account only if extension=''.#\n#  'extension': if not empty then the first parameter will be replaced by the name of \n#      your FreeCAD file but with this extension.\n#  'question to ask': the question to display in the dialog box\n#  time_wait : optional : nb of seconds to wait after execution\n#      allows for example to wait for the printer to start before asking it to heat the plate\n\n#  Note in the examples below the double \\ in place of \\ (because the special characters\n#    must be preceded by an \\ in python). Ditto for the apostrophe for example\n#  the lines in question are to be inserted further down after commands=[...\n#\n# Examples of possible launches:\n\n\"\"\"\nLaunching a program :\n----------------------\n  to launche a program without parameter\n[ ['calc.exe'                                         ] ,''    ,'Launch the calculator ?'],\n  to launche a program with a parameter (here : dessin.jpg)\n[ ['C:\\\\WINDOWS\\\\system32\\\\mspaint.exe','dessin.jpg'  ] ,''    ,'Launch  Paint ?'          ],\n  to launche a program with an extension parameter. If for example, \n  the freecad project file name is 'mondessin.FCStd'\n  and if you give '.stl' as extension, the program will be launched with as first parameter 'mondessin.stl'\n  Here cura will be launched with the file 'modessin.stl' loaded : \n[ ['C:\\\\Program Files\\\\Ultimaker Cura 4.8.0\\\\Cura.exe'] ,'.stl','Launch  Cura ?'           ],\n  to load an url in firefox. Here, to launch octopi in firefox.\n[ ['C:\\\\Program Files\\\\Mozilla Firefox\\\\firefox.exe','https://octopi.local'],'','Launch Octoprint ?'],\n    On linux:\n[ [   'firefox','https://octopi.local'                ] , ''   ,'Launch Octoprint ?'      ], \n\nLaunching a web page (here, a php script) :\n-----------------------------------------\n[ ['curl','http://pidomotique/connecte.php'           ] , ''   ,'Connect the printer ?'],\nLaunching an url using https but insecure\n[ ['curl','https://pidomotique/connecte.php,'--insecure'] , ''   ,'Connect the printer ?'],\nAnd if we want a delay of 10 seconds before the following program is executed: :\n[ ['curl','https://pidomotique/connecte.php,'--insecure'] , ''   ,'Connect the printer ?',10],\nExample of printer control via octoprint (f you have it...): \n   send a G-code (see https://marlinfw.org/meta/gcode/ for others G-codes)\n   here : temperature setting of the plate \n- Replace the XXX after X-Api-Key: by your API key (found in the octoprint parameters)\n- Replace http://octopi.local by the url with which you access octoprint\n- Change the value 050 in \"M140 S050\". S050 indicates that you need to heat to 50\u00b0.\n     if you want 60\u00b0, replace S050 by S060\n- 2 lines to copy after having adapted it:\n  [  [  'curl','-H', 'Content-Type: application/json','-H', 'X-Api-Key: XXXXXXXXXXXXXXXXXXXXX', '-X', 'POST',\n            '-d {\"command\":\"M140 S050\"}','http://octopi.local/api/printer/command' ] , '','Warm up the printer plate ?' ],\n\n\n\"\"\"\n\n\ncommandes=[\n# insert your lines here.\n#  [ ['calc.exe'                                         ] ,''    ,'Lancer la calculatrice ?',2],\n#  [ ['C:\\\\Program Files\\\\Ultimaker Cura 5.2.1\\\\Ultimaker-Cura.exe'] ,'.stl','Lancer Cura ?'           ],\n#  [  ['curl','http://pidomotique/connecte.php'              ] , ''   ,'Allumer et connecter l\\'imprimante ?',4],\n#  [  [  'curl','-H', 'Content-Type: application/json','-H', 'X-Api-Key: XXXXXXXXXXXXXXXXXXXXX', '-X', 'POST',\n#            '-d {\"command\":\"M140 S050\"}','http://octopi.local/api/printer/command' ] , '','Warm up the printer plate ?' ],\n# 2 jeedom command that I use. Put a # at the begining of the 2 lines.\n  [  ['curl', 'https://pijeedom/core/api/jeeApi.php?apikey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&type=cmd&id=4042','--insecure' ] , ''   ,'Turn on and connect printer ?',10],\n  [  ['curl','https://pijeedom/core/api/jeeApi.php?apikey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&type=cmd&id=4048','--insecure'  ] , ''   ,'Heat the bed ?'],\n  [  ['C:\\\\Program Files\\\\Mozilla Firefox\\\\firefox.exe','https://octopi'],'','Launch Octoprint ?'],\n\n\n\n           ]\n\n\n#===============\n#Initialisations\n#===============\ndictionnaireOrigineDeviation={}\nmw = Gui.getMainWindow()\nindiceCommandeEtParam=0\nindiceExtFileNameParamCommandeALancer=1\nindiceTextAutreCommandeALancer=2\nindiceDelai=3\n\n# UI Class definitions\nclass BoiteDialogueSTLGuiClass(QtWidgets.QDialog):\n\n    def  __init__(self, parent=None):\n        super(BoiteDialogueSTLGuiClass, self).__init__(parent)\n        self.initUI()\n\n    def initUI(self):\n        self.tabCheckboxTextCommandes=[] # table of checkbox commands to run\n        self.setGeometry( 250, 250, 400, 150)\n        self.setWindowTitle(\"Export and launch software\")\n        lay = QtWidgets.QGridLayout(self)\n\n        # checkboxs\n        self.checkboxGenererSTL = QtWidgets.QCheckBox(\"Generate STL ?\", self)\n        self.checkboxGenererSTL.setCheckState(QtCore.Qt.Checked)\n        lay.addWidget(self.checkboxGenererSTL, 0, 0)\n        if doitLancerFichier :\n            self.checkboxLancerSTL = QtWidgets.QCheckBox(\"Launch the slicer ?\", self)\n            self.checkboxLancerSTL.setCheckState(QtCore.Qt.Checked)\n            lay.addWidget(self.checkboxLancerSTL, 2, 0)\n\n        for posLigne, cmd in enumerate(commandes, start=3):\n           textCommande=cmd[indiceTextAutreCommandeALancer]\n           self.checkboxTextCommande = QtWidgets.QCheckBox(textCommande, self)\n           # storing this checkbox in a table :\n           self.tabCheckboxTextCommandes.append(self.checkboxTextCommande)\n           self.checkboxTextCommande.setCheckState(QtCore.Qt.Checked)\n           lay.addWidget(self.checkboxTextCommande, posLigne, 0)\n\n        # numeric input field\n        self.label2 = QtWidgets.QLabel('Accuracy (param deviation)\\nbetween 0.01 and 1\\n' +\n            '0.01 for high quality', self)\n        lay.addWidget(self.label2, 0, 1)\n\n        self.precision = QtWidgets.QDoubleSpinBox(self)\n        self.precision.setValue(deviation)\n        self.precision.setRange(0.01,1)\n        self.precision.setSingleStep(0.01)\n        self.precision.setToolTip('The larger the number, the larger the file size\\n' +\n            'and the better the accuracy.\\n' +\n            'See the deviation parameter in FreeCAD')\n        lay.addWidget(self.precision, 0, 2)\n\n        butBox = QtWidgets.QDialogButtonBox(self)\n        butBox.setOrientation(QtCore.Qt.Horizontal)\n        butBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok)\n        lay.addWidget(butBox)\n        butBox.accepted.connect(self.accept)\n        butBox.rejected.connect(self.reject)\n\n        self.setLayout(lay)\n\n\n#===============\n#functions\n#===============\ndef octopi(api,commande,urlOctopi,apiKey) :\n    \"\"\"\n    Function that returns the parameter to pass to subprocess.Popen if you \n    want to run an octopi API. Not used here. But for memory purposes \n    and a future evolution\n\n    Arguments :\n        api : the api to run ex: '/api/printer/command'\n        commande : the command of the API in question ex: '{\"command\": \"M140 S050\"}'\n        urlOctoprint : the url of your octopi ex : 'https://octopi.local'\n        apiKey : the API key you find in setting/API of octoprint\n    Returns :\n\n   Example\n       API running a gcode. Here the heating of the printer plate\n       subprocess.Popen(\n                          octopi(\n                                '/api/printer/command',\n                                '{\"command\":\"M140 S050\"}',\n                                'https://octopi.local',\n                                'XXXXKEYXAPIXXXXXXXX'))\n                 ,close_fds=True)\n    \"\"\"\n    commandeCurl=[\n    'curl','-H', 'Content-Type: application/json','-H',\n         'X-Api-Key: '+apiKey,\n         '-X', 'POST',\n        '-d '+commande,urlOctopi+api\n    ]\n    return commandeCurl\n\n\ndef nameFileStl(dictionnaireOrigineDeviation,mw=Gui.getMainWindow()):\n    \"\"\"\n    Function that determines and returns the file name including path\n    where the stl will be saved\n    The FreeCAD document containing the dictionary objects must be\n    opened and saved\n\n    Arguments :\n        dictionaryOrigineDeviation (dictionary) :\n            a dictionary whose keys are FreeCAD solids.\n            the filename will be obtained from the filename of the\n            of the document containing the first object (solid) of this\n            dictionary\n\n    Returns :\n        '' if the document does not exist,\n        otherwise the name of the file where the stl will be saved\n\n    Example\n    \"\"\"\n\n    doc=list(dictionnaireOrigineDeviation.keys())[0].Document\n    if doc is None:\n        QtWidgets.QMessageBox.information(mw,'Warning',\\\n            \"You do not have a document open\")\n        return ''\n    if doc.FileName=='':\n        QtWidgets.QMessageBox.information(mw,\n             'Warning','Save your document before restarting the order')\n        return ''\n    return(os.path.splitext(doc.FileName)[0]+'.stl')\n\ndef memoriseObjEtDeviation(selection,deviationImpose):\n    \"\"\"\n    Memorises the solids that are contained in selection and their\n    deviation property and replaces it with the value\n    of deviationImpose\n    It imposes a subsequent recompute by a touch.\n    Recompute() must eventually be run after\n\n    Arguments :\n        selection: a selection of objects\ndeviationImpose (float): value that we want to impose to deviation.\n\n    Returns:\n        a dictionary containing the object in key and the deviation in value\n        Returns {} if there is no suitable object in the selection\n\n    Example:\n        memoriseObjEtDeviation(Gui.Selection.getSelection(),deviation)\n    \"\"\"\n    dicoObjDeviation={}\n    for objData in selection :\n        if objData.isDerivedFrom('Part::Feature') \\\n          and not objData.isDerivedFrom('PartDesign::Feature')\\\n          and not objData.isDerivedFrom('Part::Part2DObject'):\n            dicoObjDeviation[objData]=objData.ViewObject.Deviation\n            objData.ViewObject.Deviation=deviationImpose\n           # pour imposer un recompute m\u00eame si la d\u00e9viation est plus petite\n           # qu'avant :\n            objData.touch()\n            for o in objData.ViewObject.claimChildren():\n                    o.touch()\n    return dicoObjDeviation\n\ndef restitueDeviation(dicoOrigineDeviation):\n    \"\"\"\n Function that replaces the deviation property in the objects\n    It imposes a recompute by a touch. recompute() must be\n    run after\n\n    Arguments:\n        dicoOrigineDeviation a dictionary containing the object in key\n        and the value to be imposed in the deviation property of the object\n        in value\n\n    Returns: Does not return anything\n\n    Example:\n        restitueDeviation(dicoOrigineDeviation)\n\n    \"\"\"\n    for ob2 in dicoOrigineDeviation:\n        ob2.ViewObject.Deviation=dicoOrigineDeviation[ob2]\n        # to impose a recompute even if the deviation is smaller\n        # than before:\n        ob2.touch()\n        for o in ob2.ViewObject.claimChildren():\n            o.touch()\n\ndef openFile(fileName):\n    \"\"\"\n function that launches a file depending on the operating system\n    checked for now only under windows\n\n    Arguments:\n        fileName (string) the name of the file to run\n\n    Returns\n        Does not return anything\n\n    Example:\n        openFile(unfichier.stl)\n        openFile(calc.exe)\n    \"\"\"\n    if sys.platform == \"win32\":\n        os.startfile(fileName)\n    else:\n        opener =\"open\" if sys.platform == \"darwin\" else \"xdg-open\"\n        subprocess.Popen([opener, fileName],close_fds=True)\n\ndef recalcul(dicoObjs):\n    \"\"\"\n    launches a recompute for each Document of the dico objects\n    only if it has not already been done\n    Arguments:\n        dicoObjs a dictionary containing the object in key\n\n    Returns\n        Does not return anything\n\n    Example:\n        recalcul(dicoMesObjets)\n    \"\"\"\n    docDejaRecalcul=[]\n    for obj in dicoObjs:\n        if obj.Document not in docDejaRecalcul:\n            obj.Document.recompute()\n            docDejaRecalcul.append(obj.Document)\n\ndef lanceCommmandes(commandesAlancer,fileStlName,formBoiteDialogueSTL):\n    \"\"\"\n    launch the orders\n    Arguments:\n        commandesAlancer in the form of an array of arrays\n        [ ['command to execute', 'param 1', param 2, ] ,'.extention','question to ask',delay ],\n          ['command to execute', 'param 1', param 2, ] ,'.extention','question to ask',delay ],\n          ...\n        ]\n         'command to execute' : the command you want to execute.\n         For example 'myProgram.exe' if need, put also its path.\n         param 1, param2... ' : if your program needs parameters.\n            Will only be taken into account if extention=''.\n         'extention': if not empty, parameter param 1 will be the name of your\n              FreeCAD file but with your extension :\n         question to ask': the question to display in the dialog box\n         delay: waiting time in seconds before going to the next command.\n\n    Returns\n         Do not return anything\n\n    Example:\n        lanceCommmandes(commandes,fileStlName,formBoiteDialogueSTL) # runs the commands described in commands\n    \"\"\"\n\n    for tbktc in formBoiteDialogueSTL.tabCheckboxTextCommandes :\n        if tbktc.isChecked() :\n            i= formBoiteDialogueSTL.tabCheckboxTextCommandes.index(tbktc)\n            commande=commandesAlancer[i]\n            commandeEtParam=commande[indiceCommandeEtParam]\n            extFileNameParamCommandeALancer=commande[indiceExtFileNameParamCommandeALancer]\n            textAutreCommandeALancer=commande[indiceTextAutreCommandeALancer]\n            delai=0\n            try :\n               if commande[indiceDelai:indiceDelai+1]!=[] : #if the user has entered a delay\n                  delai=commande[indiceDelai]\n            except :\n               print ('Delay not taken into account because of invalid numerical value'+\n                      'for the command '+ textAutreCommandeALancer)\n            if delai > delaiMax :\n                delai=delaiMax\n\n            if extFileNameParamCommandeALancer!='':\n                if commandeEtParam[2:3]==[]  : # There is no parameter.\n                   # We add a parameter to put our file name\n                   # with our extension.\n                   commandeEtParam.append('')\n                commandeEtParam[1]=   os.path.splitext(fileStlName)[0]+  extFileNameParamCommandeALancer\n            subprocess.Popen(commandeEtParam,close_fds=True)\n            print(commandeEtParam)\n            time.sleep(delai)# Pause time (seconds)\n\n\ndef run(objs=Gui.Selection.getSelection(), dev=deviation):\n    \"\"\"\n    main function\n    Arguments:\n        doc: the active document\n        objs : the objects that have been selected beforehand\n        dev : the value of the deviation property which will be\n              imposed before the generation of the stl\n\n    Returns\n        Returns nothing\n\n    Example:\n        run()\n    \"\"\"\n\n   #check if at least one solid (body and similar) has been selected\n    nbBody=0\n    for objData in objs :\n        if objData.isDerivedFrom('Part::Feature') \\\n          and not objData.isDerivedFrom('PartDesign::Feature')\\\n          and not objData.isDerivedFrom('Part::Part2DObject'):\n          nbBody=nbBody+1\n\n    if nbBody==0: #  if we haven't found any solids, we have to have an active one\n         try:\n            objs=[]\n            objs.append(Gui.ActiveDocument.ActiveView.getActiveObject('pdbody'))\n            response=QtWidgets.QMessageBox.information(mw, 'Warning',\\\n            '-You did not select a solid. Automatic solid selection : '+objs[0].Label +\n            ' by the macro..\\n-If not adequate, select one or more solids before running the macro',\n                  QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel )\n            if response==QtWidgets.QMessageBox.Cancel :\n              return\n         except :\n            QtWidgets.QMessageBox.information(mw, 'Warning',\\\n            '--Select one or more solids before running the macro')\n            return\n\n# Dialog box of what we want to do\n    formBoiteDialogueSTL=BoiteDialogueSTLGuiClass(mw)\n    if not formBoiteDialogueSTL.exec_() :\n        return\n    dev=formBoiteDialogueSTL.precision.value()\n    # we memorize the selected solids and their deviation,\n    # we make a touch() of their child to be taken into account in recompute :\n    dictionnaireOrigineDeviation=memoriseObjEtDeviation(objs,dev)\n    if len(dictionnaireOrigineDeviation)==0: # if no solids were found\n        QtWidgets.QMessageBox.information(mw, 'Warning',\\\n            '-Select one or more solids before running the macro')\n        return\n    # we get the name of the file where we have to save the stl\n    fileStlName=nameFileStl(dictionnaireOrigineDeviation)\n    if fileStlName == '' :\n        return\n    #The solids in dictionaryOriginDeviation are passed as parameters\n    if formBoiteDialogueSTL.checkboxGenererSTL.isChecked():\n       Mesh.export(list(dictionnaireOrigineDeviation.keys()), fileStlName)\n       print('Export done')\n    # restitution of the original property deviation for all solids :\n    restitueDeviation(dictionnaireOrigineDeviation)\n    recalcul(dictionnaireOrigineDeviation)\n\n    if formBoiteDialogueSTL.checkboxLancerSTL.isChecked():\n            #runs for example cura if cura has been associated with *.stl files\n            openFile(fileStlName)\n\n    lanceCommmandes(commandes,fileStlName,formBoiteDialogueSTL)\n            # runs the commands described in commands\n\n\nif __name__ == '__main__':\n    run()\n",
    "url": "https://wiki.freecad.org/Macro_3D_Printer_Workflow",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/Macro_3D_Printer_Workflow",
    "version": "2023/02/05",
    "license": "",
    "date": "2023/02/05",
    "src_filename": "",
    "filename_from_url": "",
    "author": "2cv001",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_3D_Printer_Workflow.png",
    "icon_source": "https://wiki.freecadweb.org/images/b/b4/Macro_3D_Printer_Workflow.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FreeCAD to Kerkythea",
    "on_wiki": true,
    "on_git": false,
    "desc": "Macro to export your model to the raytracing program <a rel=\"nofollow\" class=\"external text\" href=\"http://www.kerkythea.net/cms/\">Kerkythea</a>.<br /><br />Macro version: 1.0<br />Last modified: 2015-05-30<br />FreeCAD version: 0.17 and above<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/8/8c/Macro_FreeCAD_to_Kerkythea.png\">ToolBar Icon</a><br />Author: marmni<br /> ",
    "comment": "Macro to export your model to the raytracing program Kerkythea.",
    "code": "# -*- coding: utf8 -*-\n#**************************************************************************************\n#*                                                                                    *\n#*   Kerkythea exporter                                                               *\n#*   Copyright (c) 2014,2015                                                          *\n#*   marmni <marmni@onet.eu>                                                          *\n#*                                                                                    *\n#*   This program is free software; you can redistribute it and/or modify             *\n#*   it under the terms of the GNU Lesser General Public License (LGPL)               *\n#*   as published by the Free Software Foundation; either version 2 of                *\n#*   the License, or (at your option) any later version.                              *\n#*   for detail see the LICENCE text file.                                            *\n#*                                                                                    *\n#*   This program is distributed in the hope that it will be useful,                  *\n#*   but WITHOUT ANY WARRANTY; without even the implied warranty of                   *\n#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *\n#*   GNU Library General Public License for more details.                             *\n#*                                                                                    *\n#*   You should have received a copy of the GNU Library General Public                *\n#*   License along with this program; if not, write to the Free Software              *\n#*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307             *\n#*   USA                                                                              *\n#*                                                                                    *\n#**************************************************************************************\n\n#**************************************************************************************\n#*                                                                                    *\n#*                                 BASED ON                                           *\n#*                                                                                    *\n#* IOANNIS PANTAZOPOULOS                                                              *\n#*                                                                                    *\n#* Sample code exporting basic Kerkythea XML file.                                    *\n#*                                                                                    *\n#* Version v1.0                                                                       *\n#*                                                                                    *\n#**************************************************************************************\n\n__title__=\"Kerkythea exporter\"\n__author__ = \"marmni <marmni@onet.eu>\"\n__url__ = [\"http://www.freecadweb.org\"]\n\n\nimport FreeCAD, FreeCADGui\nimport re\nimport random\nimport __builtin__\nimport Mesh\nfrom PySide import QtCore, QtGui\nimport sys\nimport os\n\n\n##############################################\n#\n##############################################\nclass point3D:\n\tdef __init__(self, point):\n\t\tself.x = \"%.4f\" % (point[0] * 0.001)\n\t\tself.y = \"%.4f\" % (point[1] * 0.001)\n\t\tself.z = \"%.4f\" % (point[2] * 0.001)\n\n\tdef __str__(self):\n\t\treturn '<P xyz=\"{0} {1} {2}\"/>'.format(self.x, self.y, self.z)\n\n\t#def __eq__(self, other):\n\t\t#if self.x == other.x and self.y == other.y and self.z == other.z:\n\t\t\t#return True\n\t\t#else:\n\t\t\t#return False \n\n\n##############################################\n#\n##############################################\nclass indexListPoint3D:\n\tdef __init__(self, point):\n\t\tself.i = point[0]\n\t\tself.j = point[1]\n\t\tself.k = point[2]\n\n\tdef __str__(self):\n\t\treturn '<F ijk=\"{0} {1} {2}\"/>'.format(self.i, self.j, self.k)\n\n\n##############################################\n#\n##############################################\nclass Material:\n\tdef __init__(self):\n\t\tself.diffuse = None  # Texture()\n\t\tself.shininess = 1000.0\n\t\tself.ior = 2.0\n\n\tdef write(self, file):\n\t\tfile.write('''<Object Identifier=\"Whitted Material\" Label=\"Whitted Material\" Name=\"\" Type=\"Material\">\\n''')\n\n\t\tself.diffuse.write(file, \"Diffuse\")\n\t\tself.diffuse.write(file, \"Translucent\")\n\t\tself.diffuse.write(file, \"Specular\")\n\t\tself.diffuse.write(file, \"Transmitted\")\n\n\t\tfile.write('''<Parameter Name=\"Shininess\" Type=\"Real\" Value=\"{shininess}\"/>\n<Parameter Name=\"Transmitted Shininess\" Type=\"Real\" Value=\"{shininess}\"/>\n<Parameter Name=\"Index of Refraction\" Type=\"Real\" Value=\"{ior}\"/>\n</Object>\\n'''.format(shininess=self.shininess, ior=self.ior))\n\n\n##############################################\n#\n##############################################\nclass Texture:\n\tdef __init__(self, color):\n\t\tself.color = color\n\t\t\n\tdef getColorSTR(self):\n\t\treturn '{0} {1} {2}'.format(self.color[0], self.color[1], self.color[2])\n\n\tdef toGrayscale(self):\n\t\tRGB = 0.299 * self.color[0] + 0.587 * self.color[1] + 0.114 * self.color[2]\n\t\tself.color = [RGB, RGB, RGB]\n\n\tdef write(self, file, identifier):\n\t\tfile.write('''<Object Identifier=\"./{identifier}/Constant Texture\" Label=\"Constant Texture\" Name=\"\" Type=\"Texture\">\n<Parameter Name=\"Color\" Type=\"RGB\" Value=\"{color}\"/>\n</Object>\\n'''.format(identifier=identifier, color=self.getColorSTR()))\n\n\n##############################################\n#\n##############################################\nclass Model:\n\tdef __init__(self):\n\t\tself.vertexList = []\n\t\tself.normalList = []\n\t\tself.indexList = []\n\t\t\n\t\tself.name = self.wygenerujID(5, 5)\n\t\tself.material = Material()\n\t\t\n\tdef addFace(self, face):\n\t\tmesh = self.meshFace(face)\n\t\tfor pp in mesh.Facets:\n\t\t\tnum = len(self.vertexList)\n\t\t\tfor kk in pp.Points:\n\t\t\t\tself.vertexList.append(point3D(kk))\n\t\t\tself.indexList.append(indexListPoint3D([num, num + 1, num + 2]))\n\t\t\n\tdef meshFace(self, shape):\n\t\tfaces = []\n\t\ttriangles = shape.tessellate(1) # the number represents the precision of the tessellation\n\t\tfor tri in triangles[1]:\n\t\t\tface = []\n\t\t\tfor i in range(3):\n\t\t\t\tvindex = tri[i]\n\t\t\t\tface.append(triangles[0][vindex])\n\t\t\tfaces.append(face)\n\t\tm = Mesh.Mesh(faces)\n\t\t#Mesh.show(m)\n\t\treturn m\n\t\t\n\tdef wygenerujID(self, ll, lc):\n\t\t''' generate random model name '''\n\t\tnumerID = \"\"\n\n\t\tfor i in range(ll):\n\t\t\tnumerID += random.choice('abcdefghij')\n\t\tnumerID += \"_\"\n\t\tfor i in range(lc):\n\t\t\tnumerID += str(random.randrange(0, 99, 1))\n\t\t\n\t\treturn numerID\n\n\tdef write(self, file):\n\t\tfile.write('''\n<Object Identifier=\"./Models/{name}\" Label=\"Default Model\" Name=\"{name}\" Type=\"Model\"> \n<Object Identifier=\"Triangular Mesh\" Label=\"Triangular Mesh\" Name=\"\" Type=\"Surface\">\n<Parameter Name=\"Vertex List\" Type=\"Point3D List\" Value=\"{pointListSize}\">\\n'''.format(name=self.name, pointListSize=len(self.vertexList)))\n\n\t\tfor i in self.vertexList:\n\t\t\tfile.write('{0}\\n'.format(i))\n\n\t\tfile.write('''</Parameter>\n<Parameter Name=\"Normal List\" Type=\"Point3D List\" Value=\"{pointListSize}\">\\n'''.format(pointListSize=len(self.vertexList)))\n\t\tfile.write('<P xyz=\"0 0 -1\"/>\\n' * len(self.vertexList))\n\t\tfile.write('''</Parameter>\n<Parameter Name=\"Index List\" Type=\"Triangle Index List\" Value=\"{indexListSize}\">\\n'''.format(indexListSize=len(self.indexList)))\n\n\t\tfor i in self.indexList:\n\t\t\tfile.write('{0}\\n'.format(i))\n\n\t\tfile.write('''</Parameter>\\n</Object>\\n''')\n\n\t\tself.material.write(file)\n\t\t\n\t\tfile.write('</Object>\\n')\n\n\n##############################################\n#\n##############################################\nclass Camera:\n\tdef __init__(self):\n\t\tself.name = \"Camera_1\"\n\t\tself.f_number = \"Pinhole\"\n\t\tself.resolution = \"1024x768\"\n\t\tself.focusDistance = \"1\"\n\t\tself.lensSamples = \"3\"\n\t\tself.blades = \"3\"\n\t\tself.diaphragm = \"Circular\"\n\t\tself.projection = \"Planar\"\n\n\tdef addParameter(self, name, pType, value):\n\t\treturn '<Parameter Name=\"{0}\" Type=\"{1}\" Value=\"{2}\"/>\\n'.format(name, pType, value)\n\t\t\n\tdef write(self, file):\n\t\tcam = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()\n\t\tcamValues = cam.position.getValue()\n\t\t\n\t\tx = \"%.4f\" % (30 * .0254)\n\t\ty = \"%.4f\" % (30 * .0254)\n\t\tz = \"%.4f\" % (30 * .0254)\n\t\t\n\t\tfile.write('<Object Identifier=\"./Cameras/{0}\" Label=\"Pinhole Camera\" Name=\"{0}\" Type=\"Camera\">\\n'.format(self.name))\n\t\tfile.write(self.addParameter(\"Resolution\", \"String\", self.resolution))\n\t\tfile.write(self.addParameter(\"Frame\", \"Transform\", \"-0.609474 0.471636 -0.63726 {0} 0.792806 0.362576 -0.489895 {1} 2.70762e-06 -0.803802 -0.594897 {2}\".format(x, y, z)))\n\t\tfile.write(self.addParameter(\"Focus Distance\", \"Real\", self.focusDistance))\n\t\tfile.write(self.addParameter(\"f-number\", \"String\", self.f_number))\n\t\tfile.write(self.addParameter(\"Lens Samples\", \"Integer\",self.lensSamples ))\n\t\tfile.write(self.addParameter(\"Blades\", \"Integer\", self.blades))\n\t\tfile.write(self.addParameter(\"Diaphragm\", \"String\", self.diaphragm))\n\t\tfile.write(self.addParameter(\"Projection\", \"String\", self.projection))\n\t\tfile.write('</Object>\\n')\n\n\n##############################################\n#\n##############################################\nclass exportTokerkythea:\n\tdef __init__(self):\n\t\tself.models = []\n\t\tself.cameras = []\n\t\tmodelsMultiColors = False\n\n\tdef write(self, file, name):\n\t\tfile = __builtin__.open(file, \"w\")\n\t\t#\n\t\tself.writeHeader(file, name)\n\t\t\n\t\tif self.modelsMultiColors:\n\t\t\tfor i, j in self.models.items():\n\t\t\t\tfile.write('<Object Identifier=\"./Models/{0}\" Label=\"Default Model\" Name=\"{0}\" Type=\"Model\">\\n'.format(i))\n\t\t\t\tfor k in j:\n\t\t\t\t\tk.write(file)\n\t\t\t\tfile.write('</Object>\\n')\n\t\telse:\n\t\t\tfor i in self.models.values():\n\t\t\t\ti.write(file)\n\t\t# CAMERA\n\t\tactiveCamera = self.cameras[0][0].name\n\t\tfor i in self.cameras:\n\t\t\ti[0].write(file)\n\t\t\tif i[1]:\n\t\t\t\tactiveCamera = i[0].name\n\t\t#\n\t\tfile.write('<Parameter Name=\"./Cameras/Active\" Type=\"String\" Value=\"{0}\"/>\\n'.format(activeCamera))\n\n\t\tself.writeFooter(file, name)\n\n\tdef writeHeader(self, file, name):\n\t\tfile.write('''<Root Label=\"Kernel\" Name=\"\" Type=\"Kernel\">\n<Object Identifier=\"./Ray Tracers/Metropolis Light Transport\" Label=\"Metropolis Light Transport\" Name=\"Metropolis Light Transport\" Type=\"Ray Tracer\">\n</Object>\n<Object Identifier=\"./Environments/Octree Environment\" Label=\"Octree Environment\" Name=\"Octree Environment\" Type=\"Environment\">\n</Object>\n<Object Identifier=\"./Filters/Simple Tone Mapping\" Label=\"Simple Tone Mapping\" Name=\"\" Type=\"Filter\">\n</Object>\n<Object Identifier=\"./Scenes/{0}\" Label=\"Default Scene\" Name=\"{0}\" Type=\"Scene\">\\n\n'''.format(name))\n\n\tdef writeFooter(self, file, name):\n\t\tfile.write('''</Object>\n<Parameter Name=\"Mip Mapping\" Type=\"Boolean\" Value=\"1\"/>\n<Parameter Name=\"./Interfaces/Active\" Type=\"String\" Value=\"Null Interface\"/>\n<Parameter Name=\"./Modellers/Active\" Type=\"String\" Value=\"XML Modeller\"/>\n<Parameter Name=\"./Image Handlers/Active\" Type=\"String\" Value=\"Free Image Support\"/>\n<Parameter Name=\"./Ray Tracers/Active\" Type=\"String\" Value=\"Metropolis Light Transport\"/>\n<Parameter Name=\"./Irradiance Estimators/Active\" Type=\"String\" Value=\"Null Irradiance Estimator\"/>\n<Parameter Name=\"./Direct Light Estimators/Active\" Type=\"String\" Value=\"Null Direct Light Estimator\"/>\n<Parameter Name=\"./Environments/Active\" Type=\"String\" Value=\"Octree Environment\"/>\n<Parameter Name=\"./Filters/Active\" Type=\"String\" Value=\"Simple Tone Mapping\"/>\n<Parameter Name=\"./Scenes/Active\" Type=\"String\" Value=\"{0}\"/>\n<Parameter Name=\"./Libraries/Active\" Type=\"String\" Value=\"Material Librarian\"/>\n</Root>'''.format(name))\n\n\n##############################################\n#\n##############################################\n\nclass exportKerkytheaDialog(QtGui.QDialog):\n\tdef __init__(self, parent=None):\n\t\tQtGui.QDialog.__init__(self, parent)\n\n\t\tself.setWindowTitle(u'Export to Kerkythea v1.1')\n\t\tself.setFixedSize(500, 550)\n\n\t\t#\n\t\tself.buttonAccept = QtGui.QPushButton('Accept')\n\t\t#\n\t\ttab = QtGui.QTabWidget()\n\t\ttab.addTab(self.addGeneralPage(), u'General')\n\t\ttab.addTab(self.addLightsPage(), u'Light')\n\t\ttab.addTab(self.addCmerasPage(), u'Camera')\n\t\t#\n\t\tlay = QtGui.QVBoxLayout(self)\n\t\tlay.addWidget(tab)\n\t\tlay.addWidget(self.buttonAccept)\n\n\tdef changePathF(self):\n\t\tpath = QtGui.QFileDialog().getSaveFileName(self, u\"Save as\", os.path.expanduser(\"~\"), \"*.xml\")\n\t\t\n\t\tfileName = path[0]\n\t\tif not fileName == \"\":\n\t\t\tif not fileName.endswith('xml'):\n\t\t\t\tfileName = fileName + '.xml'\n\t\t\tself.filePath.setText(fileName)\n\t\t\t\n\tdef addGeneralPage(self):\n\t\tself.filePath = QtGui.QLineEdit(os.path.join(os.path.expanduser(\"~\"), 'Unnamed.xml'))\n\t\tself.filePath.setReadOnly(True)\n\n\t\tchangePath = QtGui.QPushButton('...')\n\t\tchangePath.setFixedWidth(30)\n\t\tself.connect(changePath, QtCore.SIGNAL(\"clicked ()\"), self.changePathF)\n\n\t\tgeneralBox = QtGui.QGroupBox(u'General')\n\t\tgeneralBoxLay = QtGui.QGridLayout(generalBox)\n\t\tgeneralBoxLay.addWidget(QtGui.QLabel(u'Path           '), 0, 0, 1, 1)\n\t\tgeneralBoxLay.addWidget(self.filePath, 0, 1, 1, 2)\n\t\tgeneralBoxLay.addWidget(changePath, 0, 3, 1, 1)\n\n\t\tgeneralBoxLay.setColumnStretch(1, 10)\n\t\t#\n\t\tself.exportObjects_All = QtGui.QRadioButton(u'All visible objects')\n\t\tself.exportObjects_All.setChecked(True)\n\t\tself.exportObjects_Selected = QtGui.QRadioButton(u'All selected objects')\n\t\tself.exportObjects_SelectedFaces = QtGui.QRadioButton(u'All selected faces')\n\t\tself.exportObjects_SelectedFaces.setDisabled(True)\n\t\t\n\t\texportObjectsBox = QtGui.QGroupBox(u'Export objects')\n\t\texportObjectsBoxLay = QtGui.QVBoxLayout(exportObjectsBox)\n\t\texportObjectsBoxLay.addWidget(self.exportObjects_All)\n\t\texportObjectsBoxLay.addWidget(self.exportObjects_Selected)\n\t\texportObjectsBoxLay.addWidget(self.exportObjects_SelectedFaces)\n\t\t#\n\t\tself.exportObjectsAs_YES = QtGui.QRadioButton(u'Yes')\n\t\tself.exportObjectsAs_YES.setChecked(True)\n\t\tself.exportObjectsAs_NO = QtGui.QRadioButton(u'No')\n\t\t\n\t\texportObjectsAsBox = QtGui.QGroupBox(u'Group models by color')\n\t\texportObjectsAsBoxLay = QtGui.QVBoxLayout(exportObjectsAsBox)\n\t\texportObjectsAsBoxLay.addWidget(self.exportObjectsAs_YES)\n\t\texportObjectsAsBoxLay.addWidget(self.exportObjectsAs_NO)\n\t\t#\n\t\tself.exportObjectColor_MulCol = QtGui.QRadioButton(u'Multi colors')\n\t\tself.exportObjectColor_Gray = QtGui.QRadioButton(u'Grayscale')\n\t\tself.exportObjectColor_SinCol = QtGui.QRadioButton(u'Single color (random)')\n\t\tself.exportObjectColor_SinCol.setChecked(True)\n\n\t\tself.exportObjectColorBox = QtGui.QGroupBox(u'Colors')\n\t\tself.exportObjectColorBox.setDisabled(True)\n\t\texportObjectColorBoxLay = QtGui.QVBoxLayout(self.exportObjectColorBox)\n\t\texportObjectColorBoxLay.addWidget(self.exportObjectColor_MulCol)\n\t\texportObjectColorBoxLay.addWidget(self.exportObjectColor_Gray)\n\t\texportObjectColorBoxLay.addWidget(self.exportObjectColor_SinCol)\n\t\t#####\n\t\twidget = QtGui.QWidget()\n\t\t\n\t\tlay = QtGui.QGridLayout(widget)\n\t\tlay.addWidget(generalBox, 0, 0, 1, 4)\n\t\tlay.addWidget(exportObjectsBox, 1, 0, 1, 4)\n\t\tlay.addWidget(exportObjectsAsBox, 2, 0, 1, 2)\n\t\tlay.addWidget(self.exportObjectColorBox, 2, 2, 1, 2)\n\t\t\n\t\tlay.setRowStretch(10, 10)\n\t\t#lay.setColumnStretch(10, 10)\n\t\treturn widget\n\t\t\n\tdef addLightsPage(self):\n\t\twidget = QtGui.QWidget()\n\t\t\n\t\treturn widget\n\t\t\n\tdef addCmerasPage(self):\n\t\tself.resolution = QtGui.QComboBox()\n\t\tself.resolution.addItems(['200x200', '320x200', '320x240', '500x500', '512x384', '640x480', '768x576', '800x600', '1024x768', '1280x1024', '1600x1200', '2048x1536', '2816x2112'])\n\t\tself.resolution.setCurrentIndex(self.resolution.findText('1024x768'))\n\n\t\tself.cameraName = QtGui.QLineEdit(u'Camera 1')\n\n\t\tfilmBox = QtGui.QGroupBox(u'General')\n\t\tfilmBoxLay = QtGui.QGridLayout(filmBox)\n\t\tfilmBoxLay.addWidget(QtGui.QLabel(u'Camera name'), 0, 0, 1, 1)\n\t\tfilmBoxLay.addWidget(self.cameraName, 0, 1, 1, 1)\n\t\tfilmBoxLay.addWidget(QtGui.QLabel(u'Resolution'), 1, 0, 1, 1)\n\t\tfilmBoxLay.addWidget(self.resolution, 1, 1, 1, 1)\n\n\t\tfilmBoxLay.setHorizontalSpacing(50)\n\t\t#\n\t\tself.fNumber = QtGui.QComboBox()\n\t\tself.fNumber.addItems(['1', '1.4', '2', '2.8', '4', '5.6', '8', '16', '22', 'Pinhole'])\n\t\tself.fNumber.setCurrentIndex(self.fNumber.findText('Pinhole'))\n\n\t\tself.focusDistance = QtGui.QDoubleSpinBox()\n\t\tself.focusDistance.setValue(1.0)\n\t\tself.focusDistance.setRange(0.0, 1000.0)\n\n\t\tself.lensSamples = QtGui.QSpinBox()\n\t\tself.lensSamples.setValue(3)\n\t\tself.lensSamples.setRange(0, 1000)\n\n\t\tlensBox = QtGui.QGroupBox(u'Lens')\n\t\tlensBoxLay = QtGui.QGridLayout(lensBox)\n\t\tlensBoxLay.addWidget(QtGui.QLabel(u'f-number'), 0, 0, 1, 1, QtCore.Qt.AlignHCenter)\n\t\tlensBoxLay.addWidget(self.fNumber, 1, 0, 1, 1)\n\t\tlensBoxLay.addWidget(QtGui.QLabel(u'Focus Distance'), 0, 1, 1, 1, QtCore.Qt.AlignHCenter)\n\t\tlensBoxLay.addWidget(self.focusDistance, 1, 1, 1, 1)\n\t\tlensBoxLay.addWidget(QtGui.QLabel(u'Lens Samples'), 0, 2, 1, 1, QtCore.Qt.AlignHCenter)\n\t\tlensBoxLay.addWidget(self.lensSamples, 1, 2, 1, 1)\n\n\t\tlensBoxLay.setHorizontalSpacing(50)\n\t\t#\n\t\tself.projection = QtGui.QComboBox()\n\t\tself.projection.addItems(['Planar', 'Cylindrical', 'Spherical', 'Parallel'])\n\t\tself.projection.setCurrentIndex(self.projection.findText('Planar'))\n\n\t\tself.diaphragm = QtGui.QComboBox()\n\t\tself.diaphragm.addItems(['Circular', 'Polygonal'])\n\t\tself.diaphragm.setCurrentIndex(self.diaphragm.findText('Circular'))\n\t\t\n\t\tself.blades = QtGui.QSpinBox()\n\t\tself.blades.setValue(3)\n\t\tself.blades.setRange(3, 1000)\n\n\t\tgeometryBox = QtGui.QGroupBox(u'Geometry')\n\t\tgeometryBoxLay = QtGui.QGridLayout(geometryBox)\n\t\tgeometryBoxLay.addWidget(QtGui.QLabel(u'Projection'), 0, 0, 1, 1, QtCore.Qt.AlignHCenter)\n\t\tgeometryBoxLay.addWidget(self.projection, 1, 0, 1, 1)\n\t\tgeometryBoxLay.addWidget(QtGui.QLabel(u'Diaphragm'), 0, 1, 1, 1, QtCore.Qt.AlignHCenter)\n\t\tgeometryBoxLay.addWidget(self.diaphragm, 1, 1, 1, 1)\n\t\tgeometryBoxLay.addWidget(QtGui.QLabel(u'Blades'), 0, 2, 1, 1, QtCore.Qt.AlignHCenter)\n\t\tgeometryBoxLay.addWidget(self.blades, 1, 2, 1, 1)\n\n\t\tgeometryBoxLay.setHorizontalSpacing(50)\n\t\t#\n\t\t#####\n\t\twidget = QtGui.QWidget()\n\t\tlay = QtGui.QVBoxLayout(widget)\n\t\tlay.addWidget(filmBox)\n\t\tlay.addWidget(lensBox)\n\t\tlay.addWidget(geometryBox)\n\t\tlay.addStretch(10)\n\n\t\treturn widget\n\t\t\n\n\nclass exportKerkythea(exportKerkytheaDialog):\n\tdef __init__(self, parent=None):\n\t\texportKerkytheaDialog.__init__(self, parent)\n\n\t\tself.connect(self.buttonAccept, QtCore.SIGNAL(\"clicked ()\"), self.acceptw)\n\t\tself.connect(self.exportObjectsAs_YES, QtCore.SIGNAL(\"clicked ()\"), self.setColors)\n\t\tself.connect(self.exportObjectsAs_NO, QtCore.SIGNAL(\"clicked ()\"), self.setColors)\n\n\tdef setColors(self):\n\t\tif self.exportObjectsAs_YES.isChecked():\n\t\t\tself.exportObjectColor_SinCol.setChecked(True)\n\t\t\tself.exportObjectColorBox.setDisabled(True)\n\t\telse:\n\t\t\tself.exportObjectColorBox.setDisabled(False)\n\n\tdef acceptw(self):\n\t\tif self.exportObjects_All.isChecked():\n\t\t\tprojectObjects = [i for i in FreeCAD.ActiveDocument.Objects if i.ViewObject.Visibility]\n\t\telif self.exportObjects_Selected.isChecked():\n\t\t\tprojectObjects = []\n\t\t\tfor i in FreeCADGui.Selection.getSelection():\n\t\t\t\tif i.ViewObject.Visibility and i not in projectObjects:\n\t\t\t\t\tprojectObjects.append(i)\n\t\t#\n\n\t\tprojectModels = {}\n\t\tfor i in projectObjects:  # objects in document\n\t\t\ttry:\n\t\t\t\tobjectColors = i.ViewObject.DiffuseColor\n\t\t\t\tshape = i.Shape.Faces\n\t\t\texcept:\n\t\t\t\tcontinue\n\t\t\t\t\n\t\t\tfor j in range(len(i.Shape.Faces)):  # object faces\n\t\t\t\t# get face color\n\t\t\t\tif len(objectColors) == len(i.Shape.Faces):\n\t\t\t\t\tmodelType = objectColors[j]\n\t\t\t\telse:\n\t\t\t\t\tmodelType = objectColors[0]\n\t\t\t\t#\n\t\t\t\tif self.exportObjectsAs_YES.isChecked():\n\t\t\t\t\tmodelID = str(modelType)\n\t\t\t\telse:\n\t\t\t\t\tmodelID = i.Label\n\t\t\t\t#\n\t\t\t\tif self.exportObjectColor_SinCol.isChecked():\n\t\t\t\t\tmodelsMultiColors = False\n\n\t\t\t\t\tif not modelID in projectModels:\n\t\t\t\t\t\tmodel = Model()\n\t\t\t\t\t\tif self.exportObjectsAs_NO.isChecked():\n\t\t\t\t\t\t\tmodel.name = modelID\n\t\t\t\t\t\tmodel.material.diffuse = Texture(modelType)\n\t\t\t\t\t\tprojectModels[modelID] = model\n\t\t\t\t\telse:\n\t\t\t\t\t\tmodel = projectModels[modelID]\n\t\t\t\telse:\n\t\t\t\t\tmodelsMultiColors = True\n\n\t\t\t\t\tif not modelID in projectModels:\n\t\t\t\t\t\tprojectModels[modelID] = []\n\n\t\t\t\t\tmodel = Model()\n\t\t\t\t\tmodel.name = 'Face {0}'.format(j)\n\t\t\t\t\tmodel.material.diffuse = Texture(modelType)\n\t\t\t\t\tif self.exportObjectColor_Gray.isChecked():\n\t\t\t\t\t\tmodel.material.diffuse.toGrayscale()\n\t\t\t\t\tprojectModels[modelID].append(model)\n\t\t\t\t   \n#\t\t\t\t\tmodel = Model()\n#\t\t\t\t\tmodel.material.diffuse = Texture(modelType)\n#\t\t\t\t\tprojectModels[i.Label].append(model)\n\t\t\t\t#\n\t\t\t\tmodel.addFace(i.Shape.Faces[j])\n\n\t\texporter = exportTokerkythea()\n\t   \texporter.modelsMultiColors = modelsMultiColors\n\t\texporter.models = projectModels\n\t\t# CAMERA\n\t\tcamera = Camera()\n\t\tcamera.name = self.cameraName.text()\n\t\tcamera.f_number = self.fNumber.currentText()\n\t\tcamera.resolution = self.resolution.currentText()\n\t\tcamera.focusDistance = self.focusDistance.value()\n\t\tcamera.lensSamples = self.lensSamples.value()\n\t\tcamera.blades = self.blades.value()\n\t\tcamera.diaphragm = self.diaphragm.currentText()\n\t\tcamera.projection = self.projection.currentText()\n\t\t\n\t\texporter.cameras.append([camera, True])\n\t\t#\n\t\texporter.write(self.filePath.text(), FreeCAD.ActiveDocument.Label)\n\n\t\tself.close()\n\nexportKerkythea().exec_()",
    "url": "https://wiki.freecad.org/Macro_FreeCAD_to_Kerkythea",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2015-05-30",
    "src_filename": "",
    "filename_from_url": "",
    "author": "marmni <marmni@onet.eu>",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_FreeCAD_to_Kerkythea.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/8/8c/Macro_FreeCAD_to_Kerkythea.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Z Height Map",
    "on_wiki": true,
    "on_git": false,
    "desc": "Makes a grayscale height map in Z.<br /><br />Macro version: 0.1<br />Last modified: 2022-08-28<br />Author: heda<br /> ",
    "comment": "Makes a grayscale heightmap in z",
    "code": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n# ***************************************************************************\n# *   Copyright (c) 2022 heda <heda @ freecad forum>                        *\n# *                                                                         *\n# *   This file is part of the FreeCAD CAx development system.              *\n# *                                                                         *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU Lesser General Public License (LGPL)    *\n# *   as published by the Free Software Foundation; either version 2 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENCE text file.                                 *\n# *                                                                         *\n# *   This program is distributed in the hope that it will be useful,       *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU Library General Public License for more details.                  *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with this program; if not, write to the Free Software   *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\n\n__Name__ = 'Z_height_map'\n__Comment__ = 'Makes a grayscale heightmap in z'\n__Author__ = 'heda @ fc-forum'\n__Version__ = '0.1'\n__Date__ = '2022-08-28'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = ''\n__Wiki__ = 'https://wiki.freecadweb.org/Macro_Z_height_map'\n__Icon__ = ''\n__Help__ = 'Run macro and heightmap is created.'\n__Status__ = 'Stable'\n__Requires__ = 'tested on FreeCAD v0.20'\n__Communication__ = 'forum'\n__Files__ = ''\n\n\n__doc__ = \"\"\"\nMakes the grayscale height map for all visible root objects with a volume\nfrom the active document.\n\nNo gui, options can be set in macro-file.\n\npng file saved with document name.\n\"\"\"\n\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom PIL import Image\n\npxpmm = 1 # pixels per mm\n# adjust pxpmm up/down if there are bands in the heightmap\npad = 2\ngrayscale_compress = 0.1 # range 0 - 1\ninvert = False # grayscale, high is white with False\n\nIMSHOW = True\nIMSAVE = True\nIMRESIZE = False # only saved pil-image, quicker than increase of pxpmm\nimwidth = 500 # resizing does give artefacts, can change interpolation...\n\ndoc = App.ActiveDocument\n\nshapes = list()\nfor obj in doc.Objects:\n    if hasattr(obj, 'Shape'):\n        if hasattr(obj.Shape, 'Volume'):\n            if obj.Shape.Volume > 0:\n                if obj.ViewObject.Visibility:\n                    shapes.append(obj.Shape)\n\nxmin, ymin, zmin =  (min((getattr(shp.BoundBox, f'{which}Min')\n                          for shp in shapes)) for which in 'XYZ')\nxmax, ymax, zmax =  (max((getattr(shp.BoundBox, f'{which}Max')\n                          for shp in shapes)) for which in 'XYZ')\n\nxspan, yspan, zspan = xmax - xmin, ymax - ymin, zmax - zmin\nw, h = (int(span * pxpmm) for span in (xspan, yspan))\npic = np.zeros((w + 1, h + 1, len(shapes)))\n\nprint('w x h --> {} x {}'.format(w, h))\nprint('working on pixels, might take a while...')\n\nfor i, shape in enumerate(shapes):\n    pv = shape.getPoints(1/pxpmm)\n    zpoints = (p for p, v in zip(*pv) if v.z > 0)\n    for zpoint in zpoints:\n        x = round((zpoint.x - xmin) / xspan * w)\n        y = round((zpoint.y - ymin) / yspan * h)\n        pic[x, y, i] = zpoint.z\n\nprint('pic loop done')\n\npic = (pic.max(axis=2) - zmin) / zspan\nim = np.zeros((w + 1 + 2 * pad, h + 1 + 2 * pad))\npic = (1 - grayscale_compress) * pic + grayscale_compress\nim[pad:pad + w + 1, pad:pad + h + 1] = pic\nim = (im.T * 255).astype(np.uint8)\nh, w = im.shape\n\nif invert:\n    im = 255 - im\n    print('grayscale inverted')\n\nif IMSHOW:\n    plt.imshow(im, cmap='gray', interpolation='none')\n    plt.grid(color='r')\n    plt.show()\n\nif IMSAVE:\n    with Image.fromarray(im, mode='L') as pim:\n        if IMRESIZE:\n            pim = pim.resize((imwidth, int(h * imwidth / w)),\n                             Image.Resampling.LANCZOS)\n            print('resized to:', pim.size)\n        pim.save('{}.png'.format(doc.Name), mode='L')\n\nprint('height map done')",
    "url": "https://wiki.freecad.org/Macro_Z_Height_Map",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_Z_height_map",
    "version": "0.1",
    "license": "",
    "date": "2022-08-28",
    "src_filename": "",
    "filename_from_url": "",
    "author": "heda @ fc-forum",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Alias For Table For Object",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro automatically creates aliases in a two-dimensional table using the names of the rows and columns.<br /> <p>A second function can create a link between a cell and a property value in an object.<br /> To be able to use this function, you just have to place the name of the relevant object in the column and the name of the property in the row.<br /><br />Macro version: beta<br />Last modified: 2024-02-22<br />FreeCAD version: All<br />Author: 2cv001<br /> </p> ",
    "comment": "Automatically creates aliases in a two-dimensional table using the names of the rows and columns",
    "code": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# ========================================================================\n# Macro Alias for table for object\n# file name : Alias_For_Table_For_Object.FCMacro\n# ========================================================================\n\n\n__Name__   = \"Alias for table for object\"\n__Comment__ =\"Automatically creates aliases in a two-dimensional table using the names of the rows and columns\"\n__Author__ = \"2cv001\"\n__Title__   = \"Alias For Table For Object\"\n__Date__    = \"2024/02/20\"    #YYYY/MM/DD 14;21 B\u00e9ta\n__Version__ = __Date__\n__License__ = \"Apache-2.0\"\n__Wiki__ = \"https://wiki.freecad.org/Macro_Alias_For_Table_For_Object\"\n# https://forum.freecad.org/viewtopic.php?t=84878\n#===========================================================================================\n# The macro automatically creates alias in a two-dimensional table using the name of the row\n# and the name of the column. To be able to use the \"Table to object\" function\n# put the name of the concerned object in the column and the name of the property in the row.\n# the alias creation function will create alias (except dico, see below)\n# with this syntax  \"LabelObject_property\"\n#\n# The macro can also automatically fill the properties of objects (body, sketch, ...) based on\n# aliases created by 'Create alias for table' and which indicate the object and the property\n#\n# The dico (see further in the code) is used to convert what you put in the top line to match\n# what needs to be put in the expression. For example, if you have \"posx\" in the\n# first line of your selection, in the expression, for the property part, there will be\n# \"Placement.Base.x\"\n#==========================================================================================\n\n\n\nimport FreeCAD, FreeCADGui\nimport re\nfrom PySide import QtGui, QtCore\n\naddNumberIfOther=True\n\nclass CheckBoxDialog(QtGui.QDialog):\n    def __init__(self, parent=None):\n        super(CheckBoxDialog, self).__init__(parent)\n\n        self.setWindowTitle(\"Macro FreeCAD\")\n\n        self.createAliasForTableCheckBox = QtGui.QCheckBox(\"Alias creation\")\n        self.createAliasForTableCheckBox.setToolTip(\"Creates an alias in each selected cell\" +\n                \"\\nbased on the first selected row and column\" +\n                \"\\nThe aliases will be in the format 'LabelObject_property'\")\n        self.tableToObjectCheckBox = QtGui.QCheckBox(\"Properties in objects based on aliases\")\n        self.tableToObjectCheckBox.setToolTip(\"Automatically fills the properties of objects (body, sketch, ...)\" +\n                \"\\nbased on aliases which must be in the format 'LabelObject_property'\")\n        buttonBox = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel)\n        buttonBox.accepted.connect(self.accept)\n        buttonBox.rejected.connect(self.reject)\n\n        layout = QtGui.QVBoxLayout()\n        layout.addWidget(self.createAliasForTableCheckBox)\n        layout.addWidget(self.tableToObjectCheckBox)\n        layout.addWidget(buttonBox)\n        self.setLayout(layout)\n\n    def accept(self):\n        super(CheckBoxDialog, self).accept()\n\n\n\n\ndef get_column(cell):\n    column = ''.join([c for c in cell if not c.isdigit()])\n    return column \n    \ndef get_row(cell):\n    row = ''.join([c for c in cell if c.isdigit()])\n    if row=='' :\n        row='1'\n    return int(row)  \n\n\n\n\n#################################################################################\n# part code for alias\n#################################################################################\n# parameters for alias creation\nseparateur = \" \"      # typically put \" \" so blanks will be replaced by nouveauCaract\nnouveauCaract = ''    #Put for example \"_\" to have the separators replaced by \"_\". Put \"\" to have no separator\nmajuscule = True      #set to True if you want  \"Diametre du cercle\" to be \"DiametreDuCercle\"\nchangeTexteCellule = False  # the text will only be changed if changeCellText is True. \n                          # This does not change anything for the allias itself\npremierCaractereEnMinuscule = False # Force the first character to be in lower case\n\n# list of characters to be replaced by an equivalent. for example an @ will be replaced by 'a'\n# if you add characters, please send me a private message. Il will eventually add it in my code.\ncaracEquivalents = [ ['\u00e9','e'],['\u00e8','e'],['\u00ea','e'],['\u00e0','a'],['@','a'],['&','e'],['\u00e7','c'],\n                  ['\u00b2','2'],[\"'\",''],['?',''],['\"',''],['(',''],[')',''],['#',''],['.',''],\n                  [',',''],[';',''],['$',''],['+',''],['-',''],['*',''],['/',''],['\\\\',''] ,\n                  ['[',''],[']',''],\n                  ]\n\n\n\ndef traitementChaineSource(chaineSource, separateur, nouveauCaract, majuscule):\n# If separator is ' ' and nouveauCaract is '_', and majuscule is True\n# transforms \"Diametre du cylindre\" into \"Diametre_Du_Cylindre\n\n    def remplaceCararcDansMot(mot):\n\n        def remplaceCartatParEquivalent(caractere):\n        # replaces a character with its equivalent if it exists\n            caracResult = caractere   \n            for couple in caracEquivalents:\n                if (couple[0] == caractere):\n                    caracResult = couple[1]\n                    break\n            return caracResult\n\n    #replaces all characters of the word with its equivalent if it exists\n        motResult = mot\n        for caract in mot:\n            a = remplaceCartatParEquivalent(caract)\n            motResult = motResult.replace(caract, a)\n        return motResult\n        \n\n    chaineResult = ''\n    first = True\n    carctDeSeparation = ''\n    for mots in chaineSource.split(separateur): \n        mots = remplaceCararcDansMot(mots)\n        if (not (first)):\n            carctDeSeparation = nouveauCaract \n            if (majuscule):\n                chaineResult = chaineResult + nouveauCaract + mots[:1].upper() + mots[1:]\n                # We use \"[:1]\" instead of \"[0]\", \n                # for no crash in case of an empty string (which happens if the cell is empty)\n        else:\n            chaineResult = chaineResult + nouveauCaract + mots\n        first=False    \n    if premierCaractereEnMinuscule :\n        chaineResult = chaineResult[:1].lower() + chaineResult[1:]\n    return chaineResult\n\n\ndef create_alias_for_table_cells_Selected():\n    mySpreadsheet = Gui.ActiveDocument.ActiveView.getSheet()    \n    aw = Gui.getMainWindow().centralWidget().activeSubWindow() # Store the active window      \n    # To get list of all selected cells\n    sel_items = aw.widget().findChild(QtGui.QTableView).selectedIndexes() \n\n    getCellName = lambda r,c:'{}{}{}'.format(chr(c//26 + 64) if c//26 > 0 else '', chr(c%26 + 65), r + 1)\n\n\n\n    for item in sel_items: # The selected cells are scanned\n\n        if  (sel_items[0].column()!=item.column() and sel_items[0].row()!=item.row()) :\n            cellName=getCellName(item.row(), item.column())\n            firstcellName=getCellName(sel_items[0].row(), sel_items[0].column())\n            \n            cellTextLine=get_column(firstcellName)+str(get_row(cellName))\n            cellTextColumn=get_column(cellName)+ str(get_row(firstcellName)) \n            try :\n                textLine = mySpreadsheet.get(cellTextLine)\n                textColumn = mySpreadsheet.get(cellTextColumn)\n\n            except :\n                #print('Des cellules en premi\u00e8re colonne ou en premi\u00e8re ligne ne sont pas conformes')\n                continue\n            textAlias =  str(textLine) + '_'  + str(textColumn)\n            textAlias=traitementChaineSource(textAlias, separateur, nouveauCaract, majuscule)\n            if addNumberIfOther :\n                startIndexForTextAlias=1\n                for i in range(startIndexForTextAlias, 201):\n                    try:\n                        if i == 1:\n                            mySpreadsheet.setAlias(cellName, textAlias)\n                        else:\n                            mySpreadsheet.setAlias(cellName, textAlias + '_' + str(i-1))\n                            startIndexForTextAlias=i+1    \n                        break  # Arr\u00eate la boucle si aucune exception n'est lev\u00e9e\n                    except:\n                        continue  # Passe \u00e0 l'it\u00e9ration suivante si une exception est lev\u00e9e\n\n\n\n\n\n# The dictionary is used to convert what you put in the top line to match\n# what needs to be put in the expression. For example, if you have \u201cposx\u201d in the\n# first line of your selection, in the expression, for the property part, there will be\n# \"Placement.Base.x\" \ndico={\n        \"posx\" : \"Placement.Base.x\",\n        \"posy\" : \"Placement.Base.y\",\n        \"posz\" : \"Placement.Base.z\",\n        \"posX\" : \"Placement.Base.x\",\n        \"posY\" : \"Placement.Base.y\",\n        \"posZ\" : \"Placement.Base.z\",\n        \"angle\": \"Placement.Rotation.Angle\",\n        \"ang\": \"Placement.Rotation.Angle\",\n        \"axisx\": \"Placement.Rotation.Axis.x\",\n        \"axisy\": \"Placement.Rotation.Axis.y\",       \n        \"axisz\": \"Placement.Rotation.Axis.z\", \n        \"axeX\": \"Placement.Rotation.Axis.x\",\n        \"axeY\": \"Placement.Rotation.Axis.y\",       \n        \"axeZ\": \"Placement.Rotation.Axis.z\", \n        \"attachementX\" : \"AttachmentOffset.Base.x\",\n        \"attachementY\" : \"AttachmentOffset.Base.y\",\n        \"attachementZ\" : \"AttachmentOffset.Base.z\",\n        \"attachementAngle\" : \"AttachmentOffset.Rotation.Angle\",\n        \"attachementAxisX\" : \"AttachmentOffset.Rotation.Axis.x\",\n        \"attachementAxisY\" : \"AttachmentOffset.Rotation.Axis.y\",        \n        \"attachementAxisZ\" : \"AttachmentOffset.Rotation.Axis.z\",\n        \"Length\" : \"Length\",\n        \"Length2\" : \"Length2\",\n        \"Radius\" : \"Radius\",\n        \"Height\" : \"Height\",\n        \"FirstAngle\" : \"FirstAngle\",\n        \"SecondAngle\" : \"SecondAngle\",\n        \"Angle1\" : \"Angle1\",\n        \"Angle2\" : \"Angle2\",\n        \"Angle3\" : \"Angle3\",\n     }   \n\n  \ndef set_constraint_expression(sketchLabel, constraint_name, expression):\n    # Get all Sketches with this label\n    findConstraint = False\n    sketches = App.ActiveDocument.getObjectsByLabel(sketchLabel)\n    if len(sketches)>1 :\n        print(\"Warning, multiple sketches have the same label. \" \n            + \" All these sketches will be processed. \" \n            + \"This may cause problems if different sketches with the same label \"\n            + \"have constraints with the same name.\")\n    # Go through all Sketches\n\n    for sketch in sketches:\n\n        # Go through all constraints in the Sketch\n        for i in range(sketch.ConstraintCount):\n            # Get the constraint\n            constraint = sketch.Constraints[i]\n            \n            # Check if the constraint name matches the one we're looking for\n            if constraint.Name == constraint_name:\n                # Modify the constraint value\n                sketch.setExpression('Constraints[' +  str(i)+ ']', expression)\n                findConstraint=True\n                break\n    return findConstraint\n\n  \ndef set_property_based_on_alias(sheet,cell):\n\n    # alias of the cell\n    alias = sheet.getAlias(cell)\n    # Check if the alias is valid\n    if sheet.getContents(cell)!='' :\n        if alias is None:\n            print(\"The selected cell \" + cell +  \" does not have an alias.\")\n            return\n\n    # Separate the alias into body name and property name\n    # ex 'body_Name_posX' -> body_Name for the object and posX for property name\n    parts = alias.rsplit('_', 1)\n    if len(parts) != 2:\n        print(\"The alias must be in the form 'BodyName_PropertyName'.\")\n        return\n\n    objLabel, property_name = parts\n    try :\n        obj=App.ActiveDocument.getObjectsByLabel(objLabel)[0]\n    except :\n        print('no object with this label : ',objLabel)\n        return\n    try :\n        property_name=dico[property_name]\n    except :\n        try :\n            if  obj.TypeId != 'Sketcher::SketchObject' :\n                print ('property ' + property_name + ' not found in the dictionary. See at the top of the source code')\n        except :\n            pass\n\n       \n\n    if obj is None:\n        print(f\"There is no object named '{objLabel}' in the document.\")\n        return\n\n    # Create an expression that refers to the cell's alias\n    expression = f\"<<{sheet.Label}>>.{alias}\"\n\n    # Modify the object's property\n    # if it's a constraint\n    if  obj.TypeId == 'Sketcher::SketchObject' :\n        findConstraint=set_constraint_expression(objLabel, property_name, expression)\n        if findConstraint : # if not we continue to find a property\n            return\n        \n    if hasattr(obj, property_name.split('.')[0]): # Placement.Base.x -> Placement\n        obj.setExpression(property_name, expression)\n    else:\n        print(f\"The object '{objLabel}' does not have a property '{property_name}'.\")\n\n\ndef tableToObject() :\n    sheet = Gui.ActiveDocument.ActiveView.getSheet()\n    # Check if the spreadsheet is active\n    if sheet.TypeId != 'Spreadsheet::Sheet':\n        print(\"Please select cells in a spreadsheet.\")\n        return\n\n    # active cell\n    #cell = Gui.activeView().currentIndex()\n    \n    aw = Gui.getMainWindow().centralWidget().activeSubWindow() # Store the active window      \n    # To get list of all selected cells\n    sel_items = aw.widget().findChild(QtGui.QTableView).selectedIndexes() \n    getCellName = lambda r,c:'{}{}{}'.format(chr(c//26 + 64) if c//26 > 0 else '', chr(c%26 + 65), r + 1)\n    for cell in sel_items: # The selected cells are scanned\n        cellName=getCellName(cell.row(), cell.column())\n\n        if str(sheet.getContents(cellName))!= '' :\n            set_property_based_on_alias(sheet, cellName)\n            \n       \n\n\n\n\ndef main():\n    dialog = CheckBoxDialog()\n    result = dialog.exec_()\n    if result and dialog.createAliasForTableCheckBox.isChecked() :\n        create_alias_for_table_cells_Selected()\n    if result and dialog.tableToObjectCheckBox.isChecked() :\n        tableToObject()\n    return result\n\n\n\nif __name__ == '__main__':\n    main()\n",
    "url": "https://wiki.freecad.org/Macro_Alias_For_Table_For_Object",
    "raw_code_url": "",
    "wiki": "https://wiki.freecad.org/Macro_Alias_For_Table_For_Object",
    "version": "2024/02/20",
    "license": "",
    "date": "2024/02/20",
    "src_filename": "",
    "filename_from_url": "",
    "author": "2cv001",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "ConstraintToAlias",
    "on_wiki": true,
    "on_git": false,
    "desc": "Create an alias from within the Sketcher editor from a selected named constraint.<br /><br />Macro version: 0.2023.12.10<br />Last modified: 2023-12.10<br />FreeCAD version: 0.21<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/3/31/ConstraintToAlias.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Create an alias from within the Sketcher editor from a selected named constraint.",
    "code": "# ConstraintToAlias, 2023, by <TheMarkster> LGPL 2.1 or later\n# Usage: Create a constraint, give it a name, then run the macro\n# to put a new alias into a spreadsheet and link the constraint\n# to it via Expressions.  If no constraint is selected, then the\n# macro will open the dialog with some default values of \"Label\"\n# for the label and alias, and 0.0 default value for Value.\n\n__version__ = \"0.2023.12.10\"\n__icon__ = \"https://wiki.freecad.org/images/3/31/ConstraintToAlias.svg\"\n\nfrom PySide import QtGui,QtCore\nimport math\nimport Sketcher\nimport warnings\nwarnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n\nclass HighlightDelegate(QtGui.QStyledItemDelegate):\n    def paint(self, painter, option, index):\n        super(HighlightDelegate, self).paint(painter, option, index)\n\n        if index.data(QtCore.Qt.BackgroundRole) == \"lightyellow\":\n            painter.save()\n            painter.fillRect(option.rect, QtGui.QBrush(QColor(\"lightyellow\")))\n            painter.restore()\n\n        if index.data(QtCore.Qt.BackgroundRole) == \"lightblue\":\n            painter.save()\n            painter.fillRect(option.rect, QtGui.QBrush(QColor(\"lightblue\")))\n            painter.restore()\n\nclass ConstraintToAlias(QtGui.QDialog):\n    def __init__(self, sketch, constraint, spreadsheet, parent=None):\n        super(ConstraintToAlias, self).__init__(parent)\n        self.sketch = sketch\n        self.con = constraint\n        self.spreadsheet = spreadsheet\n        self.setWindowTitle(\"Alias preview\")\n        self.icon = self.QIconFromXPMString(__xpm__)\n        self.aliases = [] #existing aliases in the current spreadsheet\n        self.setWindowIcon(self.icon)\n        self.rowCount = 8\n        self.rowForAlias = 0\n        self.setupUi()\n        if sketch:\n            self.spreadsheet_view.setFocus()\n        else:\n            self.label.setFocus()\n\n\n    def QIconFromXPMString(self, xpm_string):\n        if \"/*pixels*/\" in xpm_string:\n            xpm = xpm_string.replace(\"\\\"\",\"\").replace(',','').splitlines()[4:]\n        else:\n            xpm = xpm_string.replace(\"\\\"\",\"\").replace(',','').splitlines()[3:]\n        for line in reversed(xpm):\n            if line.startswith(\"/*\") and line.endswith(\"*/\"):\n                xpm.pop(xpm.index(line))\n        pixmap = QtGui.QPixmap(xpm)\n        icon = QtGui.QIcon(pixmap)\n        return icon\n\n    def setupUi(self):\n        spreadsheets_label = QtGui.QLabel(\"Spreadsheets:\")\n        self.sheet_box = QtGui.QComboBox()\n        sheets = [obj.Label for obj in FreeCAD.ActiveDocument.Objects if obj.isDerivedFrom(\"Spreadsheet::Sheet\")\n                    or obj.isDerivedFrom(\"App::Link\")\n                    and obj.getLinkedObject().isDerivedFrom(\"Spreadsheet::Sheet\")]\n        self.sheet_box.addItems(sheets)\n        self.sheet_box.setCurrentText(self.Spreadsheet.Label)\n        self.sheet_box.currentIndexChanged.connect(self.onCurrentIndexChanged)\n        self.spreadsheet_view = QtGui.QTableView()\n        self.spreadsheet_view.setItemDelegate(HighlightDelegate())\n        model = QtGui.QStandardItemModel()\n        model.setColumnCount(2)\n        model.setRowCount(8)\n        model.setHorizontalHeaderLabels([\"A\", \"B\"])\n        self.spreadsheet_view.setModel(model)\n        self.spreadsheet_view.setMinimumSize(350,450)\n        self.spreadsheet_view.setMaximumHeight(450)\n        horiz_header = self.spreadsheet_view.horizontalHeader()\n        horiz_header.setSectionResizeMode(0, QtGui.QHeaderView.Stretch)\n        horiz_header.setSectionResizeMode(1, QtGui.QHeaderView.Stretch)\n\n        constraint_label = QtGui.QLabel(\"Label:\")\n        self.label = QtGui.QLineEdit()\n        self.label.textChanged.connect(self.onLabelChanged)\n\n        alias_label = QtGui.QLabel(\"Alias:\")\n        self.alias = QtGui.QLineEdit()\n        self.alias.textChanged.connect(self.onAliasChanged)\n\n        value_label = QtGui.QLabel(\"Value:\")\n        self.value = QtGui.QLineEdit()\n        self.value.textChanged.connect(self.onValueChanged)\n\n        # Create layout\n        layout = QtGui.QGridLayout(self)\n        self.setLayout(layout)\n        layout.addWidget(spreadsheets_label, 0, 0)\n        layout.addWidget(self.sheet_box, 0, 1, 1, 3)\n        layout.addWidget(self.spreadsheet_view, 1, 0, self.rowCount, 3)\n        layout.addWidget(constraint_label, self.rowCount + 2, 0)\n        layout.addWidget(self.label, self.rowCount + 2, 1)\n        layout.addWidget(alias_label, self.rowCount + 3, 0)\n        layout.addWidget(self.alias, self.rowCount + 3, 1)\n        layout.addWidget(value_label, self.rowCount + 4, 0)\n        layout.addWidget(self.value, self.rowCount + 4, 1)\n\n        self.label.setText(self.con.Name)\n        self.alias.setText(self.con.Name)\n        self.value.setText(f\"{self.con.Value if not con.Type == 'Angle' else math.degrees(self.con.Value)}\")\n\n        self.set_cells(FreeCAD.ActiveDocument.getObjectsByLabel(self.sheet_box.currentText())[0])\n        self.set_sheet_read_only()\n        self.adjustSize()\n\n\n        self.button_box = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel)\n        self.button_box.accepted.connect(self.accept)\n        self.button_box.rejected.connect(self.reject)\n        box_layout = QtGui.QHBoxLayout()\n        box_layout.addWidget(self.button_box)\n        layout.addLayout(box_layout, self.rowCount + 5, 0, 1, 3)\n        self.scroll_to_last()\n\n    def update_values(self):\n        \"\"\"updates the QTableView's alias cells\"\"\"\n        self.set_cell_value(self.rowForAlias, 0, self.Label, True, True) #highlight lightblue\n        self.set_cell_value(self.rowForAlias, 1, \"{\" + self.Alias + \"} \" + f\"{self.Value}\", True)\n        self.spreadsheet_view.setSizeAdjustPolicy(QtGui.QTableView.AdjustToContents)\n        if self.Alias in self.aliases:\n            self.alias.setStyleSheet(\"color:red;\")\n            self.alias.setToolTip(\"Alias already exists in spreadsheet.\")\n        else:\n            self.alias.setStyleSheet(\"color:black;\")\n            self.alias.setToolTip(\"Alias available for use.\")\n\n    def onValueChanged(self):\n        self.update_values()\n\n    def onLabelChanged(self):\n        self.update_values()\n\n    def onAliasChanged(self):\n        self.update_values()\n\n    @property\n    def Spreadsheet(self):\n        obj = FreeCAD.ActiveDocument.getObjectsByLabel(self.sheet_box.currentText())[0]\n        if obj.isDerivedFrom(\"Spreadsheet::Sheet\"):\n            return obj\n        else:\n            return obj.getLinkedObject()\n\n    def onCurrentIndexChanged(self, idx):\n        self.spreadsheet = self.Spreadsheet\n        self.set_cells(self.spreadsheet)\n        self.set_sheet_read_only()\n        self.scroll_to_last()\n\n    @property\n    def Label(self):\n        return self.label.text()\n\n    @property\n    def Alias(self):\n        return self.text_to_alias(self.alias.text())\n\n    @property\n    def Value(self):\n        return self.value.text()\n\n    def clear_all_cells(self):\n        model = self.spreadsheet_view.model()\n        if model is not None:\n            rows = model.rowCount()\n            columns = model.columnCount()\n            for row in range(rows):\n                for col in range(columns):\n                    item = model.item(row, col)\n                    if item is not None:\n                        model.setItem(row, col, None)\n\n    def scroll_to_last(self):\n        \"\"\"scroll to last cell with a value\"\"\"\n        model = self.spreadsheet_view.model()\n        self.spreadsheet_view.scrollTo(model.index(self.rowForAlias-1, 0))\n        idx = model.index(self.rowForAlias-1, 0)\n        self.select_cell(self.rowForAlias-1, 0)\n\n    def select_cell(self, row, column):\n        index = self.spreadsheet_view.model().index(row, column)\n        selection_model = self.spreadsheet_view.selectionModel()\n        selection_model.clear()\n        selection_model.select(index, QtCore.QItemSelectionModel.Select)\n\n    def text_to_alias(self, text:str):\n        REPLACEMENTS = {\n            \" \": \"_\",\n            \".\": \"_\",\n            \"\u00e4\": \"ae\",\n            \"\u00f6\": \"oe\",\n            \"\u00fc\": \"ue\",\n            \"\u00c4\": \"Ae\",\n            \"\u00d6\": \"Oe\",\n            \"\u00dc\": \"Ue\",\n            \"\u00df\": \"ss\",\n            \"'\": \"\"\n        }\n\n        for character in REPLACEMENTS:\n            text = text.replace(character,REPLACEMENTS.get(character))\n        return text\n\n    def set_cells(self, ss):\n        \"\"\"set the cells of the sheet view according to the values in the selected sheet\"\"\"\n        self.clear_all_cells()\n        self.aliases = []\n        found = False #empty cells found\n        row = 1 #start with A2-B2\n        while not found:\n            row += 1\n            cellAddressA = f\"A{row}\"\n            cellAddressB = f\"B{row}\"\n            contentsA = ss.getContents(cellAddressA)\n            contentsB = ss.getContents(cellAddressB)\n            alias = ss.getAlias(cellAddressB)\n            if alias:\n                self.aliases.append(alias)\n            if not contentsA and not contentsB and not alias:\n                found = True\n            else:\n                contentsB = (\"{\" + alias + \"} \" + contentsB) if alias else contentsB\n                self.set_cell_value(row, 0, f\"{contentsA}\")\n                self.set_cell_value(row, 1, f\"{contentsB}\", bool(alias))\n\n        self.rowForAlias = row\n        self.update_values()\n\n    def set_cell_value(self, row, column, value, highlight=False, blue=False):\n        model = self.spreadsheet_view.model()\n        if model is not None:\n            item = model.item(row-1, column)\n            if item is None:\n                item = QtGui.QStandardItem()\n            # Set the value of the cell\n            item.setText(str(value))\n            model.setItem(row-1, column, item)\n            self.scroll_to_last()\n\n            if highlight:\n                if not blue:\n                    item.setData(QtGui.QBrush(QtGui.QColor(\"lightyellow\")), QtCore.Qt.BackgroundRole)\n                else:\n                    item.setData(QtGui.QBrush(QtGui.QColor(\"lightblue\")), QtCore.Qt.BackgroundRole)\n\n    def set_sheet_read_only(self):\n        model = self.spreadsheet_view.model()\n        if model is not None:\n            rows = model.rowCount()\n            columns = model.columnCount()\n            for row in range(rows):\n                for col in range(columns):\n                    item = model.item(row, col)\n                    if item is not None:\n                        # Make the item read-only\n                        item.setFlags(item.flags() & ~QtCore.Qt.ItemIsEditable)\n\n    def add_alias(self, ss, sk, con, row, label, value, alias):\n        if hasattr(ss, alias):\n            print(f\"{ss.Label} already has an alias named {alias}, skipping.\")\n            return\n\n        cellA = f\"A{row}\"\n        cellB = f\"B{row}\"\n        ss.set(cellA, label)\n        ss.set(cellB, f\"{value}\")\n        ss.setAlias(cellB, alias)\n        if self.get_expression(sk, con):\n            sk.setExpression(f\".Constraints.{con.Name}\",None)\n            FreeCAD.Console.PrintWarning(f\"\\\nWarning: alias is set by value, not by expression so as not \\\nto create a cyclic redundancy.  The expression for {con.Name} \\\nis being cleared and set to {ss.Label}.{con.Name}\\n\")\n        FreeCAD.ActiveDocument.recompute()\n        if sk:\n            sk.setExpression(f\".Constraints.{con.Name}\", f\"{ss.Name}.{alias}\")\n            print(f\"\\\nAdding alias {alias} from Sketch: {sk.Label} to spreadsheet: {ss.Label} \\\nat cell A{row} with value {value}\")\n\n    def get_expression(self, sketch, con):\n        \"\"\"get the current expression for sketch.constraint, if any\"\"\"\n        eng = sketch.ExpressionEngine if sketch else []\n        for expr in eng:\n            if f\"Constraints.{con.Name}\" in expr[0]:\n                return expr[1]\n        return None\n\n    def accept(self):\n        self.add_alias(self.Spreadsheet, self.sketch, self.con, self.rowForAlias, self.Label, self.Value, self.Alias)\n        super().accept()\n\n    def reject(self):\n        #FreeCAD.Console.PrintMessage(\"User canceled\\n\")\n        super().reject()\n\n__xpm__=\"\"\"\n/* XPM */\nstatic char *dummy[]={\n\"64 64 4 1\",\n\"b c #019eff\",\n\"# c #8b0000\",\n\"a c #ff0000\",\n\". c None\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"........########................................................\",\n\".......#aaaaaaaa#...............................................\",\n\"......#aaaaaaaaaa#..............................................\",\n\"....#..#aaaaaaaaa#..............................................\",\n\"...#a#..###aaaaaa#..............................................\",\n\"..#aaa#...aaaaaaa#..............................................\",\n\"..#aaa#..aaaaaaaa#..............................................\",\n\"..#aaa#.aaaaa#aaa#..............................................\",\n\"..#aaa#aaaaa.#aaa#..............................................\",\n\"..#aaaaaaaa..#aaa#..............................................\",\n\"..#aaaaaaa....#a#...............................................\",\n\"..#aaaaaa####..#.....................#####...#.......####...#...\",\n\"..#aaaaaaaaaa#......................#bbbbb###b#....##bbbb###b#..\",\n\"..#aaaaaaaaaaa#........#..........#bbbbbbbbbbbb#.#bbbbbbbbbbbb#.\",\n\"...#aaaaaaaaa#........#aa........#bbbbbbbbbbbbb#.bbbbbbbbbbbbb#.\",\n\"....#########........#aaaa.......#bbbb####bbbbb##bbbb####bbbbb#.\",\n\"......................aaaaa......#bbb###.##bbbb##bbbb##.##bbbb#.\",\n\".......................aaaaa.....#bbbbbb###bbbb##bbbbbb##.#bbb#.\",\n\"..............##########aaaaa....#bbbbbbbb###b#..bbbbbbbb###b#..\",\n\".............#aaaaaaaaaaaaaaaa....#bbbbbbbbb##...#bbbbbbbbbb#...\",\n\"............#aaaaaaaaaaaaaaaaa#....##bbbbbbbb##...##bbbbbbbbb#..\",\n\".............#aaaaaaaaaaaaaaaa....#b###bbbbbbb#..#b###bbbbbbbb..\",\n\"..............##########aaaaa....#bbb#..##bbbbb##bbb#..##bbbbb#.\",\n\".......................aaaaa.....#bbb#....##bbb##bbbb#...##bbb#.\",\n\"......................aaaaa......#bbbb#####bbbb##bbbbb####bbbb#.\",\n\".....................#aaaa.......#bbbbbbbbbbbb#.#bbbbbbbbbbbbb..\",\n\"...............#......#aa........#bbbbbbbbbbb##.#bbbbbbbbbbbb#..\",\n\"..............aa#......#..........#b##bbbbb###...#b##bbbbbb##...\",\n\".............aaaa#.................#.#######......#..######.....\",\n\"............aaaaa...............................................\",\n\"..........#aaaaa................................................\",\n\".........#aaaaa.................................................\",\n\"........#aaaaa..................................................\",\n\"........aaaaaa..................................................\",\n\".......aaaaaaa#.................................................\",\n\"......aaaaaaaaa.................................................\",\n\".....aaaaa.aaaa#................................................\",\n\"....aaaaa###aaa#####............................................\",\n\"...aaaaaaaaaaaaaaaaa#...........................................\",\n\"..#aaaaaaaaaaaaaaaaaa#..........................................\",\n\"...#aaaaaaaaaaaaaaaa#...........................................\",\n\"....################............................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\",\n\"................................................................\"};\n\"\"\"\n\nmw = Gui.getMainWindow()\nspreadsheets = [obj for obj in FreeCAD.ActiveDocument.Objects if obj.isDerivedFrom(\"Spreadsheet::Sheet\")]\nlinks = [obj.getLinkedObject() for obj in FreeCAD.ActiveDocument.Objects if obj.isDerivedFrom(\"App::Link\") and obj.getLinkedObject().isDerivedFrom(\"Spreadsheet::Sheet\")]\nfor link in links:\n    if not link in spreadsheets:\n        spreadsheets.append(link)\nss = None\nif len(spreadsheets) == 1:\n    ss = spreadsheets[0]\nelif len(spreadsheets) == 0:\n    ss = FreeCAD.ActiveDocument.addObject(\"Spreadsheet::Sheet\",\"ss\")\n    FreeCAD.ActiveDocument.recompute()\n    FreeCAD.Console.PrintMessage(f\"A new spreadsheet named {ss.Name} has been created.\\n\")\n\nsel = Gui.Selection.getCompleteSelection()\ncon = None\nfor s in sel:\n    sk = s.Object\n    if not sk.isDerivedFrom(\"Sketcher::SketchObject\"):\n        continue\n    if not \"Constraint\" in s.SubElementNames[0]:\n        continue\n    conString = s.SubElementNames[0].replace(\"Constraint\",\"\")\n    conIdx = int(conString) - 1\n    con = sk.Constraints[conIdx]\n    if not con.Name:\n        continue\n    dlg = ConstraintToAlias(sk,con,ss,mw)\n    dlg.exec_()\n\nif not con: #no constraint selected, so create generic alias options\n    con = Sketcher.Constraint()\n    con.Name = \"Label\"\n    dlg = ConstraintToAlias(None,con,ss,mw)\n    ii = 1\n    while hasattr(ss,f\"Alias{ii}\"):\n        ii += 1\n    dlg.alias.setText(f\"Alias{ii}\")\n    dlg.exec_()\n",
    "url": "https://wiki.freecad.org/Macro_ConstraintToAlias",
    "raw_code_url": "https://gist.github.com/mwganson/005765b49123d80cbb54569e081779a1/raw/556bf483802da8d756f869a4f894ba150d322305/ConstraintToAlias.FCMacro",
    "wiki": "",
    "version": "0.2023.12.10",
    "license": "",
    "date": "2023-12.10",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\ConstraintToAlias.svg",
    "icon_source": "https://wiki.freecad.org/images/3/31/ConstraintToAlias.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "EasyAlias",
    "on_wiki": true,
    "on_git": false,
    "desc": "Use this to quickly and easily create aliases for cells in your spreadsheets. It takes the text labels you will have already created in one column and uses those labels as aliases in the next column.<br /><br />Macro version: 2024.12.24<br />Last modified: 2024-12-24<br />FreeCAD version: 0.21<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/5/5e/Easy-alias-icon.png\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Use this to quickly and easily create aliases for cells in your spreadsheets. It takes the text labels you will have already created in one column and uses those labels as aliases in the next column.",
    "code": "# -*- coding: utf-8 -*-\nimport FreeCAD\nimport re\nfrom PySide import QtGui\n\n\"\"\"\nEasyAlias.FCMacro.py\n\nThis macro can be used to easily create aliases based on the contents of selected spreadsheet\ncells in the previous column. As an example, suppose you wish to have the following:\n\nA1: content = 'radius', B1: content = '5', alias = 'radius'\nA2: content = 'height', B1: content = '15', alias = 'height'\n\nThe traditional way to set this up would be:\nSelect A1\nEnter radius\nSelect B1\nEnter 5\nRight-click B1\nSelect properties\nSelect Alias\nEnter radius\nclick OK\nSelect A2\nEnter height\nSelect B2\nEnter 15\nRight-click B2\nSelect Properties\nSelect Alias\nEnter height\nClick OK\n\nUsing this macro, the work flow becomes:\nSelect A1\nEnter radius\nSelect B1\nEnter 5\nSelect A2\nEnter height\nSelect B2\nEnter 15\nSelect A1 through A2\nRun the EasyAlias macro\nDone\n\n\"\"\"\n\n__title__ = \"EasyAlias\"\n__author__ = \"TheMarkster and rosta\"\n__url__ = \"https://wiki.freecadweb.org/Macro_EasyAlias\"\n__Wiki__ = \"https://wiki.freecadweb.org/Macro_EasyAlias\"\n__date__ = \"2024.12.24\" #year.month.date\n__version__ = __date__\n__icon__ = \"https://www.freecadweb.org/wiki/images/5/5e/Easy-alias-icon.png\"\n\nCELL_ADDR_RE = re.compile(r\"([A-Za-z]+)([1-9]\\d*)\")\nCUSTOM_ALIAS_RE = re.compile(r\".*\\((.*)\\)\")\nMAGIC_NUMBER = 64\nREPLACEMENTS = {\n    \" \": \"_\",\n    \".\": \"_\",\n    \"\u00e4\": \"ae\",\n    \"\u00f6\": \"oe\",\n    \"\u00fc\": \"ue\",\n    \"\u00c4\": \"Ae\",\n    \"\u00d6\": \"Oe\",\n    \"\u00dc\": \"Ue\",\n    \"\u00df\": \"ss\",\n    \"'\": \"\"\n}\n\ndef getSpreadsheets():\n    \"\"\"\n    Returns a set of selected spreadsheets in the active document or None if none is selected.\n    :returns: a set of selected spreadsheets in the active document or None if none is selected\n    :rtype: set\n    \"\"\"\n\n    spreadsheets = set()\n    for selectedObject in Gui.Selection.getSelection():\n        if selectedObject.TypeId == 'Spreadsheet::Sheet':\n            spreadsheets.add(selectedObject)\n        elif selectedObject.TypeId == \"App::Link\":\n            linkedObject = selectedObject.LinkedObject\n            if linkedObject.TypeId == 'Spreadsheet::Sheet':\n                spreadsheets.add(linkedObject)\n    if spreadsheets:\n        return spreadsheets\n    else:\n        # check if there is only one spreadsheet and use that one if none are selected\n        doc = FreeCAD.ActiveDocument\n        if not doc:\n            return spreadsheets\n        all_spreadsheets = [obj for obj in doc.Objects if obj.isDerivedFrom(\"Spreadsheet::Sheet\")]\n        if len(all_spreadsheets) == 1:\n            return set(all_spreadsheets)\n    return spreadsheets\n\n# The original implementatin of a1_to_rowcol and rowcol_to_a1 can be found here:\n# https://github.com/burnash/gspread/blob/master/gspread/utils.py\n\ndef a1_to_rowcol(label:str):\n    \"\"\"Translates a cell's address in A1 notation to a tuple of integers.\n    :param str label: A cell label in A1 notation, e.g. 'B1'. Letter case is ignored.\n    :returns: a tuple containing `row` and `column` numbers. Both indexed from 1 (one).\n    :rtype: tuple\n    Example:\n    >>> a1_to_rowcol('A1')\n    (1, 1)\n    \"\"\"\n\n    match = CELL_ADDR_RE.match(label)\n\n    row = int(match.group(2))\n\n    column_label = match.group(1).upper()\n    column = 0\n    for i, c in enumerate(reversed(column_label)):\n        column += (ord(c) - MAGIC_NUMBER) * (26**i)\n\n    return (row, column)\n\ndef rowcol_to_a1(row:int, column:int):\n    \"\"\"Translates a row and column cell address to A1 notation.\n    :param row: The row of the cell to be converted. Rows start at index 1.\n    :type row: int, str\n    :param col: The column of the cell to be converted. Columns start at index 1.\n    :type row: int, str\n    :returns: a string containing the cell's coordinates in A1 notation.\n    Example:\n    >>> rowcol_to_a1(1, 1)\n    A1\n    \"\"\"\n\n    row = int(row)\n\n    column = int(column)\n    dividend = column\n    column_label = \"\"\n    while dividend:\n        (dividend, mod) = divmod(dividend, 26)\n        if mod == 0:\n            mod = 26\n            dividend -= 1\n        column_label = chr(mod + MAGIC_NUMBER) + column_label\n\n    label = \"{}{}\".format(column_label, row)\n\n    return label\n\ndef textToAlias(text:str):\n    # support for custom aliases between parentheses\n    match = CUSTOM_ALIAS_RE.match(text)\n    if match:\n        return match.group(1)\n\n    for character in REPLACEMENTS:\n        text = text.replace(character,REPLACEMENTS.get(character))\n    return text\n\ndef main():\n    spreadsheets = getSpreadsheets()\n    if not spreadsheets:\n        QtGui.QMessageBox.critical(None, \"Error\",\n            \"No spreadsheet selected.\\nPlease select a spreadsheet in the tree view.\")\n        return\n    for spreadsheet in spreadsheets:\n        for selectedCell in spreadsheet.ViewObject.getView().selectedCells():\n            contents = spreadsheet.getContents(selectedCell) #get() throws exception on empty cell\n            if contents:\n                contents = spreadsheet.get(selectedCell)\n                alias = textToAlias(contents)\n                row, column = a1_to_rowcol(selectedCell)\n                nextCell = rowcol_to_a1(row, column + 1)\n                try:\n                    spreadsheet.setAlias(nextCell, alias)\n                except:\n                    QtGui.QMessageBox.critical(None, \"Error\",\n                        \"Unable to set alias <i>\" + alias + \"</i> at cell \" + nextCell +\n                        \"<br>in spreadsheet <i>\" + spreadsheet.FullName + \"</i>.\" +\n                        \"<br><br><b>Remember, aliases cannot begin with a numeral or an \" +\n                        \"underscore or contain any invalid characters.</b>\")\n\n    App.ActiveDocument.recompute()\n\nmain()",
    "url": "https://wiki.freecad.org/Macro_EasyAlias",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_EasyAlias",
    "version": "2024.12.24",
    "license": "",
    "date": "2024.12.24",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster and rosta",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Easy-alias-icon.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/5/5e/Easy-alias-icon.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FCSpreadSheet Extract",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro save the spreadsheet data in a csv file with the formula or in a xml file.<br /> <br /><span style=\"background-color:#ff0000; color:#ffffff;\">New version run only FC version 0.18 and more (PySide2 Qt5)</span> <br /> <br /> For the precedent version see <a rel=\"nofollow\" class=\"external text\" href=\"https://gist.githubusercontent.com/mario52a/29f7dce6934e8adf5d584bdddd2e469f/raw/ef0b0de56a65afc34a9a1a969969797910f3a004/Macro_FCSpreadSheet_Extract.FCMacro\">Macro_FCSpreadSheet_Extract.FCMacro</a> and install it manually.<br /><br />Macro version: 0.2<br />Last modified: 2020-03-14<br />FreeCAD version: 0.18 and more<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/d/d5/Macro_FCSpreadsheet_Extract.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "This macro save the spreadsheet data in a csv file with the formula or in a xml file.",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2018 2019 2020 <mario52>                                *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#05/05/2018 14/03/2020\n#\n__title__   = \"FCSpreadSheet_Extract\"\n__author__  = \"Mario52\"\n__url__     = \"https://www.freecadweb.org\"\n__Wiki__    = \"https://wiki.freecadweb.org/Macro_FCSpreadSheet_Extract\"\n__version__ = \"00.03\"\n__date__    = \"2020/03/14\" #YYYY/MM/DD\n\n\n#### Test FreeCAD.Version above 0.17 BEGIN ##########################################################################################################\nimport WebGui\n#WebGui.openBrowser(\"http://www.freecadweb.org/\")\ntry:\n    import PySide\n    from PySide import QtGui\n    import sys, os\n    def errorDialog(msg):\n        diag = QtGui.QMessageBox(QtGui.QMessageBox.Critical,u\"Error FreeCAD Version\",msg )\n        diag.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint) # PySide #cette fonction met la fenetre en avant\n        diag.setStyleSheet(\"QLabel {color : #ffffff; background-color : #FF3300;  font: bold}\")\n        WebGui.openBrowser(\"https://gist.githubusercontent.com/mario52a/29f7dce6934e8adf5d584bdddd2e469f/raw/ef0b0de56a65afc34a9a1a969969797910f3a004/Macro_FCSpreadSheet_Extract.FCMacro\" + \"\\n\\n\")\n        diag.exec_()\n        diag.setStyleSheet(\"Base\")\n\n    if int(FreeCAD.Version()[1]) < 18:      # Version of FreeCAD\n        memo = PySide.QtGui.QClipboard()    # Copy the title in to the clipBoard\n        memo.setText(__title__)    \n        FreeCAD.Console.PrintMessage(\"https://gist.githubusercontent.com/mario52a/29f7dce6934e8adf5d584bdddd2e469f/raw/ef0b0de56a65afc34a9a1a969969797910f3a004/Macro_FCSpreadSheet_Extract.FCMacro\" + \"\\n\\n\")\n        errorDialog(\"This version \" + __title__ + \" works with FreeCAD v0.18 or higher. \" + \"\\n\\n\"\n                    \"PySide2 Qt version: 5\" + \"\\n\\n\"\n                    \"The macro it was derived from (30/04/2018 for FC v0.17) is displayed in your FreeCAD browser\" + \"\\n\\n\"\n                    \"copy and paste it into the FCSpreadSheet_Extract macro or install it manually.\" + \"\\n\\n\"\n                    \"If the code is not displayed in the FreeCAD browser page,\" + \"\\n\"\n                    \"copy the URL displayed in the Report View\")\nexcept Exception:\n    None\n#### Test FreeCAD.Version above 0.17 END ############################################################################################################\n\nimport PySide2\nfrom PySide2 import QtWidgets, QtGui ,QtCore \nfrom PySide2.QtGui import *\nfrom PySide2.QtCore import *\nimport copy\nimport re\n\n\npath = FreeCAD.ConfigGet(\"UserAppData\")\n#path = Your path\n\nglobal ESCAPE\nglobal tableau\nglobal data\n\n########## separator \nESCAPE = \"\\t\"           #tabulation    #compatible FC\n#ESCAPE = \",\"            #virgule       #compatible FCInfo\n#ESCAPE = \";\"            #point virgule #option\n#ESCAPE = \" \"            #espace        #option\n#ESCAPE = \"\"             #vide          #option\n##########\n\ndef decodeColonne(colonne = \"A\"):                                  # converti la chaine A ... ZZ en numero de colonne ex: A = 1; AA = 27\n    colonne  = re.split('[0-9]+', colonne, flags=re.IGNORECASE)[0] # supp the alphanumeric number ex: A2 = A; A12 = A (1A return 0)\n    try:\n        if len(colonne) > 1:\n            return ((ord(colonne[0].upper()) - 64) * 26 ) + (ord(colonne[1].upper()) - 64) # max 2 car (AAAA return 27)\n        else:\n            return (ord(colonne.upper()) - 64 )\n    except Exception:\n        return 0\n\ndef decodeOccupation(dataTableau = \"\"):  # decode the max occupation Colonnes, Lines and give the cell occupation\n    #\n    #lineMax, colonneMax, cellsOccupation = decodeOccupation(FreeCAD.ActiveDocument.getObject(str(Sheet.Name)))\n    #\n    try:\n        #tyty = unicode(dataTableau.cells.Content, \"utf-8\")\n        tyty = dataTableau.cells.Content\n        tyty = tyty.split(\">\")\n\n        ####\n        cellsOccupation = [] \n        cellsSorted     = []                                                 # search the \"A1\" definition\n        for i in tyty[1:-2]:                                                 # split les cases dans la chaine XML\n            i = i[i.find('\"')+1:]\n            i = i[:i.find('\"')]\n            cellsOccupation.append(i)\n\n        cellsSorted = copy.deepcopy(cellsOccupation)\n        cellsSorted.sort()\n\n        ####\n        linesMax = 0\n        for i in cellsSorted:                                                # recherche le max (ligne et colonne)\n            colonnesMax = re.split('[0-9]+', i, flags=re.IGNORECASE)         # colonne max (AA)\n            try:\n                dummy   = int(re.split('[A-Z]+', i, flags=re.IGNORECASE)[1]) # line\n                if dummy > linesMax:\n                    linesMax = dummy                                         # lines max\n            except Exception:\n                None\n        del cellsSorted[:]\n        ####\n        return linesMax, decodeColonne(colonnesMax[0]), cellsOccupation      # return linesMax , colonnesMax, cellsOccupation\n\n    except Exception:\n        FreeCAD.Console.PrintError(\"Error data, Enter object <Sheet object> ex:\" + \"\\n\")\n        FreeCAD.Console.PrintError(\"lineMax, colonneMax, cellsOccupation = decodeOccupation(FreeCAD.ActiveDocument.getObject(str(Sheet.Name)))\" + \"\\n\")\n        return 0, 0, []\n\ndef caseTableau(ligne = 1, colonne = 1):                                     # calcule et code la case du tableur ex: 1,1 = A1; 7,7 = G7\n    #\n    # print caseTableau( 1, 1)\n    #\n    if ligne < 1: ligne = 1\n    if ligne > 16384: ligne = 16384\n    if colonne < 1: colonne = 1\n    if colonne > 702: colonne = 702\n    if (colonne > 26):\n        if abs(colonne % 26) == 0:\n            return chr(64 + (abs(colonne / 26) -1)) + chr(90) + str(ligne)\n        else:\n            return chr(64 + (abs(colonne / 26))) + chr(64 + (abs(colonne % 26))) + str(ligne)\n    else:\n        return chr(colonne + 64) + str(ligne)\n\ndef saveDataInFile(data = \"\"):\n    global tableau\n\n    SaveName, Filter = PySide2.QtWidgets.QFileDialog.getSaveFileName(None, \"Save a file txt\", path, \"CSV (*.csv);;XML (*.xml)\") # PySide\n\n    if (SaveName == \"\"):\n        App.Console.PrintMessage(\"Process aborted\"+\"\\n\")\n    else:\n        App.Console.PrintMessage(\"Registration of \"+SaveName+\"\\n\")\n        try:\n            file = open(SaveName, 'w')\n            try:\n                if Filter == \"XML (*.xml)\":\n                    ext = \"(*.xml)\"\n                    file.write(tableau.cells.Content)          # save XML\n                else:\n                    ext = \"(*.csv)\"\n                    for i in data:\n#                        file.write(unicode(i).encode(\"utf-8\")) # save CSV\n                        file.write(i) # save CSV\n\n                        print(i)\n\n            except Exception:\n                App.Console.PrintError(\"Error write file \"+ext+\"\\n\")\n            finally:\n                file.close()\n        except Exception:\n            App.Console.PrintError(\"Error Open file \"+SaveName+\"\\n\")\n\n##tableau.getContents(\"A2\")                             #lire une celulle\n##print App.ActiveDocument.Spreadsheet.cells.Content    #lire toutes les celulles # XML\n\ntry:\n    for i in FreeCAD.ActiveDocument.Objects:               # search SpreadSheet in all object\n        obj = FreeCAD.ActiveDocument.getObject(i.Name).TypeId.split(\"::\")[0]\n        if obj == \"Spreadsheet\":\n            tableau = FreeCAD.ActiveDocument.getObject(str(i.Name))\n            print( \"Name : \",i.Name,\" ; Label : \",i.Label)\n            break                                          # quit to the first SpreadSheet\n    \n    linesMax    = decodeOccupation(tableau)[0]             # linesMax\n    colonnesMax = decodeOccupation(tableau)[1]             # colonnesMax\n    #print decodeOccupation(tableau)[2]                    # display the cells occupied\n    \n    print( \"Number cell : \", linesMax * colonnesMax,\" (\", linesMax,\" L x \", colonnesMax,\" C)\")\n    FreeCADGui.updateGui()                                          # rafraichi l'ecran\n    \n    dataToSave = []\n    for i in range(1, linesMax+1):\n        for ii in range(1, colonnesMax+1):\n    #        dataToSave.append(unicode(tableau.getContents(caseTableau(i,ii)), 'utf-8') + ESCAPE)\n            dataToSave.append(tableau.getContents(caseTableau(i,ii)) + ESCAPE)\n        dataToSave.append(\"\\n\")\n    \n    saveDataInFile(dataToSave)\n    del dataToSave[:]\n    \n    print( \"__Fin FCSpreadSheet_Extract__________\\n\")\nexcept Exception:\n    print (\"No SpreadSheet in the document or Error\")",
    "url": "https://wiki.freecad.org/Macro_FCSpreadSheet_Extract",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_FCSpreadSheet_Extract",
    "version": "00.03",
    "license": "",
    "date": "2020/03/14",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_FCSpreadsheet_Extract.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/d/d5/Macro_FCSpreadsheet_Extract.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "FindAliasReferences",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro will scan all the expressions in all the open documents then output, to the Report View, all expressions that contain the alias or if the alias is not defined then the value in the spreadsheet selected cell(s).<br /><br />Macro version: 2024.04.09<br />Last modified: 2024-04-09<br />FreeCAD version: 0.22<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/b/bd/FindAliasReferences.png?20240117201630\">ToolBar Icon</a><br />Author: RoyW<br /> ",
    "comment": "Find references to spreadsheet aliases in open documents",
    "code": "from typing import Generator\n\nimport FreeCAD\nimport re\nfrom PySide import QtGui\n\n\n\"\"\"\nThis macro will scan all the expressions in all the open documents then output, to the Report View, all \nexpressions that contain the alias or if the alias is not defined then the value in the spreadsheet \nselected cell(s).  This is a string match, not a wildcard match and not a regular expression.\n\nThe primary use case is to locate usages of spreadsheet aliases where the user has one or more cells selected\nthat contain either the alias or a string containing the alias name.  Aliases without any references may \nsafely be removed if they are not used internally in the spreadsheet.\n\nThe secondary use case is for the user to put an arbitrary string in a cell then search the open document's\nexpressions for tokens that start with the cell's value.\n\nFor example, say you have your spreadsheet in the globals.FCStd file and you link to the spreadsheet from\nother documents.  Now say you set your spreadsheet label to \"params\".  This allows you to reference alias\nvalues as either \"globals#<<params>>.aliasName\" or shorter as \"<<params>>.aliasName\".  To use alias name\ncompletion you must use the former, but when done you want to change these alias references to the latter\nformat for brevity.  To find them, enter the unique start of the alias value in a cell, \"globals\" in this\nexample, then run this macro on the cell.\n\nThis macro reuses the spreadsheet handling code from EasyAlias macro by TheMarkster and rosta:\nref: \"https://wiki.freecadweb.org/Macro_EasyAlias\"\n\nUsage:\n\n* Select the spreadsheet in the tree view.  Note, must be the actual spreadsheet and not a link to the spreadsheet.\n* Select one or more cells in the spreadsheet that contain the alias or substrings to find in expressions.\n* Run this macro.\n* Examine output in the Report View.\n\nThe output in the Report View will look like this:\n\nFor non-container objects:\n\n  document_name => object_label (object_name)\n  alias_name = expression\n  alias_name = expression\n  ...\n\nFor a container object:\n\n  document_name => container_label (container_name) => object_label (object_name)\n  alias_name = expression\n  ...\n\nIf no references are found for a substring, then \"No references to \"{substring}\" found\" will be displayed.\n\nFor an empty spreadsheet cell no output will be generated.  This allows ignoring blank cells when a range \nof cells is selected.\n\nTested on: \n\nOS: Ubuntu 23.10 (KDE/plasmawayland)\nWord size of FreeCAD: 64-bit\nVersion: 0.22.0dev.35485 (Git) AppImage\nBuild type: Release\nBranch: main\nHash: a662fbb2ff267fb8dd56fcc3d1ec55a5968b7f5a\nPython 3.10.13, Qt 5.15.8, Coin 4.0.2, Vtk 9.2.6, OCC 7.6.3\nLocale: English/United States (en_US)\nInstalled mods: \n  * CurvedShapes 1.0.4\n  * Assembly4 0.12.5\n  * A2plus 0.4.60h\n  * fasteners 0.4.58\n  * lattice2 1.0.0\n  * Curves 0.6.12\n\n\n__title__ = \"FindAliasReferences\"\n__author__ = \"RoyW\"\n__date__ = \"2024.04.09\" #year.month.date\n__version__ = __date__\n__comment__ = \"Find references to spreadsheet aliases in open documents\"\n__url__ = \"https://wiki.freecadweb.org/Macro_FindAliasReferences\"\n__Wiki__ = \"https://wiki.freecadweb.org/Macro_FindAliasReferences\"\n__License__ = \"MIT\"\n\n\"\"\"\n\nCELL_ADDR_RE = re.compile(r\"([A-Za-z]+)([1-9]\\d*)\")\nCUSTOM_ALIAS_RE = re.compile(r\".*\\((.*)\\)\")\nMAGIC_NUMBER = 64\nREPLACEMENTS = {\n    \" \": \"_\",\n    \".\": \"_\",\n    \"\u00e4\": \"ae\",\n    \"\u00f6\": \"oe\",\n    \"\u00fc\": \"ue\",\n    \"\u00c4\": \"Ae\",\n    \"\u00d6\": \"Oe\",\n    \"\u00dc\": \"Ue\",\n    \"\u00df\": \"ss\",\n    \"'\": \"\"\n}\n\n\ndef get_spreadsheets():\n    \"\"\"\n    Returns a set of selected spreadsheets in the active document or None if none is selected.\n    :returns: a set of selected spreadsheets in the active document or None if none is selected\n    :rtype: set\n    \"\"\"\n\n    spreadsheets = set()\n    for selectedObject in Gui.Selection.getSelection():\n        if selectedObject.TypeId == 'Spreadsheet::Sheet':\n            spreadsheets.add(selectedObject)\n        elif selectedObject.TypeId == \"App::Link\":\n            linkedObject = selectedObject.LinkedObject\n            if linkedObject.TypeId == 'Spreadsheet::Sheet':\n                spreadsheets.add(linkedObject)\n    return spreadsheets\n\n\n# The original implementation of a1_to_rowcol and rowcol_to_a1 can be found here:\n# https://github.com/burnash/gspread/blob/master/gspread/utils.py\n\n\ndef a1_to_rowcol(label: str):\n    \"\"\"Translates a cell's address in A1 notation to a tuple of integers.\n    :param str label: A cell label in A1 notation, e.g. 'B1'. Letter case is ignored.\n    :returns: a tuple containing `row` and `column` numbers. Both indexed from 1 (one).\n    :rtype: tuple\n    Example:\n    >>> a1_to_rowcol('A1')\n    (1, 1)\n    \"\"\"\n\n    match = CELL_ADDR_RE.match(label)\n\n    row = int(match.group(2))\n\n    column_label = match.group(1).upper()\n    column = 0\n    for i, c in enumerate(reversed(column_label)):\n        column += (ord(c) - MAGIC_NUMBER) * (26 ** i)\n\n    return row, column\n\n\ndef rowcol_to_a1(row: int, column: int):\n    \"\"\"Translates a row and column cell address to A1 notation.\n    :param row: The row of the cell to be converted. Rows start at index 1.\n    :type row: int, str\n    :param column: The column of the cell to be converted. Columns start at index 1.\n    :type row: int, str\n    :returns: a string containing the cell's coordinates in A1 notation.\n    Example:\n    >>> rowcol_to_a1(1, 1)\n    A1\n    \"\"\"\n\n    row = int(row)\n\n    column = int(column)\n    dividend = column\n    column_label = \"\"\n    while dividend:\n        (dividend, mod) = divmod(dividend, 26)\n        if mod == 0:\n            mod = 26\n            dividend -= 1\n        column_label = chr(mod + MAGIC_NUMBER) + column_label\n\n    label = \"{}{}\".format(column_label, row)\n\n    return label\n\n\ndef text_to_alias(text: str) -> str:\n    # support for custom aliases between parentheses\n    match = CUSTOM_ALIAS_RE.match(text)\n    if match:\n        return match.group(1)\n\n    for character in REPLACEMENTS:\n        text = text.replace(character, REPLACEMENTS.get(character))\n    return text\n\n\ndef _object_description(label: str, name: str) -> str:\n    \"\"\"\n    Helper function to format label+name.\n\n    if only label is not None, then return f\"{label}\"\n    if only name is not None, then return f\"{name}\"\n    if both are not None and equal, then return f\"{label}\"\n    if both are not None and not equal, then return f\"{label} ({name})\"\n    if both are None, then return \"\" (should not happen)\n\n    :param label: object label string.\n    :param name: object name string.\n    :return: formatted string with label and name.\n    \"\"\"\n    if label:\n        if name:\n            if label != name:\n                return f\"{label} ({name})\"\n        return label\n    return \"\"\n\n\ndef _location_string(doc, obj) -> str:\n    \"\"\"\n    The location of the object containing expressions may be either just the document for containerless objects\n    or the object's container combined with the object itself.\n\n    Containerless output will be:\n    \"Document.Name\"\n\n    Objects inside of containers with the same object label and name will be:\n    \"Document.Name => Object.Label\"\n\n    Objects inside of containers with different object label and name will be:\n    \"Document.Name => Object.Label (Object.Name)\"\n\n    :param doc: document instance.\n    :param obj: object instance.\n    :return: location string.\n    \"\"\"\n    location = f\"{doc.Name}\"\n    try:\n        parent = obj.getParent()  # note FreeCAD-RealThunder has removed getParent()\n        if parent:\n            # location typically contains \"DocName => MyContainer (Body001)\"\n            location = f\"{doc.Name} => {_object_description(parent.Label, parent.Name)}\"\n    except:\n        pass\n    return location or \"\"\n\n\ndef _contains_alias(spreadsheet, substring: str, expression: str) -> bool:\n    \"\"\"\n    Checks if the expression contains a reference to the spreadsheet's substring.\n\n    The contains rules are:\n      if any token of the expression matches:\n        *<<{spreadsheet.Label}>>.{substring}\n      or\n        *<<{spreadsheet.Name}>>.{substring}\n      or\n        *{spreadsheet.Label}.{substring}\n      or\n        *{spreadsheet.Name}.{substring}\n      or\n        {substring}*\n\n    FreeCAD formats alias references with \"<<{spreadsheet.Label or spreadsheet.Name}.{alias_name}\".\n    For object parameters it uses \"<<{object.Label or object.Name}>>.{parameter_name}\".\n    Fully qualified alias references use:\n      \"{spreadsheet_document.Name}#<<{spreadsheet.Label or spreadsheet.Name}.{alias_name}\"\n    The last content rule is to allow you to put the {spreadsheet_document.Name} in a cell and search for all\n    fully qualified references.\n\n    :param spreadsheet: The selected spreadsheet instance.\n    :param substring: The substring (i.e. the alias name) to look for in the expression.\n    :param expression:  The expression string to check if it contains the substring.\n    :return: True if the expression contains the substring, False otherwise.\n    \"\"\"\n    tokens = expression.split()\n    pattern1 = f\"<<{spreadsheet.Label or spreadsheet.Name}>>.{substring}\"\n    pattern2 = f\"{spreadsheet.Label or spreadsheet.Name}.{substring}\"\n    for token in tokens:\n        if token.endswith(pattern1):\n            return True\n        if token.endswith(pattern2):\n            return True\n        if token.startswith(substring):\n            return True\n    return False\n\n\ndef _finder(substring: str, spreadsheet) -> Generator[str, None, None]:\n    \"\"\"\n    Helper that performs the search and returns a list of formatted output lines.\n\n    :param substring: the substring to match in all expressions.\n    :yields: the formatted output as a single line string.\n    \"\"\"\n\n    # for each open document\n    for doc in App.listDocuments().values():\n        # iterate over non-null objects in the current document\n        for obj in [o for o in doc.Objects if o]:\n            try:\n                location = _location_string(doc, obj)\n                header = True\n                # find the expressions that contain the substring\n                for ee in [x for x in obj.ExpressionEngine if _contains_alias(spreadsheet, substring, x[1])]:\n                    # just emit the header once for each document object that has expressions that contain\n                    # the substring\n                    if header:\n                        yield ''\n                        # typically yields \"DocName => MyContainer (Body001) => MySketch (Sketch003)\"\n                        yield f\"{location} => {_object_description(obj.Label, obj.Name)}\"\n                        header = False\n                    # ee typically contains [\"Constraints[N]\", expression_string]\n                    # so typically yields \"Constraints[N] = expression_string\"\n                    yield f\"{ee[0]} = {ee[1]}\"\n            except AttributeError as ex:\n                # shouldn't happen...\n                print(ex)\n\n\ndef find_alias_references(substring: str, spreadsheet) -> str:\n    \"\"\"\n    Search expressions in all the open documents for the given substring.\n\n    :param substring: the substring to match in all expressions.\n    :param spreadsheet: the spreadsheet instance.\n    :return: formatted multi-line string containing the found references.\n    \"\"\"\n    return '\\n'.join(_finder(substring, spreadsheet))\n\n\ndef main() -> None:\n    \"\"\"\n    For each of the selected cells in the spreadsheet, find and print to the report view all the expressions\n    that contain the alias, or if not defined, then the value in the selected cell.\n\n    Note that the spreadsheet must be selected in the tree view.\n    :return: None\n    \"\"\"\n    spreadsheets = get_spreadsheets()\n    if not spreadsheets:\n        QtGui.QMessageBox.critical(None, \"Error\",\n                                   \"No spreadsheet selected.\\nPlease select a spreadsheet in the tree view.\")\n        return\n    for spreadsheet in spreadsheets:\n        for selectedCell in spreadsheet.ViewObject.getView().selectedCells():\n            # set substring to the cell's alias if present\n            # If not then set substring to the cell's value\n            substring = spreadsheet.getAlias(selectedCell)\n            if not substring:\n                contents = spreadsheet.getContents(selectedCell)\n                if contents:\n                    substring = text_to_alias(contents)\n            # ignore blank cells\n            if substring:\n                # contents typically look like \"'String\\n\" so strip off the leading ' and trailing newline\n                substring = substring.lstrip(\"'\").rstrip(\"\\n\\r\")\n                # print the report for the spreadsheet cell to the report view\n                report_string = find_alias_references(substring, spreadsheet)\n                print(report_string or f\"No references to \\\"{substring}\\\" found\")\n\n\nmain()",
    "url": "https://wiki.freecad.org/Macro_FindAliasReferences",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_FindAliasReferences",
    "version": "2024.04.09",
    "license": "",
    "date": "2024.04.09",
    "src_filename": "",
    "filename_from_url": "",
    "author": "RoyW",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\FindAliasReferences.png",
    "icon_source": "https://wiki.freecad.org/images/b/bd/FindAliasReferences.png?20240117201630",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Sketch Constraint From Spreadsheet",
    "on_wiki": true,
    "on_git": false,
    "desc": "Macro which, with a simple click on a spreadsheet cell, adds a length constraint to a line, a circle, or between 2 points using a spreadsheet cell alias or address (ex. C2). Future changes to the spreadsheet will update the constraint. The macro can create alias for you.<br />Just select 1 line, 2 points or a constraint, click on a spreadsheet cell and run the macro. You can select lines, points at the ends of a line, points, circles or arcs of circles.<br /><br /><br />Macro version: 01.06<br />Last modified: 2025-01-28<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/d/dc/Macro_Sketch_Constraint_From_Spreadsheet.svg\">ToolBar icon</a><br />Author: 2cv001<br /> ",
    "comment": "A simple click on a spreadsheet cell, adds a length constraint to a line, circle, points... using a spreadsheet cell alias or address (ex. C2). The macro can create alias for you.",
    "code": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# ========================================================================\n# Macro Sketch Constraint From Spreadsheet\n# file name : Sketch_Constraint_From_Spreadsheet.FCMacro\n# ========================================================================\n# ==                                                                    ==\n# == Adds a length constraint to a line, circle, points ...             ==\n# == using a spreadsheet cell alias or name (ex. C2).                   ==\n# == Future changes to the spreadsheet will update the constraint.      ==\n# == if necessary, the macro help you to create alias                   ==\n# == USE:                                                               ==\n# == 1) Select 1 line, 2 points or a constraint                         ==\n# == 2) Click on a spreadsheet cell                                     ==\n# == 3) Launch the macro                                                ==\n# ==    if the cell has an alias, the length property will be something ==\n# ==    like 'Spreadsheet.alias'.                                       ==\n# ==    if not, just something like 'Spreadsheet.C2'                    ==\n# == You can select lines, points line, points, circle...               ==\n# == You can select external objetcs                                    ==\n# ========================================================================\n# ========================================================================\n__Name__   = \"Sketch Constraint From Spreadsheet\"\n__Comment__ =\"A simple click on a spreadsheet cell, adds a length constraint to a line, circle, points... using a spreadsheet cell alias or address (ex. C2). The macro can create alias for you.\"\n__Author__ = \"2cv001\"\n__Title__   = \"Macro Sketch Constraint From Spreadsheet\"\n__Date__    = \"2025/01/30\"    #YYYY/MM/DD \n__Version__ = __Date__\n__Icon__    = \"https://wiki.freecad.org/images/d/dc/Macro_Sketch_Constraint_From_Spreadsheet.svg\"\n__Wiki__    = \"https://wiki.freecad.org/Macro_sketchConstraintFromSpreadsheet\"\n__License__ = \"Apache-2.0\"\n\nfrom PySide import QtGui, QtCore\nfrom PySide2.QtGui import QIcon\nfrom PySide2 import QtWidgets\nfrom PySide2.QtGui import QGuiApplication\nfrom datetime import datetime\nimport configparser\nimport os\nimport FreeCAD\nimport re\nimport itertools\nimport locale\n\n# macro directory (for ini file)\nmacroDirectory = FreeCAD.getUserMacroDir(True)\n\nfrom PySide2 import QtWidgets, QtCore\nimport FreeCADGui as Gui\n\n\n\n\ndef recomputeAll() :                \n    for obj in FreeCAD.ActiveDocument.Objects:\n        obj.touch()\n    FreeCAD.ActiveDocument.recompute()\n\n\n\ndef getLanguage() : \n    # Dictionary of common languages\n    common_languages = {\n        'en': 'English',\n        'fr': 'French',\n    }\n\n    lang = App.ParamGet(\"User parameter:BaseApp/Preferences/General\").GetString('Language')\n\n    if not lang :   # if App.ParamGet found nothing\n        system_language = locale.getlocale()[0][:2]\n        if system_language in common_languages:\n            lang = common_languages[system_language]        \n    if lang not in common_languages.values() :\n        lang = 'English'\n    return lang\n\n\n    \nlanguage = getLanguage()\n\n# use : messages[language][\"Values\"]\n\nmessages = {\n    \"French\": {\n        \n        \"DialogCheckbox1Document\": \"Document\",        \n        \"DialogToolLip\": \"Si coch\u00e9, l'alias sera automatiquement cr\u00e9\u00e9 lors de l'\u00e9x\u00e9cution de la macro. \"+\n                        \"\\nLes Alias seront cr\u00e9\u00e9s \u00e0 droite des cellules avec texte. Les cellules avec texte sont celle ci et en dessous : \",\n        \"DialogCheckboxAlias\": \"Cellule de d\u00e9part pour les textes des alias  :\",\n        \"DialogCheckboxSpreadsheet\": \"Spreadsheets\",        \n        \"DialogTextboxSpreadsheetNameTolLip\": \"Nom pour les spreadsheet\", \n        \n        \"DialogCheckboxTextDocument\": \"Text document\", \n        \"DialogTextboxTextdocumentNameToolTip\": \"Nom pour les Text Document\",        \n\n        \"DialogcheckboxBody\": \"Body\",  \n        \"DialogTextboxBodyNameToolTip\": \"Nom pour les body\", \n        \n        \"DialogcheckboxSketch\": \"Sketch\",  \n        \"DialogTextboxSketchNameTolLip\": \"Nom pour les sketch\", \n        'TITLE':'TITRE',\n        'Textsforalias':'Libell\u00e9 des alias',\n        'Values' : 'Valeurs',\n        'OkOui':'Oui',        \n        'NoPasDe':'Pas de',        \n        'foundTrouve':'trouv\u00e9',\n        'foundCreateOne':'trouv\u00e9, en cr\u00e9er un ?',\n        'Cancel':'Abandon', \n        'Warning':'Attention',\n        'Warning':'Warning',\n        'XYPlane':'Plan XY',\n        'XZPlane':'Plan XZ',\n        'YZPlane':'Plan YZ', \n\n        'referenceNoName':\n        'La contrainte que vous avez s\u00e9lectionn\u00e9e est une contrainte de type r\u00e9f\u00e9rence.'+\n                    \"\\n Elle n'a pas de nom. \\nVoulez-vous que la macro lui en donne \"+\n                    \"\\n et voulez-vous que la cellule contienne la valeur de la contrainte ?\"+\n                    \"\\n ATTENTION, v\u00e9rifiez que vous n'allez pas cr\u00e9er une r\u00e9f\u00e9rence circulaire.\"+\n                    \"\\n\\nIl se peut que PENDING apparaisse dans la cellule. Pour l'instant, \" +\n                    \"je ne recommande pas son utilisation car FreeCad manage mal les href.\",\n        'referenceWithName' :\n        'La contrainte que vous avez s\u00e9lectionn\u00e9e est une contrainte de type r\u00e9f\u00e9rence.'+\n                    \"\\n\\nVoulez-vous que la cellule contienne la valeur de la contrainte ?\"+\n                    \"\\n ATTENTION, v\u00e9rifiez que vous n'allez pas cr\u00e9er une r\u00e9f\u00e9rence circulaire.\"+\n                    \"\\n\\nIl se peut que PENDING apparaisse dans la cellule. \" + \n                    \"En ce cas, tapez Gui.ActiveDocument.ActiveView.getSheet().recompute(True) dans la console python \" +\n                    \"je ne recommande pas son utilisation car FreeCad manage mal les href.\",\n\n        \n        'ClickOnACellBefore': \"Cliquez dans une cellule avec une valeur num\u00e9rique avant de lancer la macro.\", \n\n        \"NoObjectSelected\" : \"Vous n'avez pas s\u00e9lectionn\u00e9 d'objets dans le sketch actif.\"\n                     + \"\\nCela veut il dire que vous souhaitez cr\u00e9er automatiquement des alias \u00e0 droite des cellules s\u00e9lectionn\u00e9es\" \n                     + \"en utilisant le texte de ces cellules s\u00e9lectionn\u00e9es.\",\n\n        \"NoActiveSpreadsheet\":\"Pas de cellule s\u00e9lectionn\u00e9e dans un spreadsheet actif.\"+\n                               \"\\nS\u00e9lectionnez un objet dans un sketch, puis s\u00e9lectionnez une cellule dans un spreadsheet.\",                       \n                     \n        \"ConstarintConflicDetected\"  :\"D\u00e9tection de conflit dans les contraintes. Annulation de la cr\u00e9ation de la conrainte ?\",  \n                     \n        \"getConstraintTypeAliasToolLip\": \"Si coch\u00e9, l'alias sera automatiquement cr\u00e9\u00e9 lors de l'\u00e9x\u00e9cution de la macro.\"\n                        +\"\\nLes Alias seront cr\u00e9\u00e9s \u00e0 droite des cellules avec texte. Les cellules avec texte sont celle ci et en dessous : \",\n        \"getConstraintTypeOption1ButtonSetText\": \"Contrainte horizontale \",\n        \"getConstraintTypeOption2ButtonSetText\": \"Contrainte verticale\",\n        \"getConstraintTypeOption3ButtonSetText\": \"Contrainte align\u00e9e\",\n        \"getConstraintTypeOption1ButtonSetTextToolLip\": \"Contrainte horizontale\",\n        \"getConstraintTypeOption2ButtonSetTextToolLip\": \"Contrainte verticale\",\n        \"getConstraintTypeOption3ButtonSetTextToolLip\": \"Contrainte align\u00e9e\",         \n        \"getConstraintTypeCheckboxConflic\": \"D\u00e9tecttion des conflits\",\n        \"getConstraintTypeCheckboxConflicToolLip\" : \"Avertissement en cas de conflit de contraintes.\" +\n            \"\\nDonne la possibilit\u00e9 d'annuler la contrainte \",  \n        \"getConstraintTypeWindowTitle\" : \"Choix du type de contrainte\", \n        \"getConstraintTypeCheckboxAlias\": \"Textes pour alias automatiques dans cette cellule et en dessous :\",         \n    },\n    \n \n    \n    \"English\": {\n\n        \"DialogCheckbox1Document\": \"Document\", \n        \"DialogToolLip\": \"If checked, alias will automatically be created during each macro execution. \"+\n                        \"\\nAlias will be created at the right of cells with text. Cells with text is this one and cells and under : \",\n                        \n                        \n        \"DialogCheckboxAlias\": \"Starting cell for alias texts  :\",\n        \"DialogCheckboxSpreadsheet\": \"Spreadsheets\",        \n        \"DialogTextboxSpreadsheetNameTolLip\": \"Name for the spreadsheet\", \n        \n        \"DialogCheckboxTextDocument\": \"Text document\", \n        \"DialogTextboxTextdocumentNameToolTip\": \"Name for the Text Document\",        \n\n        \"DialogcheckboxBody\": \"Body\",        \n        \"DialogTextboxBodyNameToolTip\": \"Name for the body\",  \n        \"DialogcheckboxSketch\": \"Sketch\",  \n        \"DialogTextboxSketchNameTolLip\": \"Name for the sketch\", \n        'TITLE':'TITLE',\n        'Textsforalias':'Texts for alias',\n        'Values' : 'Values',\n        'OkOui':'Ok',\n        'NoPasDe':'No',\n        'foundTrouve':'found',\n        'foundCreateOne':'found, create one?',\n        'Cancel':'Cancel',\n        'Warning':'Warning',\n        'XYPlane':'XY Plane',\n        'XZPlane':'XZ Plane',\n        'YZPlane':'YZ Plane',\n        \n        \n        \n        'referenceNoName':\n        'The constraint you have selected is a reference type constraint.'+\n                    \"\\n It does not have a name. \\nDo you want the macro to give it one \"+\n                    \"\\n and do you want the cell to contain the value of the constraint?\"+\n                    \"\\n WARNING, check that you are not going to create a circular reference.\"+\n                    \"\\n\\nPENDING may appear in the cell. This will appear too often. \\nFor now, \"+\n                    \"I do not recommend its use..\",\n        'referenceWithName' :\n        'The constraint you have selected is a reference type constraint.'+\n                    \"\\n\\nDo you want the cell to contain the value of the constraint?\"+\n                    \"\\n WARNING, check that you are not going to create a circular reference.\"+\n                    \"\\n\\nPENDING may appear in the cell. in this case, type Gui.ActiveDocument.ActiveView.getSheet().recompute(True) dans la console python in the python console.\",\n        \n        \n        'ClickOnACellBefore':\"Click on a cell with a numeric value before runing the macro\",\n        \n        \"NoObjectSelected\" : \"You did not select any object in an active sketch.\"\n                     + \"\\nDoes it mean you want to create alias at the right of selected cells \"\n                     + \"using text in selected cells ?\" ,\n                     \n                     \n        \"NoActiveSpreadsheet\":\"No active spreadsheet with selected cells.\"+\n                                            \"\\nSelect objects in sketch, and then select a cell in spreadsheet.\",             \n                     \n        \"ConstarintConflicDetected\" :\"Constraints conflic detected. Cancel constraint creation?\", \n        \n        \"getConstraintTypeAliasToolLip\": \"If checked, alias will automatically be created during each macro execution.\" + \n            \"\\nAlias will be built for the right cells from the text in this cell and under.\",       \n\n        \"getConstraintTypeOption1ButtonSetText\": \"Lenght constrainte X \",\n        \"getConstraintTypeOption2ButtonSetText\": \"Lenght constrainte Y\",\n        \"getConstraintTypeOption3ButtonSetText\": \"Lenght constrainte\",  \n        \"getConstraintTypeOption1ButtonSetTextToolLip\": \"Lenght constrainte X \",\n        \"getConstraintTypeOption2ButtonSetTextToolLip\": \"Lenght constrainte Y\",\n        \"getConstraintTypeOption3ButtonSetTextToolLip\": \"Lenght constrainte\",  \n        \"getConstraintTypeCheckboxConflic\": \"Conflict detection\", \n        \"getConstraintTypeCheckboxConflicToolLip\" : \"Warning in case of constraint conflict. Gives the possibility to cancel the constraint.\",\n        \"getConstraintTypeWindowTitle\" : \"Choose a constraint type\",\n        \"getConstraintTypeWindowTitle\" : \"Choose a constraint type\",\n        \"getConstraintTypeCheckboxAlias\": \"Texts for Automatic alias labels for this cell, and under :\", \n        \n\n        \n        \n    }\n}\n    \n\n\n\n\n\n# save objects names in ini file\n#typeObject : Spreadsheet, Body....\ndef save_settings_Name(typeObject,objectName):\n    config = configparser.ConfigParser()\n    ini_file = os.path.join(macroDirectory, \"sketchConstraintFromSpreadsheet.ini\")\n    config.read(ini_file)\n    if 'SettingNames' not in config:\n        config.add_section('SettingNames')        \n    config.set('SettingNames', typeObject, objectName)\n    with open(ini_file, 'w') as configfile:\n        config.write(configfile)\n\n# Read name given by user for object choiseObject in ini file\ndef getIniName(choiceObject):\n    config = configparser.ConfigParser()\n    ini_file = os.path.join(macroDirectory, \"sketchConstraintFromSpreadsheet.ini\")\n    if os.path.exists(ini_file):\n        config.read(ini_file)\n        label=config.get('SettingNames', choiceObject, fallback=choiceObject)\n        return label\n    return choiceObject\n\n\n# Read cell for alias labelss value in ini file\ndef getIniCellForAlias():\n    config = configparser.ConfigParser()\n    ini_file = os.path.join(macroDirectory, \"sketchConstraintFromSpreadsheet.ini\")\n    if os.path.exists(ini_file):\n        config.read(ini_file)\n        cell=config.get('SettingsAlias', 'textboxAlias', fallback='A3')\n        if cell=='' :\n            cell='A3'\n        return cell            \n    else:\n        return 'A3'\n        \n # read checkbox value in ini file       \ndef getIniCheckboxStateForAlias():\n    config = configparser.ConfigParser()\n    ini_file = os.path.join(macroDirectory, \"sketchConstraintFromSpreadsheet.ini\")\n    if os.path.exists(ini_file):\n        config.read(ini_file)\n        return config.getboolean('SettingsAlias', 'checkboxAlias', fallback=True)\n    else:\n        return True\n\n\n# save column for alias labels and checkbox for alias value in ini file\ndef save_settings_Alias(cell,checked):\n    config = configparser.ConfigParser()\n    ini_file = os.path.join(macroDirectory, \"sketchConstraintFromSpreadsheet.ini\")\n    config.read(ini_file)\n    if 'SettingsAlias' not in config:\n        config.add_section('SettingsAlias')\n        \n    config.set('SettingsAlias', 'textboxAlias', cell.upper())\n    config.set('SettingsAlias', 'checkboxAlias', str(checked))\n    with open(ini_file, 'w') as configfile:\n        config.write(configfile)\n\n#################################################################################\n# part code for objects creation at the begining of the macro execution.\n# If there is no spreadsheet or sketch: ask for creation.\n#################################################################################\n\n\n#===============================================================================\n# dialog box class for objects creations\n#===============================================================================\nclass Dialog(QtGui.QDialog):            \n    def __init__(self, documentState, spreadsheetState, textdocumentState,  bodyState, sketchState, text='', parent=None):\n        super(Dialog, self).__init__(parent)\n        # toolLip=(\"If checked, alias will automatically be created during each macro execution. \"+\n                # \"Alias will be created at the right of cells with text. Cells with text is this one or cells and under  :\")\n        toolLip=messages[language][\"DialogToolLip\"]\n        self.documentState = documentState\n        self.textdocumentState = textdocumentState        \n        self.spreadsheetState = spreadsheetState\n        self.bodyState = bodyState\n        self.sketchState = sketchState\n        \n        self.text_widget = QtGui.QLabel(text)       \n                              \n        #self.checkbox1Document = self.create_checkbox(\"Document\", documentState)\n        self.checkbox1Document = self.create_checkbox(messages[language][\"DialogCheckbox1Document\"], documentState)\n        \n        #self.checkboxTextDocument = self.create_checkbox(\"Text document\", textdocumentState)    \n        self.checkboxTextDocument = self.create_checkbox(messages[language][\"DialogCheckboxTextDocument\"], textdocumentState)\n        \n        #self.checkboxSpreadsheet = self.create_checkbox(\"Spreadsheets\", spreadsheetState)\n        self.checkboxSpreadsheet = self.create_checkbox(messages[language][\"DialogCheckboxSpreadsheet\"], spreadsheetState)        \n        \n        #self.checkboxBody = self.create_checkbox(\"Body\", bodyState)\n        self.checkboxBody = self.create_checkbox(messages[language][\"DialogcheckboxBody\"], bodyState)        \n        \n        #self.checkboxSketch = self.create_checkbox(\"Sketch\", sketchState)  \n        self.checkboxSketch = self.create_checkbox(messages[language][\"DialogcheckboxSketch\"], sketchState)\n        \n        #self.checkboxAlias = QtGui.QCheckBox(\"Starting cell for alias texts  :\") \n        self.checkboxAlias = QtGui.QCheckBox(messages[language][\"DialogCheckboxAlias\"]) \n            \n        self.checkboxAlias.setToolTip(toolLip)   \n        \n\n        self.textboxSpreadsheetName = QtGui.QLineEdit(getIniName('Spreadsheet'))\n        self.textboxSpreadsheetName.setFixedWidth(200)  # size\n        #self.textboxSpreadsheetName.setToolTip('Name for the spreadsheet')  \n        self.textboxSpreadsheetName.setToolTip(messages[language][\"DialogTextboxSpreadsheetNameTolLip\"])  \n\n        self.textboxTextdocumentName = QtGui.QLineEdit(getIniName('Textdocument'))\n        self.textboxTextdocumentName.setFixedWidth(200)  # size\n        \n        #self.textboxTextdocumentName.setToolTip('Name for the Text Document')   \n        self.textboxTextdocumentName.setToolTip(messages[language][\"DialogTextboxTextdocumentNameToolTip\"]) \n        \n        self.textboxBodyName = QtGui.QLineEdit(getIniName('Body'))\n        self.textboxBodyName.setFixedWidth(200)  # size\n        #self.textboxBodyName.setToolTip('Name for the Body')    \n        self.textboxBodyName.setToolTip(messages[language][\"DialogTextboxBodyNameToolTip\"])    \n        \n        self.textboxSketchName = QtGui.QLineEdit(getIniName('Sketch'))\n        self.textboxSketchName.setMaximumWidth(200)  # Set the maximum width of the text box\n        self.textboxSketchName.setFixedWidth(200)  # size\n        self.textboxSketchName.setToolTip('Name for the Sketch')  \n        self.textboxSketchName.setToolTip(messages[language][\"DialogTextboxSketchNameTolLip\"]) \n   \n\n        layout_checkbox1Document = QtGui.QHBoxLayout()\n        #layout_checkbox1Document.addSpacing(20)\n        if documentState !='no' :        \n            layout_checkbox1Document.addWidget(self.checkbox1Document)   \n      \n        layout_checkboxSpreadSheet = QtGui.QHBoxLayout()\n        layout_checkboxSpreadSheet.addSpacing(20)\n        if spreadsheetState !='no' :        \n            layout_checkboxSpreadSheet.addWidget(self.checkboxSpreadsheet)   \n            layout_checkboxSpreadSheet.addWidget(self.textboxSpreadsheetName)  \n        \n        \n        layout_checkboxTextDocument = QtGui.QHBoxLayout()\n        layout_checkboxTextDocument.addSpacing(20)\n        if textdocumentState!= 'no' :\n            layout_checkboxTextDocument.addWidget(self.checkboxTextDocument)           \n            layout_checkboxTextDocument.addWidget(self.textboxTextdocumentName)         \n        \n        layout_checkboxBody = QtGui.QHBoxLayout()\n        layout_checkboxBody.addSpacing(20)\n        if bodyState != 'no' :\n            layout_checkboxBody.addWidget(self.checkboxBody)\n            layout_checkboxBody.addWidget(self.textboxBodyName)\n        \n        layout_checkboxSketch = QtGui.QHBoxLayout()\n        layout_checkboxSketch.addSpacing(40)\n        if sketchState != 'no' :\n            layout_checkboxSketch.addWidget(self.checkboxSketch) \n            layout_checkboxSketch.addWidget(self.textboxSketchName)            \n        \n        self.radiobutton1 = QtGui.QRadioButton(messages[language][\"XYPlane\"])\n        self.radiobutton2 = QtGui.QRadioButton(messages[language][\"XZPlane\"])\n        self.radiobutton3 = QtGui.QRadioButton(messages[language][\"YZPlane\"])\n        self.radiobutton1.setIcon(QIcon(\":/icons/view-top\"))  \n        self.radiobutton2.setIcon(QIcon(\":/icons/view-front\"))     \n        self.radiobutton3.setIcon(QIcon(\":/icons/view-right\"))          \n        \n        # Set the XY Plane radio button to be checked by default\n        self.radiobutton1.setChecked(True)\n\n        self.textboxAlias = QtGui.QLineEdit(self.getIniCellForAlias())\n        self.textboxAlias.setMaximumWidth(50)  # Set the maximum width of the text box\n        self.textboxAlias.setMaxLength(4)  # Limit the text box to 4 characters\n        self.textboxAlias.setToolTip(toolLip) \n       \n               \n        regex = QtCore.QRegExp(\"^[a-zA-Z]+[0-9]+$\")\n        validator = QtGui.QRegExpValidator(regex, self)\n        self.textboxAlias.setValidator(validator)  \n        self.textboxAlias.textChanged.connect(self.onTextChanged)    \n     \n\n        # Set the checkboxes\n        self.checkbox1Document.setChecked(documentState == \"exist\" or documentState == \"on\")\n        self.checkboxTextDocument.setChecked(True)\n        self.checkboxSpreadsheet.setChecked(spreadsheetState == \"exist\" or spreadsheetState == \"on\")\n        self.checkboxBody.setChecked(bodyState == \"exist\" or bodyState == \"on\")\n        self.checkboxSketch.setChecked(sketchState == \"exist\" or sketchState == \"on\")\n        self.checkboxAlias.setChecked(self.getIniCheckboxStateForAlias())\n\n        self.checkbox1Document.stateChanged.connect(self.update_document_checkbox)\n        self.checkboxTextDocument.stateChanged.connect(self.update_textdocument_checkbox)        \n        self.checkboxSpreadsheet.stateChanged.connect(self.update_spreadsheet_checkbox)\n        self.checkboxBody.stateChanged.connect(self.update_body_checkbox)\n        self.checkboxSketch.stateChanged.connect(self.update_sketch_checkbox)\n\n        layout = QtGui.QVBoxLayout()\n        if text!='' :\n            layout.addWidget(self.text_widget)\n\n        layout.addLayout(layout_checkbox1Document)           \n        layout.addLayout(layout_checkboxSpreadSheet)\n        layout.addLayout(layout_checkboxTextDocument)        \n        layout.addLayout(layout_checkboxBody)\n        layout.addLayout(layout_checkboxSketch)\n        \n        layout_radio1 = QtGui.QHBoxLayout()\n        layout_radio1.addSpacing(60)\n        if sketchState !='no' :\n            layout_radio1.addWidget(self.radiobutton1)\n\n        layout_radio2 = QtGui.QHBoxLayout()\n        layout_radio2.addSpacing(60)\n        if sketchState !='no' :\n            layout_radio2.addWidget(self.radiobutton2)\n\n\n        layout_radio3 = QtGui.QHBoxLayout()\n        layout_radio3.addSpacing(60)\n        if sketchState !='no' :\n            layout_radio3.addWidget(self.radiobutton3)\n\n        layout.addLayout(layout_radio1)\n        layout.addLayout(layout_radio2)\n        layout.addLayout(layout_radio3)\n\n        layout_Alias = QtGui.QHBoxLayout()\n        layout_Alias.addWidget(self.checkboxAlias)\n        layout_Alias.addWidget(self.textboxAlias)\n        layout_Alias.addItem(QtGui.QSpacerItem(0, 0, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred))\n        layout.addLayout(layout_Alias)\n\n        # Add OK and Cancel buttons\n        self.buttons = QtGui.QDialogButtonBox(\n            QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel,\n            QtCore.Qt.Horizontal, self)\n        self.buttons.accepted.connect(self.accept)\n        self.buttons.rejected.connect(self.reject)\n        self.buttons.button(QtGui.QDialogButtonBox.Ok).setText(messages[language][\"OkOui\"])       \n        layout.addWidget(self.buttons)\n\n        self.setLayout(layout)\n        self.update_document_checkbox()\n        self.update_spreadsheet_checkbox()        \n        self.update_textdocument_checkbox()   \n        self.update_body_checkbox()\n        self.update_sketch_checkbox()\n        self.update_radiobuttons()\n        \n\n    def onTextChanged(self, text):\n        # Convertir le texte en majuscules\n        uppercase_text = text.upper() \n        self.textboxAlias.blockSignals(True)\n        self.textboxAlias.setText(uppercase_text)\n        self.textboxAlias.blockSignals(False)   \n\n\n    def update_document_checkbox(self):\n        self.checkboxTextDocument.setEnabled(self.checkbox1Document.isChecked())  \n        if not self.checkbox1Document.isChecked() :\n            self.checkboxTextDocument.setChecked(False)            \n        self.checkboxSpreadsheet.setEnabled(self.checkbox1Document.isChecked())  \n        self.checkboxSpreadsheet.setChecked(self.checkbox1Document.isChecked())   \n        self.checkboxTextDocument.setEnabled(self.checkbox1Document.isChecked())  \n        self.checkboxTextDocument.setChecked(self.checkbox1Document.isChecked())         \n        self.checkboxBody.setEnabled(self.checkbox1Document.isChecked())  \n        self.checkboxBody.setChecked(self.checkbox1Document.isChecked())   \n\n        self.update_textdocument_checkbox()\n        self.update_spreadsheet_checkbox()\n        self.update_body_checkbox()        \n        \n    def update_textdocument_checkbox(self):\n        if self.textdocumentState == 'exist' :\n            self.checkboxTextDocument.setEnabled(False)  \n            self.checkboxTextDocument.setChecked(True)\n        self.textboxTextdocumentName.setEnabled(self.checkboxTextDocument.isChecked()\n        and self.checkboxTextDocument.isEnabled())\n        \n            \n    def update_spreadsheet_checkbox(self):\n        if self.spreadsheetState == 'exist' :\n            self.checkboxSpreadsheet.setEnabled(False)  \n            self.checkboxSpreadsheet.setChecked(True) \n        self.textboxSpreadsheetName.setEnabled(self.checkboxSpreadsheet.isChecked() \n                and self.checkboxSpreadsheet.isEnabled())\n        \n    def update_body_checkbox(self):\n        if self.bodyState == 'exist' :\n            self.checkboxBody.setEnabled(False)  \n            self.checkboxBody.setChecked(True)  \n \n        self.textboxBodyName.setEnabled(self.checkboxBody.isChecked()\n                and self.checkboxBody.isEnabled()) \n        self.checkboxSketch.setEnabled(self.checkboxBody.isChecked())  \n        self.checkboxSketch.setChecked(self.checkboxBody.isChecked())      \n        self.update_sketch_checkbox () \n\n    def update_sketch_checkbox(self):\n        # checked = self.checkboxBody.isChecked()\n        if self.sketchState =='exist' :\n            self.checkboxSketch.setEnabled(False)   \n            self.checkboxSketch.setChecked(True) \n        self.textboxSketchName.setEnabled(self.checkboxSketch.isChecked()\n                and self.checkboxSketch.isEnabled())             \n        self.update_radiobuttons()          \n\n    def update_radiobuttons(self):\n        enable = self.checkboxSketch.isChecked() and self.checkboxBody.isChecked()\n        if not self.checkboxSketch.isChecked() or not self.checkboxBody.isChecked():\n          enable=False\n          \n        if not self.checkboxSketch.isChecked() :\n            enable=False\n            \n        if   not self.checkboxSketch.isEnabled()  :\n            enable=False   \n            \n        self.radiobutton1.setEnabled(enable)\n        self.radiobutton2.setEnabled(enable)\n        self.radiobutton3.setEnabled(enable)\n        \n        \n        \n\n        \n        \n        \n\n    def create_checkbox(self, text, state):\n        # checkbox = QtGui.QCheckBox(text+' found' if state == \"exist\" else \"No \" + \n                                    # text + \" found, create one?\")\n                                    \n        checkbox = QtGui.QCheckBox(text+' '+ messages[language][\"foundTrouve\"] if state == \"exist\" else  messages[language][\"NoPasDe\"]  + \n                                    ' ' + text + ' ' + messages[language][\"foundCreateOne\"])\n                                    \n                                    \n        checkbox.setEnabled(state != \"off\")\n        checkbox.setChecked(state != \"off\")\n        if state == \"exist\" :\n          checkbox.setEnabled(False)\n          checkbox.setChecked(True) \n          \n        return checkbox\n\n    def getIniCellForAlias(self):\n        return getIniCellForAlias()\n            \n    def getIniCheckboxStateForAlias(self):\n        return getIniCheckboxStateForAlias()\n\n\n    def save_settings(self):\n        save_settings_Alias(self.textboxAlias.text(),self.checkboxAlias.isChecked())\n\n        save_settings_Name('Body',self.textboxBodyName.text())\n        save_settings_Name('Spreadsheet', self.textboxSpreadsheetName.text())\n        save_settings_Name('Textdocument', self.textboxTextdocumentName.text())\n        save_settings_Name('Sketch', self.textboxSketchName.text())        \n        \n\n            \n# Retrieve the results after displaying the object creation dialogue box.\n###############################################################################\ndef get_user_input(documentState, spreadsheetState, textdocumentState, bodyState, sketchState, text=''):\n    dialog = Dialog(documentState, spreadsheetState, textdocumentState,  bodyState, sketchState, text)\n    result = dialog.exec_()  # Display the dialog box and wait for the user to make their choices\n    if result :\n        dialog.save_settings()  # Save the settings to the INI file\n\n    # Return the state of the checkboxes and radio buttons, and the result of the dialog box\n    return {\n        'checkbox1Document': dialog.checkbox1Document.isChecked(),\n        'checkboxSpreadsheet': dialog.checkboxSpreadsheet.isChecked(),        \n        'checkboxTextDocument': dialog.checkboxTextDocument.isChecked(),\n        'checkboxBody': dialog.checkboxBody.isChecked(),\n        'checkboxSketch': dialog.checkboxSketch.isChecked(),\n        'radiobutton1': dialog.radiobutton1.isChecked(),\n        'radiobutton2': dialog.radiobutton2.isChecked(),\n        'radiobutton3': dialog.radiobutton3.isChecked(),\n        'checkboxAlias': dialog.checkboxAlias.isChecked(),\n        'textboxAlias': dialog.textboxAlias.text(),\n        'textboxSpreadsheetName' : dialog.textboxSpreadsheetName.text(),\n        'textboxTextdocumentName' : dialog.textboxTextdocumentName.text(),\n        'textboxBodyName' : dialog.textboxBodyName.text(),\n        'textboxSketchName' : dialog.textboxSketchName.text(),\n        'result': 'OK' if result == QtGui.QDialog.Accepted else 'Cancel' if result == QtGui.QDialog.Rejected else 'Closed'\n    }\n\n#=========================================================\n# Function that manages everything to add\n#  necessary or desired objects.\n#=========================================================\ndef addTheObjects():\n    \n    def firstObject(type, doc = App.ActiveDocument): \n        if doc==None :\n            return None\n            \n        for obj in doc.Objects:\n            if obj.TypeId == type:\n                return obj\n               \n    doc = Gui.ActiveDocument\n    firstTextdocument=None\n    firstSpreadsheet=None\n    firstBody=None\n    firstSketch=None\n    \n    if not doc : \n        paramDocument='on'\n        paramTextdocument ='on'\n        paramSpreadsheet ='on'\n        paramBody ='on'\n        paramSketch ='on'        \n    else :   \n        paramDocument='exist'\n        firstTextdocument=firstObject('App::TextDocument')\n        if firstTextdocument!=None :\n            paramTextdocument= 'exist'            \n        else :\n            paramTextdocument= 'off'            \n        firstSpreadsheet=firstObject('Spreadsheet::Sheet')\n        if firstSpreadsheet!=None :\n            paramSpreadsheet= 'exist'            \n        else :\n            paramSpreadsheet= 'on'            \n        firstBody=firstObject('PartDesign::Body' )\n        if firstBody!=None :\n            paramBody= 'exist'            \n        else :\n            paramBody= 'on'            \n        firstSketch=firstObject('Sketcher::SketchObject' )\n        if firstSketch!=None :\n            paramSketch= 'exist'            \n        else :\n            paramSketch= 'on'\n\n\n    # The creation of the objects themselves. Return the object\n    def createObjects(user_input):\n        objCreate=False\n        if user_input['checkbox1Document'] and not Gui.ActiveDocument:\n             firstDocument=App.newDocument()\n             objCreate=True\n             \n        if firstObject('Spreadsheet::Sheet')==None and user_input['checkboxSpreadsheet'] :\n            firstSpreadsheet = App.activeDocument().addObject('Spreadsheet::Sheet', user_input['textboxSpreadsheetName'])\n            # si la checkbox est coch\u00e9e alors on ajoute les textes titres dans les cellules\n\n            firstSpreadsheet.mergeCells('A1:B1')\n            firstSpreadsheet.setAlignment('A1:B1', 'center|vcenter|vimplied')\n            firstSpreadsheet.setStyle('A1:B1', 'bold')\n            firstSpreadsheet.set('A1', messages[language][\"TITLE\"])\n            if getIniCellForAlias() :\n                cellAbove, cellRight = get_adjacent_cells(getIniCellForAlias())\n                if cellAbove != \"\" and cellAbove not in['A1','B1']:\n                    firstSpreadsheet.set(cellAbove, messages[language][\"Textsforalias\"])\n                    firstSpreadsheet.set(cellRight, messages[language][\"Values\"])\n                    firstSpreadsheet.setStyle(cellAbove, 'bold')\n                    firstSpreadsheet.setStyle(cellRight, 'bold') \n                    firstSpreadsheet.recompute()\n            \n            Gui.ActiveDocument.getObject(firstSpreadsheet.Name).doubleClicked()            \n            objCreate=True\n             \n        if firstObject('App::TextDocument')==None and user_input['checkboxTextDocument'] :\n            firstTextdocument = App.activeDocument().addObject('App::TextDocument', user_input['textboxTextdocumentName'])\n            #Gui.ActiveDocument.getObject(firstTextdocument.Name).doubleClicked()   \n            objCreate=True\n\n        if firstObject('PartDesign::Body' )==None and user_input['checkboxBody'] :\n            firstBody = App.activeDocument().addObject('PartDesign::Body',  user_input['textboxBodyName'])\n            objCreate=True\n        else :\n            firstBody = firstObject('PartDesign::Body' )\n        if firstObject('Sketcher::SketchObject' )==None and user_input['checkboxSketch'] :\n            if user_input['radiobutton1']:\n                sketchSupport='XY_Plane'                \n            elif user_input['radiobutton2']:\n                sketchSupport='XZ_Plane'                \n            elif user_input['radiobutton3']:\n                sketchSupport='YZ_Plane'\n                \n            # attachedTo=App.ActiveDocument.getObject('Body')\n            # attachedTo=firstObject('PartDesign::Body' )\n            firstSketch=firstBody.newObject('Sketcher::SketchObject', user_input['textboxSketchName'])\n            if hasattr(firstSketch, 'AttachmentSupport'):            \n              firstSketch.AttachmentSupport = (App.ActiveDocument.getObject(sketchSupport),[''])\n            else :\n              firstSketch.Support = (App.ActiveDocument.getObject(sketchSupport),[''])\n            firstSketch.MapMode = 'FlatFace'\n            #Gui.ActiveDocument.getObject(firstSketch.Name).doubleClicked()\n            Gui.runCommand('Std_TileWindows',0)\n            objCreate=True\n        return objCreate\n    \n    # Use the function to display the dialog box and get the user's input\n    if paramSpreadsheet!='exist' or paramSketch!='exist' :\n        user_input = get_user_input(paramDocument, paramSpreadsheet, paramTextdocument, \n                                    paramBody, paramSketch) \n        if user_input['result']=='OK' :\n            return createObjects(user_input)\n        else :\n            return True # To stop macro because canceled\n        # App.ActiveDocument.recompute()\n    \n# end of def addTheObjects()\n\n\n\n\n#############################################################\n#############################################################\n# end part for objects creation at the begining.\n##############################################################\n##############################################################\n\n\n\n#################################################################################\n# part code for alias\n#################################################################################\n# parameters for alias creation\nseparateur = \" \"      # typically put \" \" so blanks will be replaced by nouveauCaract\nnouveauCaract = ''    #Put for example \"_\" to have the separators replaced by \"_\". Put \"\" to have no separator\nmajuscule = True      #set to True if you want  \"Diametre du cercle\" to be \"DiametreDuCercle\"\nchangeTexteCellule = False  # the text will only be changed if changeCellText is True. \n                          # This does not change anything for the allias itself\npremierCaractereEnMinuscule = False # Force the first character to be in lower case\n\n# list of characters to be replaced by an equivalent. for example an @ will be replaced by 'a'\n# if you add characters, please send me a private message. Il will eventually add it in my code.\ncaracEquivalents = [ ['\u00e9','e'],['\u00e8','e'],['\u00ea','e'],['\u00e0','a'],['@','a'],['&','e'],['\u00e7','c'],\n                  ['\u00b2','2'],[\"'\",''],['?',''],['\"',''],['(',''],[')',''],['#',''],['.',''],\n                  [',',''],[';',''],['$',''],['+',''],['-',''],['*',''],['/',''],['\\\\',''] ,\n                  ['[',''],[']',''],\n                  ]\n                  \n\n\n\ndef traitementChaineSource(chaineSource, separateur, nouveauCaract, majuscule):\n# If separator is ' ' and nouveauCaract is '_', and majuscule is True\n# transforms \"Diametre du cylindre\" into \"Diametre_Du_Cylindre\n\n    def remplaceCararcDansMot(mot):\n\n        def remplaceCartatParEquivalent(caractere):\n        # replaces a character with its equivalent if it exists\n            caracResult = caractere   \n            for couple in caracEquivalents:\n                if (couple[0] == caractere):\n                    caracResult = couple[1]\n                    break\n            return caracResult\n\n    #replaces all characters of the word with its equivalent if it exists\n        motResult = mot\n        for caract in mot:\n            a = remplaceCartatParEquivalent(caract)\n            motResult = motResult.replace(caract, a)\n        return motResult\n        \n\n    chaineResult = ''\n    first = True\n    carctDeSeparation = ''\n    for mots in chaineSource.split(separateur): \n        mots = remplaceCararcDansMot(mots)\n        if (not (first)):\n            carctDeSeparation = nouveauCaract \n        if (majuscule):\n            chaineResult = chaineResult + nouveauCaract + mots[:1].upper() + mots[1:]\n            # We use \"[:1]\" instead of \"[0]\", \n            # for no crash in case of an empty string (which happens if the cell is empty)\n        else:\n            chaineResult = chaineResult + nouveauCaract + mots\n    if premierCaractereEnMinuscule :\n        chaineResult = chaineResult[:1].lower() + chaineResult[1:]\n    return chaineResult\n\n\n\n\n\ndef get_adjacent_cells(cell):\n    # Use a regular expression to separate the letters and numbers\n    match = re.match(r\"([a-z]+)([0-9]+)\", cell, re.I)\n    if match:\n        items = match.groups()\n    else:\n        return None, None\n    # Retrieve the letter and number of the cell\n    letter = items[0].upper()\n    number = int(items[1])\n    # If the cell is in the first row, return an empty string\n    if number == 1:\n        return \"\", \"\"\n    # Calculate the cell above\n    above = letter + str(number - 1)\n\n    # Calculate the cell above to the right\n    right = \"\"\n    for char in reversed(letter):\n        if char != 'Z':\n            right = chr(ord(char) + 1) + right\n            break\n        else:\n            right = 'A' + right\n    if not any(char != 'Z' for char in letter):\n        right = 'A' + right\n    right += str(number-1)\n\n    return above, right\n\n\n\ndef get_column(cell):\n    column = ''.join([c for c in cell if not c.isdigit()])\n    return column \n    \ndef get_row(cell):\n    row = ''.join([c for c in cell if c.isdigit()])\n    if row=='' :\n        row='1'\n    return int(row)  \n\n\n\n\ndef get_next_column(column):\n    column = list(column)\n\n    for i in range(len(column)-1, -1, -1):\n        if column[i] != 'Z':\n            column[i] = chr(ord(column[i]) + 1)\n            break\n        else:\n            column[i] = 'A' if i != 0 else 'AA'    \n    return ''.join(column)\n\n\ndef get_previous_column(column):\n    column = list(column)\n\n    for i in range(len(column)-1, -1, -1):\n        if column[i] != 'A':\n            column[i] = chr(ord(column[i]) - 1)\n            break\n        else:\n            column[i] = 'Z' if i != 0 else ''\n    \n    return ''.join(column)\n\n\ndef nextCell(cell):\n    colonne, ligne = re.match(r\"([A-Z]+)([0-9]+)\", cell).groups()\n    num = 0\n    for c in colonne:\n        num = num * 26 + ord(c) - ord('A') + 1\n    num += 1\n    colonne_suivante = \"\"\n    while num > 0:\n        num, reste = divmod(num-1, 26)\n        colonne_suivante = chr(65 + reste) + colonne_suivante\n    return colonne_suivante + ligne \n\ndef setAlias(aliasCellsSelect, aliasAuto):\n    # If the user wants to trigger the creation of alias\n    # it is sufficient that he does not select any objects in the Sketch \n    # but select cells containing strings in the left hand column \n    # of where he want the alias to be created\n    # so test if an object is selected :\n    # result : False if macro can continue.\n    \n    sels = Gui.Selection.getSelectionEx() \n      \n    try :\n        mySpreadsheet = Gui.ActiveDocument.ActiveView.getSheet()\n    except :\n        QtWidgets.QMessageBox.warning(Gui.getMainWindow(),messages[language][\"Warning\"], \n                                            # \"No active spreadsheet with selected cells.\"+\n                                            # \"\\nSelect objects in Sketch, \\n\"+\n                                            # \"and then select a cell in spreadsheet\")                                            \n                                            messages[language][\"NoActiveSpreadsheet\"])\n        return True\n      \n    # aw = Gui.getMainWindow().centralWidget().activeSubWindow() # Store the active window \n    #view = Gui.activeView()\n     \n    # To get list of all selected cells\n    # sel_items = aw.widget().findChild(QtGui.QTableView).selectedIndexes() \n    sel_items = Gui.activeView().selectedCells()\n    # sel_items est un tableau sous la forme ['C4', 'C5', 'C6', 'C7', 'D6', 'D7', 'E4', 'E5', 'E6', 'E7']\n\n    ### We define a function that will return the cell identifier from its row (r) and column (c) numbers\n    ### Numbers start at 0 for the first row/column\n    ### Columns are correctly managed with a 2-letter identifier\n    cellName = lambda r,c:'{}{}{}'.format(chr(c//26 + 64) if c//26 > 0 else '', chr(c%26 + 65), r + 1)\n      \n    tabCells=[]\n#    if getIniCheckboxStateForAlias() :\n    if aliasAuto :\n        sellStart=getIniCellForAlias()\n        columnTextAlias=get_column(sellStart)\n        rowStartAlias=get_row(sellStart)\n        for i in range(rowStartAlias, 20000):\n            try :\n                activeCellContenu = mySpreadsheet.getContents(columnTextAlias+format(i))\n                tabCells.append(columnTextAlias+format(i))\n            except :\n                break\n#    else :\n    if aliasCellsSelect :\n        #for item in sel_items: # The selected cells are scanned\n            #tabCells.append( cellName(item.row(), item.column())) # We retrieve the cell ID in tabCells \n       tabCells=sel_items\n       \n    changed=False    \n    for cell in tabCells: # The selected cells are scanned     \n        next_cell=nextCell(cell)# cell at the right\n        activeCellContenu = mySpreadsheet.getContents(cell)\n        # processing the character string contained in the cell\n        activeCellContenu = traitementChaineSource(activeCellContenu, separateur, nouveauCaract, majuscule)\n        if changeTexteCellule:# if the changeCellText parameter is set to True then we replace the text in the cell\n            mySpreadsheet.set(cell, activeCellContenu)\n        alias = activeCellContenu\n        try: # Bloc try to recover errors\n            if alias!='' :\n                mySpreadsheet.setAlias(next_cell, alias) # The alias is assigned to the right-hand neighbouring cell\n                changed=True\n        except ValueError: # If a \"ValueError\" is triggered (which happens when the alias is not valid)\n            # The user is warned in the report\n            App.Console.PrintWarning(\"Can't set alias for cell {} : {} isn't valid\\n\".format(next_cell, alias))\n\n    # else :\n        # return True\n    return False\n            \n\n\n#################################################################################\n# End part code for alias\n#################################################################################\n\n\n\n\n#=======================================================\n# Dialog box\n# Ask user which sort of constraint is required\n#=======================================================\nclass getConstraintType(QtGui.QDialog):\n    def __init__(self, widgetToFocus = None):\n        super(getConstraintType, self).__init__()\n        self.widgetToFocus = widgetToFocus\n        self.initUI()\n\n    def initUI(self):\n        # toolLip=\"If checked, alias will automatically be created during each macro execution. Alias will be built for the right cell from the text in this cell.\"\n        toolLip=messages[language][\"getConstraintTypeAliasToolLip\"]\n       \n        self.setWindowIcon(QtGui.QIcon('dialog_icon.png'))\n        gridLayout = QtGui.QGridLayout()\n        option1Button = QtGui.QPushButton(QtGui.QIcon(\":/icons/constraints/Constraint_HorizontalDistance.svg\"), \"\")\n        option2Button = QtGui.QPushButton(QtGui.QIcon(\":/icons/constraints/Constraint_VerticalDistance.svg\"), \"\")\n        option3Button = QtGui.QPushButton(QtGui.QIcon(\":/icons/constraints/Constraint_Length.svg\"), \"\")\n        \n        #option1Button.setText(\"Lenght constrainte X\")\n        option1Button.setText(messages[language][\"getConstraintTypeOption1ButtonSetText\"])        \n        #option2Button.setText(\"Lenght constrainte Y\")\n        option2Button.setText(messages[language][\"getConstraintTypeOption2ButtonSetText\"])\n        #option3Button.setText(\"Lenght constrainte\")\n        option3Button.setText(messages[language][\"getConstraintTypeOption3ButtonSetText\"])        \n        \n        \n        #option1Button.setToolTip(\"Lenght constrainte X\")\n        option1Button.setToolTip(messages[language][\"getConstraintTypeOption1ButtonSetTextToolLip\"])\n        #option2Button.setToolTip(\"Lenght constrainte Y\")\n        option2Button.setToolTip(messages[language][\"getConstraintTypeOption2ButtonSetTextToolLip\"])\n        #option3Button.setToolTip(\"Lenght constrainte\")\n        option3Button.setToolTip(messages[language][\"getConstraintTypeOption3ButtonSetTextToolLip\"])\n       \n        \n        option1Button.clicked.connect(self.onOption1)\n        option2Button.clicked.connect(self.onOption2)\n        option3Button.clicked.connect(self.onOption3)\n\n        option4Button = QtGui.QPushButton(QtGui.QIcon(\":/icons/application-exit.svg\"), messages[language][\"Cancel\"])\n        \n        option4Button.clicked.connect(self.onOption4)\n        \n        self.textboxAlias = QtGui.QLineEdit(self.getIniCellForAlias())\n\n        self.textboxAlias.setMaximumWidth(50)  # Set the maximum width of the text box\n        self.textboxAlias.setMaxLength(4)  # Limit the text box to 4 characters\n        self.textboxAlias.setToolTip(toolLip) \n        \n        gridLayout.addWidget(option1Button, 0, 0)\n        gridLayout.addWidget(option2Button, 0, 1)\n        gridLayout.addWidget(option3Button, 1, 0)\n        gridLayout.addWidget(option4Button, 1, 1)\n\n        gridLayout.addWidget(self.textboxAlias,4,1)\n\n        self.setLayout(gridLayout)\n        self.setGeometry(250, 250, 0, 50)\n        #self.setWindowTitle(\"Choose a constraint type\")\n        self.setWindowTitle(messages[language][\"getConstraintTypeWindowTitle\"])  \n        \n        self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)\n        self.choiceConstraint = ''\n\n        option1Button.setFocusPolicy(QtCore.Qt.NoFocus)\n        option2Button.setFocusPolicy(QtCore.Qt.NoFocus)\n        option3Button.setFocusPolicy(QtCore.Qt.NoFocus)\n        option4Button.setFocusPolicy(QtCore.Qt.NoFocus)\n\n        # set focus to specified widget\n        if self.widgetToFocus == 'DistanceX':\n            option1Button.setFocus()\n        elif self.widgetToFocus == 'DistanceY':\n            option2Button.setFocus()\n        elif self.widgetToFocus == 'Distance':\n            option3Button.setFocus()\n\n        # Add checkbox\n        #self.checkboxConflic = QtGui.QCheckBox(\"Conflict detection\")\n        self.checkboxConflic = QtGui.QCheckBox(messages[language][\"getConstraintTypeCheckboxConflic\"])        \n        self.checkboxConflic.setToolTip(messages[language][\"getConstraintTypeCheckboxConflicToolLip\"])        \n        \n        self.checkboxConflic.setChecked(True)\n        gridLayout.addWidget(self.checkboxConflic, 2, 0, 1, 2)\n        self.checkboxConflic.clicked.connect(self.onOptionCheckBox)\n        \n        #self.checkboxAlias = QtGui.QCheckBox(\"Automatic alias labels for this cell, and under :\")\n        self.checkboxAlias = QtGui.QCheckBox(messages[language][\"getConstraintTypeCheckboxAlias\"])        \n        \n        self.checkboxAlias.setToolTip(toolLip) \n        # Only letter in textboxAlias         \n        regex = QtCore.QRegExp(\"^[a-zA-Z]+[0-9]+$\")\n        validator = QtGui.QRegExpValidator(regex, self)\n        self.textboxAlias.setValidator(validator)\n        self.textboxAlias.textChanged.connect(self.onTextChanged)    \n        \n        # self.checkboxAlias.setChecked(True)\n        self.checkboxAlias.setChecked(getIniCheckboxStateForAlias())\n        gridLayout.addWidget(self.checkboxAlias, 4, 0)        \n\n        horizontal_line = QtGui.QFrame()\n        horizontal_line.setFrameShape(QtGui.QFrame.HLine)\n        horizontal_line.setFrameShadow(QtGui.QFrame.Sunken)\n        gridLayout.addWidget(horizontal_line, 3, 0,1,2) \n        \n        \n        # read ini file to get last checkBoxState\n        config = configparser.ConfigParser()\n        # macroDirectory = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\").GetString(\"MacroPath\") + \"\\\\\"\n        macroDirectory = FreeCAD.getUserMacroDir(True)\n        try :\n            filePath = os.path.join(macroDirectory, \"sketchConstraintFromSpreadsheet.ini\")\n            config.read(filePath)\n            # read ini file to know last time state\n            lasChecked = config.getboolean('ConflictDetection', 'save_checkbox_state')\n            self.checkboxConflic.setChecked(lasChecked)\n        except :\n            pass\n\n        # window positioning\n        centerPoint = QGuiApplication.screens()[0].geometry().center()\n        self.move(centerPoint - self.frameGeometry().center())\n\n    def onTextChanged(self, text):\n        # Convertir le texte en majuscules\n        uppercase_text = text.upper() \n        self.textboxAlias.blockSignals(True)\n        self.textboxAlias.setText(uppercase_text)\n        self.textboxAlias.blockSignals(False)   \n\n\n    def onOption1(self):\n        self.choiceConstraint = 'DistanceX'\n        self.save_settings()\n        self.close()\n\n    def onOption2(self):\n        self.choiceConstraint = 'DistanceY'\n        self.save_settings()        \n        self.close()\n\n    def onOption3(self):\n        self.save_settings()    \n        self.choiceConstraint = 'Distance'\n        self.close()\n\n    def onOption4(self):\n        self.choiceConstraint = 'Cancel'\n        self.close()\n\n    def onOptionCheckBox(self):\n        #macroDirectory = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\").GetString(\"MacroPath\") + \"\\\\\"\n        macroDirectory = FreeCAD.getUserMacroDir(True)\n        # Save checkbox state to file\n        filePath = os.path.join(macroDirectory, \"sketchConstraintFromSpreadsheet.ini\")\n        config = configparser.ConfigParser()\n        config['Conflict_detection'] = {'save_checkbox_state': str(int(self.getCheckBoxState()))}\n        with open(filePath, 'w') as configfile:\n            config.write(configfile)\n            \n    def save_settings(self):\n        save_settings_Alias(self.textboxAlias.text(),self.checkboxAlias.isChecked())         \n \n\n    def getIniCellForAlias(self):\n        return getIniCellForAlias()\n            \n    def getIniCheckboxStateForAlias(self):\n        return getIniCheckboxStateForAlias() \n \n    def getCheckBoxState(self):\n        return self.checkboxConflic.isChecked()\n        \n\n\n#=======================================================\n# Give the focus to editing Sketch window\n# no parameter\n# use : activateSketchEditingWindow()\n#=======================================================\ndef activateSketchEditingWindow():\n    def searchForNode(tree, childName, maxLevel = 0):\n        return recursiveSearchForNode(tree, childName, maxLevel, 1)\n\n    def recursiveSearchForNode(tree, childName, maxLevel, currentLevel):\n        try:\n            if tree.getByName(childName):\n                return True;\n            elif maxLevel > 0 and currentLevel >= maxLevel:\n                return False;\n            else:\n                for child in tree.getChildren():\n                    if recursiveSearchForNode(child, childName, maxLevel, currentLevel + 1):\n                        return True\n        except:\n            pass\n        return False\n\n    #Gui.activateWorkbench(\"SketcherWorkbench\")####################################\n    doc = Gui.ActiveDocument\n    if not doc:\n        QtWidgets.QMessageBox.information(Gui.getMainWindow(), \"Activate window\", \"No active document\")\n        return\n    views = Gui.ActiveDocument.mdiViewsOfType(\"Gui::View3DInventor\")\n    if not views:\n        QtWidgets.QMessageBox.information(Gui.getMainWindow(), \"Activate window\", \"No 3D view opened for active document\")\n        return\n    editView = None\n    for view in views:\n        if searchForNode(view.getSceneGraph(), \"Sketch_EditRoot\", 3):\n            editView = view\n            break\n    if not editView:\n        QtWidgets.QMessageBox.information(Gui.getMainWindow(), \"Activate window\", \"No 3D view has sketch in edit mode for active document\")\n        return\n    for win in Gui.getMainWindow().centralWidget().subWindowList():\n        if editView.graphicsView() in win.findChildren(QtWidgets.QGraphicsView):\n                Gui.getMainWindow().centralWidget().setActiveSubWindow(win)\n                break\n\n\n\n\n######################################################################################\n# to get necessary values for the constraint\n# Parameters :\n# sel : selection of objects (a line, 2 points..).\n# numOrdreObjSelected if we want the first objetc selected or the second.\n# indexExtremite if we want the start point (1) or the end point (2), if exist, of the sel\n# return features of a point\n# - typeIdGeometry : Part::GeomLineSegment ....\n# - typeInSubElementName : Edge, vertex ...\n# - indexObjectHavingPoint index of the object having the point (line...)\n# - indexExtremiteLine index of the ends (points) of the line (= start point or end point)\n# - x, y : coordinates of the point\n# - isInternalObject : True if the objetct is on the active sketch\n#####################################################################################\ndef featuresObjSelected (mySketch, sel, numOrdreObjSelected, indexExtremite) :\n    indexExtremiteLine = 1\n    indexObjectHavingPoint = -10\n    typeIdGeometry = None\n    x, y = 0, 0\n    isInternalObject=True\n    itemName = sel.SubElementNames[numOrdreObjSelected] # ex Edge5 ( line)\n        \n    tabExternalGeomery = []\n    for item in ActiveSketch.ExternalGeometry :\n        for objName in item [1] :\n            # to get something like\n            # [('Sketch', 'Edge2'), ('Sketch001', 'Edge2'), ('Sketch001', 'Edge1'), ('Sketch', 'Edge1')]\n            tabExternalGeomery.append((item[0].Name, objName))\n        \n    if itemName in ['V_Axis', 'H_Axis', 'RootPoint'] :\n        typeInSubElementName = itemName\n        indexObjectHavingPoint = -1\n        typeIdGeometry = mySketch.Geometry[indexObjectHavingPoint].TypeId\n        x, y = 0, 0\n    else : \n        typeInSubElementName, numInNameStr = [''.join(c) for _, c in itertools.groupby(itemName, str.isalpha)] \n        numInName = int(numInNameStr)\n\n    # only one selected object\n    if typeInSubElementName == 'Edge'and len(sel.SubElementNames) == 1: # selection is only one line\n        indexObjectHavingPoint = numInName - 1\n        indexExtremiteLine = indexExtremite\n        typeIdGeometry = mySketch.Geometry[indexObjectHavingPoint].TypeId\n        # typeIdGeometry : 'Part::GeomCircle' or 'Part::GeomLineSegment'\n        if typeIdGeometry in  ['Part::GeomLineSegment'] :\n            if indexExtremite == 1 :\n                x = mySketch.Geometry[indexObjectHavingPoint].StartPoint.x\n                y = mySketch.Geometry[indexObjectHavingPoint].StartPoint.y\n            elif indexExtremite == 2 :\n                x = mySketch.Geometry[indexObjectHavingPoint].EndPoint.x\n                y = mySketch.Geometry[indexObjectHavingPoint].EndPoint.y\n                \n    if typeInSubElementName == 'ExternalEdge' :\n        isInternalObject = False\n        indexObjectHavingPoint = - numInName - 2 \n        indexExtremiteLine = indexExtremite \n        externalSketchName, externalGeometryName = tabExternalGeomery[numInName - 1]\n        iTypeExternal, iNumStr = [''.join(c) for _, c in itertools.groupby(externalGeometryName, str.isalpha)]\n        iNumExtGeometry = int(iNumStr)\n        typeIdGeometry = App.ActiveDocument.getObject(externalSketchName).Geometry[iNumExtGeometry - 1].TypeId\n        \n        if len(sel.SubElementNames) == 1 :  \n            if typeIdGeometry == 'Part::GeomLineSegment' : \n                if   indexExtremite == 1 :\n                    x = App.ActiveDocument.getObject(externalSketchName).Geometry[iNumExtGeometry - 1].StartPoint.x\n                    y = App.ActiveDocument.getObject(externalSketchName).Geometry[iNumExtGeometry - 1].StartPoint.y\n                elif indexExtremite == 2 :    \n                    x = App.ActiveDocument.getObject(externalSketchName).Geometry[iNumExtGeometry - 1].EndPoint.x\n                    y = App.ActiveDocument.getObject(externalSketchName).Geometry[iNumExtGeometry - 1].EndPoint.y\n\n        if typeIdGeometry in ['Part::GeomCircle', 'Part::GeomArcOfCircle'] :       \n            x = App.ActiveDocument.getObject(externalSketchName).Geometry[iNumExtGeometry - 1].Center.x\n            y = App.ActiveDocument.getObject(externalSketchName).Geometry[iNumExtGeometry - 1].Center.y\n            indexExtremiteLine = 3 # 3 for center\n                \n\n    # We selected an internal circle but for center (two objects selected)\n    if typeInSubElementName == 'Edge'and len(sel.SubElementNames) == 2 :\n        typeIdGeometry = mySketch.Geometry[numInName - 1].TypeId\n        if typeIdGeometry in  ['Part::GeomCircle', 'Part::GeomArcOfCircle'] :\n            indexObjectHavingPoint = numInName - 1\n            x = mySketch.Geometry[indexObjectHavingPoint].Location.x\n            y = mySketch.Geometry[indexObjectHavingPoint].Location.y\n            indexExtremiteLine = 3 # 3 for center        \n            \n\n    # We selected a vertex\n    if typeInSubElementName == 'Vertex' : # selection is 2 points. sel is a vertex (a point of a line) :\n        indexObjectHavingPoint, indexExtremiteLine = sel.Object.getGeoVertexIndex(numInName - 1)\n        \n        if indexObjectHavingPoint >= 0 : # internal vertex\n            typeIdGeometry = mySketch.Geometry[indexObjectHavingPoint].TypeId\n            if mySketch.Geometry[indexObjectHavingPoint].TypeId == 'Part::GeomLineSegment' :\n                if indexExtremiteLine == 1 :\n                    x = mySketch.Geometry[indexObjectHavingPoint].StartPoint.x\n                    y = mySketch.Geometry[indexObjectHavingPoint].StartPoint.y\n                if indexExtremiteLine == 2:\n                    x = mySketch.Geometry[indexObjectHavingPoint].EndPoint.x\n                    y = mySketch.Geometry[indexObjectHavingPoint].EndPoint.y\n            if mySketch.Geometry[indexObjectHavingPoint].TypeId == 'Part::GeomPoint' :\n                x = mySketch.Geometry[indexObjectHavingPoint].X\n                y = mySketch.Geometry[indexObjectHavingPoint].Y\n            # we select a vertex Circle (so the center)\n            if mySketch.Geometry[indexObjectHavingPoint].TypeId in ['Part::GeomCircle', 'Part::GeomArcOfCircle'] :\n                x = mySketch.Geometry[indexObjectHavingPoint].Location.x\n                y = mySketch.Geometry[indexObjectHavingPoint].Location.y\n                \n        if indexObjectHavingPoint < 0 : # external vertex = vertex of another sketch\n            isInternalObject = False\n            externalSketchName, externalGeometryName = tabExternalGeomery[-indexObjectHavingPoint-3]\n            \n            iType, iNumStr = [''.join(c) for _, c in itertools.groupby(externalGeometryName, str.isalpha)]\n            iNumExtGeometry = int(iNumStr)\n            typeExternal=App.ActiveDocument.getObject(externalSketchName).Geometry[iNumExtGeometry-1].TypeId   \n            typeIdGeometry = typeExternal\n                    \n            if typeExternal=='Part::GeomLineSegment' :\n                if indexExtremiteLine == 1 :\n                    x = App.ActiveDocument.getObject(externalSketchName).Geometry[iNumExtGeometry-1].StartPoint.x\n                    y = App.ActiveDocument.getObject(externalSketchName).Geometry[iNumExtGeometry-1].StartPoint.y\n                if indexExtremiteLine == 0 :\n                    x = App.ActiveDocument.getObject(externalSketchName).Geometry[iNumExtGeometry-1].EndPoint.x\n                    y = App.ActiveDocument.getObject(externalSketchName).Geometry[iNumExtGeometry-1].EndPoint.y\n            if typeExternal == 'Part::GeomCircle' :\n                x = App.ActiveDocument.getObject(externalSketchName).Geometry[iNumExtGeometry-1].Center.x\n                y = App.ActiveDocument.getObject(externalSketchName).Geometry[iNumExtGeometry-1].Center.y\n\n    if typeInSubElementName == 'Constraint' and len(sel.SubElementNames) == 1 :\n        indexConstraint = numInName - 1\n        indexObjectHavingPoint = indexConstraint\n        typeIdGeometry = 'Constraint'\n    return typeIdGeometry, typeInSubElementName, indexObjectHavingPoint, indexExtremiteLine, x ,y, isInternalObject\n\n\n\n##########################################\n# function returning selected objects at GUI level\n#  = Sketch, SpreadSheet ....\n# parameter :\n# '' = no filter\n# 'Spreadsheet::Sheet' for spreadsheets only\n# 'Sketcher::SketchObject' for sketches etc...\n# output: an array of sketch objects, spreadsheets etc.\n##########################################\ndef getGuiObjsSelect(type = ''):\n    tabGObjSelect = []\n    selections = Gui.Selection.getCompleteSelection()\n    for sel in (selections):\n        if hasattr(sel, 'Object'):   # depend freecad version\n            if type == '' or sel.Object.TypeId == type :\n                tabGObjSelect.append(sel.Object)\n        else :\n            obj=App.ActiveDocument.getObject(sel.Name)\n            if type == '' or obj.TypeId == type :\n                tabGObjSelect.append(obj)\n    return tabGObjSelect\n\n\n\n\n\n\n##########################################\n# Main proceddure\n##########################################\ndef main():\n    #initialization\n    sheckBoxConstraintConflicState = False\n    indexConstraint = -1    \n    \n\n         \n    if addTheObjects():# Creation of missing objects if wanted\n        return\n               \n    #Part of setAlias : problem to create alias ?\n #   if not getIniCheckboxStateForAlias() :\n    \n    sels = Gui.Selection.getSelectionEx() \n\n    if not(len(sels) != 0 and len(sels[0].SubElementNames) != 0) : # nothing selected\n        message=(messages[language][\"NoObjectSelected\"]) \n        if QtGui.QMessageBox.warning(Gui.getMainWindow(),\n            messages[language][\"Warning\"], message,\n            QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel) == QtGui.QMessageBox.Cancel: \n            # if user don't want\n            return True \n        setAlias(True,False) \n        return\n\n    try :\n        mySpreadsheet = Gui.ActiveDocument.ActiveView.getSheet()\n    except :\n\n  \n        QtWidgets.QMessageBox.warning(Gui.getMainWindow(), messages[language][\"Warning\"], \n                                            # \"No active spreadsheet with selected cells.\"+\n                                            # \"\\nSelect objects in sketch, \\n\"+\n                                            # \"and then select a cell in spreadsheet\")                                            \n                                            messages[language][\"NoActiveSpreadsheet\"])                          \n                               \n        return True    \n  \n\n####If we select a Pad, Pocket... not in edition mode and a cell\n    myPadOrPocket=None\n    try :\n        sels = Gui.Selection.getSelectionEx()\n        # print('sels[0].Object.TypeId',sels[0].Object.TypeId)\n        if sels[0].Object.TypeId in ['PartDesign::Pad','PartDesign::Pocket',\n                'Part::Part2DObjectPython','PartDesign::Thickness', # ShapeString, Thickness\n                'PartDesign::Chamfer', 'PartDesign::Fillet'] : \n            myPadOrPocket=sels[0].Object\n            typeIdGeometry1=myPadad.TypeId                 \n    except :\n        pass\n        \n\n    try :\n        mySketch = ActiveSketch\n    except :\n        if myPadOrPocket==None :\n            QtWidgets.QMessageBox.information(None, messages[language][\"Warning\"], \n                \"Select object (point, line...) in the sketch in edition mode\")\n            # activateSketchEditingWindow()\n            return    \n    \n    \n    # Part SpreadSheet\n    #---------------------------------\n    sheets = getGuiObjsSelect('Spreadsheet::Sheet')\n    for sheet in sheets :\n        Gui.Selection.removeSelection(FreeCAD.ActiveDocument.Name, sheet.Name)\n    try :\n        mySpreadsheet = Gui.ActiveDocument.ActiveView.getSheet()\n    except :\n        QtWidgets.QMessageBox.information(None, messages[language][\"Warning\"],\n                \"1- Select a line or 2 points\" + \n                \"\\n 2- go to a spreadsheet\" + \n                \"\\n 3- select the cell containing the value.\" + \n                \"\\n 4- stay in the spreadsheet and launch the macro\")\n        activateSketchEditingWindow()\n        return\n    mySpreadSheetName = mySpreadsheet.Name\n    mySpreadSheetLabel = mySpreadsheet.Label\n    \n    ################################# select the Spreadsheet To be able to retrieve the selected cell :\n ############################################################################8\"\"   mySpreadsheet.ViewObject.doubleClicked()\n    # retrieve the selected cell\n    #ci = lambda :Gui.getMainWindow().centralWidget().activeSubWindow().widget().findChild(QtGui.QTableView).currentIndex()\n    #cellCode = '{}{}{}'.format(chr(ci().column()//28 + 64) if ci().column()//26 > 0 else '', chr(ci().column()%26 + 65), ci().row() + 1)\n    cellCode = Gui.activeView().currentIndex()\n\n    try:\n        if sels[0].Object.TypeId not in ['Part::Part2DObjectPython'] :  # ShapeString\n            cellContents = float(mySpreadsheet.get(cellCode))\n    except:\n        QtWidgets.QMessageBox.information(None, messages[language][\"Warning\"],\n                 messages[language][\"ClickOnACellBefore\"])\n        return\n          \n    \n    \n    column = get_column(cellCode)\n   \n\n\n    # Part sketch\n    #----------------------------\n    sels = Gui.Selection.getSelectionEx()\n\n    if (len(sels) == 0 or len(sels[0].SubElementNames) == 0) and myPadOrPocket==None : \n        QtWidgets.QMessageBox.information(None, messages[language][\"Warning\"], \"Anything is select.\\n\" + \n              \"Select 1 line, 2 points or a constraint in a sketch before selecting a cell in the spreadsheet\")\n        activateSketchEditingWindow()\n        return\n    elif len(sels[0].SubElementNames) > 2  :\n        QtWidgets.QMessageBox.information(None, messages[language][\"Warning\"], \"Too many objects selected.\\n\" + \n              \"Select 1 line, 2 points or a constraint in a sketch before selecting a cell in the spreadsheet\")\n        activateSketchEditingWindow()\n        return\n    else :\n\n        # only one obj selected\n        #------------------------\n        if len(sels[0].SubElementNames) == 1 : # only one obj selected\n            #startPoint of the line\n            (typeIdGeometry1, typeInSubElementName1, indexObjectHavingPoint1, indexExtremiteLine1, \n                x1 ,y1, isInternalObject1)=featuresObjSelected (ActiveSketch, sels[0], 0, 1)\n            \n            if typeInSubElementName1 == 'Constraint' and len(sels[0].SubElementNames) == 1 :\n                indexConstraint=indexObjectHavingPoint1\n            elif typeIdGeometry1 == 'Part::GeomLineSegment' :\n                (typeIdGeometry2, typeInSubElementName2, indexObjectHavingPoint2, indexExtremiteLine2, \n                x2 ,y2, isInternalObject2) = featuresObjSelected (ActiveSketch, sels[0], 0, 2)\n                \n        # two obj selected\n        #------------------------\n        if len(sels[0].SubElementNames) == 2: # two obj selected\n            (typeIdGeometry1,typeInSubElementName1, indexObjectHavingPoint1, indexExtremiteLine1, \n            x1 ,y1, isInternalObject1) = featuresObjSelected (ActiveSketch, sels[0], 0, 1)\n            (typeIdGeometry2,typeInSubElementName2, indexObjectHavingPoint2, indexExtremiteLine2, \n            x2 ,y2, isInternalObject2) = featuresObjSelected (ActiveSketch, sels[0], 1, 1)\n\n            if ((typeInSubElementName1 not in ('Vertex', 'V_Axis', 'H_Axis', 'RootPoint', 'ExternalEdge') \\\n                or typeInSubElementName2 not in ('Vertex', 'V_Axis', 'H_Axis', 'RootPoint', 'ExternalEdge'))\n                    and not(typeIdGeometry1 in ('Part::GeomCircle', 'Part::GeomArcOfCircle') \\\n                    and typeInSubElementName1 in ['Edge'])) :\n                QtWidgets.QMessageBox.information(None, messages[language][\"Warning\"], \"2 objects are selected but not 2 points .\\n\" + \n                \"Select 1 line, 2 points or a constraint in a sketch before selecting a cell in the spreadsheet\")\n                activateSketchEditingWindow()\n                return\n\n\n    #--------------------------------------\n    # line or points have been selected have a look if we need to swap points\n    # -------------------------------------\n    if ((len(sels[0].SubElementNames) == 1 and typeIdGeometry1 in['Part::GeomLineSegment'] )\n           or (len(sels[0].SubElementNames) == 2 and typeIdGeometry1\n            in['Part::GeomLineSegment', 'Part::GeomCircle', 'Part::GeomArcOfCircle', 'Part::GeomPoint'] )) :\n\n\n        # to give focus on the good button\n        # (Button DistanceX if the two points are more horizontal than vertical)\n        if abs(x1 - x2) > abs(y1 - y2) :\n            buttonHavingFocus = 'DistanceX'\n        else :\n            buttonHavingFocus = 'DistanceY'\n            \n        # ------------------------------------------------    \n        # ask the user what kind of constraint he wants\n        #------------------------------------------------\n        form = getConstraintType(buttonHavingFocus)\n                    # conflict : is the checkboxSheced?\n        sheckBoxConstraintConflicState = form.getCheckBoxState()\n        \n        if   typeInSubElementName1 in ['V_Axis'] or typeInSubElementName2 in ['V_Axis'] :\n            myConstraint='DistanceX'\n        elif typeInSubElementName1 in ['H_Axis'] or typeInSubElementName2 in ['H_Axis'] :\n            myConstraint='DistanceY'\n        else : \n            form.exec_()  #open dialog box                 \n            # conflict : is the checkbox Shecked?\n            sheckBoxConstraintConflicState = form.getCheckBoxState()\n            if form.choiceConstraint in ('Cancel', '') :\n                activateSketchEditingWindow()\n                return\n            myConstraint = form.choiceConstraint # 'DistanceX' or 'DistanceY' or 'Distance'\n\n        if (myConstraint == 'DistanceX' and x1 > x2) or  (myConstraint == 'DistanceY' and y1 > y2) :\n                indexObjectHavingPoint1, indexObjectHavingPoint2 = indexObjectHavingPoint2, indexObjectHavingPoint1\n                indexExtremiteLine1, indexExtremiteLine2 = indexExtremiteLine2, indexExtremiteLine1\n                isInternalObject1, isInternalObject2 = isInternalObject2, isInternalObject1\n                x1, x2, y1, y2 = x2, x1, y2, y1\n\n     \n\n    if getIniCheckboxStateForAlias() : \n        setAlias(False,True)\n\n    cellAlias = App.ActiveDocument.getObject(mySpreadSheetName).getAlias(cellCode)\n\n    \n    # create constraint\n    #=================================\n    # get value for constraint \n    cellAlias = App.ActiveDocument.getObject(mySpreadSheetName).getAlias(cellCode)\n        \n    if cellAlias == None :\n        cellExpression = '<<' + mySpreadSheetLabel + '>>' + '.' + cellCode\n    else :\n        cellExpression = '<<' + mySpreadSheetLabel + '>>' + '.' + cellAlias           \n        \n    if myPadOrPocket!=None :\n        #myPadOrPocket.setExpression('Length', u'SpreadSheetDatas12.B5') \n        if myPadOrPocket.TypeId == 'Part::Part2DObjectPython' :\n            myPadOrPocket.setExpression('String', str(cellExpression))\n        elif myPadOrPocket.TypeId == 'PartDesign::Thickness' : \n            myPadOrPocket.setExpression('Value', cellExpression) \n        elif myPadOrPocket.TypeId == \"PartDesign::Chamfer\" :\n             myPadOrPocket.setExpression('Size', cellExpression) \n        elif myPadOrPocket.TypeId == \"PartDesign::Fillet\" :\n             myPadOrPocket.setExpression('Radius', cellExpression)               \n        else :\n            myPadOrPocket.setExpression('Length', cellExpression)         \n        return\n\n\n        \n    # create constraint for internal or external circle\n    if (len(sels[0].SubElementNames) == 1 and typeIdGeometry1 in['Part::GeomCircle', 'Part::GeomArcOfCircle'] ) :\n        indexConstraint = mySketch.addConstraint(Sketcher.Constraint('Diameter'\n        , indexObjectHavingPoint1, cellContents))\n\n    # create constraint for line or points\n    elif typeIdGeometry1 != 'Constraint' : # no selected constraint, just line or points\n        #create the constraint\n        indexConstraint = mySketch.addConstraint(Sketcher.Constraint(myConstraint\n                 , indexObjectHavingPoint1, indexExtremiteLine1, indexObjectHavingPoint2\n                 , indexExtremiteLine2, cellContents))\n         \n    # if one external line or only one external circle or two external object\n    # was selected : constraint is a reference    \n    if  len(sels[0].SubElementNames) == 1 and not isInternalObject1 \\\n        or len(sels[0].SubElementNames) == 2 and not isInternalObject1 and not isInternalObject2 :\n        mySketch.setDriving(indexConstraint, False)  # External edge constraint is a reference\n    elif mySketch.Constraints[indexConstraint].Driving : # not a reference constraint\n        # set the constraint'formula' (ex : 'spreadSheet.unAlias')\n        mySketch.setExpression('Constraints[' + str(indexConstraint) + ']', cellExpression)\n        \n    elif not mySketch.Constraints[indexConstraint].Driving : # it is a reference constraint\n        # on va mettre dans la cellule du spreadsheet la formule pour r\u00e9cup\u00e9rer la valeur de la contrainte\n        # par exemple =href(Sketch.Constraints.Distance)\n        print(\"The constraints is a reference one\")\n        \n        if mySketch.Constraints[indexConstraint].Name == '' :\n            message=messages[language][\"referenceNoName\"] \n \n        else :  \n            message= messages[language][\"referenceWithName\"] \n                    \n        if QtGui.QMessageBox.warning(Gui.getMainWindow(),\n            messages[language][\"Warning\"], message,\n            QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel) == QtGui.QMessageBox.Ok: \n            # if user  want\n            mySketch.renameConstraint(indexConstraint,mySketch.Name + '_'+str(indexConstraint)+ '_'+ datetime.now().strftime(\"%S\"))\n\n        # nommer la contrainte\n        #mySpreadsheet.touch()\n        mySpreadsheet.set(cellCode, '=href('+mySketch.Name+'.Constraints.'+mySketch.Constraints[indexConstraint].Name + ')')\n\n        \n    # put Sketch window ahead\n    activateSketchEditingWindow()\n    FreeCADGui.Selection.clearSelection()\n\n    \n\n    #if Gui.ActiveDocument.getInEdit() == Gui.ActiveDocument.Sketch:\n    #Gui.ActiveDocument.Sketch.doubleClicked()\n\n    mySketch.recompute()\n    # is ther constraintes conflicts?\n    if sheckBoxConstraintConflicState :\n        #if App.activeDocument().isTouched(): # isTouched is not ok in Daily Freecad\n        if 'Invalid' in mySketch.State :\n            a = QtWidgets.QMessageBox.question(None, \"\",\n                #\"Constraints conflic detected. Cancel constraint creation? \",\n                messages[language][\"ConstarintConflicDetected\"],\n                QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)\n            if a == QtWidgets.QMessageBox.Yes:\n                mySketch.delConstraint(indexConstraint)\n                # FreeCAD.ActiveDocument.recompute()\n                \n    \n    recomputeAll()                 \n    activateSketchEditingWindow()\n    \n    #FreeCADGui.ActiveDocument.setEdit(mySketch.Name, 0)############################################\n\n    return\n\n\n\n    \n\n        \nif __name__ == '__main__':\n    main()\n\n\n",
    "url": "https://wiki.freecad.org/Macro_Sketch_Constraint_From_Spreadsheet",
    "raw_code_url": "https://raw.githubusercontent.com/2cv001/FreeCAD-macros/master/Spreadsheet/Sketch_Constraint_From_Spreadsheet.FCMacro",
    "wiki": "https://wiki.freecad.org/Macro_sketchConstraintFromSpreadsheet",
    "version": "2025/01/30",
    "license": "",
    "date": "2025/01/30",
    "src_filename": "",
    "filename_from_url": "",
    "author": "2cv001",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Sketch_Constraint_From_Spreadsheet.svg",
    "icon_source": "https://wiki.freecad.org/images/d/dc/Macro_Sketch_Constraint_From_Spreadsheet.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "SpreadsheetTools",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro helps managing cells inside FreeCAD's Spreadsheet-workbench. It helps managing cells inside FreeCAD's Spreadsheet-workbench. With its help one is able to:Cut/delete data and/or alias information, Copy data and/or an alias information, Paste data and/or alias information<br /><br />Macro version: 0.2.08<br />Last modified: 2017-11-03<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/3/35/Macro_SpreadsheetTools.png\">ToolBar Icon</a><br />Author: Wilfried Hortschitz<br /> ",
    "comment": "This macro helps managing cells inside a single spreadsheet of FreeCAD Spreadsheet workbench. It is able to cut/delete, copy and paste an area of cells including format, alias and units. Merged cells are not supported.",
    "code": "# ============================================================================================================\n# ============================================================================================================\n# ==                                                                                                        ==\n# ==                                       Spreadsheet tools                                                ==\n# ==                                                                                                        ==\n# ============================================================================================================\n# ============================================================================================================\n# ABOUT\n# ============================================================================================================\n# version v0.2.08 !!! This is beta version code so backup your data first!!! The author assumes no liability for data loss.\n#\n# Macro developed for FreeCAD (http://www.freecadweb.org/).\n# This macro helps managing cells inside FreeCAD Spreadsheet workbench. It is able to:\n#        - Cut/delete data and/or alias fields in a selected area of cells\n#        - Copy data and/or alias fields in a selected area of cells to clipboard\n#        - Paste data and/or alias fields in a selected area of cells from cliboard\n# More information might be found on FreeCAD forums: http://forum.freecadweb.org/\n#\n#\n# LICENSE\n# ============================================================================================================\n#\n# This work is licensed under GNU Lesser General Public License (LGPL).\n# To view a copy of this license, visit https://www.gnu.org/licenses/lgpl-3.0.html.\n# \n# ============================================================================================================\n__title__   = \"Spreadsheet_tools\"\n__author__  = \"HoWil\"\n__version__ = \"0.2.08\"\n__date__    = \"2017-09-02\"\n\n__Comment__ = \"This macro helps managing cells inside a single spreadsheet of FreeCAD Spreadsheet workbench. It is able to cut/delete, copy and paste an area of cells including format, alias and units. Merged cells are not supported.\"\n\n__Status__ = \"stable\"\n__Requires__ = \"FreeCAD 0.17\"\n\nfrom PySide import QtGui, QtCore\n\nimport FreeCADGui\n#import FreeCAD\nimport FreeCAD as App\n\nimport string\n\n\n'''\n*Working* Cut/delete the selected area\n*Working* Copy to clipboard\n*Working* Paste from clipboard\n*Working* Copy and paste alias\n\nTODO:\n* Check if something is overwritten and show a warning.\n* Use shortcuts like Ctrl-c.\n* Test if pandas is installed and offer import-export if available.\n\n* Right click menu??\n* Copy and paste formating???\n\nKnown limitations:\n* Does work only with one opened FC-Spreadsheet.\n* A cell has to be selected before selecting one of the options of Spreadsheet_tools.\n* Does not work on merged cells.\n'''\n\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\n\n# ===== Global variables ==============================================\nalphabet_list = list(string.ascii_uppercase)\n\ncolumn_list = [] # is filled with A, B, C,.... AA, AB, AC,...\nfor i in range(0,26):\n    column_list.append(alphabet_list[i])\n\nfor i in range(0,26):\n    for j in range(0,26):\n        column_list.append(alphabet_list[i] + alphabet_list[j])\n\n\nclass Spreadsheet_Tools(QtGui.QDialog):\n    \"\"\"\"\"\"\n    def __init__(self, MainWindow):\n        super(Spreadsheet_Tools, self).__init__()\n        self.window = MainWindow\n\n        #MainWindow.setObjectName(_fromUtf8(\"MainWindow\"))\n        #MainWindow.resize(400, 450)\n        #MainWindow.setMinimumSize(QtCore.QSize(400, 450))\n        #MainWindow.setMaximumSize(QtCore.QSize(400, 450))\n        #self.widget = QtGui.QWidget(MainWindow)\n        #self.widget.setObjectName(_fromUtf8(\"widget\"))\n\n\n        self.init_UI()\n\n\n    def init_UI(self):\n        FreeCAD.Console.PrintMessage(\"init_UI\")\n\n        option3Button = QtGui.QPushButton(\"Copy to clipboard\")\n        option3Button.clicked.connect(self.copy_to_clipboard)\n        option1Button = QtGui.QPushButton(\"Cut to clipboard/Delete selection\")\n        option1Button.clicked.connect(self.cut_delete_selection)\n        option2Button = QtGui.QPushButton(\"Paste from clipboard\")\n        option2Button.clicked.connect(self.paste_from_clipboard)\n        option4Button = QtGui.QPushButton(\"Close this dialog\")\n        option4Button.clicked.connect(self.close_dialog)\n\n        buttonBox = QtGui.QDialogButtonBox()\n        buttonBox = QtGui.QDialogButtonBox(QtCore.Qt.Vertical)\n        buttonBox.setGeometry(QtCore.QRect(00, 100, 210, 200))\n        buttonBox.addButton(option3Button, QtGui.QDialogButtonBox.ActionRole)\n        buttonBox.addButton(option1Button, QtGui.QDialogButtonBox.ActionRole)\n        buttonBox.addButton(option2Button, QtGui.QDialogButtonBox.ActionRole)\n        buttonBox.addButton(option4Button, QtGui.QDialogButtonBox.ActionRole)\n\n\n\n        self.groupBox = QtGui.QGroupBox()                                        # this is the group for associate\n        self.groupBox.setGeometry(QtCore.QRect(00, 220, 125, 200))                          # coordinates position\n        self.groupBox.setObjectName(_fromUtf8(\"groupBox\"))                                  # name of window groupBox\n\n#        section checkBox 1\n        self.checkBox_1 = QtGui.QCheckBox(self.groupBox)                                    # create object QRadioButton in groupBox\n        self.checkBox_1.setGeometry(QtCore.QRect(0, 0, 150, 20))                         # coordinates position\n        self.checkBox_1.setObjectName(_fromUtf8(\"Copy/paste/cut visible cell-content\"))                              # name of object\n        self.checkBox_1.setChecked(True)                                                    # Check by default True or False\n\n        self.checkBox_1.setToolTip(_translate(\"MainWindow\", \"Copy/paste/cut visible cell-content\", None))\n        self.checkBox_1.setText(_translate(\"MainWindow\", \"Use visible content\", None))\n        #self.checkBox_1.clicked.connect(self.on_checkBox_1_clicked)\n\n#        section checkBox 2\n        self.checkBox_2 = QtGui.QCheckBox(self.groupBox)                                    # create object QRadioButton in groupBox\n        self.checkBox_2.setGeometry(QtCore.QRect(160, 0, 150, 20))                         # coordinates position\n        self.checkBox_2.setObjectName(_fromUtf8(\"Copy/paste/cut cell-alias\"))                              # name of object\n        self.checkBox_2.setChecked(True)                                                    # Check by default True or False\n\n        self.checkBox_2.setToolTip(_translate(\"MainWindow\", \"Use alias\", None))\n        self.checkBox_2.setText(_translate(\"MainWindow\", \"Use alias\", None))\n        #self.checkBox_2.clicked.connect(self.on_checkBox_2_clicked)\n\n        self.checkBox_3 = QtGui.QCheckBox(self.groupBox)                                    # create object QRadioButton in groupBox\n        self.checkBox_3.setGeometry(QtCore.QRect(280, 0, 150, 20))                         # coordinates position\n        self.checkBox_3.setObjectName(_fromUtf8(\"Copy/paste/cut cell-alias\"))                              # name of object\n        self.checkBox_3.setChecked(True)                                                    # Check by default True or False\n\n        self.checkBox_3.setToolTip(_translate(\"MainWindow\", \"Use formatting\", None))\n        self.checkBox_3.setText(_translate(\"MainWindow\", \"Use formatting\", None))\n        #self.checkBox_3.clicked.connect(self.on_checkBox_3_clicked)\n\n        mainLayout = QtGui.QVBoxLayout()\n\n        mainLayout.addWidget(self.groupBox)\n        mainLayout.addWidget(buttonBox)\n\n        self.setLayout(mainLayout)\n        # define window     xLoc,yLoc,xDim,yDim\n        self.setGeometry(   500, 500, 450, 220)\n        self.setWindowTitle(\"Pick a Button\")\n\n\n    def get_selection(self):\n\n        mw = FreeCADGui.getMainWindow()\n        mdiarea = mw.findChild(QtGui.QMdiArea)\n\n        subw = mdiarea.subWindowList()\n\n        for i in subw:\n            if i.widget().metaObject().className() == \"SpreadsheetGui::SheetView\":\n                sheet = i.widget()\n\n                table = sheet.findChild(QtGui.QTableView)\n        ind = table.selectedIndexes()\n\n        self.mw = mw    # mainwindow\n        self.sheet = sheet  # spreadsheet\n        self.table = table  # table\n        self.ind = ind\n\n        l_elements = len(ind)\n\n        first_element = ind.__getitem__(0)\n        fe_col = first_element.column()\n        fe_row = first_element.row()\n        fe_alphanum = column_list[fe_col] + str(fe_row+1)\n\n        last_element = ind.__getitem__(l_elements-1)\n        le_col = last_element.column()\n        le_row = last_element.row()\n        le_alphanum = column_list[le_col] + str(le_row+1)\n\n        self.fe_alphanum = fe_alphanum\n        self.fe_col = fe_col # numeric representation of column, D=>3\n        self.fe_row = fe_row # numeric representation of row\n\n        self.le_alphanum = le_alphanum\n        self.le_col = le_col\n        self.le_row = le_row\n\n\n    def delete_selection(self):\n        # Delete selection\n        self.get_selection()\n\n        ind = self.ind\n\n        rows = range(self.fe_row, self.le_row+1)\n        columns = range(self.fe_col, self.le_col+1)\n\n\n        for row in rows:\n            for column in columns:\n                cell = column_list[column] + str(row+1)\n                if self.checkBox_1.isChecked():\n                    App.ActiveDocument.Spreadsheet.set(cell, str(' ') )\n                if self.checkBox_2.isChecked():\n                    try:\n                        App.ActiveDocument.Spreadsheet.setAlias(cell, None)\n                    except:\n                        FreeCAD.Console.PrintMessage(\"\\nCould not delete alias.\")\n                if self.checkBox_3.isChecked():\n                    try:\n                        App.ActiveDocument.Spreadsheet.set(cell, '')\n                    except:\n                        FreeCAD.Console.PrintMessage(\"\\nCould not delete formatting.\")\n\n        App.activeDocument().recompute()\n\n\n    def cut_delete_selection(self):\n        # Cut selection\n        self.copy_to_clipboard()\n        self.delete_selection()\n\n\n    def paste_from_clipboard(self):\n        # Paste from clipboard\n\n        self.get_selection()\n\n        clipboard = QtGui.QApplication.clipboard()\n\n        if clipboard.mimeData().hasText():\n\n            cbtext = clipboard.mimeData().text()\n            cbtext_split = [s.split('\\t') for s in cbtext.splitlines()]\n\n            if self.checkBox_1.isChecked() and self.checkBox_2.isChecked() and self.checkBox_3.isChecked():\n\n                n_cells = len(cbtext_split)/3\n\n                index_col = self.fe_col\n                for n_line, line in zip(range(n_cells), cbtext_split[0:n_cells]):\n                    for n_word, col in zip(range(len(line)), line):\n                        cell = column_list[index_col+n_word] + str(self.fe_row+n_line+1)\n                        App.ActiveDocument.Spreadsheet.set(cell, str(col) )\n\n                for n_line, line in zip(range(n_cells), cbtext_split[n_cells:n_cells*2]):\n                    for n_word, col in zip(range(len(line)), line):\n                        cell = column_list[index_col+n_word] + str(self.fe_row+n_line+1)\n                        try:\n                            App.ActiveDocument.Spreadsheet.setAlias(cell, str(col))\n                        except:\n                            FreeCAD.Console.PrintMessage(\"\\nCould not set/paste alias.\")\n\n                for n_line, line in zip(range(n_cells), cbtext_split[n_cells*2:]):\n                    for n_word, col in zip(range(len(line)), line):\n                        cell = column_list[index_col+n_word] + str(self.fe_row+n_line+1)\n                        import ast\n                        col = ast.literal_eval(col)\n\n                        try:\n                            if not(col['style'] == 'None'):\n                                eval(\"App.ActiveDocument.Spreadsheet.setStyle('\"+cell+\"', \"+col['style']+\")\")\n                            if not(col['alignment'] == 'None'):\n                                eval(\"App.ActiveDocument.Spreadsheet.setAlignment('\"+cell+\"', \"+col['alignment']+\")\")\n                        except:\n                            FreeCAD.Console.PrintMessage(\"\\nCould not set formatting (style, alignment).\")\n\n                        try:\n                            if not(col['foreground'] == 'None'):\n                                App.ActiveDocument.Spreadsheet.setForeground(cell, ast.literal_eval(col['foreground']))\n                            if not(col['background'] == 'None'):\n                                eval(\"App.ActiveDocument.Spreadsheet.setBackground('\"+cell+\"', \"+col['background']+\")\")\n                        except:\n                            FreeCAD.Console.PrintMessage(\"\\nCould not set formatting ( background, foreground).\")\n\n                        try:\n                            if not(col['contents'] == ''):\n                                App.ActiveDocument.Spreadsheet.set(cell, col['contents'])\n                            if not(col['displayunit'] == 'None'):\n                                App.ActiveDocument.Spreadsheet.setDisplayUnit(cell, col['displayunit'])\n                        except:\n                            FreeCAD.Console.PrintMessage(\"\\nCould not set formatting (displayunit and contents).\")\n\n\n            if self.checkBox_1.isChecked() and (not self.checkBox_2.isChecked()):\n                n_cells = len(cbtext_split)\n\n                index_col = self.fe_col\n                for n_line, line in zip(range(n_cells), cbtext_split[0:n_cells]):\n                    for n_word, col in zip(range(len(line)), line):\n                        cell = column_list[index_col+n_word] + str(self.fe_row+n_line+1)\n                        App.ActiveDocument.Spreadsheet.set(cell, str(col) )\n\n            if (not self.checkBox_1.isChecked()) and self.checkBox_2.isChecked():\n                n_cells = len(cbtext_split)\n\n                index_col = self.fe_col\n                for n_line, line in zip(range(n_cells), cbtext_split[0:n_cells]):\n                    for n_word, col in zip(range(len(line)), line):\n                        cell = column_list[index_col+n_word] + str(self.fe_row+n_line+1)\n                        try:\n                            App.ActiveDocument.Spreadsheet.setAlias(cell, str(col))\n                        except:\n                            FreeCAD.Console.PrintMessage(\"\\nCould not set/paste alias.\")\n\n            App.activeDocument().recompute()\n\n        else:\n            clipboard.setText(tr(\"Cannot display data! No proper information stored in clipboard.\"))\n\n\n    def copy_to_clipboard(self):\n        # Copy to clipboard\n\n        self.get_selection()\n\n        if len(self.ind) > 0:\n            # sort select indexes into rows and columns\n            previous = self.ind[0]\n            columns = []\n            rows = []\n            clipboard = \"\"\n\n            if self.checkBox_1.isChecked():\n\n                for index in self.ind:\n                    if previous.column() != index.column():\n                        columns.append(rows)\n                        rows = []\n                    rows.append(index.data())\n\n                    idx_col = index.column()\n                    idx_row = index.row()\n                    idx_alphanum = column_list[idx_col] + str(idx_row+1)\n\n                    previous = index\n\n                columns.append(rows)\n                cell_content = columns\n                self.cell_content = cell_content\n\n                # add rows and columns to clipboard\n                nrows = len(cell_content[0])\n                ncols = len(cell_content)\n                for r in xrange(nrows):\n                    for c in xrange(ncols):\n                        if cell_content[c][r] is not None:\n                            clipboard += cell_content[c][r]\n                        else:\n                            clipboard += ''\n                        if c != (ncols-1):\n                            clipboard += '\\t'\n                    clipboard += '\\n'\n\n            previous_alias = self.ind[0]\n            columns_alias = []\n            rows_alias = []\n            clipboard_alias = \"\"\n\n            if self.checkBox_2.isChecked():\n\n                for index in self.ind:\n                    if previous_alias.column() != index.column():\n                        columns_alias.append(rows_alias)\n                        rows_alias = []\n\n                    idx_col = index.column()\n                    idx_row = index.row()\n                    idx_alphanum = column_list[idx_col] + str(idx_row+1)\n                    rows_alias.append(App.ActiveDocument.Spreadsheet.getAlias(idx_alphanum))\n\n                    previous_alias = index\n\n                columns_alias.append(rows_alias)\n                cell_content_alias = columns_alias\n                self.cell_content_alias = cell_content_alias\n\n                # add rows and columns to clipboard\n                nrows = len(cell_content_alias[0])\n                ncols = len(cell_content_alias)\n                for r in xrange(nrows):\n                    for c in xrange(ncols):\n                        if cell_content_alias[c][r] is not None:\n                            clipboard_alias += cell_content_alias[c][r]\n                        else:\n                            clipboard_alias += ''\n                        if c != (ncols-1):\n                            clipboard_alias += '\\t'\n                    clipboard_alias += '\\n'\n\n            previous_formatting = self.ind[0]\n            columns_formatting = []\n            rows_formatting = []\n            clipboard_formatting = \"\"\n\n            if self.checkBox_3.isChecked():\n\n                for index in self.ind:\n                    if previous_formatting.column() != index.column():\n                        columns_formatting.append(rows_formatting)\n                        rows_formatting = []\n\n                    idx_col = index.column()\n                    idx_row = index.row()\n                    idx_alphanum = column_list[idx_col] + str(idx_row+1)\n                    formatting_dict = {'style':str(App.ActiveDocument.Spreadsheet.getStyle(idx_alphanum)),\n                                        'foreground':str(App.ActiveDocument.Spreadsheet.getForeground(idx_alphanum)),\n                                        'background':str(App.ActiveDocument.Spreadsheet.getBackground(idx_alphanum)),\n                                        'contents':str(App.ActiveDocument.Spreadsheet.getContents(idx_alphanum)),\n                                        'displayunit':str(App.ActiveDocument.Spreadsheet.getDisplayUnit(idx_alphanum)),\n                                        'alignment':str(App.ActiveDocument.Spreadsheet.getAlignment(idx_alphanum))}\n                    rows_formatting.append(formatting_dict)\n\n                    previous_formatting = index\n\n                columns_formatting.append(rows_formatting)\n                cell_content_formatting = columns_formatting\n                self.cell_content_formatting = cell_content_formatting\n                FreeCAD.Console.PrintMessage(cell_content_formatting)\n                # add rows and columns to clipboard\n                nrows = len(cell_content_formatting[0])\n                ncols = len(cell_content_formatting)\n                for r in xrange(nrows):\n                    for c in xrange(ncols):\n\n                        if cell_content_formatting[c][r] is not None:\n                            clipboard_formatting += str( cell_content_formatting[c][r] )\n                        else:\n                            clipboard_formatting += ''\n                        if c != (ncols-1):\n                            clipboard_formatting += '\\t'\n\n                    clipboard_formatting += '\\n'\n\n            # copy to the system clipboard\n            sys_clip = QtGui.QApplication.clipboard()\n            sys_clip.setText(clipboard + clipboard_alias + clipboard_formatting)\n\n    def close_dialog(self):\n        self.close()\n\nMainWindow = QtGui.QMainWindow()\nform = Spreadsheet_Tools(MainWindow)\nform.show()",
    "url": "https://wiki.freecad.org/Macro_SpreadsheetTools",
    "raw_code_url": "",
    "wiki": "",
    "version": "0.2.08",
    "license": "",
    "date": "2017-09-02",
    "src_filename": "",
    "filename_from_url": "",
    "author": "HoWil",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_SpreadsheetTools.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/3/35/Macro_SpreadsheetTools.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Spreadsheet2html",
    "on_wiki": true,
    "on_git": false,
    "desc": "Exports a fc spreadsheet as html.<br /><br />Macro version: 0.1<br />Last modified: 2021-08-09<br />FreeCAD version: any with spreadsheet<br />Author: heda<br /> ",
    "comment": "Exports a fc spreadsheet as html. NOTE: wiki caps code so follow instruction on wiki for install.",
    "code": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n# ***************************************************************************\n# *   Copyright (c) 2021 heda <@fc-forum>                                   *\n# *                                                                         *\n# *   This file is part of the FreeCAD CAx development system.              *\n# *                                                                         *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU Lesser General Public License (LGPL)    *\n# *   as published by the Free Software Foundation; either version 2 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENCE text file.                                 *\n# *                                                                         *\n# *   This program is distributed in the hope that it will be useful,       *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU Library General Public License for more details.                  *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with this program; if not, write to the Free Software   *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\n\n__Name__ = 'Spreadsheet2html'\n__Comment__ = 'Exports a fc spreadsheet as html. NOTE: wiki caps code so follow instruction on wiki for install.'\n__Author__ = 'heda @ fc-forum'\n__Version__ = '0.1'\n__Date__ = '2021-08-09'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = ''\n__Wiki__ = 'Associated wiki page'\n__Icon__ = ''\n__Help__ = 'Select a spreadsheet and launch macro.'\n__Status__ = 'Stable'\n__Requires__ = 'tested on FreeCAD v0.19'\n__Communication__ = 'forum'\n__Files__ = ''\n\n\n\n__doc__ = \"\"\"\nExports a selected spreadsheet as html, can be opened directly in LO-Writer.\nFile is saved in user Documents with similar name as the fc-file.\nAll cells with content are included in the exported range.\n\nTo use with LO-Writer:\n  - open the html-file directly with LO-Writer\n\nTo use with LO-Calc:\n  - create new LO-Calc doc\n  - menu: \"Sheet/Link to External Data\" and select the generated html file\n\nThere are 5 options for the generated html:\n  - values without any formatting or comments\n  - values with formatting & comments (default)\n  - formulas with formatting & comments\n  - extra table for comments, i.e. units, formulas & alias (default without)\n  - with/without table borders (default with)\n  \nThe options are set in the macrofile, not via gui.\n\nImports to Calc does not respect column width & row heigth,\nhtml in browser and Writer does...\nSame goes for merged cells.\nNeither Writer nor Calc parses the comments, hence the option for extra table.\n\nAlias:\n  The extra table helps in recreating alias in Calc, to redefine the\n  name within Calc (look in LO-Calc docs if you want to know how).\n\n  Obviously the use of alias is only working for an alias that\n  has references that Calc understands, so \"=A1+B2\" works,\n  while \"=Box.Length\" does not.\n  \n  For the cases where the evaluation should work, one still has to\n  select the cell with the formula and click the \"equal sign\" in\n  the formula bar of Calc user interface.\n\nComments contains the following as per availability:\n  - unit strings when defined on cells in fc\n  - name of alias when defined on cells in fc\n  - formulas if the option to evaluate expressions to values is True (default)\n  - evaluated value if the option to keep formulas is True\n\nFor the option \"paste values\" it is just the evaluated values of the cells.\nThe option does not pass along comments.\n\"\"\"\n\nfilelocation = 'Documents'\noptions = dict(PasteSpecial_values=False,\n               PasteSpecial_values_and_format=True,\n               PasteSpecial_formulas_and_format=False,\n               CommentTable=False,\n               TableBorder=True)\n\nColumnWidthFactor = 100/85 # FC has 100 as std width, 85 is reasonable for LO\nRowHeightFactor = 30/17\n\nimport FreeCADGui as Gui\n\nimport re\nimport html as htmllib\nimport xml.etree.ElementTree as ET\nfrom string import ascii_uppercase\nfrom itertools import product\nfrom pathlib import Path\nfrom datetime import datetime as dt\n\n\n#spreadsheet = App.ActiveDocument.Spreadsheet\n\nspreadsheet, = Gui.Selection.getSelection()\nsp_name = spreadsheet.FullName.replace('#', '-')\nsp_content = spreadsheet.cells.Content\nroot = ET.fromstring(sp_content)\n\ncells = dict()\nfor el in root:\n    if not 'Cell' in el.tag: continue\n    address = el.attrib.pop('address')\n    cells[address] = el.attrib\n\n#import pprint\n#pp = pprint.PrettyPrinter(indent=4)\n#pp.pprint(cells)\n\n### find range of sheet\n##  (would be nice with a simple sp.getRange())\nchar = re.compile(r'\\d+')\nnum = re.compile(r'\\D+')\n\ndef split_address(address):\n    C, _, _, R = char.split(address) + num.split(address)\n    return C, int(R)\n\ntmp = dict(split_address(address) for address in cells)\nRmax = max(tmp.values())\n## need to separate one and two chars comparison\nif any(map(lambda s: len(s) == 2, tmp)):\n    Cmax = max(filter(lambda s: len(s) == 2, tmp))\nelse:\n    Cmax = max(tmp)\n\n### prepare column and row iterable for actual range\ncolumn_iter = list(ascii_uppercase)\ncolumn_extension = 10 # assume that col-span on last col is limited to 9...\ncart = product(ascii_uppercase, repeat=2)\nif Cmax in column_iter:\n    cut_idx = column_iter.index(Cmax) + 1\n    length = range(column_extension)\n    column_iter += [''.join(c) for _, c in zip(length, cart)]\n\n    column_extension = column_iter[cut_idx:cut_idx + column_extension]\n    column_iter = column_iter[:cut_idx]\nelse:\n    a, b = (ord(c)-65 for c in Cmax)\n    length = range(a * len(ascii_uppercase) + b + 1 + column_extension)\n    column_iter += [''.join(c) for _, c in zip(length, cart)]\n                \n    column_extension = column_iter[-column_extension:]\n    column_iter = column_iter[:-len(column_extension)]\n\n## extend range where needed\nhitcells = (cell for cell in cells if str(Rmax) in cell)\nextend = max(cells.get(address).get('rowSpan', '1') for cell in hitcells)\nRmax += int(extend) - 1\n\nextend = 1\nfor address in (cell for cell in cells if str(Cmax) in cell):\n    v = int(cells.get(address).get('colSpan', 1))\n    extend = v if v > extend else extend\ncolumn_iter += column_extension[:int(extend) - 1]\ncolumn_iter = tuple(column_iter)\nCmax = column_iter[-1]\n\n\n### generating html\n# doctype workaround, tripping parser if there\ndoctype = '<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"/>'\n\ntemplate = \"\"\"\n<html>\n<head>\n\t\n\t<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/>\n\t<title>FreeCAD</title>\n\t<meta name=\"template\" content=\"LibreOffice (Calc) 6.4\"/>\n\t<meta name=\"generator\" content=\"FreeCAD macro - SpreadSheet2LibreOffice\"/>\n\t<meta name=\"created\" content=\"\"/>\n\t\n\t<style type=\"text/css\">\n\t\ta.comment-indicator:hover + comment { background:#ffd; position:absolute; display:block; border:1px solid black; padding:0.5em;  } \n\t\ta.comment-indicator { background:red; display:inline-block; border:1px solid black; width:0.5em; height:0.5em;  } \n\t\tcomment { display:none;  } \n\t</style>\n\t\n</head>\n\n<body>\n<table cellspacing=\"0\" cellpadding=\"3\" border=\"1\">\n</table>\n</body>\n\n</html>\n\"\"\"\n\ndoc = ET.fromstring(template)\n\ntitle = doc.find('./head/title')\ntitle.text += ' ' + sp_name\ncreated = doc.find(\"./head/meta[@name='created']\")\ncreated.set('content', dt.now().strftime('%Y-%m-%d %H:%M:%S'))\n\ntable = doc.find('./body/table')\ntable.set('border', str(int(options.get('TableBorder'))))\n    \nfor width in (spreadsheet.getColumnWidth(c) for c in column_iter):\n    ET.SubElement(table, 'colgroup',\n                  dict(width='{:.0f}'.format(width/ColumnWidthFactor)))\n\nalign_table = dict(left=('align', 'left'), center=('align', 'center'),\n                   right=('align', 'right'),\n                   top=('valign', 'top'), vcenter=('valign', 'middle'),\n                   bottom=('valign', 'bottom'))\nstyle_table = dict(bold='b', italic='i', underline='u')\n\nskip_list = list()\nfor r in range(1, Rmax+1):\n    rowheight = spreadsheet.getRowHeight(str(r)) / RowHeightFactor\n    tr = ET.Element('tr', dict(height='{:.0f}'.format(rowheight)))\n    for c in column_iter:\n        address = f'{c}{r}'\n        cell = cells.get(address, dict())\n        new_attrib = dict()\n        td = ET.Element('td')\n        td.text = cell.get('content')\n        # avoid overflow, implies look ahead\n        colspan = int(cell.get('colSpan', 0))\n        rowspan = int(cell.get('rowSpan', 0))\n        if colspan > 0:\n            idx = column_iter.index(c) + 1\n            gen = (f'{ci}{r}' for ci in column_iter[idx:idx + colspan - 1])\n            skip_list.extend(gen)\n            new_attrib.update(dict(colspan=str(colspan)))\n        if rowspan > 0:\n            gen = (f'{c}{ri}' for ri in range(r + 1, r + rowspan))\n            skip_list.extend(gen)\n            new_attrib.update(dict(rowspan=str(rowspan)))\n            \n        if address in skip_list:\n            continue\n        \n        tr.append(td)\n        \n        # styling and attributes\n        subel, comment = list(), list()\n        for k in sorted(cell):\n            v = cell.get(k)\n            if k == 'alias':\n                comment.append('alias: {}'.format(v))\n            elif k == 'alignment':\n                for which in v.split('|'):\n                    kva = align_table.get(which)\n                    if kva:\n                        new_attrib.update(dict((kva,)))\n            elif k == 'backgroundColor':\n                new_attrib.update(dict(bgcolor=v[:-2]))\n            elif k == 'displayUnit':\n                comment.append('unit: {}'.format(v))\n            elif k == 'foregroundColor': # will always be first\n                font = ET.Element('font', dict(color=v[:-2]))\n                subel.append(font)\n            elif k == 'style':\n                for which in v.split(chr(124)):\n                    sty = ET.Element(style_table.get(which))\n                    subel.insert(0, sty)\n        \n        # formula options\n        if isinstance(td.text, str) and td.text.startswith('='):\n            if options.get('PasteSpecial_values'):\n                td.text = str(spreadsheet.get(address)) # returns casted type\n            elif options.get('PasteSpecial_values_and_format'):\n                formula = td.text\n                td.text = str(spreadsheet.get(address))\n                comment.append('formula: {}'.format(formula))\n            elif options.get('PasteSpecial_formulas_and_format'):\n                value = spreadsheet.get(address)\n                comment.append('value: {}'.format(value))\n\n        if options.get('PasteSpecial_values'):\n            subel, comment = list(), list()\n            for k in tuple(new_attrib):\n                if not 'span' in k:\n                    _ = new_attrib.pop(k)\n\n        # sanitize for html\n        if td.text:\n            td.text = htmllib.escape(td.text)\n\n        if comment:\n            ET.SubElement(td, 'a', {'class': 'comment-indicator'})\n            popup = ET.Element('comment')\n            popup.text = '  |  '.join((htmllib.escape(cm) for cm in comment))\n            td.append(popup)\n                        \n        td.attrib = new_attrib\n\n        if subel:\n            parent = td\n            for child in subel:\n                child.text = parent.text\n                parent.text = None\n                parent.append(child)\n                parent = child\n\n    table.append(tr)\n\n### extra table\nif options.get('CommentTable'):\n\n    template_extra = \"\"\"\n    <table cellspacing=\"0\" cellpadding=\"3\" border=\"1\">\n    <tr>\n        <td><b>adress</b></td>\n        <td><b>trace</b></td>\n        <td><b>evaluated</b></td>\n        <td><b>unit</b></td>\n        <td><b>formula</b></td>\n        <td><b>alias</b></td>\n    </tr>\n    </table>\n    \"\"\"\n    table_extra = ET.fromstring(template_extra)\n    \n    table_extra.set('border', str(int(options.get('TableBorder'))))\n    \n    body = doc.find('./body')\n    body.extend((ET.Element('p'), table_extra))\n    \n    for address, attrib in cells.items():\n        row = [address, f'={address}', None,\n               attrib.get('displayUnit'), None, attrib.get('alias')]\n\n        content = attrib.get('content')\n        if not content:\n            continue\n\n        row[2] = content\n        if content.startswith('='):\n            value = spreadsheet.get(address)\n            row[2] = value\n            row[4] = chr(39) + content\n    \n        tr = ET.Element('tr')\n        for r in row:\n            td = ET.Element('td')\n            td.text = r\n            tr.append(td)\n\n        table_extra.append(tr)\n\n\n### save file on disk\nfilehandle = Path.home() / filelocation / '{}.html'.format(sp_name)\nhtmldoc = ET.ElementTree(doc)\nhtmldoc.write(filehandle, encoding='utf-8',\n              xml_declaration=True, method='html')\n\nfilehandle.write_text('\\n'.join((doctype, filehandle.read_text())))\n\nprint('Exported spreadsheet as html.')\n\n# end\n",
    "url": "https://wiki.freecad.org/Macro_Spreadsheet2html",
    "raw_code_url": "",
    "wiki": "Associated wiki page",
    "version": "0.1",
    "license": "",
    "date": "2021-08-09",
    "src_filename": "",
    "filename_from_url": "",
    "author": "heda @ fc-forum",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Arch Axis System Repartition",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro help you to create an Arch Axis System along a line with a set of parameters. You can even create a Structural System directly from the FreeCAD-Library.<br /><br />Macro version: 1.0<br />Last modified: 2014-12-22<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/a/a0/Macro_Arch_Axis_System_Repartition.png\">ToolBar Icon</a><br />Author: rockn<br /> ",
    "comment": "This macro help you to create an Arch Axis System along a line with a set of parameters. You can even create a Structural System directly from the FreeCAD-Library.",
    "code": "\n\n#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n#***************************************************************************\n#*                                                                         *\n#*   Copyright (c) 2014 Jonathan Wiedemann <wood.galaxy@gmail.com          *\n#*                                                                         *\n#*   This program is free software; you can redistribute it and/or modify  *\n#*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n#*   as published by the Free Software Foundation; either version 2 of     *\n#*   the License, or (at your option) any later version.                   *\n#*   for detail see the LICENCE text file.                                 *\n#*                                                                         *\n#*   This program is distributed in the hope that it will be useful,       *\n#*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n#*   GNU Library General Public License for more details.                  *\n#*                                                                         *\n#*   You should have received a copy of the GNU Library General Public     *\n#*   License along with this program; if not, write to the Free Software   *\n#*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n#*   USA                                                                   *\n#*                                                                         *\n#***************************************************************************\n\n__title__=\"Repartition\"\n__author__ = \"Jonathan Wiedemann\"\n__url__ = \"http://www.freecad-france.com\"\n\nimport FreeCAD, FreeCADGui, DraftGeomUtils, DraftVecUtils\nimport Arch\nimport Part\nimport math\nfrom PySide import QtCore, QtGui\n\nclass _RepartitionTaskPanel:\n\tdef __init__(self):\n\t\tself.title = QtGui.QLabel('Repartition')\n\t\tself.grid = QtGui.QGridLayout()\n\t\tself.grid.addWidget(self.title, 1, 0)\n\n\t\tself.longueurLabel = QtGui.QLabel('Longueur')\n\n\t\tself.dSBLongueur = QtGui.QDoubleSpinBox()\n\t\tself.dSBLongueur.setRange(0., 9999999.)\n\t\tself.sel = FreeCADGui.Selection.getSelection()\n\t\tif self.sel:\n\t\t\tself.longueur = self.sel[0].Shape.Length\n\t\t\tself.dSBLongueur.setValue(self.longueur)\n\t\telse:\n\t\t\tself.dSBLongueur.setValue(5000.)\n\n\t\tself.grid.addWidget(self.longueurLabel, 2, 0)\n\t\tself.grid.addWidget(self.dSBLongueur, 2, 1)\n\n\t\tself.ecartementLabel = QtGui.QLabel('Ecartement')\n\t\tself.ecartementDSB = QtGui.QDoubleSpinBox()\n\t\tself.ecartementDSB.setRange(0., 9999999.)\n\t\tself.ecartementDSB.setValue(500.)\n\t\tself.grid.addWidget(self.ecartementLabel, 3, 0)\n\t\tself.grid.addWidget(self.ecartementDSB, 3, 1)\n\n\t\tself.qteLabel = QtGui.QLabel('Quantite')\n\t\tself.qteSB = QtGui.QSpinBox()\n\t\tself.qteSB.setRange(0,99999)\n\t\tself.grid.addWidget(self.qteLabel, 4, 0)\n\t\tself.grid.addWidget(self.qteSB, 4, 1)\n\n\t\tself.infoText = QtGui.QLabel('Espace restant = ')\n\t\tself.grid.addWidget(self.infoText, 5, 0)\n\t\tself.combobox = QtGui.QComboBox()\n\t\titems = [\"Debut\",\"Fin\",\"Divise\"]\n\t\tself.combobox.addItems(items)\n\t\tself.combobox.setCurrentIndex(items.index(\"Fin\"))\n\t\tself.grid.addWidget(self.combobox, 5, 1)\n\n\t\tself.debutLabel = QtGui.QLabel('Debut')\n\t\tself.grid.addWidget(self.debutLabel, 6, 0)\n\n\t\tself.debutRepartitionCB = QtGui.QCheckBox()\n\t\tself.debutRepartitionCB.setCheckState(QtCore.Qt.CheckState.Checked)\n\t\tself.grid.addWidget(self.debutRepartitionCB, 6, 1)\n\n\t\tself.decalageDebutLabel = QtGui.QLabel('Decalage')\n\t\tself.grid.addWidget(self.decalageDebutLabel, 7, 0)\n\n\t\tself.decalageDebutDSB = QtGui.QDoubleSpinBox()\n\t\tself.decalageDebutDSB.setRange(0., 9999999.)\n\t\tself.grid.addWidget(self.decalageDebutDSB, 7, 1)\n\n\t\tself.finLabel = QtGui.QLabel('Fin')\n\t\tself.grid.addWidget(self.finLabel, 8, 0)\n\n\t\tself.finRepartitionCB = QtGui.QCheckBox()\n\t\tself.finRepartitionCB.setCheckState(QtCore.Qt.CheckState.Checked)\n\t\tself.grid.addWidget(self.finRepartitionCB, 8, 1)\n\n\t\tself.decalageFinLabel = QtGui.QLabel('Decalage')\n\t\tself.grid.addWidget(self.decalageFinLabel, 9, 0)\n\n\t\tself.decalageFinDSB = QtGui.QDoubleSpinBox()\n\t\tself.decalageFinDSB.setRange(0., 9999999.)\n\t\tself.grid.addWidget(self.decalageFinDSB, 9, 1)\n\n\t\tgroupBox = QtGui.QGroupBox()\n\t\tgroupBox.setLayout(self.grid)\n\t\tself.form = groupBox\n\n\t\tQtCore.QObject.connect(self.dSBLongueur,QtCore.SIGNAL(\"valueChanged(double)\"),self.changerLongueur)\n\t\tQtCore.QObject.connect(self.ecartementDSB,QtCore.SIGNAL(\"valueChanged(double)\"),self.changerEcartement)\n\t\tQtCore.QObject.connect(self.qteSB,QtCore.SIGNAL(\"valueChanged(int)\"),self.changerQte)\n\t\tQtCore.QObject.connect(self.combobox,QtCore.SIGNAL(\"currentIndexChanged(int)\"),self.afficherResultats)\n\t\tself.changerLongueur()\n\n\tdef recupererDonnees(self):\n\t\tself.sel = FreeCADGui.Selection.getSelection()\n\t\tif self.sel:\n\t\t\tself.longueur = self.sel[0].Shape.Length\n\t\telse:\n\t\t\tself.longueur = self.dSBLongueur.value()\n\t\tself.ecartementRegulier = self.ecartementDSB.value()\n\t\tself.qteEcartement = self.qteSB.value()\n\n\t\tself.objetDebut =  self.debutRepartitionCB.isChecked()\n\t\tself.decalageDebut = self.decalageDebutDSB.value()\n\t\tself.plEspaceRestant = self.combobox.currentIndex()\n\t\tself.objetFin = self.finRepartitionCB.isChecked()\n\t\tself.decalageFin = self.decalageFinDSB.value()\n\n\tdef changerLongueur(self):\n\t\tself.recupererDonnees()\n\t\tself.qteEcartement = int(math.ceil(self.longueur/self.ecartementRegulier))\n\t\tself.afficherResultats()\n\n\tdef changerEcartement(self):\n\t\tself.recupererDonnees()\n\t\tself.qteEcartement = int(math.ceil(self.longueur/self.ecartementRegulier))\n\t\tself.afficherResultats()\n\n\tdef changerQte(self):\n\t\tself.recupererDonnees()\n\t\tself.ecartementRegulier = self.longueur/self.qteEcartement\n\t\tself.afficherResultats()\n\n\tdef afficherResultats(self):\n\t\tself.dSBLongueur.blockSignals(True)\n\t\tself.dSBLongueur.setValue(self.longueur)\n\t\tself.dSBLongueur.blockSignals(False)\n\n\t\tself.ecartementDSB.blockSignals(True)\n\t\tself.ecartementDSB.setValue(self.ecartementRegulier)\n\t\tself.ecartementDSB.blockSignals(False)\n\n\n\t\tself.qteSB.blockSignals(True)\n\t\tself.qteSB.setValue(self.qteEcartement)\n\t\tself.qteSB.blockSignals(False)\n\n\t\tself.espaceRestant = self.longueur - (self.qteEcartement-1) * self.ecartementRegulier\n\t\tif round(self.espaceRestant,2) == round(self.ecartementRegulier,2):\n\t\t\tself.espaceRestant = 0.\n\t\tif self.combobox.currentIndex() == 2:\n\t\t\tself.infoText.setText( str('Espace restant = 2 x ') + str(round(self.espaceRestant/2,2)) + str(' mm') )\n\t\telse:\n\t\t\tself.infoText.setText( str('Espace restant = ') + str(round(self.espaceRestant,2)) + str(' mm') )\n\n\tdef accept(self):\n\t\tself.recupererDonnees()\n\t\tdistancesListe = []\n\t\tif self.objetDebut:\n\t\t\tdistancesListe.append(self.decalageDebut)\n\t\tif self.plEspaceRestant == 0:\n\t\t\tdistancesListe.append(self.espaceRestant)\n\t\tif self.plEspaceRestant == 1:\n\t\t\tdistancesListe.append(self.ecartementRegulier-self.decalageDebut)\n\t\tif self.plEspaceRestant == 2:\n\t\t\tdistancesListe.append(self.espaceRestant/2-self.decalageDebut)\n\t\tfor i in range(self.qteEcartement-2):\n\t\t\tdistancesListe.append(self.ecartementRegulier)\n\t\tif self.objetFin:\n\t\t\tif self.plEspaceRestant == 0:\n\t\t\t\tdistancesListe.append(self.ecartementRegulier-self.decalageFin-self.decalageDebut)\n\t\t\tif self.plEspaceRestant == 1:\n\t\t\t\tdistancesListe.append(self.espaceRestant-self.decalageFin)\n\t\t\tif self.plEspaceRestant == 2:\n\t\t\t\tdistancesListe.append(self.ecartementRegulier)\n\t\t\t\tdistancesListe.append((self.espaceRestant/2)-self.decalageFin)\n\t\trepartition = Arch.makeAxis(num=len(distancesListe), name=\"Repartition\")\n\t\trepartition.Length = 1000.00\n\t\trepartition.Distances= distancesListe\n\n\t\tself.sel = FreeCADGui.Selection.getSelection()\n\t\tif self.sel:\n\t\t\tedges = DraftGeomUtils.sortEdges(self.sel[0].Shape.Wires[0].Edges)\n\t\t\tvec1 = edges[0].Vertexes[-1].Point.sub(edges[0].Vertexes[0].Point)\n\t\t\tpoint1 = edges[0].Vertexes[0].Point\n\t\t\trot = math.degrees(DraftVecUtils.angle(vec1))*-1\n\t\t\trepartition.Placement = App.Placement(App.Vector(point1),App.Rotation(App.Vector(0.0,0.0,1.0),rot))\n\t\t\tFreeCAD.ActiveDocument.recompute()\n\t\telse:\n\t\t\trepartition.Placement = App.Placement(App.Vector(0.0,0.0,0.0),App.Rotation(App.Vector(0.0,0.0,1.0),0))\n\n\t\tm = FreeCADGui.getMainWindow()\n\t\tw = m.findChild(QtGui.QDockWidget,\"PartsLibrary\")\n\t\tif w:\n\t\t\tif w.isVisible():\n\t\t\t\tindex = w.folder_view.selectedIndexes()[0]\n\t\t\t\tpath = w.dirmodel.filePath(index)\n\t\t\t\tif path.lower().endswith(\".stp\") or path.lower().endswith(\".step\") or path.lower().endswith(\".brep\"):\n\t\t\t\t\tobjetRepartit = Part.show(Part.read(path))\n\t\t\t\telse:\n\t\t\t\t\tobjetRepartit = FreeCADGui.ActiveDocument.mergeProject(path)\n\t\t\t\trepartitionStructurel = Arch.makeStructuralSystem([FreeCAD.ActiveDocument.Objects[-1],],[repartition,], name=\"RepartitionStructurelle\")\n\t\treturn True\n\n\tdef reject(self):\n\t\treturn True\n\n\tdef getStandardButtons(self):\n\t\treturn int(QtGui.QDialogButtonBox.Ok|QtGui.QDialogButtonBox.Cancel)\n\n\npanel=_RepartitionTaskPanel()\nFreeCADGui.Control.showDialog(panel)\n\n",
    "url": "https://wiki.freecad.org/Macro_Arch_Axis_System_Repartition",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-12-22",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Jonathan Wiedemann",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Arch_Axis_System_Repartition.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/a/a0/Macro_Arch_Axis_System_Repartition.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Convert 021",
    "on_wiki": true,
    "on_git": false,
    "desc": "Converts a FreeCAD file saved with a post-0.21 version back to 0.21 format.<br /><br />Macro version: 0.1<br />Last modified: 2024-03-13<br />FreeCAD version: any<br />Author: yorik<br /> ",
    "comment": "Converts a FreeCAD file saved with a post-0.21 version back to 0.21 format.",
    "code": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ***************************************************************************\n# *                                                                         *\n# *   Copyright (c) 2024 Yorik van Havre <yorik@uncreated.net>              *\n# *                      Florian Foinant-Willig <ffw@2f2v.fr>               *\n# *                                                                         *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU General Public License (GPL)            *\n# *   as published by the Free Software Foundation; either version 3 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENCE text file.                                 *\n# *                                                                         *\n# *   This program is distributed in the hope that it will be useful,       *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU General Public License for more details.                          *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with this program; if not, write to the Free Software   *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\n\"\"\"This macro opens a file dialog to allow to choose a FreeCAD file\nand converts it to 0.21 format (replace AttachmentSupport property to Support).\nA new file with extension .021.FCStd is created so the original file is not modified\"\"\"\nimport os\nimport zipfile\nfrom PySide import QtGui\n\nfilenames = QtGui.QFileDialog.getOpenFileNames(None,\n                                             \"Open FreeCAD file\",\n                                             None,\n                                             \"FreeCAD Files (*.FCStd *.fcstd)\")\nfor filename in filenames[0]:\n    print(\"Processing\", filename, \"...\")\n    spl = os.path.splitext(filename)\n    filename021 = spl[0] + \".021\" + spl[1]\n    with zipfile.ZipFile(filename) as inzip, zipfile.ZipFile(filename021, \"w\") as outzip:\n        for inzipinfo in inzip.infolist():\n            with inzip.open(inzipinfo) as infile:\n                if inzipinfo.filename == \"Document.xml\":\n                    content = infile.read()\n                    content = content.replace(b\"AttachmentSupport\", b\"Support\")\n                    outzip.writestr(inzipinfo, content)\n                else:\n                    outzip.writestr(inzipinfo, infile.read())\n    print(filename021, \"successfully written\")\n\nprint (\"All done!\")\n",
    "url": "https://wiki.freecad.org/Macro_Convert_021",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2024-03-13",
    "src_filename": "",
    "filename_from_url": "",
    "author": "yorik",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Download Classifications",
    "on_wiki": true,
    "on_git": false,
    "desc": "Downloads a package of BIM classification systems for use in FreeCAD<br /><br />Macro version: 1.0<br />Last modified: 2024-12-13<br />FreeCAD version: All<br />Author: yorik<br /> ",
    "comment": "Downloads a package of BIM classification systems for use in FreeCAD",
    "code": "import os\nimport FreeCAD\nimport requests\nimport json\n\ntarget = os.path.join(FreeCAD.getUserAppDataDir(), \"BIM\", \"Classification\")\napireq = \"https://api.github.com/repos/Moult/IfcClassification/contents/xml\"\n\nr = requests.get(apireq)\nif r.ok:\n    j = json.loads(r.content)\n    print(\"Installing to\", target\", ...\")\n    for f in j:\n        df = requests.get(f[\"download_url\"])\n        with open(os.path.join(target, f[\"name\"]), 'wb') as tf:\n            tf.write(df.content)\n            print(\"Downloaded\", f[\"name\"])\nelse:\n    print(\"error getting repo contents\")",
    "url": "https://wiki.freecad.org/Macro_Download_Classifications",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2024-12-13",
    "src_filename": "",
    "filename_from_url": "",
    "author": "yorik",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Duplicate Selection",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro changes the mouse cursor to \"ForbiddenCursor\" if a selection is duplicated.<br /><br />Macro version: 00.00<br />Last modified: 2016-06-06<br />FreeCAD version: 0.16<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/5/54/Macro_Duplicate_Selection.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "This macro changes the mouse cursor to \"ForbiddenCursor\" if a selection is duplicated.",
    "code": "# -*- coding: utf-8 -*-\nimport FreeCADGui\nimport PySide\nfrom PySide import QtGui ,QtCore\nfrom PySide.QtGui import *\nfrom PySide.QtCore import *\n\n__title__   = \"Macro_Duplicate_Selection\"\n__author__  = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__version__ = \"00.00\"\n__date__    = \"06/06/2016\"\n\n__Help__    = \"Start the macro select the object IN THE 3D VIEW the ForbiddenCursor stay if the selection is duplicate\"\n\ndef selectionObject():\n    sel = FreeCADGui.Selection.getSelection() \n    x  = []\n    del x[:]\n    for a in range(len(sel)):\n       x.append(sel[a].Name)\n    doublet = 0\n    for i in range(len(sel)):\n        for ii in range((i+1),len(sel)):\n            if x[i] == x[ii]:\n                doublet = 1\n                break\n    if doublet == 1:\n        QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.ForbiddenCursor))\n#        FreeCAD.Console.PrintError(\"HELP \"+sel[-1].Name+\" duplicate selection\"+\"\\n\")\n    else:\n        QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))\n\nclass SelObserver:\n    def addSelection(self,doc,obj,sub,pnt):   # Selection\n        selectionObject()\n    def removeSelection(self,doc,obj,sub):    # Effacer l'objet salectionne\n        selectionObject()\n    def setPreselection(self, doc, obj, sub):\n        selectionObject()\n    def clearSelection(self,doc):             # Si clic sur l'ecran, effacer la selection\n        selectionObject()\n#    def setSelection(self,doc):               # Selection dans Combo View pour quitter la fonction\n#        App.Console.PrintMessage(\"Fin Macro_Duplicate\"+\"\\n\")\n#        QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))\n#        FreeCADGui.Selection.removeObserver(s)# desinstalle la fonction residente\n\ns=SelObserver()\nFreeCADGui.Selection.addObserver(s)    # installe la fonction en mode resident",
    "url": "https://wiki.freecad.org/Macro_Duplicate_Selection",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.00",
    "license": "",
    "date": "06/06/2016",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Duplicate_Selection.png",
    "icon_source": "https://wiki.freecad.org/images/5/54/Macro_Duplicate_Selection.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Easy cutouts for Enclosure Design",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro makes Cutouts for Enclosures in a very handy way. Just select a face of the object that is the base for the cutout and the macro will create a clone of the external outline with a margin of 0.5mm (set in the macro)<br /><span style=\"background-color: #ff0000\">This macro needs to be upgraded</span><br /><br />Macro version: 0.25<br />Last modified: 2016-11-26<br />FreeCAD version: 0.16<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/7/71/Macro_Easy_cutouts_for_Enclosure_Design_icon.png\">ToolBar Icon</a><br />Author: maurice<br /> ",
    "comment": "This macro makes Cutouts for Enclosures in a very handy way. Just select a face of the object that is the base for the cutout and the macro will create a clone of the external outline with a margin of 0.5mm (set in the macro)",
    "code": "# -*- coding: utf-8 -*-\n# clone, enlarge & center clone-obj to selected obj\n#\n \n__title__   = \"Clone-Enlarge-Center Face for cutouts\"\n__author__  = \"maurice\"\n__url__     = \"kicad stepup\"\n__version__ = \"0.25\"\n__date__    = \"11.2016\"\n\nimport FreeCAD, FreeCADGui, Draft, Part, DraftTools\nfrom FreeCAD import Base\n\n\ndef say(msg):\n    FreeCAD.Console.PrintMessage(msg)\n    FreeCAD.Console.PrintMessage('\\n')\n\ndef sayw(msg):\n    FreeCAD.Console.PrintWarning(msg)\n    FreeCAD.Console.PrintWarning('\\n')\n \ndef getNormal(self):\n    return self.Object.Shape.Faces[0].normalAt(0,0)\n\n#Init        \nif Gui.ActiveDocument <> None:\n    #say (Gui.ActiveDocument)\n\n    cx = 1  # center x -> 1  \n    cy = 1  # center y -> 1 \n    cz = 1  # center z -> 1 \n    \n    # scaleX = 1.1 # scale factor for Clone\n    # scaleY = 1.1 # scale factor for Clone\n    # scaleZ = 1.1 # scale factor for Clone\n    \n    margin = 0.5 #margin in mm\n    extrudeLenght = 10 #10mm    \n    #selEx = FreeCADGui.Selection.getSelectionEx()\n    sel = FreeCADGui.Selection.getSelection()\n    \n    #print sel[0].Label\n    #objs = [selobj.Object for selobj in selEx]\n    selF = FreeCADGui.Selection.getSelectionEx()\n    \n    #if len(Gui.Selection.getSelectionEx()[0].SubElementNames) <1:\n    #    stop\n    \n    if len(sel) > 0:\n        FreeCADGui.Selection.removeSelection(sel[0])\n    #for o in FreeCADGui.ActiveDocument.getObjects():\n    #    FreeCADGui.Selection.removeSelection(o.Name)\n    coords = []\n    j = 0\n    #if len(sel) == 1: # only 1 object selected\n    #if len(selF) == 1: # only 1 object selected\n    if len(sel) > 0:\n        if len(selF[0].SubElementNames) ==1:\n            f_names=[]\n            f = Draft.makeFacebinder(selF)\n            f1=App.ActiveDocument.getObject(f.Name)\n            face=0\n            try:\n                norm = f1.Shape.Faces[0].normalAt(0,0)\n                say (norm)\n                face=1\n            except:\n                App.Console.PrintMessage(\"Select ONLY one single Face of object!\"+\"\\n\")\n                # stop\n            if face==1:\n                l = Draft.downgrade(f,delete=False)\n                k = 0; bbM = 0\n                for o in l:\n                    for w in o:\n                        #print w.Name\n                        f_names.append (w.Name)\n                        say(w.Name)\n                        if \"Facebinder\" not in w.Name:\n                            bb=w.Shape.BoundBox\n                            bbX=float(bb.XLength)\n                            bbY=float(bb.YLength)\n                            bbZ=float(bb.ZLength)\n                            say (str(bbX)+\";\"+str(bbY)+\";\"+str(bbZ))\n                            if bbX > bbM:\n                                bbM = bbX; m = k\n                            if bbY > bbM:\n                                bbM = bbY; m = k\n                            if bbZ > bbM:\n                                bbM = bbZ; m = k\n                        k=k+1\n                print f_names\n                k = 0\n                #f_names=[]\n                for o in l:\n                    for w in o:\n                        say(w.Name)\n                        #f_names.append (w.Name)\n                        if k!=m:\n                            say ( \"deleting \"+f_names[k] )\n                            FreeCAD.ActiveDocument.removeObject(f_names[k])\n                        else:\n                            FreeCADGui.ActiveDocument.getObject(f_names[k]).Visibility=False\n                            f = FreeCAD.ActiveDocument.addObject('Part::Extrusion', 'Extrude_for_cut')\n                            f = FreeCAD.ActiveDocument.getObject(f.Name)\n                            f.Base = FreeCAD.ActiveDocument.getObject(f_names[k])\n                            f.Dir = norm * extrudeLenght * -1\n                            f.Solid = (True)\n                            f.TaperAngle = (0)\n                        k=k+1        \n                #FreeCAD.ActiveDocument.removeObject(f_names[len(l)])\n                say( f_names )\n                say( f_names[m] )\n                say( bbM )\n                \n                FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(f.Name))\n                FreeCAD.ActiveDocument.recompute()\n                \n                sel = FreeCADGui.Selection.getSelection()   \n                #objs = [selobj.Object for selobj in selEx]\n                \n                coords = []\n                j = 0\n                s = sel[0].Shape\n                \n                bb=s.BoundBox\n                \n                bbX=float(bb.XLength)\n                bbY=float(bb.YLength)\n                bbZ=float(bb.ZLength)\n                # boundBox\n                boundBox_ = s.BoundBox\n                \n                a = str(boundBox_)\n                a,b = a.split('(')\n                c = b.split(',')\n                oripl_X = float(c[0])\n                oripl_Y = float(c[1])\n                oripl_Z = float(c[2])\n                coords.append ([oripl_X+bbX/2, oripl_Y+bbY/2, oripl_Z+bbZ/2])\n                App.Console.PrintMessage(str(boundBox_)+\"\\r\\n\")\n                App.Console.PrintMessage(\"BBox           : \"+str(bbX)+\" x \"+str(bbY)+\" x \"+str(bbZ)+\"\\r\\n\")\n                App.Console.PrintMessage(\"Base Pos       : \"+str(oripl_X)+\" x \"+str(oripl_Y)+\" x \"+str(oripl_Z)+\"\\r\\n\")\n                App.Console.PrintMessage(\"Center Pos     : \"+str(oripl_X+bbX/2)+\" x \"+str(oripl_Y+bbY/2)+\" x \"+str(oripl_Z+bbZ/2)+\"\\r\\n\")\n                App.Console.PrintMessage(\"Coords         : \"+str(coords[j])+\"\\r\\n\")\n            \n                #objC = FreeCAD.ActiveDocument.addObject('Part::AttachableObjectPython', 'Clone_for_cut')\n                #objC = FreeCAD.ActiveDocument.getObject(objC.Name)\n                objC=Draft.clone(sel)\n                if bbX!=0:\n                    scaleX = (bbX + 2*margin) / bbX\n                else:\n                    scaleX = 1\n                if bbY!=0:\n                    scaleY = (bbY + 2*margin) / bbY\n                else:\n                    scaleY = 1\n                if bbZ!=0:\n                    scaleZ = (bbZ + 2*margin) / bbZ\n                else:\n                    scaleZ = 1\n                objC.Scale = (scaleX,scaleY,scaleZ)\n                #Draft.scale(objC,delta=App.Vector(scaleX,scaleY,scaleZ),center=App.Vector(0,0,0),copy=True,legacy=True)\n                \n                oL = sel[0].Label + \"_enlarged\"\n                objC.Label = oL\n                FreeCADGui.Selection.addSelection(objC)\n                \n                FreeCAD.ActiveDocument.recompute()\n            \n                selEx = FreeCADGui.Selection.getSelectionEx()\n                objs = [selobj.Object for selobj in selEx]\n                coords = []\n                j = 0\n                if len(objs) >= 1:\n                    for obj in objs:\n                        #s = objs[0].Shape\n                        s = obj.Shape\n                        \n                        # boundBox\n                        boundBox_ = s.BoundBox\n                        boundBoxLX = boundBox_.XLength\n                        boundBoxLY = boundBox_.YLength\n                        boundBoxLZ = boundBox_.ZLength\n                        \n                        a = str(boundBox_)\n                        a,b = a.split('(')\n                        c = b.split(',')\n                        oripl_X = float(c[0])\n                        oripl_Y = float(c[1])\n                        oripl_Z = float(c[2])\n                        coords.append ([oripl_X+boundBox_.XLength/2, oripl_Y+boundBox_.YLength/2, oripl_Z+boundBox_.ZLength/2])\n                        App.Console.PrintMessage(str(boundBox_)+\"\\r\\n\")\n                        App.Console.PrintMessage(\"BBox           : \"+str(boundBox_.XLength)+\" x \"+str(boundBox_.YLength)+\" x \"+str(boundBox_.ZLength)+\"\\r\\n\")\n                        App.Console.PrintMessage(\"Base Pos       : \"+str(oripl_X)+\" x \"+str(oripl_Y)+\" x \"+str(oripl_Z)+\"\\r\\n\")\n                        App.Console.PrintMessage(\"Center Pos     : \"+str(oripl_X+boundBox_.XLength/2)+\" x \"+str(oripl_Y+boundBox_.YLength/2)+\" x \"+str(oripl_Z+boundBox_.ZLength/2)+\"\\r\\n\")\n                        App.Console.PrintMessage(\"Coords         : \"+str(coords[j])+\"\\r\\n\")\n                        if j>0:\n                            if cx==1:\n                                coordNx=coords[0][0]-coords[j][0]\n                            else:\n                                coordNx=0\n                            if cy==1:\n                                coordNy=coords[0][1]-coords[j][1]\n                            else:\n                                coordNy=0\n                            if cz==1:\n                                coordNz=coords[0][2]-coords[j][2]\n                            else:\n                                coordNz=0\n                            obj.Placement.move(App.Vector(coordNx,coordNy,coordNz))\n                            App.Console.PrintMessage(\"Moved     : \"+str(coordNx)+\" \"+str(coordNy)+\" \"+str(coordNz)+\"\\r\\n\")\n                        j=j+1\n                    \n                        App.Console.PrintMessage(\"_____________________\"+\"\\r\\n\")\n                        \n                    FreeCADGui.Selection.removeSelection(objs[0])\n                    FreeCADGui.ActiveDocument.getObject(objs[0].Name).Visibility=False\n                    FreeCADGui.ActiveDocument.getObject(objs[1].Name).Transparency=70\n                    App.ActiveDocument.recompute() \n            \n        else:\n            App.Console.PrintMessage(\"Select ONLY one single Face of object!\"+\"\\n\")\n    else:\n        App.Console.PrintMessage(\"Select ONLY one single Face of object!\"+\"\\n\")\nelse:\n    sayw(\"no document to work with\")   \n    #http://forum.freecadweb.org/viewtopic.php?t=4625",
    "url": "https://wiki.freecad.org/Macro_Easy_cutouts_for_Enclosure_Design",
    "raw_code_url": "",
    "wiki": "",
    "version": "0.25",
    "license": "",
    "date": "11.2016",
    "src_filename": "",
    "filename_from_url": "",
    "author": "maurice",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Easy_cutouts_for_Enclosure_Design_icon.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/7/71/Macro_Easy_cutouts_for_Enclosure_Design_icon.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "ExpandTreeItem",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro expands selected tree and all sub trees in the tree view.<br />If there is no selection, all trees are expanded.<br /><br />Macro version: 00.02<br />Last modified: 2019-07-25<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/9/94/Macro_ExpandTreeItem.svg\">ToolBar Icon</a><br />Author: wmayer, UR_<br /> ",
    "comment": "This macro expands selected tree and all sub trees in the tree view.",
    "code": "# -*- coding: utf-8 -*-\n#\n# Expands selected tree and all sub trees in the tree view.\n# if selected tree is already expanded this tree and all sub trees are collapsed True/False\n# if there is no selection all trees are expanded\n#\n__Title__    = \"Macro ExpandTreeItem\"\n__Author__   = \"wmayer, UR_\"\n__Version__  = \"00.02\"\n__Date__     = \"2019-07-25\"\n\nimport PySide\nfrom PySide import QtGui ,QtCore\nfrom PySide.QtGui import *\nfrom PySide.QtCore import *\n\ndef toggleAll(tree, item, collapse):\n    if collapse == False:\n        tree.expandItem(item)\n    elif collapse == True:  \n        tree.collapseItem(item)\n\n    for i in range(item.childCount()):\n        toggleAll(tree, item.child(i), collapse)\n\nmw = Gui.getMainWindow()\ntrees = mw.findChildren(QtGui.QTreeWidget)\n\nfor tree in trees:\n    items = tree.selectedItems()\n\n    try:\n        if items == []:\n            #tree.selectAll()                          # select all object\n            for obj in FreeCAD.ActiveDocument.Objects: # select obj.OutList\n                if len(obj.OutList) != 0:\n                    Gui.Selection.addSelection(obj)\n                    items = tree.selectedItems()\n            for item in items:\n                toggleAll(tree, item, False)\n    except Exception:\n        None\n\n    for item in items:\n            if item.isExpanded() == True:\n                toggleAll(tree, item, True)\n        #            print (\"collapsing\")\n            else:\n                toggleAll(tree, item, False)\n        #            print (\"expanding\")",
    "url": "https://wiki.freecad.org/Macro_ExpandTreeItem",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.02",
    "license": "",
    "date": "2019-07-25",
    "src_filename": "",
    "filename_from_url": "",
    "author": "wmayer, UR_",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_ExpandTreeItem.svg",
    "icon_source": "https://www.freecadweb.org/wiki/images/9/94/Macro_ExpandTreeItem.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "findConfigFiles",
    "on_wiki": true,
    "on_git": false,
    "desc": "Use this macro to find your user setting configuration files, that is,<br /><b>system.cfg</b><br /><b>user.cfg</b><br />These files can be renamed in order to reset FreeCAD's settings back to their original defaults. This can sometimes fix problems you are having with FreeCAD.<br />You should exit FreeCAD before renaming the files, and then open FreeCAD again afterwards. If renaming the files did not solve the issue you were having you can delete the new files FreeCAD created and rename the original files back to their original names in order to restore your previous settings. You can also safely delete the renamed files once you are certain you no longer need or want them, but it is recommended to rename them instead of deleting until you are certain they are no longer needed.<br />Note: The macro does not rename the files or make any changes to your settings. It merely finds the location of these files, copies that location to the clipboard, and (attempts to) open the folder containing these files on your computer using the default file browser.<br /><br />Macro version: 2022.03.15<br />Last modified: 2022-03-15<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/b/b5/Macro_findConfigFiles.png\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Use this macro to find your user setting configuration files, that is,",
    "code": "# -*- coding: utf-8 -*-\nimport FreeCAD\nimport subprocess, os \nfrom PySide import QtCore,QtGui\nimport platform \n__title__ = \"findConfigFiles\"\n__author__ = \"TheMarkster\"\n__url__ = \"https://www.freecadweb.org/wiki/Macro_findConfigFiles\"\n__Wiki__ = \"http://www.freecadweb.org/wiki/index.php?title=Macro_findConfigFiles\"\n__date__ = \"2022.03.15\" \n__version__ = __date__\n\n\n\"\"\"A macro to help with user configuration files --<TheMarkster>\"\"\"\n\nclipboard = QtGui.QApplication.clipboard()\nsys = platform.system()\nuserFolder = App.getUserConfigDir() if hasattr(App,\"getUserConfigDir\") else App.getUserAppDataDir()\n\nmsgBox = QtGui.QMessageBox()\nmsgBox.setWindowTitle('findConfigFiles macro')\nmsgBox.setTextFormat(QtCore.Qt.RichText)\n#msgBox.setStandardButtons(QtGui.QMessageBox.Ok.__or__(QtGui.QMessageBox.Cancel))\n#__or__() is deprecated in python 3.8 and the pipe symbol interferes with addon manager, so add buttons separately\nmsgBox.addButton(QtGui.QMessageBox.Ok)\nmsgBox.addButton(QtGui.QMessageBox.Cancel)\nmsgBox.addButton(\"Copy to Clipboard and Open\",QtGui.QMessageBox.ApplyRole)\n\n#HTML tags are part of the source -- do not edit\n#thanks to user C4e for help with the paragraph formatting\nmsg = \"\"\"\n These files are located here on your system:\n <p>\n    <b><font color = 'blue'>\"\"\" + userFolder + \"\"\"</font></b>\n </p>\n <p>\n This macro was created to support you in renaming the configuration files of your user application. \n This can <i>sometimes</i> correct some issues you are having using FreeCAD.\n If it doesn't work you can always go back and rename them back to their original names.\n </p>\n <p>\n To reset your configuration settings, exit FreeCAD and rename these 2 files:\n <ul>\n    <li><b><font color='blue'>system.cfg</font></b>\n    <li><b><font color = 'blue'>user.cfg</font></b>\n </ul>\n Rename them e.g. to user/system.cfg.backup or something similar.\n </p>\n <p>\n When you press OK the macro will attempt to open the folder location for you, but \n you might need to open it manually if this doesn't work.\n </p>\n <p>\n Renaming these files will reset <i>all</i> of your FreeCAD settings back to default.\n </p>\n <p>\n (This macro does <i>not</i> make any changes to these files or to your user settings.)</p>\n \"\"\"\n\n\nmsgBox.setText(msg)\nok = msgBox.exec_()\nif ok==0:\n    clipboard.setText(userFolder)\nif ok == QtGui.QMessageBox.Ok or ok==0:\n    if 'Windows' in sys:\n        subprocess.Popen('start explorer.exe '+userFolder, shell=True)\n    elif 'Linux' in sys:\n        os.system(\"xdg-open '%s'\" % userFolder)\n    elif 'Darwin' in sys:\n        subprocess.Popen([\"open\", userFolder])\n    else:\n        msgBox = QtGui.QMessageBox()\n        msg = \"We were unable to determine your platform, and thus cannot open your '+userFolder+' for you, but you can still do it manually.\\n\"\n        msgBox.exec_()",
    "url": "https://wiki.freecad.org/Macro_findConfigFiles",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_findConfigFiles",
    "version": "2022.03.15",
    "license": "",
    "date": "2022.03.15",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_findConfigFiles.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/b/b5/Macro_findConfigFiles.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "ForceRecompute",
    "on_wiki": true,
    "on_git": false,
    "desc": "This small macro forces a manual recompute of the model.<br />Sometimes the user applies changes to the model in FreeCAD.<br />But FreeCAD does not seem to recognize them.<br />(As of <span style=\"font-size:small;\"><a href=\"/Release_notes_0.17\" title=\"Release notes 0.17\">introduced in 0.17</a></span> the effect of this macro can be achieved through GUI. Right-click project in model tree view, and pick \"Mark to recompute\" from context menu. After that, press Recompute button.)<br /><br />Macro version: 1.0<br />Last modified: 2014-09-01<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/8/88/Force_Recompute.png\">ToolBar Icon</a><br />Author: shoogen<br /> ",
    "comment": "This small macro forces a manual recompute of the model.",
    "code": "# -*- coding: utf-8 -*-\n# Force Recompute\n# macro provided by shoogen\n\nimport FreeCAD\nfor obj in FreeCAD.ActiveDocument.Objects:\n obj.touch()\nFreeCAD.ActiveDocument.recompute()",
    "url": "https://wiki.freecad.org/Macro_ForceRecompute",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-09-01",
    "src_filename": "",
    "filename_from_url": "",
    "author": "shoogen",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Force_Recompute.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/8/88/Force_Recompute.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "If Selected Stay If Not Then Delete",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro delete all objects not selected.<br /><br />Macro version: 00.03b<br />Last modified: 2023-09-24<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/6/62/Macro_If_Selected_Stay_If_Not_Then_Delete.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "This macro delete all objects not selected.",
    "code": "import FreeCAD\nimport Draft\n# 16/06/2016, 21/02/2018, 22/09/2023, 24/09/2023\n# Macro_SelectVisible series\n__title__   = \"Macro_If_Selected_Stay_If_Not_Then_Delete\"\n__author__  = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__version__ = \"00.03b\"\n__date__    = \"24/09/2023\"\n\nApp = FreeCAD\ntry:\n    for ShapeNameObj in FreeCAD.ActiveDocument.Objects:\n        if str(ShapeNameObj) == \"<group object>\":\n            if len(Draft.get_group_contents(ShapeNameObj)) == 0:\n                App.ActiveDocument.removeObject(ShapeNameObj.Name)        # remove group not selecteds\n        else:\n            if Gui.Selection.isSelected(ShapeNameObj):\n                None\n            else:\n                App.ActiveDocument.removeObject(ShapeNameObj.Name)        # remove objects not selecteds\n    \n    for ShapeNameGroup in FreeCAD.ActiveDocument.Objects:\n        if (str(ShapeNameGroup) == \"<group object>\"):\n            if len(Draft.get_group_contents(ShapeNameGroup)) == 0:\n                App.ActiveDocument.removeObject(ShapeNameGroup.Name)      # remove group emptied\nexcept Exception:\n    None",
    "url": "https://wiki.freecad.org/Macro_If_Selected_Stay_If_Not_Then_Delete",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.03b",
    "license": "",
    "date": "24/09/2023",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_If_Selected_Stay_If_Not_Then_Delete.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/6/62/Macro_If_Selected_Stay_If_Not_Then_Delete.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "ImperialScales",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro shows a list of US Imperial Arch scales list with the corresponding factor to apply to TechDraw pages or views<br /><br />Macro version: 0.1<br />Last modified: 2021-06-01<br />FreeCAD version: 0.18+<br />Author: Yorik<br /> ",
    "comment": "This macro shows a list of US Imperial Arch scales list with the corresponding factor to apply to TechDraw pages or views",
    "code": "# -*- coding: utf-8 -*-\n\nfrom PySide2.QtCore import *\nfrom PySide2.QtGui import *\nfrom PySide2.QtWidgets import *\n\nclass Dialog(QDialog):\n\n    def __init__(self):\n\n        QDialog.__init__(self)\n        self.resize(221, 413)\n        self.verticalLayout = QVBoxLayout(self)\n        self.tableWidget = QTableWidget(self)\n        self.tableWidget.setColumnCount(1)\n        qtablewidgetitem = QTableWidgetItem()\n        qtablewidgetitem.setTextAlignment(Qt.AlignHCenter|Qt.AlignVCenter|Qt.AlignCenter)\n        self.tableWidget.setHorizontalHeaderItem(0, qtablewidgetitem)\n        self.tableWidget.setRowCount(11)\n        qtablewidgetitem1 = QTableWidgetItem()\n        self.tableWidget.setVerticalHeaderItem(0, qtablewidgetitem1)\n        qtablewidgetitem2 = QTableWidgetItem()\n        self.tableWidget.setVerticalHeaderItem(1, qtablewidgetitem2)\n        qtablewidgetitem3 = QTableWidgetItem()\n        self.tableWidget.setVerticalHeaderItem(2, qtablewidgetitem3)\n        qtablewidgetitem4 = QTableWidgetItem()\n        self.tableWidget.setVerticalHeaderItem(3, qtablewidgetitem4)\n        qtablewidgetitem5 = QTableWidgetItem()\n        self.tableWidget.setVerticalHeaderItem(4, qtablewidgetitem5)\n        qtablewidgetitem6 = QTableWidgetItem()\n        self.tableWidget.setVerticalHeaderItem(5, qtablewidgetitem6)\n        qtablewidgetitem7 = QTableWidgetItem()\n        self.tableWidget.setVerticalHeaderItem(6, qtablewidgetitem7)\n        qtablewidgetitem8 = QTableWidgetItem()\n        self.tableWidget.setVerticalHeaderItem(7, qtablewidgetitem8)\n        qtablewidgetitem9 = QTableWidgetItem()\n        self.tableWidget.setVerticalHeaderItem(8, qtablewidgetitem9)\n        qtablewidgetitem10 = QTableWidgetItem()\n        self.tableWidget.setVerticalHeaderItem(9, qtablewidgetitem10)\n        qtablewidgetitem11 = QTableWidgetItem()\n        self.tableWidget.setVerticalHeaderItem(10, qtablewidgetitem11)\n        qtablewidgetitem12 = QTableWidgetItem()\n        qtablewidgetitem12.setTextAlignment(Qt.AlignHCenter|Qt.AlignVCenter|Qt.AlignCenter)\n        self.tableWidget.setItem(0, 0, qtablewidgetitem12)\n        qtablewidgetitem13 = QTableWidgetItem()\n        qtablewidgetitem13.setTextAlignment(Qt.AlignHCenter|Qt.AlignVCenter|Qt.AlignCenter)\n        self.tableWidget.setItem(1, 0, qtablewidgetitem13)\n        qtablewidgetitem14 = QTableWidgetItem()\n        qtablewidgetitem14.setTextAlignment(Qt.AlignHCenter|Qt.AlignVCenter|Qt.AlignCenter)\n        self.tableWidget.setItem(2, 0, qtablewidgetitem14)\n        qtablewidgetitem15 = QTableWidgetItem()\n        qtablewidgetitem15.setTextAlignment(Qt.AlignHCenter|Qt.AlignVCenter|Qt.AlignCenter)\n        self.tableWidget.setItem(3, 0, qtablewidgetitem15)\n        qtablewidgetitem16 = QTableWidgetItem()\n        qtablewidgetitem16.setTextAlignment(Qt.AlignHCenter|Qt.AlignVCenter|Qt.AlignCenter)\n        self.tableWidget.setItem(4, 0, qtablewidgetitem16)\n        qtablewidgetitem17 = QTableWidgetItem()\n        qtablewidgetitem17.setTextAlignment(Qt.AlignHCenter|Qt.AlignVCenter|Qt.AlignCenter)\n        self.tableWidget.setItem(5, 0, qtablewidgetitem17)\n        qtablewidgetitem18 = QTableWidgetItem()\n        qtablewidgetitem18.setTextAlignment(Qt.AlignHCenter|Qt.AlignVCenter|Qt.AlignCenter)\n        self.tableWidget.setItem(6, 0, qtablewidgetitem18)\n        qtablewidgetitem19 = QTableWidgetItem()\n        qtablewidgetitem19.setTextAlignment(Qt.AlignHCenter|Qt.AlignVCenter|Qt.AlignCenter)\n        self.tableWidget.setItem(7, 0, qtablewidgetitem19)\n        qtablewidgetitem20 = QTableWidgetItem()\n        qtablewidgetitem20.setTextAlignment(Qt.AlignHCenter|Qt.AlignVCenter|Qt.AlignCenter)\n        self.tableWidget.setItem(8, 0, qtablewidgetitem20)\n        qtablewidgetitem21 = QTableWidgetItem()\n        qtablewidgetitem21.setTextAlignment(Qt.AlignHCenter|Qt.AlignVCenter|Qt.AlignCenter)\n        self.tableWidget.setItem(9, 0, qtablewidgetitem21)\n        qtablewidgetitem22 = QTableWidgetItem()\n        qtablewidgetitem22.setTextAlignment(Qt.AlignHCenter|Qt.AlignVCenter|Qt.AlignCenter)\n        self.tableWidget.setItem(10, 0, qtablewidgetitem22)\n        self.tableWidget.setEditTriggers(QAbstractItemView.AnyKeyPressed|QAbstractItemView.DoubleClicked|QAbstractItemView.EditKeyPressed)\n        self.tableWidget.horizontalHeader().setVisible(True)\n        self.tableWidget.verticalHeader().setVisible(True)\n\n        self.verticalLayout.addWidget(self.tableWidget)\n\n        self.buttonBox = QDialogButtonBox(self)\n        self.buttonBox.setOrientation(Qt.Horizontal)\n        self.buttonBox.setStandardButtons(QDialogButtonBox.Ok)\n\n        self.verticalLayout.addWidget(self.buttonBox)\n\n        self.retranslateUi()\n        self.buttonBox.accepted.connect(self.accept)\n        self.buttonBox.rejected.connect(self.reject)\n\n        QMetaObject.connectSlotsByName(self)\n\n    def retranslateUi(self,dlg=None):\n\n        self.setWindowTitle(QCoreApplication.translate(\"Dialog\", u\"Arch scale factors\", None))\n        qtablewidgetitem = self.tableWidget.horizontalHeaderItem(0)\n        qtablewidgetitem.setText(QCoreApplication.translate(\"Dialog\", u\"Factor\", None))\n        qtablewidgetitem1 = self.tableWidget.verticalHeaderItem(0)\n        qtablewidgetitem1.setText(QCoreApplication.translate(\"Dialog\", u\"1/16\\\" = 1'-0\\\"\", None))\n        qtablewidgetitem2 = self.tableWidget.verticalHeaderItem(1)\n        qtablewidgetitem2.setText(QCoreApplication.translate(\"Dialog\", u\"3/32\\\" = 1'-0\\\"\", None))\n        qtablewidgetitem3 = self.tableWidget.verticalHeaderItem(2)\n        qtablewidgetitem3.setText(QCoreApplication.translate(\"Dialog\", u\"1/8\\\" = 1'-0\\\"\", None))\n        qtablewidgetitem4 = self.tableWidget.verticalHeaderItem(3)\n        qtablewidgetitem4.setText(QCoreApplication.translate(\"Dialog\", u\"3/16\\\" = 1'-0\\\"\", None))\n        qtablewidgetitem5 = self.tableWidget.verticalHeaderItem(4)\n        qtablewidgetitem5.setText(QCoreApplication.translate(\"Dialog\", u\"1/4\\\" = 1'-0\\\"\", None))\n        qtablewidgetitem6 = self.tableWidget.verticalHeaderItem(5)\n        qtablewidgetitem6.setText(QCoreApplication.translate(\"Dialog\", u\"3/8\\\" = 1'-0\\\"\", None))\n        qtablewidgetitem7 = self.tableWidget.verticalHeaderItem(6)\n        qtablewidgetitem7.setText(QCoreApplication.translate(\"Dialog\", u\"1/2\\\" = 1'-0\\\"\", None))\n        qtablewidgetitem8 = self.tableWidget.verticalHeaderItem(7)\n        qtablewidgetitem8.setText(QCoreApplication.translate(\"Dialog\", u\"3/4\\\" = 1'-0\\\"\", None))\n        qtablewidgetitem9 = self.tableWidget.verticalHeaderItem(8)\n        qtablewidgetitem9.setText(QCoreApplication.translate(\"Dialog\", u\"1\\\" = 1'-0\\\"\", None))\n        qtablewidgetitem10 = self.tableWidget.verticalHeaderItem(9)\n        qtablewidgetitem10.setText(QCoreApplication.translate(\"Dialog\", u\"1 1/2\\\" = 1'-0\\\"\", None))\n        qtablewidgetitem11 = self.tableWidget.verticalHeaderItem(10)\n        qtablewidgetitem11.setText(QCoreApplication.translate(\"Dialog\", u\"3\\\" = 1'-0\\\"\", None))\n\n        sortingEnabled = self.tableWidget.isSortingEnabled()\n        self.tableWidget.setSortingEnabled(False)\n        qtablewidgetitem12 = self.tableWidget.item(0, 0)\n        qtablewidgetitem12.setText(QCoreApplication.translate(\"Dialog\", u\"1/192\", None))\n        qtablewidgetitem13 = self.tableWidget.item(1, 0)\n        qtablewidgetitem13.setText(QCoreApplication.translate(\"Dialog\", u\"1/128\", None))\n        qtablewidgetitem14 = self.tableWidget.item(2, 0)\n        qtablewidgetitem14.setText(QCoreApplication.translate(\"Dialog\", u\"1/96\", None))\n        qtablewidgetitem15 = self.tableWidget.item(3, 0)\n        qtablewidgetitem15.setText(QCoreApplication.translate(\"Dialog\", u\"1/64\", None))\n        qtablewidgetitem16 = self.tableWidget.item(4, 0)\n        qtablewidgetitem16.setText(QCoreApplication.translate(\"Dialog\", u\"1/48\", None))\n        qtablewidgetitem17 = self.tableWidget.item(5, 0)\n        qtablewidgetitem17.setText(QCoreApplication.translate(\"Dialog\", u\"1/32\", None))\n        qtablewidgetitem18 = self.tableWidget.item(6, 0)\n        qtablewidgetitem18.setText(QCoreApplication.translate(\"Dialog\", u\"1/24\", None))\n        qtablewidgetitem19 = self.tableWidget.item(7, 0)\n        qtablewidgetitem19.setText(QCoreApplication.translate(\"Dialog\", u\"1/16\", None))\n        qtablewidgetitem20 = self.tableWidget.item(8, 0)\n        qtablewidgetitem20.setText(QCoreApplication.translate(\"Dialog\", u\"1/12\", None))\n        qtablewidgetitem21 = self.tableWidget.item(9, 0)\n        qtablewidgetitem21.setText(QCoreApplication.translate(\"Dialog\", u\"1/8\", None))\n        qtablewidgetitem22 = self.tableWidget.item(10, 0)\n        qtablewidgetitem22.setText(QCoreApplication.translate(\"Dialog\", u\"1/4\", None))\n        self.tableWidget.setSortingEnabled(sortingEnabled)\n\ndlg = Dialog()\ndlg.show()\n",
    "url": "https://wiki.freecad.org/Macro_ImperialScales",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2021-06-01",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Yorik",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "merge duplicate materials",
    "on_wiki": true,
    "on_git": false,
    "desc": "Merges materials that have the same base name (with different numeral endings like 001, 002,...) into one. Only the first one will be kept, and all the objects that link to the duplicates will be linking to the first one instead. So before using this macro, make sure your first material (either the one without numerical ending or the lowest number found) is the right one.<br /><br />Macro version: 2.0<br />Last modified: 20197-07-12<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/e/ed/Macro_merge_duplicate_materials.png\">ToolBar Icon</a><br />Author: yorik<br /> ",
    "comment": "Merges materials that have the same base name (with different numeral endings like 001, 002,...) into one. Only the first one will be kept, and all the objects that link to the duplicates will be linking to the first one instead. So before using this macro, make sure your first material (either the one without numerical ending or the lowest number found) is the right one.",
    "code": "import FreeCAD,FreeCADGui\nmats = [o for o in FreeCAD.ActiveDocument.Objects if o.isDerivedFrom(\"App::MaterialObject\")]\ntodelete = []\nfor mat in mats:\n    if mat.Label[-1].isdigit() and mat.Label[-2].isdigit() and mat.Label[-3].isdigit():\n        orig = None\n        for om in mats:\n            if om.Label == mat.Label[:-3].strip():\n                orig = om\n                break\n        if orig:\n            for par in mat.InList:\n                for prop in par.PropertiesList:\n                    if getattr(par,prop) == mat:\n                        print( \"Changed property '\"+prop+\"' of object \"+par.Label+\" from \"+mat.Label+\" to \"+orig.Label)\n                        setattr(par,prop,orig)\n            todelete.append(mat)\nfor tod in todelete:\n    if not tod.InList:\n        print( \"Deleting material \"+tod.Label)\n        FreeCAD.ActiveDocument.removeObject(tod.Name)\n    elif (len(tod.InList) == 1) and (tod.InList[0].isDerivedFrom(\"App::DocumentObjectGroup\")):\n        print( \"Deleting material \"+tod.Label)\n        FreeCAD.ActiveDocument.removeObject(tod.Name)\n    else:\n        print( \"Unable to delete material \"+tod.Label+\": InList not empty\")",
    "url": "https://wiki.freecad.org/Macro_merge_duplicate_materials",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "20197-07-12",
    "src_filename": "",
    "filename_from_url": "",
    "author": "yorik",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_merge_duplicate_materials.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/e/ed/Macro_merge_duplicate_materials.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "PCBWay",
    "on_wiki": true,
    "on_git": false,
    "desc": "Sends a selected object to PCBWay for manufacturing through CNC milling, laser cutting or 3D printing.<br /><br />Macro version: 1.0<br />Last modified: 2022-07-22<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/images/7/7b/Pcbway.png\">ToolBar Icon</a><br />Author: Yorik van Havre<br /> ",
    "comment": "Sends a selected object to PCBWay for manufacturing through CNC milling, laser cutting or 3D printing.",
    "code": "#***************************************************************************\n#*                                                                         *\n#*   Copyright (c) 2022 Yorik van Havre <yorik@uncreated.net>              *\n#*                                                                         *\n#*   This program is free software; you can redistribute it and/or modify  *\n#*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n#*   as published by the Free Software Foundation; either version 2 of     *\n#*   the License, or (at your option) any later version.                   *\n#*   for detail see the LICENCE text file.                                 *\n#*                                                                         *\n#*   This program is distributed in the hope that it will be useful,       *\n#*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n#*   GNU Library General Public License for more details.                  *\n#*                                                                         *\n#*   You should have received a copy of the GNU Library General Public     *\n#*   License along with this program; if not, write to the Free Software   *\n#*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n#*   USA                                                                   *\n#*                                                                         *\n#***************************************************************************\n\n\"\"\"\nPCBWay Macro for FreeCAD\n\nhttps://pcbway.com\n\nThis macro sends the currently selected object to the PCBWay website\nto get an instant quote for manufacturing. After the object is sent,\na page will be opened on the PCBWay website to allow the user to adjust\ndetails and options.\n\"\"\"\n\n# code inspired / borrowed from:\n# KiCAD PcbWay plugin: https://github.com/pcbway/PCBWay-Plug-in-for-Kicad/blob/main/plugins/thread.py\n# urllib-based upload: http://pymotw.com/2/urllib2/#uploading-files\n# mime stuff: https://stackoverflow.com/questions/27099290/where-is-mimetools-choose-boundary-function-in-python3#27174474\n\n# version history:\n# version 1.0 - 2022.07.22\n\n__title__   = \"Macro_PCBWay\"\n__author__  = \"Yorik van Havre\"\n__wiki__    = \"https://www.freecad.org/wiki/Macro_PCBWay\"\n__url__     = \"https://www.pcbway.com\"\n__version__ = \"1.0\"\n__date__    = \"22/07/2022\"\n\n\nimport tempfile\nimport os\nimport FreeCAD\nimport FreeCADGui\nimport json\nimport webbrowser\nimport urllib.request\nimport urllib.parse\nimport email.generator\nimport itertools\n\n\npcb_url = \"https://www.pcbway.com/common/freecadupfile\"\n\n\ndef msg(message):\n\n    \"\"\"prints a message where appropriate\"\"\"\n\n    FreeCAD.Console.PrintError(message+\"\\n\")\n    if FreeCAD.GuiUp:\n        from PySide import QtGui\n        reply = QtGui.QMessageBox.critical(None,\"PCBWay export\",message)\n\n\nclass MultiPartData(object):\n\n    \"\"\"Gathers data and files to be sent via HTTP POST\"\"\"\n\n    def __init__(self):\n        self.form_fields = []\n        self.files = []\n        self.boundary = email.generator._make_boundary()\n        self.add_field(\"Unit\",\"Millimeter\") #FreeCAD's boundboxes are always in mm\n        return\n\n    def get_content_type(self):\n        return 'multipart/form-data; boundary=%s' % self.boundary\n\n    def add_field(self, name, value):\n        \"\"\"Add a simple field to the form data.\"\"\"\n        self.form_fields.append((name, str(value)))\n        return\n\n    def add_file(self, fieldname, filename, fileHandle, mime):\n        \"\"\"Add a file to be uploaded.\"\"\"\n        body = fileHandle.read()\n        self.files.append((fieldname, filename, mime, body))\n        return\n\n    def get_bytes(self):\n        \"\"\"Return a string representing the form data, including attached files.\"\"\"\n        parts = []\n        part_boundary = '--' + self.boundary\n        parts.extend([part_boundary,'Content-Disposition: form-data; name=\"%s\"' % name,'',value] for name, value in self.form_fields)\n        parts.extend([part_boundary,'Content-Disposition: file; name=\"%s\"; filename=\"%s\"' % (field_name, filename),\n                                    'Content-Type: %s' % content_type,'',body] for field_name, filename, content_type, body in self.files)\n        flattened = list(itertools.chain(*parts))\n        flattened.append('--' + self.boundary + '--')\n        flattened.append('')\n        return bytes('\\r\\n'.join(flattened),'utf8')\n\n\ndef main():\n\n    # validity tests\n    mesh = None\n    shape = None\n    if not FreeCAD.GuiUp:\n        return\n    if not FreeCAD.ActiveDocument:\n        msg(\"There is no opened document. Please open or create a document containing objects before running this macro.\")\n        return\n    # get the selected object, or the only visible body or object if nothing is selected\n    selection = FreeCADGui.Selection.getSelection()\n    if not selection:\n        visibles = [obj for obj in FreeCAD.ActiveDocument.Objects if obj.ViewObject.Visibility]\n        if len(visibles) == 1:\n            obj = visibles[0]\n            if hasattr(obj,\"Shape\"):\n                shape = obj.Shape\n            elif hasattr(obj,\"Mesh\"):\n                mesh = obj.Mesh\n        elif len(visibles) > 1:\n            bodies = [obj for obj in visibles if obj.isDerivedFrom(\"PartDesign::Body\")]\n            if len(bodies) == 1:\n                shape = bodies[0].Shape\n            else:\n                msg(\"No object is selected. Please select one object or body before running this macro.\")\n                return\n    elif len(selection) > 1:\n        msg(\"More than one object is selected. Please select only one object or body before running this macro.\")\n        return\n    else:\n        obj = selection[0]\n        if hasattr(obj,\"Shape\"):\n            shape = obj.Shape\n            if (not shape) or (not hasattr(shape,\"isNull\")) or shape.isNull():\n                msg(\"The selected object has no shape. Please select an object with a shape before running this macro.\")\n                return\n        elif hasattr(obj,\"Mesh\"):\n            mesh = obj.Mesh\n    if (not shape) and (not mesh):\n        msg(\"Unable to find a suitable shape in the selection or in the visible objects. Please select an object before running this macro.\")\n        return\n\n    # offer to add the macro as a button on first run\n    # not working yet!\n    # prefs = FreeCAD.ParamGet(\"User parameter:Plugins/PCBWay\")\n    # if prefs.GetBool(\"FirstTime\",True):\n    #    prefs.SetBool(\"FirstTime\",False)\n    #    from PySide import QtGui\n    #    reply = QtGui.QMessageBox.question(None, \"Install macro?\",\n    #        \"This is the first time you are launching the PCBWay macro. Do you wish to add a toolbar button for it?\",\n    #        QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)\n    #    if reply == QtGui.QMessageBox.Yes:\n    #        icon = \"https://github.com/pcbway/PCBWay-Plug-in-for-Kicad/raw/main/resources/icon.png\"\n    #        u = urllib.request.urlopen(icon)\n    #        idata = u.read()\n    #        u.close()\n    #        idir = os.path.join(FreeCAD.getUserAppDataDir(),\"icons\")\n    #        os.makedirs(idir,exist_ok=False)\n    #        f = open(os.path.join(idir,\"pcbway.png\"),\"wb\")\n    #        f.write(idata)\n    #        f.close()\n\n    if shape:\n        # saving the file as step\n        tf = tempfile.NamedTemporaryFile(suffix=\".stp\")\n        tf.close()\n        shape.exportStep(tf.name)\n        bb = shape.BoundBox\n        mime = \"application/STEP\"\n    elif mesh:\n        # saving the file as step\n        tf = tempfile.NamedTemporaryFile(suffix=\".obj\")\n        tf.close()\n        mesh.write(tf.name)\n        bb = mesh.BoundBox\n        mime = \"model/obj\"\n\n    # prepare and upload data\n    data = MultiPartData()\n    data.add_field('Length', bb.XLength)\n    data.add_field('Width',  bb.YLength)\n    data.add_field('Height', bb.ZLength)\n    data.add_file('upload[file]', os.path.basename(tf.name), open(tf.name,'r'), mime)\n    request = urllib.request.Request(pcb_url)\n    request.add_header('User-agent', 'FreeCAD (https://freecad.org)')\n    body = data.get_bytes()\n    request.add_header('Content-type', data.get_content_type())\n    request.add_header('Content-length', len(body))\n    rsp = urllib.request.urlopen(request,data=body).read()\n    rsp_link = json.loads(rsp.decode('utf8'))['redirect']\n\n    # get the respnse and open a link\n    webbrowser.open(rsp_link)\n\n\n\n# run when macro is launched\nmain()\n\n",
    "url": "https://wiki.freecad.org/Macro_PCBWay",
    "raw_code_url": "https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/master/Utility/pcbway.FCMacro",
    "wiki": "https://www.freecad.org/wiki/Macro_PCBWay",
    "version": "1.0",
    "license": "",
    "date": "22/07/2022",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Yorik van Havre",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Pcbway.png",
    "icon_source": "https://wiki.freecadweb.org/images/7/7b/Pcbway.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Pinger",
    "on_wiki": true,
    "on_git": false,
    "desc": "Use this macro to easily ping users on the FreeCAD forum. Select the user from the combo box, click Ping, paste code into the forum post. You may add new users.<br /><br />Macro version: 1.81<br />Last modified: 2022.03.28<br />FreeCAD version: 0.19<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/images/6/67/Pinger_Icon.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Use this macro to easily ping users on the FreeCAD forum. Select the user from the combo box, click Ping, paste code into the forum post. You may add new users.",
    "code": "# -*- coding: utf-8 -*-\n## Pinger macro v1.8\n## By: TheMarkster\n#  2022.03.28\n## Aids in pinging users on the forum\n## Select the user from the list and paste clipboard contents into the forum\n__version__ = \"1.81\"\nfrom PySide import QtGui,QtCore\nimport FreeCADGui as Gui\nimport FreeCAD\nimport json\n\n#werner's code to get about info\nclass AboutInfo(QtCore.QObject):\n    def __init__(self):\n        super(AboutInfo, self).__init__()\n\n    def eventFilter(self, obj, ev):\n        if obj.metaObject().className() == \"Gui::Dialog::AboutDialog\" and\\\n        ev.type() == ev.ChildPolished and\\\n        hasattr(obj, 'on_copyButton_clicked'):\n            obj.on_copyButton_clicked()\n            QtGui.QApplication.instance().postEvent(obj, QtGui.QCloseEvent())\n        return False\n\nclass PingerDlg:\n    def __init__(self,parent=Gui.getMainWindow()):\n        self.dict1 = {}\n        self.setupDict1()\n        self.pg = FreeCAD.ParamGet(\"User parameter:Plugins/Pinger\")\n        self.addedDict = {}\n        self.fetchAdded() #updates self.addedDict\n        self.fullDict = {}\n        self.recentDict = {}\n        self.cbUsers = QtGui.QComboBox()\n        self.cbUsers.setEditable(True)\n        self.cbUsers.lineEdit().returnPressed.connect(self.onReturnPressed)\n        self.cbUsers.setToolTip(\"Type in a new name to add a new user, then click Ping/Add or press Enter.\")\n        self.form = QtGui.QDialog(parent, QtCore.Qt.Tool)\n        self.form.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)\n        self.form.setWindowTitle(\"Pinger v\"+__version__)\n        self.form.setWindowIcon(QIconFromXPMString(__icon__))\n        self.layout = QtGui.QVBoxLayout()\n        self.form.setLayout(self.layout)\n        topLine = QtGui.QHBoxLayout()\n        iconBtn = QtGui.QPushButton()\n        iconBtn.setIcon(QIconFromXPMString(__icon__))\n        iconBtn.clicked.connect(self.information)\n        topLine.addWidget(iconBtn)\n        iconBtn.setMaximumWidth(48)\n        self.layout.addLayout(topLine)\n        usersLabel = QtGui.QLabel(\"Users: \")\n        usersLabel.setMaximumWidth(100)\n        topLine.addWidget(usersLabel)\n        topLine.addWidget(self.cbUsers)\n        self.pingBtn = QtGui.QPushButton(\"Ping/Add\")\n        self.pingBtn.setToolTip(\"Ping this user or add the user if not already in database.\")\n        topLine.addWidget(self.pingBtn)\n        self.pingBtn.clicked.connect(self.onPingBtnClicked)\n        secondLine = QtGui.QHBoxLayout()\n        self.layout.addLayout(secondLine)\n        self.aboutBtn = QtGui.QPushButton(\"About info\")\n        self.aboutBtn.setToolTip(\"Copy FreeCAD about information to clipboard\")\n        self.aboutBtn.clicked.connect(self.getAboutInfo)\n        secondLine.addWidget(self.aboutBtn)\n        self.editBtn = QtGui.QPushButton(\"Edit user id\")\n        self.editBtn.clicked.connect(self.onEditBtnClicked)\n        secondLine.addWidget(self.editBtn)\n        self.delBtn = QtGui.QPushButton(\"Remove user\")\n        self.delBtn.setToolTip(\"Remove user from added user list\")\n        self.delBtn.clicked.connect(self.onDelBtnClicked)\n        secondLine.addWidget(self.delBtn)\n        self.sortCheckBox = QtGui.QCheckBox(\"Sorted\")\n        secondLine.addWidget(self.sortCheckBox)\n        self.sortCheckBox.stateChanged.connect(self.populateUsers)\n        self.msgBox = QtGui.QPlainTextEdit()\n        self.layout.addWidget(self.msgBox)\n        recentLine = QtGui.QHBoxLayout()\n        self.recentList = QtGui.QComboBox()\n        self.recentList.setMinimumWidth(175)\n        recentLine.addWidget(QtGui.QLabel(\"Recents:\"))\n        recentLine.addWidget(self.recentList)\n        self.layout.addLayout(recentLine)\n        self.recentPingBtn = QtGui.QPushButton(\"Ping\")\n        self.recentPingBtn.clicked.connect(self.onRecentPingBtnClicked)\n        recentLine.addWidget(self.recentPingBtn)\n        self.removeUserFromRecentBtn = QtGui.QPushButton(\"Remove user\")\n        self.removeUserFromRecentBtn.clicked.connect(self.onRemoveUserFromRecentBtnClicked)\n        self.removeUserFromRecentBtn.setToolTip(\"Remove this user from recent list\")\n        recentLine.addWidget(self.removeUserFromRecentBtn)\n        self.removeAllUsersFromRecentBtn = QtGui.QPushButton(\"Remove all\")\n        self.removeAllUsersFromRecentBtn.setToolTip(\"Remove all users from recent list\")\n        self.removeAllUsersFromRecentBtn.clicked.connect(self.onRemoveAllUsersFromRecentBtnClicked)\n        recentLine.addWidget(self.removeAllUsersFromRecentBtn)\n        self.populateUsers()\n\n    def onRecentPingBtnClicked(self, arg1):\n        curRecent = self.recentList.currentText()\n        if not curRecent:\n            self.msg(\"Recent users is empty\",\"Error\")\n            return\n        self.cbUsers.setCurrentText(curRecent)\n        self.onPingBtnClicked(True)\n\n    def onRemoveUserFromRecentBtnClicked(self, arg1):\n        curRecent = self.recentList.currentText()\n        if not curRecent:\n            self.msg(\"Recent users is empty\",\"Error\")\n            return\n        self.recentDict.pop(curRecent)\n        jstring = json.dumps(self.recentDict)\n        self.pg.SetString(\"RecentUsers\",jstring)\n        self.populateUsers()\n\n    def onRemoveAllUsersFromRecentBtnClicked(self, arg1):\n        self.recentDict = {}\n        self.pg.SetString(\"RecentUsers\",\"{}\")\n        self.populateUsers()\n\n    def msg(self, txt, msgType=\"Message\"):\n        if msgType == \"Message\":\n            self.msgBox.setStyleSheet(\"color:black\")\n        elif msgType == \"Error\":\n            self.msgBox.setStyleSheet(\"color:red\")\n        elif msgType == \"Warning\":\n            self.msgBox.setStyleSheet(\"color:yellow\")\n        self.msgBox.setPlainText(txt)\n\n    def buildFullDict(self):\n        self.fullDict = {}\n        defaultUsers = [k for k in self.dict1.keys()]\n        self.fetchAdded()\n        self.fetchRecent()\n        addedUsers = [k for k in self.addedDict.keys()]\n        for k,v in self.addedDict.items():\n            self.fullDict[k] = v\n        for k,v in self.dict1.items():\n            self.fullDict[k] = v\n\n\n\n    def populateUsers(self):\n        self.buildFullDict()\n        self.cbUsers.clear()\n        self.cbUsers.addItem('--select user--')\n        if self.sortCheckBox.checkState():\n            self.cbUsers.addItems(sorted(self.fullDict))\n        else:\n            self.cbUsers.addItems(list(self.fullDict))\n        self.fetchRecent()\n        self.recentList.clear()\n        self.recentList.addItems(list(self.recentDict))\n\n    def fetchAdded(self):\n        addedStr = self.pg.GetString(\"AddedUsers\",\"{}\")\n        self.addedDict = json.loads(addedStr)\n\n    def fetchRecent(self):\n        recentStr = self.pg.GetString(\"RecentUsers\",\"{}\")\n        self.recentDict = json.loads(recentStr)\n\n    def addUser(self, username):\n        self.fetchAdded()\n        self.fetchRecent()\n        curId =\"\"\n        if username in self.addedDict:\n            curId = self.addedDict[username]\n        id,ok = QtGui.QInputDialog.getText(self.form,\"Add/Edit user\",f\"Enter user id for {username}:\",text=curId)\n        if not ok:\n            return False\n        try:\n            id_int = int(id)\n        except ValueError as ve:\n            self.msg(f\"{ve}\",\"Error\")\n            return False\n        self.addedDict[username] = id\n        self.recentDict[username] = id\n        jstring = json.dumps(self.addedDict)\n        self.pg.SetString(\"AddedUsers\",jstring)\n        jstring = json.dumps(self.recentDict)\n        self.pg.SetString(\"RecentUsers\",jstring)\n        self.buildFullDict()\n        self.populateUsers()\n        return True\n\n    def information(self):\n        self.msg(\"Pinger macro is to help in pinging users on the FreeCAD forum.\\n\\\nUsage: select a user, click Ping/Add button, paste text from clipboard into forum\\n\\n\\\nTo add a new user: type in the new name, click Ping/Add button.\\n\\n\\\nClick About info button to copy your FreeCAD version information to the clipboard.\\n\\n\\\nOnly added users may be edited or removed.\\n\\n\\\nSorted checkbox sorts the users alphabetically.  \\\nAdded users are at the top of the list when not sorted, then according to number of posts.\\n\\n\\\nOnly users with 100+ posts (at the time the database was updated) are guaranteed to appear in the list.\\n\\\n\")\n\n    def onDelBtnClicked(self, arg1):\n        username = self.cbUsers.currentText()\n        if not username in self.addedDict:\n            self.msg(f\"{username} is not an added user, cannot be deleted\",\"Error\")\n            return\n        self.addedDict.pop(username)\n        jstring = json.dumps(self.addedDict)\n        self.pg.SetString(\"AddedUsers\",jstring)\n        if username in self.recentDict:\n            self.recentDict.pop(username)\n            jstring = json.dumps(self.recentDict)\n            self.pg.SetString(\"RecentUsers\",jstring)\n        self.cbUsers.clear()\n        self.populateUsers()\n        self.msg(f\"{username} has been removed from added users\",\"Message\")\n\n    def onReturnPressed(self):\n        self.onPingBtnClicked(True)\n\n    def onEditBtnClicked(self, arg1):\n        username = self.cbUsers.currentText()\n        if not username in self.dict1: #adding edits addedusers only\n            if not self.addUser(username):\n                return\n        else:\n            self.msg(f\"{username} is in default dictionary, cannot be edited\",\"Error\")\n            return\n\n    def onPingBtnClicked(self, arg1):\n        username = self.cbUsers.currentText()\n        if username == '--select user--':\n            return\n        if not username in self.fullDict:\n            if not self.addUser(username):\n                return\n        ping = \"[quote=\"+username+\" user_id=\"+self.fullDict[username]+\"]\\npinged by pinger macro\\n[/quote]\"\n        self.setClipText(ping)\n        self.msg(\"Success!\\n\\nNow copied to clipboard: \\n\\n\"+ping)\n        self.form.setFocus()\n        self.fetchRecent()\n        if not username in self.recentDict:\n            self.recentDict[username] = self.fullDict[username]\n            jstring = json.dumps(self.recentDict)\n            self.pg.SetString(\"RecentUsers\",jstring)\n            self.populateUsers()\n        #self.form.close()\n\n    def getClipText(self):\n        clip = QtGui.QClipboard()\n        return clip.text(QtGui.QClipboard.Clipboard)\n\n    def setClipText(self,txt):\n        clip = QtGui.QClipboard()\n        clip.setText(txt)\n\n    def getAboutInfo(self):\n        ai=AboutInfo()\n        QtGui.QApplication.instance().installEventFilter(ai)\n        Gui.runCommand(\"Std_About\")\n        QtGui.QApplication.instance().removeEventFilter(ai)\n        del ai\n        clipText = self.getClipText()\n        self.msg(f\"Success!  Following now copied to clipboard:\\n\\n{clipText}\")\n        self.form.setFocus()\n\n    def setupDict1(self):\n        self.dict1 = {'chrisb': '5646', 'NormandC': '202', 'wmayer': '69', 'yorik': '68', 'bernd': '2069', 'Kunda1': '12229', 'jmaustpc': '611', 'triplus': '782', 'DeepSOIC': '3888', 'freecad-heini-1': '2598', 'openBrain': '22265', 'sgrogan': '4252', 'bejant': '1940', 'thomas-neemann': '29293', 'vocx': '21943', 'drmacro': '2867', 'microelly2': '2364', 'Roy_043': '22936', 'abdullah': '3232', 'papyblaise': '25808', 'wandererfan': '1375', 'TheMarkster': '19292', 'paullee': '8738', 'kisolre': '22435', 'mario52': '1058',\n'quick61': '2030', 'looo': '2349', 'Vincen': '5772', 'uwestoehr': '23505', 'Shalmeneser': '38754', 'PrzemoF': '3666', 'jriegel': '67', 'GeneFC': '8180', 'ickby': '686', 'easyw-fc': '6387', 'meme2704': '14145', 'shoogen': '765', 'sliptonic': '708', 'renatorivo': '918', 'thschrader': '15166', 'kkremitzki': '7997', 'freedman': '19098', 'Bance': '5418', 'herbk': '4353', 'keithsloan52': '930', 'Jee-Bee': '6234', 'r-frank': '1529', 'realthunder': '12167', 'carlopav': '23005', 'Chris_G': '2561',\n'onekk': '5245', 'ulrich1a': '1928', 'Joel_graff': '14673', 'chennes': '11959', 'Forthman': '19652', 'rockn': '681', 'freman': '22524', 'adrianinsaval': '19302', 'saso': '3305', 'Zolko': '22794', 'Willem': '9760', 'mlampert': '10163', 'tanderson69': '208', 'bitacovir': '3136', 'Syres': '21041', 'hammax': '12483', 'HakanSeven12': '23711', 'roerich_64': '6075', 'UR_': '12184', 'Dirk.B': '23630', 'HoWil': '6222', 'user1234': '9411', '-alex-': '23825', 'HarryGeier': '15774', 'freecadjam': '20736',\n'flachyjoe': '984', 'bambuko': '27936', 'jeno': '3508', 'HarryvL': '18062', 'kbwbe': '19380', 'peterl94': '1819', 'RatonLaveur': '24547', 'johnwang': '23504', 'cox': '4523', 'M4x': '13711', 'reox': '9769', 'pablogil': '4517', 'domad': '33963', 'david69': '2566', 'edwilliams16': '36484', 'leoheck': '19003', 'Russ4262': '20523', 'heda': '7350', 'ppemawm': '1807', 'ArminF': '11953', 'jp-willm': '7776', 'Pauvres_honteux': '2803', 'regis': '6401', 'vejmarie': '7506', 'Gift': '6611',\n'ian.rees': '3449', 'pperisin': '356', 'emills2': '5929', 'dubstar-04': '1642', 'ezzieyguywuf': '6058', 'mrlukeparry': '607', 'fc_tofu': '29038', 'logari81': '270', 'FaDa3D': '16107', 'jpg87': '13810', 'NewJoker': '36858', 'eivindkvedalen': '1546', 'damian': '6134', 'oliveroxtoby': '11950', 'Vagulus': '35139', 'jtm2020hyo': '35626', 'Cobraschock': '25890', 'jrheinlaender': '997', 'cappy0815': '4130', 'kaktus': '26846', 'Jimidi': '15956', 'vanuan': '22024', 'davidosterberg': '36295', 'ebrahi': '21433', 'kwahoo': '2441',\n'Joyas': '3582', 'r.tec': '4264', 'dcapeletti': '3651', 'drei': '3278', 'schupin': '18259', 'mariwan': '39136', 'agryson': '11337', 'JoshM': '16808', 'jnxd': '5734', 'Cekuhnen': '43243', 'manuelkrause': '20592', 'Mar': '14191', 'aapo': '22095', 'blue0cean': '23920', 'fandaL': '3658', 'Fran': '16427', 'teobo': '2833', 'paddle': '29478', 'OficineRobotica': '23938', 'Giuli': '9935', 'danielfalck': '689', 'makkemal': '5932', 'apeltauer': '16146', 'shaise': '6188', 'bavariaSHAPE': '3425',\n'ragohix769': '35209', 'galou_breizh': '334', 'garya': '22407', 'fcaduser': '2823', 'jaisejames': '10269', 'bill': '5185', 'blacey': '7328', 'fosselius': '8591', 'herrdeh': '3918', 'jruiz': '4299', 'edi': '29214', 'Sudhanshu': '21878', 'fran6t': '3600', 'wsteffe': '3846', 'nemesis': '2986', 'holdi': '11560', 'piffpoof': '4556', 'mnesarco': '30314', 'f3nix': '6125', 'furti': '17491', 'balrobs': '30989', 'amrit3701': '9146', 'jbe': '2330', 'Roland': '6638', 'rynn': '20919',\n'jreinhardt': '2072', 'koluna': '21576', 'chakkree': '6331', 'RedBaron': '36427', 'memfis': '11177', 'Evgeniy': '43393', 'plgarcia': '6249', 'arturromarr': '15598', 'Sura': '21412', 'Lauri': '13429', 'joha2': '10551', 'cad1234': '22955', 'lemonbug': '4228', 'C4e': '49784', 'MRx': '35035', 'Claud': '29138', 'clintonsam75': '3470', 'Repman': '3536', 'Moult': '23100', 'OldDraftsman': '16332', 'LHC': '36255', 'usbhub': '24632', 'efyx': '4074', 'catman': '23210', 'JMG': '2538',\n'polymer': '3974', 'Miq58': '46857', 'hobbes1069': '725', 'dxp.dev': '22713', 'wega': '2347', 'mendy': '19994', 'Konstantin': '3649', 'Renat': '3315', 'davecoventry': '2481', 'gsandy': '23521', 'blonblon': '10279', 'Drederwisch': '11726', 'Aleks': '30029', 'oldmachine': '15343', 'salp': '2409', 'FBXL5': '26761', 'Marco_T': '7564', 'bgoodr': '3447', 'dimitar': '25801', 'CharlieMAC': '3179', 'Markymark': '28078', 'HBC0': '6833', 'obelisk79': '36480', 'ceremcem': '18069', 'arcol': '2320',\n'qingfeng.xia': '6825', 'MaurinoWeb': '15573', 'hhassey': '6158', 'Brutha': '5971', 'lainegates': '1295', 'FC-Architecter': '19079', 'papy': '21427', 'chrisf': '2578', 'nahshon': '1973', 'MSOlsen65': '29727', 'ediloren': '1783', 'dan-miel': '21478', 'jean.thil': '6498', 'pl7i92LCNC': '24265', 'falviani': '25270', 'foxint': '7589', 'project4': '1944', 'j-dowsett': '652', 'un1corn': '7434', 'kwahooo': '254', 'qwerty_f': '36471', 'drum22': '40830', 'Luixx': '18322', 'paul18': '3622', 'serrepattes': '15169',\n'cram': '11546', 'a3bksll47': '19044', 'joel': '12631', 'yoshimitsuspeed': '1337', 'heron': '30887', 'HartmutG': '10744', 'Smiling_user': '35383', 'josegegas': '13017', 'gdo35': '858', 'spanner888': '25590', 'dprojects': '13594', 'ProBowlUk': '4171', 'C_h_o_p_i_n': '25037', 'JussyAD': '41661', 'rentlau_64': '4246', 'Do': '11781', 'Piero69': '26052', 'tonyaimer': '27612', 'AR795': '20058', 'heilo': '12525', 'iplayfast': '27301', 'hardeeprai': '255', 'Turro75': '9800', 'Wsk8': '22665', 'Fat-Zer': '4325',\n'Grub': '37710', 'Sam': '8192', 'TomB19': '25136', 'agima2': '12024', 'jmarie3D': '31172', 'Norus': '6964', 'S.N.A.L': '3080', 'PeterSD': '48559', 'Olav': '11423', 'Renato': '5905', 'kanagan': '5980', 'Routerworks': '19363', 'tom': '5727', 'Spindoctor': '6848', 'm42kus': '3911', 'freecc': '18704', 'ikua': '14240', 'grandcross': '6949', 'JellyPalm': '30355', 'TopDown': '20410', 'babaroga': '9780', 'Leatherman': '12789', 'cblt2l': '251', 'psicofil': '789', 'japie': '3493',\n'turn211': '39797', 'crobar': '3893', 'christi': '22009', 'gbroques': '29296', 'industromatic': '2997', 'clytle374': '2207', 'nyholku': '12058', 'doia': '42412', 'ajoeiam': '24132', 'ABeton': '27254', 'CrashedAgain': '29187', 'wvmarle': '4214', 'run_the_race': '39789', 'derschutzhund': '3592', 'ToniTen': '36030', 'sanguinariojoe': '574', 'perot': '16372', '1D_Inc': '23696', 'etrombly': '28581', 'cadcam': '30470', 'TedM': '30824', 'crashfridh': '1483', 'Anderl': '17746', 'Chaospilot': '22486', 'Eric': '25272',\n'ektus': '1283', 'Eric': '25272', 'xbit': '36362', 'bhs67': '5322', 'hyarion': '34430', 'Mongrel_Shark': '10595', 'zbigg': '17804', '2cv001': '28971', 'oddtopus': '10205', 'exsolvespacer': '39536', 'jakob': '3595', 'FemUser': '16291', 'luggw1': '13046', 'Cyril': '16289', 'jmcornil': '37409', 'kcleung': '512', 'm0n5t3r': '12818', 'Galahad': '20671', 'schnebeck': '15579', 'Crossleyuk': '20393', 'Hannu': '6761', 'HardRock': '18990', 'IzzY': '14602', 'maker': '19242', 'waebbl': '21119',\n'bmsaus4ax': '37689', 'rebeltaz': '24648', 'Koemi': '17917', 'nic': '24865', 'xibinke': '5703', 'ifohancroft': '25644', 'albertdela': '16540', 'lot': '25410', 'jonasthomas': '873', 'Jos': '31258', 'jonasb': '38748', 'Ukacor': '24411', 'jmplonka': '11876', 'JiPe38': '28975', 'mfasano': '19405', 'KAP': '28935', 'scrungy_doolittle': '20416', 'doubters': '8165', 'smktec': '29984', 'eason': '5803', 'OakLD': '18151', 'brjhaverkamp': '6838', 'zohozer': '3684', 'roivai': '12794', 'prrvchr': '4119',\n'hds': '13102', 'hholgi': '21563', 'bbear123': '2465', 'xf3qc': '16073', 'kreso-t': '20975', 'more11': '4079', 'alex::freecad': '3892', 'aerospaceweeb': '41416', 'cnirbhay': '9824', 'IanP': '7957', 'heideachim': '18226', 'felixlee868': '26041', 'seppelw': '18203', 'aguseguedre': '535', 'frecd': '5116', 'R23D': '29332', 'F_Rosa': '7885', 'Petrikas': '38333', 'freecadlzh': '30003', 'mrdic': '14954', 'Petert': '7290', 'duckmug': '42568', 'Gauthier': '3532', 'czinehuba': '21877', 'm.cavallerin': '20120',\n'Gauthier': '3532', 'wagnerlip': '29985', 'abasel': '21318', 'NC3D': '10606', 'sibelius': '29023', 'mack5': '15924', 'Linden': '6627', 'manos': '37638', 'EkaitzEsteban': '21473', 's-light': '5425', 'NateM': '2390', 'kaih': '28962', 'julieng': '22492', 'Sidemountyucatan': '24853', 'django013': '5218', 'Bertel': '37383', 'lhagan': '108', 'PMac': '16406', 'MrRossi': '11492', 'spikey': '7624', 'Daniel84': '13510', 'Andr': '7655', 'PunyTune': '23110', 'bzb.dev001': '25224', 'godblessfq': '6436',\n'godblessfq': '6436', 'DrBwts': '4281', 'neondata': '1573', 'mikeprice99': '34491', 'watsug': '36528', 'balazs': '4211', 'atzensepp': '5514', 'foadsf': '5587', 'onesz': '729', 'Gregor': '30570', 'Rost': '37043', 'oldestfox': '1910', 'Magnum56': '19253', 'hinckel': '4480', 'jmh': '4317', 'Serchu': '5411', 'miniellipse': '19613', 'Enyalios': '13094', 'Quaoar': '15966', 'Xav-83': '3750', 'A_3': '7639', 'andre': '2370', 'iogui': '24401', 'dulouie': '16780', 'j9lemmon': '2018',\n        #add new users and userids here\n        #some examples:\n        #'Enyalios': '13094',\n        #'agima2': '12024'\n\n        }\ndef QIconFromXPMString(xpm_string):\n    xpm = xpm_string.replace(\"\\\"\",\"\").replace(',','').splitlines()[4:-1]\n    pixmap = QtGui.QPixmap(xpm)\n    icon = QtGui.QIcon(pixmap)\n    return icon\n\n__icon__ = \"\"\"\n/* XPM */\nstatic char *_648433055688[] = {\n/* columns rows colors chars-per-pixel */\n\"64 64 4 1 \",\n\"  c black\",\n\". c #FD8711\",\n\"X c #FFC90E\",\n\"o c None\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooXXXXXXXoooooooooooooooooooooooooooooo\",\n\"ooooooooooooooooooooooooXXXXXXXXXXXXoooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooXXXXX     XXXXooooooooooooooooooooooooooo\",\n\"ooooooooooooooooooooooXXXX         XXXXooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooXXX            XXXXoooooooooooooooooooooooo\",\n\"oooooooooooooooooooooXX      XXX      XXXooooooooooooooooooooooo\",\n\"ooooooooooooooooooooXXX     XXXXX      XXXoooooooooooooooooooooo\",\n\"oooooooooooooooooooXXX    XXXXXXXXX     XXoooooooooooooooooooooo\",\n\"ooooooooooooooooooXXX    XXXXXXXXXXX    XXoooooooooooooooooooooo\",\n\"oooooooooooooooooXXX    XXXXXoooXXXXX   XXXooooooooooooooooooooo\",\n\"ooooooooooooooooXXX     XXXXoooooXXXX    XXXoooooooooooooooooooo\",\n\"ooooooooooooooooXX     XXXXooo.oooXXXX    XXoooooooooooooooooooo\",\n\"oooooooooooooooXXX    XXXXooo...oooXXXX   XXoooooooooooooooooooo\",\n\"oooooooooooooooXXX    XXXXoo.....oooXXX   XXXooooooooooooooooooo\",\n\"oooooooooooooooXXX   XXXXoo.......ooXXXX   XXooooooooooooooooooo\",\n\"oooooooooooooooXXX   XXXXoo.......ooXXXX   XXooooooooooooooooooo\",\n\"oooooooooooooooXX    XXXXoo.......ooXXXX   XXXoooooooooooooooooo\",\n\"ooooooooooooooXXX    XXXooo.......oooXXX    XXoooooooooooooooooo\",\n\"oooooooooooooXXX     XXXoo.........ooXXX    XXXooooooooooooooooo\",\n\"oooooooooooooXXX    XXXXoo.........ooXXXX    XXooooooooooooooooo\",\n\"oooooooooooooXXX   XXXXooo.........oooXXX    XXooooooooooooooooo\",\n\"oooooooooooooXX    XXXXoo...........ooXXX    XXXoooooooooooooooo\",\n\"oooooooooooooXX    XXXooo...........ooXXXX   XXXoooooooooooooooo\",\n\"ooooooooooooXXX    XXXoo............ooXXXX    XXXooooooooooooooo\",\n\"ooooooooooooXX    XXXooo............ooXXXXX    XXooooooooooooooo\",\n\"ooooooooooooXX    XXXoo.............ooXXXXX    XXooooooooooooooo\",\n\"oooooooooooXXX    XXXoo.............oooXXXX    XXooooooooooooooo\",\n\"ooooooooooXXXX    XXooo..............oooXXX    XXooooooooooooooo\",\n\"oooooooooXXX     XXXoo................oooXXX   XXXXooooooooooooo\",\n\"ooooooooXXX      XXXoooooooooooooooooooooXXX    XXXXoooooooooooo\",\n\"oooooooXXXX     XXXXXoooooooooooooooooooooXXX     XXXooooooooooo\",\n\"oXXXXXXXX     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX    XXXXXXXXXXooo\",\n\"oXXXXXXX      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX     XXXXXXXXXooo\",\n\"oXX                                                        XXooo\",\n\"oXX                                                        XXooo\",\n\"oXX                                                        XXooo\",\n\"oXX                                                        XXooo\",\n\"oXX                                                        XXooo\",\n\"oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXooo\",\n\"oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXooo\",\n\"oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\",\n\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\"\n};\n\"\"\"\n#pinger = Pinger()\ndlg = PingerDlg()\n\nif __name__ == \"__main__\":\n#    pinger.run()\n    dlg.form.show()",
    "url": "https://wiki.freecad.org/Macro_Pinger",
    "raw_code_url": "",
    "wiki": "",
    "version": "1.81",
    "license": "",
    "date": "2022.03.28",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Pinger_Icon.svg",
    "icon_source": "https://wiki.freecadweb.org/images/6/67/Pinger_Icon.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Recompute Profiler",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro is to help you find, what features cause long delays in updates to the project. It performs a recompute, measuring the time it takes to recompute each feature.<br /><br />Macro version: 0.1<br />Last modified: 2017-04-03<br />FreeCAD version: 0.17.10644 and above<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/c/ca/Macro_Recompute_Profiler.png\">ToolBar Icon</a><br />Author: DeepSOIC<br /> ",
    "comment": "Measures time it takes to recmpute features in a project",
    "code": "__Title__=\"Macro Recompute Profiler\"\n__Author__ = \"DeepSOIC\"\n__Version__ = \"0.1\"\n__Date__    = \"03.04.2017\"\n\n__Comment__ = \"Measures time it takes to recmpute features in a project\"\n__Wiki__ = \"https://www.freecadweb.org/wiki/index.php?title=Macro_Recompute_Profiler\"\n__Help__ = \"Right-click an object, and pick 'Mark to recompute', then run this macro. This will only profile recomputing the subgraph. To profile the whole project, right-click the project in tree view, and pick 'Mark to recompute', then run this macro. Results will be printed to report view.\"\n__Status__ = \"experimental\"\n__Requires__ = \"freecad 0.17.10644\"\n__Communication__ = \"https://forum.freecadweb.org/memberlist.php?mode=viewprofile&u=3888\" \n\nimport FreeCAD as App\n\nimport FreeCADGui as Gui\n\nclass ExecutionError(Exception):\n    pass\n\nclass CancelError(Exception):\n    pass\n\ndef execute(feature):\n    feature.recompute()\n    if 'Invalid' in feature.State:\n        raise ExecutionError(\"Feature '{label}' failed to recompute\".format(label= feature.Label))\n\ndef msgbox(title, text):\n    from PySide import QtGui\n    mb = QtGui.QMessageBox()\n    mb.setIcon(mb.Icon.Information)\n    mb.setText(text)\n    mb.setWindowTitle(title)\n    mb.exec_()\n\ndef log(string):\n    App.Console.PrintWarning(string+\"\\n\")\n\ndef getAllDependent(feat_list):\n    '''getAllDependent(feat_list): gets all features that depend on features in feat_list, directly or indirectly.\n    Returns a set. Features from feat_list are not included, unless there are interdependencies between them.'''\n\n    list_traversing_now = feat_list\n    set_of_deps = set()\n    list_of_deps = []\n\n    while len(list_traversing_now) > 0:\n        list_to_be_traversed_next = []\n        for feat in list_traversing_now:\n            for dep in feat.InList:\n                if not (dep in set_of_deps):\n                    set_of_deps.add(dep)\n                    list_of_deps.append(dep)\n                    list_to_be_traversed_next.append(dep)\n\n        list_traversing_now = list_to_be_traversed_next\n\n    return set_of_deps\n\n\ndef run():\n    touched = [obj for obj in App.ActiveDocument.Objects if 'Touched' in obj.State]\n\n    if len(touched) == 0:\n        App.ActiveDocument.RecomputesFrozen = True\n        msgbox(\"Macro Recompute Profiler\", \"Project was switched to suspend recomputes. Please modify an object that triggers a recompute, and run this macro again. The macro will perform a step-by-step recompute, and measure the time it takes to recompute features.\")\n        return\n\n    log(\"{n} features are touched\".format(n= len(touched)))\n\n    log(\"Generating execution order...\")\n\n    to_be_executed = set.union(getAllDependent(touched), set(touched))\n    log(\"Number of features to execute: {n}\".format(n= len(to_be_executed)))\n\n    exec_list = []\n    for obj in App.ActiveDocument.TopologicalSortedObjects[::-1]:\n        if obj in to_be_executed:\n            exec_list.append(obj)\n    assert(len(exec_list) == len(to_be_executed))\n    n = len(exec_list)\n\n    log(\"Execution order:\")\n    for obj in exec_list:\n        log(\"    \"+obj.Label)\n\n\n    import PySide\n    progress = PySide.QtGui.QProgressDialog(u\"Preparing to recompute....\", u\"Abort\", 0, n+1)\n    progress.setModal(True)\n    progress.show()\n    \n    try:\n        log(\"Recomputing... (time in seconds, label)\")\n        import time\n        for obj in exec_list:\n            progress.setValue(progress.value()+1)\n            progress.setLabelText(\"Recomputing {feature}...\".format(feature= obj.Label))\n            if progress.wasCanceled():\n                raise CancelError()\n\n            time_start = time.time()\n            try:\n                execute(obj)\n            finally:\n                exec_time = time.time()-time_start\n                log(\"\\t{time}\\t{label}\".format(time= exec_time, label= obj.Label))\n\n        progress.setValue(n+1)\n        msgbox(\"Macro Recompute Profiler\", \"Recompute completed. Results are in report view.\")\n\n        for obj in exec_list:\n            obj.purgeTouched()\n\n    except Exception as err:\n        msgbox(\"Macro Recompute Profiler\", \"An error occured: {err}\".format(err= str(err)))\n    finally:\n        progress.hide()\n        App.ActiveDocument.RecomputesFrozen = False\n\nrun()",
    "url": "https://wiki.freecad.org/Macro_Recompute_Profiler",
    "raw_code_url": "",
    "wiki": "https://www.freecadweb.org/wiki/index.php?title=Macro_Recompute_Profiler",
    "version": "0.1",
    "license": "",
    "date": "03.04.2017",
    "src_filename": "",
    "filename_from_url": "",
    "author": "DeepSOIC",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Recompute_Profiler.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/c/ca/Macro_Recompute_Profiler.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Wiki Object Properties List Generator",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro generates lists of properties of the selected object in different forms in Wiki format.<br /><br />Macro version: 0.15<br />Last modified: 2021-09<br />Author: Evgeniy<br /> ",
    "comment": "This macro generates lists of properties of the selected object in different forms in Wiki format.",
    "code": "#! python\n# -*- coding: utf-8 -*-\n# (c) 2021 <Evgeniy> LGPL\n\nfrom FreeCAD import Qt\nimport re, FreeCAD\nfrom PySide import QtCore, QtGui\n\ndef clear_report_view():\n   main_window=Gui.getMainWindow()\n   #console=main_window.findChild(QtGui.QPlainTextEdit, \"Python console\")\n   #console.clear()\n   report_view=main_window.findChild(QtGui.QTextEdit, \"Report view\")\n   report_view.clear()\n\ndef printsr(text,show_report):\n   if show_report:   \n      print(text)\n\n# Based on https://github.com/FreeCAD/FreeCAD/blob/5d49bf78de785a536f941f1a6d06d432582a95d3/src/App/PropertyFile.h\n# and https://github.com/FreeCAD/FreeCAD/blob/5d49bf78de785a536f941f1a6d06d432582a95d3/src/App/PropertyContainerPyImp.cpp\nstatus_dictionary={\n0:\"Touched\",      # touched property\n#1:\"Immutable\",   # can't modify property\n#2:\"ReadOnly\",    # for property editor\n#3:\"Hidden\",      # for property editor\n#4:\"Transient\",   # for property container save\n#5:\"MaterialEdit\", # to turn ON PropertyMaterial edit\n#6:\"NoMaterialListEdit\", # to turn OFF PropertyMaterialList edit\n#7:\"Output\",      # same effect as Prop_Output\n#8:\"LockDynamic\", # prevent being removed from dynamic property\n#9:\"NoModify\",    # prevent causing Gui::Document::setModified()\n#10:\"PartialTrigger\", # allow change in partial doc\n11:\"NoRecompute\", # touch owner for recompute on property change\n12:\"Single\",      # for save/load of floating point numbers\n13:\"Ordered\",     # for PropertyLists whether the order of the elements is relevant for the container using it\n14:\"EvalOnRestore\", # In case of expression binding, evaluate the expression on restore and touch the object on value change.\n# The following bits are corresponding to PropertyType set when the\n# property added. These types are meant to be static, and cannot be\n# changed in runtime. It is mirrored here to save the linear search\n# required in PropertyContainer::getPropertyType()\n21:\"Dynamic\",     # indicating the property is dynamically added\n22:\"NoPersist\",   # corresponding to Prop_NoPersist\n23:\"NoRecompute\", # corresponding to Prop_NoRecompute\n24:\"ReadOnly\",    # corresponding to Prop_ReadOnly\n25:\"Transient\",   # corresponding to Prop_Transient\n26:\"Hidden\",      # corresponding to Prop_Hidden\n27:\"Output\",      # corresponding to Prop_Output\n}\n\ndef print_obj_properties(obj,typ,blacklist,show_inherits):\n   prop={}\n   i=1\n   inherits = \"\"\n   for pr in obj.PropertiesList:\n      typeid = (obj.getTypeIdOfProperty(pr) or \"\").replace(\"App::Property\",\"\")\n      # Get all possible status variants \n      stat = obj.getPropertyStatus(pr) or (\"\")\n      if stat != (\"\"):\n         for st in stat:\n            # get status without name from dictionary\n            if isinstance(st, int):\n               stat.insert(stat.index(st),status_dictionary[st])\n               stat.remove(st)\n         # remove symbols ['] from str by regexp and trim spaces\n         stat = re.sub(r\"[\\[\\]\\']\",\"\",str(stat)).strip()\n         # Uncomment this two strings to make the list look like the list of parameters from the editor\n         #if 'Hidden' in stat:\n         #   continue\n      else:\n         stat = \"\"\n      if blacklist == None or (blacklist != None and pr not in blacklist):\n         prop[str(i)] = pr,obj.getGroupOfProperty(pr),typeid,obj.getDocumentationOfProperty(pr),stat\n         i+=1\n      else:\n         inherits += pr + \" inherited from class \" + blacklist[pr] + \"\\n\"\n\n   if inherits != \"\" and show_inherits:\n      # angle brackets is masked as \\x3C and \\x3E to this code can be published in the wiki\n      print(\"\\n\\x3C!--\\n\"+inherits+\"--\\x3E\")\n   sorted_prop = sorted(prop.items(), key=lambda x: x[1][1])\n\n   title=\"\"\n   for pr in sorted_prop:\n      if title != pr[1][1]:\n         title = pr[1][1]\n         print(\"\\n\"+\"{{TitleProperty|\"+title+\"}}\")\n      # use ternary operator \"|\"+pr[1][4] if pr[1][4]!=\"\" else \"\" to ignore status field if it not exists \n      print(\"\\n\"+\"* {{Property\"+typ+\"|\"+pr[1][0]+\"|\"+pr[1][2]+(\"|\"+pr[1][4] if pr[1][4]!=\"\" else \"\")+\"}}: \"+pr[1][3])\n\n# Add propertyes to blacklist if it not presentet in it yet\ndef add_to_blacklist(data_blacklist,view_blacklist,obj_type,temp_obj_name,show_report):\n   printsr(\"Class: '\"+obj_type+\"'\",show_report)\n   # Make tempory object\n   obj = FreeCAD.activeDocument().addObject(obj_type,temp_obj_name)\n   name = obj.Name\n   # Get Data parametrs\n   printsr(\"Data parameters list:\",show_report)\n   for pr in obj.PropertiesList:\n      if not show_report or pr not in data_blacklist:\n         data_blacklist[pr]=obj_type\n         atr = str(obj.getPropertyStatus(pr)).replace(\"[]\",\"\")\n         typeid = (obj.getTypeIdOfProperty(pr) or \"\").replace(\"App::Property\",\"\")\n         printsr(pr+\" (\"+typeid+\") \"+atr,show_report)\n   # Get View parameters if it is possible\n   obj = Gui.activeDocument().getObject(name)\n   try:\n      test = obj.PropertiesList\n      printsr(\"View parameters list:\",show_report)\n      for pr in obj.PropertiesList:\n         if not show_report or pr not in view_blacklist:\n            view_blacklist[pr]=obj_type\n            atr = str(obj.getPropertyStatus(pr)).replace(\"[]\",\"\")\n            typeid = (obj.getTypeIdOfProperty(pr) or \"\").replace(\"App::Property\",\"\")\n            printsr(pr+\" (\"+typeid+\") \"+atr,show_report)\n   except:\n      printsr(\"This class not support View parameters.\",show_report)\n   # Remove object\n   FreeCAD.activeDocument().removeObject(name)\n   printsr(\"\",show_report)\n   return data_blacklist,view_blacklist\n\ndef fill_blacklists(show_report):\n   data_blacklist={}\n   view_blacklist={}\n   # Interfaces are not supported\n   #data_blacklist,view_blacklist = add_to_blacklist(data_blacklist,view_blacklist,\"App::OriginGroupExtension\",\"Temp\",show_report)\n   #data_blacklist,view_blacklist = add_to_blacklist(data_blacklist,view_blacklist,\"Part::AttachExtension\",\"Temp\",show_report)\n   #data_blacklist,view_blacklist = add_to_blacklist(data_blacklist,view_blacklist,\"Sketcher::PropertyConstrainList\",\"Temp\",show_report)\n   data_blacklist,view_blacklist = add_to_blacklist(data_blacklist,view_blacklist,\"App::DocumentObject\",\"Temp\",show_report)\n   data_blacklist,view_blacklist = add_to_blacklist(data_blacklist,view_blacklist,\"App::GeoFeature\",\"Temp\",show_report)\n   data_blacklist,view_blacklist = add_to_blacklist(data_blacklist,view_blacklist,\"App::Part\",\"Temp\",show_report)\n   data_blacklist,view_blacklist = add_to_blacklist(data_blacklist,view_blacklist,\"Mesh::Feature\",\"Temp\",show_report)\n   data_blacklist,view_blacklist = add_to_blacklist(data_blacklist,view_blacklist,\"Fem::FemMeshObject\",\"Temp\",show_report)\n   data_blacklist,view_blacklist = add_to_blacklist(data_blacklist,view_blacklist,\"Path::Feature\",\"Temp\",show_report)\n   data_blacklist,view_blacklist = add_to_blacklist(data_blacklist,view_blacklist,\"Part::Part2DObject\",\"Temp\",show_report)\n   # Part::Primitive is not possible to create\n   #data_blacklist,view_blacklist = add_to_blacklist(data_blacklist,view_blacklist,\"Part::Primitive\",\"Temp\",show_report)\n   data_blacklist,view_blacklist = add_to_blacklist(data_blacklist,view_blacklist,\"PartDesign::Feature\",\"Temp\",show_report)\n   data_blacklist,view_blacklist = add_to_blacklist(data_blacklist,view_blacklist,\"Part::BodyBase\",\"Temp\",show_report)\n   data_blacklist,view_blacklist = add_to_blacklist(data_blacklist,view_blacklist,\"PartDesign::Body\",\"Temp\",show_report)\n   if show_report:\n      print(\"List of all not unique properties of Data:\\n\"+str(data_blacklist)+\"\\n\\nList of all not unique properties of View:\\n\"+str(view_blacklist)+\"\\n\")\n   return data_blacklist,view_blacklist\n\nsel = FreeCADGui.Selection.getSelection()\nif len(sel) != 1:\n   msgbox = QtGui.QMessageBox(QtGui.QMessageBox.Question, u'Properties Generator', \"\"\"You must select only one object in tree view!\"\"\")\n   msgbox.exec_()\nelse:\n   # Show dialog for select type of report\n   msgbox = QtGui.QMessageBox(QtGui.QMessageBox.Question, u'Properties Generator', \"\"\"Select type of report\n   \nOnly Main - print only unique properties of main classes with types.\nAll Properties - print all properties of selected object.\nInherits+Unique Properties - print unique properties with inherits report.\nOnly Unique Properties - print only unique properties of selected object.\n\"\"\")\n   msgbox.setStandardButtons(QtGui.QMessageBox.Cancel) #|QtGui.QMessageBox.Ok\n   only_main = msgbox.addButton(\"Only Main\", QtGui.QMessageBox.AcceptRole)\n   all_properties = msgbox.addButton(\"All Properties\", QtGui.QMessageBox.AcceptRole)\n   unique_prop_inherits = msgbox.addButton(\"Inherits+Unique Properties \", QtGui.QMessageBox.AcceptRole)\n   unique_properties = msgbox.addButton(\"Only Unique Properties\", QtGui.QMessageBox.AcceptRole)\n   msgbox.exec_()\n   res = msgbox.clickedButton()\n   # Clear Report view\n   clear_report_view()\n   if res == only_main :\n      data_blacklist,view_blacklist=fill_blacklists(True)\n   if res == unique_properties or  res == all_properties or res == unique_prop_inherits :\n      name = sel[0].Name\n      act_obj = Gui.activeDocument().getObject(name)\n      data_blacklist={}\n      view_blacklist={}\n      if res == unique_properties or res == unique_prop_inherits:\n         data_blacklist,view_blacklist=fill_blacklists(False)\n      print(\"\\n\"+\"==Properties==\")\n      print(\"\\n\"+\"===View===\")\n      print_obj_properties(act_obj,\"View\",view_blacklist, res == unique_prop_inherits)\n      print(\"\\n\"+\"===Data===\")\n      act_obj = FreeCAD.activeDocument().getObject(name)\n      print_obj_properties(act_obj,\"Data\",data_blacklist, res == unique_prop_inherits)  \n\n",
    "url": "https://wiki.freecad.org/Macro_Wiki_Object_Properties_List_Generator",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2021-09",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Evgeniy",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Wiki Object Properties List Generator Basic Version",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro generate properties list of selected object. List presented in wiki format into Python report view.<br /><br />Macro version: 0.1<br />Last modified: 2021-09<br />Author: Evgeniy<br /> ",
    "comment": "This macro generate properties list of selected object. List presented in wiki format into Python report view.",
    "code": "#! python\n# -*- coding: utf-8 -*-\n# (c) 2021 <Evgeniy> LG\nfrom FreeCAD import Qt\n\ndef print_obj_properties(obj,typ):\n   prop={}\n   i=1\n   for pr in obj.PropertiesList:\n      tp = obj.getTypeIdOfProperty(pr) or \"\"\n      atr = obj.getTypeOfProperty(pr) or (\"\")\n      # Wiki template supports only Hidden type of property. But it can be as: Hidden,Output,Readonly etc...\n      if atr != \"\" and atr[0] == \"Hidden\":\n         atr = \"|\"+atr[0]\n      else:\n         atr = \"\"      \n      prop[str(i)] = pr,obj.getGroupOfProperty(pr),tp.replace(\"App::Property\",\"\"),obj.getDocumentationOfProperty(pr),atr\n      i+=1\n   sorted_prop = sorted(prop.items(), key=lambda x: x[1][1])\n\n   title=\"\"\n   for pr in sorted_prop:\n      if title != pr[1][1]:\n         title = pr[1][1]\n         print(\"\\n\"+\"{{TitleProperty{\"+title+\"}}\")\n      print(\"\\n\"+\"* {{Property\"+typ+\"{\"+pr[1][0]+\"{\"+pr[1][2]+pr[1][4]+\"}}: \"+pr[1][3])\n\nprint(\"\\n\"+\"==Properties==\")\nprint(\"\\n\"+\"===View===\")\nobj = Gui.activeDocument().ActiveObject\nprint_obj_properties(obj,\"View\")\nprint(\"\\n\"+\"===Data===\")\nobj = FreeCAD.activeDocument().ActiveObject\nprint_obj_properties(obj,\"Data\")\n",
    "url": "https://wiki.freecad.org/Macro_Wiki_Object_Properties_List_Generator_Basic_Version",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2021-09",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Evgeniy",
    "icon": "",
    "icon_source": null,
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Replace Part in Assembly",
    "on_wiki": true,
    "on_git": false,
    "desc": "Especially when doing \"Assemblies\" with simple copies of parts, one needs to replace one part by another from time to time.<br /><br />Macro version: 1.0<br />Last modified: 2014-09-10<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/0/07/Replace_Part.png\">ToolBar Icon</a><br />Author: ralvejd<br /> ",
    "comment": "Especially when doing \"Assemblies\" with simple copies of parts, one needs to replace one part by another from time to time.",
    "code": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"\nMacro to replace parts in assembly FreeCAD.\nVersion 0.1 from 20140910\n\n********************************************************************************************\n*   Copyright (c) 2013 Joakim Isaksson <ralvejd[at]users.sourceforge.net>          *\n*                                                                                                                                       *\n*   This file is a supplement to the FreeCAD CAx development system.                *\n*                                                                                                                                       *\n*   This program is free software; you can redistribute it and/or modify                  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)               *\n*   as published by the Free Software Foundation; either version 2 of                    *\n*   the License, or (at your option) any later version.                                                  *\n*   for detail see the LICENCE text file.                                                                        *\n*                                                                                                                                        *\n*   This software is distributed in the hope that it will be useful,                                  *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of                *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *\n*   GNU Library General Public License for more details.                                           *\n*                                                                                                                                          *\n*   You should have received a copy of the GNU Library General Public                    *\n*   License along with this macro; if not, write to the Free Software                            *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307              *\n*   USA                                                                                                                                *\n*                                                                                                                                           *\n***********************************************************************************************\n\"\"\"\n\n__author__ = \"Joakim Isaksson <ralvejd[at]users.sourceforge.net>\"\n\n\nimport FreeCAD, Part, math\nfrom FreeCAD import Base\nimport DraftVecUtils\nimport sys\ntry:\n   from PySide import QtCore, QtGui\n   from PySide.QtCore import SIGNAL, QTimer\n   from PySide.QtGui import QApplication\nexcept:\n   from PyQt4 import QtCore, QtGui\n   from PyQt4.QtCore import SIGNAL, QTimer\n   from PyQt4.QtGui import QApplication\n\ntry:\n   _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n   _fromUtf8 = lambda s: s\n\ntry:\n   _encoding = QtGui.QApplication.UnicodeUTF8\n   def _translate(context, text, disambig):\n      return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n   def _translate(context, text, disambig):\n      return QtGui.QApplication.translate(context, text, disambig)\n\n#                     [document , name, label, position, rotation, group]\nglobal newpart ; newpart = [ \"\" , \"\", \"\" , \"\", \"\" , \"\" ] ;\nglobal oldpart ; oldpart = [ \"\" , \"\", \"\" , \"\", \"\" , \"\" ] ;\nglobal newPartName ; newPartName = \"\"\nglobal newPartLabel ; newPartLabel = \"\"\nglobal uiRowOffset ; uiRowOffset = 30\nglobal uiColWidth ; uiColWidth = 150\nglobal uiPad ; uiPad = 5\nglobal uiMainWidth ; uiMainWidth = 400\n\nclass Ui_ReplacePart(object):\n\n   def setupUi(self, ReplacePart):\n      global uiMainWidth\n      global uiRowOffset\n      global uiColWidth\n      global uiPad\n      uiTextPartWidth = uiMainWidth -(3*uiPad)-uiColWidth\n\n      ReplacePart.setObjectName(_fromUtf8(\"ReplacePart\"))\n      ReplacePart.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedKingdom))   \n\n      captionFont = QtGui.QFont()\n      captionFont.setBold(True)\n\n      self.centralWidget = QtGui.QWidget(ReplacePart)\n      self.centralWidget.setObjectName(_fromUtf8(\"centralWidget\"))\n      \n      \"\"\"\n      #*** FIXME ***----------------------------\n      #self.centralWidget.setAttribute(QtCore.Qt.WA_DeleteOnClose)\n      self.centralWidget.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)\n      #*** FIXME ***----------------------------\n      \"\"\"\n      \n      self.groupBoxNewName = QtGui.QButtonGroup()\n      self.groupBoxNewLabel = QtGui.QButtonGroup()\n      self.groupBoxColorFrom = QtGui.QButtonGroup()\n\n      self.labelCapSelected = QtGui.QLabel(self.centralWidget)\n      self.labelCapSelected.setGeometry(QtCore.QRect(uiPad, uiPad, uiColWidth, uiRowOffset-10))\n      self.labelCapSelected.setAlignment(QtCore.Qt.AlignRight)\n      self.labelCapSelected.setFont(captionFont)\n      self.labelCapSelected.setObjectName(_fromUtf8(\"labelCapSelected\"))\n\n      self.labelSelected = QtGui.QLabel(self.centralWidget)\n      self.labelSelected.setGeometry(QtCore.QRect(uiColWidth+(2*uiPad), uiPad, uiTextPartWidth, uiRowOffset-10))\n      self.labelSelected.setObjectName(_fromUtf8(\"labelSelected\"))\n\n      row = uiPad+uiRowOffset   \n      self.pushButtonNew = QtGui.QPushButton(self.centralWidget)\n      self.pushButtonNew.setGeometry(QtCore.QRect(uiPad, row, uiColWidth, uiRowOffset-2))\n      self.pushButtonNew.setObjectName(_fromUtf8(\"pushButtonNew\"))\n      self.pushButtonNew.clicked.connect(self.on_pushButtonNew_clicked)   \n\n      self.labelNew = QtGui.QLabel(self.centralWidget)\n      self.labelNew.setGeometry(QtCore.QRect(uiColWidth+(2*uiPad), row, uiTextPartWidth, uiRowOffset-2))\n      self.labelNew.setObjectName(_fromUtf8(\"labelNew\"))\n\n      row = row+uiRowOffset\n      self.pushButtonOld = QtGui.QPushButton(self.centralWidget)\n      self.pushButtonOld.setGeometry(QtCore.QRect(uiPad, row, uiColWidth, uiRowOffset-2))\n      self.pushButtonOld.setObjectName(_fromUtf8(\"pushButtonOld\"))\n      self.pushButtonOld.clicked.connect(self.on_pushButtonOld_clicked)\n\n      self.LabelOld = QtGui.QLabel(self.centralWidget)\n      self.LabelOld.setGeometry(QtCore.QRect(uiColWidth+(2*uiPad), row, uiTextPartWidth, uiRowOffset-2))\n      self.LabelOld.setObjectName(_fromUtf8(\"labelOld\"))\n\n      row = row+uiRowOffset\n      self.pushButtonOk = QtGui.QPushButton(self.centralWidget)\n      self.pushButtonOk.setGeometry(QtCore.QRect(uiPad, row, uiColWidth, uiRowOffset-2))\n      self.pushButtonOk.setObjectName(_fromUtf8(\"pushButtonOk\"))\n      self.pushButtonOk.setEnabled(False)\n      self.pushButtonOk.clicked.connect(self.on_pushButtonOk_clicked)\n\n      row = row+uiRowOffset+uiPad\n      self.labelCapNewName = QtGui.QLabel(self.centralWidget)\n      self.labelCapNewName.setGeometry(QtCore.QRect(uiPad, row, uiColWidth, uiRowOffset-10))\n      self.labelCapNewName.setFont(captionFont)\n      self.labelCapNewName.setObjectName(_fromUtf8(\"labelCapNewName\"))\n\n      self.labelCapNewLabel = QtGui.QLabel(self.centralWidget)\n      self.labelCapNewLabel.setGeometry(QtCore.QRect(uiColWidth+(2*uiPad), row, uiColWidth, uiRowOffset-10))\n      self.labelCapNewLabel.setFont(captionFont)\n      self.labelCapNewLabel.setObjectName(_fromUtf8(\"labelCapNewLabel\"))\n\n      row = row+uiRowOffset\n      self.radioButtonNameFromNewDoc = QtGui.QRadioButton(self.centralWidget)\n      self.radioButtonNameFromNewDoc.setGeometry(QtCore.QRect(uiPad, row, uiColWidth, uiRowOffset-2))\n      self.radioButtonNameFromNewDoc.setObjectName(_fromUtf8(\"radioButtonNameFromNewDoc\"))\n      self.radioButtonNameFromNewDoc.clicked.connect(self.on_radioButtonNameFromNewDoc_clicked)\n\n      self.radioButtonLabelFromNewDoc = QtGui.QRadioButton(self.centralWidget)\n      self.radioButtonLabelFromNewDoc.setGeometry(QtCore.QRect(uiColWidth+(2*uiPad), row, uiColWidth, uiRowOffset-2))\n      self.radioButtonLabelFromNewDoc.setObjectName(_fromUtf8(\"radioButtonLabelFromNewDoc\"))\n      self.radioButtonLabelFromNewDoc.clicked.connect(self.on_radioButtonLabelFromNewDoc_clicked)\n\n      row = row+uiRowOffset\n      self.radioButtonNameFromNewName = QtGui.QRadioButton(self.centralWidget)\n      self.radioButtonNameFromNewName.setGeometry(QtCore.QRect(uiPad, row, uiColWidth, uiRowOffset-2))\n      self.radioButtonNameFromNewName.setObjectName(_fromUtf8(\"radioButtonNameFromNewName\"))\n      self.radioButtonNameFromNewName.clicked.connect(self.on_radioButtonNameFromNewName_clicked)\n\n      self.radioButtonLabelFromNewName = QtGui.QRadioButton(self.centralWidget)\n      self.radioButtonLabelFromNewName.setGeometry(QtCore.QRect(uiColWidth+(2*uiPad), row, uiColWidth, uiRowOffset-2))\n      self.radioButtonLabelFromNewName.setObjectName(_fromUtf8(\"radioButtonLabelFromNewName\"))\n      self.radioButtonLabelFromNewName.clicked.connect(self.on_radioButtonLabelFromNewName_clicked)\n\n      row = row+uiRowOffset\n      self.radioButtonNameFromNewLabel = QtGui.QRadioButton(self.centralWidget)\n      self.radioButtonNameFromNewLabel.setGeometry(QtCore.QRect(uiPad, row, uiColWidth, uiRowOffset-2))\n      self.radioButtonNameFromNewLabel.setObjectName(_fromUtf8(\"radioButtonNameFromNewLabel\"))\n      self.radioButtonNameFromNewLabel.clicked.connect(self.on_radioButtonNameFromNewLabel_clicked)\n\n      self.radioButtonLabelFromNewLabel = QtGui.QRadioButton(self.centralWidget)\n      self.radioButtonLabelFromNewLabel.setGeometry(QtCore.QRect(uiColWidth+(2*uiPad), row, uiColWidth, uiRowOffset-2))\n      self.radioButtonLabelFromNewLabel.setObjectName(_fromUtf8(\"radioButtonLabelFromNewLabel\"))\n      self.radioButtonLabelFromNewLabel.clicked.connect(self.on_radioButtonLabelFromNewLabel_clicked)\n\n      row = row+uiRowOffset\n      self.radioButtonNameFromOldName = QtGui.QRadioButton(self.centralWidget)\n      self.radioButtonNameFromOldName.setGeometry(QtCore.QRect(uiPad, row, uiColWidth, uiRowOffset-2))\n      self.radioButtonNameFromOldName.setObjectName(_fromUtf8(\"radioButtonNameFromOldName\"))\n      self.radioButtonNameFromOldName.clicked.connect(self.on_radioButtonNameFromOldName_clicked)\n\n      self.radioButtonLabelFromOldName = QtGui.QRadioButton(self.centralWidget)\n      self.radioButtonLabelFromOldName.setGeometry(QtCore.QRect(uiColWidth+(2*uiPad), row, uiColWidth, uiRowOffset-2))\n      self.radioButtonLabelFromOldName.setObjectName(_fromUtf8(\"radioButtonLabelFromOldName\"))\n      self.radioButtonLabelFromOldName.clicked.connect(self.on_radioButtonLabelFromOldName_clicked)\n\n      row = row+uiRowOffset\n      self.radioButtonNameFromOldLabel = QtGui.QRadioButton(self.centralWidget)\n      self.radioButtonNameFromOldLabel.setGeometry(QtCore.QRect(uiPad, row, uiColWidth, uiRowOffset-2))\n      self.radioButtonNameFromOldLabel.setObjectName(_fromUtf8(\"radioButtonNameFromOldLabel\"))\n      self.radioButtonNameFromOldLabel.clicked.connect(self.on_radioButtonNameFromOldLabel_clicked)\n\n      self.radioButtonLabelFromOldLabel = QtGui.QRadioButton(self.centralWidget)\n      self.radioButtonLabelFromOldLabel.setGeometry(QtCore.QRect(uiColWidth+(2*uiPad), row, uiColWidth, uiRowOffset-2))\n      self.radioButtonLabelFromOldLabel.setObjectName(_fromUtf8(\"radioButtonLabelFromOldLabel\"))\n      self.radioButtonLabelFromOldLabel.clicked.connect(self.on_radioButtonLabelFromOldLabel_clicked)\n\n      row = row+uiRowOffset\n      self.radioButtonNameFromText = QtGui.QRadioButton(self.centralWidget)\n      self.radioButtonNameFromText.setGeometry(QtCore.QRect(uiPad, row, 20, uiRowOffset-2))\n      self.radioButtonNameFromText.setObjectName(_fromUtf8(\"radioButtonNameFromText\"))\n      self.radioButtonNameFromText.clicked.connect(self.on_radioButtonNameFromText_clicked)\n\n      self.lineEditNameFromText = QtGui.QLineEdit(self.centralWidget)\n      self.lineEditNameFromText.setGeometry(QtCore.QRect(uiPad+20, row, uiColWidth-20, uiRowOffset-2))\n      self.lineEditNameFromText.setObjectName(_fromUtf8(\"lineEditNameFromText\"))\n      self.lineEditNameFromText.textChanged.connect(self.on_lineEditNameFromText_changed)\n\n      self.radioButtonLabelFromText = QtGui.QRadioButton(self.centralWidget)\n      self.radioButtonLabelFromText.setGeometry(QtCore.QRect(uiColWidth+(2*uiPad), row, 20, uiRowOffset-2))\n      self.radioButtonLabelFromText.setObjectName(_fromUtf8(\"radioButtonLabelFromText\"))\n      self.radioButtonLabelFromText.clicked.connect(self.on_radioButtonLabelFromText_clicked)\n\n      self.lineEditLabelFromText = QtGui.QLineEdit(self.centralWidget)\n      self.lineEditLabelFromText.setGeometry(QtCore.QRect(uiColWidth+(2*uiPad)+20, row, uiColWidth-20, uiRowOffset-2))\n      self.lineEditLabelFromText.setObjectName(_fromUtf8(\"lineEditLabelFromText\"))\n      self.lineEditLabelFromText.textChanged.connect(self.on_lineEditLabelFromText_changed)\n\n      row = row+uiRowOffset+uiPad\n      self.labelCapColorFrom = QtGui.QLabel(self.centralWidget)\n      self.labelCapColorFrom.setGeometry(QtCore.QRect(uiPad, row, uiColWidth, uiRowOffset-10))\n      self.labelCapColorFrom.setFont(captionFont)\n      self.labelCapColorFrom.setObjectName(_fromUtf8(\"labelCapColorFrom\"))\n\n      row = row+uiRowOffset\n      self.radioButtonColorFromNew = QtGui.QRadioButton(self.centralWidget)\n      self.radioButtonColorFromNew.setGeometry(QtCore.QRect(uiPad, row, uiColWidth, uiRowOffset-2))\n      self.radioButtonColorFromNew.setObjectName(_fromUtf8(\"radioButtonColorFromNew\"))\n\n      self.radioButtonColorFromOld = QtGui.QRadioButton(self.centralWidget)\n      self.radioButtonColorFromOld.setGeometry(QtCore.QRect(uiColWidth+(2*uiPad), row, uiColWidth, uiRowOffset-2))\n      self.radioButtonColorFromOld.setObjectName(_fromUtf8(\"radioButtonColorFromOld\"))\n\n      row = row+uiRowOffset+uiPad\n      ReplacePart.resize(uiMainWidth,row)\n\n      self.groupBoxNewName.addButton(self.radioButtonNameFromNewDoc)\n      self.groupBoxNewName.addButton(self.radioButtonNameFromNewName)\n      self.groupBoxNewName.addButton(self.radioButtonNameFromNewLabel)\n      self.groupBoxNewName.addButton(self.radioButtonNameFromOldName)\n      self.groupBoxNewName.addButton(self.radioButtonNameFromOldLabel)\n      self.groupBoxNewName.addButton(self.radioButtonNameFromText)\n\n      self.groupBoxNewLabel.addButton(self.radioButtonLabelFromNewDoc)\n      self.groupBoxNewLabel.addButton(self.radioButtonLabelFromNewName)\n      self.groupBoxNewLabel.addButton(self.radioButtonLabelFromNewLabel)\n      self.groupBoxNewLabel.addButton(self.radioButtonLabelFromOldName)\n      self.groupBoxNewLabel.addButton(self.radioButtonLabelFromOldLabel)\n      self.groupBoxNewLabel.addButton(self.radioButtonLabelFromText)\n\n      self.groupBoxColorFrom.addButton(self.radioButtonColorFromNew)\n      self.groupBoxColorFrom.addButton(self.radioButtonColorFromOld)\n\n      self.radioButtonNameFromNewDoc.setChecked(True)  #Set the default name to your preference\n      self.radioButtonLabelFromOldLabel.setChecked(True) #Set the default label to your preference\n      self.radioButtonColorFromOld.setChecked(True) #Set the default color inherit to your preference\n\n      \"\"\"\n      #*** FIXME ***----------------------------\n      self.timer = QtCore.QTimer()\n      QtCore.QObject.connect(self.timer, QtCore.SIGNAL(\"timeout()\"), self.my_update)\n      self.timer.start(2000)\n\n      #*** FIXME ***----------------------------\n      \"\"\"\n      self.retranslateUi(ReplacePart)\n      \n      QtCore.QMetaObject.connectSlotsByName(ReplacePart)\n\n   def retranslateUi(self, ReplacePart):\n      ReplacePart.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)\n      ReplacePart.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)\n      ReplacePart.setWindowTitle(_translate(\"ReplacePart\", \"Replace part\", None))\n      self.labelCapSelected.setText(_translate(\"ReplacePart\", \"Selected Part :\", None))\n      self.labelSelected.setText(_translate(\"ReplacePart\", \"No Selected Part\", None))\n      self.labelNew.setText(_translate(\"ReplacePart\", \"Select New Part\", None))\n      self.LabelOld.setText(_translate(\"ReplacePart\", \"Select Old Part\", None))\n      self.pushButtonNew.setText(_translate(\"ReplacePart\", \"Select New Part\", None))\n      self.pushButtonOld.setText(_translate(\"ReplacePart\", \"Select Old Part\", None))\n      self.pushButtonOk.setText(_translate(\"ReplacePart\", \"Replace Old Part\", None))\n      self.labelCapNewName.setText(_translate(\"ReplacePart\", \"New Name from\", None))\n      self.radioButtonNameFromNewDoc.setText(_translate(\"ReplacePart\", \"New document\", None))\n      self.radioButtonNameFromNewName.setText(_translate(\"ReplacePart\", \"New name\", None))\n      self.radioButtonNameFromNewLabel.setText(_translate(\"ReplacePart\", \"New label\", None))\n      self.radioButtonNameFromOldName.setText(_translate(\"ReplacePart\", \"Old name\", None))\n      self.radioButtonNameFromOldLabel.setText(_translate(\"ReplacePart\", \"Old label\", None))\n      self.radioButtonNameFromText.setText(_translate(\"ReplacePart\", \"t\", None))\n      self.lineEditNameFromText.setText(_translate(\"ReplacePart\", \"name\", None))\n      self.labelCapNewLabel.setText(_translate(\"ReplacePart\", \"New Label from\", None))\n      self.radioButtonLabelFromNewDoc.setText(_translate(\"ReplacePart\", \"New document\", None))\n      self.radioButtonLabelFromNewName.setText(_translate(\"ReplacePart\", \"New name\", None))\n      self.radioButtonLabelFromNewLabel.setText(_translate(\"ReplacePart\", \"New label\", None))\n      self.radioButtonLabelFromOldName.setText(_translate(\"ReplacePart\", \"Old name\", None))\n      self.radioButtonLabelFromOldLabel.setText(_translate(\"ReplacePart\", \"Old label\", None))\n      self.radioButtonLabelFromText.setText(_translate(\"ReplacePart\", \"t\", None))\n      self.lineEditLabelFromText.setText(_translate(\"ReplacePart\", \"label\", None))\n      self.labelCapColorFrom.setText(_translate(\"ReplacePart\", \"Inherit color from\", None))\n      self.radioButtonColorFromNew.setText(_translate(\"ReplacePart\", \"New part\", None))\n      self.radioButtonColorFromOld.setText(_translate(\"ReplacePart\", \"Old part\", None))\n\n   \"\"\"\n   #*** FIXME ***----------------------------\n\n   def my_update(self):\n      selectedPart = self.getSelectedPart()\n      self.labelSelected.setText(selectedPart[0] + \",\" + selectedPart[1] + \",\"+ selectedPart[2])\n      FreeCAD.Console.PrintMessage(\"Selected part: \" + selectedPart[0] + \",\" + selectedPart[1] + \",\"+ selectedPart[2] + \",\" + \"\\n\")\n\n   def closeEvent(self, event):\n      FreeCAD.Console.PrintMessage(\"closeEvent\\n\")\n      if self.timer.stop():\n         self.timer.stop()\n         event.accept() # let the window close\n      else:\n         event.ignore()\n\n   def on_exit(self, event):\n      FreeCAD.Console.PrintMessage(\"exitEvent\\n\")\n      if self.timer.stop():\n         self.timer.stop()\n         event.accept() # let the window close\n      else:\n         event.ignore()\n\n   def hideEvent(self, event):\n      FreeCAD.Console.PrintMessage(\"hideEvent\\n\")\n      if self.timer.stop():\n         self.timer.stop()\n         event.accept() # let the window close\n      else:\n         event.ignore()\n\n   #--------------------------------------\n   \"\"\"\n\n   def on_pushButtonNew_clicked(self):\n      global oldpart\n      global newpart\n      newpart = self.getSelectedPart()\n      if str(newpart[0]) == \"\":\n         self.labelNew.setText(\"No part selected\")\n      else:\n         self.labelNew.setText(str(newpart[0])+ \" , \" + str(newpart[1]))\n         self.radioButtonName()\n         self.radioButtonLabel()\n         Gui.Selection.clearSelection()\n      if str(oldpart[0]) == str(newpart[0]):\n         self.pushButtonOk.setEnabled(False)\n      elif str(oldpart[0]) == \"\":\n         self.pushButtonOk.setEnabled(False)\n      elif str(newpart[0]) == \"\":\n         self.pushButtonOk.setEnabled(False)\n      else:\n         self.pushButtonOk.setEnabled(True)\n\n   def on_pushButtonOld_clicked(self):\n      global oldpart\n      global newpart\n      oldpart = self.getSelectedPart()\n      if str(oldpart[0]) == \"\":\n         self.LabelOld.setText(\"No part selected\")\n      else:\n         self.LabelOld.setText(str(oldpart[0])+ \" , \" + str(oldpart[1]))\n         self.radioButtonName()\n         self.radioButtonLabel()\n         Gui.Selection.clearSelection()\n      if str(oldpart[0]) == str(newpart[0]):\n         self.pushButtonOk.setEnabled(False)\n      elif str(oldpart[0]) == \"\":\n         self.pushButtonOk.setEnabled(False)\n      elif str(newpart[0]) == \"\":\n         self.pushButtonOk.setEnabled(False)\n      else:\n         self.pushButtonOk.setEnabled(True)\n\n   def on_pushButtonOk_clicked(self):\n      if self.radioButtonColorFromNew.isChecked():\n         colors = self.getColors(\"new\")\n      if self.radioButtonColorFromOld.isChecked():\n         colors = self.getColors(\"old\")\n      self.deleteOldPart()\n      newPartName = self.makeSimple(colors)\n      self.moveNew2Old(newPartName)\n      self.move2Group(newPartName)\n      App.ActiveDocument.recompute()\n      App.Console.PrintMessage(\"Part replaced\\n\")\n      #self.window.hide()\n\n   def on_radioButtonNameFromNewDoc_clicked(self):\n      self.radioButtonName()\n\n   def on_radioButtonNameFromNewName_clicked(self):\n      self.radioButtonName()\n\n   def on_radioButtonNameFromNewLabel_clicked(self):\n      self.radioButtonName()\n\n   def on_radioButtonNameFromOldName_clicked(self):\n      self.radioButtonName()\n\n   def on_radioButtonNameFromOldLabel_clicked(self):\n      self.radioButtonName()\n\n   def on_radioButtonNameFromText_clicked(self):\n      self.radioButtonName()\n\n   def on_lineEditNameFromText_changed(self):\n      self.radioButtonName()\n\n   def on_radioButtonLabelFromNewDoc_clicked(self):\n      self.radioButtonLabel()\n\n   def on_radioButtonLabelFromNewName_clicked(self):\n      self.radioButtonLabel()\n\n   def on_radioButtonLabelFromNewLabel_clicked(self):\n      self.radioButtonLabel()\n\n   def on_radioButtonLabelFromOldName_clicked(self):\n      self.radioButtonLabel()\n\n   def on_radioButtonLabelFromOldLabel_clicked(self):\n      self.radioButtonLabel()\n\n   def on_radioButtonLabelFromText_clicked(self):\n      self.radioButtonLabel()\n\n   def on_lineEditLabelFromText_changed(self):\n      self.radioButtonLabel()\n\n   def radioButtonName(self):\n      global newPartName\n      if self.radioButtonNameFromNewDoc.isChecked():\n         newPartName=self.getFromNew(0)\n      elif self.radioButtonNameFromNewName.isChecked():\n         newPartName=self.getFromNew(1)\n      elif self.radioButtonNameFromNewLabel.isChecked():\n         newPartName=self.getFromNew(2)\n      elif self.radioButtonNameFromOldName.isChecked():\n         newPartName=self.getFromOld(1)\n      elif self.radioButtonNameFromOldLabel.isChecked():\n         newPartName=self.getFromOld(2)\n      elif self.radioButtonNameFromText.isChecked():\n         newPartName=str(self.lineEditNameFromText.displayText())\n      else:\n         FreeCAD.Console.PrintError(\"Error: Unknown Name error\\n\")\n\n   def radioButtonLabel(self):\n      global newPartLabel\n      if self.radioButtonLabelFromNewDoc.isChecked():\n         newPartLabel=self.getFromNew(0)\n      elif self.radioButtonLabelFromNewName.isChecked():\n         newPartLabel=self.getFromNew(1)\n      elif self.radioButtonLabelFromNewLabel.isChecked():\n         newPartLabel=self.getFromNew(2)\n      elif self.radioButtonLabelFromOldName.isChecked():\n         newPartLabel=self.getFromOld(1)\n      elif self.radioButtonLabelFromOldLabel.isChecked():\n         newPartLabel=self.getFromOld(2)\n      elif self.radioButtonLabelFromText.isChecked():\n         newPartLabel=str(self.lineEditLabelFromText.displayText())\n      else:\n         FreeCAD.Console.PrintError(\"Error: Unknown Label error\\n\")\n\n   def getFromNew(self, index):\n      global newpart\n      return newpart[index];\n\n   def getFromOld(self, index):\n      global oldpart\n      return oldpart[index];\n\n   def getSelectedPart(self):\n      sel = FreeCADGui.Selection.getSelection()\n      if sel:\n         sel = sel[0]\n         name = sel.Name\n         label = sel.Label\n         doc = FreeCAD.ActiveDocument.Name\n         pos = App.ActiveDocument.getObject(name).Placement.Base   \n         rot = App.ActiveDocument.getObject(name).Placement.Rotation\n         grp = self.inGroup(name)\n         the_part=[doc , name, label, pos, rot, grp];\n         return the_part;\n      else:\n         FreeCAD.Console.PrintError(\"Error: One object must be selected\\n\")\n         the_part=[\"\" , \"\"];\n         return the_part;\n\n   def makeSimple(self, colors):\n      global oldpart\n      global newpart\n      global newPartName\n      global newPartLabel\n      fixPartName = newPartName\n      #newPartLabel = newPartLabel\n      newPartName = self.uniqeName(fixPartName)\n      App.setActiveDocument(oldpart[0])\n      Gui.ActiveDocument=Gui.getDocument(oldpart[0])\n      App.ActiveDocument=App.getDocument(oldpart[0])\n      App.ActiveDocument.addObject('Part::Feature',newPartName).Shape=App.getDocument(newpart[0]).getObject(newpart[1]).Shape\n      App.ActiveDocument.ActiveObject.Label = newPartLabel\n      App.ActiveDocument.getObject(newPartName).Label = newPartLabel\n      Gui.getDocument(oldpart[0]).getObject(newPartName).ShapeColor = colors[0]\n      Gui.getDocument(oldpart[0]).getObject(newPartName).LineColor =  colors[1]\n      Gui.getDocument(oldpart[0]).getObject(newPartName).PointColor = colors[2]\n      return newPartName;\n\n   def moveNew2Old(self, newPartName):\n      global oldpart\n      global newpart\n      App.ActiveDocument.getObject(newPartName).Placement = App.Placement(oldpart[3], oldpart[4])\n\n   def deleteOldPart(self):\n      global oldpart\n      App.setActiveDocument(oldpart[0])\n      Gui.ActiveDocument=Gui.getDocument(oldpart[0])\n      App.ActiveDocument=App.getDocument(oldpart[0])\n      App.ActiveDocument.removeObject(oldpart[1])\n\n   def inGroup(self, partName):\n      try:\n         grp = App.ActiveDocument.getObject(partName).InList\n         grpName = grp[0].Name\n      except:\n         grpName = \"\"\n      return grpName;\n\n   def move2Group(self,  newPartName):\n      global oldpart\n      grp = App.ActiveDocument.getObject(oldpart[5])\n      part = App.ActiveDocument.getObject(newPartName)\n      grp.addObject(part)\n\n   def getColors(self, newORold):\n      global oldpart\n      global newpart\n      if newORold == \"new\":\n         shape = Gui.getDocument(newpart[0]).getObject(newpart[1]).ShapeColor\n         line = Gui.getDocument(newpart[0]).getObject(newpart[1]).LineColor\n         point = Gui.getDocument(newpart[0]).getObject(newpart[1]).PointColor\n      elif newORold == \"old\":\n         shape = Gui.getDocument(oldpart[0]).getObject(oldpart[1]).ShapeColor\n         line = Gui.getDocument(oldpart[0]).getObject(oldpart[1]).LineColor\n         point = Gui.getDocument(oldpart[0]).getObject(oldpart[1]).PointColor\n      else:\n         FreeCAD.Console.PrintMessage(\"Error! Color from newpart or old?\\n\")\n      colors = [ shape, line, point ];\n      return colors;\n\n   def uniqeName(self, newPartName):\n      global oldpart\n      objs = App.getDocument(oldpart[0]).Objects\n      for obj in objs:\n         if obj.Name  == newPartName:\n            if obj.Name != oldpart[1]:\n               i = 0\n               for iobj in objs:\n                  if iobj.Name == newPartName + \"_\" + str(i) and iobj.Name != oldpart[1]:\n                     i += 1\n               return newPartName + \"_\" + str(i);\n      return newPartName;\n\nclass replace():\n   Gui.Selection.clearSelection()\n   d = QtGui.QWidget()\n   d.ui = Ui_ReplacePart()\n   d.ui.setupUi(d)\n   d.show()",
    "url": "https://wiki.freecad.org/Macro_Replace_Part_in_Assembly",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-09-10",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Joakim Isaksson <ralvejd[at]users.sourceforge.net>",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Replace_Part.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/0/07/Replace_Part.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Select Hovering",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro select a choice Face, Edge, Vertex hovering by the mouse.<br />PS: For unselected one face (or other) click the <span style=\"background: #f9f9f9; -moz-box-shadow: 0.1em 0.1em 0.2em rgba(0,0,0,0.1); -webkit-box-shadow: 0.1em 0.1em 0.2em rgba(0,0,0,0.1); box-shadow: 0.1em 0.1em 0.2em rgba(0,0,0,0.1); border: 1px solid #888888; border-radius: 0.3em; padding: 0px 5px 1px 5px;\">Pause grab</span> and use the standard procedure&#160;: CTRL + Click<br /><br />Macro version: 00.04<br />Last modified: 2024-01-11<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/d/d8/Macro_Select_Hovering.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "This macro select a choice Face, Edge, Vertex hovering by the mouse.",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n#\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2017 2018 2019 2020 2023 2024 <mario52>                 *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#\n#Macro_ _01-25/12/2017 02-26/12/2017 03-26/12/2017 03b-28/10/2020 04-15/12/2023 11/01/2024\n#\n#OS: Windows 10 build 19045\n#Word size of FreeCAD: 64-bit\n#Version: 0.22.0dev.35554 (Git)\n#Build type: Release\n#Branch: main\n#Hash: 8e2ab9f76888ac4da971f9d5069cec7bcc2b572f\n#Python 3.10.13, Qt 5.15.8, Coin 4.0.2, Vtk 9.2.6, OCC 7.6.3\n#Locale: French/Mars (fr_MA)\n#\n#\n__title__   = \"Select_Hovering\"\n__author__  = \"Mario52\"\n__url__     = \"http://www.freecadweb.org/index-fr.html\"\n__wiki__    = \"http://www.freecadweb.org/wiki/index.php?title=Macro_Select_Hovering\"\n__icon__    = \"https://wiki.freecad.org/images/d/d8/Macro_Select_Hovering.png\"\n__version__ = \"00.04\"\n__date__    = \"2024/01/11\" #YYYY/MM/DD\n#\n\n# icon by FreeCAD\nimport PySide2\nfrom PySide2 import QtWidgets, QtGui ,QtCore\nfrom PySide2.QtWidgets import *\nfrom PySide2.QtGui import *\nfrom PySide2.QtCore import *\n \nimport Draft, Part, PartGui, FreeCADGui, FreeCAD\n\nGui = FreeCADGui\nApp = FreeCAD\n\n#### ParamGetSet\nglobal FC_Macro_ParamGetSet; FC_Macro_ParamGetSet = FreeCAD.ParamGet(u\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__)    # FC_Macro_ParamGetSet\n## ex: FC_Macro_ParamGetSet.GetBool(u\"switchVersionSearch\")\nFC_Macro_ParamGetSet.SetString(\"Version\",__version__ + \" (\" + __date__ + \")\")# \n#### geomery\nglobal setMainWindowMoveX  ; setMainWindowMoveX  = 950  # position X macro window\nglobal setMainWindowMoveY  ; setMainWindowMoveY  = 200  # position Y macro window\nglobal setFrameWindowSizeX ; setFrameWindowSizeX = 340  # dimension X macro window\nglobal setFrameWindowSizeY ; setFrameWindowSizeY = 540  # dimension Y macro window\n\nsetMainWindowMoveX = FC_Macro_ParamGetSet.GetInt(\"setMainWindowMoveX\")\nsetMainWindowMoveY = FC_Macro_ParamGetSet.GetInt(\"setMainWindowMoveY\")\nsetFrameWindowSizeX= FC_Macro_ParamGetSet.GetInt(\"setFrameWindowSizeX\", setFrameWindowSizeX)\nFC_Macro_ParamGetSet.SetInt(\"setFrameWindowSizeX\", setFrameWindowSizeX)\nsetFrameWindowSizeY= FC_Macro_ParamGetSet.GetInt(\"setFrameWindowSizeY\", setFrameWindowSizeY)\nFC_Macro_ParamGetSet.SetInt(\"setFrameWindowSizeY\", setFrameWindowSizeY)\n#### geomery\nFC_Macro_ParamGetSet.SetString(u\"Version\", __version__ + \" (\" + __date__ + \")\")\n##\nglobal seTTextHeigthValue       #; seTTextHeigthValue       = 11  # heigth Text value\nseTTextHeigthValue = FC_Macro_ParamGetSet.GetInt(u\"seTTextHeigthValue\")\nif seTTextHeigthValue == 0: seTTextHeigthValue = 10\nFC_Macro_ParamGetSet.SetInt(u\"seTTextHeigthValue\", seTTextHeigthValue)               # 11\n####\n\nglobal ui               ; ui = \"\"\nglobal s                ; s  = \"\"\nglobal objectsListing   ; objectsListing   = []\nglobal objectsListingA  ; objectsListingA  = []\nglobal objectsMemo      ; objectsMemo      = []\nglobal objectsMemoA     ; objectsMemoA     = []\nglobal toolTipCBBox_Memo;toolTipCBBox_Memo = []\n\nglobal compt_Memo      ; compt_Memo      = 0\nglobal toolTip_Memo    ; toolTip_Memo    = []\nglobal CB_ResetMode    ; CB_ResetMode    = 0\n\nglobal cTB      ; \nglobal oTB      ; \nglobal vTB      ; \nglobal position ; position = \"\"\nglobal pos2D    ; \n\nimport copy                                                  # pour copier 2 tableaux\n#import re\n#import time\n#import operator\n#from operator import itemgetter, attrgetter, methodcaller    # pour sort \n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\nclass Ui_MainWindow(object):\n\n    def __init__(self, MainWindow):\n        self.window = MainWindow\n        global seTTextHeigthValue\n        #################################################################################\n        #self.path  = FreeCAD.ConfigGet(\"AppHomePath\")\n        #self.path  = FreeCAD.ConfigGet(\"UserAppData\")\n        #self.path  = \"your path\"\n        param = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")# macro path\n        self.macroPath = param.GetString(\"MacroPath\",\"\") + \"/\"                   # macro path\n        self.macroPath = self.macroPath.replace(\"\\\\\",\"/\")\n#        print( \"Path for the icons : \" , self.macroPath)\n        #################################################################################\n        self.FontImpost    = \"Arial\"\n        self.fontGlobal_08 = QtGui.QFont()            # pour compatibilite Windows Linux\n        self.fontGlobal_08.setFamily(self.FontImpost) # pour compatibilite Windows Linux\n        self.fontGlobal_08.setPointSize(seTTextHeigthValue) # pour compatibilite Windows Linux\n        #self.xxxx.setFont(self.fontGlobal_08)        # pour W L\n        #self.xxxx.setFont(QtGui.QFont(self.FontImpost,weight=QtGui.QFont.Bold))  # Bold\n        #################################################################################\n\n        #Gui.Selection.clearSelection()\n        self.comptFace         = 0\n        self.comptEdge         = 0\n        self.comptVertex       = 0\n        self.comptNumbObject   = 0\n        self.comptFaceEdgeVertex = 0\n        self.Stop_Grab         = 1\n        self.comptSurfaceFace  = 0.0\n        self.comptSurfaceTotal = 0.0\n        self.comptLengthObject = 0.0\n        self.comptLengthTotal  = 0.0\n\n    def setupUi(self, MainWindow):\n        global setMainWindowMoveX\n        global setMainWindowMoveX\n        global setFrameWindowSizeX\n        global setFrameWindowSizeY\n\n#        MainWindow.resize(197, 307)\n#        MainWindow.setMinimumSize(QtCore.QSize(197, 350))\n#        MainWindow.setMaximumSize(QtCore.QSize(197, 350))\n#        MainWindow.move(950, 200)\n#        MainWindow.move(setMainWindowMoveX, setMainWindowMoveX)\n        MainWindow.setGeometry(setMainWindowMoveX, setMainWindowMoveY, setFrameWindowSizeX, setFrameWindowSizeY)\n\n        self.centralwidget = QtWidgets.QWidget(MainWindow)\n        self.centralwidget.setObjectName(_fromUtf8(\"centralwidget\"))\n\n        self.GBOX_00 = QtWidgets.QGroupBox()\n        self.GBOX_00.setFont(self.fontGlobal_08)         # pour W L\n        self.GBOX_00.setObjectName(_fromUtf8(\"GBOX_00\"))\n\n        self.GBOX_01_Face = QtWidgets.QGroupBox()\n        self.GBOX_01_Face.setFont(self.fontGlobal_08)         # pour W L\n        self.GBOX_01_Face.setObjectName(_fromUtf8(\"GBOX_01_Face\"))\n\n        self.LE_02_Area_Object = QtWidgets.QLineEdit()\n        self.LE_02_Area_Object.setFont(self.fontGlobal_08)    # pour W L\n        self.LE_02_Area_Object.setObjectName(_fromUtf8(\"LE_02_Area_Object\"))\n\n        self.LAB_05_Area_Object = QtWidgets.QLabel()\n        self.LAB_05_Area_Object.setFont(self.fontGlobal_08)   # pour W L\n        self.LAB_05_Area_Object.setObjectName(_fromUtf8(\"LAB_05_Area_Object\"))\n\n        self.CB_01_Sel_Face = QtWidgets.QCheckBox()\n        self.CB_01_Sel_Face.setIcon(QtGui.QIcon.fromTheme(\"Draft\",QtGui.QIcon(\":/icons/face-selection.svg\")))\n        self.CB_01_Sel_Face.setFont(self.fontGlobal_08)       # pour W L\n        self.CB_01_Sel_Face.setObjectName(_fromUtf8(\"CB_01_Sel_Face\"))\n\n        self.LE_01_Area_Total = QtWidgets.QLineEdit()\n        self.LE_01_Area_Total.setFont(self.fontGlobal_08)     # pour W L\n        self.LE_01_Area_Total.setObjectName(_fromUtf8(\"LE_01_Area_Total\"))\n\n        self.LAB_01_Face = QtWidgets.QLabel()\n        self.LAB_01_Face.setFont(self.fontGlobal_08)          # pour W L\n        self.LAB_01_Face.setObjectName(_fromUtf8(\"LAB_01_Face\"))\n\n        self.LAB_04_Area_Total = QtWidgets.QLabel()\n        self.LAB_04_Area_Total.setFont(self.fontGlobal_08)    # pour W L\n        self.LAB_04_Area_Total.setObjectName(_fromUtf8(\"LAB_04_Area_Total\"))\n\n\n        self.GBOX_02_Edge = QtWidgets.QGroupBox()\n        self.GBOX_02_Edge.setFont(self.fontGlobal_08)         # pour W L\n        self.GBOX_02_Edge.setObjectName(_fromUtf8(\"GBOX_02_Edge\"))\n\n        self.LAB_02_Edge = QtWidgets.QLabel()\n        self.LAB_02_Edge.setFont(self.fontGlobal_08)          # pour W L\n        self.LAB_02_Edge.setObjectName(_fromUtf8(\"LAB_02_Edge\"))\n\n        self.CB_02_Sel_Edge = QtWidgets.QCheckBox()\n        self.CB_02_Sel_Edge.setIcon(QtGui.QIcon.fromTheme(\"Draft\",QtGui.QIcon(\":/icons/edge-selection.svg\")))\n        self.CB_02_Sel_Edge.setFont(self.fontGlobal_08)       # pour W L\n        self.CB_02_Sel_Edge.setObjectName(_fromUtf8(\"CB_02_Sel_Edge\"))\n\n        self.LE_03_Length_Total = QtWidgets.QLineEdit()\n        self.LE_03_Length_Total.setFont(self.fontGlobal_08)   # pour W L\n        self.LE_03_Length_Total.setObjectName(_fromUtf8(\"LE_03_Length_Total\"))\n\n        self.LE_04_Length_Object = QtWidgets.QLineEdit()\n        self.LE_04_Length_Object.setFont(self.fontGlobal_08)  # pour W L\n        self.LE_04_Length_Object.setObjectName(_fromUtf8(\"LE_04_Length_Object\"))\n\n        self.LAB_06_Length_Total = QtWidgets.QLabel()\n        self.LAB_06_Length_Total.setFont(self.fontGlobal_08)  # pour W L\n        self.LAB_06_Length_Total.setObjectName(_fromUtf8(\"LAB_06_Length_Total\"))\n\n        self.LAB_07_Length_Obgect = QtWidgets.QLabel()\n        self.LAB_07_Length_Obgect.setFont(self.fontGlobal_08) # pour W L\n        self.LAB_07_Length_Obgect.setObjectName(_fromUtf8(\"LAB_07_Length_Obgect\"))\n\n\n        self.GBOX_03_Vertex = QtWidgets.QGroupBox()\n        self.GBOX_03_Vertex.setFont(self.fontGlobal_08)       # pour W L\n        self.GBOX_03_Vertex.setObjectName(_fromUtf8(\"GBOX_03_Vertex\"))\n\n        self.LAB_03_Vertex = QtWidgets.QLabel()\n        self.LAB_03_Vertex.setFont(self.fontGlobal_08)        # pour W L\n        self.LAB_03_Vertex.setObjectName(_fromUtf8(\"LAB_03_Vertex\"))\n\n        self.CB_03_Sel_Vertex = QtWidgets.QCheckBox()\n        self.CB_03_Sel_Vertex.setIcon(QtGui.QIcon.fromTheme(\"Draft\",QtGui.QIcon(\":/icons/vertex-selection.svg\")))\n        self.CB_03_Sel_Vertex.setFont(self.fontGlobal_08)     # pour W L\n        self.CB_03_Sel_Vertex.setObjectName(_fromUtf8(\"CB_03_Sel_Vertex\"))\n\n\n        self.GBOX_04_Main = QtWidgets.QGroupBox()\n        self.GBOX_04_Main.setFont(self.fontGlobal_08)         # pour W L\n        self.GBOX_04_Main.setObjectName(_fromUtf8(\"GBOX_04_Main\"))\n\n        self.LE_00_InfoSel = QtWidgets.QLineEdit()\n        self.LE_00_InfoSel.setFont(self.fontGlobal_08)        # pour W L\n        self.LE_00_InfoSel.setObjectName(_fromUtf8(\"LE_00_InfoSel\"))\n\n        self.CBBox_Memo = QtWidgets.QComboBox()\n        self.CBBox_Memo.setMaxVisibleItems(16)\n        QtCore.QObject.connect(self.CBBox_Memo, QtCore.SIGNAL(\"textActivated (QString)\"), self.on_CBBox_Memo_Clicked)\n        self.CBBox_Memo.textHighlighted.connect(self.on_CBBox_Memo_Info_ToolTip)\n\n        self.PB_05_CBBox_Memo = QtWidgets.QPushButton()\n        self.PB_05_CBBox_Memo.setIcon(QtGui.QIcon.fromTheme(\"View\",QtGui.QIcon(\":/icons/edit-copy.svg\")))\n        self.PB_05_CBBox_Memo.setFont(self.fontGlobal_08)      # pour W L\n        self.PB_05_CBBox_Memo.setObjectName(_fromUtf8(\"PB_05_CBBox_Memo\"))\n        self.PB_05_CBBox_Memo.clicked.connect(self.on_PB_05_CBBox_Memo_clicked)\n\n        self.PB_03_Box = QtWidgets.QPushButton()\n        self.PB_03_Box.setIcon(QtGui.QIcon.fromTheme(\"View\",QtGui.QIcon(\":/icons/edit-element-select-box.svg\")))\n        self.PB_03_Box.setFont(self.fontGlobal_08)      # pour W L\n        self.PB_03_Box.setObjectName(_fromUtf8(\"PB_03_Box\"))\n        self.PB_03_Box.clicked.connect(self.on_PB_03_Box_clicked)\n\n        self.PB_04_Reset = QtWidgets.QPushButton()\n        self.PB_04_Reset.setIcon(QtGui.QIcon.fromTheme(\"View\",QtGui.QIcon(\":/icons/delete.svg\")))\n        self.PB_04_Reset.setFont(self.fontGlobal_08)      # pour W L\n        self.PB_04_Reset.setObjectName(_fromUtf8(\"PB_04_Reset\"))\n        self.PB_04_Reset.clicked.connect(self.on_PB_04_Reset_clicked)\n\n        self.PB_05_Reset_Memo = QtWidgets.QPushButton()\n        self.PB_05_Reset_Memo.setIcon(QtGui.QIcon.fromTheme(\"View\",QtGui.QIcon(\":/icons/delete.svg\")))\n        self.PB_05_Reset_Memo.setFont(self.fontGlobal_08)      # pour W L\n        self.PB_05_Reset_Memo.setObjectName(_fromUtf8(\"PB_05_Reset_Memo\"))\n        self.PB_05_Reset_Memo.clicked.connect(self.on_PB_05_Reset_Memo_clicked)\n\n        self.PB_06_removeSelection_Selection = QtWidgets.QPushButton()\n        self.PB_06_removeSelection_Selection.setIcon(QtGui.QIcon.fromTheme(\"View\",QtGui.QIcon(\":/icons/delete.svg\")))\n        self.PB_06_removeSelection_Selection.setFont(self.fontGlobal_08)      # pour W L\n        self.PB_06_removeSelection_Selection.setObjectName(_fromUtf8(\"PB_06_removeSelection_Selection\"))\n        self.PB_06_removeSelection_Selection.clicked.connect(self.on_PB_06_removeSelection_Selection_clicked)\n\n        self.PB_01_Quit = QtWidgets.QPushButton()\n        self.PB_01_Quit.setIcon(QtGui.QIcon.fromTheme(\"View\",QtGui.QIcon(\":/icons/application-exit.svg\")))\n        self.PB_01_Quit.setFont(self.fontGlobal_08)           # pour W L\n        self.PB_01_Quit.setObjectName(_fromUtf8(\"PB_01_Quit\"))\n        self.PB_01_Quit.clicked.connect(self.on_PB_Quit_clicked)\n\n        self.PB_02_Stop_Grab = QtWidgets.QPushButton()\n        self.PB_02_Stop_Grab.setIcon(QtGui.QIcon.fromTheme(\"View\",QtGui.QIcon(\":/icons/view-refresh.svg\")))\n        self.PB_02_Stop_Grab.setFont(self.fontGlobal_08)      # pour W L\n        self.PB_02_Stop_Grab.setObjectName(_fromUtf8(\"PB_02_Stop_Grab\"))\n        self.PB_02_Stop_Grab.clicked.connect(self.on_PB_02_Stop_Grab_clicked)\n\n        MainWindow.setCentralWidget(self.centralwidget)\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n        #### layout ###################################################\n        self.gridLayoutWidget = QtWidgets.QWidget(self.centralwidget)   # cadre principal\n        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)\n        self.gridLayout.setContentsMargins(10, 10, 10, 10)\n\n        self.gridLayout_3 = QtWidgets.QGridLayout(self.GBOX_00)\n        self.gridLayout_3.setContentsMargins(10, 10, 10, 10)\n\n        self.gridLayout_2 = QtWidgets.QGridLayout(self.GBOX_01_Face)\n        self.gridLayout_2.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_2.addWidget(self.CB_01_Sel_Face, 0, 0, 1, 1)\n        self.gridLayout_2.addWidget(self.LAB_01_Face, 0, 1, 1, 1)\n        self.gridLayout_2.addWidget(self.LAB_04_Area_Total, 1, 0, 1, 1)\n        self.gridLayout_2.addWidget(self.LAB_05_Area_Object, 1, 1, 1, 1)\n        self.gridLayout_2.addWidget(self.LE_01_Area_Total, 2, 0, 1, 1)\n        self.gridLayout_2.addWidget(self.LE_02_Area_Object, 2, 1, 1, 1)\n        self.gridLayout_3.addWidget(self.GBOX_01_Face, 0, 0, 1, 1)\n\n        self.gridLayout_4 = QtWidgets.QGridLayout(self.GBOX_02_Edge)\n        self.gridLayout_4.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_4.addWidget(self.CB_02_Sel_Edge, 0, 0, 1, 1)\n        self.gridLayout_4.addWidget(self.LAB_02_Edge, 0, 1, 1, 1)\n        self.gridLayout_4.addWidget(self.LAB_06_Length_Total, 1, 0, 1, 1)\n        self.gridLayout_4.addWidget(self.LAB_07_Length_Obgect, 1, 1, 1, 1)\n        self.gridLayout_4.addWidget(self.LE_03_Length_Total, 2, 0, 1, 1)\n        self.gridLayout_4.addWidget(self.LE_04_Length_Object, 2, 1, 1, 1)\n        self.gridLayout_3.addWidget(self.GBOX_02_Edge, 1, 0, 1, 1)\n\n        self.gridLayout_5 = QtWidgets.QGridLayout(self.GBOX_03_Vertex)\n        self.gridLayout_5.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_5.addWidget(self.CB_03_Sel_Vertex, 0, 0, 1, 1)\n        self.gridLayout_5.addWidget(self.LAB_03_Vertex, 0, 1, 1, 1)\n        self.gridLayout_3.addWidget(self.GBOX_03_Vertex, 2, 0, 1, 1)\n\n        self.gridLayout_7 = QtWidgets.QGridLayout(self.GBOX_04_Main)\n        self.gridLayout_7.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_7.addWidget(self.LE_00_InfoSel, 0, 0, 1, 2)\n        self.gridLayout_7.addWidget(self.CBBox_Memo, 1, 0, 1, 2)\n        self.gridLayout_7.addWidget(self.PB_05_CBBox_Memo, 2, 0, 1, 2)\n        self.gridLayout_7.addWidget(self.PB_03_Box, 3, 0, 1, 2)\n        self.gridLayout_7.addWidget(self.PB_04_Reset, 4, 0, 1, 1)\n        self.gridLayout_7.addWidget(self.PB_05_Reset_Memo, 4, 1, 1, 1)\n        self.gridLayout_7.addWidget(self.PB_06_removeSelection_Selection, 5, 0, 1, 2)\n        self.gridLayout_7.addWidget(self.PB_01_Quit, 6, 0, 1, 1)\n        self.gridLayout_7.addWidget(self.PB_02_Stop_Grab, 6, 1, 1, 1)\n        self.gridLayout_3.addWidget(self.GBOX_04_Main, 3, 0, 1, 1)\n        self.gridLayout.addWidget(self.GBOX_00, 0, 0, 1, 1)\n        #### layout ###################################################\n\n    def retranslateUi(self, MainWindow):\n        MainWindow.setWindowTitle(\"Select_Hovering\")\n        MainWindow.setWindowIcon(QtGui.QIcon(self.macroPath + \"Macro_\" + __title__ + \".png\"))#\n        ####\n        self.GBOX_00.setTitle(\"Version: \" + __version__ + \" : \" + __date__)\n        self.GBOX_01_Face.setTitle(\"Face\")\n        self.CB_01_Sel_Face.setText(\"Select Face\")\n        self.LAB_01_Face.setText(\"0\")\n        self.LAB_04_Area_Total.setText(\"Area Total\")\n        self.LAB_04_Area_Total.setToolTip(\"Area Total of the faces selected\")\n        self.LAB_05_Area_Object.setText(\"Area Face\")\n        self.LAB_05_Area_Object.setToolTip(\"Area of the latest face selected\")\n        self.LE_01_Area_Total.setToolTip(\"Area Total of the faces selected\")\n        self.LE_02_Area_Object.setToolTip(\"Area of the latest face selected\")\n\n        self.GBOX_02_Edge.setTitle(\"Edge\")\n        self.CB_02_Sel_Edge.setText(\"Select Edge\")\n        self.LAB_02_Edge.setText(\"0\")\n        self.LAB_06_Length_Total.setText(\"Length Total\")\n        self.LAB_06_Length_Total.setToolTip(\"Length of the total Edges selected\")\n        self.LAB_07_Length_Obgect.setText(\"Length Edge\")\n        self.LAB_07_Length_Obgect.setToolTip(\"Length of the latest Edge selected\")\n        self.LE_03_Length_Total.setToolTip(\"Length of the total Edges selected\")\n        self.LE_04_Length_Object.setToolTip(\"Length of the latest Edges selected\")\n\n        self.GBOX_03_Vertex.setTitle(\"Vertex\")\n        self.CB_03_Sel_Vertex.setText(\"Select Vertex\")\n        self.LAB_03_Vertex.setText(\"0\")\n\n        self.GBOX_04_Main.setTitle(\"Main\")\n        self.CBBox_Memo.setToolTip(\"\\n\" + \"Detail of label ex:\" + \"\\n\\n\"\n                                   \"2: ( 15 sel. )( Obj. 2, Fa. 5, Ed. 10, Ve. 4)\" + \"\\n\\n\"\n                                   \"2:  \\t: item ComboBox\" + \"\\n\"\n                                   \"15 sel.  \\t: number of selection(s)\" + \"\\n\"\n                                   \"Obj. 2\\t: number of different object(s)\" + \"\\n\"\n                                   \"Fa. 5\\t: number total of Face(s)\" + \"\\n\"\n                                   \"Ed. 6\\t: number total of Edge(s)\" + \"\\n\"\n                                   \"Ve. 4\\t: number total of Vertex(s)\" + \"\\n\"\n                                   \"\"+ \"\\n\")\n        self.PB_05_CBBox_Memo.setText(\"Memo selection\")\n        self.PB_05_CBBox_Memo.setToolTip(\"Store the selection(s)\" + \"\\n\"\n                                         \"If sveral documents hare open and objects selected:\" + \"\\n\"\n                                         \"the macro is upgrade the data of the selection for each document\")\n        self.PB_03_Box.setText(\"Selected by Box\")\n        self.PB_03_Box.setToolTip(\"\\n\" + \"Select all elements (with the option checked) of the object(s) selected\" + \"\\n\" + \"\\n\"\n                                  \"Select the objects with the Box tool or the objects already selected\" + \"\\n\" + \"\\n\"\n                                  \"Choice your CheckBox 'Select Face', 'Select Edge' or 'Select Vertex'\" + \"\\n\"\n                                  \"Click the 'Selected by box' button\" + \"\\n\" + \"\\n\"\n                                  \"This feature not select the object but his SubObject ... Face, Edge, Vertex\" + \"\\n\"\n                                  \"it may take time depending on the object being worked on\" + \"\\n\")\n        self.PB_04_Reset.setText(\"Reset Data\")\n        self.PB_04_Reset.setToolTip(\"Reset all data information in the macro\")\n        self.PB_05_Reset_Memo.setText(\"Reset Memo\")\n        self.PB_05_Reset_Memo.setToolTip(\"Reset all memorised data\")\n        self.PB_06_removeSelection_Selection.setText(\"Remove Selection\")\n        self.PB_06_removeSelection_Selection.setToolTip(\"Remove Selection of active document\" + \"\\n\"\n                                         \"If you click in the 3Dview\" + \"\\n\"\n                                         \" ! all objects selected in all document open hare removed\" + \"\\n\")\n        self.PB_01_Quit.setText(\"Quit\")\n        self.PB_02_Stop_Grab.setText(\"Pause grab / Refresh\")\n        self.PB_02_Stop_Grab.setToolTip(\"\\n\" + \"Use CTRL + click mouse\" + \"\\n\"\n                                        \"for select or unselect object(s)\" + \"\\n\"\n                                        \"or validate in the macro the objects selected in 3Dview\" + \"\\n\"\n                                        \"Ex: objects selectet before starting the macro or refresh\")\n        MainWindow.setWindowFlags(PySide2.QtCore.Qt.WindowStaysOnTopHint)       # PySide cette fonction met la fenetre en avant\n\n    def around(self, number):\n        return round(number, 5)\n\n    def displayOnWindow(self):\n        self.LAB_01_Face.setText(str(self.comptFace))\n        self.LE_01_Area_Total.setText(str(self.around(self.comptSurfaceTotal)))\n        self.LE_02_Area_Object.setText(str(self.around(self.comptSurfaceFace)))\n\n        self.LAB_02_Edge.setText(str(self.comptEdge))\n        self.LE_03_Length_Total.setText(str(self.around(self.comptLengthTotal)))\n        self.LE_04_Length_Object.setText(str(self.around(self.comptLengthObject)))\n\n        self.LAB_03_Vertex.setText(str(self.comptVertex))\n\n        self.comptFaceEdgeVertex = self.comptFace + self.comptEdge + self.comptVertex\n        self.GBOX_04_Main.setTitle(\"Main ( Obj: \" + str(self.comptNumbObject) + \" ) ( Sub: \" + str(self.comptFaceEdgeVertex) + \" ) ( Tot: \" + str(self.comptNumbObject + self.comptFaceEdgeVertex) + \" )\")\n\n        if self.comptFace   != 0 : self.GBOX_01_Face.setEnabled(True)    # cas selection hors de la macro (pause grab)\n        if self.comptEdge   != 0 : self.GBOX_02_Edge.setEnabled(True)    # cas selection hors de la macro (pause grab)\n        if self.comptVertex != 0 : self.GBOX_03_Vertex.setEnabled(True)  # cas selection hors de la macro (pause grab)\n\n    def selectSelection(self):     # one subObjects\n        global objectsListing\n        global objectsMemoA\n\n        count  = self.comptFace = self.comptSurfaceFace = self.comptSurfaceTotal = 0\n        count  = self.comptEdge = self.comptLengthObject = self.comptLengthTotal = 0\n        count  = self.comptVertex = 0\n        objets = []\n        objectsMemoA = []\n\n        for i in range(len(objectsListing)):\n            selected = FreeCAD.ActiveDocument.getObject(objectsListing[i]) #<PartDesign::AdditivePipe>\n            try:\n                if str(selected) != \"<body object>\":\n                    typeID = selected.TypeId  # 'PartDesign::AdditivePipe'\n                    if \"PartDesign\" in typeID:\n                        parentNamePaDe = selected.getParent().Name # 'Body001'\n                        subNamePaDe    = selected.Name             # 'Additivepipe001'\n\n                        count = 0\n                        for ii in selected.Parents[0][0].Shape.Faces:\n                            count += 1\n                            faceSel = \"Face\" + str(count)\n                            faceA = \"\"\n                            faceA = Gui.Selection.isSelected(FreeCAD.ActiveDocument.getObject(parentNamePaDe), subNamePaDe + \".\" + faceSel)\n                            if faceA == True:\n                                objectsMemoA.append((objectsListing[i], faceSel))\n                                self.comptFace += 1\n                                self.comptSurfaceFace = FreeCAD.ActiveDocument.getObject(parentNamePaDe).Shape.getElement(faceSel).Area\n                                self.comptSurfaceTotal += self.comptSurfaceFace\n\n                        count = 0\n                        for ii in selected.Parents[0][0].Shape.Edges:\n                            count += 1\n                            edgeSel = \"Edge\" + str(count)\n                            edgeA = \"\"\n                            edgeA = Gui.Selection.isSelected(FreeCAD.ActiveDocument.getObject(parentNamePaDe), subNamePaDe + \".\" + edgeSel)\n                            if edgeA == True:\n                                objectsMemoA.append((objectsListing[i], edgeSel))\n                                self.comptEdge += 1\n                                self.comptLengthObject = FreeCAD.ActiveDocument.getObject(parentNamePaDe).Shape.getElement(edgeSel).Length\n                                self.comptLengthTotal += self.comptLengthObject\n\n                        count = 0\n                        for ii in selected.Parents[0][0].Shape.Vertexes:                        # search Vertexes \n                            count += 1\n                            vertexSel = \"Vertex\" + str(count)\n                            vertexA = \"\"\n                            vertexA = Gui.Selection.isSelected(FreeCAD.ActiveDocument.getObject(parentNamePaDe), subNamePaDe + \".\" + vertexSel)\n                            if vertexA == True: # isSelected\n                                objectsMemoA.append((objectsListing[i], vertexSel))\n                                self.comptVertex += 1\n                        count = 0\n\n                    else:\n                        count = 0\n                        for j in FreeCAD.ActiveDocument.getObject(objectsListing[i]).Shape.Faces:                         # search Faces \n                            count += 1\n                            faceSel = \"Face\" + str(count)\n                            if \"Sketcher\" in typeID:                                                                      # Sketcher\n                                try:\n                                    parentNamePaDe = FreeCAD.ActiveDocument.getObject(objectsListing[i]).getParent().Name # 'Body001'\n                                    subNamePaDe    = FreeCAD.ActiveDocument.getObject(objectsListing[i]).Name             # 'Additivepipe001'\n                                    #sub                                                                                  #  Edge26\n                                    if Gui.Selection.isSelected(FreeCAD.ActiveDocument.getObject(parentNamePaDe), subNamePaDe + \".\" + faceSel):\n                                        objectsMemoA.append((objectsListing[i], faceSel))\n                                        self.comptFace += 1\n                                        self.comptSurfaceFace = FreeCAD.ActiveDocument.getObject(objectsListing[i]).Shape.Faces[count-1].Area\n                                        self.comptSurfaceTotal += self.comptSurfaceFace\n                                except Exception:\n                                    if Gui.Selection.isSelected(FreeCAD.ActiveDocument.getObject(objectsListing[i]), faceSel): # isSelected\n                                        objectsMemoA.append((objectsListing[i], faceSel))\n                                        self.comptFace += 1\n                                        self.comptSurfaceFace = FreeCAD.ActiveDocument.getObject(objectsListing[i]).Shape.Faces[count-1].Area\n                                        self.comptSurfaceTotal += self.comptSurfaceFace\n                            else:\n                                if Gui.Selection.isSelected(FreeCAD.ActiveDocument.getObject(objectsListing[i]), faceSel): # isSelected\n                                    objectsMemoA.append((objectsListing[i], faceSel))\n                                    self.comptFace += 1\n                                    self.comptSurfaceFace = FreeCAD.ActiveDocument.getObject(objectsListing[i]).Shape.Faces[count-1].Area\n                                    self.comptSurfaceTotal += self.comptSurfaceFace\n                        count = 0\n\n                        for j in FreeCAD.ActiveDocument.getObject(objectsListing[i]).Shape.Edges:                         # search Edges \n                            count += 1\n                            edgeSel = \"Edge\" + str(count)\n                            if \"Sketcher\" in typeID:                                                                      # Sketcher\n                                try:\n                                    parentNamePaDe = FreeCAD.ActiveDocument.getObject(objectsListing[i]).getParent().Name # 'Body001'\n                                    subNamePaDe    = FreeCAD.ActiveDocument.getObject(objectsListing[i]).Name             # 'Additivepipe001'\n                                    #sub                                                                                  #  Edge26\n                                    if Gui.Selection.isSelected(FreeCAD.ActiveDocument.getObject(parentNamePaDe), subNamePaDe + \".\" + edgeSel):\n                                        objectsMemoA.append((objectsListing[i], edgeSel))\n                                        self.comptEdge += 1\n                                        self.comptLengthObject = FreeCAD.ActiveDocument.getObject(objectsListing[i]).Shape.Edges[count-1].Length\n                                        self.comptLengthTotal += self.comptLengthObject\n                                except Exception:\n                                    if Gui.Selection.isSelected(FreeCAD.ActiveDocument.getObject(objectsListing[i]), edgeSel): # isSelected\n                                        objectsMemoA.append((objectsListing[i], edgeSel))\n                                        self.comptEdge += 1\n                                        self.comptLengthObject = FreeCAD.ActiveDocument.getObject(objectsListing[i]).Shape.Edges[count-1].Length\n                                        self.comptLengthTotal += self.comptLengthObject\n                            else:\n                                if Gui.Selection.isSelected(FreeCAD.ActiveDocument.getObject(objectsListing[i]), edgeSel): # isSelected\n                                    objectsMemoA.append((objectsListing[i], edgeSel))\n                                    self.comptEdge += 1\n                                    self.comptLengthObject = FreeCAD.ActiveDocument.getObject(objectsListing[i]).Shape.Edges[count-1].Length\n                                    self.comptLengthTotal += self.comptLengthObject\n                        count = 0\n\n                        for j in FreeCAD.ActiveDocument.getObject(objectsListing[i]).Shape.Vertexes:                        # search Vertexes \n                            count += 1\n                            vertexSel = \"Vertex\" + str(count)\n                            if \"Sketcher\" in typeID:                                                                      # Sketcher\n                                try:\n                                    parentNamePaDe = FreeCAD.ActiveDocument.getObject(objectsListing[i]).getParent().Name # 'Body001'\n                                    subNamePaDe    = FreeCAD.ActiveDocument.getObject(objectsListing[i]).Name             # 'Additivepipe001'\n                                    #sub                                                                    #  Edge26\n                                    if Gui.Selection.isSelected(FreeCAD.ActiveDocument.getObject(parentNamePaDe), subNamePaDe + \".\" + vertexSel):\n                                        objectsMemoA.append((objectsListing[i], vertexSel))\n                                        self.comptVertex += 1\n                                except Exception:\n                                    if Gui.Selection.isSelected(FreeCAD.ActiveDocument.getObject(objectsListing[i]), vertexSel): # isSelected\n                                        objectsMemoA.append((objectsListing[i], vertexSel))\n                                        self.comptVertex += 1\n                            else:\n                                if Gui.Selection.isSelected(FreeCAD.ActiveDocument.getObject(objectsListing[i]), vertexSel): # isSelected\n                                    objectsMemoA.append((objectsListing[i], vertexSel))\n                                    self.comptVertex += 1\n\n                        count = 0\n            except Exception:\n                None\n\n        self.comptNumbObject = len(objectsListing)\n        self.displayOnWindow()\n        FreeCAD.ActiveDocument.recompute(None,True,True)\n\n    def on_PB_03_Box_clicked(self):     # all subObjects checked\n        global objectsListing\n        ##https://forum.freecad.org/viewtopic.php?p=722362#p722362\n        ##Feature Request: Preselection Order Priority.\n\n        objectsListing = []\n        sel=Gui.Selection.getSelection()\n\n        if (self.CB_01_Sel_Face.isChecked() or self.CB_02_Sel_Edge.isChecked() or self.CB_03_Sel_Vertex.isChecked()) and (len(sel) != 0):\n            self.LE_00_InfoSel.setText(\"(Face: \" + str(self.CB_01_Sel_Face.isChecked()) + \") (Edge: \" + str(self.CB_02_Sel_Edge.isChecked()) + \") (Vertex: \" + str(self.CB_03_Sel_Vertex.isChecked()) + \")\")\n\n            for i in range(len(sel)):\n                if self.CB_01_Sel_Face.isChecked():            # search Faces\n                    for j in enumerate(sel[i].Shape.Faces):\n                        #objetSelect = Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(sel[i].Name), 'Face'+str(j[0]+1))\n                            try:\n                                parentNamePaDe = FreeCAD.ActiveDocument.getObject(sel[i].Name).getParent().Name # 'Body001'\n                                subNamePaDe    = FreeCAD.ActiveDocument.getObject(sel[i].Name).Name             # 'Additivepipe001'\n                                #sub                                                                            # Edge26\n                                Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(parentNamePaDe), subNamePaDe + \".\" + 'Face'+str(j[0]+1))\n                            except Exception:\n                                Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(sel[i].Name), 'Face'+str(j[0]+1))\n\n                if self.CB_02_Sel_Edge.isChecked():            # search Edges\n                    for j in enumerate(sel[i].Shape.Edges):\n                        #objetSelect = Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(sel[i].Name), 'Edge'+str(j[0]+1))\n                            try:\n                                parentNamePaDe = FreeCAD.ActiveDocument.getObject(sel[i].Name).getParent().Name # 'Body001'\n                                subNamePaDe    = FreeCAD.ActiveDocument.getObject(sel[i].Name).Name             # 'Additivepipe001'\n                                #sub                                                                            # Edge26\n                                Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(parentNamePaDe), subNamePaDe + \".\" + 'Edge'+str(j[0]+1))\n                            except Exception:\n                                Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(sel[i].Name), 'Edge'+str(j[0]+1))\n\n                if self.CB_03_Sel_Vertex.isChecked():          # search Vertexes\n                    for j in enumerate(sel[i].Shape.Vertexes):\n                        #objetSelect = Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(sel[i].Name), 'Vertex'+str(j[0]+1))\n                            try:\n                                parentNamePaDe = FreeCAD.ActiveDocument.getObject(sel[i].Name).getParent().Name # 'Body001'\n                                subNamePaDe    = FreeCAD.ActiveDocument.getObject(sel[i].Name).Name             # 'Additivepipe001'\n                                #sub                                                                            # Edge26\n                                Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(parentNamePaDe), subNamePaDe + \".\" + 'Vertex'+str(j[0]+1))\n                            except Exception:\n                                Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(sel[i].Name), 'Vertex'+str(j[0]+1))\n                objectsListing.append(sel[i].Name)\n\n            self.selectSelection()\n        else:\n            if (len(sel) == 0):\n                self.LE_00_InfoSel.setText(\"Not object selected\")\n\n    def on_PB_04_Reset_clicked(self):\n        global objectsListing\n        global CB_ResetMode\n\n        objectsListing = []\n        self.comptFace   = 0\n        self.comptEdge   = 0\n        self.comptVertex = 0\n        self.comptNumbObject   = 0\n        self.comptSurfaceFace  = 0.0\n        self.comptSurfaceTotal = 0.0\n        self.comptLengthObject = 0.0\n        self.comptLengthTotal  = 0.0\n\n        if CB_ResetMode == 0:\n            self.CB_01_Sel_Face.setChecked(False)\n            self.CB_02_Sel_Edge.setChecked(False)\n            self.CB_03_Sel_Vertex.setChecked(False)\n        CB_ResetMode = 0\n\n        self.LAB_01_Face.setText(str(self.comptFace))\n        self.LAB_02_Edge.setText(str(self.comptEdge))\n        self.LAB_03_Vertex.setText(str(self.comptVertex))\n        self.LE_01_Area_Total.setText(str(self.comptSurfaceTotal))\n        self.LE_02_Area_Object.setText(str(self.comptSurfaceFace))\n        self.LE_03_Length_Total.setText(str(self.comptLengthTotal))\n        self.LE_04_Length_Object.setText(str(self.comptLengthObject))\n        self.selectSelection()\n        self.LE_00_InfoSel.setText(\"(Face: \" + str(self.CB_01_Sel_Face.isChecked()) + \") (Edge: \" + str(self.CB_02_Sel_Edge.isChecked()) + \") (Vertex: \" + str(self.CB_03_Sel_Vertex.isChecked()) + \")\")\n\n    def on_PB_05_Reset_Memo_clicked(self):\n        global objectsMemo\n        global objectsMemoA\n        global compt_Memo\n        global toolTipCBBox_Memo\n\n        try:\n            self.CBBox_Memo.clear()\n        except Exception:\n            None\n        objectsMemo = []\n        objectsMemoA = []\n        toolTipCBBox_Memo = []\n        compt_Memo = 0\n\n        self.PB_05_CBBox_Memo.setText(\"Memo selection (\" + str(compt_Memo) + \")\")\n        self.on_PB_04_Reset_clicked()\n\n    def on_PB_02_Stop_Grab_clicked(self):\n        global s\n        global objectsListing\n        global objectsListingA\n\n        if self.Stop_Grab == 1:\n            FreeCADGui.Selection.removeObserver(s)                             # desinstalle la fonction residente SelObserver\n            self.Stop_Grab = 0\n            self.PB_02_Stop_Grab.setText(\"Return / Refresh\")\n            self.GBOX_01_Face.setEnabled(False)\n            self.GBOX_02_Edge.setEnabled(False)\n            self.GBOX_03_Vertex.setEnabled(False)\n            self.PB_03_Box.setEnabled(False)\n        else:\n            s=SelObserver()\n            FreeCADGui.Selection.addObserver(s)                                # installe la fonction en mode resident\n            self.Stop_Grab = 1\n            self.PB_02_Stop_Grab.setText(\"Pause grab / Refresh\")\n            self.GBOX_01_Face.setEnabled(True)\n            self.GBOX_02_Edge.setEnabled(True)\n            self.GBOX_03_Vertex.setEnabled(True)\n            self.PB_03_Box.setEnabled(True)\n            sel=Gui.Selection.getSelection()\n            objectsListing = []\n            objectsListingA = []\n\n            for i in sel:\n                try:\n                    objectsListingA.append(i.Name)\n                except Exception:\n                    objectsListingA.append(i)\n\n            for i in objectsListingA:   # elimine les doublons\n                if i not in objectsListing:\n                    objectsListing.append(i)\n\n            if len(sel) == 0:\n                self.on_PB_04_Reset_clicked()\n            else:\n                self.CB_01_Sel_Face.setChecked(True)    # cas selection hors de la macro (pause grab)\n                self.CB_02_Sel_Edge.setChecked(True)    # cas selection hors de la macro (pause grab)\n                self.CB_03_Sel_Vertex.setChecked(True)  # cas selection hors de la macro (pause grab)\n                self.selectSelection()\n\n    def on_CBBox_Memo_Info_ToolTip(self, text):\n        global objectsMemoA\n        global toolTipCBBox_Memo\n\n        if len(objectsMemoA) != 0:\n            itemFile = self.CBBox_Memo.currentIndex()\n            self.CBBox_Memo.setItemData(itemFile, toolTipCBBox_Memo[itemFile], QtCore.Qt.ToolTipRole)\n\n    def on_CBBox_Memo_Clicked(self, text):  # object memorised in CBBox\n        global objectsListing\n        global objectsMemo\n\n        try:\n            dummy = self.CBBox_Memo.currentText().split()[0]\n            if dummy == FreeCAD.ActiveDocument.Name:\n                if len(objectsMemo) != 0:\n                    objectsListing = []\n                    itemFile = self.CBBox_Memo.currentIndex()\n                    self.on_PB_03_Box_clicked()\n                    position = [0,0,0]  # controler !!\n                    for obj, sub in objectsMemo[itemFile]:\n                        try:\n                            typeID = FreeCAD.ActiveDocument.getObject(obj).TypeId  # 'PartDesign::AdditivePipe'\n                        except Exception:\n                            typeID = \"\"\n                        if (\"Sketcher\" in typeID) or (\"PartDesign\" in typeID):\n                            try:\n                                parentNamePaDe = FreeCAD.ActiveDocument.getObject(obj).getParent().Name # 'Body001'\n                                subNamePaDe    = FreeCAD.ActiveDocument.getObject(obj).Name             # 'Additivepipe001'\n                                #sub                                                                    #  Edge26\n                                Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(parentNamePaDe), subNamePaDe + \".\" + sub, position[0], position[1], position[2])\n                            except Exception:\n                                Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(obj), sub, position[0], position[1], position[2])\n                        else:\n                                Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(obj), sub, position[0], position[1], position[2])\n                        if obj not in objectsListing:   # filtre les noms\n                            objectsListing.append(obj)\n\n                    self.selectSelection()\n            else:\n                self.LE_00_InfoSel.setText(\"Wrong document: actual: \" + FreeCAD.ActiveDocument.Name)\n                #print(\"Wrong document\")\n        except Exception:\n            None\n\n    def on_PB_05_CBBox_Memo_clicked(self):  # store the objects selected\n        global objectsMemo\n        global objectsMemoA\n        global compt_Memo\n        global toolTip_Memo\n        global toolTipCBBox_Memo\n\n        dummy = []\n        toolTip_Memo = []\n        objets = []\n        Fc = Ed = Ve = 0\n        subElements = \"\"\n\n        if len(objectsMemoA) != 0:\n            for i in objectsMemoA:   # elimine les doublons ()\n                if i not in dummy:\n                    dummy.append(i)\n                    if \"Face\" in i[1]:\n                        Fc += 1\n                    if \"Edge\" in i[1]:\n                        Ed += 1\n                    if \"Vertex\" in i[1]:\n                        Ve += 1\n\n            for i in dummy:\n                if i[0] not in objets:   # elimine les doublons (nom)\n                    objets.append(i[0])  # number objects\n\n            self.comptNumbObject = len(objets)\n            self.CBBox_Memo.addItem( FreeCAD.ActiveDocument.Name + \" : \" + str(compt_Memo + 1) + \" : ( \" + str(len(dummy)) + \" sel. ) ( Obj. \" + str(self.comptNumbObject) + \", Fa. \" + str(Fc) + \", Ed. \" + str(Ed) + \", Ve. \" + str(Ve) + \" )\") # text in comboBox\n            objectsMemo += [copy.deepcopy(dummy)]\n\n            toolTipCBo = \"\"\n            toolTipCBo = \"\\n\" + FreeCAD.ActiveDocument.Name + \"\\n\\n\"\n            for i in objectsMemo[compt_Memo]:\n                toolTipCBo += str(i) + \"\\n\"\n\n            toolTipCBBox_Memo += [toolTipCBo]\n            self.CBBox_Memo.setItemData(compt_Memo, toolTipCBBox_Memo[compt_Memo], QtCore.Qt.ToolTipRole)\n            compt_Memo += 1\n        else:\n            self.LE_00_InfoSel.setText(\"Not object selected\")\n\n        self.PB_05_CBBox_Memo.setText(\"Memo selection (\" + str(compt_Memo) + \")\")\n        dummy = []\n        objets = []\n\n    def on_PB_06_removeSelection_Selection_clicked(self):\n        try:\n            for obj in FreeCAD.ActiveDocument.Objects:\n                FreeCADGui.Selection.removeSelection(FreeCAD.ActiveDocument.Name, obj.Name)\n            self.on_PB_04_Reset_clicked()\n        except Exception:\n            None\n\n    def on_PB_Quit_clicked(self):\n        global s\n        global vTB\n        global cTB\n        global obs\n        global oTB\n        global FC_Macro_ParamGetSet\n        global setMainWindowMoveX\n        global setMainWindowMoveY\n        global setFrameWindowSizeX\n        global setFrameWindowSizeY\n\n        FreeCADGui.Selection.removeObserver(s)                            # desinstalle la fonction residente SelObserver\n        vTB.removeEventCallback(\"SoEvent\",cTB)                            # close event observation\n        vTB.removeEventCallback(\"SoEvent\",oTB.logPosition)                # \n        App.removeDocumentObserver(obs)                                   # desinstalle la fonction residente\n\n        #### geometry\n        positionWindowXY = MainWindow.geometry()\n        setMainWindowMoveX  = positionWindowXY.x()\n        setMainWindowMoveY  = positionWindowXY.y()\n        positionWindowXY = MainWindow.size()\n        setFrameWindowSizeX = positionWindowXY.width()\n        setFrameWindowSizeY = positionWindowXY.height()\n        FC_Macro_ParamGetSet.SetInt(\"setMainWindowMoveX\",  setMainWindowMoveX)      # setMainWindowMoveX\n        FC_Macro_ParamGetSet.SetInt(\"setMainWindowMoveY\",  setMainWindowMoveY)      # setMainWindowMoveY\n        FC_Macro_ParamGetSet.SetInt(\"setFrameWindowSizeX\", setFrameWindowSizeX)     # setFrameWindowSizeX\n        FC_Macro_ParamGetSet.SetInt(\"setFrameWindowSizeY\", setFrameWindowSizeY)     # setFrameWindowSizeY\n        #### geometry\n\n        try:\n            self.window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)    # destroy\n            self.window.deleteLater()                                     # destroy\n            self.window.destroy()                                         # destroy\n        except Exception:\n            self.window.hide()                                            # hide the window and close the macro\n\n        print( \"Quit \",__title__, \" Bye\")\n\n### section Observer begin ######################\nglobal cTB\nglobal oTB\nglobal vTB; vTB=Gui.activeDocument().activeView()\nglobal obs\n\nclass DocObserver:                      # document Observer\n    def slotActivateDocument(self,doc):\n        global cTB\n        global oTB\n        global vTB\n        global ui\n\n        try:\n            vTB.removeEventCallback(\"SoEvent\",cTB)                        # close event observation\n        except Exception: None\n\n        ui.Stop_Grab = 0\n        ui.on_PB_02_Stop_Grab_clicked()\n        ui.LE_00_InfoSel.setText(doc.Name)\n\n        try:\n            vTB=Gui.activeDocument().activeView()\n            oTB = ViewObserver(vTB)\n            cTB = vTB.addEventCallback(\"SoEvent\",oTB.logPosition)\n        except Exception: None\n\nobs=DocObserver()\nApp.addDocumentObserver(obs)\n#App.removeDocumentObserver(obs)                                          # desinstalle la fonction residente\n####\n\nvTB=Gui.activeDocument().activeView()\nclass ViewObserver:                     # vue souris Observer\n\n    def __init__(self, view):\n        self.view = view\n    def logPosition(self, info):\n        global cTB\n        global oTB\n        global vTB\n        global position\n        global pos2D\n        try:\n            vTB=Gui.activeDocument().activeView()\n            objectSurvol = vTB.getObjectInfo(vTB.getCursorPos())          # here for objectSurvol preselected\n            position = FreeCAD.Vector(float(objectSurvol[\"x\"]),float(objectSurvol[\"y\"]),float(objectSurvol[\"z\"]))# vector on position mouse to objectSurvol\n        except Exception:\n            None\n\noTB = ViewObserver(vTB)\ncTB = vTB.addEventCallback(\"SoEvent\",oTB.logPosition)\n#vTB.removeEventCallback(\"SoEvent\",cTB)                                   # close event observation\n### section Observer end ######################\n\nclass SelObserver:                     # selection Observer\n    global ui\n\n    def setPreselection(self, doc, obj, sub): # preselection## self, coin_carre, AdditivePipe001, Edge26  #dans body\n        global ui\n        global objectsListingA\n        global objectsListing\n        global position\n        global vTB\n\n        try:\n            if (ui.Stop_Grab == 1) and (position != \"\"):\n                typeID = FreeCAD.ActiveDocument.getObject(obj).TypeId  # 'PartDesign::AdditivePipe'\n                if typeID != \"NoneType\":\n                    ui.LE_00_InfoSel.setText(FreeCAD.ActiveDocument.Name + \": \" + str(obj) + \". \" + str(sub) + \" (\" + str(round(position[0],2)) + \",\" + str(round(position[1],2)) + \",\" + str(round(position[2],2)) + \")\")\n\n                    if ui.CB_01_Sel_Face.isChecked():\n                        if (sub[:4] == \"Face\") and (Gui.Selection.isSelected(FreeCAD.ActiveDocument.getObject(obj), sub) == False):\n                            if \"Sketcher\" in typeID:\n                                try:\n                                    parentNamePaDe = FreeCAD.ActiveDocument.getObject(obj).getParent().Name # 'Body001'\n                                    subNamePaDe    = FreeCAD.ActiveDocument.getObject(obj).Name             # 'Additivepipe001'\n                                    #sub                                                                    #  Edge26\n                                    Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(parentNamePaDe), subNamePaDe + \".\" + sub, position[0], position[1], position[2])\n                                except Exception:\n                                    Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(obj), sub, position[0], position[1], position[2])\n                            else:\n                                    Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(obj), sub, position[0], position[1], position[2])\n                            objectsListingA.append(obj)\n\n                    if ui.CB_02_Sel_Edge.isChecked():\n                        if (sub[:4] == \"Edge\") and (Gui.Selection.isSelected(FreeCAD.ActiveDocument.getObject(obj), sub) == False):\n                            if \"Sketcher\" in typeID:\n                                try:\n                                    parentNamePaDe = FreeCAD.ActiveDocument.getObject(obj).getParent().Name # 'Body001'\n                                    subNamePaDe    = FreeCAD.ActiveDocument.getObject(obj).Name             # 'Additivepipe001'\n                                    #sub                                                                    #  Edge26\n                                    Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(parentNamePaDe), subNamePaDe + \".\" + sub, position[0], position[1], position[2])\n                                except Exception:\n                                    Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(obj), sub, position[0], position[1], position[2])\n                            else:\n                                    Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(obj), sub, position[0], position[1], position[2])\n                            objectsListingA.append(obj)\n\n                    if (ui.CB_03_Sel_Vertex.isChecked()) and (position != \"\"):\n                        if sub[:6] == \"Vertex\" and (Gui.Selection.isSelected(FreeCAD.ActiveDocument.getObject(obj), sub) == False):\n                            if \"Sketcher\" in typeID:\n                                try:\n                                    parentNamePaDe = FreeCAD.ActiveDocument.getObject(obj).getParent().Name # 'Body001'\n                                    subNamePaDe    = FreeCAD.ActiveDocument.getObject(obj).Name             # 'Additivepipe001'\n                                    #sub                                                                    #  Edge26\n                                    Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(parentNamePaDe), subNamePaDe + \".\" + sub, position[0], position[1], position[2])\n                                except Exception:\n                                    Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(obj), sub, position[0], position[1], position[2])\n                            else:\n                                    Gui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(obj), sub, position[0], position[1], position[2])\n                            objectsListingA.append(obj)\n\n                    #### elimine les doublons\n                    for i in objectsListingA:   # elimine les doublons\n                        if i in objectsListing:\n                            None\n                        else:\n                            objectsListing.append(i)\n                    ####\n\n                    objectsListingA = []\n                    ui.selectSelection()\n        except Exception:\n            None\n#    def removePreselection(self,doc,obj,sub): # \n#        print( \"removePreselection\")\n#    def addSelection(self,doc,obj,sub,pnt):  # Selection\n#        print( \"addSelection\")\n#    def removeSelection(self,doc,obj,sub):   # Effacer l'objet selectionne\n#        print( \"removeSelection\")\n#    def setSelection(self,doc):              # Selection dans ComboView\n#        FreeCADGui.Selection.removeObserver(s)\n#        print( \"setSelection quit\")\n\n    def clearSelection(self,doc):            # Si clic sur l'ecran, effacer la selection\n        global ui\n        global CB_ResetMode\n\n        try:\n            CB_ResetMode = 1\n            ui.on_PB_04_Reset_clicked()\n        except Exception:\n            None\n\ns=SelObserver()\nFreeCADGui.Selection.addObserver(s)          # installe la fonction en mode resident\n#FreeCADGui.Selection.removeObserver(s)\n### section Observer end ######################\n\ndoc = FreeCAD.ActiveDocument\nif doc == None:\n    doc = FreeCAD.newDocument()\n\nMainWindow = QtWidgets.QMainWindow()\nui = Ui_MainWindow(MainWindow)\nui.setupUi(MainWindow)\nMainWindow.show()\n",
    "url": "https://wiki.freecad.org/Macro_Select_Hovering",
    "raw_code_url": "https://gist.githubusercontent.com/mario52a/7ebe6b3fd047441114d9d0e08ceddd63/raw/f9dea03a0327b48c76a7c3e9d7cd391b5093a8cf/Macro%2520Select%2520Hovering.FCMacro",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_Select_Hovering",
    "version": "00.04",
    "license": "",
    "date": "2024/01/11",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Select_Hovering.png",
    "icon_source": "https://wiki.freecad.org/images/d/d8/Macro_Select_Hovering.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Shake Sketch",
    "on_wiki": true,
    "on_git": false,
    "desc": "Shake a sketch in order to discover its unconstrained parts. Enter edit mode for a sketch and launch the macro. The macro will add a random displacement on all sketch points. The sketch is then solved, constrained parts will retain their position, free parts will move.<br /> <span style=\"background-color:#ff0000; color:#ffff00;\">Use the Undo (Ctrl+Z) and Redo (Ctrl+Y) button (labelled \"Shake Sketch\") or run this macro on a copy of the original sketch.</span><br /><br />Macro version: 1.3<br />Last modified: 2022-06-01<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/4/4a/Macro_Shake_Sketch.png\">ToolBar Icon</a><br />Author: Ga\u00ebl Ecorchard, heda<br /> ",
    "comment": "Shake a sketch in order to discover its unconstrained parts. Enter edit mode for a sketch and launch the macro. The macro will add a random displacement on all sketch points. The sketch is then solved, constrained parts will retain their position, free parts will move.",
    "code": "# -*- coding: utf-8 -*-\n\n# FreeCAD macro to shake a sketch in order to discover its unconstrained parts.\n#\n# A Gaussian noise is introduced in all sketch points and the sketch is then\n# solved.\n# Beware that the sketch can look different because some constraints have\n# several solutions. In this case, just undo.\n#\n# This file is released under the MIT License.\n# Author: Ga\u00ebl Ecorchard v1.0 & v1.1\n# Author: heda v1.2\n# Version:\n# - 1.3: 2022-06-01\n#       * added openTransaction(u\"Shake Sketch\") for restore the original Sketch\n# - 1.2: 2021-10-22\n#       * made macro runnable for current versions of fc\n#       * added Part.LineSegment\n#       * added start info & result dialogue\n#       * hides constraints during shake\n#       * added simple debug printing\n# - 1.1: 2014-10-31\n#       * correct import for Part\n# - 1.0: 2014-08\n#       * first release\n# Amplitude of the point displacements.\n# The standard deviation of the Gaussian noise is the largest sketch dimension\n# multiplied by this factor.\n\n__title__ = 'Sketch Shaker'\n__version__ = '1.3'\n__date__ = '2022/06/01'\n__icon__ = 'https://wiki.freecadweb.org/images/4/4a/Macro_Shake_Sketch.png'\n\ndisplacement_amplitude = 0.1\ndebug_print = False\n\n# End of configuration.\n\nfrom random import gauss\n\nfrom PySide.QtGui import QMessageBox\n\nimport FreeCADGui as Gui\nfrom FreeCAD import Base\nimport Part\n\nprint('Running Macro ' + __title__ + ' ver: ' + __version__)\nFreeCAD.ActiveDocument.openTransaction(u\"Shake Sketch\")    # memorise les actions (avec annuler restore)\n\n# For each sketch geometry type, map a list of points to move.\ng_geom_points = {\n    Base.Vector: [1],\n    Part.Line: [1, 2],  # first point, last point\n    Part.LineSegment: [1, 2],  # first point, last point\n    Part.Circle: [0, 3],  # curve, center\n    Part.ArcOfCircle: [1, 2, 3],  # first point, last point, center\n} # moves bsplines and conics via lines and circles, no op for Part.Points\n\n\ndef dprint(msg, *args):\n    if debug_print:\n        if args:\n            print(msg.format(*args))\n        else:\n            print(msg)\n\nclass BoundingBox:\n    xmin = xmax = ymin = ymax = None\n\n    def enlarge_x(self, x):\n        if self.xmin is None:\n            self.xmin = self.xmax = x\n        elif self.xmin > x:\n            self.xmin = x\n        elif self.xmax < x:\n            self.xmax = x\n\n    def enlarge_y(self, y):\n        if self.ymin is None:\n            self.ymin = self.ymax = y\n        elif self.ymin > y:\n            self.ymin = y\n        elif self.ymax < y:\n            self.ymax = y\n\n    def enlarge_point(self, point):\n        self.enlarge_x(point.x)\n        self.enlarge_y(point.y)\n\n    def enlarge_line(self, line):\n        self.enlarge_x(line.StartPoint.x)\n        self.enlarge_x(line.EndPoint.x)\n        self.enlarge_y(line.StartPoint.y)\n        self.enlarge_y(line.EndPoint.y)\n\n    def enlarge_circle(self, circle):\n        self.enlarge_x(circle.Center.x - circle.Radius)\n        self.enlarge_x(circle.Center.x + circle.Radius)\n        self.enlarge_y(circle.Center.y - circle.Radius)\n        self.enlarge_y(circle.Center.y + circle.Radius)\n\n    def enlarge_arc_of_circle(self, arc):\n        # TODO: correctly compute the arc extrema (cf. toShape().BoundBox)\n        self.enlarge_x(arc.Center.x)\n        self.enlarge_y(arc.Center.y)\n\n\ndef get_sketch_dims(sketch):\n    bbox = BoundingBox()\n    for geom in sketch.Geometry:\n        if isinstance(geom, Base.Vector):\n            bbox.enlarge_point(geom)\n        elif isinstance(geom, (Part.Line, Part.LineSegment)):\n            bbox.enlarge_line(geom)\n        elif isinstance(geom, Part.Circle):\n            bbox.enlarge_circle(geom)\n        elif isinstance(geom, Part.ArcOfCircle):\n            bbox.enlarge_arc_of_circle(geom)\n    if None in (bbox.xmin, bbox.ymin):\n        dprint('sketch bbox not found')\n        return 0, 0\n    else:\n        dprint('sketch bbox found')\n        return bbox.xmax - bbox.xmin, bbox.ymax - bbox.ymin\n\n\ndef add_noise(point, sigma):\n    \"\"\"Add a Gaussian noise with standard deviation sigma\"\"\"\n    dprint('  x0:{:>9.3f}  y0:{:>9.3f}', point.x, point.y)\n    point.x = gauss(point.x, sigma)\n    point.y = gauss(point.y, sigma)\n    dprint('  xt:{:>9.3f}  yt:{:>9.3f}', point.x, point.y)\n\n\ndef move_points(sketch, geom_index, sigma):\n    point_indexes = g_geom_points.get(type(sketch.Geometry[i]), [])\n    # Direct access to sketch.Geometry[index] does not work. This would,\n    # however prevent repeated recompute.\n    # not checked validity of comment for v1.2\n    moved = False\n    for point_index in point_indexes:\n        dprint('---- geo idx [{:>3} ] -- pt idx [{:>3} ] ----',\n               geom_index, point_index)\n        point = sketch.getPoint(geom_index, point_index)\n        add_noise(point, sigma)\n        try:\n            sketch.movePoint(geom_index, point_index, point)\n        except ValueError as e:\n            dprint(repr(e))\n        new_pos = sketch.getPoint(geom_index, point_index)\n        test = point.isEqual(new_pos, 0)\n        dprint('  did it move? {}', test)\n        if test: moved = True\n    return moved\n\ndef toggle_constraints(sketch, toggle):\n    for cid in toggle:\n        sketch.toggleVirtualSpace(cid)\n    \n\nview_provider = Gui.activeDocument().getInEdit()\n\nshake_it = False\nif not view_provider:\n    msg = 'A sketch needs to be in edit to be shaken.'\n    print(msg)\n    _ = QMessageBox.information(None, __title__, msg)\nelse:\n    sketch = view_provider.Object\n    if sketch.TypeId == 'Sketcher::SketchObject':\n        sketch.recompute() # ensure update\n        to_virtual = [cid for cid, cts in enumerate(sketch.Constraints)\n                      if cts.InVirtualSpace]\n        sketch_span = get_sketch_dims(sketch)\n        sigma = max(sketch_span) * displacement_amplitude\n        dprint('sketch span: dx:{:>9.3f} dy:{:>9.3f}', *sketch_span)\n        dprint('sigma for gauss-dist: {:.3f}', sigma)\n        toggle_constraints(sketch, to_virtual)\n        msg = ('Shake sketch will deform the loose parts of the sketch.\\n'\n               'The deformation can be restored with : \\n'\n               'the Undo (Ctrl+Z) and Redo (Ctrl+Y) button (labeled \"Shake Sketch\").\\n'\n               'If that is not desired, click Cancel,\\n'\n               'and run the macro on a copy of the sketch.\\n\\n'\n               'Visibility of constraints has been toggled.\\n'\n               'Visibility of constraints is restored'\n               ' after shaking the sketch.')\n        reply = QMessageBox.information(None, 'Running Macro ' + __title__ + ' ver: ' + __version__, msg,\n                                        QMessageBox.Ok | QMessageBox.Cancel,\n                                        QMessageBox.Ok)\n        shake_it = reply == QMessageBox.Ok\n        \n        if not shake_it:\n            toggle_constraints(sketch, to_virtual)\n\nif shake_it:\n    nbr_moves = 0\n    for i in range(sketch.GeometryCount):\n        did_move = move_points(sketch, i, sigma)\n        if did_move:\n            nbr_moves += 1\n\n    msg = 'Did {} moves. Sketch has a total of {} geometry entities.\\n\\n'\n    msg = msg.format(nbr_moves, sketch.GeometryCount)\n    open_verts = sketch.OpenVertices\n    if open_verts:\n        if len(open_verts) == 1:\n            ov, form = 'one', 'vertex'\n        else:\n            ov, form = len(open_verts), 'vertices'\n        msg += 'Sketch has {} open {}.'.format(ov, form)\n        msg += ('\\nA sketch with open vertices'\n                ' cannot be used to create a solid.')\n    else:\n        msg += 'Sketch is free from open vertices.'\n\n    msg += ('\\n\\nMenu: \"Sketch/Validate Sketch...\" can be used\\n'\n            'for additional info about sketch status.')\n    \n    _ = QMessageBox.information(None, 'Running Macro ' + __title__ + ' ver: ' + __version__, msg)\n    toggle_constraints(sketch, to_virtual)\n        \n\nprint('Macro finished.')\n",
    "url": "https://wiki.freecad.org/Macro_Shake_Sketch",
    "raw_code_url": "",
    "wiki": "",
    "version": "1.3",
    "license": "",
    "date": "2022/06/01",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Ga\u00ebl Ecorchard, heda",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Shake_Sketch.png",
    "icon_source": "https://wiki.freecadweb.org/images/4/4a/Macro_Shake_Sketch.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Unbind Numpad Shortcuts",
    "on_wiki": true,
    "on_git": false,
    "desc": "When entering numbers, and the number input box is not properly focused, FreeCAD will react to digits by switching standard views. This macro is a quick way to re-bind the shortcuts to Ctrl+number. Doesn't help very much with entering numbers, but at least the view won't spin like crazy.<br /><br />Macro version: 2.0<br />Last modified: 2022-04-13<br />FreeCAD version: 0.20<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/1/1e/Macro_Unbind_Numpad_Shortcuts.png\">ToolBar Icon</a><br />Author: DeepSOIC<br /> ",
    "comment": "When entering numbers, and the number input box is not properly focused, FreeCAD will react to digits by switching standard views. This macro is a quick way to re-bind the shortcuts to Ctrl+number. Doesn't help very much with entering numbers, but at least the view won't spin like crazy.",
    "code": "preset = [\n    (\"Std_ViewIsometric\"   , \"Ctrl+0\"),\n    (\"Std_ViewFront\" , \"Ctrl+1\"),\n    (\"Std_ViewTop\"   , \"Ctrl+2\"),\n    (\"Std_ViewRight\" , \"Ctrl+3\"),\n    (\"Std_ViewRear\"  , \"Ctrl+4\"),\n    (\"Std_ViewBottom\", \"Ctrl+5\"),\n    (\"Std_ViewLeft\"  , \"Ctrl+6\"),\n]\nfor (cmd, shortcut) in preset:\n    App.ParamGet(\"User parameter:BaseApp/Preferences/Shortcut\").SetString(cmd, shortcut)",
    "url": "https://wiki.freecad.org/Macro_Unbind_Numpad_Shortcuts",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2022-04-13",
    "src_filename": "",
    "filename_from_url": "",
    "author": "DeepSOIC",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Unbind_Numpad_Shortcuts.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/1/1e/Macro_Unbind_Numpad_Shortcuts.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Fonts Win10 PYMP",
    "on_wiki": true,
    "on_git": false,
    "desc": "<span style=\"background-color:#ff0000; color:#ffffff;\">New version GUI modified for the HD dpi (QGridLayout) runs only FC version 0.18 and more (PySide2 Qt5)</span> <br /> <br />For the previous version see <a rel=\"nofollow\" class=\"external text\" href=\"https://gist.githubusercontent.com/mario52a/e7aa19a9dc8ea28ad4f03944ffc8f731/raw/0f5d54209d6c242b49519c83e96c548b06a8f4c6/Macro_Fonts_Win10_PYMP.FCMacro\">Macro Fonts Win10 PYMP</a> and install it manually. This little macro is dedicate to users of Windows 10. The explorer fonts for use the ShapeString is empty and this little macro can help you see easily the font to use.<br /><br />Macro version: 02.00<br />Last modified: 2020-06-06<br />FreeCAD version: 0.18 and more<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/f/fa/Macro_Fonts_Win10_PYMP.png\">ToolBar Icon</a><br />Author: Mario52<br /> ",
    "comment": "New version GUI modified for the HD dpi (QGridLayout) runs only FC version 0.18 and more (PySide2 Qt5) ",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2019 2020 <mario52>                                     *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#Macro_Fonts_Win10_PYMP 10/05/2019, 06/06/2020\n#\n###############################################################################################\n#OS: Windows 10 (10.0)                         #OS: Ubuntu 20.04 LTS\n#Word size of OS: 64-bit                       #Word size of OS: 64-bit\n#Word size of FreeCAD: 64-bit                  #Word size of FreeCAD: 64-bit\n#Version: 0.19.21280 (Git)                     #Version: 0.18.16131 (Git) AppImage\n#Build type: Release                           #Build type: Release\n#Branch: master                                #Branch: (HEAD detached at 0.18.3)\n#Hash: 6f3160db3e88733536c7eaf97ad7d6ebd21baccd#Hash: 3129ae4296e40ed20e7b3d460b86e6969acbe1c3\n#Python version: 3.6.8                         #Python version: 3.6.7\n#Qt version: 5.12.1                            #Qt version: 5.6.2\n#Coin version: 4.0.0a                          #Coin version: 4.0.0a\n#OCC version: 7.3.0                            #OCC version: 7.3.0\n#Locale: French/Mars (fr_MA)                   #\n################################################################################################\n#\n__title__   = \"Fonts Win10 PYMP\"\n__author__  = \"Mario52\"\n__url__     = \"https://wiki.freecadweb.org/Macro_Fonts_ Win10_PYMP\"\n__version__ = \"02.00\"\n__date__    = \"2020/06/06\"    #YYYY/MM/DD\n__icon__    = \"https://wiki.freecadweb.org/images/f/fa/Macro_Fonts_Win10_PYMP.png\"\n__Gist__    = \"https://gist.github.com/mario52a/e7aa19a9dc8ea28ad4f03944ffc8f731\"\n#\n#### Test FreeCAD.Version simple ############################################################################################################\nif int(FreeCAD.Version()[1]) < 18:      # Version de FreeCAD\n    FreeCAD.Console.PrintMessage(\"This version \" + __title__ + \" rmu  work with the FreeCAD 0.18 or higher.\" + \"\\n\\n\")\n    FreeCAD.Console.PrintMessage(\"For the precedent version see the page \" + \"\\n\\n\")\n    FreeCAD.Console.PrintMessage(\"https://gist.githubusercontent.com/mario52a/e7aa19a9dc8ea28ad4f03944ffc8f731/raw/0f5d54209d6c242b49519c83e96c548b06a8f4c6/Macro_Fonts_Win10_PYMP.FCMacro\" + \"\\n\\n\")\n#### Test FreeCAD.Version simple ############################################################################################################\n\nimport PySide2\nfrom PySide2 import (QtWidgets, QtCore, QtGui)\nfrom PySide2.QtWidgets import (QWidget, QApplication, QSlider, QGraphicsView, QGraphicsScene, QVBoxLayout, QStyle)\nfrom PySide2.QtGui import (QPainter, QColor, QIcon)\nfrom PySide2.QtSvg import *\n\nimport Draft, Part, PartGui, FreeCADGui, FreeCAD, FreeCADGui\nfrom FreeCAD import Base\nimport os, time, sys\n\nimport math\nfrom math import sqrt, pi, sin, cos, asin\n\nApp=FreeCAD\nGui=FreeCADGui\nimport WebGui\n                                                       \nglobal ui         ; ui = \"\"\n\n#path#################################################################\nglobal path                                                          #\n#path  = FreeCAD.ConfigGet(\"AppHomePath\")                             # path FreeCAD installation\n#path  = FreeCAD.ConfigGet(\"UserAppData\")                             # path FreeCAD User data\n#path  = \"your path\"                                                  # your directory path\nparam = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\") # macro path\npath  = param.GetString(\"MacroPath\",\"\") + \"/\"                        # macro path\npath  = path.replace(\"\\\\\",\"/\")                                       # convert the \"\\\" to \"/\"\n#FreeCAD.Console.PrintMessage( \"Path for the icons : \" + path  + \"\\n\")# \n######################################################################\n\n#### matplotlib debut 1/5 #################################################################\n#import PySide2\n#from PySide2 import (QtWidgets, QtCore, QtGui)\n#from PySide2.QtWidgets import (QWidget, QApplication, QSlider, QGraphicsView, QGraphicsScene, QVBoxLayout, QStyle)\n\nimport re\nimport operator\nfrom operator import itemgetter #, attrgetter, methodcaller    # pour sort \nimport platform\n\nglobal newPolicePath\nglobal PolicePath\nglobal originalFontName\nglobal originalFontPath\nglobal searchFontName\n\nif platform.system()   == \"Windows\" :\n    PolicePath = newPolicePath = originalFontPath = \"C:/Windows/Fonts/\"\n    originalFontName = \"ARIAL\"\nelif platform.system() == \"Linux\" :\n    PolicePath = newPolicePath = originalFontPath = \"/usr/share/fonts/\"\n    originalFontName = \"UBUNTU-M\"\nelif platform.system() == \"Darwin\":\n    PolicePath = newPolicePath = originalFontPath = \"/Library/Fonts/\"\n    originalFontName = \"Arial\"\n\n#import glob\n#files_TTF = glob.glob(self.pathFont + \"/*.TTF\") \n##################################\nimport matplotlib\nimport matplotlib.font_manager\nimport matplotlib.font_manager as fontman\nimport matplotlib.font_manager as fontconfig\nfrom matplotlib.font_manager import FontProperties\n#from matplotlib.ft2font import FT2Font\n##################################\n\n#### Config Begin matplotlib font #######################\n                                                        # # https://en.wikipedia.org/wiki/Web_colors\nglobal setColorTTF       ; setColorTTF       = \"blue\"   # .TTF   color by \"extension name\" or hexa \"#0000FF\" \nglobal setColorFON       ; setColorFON       = \"orange\" # .FON   color by \"extension name\" or hexa \"#FFA500\"\nglobal setColorOTF       ; setColorOTF       = \"green\"  # .OTF   color by \"extension name\" or hexa \"#008000\"\nglobal setColorPOL       ; setColorPOL       = \"black\"  # .OTHER color by \"extension name\" or hexa \"#000000\"\n                                                      #####\nglobal switchModeTextList; switchModeTextList= 1        # 0 = mode text normal (et noir) coupe le switchFontComBox\n                                                        # 1 = permet le switchFontComBox 1 (default)\n                                                      #####\nglobal switchFontComBox  ; switchFontComBox  = 0        # 0 = (et switchModeTextList= 1) mode texte (en couleur) dans liste ComboBox plus rapide (default)\n                                                        # 1 = (et switchModeTextList= 1) fontFamily dans liste ComboBox plus lent mais plus beau!\n                                                      #####\nglobal setSystemFonts    ; setSystemFonts    = 1        # 0 = matplotlib.font_manager.findSystemFonts(\"C:/\", \"ttf\") \n                                                        #     fait toutes les fontes (dans tous les dossiers et sous dossiers du DD) time !!\n                                                        # 1 = fontman.findSystemFonts(self.pathFont)\n                                                        #     fait toutes les fontes du repertoire (et dans tous les sous dossiers) (default)\n                                                      #####\nglobal seTtextAlignement ; seTtextAlignement = 0        # 0 = AlignLeft (default)\n                                                        # 1 = AlignCenter\n                                                        # 2 = AlignRight\n                                                      #####\nglobal setFontByDefault  ; setFontByDefault  = \"ARIAL\"  # Font by Default\n                                                      #####\nglobal setLastFontPath   ; setLastFontPath   = PolicePath#directory font by start\n                                                      #####\n#### Config End matplotlib font #########################\n\n###### Read Configuration begin ####\nseTtextAlignement  = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetInt(\"seTtextAlignement\")\nsetSystemFonts     = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"setSystemFonts\")\nswitchFontComBox   = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switchFontComBox\")\nswitchModeTextList = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"switchModeTextList\")\nsetFontByDefault   = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetString(\"setFontByDefault\")\nsetLastFontPath    = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetString(\"setLastFontPath\")\n\nif setLastFontPath == \"\":\n    setLastFontPath = PolicePath\nelse:\n    PolicePath = setLastFontPath\n\nif setFontByDefault == \"\":\n    if platform.system()   == \"Windows\" :\n        setFontByDefault = \"ARIAL\"\n    elif platform.system() == \"Linux\" :\n        setFontByDefault = \"UBUNTU-M\"\n    elif platform.system() == \"Darwin\":\n        setFontByDefault = \"Arial\"\nsearchFontName = setFontByDefault\n###### Read Configuration end   ####\n\nhomeIcon = [\n\"24 24 14 1\",\n\" \tc None\",\n\".\tc #EF2929\",\n\"+\tc #A40000\",\n\"@\tc #DDDFDC\",\n\"#\tc #888A85\",\n\"$\tc #DDDEDB\",\n\"%\tc #DCDEDB\",\n\"&\tc #DCDEDC\",\n\"*\tc #DBDDDA\",\n\"=\tc #BABDB6\",\n\"-\tc #555753\",\n\";\tc #729FCF\",\n\">\tc #3465A4\",\n\",\tc #8191AA\",\n\"                        \",\n\"                        \",\n\"           .+           \",\n\"          ..++          \",\n\"         ....++         \",\n\"        .....+++        \",\n\"       ....@#++++       \",\n\"      ....@@@#++++      \",\n\"     ....@@@@@#++++     \",\n\"    ....@@@@$@@#++++    \",\n\"   ....@@@$@@%@@#++++   \",\n\"  ....@@@@@@@@%@@#++++  \",\n\"  ...@@@%%%%&%%*@@#+++  \",\n\"  ..@@@@@@@@@@@@@@@#++  \",\n\"   #@@=#---@@=====@#    \",\n\"   #@@=#---@@;>>>;@#    \",\n\"   #@@,#---@@;>>>;@#    \",\n\"   #@@,#---@@;>>>;@#    \",\n\"   #@@=#---@@-----@#    \",\n\"   #@@=#---@@@@@@@@#    \",\n\"   #@@=##--@@@@@@@@#    \",\n\"   #################    \",\n\"                        \",\n\"                        \"]\n\nfolderNewIcon = [\n\"24 24 11 1\",\n\" \tc None\",\n\".\tc #FCE94F\",\n\"+\tc #EDD400\",\n\"@\tc #555753\",\n\"#\tc #BABDB6\",\n\"$\tc #2B4F89\",\n\"%\tc #D3D7CF\",\n\"&\tc #5479AB\",\n\"*\tc #B8BBB5\",\n\"=\tc #B6BAB4\",\n\"-\tc #2E5089\",\n\" ......                 \",\n\"........                \",\n\"........                \",\n\".+++++++                \",\n\".+.....+@@@@@@@@@@@@    \",\n\".+......###########@    \",\n\".+....$$$$$########@    \",\n\" +....$%%%$$$$$$$$$$$$& \",\n\" @####$$$$$$$$$$$$$$$$& \",\n\" @####$$$$$$$$$$$$$$$$& \",\n\"  @###$$$$$$$$$$$$$$$$& \",\n\"  @#*$$$$$$$$$$$$$$$$$& \",\n\"  @#=$$$$$$$$$$$$$$$$$& \",\n\"  @#=$$$$$$$$$$$$$$$$$& \",\n\"  @#=$$$$$$$$$$$$$$$&&& \",\n\"  @##$$$$$$$$$$$$$$$&   \",\n\"   @$$$$$$$$$$$$$$$$&   \",\n\"   @$-$$$$$$$$$$$$$$&   \",\n\"   @$$$$$$$$$$$$$$$&&   \",\n\"   &&&&&&&&&&&&&&&&&    \",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                        \"]\n\nhelpIcon = [\n\"24 24 4 1\",\n\" \tc None\",\n\".\tc #016AC5\",\n\"+\tc #F8F8FF\",\n\"@\tc #FFFFFF\",\n\"........................\",\n\".++++++++++++++++++++++.\",\n\".++++++++++++++++++++++.\",\n\".++..................++.\",\n\".++..................++.\",\n\".++......@@@@@@......++.\",\n\".++.....@@@@@@@@.....++.\",\n\".++.....@@@..@@@.....++.\",\n\".++.....@@....@@.....++.\",\n\".++.....@@....@@.....++.\",\n\".++...........@@.....++.\",\n\".++..........@@@.....++.\",\n\".++.........@@@......++.\",\n\".++........@@@.......++.\",\n\".++........@@........++.\",\n\".++........@@........++.\",\n\".++..................++.\",\n\".++........@@........++.\",\n\".++........@@........++.\",\n\".++..................++.\",\n\".++..................++.\",\n\".++++++++++++++++++++++.\",\n\".++++++++++++++++++++++.\",\n\"........................\"]\n\nvalidIcon = [\n\"24 24 3 1\",\n\" \tc None\",\n\".\tc #4E9A06\",\n\"+\tc #FFFFFF\",\n\"                        \",\n\"                        \",\n\"                        \",\n\"                  .     \",\n\"                 .+.    \",\n\"                .+.+.   \",\n\"               .+...+.  \",\n\"              .+.....+. \",\n\"     .       .+.......+.\",\n\"    .+.     .+.......+. \",\n\"   .+.+.   .+.......+.  \",\n\"  .+...+. .+.......+.   \",\n\" .+.....+.+.......+.    \",\n\".+.......+.......+.     \",\n\" .+.............+.      \",\n\"  .+...........+.       \",\n\"   .+.........+.        \",\n\"    .+.......+.         \",\n\"     .+.....+.          \",\n\"      .+...+.           \",\n\"       .+.+.            \",\n\"        .+.             \",\n\"         .              \",\n\"                        \"]\n\npaintIcon = [\n\"24 24 9 1\",\n\" \tc None\",\n\".\tc #16D0D2\",\n\"+\tc #D3D7CF\",\n\"@\tc #C17D11\",\n\"#\tc #EDD400\",\n\"$\tc #73D216\",\n\"%\tc #F57900\",\n\"&\tc #3465A4\",\n\"*\tc #CC0000\",\n\"         ....           \",\n\" +++     ....      @@@@ \",\n\" ++####  ....  $$$ @@@@ \",\n\" ++####%%%...&&$$$ @@@@ \",\n\"   ####%%% &&&&$$$ @@@@ \",\n\"   ####%%%+&&&&**       \",\n\"    $$$$ ++&&&&**##%%%  \",\n\"@@@@$$$$ ++++ ***##%%%  \",\n\"@@@@$$$$ ++++  ####%%%  \",\n\"@@@@      &&&$$$$##     \",\n\"@@@$$$$ %%&&&$$$$ %%%%  \",\n\"   $$$$ %%&***$$$ %%%%  \",\n\"...$$$$ %%%***$$$ %%%%  \",\n\"...$$$$*** ***&&&+%%%%  \",\n\"....%%%***### &&&+++@@@@\",\n\"....%%%***### &&&+++@@@@\",\n\"  +++%%   ### ....  @@@@\",\n\"  +++ &&&  $$$..####@@@@\",\n\"  +++ &&****$$..####    \",\n\" #### &&****$&&&###**** \",\n\" ####+++**...&&&###**** \",\n\" ####+++**...&&&&  **** \",\n\" ####+++  ...&&&&  **** \",\n\"          ....          \"]\n\nquitIcon = [\n\"24 24 3 1\",\n\" \tc None\",\n\".\tc #FFFFFF\",\n\"+\tc #CC0000\",\n\"          ....          \",\n\"++++++++++....++++++++++\",\n\"+.......++....++.......+\",\n\"+.......++....++.......+\",\n\"+.......++....++.......+\",\n\"+...++++++....++++++...+\",\n\"+...++++++....++++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...+++++......+++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+...++++++++++++++++...+\",\n\"+......................+\",\n\"+......................+\",\n\"+......................+\",\n\"++++++++++++++++++++++++\"]\n\nsetIconTTF = [\n\"16 16 6 1\",\n\" \tc None\",\n\".\tc #204A87\",\n\"+\tc None\",\n\"@\tc #729FCF\",\n\"#\tc #CC0000\",\n\"$\tc #EDD400\",\n\".+++++++++++@@@@\",\n\".++++++++@+@++@@\",\n\".++#####++++@@+@\",\n\".+++$#$$$++@+@+@\",\n\".++++#$+++++++@+\",\n\".++++#$#####++++\",\n\".++++#$+$#$$$+++\",\n\".++++#$++#$+++++\",\n\".@++++$++#$+###+\",\n\".@@++++++#$+#$$$\",\n\"..@@+++++#$+#$++\",\n\"...@@+++++$+###+\",\n\"....@@++++++#$$$\",\n\".....@@+++++#$++\",\n\"......@@+++++$++\",\n\"................\"]\n\nsetIconFON = [\n\"16 16 6 1\",\n\" \tc None\",\n\".\tc #204A87\",\n\"+\tc None\",\n\"@\tc #F57900\",\n\"#\tc #CC0000\",\n\"$\tc #EDD400\",\n\".+++++++++++@@@@\",\n\".++++++++@+@++@@\",\n\".++###++++++@@+@\",\n\".++#$$$++++@+@+@\",\n\".++#$+++++++++@+\",\n\".++###+###++++++\",\n\".++#$$$#$#$+++++\",\n\".++#$++#$#$+++++\",\n\".@++$++#$#$##+#+\",\n\".@@++++#$#$##$#$\",\n\"..@@+++###$#$##$\",\n\"...@@+++$$$#$##$\",\n\"....@@+++++#$+#$\",\n\".....@@++++#$+#$\",\n\"......@@++++$++$\",\n\"................\"]\n\nsetIconOTF = [\n\"16 16 6 1\",\n\" \tc None\",\n\".\tc #204A87\",\n\"+\tc None\",\n\"@\tc #4E9A06\",\n\"#\tc #CC0000\",\n\"$\tc #EDD400\",\n\".+++++++++++@@@@\",\n\".++++++++@+@++@@\",\n\".++###++++++@@+@\",\n\".++#$#$++++@+@+@\",\n\".++#$#$+++++++@+\",\n\".++#$#$###++++++\",\n\".++#$#$+#$$+++++\",\n\".++###$+#$++++++\",\n\".@++$$$+#$+###++\",\n\".@@+++++#$+#$$$+\",\n\"..@@++++#$+#$+++\",\n\"...@@++++$+###++\",\n\"....@@+++++#$$$+\",\n\".....@@++++#$+++\",\n\"......@@++++$+++\",\n\"................\"]\n\nsetIconPOL = [\n\"16 16 12 1\",\n\" \tc None\",\n\".\tc #204A87\",\n\"+\tc None\",\n\"@\tc #06989A\",\n\"#\tc #73D216\",\n\"$\tc #000000\",\n\"%\tc #75507B\",\n\"&\tc #729FCF\",\n\"*\tc #CC0000\",\n\"=\tc #F57900\",\n\"-\tc #EDD400\",\n\";\tc #4E9A06\",\n\".+++++++++++@#$%\",\n\".++++++++$+#++&$\",\n\".++***++++++=@+%\",\n\".++*-*-++++*+&+$\",\n\".++*-*-+++++++*+\",\n\".++***-***++++++\",\n\".++*---*-*-+++++\",\n\".++*-++*-*-+++++\",\n\".$++-++*-*-*++++\",\n\".*@++++*-*-*-+++\",\n\"..#*+++***-*-+++\",\n\"...;#+++---*-+++\",\n\"....%=+++++*-+++\",\n\".....;$++++****+\",\n\"......@%++++----\",\n\"................\"]\n\ndef createSpace(texte):    # detecte majuscule et ajoute un espace devant la lettre\n    # return createSpace(TexTe) = Tex Te , if createSpace(TEXTE) = TEXTE\n    if texte.isupper():\n        stringSpace = texte\n    else:\n        try:\n            stringSpace = texte[0]\n            for i in texte[1:]:\n                if re.search(r\"[A-Z]\", i): i = \" \" +  i\n                stringSpace += i\n        except Exception:\n            stringSpace = texte\n    return stringSpace\n\ndef family(chaine):\n    # return family(chaine)[1] = Family , family(chaine)[2] = typeCar (form [a, b, c ...]\n    famille = typeCar = \"\"\n    try:\n        if chaine.find('-') != -1:\n            famille = chaine[:chaine.find('-')]\n            typeCar = chaine[chaine.find('-')+1:]\n        else:\n            famille = chaine\n            typeCar = \"\"\n    except Exception:\n        famille = chaine\n        typeCar = \"\"\n    typeCar = str(createSpace(typeCar)).split()\n    return [createSpace(famille), typeCar]\n\nclass MyLabelPatience():        # fenetre image d'attente de chargement\n    global path\n    label = QtWidgets.QLabel()\n    label.setText(\"<img src=\" + path + \"Macro_Fonts_Win10_PYMP.png><b><center>Wait please</center> \\n\\n<center>i search the fonts !\\n\\n</right></b>\")\n    ecran = FreeCADGui.getMainWindow().frameGeometry()\n    xF = 250; yF = 250\n    xW = (ecran.width()/2) - (xF/2)\n    yW = (ecran.height()/2)- (yF/2)\n    label.setGeometry(xW, yW, xF, yF)\n    label.setStyleSheet(\"QLabel {background-color : #F0C300;font: 12pt; }\");\n    label.setWindowFlags(PySide2.QtCore.Qt.WindowFlags(PySide2.QtCore.Qt.FramelessWindowHint))        # pas de bords\n    label.setWindowFlags(PySide2.QtCore.Qt.WindowStaysOnTopHint)         # PySide cette fonction met la fenetre en avant\n#### matplotlib fin 1/5 #################################################################\n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\nclass Ui_MainWindow(object):\n\n    def __init__(self ):\n        self.window = MainWindow\n        global path                                                          #\n        self.path = path\n\n        #### matplotlib font textEdit\n        self.nomPolice     = \"Arial\"\n        self.FontTextSize  = 20\n        self.fonteComp     = \"\"\n        self.font          = QtGui.QFont()\n        ####font textEdit\n        self.FontSize  = 10.0\n        self.red       = (204.0 / 255.0)\n        self.green     = (204.0 / 255.0)\n        self.blue      = (204.0 / 255.0)\n        self.alpha     = 1.0                      # 1.0 = visibility max (opacity)\n\n        self.tableau   = []    #Index (), [chemin plus nom fichier (nomPathPolice), nom sans extension (nomSimple), nomSimpleExt (nomSimple + Ext)]\n        self.index     = 0     #Index ()\n        #### matplotlib font textEdit\n\n    def searchFont(self,pathSearch):\n        global ui\n        global setSystemFonts\n        global seTtextAlignement\n        global switchFontComBox\n        global switchModeTextList\n        global setFontByDefault\n        global searchFontName\n\n        MyLabelPatience.label.show()\n        FreeCADGui.updateGui()                                 # rafraichi l'ecran\n\n        files_All_Fonts = \"\"\n        ##https://matplotlib.org/_modules/matplotlib/font_manager.html\n\n        if setSystemFonts == 0:\n            files_All_Fonts = matplotlib.font_manager.findSystemFonts(pathSearch, \"ttf\")  # fait toutes les fontes ? ()\n        else:\n            files_All_Fonts = fontman.findSystemFonts(pathSearch)                         # fait toutes les fontes (et dans tous les sous dossiers)\n\n        if len(files_All_Fonts) > 0:           \n            self.tableau = []\n            self.index = 0\n\n            for fonte in files_All_Fonts:\n                ####\n                nomPathPolice = nomFichier = nomSimpleExt = nomSimple = nomExtension = nameName = \"\"\n\n                nomPathPolice = fonte.replace(\"\\\\\",\"/\")     # convert the \"\\\" to \"/\"\n                nomFichier    = nomPathPolice.split(\"/\")    # complet split\n                nomSimpleExt  = nomFichier[-1]              # nom avec extension\n                nomSimple     = nomFichier[-1][:-4]         # nom sans extension\n                nomExtension  = nomSimpleExt[nomSimpleExt.rfind('.')+1:].upper() # extension\n\n                ####\n                try:\n#                    nameFamily    = matplotlib.font_manager.FontProperties(fname=fonte).get_family()            ##['sans-serif']\n#                    nameStyle     = matplotlib.font_manager.FontProperties(fname=fonte).get_style()              #normal\n#                    nameVariant   = matplotlib.font_manager.FontProperties(fname=fonte).get_variant()            #normal\n#                    nameWeight    = matplotlib.font_manager.FontProperties(fname=fonte).get_weight()             #normal\n#                    nameStretch   = matplotlib.font_manager.FontProperties(fname=fonte).get_stretch()            #normal\n#                    nameFileComp  = matplotlib.font_manager.FontProperties(fname=fonte).get_file()              ##c:\\windows\\fonts\\NotoNaskhArabicUI-Regular.ttf\n#                    nameSize      = matplotlib.font_manager.FontProperties(fname=fonte).get_size()               #10.0\n                    nameName      = matplotlib.font_manager.FontProperties(fname=fonte).get_name()              ##Noto Naskh Arabic UI\n#                    nameSizePoint = matplotlib.font_manager.FontProperties(fname=fonte).get_size_in_points()     #10.0\n#                    nameSlant     = matplotlib.font_manager.FontProperties(fname=fonte).get_slant()              #normal\n#                    namePattern   = matplotlib.font_manager.FontProperties(fname=fonte).get_fontconfig_pattern() #:family=sans-serif:style=normal:variant=normal:weight=normal:stretch=normal:file=c:\\windows\\fonts\\NotoNaskhArabicUI-Regular.ttf:size=10.0\n                except Exception:\n                    nameFamily = nameStyle = nameVariant = nameWeight = nameStretch = nameFileComp = nameSize = nameName = nameSizePoint = nameSlant = namePattern = \"\"\n                ####\n                if nameName == \"\" :\n                    nameName = nomSimple\n                self.tableau.append([0, nomPathPolice, nomSimple, nomSimpleExt.upper(), nomExtension.upper(), nameName])\n            self.tableau = sorted(self.tableau, key=itemgetter(3))          # sorted by nomSimple.upper()\n\n            try:\n                for line in range(len(self.tableau)):                       # enleve les doubles (bon)\n                    if self.tableau[line][2] == self.tableau[line + 1][2]:  # enleve les doubles (bon)\n                        del(self.tableau[line + 1])                         # enleve les doubles (bon)\n            except Exception:\n                None\n            self.comboBoxPy.clear()\n\n            for line in range(len(self.tableau)): \n                try:\n                    self.tableau[line][0] = line                 # ajoute le numero de ligne\n                    if self.tableau[line][2].upper() == searchFontName.upper(): # detecte la fonte de base\n                        self.index = line\n                        PolicePath = self.tableau[line][1]\n                    ####Section common color and font begin ######################\n                    model = self.comboBoxPy.model()\n\n                    if switchModeTextList == 1:\n                        if self.tableau[line][4] == \"TTF\":\n                            item = QtGui.QStandardItem(QtGui.QPixmap(setIconTTF), str(line))\n                            item.setForeground(QtGui.QColor(setColorTTF))\n                        elif self.tableau[line][4] == \"FON\":\n                            item = QtGui.QStandardItem(QtGui.QPixmap(setIconFON), str(line))\n                            item.setForeground(QtGui.QColor(setColorFON))\n                        elif self.tableau[line][4] == \"OTF\":\n                            item = QtGui.QStandardItem(QtGui.QPixmap(setIconOTF), str(line))\n                            item.setForeground(QtGui.QColor(setColorOTF))\n                        else:\n                            item = QtGui.QStandardItem(QtGui.QPixmap(setIconPOL), str(line))\n                            item.setForeground(QtGui.QColor(setColorPOL))\n\n                        if   seTtextAlignement == 0:\n                            item.setTextAlignment(QtCore.Qt.AlignLeft)\n                        elif seTtextAlignement == 1:\n                            item.setTextAlignment(QtCore.Qt.AlignCenter)\n                        elif seTtextAlignement == 2:\n                            item.setTextAlignment(QtCore.Qt.AlignRight)\n                        else:\n                            self.comboBoxPy.addItem(self.tableau[line][2])    \n                        model.appendRow(item)\n                    else:\n                        self.comboBoxPy.addItem(\"\")\n                    self.comboBoxPy.setItemText(line, self.tableau[line][2])\n                    ####Section item color and font end ##########################\n    \n                    ####Section setfont Family switchFontComBox begin#############\n                    if (switchFontComBox == 1) and (switchModeTextList == 1):\n                        typeCar = font = \"\"\n                        font = QtGui.QFont()\n                        #font = item.font()\n        \n                        typeCar   = family(self.tableau[line][2])[1]\n                        font.setBold(False)\n                        font.setItalic(False)\n        \n                        if len(typeCar) > 0:\n                            for option in typeCar:\n                                if option == \"Bold\":\n                                    font.setBold(True)\n                                if (option == \"Italic\") or (option == \"It\") or (option == \"Slanted\"):\n                                    font.setItalic(True)\n                                if option == \"Oblique\":\n                                    font.setItalic(True)\n                        #'Bold''Regular''Slanted''Italic''Medium''Extra''Light''Condensed''Black''It''Semibold'\n                        \n                        font.setFamily(self.tableau[line][5])\n                        font.setPixelSize(15)\n                        if switchModeTextList == 1:\n                            item.setFont(font)\n                        else:\n                            self.comboBoxPy.addItem(\"\")\n                    ####Section setfont Family switchFontComBox end###############\n                except Exception:\n                    FreeCAD.Console.PrintMessage(\"searchFont()\")\n                    None\n            #for i in self.tableau: print(i)\n            font = QtGui.QFont()\n            font.setFamily(self.tableau[self.index][5])\n            font.setPointSize(self.FontTextSize)\n            self.textEditFont.setFont(font)\n            self.textEditFont.setToolTip(\"Your text here\" + \"\\n\"\n                                     \"Title (\" + str(self.index + 1) + \"/\" + str(len(self.tableau)) + \") = (index file, number file font)\" + \"\\n\"\n                                     \"Version \" + __version__ + \" : \" + __date__ + \") of \" + __title__  + \")\" + \"\\n\\n\"\n                                     \"It is possible that a font is not visible in its normal design,\" + \"\\n\"\n                                     \"but it is normal in the 3DView, sorry !\")\n            self.lineEdit_NameFile.setText(\"(\" + str(self.index + 1) + \"/\" + str(len(self.tableau)) + \") \" + self.tableau[self.index][1])\n            self.comboBoxPy.setCurrentIndex(self.index)\n            self.fonteComp  = self.tableau[self.index][1]\n        else:\n            self.PB_systemPath.setStyleSheet(\"background-color: rgb(0, 224, 0)\")\n            self.PB_newPathFont.setStyleSheet(\"background-color: rgb(0, 224, 0)\")\n        MyLabelPatience.label.close()\n\n    def setupUi(self, MainWindow):\n        global ui\n        global PolicePath          \n               \n        self.window = MainWindow\n        MainWindow.setObjectName((\"MainWindow\"))\n        MainWindow.resize(470, 250)\n#        MainWindow.setMinimumSize(QtCore.QSize(470, 250))\n#        MainWindow.setMaximumSize(QtCore.QSize(470, 250))\n        self.centralwidget = QtWidgets.QWidget(MainWindow)\n        self.centralwidget.setObjectName((\"centralwidget\"))\n\n        self.groupBox_00 = QtWidgets.QGroupBox()\n        self.groupBox_01 = QtWidgets.QGroupBox()\n        self.groupBox_02 = QtWidgets.QGroupBox()\n\n        self.textEditFont = QtWidgets.QTextEdit(self.centralwidget)\n        self.lineEdit_NameFile = QtWidgets.QLineEdit(self.centralwidget)\n\n        self.PB_color = QtWidgets.QPushButton(self.centralwidget)\n        self.PB_color.setIcon(QtGui.QIcon(QtGui.QPixmap(paintIcon))) # icone dans une variable \n        self.PB_color.clicked.connect(self.on_PB_color)                             # \"\"\n                                        \n        self.doubleSpinBox_1 = QtWidgets.QDoubleSpinBox(self.centralwidget)\n        self.doubleSpinBox_1.setMinimum(0.0)\n        self.doubleSpinBox_1.setMaximum(10000.0)\n        self.doubleSpinBox_1.setSingleStep(1.0)\n        self.doubleSpinBox_1.setValue(self.FontSize)\n        self.doubleSpinBox_1.valueChanged.connect(self.on_doubleSpinBox_1_valueChanged)# \"\"\n\n        self.checkBox_1 = QtWidgets.QCheckBox(self.centralwidget)\n        self.checkBox_1.setChecked(False)\n#        self.checkBox_1.clicked.connect(self.on_checkBox_1_clicked)\n\n        self.doubleSpinBox_2 = QtWidgets.QDoubleSpinBox(self.centralwidget)\n        self.doubleSpinBox_2.setMinimum(0.0)\n        self.doubleSpinBox_2.setMaximum(10000.0)\n        self.doubleSpinBox_2.setSingleStep(1.0)\n        self.doubleSpinBox_2.setValue(self.FontTextSize)\n        self.doubleSpinBox_2.valueChanged.connect(self.on_doubleSpinBox_2_valueChanged)#connect on def \"on_doubleSpinBox_2_valueChanged\"\n\n        self.PU_Exit = QtWidgets.QPushButton(self.centralwidget)\n        self.PU_Exit.setIcon(QtGui.QIcon(QtGui.QPixmap(quitIcon)))          # icone dans une variable \n        self.PU_Exit.clicked.connect(self.on_PU_Exit)\n\n        self.PB_OK = QtWidgets.QPushButton(self.centralwidget)\n        self.PB_OK.setIcon(QtGui.QIcon(QtGui.QPixmap(validIcon)))           # icone dans une variable \n        self.PB_OK.clicked.connect(self.on_PB_OK)\n                                          \n        self.PB_newPathFont = QtWidgets.QPushButton(self.centralwidget)\n        self.PB_newPathFont.setIcon(QtGui.QIcon(QtGui.QPixmap(folderNewIcon)))# icone dans une variable \n        self.PB_newPathFont.clicked.connect(self.on_PB_newPathFont)\n\n        self.PB_systemPath = QtWidgets.QPushButton(self.centralwidget)\n        self.PB_systemPath.setIcon(QtGui.QIcon(QtGui.QPixmap(homeIcon)))    # icone dans une variable \n        self.PB_systemPath.clicked.connect(self.on_PB_systemPath)\n\n        self.PB_Help = QtWidgets.QPushButton()\n        self.PB_Help.setIcon(QtGui.QIcon(QtGui.QPixmap(helpIcon)))          # icone dans une variable \n        self.PB_Help.clicked.connect(self.on_PB_Help)\n        ####\n        self.comboBoxPy = QtWidgets.QComboBox(self.centralwidget)\n        ui.searchFont(PolicePath)\n#        ui.on_fontComboBoxPython(self.index)\n        QtCore.QObject.connect(self.comboBoxPy, QtCore.SIGNAL(\"currentIndexChanged(int)\"), self.on_fontComboBoxPython)\n        ####\n\n        ####Layout#########################################################\n        gridLayout_00_Font = QtWidgets.QGridLayout(self.centralwidget)    # cadre principal\n        gridLayout_00_Font.addWidget(self.groupBox_00)                    # cadre groupbox principal\n        gridLayout_01_Font = QtWidgets.QGridLayout(self.groupBox_00)      # groupBox_00\n\n        self.gridLayout_Font_Font = QtWidgets.QGridLayout(self.groupBox_01)\n        self.gridLayout_Font_Font.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_Font_Font.addWidget(self.textEditFont, 0, 0, 1, 1)\n        self.gridLayout_Font_Font.addWidget(self.lineEdit_NameFile, 1, 0, 1, 1)\n        self.gridLayout_Font_Font.addWidget(self.comboBoxPy, 2, 0, 1, 1)\n        gridLayout_01_Font.addWidget(self.groupBox_01, 0, 0, 1, 1)\n        ####\n        self.gridLayout_Command_Font = QtWidgets.QGridLayout(self.groupBox_02)\n        self.gridLayout_Command_Font.setContentsMargins(10, 10, 10, 10)\n        self.gridLayout_Command_Font.addWidget(self.PB_color, 0, 0, 1, 1)\n        self.gridLayout_Command_Font.addWidget(self.doubleSpinBox_1, 0, 1, 1, 1)\n        self.gridLayout_Command_Font.addWidget(self.checkBox_1, 0, 3, 1, 1)\n        self.gridLayout_Command_Font.addWidget(self.doubleSpinBox_2, 0, 4, 1, 1)\n        self.gridLayout_Command_Font.addWidget(self.PU_Exit, 1, 0, 1, 1)\n        self.gridLayout_Command_Font.addWidget(self.PB_OK, 1, 1, 1, 1)\n        self.gridLayout_Command_Font.addWidget(self.PB_newPathFont, 1, 2, 1, 1)\n        self.gridLayout_Command_Font.addWidget(self.PB_systemPath, 1, 3, 1, 1)\n        self.gridLayout_Command_Font.addWidget(self.PB_Help, 1, 4, 1, 1)\n        gridLayout_01_Font.addWidget(self.groupBox_02, 1, 0, 1, 1)\n        ####Layout#########################################################\n\n        MainWindow.setCentralWidget(self.centralwidget)\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n\n        MainWindow.setWindowTitle(_fromUtf8(__title__))\n        MainWindow.setWindowFlags(PySide2.QtCore.Qt.WindowStaysOnTopHint)            # PySide cette fonction met la fenetre en avant\n        MainWindow.setWindowIcon(QtGui.QIcon(_fromUtf8(self.path + \"Macro_Fonts_Win10_PYMP.png\")))  # change l'icone de la fenetre principale\n\n        self.groupBox_00.setTitle(_fromUtf8(\"ver : \" + __version__ + \" : \" + __date__ + \" (rmu)\"))\n        self.groupBox_01.setTitle(_fromUtf8(\"Font\"))\n        self.textEditFont.setText(\"Your text here\")\n        self.textEditFont.setToolTip(\"Your text here\" + \"\\n\"\n                                 \"Title (\" + str(self.index + 1) + \"/\" + str(len(self.tableau)) + \") = (index file, number file font)\" + \"\\n\"\n                                 \"Version \" + __version__ + \" : \" + __date__ + \") of \" + __title__  + \")\" + \"\\n\\n\"\n                                 \"It is possible that a font is not visible in its normal design,\" + \"\\n\"\n                                 \"but it is normal in the 3DView, sorry !\")\n        self.lineEdit_NameFile.setToolTip(\"Complete path and name of Font file\")\n        self.comboBoxPy.setToolTip(\"Choice your Font\" + \"\\n\" +\n                                   \"\\n\" +\n                                   \"You must modify the configuration of display\" + \"\\n\" +\n                                   \"Menu Edit parameter: User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__ + \":\" + \"\\n\" +\n                                   \"####\" + \"\\n\" +\n                                   \"switchModeTextList= 1\\t# 0 = mode text normal (the switchFontComBox is enabled)\" + \"\\n\"\n                                   \"\\t\\t\\t# 1 = switchFontComBox authorized (default)\" + \"\\n\"\n                                   \"\\t\\t\\t#####\" + \"\\n\"\n                                   \"switchFontComBox  = 1\\t# 0 = mode text in color .. faster\" + \"\\n\"\n                                   \"\\t\\t\\t# 1 = fontFamily listed ComboBox slower but beautiful (default)\" + \"\\n\"\n                                   \"\\t\\t\\t#####\" + \"\\n\"\n                                   \"setSystemFonts    = 1\\t# 0 = matplotlib.font_manager.findSystemFonts\" + \"\\n\"\n                                   \"\\t\\t\\t#   all fonts in System font\" + \"\\n\"\n                                   \"\\t\\t\\t# 1 = fontman.findSystemFonts(self.pathFont) (default)\" + \"\\n\"\n                                   \"\\t\\t\\t# all fonts in all directory and sub directory\" + \"\\n\"\n                                   \"\\t\\t\\t#####\" + \"\\n\"\n                                   \"seTtextAlignement = 0\\t# 0 = AlignLeft (default)\" + \"\\n\"\n                                   \"\\t\\t\\t# 1 = AlignCenter\" + \"\\n\"\n                                   \"\\t\\t\\t# 2 = AlignRight\" + \"\\n\"\n                                   \"\\t\\t\\t#####\" + \"\\n\"\n                                   \"setFontByDefault = \"\"ARIAL\"\"\\t # ARIAL\" + \"\\n\"\n                                   \"\\t\\t\\t#####\" + \"\\n\"\n                                   \"setLastFontPath  = PolicePath# directory font by start\" + \"\\n\"\n                                   \"####\" + \"\\n\"\n                                   \"Actual configuration : \" + str(switchModeTextList) + \", \" + str(switchFontComBox) + \", \" + str(setSystemFonts) + \", \"\n                                                             + str(seTtextAlignement) + \", \" + setFontByDefault + \", \" + setLastFontPath + \"\\n\"\n                                   \"####\" + \"\\n\" +\n                                   \"Read the info\")\n        ####\n        self.groupBox_02.setTitle(_fromUtf8(\"Command\"))\n        self.PB_OK.setText(_fromUtf8(\"Ok\"))\n        self.PB_OK.setToolTip(_fromUtf8(\"Validate\"))\n        self.PB_color.setText(_fromUtf8(\"Color\"))\n        self.PB_color.setToolTip(_fromUtf8(\"Text color\"))\n        self.doubleSpinBox_1.setToolTip(_fromUtf8(\"Dimension of the Shape\"))\n        self.doubleSpinBox_1.setSuffix(\" mm\")\n        self.checkBox_1.setText(_fromUtf8(\"Text\"))\n        self.checkBox_1.setToolTip(_fromUtf8(\"Create text\"))\n        self.PB_newPathFont.setText(_fromUtf8(\"New folder\"))\n        self.PB_newPathFont.setToolTip(_fromUtf8(\"New directory font\"))\n        self.doubleSpinBox_2.setToolTip(_fromUtf8(\"Dimension of text in window macro\"))\n        self.PU_Exit.setText(_fromUtf8(\"Exit\"))\n        self.doubleSpinBox_2.setSuffix(\" mm\")\n        self.PU_Exit.setToolTip(_fromUtf8(\"Quit Fonts Win10 PYMP by by\"))\n        self.PB_Help.setText(_fromUtf8(\"Help\"))\n        self.PB_Help.setToolTip(_fromUtf8(\"Help on line  \" + __version__ + \"  \" + __date__ + \" rmu\"))\n        self.PB_systemPath.setText(_fromUtf8(\"Origin\"))\n        self.PB_systemPath.setToolTip(_fromUtf8(\"Return origin font system\"))\n\n    def on_doubleSpinBox_1_valueChanged(self,value):    # \n\n        self.FontSize = value\n\n    def on_doubleSpinBox_2_valueChanged(self,value):\n\n        self.FontTextSize = value\n        self.font.setPointSize(self.FontTextSize)\n        self.textEditFont.setCurrentFont(self.font)\n        self.textEditFont.setFont(self.font)\n\n    def on_fontComboBoxPython(self,indeX):                                          # 0: for fontComboBoxPython\n        global setFontByDefault\n\n        self.index = indeX\n        self.lineEdit_NameFile.setText(\"(\" + str(self.index + 1) + \"/\" + str(len(self.tableau)) + \") \" + self.tableau[self.index][1])\n\n        famille   = typeCar = self.font = \"\"\n        self.font = QtGui.QFont()\n        typeCar   = family(self.tableau[self.index][2])[1]\n        self.font.setBold(False)\n        self.font.setItalic(False)\n\n        if len(typeCar) > 0:\n            for option in typeCar:\n                if option == \"Bold\":\n                    self.font.setBold(True)\n                if (option == \"Italic\") or (option == \"It\") or (option == \"Slanted\"):\n                    self.font.setItalic(True)\n                if option == \"Oblique\":\n                    self.font.setItalic(True)\n        #'Bold''Regular''Slanted''Italic''Medium''Extra''Light''Condensed''Black''It''Semibold'#+\n        \n        self.font.setFamily(self.tableau[self.index][5])\n        self.font.setPointSize(self.FontTextSize)\n\n        self.textEditFont.setCurrentFont(self.font)\n        self.textEditFont.setFont(self.font)\n        ####\n        self.fonteComp   = self.tableau[self.index][1]\n        setFontByDefault = self.tableau[self.index][2]\n#        FreeCAD.Console.PrintMessage(str(self.index) + \" , \" + self.tableau[self.index][1] + \" , \" + self.tableau[self.index][2] + \" , ' \" + famille + \"' , ' \" + typeCar + \" ' \\n\")\n\n    def on_PB_OK(self):\n        texte = self.textEditFont.toPlainText()\n        if texte != \"\":\n            tx = Draft.makeShapeString(String=texte, FontFile = self.fonteComp, Size = self.FontSize, Tracking = 0.0)\n            tx.Label = self.tableau[self.index][2]\n            tx.ViewObject.ShapeColor = (self.red, self.green, self.blue)                # color of ShapeString\n\n            ## section Texte\n            if self.checkBox_1.isChecked():\n                tx2 = Draft.makeText([texte],point=FreeCAD.Vector(0.0,0.0,0.0))\n                tx2.ViewObject.FontName  = self.tableau[self.index][1]\n                tx2.ViewObject.TextColor = (self.red, self.green, self.blue)            # color of text\n                tx2.ViewObject.FontSize  = self.FontSize\n                tx2.Label                = self.tableau[self.index][2]\n                               \n            FreeCAD.Console.PrintMessage(\"___________________\" + \"\\n\")\n            FreeCAD.Console.PrintMessage(texte + \"\\n\")\n            FreeCAD.Console.PrintMessage(self.tableau[self.index][1] + \"\\n\")\n            FreeCAD.Console.PrintMessage(self.tableau[self.index][2] + \"\\n\")\n            FreeCAD.Console.PrintMessage(str(self.FontSize) + \"\\n\")\n            FreeCAD.Console.PrintMessage(\"___________________\" + \"\\n\")\n            FreeCAD.ActiveDocument.recompute()\n        else:\n            FreeCAD.Console.PrintMessage(\"Not string\" + \"\\n\")\n\n    def on_PB_color(self):\n        self.PB_color.setStyleSheet(\"background-color: QPalette.Base\")\n        self.window.hide()\n        couleur = QtWidgets.QColorDialog.getColor()\n        if couleur.isValid():\n            self.red   = couleur.redF()\n            self.green = couleur.greenF()\n            self.blue  = couleur.blueF()\n            self.alpha = couleur.alphaF()\n        self.PB_color.setStyleSheet(\"background-color: \" + couleur.name())\n        self.window.show()\n\n    def on_PB_newPathFont(self):\n        global ui\n        global newPolicePath\n        global setSystemFonts\n        global setLastFontPath\n\n        self.PB_systemPath.setStyleSheet(\"background-color: QPalette.Base\")\n        self.PB_newPathFont.setStyleSheet(\"background-color: QPalette.Base\")\n        newPolicePath = str(QtWidgets.QFileDialog.getExistingDirectory(None, \"Select new font directory\", newPolicePath, QtWidgets.QFileDialog.ShowDirsOnly))\n        if newPolicePath:\n            setLastFontPath = newPolicePath\n            ui.searchFont(newPolicePath)\n            setSystemFonts = 1\n\n    def on_PB_systemPath(self):\n        global ui\n        global setSystemFonts\n        global originalFontPath\n        global originalFontName\n        global setLastFontPath\n        global searchFontName\n        \n        self.PB_systemPath.setStyleSheet(\"background-color: QPalette.Base\")\n        self.PB_newPathFont.setStyleSheet(\"background-color: QPalette.Base\")\n        setSystemFonts = 1\n        setLastFontPath  = originalFontPath\n        searchFontName   = originalFontName\n        ui.searchFont(originalFontPath)\n\n    def on_PB_Help(self):\n        WebGui.openBrowser(\"https://wiki.freecadweb.org/Macro_Fonts_Win10_PYMP\")\n        App.Console.PrintMessage(\"https://wiki.freecadweb.org/Macro_Fonts_ Win10_PYMP\" + \"\\n\")\n\n    def on_PU_Exit(self):                      # Exit\n        global switchModeTextList\n        global switchFontComBox\n        global setSystemFonts\n        global seTtextAlignement\n        global setFontByDefault\n        global setLastFontPath\n\n        ###### Write Configuration begin ####\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"setLastFontPath\", setLastFontPath)     # \"PolicePath\"\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"setFontByDefault\", setFontByDefault)   # \"Arial\"\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchModeTextList\", switchModeTextList) # True or False\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"switchFontComBox\", switchFontComBox)     # True or False\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"setSystemFonts\", setSystemFonts)         # True or False\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetInt(\"seTtextAlignement\", seTtextAlignement)    # 0, 1, 2\n        ###### Write Configuration end   ####\n        App.Console.PrintMessage(\"Fin \" + __title__ + \"\\n\")\n        self.window.hide()\n####\nFreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"Version\",__version__ + \" (\" + __date__ + \")\")# \n\ndoc = FreeCAD.ActiveDocument\nif doc == None:\n    doc = FreeCAD.newDocument()\n\nMainWindow = QtWidgets.QMainWindow()\nui = Ui_MainWindow()\nui.setupUi(MainWindow)\nMainWindow.show()",
    "url": "https://wiki.freecad.org/Macro_Fonts_Win10_PYMP",
    "raw_code_url": "",
    "wiki": "",
    "version": "02.00",
    "license": "",
    "date": "2020/06/06",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Fonts_Win10_PYMP.png",
    "icon_source": "https://wiki.freecadweb.org/images/f/fa/Macro_Fonts_Win10_PYMP.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "GenerateDrawing",
    "on_wiki": true,
    "on_git": false,
    "desc": "Macro for automatic drawing generation with 3 normal projections and one isometric.<br /><br />Macro version: 1.0.0<br />Last modified: 2022-01-08<br />FreeCAD version: 0.18.4 and above<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/7/74/GenerateDrawing.svg\">ToolBar Icon</a><br />Author: PR-DC<br /> ",
    "comment": "Macro for automatic drawing generation.",
    "code": "# Macro for automatic drawing generation \n# with 3 normal projections and one isometric.\n# Author: Milos Petrasinovic <mpetrasinovic@pr-dc.com>\n# PR-DC, Republic of Serbia\n# info@pr-dc.com\n# \n# --------------------\n#\n# Copyright (C) 2022 PRDC <info@pr-dc.com>\n# \n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU Lesser General Public License as \n# published by the Free Software Foundation, either version 3 of the \n# License, or (at your option) any later version.\n#  \n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU Lesser General Public License for more details.\n#  \n# You should have received a copy of the GNU Lesser General Public License\n# along with this program.  If not, see <https://www.gnu.org/licenses/>.\n#\n# ----- PARAMS -----\npaper = [420, 297] # A3 paper size\nborder = [10, 10, 400, 277] # border position ans size\ntable = [190, 74] # table size\ndx = 10 # space between views along x axis\ndy = 10 # space between views along y axis\nauthor = \"Milo\u0161 Petra\u0161inovi\u0107\" # author name\ndrawn_date = \"07.01.2022.\" # drawing drawn date\ntemplate_file = \"test\\\\PRDC_template_A3.svg\" # drawing template\n# --------------------\n\n__Name__ = 'GenerateDrawing'\n__Comment__ = 'Macro for automatic drawing generation.'\n__Author__ = 'Milos Petrasinovic <mpetrasinovic@pr-dc.com>'\n__Version__ = '1.0.0'\n__Date__ = '2022-01-07'\n__License__ = 'GPL-3.0-or-later'\n__Web__ = 'https://github.com/PR-DC/PRDC_GenerateDrawing_FC'\n__Wiki__ = 'https://wiki.freecadweb.org/Macro_GenerateDrawing'\n__Icon__ = 'https://wiki.freecad.org/images/7/74/GenerateDrawing.svg'\n__Help__ = 'Open model and run the macro program!'\n__Status__ = 'stable'\n__Requires__ = 'Freecad >= 0.18'\n__Communication__ = 'https://github.com/PR-DC/PRDC_GenerateDrawing_FC/issues/'\n__Files__ = 'GenerateDrawing.svg'\n\nimport FreeCAD as App\nimport FreeCADGui as Gui\nfrom PySide import QtGui\nimport Draft\nimport math\nimport os\n\nif not os.path.isabs(template_file):\n    template_file = os.path.dirname(__file__) + '\\\\' + template_file\nprint(template_file)\n\ndoc = App.activeDocument()\ndoc_gui = Gui.activeDocument()\nGui.activateWorkbench(\"TechDrawWorkbench\")\nshapes = []\n\ndef GetShapes(objs, shapes):\n    for obj in objs:\n        if obj.TypeId == 'App::DocumentObjectGroup':\n            GetShapes(obj.OutList, shapes)\n        elif hasattr(obj, \"Shape\") and doc_gui.getObject(obj.Name).Visibility:\n            shapes.append(obj)\n    return shapes\n    \nif doc is not None:\n    shapes = GetShapes(doc.RootObjects, shapes)\n    if len(shapes):\n        if len(shapes) == 1:\n            model = shapes[0]\n        else:\n            model = doc.addObject(\"Part::Compound\", \"DrawingModel\")\n            model.Links = shapes\n            doc.recompute()\n        \n        # Obtain model bounding box\n        BB = model.Shape.BoundBox\n        X = BB.XMax-BB.XMin\n        Y = BB.YMax-BB.YMin\n        Z = BB.ZMax-BB.ZMin\n        \n        Isometric = Draft.makeShape2DView(model, App.Vector(0.57735, 0.57735, 0.57735))\n        doc.recompute()\n        IBB = Isometric.Shape.BoundBox\n        if App.Version()[1] < \"19\":\n            Xrot = IBB.XMin+(IBB.XMax-IBB.XMin)/2\n            Yrot = IBB.YMin+(IBB.YMax-IBB.YMin)/2\n            Draft.rotate(Isometric, -120, center=App.Vector(Xrot, Yrot, 0), axis=App.Vector(0, 0, 1), copy=False)\n            doc.recompute()\n            IBB = Isometric.Shape.BoundBox\n        IsometricBB = [IBB.XMax-IBB.XMin, IBB.YMax-IBB.YMin]\n        \n        doc.removeObject(Isometric.Name)\n        if len(shapes) > 1:\n            doc.removeObject(model.Name)\n            for obj in shapes:\n                doc_gui.getObject(obj.Name).Visibility = True\n                \n        # Page scale\n        p1 = border[2]/(X+dx+Z)\n        p2 = border[3]/(Y+dy+Z)\n        \n        if p1 < 1 or p2 < 1:\n            # Decrease\n            if p1 > p2:\n                s = math.ceil(1/p2)\n            else:\n                s = math.ceil(1/p1)\n            s = 1/s\n            scale_str = \"1:\"+str(s)\n        else:\n            # Increase\n            if p1 > p2:\n                s = math.floor(p2)\n            else:\n                s = math.floor(p1)\n            scale_str = str(s)+\":1\"\n        \n        # Add page with template\n        page = doc.addObject('TechDraw::DrawPage', 'Page')\n        template = doc.addObject('TechDraw::DrawSVGTemplate', 'Template')\n        template.Template = template_file\n        page.Template = template\n        page.Scale = s\n        \n        # Add project group views\n        views = doc.addObject('TechDraw::DrawProjGroup', 'ProjGroup')\n        views.AutoDistribute = False\n        page.addView(views)\n        views.Source = shapes\n        doc.recompute()\n        Top = views.addProjection('Front')\n        Top.Label = \"Top\"\n        views.Anchor.Direction = App.Vector(0, 0, 1)\n        if App.Version()[1] >= \"19\":\n            views.Anchor.XDirection = App.Vector(1, 0, 0)\n        views.Anchor.RotationVector = App.Vector(1, 0, 0)\n        views.Anchor.recompute()\n        views.ProjectionType = 'First Angle'\n        Front = views.addProjection('Top')\n        Front.Label = \"Front\"\n        Left = views.addProjection('Left')\n        Left.Label = \"Left\"\n        \n        # Isometric view\n        Isometric = doc.addObject('TechDraw::DrawViewPart', 'Isometric')\n        page.addView(Isometric)\n        Isometric.Source = shapes\n        Isometric.ScaleType = \"Custom\"\n        Isometric.Scale = s/2\n        Isometric.Label = \"Isometric\"\n        Isometric.Direction = App.Vector(0.57735, 0.57735, 0.57735)\n        if App.Version()[1] >= \"19\":\n            Isometric.XDirection = App.Vector(0.57735, 0.57735, 0.57735)\n        else: \n            Isometric.Rotation = -120.00\n        Isometric.recompute()\n           \n        # Views position\n        px0 = border[0]+dx\n        py0 = paper[1]-dy-border[1]\n        \n        views.X = px0+s*X/2\n        views.Y = py0-s*Y/2\n        Front.Y = -(s*Y/2+dy+s*Z/2)\n        Left.X = s*X/2+dx+s*Z/2\n        Isometric.X = paper[0]-border[0]-dx-s/2*IsometricBB[0]/2\n        Isometric.Y = border[1]+table[1]+dy+s/2*IsometricBB[1]/2\n        \n        # Change drawing text fields\n        template.setEditFieldContent(\"AUTHOR_NAME\", author)\n        template.setEditFieldContent(\"AUTHOR_DATE\", drawn_date)\n        template.setEditFieldContent(\"DRAWING_SCALE\", scale_str)\n        template.setEditFieldContent(\"PROJECT_NAME\", \"PROJECT NAME\")\n        template.setEditFieldContent(\"DRAWING_TITLE\", \"DRAWING TITLE\")\n        template.setEditFieldContent(\"PCS_NUMBER\", \"X pcs\")\n        template.setEditFieldContent(\"MATERIAL_NAME\", \"x\")\n        template.setEditFieldContent(\"FINISH_TYPE\", \"As Produced\")\n        template.setEditFieldContent(\"TOLERANCE_VALUE\", \"xxx\")\n        template.setEditFieldContent(\"SUPERVISOR_NAME\", \"Supervisor\")\n        template.setEditFieldContent(\"SUPERVISOR_DATE\", \"xxx\")\n        template.setEditFieldContent(\"DESIGNER_NAME\", \"Designer\")\n        template.setEditFieldContent(\"DESIGNER_DATE\", \"xxx\")\n        template.setEditFieldContent(\"PAGE_SIZE\", \"A3\")\n        template.setEditFieldContent(\"REV_NUMBER\", \"X\")\n        template.setEditFieldContent(\"PART_WEIGHT\", \"XXX\")\n        template.setEditFieldContent(\"SHEET_NUMBER\", \"1/1\")\n        \n        doc.recompute()        \n        doc_gui.getObject(page.Name).show()\n        Gui.updateGui()\n    else:\n        msgBox = QtGui.QMessageBox()\n        msgBox.setWindowTitle(\"Error\")\n        msgBox.setText(\"No shapes for drawing!\")\n        msgBox.exec_()\n        App.Console.PrintError(\"\\nError: No shapes for drawing!\\n\")\nelse:\n    msgBox = QtGui.QMessageBox()\n    msgBox.setWindowTitle(\"Error\")\n    msgBox.setText(\"No active document!\")\n    msgBox.exec_()\n    App.Console.PrintError(\"\\nError: No active document!\\n\")",
    "url": "https://github.com/PR-DC/PRDC_GenerateDrawing_FC",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_GenerateDrawing",
    "version": "1.0.0",
    "license": "",
    "date": "2022-01-07",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Milos Petrasinovic <mpetrasinovic@pr-dc.com>",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\GenerateDrawing.svg",
    "icon_source": "https://wiki.freecad.org/images/7/74/GenerateDrawing.svg",
    "xpm": "",
    "other_files": [
      "GenerateDrawing.svg"
    ],
    "parsed": true
  },
  {
    "name": "GenerateViews",
    "on_wiki": true,
    "on_git": false,
    "desc": "Macro for automatic 2D views generation with 6 normal projections and one isometric.<br /><br />Macro version: 1.0.0<br />Last modified: 2022-01-08<br />FreeCAD version: 0.18.4 and above<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/2/21/GenerateViews.svg\">ToolBar Icon</a><br />Author: PR-DC<br /> ",
    "comment": "Macro for automatic 2D views generation.",
    "code": "# Macro for automatic 2D views generation\n# with 6 normal projections and one isometric\n# Author: Milos Petrasinovic <mpetrasinovic@prdc.rs>\n# PR-DC, Republic of Serbia\n# info@pr-dc.com\n# \n# --------------------\n#\n# Copyright (C) 2022 PRDC <info@pr-dc.com>\n# \n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU Lesser General Public License as \n# published by the Free Software Foundation, either version 3 of the \n# License, or (at your option) any later version.\n#  \n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU Lesser General Public License for more details.\n#  \n# You should have received a copy of the GNU Lesser General Public License\n# along with this program.  If not, see <https://www.gnu.org/licenses/>.\n#\n# ----- PARAMS -----\ndx = 10 # space between views along x axis\ndy = 10 # space between views along y axis\n# --------------------\n\n__Name__ = 'GenerateViews'\n__Comment__ = 'Macro for automatic 2D views generation.'\n__Author__ = 'Milos Petrasinovic <mpetrasinovic@pr-dc.com>'\n__Version__ = '1.0.0'\n__Date__ = '2022-01-07'\n__License__ = 'GPL-3.0-or-later'\n__Web__ = 'https://github.com/PR-DC/PRDC_GenerateViews_FC'\n__Wiki__ = 'https://wiki.freecadweb.org/Macro_GenerateViews'\n__Icon__ = 'https://wiki.freecad.org/images/2/21/GenerateViews.svg'\n__Help__ = 'Open model and run the macro program!'\n__Status__ = 'stable'\n__Requires__ = 'Freecad >= 0.18'\n__Communication__ = 'https://github.com/PR-DC/PRDC_GenerateViews_FC/issues/'\n__Files__ = 'GenerateViews.svg'\n\nimport FreeCAD as App\nimport FreeCADGui as Gui\nfrom PySide import QtGui\nimport Draft\n\ndoc = App.activeDocument()\ndoc_gui = Gui.activeDocument()\nshapes = []\n\ndef GetShapes(objs, shapes):\n    for obj in objs:\n        if obj.TypeId == 'App::DocumentObjectGroup':\n            GetShapes(obj.OutList, shapes)\n        elif hasattr(obj, \"Shape\") and doc_gui.getObject(obj.Name).Visibility:\n            shapes.append(obj)\n    return shapes\n\ndef InitPosition(obj):\n    doc.recompute()\n    BB = obj.Shape.BoundBox\n    Draft.move(obj, App.Vector(-BB.XMin, -BB.YMin, 0.0), copy=False)\n    return [BB.XMax-BB.XMin, BB.YMax-BB.YMin]\n    \nif doc is not None:\n    shapes = GetShapes(doc.RootObjects, shapes)\n    if len(shapes):\n        if len(shapes) == 1:\n            model = shapes[0]\n        else:\n            model = doc.addObject(\"Part::Compound\", \"DrawingModel\")\n            model.Links = shapes\n            doc.recompute()\n        \n        # Generate views\n        Top = Draft.makeShape2DView(model, App.Vector(0, 0, 1))\n        Top.Label = \"TopView\"\n        TopBB = InitPosition(Top)\n        Bottom = Draft.makeShape2DView(model, App.Vector(0, 0, -1))\n        Bottom.Label = \"BottomView\"\n        BottomBB = InitPosition(Bottom)\n        Front = Draft.makeShape2DView(model, App.Vector(0, -1, 0))\n        Front.Label = \"FrontView\"\n        Draft.rotate(Front, -90, center=App.Vector(0, 0, 0), axis=App.Vector(0, 0, 1), copy=False)\n        FrontBB = InitPosition(Front)\n        Rear = Draft.makeShape2DView(model, App.Vector(0, 1, 0))\n        Rear.Label = \"RearView\"\n        Draft.rotate(Rear, -90, center=App.Vector(0, 0, 0), axis=App.Vector(0, 0, 1), copy=False)\n        RearBB = InitPosition(Rear)\n        Right = Draft.makeShape2DView(model, App.Vector(1, 0, 0))\n        Right.Label = \"RightView\"\n        Draft.rotate(Right, 180, center=App.Vector(0, 0, 0), axis=App.Vector(0, 0, 1), copy=False)\n        RightBB = InitPosition(Right)\n        Left = Draft.makeShape2DView(model, App.Vector(-1, 0, 0))\n        Left.Label = \"LeftView\"\n        Draft.rotate(Left, 180, center=App.Vector(0, 0, 0), axis=App.Vector(0, 0, 1), copy=False)\n        LeftBB = InitPosition(Left)\n        Isometric = Draft.makeShape2DView(model, App.Vector(0.57735, 0.57735, 0.57735))\n        Isometric.Label = \"IsometricView\"\n        IsometricBB = InitPosition(Isometric)\n        doc.recompute()\n        \n        # Views position \n        RearPos = [RightBB[0]+2*dx, dy]\n        Draft.move(Rear, App.Vector(RearPos[0], RearPos[1], 0.0), copy=False)\n        RightPos = [dx, RearBB[1]+2*dy]\n        Draft.move(Right, App.Vector(RightPos[0], RightPos[1], 0.0), copy=False)\n        TopPos = [RearPos[0], RightPos[1]]\n        Draft.move(Top, App.Vector(TopPos[0], TopPos[1], 0.0), copy=False)\n        FrontPos = [RearPos[0], TopPos[1]+TopBB[1]+dy]\n        Draft.move(Front, App.Vector(FrontPos[0], FrontPos[1], 0.0), copy=False)\n        LeftPos = [TopPos[0]+TopBB[0]+dx, TopPos[1]]\n        Draft.move(Left, App.Vector(LeftPos[0], LeftPos[1], 0.0), copy=False)\n        BottomPos = [LeftPos[0]+LeftBB[0]+dx, TopPos[1]]\n        Draft.move(Bottom, App.Vector(BottomPos[0], BottomPos[1], 0.0), copy=False)\n        IsometricPos = [LeftPos[0], FrontPos[1]]\n        Draft.move(Isometric, App.Vector(IsometricPos[0], IsometricPos[1], 0.0), copy=False)\n        doc.recompute()\n        \n        if len(shapes) > 1:\n            doc.removeObject(model.Name)\n            for obj in shapes:\n                doc_gui.getObject(obj.Name).Visibility = True\n                \n        # Add views to group\n        ViewsGroup = doc.addObject('App::DocumentObjectGroup', 'ViewsGroup')\n        ViewsGroup.addObjects([Top, Bottom, Front, Rear, Right, Left, Isometric])\n        \n        Gui.updateGui()\n    else:\n        msgBox = QtGui.QMessageBox()\n        msgBox.setWindowTitle(\"Error\")\n        msgBox.setText(\"No shapes for drawing!\")\n        msgBox.exec_()\n        App.Console.PrintError(\"\\nError: No shapes for drawing!\\n\")\nelse:\n    msgBox = QtGui.QMessageBox()\n    msgBox.setWindowTitle(\"Error\")\n    msgBox.setText(\"No active document!\")\n    msgBox.exec_()\n    App.Console.PrintError(\"\\nError: No active document!\\n\")",
    "url": "https://github.com/PR-DC/PRDC_GenerateViews_FC",
    "raw_code_url": "",
    "wiki": "https://wiki.freecadweb.org/Macro_GenerateViews",
    "version": "1.0.0",
    "license": "",
    "date": "2022-01-07",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Milos Petrasinovic <mpetrasinovic@pr-dc.com>",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\GenerateViews.svg",
    "icon_source": "https://wiki.freecad.org/images/2/21/GenerateViews.svg",
    "xpm": "",
    "other_files": [
      "GenerateViews.svg"
    ],
    "parsed": true
  },
  {
    "name": "Geneva Wheel",
    "on_wiki": true,
    "on_git": false,
    "desc": "Allows the user to create a Geneva wheel mechanism from scratch. Must edit values within the Macro to alter the size of the object.<br /><br />Macro version: 1.0<br />Last modified: 2014-09-21<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/8/8d/GW_Dim.png\">ToolBar Icon</a><br />Author: Drei<br /> ",
    "comment": "Allows the user to create a Geneva wheel mechanism from scratch. Must edit values within the Macro to alter the size of the object.",
    "code": "#Creation of a Geneva Wheel with Parametric values  By: Isaac Ayala (drei)\n#This Macro creates the main parts of a Geneva Wheel Mechanism \n\n#It depends on six values that must be altered in the following code\n#The variables are a, b, n, p, t and h. \n\n#Definition for each variable\n#    Input\n#a = Drive Crank Radius\n#b = Geneva Wheel Radius\n#n = Driven Slot Quantity\n#p = Drive Pin Diameter\n#t = Tolerance\n#h = Height\n#    Output\n#c = Distance Between Centers\n#s = Slot Center Width\n#w = Slot Width\n#y = Stop Arc Radius\n#z = Stop Disc Radius\n#v = Clearance Arc\n\n#Please note that you can alter the code so it depends on five values exclusively\n#Just replace c, and either a or b with the following\n#    Keep value for a\n#c = a/math.sin(math.pi/n)\n#b = math.sqrt((math.pow(c,2))-(math.pow(a,2)))\n#    Keep value for b\n#c = b/math.cos(math.pi/n)\n#a = math.sqrt((math.pow(c,2))-(math.pow(b,2)))\n\nfrom __future__ import division\nimport time\nimport math\nfrom PySide import QtCore, QtGui\nfrom FreeCAD import Base\nimport Part\n\n#Inputs\na = 25.0\nb = 60.0\nn = 6\np = 4\nt = 0.01\nh = 5\nT = 60\n\n#Outputs\nc = math.sqrt(pow(a,2) + pow(b,2))\ns = a + b - c\nw = p + t\ny = a - (1.5 * p)\nz = y - t\nv = (b * z)/a \n\n#    Create the Drive Crank (Will be placed on the origin)\ndriveCrank = Part.makeCylinder(z, h)\ndriveCrank.translate(Base.Vector(0,0,0))\n\ngenevaWheelClearanceCut = Part.makeCylinder(b, h)\ngenevaWheelClearanceCut.translate(Base.Vector(-c,0,0))\n\ndriveCrank = driveCrank.cut(genevaWheelClearanceCut)\n\ndriveCrankBase = Part.makeCylinder((1.5*a), h)\ndriveCrankBase.translate(Base.Vector(0,0,-h))\n\ndriveCrank = driveCrank.fuse(driveCrankBase)\n\ndrivePin = Part.makeCylinder(p,h)\ndrivePin.translate(Base.Vector(-a,0,0))\n\ndriveCrank = driveCrank.fuse(drivePin)\n\n#    Create the Geneva  Wheel (Will be placed on the x-axis on the left side)\ngenevaWheel = Part.makeCylinder(b,h)\ngenevaWheel.translate(Base.Vector(-c,0,0))\n\nstopArc = Part.makeCylinder(y, h)\nstopArc.translate(Base.Vector(((y-(b/2)),0,0)))\nstopArc.rotate(Base.Vector(-c,0,0),Base.Vector(0,0,1),30)\n\nfor i in range(6):\n    stopArc.rotate(Base.Vector(-c,0,0),Base.Vector(0,0,1),60)\n    genevaWheel = genevaWheel.cut(stopArc)\n\nslotLength = Part.makeBox(s,(2*w),h)\nslotLength.translate(Base.Vector(-a,-w,0))\n\nslotRadius = Part.makeCylinder(w,h)\nslotRadius.translate(Base.Vector(-a,0,0))\n\nslot=slotLength.fuse(slotRadius)\n\nfor i in range(6):\n    slot.rotate(Base.Vector(-c,0,0),Base.Vector(0,0,1),60)\n    genevaWheel = genevaWheel.cut(slot)\n\n#    Display Result\n\nPart.show(driveCrank)\nPart.show(genevaWheel)",
    "url": "https://wiki.freecad.org/Macro_Geneva_Wheel",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-09-21",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Drei",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\GW_Dim.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/8/8d/GW_Dim.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Geneva Wheel GUI",
    "on_wiki": true,
    "on_git": false,
    "desc": "A GUI front end that allows the user to create a Geneva wheel mechanism from scratch. Based on drei's <a href=\"/Macro_Geneva_Wheel\" title=\"Macro Geneva Wheel\">Macro Geneva Wheel</a><br /><br />Macro version: 1.0<br />Last modified: 2014-09-21<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/8/8d/GW_Dim.png\">ToolBar Icon</a><br />Author: quick61<br /> ",
    "comment": "A GUI front end that allows the user to create a Geneva wheel mechanism from scratch. Based on drei's Macro Geneva Wheel",
    "code": "#Creation of a Geneva Wheel with Parametric values  By: Isaac Ayala (drei) & Mark Stephen (quick61)\n#This Macro creates the main parts of a Geneva Wheel Mechanism \n\n#It depends on six values that must be altered in the following code\n#The variables are a, b, n, p, t and h.\n\n#Definition for each variable\n#    Input\n#a = Drive Crank Radius\n#b = Geneva Wheel Radius\n#p = Drive Pin Radius\n#t = Geneva Wheel Tolerance\n#h = Geneva Wheel Height \n#n = Driven Slot Quantity\n#    Output\n#c = Distance Between Centers\n#s = Slot Center Width\n#w = Slot Width\n#y = Stop Arc Radius\n#z = Stop Disc Radius\n#v = Clearance Arc\n\n#Please note that you can alter the code so it depends on five values exclusively\n#Just replace c, and either a or b with the following\n#    Keep value for a\n#c = a/math.sin(math.pi/n)\n#b = math.sqrt((math.pow(c,2))-(math.pow(a,2)))\n#    Keep value for b\n#c = b/math.cos(math.pi/n)\n#a = math.sqrt((math.pow(c,2))-(math.pow(b,2)))\n\nfrom __future__ import division\nimport math\nfrom FreeCAD import Base\nfrom PySide import QtGui, QtCore\nfrom PySide.QtGui import QApplication, QDialog, QMainWindow\nimport Part\nimport Draft\nclass p():\n\n\n   def Ggear(self):\n\n      try:\n         #Inputs\n         a = float(self.dCr.text())\n         #b = float(self.gWr.text())\n         p = float(self.dPd.text())\n         t = float(self.gWt.text())\n         h = float(self.gWh.text())\n         n = float(self.gWn.text())\n\n         #Outputs\n         #c = math.sqrt(pow(a,2) + pow(b,2))\n         c = a/math.sin(math.pi/n)\n         b = math.sqrt((math.pow(c,2))-(math.pow(a,2)))\n         s = a + b - c\n         w = p + t\n         y = a - (3 * p)\n         z = y - t\n         v = (b * z)/a\n         m = math.sqrt((v**2)+(z**2)) # Solves for location of clearance cut axis\n\n         #    Create the Drive Crank (Will be placed on the origin)\n         driveCrank = Part.makeCylinder(z, h)\n         #driveCrank.translate(Base.Vector(0,0,0))\n\n         #genevaWheelClearanceCut = Part.makeCylinder(b, h)\n         #genevaWheelClearanceCut.translate(Base.Vector(-c,0,0))\n\n         genevaWheelClearanceCut = Part.makeCylinder(v, h)\n         genevaWheelClearanceCut.translate(Base.Vector(-m,0,0))\n\n         driveCrank = driveCrank.cut(genevaWheelClearanceCut)\n\n         driveCrankBase = Part.makeCylinder((a+(2*p)), h)\n         driveCrankBase.translate(Base.Vector(0,0,-h))\n\n         driveCrank = driveCrank.fuse(driveCrankBase)\n\n         drivePin = Part.makeCylinder(p,h)\n         drivePin.translate(Base.Vector(-a,0,0))\n\n         driveCrank = driveCrank.fuse(drivePin)\n\n         #    Create the Geneva  Wheel (Will be placed on the x-axis on the left side)\n         genevaWheel = Part.makeCylinder(b,h)\n         genevaWheel.translate(Base.Vector(-c,0,0))\n\n         stopArc = Part.makeCylinder(y, h)\n         stopArc.rotate(Base.Vector(-c,0,0),Base.Vector(0,0,1),(180/n))\n\n         for i in range(int(n)):\n            stopArc.rotate(Base.Vector(-c,0,0),Base.Vector(0,0,1),(360/n))\n            genevaWheel = genevaWheel.cut(stopArc)\n\n         slotLength = Part.makeBox(s,(2*w),h)\n         slotLength.translate(Base.Vector(-a,-w,0))\n\n         slotRadius = Part.makeCylinder(w,h)\n         slotRadius.translate(Base.Vector(-a,0,0))\n\n         slot=slotLength.fuse(slotRadius)\n\n         for i in range(int(n)):\n            slot.rotate(Base.Vector(-c,0,0),Base.Vector(0,0,1),(360/n))\n            genevaWheel = genevaWheel.cut(slot)\n\n         #    Display Result\n\n         Part.show(driveCrank)\n         Part.show(genevaWheel)\n\n      except:\n         FreeCAD.Console.PrintError(\"Unable to complete task. Please recheck your data entries.\")\n\n      self.close()\n\n   def close(self):\n      self.dialog.hide()\n\n   def __init__(self):\n      self.dialog = None\n\n      self.dialog = QtGui.QDialog()\n      self.dialog.resize(240,100)\n\n      self.dialog.setWindowTitle(\"Geneva Wheel Macro\")\n      la = QtGui.QVBoxLayout(self.dialog)\n\n      DCR = QtGui.QLabel(\"Drive Crank Radius ( A )\")\n      la.addWidget(DCR)\n      self.dCr = QtGui.QLineEdit()\n      la.addWidget(self.dCr)\n\n      #GWR = QtGui.QLabel(\"Geneva Wheel Radius ( B )\")\n      #la.addWidget(GWR)\n      #self.gWr = QtGui.QLineEdit()\n      #la.addWidget(self.gWr)\n\n      DPD = QtGui.QLabel(\"Drive Pin Radius ( C )\")\n      la.addWidget(DPD)\n      self.dPd = QtGui.QLineEdit()\n      la.addWidget(self.dPd)\n\n      GWT = QtGui.QLabel(\"Geneva Wheel Tolerance ( D )\")\n      la.addWidget(GWT)\n      self.gWt = QtGui.QLineEdit()\n      la.addWidget(self.gWt)\n\n      GWH = QtGui.QLabel(\"Geneva Wheel Height\")\n      la.addWidget(GWH)\n      self.gWh = QtGui.QLineEdit()\n      la.addWidget(self.gWh)\n\n      GWN = QtGui.QLabel(\"Driven Slot Quantity\")\n      la.addWidget(GWN)\n      self.gWn = QtGui.QLineEdit()\n      la.addWidget(self.gWn)\n\n      #\n      # - Include graphic image in dialog window - \n      #\n      # Insure that image is in the same directory as this Macro.\n      # Image should be available from same source as Macro.\n      #\n  \n      import os\n      macro_dir = os.path.dirname(__file__)\n      self.PiX = QtGui.QLabel()\n      self.PiX.setPixmap(os.path.join(macro_dir, \"GW_Dim.png\"))\n\n      hbox = QtGui.QHBoxLayout()\n      hbox.addStretch()\n      hbox.addWidget(self.PiX)\n      hbox.addStretch()\n      \n      la.addSpacing(15)\n      la.addLayout(hbox)\n      la.addSpacing(15)\n\n      # - End Image layout -\n\n      okbox = QtGui.QDialogButtonBox(self.dialog)\n      okbox.setOrientation(QtCore.Qt.Horizontal)\n      okbox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)\n      la.addWidget(okbox)\n      QtCore.QObject.connect(okbox, QtCore.SIGNAL(\"accepted()\"), self.Ggear)\n      QtCore.QObject.connect(okbox, QtCore.SIGNAL(\"rejected()\"), self.close)\n      QtCore.QMetaObject.connectSlotsByName(self.dialog)\n      self.dialog.show()\n      self.dialog.exec_()\n\np()\n",
    "url": "https://wiki.freecad.org/Macro_Geneva_Wheel_GUI",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2014-09-21",
    "src_filename": "",
    "filename_from_url": "",
    "author": "quick61",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\GW_Dim.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/8/8d/GW_Dim.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Megaminx",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro creates a virtual <a rel=\"nofollow\" class=\"external text\" href=\"https://en.wikipedia.org/wiki/Megaminx\">Megaminx</a>.<br /><br />Last modified: 2019-02-17<br />FreeCAD version: 0.18 and higher<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/4/43/Macro_Megaminx.png\">ToolBar Icon</a><br />Author: aleph0<br /> ",
    "comment": "Virtual Megaminx",
    "code": "# -*- coding: utf-8 -*-\n# Copyright \u00a9 2019 Richard P. Parkins, M. A.\n# Released under the GPL\n\"\"\"\n***************************************************************************\n*                                                                         *\n*   This macro creates a FreeCAD document containing a virtual Megaminx   *\n*   (see https://en.wikipedia.org/wiki/Megaminx) and enables you to       *\n*   manipulate it. It displays six views of the Megaminx including each   *\n*   of the twelve faces at least once. There are various arrows (each     *\n*   with a tooltip which will be displayed as long as you hover the       *\n*   mouse over it). By clicking on arrows you can rotate faces of the     *\n*   Megaminx, rotate the whole Megaminx, or rotate or reflect the history *\n*   which it maintains of the rotations that you have done so far. There  *\n*   is also a Megaminx menu which is shown at the right of the menu bar   *\n*   as long as you have at least one Megaminx document open. From the     *\n*   menu you can display some help text, reset the Megaminx to its        *\n*   initial (solved) state, undo the last rotation (and remove it from    *\n*   the history), copy the history to the clipboard, step through the     *\n*   history, randomise the Megaminx, and enable or disable the echoing of *\n*   rotations to the Report View. All of these functions can also be      *\n*   invoked by typing suitable commands into the Python console window.   *\n*                                                                         *\n*   A history saved to the clipboard can be pasted into the Python        *\n*   console window or copied into a file which can be called as a macro   *\n*   into the active Megaminx document. You can have more than one         *\n*   Megaminx document open at a time, although only one can be active.    *\n*                                                                         *\n***************************************************************************\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU General Public License (GPL) as         *\n*   as published by the Free Software Foundation; either version 3 of     *\n*   the License, or (at your option) any later version. For details or to *\n*   obtain a copy see http://www.gnu.org/licenses/gpl.html or write to    *                                     *   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,      *\n*   Boston, MA  02110-1335 USA                                            *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU General Public License for more details.                          *\n*                                                                         *\n***************************************************************************\n\"\"\"\n__title__   = \"Megaminx\"\n__author__  = \"Aleph0\"\n__version__ = \"00.06\"\n__date__    = \"17/02/2019\"\n__Comment__ = \"Virtual Megaminx\"\n__Wiki__ = \"http://www.freecadweb.org/wiki/index.php?title=Macro_Megaminx\"\n__Help__ = \"see first few lines of macro text\"\n__Status__ = \"stable\"\n__Requires__ = \"freecad 0.17\"\n\n#OS: \"openSUSE Leap 15.0\"\n#Word size of OS: 64-bit\n#Word size of FreeCAD: 64-bit\n#Version: 0.17.Unknown\n#Build type: Release\n#Python version: 3.6.5\n#Qt version: 5.9.4\n#Coin version: 3.1.3\n#OCC version: 7.2.0\n#Locale: English/UnitedKingdom (en_GB)\n\n# To show a function's documentation string, type\n## print(function.__doc__)\n# at the FreeCAD Python console.\n\nimport FreeCAD\nfrom FreeCAD import Base\nimport Part\nimport Draft\nimport DraftVecUtils as DVU\nfrom pivy import coin\nfrom pivy.coin import *\nfrom PySide import *\nimport math\nimport ctypes\nimport random\n\n# All this work takes a while, so show the wait cursor.\nQtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))\n\n# Create a new document and make it current.\nApp.ActiveDocument = App.newDocument(\"Megaminx\")\nGui.ActiveDocument = Gui.getDocument(App.ActiveDocument.Name)\n\n# We use a dictionary to avoid having global variables which would\n# cause interference between multiple instantiations of the Megaminx\n# if you run this macro more than once.\n# It would be easier to have a dictionary for each document, but I have not\n# found a way to attach a dictionary to a document, so each dictionary key\n# is tagged with its document name.\n# Dictionary objects can be *anything* including other dictionaries or\n# class instances containing lots of fields.\ndef _set(name, object):\n    \"\"\" This internal function sets a value for this document.\n\"\"\"\n    d = FreeCAD.Megaminx_Dictionary\n    d[App.ActiveDocument.Name + \"$\" + name] = object\ndef _get(name):\n    \"\"\" This internal function gets a value for this document.\\\n\"\"\"\n    d = FreeCAD.Megaminx_Dictionary\n    return d[App.ActiveDocument.Name + \"$\" + name]\nclass deletionCleaner(object):\n    \"\"\" This class handle tidying up after a document is deleted.\\\n\"\"\"\n    def __init__(self):\n        pass\n    def slotDeletedDocument(self, doc):\n        \"\"\" This function is called when a document gets deleted.\nIt goes through the dictionary removing all the entries belonging to\nthe deleted document. If there are no Megaminx documents left\n(the dictionary in empty), it removes the Megaminx menu,\\\n\"\"\"\n        d = FreeCAD.Megaminx_Dictionary\n        s = str(doc.Label) + \"$\"\n        n = len(s)\n        deletions = []\n        action = None\n        for key in d:\n            if key[0:n] == s:\n                deletions.append(key)\n                if key[n:] == \"menu\":\n                    action = d[key].menuAction()\n        for key in deletions:\n            del d[key]\n        if len(d) == 0 and action != None:\n            # last document gone, remove menu\n            Gui.getMainWindow().menuBar().removeAction(action)\n\n# If this is the first time this macro has been run in this invocation of\n# FreeCAD, create our dictionary of document-specific data and add\n# an observer to the app that cleans up after a document is deleted.\nif not hasattr(FreeCAD, \"Megaminx_Dictionary\"):\n    FreeCAD.Megaminx_Dictionary = {}\n    App.addDocumentObserver(deletionCleaner())\n\n# This parameter is the step count for animating rotations.\n# If you have a fast computer you can increase the value.\n# This will make the animation slower and smoother.\n# If you have a slow computer you can decrease the value.\n# This will make the animation faster but more jerky.\n# Zero gives instantaneous rotations with no animation.\n_set(\"slowness\", 20)\n\n# This parameter is the step count for animating history modifications.\n# It is like slowness, but for history modifications.\n# The default is zero which gives instantaneous history modifications with\n# no animation. If you want to animate history playback, set a nonzero value.\n_set(\"historyslowness\", 0)\n\n# This parameter controls the scaling of the text and buttons\n# texture-mapped onto some facets. It should be your screen's\n# dots per inch count.\n_set(\"dpi\", 130)\n\n# This parameter controls echoing of rotations to the console.\n# True enables echoing, False disables it.\n# Output may go to the Python console or the Report view depending on your\n# FreeCAD version and setup and where the command came from.\n_set(\"echo\", False)\ndef set_echo(newstate):\n    \"\"\" This function sets the state of echo from its argument.\\\n\"\"\"\n    _set(\"echo\", newstate)\n    d = FreeCAD.Megaminx_Dictionary\n    for key in d:\n        if key.endswith(\"menu\"):\n            menu = d[key]\n            for action in menu.actions():\n                if action.iconText() == \"Echo\":\n                    action.setChecked(newstate)\n                    break\ndef _set_echo():\n    \"\"\" This internal function sets the state of echo from the menu item.\\\n\"\"\"\n    d = FreeCAD.Megaminx_Dictionary\n    for key in d:\n        if key.endswith(\"menu\"):\n            menu = d[key]\n            for action in menu.actions():\n                if action.iconText() == \"Echo\":\n                    _set(\"echo\", action.isChecked())\n                    break\n\ndef compressImage(s):\n    \"\"\" Compress an image\n    This is an internal function used to build the Megaminx macro.\n    Its argument should be a string returned by image.get().getString()\n    and it returns a compressed version which can be assigned to an image.\n    \"\"\"\n    s = s.replace(\"0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff\", \"' + ffs + '\")\n    s = s.replace(\"ffs + '\\n' + ffs + '\\n' + ffs + '\\n' + ffs\", \"ffs4\")\n    s = s.replace(\"ffs4 + '\\n' + ffs4 + '\\n' + ffs4 + '\\n' + ffs4\", \"ffs16\")\n    s = s.replace(\n        \"ffs16 + '\\n' + ffs16 + '\\n' + ffs16 + '\\n' + ffs16\", \"ffs64\")\n    s = s.replace (\"\\n\", \" \\\\\\n\")\n    s = \"'\" + s + \"'\"\n    t = \"\"\n    s.replace(\" + ' '\", t)\n    return s\n\n# Distance factor for extra views\n_set(\"dd\", 6.2)\n# Scale factor for extra views\n_set(\"sf\", 0.8)\n\n# Some geometry constants\nphi = 1.6180339887\npiz4 = 3.1415926535 * 0.4\nc0 = 1.0\ns0 = 0.0\nc1 = math.cos(piz4)\ns1 = math.sin(piz4)\nc2 = math.cos(piz4 * 2)\ns2 = math.sin(piz4 * 2)\nc3 = math.cos(piz4 * 3)\ns3 = math.sin(piz4 * 3)\nc4 = math.cos(piz4 * 4)\ns4 = math.sin(piz4 * 4)\norigin = Base.Vector(0.0, 0.0, 0.0)\n\nclass helpWindow(QtGui.QDialog):\n    \"\"\" This class is a dialog box contatining help text.\n    \"\"\"\n    def __init__(self, parent):\n        super(helpWindow, self).__init__()\n        self.setParent(parent)\n        self.setGeometry(parent.geometry())\n        self.helptext = QtGui.QTextEdit(self)\n        self.helptext.setText(\n\"\"\"This macro displays six views of a Megaminx on which you can \\\nrotate faces (by clicking on the black arrows) or rotate the \\\nwhole Megaminx (by shift-clicking on the back arrows). Each arrow has a \\\ntooltip which will appear if you hover the mouse over it. Rotations can be \\\nechoed to the report view if the variable echo (which can be changed from \\\nthe Megaminx menu) is True.\nEach face has a text label on it which shows its face number. Note that \\\nthe face numbers are fixed in the coordinate system of the view, not in \\\nthe coordinate system of the Megaminx itself. So if you rotate the Megaminx, \\\nthe face numbers will be on different faces but in the same places in the \\\ndisplay. The reason for this is that the sine and cosine of 72 degrees \\\ncannot be represented exactly, so if it did lots of rotations the rounding \\\nerrors would accumulate and it would look wrong: in order to avoid this the \\\nmacro cheats and just switches the colours.\nThe macro maintains a history of the rotations that have been done. \\\nThis allows you to undo your rotations. The history is a Python \\\nscript which is executable if this macro has been loaded. You can \\\ncopy the  history to the clipboard and replay it by pasting into the \\\nPython console, or paste it into your favourite editor and save it \\\nas a FreeCAD macro. You can reset the model to its initial state \\\nwhich also clears  the history.\nYou can also reset the model and then step through a copy of the \\\nhistory displaying a dialog box before each step. Clicking on the OK \\\nbutton or typing a return will remove the dialog box and execute the \\\nstep: if there are more steps to do it will then redisplay the dialog \\\nbox with the next step. Clicking on the Stop button or typing an ESC \\\nwill remove the dialog box without executing the step and cease \\\nstepping through the history. The history is left containing the \\\nsteps actually executed.\nYou can randomise the Megaminx which executes 120 random rotations \\\n(without animation to speed it up) to get it thoroughly confused and \\\ngive you a puzzle to solve. The random  rotations are stored in the \\\nhistory, so if you have partially solved the puzzle, copying and saving \\\nthe history will produce a macro which can be run on a reset Megaminx to \\\nrecreate the partially solved state.\nYou can rotate the history (by ctrl-clicking on the black arrows) or \\\nreflect the history (by clicking on the green arrows). You can also \\\nreplace the history by its group-theoretic inverse (the sequence of \\\nrotations which would undo the whole history). These functions can be \\\nuseful in composing more useful macros out of simple ones.\nAll these functions are available by calling them from the Python \\\nconsole or by clicking on a suitable arrow or from the menu which \\\nthis macro adds to the menu bar. Each menu item has a brief usage \\\ntip which appears on the status bar at the bottom of the FreeCAD \\\nwindow when you move the mouse over that menu item.\nIf you want to drive it from the Python console, the function names are \\\n(where face?? is one of face00, face10, face11, face12, face13, \\\nface14, face20, face21, face22, face23, face24, face30; and steps \\\nis the number of steps to animate the rotation, defaulting if \\\nomitted to the value of the variable slowness set near the start \\\nof this macro; and arrow is one of arrow00x, arrow01x, arrow02x, \\\narrow03x, arrow04x, arrow10x, arrow14x, arrow20x, arrow11x, \narrow21x, arrow12x, arrow22x, arrow13x, arrow23x, arrow24x):-\nhelp_window() [displays this window]\nreset()\nundo()\ncopy_history()\nundo_history()\nrandomise()\nset_echo(True or False)\nrotp(\"face??\", steps) [rotate face by 72 degrees anticlockwise]\nrotm(\"face??\", steps) [rotate face by 72 degrees clockwise]\nrota(\"face??\", steps) [rotate whole Megaminx by 72 degrees anticlockwise]\nroth(\"face??\") [rotate the history by 72 degrees anticlockwise]\nreflect(\"arrow\") [reflect the history]\\\n\"\"\")\n        self.helptext.setReadOnly(True)\n        self.OKbutton = QtGui.QPushButton(self)\n        self.OKbutton.setText(\"OK\")\n        self.OKbutton.clicked.connect(self.accept)\n        self.OKbutton.setDefault(True)\n        self.setAutoFillBackground(True)\n    def paintEvent(self, event):\n        \"\"\" This internal methodn overrides QWidget.paint().\nIt adjusts the geometry of this window in case FreeCAD's window has been or \\\nis being resized.\\\n\"\"\"\n        geom = self.parent().geometry()\n        font = self.OKbutton.font()\n        margin = 10\n        r = QtGui.QFontMetrics(font).boundingRect(\"  OK  \")\n        xpos = (geom.width() - r.width()) / 2\n        h = r.height()\n        ypos = geom.height() - h - 2 * margin\n        self.helptext.setGeometry(0, 0, geom.width(), ypos)\n        self.OKbutton.setGeometry(xpos, ypos + margin, r.width(), h)\n        self.setGeometry(0, 0, geom.width(), geom.height())\n        super(helpWindow, self).paintEvent(event)\ndef help_window():\n    \"\"\" This function displays the help window.\\\n\"\"\"\n    global hw\n    mw = Gui.getMainWindow()\n    view3DWidget = findView(mw.centralWidget())\n    if view3DWidget != None:\n        hw = helpWindow(view3DWidget)\n        d = FreeCAD.Megaminx_Dictionary\n        actionHelp = None\n        for key in d:\n            if key.endswith(\"menu\"):\n                menu = d[key]\n                for action in menu.actions():\n                    if action.iconText() == \"Show help\":\n                        actionHelp = action\n                        actionHelp.setEnabled(False)\n                        break\n                break\n        hw.exec()\n        if action != None:\n            actionHelp.setEnabled(True)\n\nclass face:\n    \"\"\" Class containing the parts and operations of a face of the Megaminx.\\\n\"\"\"\n    def __init__(self, normal):\n        # face normal\n        self.normal = normal\n        # face centre facet\n        self.middle = None\n        # opposite face\n        self.opposite = None # filled in when we have defined all faces\n        # name\n        self.name = \"\"\n        # 5 vertices in ccw order round middle from outside\n        # each with 3 facets in ccw order round vertex from outside\n        self.vertex = [[None, None, None] for i in range (5)]\n        # 5 edges in ccw order round middle from outside\n        # each with 2 facets, on face before on adjacent face\n        self.edge = [[None, None] for i in range (5)]\n        # black interior facets only visible partly during rotation\n        # order doesn't matter\n        self.invis = [None for i in range(40)]\n        # adjacent facets for all rotation\n        self.allvis = [[None for i in range (8)] for j in range(5)]\n        # dictionary for roth()\n        self.rhdict = {}\n        # texture image for face label\n        self.image = None\n    def setColour(self, c):\n        \"\"\" Set this face's colour to c.\\\n\"\"\"\n        for i in range(5):\n            self.vertex[i][0].ViewObject.DiffuseColor = c\n            self.edge[i][0].ViewObject.DiffuseColor = c\n        self.middle.ViewObject.DiffuseColor = c\n    def _rwhole(self, degrees):\n        \"\"\" This internal face method rotates the model about this face's \\\n        normal.\nDegrees is the angle to rotate by.\\\n \"\"\"\n        pl = Base.Placement(origin, self.normal, degrees)\n        for ob in _get(\"all\"):\n            ob.Placement = pl\n    def _rotate(self, degrees):\n        \"\"\" Internal function to rotate this face.\n        degrees is the angle to rotate by\n        \"\"\"\n        pl = Base.Placement(origin, self.normal, degrees)\n        self.middle.Placement = pl\n        for a in self.vertex:\n            a[0].Placement = pl\n            a[1].Placement = pl\n            a[2].Placement = pl\n        for a in self.edge:\n            a[0].Placement = pl\n            a[1].Placement = pl\n        for ob in self.invis:\n            ob.Placement = pl\n    def _cfixp(self):\n        \"\"\" This internal face method sets the colours after rotating \\\n        +72 degrees.\\\n\"\"\"\n        c0 = self.vertex[4][0].ViewObject.DiffuseColor\n        c1 = self.vertex[4][1].ViewObject.DiffuseColor\n        c2 = self.vertex[4][2].ViewObject.DiffuseColor\n        c3 = self.edge[4][0].ViewObject.DiffuseColor\n        c4 = self.edge[4][1].ViewObject.DiffuseColor\n        for i in range(4):\n            self.vertex[4 - i][0].ViewObject.DiffuseColor =\\\n                self.vertex[3 - i][0].ViewObject.DiffuseColor\n            self.vertex[4 - i][1].ViewObject.DiffuseColor =\\\n                self.vertex[3 - i][1].ViewObject.DiffuseColor\n            self.vertex[4 - i][2].ViewObject.DiffuseColor =\\\n                self.vertex[3 - i][2].ViewObject.DiffuseColor\n            self.edge[4 - i][0].ViewObject.DiffuseColor =\\\n                self.edge[3 - i][0].ViewObject.DiffuseColor\n            self.edge[4 - i][1].ViewObject.DiffuseColor =\\\n                self.edge[3 - i][1].ViewObject.DiffuseColor\n        self.vertex[0][0].ViewObject.DiffuseColor = c0\n        self.vertex[0][1].ViewObject.DiffuseColor = c1\n        self.vertex[0][2].ViewObject.DiffuseColor = c2\n        self.edge[0][0].ViewObject.DiffuseColor = c3\n        self.edge[0][1].ViewObject.DiffuseColor = c4\n    def _cfixm(self):\n        \"\"\" This internal face method sets the colours after rotating\\\n        -72 degrees.\\\n\"\"\"\n        c0 = self.vertex[0][0].ViewObject.DiffuseColor\n        c1 = self.vertex[0][1].ViewObject.DiffuseColor\n        c2 = self.vertex[0][2].ViewObject.DiffuseColor\n        c3 = self.edge[0][0].ViewObject.DiffuseColor\n        c4 = self.edge[0][1].ViewObject.DiffuseColor\n        for i in range(4):\n            self.vertex[i][0].ViewObject.DiffuseColor =\\\n                self.vertex[i + 1][0].ViewObject.DiffuseColor\n            self.vertex[i][1].ViewObject.DiffuseColor =\\\n                self.vertex[i + 1][1].ViewObject.DiffuseColor\n            self.vertex[i][2].ViewObject.DiffuseColor =\\\n                self.vertex[i + 1][2].ViewObject.DiffuseColor\n            self.edge[i][0].ViewObject.DiffuseColor =\\\n                self.edge[i + 1][0].ViewObject.DiffuseColor\n            self.edge[i][1].ViewObject.DiffuseColor =\\\n                self.edge[i + 1][1].ViewObject.DiffuseColor\n        self.vertex[4][0].ViewObject.DiffuseColor = c0\n        self.vertex[4][1].ViewObject.DiffuseColor = c1\n        self.vertex[4][2].ViewObject.DiffuseColor = c2\n        self.edge[4][0].ViewObject.DiffuseColor = c3\n        self.edge[4][1].ViewObject.DiffuseColor = c4\n    def _rotp(self, steps = None):\n        \"\"\" This internal face method rotates this face by +72 degrees.\\\n\"\"\"\n        if steps == None:\n            steps = _get(\"slowness\")\n        if steps > 1:\n            removeTextures()\n            angle = 0.0\n            for i in range(steps - 1):\n                angle = angle + 72.0 / steps\n                self._rotate(angle)\n                Gui.updateGui()\n            # finally we undo the rotation and switch the colours instead\n            # because a 72 degree rotation cannot be represented exactly\n            # so doing lots of them would accumulate rounding errors\n            self._rotate(0.0)\n            setTextures()\n        self._cfixp()\n    def rotp(self, steps = None):\n        \"\"\" Rotate this face by +72 degrees.\nIt also updates the history and does echoing if enabled.\nsteps is the number of steps to animate the rotation,\nwhich defaults to slowness defined near the start of this macro.\nZero steps omits the animation.\nThis can be invoked by clicking an anticlockwise pointing curved black arrow./\n\"\"\"\n        if steps == None:\n            steps = _get(\"slowness\")\n        self._rotp(steps)\n        s = \"rotp('\" + self.name + \"', \" + str(steps) + \")\"\n        _get(\"history\").append(s)\n        if _get(\"echo\"):\n            print(s)\n        updateMenu()\n    def _rotm(self, steps = None):\n        \"\"\" This internal face method rotates this face by -72 degrees.\\\n\"\"\"\n        if steps == None:\n            steps = _get(\"slowness\")\n        if steps > 1:\n            removeTextures()\n            angle = 0.0\n            for i in range(steps - 1):\n                angle = angle - 72.0 / steps\n                self._rotate(angle)\n                Gui.updateGui()\n            # finally we undo the rotation and switch the colours instead\n            # because a 72 degree rotation cannot be represented exactly\n            # so doing lots of them would accumulate rounding errors\n            self._rotate(0.0)\n            setTextures()\n        self._cfixm()\n    def rotm(self, steps = None):\n        \"\"\" Rotate this face by -72 degrees.\nIt also updates the history and does echoing if enabled.\nsteps is the number of steps to animate the rotation,\nwhich defaults to slowness defined near the start of this macro\nZero steps omits the animation.\nThis can be invoked by clicking a clockwise pointing curved black arrow.\\\n\"\"\"\n        if steps == None:\n            steps = _get(\"slowness\")\n        self._rotm(steps)\n        s = \"rotm('\" + self.name + \"', \" + str(steps) + \")\"\n        _get(\"history\").append(s)\n        if _get(\"echo\"):\n            print(s)\n        updateMenu()\n    def _rota(self, steps = None):\n        \"\"\" This internal face method rotates the Megaminx by +72 degrees.\\\n\"\"\"\n        if steps == None:\n            steps = _get(\"slowness\")\n        if steps > 1:\n            removeTextures()\n            angle = 0.0\n            for i in range(steps - 1):\n                angle = angle + 72.0 / steps\n                self._rwhole(angle)\n                Gui.updateGui()\n            # finally we undo the rotation and switch the colours instead\n            # because a 72 degree rotation cannot be represented exactly\n            # so doing lots of them would accumulate rounding errors\n            self._rwhole(0.0)\n            setTextures()\n        self._cfixp()\n        opp = self.opposite\n        opp._cfixm()\n        a = [self.allvis[4][i].ViewObject.DiffuseColor for i in range(8)]\n        b = [opp.allvis[0][i].ViewObject.DiffuseColor for i in range(8)]\n        for i in range(8):\n            for j in range(4):\n                self.allvis[4 - j][i].ViewObject.DiffuseColor =\\\n                    self.allvis[3 - j][i].ViewObject.DiffuseColor\n                opp.allvis[j][i].ViewObject.DiffuseColor =\\\n                    opp.allvis[j + 1][i].ViewObject.DiffuseColor\n            self.allvis[0][i].ViewObject.DiffuseColor = a[i]\n            opp.allvis[4][i].ViewObject.DiffuseColor = b[i]\n    def rota(self, steps = None):\n        \"\"\" Rotate the whole Megaminx by +72 degrees.\nIt also updates the history and does echoing if enabled.\nsteps is the number of steps to animate the rotation,\nwhich defaults to slowness defined near the start of this macro.\nZero steps omits the animation.\nUse face.opposite.rota() to rotate by -72 degrees.\nThis function is invoked by shift-clicking on a curved black arrow.\\\n\"\"\"\n        if steps == None:\n            steps = _get(\"slowness\")\n        self._rota(steps)\n        s = \"rota('\" + self.name + \"', \" + str(steps) + \")\"\n        _get(\"history\").append(s)\n        if _get(\"echo\"):\n            print(s)\n        updateMenu()\n    def roth(self):\n        \"\"\" Rotate the history by +72 degrees.\nThis replaces the history by the equivalent of rotating the Megaminx\nby -72 degrees about this face's normal, executing the history, and\nthen rotating the Megaminx by +72 degrees about this face's normal.\nHowever it does this by modifying the operations in the history\nwithout adding extra rotations.\nUse face.opposite.roth() to rotate by -72 degrees.\nThis can be invoked by control-clicking on a curved black arrow.\nRotating the history can be useful to align it with a real Megaminx\nbefore doing step_history(), or to compose more complex macros out of\nsimple ones.\\\n\"\"\"\n        history = _get(\"history\")\n        nh = history[:]\n        reset()\n        hs = _get(\"historyslowness\")\n        while len(nh) > 0:\n            s = nh.pop(0)\n            sl = len(s) - 1\n            f = \"\"\n            rot = \"\"\n            steps = \"\"\n            if sl >= 13 and s[0:3] == \"rot\" and s[4] == \"(\" \\\n                and (s[5] == '\"' or s[5] == \"'\") \\\n                and s[5] == s[12] and s.endswith(\")\"):\n                f = s[6:12]\n                rot = s[0:4]\n                if s[13] == \",\":\n                    steps = s[14:sl].strip()\n            if steps == \"\":\n                steps = \"0\"\n            d = FreeCAD.Megaminx_Dictionary\n            key = App.ActiveDocument.Name + \"$\" + f\n            if rot in [\"rota\", \"rotm\", \"rotp\"] and key in d \\\n                and f in self.rhdict and steps.isnumeric():\n                fn = self.rhdict[f]\n                if rot == \"rota\":\n                    fn._rota(hs)\n                    history.append(\"rota('\" + fn.name + \"', \" + steps + \")\")\n                elif rot == \"rotm\":\n                    fn._rotm(hs)\n                    history.append(\"rotm('\" + fn.name + \"', \" + steps + \")\")\n                elif rot == \"rotp\":\n                    fn._rotp(hs)\n                    history.append(\"rotp('\" + fn.name + \"', \" + steps + \")\")\n            else:\n                print(\"Invalid history entry '\" + s + \"'\")\n        updateMenu()\n\ndef reset():\n    \"\"\" Reset the model to its initial state.\\\n\"\"\"\n    _get(\"history\").clear()\n    _get(\"face00\").setColour([(1.0, 1.0, 1.0)])  # white\n    _get(\"face10\").setColour([(0.1, 0.6, 0.1)])  # darkgreen\n    _get(\"face11\").setColour([(0.75, 0.0, 0.0)]) # red\n    _get(\"face12\").setColour([(0.2, 0.2, 0.9)])  # darkblue\n    _get(\"face13\").setColour([(1.0, 1.0, 0.0)])  # yellow\n    _get(\"face14\").setColour([(0.4, 0.0, 0.4)])  # purple\n    _get(\"face20\").setColour([(0.1, 0.5, 0.6)])  # paleblue\n    _get(\"face21\").setColour([(1.0, 1.0, 0.8)])  # cream\n    _get(\"face22\").setColour([(1.0, 0.6, 0.8)])  # pink\n    _get(\"face23\").setColour([(0.4, 0.6, 0.4)])  # palegreen\n    _get(\"face24\").setColour([(0.8, 0.3, 0.1)])  # orange\n    _get(\"face30\").setColour([(0.8, 0.8, 0.8)])  # gray\n    updateMenu()\n\ndef setTextures():\n    \"\"\" This is an internal function used to make the model.\nIt creates the text labels on the face centres by applying a texture\nto each face centre. The textures are made from images with the\nrequired text. The images are defined in a big table below. Note that the\nface labels are in the coordinate syste of the view, not the coordinate\nsytem of the model. If you rotate the Megaminx, the face labels will be on faces with different colours but in the same positions in the view.\\\n\"\"\"\n    s = str(_get(\"dpi\") / 130.0)\n    s = s + \" \" + s\n    f = _get(\"face00\")\n    node = f.middle.ViewObject.RootNode\n    textr = coin.SoTexture2Transform()\n    textr.rotation.set('1.5708')\n    textr.scaleFactor.set(s)\n    texim = coin.SoTexture2()\n    texim.image.set(f.image)\n    node.insertChild(textr, 1)\n    node.insertChild(texim, 2)\n    f = _get(\"face10\")\n    node = f.middle.ViewObject.RootNode\n    textr = coin.SoTexture2Transform()\n    textr.rotation.set('3.0')\n    textr.scaleFactor.set(s)\n    texim = coin.SoTexture2()\n    texim.image.set(f.image)\n    node.insertChild(textr, 1)\n    node.insertChild(texim, 2)\n    f = _get(\"face11\")\n    node = f.middle.ViewObject.RootNode\n    textr = coin.SoTexture2Transform()\n    textr.rotation.set('-0.5')\n    textr.scaleFactor.set(s)\n    texim = coin.SoTexture2()\n    texim.image.set(f.image)\n    node.insertChild(textr, 1)\n    node.insertChild(texim, 2)\n    f = _get(\"face12\")\n    node = f.middle.ViewObject.RootNode\n    textr = coin.SoTexture2Transform()\n    textr.rotation.set('1.57')\n    textr.scaleFactor.set(s)\n    texim = coin.SoTexture2()\n    texim.image.set(f.image)\n    node.insertChild(textr, 1)\n    node.insertChild(texim, 2)\n    f = _get(\"face13\")\n    node = f.middle.ViewObject.RootNode\n    textr = coin.SoTexture2Transform()\n    textr.rotation.set('-0.4')\n    textr.scaleFactor.set(s)\n    texim = coin.SoTexture2()\n    texim.image.set(f.image)\n    node.insertChild(textr, 1)\n    node.insertChild(texim, 2)\n    f = _get(\"face14\")\n    node = f.middle.ViewObject.RootNode\n    textr = coin.SoTexture2Transform()\n    textr.rotation.set('0.0')\n    textr.scaleFactor.set(s)\n    texim = coin.SoTexture2()\n    texim.image.set(f.image)\n    node.insertChild(textr, 1)\n    node.insertChild(texim, 2)\n    f = _get(\"face20\")\n    node = f.middle.ViewObject.RootNode\n    textr = coin.SoTexture2Transform()\n    textr.rotation.set('1.5708')\n    textr.scaleFactor.set(s)\n    texim = coin.SoTexture2()\n    texim.image.set(f.image)\n    node.insertChild(textr, 1)\n    node.insertChild(texim, 2)\n    f = _get(\"face21\")\n    node = f.middle.ViewObject.RootNode\n    textr = coin.SoTexture2Transform()\n    textr.rotation.set('0.3')\n    textr.scaleFactor.set(s)\n    texim = coin.SoTexture2()\n    texim.image.set(f.image)\n    node.insertChild(textr, 1)\n    node.insertChild(texim, 2)\n    f = _get(\"face22\")\n    node = f.middle.ViewObject.RootNode\n    textr = coin.SoTexture2Transform()\n    v = coin.SoSFVec2f()\n    v.setValue(0.6, 0.5)\n    textr.center = v\n    textr.rotation.set('-0.8')\n    textr.scaleFactor.set(s)\n    texim = coin.SoTexture2()\n    texim.image.set(f.image)\n    node.insertChild(textr, 1)\n    node.insertChild(texim, 2)\n    f = _get(\"face23\")\n    node = f.middle.ViewObject.RootNode\n    textr = coin.SoTexture2Transform()\n    v = coin.SoSFVec2f()\n    v.setValue(0.5, 0.5)\n    textr.center = v\n    textr.rotation.set('0.8')\n    textr.scaleFactor.set(s)\n    texim = coin.SoTexture2()\n    texim.image.set(f.image)\n    node.insertChild(textr, 1)\n    node.insertChild(texim, 2)\n    f = _get(\"face24\")\n    node = f.middle.ViewObject.RootNode\n    textr = coin.SoTexture2Transform()\n    v = coin.SoSFVec2f()\n    v.setValue(0.5, 0.5)\n    textr.center = v\n    textr.rotation.set('0.4')\n    textr.scaleFactor.set(s)\n    texim = coin.SoTexture2()\n    texim.image.set(f.image)\n    node.insertChild(textr, 1)\n    node.insertChild(texim, 2)\n    f = _get(\"face30\")\n    node = f.middle.ViewObject.RootNode\n    textr = coin.SoTexture2Transform()\n    v = coin.SoSFVec2f()\n    v.setValue(0.5, 0.5)\n    textr.center = v\n    textr.rotation.set('-0.4')\n    textr.scaleFactor.set(s)\n    texim = coin.SoTexture2()\n    texim.image.set(f.image)\n    node.insertChild(textr, 1)\n    node.insertChild(texim, 2)\ndef removeTextures():\n    \"\"\" This is an internal function used when rotating a face or the model.\nIt removes the face labels which are later replaced when the rotation\nis completed.\\\n\"\"\"\n    node = _get(\"face00\").middle.ViewObject.RootNode\n    if node.getNumChildren() > 2:\n        texim = node.getChild(2)\n        textr = node.getChild(1)\n        if texim.getTypeId().getName().__str__() == \"Texture2\":\n            node.removeChild(2)\n        if textr.getTypeId().getName().__str__() == \"Texture2Transform\":\n            node.removeChild(1)\n    node = _get(\"face10\").middle.ViewObject.RootNode\n    if node.getNumChildren() > 2:\n        texim = node.getChild(2)\n        textr = node.getChild(1)\n        if texim.getTypeId().getName().__str__() == \"Texture2\":\n            node.removeChild(2)\n        if textr.getTypeId().getName().__str__() == \"Texture2Transform\":\n            node.removeChild(1)\n    node = _get(\"face11\").middle.ViewObject.RootNode\n    if node.getNumChildren() > 2:\n        texim = node.getChild(2)\n        textr = node.getChild(1)\n        if texim.getTypeId().getName().__str__() == \"Texture2\":\n            node.removeChild(2)\n        if textr.getTypeId().getName().__str__() == \"Texture2Transform\":\n            node.removeChild(1)\n    node = _get(\"face12\").middle.ViewObject.RootNode\n    if node.getNumChildren() > 2:\n        texim = node.getChild(2)\n        textr = node.getChild(1)\n        if texim.getTypeId().getName().__str__() == \"Texture2\":\n            node.removeChild(2)\n        if textr.getTypeId().getName().__str__() == \"Texture2Transform\":\n            node.removeChild(1)\n    node = _get(\"face13\").middle.ViewObject.RootNode\n    if node.getNumChildren() > 2:\n        texim = node.getChild(2)\n        textr = node.getChild(1)\n        if texim.getTypeId().getName().__str__() == \"Texture2\":\n            node.removeChild(2)\n        if textr.getTypeId().getName().__str__() == \"Texture2Transform\":\n            node.removeChild(1)\n    node = _get(\"face14\").middle.ViewObject.RootNode\n    if node.getNumChildren() > 2:\n        texim = node.getChild(2)\n        textr = node.getChild(1)\n        if texim.getTypeId().getName().__str__() == \"Texture2\":\n            node.removeChild(2)\n        if textr.getTypeId().getName().__str__() == \"Texture2Transform\":\n            node.removeChild(1)\n    node = _get(\"face20\").middle.ViewObject.RootNode\n    if node.getNumChildren() > 2:\n        texim = node.getChild(2)\n        textr = node.getChild(1)\n        if texim.getTypeId().getName().__str__() == \"Texture2\":\n            node.removeChild(2)\n        if textr.getTypeId().getName().__str__() == \"Texture2Transform\":\n            node.removeChild(1)\n    node = _get(\"face21\").middle.ViewObject.RootNode\n    if node.getNumChildren() > 2:\n        texim = node.getChild(2)\n        textr = node.getChild(1)\n        if texim.getTypeId().getName().__str__() == \"Texture2\":\n            node.removeChild(2)\n        if textr.getTypeId().getName().__str__() == \"Texture2Transform\":\n            node.removeChild(1)\n    node = _get(\"face22\").middle.ViewObject.RootNode\n    if node.getNumChildren() > 2:\n        texim = node.getChild(2)\n        textr = node.getChild(1)\n        if texim.getTypeId().getName().__str__() == \"Texture2\":\n            node.removeChild(2)\n        if textr.getTypeId().getName().__str__() == \"Texture2Transform\":\n            node.removeChild(1)\n    node = _get(\"face23\").middle.ViewObject.RootNode\n    if node.getNumChildren() > 2:\n        texim = node.getChild(2)\n        textr = node.getChild(1)\n        if texim.getTypeId().getName().__str__() == \"Texture2\":\n            node.removeChild(2)\n        if textr.getTypeId().getName().__str__() == \"Texture2Transform\":\n            node.removeChild(1)\n    node = _get(\"face24\").middle.ViewObject.RootNode\n    if node.getNumChildren() > 2:\n        texim = node.getChild(2)\n        textr = node.getChild(1)\n        if texim.getTypeId().getName().__str__() == \"Texture2\":\n            node.removeChild(2)\n        if textr.getTypeId().getName().__str__() == \"Texture2Transform\":\n            node.removeChild(1)\n    node = _get(\"face30\").middle.ViewObject.RootNode\n    if node.getNumChildren() > 2:\n        texim = node.getChild(2)\n        textr = node.getChild(1)\n        if texim.getTypeId().getName().__str__() == \"Texture2\":\n            node.removeChild(2)\n        if textr.getTypeId().getName().__str__() == \"Texture2Transform\":\n            node.removeChild(1)\n\ndef mkarrow(v0, dx, dy, fs):\n    \"\"\" Internal function to create a curved black arrow.\nv0 is a Vector to the point at the start of the arrow,\ndx is a Vector along the arrow,\ndy is a Vector across the arrow,\nfs is  a string which will be the arrow's name.\nThese arrows are not selectable because mouse clicks on them are interpreted\nby the ViewObserver defined later to call rotation functions.\\\n\"\"\"\n    v1 = v0.sub(dy)\n    v2 = v1.add(DVU.scale(dx, 0.707107))\n    v3 = v2.add(DVU.scale(dx, 1.2)).add(DVU.scale(dy, 0.403107))\n    v4 = v3.add(DVU.scale(dx, 1.507107)).add(DVU.scale(dy, 1.304107))\n    v5 = v4.sub(DVU.scale(dy, 0.5)).add(DVU.scale(dx, 0.5))\n    v6 = v5.add(DVU.scale(dy, 1.62137))\n    v7 = v6.sub(DVU.scale(dx, 1.62137))\n    v8 = v7.sub(DVU.scale(dy, 0.5)).add(DVU.scale(dx, 0.5))\n    v9 = v8.sub(dy).sub(dx)\n    v10 = v9.sub(DVU.scale(dy, 0.328584)).sub(dx)\n    arrow = App.ActiveDocument.addObject(\"Part::Feature\", fs)\n    arrow.Label = fs\n    arrow.Shape = Part.Face(\n        Part.makePolygon([v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v0]))\n    arrow.ViewObject.RootNode.setName(coin.SbName(fs))\n    arrow.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    if fs[7] in \"pqrst\":\n        _set(\"tooltip\" + fs, \\\n        \"Click to rotate face\" + fs[5:7] + \" 72 degrees anticlockwise\\n\" +\n        \"Shift-click to rotate the whole Megaminx 72 degrees anticlockwise\\n\" +\n        \"Control-click to rotate the history 72 degrees anticlockwise\")\n    elif fs[7] in \"ijklm\":\n        _set(\"tooltip\" + fs, \\\n        \"Click to rotate face\" + fs[5:7] + \" 72 degrees clockwise\\n\" +\n        \"Shift-click to rotate the whole Megaminx 72 degrees clockwise\\n\" +\n        \"Control-click to rotate the history 72 degrees clockwise\")\n    arrow.ViewObject.Selectable = False\ndef mkarrowx(v0, dx, dy, fs, ff):\n    \"\"\" This internal function makes a green double headed arrow.\nv0 is a Vector to the centre of the arrow,\ndx is a Vector along the arrow,\ndy is a Vector across the arrow,\nfs is  a string which will be the arrow's name,\nff is the variable part of the arrow's tooltip.\nThese arrows are not selectable because mouse clicks on them are interpreted\nby the ViewObserver defined later to call reflection functions.\\\n\"\"\"\n    v0 = v0.sub(DVU.scale(dy, 0.5))\n    v1 = v0.add(dy)\n    v2 = v1.add(dx)\n    v3 = v2.add(DVU.scale(dy, 0.5))\n    v4 = v3.add(dx).sub(dy)\n    v5 = v4.sub(dx).sub(dy)\n    v6 = v5.add(DVU.scale(dy, 0.5))\n    v7 = v6.sub(DVU.scale(dx, 2.0))\n    v8 = v7.sub(DVU.scale(dy, 0.5))\n    v9 = v8.sub(dx).add(dy)\n    v10 = v9.add(dx).add(dy)\n    v11 = v10.sub(DVU.scale(dy, 0.5))\n    v12 = v11.add(dx)\n    arrow = App.ActiveDocument.addObject(\"Part::Feature\", fs)\n    arrow.Label = fs\n    arrow.Shape = Part.Face(Part.makePolygon(\n        [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v1]))\n    arrow.ViewObject.DiffuseColor = [(0.0, 1.0, 0.0)]\n    arrow.ViewObject.RootNode.setName(coin.SbName(fs))\n    _set(\"tooltip\" + fs, \\\n    \"Click to reflect the history in a plane through the centre of the\\n\" + \\\n    \"Megaminx and the edge between faces \" + ff)\n    arrow.ViewObject.Selectable = False\n\ndef undo():\n    \"\"\" Undo the last rotation and remove it from the history.\n    \"\"\"\n    history = _get(\"history\")\n    if len(history) > 0:\n        s = history.pop()\n        sl = len(s) - 1\n        f = \"\"\n        rot = \"\"\n        steps = \"\"\n        if sl >= 13 and s[0:3] == \"rot\" and s[4] == \"(\" \\\n            and (s[5] == '\"' or s[5] == \"'\") \\\n            and s[5] == s[12] and s.endswith(\")\"):\n            f = s[6:12]\n            rot = s[0:4]\n            if s[13] == \",\":\n                steps = s[14:sl].strip()\n        if steps == \"\":\n            steps = \"0\"\n        d = FreeCAD.Megaminx_Dictionary\n        ff = App.ActiveDocument.Name + \"$\" + f\n        if rot in [\"rota\", \"rotm\", \"rotp\"] and ff in d and steps.isnumeric():\n            if rot == \"rota\":\n                d[ff].opposite._rota(int(steps))\n            elif rot == \"rotm\":\n                d[ff]._rotp(int(steps))\n            elif rot == \"rotp\":\n                d[ff]._rotm(int(steps))\n        else:\n            print(\"Invalid history entry '\" + s + \"'\")\n    updateMenu()\n\ndef undo_history():\n    \"\"\" Replace the history by its group-theoretic inverse.\nThis replaces the history by a sequence of rotations which if done before\nor after the history would restore the model to its initial state.\\\n\"\"\"\n    history = _get(\"history\")\n    nh = history[:]\n    reset()\n    hs = _get(\"historyslowness\")\n    while len(nh) > 0:\n        s = nh.pop()\n        sl = len(s) - 1\n        f = \"\"\n        rot = \"\"\n        steps = \"\"\n        if sl >= 13 and s[0:3] == \"rot\" and s[4] == \"(\" \\\n            and (s[5] == '\"' or s[5] == \"'\") \\\n            and s[5] == s[12] and s.endswith(\")\"):\n            f = s[6:12]\n            rot = s[0:4]\n            if s[13] == \",\":\n                steps = s[14:sl].strip()\n        if steps == \"\":\n            steps = \"0\"\n        d = FreeCAD.Megaminx_Dictionary\n        ff = App.ActiveDocument.Name + \"$\" + f\n        if rot in [\"rota\", \"rotm\", \"rotp\"] and ff in d \\\n            and steps.isnumeric():\n            if rot == \"rota\":\n                opp = d[ff].opposite\n                opp._rota(hs)\n                history.append(\"rota('\" + opp.name + \"',\" + steps + \")\")\n            elif rot == \"rotm\":\n                d[ff]._rotp(hs)\n                history.append(\"rotp('\" + f + \"',\" + steps + \")\")\n            elif rot == \"rotp\":\n                d[ff]._rotm(hs)\n                history.append(\"rotm('\" + f + \"',\" + steps + \")\")\n        else:\n            print(\"Invalid history entry '\" + s + \"'\")\n    updateMenu()\n\ndef copy_history():\n    \"\"\" Save the history to the clipboard.\n    The history is a sequence of function calls \n    From the clipboard it can be pasted into the Python console or pasted\n    into your favourite editor and saved into a new FreeCAD macro file.\n    \"\"\"\n    history = _get(\"history\")\n    if len(history) > 0:\n        fs = \"\"\n        for s in history:\n            fs = fs + s + \"\\n\"\n        clip = QtGui.QApplication.clipboard()\n        clip.setText(fs)\n\ndef make_faces():\n    \"\"\" This internal function makes all the faces of the Megaminx.\nWe put them into the dictionary so that multiple Megaminx documents\ndon't interfere with each other.\\\n\"\"\"\n    # define the geometry, starting with lots of points\n    p00 = Base.Vector(2 * c0, 2 * s0, phi + 1)\n    p01 = Base.Vector(2 * c1, 2 * s1, phi + 1)\n    p02 = Base.Vector(2 * c2, 2 * s2, phi + 1)\n    p03 = Base.Vector(2 * c3, 2 * s3, phi + 1)\n    p04 = Base.Vector(2 * c4, 2 * s4, phi + 1)\n    p10 = Base.Vector(2 * phi * c0, 2 * phi * s0, phi - 1)\n    p11 = Base.Vector(2 * phi * c1, 2 * phi * s1, phi - 1)\n    p12 = Base.Vector(2 * phi * c2, 2 * phi * s2, phi - 1)\n    p13 = Base.Vector(2 * phi * c3, 2 * phi * s3, phi - 1)\n    p14 = Base.Vector(2 * phi * c4, 2 * phi * s4, phi - 1)\n    p20 = Base.Vector(-2 * phi * c0, -2 * phi * s0, 1 - phi)\n    p21 = Base.Vector(-2 * phi * c1, -2 * phi * s1, 1 - phi)\n    p22 = Base.Vector(-2 * phi * c2, -2 * phi * s2, 1 - phi)\n    p23 = Base.Vector(-2 * phi * c3, -2 * phi * s3, 1 - phi)\n    p24 = Base.Vector(-2 * phi * c4, -2 * phi * s4, 1 - phi)\n    p30 = Base.Vector(-2 * c0, -2 * s0, -1 - phi)\n    p31 = Base.Vector(-2 * c1, -2 * s1, -1 - phi)\n    p32 = Base.Vector(-2 * c2, -2 * s2, -1 - phi)\n    p33 = Base.Vector(-2 * c3, -2 * s3, -1 - phi)\n    p34 = Base.Vector(-2 * c4, -2 * s4, -1 - phi)\n\n    p00p01 = DVU.scale(p00, 0.6).add(DVU.scale(p01, 0.4))\n    p00p04 = DVU.scale(p00, 0.6).add(DVU.scale(p04, 0.4))\n    p00p10 = DVU.scale(p00, 0.6).add(DVU.scale(p10, 0.4))\n    p01p00 = DVU.scale(p01, 0.6).add(DVU.scale(p00, 0.4))\n    p01p02 = DVU.scale(p01, 0.6).add(DVU.scale(p02, 0.4))\n    p01p11 = DVU.scale(p01, 0.6).add(DVU.scale(p11, 0.4))\n    p02p01 = DVU.scale(p02, 0.6).add(DVU.scale(p01, 0.4))\n    p02p03 = DVU.scale(p02, 0.6).add(DVU.scale(p03, 0.4))\n    p02p12 = DVU.scale(p02, 0.6).add(DVU.scale(p12, 0.4))\n    p03p02 = DVU.scale(p03, 0.6).add(DVU.scale(p02, 0.4))\n    p03p04 = DVU.scale(p03, 0.6).add(DVU.scale(p04, 0.4))\n    p03p13 = DVU.scale(p03, 0.6).add(DVU.scale(p13, 0.4))\n    p04p00 = DVU.scale(p04, 0.6).add(DVU.scale(p00, 0.4))\n    p04p03 = DVU.scale(p04, 0.6).add(DVU.scale(p03, 0.4))\n    p04p14 = DVU.scale(p04, 0.6).add(DVU.scale(p14, 0.4))\n    p10p00 = DVU.scale(p10, 0.6).add(DVU.scale(p00, 0.4))\n    p10p22 = DVU.scale(p10, 0.6).add(DVU.scale(p22, 0.4))\n    p10p23 = DVU.scale(p10, 0.6).add(DVU.scale(p23, 0.4))\n    p11p01 = DVU.scale(p11, 0.6).add(DVU.scale(p01, 0.4))\n    p11p23 = DVU.scale(p11, 0.6).add(DVU.scale(p23, 0.4))\n    p11p24 = DVU.scale(p11, 0.6).add(DVU.scale(p24, 0.4))\n    p12p02 = DVU.scale(p12, 0.6).add(DVU.scale(p02, 0.4))\n    p12p20 = DVU.scale(p12, 0.6).add(DVU.scale(p20, 0.4))\n    p12p24 = DVU.scale(p12, 0.6).add(DVU.scale(p24, 0.4))\n    p13p03 = DVU.scale(p13, 0.6).add(DVU.scale(p03, 0.4))\n    p13p20 = DVU.scale(p13, 0.6).add(DVU.scale(p20, 0.4))\n    p13p21 = DVU.scale(p13, 0.6).add(DVU.scale(p21, 0.4))\n    p14p04 = DVU.scale(p14, 0.6).add(DVU.scale(p04, 0.4))\n    p14p21 = DVU.scale(p14, 0.6).add(DVU.scale(p21, 0.4))\n    p14p22 = DVU.scale(p14, 0.6).add(DVU.scale(p22, 0.4))\n    p20p12 = DVU.scale(p20, 0.6).add(DVU.scale(p12, 0.4))\n    p20p13 = DVU.scale(p20, 0.6).add(DVU.scale(p13, 0.4))\n    p20p30 = DVU.scale(p20, 0.6).add(DVU.scale(p30, 0.4))\n    p21p13 = DVU.scale(p21, 0.6).add(DVU.scale(p13, 0.4))\n    p21p14 = DVU.scale(p21, 0.6).add(DVU.scale(p14, 0.4))\n    p21p31 = DVU.scale(p21, 0.6).add(DVU.scale(p31, 0.4))\n    p22p10 = DVU.scale(p22, 0.6).add(DVU.scale(p10, 0.4))\n    p22p14 = DVU.scale(p22, 0.6).add(DVU.scale(p14, 0.4))\n    p22p32 = DVU.scale(p22, 0.6).add(DVU.scale(p32, 0.4))\n    p23p10 = DVU.scale(p23, 0.6).add(DVU.scale(p10, 0.4))\n    p23p11 = DVU.scale(p23, 0.6).add(DVU.scale(p11, 0.4))\n    p23p33 = DVU.scale(p23, 0.6).add(DVU.scale(p33, 0.4))\n    p24p11 = DVU.scale(p24, 0.6).add(DVU.scale(p11, 0.4))\n    p24p12 = DVU.scale(p24, 0.6).add(DVU.scale(p12, 0.4))\n    p24p34 = DVU.scale(p24, 0.6).add(DVU.scale(p34, 0.4))\n    p30p20 = DVU.scale(p30, 0.6).add(DVU.scale(p20, 0.4))\n    p30p31 = DVU.scale(p30, 0.6).add(DVU.scale(p31, 0.4))\n    p30p34 = DVU.scale(p30, 0.6).add(DVU.scale(p34, 0.4))\n    p31p21 = DVU.scale(p31, 0.6).add(DVU.scale(p21, 0.4))\n    p31p30 = DVU.scale(p31, 0.6).add(DVU.scale(p30, 0.4))\n    p31p32 = DVU.scale(p31, 0.6).add(DVU.scale(p32, 0.4))\n    p32p22 = DVU.scale(p32, 0.6).add(DVU.scale(p22, 0.4))\n    p32p31 = DVU.scale(p32, 0.6).add(DVU.scale(p31, 0.4))\n    p32p33 = DVU.scale(p32, 0.6).add(DVU.scale(p33, 0.4))\n    p33p23 = DVU.scale(p33, 0.6).add(DVU.scale(p23, 0.4))\n    p33p32 = DVU.scale(p33, 0.6).add(DVU.scale(p32, 0.4))\n    p33p34 = DVU.scale(p33, 0.6).add(DVU.scale(p34, 0.4))\n    p34p24 = DVU.scale(p34, 0.6).add(DVU.scale(p24, 0.4))\n    p34p30 = DVU.scale(p34, 0.6).add(DVU.scale(p30, 0.4))\n    p34p33 = DVU.scale(p34, 0.6).add(DVU.scale(p33, 0.4))\n    p00p01p04 = p00p04p01 = p00p01.add(p00p04).sub(p00)\n    p00p01p10 = p00p10p01 = p00p01.add(p00p10).sub(p00)\n    p00p04p10 = p00p10p04 = p00p04.add(p00p10).sub(p00)\n    p01p00p02 = p01p02p00 = p01p00.add(p01p02).sub(p01)\n    p01p00p11 = p01p11p00 = p01p00.add(p01p11).sub(p01)\n    p01p02p11 = p01p11p02 = p01p02.add(p01p11).sub(p01)\n    p02p01p03 = p02p03p01 = p02p01.add(p02p03).sub(p02)\n    p02p01p12 = p02p12p01 = p02p01.add(p02p12).sub(p02)\n    p02p03p12 = p02p12p03 = p02p03.add(p02p12).sub(p02)\n    p03p02p04 = p03p04p02 = p03p02.add(p03p04).sub(p03)\n    p03p02p13 = p03p13p02 = p03p02.add(p03p13).sub(p03)\n    p03p04p13 = p03p13p04 = p03p04.add(p03p13).sub(p03)\n    p04p00p03 = p04p03p00 = p04p00.add(p04p03).sub(p04)\n    p04p00p14 = p04p14p00 = p04p00.add(p04p14).sub(p04)\n    p04p03p14 = p04p14p03 = p04p03.add(p04p14).sub(p04)\n    p10p00p22 = p10p22p00 = p10p00.add(p10p22).sub(p10)\n    p10p00p23 = p10p23p00 = p10p00.add(p10p23).sub(p10)\n    p10p22p23 = p10p23p22 = p10p22.add(p10p23).sub(p10)\n    p11p01p23 = p11p23p01 = p11p01.add(p11p23).sub(p11)\n    p11p01p24 = p11p24p01 = p11p01.add(p11p24).sub(p11)\n    p11p23p24 = p11p24p23 = p11p23.add(p11p24).sub(p11)\n    p12p02p20 = p12p20p02 = p12p02.add(p12p20).sub(p12)\n    p12p02p24 = p12p24p02 = p12p02.add(p12p24).sub(p12)\n    p12p20p24 = p12p24p20 = p12p20.add(p12p24).sub(p12)\n    p13p03p20 = p13p20p03 = p13p03.add(p13p20).sub(p13)\n    p13p03p21 = p13p21p03 = p13p03.add(p13p21).sub(p13)\n    p13p20p21 = p13p21p20 = p13p20.add(p13p21).sub(p13)\n    p14p04p21 = p14p21p04 = p14p04.add(p14p21).sub(p14)\n    p14p04p22 = p14p22p04 = p14p04.add(p14p22).sub(p14)\n    p14p21p22 = p14p22p21 = p14p21.add(p14p22).sub(p14)\n    p20p12p13 = p20p13p12 = p20p12.add(p20p13).sub(p20)\n    p20p12p30 = p20p30p12 = p20p12.add(p20p30).sub(p20)\n    p20p13p30 = p20p30p13 = p20p13.add(p20p30).sub(p20)\n    p21p13p14 = p21p14p13 = p21p13.add(p21p14).sub(p21)\n    p21p13p31 = p21p31p13 = p21p13.add(p21p31).sub(p21)\n    p21p14p31 = p21p31p14 = p21p14.add(p21p31).sub(p21)\n    p22p10p14 = p22p14p10 = p22p10.add(p22p14).sub(p22)\n    p22p10p32 = p22p32p10 = p22p10.add(p22p32).sub(p22)\n    p22p14p32 = p22p32p14 = p22p14.add(p22p32).sub(p22)\n    p23p10p11 = p23p11p10 = p23p10.add(p23p11).sub(p23)\n    p23p10p33 = p23p33p10 = p23p10.add(p23p33).sub(p23)\n    p23p11p33 = p23p33p11 = p23p11.add(p23p33).sub(p23)\n    p24p11p12 = p24p12p11 = p24p11.add(p24p12).sub(p24)\n    p24p11p34 = p24p34p11 = p24p11.add(p24p34).sub(p24)\n    p24p12p34 = p24p34p12 = p24p12.add(p24p34).sub(p24)\n    p30p20p31 = p30p31p20 = p30p20.add(p30p31).sub(p30)\n    p30p20p34 = p30p34p20 = p30p20.add(p30p34).sub(p30)\n    p30p31p34 = p30p34p31 = p30p31.add(p30p34).sub(p30)\n    p31p21p30 = p31p30p21 = p31p21.add(p31p30).sub(p31)\n    p31p21p32 = p31p32p21 = p31p21.add(p31p32).sub(p31)\n    p31p30p32 = p31p32p30 = p31p30.add(p31p32).sub(p31)\n    p32p22p31 = p32p31p22 = p32p22.add(p32p31).sub(p32)\n    p32p22p33 = p32p33p22 = p32p22.add(p32p33).sub(p32)\n    p32p31p33 = p32p33p31 = p32p31.add(p32p33).sub(p32)\n    p33p23p32 = p33p32p23 = p33p23.add(p33p32).sub(p33)\n    p33p23p34 = p33p34p23 = p33p23.add(p33p34).sub(p33)\n    p33p32p34 = p33p34p32 = p33p32.add(p33p34).sub(p33)\n    p34p24p30 = p34p30p24 = p34p24.add(p34p30).sub(p34)\n    p34p24p33 = p34p33p24 = p34p24.add(p34p33).sub(p34)\n    p34p30p33 = p34p33p30 = p34p30.add(p34p33).sub(p34)\n    p00c = p00p01.add(p00p04).add(p00p10).sub(DVU.scale(p00, 2))\n    p01c = p01p02.add(p01p00).add(p01p11).sub(DVU.scale(p01, 2))\n    p02c = p02p03.add(p02p01).add(p02p12).sub(DVU.scale(p02, 2))\n    p03c = p03p04.add(p03p02).add(p03p13).sub(DVU.scale(p03, 2))\n    p04c = p04p00.add(p04p03).add(p04p14).sub(DVU.scale(p04, 2))\n    p10c = p10p00.add(p10p22).add(p10p23).sub(DVU.scale(p10, 2))\n    p11c = p11p01.add(p11p23).add(p11p24).sub(DVU.scale(p11, 2))\n    p12c = p12p02.add(p12p24).add(p12p20).sub(DVU.scale(p12, 2))\n    p13c = p13p03.add(p13p20).add(p13p21).sub(DVU.scale(p13, 2))\n    p14c = p14p04.add(p14p21).add(p14p22).sub(DVU.scale(p14, 2))\n    p20c = p20p12.add(p20p13).add(p20p30).sub(DVU.scale(p20, 2))\n    p21c = p21p13.add(p21p14).add(p21p31).sub(DVU.scale(p21, 2))\n    p22c = p22p14.add(p22p10).add(p22p32).sub(DVU.scale(p22, 2))\n    p23c = p23p10.add(p23p11).add(p23p33).sub(DVU.scale(p23, 2))\n    p24c = p24p11.add(p24p12).add(p24p34).sub(DVU.scale(p24, 2))\n    p30c = p30p20.add(p30p31).add(p30p34).sub(DVU.scale(p30, 2))\n    p31c = p31p21.add(p31p32).add(p31p30).sub(DVU.scale(p31, 2))\n    p32c = p32p22.add(p32p33).add(p32p31).sub(DVU.scale(p32, 2))\n    p33c = p33p23.add(p33p34).add(p33p32).sub(DVU.scale(p33, 2))\n    p34c = p34p24.add(p34p30).add(p34p33).sub(DVU.scale(p34, 2))\n\n    # Now define all the movable bits of the faces\n    # face centres\n    a = [p00p01p04, p01p02p00, p02p03p01, p03p04p02, p04p00p03, p00p01p04]\n    fc00 = App.ActiveDocument.addObject(\"Part::Feature\", \"fc00\")\n    fc00.Shape = Part.Face(Part.makePolygon(a))\n    a = [p01p11p00, p11p23p01, p23p10p11, p10p23p00, p00p01p10, p01p11p00]\n    fc10 = App.ActiveDocument.addObject(\"Part::Feature\", \"fc10\")\n    fc10.Shape = Part.Face(Part.makePolygon(a))\n    a = [p01p02p11, p02p12p01, p12p24p02, p24p11p12, p11p24p01, p01p02p11]\n    fc11 = App.ActiveDocument.addObject(\"Part::Feature\", \"fc11\")\n    fc11.Shape = Part.Face(Part.makePolygon(a))\n    a = [p02p03p12, p03p13p02, p13p20p03, p20p12p13, p12p20p02, p02p03p12]\n    fc12 = App.ActiveDocument.addObject(\"Part::Feature\", \"fc12\")\n    fc12.Shape = Part.Face(Part.makePolygon(a))\n    a = [p03p04p13, p04p14p03, p14p21p04, p21p13p14, p13p21p03, p03p04p13]\n    fc13 = App.ActiveDocument.addObject(\"Part::Feature\", \"fc13\")\n    fc13.Shape = Part.Face(Part.makePolygon(a))\n    a = [p04p00p14, p00p10p04, p10p22p00, p22p14p10, p14p22p04, p04p00p14]\n    fc14 = App.ActiveDocument.addObject(\"Part::Feature\", \"fc14\")\n    fc14.Shape = Part.Face(Part.makePolygon(a))\n    a = [p10p22p23, p23p33p10, p33p32p23, p32p33p22, p22p32p10, p10p22p23]\n    fc20 = App.ActiveDocument.addObject(\"Part::Feature\", \"fc20\")\n    fc20.Shape = Part.Face(Part.makePolygon(a))\n    a = [p11p23p24, p24p34p11, p34p33p24, p33p34p23, p23p33p11, p11p23p24]\n    fc21 = App.ActiveDocument.addObject(\"Part::Feature\", \"fc21\")\n    fc21.Shape = Part.Face(Part.makePolygon(a))\n    a = [p12p24p20, p20p30p12, p30p34p20, p34p30p24, p24p34p12, p12p24p20]\n    fc22 = App.ActiveDocument.addObject(\"Part::Feature\", \"fc22\")\n    fc22.Shape = Part.Face(Part.makePolygon(a))\n    a = [p13p20p21, p21p31p13, p31p30p21, p30p31p20, p20p30p13, p13p20p21]\n    fc23 = App.ActiveDocument.addObject(\"Part::Feature\", \"fc23\")\n    fc23.Shape = Part.Face(Part.makePolygon(a))\n    a = [p14p21p22, p22p32p14, p32p31p22, p31p32p21, p21p31p14, p14p21p22]\n    fc24 = App.ActiveDocument.addObject(\"Part::Feature\", \"fc24\")\n    fc24.Shape = Part.Face(Part.makePolygon(a))\n    a = [p30p31p34, p34p30p33, p33p34p32, p32p33p31, p31p32p30, p30p31p34]\n    fc30 = App.ActiveDocument.addObject(\"Part::Feature\", \"fc30\")\n    fc30.Shape = Part.Face(Part.makePolygon(a))\n\n    # edge centre facets\n    a = [p00p01, p01p00, p01p00p02, p00p01p04, p00p01]\n    ec0204 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec0204\")\n    ec0204.Shape = Part.Face(Part.makePolygon(a))\n    a = [p01p02, p02p01, p02p01p03, p01p02p00, p01p02]\n    ec0300 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec0300\")\n    ec0300.Shape = Part.Face(Part.makePolygon(a))\n    a = [p02p03, p03p02, p03p02p04, p02p01p03, p02p03]\n    ec0401 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec0401\")\n    ec0401.Shape = Part.Face(Part.makePolygon(a))\n    a = [p03p04, p04p03, p04p03p00, p03p04p02, p03p04]\n    ec0002 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec0002\")\n    ec0002.Shape = Part.Face(Part.makePolygon(a))\n    a = [p04p00, p00p04, p00p04p01, p04p00p03, p04p00]\n    ec0103 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec0103\")\n    ec0103.Shape = Part.Face(Part.makePolygon(a))\n    a = [p00p01, p01p00, p01p00p11, p00p01p10, p00p01]\n    ec1011 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec1011\")\n    ec1011.Shape = Part.Face(Part.makePolygon(a))\n    a = [p01p11, p11p01, p11p01p23, p01p11p00, p01p11]\n    ec0023 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec0023\")\n    ec0023.Shape = Part.Face(Part.makePolygon(a))\n    a = [p11p23, p23p11, p23p11p10, p11p23p01, p11p23]\n    ec0110 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec0110\")\n    ec0110.Shape = Part.Face(Part.makePolygon(a))\n    a = [p23p10, p10p23, p10p23p00, p23p10p11, p23p10]\n    ec1100 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec1100\")\n    ec1100.Shape = Part.Face(Part.makePolygon(a))\n    a = [p10p00, p00p10, p00p10p01, p10p00p23, p10p00]\n    ec2301 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec2301\")\n    ec2301.Shape = Part.Face(Part.makePolygon(a))\n    a = [p01p02, p02p01, p02p01p12, p01p02p11, p01p02]\n    ec1112 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec1112\")\n    ec1112.Shape = Part.Face(Part.makePolygon(a))\n    a = [p02p12, p12p02, p12p02p24, p02p12p01, p02p12]\n    ec0124 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec0124\")\n    ec0124.Shape = Part.Face(Part.makePolygon(a))\n    a = [p12p24, p24p12, p24p12p11, p12p24p02, p12p24]\n    ec0211 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec0211\")\n    ec0211.Shape = Part.Face(Part.makePolygon(a))\n    a = [p24p11, p11p24, p11p24p01, p24p11p12, p24p11]\n    ec1201 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec1201\")\n    ec1201.Shape = Part.Face(Part.makePolygon(a))\n    a = [p11p01, p01p11, p01p11p02, p11p01p24, p11p01]\n    ec2402 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec2402\")\n    ec2402.Shape = Part.Face(Part.makePolygon(a))\n    a = [p02p03, p03p02, p03p02p13, p02p03p12, p02p03]\n    ec1213 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec1213\")\n    ec1213.Shape = Part.Face(Part.makePolygon(a))\n    a = [p03p13, p13p03, p13p03p20, p03p13p02, p03p13]\n    ec0220 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec0220\")\n    ec0220.Shape = Part.Face(Part.makePolygon(a))\n    a = [p13p20, p20p13, p20p13p12, p13p20p03, p13p20]\n    ec0312 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec0312\")\n    ec0312.Shape = Part.Face(Part.makePolygon(a))\n    a = [p20p12, p12p20, p12p20p02, p20p12p13, p20p12]\n    ec1302 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec1302\")\n    ec1302.Shape = Part.Face(Part.makePolygon(a))\n    a = [p12p02, p02p12, p02p12p03, p12p02p20, p12p02]\n    ec2003 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec2003\")\n    ec2003.Shape = Part.Face(Part.makePolygon(a))\n    a = [p03p04, p04p03, p04p03p14, p03p04p13, p03p04]\n    ec1314 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec1314\")\n    ec1314.Shape = Part.Face(Part.makePolygon(a))\n    a = [p04p14, p14p04, p14p04p21, p04p14p03, p04p14]\n    ec0321 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec0321\")\n    ec0321.Shape = Part.Face(Part.makePolygon(a))\n    a = [p14p21, p21p14, p21p14p13, p14p21p04, p14p21]\n    ec0413 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec0413\")\n    ec0413.Shape = Part.Face(Part.makePolygon(a))\n    a = [p21p13, p13p21, p13p21p03, p21p13p14, p21p13]\n    ec1403 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec1403\")\n    ec1403.Shape = Part.Face(Part.makePolygon(a))\n    a = [p13p03, p03p13, p03p13p04, p13p03p21, p13p03]\n    ec2104 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec2104\")\n    ec2104.Shape = Part.Face(Part.makePolygon(a))\n    a = [p04p00, p00p04, p00p04p10, p04p00p14, p04p00]\n    ec1014 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec1014\")\n    ec1014.Shape = Part.Face(Part.makePolygon(a))\n    a = [p00p10, p10p00, p10p00p22, p00p10p04, p00p10]\n    ec2204 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec2204\")\n    ec2204.Shape = Part.Face(Part.makePolygon(a))\n    a = [p10p22, p22p10, p22p10p14, p10p22p00, p10p22]\n    ec1400 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec1400\")\n    ec1400.Shape = Part.Face(Part.makePolygon(a))\n    a = [p22p14, p14p22, p14p22p04, p22p14p10, p22p14]\n    ec0410 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec0410\")\n    ec0410.Shape = Part.Face(Part.makePolygon(a))\n    a = [p14p04, p04p14, p04p14p00, p14p04p22, p14p04]\n    ec0022 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec0022\")\n    ec0022.Shape = Part.Face(Part.makePolygon(a))\n    a = [p10p23, p23p10, p23p10p33, p10p23p22, p10p23]\n    ec3322 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec3322\")\n    ec3322.Shape = Part.Face(Part.makePolygon(a))\n    a = [p23p33, p33p23, p33p23p32, p23p33p10, p23p33]\n    ec3210 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec3210\")\n    ec3210.Shape = Part.Face(Part.makePolygon(a))\n    a = [p33p32, p32p33, p32p33p22, p33p32p23, p33p32]\n    ec2223 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec2223\")\n    ec2223.Shape = Part.Face(Part.makePolygon(a))\n    a = [p32p22, p22p32, p22p32p10, p32p22p33, p32p22]\n    ec1033 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec1033\")\n    ec1033.Shape = Part.Face(Part.makePolygon(a))\n    a = [p22p10, p10p22, p10p22p23, p22p10p32, p22p10]\n    ec2332 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec2332\")\n    ec2332.Shape = Part.Face(Part.makePolygon(a))\n    a = [p11p24, p24p11, p24p11p34, p11p24p23, p11p24]\n    ec3423 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec3423\")\n    ec3423.Shape = Part.Face(Part.makePolygon(a))\n    a = [p24p34, p34p24, p34p24p33, p24p34p11, p24p34]\n    ec3311 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec3311\")\n    ec3311.Shape = Part.Face(Part.makePolygon(a))\n    a = [p34p33, p33p34, p33p34p23, p34p33p24, p34p33]\n    ec2324 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec2324\")\n    ec2324.Shape = Part.Face(Part.makePolygon(a))\n    a = [p33p23, p23p33, p23p33p11, p33p23p34, p33p23]\n    ec1144 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec1144\")\n    ec1144.Shape = Part.Face(Part.makePolygon(a))\n    a = [p23p11, p11p23, p11p23p24, p23p11p33, p23p11]\n    ec2433 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec2433\")\n    ec2433.Shape = Part.Face(Part.makePolygon(a))\n    a = [p24p12, p12p24, p12p24p20, p24p12p34, p24p12]\n    ec2034 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec2034\")\n    ec2034.Shape = Part.Face(Part.makePolygon(a))\n    a = [p12p20, p20p12, p20p12p30, p12p20p24, p12p20]\n    ec3024 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec3024\")\n    ec3024.Shape = Part.Face(Part.makePolygon(a))\n    a = [p20p30, p30p20, p30p20p34, p20p30p12, p20p30]\n    ec3412 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec3412\")\n    ec3412.Shape = Part.Face(Part.makePolygon(a))\n    a = [p30p34, p34p30, p34p30p24, p30p34p20, p30p34]\n    ec2420 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec2420\")\n    ec2420.Shape = Part.Face(Part.makePolygon(a))\n    a = [p34p24, p24p34, p24p34p12, p34p24p30, p34p24]\n    ec1230 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec1230\")\n    ec1230.Shape = Part.Face(Part.makePolygon(a))\n    a = [p20p13, p13p20, p13p20p21, p20p13p30, p20p13]\n    ec2130 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec2130\")\n    ec2130.Shape = Part.Face(Part.makePolygon(a))\n    a = [p13p21, p21p13, p21p13p31, p13p21p20, p13p21]\n    ec3120 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec3120\")\n    ec3120.Shape = Part.Face(Part.makePolygon(a))\n    a = [p21p31, p31p21, p31p21p30, p21p31p13, p21p31]\n    ec3013 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec3013\")\n    ec3013.Shape = Part.Face(Part.makePolygon(a))\n    a = [p31p30, p30p31, p30p31p20, p31p30p21, p31p30]\n    ec2021 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec2021\")\n    ec2021.Shape = Part.Face(Part.makePolygon(a))\n    a = [p30p20, p20p30, p20p30p13, p30p20p31, p30p20]\n    ec1331 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec1331\")\n    ec1331.Shape = Part.Face(Part.makePolygon(a))\n    a = [p21p14, p14p21, p14p21p22, p21p14p31, p21p14]\n    ec2231 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec2231\")\n    ec2231.Shape = Part.Face(Part.makePolygon(a))\n    a = [p14p22, p22p14, p22p14p32, p14p22p21, p14p22]\n    ec3221 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec3221\")\n    ec3221.Shape = Part.Face(Part.makePolygon(a))\n    a = [p22p32, p32p22, p32p22p31, p22p32p14, p22p32]\n    ec3114 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec3114\")\n    ec3114.Shape = Part.Face(Part.makePolygon(a))\n    a = [p32p31, p31p32, p31p32p21, p32p31p22, p32p31]\n    ec2122 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec2122\")\n    ec2122.Shape = Part.Face(Part.makePolygon(a))\n    a = [p31p21, p21p31, p21p31p14, p31p21p32, p31p21]\n    ec1432 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec1432\")\n    ec1432.Shape = Part.Face(Part.makePolygon(a))\n    a = [p30p31, p31p30, p31p30p32, p30p31p34, p30p31]\n    ec3234 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec3234\")\n    ec3234.Shape = Part.Face(Part.makePolygon(a))\n    a = [p31p32, p32p31, p32p31p33, p31p32p30, p31p32]\n    ec3330 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec3330\")\n    ec3330.Shape = Part.Face(Part.makePolygon(a))\n    a = [p32p33, p33p32, p33p32p34, p32p33p31, p32p33]\n    ec3431 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec3431\")\n    ec3431.Shape = Part.Face(Part.makePolygon(a))\n    a = [p33p34, p34p33, p34p33p30, p33p34p32, p33p34]\n    ec3032 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec3032\")\n    ec3032.Shape = Part.Face(Part.makePolygon(a))\n    a = [p34p30, p30p34, p30p34p31, p34p30p33, p34p30]\n    ec3133 = App.ActiveDocument.addObject(\"Part::Feature\", \"ec3133\")\n    ec3133.Shape = Part.Face(Part.makePolygon(a))\n\n    # vertex facets\n    a = [p00, p00p01, p00p01p04, p00p04, p00]\n    v000104 = App.ActiveDocument.addObject(\"Part::Feature\", \"v000104\")\n    v000104.Shape = Part.Face(Part.makePolygon(a))\n    a = [p01, p01p02, p01p02p00, p01p00, p01]\n    v010200 = App.ActiveDocument.addObject(\"Part::Feature\", \"v010200\")\n    v010200.Shape = Part.Face(Part.makePolygon(a))\n    a = [p02, p02p03, p02p03p01, p02p01, p02]\n    v020301 = App.ActiveDocument.addObject(\"Part::Feature\", \"v020301\")\n    v020301.Shape = Part.Face(Part.makePolygon(a))\n    a = [p03, p03p04, p03p04p02, p03p02, p03]\n    v030402 = App.ActiveDocument.addObject(\"Part::Feature\", \"v030402\")\n    v030402.Shape = Part.Face(Part.makePolygon(a))\n    a = [p04, p04p00, p04p00p03, p04p03, p04]\n    v040003 = App.ActiveDocument.addObject(\"Part::Feature\", \"v040003\")\n    v040003.Shape = Part.Face(Part.makePolygon(a))\n    a = [p00, p00p01, p00p01p10, p00p10, p00]\n    v000110 = App.ActiveDocument.addObject(\"Part::Feature\", \"v000110\")\n    v000110.Shape = Part.Face(Part.makePolygon(a))\n    a = [p01, p01p11, p01p11p00, p01p00, p01]\n    v011100 = App.ActiveDocument.addObject(\"Part::Feature\", \"v011100\")\n    v011100.Shape = Part.Face(Part.makePolygon(a))\n    a = [p11, p11p23, p11p23p01, p11p01, p11]\n    v112301 = App.ActiveDocument.addObject(\"Part::Feature\", \"v112301\")\n    v112301.Shape = Part.Face(Part.makePolygon(a))\n    a = [p23, p23p10, p23p10p11, p23p11, p23]\n    v231011 = App.ActiveDocument.addObject(\"Part::Feature\", \"v231011\")\n    v231011.Shape = Part.Face(Part.makePolygon(a))\n    a = [p10, p10p00, p10p00p23, p10p23, p10]\n    v100023 = App.ActiveDocument.addObject(\"Part::Feature\", \"v100023\")\n    v100023.Shape = Part.Face(Part.makePolygon(a))\n    a = [p01, p01p02, p01p02p11, p01p11, p01]\n    v010211 = App.ActiveDocument.addObject(\"Part::Feature\", \"v010211\")\n    v010211.Shape = Part.Face(Part.makePolygon(a))\n    a = [p02, p02p12, p02p12p01, p02p01, p02]\n    v021201 = App.ActiveDocument.addObject(\"Part::Feature\", \"v021201\")\n    v021201.Shape = Part.Face(Part.makePolygon(a))\n    a = [p12, p12p24, p12p24p02, p12p02, p12]\n    v122402 = App.ActiveDocument.addObject(\"Part::Feature\", \"v122402\")\n    v122402.Shape = Part.Face(Part.makePolygon(a))\n    a = [p24, p24p11, p24p11p12, p24p12, p24]\n    v241112 = App.ActiveDocument.addObject(\"Part::Feature\", \"v241112\")\n    v241112.Shape = Part.Face(Part.makePolygon(a))\n    a = [p11, p11p01, p11p01p24, p11p24, p11]\n    v110124 = App.ActiveDocument.addObject(\"Part::Feature\", \"v110124\")\n    v110124.Shape = Part.Face(Part.makePolygon(a))\n    a = [p02, p02p03, p02p03p12, p02p12, p02]\n    v020312 = App.ActiveDocument.addObject(\"Part::Feature\", \"v020312\")\n    v020312.Shape = Part.Face(Part.makePolygon(a))\n    a = [p03, p03p13, p03p13p02, p03p02, p03]\n    v031302 = App.ActiveDocument.addObject(\"Part::Feature\", \"v031302\")\n    v031302.Shape = Part.Face(Part.makePolygon(a))\n    a = [p13, p13p20, p13p20p03, p13p03, p13]\n    v132003 = App.ActiveDocument.addObject(\"Part::Feature\", \"v132003\")\n    v132003.Shape = Part.Face(Part.makePolygon(a))\n    a = [p20, p20p12, p20p12p13, p20p13, p20]\n    v201213 = App.ActiveDocument.addObject(\"Part::Feature\", \"v201213\")\n    v201213.Shape = Part.Face(Part.makePolygon(a))\n    a = [p12, p12p02, p12p02p20, p12p20, p12]\n    v120220 = App.ActiveDocument.addObject(\"Part::Feature\", \"v120220\")\n    v120220.Shape = Part.Face(Part.makePolygon(a))\n    a = [p03, p03p04, p03p04p13, p03p13, p03]\n    v030413 = App.ActiveDocument.addObject(\"Part::Feature\", \"v030413\")\n    v030413.Shape = Part.Face(Part.makePolygon(a))\n    a = [p04, p04p14, p04p14p03, p04p03, p04]\n    v041403 = App.ActiveDocument.addObject(\"Part::Feature\", \"v041403\")\n    v041403.Shape = Part.Face(Part.makePolygon(a))\n    a = [p14, p14p21, p14p21p04, p14p04, p14]\n    v142104 = App.ActiveDocument.addObject(\"Part::Feature\", \"v142104\")\n    v142104.Shape = Part.Face(Part.makePolygon(a))\n    a = [p21, p21p13, p21p13p14, p21p14, p21]\n    v211314 = App.ActiveDocument.addObject(\"Part::Feature\", \"v211314\")\n    v211314.Shape = Part.Face(Part.makePolygon(a))\n    a = [p13, p13p03, p13p03p21, p13p21, p13]\n    v130321 = App.ActiveDocument.addObject(\"Part::Feature\", \"v130321\")\n    v130321.Shape = Part.Face(Part.makePolygon(a))\n    a = [p04, p04p00, p04p00p14, p04p14, p04]\n    v040014 = App.ActiveDocument.addObject(\"Part::Feature\", \"v040014\")\n    v040014.Shape = Part.Face(Part.makePolygon(a))\n    a = [p00, p00p10, p00p10p04, p00p04, p00]\n    v001004 = App.ActiveDocument.addObject(\"Part::Feature\", \"v001004\")\n    v001004.Shape = Part.Face(Part.makePolygon(a))\n    a = [p10, p10p22, p10p22p00, p10p00, p10]\n    v102200 = App.ActiveDocument.addObject(\"Part::Feature\", \"v102200\")\n    v102200.Shape = Part.Face(Part.makePolygon(a))\n    a = [p22, p22p14, p22p14p10, p22p10, p22]\n    v221410 = App.ActiveDocument.addObject(\"Part::Feature\", \"v221410\")\n    v221410.Shape = Part.Face(Part.makePolygon(a))\n    a = [p14, p14p04, p14p04p22, p14p22, p14]\n    v140422 = App.ActiveDocument.addObject(\"Part::Feature\", \"v140422\")\n    v140422.Shape = Part.Face(Part.makePolygon(a))\n    a = [p10, p10p22, p10p22p23, p10p23, p10]\n    v102223 = App.ActiveDocument.addObject(\"Part::Feature\", \"v102223\")\n    v102223.Shape = Part.Face(Part.makePolygon(a))\n    a = [p22, p22p32, p22p32p10, p22p10, p22]\n    v223210 = App.ActiveDocument.addObject(\"Part::Feature\", \"v223210\")\n    v223210.Shape = Part.Face(Part.makePolygon(a))\n    a = [p32, p32p33, p32p33p22, p32p22, p32]\n    v323322 = App.ActiveDocument.addObject(\"Part::Feature\", \"v323322\")\n    v323322.Shape = Part.Face(Part.makePolygon(a))\n    a = [p33, p33p23, p33p23p32, p33p32, p33]\n    v332332 = App.ActiveDocument.addObject(\"Part::Feature\", \"v332332\")\n    v332332.Shape = Part.Face(Part.makePolygon(a))\n    a = [p23, p23p10, p23p10p33, p23p33, p23]\n    v231033 = App.ActiveDocument.addObject(\"Part::Feature\", \"v231033\")\n    v231033.Shape = Part.Face(Part.makePolygon(a))\n    a = [p11, p11p23, p11p23p24, p11p24, p11]\n    v112324 = App.ActiveDocument.addObject(\"Part::Feature\", \"v112324\")\n    v112324.Shape = Part.Face(Part.makePolygon(a))\n    a = [p23, p23p33, p23p33p11, p23p11, p23]\n    v233311 = App.ActiveDocument.addObject(\"Part::Feature\", \"v233311\")\n    v233311.Shape = Part.Face(Part.makePolygon(a))\n    a = [p33, p33p34, p33p34p23, p33p23, p33]\n    v333423 = App.ActiveDocument.addObject(\"Part::Feature\", \"v333423\")\n    v333423.Shape = Part.Face(Part.makePolygon(a))\n    a = [p34, p34p24, p34p24p33, p34p33, p34]\n    v342433 = App.ActiveDocument.addObject(\"Part::Feature\", \"v342433\")\n    v342433.Shape = Part.Face(Part.makePolygon(a))\n    a = [p24, p24p11, p24p11p34, p24p34, p24]\n    v241134 = App.ActiveDocument.addObject(\"Part::Feature\", \"v241134\")\n    v241134.Shape = Part.Face(Part.makePolygon(a))\n    a = [p12, p12p24, p12p24p20, p12p20, p12]\n    v122420 = App.ActiveDocument.addObject(\"Part::Feature\", \"v122420\")\n    v122420.Shape = Part.Face(Part.makePolygon(a))\n    a = [p24, p24p34, p24p34p12, p24p12, p24]\n    v243412 = App.ActiveDocument.addObject(\"Part::Feature\", \"v243412\")\n    v243412.Shape = Part.Face(Part.makePolygon(a))\n    a = [p34, p34p30, p34p30p24, p34p24, p34]\n    v343024 = App.ActiveDocument.addObject(\"Part::Feature\", \"v343024\")\n    v343024.Shape = Part.Face(Part.makePolygon(a))\n    a = [p30, p30p20, p30p20p34, p30p34, p30]\n    v302034 = App.ActiveDocument.addObject(\"Part::Feature\", \"v302034\")\n    v302034.Shape = Part.Face(Part.makePolygon(a))\n    a = [p20, p20p12, p20p12p30, p20p30, p20]\n    v201230 = App.ActiveDocument.addObject(\"Part::Feature\", \"v201230\")\n    v201230.Shape = Part.Face(Part.makePolygon(a))\n    a = [p13, p13p20, p13p20p21, p13p21, p13]\n    v132021 = App.ActiveDocument.addObject(\"Part::Feature\", \"v132021\")\n    v132021.Shape = Part.Face(Part.makePolygon(a))\n    a = [p20, p20p30, p20p30p13, p20p13, p20]\n    v203013 = App.ActiveDocument.addObject(\"Part::Feature\", \"v203013\")\n    v203013.Shape = Part.Face(Part.makePolygon(a))\n    a = [p30, p30p31, p30p31p20, p30p20, p30]\n    v303120 = App.ActiveDocument.addObject(\"Part::Feature\", \"v303120\")\n    v303120.Shape = Part.Face(Part.makePolygon(a))\n    a = [p31, p31p21, p31p21p30, p31p30, p31]\n    v312130 = App.ActiveDocument.addObject(\"Part::Feature\", \"v312130\")\n    v312130.Shape = Part.Face(Part.makePolygon(a))\n    a = [p21, p21p13, p21p13p31, p21p31, p21]\n    v211331 = App.ActiveDocument.addObject(\"Part::Feature\", \"v211331\")\n    v211331.Shape = Part.Face(Part.makePolygon(a))\n    a = [p14, p14p21, p14p21p22, p14p22, p14]\n    v142122 = App.ActiveDocument.addObject(\"Part::Feature\", \"v142122\")\n    v142122.Shape = Part.Face(Part.makePolygon(a))\n    a = [p21, p21p31, p21p31p14, p21p14, p21]\n    v213114 = App.ActiveDocument.addObject(\"Part::Feature\", \"v213114\")\n    v213114.Shape = Part.Face(Part.makePolygon(a))\n    a = [p31, p31p32, p31p32p21, p31p21, p31]\n    v313221 = App.ActiveDocument.addObject(\"Part::Feature\", \"v313221\")\n    v313221.Shape = Part.Face(Part.makePolygon(a))\n    a = [p32, p32p22, p32p22p31, p32p31, p32]\n    v322231 = App.ActiveDocument.addObject(\"Part::Feature\", \"v322231\")\n    v322231.Shape = Part.Face(Part.makePolygon(a))\n    a = [p22, p22p14, p22p14p32, p22p32, p22]\n    v221432 = App.ActiveDocument.addObject(\"Part::Feature\", \"v221432\")\n    v221432.Shape = Part.Face(Part.makePolygon(a))\n    a = [p30, p30p31, p30p31p34, p30p34, p30]\n    v303134 = App.ActiveDocument.addObject(\"Part::Feature\", \"v303134\")\n    v303134.Shape = Part.Face(Part.makePolygon(a))\n    a = [p31, p31p32, p31p32p30, p31p30, p31]\n    v313230 = App.ActiveDocument.addObject(\"Part::Feature\", \"v313230\")\n    v313230.Shape = Part.Face(Part.makePolygon(a))\n    a = [p32, p32p33, p32p33p31, p32p31, p32]\n    v323331 = App.ActiveDocument.addObject(\"Part::Feature\", \"v323331\")\n    v323331.Shape = Part.Face(Part.makePolygon(a))\n    a = [p33, p33p34, p33p34p32, p33p32, p33]\n    v333432 = App.ActiveDocument.addObject(\"Part::Feature\", \"v333432\")\n    v333432.Shape = Part.Face(Part.makePolygon(a))\n    a = [p34, p34p30, p34p30p33, p34p33, p34]\n    v343033 = App.ActiveDocument.addObject(\"Part::Feature\", \"v343033\")\n    v343033.Shape = Part.Face(Part.makePolygon(a))\n\n    # internal facets (only partly visible when rotating)\n    # Two copies each because one rotates and one doesn't\n    a = [p00p01, p00p01p10, p00c, p00p01p04, p00p01]\n    i0001a = App.ActiveDocument.addObject(\"Part::Feature\", \"i0001a\")\n    i0001a.Shape = Part.Face(Part.makePolygon(a))\n    i0001a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i0001b = App.ActiveDocument.addObject(\"Part::Feature\", \"i0001b\")\n    i0001b.Shape = Part.Face(Part.makePolygon(a))\n    i0001b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p00p10, p00p10p01, p00c, p00p10p04, p00p10]\n    i0010a = App.ActiveDocument.addObject(\"Part::Feature\", \"i0010a\")\n    i0010a.Shape = Part.Face(Part.makePolygon(a))\n    i0010a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i0010b = App.ActiveDocument.addObject(\"Part::Feature\", \"i0010b\")\n    i0010b.Shape = Part.Face(Part.makePolygon(a))\n    i0010b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p00p04, p00p04p10, p00c, p00p04p01, p00p04]\n    i0004a = App.ActiveDocument.addObject(\"Part::Feature\", \"i0004a\")\n    i0004a.Shape = Part.Face(Part.makePolygon(a))\n    i0004a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i0004b = App.ActiveDocument.addObject(\"Part::Feature\", \"i0004b\")\n    i0004b.Shape = Part.Face(Part.makePolygon(a))\n    i0004b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p01p02, p01p02p11, p01c, p01p02p00, p01p02]\n    i0102a = App.ActiveDocument.addObject(\"Part::Feature\", \"i0102a\")\n    i0102a.Shape = Part.Face(Part.makePolygon(a))\n    i0102a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i0102b = App.ActiveDocument.addObject(\"Part::Feature\", \"i0102b\")\n    i0102b.Shape = Part.Face(Part.makePolygon(a))\n    i0102b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p01p11, p01p11p02, p01c, p01p11p00, p01p11]\n    i0111a = App.ActiveDocument.addObject(\"Part::Feature\", \"i0111a\")\n    i0111a.Shape = Part.Face(Part.makePolygon(a))\n    i0111a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i0111b = App.ActiveDocument.addObject(\"Part::Feature\", \"i0111b\")\n    i0111b.Shape = Part.Face(Part.makePolygon(a))\n    i0111b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p01p00, p01p00p11, p01c, p01p00p02, p01p00]\n    i0100a = App.ActiveDocument.addObject(\"Part::Feature\", \"i0100a\")\n    i0100a.Shape = Part.Face(Part.makePolygon(a))\n    i0100a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i0100b = App.ActiveDocument.addObject(\"Part::Feature\", \"i0100b\")\n    i0100b.Shape = Part.Face(Part.makePolygon(a))\n    i0100b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p02p03, p02p03p12, p02c,p02p03p01, p02p03]\n    i0203a = App.ActiveDocument.addObject(\"Part::Feature\", \"i0203a\")\n    i0203a.Shape = Part.Face(Part.makePolygon(a))\n    i0203a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i0203b = App.ActiveDocument.addObject(\"Part::Feature\", \"i0203b\")\n    i0203b.Shape = Part.Face(Part.makePolygon(a))\n    i0203b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p02p12, p02p12p03, p02c, p02p12p01, p02p12]\n    i0212a = App.ActiveDocument.addObject(\"Part::Feature\", \"i0212a\")\n    i0212a.Shape = Part.Face(Part.makePolygon(a))\n    i0212a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i0212b = App.ActiveDocument.addObject(\"Part::Feature\", \"i0212b\")\n    i0212b.Shape = Part.Face(Part.makePolygon(a))\n    i0212b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p02p01, p02p01p12, p02c, p02p01p03, p02p01]\n    i0201a = App.ActiveDocument.addObject(\"Part::Feature\", \"i0201a\")\n    i0201a.Shape = Part.Face(Part.makePolygon(a))\n    i0201a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i0201b = App.ActiveDocument.addObject(\"Part::Feature\", \"i0201b\")\n    i0201b.Shape = Part.Face(Part.makePolygon(a))\n    i0201b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p03p04, p03p04p13, p03c, p03p04p02, p03p04]\n    i0304a = App.ActiveDocument.addObject(\"Part::Feature\", \"i0304a\")\n    i0304a.Shape = Part.Face(Part.makePolygon(a))\n    i0304a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i0304b = App.ActiveDocument.addObject(\"Part::Feature\", \"i0304b\")\n    i0304b.Shape = Part.Face(Part.makePolygon(a))\n    i0304b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p03p13, p03p13p04, p03c, p03p13p02, p03p13]\n    i0313a = App.ActiveDocument.addObject(\"Part::Feature\", \"i0313a\")\n    i0313a.Shape = Part.Face(Part.makePolygon(a))\n    i0313a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i0313b = App.ActiveDocument.addObject(\"Part::Feature\", \"i0313b\")\n    i0313b.Shape = Part.Face(Part.makePolygon(a))\n    i0313b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p03p02, p03p02p13, p03c, p03p02p04, p03p02]\n    i0302a = App.ActiveDocument.addObject(\"Part::Feature\", \"i0302a\")\n    i0302a.Shape = Part.Face(Part.makePolygon(a))\n    i0302a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i0302b = App.ActiveDocument.addObject(\"Part::Feature\", \"i0302b\")\n    i0302b.Shape = Part.Face(Part.makePolygon(a))\n    i0302b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p04p00, p04p00p14, p04c, p04p00p03, p04p00]\n    i0400a = App.ActiveDocument.addObject(\"Part::Feature\", \"i0400a\")\n    i0400a.Shape = Part.Face(Part.makePolygon(a))\n    i0400a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i0400b = App.ActiveDocument.addObject(\"Part::Feature\", \"i0400b\")\n    i0400b.Shape = Part.Face(Part.makePolygon(a))\n    i0400b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p04p14, p04p14p00, p04c, p04p14p03, p04p14]\n    i0414a = App.ActiveDocument.addObject(\"Part::Feature\", \"i0414a\")\n    i0414a.Shape = Part.Face(Part.makePolygon(a))\n    i0414a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i0414b = App.ActiveDocument.addObject(\"Part::Feature\", \"i0414b\")\n    i0414b.Shape = Part.Face(Part.makePolygon(a))\n    i0414b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p04p03, p04p03p14, p04c, p04p03p00, p04p03]\n    i0403a = App.ActiveDocument.addObject(\"Part::Feature\", \"i0403a\")\n    i0403a.Shape = Part.Face(Part.makePolygon(a))\n    i0403a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i0403b = App.ActiveDocument.addObject(\"Part::Feature\", \"i0403b\")\n    i0403b.Shape = Part.Face(Part.makePolygon(a))\n    i0403b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p10p00, p10p00p23, p10c, p10p00p22, p10p00]\n    i1000a = App.ActiveDocument.addObject(\"Part::Feature\", \"i1000a\")\n    i1000a.Shape = Part.Face(Part.makePolygon(a))\n    i1000a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i1000b = App.ActiveDocument.addObject(\"Part::Feature\", \"i1000b\")\n    i1000b.Shape = Part.Face(Part.makePolygon(a))\n    i1000b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p10p22, p10p22p00, p10c, p10p22p23, p10p22]\n    i1022a = App.ActiveDocument.addObject(\"Part::Feature\", \"i1022a\")\n    i1022a.Shape = Part.Face(Part.makePolygon(a))\n    i1022a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i1022b = App.ActiveDocument.addObject(\"Part::Feature\", \"i1022b\")\n    i1022b.Shape = Part.Face(Part.makePolygon(a))\n    i1022b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p10p23, p10p23p00, p10c, p10p23p22, p10p23]\n    i1023a = App.ActiveDocument.addObject(\"Part::Feature\", \"i1023a\")\n    i1023a.Shape = Part.Face(Part.makePolygon(a))\n    i1023a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i1023b = App.ActiveDocument.addObject(\"Part::Feature\", \"i1023b\")\n    i1023b.Shape = Part.Face(Part.makePolygon(a))\n    i1023b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p11p01, p11p01p23, p11c, p11p01p24, p11p01]\n    i1101a = App.ActiveDocument.addObject(\"Part::Feature\", \"i1101a\")\n    i1101a.Shape = Part.Face(Part.makePolygon(a))\n    i1101a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i1101b = App.ActiveDocument.addObject(\"Part::Feature\", \"i1101b\")\n    i1101b.Shape = Part.Face(Part.makePolygon(a))\n    i1101b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p11p23, p11p23p01, p11c, p11p23p24, p11p23]\n    i1123a = App.ActiveDocument.addObject(\"Part::Feature\", \"i1123a\")\n    i1123a.Shape = Part.Face(Part.makePolygon(a))\n    i1123a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i1123b = App.ActiveDocument.addObject(\"Part::Feature\", \"i1123b\")\n    i1123b.Shape = Part.Face(Part.makePolygon(a))\n    i1123b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p11p24, p11p24p01, p11c, p11p24p23, p11p24]\n    i1124a = App.ActiveDocument.addObject(\"Part::Feature\", \"i1124a\")\n    i1124a.Shape = Part.Face(Part.makePolygon(a))\n    i1124a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i1124b = App.ActiveDocument.addObject(\"Part::Feature\", \"i1124b\")\n    i1124b.Shape = Part.Face(Part.makePolygon(a))\n    i1124b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p12p02, p12p02p24, p12c, p12p02p20, p12p02]\n    i1202a = App.ActiveDocument.addObject(\"Part::Feature\", \"i1202a\")\n    i1202a.Shape = Part.Face(Part.makePolygon(a))\n    i1202a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i1202b = App.ActiveDocument.addObject(\"Part::Feature\", \"i1202b\")\n    i1202b.Shape = Part.Face(Part.makePolygon(a))\n    i1202b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p12p20, p12p20p24, p12c, p12p20p02, p12p20]\n    i1220a = App.ActiveDocument.addObject(\"Part::Feature\", \"i1220a\")\n    i1220a.Shape = Part.Face(Part.makePolygon(a))\n    i1220a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i1220b = App.ActiveDocument.addObject(\"Part::Feature\", \"i1220b\")\n    i1220b.Shape = Part.Face(Part.makePolygon(a))\n    i1220b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p12p24, p12p24p20, p12c, p12p24p02, p12p24]\n    i1224a = App.ActiveDocument.addObject(\"Part::Feature\", \"i1224a\")\n    i1224a.Shape = Part.Face(Part.makePolygon(a))\n    i1224a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i1224b = App.ActiveDocument.addObject(\"Part::Feature\", \"i1224b\")\n    i1224b.Shape = Part.Face(Part.makePolygon(a))\n    i1224b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p13p03, p13p03p20, p13c, p13p03p21, p13p03]\n    i1303a = App.ActiveDocument.addObject(\"Part::Feature\", \"i1303a\")\n    i1303a.Shape = Part.Face(Part.makePolygon(a))\n    i1303a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i1303b = App.ActiveDocument.addObject(\"Part::Feature\", \"i1303b\")\n    i1303b.Shape = Part.Face(Part.makePolygon(a))\n    i1303b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p13p20, p13p20p21, p13c, p13p20p03, p13p20]\n    i1320a = App.ActiveDocument.addObject(\"Part::Feature\", \"i1320a\")\n    i1320a.Shape = Part.Face(Part.makePolygon(a))\n    i1320a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i1320b = App.ActiveDocument.addObject(\"Part::Feature\", \"i1320b\")\n    i1320b.Shape = Part.Face(Part.makePolygon(a))\n    i1320b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p13p21, p13p21p20, p13c, p13p21p03, p13p21]\n    i1321a = App.ActiveDocument.addObject(\"Part::Feature\", \"i1321a\")\n    i1321a.Shape = Part.Face(Part.makePolygon(a))\n    i1321a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i1321b = App.ActiveDocument.addObject(\"Part::Feature\", \"i1321b\")\n    i1321b.Shape = Part.Face(Part.makePolygon(a))\n    i1321b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p14p04, p14p04p21, p14c, p14p04p22, p14p04]\n    i1404a = App.ActiveDocument.addObject(\"Part::Feature\", \"i1404a\")\n    i1404a.Shape = Part.Face(Part.makePolygon(a))\n    i1404a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i1404b = App.ActiveDocument.addObject(\"Part::Feature\", \"i1404b\")\n    i1404b.Shape = Part.Face(Part.makePolygon(a))\n    i1404b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p14p21, p14p21p04, p14c, p14p21p22, p14p21]\n    i1421a = App.ActiveDocument.addObject(\"Part::Feature\", \"i1421a\")\n    i1421a.Shape = Part.Face(Part.makePolygon(a))\n    i1421a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i1421b = App.ActiveDocument.addObject(\"Part::Feature\", \"i1421b\")\n    i1421b.Shape = Part.Face(Part.makePolygon(a))\n    i1421b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p14p22, p14p22p21, p14c, p14p22p04, p14p22]\n    i1422a = App.ActiveDocument.addObject(\"Part::Feature\", \"i1422a\")\n    i1422a.Shape = Part.Face(Part.makePolygon(a))\n    i1422a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i1422b = App.ActiveDocument.addObject(\"Part::Feature\", \"i1422b\")\n    i1422b.Shape = Part.Face(Part.makePolygon(a))\n    i1422b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p20p12, p20p12p13, p20c, p20p12p30, p20p12]\n    i2012a = App.ActiveDocument.addObject(\"Part::Feature\", \"i2012a\")\n    i2012a.Shape = Part.Face(Part.makePolygon(a))\n    i2012a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i2012b = App.ActiveDocument.addObject(\"Part::Feature\", \"i2012b\")\n    i2012b.Shape = Part.Face(Part.makePolygon(a))\n    i2012b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p20p13, p20p13p30, p20c, p20p13p12, p20p13]\n    i2013a = App.ActiveDocument.addObject(\"Part::Feature\", \"i2013a\")\n    i2013a.Shape = Part.Face(Part.makePolygon(a))\n    i2013a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i2013b = App.ActiveDocument.addObject(\"Part::Feature\", \"i2013b\")\n    i2013b.Shape = Part.Face(Part.makePolygon(a))\n    i2013b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p20p30, p20p30p13, p20c, p20p30p12, p20p30]\n    i2030a = App.ActiveDocument.addObject(\"Part::Feature\", \"i2030a\")\n    i2030a.Shape = Part.Face(Part.makePolygon(a))\n    i2030a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i2030b = App.ActiveDocument.addObject(\"Part::Feature\", \"i2030b\")\n    i2030b.Shape = Part.Face(Part.makePolygon(a))\n    i2030b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p21p13, p21p13p14, p21c, p21p13p31, p21p13]\n    i2113a = App.ActiveDocument.addObject(\"Part::Feature\", \"i2113a\")\n    i2113a.Shape = Part.Face(Part.makePolygon(a))\n    i2113a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i2113b = App.ActiveDocument.addObject(\"Part::Feature\", \"i2113b\")\n    i2113b.Shape = Part.Face(Part.makePolygon(a))\n    i2113b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p21p14, p21p14p31, p21c, p21p14p13, p21p14]\n    i2114a = App.ActiveDocument.addObject(\"Part::Feature\", \"i2114a\")\n    i2114a.Shape = Part.Face(Part.makePolygon(a))\n    i2114a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i2114b = App.ActiveDocument.addObject(\"Part::Feature\", \"i2114b\")\n    i2114b.Shape = Part.Face(Part.makePolygon(a))\n    i2114b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p21p31, p21p31p13, p21c, p21p31p14, p21p31]\n    i2131a = App.ActiveDocument.addObject(\"Part::Feature\", \"i2131a\")\n    i2131a.Shape = Part.Face(Part.makePolygon(a))\n    i2131a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i2131b = App.ActiveDocument.addObject(\"Part::Feature\", \"i2131b\")\n    i2131b.Shape = Part.Face(Part.makePolygon(a))\n    i2131b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p22p10, p22p10p14, p22c, p22p10p32, p22p10]\n    i2210a = App.ActiveDocument.addObject(\"Part::Feature\", \"i2210a\")\n    i2210a.Shape = Part.Face(Part.makePolygon(a))\n    i2210a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i2210b = App.ActiveDocument.addObject(\"Part::Feature\", \"i2210b\")\n    i2210b.Shape = Part.Face(Part.makePolygon(a))\n    i2210b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p22p14, p22p14p32, p22c, p22p14p10, p22p14]\n    i2214a = App.ActiveDocument.addObject(\"Part::Feature\", \"i2214a\")\n    i2214a.Shape = Part.Face(Part.makePolygon(a))\n    i2214a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i2214b = App.ActiveDocument.addObject(\"Part::Feature\", \"i2214b\")\n    i2214b.Shape = Part.Face(Part.makePolygon(a))\n    i2214b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p22p32, p22p32p10, p22c, p22p32p14, p22p32]\n    i2232a = App.ActiveDocument.addObject(\"Part::Feature\", \"i2232a\")\n    i2232a.Shape = Part.Face(Part.makePolygon(a))\n    i2232a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i2232b = App.ActiveDocument.addObject(\"Part::Feature\", \"i2232b\")\n    i2232b.Shape = Part.Face(Part.makePolygon(a))\n    i2232b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p23p10, p23p10p11, p23c, p23p10p11, p23p10]\n    i2310a = App.ActiveDocument.addObject(\"Part::Feature\", \"i2310a\")\n    i2310a.Shape = Part.Face(Part.makePolygon(a))\n    i2310a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i2310b = App.ActiveDocument.addObject(\"Part::Feature\", \"i2310b\")\n    i2310b.Shape = Part.Face(Part.makePolygon(a))\n    i2310b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p23p11, p23p11p33, p23c, p23p11p10, p23p11]\n    i2311a = App.ActiveDocument.addObject(\"Part::Feature\", \"i2311a\")\n    i2311a.Shape = Part.Face(Part.makePolygon(a))\n    i2311a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i2311b = App.ActiveDocument.addObject(\"Part::Feature\", \"i2311b\")\n    i2311b.Shape = Part.Face(Part.makePolygon(a))\n    i2311b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p23p33, p23p33p10, p23c, p23p33p11, p23p33]\n    i2333a = App.ActiveDocument.addObject(\"Part::Feature\", \"i2333a\")\n    i2333a.Shape = Part.Face(Part.makePolygon(a))\n    i2333a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i2333b = App.ActiveDocument.addObject(\"Part::Feature\", \"i2333b\")\n    i2333b.Shape = Part.Face(Part.makePolygon(a))\n    i2333b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p24p11, p24p11p12, p24c, p24p11p34, p24p11]\n    i2411a = App.ActiveDocument.addObject(\"Part::Feature\", \"i2411a\")\n    i2411a.Shape = Part.Face(Part.makePolygon(a))\n    i2411a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i2411b = App.ActiveDocument.addObject(\"Part::Feature\", \"i2411b\")\n    i2411b.Shape = Part.Face(Part.makePolygon(a))\n    i2411b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p24p12, p24p12p34, p24c, p24p12p11, p24p12]\n    i2412a = App.ActiveDocument.addObject(\"Part::Feature\", \"i2412a\")\n    i2412a.Shape = Part.Face(Part.makePolygon(a))\n    i2412a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i2412b = App.ActiveDocument.addObject(\"Part::Feature\", \"i2412b\")\n    i2412b.Shape = Part.Face(Part.makePolygon(a))\n    i2412b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p24p34, p24p11p34, p24c, p24p12p34, p24p34]\n    i2434a = App.ActiveDocument.addObject(\"Part::Feature\", \"i2434a\")\n    i2434a.Shape = Part.Face(Part.makePolygon(a))\n    i2434a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i2434b = App.ActiveDocument.addObject(\"Part::Feature\", \"i2434b\")\n    i2434b.Shape = Part.Face(Part.makePolygon(a))\n    i2434b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p30p20, p30p20p31, p30c, p30p20p34, p30p20]\n    i3020a = App.ActiveDocument.addObject(\"Part::Feature\", \"i3020a\")\n    i3020a.Shape = Part.Face(Part.makePolygon(a))\n    i3020a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i3020b = App.ActiveDocument.addObject(\"Part::Feature\", \"i3020b\")\n    i3020b.Shape = Part.Face(Part.makePolygon(a))\n    i3020b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p30p31, p30p31p20, p30c, p30p31p34, p30p31]\n    i3031a = App.ActiveDocument.addObject(\"Part::Feature\", \"i3031a\")\n    i3031a.Shape = Part.Face(Part.makePolygon(a))\n    i3031a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i3031b = App.ActiveDocument.addObject(\"Part::Feature\", \"i3031b\")\n    i3031b.Shape = Part.Face(Part.makePolygon(a))\n    i3031b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p30p34, p30p34p31, p30c, p30p34p20, p30p34]\n    i3034a = App.ActiveDocument.addObject(\"Part::Feature\", \"i3034a\")\n    i3034a.Shape = Part.Face(Part.makePolygon(a))\n    i3034a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i3034b = App.ActiveDocument.addObject(\"Part::Feature\", \"i3034b\")\n    i3034b.Shape = Part.Face(Part.makePolygon(a))\n    i3034b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p31p21, p31p21p30, p31c, p31p21p32, p31p21]\n    i3121a = App.ActiveDocument.addObject(\"Part::Feature\", \"i3121a\")\n    i3121a.Shape = Part.Face(Part.makePolygon(a))\n    i3121a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i3121b = App.ActiveDocument.addObject(\"Part::Feature\", \"i3121b\")\n    i3121b.Shape = Part.Face(Part.makePolygon(a))\n    i3121b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p31p30, p31p30p21, p31c, p31p30p32, p31p30]\n    i3130a = App.ActiveDocument.addObject(\"Part::Feature\", \"i3130a\")\n    i3130a.Shape = Part.Face(Part.makePolygon(a))\n    i3130a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i3130b = App.ActiveDocument.addObject(\"Part::Feature\", \"i3130b\")\n    i3130b.Shape = Part.Face(Part.makePolygon(a))\n    i3130b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p31p32, p31p32p21, p31c, p31p32p30, p31p32]\n    i3132a = App.ActiveDocument.addObject(\"Part::Feature\", \"i3132a\")\n    i3132a.Shape = Part.Face(Part.makePolygon(a))\n    i3132a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i3132b = App.ActiveDocument.addObject(\"Part::Feature\", \"i3132b\")\n    i3132b.Shape = Part.Face(Part.makePolygon(a))\n    i3132b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p32p22, p32p22p33, p32c, p32p22p31, p32p22]\n    i3222a = App.ActiveDocument.addObject(\"Part::Feature\", \"i3122a\")\n    i3222a.Shape = Part.Face(Part.makePolygon(a))\n    i3222a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i3222b = App.ActiveDocument.addObject(\"Part::Feature\", \"i3222b\")\n    i3222b.Shape = Part.Face(Part.makePolygon(a))\n    i3222b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p32p31, p32p31p22, p32c, p32p31p33, p32p31]\n    i3231a = App.ActiveDocument.addObject(\"Part::Feature\", \"i3231a\")\n    i3231a.Shape = Part.Face(Part.makePolygon(a))\n    i3231a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i3231b = App.ActiveDocument.addObject(\"Part::Feature\", \"i3231b\")\n    i3231b.Shape = Part.Face(Part.makePolygon(a))\n    i3231b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p32p33, p32p33p22, p32c, p32p31p33, p32p33]\n    i3233a = App.ActiveDocument.addObject(\"Part::Feature\", \"i3233a\")\n    i3233a.Shape = Part.Face(Part.makePolygon(a))\n    i3233a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i3233b = App.ActiveDocument.addObject(\"Part::Feature\", \"i3233b\")\n    i3233b.Shape = Part.Face(Part.makePolygon(a))\n    i3233b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p33p23, p33p23p32, p33c, p33p23p34, p33p23]\n    i3323a = App.ActiveDocument.addObject(\"Part::Feature\", \"i3323a\")\n    i3323a.Shape = Part.Face(Part.makePolygon(a))\n    i3323a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i3323b = App.ActiveDocument.addObject(\"Part::Feature\", \"i3323b\")\n    i3323b.Shape = Part.Face(Part.makePolygon(a))\n    i3323b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p33p32, p33p32p23, p33c, p33p32p34, p33p32]\n    i3332a = App.ActiveDocument.addObject(\"Part::Feature\", \"i3332a\")\n    i3332a.Shape = Part.Face(Part.makePolygon(a))\n    i3332a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i3332b = App.ActiveDocument.addObject(\"Part::Feature\", \"i3332b\")\n    i3332b.Shape = Part.Face(Part.makePolygon(a))\n    i3332b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p33p34, p33p34p32, p33c, p33p34p32, p33p34]\n    i3334a = App.ActiveDocument.addObject(\"Part::Feature\", \"i3334a\")\n    i3334a.Shape = Part.Face(Part.makePolygon(a))\n    i3334a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i3334b = App.ActiveDocument.addObject(\"Part::Feature\", \"i3334b\")\n    i3334b.Shape = Part.Face(Part.makePolygon(a))\n    i3334b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p34p24, p34p24p30, p34c, p34p24p33, p34p24]\n    i3424a = App.ActiveDocument.addObject(\"Part::Feature\", \"i3424a\")\n    i3424a.Shape = Part.Face(Part.makePolygon(a))\n    i3424a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i3424b = App.ActiveDocument.addObject(\"Part::Feature\", \"i3424b\")\n    i3424b.Shape = Part.Face(Part.makePolygon(a))\n    i3424b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p34p30, p34p30p24, p34c, p34p30p33, p34p30]\n    i3430a = App.ActiveDocument.addObject(\"Part::Feature\", \"i3430a\")\n    i3430a.Shape = Part.Face(Part.makePolygon(a))\n    i3430a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i3430b = App.ActiveDocument.addObject(\"Part::Feature\", \"i3430b\")\n    i3430b.Shape = Part.Face(Part.makePolygon(a))\n    i3430b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p34p33, p34p33p24, p34c, p34p33p30, p34p33]\n    i3433a = App.ActiveDocument.addObject(\"Part::Feature\", \"i3433a\")\n    i3433a.Shape = Part.Face(Part.makePolygon(a))\n    i3433a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i3433b = App.ActiveDocument.addObject(\"Part::Feature\", \"i3433b\")\n    i3433b.Shape = Part.Face(Part.makePolygon(a))\n    i3433b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p00c, p01c, p01p00p02, p00p01p04, p00c]\n    i000001a = App.ActiveDocument.addObject(\"Part::Feature\", \"i000001a\")\n    i000001a.Shape = Part.Face(Part.makePolygon(a))\n    i000001a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i000001b = App.ActiveDocument.addObject(\"Part::Feature\", \"i000001b\")\n    i000001b.Shape = Part.Face(Part.makePolygon(a))\n    i000001b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p01c, p02c, p02p01p03, p01p00p02, p01c]\n    i000102a = App.ActiveDocument.addObject(\"Part::Feature\", \"i000102a\")\n    i000102a.Shape = Part.Face(Part.makePolygon(a))\n    i000102a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i000102b = App.ActiveDocument.addObject(\"Part::Feature\", \"i000102b\")\n    i000102b.Shape = Part.Face(Part.makePolygon(a))\n    i000102b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p02c, p03c, p03p04p02, p02p01p03, p02c]\n    i000203a = App.ActiveDocument.addObject(\"Part::Feature\", \"i000203a\")\n    i000203a.Shape = Part.Face(Part.makePolygon(a))\n    i000203a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i000203b = App.ActiveDocument.addObject(\"Part::Feature\", \"i000203b\")\n    i000203b.Shape = Part.Face(Part.makePolygon(a))\n    i000203b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p03c, p04c, p04p00p03, p03p02p04, p03c]\n    i000304a = App.ActiveDocument.addObject(\"Part::Feature\", \"i000304a\")\n    i000304a.Shape = Part.Face(Part.makePolygon(a))\n    i000304a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i000304b = App.ActiveDocument.addObject(\"Part::Feature\", \"i000304b\")\n    i000304b.Shape = Part.Face(Part.makePolygon(a))\n    i000304b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p04c, p00c, p00p01p04, p04p03p00, p04c]\n    i000400a = App.ActiveDocument.addObject(\"Part::Feature\", \"i000400a\")\n    i000400a.Shape = Part.Face(Part.makePolygon(a))\n    i000400a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i000400b = App.ActiveDocument.addObject(\"Part::Feature\", \"i000400b\")\n    i000400b.Shape = Part.Face(Part.makePolygon(a))\n    i000400b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p00c, p10c, p10p23p00, p00p01p10, p00c]\n    i100010a = App.ActiveDocument.addObject(\"Part::Feature\", \"i100010a\")\n    i100010a.Shape = Part.Face(Part.makePolygon(a))\n    i100010a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i100010b = App.ActiveDocument.addObject(\"Part::Feature\", \"i100010b\")\n    i100010b.Shape = Part.Face(Part.makePolygon(a))\n    i100010b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p10c, p23c, p23p10p11, p10p00p23, p10c]\n    i101023a = App.ActiveDocument.addObject(\"Part::Feature\", \"i101023a\")\n    i101023a.Shape = Part.Face(Part.makePolygon(a))\n    i101023a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i101023b = App.ActiveDocument.addObject(\"Part::Feature\", \"i101023b\")\n    i101023b.Shape = Part.Face(Part.makePolygon(a))\n    i101023b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p23c, p11c, p11p01p23, p23p10p11, p23c]\n    i102311a = App.ActiveDocument.addObject(\"Part::Feature\", \"i102311a\")\n    i102311a.Shape = Part.Face(Part.makePolygon(a))\n    i102311a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i102311b = App.ActiveDocument.addObject(\"Part::Feature\", \"i102311b\")\n    i102311b.Shape = Part.Face(Part.makePolygon(a))\n    i102311b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p11c, p01c, p01p00p11, p11p01p23, p11c]\n    i101101a = App.ActiveDocument.addObject(\"Part::Feature\", \"i101101a\")\n    i101101a.Shape = Part.Face(Part.makePolygon(a))\n    i101101a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i101101b = App.ActiveDocument.addObject(\"Part::Feature\", \"i101101b\")\n    i101101b.Shape = Part.Face(Part.makePolygon(a))\n    i101101b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p01c, p00c, p00p10p01, p01p00p11, p01c]\n    i100100a = App.ActiveDocument.addObject(\"Part::Feature\", \"i100100a\")\n    i100100a.Shape = Part.Face(Part.makePolygon(a))\n    i100100a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i100100b = App.ActiveDocument.addObject(\"Part::Feature\", \"i100100b\")\n    i100100b.Shape = Part.Face(Part.makePolygon(a))\n    i100100b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p01c, p11c, p11p01p24, p01p02p11, p01c]\n    i110111a = App.ActiveDocument.addObject(\"Part::Feature\", \"i110111a\")\n    i110111a.Shape = Part.Face(Part.makePolygon(a))\n    i110111a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i110111b = App.ActiveDocument.addObject(\"Part::Feature\", \"i110111b\")\n    i110111b.Shape = Part.Face(Part.makePolygon(a))\n    i110111b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p11c, p24c, p24p11p12, p11p01p24, p11c]\n    i111124a = App.ActiveDocument.addObject(\"Part::Feature\", \"i111124a\")\n    i111124a.Shape = Part.Face(Part.makePolygon(a))\n    i111124a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i111124b = App.ActiveDocument.addObject(\"Part::Feature\", \"i111124b\")\n    i111124b.Shape = Part.Face(Part.makePolygon(a))\n    i111124b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p24c, p12c, p12p02p24, p24p11p12, p24c]\n    i112412a = App.ActiveDocument.addObject(\"Part::Feature\", \"i112412a\")\n    i112412a.Shape = Part.Face(Part.makePolygon(a))\n    i112412a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i112412b = App.ActiveDocument.addObject(\"Part::Feature\", \"i112412b\")\n    i112412b.Shape = Part.Face(Part.makePolygon(a))\n    i112412b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p12c, p02c, p02p12p01, p12p02p24, p12c]\n    i111202a = App.ActiveDocument.addObject(\"Part::Feature\", \"i111202a\")\n    i111202a.Shape = Part.Face(Part.makePolygon(a))\n    i111202a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i111202b = App.ActiveDocument.addObject(\"Part::Feature\", \"i111202b\")\n    i111202b.Shape = Part.Face(Part.makePolygon(a))\n    i111202b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p02c, p01c, p01p02p11, p02p01p12, p02c]\n    i110201a = App.ActiveDocument.addObject(\"Part::Feature\", \"i110201a\")\n    i110201a.Shape = Part.Face(Part.makePolygon(a))\n    i110201a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i110201b = App.ActiveDocument.addObject(\"Part::Feature\", \"i110201b\")\n    i110201b.Shape = Part.Face(Part.makePolygon(a))\n    i110201b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p02c, p12c, p12p02p20, p02p03p12, p02c]\n    i120212a = App.ActiveDocument.addObject(\"Part::Feature\", \"i120212a\")\n    i120212a.Shape = Part.Face(Part.makePolygon(a))\n    i120212a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i120212b = App.ActiveDocument.addObject(\"Part::Feature\", \"i120212b\")\n    i120212b.Shape = Part.Face(Part.makePolygon(a))\n    i120212b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p12c, p20c, p20p12p13, p12p02p20, p12c]\n    i121220a = App.ActiveDocument.addObject(\"Part::Feature\", \"i121220a\")\n    i121220a.Shape = Part.Face(Part.makePolygon(a))\n    i121220a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i121220b = App.ActiveDocument.addObject(\"Part::Feature\", \"i121220b\")\n    i121220b.Shape = Part.Face(Part.makePolygon(a))\n    i121220b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p20c, p13c, p13p03p20, p20p12p13, p20c]\n    i122013a = App.ActiveDocument.addObject(\"Part::Feature\", \"i122013a\")\n    i122013a.Shape = Part.Face(Part.makePolygon(a))\n    i122013a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i122013b = App.ActiveDocument.addObject(\"Part::Feature\", \"i122013b\")\n    i122013b.Shape = Part.Face(Part.makePolygon(a))\n    i122013b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p13c, p03c, p03p02p13, p13p03p20, p13c]\n    i121303a = App.ActiveDocument.addObject(\"Part::Feature\", \"i121303a\")\n    i121303a.Shape = Part.Face(Part.makePolygon(a))\n    i121303a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i121303b = App.ActiveDocument.addObject(\"Part::Feature\", \"i121303b\")\n    i121303b.Shape = Part.Face(Part.makePolygon(a))\n    i121303b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p03c, p02c, p02p03p12, p03p02p13, p03c]\n    i120302a = App.ActiveDocument.addObject(\"Part::Feature\", \"i120302a\")\n    i120302a.Shape = Part.Face(Part.makePolygon(a))\n    i120302a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i120302b = App.ActiveDocument.addObject(\"Part::Feature\", \"i120302b\")\n    i120302b.Shape = Part.Face(Part.makePolygon(a))\n    i120302b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p03c, p13c, p13p03p21, p03p04p13, p03c]\n    i130313a = App.ActiveDocument.addObject(\"Part::Feature\", \"i130313a\")\n    i130313a.Shape = Part.Face(Part.makePolygon(a))\n    i130313a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i130313b = App.ActiveDocument.addObject(\"Part::Feature\", \"i130313b\")\n    i130313b.Shape = Part.Face(Part.makePolygon(a))\n    i130313b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p13c, p21c, p21p13p14, p13p03p21, p13c]\n    i131321a = App.ActiveDocument.addObject(\"Part::Feature\", \"i131321a\")\n    i131321a.Shape = Part.Face(Part.makePolygon(a))\n    i131321a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i131321b = App.ActiveDocument.addObject(\"Part::Feature\", \"i131321b\")\n    i131321b.Shape = Part.Face(Part.makePolygon(a))\n    i131321b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p21c, p14c, p14p04p21, p21p13p14, p21c]\n    i132114a = App.ActiveDocument.addObject(\"Part::Feature\", \"i132114a\")\n    i132114a.Shape = Part.Face(Part.makePolygon(a))\n    i132114a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i132114b = App.ActiveDocument.addObject(\"Part::Feature\", \"i132114b\")\n    i132114b.Shape = Part.Face(Part.makePolygon(a))\n    i132114b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p14c, p04c, p04p03p14, p14p04p21, p14c]\n    i131404a = App.ActiveDocument.addObject(\"Part::Feature\", \"i131404a\")\n    i131404a.Shape = Part.Face(Part.makePolygon(a))\n    i131404a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i131404b = App.ActiveDocument.addObject(\"Part::Feature\", \"i131404b\")\n    i131404b.Shape = Part.Face(Part.makePolygon(a))\n    i131404b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p04c, p03c, p03p04p13, p04p03p14, p04c]\n    i130403a = App.ActiveDocument.addObject(\"Part::Feature\", \"i130403a\")\n    i130403a.Shape = Part.Face(Part.makePolygon(a))\n    i130403a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i130403b = App.ActiveDocument.addObject(\"Part::Feature\", \"i130403b\")\n    i130403b.Shape = Part.Face(Part.makePolygon(a))\n    i130403b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p04c, p14c, p14p04p22, p04p00p14, p04c]\n    i140414a = App.ActiveDocument.addObject(\"Part::Feature\", \"i140414a\")\n    i140414a.Shape = Part.Face(Part.makePolygon(a))\n    i140414a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i140414b = App.ActiveDocument.addObject(\"Part::Feature\", \"i140414b\")\n    i140414b.Shape = Part.Face(Part.makePolygon(a))\n    i140414b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p14c, p22c, p22p10p14, p14p04p22, p14c]\n    i141422a = App.ActiveDocument.addObject(\"Part::Feature\", \"i141422a\")\n    i141422a.Shape = Part.Face(Part.makePolygon(a))\n    i141422a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i141422b = App.ActiveDocument.addObject(\"Part::Feature\", \"i141422b\")\n    i141422b.Shape = Part.Face(Part.makePolygon(a))\n    i141422b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p22c, p10c, p10p00p22, p22p10p14, p22c]\n    i142210a = App.ActiveDocument.addObject(\"Part::Feature\", \"i142210a\")\n    i142210a.Shape = Part.Face(Part.makePolygon(a))\n    i142210a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i142210b = App.ActiveDocument.addObject(\"Part::Feature\", \"i142210b\")\n    i142210b.Shape = Part.Face(Part.makePolygon(a))\n    i142210b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p10c, p00c, p00p04p10, p10p00p22, p10c]\n    i141000a = App.ActiveDocument.addObject(\"Part::Feature\", \"i141000a\")\n    i141000a.Shape = Part.Face(Part.makePolygon(a))\n    i141000a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i141000b = App.ActiveDocument.addObject(\"Part::Feature\", \"i141000b\")\n    i141000b.Shape = Part.Face(Part.makePolygon(a))\n    i141000b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p00c, p04c, p04p00p14, p00p04p10, p00c]\n    i140004a = App.ActiveDocument.addObject(\"Part::Feature\", \"i140004a\")\n    i140004a.Shape = Part.Face(Part.makePolygon(a))\n    i140004a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i140004b = App.ActiveDocument.addObject(\"Part::Feature\", \"i140004b\")\n    i140004b.Shape = Part.Face(Part.makePolygon(a))\n    i140004b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p10c, p22c, p22p10p32, p10p22p23, p10c]\n    i201022a = App.ActiveDocument.addObject(\"Part::Feature\", \"i201022a\")\n    i201022a.Shape = Part.Face(Part.makePolygon(a))\n    i201022a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i201022b = App.ActiveDocument.addObject(\"Part::Feature\", \"i201022b\")\n    i201022b.Shape = Part.Face(Part.makePolygon(a))\n    i201022b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p22c, p32c, p32p22p33, p22p10p32, p22c]\n    i202232a = App.ActiveDocument.addObject(\"Part::Feature\", \"i202232a\")\n    i202232a.Shape = Part.Face(Part.makePolygon(a))\n    i202232a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i202232b = App.ActiveDocument.addObject(\"Part::Feature\", \"i202232b\")\n    i202232b.Shape = Part.Face(Part.makePolygon(a))\n    i202232b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p32c, p33c, p33p23p32, p32p22p33, p32c]\n    i203233a = App.ActiveDocument.addObject(\"Part::Feature\", \"i203233a\")\n    i203233a.Shape = Part.Face(Part.makePolygon(a))\n    i203233a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i203233b = App.ActiveDocument.addObject(\"Part::Feature\", \"i203233b\")\n    i203233b.Shape = Part.Face(Part.makePolygon(a))\n    i203233b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p33c, p23c, p23p10p33, p33p23p32, p33c]\n    i203323a = App.ActiveDocument.addObject(\"Part::Feature\", \"i203323a\")\n    i203323a.Shape = Part.Face(Part.makePolygon(a))\n    i203323a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i203323b = App.ActiveDocument.addObject(\"Part::Feature\", \"i203323b\")\n    i203323b.Shape = Part.Face(Part.makePolygon(a))\n    i203323b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p23c, p10c, p10p22p23, p23p10p33, p23c]\n    i202310a = App.ActiveDocument.addObject(\"Part::Feature\", \"i202310a\")\n    i202310a.Shape = Part.Face(Part.makePolygon(a))\n    i202310a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i202310b = App.ActiveDocument.addObject(\"Part::Feature\", \"i202310b\")\n    i202310b.Shape = Part.Face(Part.makePolygon(a))\n    i202310b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p11c, p23c, p23p11p33, p11p23p24, p11c]\n    i211123a = App.ActiveDocument.addObject(\"Part::Feature\", \"i211123a\")\n    i211123a.Shape = Part.Face(Part.makePolygon(a))\n    i211123a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i211123b = App.ActiveDocument.addObject(\"Part::Feature\", \"i211123b\")\n    i211123b.Shape = Part.Face(Part.makePolygon(a))\n    i211123b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p23c, p33c, p33p23p34, p23p11p33, p23c]\n    i212333a = App.ActiveDocument.addObject(\"Part::Feature\", \"i212333a\")\n    i212333a.Shape = Part.Face(Part.makePolygon(a))\n    i212333a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i212333b = App.ActiveDocument.addObject(\"Part::Feature\", \"i212333b\")\n    i212333b.Shape = Part.Face(Part.makePolygon(a))\n    i212333b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p33c, p34c, p34p24p33, p33p23p34, p33c]\n    i213334a = App.ActiveDocument.addObject(\"Part::Feature\", \"i213334a\")\n    i213334a.Shape = Part.Face(Part.makePolygon(a))\n    i213334a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i213334b = App.ActiveDocument.addObject(\"Part::Feature\", \"i213334b\")\n    i213334b.Shape = Part.Face(Part.makePolygon(a))\n    i213334b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p34c, p24c, p24p11p34, p34p24p33, p34c]\n    i213424a = App.ActiveDocument.addObject(\"Part::Feature\", \"i213424a\")\n    i213424a.Shape = Part.Face(Part.makePolygon(a))\n    i213424a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i213424b = App.ActiveDocument.addObject(\"Part::Feature\", \"i213424b\")\n    i213424b.Shape = Part.Face(Part.makePolygon(a))\n    i213424b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p24c, p11c, p11p23p24, p24p11p34, p24c]\n    i212411a = App.ActiveDocument.addObject(\"Part::Feature\", \"i212411a\")\n    i212411a.Shape = Part.Face(Part.makePolygon(a))\n    i212411a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i212411b = App.ActiveDocument.addObject(\"Part::Feature\", \"i212411b\")\n    i212411b.Shape = Part.Face(Part.makePolygon(a))\n    i212411b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p12c, p24c, p24p12p34, p12p20p24, p12c]\n    i221224a = App.ActiveDocument.addObject(\"Part::Feature\", \"i221224a\")\n    i221224a.Shape = Part.Face(Part.makePolygon(a))\n    i221224a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i221224b = App.ActiveDocument.addObject(\"Part::Feature\", \"i221224b\")\n    i221224b.Shape = Part.Face(Part.makePolygon(a))\n    i221224b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p24c, p34c, p34p24p30, p24p12p34, p24c]\n    i222434a = App.ActiveDocument.addObject(\"Part::Feature\", \"i222434a\")\n    i222434a.Shape = Part.Face(Part.makePolygon(a))\n    i222434a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i222434b = App.ActiveDocument.addObject(\"Part::Feature\", \"i222434b\")\n    i222434b.Shape = Part.Face(Part.makePolygon(a))\n    i222434b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p34c, p30c, p30p20p34, p34p24p30, p34c]\n    i223430a = App.ActiveDocument.addObject(\"Part::Feature\", \"i223430a\")\n    i223430a.Shape = Part.Face(Part.makePolygon(a))\n    i223430a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i223430b = App.ActiveDocument.addObject(\"Part::Feature\", \"i223430b\")\n    i223430b.Shape = Part.Face(Part.makePolygon(a))\n    i223430b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p30c, p20c, p20p12p30, p30p20p34, p30c]\n    i223020a = App.ActiveDocument.addObject(\"Part::Feature\", \"i223020a\")\n    i223020a.Shape = Part.Face(Part.makePolygon(a))\n    i223020a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i223020b = App.ActiveDocument.addObject(\"Part::Feature\", \"i223020b\")\n    i223020b.Shape = Part.Face(Part.makePolygon(a))\n    i223020b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p20c, p12c, p12p20p24, p20p12p30, p20c]\n    i222012a = App.ActiveDocument.addObject(\"Part::Feature\", \"i222012a\")\n    i222012a.Shape = Part.Face(Part.makePolygon(a))\n    i222012a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i222012b = App.ActiveDocument.addObject(\"Part::Feature\", \"i222012b\")\n    i222012b.Shape = Part.Face(Part.makePolygon(a))\n    i222012b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p13c, p20c, p20p13p30, p13p20p21, p13c]\n    i231320a = App.ActiveDocument.addObject(\"Part::Feature\", \"i231320a\")\n    i231320a.Shape = Part.Face(Part.makePolygon(a))\n    i231320a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i231320b = App.ActiveDocument.addObject(\"Part::Feature\", \"i231320b\")\n    i231320b.Shape = Part.Face(Part.makePolygon(a))\n    i231320b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p20c, p30c, p30p20p31, p20p13p30, p20c]\n    i232030a = App.ActiveDocument.addObject(\"Part::Feature\", \"i232030a\")\n    i232030a.Shape = Part.Face(Part.makePolygon(a))\n    i232030a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i232030b = App.ActiveDocument.addObject(\"Part::Feature\", \"i232030b\")\n    i232030b.Shape = Part.Face(Part.makePolygon(a))\n    i232030b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p30c, p31c, p31p21p30, p30p20p31, p30c]\n    i233031a = App.ActiveDocument.addObject(\"Part::Feature\", \"i233031a\")\n    i233031a.Shape = Part.Face(Part.makePolygon(a))\n    i233031a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i233031b = App.ActiveDocument.addObject(\"Part::Feature\", \"i233031b\")\n    i233031b.Shape = Part.Face(Part.makePolygon(a))\n    i233031b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p31c, p21c, p21p13p31, p31p21p30, p31c]\n    i233121a = App.ActiveDocument.addObject(\"Part::Feature\", \"i233121a\")\n    i233121a.Shape = Part.Face(Part.makePolygon(a))\n    i233121a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i233121b = App.ActiveDocument.addObject(\"Part::Feature\", \"i233121b\")\n    i233121b.Shape = Part.Face(Part.makePolygon(a))\n    i233121b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p21c, p13c, p13p20p21, p21p13p31, p21c]\n    i232113a = App.ActiveDocument.addObject(\"Part::Feature\", \"i232113a\")\n    i232113a.Shape = Part.Face(Part.makePolygon(a))\n    i232113a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i232113b = App.ActiveDocument.addObject(\"Part::Feature\", \"i232113b\")\n    i232113b.Shape = Part.Face(Part.makePolygon(a))\n    i232113b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p14c, p21c, p21p14p31, p14p21p22, p14c]\n    i241421a = App.ActiveDocument.addObject(\"Part::Feature\", \"i241421a\")\n    i241421a.Shape = Part.Face(Part.makePolygon(a))\n    i241421a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i241421b = App.ActiveDocument.addObject(\"Part::Feature\", \"i241421b\")\n    i241421b.Shape = Part.Face(Part.makePolygon(a))\n    i241421b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p21c, p31c, p31p21p32, p21p14p31, p21c]\n    i242131a = App.ActiveDocument.addObject(\"Part::Feature\", \"i242131a\")\n    i242131a.Shape = Part.Face(Part.makePolygon(a))\n    i242131a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i242131b = App.ActiveDocument.addObject(\"Part::Feature\", \"i242131b\")\n    i242131b.Shape = Part.Face(Part.makePolygon(a))\n    i242131b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p31c, p32c, p32p22p31, p31p21p32, p31c]\n    i243132a = App.ActiveDocument.addObject(\"Part::Feature\", \"i243132a\")\n    i243132a.Shape = Part.Face(Part.makePolygon(a))\n    i243132a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i243132b = App.ActiveDocument.addObject(\"Part::Feature\", \"i243132b\")\n    i243132b.Shape = Part.Face(Part.makePolygon(a))\n    i243132b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p32c, p22c, p22p14p32, p32p22p31, p32c]\n    i243222a = App.ActiveDocument.addObject(\"Part::Feature\", \"i243222a\")\n    i243222a.Shape = Part.Face(Part.makePolygon(a))\n    i243222a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i243222b = App.ActiveDocument.addObject(\"Part::Feature\", \"i243222b\")\n    i243222b.Shape = Part.Face(Part.makePolygon(a))\n    i243222b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p22c, p14c, p14p21p22, p22p14p32, p22c]\n    i242214a = App.ActiveDocument.addObject(\"Part::Feature\", \"i242214a\")\n    i242214a.Shape = Part.Face(Part.makePolygon(a))\n    i242214a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i242214b = App.ActiveDocument.addObject(\"Part::Feature\", \"i242214b\")\n    i242214b.Shape = Part.Face(Part.makePolygon(a))\n    i242214b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p30c, p34c, p34p30p33, p30p31p34, p30c]\n    i303034a = App.ActiveDocument.addObject(\"Part::Feature\", \"i303034a\")\n    i303034a.Shape = Part.Face(Part.makePolygon(a))\n    i303034a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i303034b = App.ActiveDocument.addObject(\"Part::Feature\", \"i303034b\")\n    i303034b.Shape = Part.Face(Part.makePolygon(a))\n    i303034b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p34c, p33c, p33p32p34, p34p30p33, p34c]\n    i303433a = App.ActiveDocument.addObject(\"Part::Feature\", \"i303433a\")\n    i303433a.Shape = Part.Face(Part.makePolygon(a))\n    i303433a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i303433b = App.ActiveDocument.addObject(\"Part::Feature\", \"i303433b\")\n    i303433b.Shape = Part.Face(Part.makePolygon(a))\n    i303433b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p33c, p32c, p32p31p33, p33p32p34, p33c]\n    i303332a = App.ActiveDocument.addObject(\"Part::Feature\", \"i303332a\")\n    i303332a.Shape = Part.Face(Part.makePolygon(a))\n    i303332a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i303332b = App.ActiveDocument.addObject(\"Part::Feature\", \"i303332b\")\n    i303332b.Shape = Part.Face(Part.makePolygon(a))\n    i303332b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p32c, p31c, p31p30p32, p32p31p33, p32c]\n    i303231a = App.ActiveDocument.addObject(\"Part::Feature\", \"i303231a\")\n    i303231a.Shape = Part.Face(Part.makePolygon(a))\n    i303231a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i303231b = App.ActiveDocument.addObject(\"Part::Feature\", \"i303231b\")\n    i303231b.Shape = Part.Face(Part.makePolygon(a))\n    i303231b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    a = [p31c, p30c, p30p31p34, p31p30p32, p31c]\n    i303130a = App.ActiveDocument.addObject(\"Part::Feature\", \"i303130a\")\n    i303130a.Shape = Part.Face(Part.makePolygon(a))\n    i303130a.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n    i303130b = App.ActiveDocument.addObject(\"Part::Feature\", \"i303130b\")\n    i303130b.Shape = Part.Face(Part.makePolygon(a))\n    i303130b.ViewObject.DiffuseColor = [(0.0, 0.0, 0.0)]\n\n    face00 = face(p00.add(p01).add(p02).add(p03).add(p04))\n    face00.middle = fc00\n    face00.name = \"face00\"\n    face00.vertex[0] = [v000104, v001004, v000110]\n    face00.vertex[1] = [v010200, v011100, v010211]\n    face00.vertex[2] = [v020301, v021201, v020312]\n    face00.vertex[3] = [v030402, v031302, v030413]\n    face00.vertex[4] = [v040003, v041403, v040014]\n    face00.edge[0] = [ec0204, ec1011]\n    face00.edge[1] = [ec0300, ec1112]\n    face00.edge[2] = [ec0401, ec1213]\n    face00.edge[3] = [ec0002, ec1314]\n    face00.edge[4] = [ec0103, ec1014]\n    face00.invis = [\n        i0004b, i0004a, i0010a, i0001a, i0001b, i000001a, i000001b, i100100b,\n        i0100b, i0100a, i0111a, i0102a, i0102b, i000102a, i000102b, i110201b,\n        i0201b, i0201a, i0212a, i0203a, i0203b, i000203a, i000203b, i120302b,\n        i0302b, i0302a, i0313a, i0304a, i0304b, i000304a, i000304b, i130403b,\n        i0403b, i0403a, i0414a, i0400a, i0400b, i000400a, i000400b, i140004b]\n    face00.allvis = [\n        [v100023, ec2301, ec1100, fc10, v231011, ec0110, ec0023, v112301],\n        [v110124, ec2402, ec1201, fc11, v241112, ec0211, ec0124, v122402],\n        [v120220, ec2003, ec1302, fc12, v201213, ec0312, ec0220, v132003],\n        [v130321, ec2104, ec1403, fc13, v211314, ec0413, ec0321, v142104],\n        [v140422, ec0022, ec0410, fc14, v221410, ec1400, ec2204, v102200]]\n\n    face10 = face(p00.add(p01).add(p11).add(p23).add(p10))\n    face10.middle = fc10\n    face10.name = \"face10\"\n    face10.vertex[0] = [v000110, v000104, v001004]\n    face10.vertex[1] = [v100023, v102200, v102223]\n    face10.vertex[2] = [v231011, v231033, v233311]\n    face10.vertex[3] = [v112301, v112324, v110124]\n    face10.vertex[4] = [v011100, v010211, v010200]\n    face10.edge[0] = [ec1011, ec0204]\n    face10.edge[1] = [ec2301, ec2204]\n    face10.edge[2] = [ec1100, ec3322]\n    face10.edge[3] = [ec0110, ec2433]\n    face10.edge[4] = [ec0023, ec2402]\n    face10.invis = [\n        i0001b, i0001a, i0004a, i0010a, i0010b, i100010a, i100010b, i141000b,\n        i1000b, i1000a, i1022a, i1023a, i1023b, i101023a, i101023b, i202310b,\n        i2310b, i2310a, i2333a, i2311a, i2311b, i102311a, i102311b, i211123b,\n        i1123b, i1123a, i1124a, i1101a, i1101b, i101101a, i101101b, i110111b,\n        i0111b, i0111a, i0102a, i0100a, i0100b, i100100a, i100100b, i000001b]\n    face10.allvis = [\n        [v040014, ec1014, ec0022, fc14, v140422, ec0410, ec1400, v221410],\n        [v223210, ec2332, ec1033, fc20, v323322, ec2223, ec3210, v332332],\n        [v333423, ec1144, ec2324, fc21, v342433, ec3311, ec3423, v241134],\n        [v241112, ec1201, ec0211, fc11, v122402, ec0124, ec1112, v021201],\n        [v020301, ec0300, ec0401, fc00, v030402, ec0002, ec0103, v040003]]\n\n    face11 = face(p01.add(p11).add(p24).add(p12).add(p02))\n    face11.middle = fc11\n    face11.name = \"face11\"\n    face11.vertex[0] = [v010211, v010200, v011100]\n    face11.vertex[1] = [v110124, v112301, v112324]\n    face11.vertex[2] = [v241112, v241134, v243412]\n    face11.vertex[3] = [v122402, v122420, v120220]\n    face11.vertex[4] = [v021201, v020312, v020301]\n    face11.edge[0] = [ec2402, ec0023]\n    face11.edge[1] = [ec1201, ec3423]\n    face11.edge[2] = [ec0211, ec2034]\n    face11.edge[3] = [ec0124, ec2003]\n    face11.edge[4] = [ec1112, ec0300]\n    face11.invis = [\n        i0102b, i0102a, i0100a, i0111a, i0111b, i110111a, i110111b, i101101b,\n        i1101b, i1101a, i1123a, i1124a, i1124b, i111124a, i111124b, i212411b,\n        i2411b, i2411a, i2434a, i2412a, i2412b, i112412a, i112412b, i221224b,\n        i1224b, i1224a, i1220a, i1202a, i1202b, i111202a, i111202b, i120212b,\n        i0212b, i0212a, i0203a, i0201a, i0201b, i110201a, i110201b, i000102b]\n    face11.allvis = [\n        [v000110, ec1011, ec2301, fc10, v100023, ec1100, ec0110, v231011],\n        [v233311, ec2433, ec1144, fc21, v333423, ec2324, ec3311, v342433],\n        [v343024, ec1230, ec2420, fc22, v302034, ec3412, ec3024, v201230],\n        [v201213, ec1302, ec0312, fc12, v132003, ec0220, ec1213, v031302],\n        [v030402, ec0401, ec0002, fc00, v040003, ec0103, ec0204, v000104]]\n\n    face12 = face(p02.add(p12).add(p20).add(p13).add(p03))\n    face12.middle = fc12\n    face12.name = \"face12\"\n    face12.vertex[0] = [v020312, v020301, v021201]\n    face12.vertex[1] = [v120220, v122402, v122420]\n    face12.vertex[2] = [v201213, v201230, v203013]\n    face12.vertex[3] = [v132003, v132021, v130321]\n    face12.vertex[4] = [v031302, v030413, v030402]\n    face12.edge[0] = [ec2003, ec0124]\n    face12.edge[1] = [ec1302, ec3024]\n    face12.edge[2] = [ec0312, ec2130]\n    face12.edge[3] = [ec0220, ec2104]\n    face12.edge[4] = [ec1213, ec0401]\n    face12.invis = [\n        i0203b, i0203a, i0201a, i0212a, i0212b, i120212a, i120212b, i111202b,\n        i1202b, i1202a, i1224a, i1220a, i1220b, i121220a, i121220b, i222012b,\n        i2012b, i2012a, i2030a, i2013a, i2013b, i122013a, i122013b, i231320b,\n        i1320b, i1320a, i1321a, i1303a, i1303b, i121303a, i121303b, i130313b,\n        i0313b, i0313a, i0304a, i0302a, i0302b, i120302a, i120302b, i000203b]\n    face12.allvis = [\n        [v010211, ec1112, ec2402, fc11, v110124, ec1201, ec0211, v241112],\n        [v243412, ec2034, ec1230, fc22, v343024, ec2420, ec3412, v302034],\n        [v303120, ec1331, ec2021, fc23, v312130, ec3013, ec3120, v211331],\n        [v211314, ec1403, ec0413, fc13, v142104, ec0321, ec1314, v041403],\n        [v040003, ec0002, ec0103, fc00, v000104, ec0204, ec0300, v010200]]\n\n    face13 = face(p03.add(p13).add(p21).add(p14).add(p04))\n    face13.middle = fc13\n    face13.name = \"face13\"\n    face13.vertex[0] = [v030413, v030402, v031302]\n    face13.vertex[1] = [v130321, v132003, v132021]\n    face13.vertex[2] = [v211314, v211331, v213114]\n    face13.vertex[3] = [v142104, v142122, v140422]\n    face13.vertex[4] = [v041403, v040014, v040003]\n    face13.edge[0] = [ec2104, ec0220]\n    face13.edge[1] = [ec1403, ec3120]\n    face13.edge[2] = [ec0413, ec2231]\n    face13.edge[3] = [ec0321, ec0022]\n    face13.edge[4] = [ec1314, ec0002]\n    face13.invis = [\n        i0304b, i0304a, i0302a, i0313a, i0313b, i130313a, i130313b, i121303b,\n        i1303b, i1303a, i1320a, i1321a, i1321b, i131321a, i131321b, i232113b,\n        i2113b, i2113a, i2131a, i2114a, i2114b, i132114a, i132114b, i241421b,\n        i1421b, i1421a, i1422a, i1404a, i1404b, i131404a, i131404b, i140414b,\n        i0414b, i0414a, i0400a, i0403a, i0403b, i130403a, i130403b, i000304b]\n    face13.allvis = [\n        [v020312, ec1213, ec2003, fc12, v120220, ec1302, ec0312, v201213],\n        [v203013, ec2130, ec1331, fc23, v303120, ec2021, ec3013, v312130],\n        [v313221, ec1432, ec2122, fc24, v322231, ec3114, ec3221, v221432],\n        [v221410, ec0410, ec1400, fc14, v102200, ec2204, ec1014, v001004],\n        [v000104, ec0103, ec0204, fc00, v010200, ec0300, ec0401, v020301]]\n\n    face14 = face(p04.add(p14).add(p22).add(p10).add(p00))\n    face14.middle = fc14\n    face14.name = \"face14\"\n    face14.vertex[0] = [v040014, v040003, v041403]\n    face14.vertex[1] = [v140422, v142104, v142122]\n    face14.vertex[2] = [v221410, v221432, v223210]\n    face14.vertex[3] = [v102200, v102223, v100023]\n    face14.vertex[4] = [v001004, v000110, v000104]\n    face14.edge[0] = [ec0022, ec0321]\n    face14.edge[1] = [ec0410, ec3221]\n    face14.edge[2] = [ec1400, ec2332]\n    face14.edge[3] = [ec2204, ec2301]\n    face14.edge[4] = [ec1014, ec0103]\n    face14.invis = [\n        i0400b, i0400a, i0403a, i0414a, i0414b, i140414a, i140414b, i131404b,\n        i1404b, i1404a, i1421a, i1422a, i1422b, i141422a, i141422b, i242214b,\n        i2214b, i2214b, i2232a, i2210a, i2210b, i142210a, i142210b, i201022b,\n        i1022b, i1022a, i1023a, i1000a, i1000b, i141000a, i141000b, i100010b,\n        i0010b, i0010a, i0001a, i0004a, i0004b, i140004a, i140004b, i000400b]\n    face14.allvis = [\n        [v010200, ec0204, ec0300, fc00, v020301, ec0401, ec0002, v030402],\n        [v030413, ec1314, ec2104, fc13, v130321, ec1403, ec0413, v211314],\n        [v213114, ec2231, ec1432, fc24, v313221, ec2122, ec3114, v322231],\n        [v323322, ec1033, ec2223, fc20, v332332, ec3210, ec3322, v231033],\n        [v231011, ec1100, ec0110, fc10, v112301, ec0023, ec1011, v011100]]\n\n    face20 = face(p10.add(p22).add(p32).add(p33).add(p23))\n    face20.middle = fc20\n    face20.name = \"face20\"\n    face20.vertex[0] = [v102223, v100023, v102200]\n    face20.vertex[1] = [v223210, v221410, v221432]\n    face20.vertex[2] = [v323322, v322231, v323331]\n    face20.vertex[3] = [v332332, v333432, v333423]\n    face20.vertex[4] = [v231033, v233311, v231011]\n    face20.edge[0] = [ec2332, ec1400]\n    face20.edge[1] = [ec1033, ec3114]\n    face20.edge[2] = [ec2223, ec3431]\n    face20.edge[3] = [ec3210, ec1144]\n    face20.edge[4] = [ec3322, ec1100]\n    face20.invis = [\n        i1023b, i1023a, i1000a, i1022a, i1022b, i201022a, i201022b, i142210b,\n        i2210b, i2210a, i2214a, i2232a, i2232b, i202232a, i202232b, i243222b,\n        i3222b, i3222a, i3231a, i3233a, i3233b, i203233a, i203233b, i303332b,\n        i3332b, i3332a, i3323a, i3323a, i3323b, i203323a, i203323b, i212333b,\n        i2333b, i2333a, i2311a, i2310a, i2310b, i202310a, i202310b, i101023b]\n    face20.allvis = [\n        [v001004, ec2204, ec1014, fc14, v040014, ec0022, ec0410, v140422],\n        [v142122, ec3221, ec2231, fc24, v213114, ec1432, ec2122, v313221],\n        [v313230, ec3330, ec3234, fc30, v303134, ec3133, ec3032, v343033],\n        [v342433, ec2324, ec3311, fc21, v241134, ec3423, ec2433, v112324],\n        [v112301, ec0110, ec0023, fc10, v011100, ec1011, ec2301, v000110]]\n\n    face21 = face(p11.add(p23).add(p33).add(p34).add(p24))\n    face21.middle = fc21\n    face21.name = \"face21\"\n    face21.vertex[0] = [v112324, v110124, v112301]\n    face21.vertex[1] = [v233311, v231011, v231033]\n    face21.vertex[2] = [v333423, v332332, v333432]\n    face21.vertex[3] = [v342433, v343033, v343024]\n    face21.vertex[4] = [v241134, v243412, v241112]\n    face21.edge[0] = [ec2433, ec0110]\n    face21.edge[1] = [ec1144, ec3210]\n    face21.edge[2] = [ec2324, ec3032]\n    face21.edge[3] = [ec3311, ec1230]\n    face21.edge[4] = [ec3423, ec1201]\n    face21.invis = [\n        i1124b, i1124a, i1101a, i1123a, i1123b, i211123a, i211123b, i102311b,\n        i2311b, i2311a, i2310a, i2333a, i2333b, i212333a, i212333b, i203323b,\n        i3323b, i3323a, i3332a, i3334a, i3334b, i213334a, i213334b, i303433b,\n        i3433b, i3433a, i3430a, i3424a, i3424b, i213424a, i213424b, i222434b,\n        i2434b, i2434a, i2412a, i2411a, i2411b, i212411a, i212411b, i111124b]\n    face21.allvis = [\n        [v011100, ec0023, ec1011, fc10, v000110, ec2301, ec1100, v100023],\n        [v102223, ec3322, ec2332, fc20, v223210, ec1033, ec2223, v323322],\n        [v323331, ec3431, ec3330, fc30, v313230, ec3234, ec3133, v303134],\n        [v302034, ec2420, ec3412, fc22, v201230, ec3024, ec2034, v122420],\n        [v122402, ec0211, ec0124, fc11, v021201, ec1112, ec2402, v010211]]\n\n    face22 = face(p12.add(p24).add(p34).add(p30).add(p20))\n    face22.middle = fc22\n    face22.name = \"face22\"\n    face22.vertex[0] = [v122420, v120220, v122402]\n    face22.vertex[1] = [v243412, v241112, v241134]\n    face22.vertex[2] = [v343024, v342433, v343033]\n    face22.vertex[3] = [v302034, v303134, v303120]\n    face22.vertex[4] = [v201230, v203013, v201213]\n    face22.edge[0] = [ec2034, ec0211]\n    face22.edge[1] = [ec1230, ec3311]\n    face22.edge[2] = [ec2420, ec3133]\n    face22.edge[3] = [ec3412, ec1331]\n    face22.edge[4] = [ec3024, ec1302]\n    face22.invis = [\n        i1220b, i1220a, i1202a, i1224a, i1224b, i221224a, i221224b, i112412b,\n        i2412b, i2412a, i2411a, i2434a, i2434b, i222434a, i222434b, i213424b,\n        i3424b, i3424a, i3433a, i3430a, i3430b, i223430a, i223430b, i303034b,\n        i3034b, i3034a, i3031a, i3020a, i3020b, i223020a, i223020b, i232030b,\n        i2030b, i2030a, i2013a, i2012a, i2012b, i222012a, i222012b, i121220b]\n    face22.allvis = [\n        [v021201, ec0124, ec1112, fc11, v010211, ec2402, ec1201, v110124],\n        [v112324, ec3423, ec2433, fc21, v233311, ec1144, ec2324, v333423],\n        [v333432, ec3032, ec3431, fc30, v323331, ec3330, ec3234, v313230],\n        [v312130, ec2021, ec3013, fc23, v211331, ec3120, ec2130, v132021],\n        [v132003, ec0312, ec0220, fc12, v031302, ec1213, ec2003, v020312]]\n\n    face23 = face(p13.add(p20).add(p30).add(p31).add(p21))\n    face23.middle = fc23\n    face23.name = \"face23\"\n    face23.vertex[0] = [v132021, v130321, v132003]\n    face23.vertex[1] = [v203013, v201213, v201230]\n    face23.vertex[2] = [v303120, v302034, v303134]\n    face23.vertex[3] = [v312130, v313230, v313221]\n    face23.vertex[4] = [v211331, v213114, v211314]\n    face23.edge[0] = [ec2130, ec0312]\n    face23.edge[1] = [ec1331, ec3412]\n    face23.edge[2] = [ec2021, ec3234]\n    face23.edge[3] = [ec3013, ec1432]\n    face23.edge[4] = [ec3120, ec1403]\n    face23.invis = [\n        i1321b, i1321a, i1303a, i1320a, i1320b, i231320a, i231320b, i122013b,\n        i2013b, i2013a, i2012a, i2030a, i2030b, i232030a, i232030b, i223020b,\n        i3020b, i3020a, i3034a, i3031a, i3031b, i233031a, i233031b, i303130b,\n        i3130b, i3130a, i3132a, i3121a, i3121b, i233121a, i233121b, i242131b,\n        i2131b, i2131a, i2114a, i2113a, i2113b, i232113a, i232113b, i131321b]\n    face23.allvis = [\n        [v031302, ec0220, ec1213, fc12, v020312, ec2003, ec1302, v120220],\n        [v122420, ec3024, ec2034, fc22, v243412, ec1230, ec2420, v343024],\n        [v343033, ec3133, ec3032, fc30, v333432, ec3431, ec3330, v323331],\n        [v322231, ec2122, ec3114, fc24, v221432, ec3221, ec2231, v142122],\n        [v142104, ec0413, ec0321, fc13, v041403, ec1314, ec2104, v030413]]\n\n    face24 = face(p14.add(p21).add(p31).add(p32).add(p22))\n    face24.middle = fc24\n    face24.name = \"face24\"\n    face24.vertex[0] = [v142122, v140422, v142104]\n    face24.vertex[1] = [v213114, v211314, v211331]\n    face24.vertex[2] = [v313221, v312130, v313230]\n    face24.vertex[3] = [v322231, v323331, v323322]\n    face24.vertex[4] = [v221432, v223210, v221410]\n    face24.edge[0] = [ec2231, ec0413]\n    face24.edge[1] = [ec1432, ec3013]\n    face24.edge[2] = [ec2122, ec3330]\n    face24.edge[3] = [ec3114, ec1033]\n    face24.edge[4] = [ec3221, ec0410]\n    face24.invis = [\n        i1422b, i1422a, i1404a, i1421a, i1421b, i241421a, i241421b, i132114b,\n        i2114b, i2114a, i2113a, i2131a, i2131b, i242131a, i242131b, i233121b,\n        i3121b, i3121a, i3130a, i3132a, i3132b, i243132a, i243132b, i303231b,\n        i3231b, i3231a, i3233a, i3222a, i3222b, i243222a, i243222b, i202232b,\n        i2232b, i2232a, i2210a, i2214a, i2214b, i242214a, i242214b, i141422b]\n    face24.allvis = [\n        [v041403, ec0321, ec1314, fc13, v030413, ec2104, ec1403, v130321],\n        [v132021, ec3120, ec2130, fc23, v203013, ec1331, ec2021, v303120],\n        [v303134, ec3234, ec3133, fc30, v343033, ec3032, ec3431, v333432],\n        [v332332, ec2223, ec3210, fc20, v231033, ec3322, ec2332, v102223],\n        [v102200, ec1400, ec2204, fc14, v001004, ec1014, ec0022, v040014]]\n\n    face30 = face(p30.add(p34).add(p33).add(p32).add(p31))\n    face30.middle = fc30\n    face30.name = \"face30\"\n    face30.vertex[0] = [v303134, v303120, v302034]\n    face30.vertex[1] = [v343033, v343024, v342433]\n    face30.vertex[2] = [v333432, v333423, v332332]\n    face30.vertex[3] = [v323331, v323322, v322231]\n    face30.vertex[4] = [v313230, v313221, v312130]\n    face30.edge[0] = [ec3133, ec2420]\n    face30.edge[1] = [ec3032, ec2324]\n    face30.edge[2] = [ec3431, ec2223]\n    face30.edge[3] = [ec3330, ec2122]\n    face30.edge[4] = [ec3234, ec2021]\n    face30.invis = [\n        i3031b, i3031a, i3020a, i3034a, i3034b, i303034a, i303034b, i223430b,\n        i3430b, i3430a, i3424a, i3433a, i3433b, i303433a, i303433b, i213334b,\n        i3334b, i3334a, i3323a, i3332a, i3332b, i303332a, i303332b, i203233b,\n        i3233b, i3233a, i3222a, i3231a, i3231b, i303231a, i303231b, i243132b,\n        i3132b, i3132a, i3121a, i3130a, i3130b, i303130a, i303130b, i233031b]\n    face30.allvis = [\n        [v241134, ec3311, ec3423, fc21, v112324, ec2433, ec1144, v233311],\n        [v231033, ec3210, ec3322, fc20, v102223, ec2332, ec1033, v223210],\n        [v221432, ec3114, ec3221, fc24, v142122, ec2231, ec1432, v213114],\n        [v211331, ec3013, ec3120, fc23, v132021, ec2130, ec1331, v203013],\n        [v201230, ec3412, ec3024, fc22, v122420, ec2034, ec1230, v243412]]\n\n    # This list of all objects is for rotating the whole thing\n    _set(\"all\",[fc00, fc10, fc11, fc12, fc13, fc14,\n                fc20, fc21, fc22, fc23, fc24, fc30,\n                ec0204, ec0300, ec0401, ec0002, ec0103, ec1011,\n                ec0023, ec0110, ec1100, ec2301, ec1112, ec0124,\n                ec0211, ec1201, ec2402, ec1213, ec0220, ec0312,\n                ec1302, ec2003, ec1314, ec0321, ec0413, ec1403,\n                ec2104, ec1014, ec2204, ec1400, ec0410, ec0022,\n                ec3322, ec3210, ec2223, ec1033, ec2332, ec3423,\n                ec3311, ec2324, ec1144, ec2433, ec2034, ec3024,\n                ec3412, ec2420, ec1230, ec2130, ec3120, ec3013,\n                ec2021, ec1331, ec2231, ec3221, ec3114, ec2122,\n                ec1432, ec3234, ec3330, ec3431, ec3032, ec3133,\n                v000104, v010200, v020301, v030402, v040003, v000110,\n                v011100, v112301, v231011, v100023, v010211, v021201,\n                v122402, v241112, v110124, v020312, v031302, v132003,\n                v201213, v120220, v030413, v041403, v142104, v211314,\n                v130321, v040014, v001004, v102200, v221410, v140422,\n                v102223, v223210, v323322, v332332, v231033, v112324,\n                v233311, v333423, v342433, v241134, v122420, v243412,\n                v343024, v302034, v201230, v132021, v203013, v303120,\n                v312130, v211331, v142122, v213114, v313221, v322231,\n                v221432, v303134, v313230, v323331, v333432, v343033,\n                i0001a, i0001b, i0010a, i0010b, i0004a, i0004b,\n                i0102a, i0102b, i0111a, i0111b, i0100a, i0100b,\n                i0203a, i0203b, i0212a, i0212b, i0201a, i0201b,\n                i0304a, i0304b, i0313a, i0313b, i0302a, i0302b,\n                i0400a, i0400b, i0414a, i0414b, i0403a, i0403b,\n                i1000a, i1000b, i1022a, i1022b, i1023a, i1023b,\n                i1101a, i1101b, i1123a, i1123b, i1124a, i1124b,\n                i1202a, i1202b, i1220a, i1220b, i1224a, i1224b,\n                i1303a, i1303b, i1320a, i1320b, i1321a, i1321b,\n                i1404a, i1404b, i1421a, i1421b, i1422a, i1422b,\n                i2012a, i2012b, i2013a, i2013b, i2030a, i2030b,\n                i2113a, i2113b, i2114a, i2114b, i2131a, i2131b,\n                i2210a, i2210b, i2214a, i2214b, i2232a, i2232b,\n                i2310a, i2310b, i2311a, i2311b, i2333a, i2333b,\n                i2411a, i2411b, i2412a, i2412b, i2434a, i2434b,\n                i3020a, i3020b, i3031a, i3031b, i3034a, i3034b,\n                i3121a, i3121b, i3130a, i3130b, i3132a, i3132b,\n                i3222a, i3222b, i3231a, i3231b, i3233a, i3233b,\n                i3323a, i3323b, i3332a, i3332b, i3334a, i3334b,\n                i3424a, i3424b, i3430a, i3430b, i3433a, i3433b,\n                i000001a, i000001b, i000102a, i000102b, i000203a, i000203b,\n                i000304a, i000304b, i000400a, i000400b, i100010a, i100010b,\n                i101023a, i101023b, i102311a, i102311b, i101101a, i101101b,\n                i100100a, i100100b, i110111a, i110111b, i111124a, i111124b,\n                i112412a, i112412b, i111202a, i111202b, i110201a, i110201b,\n                i120212a, i120212b, i121220a, i121220b, i122013a, i122013b,\n                i121303a, i121303b, i120302a, i120302b, i130313a, i130313b,\n                i131321a, i131321b, i132114a, i132114b, i131404a, i131404b,\n                i130403a, i130403b, i140414a, i140414b, i141422a, i141422b,\n                i142210a, i142210b, i141000a, i141000b, i140004a, i140004b,\n                i201022a, i201022b, i202232a, i202232b, i203233a, i203233b,\n                i203323a, i203323b, i202310a, i202310b, i211123a, i211123b,\n                i212333a, i212333b, i213334a, i213334b, i213424a, i213424b,\n                i212411a, i212411b, i221224a, i221224b, i222434a, i222434b,\n                i223430a, i223430b, i223020a, i223020b, i222012a, i222012b,\n                i231320a, i231320b, i232030a, i232030b, i233031a, i233031b,\n                i233121a, i233121b, i232113a, i232113b, i241421a, i241421b,\n                i242131a, i242131b, i243132a, i243132b, i243222a, i243222b,\n                i242214a, i242214b, i303034a, i303034b, i303433a, i303433b,\n                i303332a, i303332b, i303231a, i303231b, i303130a, i303130b])\n\n    face00.opposite = face30\n    face10.opposite = face23\n    face11.opposite = face24\n    face12.opposite = face20\n    face13.opposite = face21\n    face14.opposite = face22\n    face20.opposite = face12\n    face21.opposite = face13\n    face22.opposite = face14\n    face23.opposite = face10\n    face24.opposite = face11\n    face30.opposite = face00\n    face00.rhdict = {\"face00\":face00, \"face14\":face10, \"face13\":face14,\n                     \"face12\":face13, \"face11\":face12, \"face10\":face11,\n                     \"face24\":face20, \"face23\":face24, \"face22\":face23,\n                     \"face21\":face22, \"face20\":face21, \"face30\":face30}\n    face10.rhdict = {\"face10\":face10, \"face11\":face00, \"face21\":face11,\n                     \"face20\":face21, \"face14\":face20, \"face00\":face14,\n                     \"face22\":face12, \"face30\":face22, \"face24\":face30,\n                     \"face13\":face24, \"face12\":face13, \"face23\":face23}\n    face11.rhdict = {\"face11\":face11, \"face12\":face00, \"face22\":face12,\n                     \"face21\":face22, \"face10\":face21, \"face00\":face20,\n                     \"face23\":face13, \"face30\":face23, \"face20\":face30,\n                     \"face14\":face20, \"face13\":face14, \"face24\":face24}\n    face12.rhdict = {\"face12\":face12, \"face13\":face00, \"face23\":face13,\n                     \"face22\":face23, \"face11\":face22, \"face00\":face11,\n                     \"face14\":face10, \"face24\":face14, \"face30\":face24,\n                     \"face21\":face30, \"face10\":face21, \"face20\":face20}\n    face13.rhdict = {\"face13\":face13, \"face14\":face00, \"face24\":face14,\n                     \"face23\":face24, \"face12\":face23, \"face00\":face12,\n                     \"face20\":face10, \"face30\":face20, \"face22\":face30,\n                     \"face11\":face22, \"face10\":face12, \"face21\":face21}\n    face14.rhdict = {\"face14\":face14, \"face10\":face00, \"face20\":face10,\n                     \"face24\":face20, \"face13\":face24, \"face00\":face13,\n                     \"face21\":face11, \"face30\":face21, \"face23\":face30,\n                     \"face12\":face23, \"face11\":face12, \"face22\":face22}\n    face20.rhdict = {\"face20\":face20, \"face21\":face10, \"face30\":face21,\n                     \"face24\":face30, \"face14\":face24, \"face10\":face14,\n                     \"face11\":face00, \"face22\":face11, \"face23\":face22,\n                     \"face13\":face23, \"face00\":face13, \"face12\":face12}\n    face21.rhdict = {\"face21\":face21, \"face11\":face10, \"face22\":face11,\n                     \"face30\":face22, \"face20\":face30, \"face10\":face20,\n                     \"face12\":face00, \"face23\":face12, \"face24\":face23,\n                     \"face14\":face24, \"face00\":face14, \"face13\":face13}\n    face22.rhdict = {\"face22\":face22, \"face12\":face11, \"face23\":face12,\n                     \"face30\":face23, \"face21\":face30, \"face11\":face21,\n                     \"face13\":face00, \"face24\":face13, \"face20\":face24,\n                     \"face10\":face20, \"face00\":face10, \"face14\":face14}\n    face23.rhdict = {\"face23\":face23, \"face13\":face12, \"face24\":face13,\n                     \"face30\":face24, \"face22\":face30, \"face12\":face22,\n                     \"face14\":face00, \"face20\":face14, \"face21\":face20,\n                     \"face11\":face21, \"face00\":face11, \"face10\":face10}\n    face24.rhdict = {\"face24\":face24, \"face14\":face13, \"face20\":face14,\n                     \"face30\":face20, \"face23\":face30, \"face13\":face23,\n                     \"face10\":face00, \"face21\":face10, \"face22\":face21,\n                     \"face12\":face22, \"face00\":face12, \"face11\":face11}\n    face30.rhdict = {\"face30\":face30, \"face21\":face20, \"face22\":face21,\n                     \"face23\":face22, \"face24\":face23, \"face20\":face24,\n                     \"face11\":face10, \"face12\":face11, \"face13\":face12,\n                     \"face14\":face13, \"face10\":face14, \"face00\":face00}\n\n    _set(\"reflect\",\n            {\"arrow00x\":{\"face00\":face10, \"face10\":face00, \"face11\":face11,\n                         \"face12\":face21, \"face13\":face20, \"face14\":face14,\n                         \"face20\":face13, \"face21\":face12, \"face22\":face22,\n                         \"face23\":face30, \"face24\":face24, \"face30\":face23},\n             \"arrow01x\":{\"face00\":face11, \"face10\":face10, \"face11\":face00,\n                         \"face12\":face12, \"face13\":face22, \"face14\":face21,\n                         \"face20\":face20, \"face21\":face14, \"face22\":face13,\n                         \"face23\":face23, \"face24\":face30, \"face30\":face24},\n             \"arrow02x\":{\"face00\":face12, \"face10\":face22, \"face11\":face11,\n                         \"face12\":face00, \"face13\":face13, \"face14\":face23,\n                         \"face20\":face30, \"face21\":face21, \"face22\":face10,\n                         \"face23\":face14, \"face24\":face24, \"face30\":face20},\n             \"arrow03x\":{\"face00\":face13, \"face10\":face24, \"face11\":face23,\n                         \"face12\":face12, \"face13\":face00, \"face14\":face14,\n                         \"face20\":face20, \"face21\":face30, \"face22\":face22,\n                         \"face23\":face11, \"face24\":face10, \"face30\":face21},\n             \"arrow04x\":{\"face00\":face14, \"face10\":face10, \"face11\":face20,\n                         \"face12\":face24, \"face13\":face13, \"face14\":face00,\n                         \"face20\":face11, \"face21\":face21, \"face22\":face30,\n                         \"face23\":face23, \"face24\":face12, \"face30\":face22},\n             \"arrow10x\":{\"face00\":face00, \"face10\":face11, \"face11\":face10,\n                         \"face12\":face14, \"face13\":face13, \"face14\":face12,\n                         \"face20\":face22, \"face21\":face21, \"face22\":face20,\n                         \"face23\":face24, \"face24\":face23, \"face30\":face30},\n             \"arrow14x\":{\"face00\":face00, \"face10\":face14, \"face11\":face13,\n                         \"face12\":face12, \"face13\":face11, \"face14\":face10,\n                         \"face20\":face20, \"face21\":face24, \"face22\":face23,\n                         \"face23\":face22, \"face24\":face21, \"face30\":face30},\n             \"arrow20x\":{\"face00\":face24, \"face10\":face20, \"face11\":face30,\n                         \"face12\":face23, \"face13\":face13, \"face14\":face14,\n                         \"face20\":face10, \"face21\":face21, \"face22\":face22,\n                         \"face23\":face12, \"face24\":face00, \"face30\":face11},\n             \"arrow11x\":{\"face00\":face00, \"face10\":face13, \"face11\":face12,\n                         \"face12\":face11, \"face13\":face10, \"face14\":face14,\n                         \"face20\":face24, \"face21\":face23, \"face22\":face22,\n                         \"face23\":face21, \"face24\":face20, \"face30\":face30},\n             \"arrow21x\":{\"face00\":face20, \"face10\":face10, \"face11\":face21,\n                         \"face12\":face30, \"face13\":face24, \"face14\":face14,\n                         \"face20\":face00, \"face21\":face11, \"face22\":face22,\n                         \"face23\":face23, \"face24\":face13, \"face30\":face12},\n             \"arrow12x\":{\"face00\":face00, \"face10\":face10, \"face11\":face14,\n                         \"face12\":face13, \"face13\":face12, \"face14\":face11,\n                         \"face20\":face21, \"face21\":face20, \"face22\":face24,\n                         \"face23\":face23, \"face24\":face22, \"face30\":face30},\n             \"arrow22x\":{\"face00\":face21, \"face10\":face10, \"face11\":face11,\n                         \"face12\":face22, \"face13\":face30, \"face14\":face20,\n                         \"face20\":face14, \"face21\":face00, \"face22\":face12,\n                         \"face23\":face23, \"face24\":face24, \"face30\":face13},\n             \"arrow13x\":{\"face00\":face00, \"face10\":face12, \"face11\":face11,\n                         \"face12\":face10, \"face13\":face14, \"face14\":face13,\n                         \"face20\":face23, \"face21\":face22, \"face22\":face21,\n                         \"face23\":face20, \"face24\":face24, \"face30\":face30},\n             \"arrow23x\":{\"face00\":face22, \"face10\":face21, \"face11\":face11,\n                         \"face12\":face12, \"face13\":face23, \"face14\":face30,\n                         \"face20\":face20, \"face21\":face10, \"face22\":face00,\n                         \"face23\":face13, \"face24\":face24, \"face30\":face14},\n             \"arrow24x\":{\"face00\":face23, \"face10\":face30, \"face11\":face22,\n                         \"face12\":face12, \"face13\":face13, \"face14\":face24,\n                         \"face20\":face20, \"face21\":face21, \"face22\":face11,\n                         \"face23\":face00, \"face24\":face14, \"face30\":face10}})\n\n    _set(\"face00\", face00)\n    _set(\"face10\", face10)\n    _set(\"face11\", face11)\n    _set(\"face12\", face12)\n    _set(\"face13\", face13)\n    _set(\"face14\", face14)\n    _set(\"face20\", face20)\n    _set(\"face21\", face21)\n    _set(\"face22\", face22)\n    _set(\"face23\", face23)\n    _set(\"face24\", face24)\n    _set(\"face30\", face30)\n\n    # Text labels for faces, done by applying textures\n    # Use this bit of code to make a new image from a .jpg file\n    ## texim = coin.SoTexture2()\n    ## texim.filename = str(\"file.jpg\")\n    ## s = texim.image.get().getString()\n    ## outfile = open(\"file.txt\", \"w\")\n    ## outfile.write(\"%s\" % compressImage(s))\n    ## outfile.close()\n    # and then paste file.txt into the image definition\n    ffs = '0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff '\n    ffs4 = ffs + ffs + ffs + ffs\n    ffs16 = ffs4 + ffs4 + ffs4 + ffs4\n    ffs64 = ffs16 + ffs16 + ffs16 + ffs16\n    face00.image = '80 80 1 \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xff 0xff 0xff 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xff 0xff 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xfe 0xff 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xfe 0xfe 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xfe 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xff 0xff 0xff 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs4 + ' \\\n    0xff 0xf7 0x92 0x41 0x15 0x4 0x14 0x3e \\\n    0x8e 0xf5 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xfe 0xff 0xf7 0x92 0x41 0x15 \\\n    0x5 0x14 0x3e 0x8e 0xf5 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xce 0x1e 0x0 0x0 0x1 0x0 0x0 0x0 \\\n    0x0 0x1b 0xcb 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xcf 0x1e 0x0 0x0 0x0 \\\n    0x0 0x0 0x0 0x0 0x1b 0xca 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xd9 \\\n    0xd 0x0 0x0 0x12 0x61 0x7d 0x64 0x14 \\\n    0x0 0x0 0xc 0xd9 0xfe 0xff 0xff 0xff \\\n    0xff 0xff 0xda 0xd 0x0 0x0 0x12 0x61 \\\n    0x7d 0x64 0x15 0x0 0x0 0xc 0xd9 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x40 \\\n    0x0 0x0 0x40 0xed 0xff 0xff 0xff 0xf0 \\\n    0x45 0x0 0x0 0x40 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0x3f 0x0 0x0 0x40 0xed 0xff \\\n    0xff 0xfe 0xf0 0x45 0x0 0x0 0x40 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0xd5 0x0 \\\n    0x0 0x10 0xed 0xff 0xff 0xff 0xff 0xff \\\n    0xef 0x10 0x0 0x0 0xd7 0xff 0xfe 0xff \\\n    0xff 0xd5 0x0 0x0 0x10 0xee 0xff 0xff \\\n    0xff 0xff 0xff 0xef 0x10 0x0 0x0 0xd7 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0x81 0x0 \\\n    0x0 0x70 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0x6f 0x0 0x0 0x85 0xff 0xff 0xff \\\n    0xff 0x82 0x0 0x0 0x70 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0x6f 0x0 0x0 0x85 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfe 0xff 0x51 0x0 \\\n    0x0 0xb6 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xb3 0x0 0x0 0x55 0xff 0xff 0xff \\\n    0xff 0x51 0x0 0x1 0xb7 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xb3 0x0 0x0 0x56 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0x28 0x0 \\\n    0x0 0xdf 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xda 0x0 0x0 0x2d 0xff 0xff 0xff \\\n    0xff 0x28 0x0 0x0 0xdf 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xda 0x0 0x0 0x2d \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0x14 0x0 \\\n    0x0 0xf6 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xf2 0x0 0x0 0x1a 0xff 0xff 0xfe \\\n    0xff 0x15 0x0 0x0 0xf6 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xfe 0xf2 0x0 0x0 0x1a \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xfe 0x8 0x0 \\\n    0x1 0xff 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xfc 0x0 0x0 0xe 0xff 0xff 0xff \\\n    0xff 0x8 0x0 0x1 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xfc 0x0 0x0 0xe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xff 0xff 0xfe 0xff 0x0 0x0 \\\n    0x3 0xff 0xff 0xff 0xfe 0xff 0xff 0xff \\\n    0xff 0xff 0x0 0x0 0x4 0xff 0xff 0xff \\\n    0xff 0x0 0x0 0x3 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xff 0x0 0x0 0x4 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0x0 0x0 \\\n    0x3 0xfe 0xff 0xfe 0xff 0xff 0xff 0xff \\\n    0xfe 0xff 0x0 0x0 0x3 0xff 0xff 0xff \\\n    0xff 0x0 0x0 0x3 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xff 0x0 0x0 0x3 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0x1 0x0 \\\n    0x3 0xff 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0x0 0x0 0x3 0xff 0xff 0xff \\\n    0xff 0x0 0x0 0x3 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xff 0x0 0x0 0x3 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0x0 0x0 \\\n    0x3 0xff 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0x0 0x0 0x4 0xff 0xff 0xff \\\n    0xff 0x0 0x0 0x4 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xff 0x0 0x0 0x4 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0x6 0x0 \\\n    0x2 0xff 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xfe 0xfd 0x0 0x0 0xb 0xff 0xff 0xff \\\n    0xff 0x6 0x0 0x2 0xff 0xff 0xff 0xff \\\n    0xfe 0xff 0xff 0xff 0xfd 0x0 0x0 0xb \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0x12 0x0 \\\n    0x0 0xf8 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xf2 0x0 0x0 0x18 0xff 0xff 0xff \\\n    0xff 0x12 0x0 0x0 0xf8 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xf2 0x0 0x0 0x17 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0x23 0x0 \\\n    0x0 0xe4 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xdf 0x0 0x0 0x29 0xff 0xff 0xff \\\n    0xff 0x23 0x0 0x0 0xe4 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xdf 0x0 0x0 0x29 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfe 0xff 0x4b 0x0 \\\n    0x0 0xbe 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xfe 0xba 0x0 0x1 0x51 0xff 0xff 0xff \\\n    0xff 0x4b 0x0 0x0 0xbe 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xba 0x0 0x0 0x51 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0x7a 0x0 \\\n    0x0 0x7b 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0x77 0x1 0x0 0x7f 0xff 0xff 0xff \\\n    0xff 0x7a 0x0 0x0 0x7c 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0x77 0x0 0x0 0x7f \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xff 0xff 0xff 0xca 0x0 \\\n    0x0 0x19 0xf4 0xff 0xff 0xff 0xff 0xfe \\\n    0xf3 0x16 0x0 0x0 0xd0 0xff 0xff 0xff \\\n    0xff 0xca 0x0 0x1 0x19 0xf4 0xfe 0xff \\\n    0xff 0xff 0xff 0xf3 0x16 0x0 0x0 0xd0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x32 \\\n    0x0 0x0 0x4c 0xf2 0xff 0xff 0xff 0xf0 \\\n    0x49 0x0 0x0 0x38 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0x33 0x0 0x0 0x4c 0xf2 0xff \\\n    0xff 0xff 0xf0 0x49 0x0 0x0 0x38 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xd1 \\\n    0x8 0x0 0x0 0x15 0x63 0x7d 0x62 0x15 \\\n    0x0 0x0 0xa 0xd4 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xd1 0x8 0x0 0x0 0x16 0x63 \\\n    0x7c 0x62 0x15 0x1 0x0 0xa 0xd4 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xc5 0x19 0x0 0x0 0x0 0x0 0x0 0x0 \\\n    0x0 0x1a 0xc8 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xc5 0x18 0x0 0x0 0x0 \\\n    0x0 0x0 0x0 0x0 0x1a 0xc8 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xf3 0x8c 0x3e 0x15 0x5 0x16 0x41 \\\n    0x8f 0xf5 0xff 0xff 0xfe 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xf4 0x8c 0x3e 0x15 \\\n    0x5 0x16 0x40 0x8f 0xf5 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xff 0xff 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfe 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs4 + ' \\\n    ' + ffs4 + ' \\\n    0xff 0xff 0xff 0xfe 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xfe 0xff 0xff 0xff 0xff \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' '\n    face10.image = '80 80 1 \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xf9 0xff 0xfd 0xfc 0xff 0xfa 0xff \\\n    0xfe 0xff 0xfd 0xff 0xfe 0xfd 0xfe 0xfe \\\n    0xff 0xff 0xfc 0xfe 0xff 0xff 0xff 0xff \\\n    0xff 0xfd 0xfe 0xfb 0xff 0xff 0xf7 0xff \\\n    0xff 0xfd 0xff 0xfc 0xfc 0xff 0xfe 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xf8 0xf9 0xff 0xfd 0xfe 0xff \\\n    0xfe 0xfc 0xff 0xff 0xfc 0xff 0xff 0xff \\\n    0xff 0xfd 0xff 0xff 0xfb 0xf9 0xff 0xff \\\n    0xff 0xff 0xfb 0xff 0xff 0xfb 0xff 0xf6 \\\n    0xff 0xff 0xfc 0xff 0xff 0xff 0xfa 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xff 0xff 0xfb 0xff 0xff 0xfc \\\n    0xff 0xff 0xfd 0xfd 0xff 0xfc 0xfd 0xfc \\\n    0xff 0xfb 0xff 0xfb 0xff 0xfd 0xfc 0xff \\\n    0xf6 0xfe 0xff 0xf8 0xff 0xfd 0xff 0xff \\\n    0xfe 0xfc 0xfa 0xff 0xfa 0xfd 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xfd 0xff 0xff 0xfd 0xff \\\n    0xfd 0xc6 0x63 0x13 0xfc 0xff 0xff 0xff \\\n    0xfb 0xff 0xf9 0xfd 0xff 0xff 0xfc 0xf7 \\\n    0xfb 0x8c 0x3e 0x17 0x6 0x18 0x3d 0x8f \\\n    0xf2 0xff 0xff 0xfe 0xff 0xfe 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xfe 0xff 0xf4 0xee 0x8d \\\n    0x2a 0x0 0x5 0x3 0xf3 0xff 0xfe 0xff \\\n    0xff 0xfe 0xff 0xfd 0xff 0xf9 0xff 0xce \\\n    0x15 0x1 0x0 0x0 0x0 0x0 0x1 0x0 \\\n    0x1a 0xc3 0xff 0xff 0xf9 0xff 0xfd 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfb 0xfd 0xb1 0x5a 0x4 0x0 \\\n    0x1 0x0 0x2 0x7 0xff 0xf9 0xfe 0xfe \\\n    0xff 0xfd 0xfe 0xff 0xfe 0xff 0xd3 0x0 \\\n    0x2 0x0 0x18 0x64 0x75 0x62 0x1e 0x0 \\\n    0x3 0x8 0xd0 0xff 0xfa 0xfc 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xfe 0x1e 0x0 0x0 0x0 0x0 \\\n    0x12 0x6 0x0 0x0 0xfb 0xff 0xff 0xff \\\n    0xff 0xfd 0xff 0xfe 0xff 0xff 0x2c 0xe \\\n    0x0 0x4c 0xf0 0xff 0xff 0xfc 0xf1 0x46 \\\n    0x0 0x0 0x44 0xff 0xff 0xfa 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfd 0x2 0x0 0x2 0x47 0xaa \\\n    0xf8 0x0 0x0 0x7 0xff 0xfd 0xff 0xfc \\\n    0xfd 0xff 0xff 0xfe 0xff 0xc8 0x0 0x0 \\\n    0x1a 0xf8 0xfe 0xfa 0xff 0xff 0xfc 0xf5 \\\n    0x16 0x0 0x0 0xce 0xfc 0xff 0xfb 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0x28 0x8c 0xe4 0xfc 0xff \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xff 0xfd 0xfd 0xff 0xff 0x78 0x0 0x1 \\\n    0x7f 0xff 0xfb 0xff 0xff 0xff 0xfd 0xff \\\n    0x78 0x3 0x0 0x80 0xff 0xff 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfd 0xf8 0xff 0xff 0xfa 0xfe \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xfe 0xff 0xff 0xff 0xfe 0x4f 0x0 0x1 \\\n    0xb6 0xff 0xfc 0xff 0xfe 0xff 0xff 0xfb \\\n    0xb3 0x5 0x0 0x50 0xfc 0xfd 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xff 0xfe 0xff 0xf8 0xff 0xfd \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xfc 0xff 0xfe 0xff 0xff 0x22 0x0 0x1 \\\n    0xe7 0xff 0xfb 0xff 0xfc 0xfe 0xff 0xfc \\\n    0xe2 0x0 0x1 0x28 0xfe 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfc 0xfe 0xff 0xf8 0xfc 0xff 0xff 0xfd \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xfe 0xff 0xfb 0xfd 0xff 0xd 0x2 0x1 \\\n    0xf9 0xfb 0xfe 0xff 0xfd 0xfc 0xff 0xff \\\n    0xf3 0x0 0x1 0x19 0xfe 0xff 0xfb 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xf7 0xff 0xff 0xfc 0xfc 0xff \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xff 0xff 0xfc 0xfd 0xff 0x8 0x2 0x1 \\\n    0xff 0xff 0xff 0xff 0xff 0xfe 0xfd 0xff \\\n    0xfe 0x0 0x0 0xd 0xfc 0xfd 0xfc 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xfa 0xff 0xfb \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xfd 0xff 0xff 0xff 0xfd 0x4 0x0 0x2 \\\n    0xff 0xff 0xff 0xfb 0xff 0xff 0xfb 0xff \\\n    0xff 0x1 0x0 0x3 0xff 0xf9 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf7 0xff 0xff 0xfa 0xff 0xfb 0xff \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xfe 0xff 0xff 0xff 0xfd 0x0 0x1 0x3 \\\n    0xfd 0xff 0xfc 0xfb 0xff 0xff 0xfe 0xff \\\n    0xfc 0x0 0x0 0x2 0xff 0xfd 0xff 0xfc \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xff 0xfe 0xfe 0xff 0xfb 0xff \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xff 0xfe 0xfc 0xff 0xff 0x0 0x4 0x3 \\\n    0xfd 0xff 0xfe 0xff 0xfe 0xff 0xff 0xff \\\n    0xfc 0x4 0x0 0x4 0xfc 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xff 0xff 0xff 0xfe 0xfd 0x3 0x0 0x4 \\\n    0xfc 0xff 0xff 0xff 0xfe 0xff 0xfb 0xff \\\n    0xff 0x0 0x2 0x3 0xff 0xfc 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xff 0xfb 0xff 0xff 0xff 0x6 0x2 0x1 \\\n    0xff 0xf6 0xff 0xfb 0xff 0xff 0xff 0xff \\\n    0xfb 0x0 0x0 0xd 0xfb 0xff 0xfe 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xff 0xfc 0xff 0xff 0xff 0x10 0x3 0x0 \\\n    0xf0 0xff 0xff 0xff 0xff 0xfe 0xff 0xfb \\\n    0xf4 0x3 0x2 0x1c 0xff 0xf8 0xff 0xf8 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xfe 0xff 0xff 0xfd 0xfd 0x27 0x3 0x0 \\\n    0xdd 0xff 0xf6 0xfc 0xfe 0xff 0xff 0xff \\\n    0xd7 0x1 0x0 0x32 0xfd 0xfc 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xfc 0xff 0xfd 0xfd 0xff 0x4e 0x0 0x6 \\\n    0xb5 0xfb 0xff 0xff 0xff 0xfa 0xf6 0xff \\\n    0xb7 0x0 0x7 0x4c 0xff 0xff 0xf7 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xff 0xff 0xfb 0xff 0xff 0x83 0x0 0x0 \\\n    0x70 0xff 0xfb 0xff 0xfa 0xfd 0xff 0xf9 \\\n    0x6d 0x3 0x0 0x87 0xff 0xfb 0xff 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xff 0xfe 0xff 0xff 0xff 0xc8 0x13 0x0 \\\n    0x11 0xec 0xff 0xf8 0xff 0xff 0xff 0xf1 \\\n    0x10 0x5 0x0 0xd8 0xf8 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    0xfd 0xfe 0xff 0xfb 0xfe 0xff 0x39 0x1 \\\n    0x0 0x3d 0xef 0xff 0xff 0xfe 0xef 0x45 \\\n    0x0 0x1 0x46 0xff 0xff 0xfc 0xfe 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfd 0x0 0x2 0x1 0xff 0xfc 0xff 0xfc \\\n    0xfd 0xff 0xff 0xfe 0xff 0xff 0xd8 0xe \\\n    0x5 0x0 0x19 0x5f 0x78 0x66 0x19 0x0 \\\n    0x0 0x13 0xd6 0xf9 0xff 0xfe 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0x0 0x3 0x0 0xfe 0xfd 0xff 0xff \\\n    0xfe 0xff 0xff 0xfb 0xff 0xfc 0xff 0xc9 \\\n    0x1a 0x1 0x0 0x1 0x0 0x6 0x0 0x4 \\\n    0x1b 0xc7 0xff 0xff 0xfd 0xf9 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfb 0x0 0x1 0x5 0xff 0xff 0xfd 0xff \\\n    0xff 0xfe 0xfd 0xfa 0xff 0xff 0xff 0xff \\\n    0xf5 0x95 0x44 0x1b 0x6 0xb 0x3e 0x8e \\\n    0xfc 0xfd 0xff 0xff 0xfc 0xff 0xff 0xfb \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfd 0xff 0xfc 0xfe 0xff 0xff \\\n    0xff 0xfc 0xff 0xff 0xfb 0xfd 0xfb 0xfc \\\n    0xff 0xfe 0xff 0xf7 0xfd 0xff 0xff 0xfd \\\n    0xfa 0xfa 0xff 0xf6 0xff 0xfc 0xf9 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfe 0xfd 0xf9 0xfd 0xff 0xff 0xfe 0xfb \\\n    0xff 0xfa 0xff 0xff 0xfb 0xfc 0xff 0xff \\\n    0xfe 0xfa 0xff 0xfe 0xff 0xfb 0xfd 0xff \\\n    0xff 0xff 0xfc 0xff 0xff 0xf9 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xff 0xff 0xff 0xf6 0xff 0xfe \\\n    0xff 0xff 0xfb 0xff 0xff 0xff 0xfd 0xfa \\\n    0xff 0xff 0xff 0xfc 0xff 0xfb 0xff 0xff \\\n    0xfa 0xfe 0xff 0xfd 0xfc 0xff 0xfe 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfd 0xfe 0xfe 0xf8 0xf8 0xff 0xfb 0xfe \\\n    0xfd 0xff 0xff 0xfa 0xfc 0xff 0xff 0xff \\\n    0xfc 0xfc 0xfd 0xff 0xff 0xff 0xff 0xfc \\\n    0xff 0xff 0xff 0xfe 0xff 0xf6 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xff 0xff 0xfc 0xfe 0xff \\\n    0xff 0xf4 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xfe 0xfb 0xff 0xff \\\n    0xff 0xfc 0xff 0xff 0xfd 0xff 0xff 0xfd \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs4 + ' '\n    face11.image = '80 80 1 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xfd 0xff 0xfe 0xff 0xf9 0xff \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xff 0xff 0xff 0xff 0xff 0xfc \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xff 0xf9 0xfe 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xff 0xfb 0xfb 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xfa 0xff 0xff 0xfa 0xff 0xfc \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfc 0xfd 0xff 0xff 0xfe 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xff 0xfd 0xff 0xfd 0xff 0xfc \\\n    ' + ffs + ' \\\n    0xfd 0xfd 0xff 0xff 0xff 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfc 0xfd 0xfd 0xff 0xff 0xf5 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfc 0xfd 0xfd 0xfe 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xfe 0xfe 0xff 0xff 0xff 0xfb \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xff 0xff 0xff 0xff 0xfe 0xfb \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xf8 0xff 0xff 0xfe 0xff 0xff 0xfd \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xfb 0xfb 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xc7 0x63 0x11 0xff 0xf8 0xff \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xfd 0xff 0xfe 0xc9 0x65 0x10 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xfc 0xff 0xff 0xfb 0xeb \\\n    0x8d 0x26 0x0 0x2 0x5 0xff 0xfe 0xfe \\\n    0xff 0xff 0xff 0xff 0xfe 0xfb 0xff 0xfe \\\n    0xfc 0xff 0xe5 0x90 0x27 0x0 0x5 0x2 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xff 0xff 0xfb 0xad 0x53 0x6 \\\n    0x1 0x0 0x0 0x0 0x2 0xff 0xfc 0xff \\\n    0xfe 0xfe 0xff 0xfd 0xff 0xff 0xff 0xfc \\\n    0xb7 0x48 0x5 0x3 0x0 0x2 0x0 0x3 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xf6 0x18 0x2 0x0 0x1 \\\n    0x3 0xb 0x6 0xa 0x0 0xff 0xff 0xf8 \\\n    0xff 0xfb 0xfa 0xff 0xfc 0xff 0xf9 0x19 \\\n    0x3 0x3 0x5 0x0 0xe 0x0 0x6 0x1 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xf9 0xff 0xf9 0xff 0x7 0x0 0x5 0x45 \\\n    0xa9 0xf8 0x0 0x0 0x0 0xfb 0xff 0xfc \\\n    0xff 0xf9 0xff 0xff 0xfc 0xfd 0xff 0x1 \\\n    0x0 0x2 0x4b 0xa7 0xfe 0x0 0x0 0xb \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xfb 0xfb 0x2d 0x89 0xe0 0xff \\\n    0xfc 0xff 0x4 0x0 0xa 0xfe 0xf8 0xff \\\n    0xff 0xff 0xf3 0xff 0xff 0xfc 0xff 0x28 \\\n    0x8e 0xe9 0xf7 0xff 0xfb 0x5 0x2 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfd 0xff 0xff 0xff \\\n    0xff 0xfe 0x0 0x2 0x0 0xff 0xfd 0xfd \\\n    0xfe 0xff 0xff 0xff 0xfb 0xfa 0xfd 0xff \\\n    0xfa 0xff 0xff 0xfc 0xff 0x0 0x5 0x3 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfc 0xfb 0xff 0xff 0xfa 0xff 0xff 0xfb \\\n    0xff 0xfe 0x0 0x1 0xc 0xf3 0xff 0xfe \\\n    0xfd 0xfd 0xfe 0xff 0xfd 0xff 0xff 0xf9 \\\n    0xff 0xfa 0xfe 0xff 0xff 0x4 0x0 0x1 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xf9 0xff 0xfc 0xff 0xff \\\n    0xfc 0xff 0x2 0x2 0x0 0xff 0xfe 0xff \\\n    0xff 0xff 0xff 0xf9 0xff 0xfd 0xfb 0xff \\\n    0xff 0xff 0xfc 0xff 0xff 0x0 0x0 0x8 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0x0 0x0 0x3 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0x0 0x0 0x3 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0x0 0x0 0x3 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0x0 0x0 0x3 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0x0 0x0 0x3 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0x0 0x0 0x3 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0x0 0x0 0x3 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0x0 0x0 0x3 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfb 0xff 0x0 0x4 0x0 0xff 0xfc 0xfe \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0x0 0x0 0x4 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfd 0xfc 0x8 0x1 0x2 0xfa 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xff 0xfd 0xfa 0x1 0x2 0x9 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xf7 0x0 0x3 0x2 0xff 0xfb 0xfb \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xfa 0xff 0xfa 0x3 0x4 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfb 0xff 0x3 0x0 0x0 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xfd 0xff 0xff 0x0 0x7 0x9 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0x0 0x5 0x8 0xfd 0xfa 0xfd \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xff 0xfa 0xfe 0x5 0x0 0x1 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x0 0x6 0xfc 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xf7 0xff 0xff 0x2 0x0 0x1 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xf7 0x5 0x7 0x0 0xff 0xfc 0xfa \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xff 0xff 0xf9 0x0 0x3 0x1 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xfc 0xff 0xfe 0xfc 0xff \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfe 0xfd 0xff 0xff 0xf9 0xff \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' '\n    face12.image = '80 80 1 \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xff 0xfb 0xff 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfa 0xff 0xfe 0xfe 0xfe 0xff \\\n    0xff 0xff 0xf8 0xff 0xfc 0xff 0xf6 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xfe 0xfc 0xff 0xf7 0xff \\\n    ' + ffs + ' \\\n    0xfb 0xfe 0xff 0xff 0xff 0xf8 0xff 0xfb \\\n    0xfc 0xfe 0xff 0xff 0xff 0xf6 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfc 0xff 0xff 0xfd 0xff 0xfb \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xf3 0xfe 0xff 0xfa 0xff \\\n    0xff 0xff 0xfe 0xff 0xfd 0xff 0xff 0xf7 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfe 0xf8 0xff 0xfd 0xfc 0xfe 0xfe 0xff \\\n    ' + ffs + ' \\\n    0xfe 0xf6 0xfe 0xff 0xfb 0xff 0xf9 0xff \\\n    0xfd 0xf9 0xfe 0xff 0xff 0xfb 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfb 0xfd 0xff 0xff 0xf9 0xfd \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfa 0xff 0xff 0xff 0xff 0xfa \\\n    0xff 0xff 0xff 0xfa 0xfc 0xff 0xfa 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfe 0xfa 0xff 0xfe 0xff 0xf8 0xff 0xff \\\n    ' + ffs + ' \\\n    0xfb 0xf9 0xff 0xfc 0xff 0xfc 0xfe 0xff \\\n    0xfc 0xfb 0xff 0xfc 0xff 0xff 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfc 0xff 0xfa 0xfe \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfd 0xfe 0xff 0xff \\\n    0xff 0xff 0xf8 0xff 0xf9 0xf9 0xff 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfb 0x0 0x2 0x0 0x2 0x4 0x0 \\\n    0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 \\\n    0x0 0xff 0xfb 0xfd 0xff 0xfe 0xff 0xfe \\\n    0xfa 0xff 0xff 0x2 0x4 0x0 0xfe 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x0 0x0 0x7 0x0 \\\n    0x1 0x0 0x1 0x0 0x4 0x0 0x2 0x0 \\\n    0x0 0xff 0xff 0xfc 0xfd 0xff 0xff 0xfc \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0x86 0x82 0x88 0x85 0x80 0x82 \\\n    0x81 0x85 0x86 0x84 0x7c 0x5d 0x0 0x0 \\\n    0x51 0xf5 0xfe 0xff 0xff 0xfa 0xfb 0xff \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfc 0xf9 0xfe 0xff 0xfa 0xff \\\n    0xff 0xfa 0xfd 0xff 0xde 0x17 0x8 0x32 \\\n    0xf1 0xff 0xfe 0xfc 0xff 0xff 0xfd 0xff \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfc 0xfc 0xff 0xff 0xfc 0xff 0xff 0xff \\\n    0xff 0xfb 0xff 0xe3 0x26 0x0 0x1b 0xe6 \\\n    0xff 0xf7 0xfc 0xfc 0xfc 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfb 0xff 0xfb 0xfa 0xfe 0xf8 \\\n    0xff 0xff 0xee 0x23 0x2 0x12 0xd4 0xff \\\n    0xfd 0xfd 0xff 0xff 0xfd 0xfc 0xff 0xfd \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xfc 0xff 0xff 0xff 0xff \\\n    0xfd 0xeb 0x40 0xd 0x0 0xbf 0xfc 0xff \\\n    0xff 0xfd 0xf7 0xfd 0xfc 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xf9 0xff 0xfc 0xfc 0xff \\\n    0xfb 0x48 0x0 0x0 0xa6 0xfb 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xff 0xfc 0xff 0xfe \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xfc 0xff 0xff 0xfe 0xfe 0xfd \\\n    0x4f 0x0 0x2 0x7d 0xff 0xfc 0xff 0xff \\\n    0xff 0xfc 0xff 0xfb 0xff 0xfe 0xff 0xfd \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfc 0xff 0xff 0xff 0xfb 0xff 0x63 \\\n    0x0 0x0 0x62 0xfe 0xff 0xff 0xf9 0xff \\\n    0xfe 0xfe 0xfd 0xff 0xff 0xff 0xff 0xfa \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfa 0xff 0xfd 0xfc 0xff 0xfe 0x8d 0x0 \\\n    0x1 0x41 0xf7 0xff 0xff 0xfc 0xff 0xf8 \\\n    0xff 0xff 0xff 0xfe 0xfa 0xff 0xfe 0xff \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xfe 0xff 0xb4 0x0 0x0 \\\n    0x27 0xf0 0xff 0xfc 0xfc 0xff 0xff 0xff \\\n    0xfc 0xfd 0xfe 0xff 0xfe 0xff 0xfa 0xff \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xff 0xff 0xe3 0x17 0x0 0x13 \\\n    0xd4 0xff 0xff 0xfb 0xfe 0xfc 0xfe 0xfc \\\n    0xff 0xff 0xfd 0xff 0xfd 0xff 0xfb 0xff \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xff 0xff 0x50 0x2 0x2 0x90 \\\n    0xff 0xfb 0xf6 0xff 0xff 0xff 0xff 0xff \\\n    0xf7 0xff 0xfb 0xff 0xfc 0xfb 0xff 0xff \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xfc 0xc5 0x6 0x0 0x3d 0xff \\\n    0xff 0xff 0xff 0xfb 0xfe 0xf7 0xff 0xfd \\\n    0xff 0xff 0xfe 0xff 0xff 0xfe 0xff 0xfa \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0x65 0x0 0x0 0xaa 0xf6 \\\n    0xff 0xff 0xf9 0xff 0xff 0xf9 0xff 0xfd \\\n    0xff 0xf3 0xff 0xfc 0xfc 0xff 0xff 0xfe \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xff 0x1f 0x4 0x0 0xe2 0xff \\\n    0xff 0xfd 0xff 0xff 0xfd 0xff 0xf9 0xb7 \\\n    0xb1 0xb4 0xff 0xff 0xff 0xff 0xfc 0xff \\\n    0xff 0xff 0xff 0x3 0x1 0x0 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfc 0x7 0x3 0x3 0xf5 0xfe \\\n    0xf9 0xff 0xff 0xf8 0xff 0xfd 0xf3 0x1 \\\n    0x0 0x15 0xfd 0xff 0xff 0xfe 0xff 0xfe \\\n    0xff 0xfb 0xff 0x8 0x0 0x0 0xff 0xfe \\\n    0xfe 0xff 0xfd 0xfa 0xff 0xff 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf8 0xff 0x1a 0x0 0x4 0xd8 0xff \\\n    0xff 0xff 0xff 0xfe 0xff 0xfb 0xb9 0x2 \\\n    0x9 0x33 0xff 0xfd 0xfe 0xff 0xfb 0xff \\\n    0xfe 0xff 0xfe 0x0 0x4 0x1 0xfb 0xff \\\n    0xff 0xe2 0x8e 0x30 0xfb 0xfc 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0x48 0x3 0x0 0x6f 0xfe \\\n    0xfe 0xfb 0xff 0xff 0xfd 0xff 0x4c 0x0 \\\n    0x0 0x8a 0xff 0xfd 0xfe 0xfc 0xff 0xfb \\\n    0xfe 0xfc 0xff 0x0 0x8 0x1 0xfa 0xaa \\\n    0x4b 0x1 0x0 0x6 0xff 0xf7 0xff 0xfa \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfb 0xfe 0xfb 0x9b 0x4 0x6 0x0 0x9f \\\n    0xff 0xf7 0xff 0xfb 0xf3 0x6d 0x0 0x3 \\\n    0x1b 0xf2 0xf9 0xf6 0xff 0xfc 0xfc 0xff \\\n    0xff 0xfc 0xff 0x1 0x0 0x0 0xd 0x0 \\\n    0x0 0x5 0x4 0x11 0xfb 0xff 0xfc 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0x4d 0x0 0x2 0x0 \\\n    0x2f 0x78 0x80 0x5d 0x1a 0xc 0x0 0x5 \\\n    0xaf 0xfd 0xff 0xff 0xfa 0xff 0xff 0xfe \\\n    0xf9 0xff 0xff 0x6 0x0 0x0 0x4 0x1 \\\n    0x3 0x51 0xb2 0xff 0xff 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xfb 0xfc 0xf0 0x57 0x2 0x0 \\\n    0x0 0x0 0x0 0x4 0x0 0x0 0x19 0xb0 \\\n    0xff 0xfc 0xff 0xfb 0xff 0xff 0xfa 0xff \\\n    0xff 0xf6 0xff 0x1 0x0 0x0 0x2b 0x8a \\\n    0xec 0xfe 0xff 0xff 0xfb 0xfc 0xfc 0xfa \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xff 0xfc 0xff 0xc5 0x5d \\\n    0x2c 0x8 0x3 0x17 0x48 0x91 0xec 0xff \\\n    0xff 0xfc 0xff 0xfd 0xff 0xfa 0xff 0xfd \\\n    0xff 0xff 0xff 0xd 0x62 0xc7 0xff 0xff \\\n    0xfc 0xfd 0xfa 0xff 0xfc 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xff 0xff 0xff 0xfd 0xfd 0xff \\\n    0xfd 0xff 0xff 0xff 0xfa 0xff 0xff 0xff \\\n    0xfb 0xff 0xfe 0xff 0xfe 0xfe 0xff 0xfd \\\n    0xfc 0xff 0xf6 0xff 0xff 0xfa 0xff 0xff \\\n    0xff 0xfe 0xfe 0xff 0xff 0xfe 0xff 0xff \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' '\n    face13.image =  '80 80 1 \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xff 0xff 0xfb 0xff 0xff 0xfc \\\n    0xff 0xff 0xfc 0xff 0xfe 0xfd 0xff 0xfd \\\n    0xfe 0xff 0xfa 0xfe 0xff 0xfc 0xfd 0xff \\\n    0xff 0xff 0xfe 0xff 0xfc 0xfb 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xff 0xff 0xfe 0xfc 0xff 0xff \\\n    0xfe 0xfc 0xff 0xf8 0xff 0xff 0xf8 0xff \\\n    0xff 0xfd 0xff 0xfd 0xfe 0xff 0xfd 0xf8 \\\n    0xff 0xff 0xfe 0xff 0xff 0xff 0xf4 0xfb \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xf6 0xfd 0xff 0xff 0xff 0xfe \\\n    0xfe 0xfe 0xff 0xfc 0xff 0xfe 0xfb 0xfc \\\n    0xfd 0xfe 0xff 0xff 0xfd 0xff 0xff 0xff \\\n    0xfe 0xfb 0xff 0xfb 0xf8 0xf6 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xf9 0x7 0x0 0x0 0xf8 0xff 0xff \\\n    0xff 0xfe 0xfe 0xff 0xfb 0xfd 0xff 0xff \\\n    0xfd 0xe0 0x84 0x30 0x17 0x0 0xd 0x35 \\\n    0x82 0xdf 0xff 0xff 0xff 0xfe 0xff 0xfa \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0x0 0x1 0xb 0xff 0xff 0xfa \\\n    0xff 0xfa 0xff 0xff 0xfe 0xff 0xff 0xf3 \\\n    0x81 0x8 0x0 0x1 0x1 0x2 0x0 0x2 \\\n    0x0 0xb 0x87 0xfe 0xff 0xfa 0xff 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x0 0x0 0xfd 0xff 0xff \\\n    0xff 0xfd 0xfe 0xff 0xfe 0xff 0xf9 0x6e \\\n    0x0 0x3 0x4 0x29 0x6d 0x80 0x71 0x2c \\\n    0x2 0x1 0x0 0x7d 0xff 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfa 0xff 0x3 0x3 0x2 0xff 0xfe 0xfd \\\n    0xff 0xff 0xfb 0xff 0xfd 0xfd 0xb5 0x0 \\\n    0x3 0x0 0xa2 0xff 0xff 0xff 0xff 0xfb \\\n    0x9f 0xc 0x0 0x0 0xca 0xfe 0xff 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfc 0x2 0x0 0x8 0xf9 0xfd 0xff \\\n    0xff 0xfd 0xff 0xfe 0xff 0xff 0x53 0x0 \\\n    0x0 0x84 0xfe 0xff 0xfd 0xfb 0xff 0xff \\\n    0xff 0x7a 0x2 0x0 0x64 0xff 0xfb 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    0xff 0xff 0xfd 0xff 0xff 0xfc 0x19 0x1 \\\n    0x0 0xe7 0xfd 0xfe 0xff 0xfc 0xff 0xff \\\n    0xfd 0xdc 0x0 0x0 0x26 0xff 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    0xfd 0xff 0xff 0xff 0xfd 0xff 0x7f 0x78 \\\n    0x79 0xfd 0xff 0xfb 0xff 0xfc 0xfd 0xff \\\n    0xff 0xf8 0x0 0x5 0x7 0xff 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    0xff 0xff 0xfe 0xfc 0xfd 0xff 0xf9 0xff \\\n    0xff 0xff 0xff 0xff 0xfc 0xff 0xff 0xf8 \\\n    0xff 0xe9 0x0 0x5 0x1b 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xfc 0xf8 0xff 0xfe \\\n    0xff 0xf9 0xfd 0xff 0xff 0xfb 0xf7 0xff \\\n    0xff 0xaf 0x2 0x0 0x51 0xfe 0xf9 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    0xfb 0xfc 0xfe 0xff 0xff 0xff 0xff 0xfe \\\n    0xfe 0xff 0xff 0xfd 0xff 0xff 0xff 0xfe \\\n    0xe4 0x25 0x0 0x0 0xc8 0xff 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    0xff 0xff 0xfc 0xfb 0xfd 0xfd 0xfd 0xff \\\n    0xfc 0xff 0xff 0xff 0xf9 0xf4 0xd1 0x83 \\\n    0x13 0x0 0x9 0x6d 0xf9 0xfa 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    0xfc 0xff 0xff 0xff 0xff 0xfe 0xff 0xfd \\\n    0xff 0xf6 0x7f 0x3 0x0 0x1 0x4 0x0 \\\n    0x3 0x1e 0x90 0xfd 0xff 0xff 0xfa 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x0 0x1 0x3 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xfd 0xfb 0xff 0xfd \\\n    0xfd 0xff 0x89 0x0 0x6 0x0 0x0 0x1 \\\n    0x2e 0xe1 0xff 0xff 0xfa 0xff 0xfb 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xff 0xfb 0xff 0xfa 0xff 0xff \\\n    0xff 0xfb 0x2 0x4 0x2 0xfb 0xff 0xff \\\n    0xfe 0xff 0xff 0xfd 0xfe 0xff 0xfb 0xfe \\\n    0xff 0xfe 0xc3 0x84 0x7e 0x72 0x36 0x0 \\\n    0x0 0x15 0xc3 0xfe 0xfd 0xff 0xfd 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xfe 0xfa 0xff 0xff 0xfe 0xff \\\n    0xff 0xff 0x0 0x0 0x0 0xff 0xff 0xfd \\\n    0xfe 0xfd 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xfb 0xff 0xfd 0xff 0xff 0xfa 0xff 0xb3 \\\n    0xd 0x0 0xf 0xeb 0xff 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xff 0xff 0xff 0xfb 0xff 0xff \\\n    0xff 0xfa 0x4 0x0 0x6 0xff 0xf6 0xff \\\n    0xff 0xfc 0xff 0xfe 0xff 0xfa 0xff 0xfa \\\n    0xff 0xff 0xfe 0xf9 0xff 0xfc 0xff 0xfa \\\n    0x87 0x0 0x9 0x74 0xff 0xf7 0xff 0xfb \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfb 0xfe 0xf9 0xff 0xfd 0xfc \\\n    0xf8 0xff 0x0 0x5 0x0 0xff 0xff 0xff \\\n    0xfe 0xfe 0xff 0xfd 0xfe 0xff 0xff 0xff \\\n    0xf9 0xff 0xff 0xff 0xfc 0xff 0xfa 0xff \\\n    0xe4 0x4 0x0 0x27 0xfd 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf9 0xff 0xff 0xff 0xfe 0xff 0xff \\\n    0xff 0xff 0x0 0x0 0xa 0xfe 0xf9 0xff \\\n    0xfd 0xfd 0xff 0xfd 0xff 0xff 0x8a 0x8c \\\n    0x90 0xff 0xfa 0xff 0xfb 0xff 0xff 0xfc \\\n    0xff 0x0 0x0 0xa 0xff 0xfa 0xfc 0xf9 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xff 0xfd 0x2c 0x86 0xdd 0xff \\\n    0xfd 0xf7 0x0 0x0 0x1 0xfc 0xff 0xfc \\\n    0xff 0xff 0xfb 0xff 0xff 0xfd 0x15 0x1 \\\n    0x0 0xe4 0xff 0xfd 0xff 0xff 0xf9 0xfe \\\n    0xea 0x1 0x6 0x11 0xfd 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xf3 0xff 0x6 0x0 0x7 0x47 \\\n    0xa7 0xfd 0x4 0x0 0x1 0xff 0xfc 0xfb \\\n    0xfd 0xff 0xff 0xff 0xfc 0xfe 0x54 0x4 \\\n    0x4 0x8e 0xfe 0xff 0xf9 0xff 0xff 0xff \\\n    0xa2 0x6 0x0 0x4a 0xff 0xf5 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfc 0xff 0xff 0x19 0x2 0x0 0x0 \\\n    0x0 0xc 0x0 0x0 0x5 0xff 0xff 0xff \\\n    0xff 0xfa 0xfe 0xff 0xff 0xff 0xb9 0x0 \\\n    0x0 0x9 0xbb 0xfd 0xff 0xff 0xff 0xdb \\\n    0x1c 0x0 0x4 0x9c 0xfd 0xff 0xff 0xfa \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xff 0xff 0xf4 0xb7 0x53 0x3 \\\n    0x0 0x4 0x0 0x0 0x4 0xff 0xfe 0xff \\\n    0xff 0xf6 0xff 0xff 0xfd 0xff 0xff 0x6c \\\n    0x0 0x3 0x0 0x3c 0x78 0x79 0x54 0x6 \\\n    0x1 0x1 0x3a 0xfc 0xfe 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xfc 0xfd 0xff 0xff 0xf9 0xed \\\n    0x8f 0x24 0x3 0x0 0x5 0xfa 0xff 0xff \\\n    0xfd 0xff 0xff 0xfb 0xff 0xfb 0xff 0xf7 \\\n    0x74 0x0 0x2 0x8 0x0 0x5 0x0 0x4 \\\n    0x3 0x3d 0xef 0xff 0xff 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xff 0xfe 0xff 0xff 0xfe \\\n    0xff 0xff 0xc7 0x68 0x16 0xfe 0xff 0xfa \\\n    0xff 0xff 0xfc 0xff 0xff 0xff 0xf9 0xff \\\n    0xff 0xcd 0x65 0x24 0x11 0x8 0x24 0x52 \\\n    0xb2 0xff 0xfc 0xfc 0xfe 0xff 0xf8 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfd 0xfb 0xfd 0xff 0xff 0xff \\\n    0xfb 0xfe 0xff 0xfb 0xfb 0xff 0xfc 0xff \\\n    0xff 0xfb 0xff 0xff 0xf4 0xff 0xfd 0xf8 \\\n    0xfe 0xff 0xfc 0xff 0xfb 0xf6 0xff 0xfb \\\n    0xff 0xf4 0xff 0xff 0xff 0xf7 0xff 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xf9 0xff 0xfd 0xf7 0xff 0xfb \\\n    0xff 0xff 0xfd 0xfe 0xfd 0xfe 0xff 0xff \\\n    0xff 0xfc 0xff 0xff 0xff 0xff 0xfc 0xff \\\n    0xff 0xff 0xf9 0xff 0xff 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xfd 0xfc 0xfd 0xff 0xff \\\n    0xff 0xf7 0xfc 0xff 0xff 0xfb 0xff 0xfd \\\n    0xfd 0xff 0xfb 0xfe 0xff 0xfe 0xfc 0xfb \\\n    0xfc 0xff 0xfd 0xfc 0xff 0xff 0xff 0xff \\\n    0xf7 0xff 0xff 0xf7 0xfc 0xff 0xf7 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xfe 0xff 0xff 0xff 0xfe 0xfb \\\n    0xff 0xff 0xff 0xfc 0xfd 0xff 0xff 0xff \\\n    0xfb 0xff 0xff 0xff 0xfa 0xfd 0xff 0xff \\\n    0xff 0xfd 0xff 0xff 0xff 0xff 0xf5 0xff \\\n    0xff 0xff 0xfb 0xff 0xff 0xff 0xfa 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xfe 0xfd 0xfd 0xff 0xff \\\n    0xff 0xff 0xff 0xfe 0xfe 0xff 0xff 0xff \\\n    0xff 0xfe 0xfb 0xff 0xfe 0xff 0xfb 0xff \\\n    0xfa 0xff 0xff 0xfe 0xfa 0xff 0xff 0xfa \\\n    0xfc 0xff 0xff 0xff 0xfe 0xfe 0xff 0xff \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs + ' '\n    face14.image = '80 80 1 \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xfe 0xfe 0xff 0xf9 0xff 0xff \\\n    0xfc 0xff 0xfb 0xff 0xfd 0xfe 0xff 0xff \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xfc 0xff 0xfa 0xff 0xff 0xfc \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xf9 0xff 0xff 0xff 0xfe 0xfb \\\n    0xff 0xfd 0xfd 0xff 0xff 0xfa 0xff 0xfb \\\n    ' + ffs + ' \\\n    0xf9 0xff 0xfe 0xff 0xff 0xfb 0xfd 0xfc \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xff 0xff 0xf3 0xff 0xff 0xff \\\n    0xfe 0xff 0xff 0xfc 0xfe 0xff 0xf7 0xff \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xff 0xf7 0xff 0xfe 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xff 0xfc 0xff 0xfe 0xf6 0xff \\\n    0xff 0xff 0xf9 0xff 0xff 0xff 0xff 0xfc \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xff 0xfe 0xfc 0xff 0xfa 0xf8 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xf9 0xff 0xff 0xff 0xff 0xf9 0xff 0xff \\\n    0xff 0xf9 0xff 0xff 0xf8 0xfa 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xfc 0xff 0xff 0xf6 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xfc 0xff 0xfb 0xff 0xf9 0xfc \\\n    0xff 0xff 0xfc 0xff 0xff 0xff 0xf8 0xfe \\\n    ' + ffs + ' \\\n    0xff 0xf8 0xff 0xfb 0xff 0xff 0xff 0xfc \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xfd 0xff 0xff 0xff 0xff \\\n    0xfa 0xfd 0xfa 0xfe 0xff 0xfd 0xff 0xfe \\\n    ' + ffs + ' \\\n    0xf9 0xff 0xff 0xfc 0xff 0xfd 0xfc 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xff 0xfd 0xfb 0xff 0x0 \\\n    0x0 0x4 0xff 0xfd 0xff 0xfd 0xfb 0xff \\\n    ' + ffs + ' \\\n    0xff 0xfc 0xfb 0xff 0xfd 0x0 0x7 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0xff 0xff 0x0 \\\n    0x0 0x2 0xfd 0xff 0xff 0xfd 0xff 0xff \\\n    0xfd 0xff 0xf9 0xfe 0xff 0xfd 0xff 0xff \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfc 0xfc 0xff 0xfc 0xfc 0xff 0xff 0x4 \\\n    0x1 0x7 0xfe 0xff 0xfd 0xff 0xf9 0xff \\\n    0xff 0xfc 0xff 0xff 0xfe 0xff 0xff 0xfd \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfc 0xff 0xfe 0x5 \\\n    0x0 0x1 0xf9 0xff 0xfe 0xfd 0xff 0xff \\\n    0xff 0xfa 0xff 0xff 0xfb 0xfa 0xfc 0xff \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xfb 0xff 0xfe 0xff 0xf8 0x5 \\\n    0x0 0x3 0xfc 0xfd 0xff 0xfb 0xff 0xfc \\\n    0xf8 0xff 0xff 0xf9 0xff 0xff 0xff 0xf6 \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xff 0xf6 0x82 0x85 0x84 0x4 \\\n    0x0 0x0 0x88 0x81 0x7f 0x87 0x7d 0x88 \\\n    0x84 0x84 0x85 0x7e 0x8a 0xf4 0xff 0xff \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xff 0x2 0x3 0x0 0x3 \\\n    0x2 0x6 0x0 0x5 0x0 0x5 0x1 0x0 \\\n    0x4 0x1 0x0 0x1 0x4 0xfe 0xfb 0xfc \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfa 0xff 0xfe 0xf3 0x2 0x0 0x8 0x0 \\\n    0x2 0x0 0x5 0x5 0x0 0x0 0x8 0x0 \\\n    0x0 0x0 0x6 0x1 0x26 0xff 0xff 0xff \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xff 0xff 0xfc 0xff 0xf8 0x5 \\\n    0x0 0x4 0xfe 0xfd 0xff 0xff 0xfa 0xff \\\n    0xfe 0x39 0x0 0x0 0xc6 0xfa 0xff 0xfe \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xfe 0xff 0x3 \\\n    0x0 0x0 0xff 0xff 0xfa 0xff 0xff 0xfe \\\n    0x8f 0x0 0x0 0x6f 0xfc 0xfe 0xff 0xfe \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xfe 0xff 0x3 \\\n    0x9 0x0 0xfa 0xf8 0xff 0xff 0xf9 0xe1 \\\n    0xd 0x1 0x22 0xee 0xff 0xff 0xff 0xfe \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xfe 0xff 0x3 \\\n    0x0 0x0 0xff 0xff 0xfc 0xff 0xff 0x47 \\\n    0x0 0x1 0xb7 0xfd 0xff 0xfd 0xff 0xfc \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xfe 0xff 0x3 \\\n    0x2 0x3 0xfc 0xff 0xfc 0xfe 0xa3 0x0 \\\n    0x6 0x57 0xfc 0xff 0xff 0xf6 0xff 0xff \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xfe 0xff 0x3 \\\n    0x0 0x0 0xfd 0xff 0xff 0xe2 0x19 0x0 \\\n    0x15 0xe9 0xfd 0xff 0xf6 0xff 0xff 0xfa \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xfe 0xff 0x3 \\\n    0x6 0x0 0xff 0xf7 0xfc 0x64 0x0 0x0 \\\n    0xa7 0xff 0xfe 0xfd 0xff 0xfc 0xf7 0xff \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xfe 0xff 0x3 \\\n    0x0 0x2 0xff 0xfa 0xbe 0x0 0x1 0x4e \\\n    0xff 0xfc 0xfe 0xfa 0xff 0xff 0xff 0xfd \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xfe 0xff 0x3 \\\n    0x2 0x0 0xfe 0xf6 0x1e 0x1 0xc 0xe6 \\\n    0xfc 0xff 0xfb 0xff 0xfc 0xfd 0xfd 0xff \\\n    0xff 0xfe 0xff 0xff 0xfe 0x4 0x1 0x0 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xff 0xfc 0xff 0xff 0x1 \\\n    0x2 0x0 0xff 0x72 0x2 0x0 0x96 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xfb 0xff 0x0 0x0 0x2 \\\n    0xfd 0xff 0xfe 0xfc 0xff 0xff 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf9 0xff 0xfd 0xf9 0xfd 0xff 0x7 \\\n    0x0 0x4 0xc7 0x0 0x0 0x41 0xff 0xfb \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xff 0xfc 0xff 0x5 0x1 0x0 \\\n    0xff 0xf9 0xff 0xe7 0x88 0x24 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xf7 0xff 0xff 0xfb 0xfa 0x0 \\\n    0x1 0x0 0x33 0x5 0x9 0xe0 0xf6 0xff \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xf4 0xff 0xff 0x2 0x0 0x0 \\\n    0xf9 0xa2 0x4c 0x4 0x0 0xa 0xfb 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xfe 0xff 0xf5 0xfe 0xff 0x3 \\\n    0x0 0x7 0x0 0x2 0x8a 0xff 0xf9 0xff \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xf9 0xff 0x0 0x8 0x0 \\\n    0x10 0x4 0x0 0x6 0x4 0x16 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf8 0xfd 0xff 0xff 0xff 0xf8 0x0 \\\n    0x2 0x8 0x1 0x31 0xfc 0xfb 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xf4 0xff 0xff 0xf7 0x5 0x1 0x3 \\\n    0x2 0x0 0x0 0x54 0xaf 0xfb 0xff 0xf9 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xff 0xff 0xff 0xf9 0xff 0x6 \\\n    0x0 0x0 0x4 0xcf 0xfd 0xff 0xff 0xfe \\\n    ' + ffs + ' \\\n    0xfa 0xff 0xfa 0xff 0xff 0x2 0x0 0x0 \\\n    0x28 0x8b 0xed 0xfb 0xff 0xfa 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xf9 0xfe 0xfd 0x1 \\\n    0x3 0x0 0x78 0xff 0xfe 0xff 0xff 0xfb \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfc 0xf9 0xfe 0x19 0x65 0xc6 \\\n    0xfc 0xff 0xff 0xff 0xfe 0xfb 0xff 0xf9 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xff 0xfe 0xff 0xff 0xfc 0xff \\\n    0xfd 0xff 0xff 0xfa 0xff 0xfe 0xf9 0xff \\\n    ' + ffs + ' \\\n    0xff 0xfc 0xff 0xff 0xfe 0xfb 0xfd 0xff \\\n    0xff 0xfe 0xfe 0xfc 0xff 0xff 0xfd 0xff \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' '\n    face20.image =  '80 80 1 \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xfe 0xfe 0xff 0xfa 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfb 0xff 0xfb 0xff \\\n    0xff 0xff 0xfc 0xff 0xfd 0xff 0xfd 0xff \\\n    0xfc 0xff 0xff 0xff 0xfb 0xff 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xf8 0xff 0xff 0xff 0xfe 0xfb \\\n    ' + ffs + ' \\\n    0xff 0xf7 0xff 0xfc 0xfe 0xff 0xff 0xfe \\\n    0xfb 0xff 0xff 0xff 0xfd 0xff 0xff 0xfd \\\n    0xff 0xfe 0xf9 0xfe 0xfd 0xff 0xfe 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xff 0xfe 0xf3 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xfd 0xff 0xff 0xfc 0xff 0xff \\\n    0xff 0xff 0xfc 0xfc 0xf7 0xfe 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0xfc 0xfb \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf9 0xff 0xfb 0xff 0xfe 0xf6 0xfe \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xfe 0xfc 0xfd 0xff 0xf8 0xfe \\\n    0xff 0xfb 0xfc 0xff 0xff 0xff 0xff 0xfd \\\n    0xff 0xfd 0xfe 0xff 0xfa 0xfe 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfa 0xff 0xff 0xff 0xff 0xfa 0xff 0xff \\\n    ' + ffs + ' \\\n    0xfd 0xf9 0xff 0xff 0xfd 0xfb 0xff 0xfd \\\n    0xff 0xfe 0xfe 0xfe 0xfe 0xfc 0xfd 0xfd \\\n    0xff 0xff 0xff 0xff 0xff 0xff 0xfe 0xf8 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xfc 0xff 0xfc 0xff 0xf9 0xfb \\\n    ' + ffs + ' \\\n    0xff 0xff 0xf8 0xff 0xfe 0xff 0xfa 0xfe \\\n    0xf8 0xff 0xff 0xfb 0xff 0xff 0xff 0xff \\\n    0xfb 0xff 0xff 0xfd 0xff 0xfe 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xfd 0xff 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xfe 0xfa 0xff 0xfc 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xf9 0xff 0xff 0xfa 0xfe \\\n    0xff 0xff 0xfa 0xf9 0xff 0xfe 0xf9 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xfe 0xff 0xfd 0xfb 0xff 0x0 \\\n    0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 \\\n    0x0 0x4 0x2 0x0 0x2 0x0 0xfb 0xff \\\n    0xff 0xfe 0xff 0xff 0xf1 0x97 0x3d 0x17 \\\n    0x3 0x15 0x41 0x90 0xee 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xff 0xfd 0xfc 0xff 0xff 0x0 \\\n    0x0 0x1 0x0 0x2 0x0 0x0 0x2 0x0 \\\n    0x0 0x7 0x0 0x0 0x1 0x0 0xff 0xff \\\n    0xff 0xfc 0xff 0xd1 0x1f 0x0 0x2 0x0 \\\n    0x2 0x0 0x0 0x4 0x1e 0xc4 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xfa 0xff 0xff 0xfe 0xf5 0x51 \\\n    0x0 0x0 0x5f 0x7a 0x86 0x85 0x86 0x81 \\\n    0x82 0x80 0x85 0x88 0x82 0x86 0xff 0xfd \\\n    0xf9 0xff 0xd3 0xb 0x0 0x8 0x12 0x62 \\\n    0x7a 0x61 0x1c 0x0 0x3 0x9 0xda 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xff 0xff 0xfc 0xfe 0xff 0xf1 \\\n    0x33 0x7 0x19 0xdc 0xff 0xfb 0xfb 0xff \\\n    0xff 0xfa 0xff 0xfe 0xf9 0xfc 0xff 0xff \\\n    0xfd 0xfa 0x4b 0x0 0x0 0x40 0xe6 0xff \\\n    0xff 0xf9 0xf0 0x46 0x0 0x3 0x43 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xfc 0xfc 0xfc 0xf7 0xff \\\n    0xe7 0x1a 0x2 0x24 0xe5 0xfe 0xfc 0xff \\\n    0xff 0xff 0xff 0xfc 0xff 0xff 0xfc 0xfc \\\n    0xff 0xd2 0x0 0x0 0xd 0xf2 0xff 0xfb \\\n    0xff 0xff 0xfd 0xf3 0xf 0x3 0x5 0xd2 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfc 0xfd 0xff 0xff 0xfd 0xfd \\\n    0xff 0xd3 0x14 0x0 0x25 0xec 0xff 0xff \\\n    0xf8 0xfe 0xfa 0xfb 0xff 0xfb 0xff 0xff \\\n    0xfe 0x83 0x0 0x1 0x72 0xfd 0xfe 0xfe \\\n    0xf8 0xff 0xff 0xfd 0x6e 0x0 0x0 0x89 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xfc 0xfd 0xf7 0xfd 0xff \\\n    0xff 0xfb 0xc1 0x0 0xf 0x3e 0xec 0xfc \\\n    0xff 0xff 0xff 0xff 0xfc 0xff 0xff 0xfe \\\n    0xfe 0x59 0x0 0x0 0xb7 0xfc 0xfe 0xff \\\n    0xff 0xff 0xff 0xfb 0xb4 0x6 0x0 0x59 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xfc 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xfd 0xa4 0x0 0x0 0x49 0xfa \\\n    0xff 0xfc 0xfc 0xff 0xf9 0xff 0xff 0xff \\\n    0xfd 0x1f 0x7 0x1 0xdf 0xff 0xfd 0xfc \\\n    0xfa 0xfc 0xff 0xfc 0xdc 0x0 0x1 0x2a \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfe 0xff 0xfb 0xff 0xfc 0xff \\\n    0xff 0xff 0xfd 0xff 0x7f 0x1 0x1 0x4f \\\n    0xfd 0xfe 0xfe 0xff 0xff 0xfc 0xff 0xfc \\\n    0xff 0x16 0x0 0x8 0xeb 0xff 0xff 0xff \\\n    0xff 0xfe 0xff 0xff 0xee 0x0 0x0 0x1d \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfa 0xff 0xff 0xff 0xff 0xfd 0xfe 0xfe \\\n    0xff 0xf9 0xff 0xff 0xfe 0x62 0x0 0x0 \\\n    0x63 0xff 0xfb 0xff 0xff 0xff 0xfc 0xff \\\n    0xff 0x7 0x0 0x0 0xff 0xff 0xfd 0xff \\\n    0xff 0xff 0xfe 0xff 0xfb 0x3 0x1 0xc \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xff 0xfa 0xfe 0xff 0xff 0xff \\\n    0xf8 0xff 0xfc 0xff 0xff 0xf7 0x41 0x1 \\\n    0x0 0x8d 0xfe 0xff 0xfc 0xfd 0xff 0xfa \\\n    0xfc 0x5 0x0 0x1 0xff 0xff 0xfd 0xff \\\n    0xfe 0xff 0xff 0xff 0xfe 0x0 0x0 0x6 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xff 0xfe 0xff 0xfe 0xfd 0xfc \\\n    0xff 0xff 0xff 0xfc 0xfc 0xff 0xf0 0x27 \\\n    0x0 0x0 0xb4 0xff 0xfe 0xfe 0xff 0xff \\\n    0xfd 0x1 0x1 0x3 0xfc 0xff 0xfc 0xff \\\n    0xfe 0xff 0xfe 0xff 0xff 0x0 0x0 0x2 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xff 0xfd 0xff 0xfd 0xff 0xff \\\n    0xfc 0xfe 0xfc 0xfe 0xfb 0xff 0xff 0xd4 \\\n    0x13 0x0 0x17 0xe3 0xff 0xff 0xfd 0xff \\\n    0xff 0x0 0x2 0x3 0xfd 0xff 0xfc 0xff \\\n    0xfe 0xff 0xfc 0xfe 0xff 0x0 0x2 0x2 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfb 0xfc 0xff 0xfb 0xff 0xf7 \\\n    0xff 0xff 0xff 0xff 0xff 0xf6 0xfb 0xff \\\n    0x90 0x2 0x2 0x50 0xff 0xff 0xfb 0xff \\\n    0xff 0x0 0x1 0x2 0xff 0xfe 0xfe 0xff \\\n    0xfe 0xff 0xfc 0xff 0xff 0x0 0x2 0x4 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfa 0xff 0xfe 0xff 0xff 0xfe 0xff 0xff \\\n    0xfd 0xff 0xf7 0xfe 0xfb 0xff 0xff 0xff \\\n    0xff 0x3d 0x0 0x6 0xc5 0xfc 0xff 0xfe \\\n    0xfe 0x3 0x0 0x3 0xff 0xfe 0xff 0xfd \\\n    0xfe 0xff 0xff 0xff 0xfb 0x3 0x0 0xb \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xfc 0xfc 0xff 0xf3 0xff \\\n    0xfd 0xff 0xf9 0xff 0xff 0xf9 0xff 0xff \\\n    0xf6 0xaa 0x0 0x0 0x65 0xff 0xff 0xff \\\n    0xfc 0x15 0x0 0x2 0xf6 0xfe 0xff 0xfe \\\n    0xfe 0xff 0xff 0xff 0xee 0x2 0x0 0x1a \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfc 0xff 0xff 0xff 0xff 0xb4 0xb1 \\\n    0xb7 0xf9 0xff 0xfd 0xff 0xff 0xfd 0xff \\\n    0xff 0xe2 0x0 0x4 0x1f 0xff 0xff 0xfd \\\n    0xfe 0x25 0x0 0x0 0xe7 0xfd 0xff 0xff \\\n    0xff 0xff 0xff 0xfa 0xe2 0x0 0x0 0x29 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xfe 0xff 0xff 0xfd 0x15 0x0 \\\n    0x1 0xf3 0xfd 0xff 0xf8 0xff 0xff 0xf9 \\\n    0xfe 0xf5 0x3 0x3 0x7 0xfc 0xff 0xff \\\n    0xff 0x48 0x7 0x0 0xc0 0xfd 0xff 0xfd \\\n    0xff 0xfb 0xff 0xf8 0xbc 0x0 0x0 0x55 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xff 0xfe 0xfd 0xff 0x33 0x9 \\\n    0x2 0xb9 0xfb 0xff 0xfe 0xff 0xff 0xff \\\n    0xff 0xd8 0x4 0x0 0x1a 0xff 0xf8 0xff \\\n    0xff 0x76 0x0 0xa 0x77 0xff 0xff 0xff \\\n    0xfc 0xff 0xf8 0xff 0x78 0x4 0x2 0x7d \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xfc 0xfe 0xfd 0xff 0x8a 0x0 \\\n    0x0 0x4c 0xff 0xfd 0xff 0xff 0xfb 0xfe \\\n    0xfe 0x6f 0x0 0x3 0x48 0xff 0xff 0xff \\\n    0xff 0xd0 0x0 0x0 0x1c 0xf4 0xff 0xf9 \\\n    0xff 0xff 0xff 0xf1 0x12 0x0 0x0 0xd2 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfc 0xfc 0xff 0xf6 0xf9 0xf2 0x1b \\\n    0x3 0x0 0x6d 0xf3 0xfb 0xff 0xf7 0xff \\\n    0x9f 0x0 0x6 0x4 0x9b 0xfb 0xfe 0xfb \\\n    0xff 0xf9 0x36 0x5 0x0 0x4b 0xea 0xff \\\n    0xfd 0xfe 0xf4 0x45 0x6 0x1 0x38 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xfa 0xff 0xff 0xfd 0xaf \\\n    0x5 0x0 0xc 0x1a 0x5d 0x80 0x78 0x2f \\\n    0x0 0x2 0x0 0x4d 0xff 0xff 0xff 0xff \\\n    0xff 0xfd 0xd6 0x7 0x1 0x2 0x17 0x5f \\\n    0x82 0x63 0x13 0x0 0x0 0x9 0xd4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xff 0xff 0xfb 0xff 0xfc 0xff \\\n    0xb0 0x19 0x0 0x0 0x4 0x0 0x0 0x0 \\\n    0x0 0x2 0x57 0xf0 0xfc 0xfb 0xff 0xfb \\\n    0xfa 0xff 0xf7 0xc1 0x1f 0x0 0x0 0x7 \\\n    0x0 0x0 0x0 0x6 0x1f 0xc2 0xff 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfa 0xff 0xfd 0xff 0xfc 0xff \\\n    0xff 0xec 0x91 0x48 0x17 0x3 0x8 0x2c \\\n    0x5d 0xc5 0xff 0xfc 0xff 0xff 0xff 0xfe \\\n    0xff 0xff 0xff 0xfe 0xf6 0x8c 0x3e 0x14 \\\n    0x4 0x15 0x47 0x89 0xf2 0xff 0xff 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfe 0xfe 0xff 0xfe 0xff 0xfb \\\n    0xff 0xff 0xff 0xfa 0xff 0xff 0xff 0xfd \\\n    0xff 0xfd 0xfd 0xff 0xff 0xff 0xfe 0xff \\\n    0xff 0xfd 0xfc 0xfd 0xff 0xfd 0xff 0xfd \\\n    0xff 0xfd 0xff 0xfb 0xff 0xfe 0xff 0xfd \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' '\n    face21.image = '80 80 1 \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xff 0xfd 0xf0 0x86 0x48 \\\n    0x19 0x4 0xa 0x27 0x61 0xbf 0xfc 0xff \\\n    0xfe 0xff 0xfb 0xff 0xfc 0xfb 0xff 0xfe \\\n    0xfd 0xff 0xfb 0xff 0xc3 0x67 0xe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfa 0xfe 0xb4 0x16 0x4 0x0 \\\n    0x2 0x0 0x0 0x6 0x0 0x0 0x5e 0xec \\\n    0xff 0xfb 0xff 0xfe 0xff 0xff 0xfc 0xfc \\\n    0xff 0xe1 0x8d 0x28 0x0 0x0 0x2 0xf9 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfd 0xfe 0xff 0xbe 0x1 0x0 0x0 0x18 \\\n    0x65 0x75 0x79 0x30 0x0 0x2 0x0 0x51 \\\n    0xff 0xf9 0xff 0xff 0xff 0xfb 0xff 0xb5 \\\n    0x51 0xe 0x0 0x3 0x0 0x0 0xb 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xf2 0xb 0x1 0x1 0x72 0xf9 \\\n    0xfb 0xff 0xfc 0xff 0xa0 0x2 0x0 0x0 \\\n    0xa4 0xff 0xfe 0xfc 0xff 0xfe 0x1e 0x1 \\\n    0x0 0x0 0x0 0xd 0x6 0x3 0x0 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0x82 0x6 0x1 0x45 0xf9 0xff \\\n    0xff 0xff 0xff 0xff 0xff 0x69 0x0 0x2 \\\n    0x49 0xf7 0xff 0xf7 0xff 0xff 0x0 0x0 \\\n    0x2 0x49 0xad 0xfa 0x0 0x1 0x2 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0x3d 0x0 0x1 0xc1 0xff 0xfc \\\n    0xfe 0xfb 0xfb 0xfb 0xfa 0xd5 0x8 0x0 \\\n    0x1c 0xfe 0xf9 0xff 0xff 0xfa 0x2d 0x91 \\\n    0xe8 0xfe 0xff 0xf7 0x6 0x2 0x0 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfb 0xfe 0x8 0x5 0x0 0xf5 0xff 0xfe \\\n    0xfc 0xff 0xfc 0xff 0xfa 0xfc 0x0 0x2 \\\n    0x8 0xfe 0xff 0xff 0xf7 0xff 0xff 0xf7 \\\n    0xff 0xf9 0xff 0xff 0x2 0x0 0x2 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xb5 0xb1 0xb7 0xfe 0xfc 0xff \\\n    0xff 0xfd 0xfe 0xff 0xff 0xe3 0x0 0x1 \\\n    0x22 0xff 0xff 0xfc 0xff 0xfe 0xff 0xff \\\n    0xfe 0xff 0xff 0xfd 0x0 0x4 0x3 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xf9 0xfe 0xff 0xfc 0xa6 0x8 0x0 \\\n    0x67 0xfc 0xff 0xff 0xfd 0xff 0xff 0xfd \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xff 0xfb 0xfe 0x35 0x0 0x3 \\\n    0xc4 0xff 0xfa 0xfe 0xfe 0xff 0xfe 0xff \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfd 0xfc 0xfe 0xfb 0xa2 0x2 0x0 0x54 \\\n    0xff 0xff 0xfd 0xff 0xfe 0xff 0xfb 0xff \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfd 0xda 0x6 0x0 0x14 0xed \\\n    0xff 0xfa 0xff 0xff 0xfd 0xff 0xfe 0xff \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfa 0xff 0xef 0x1f 0x9 0x0 0xb9 0xfe \\\n    0xff 0xfe 0xfe 0xfb 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xf3 0x3e 0x9 0x0 0x89 0xf9 0xff \\\n    0xfe 0xff 0xfd 0xfd 0xff 0xfe 0xfd 0xff \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfb 0x6a 0x0 0x1 0x63 0xfe 0xff 0xf9 \\\n    0xfa 0xff 0xff 0xff 0xff 0xfe 0xf9 0xff \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0x81 0x0 0x1 0x4d 0xff 0xff 0xfc 0xff \\\n    0xff 0xfe 0xff 0xfd 0xfa 0xff 0xfb 0xff \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xfd 0xff 0xff 0xfc 0xa3 \\\n    0x0 0x0 0x4a 0xf5 0xff 0xff 0xfd 0xff \\\n    0xfd 0xff 0xff 0xff 0xfd 0xff 0xff 0xfd \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfc 0xfd 0xff 0xfe 0xfc 0xfb 0xc5 0x2 \\\n    0x0 0x3c 0xe9 0xff 0xff 0xfb 0xff 0xfb \\\n    0xff 0xfc 0xff 0xf6 0xfe 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xfb 0xff 0xd3 0xc 0x0 \\\n    0x2c 0xf0 0xff 0xff 0xfb 0xff 0xff 0xfe \\\n    0xfa 0xff 0xff 0xfe 0xff 0xff 0xfb 0xff \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xf9 0xfc 0xfa 0xff 0xe7 0x1c 0x0 0x27 \\\n    0xe4 0xfc 0xfd 0xff 0xff 0xf8 0xf5 0xff \\\n    0xfe 0xff 0xf7 0xff 0xff 0xfc 0xff 0xfe \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfa 0xf6 0x2d 0x1 0x1c 0xda \\\n    0xff 0xff 0xf5 0xff 0xfc 0xff 0xff 0xff \\\n    0xff 0xf8 0xff 0xff 0xfb 0xfe 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfa 0xfc 0xff 0x47 0x8 0x0 0x56 0x82 \\\n    0x82 0x89 0x86 0x81 0x86 0x7e 0x84 0x7b \\\n    0x86 0x80 0xff 0xfe 0xff 0xff 0xfd 0xff \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfb 0x0 0x0 0x0 0x0 0x2 \\\n    0x0 0x4 0x0 0x0 0x5 0x0 0x2 0x2 \\\n    0x0 0x4 0xf9 0xfe 0xff 0xff 0xfb 0xff \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xff 0x0 0x0 0x0 0x2 0x0 \\\n    0x3 0x0 0x5 0x3 0x0 0x1 0x0 0x0 \\\n    0x2 0x0 0xfd 0xff 0xf8 0xff 0xff 0xfe \\\n    0xff 0xff 0xff 0xff 0x0 0x0 0x4 0xfe \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' '\n    face22.image = '80 80 1 \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xfe 0xfd 0xff 0xff 0xfc \\\n    ' + ffs + ' \\\n    0xff 0xfc 0xff 0xfb 0xff 0xfd 0xff 0xfd \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xff 0xff 0xfa 0xff 0xfe 0xfc \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfa 0xff 0xff 0xff 0xff 0xfa 0xfe 0xfb \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xfb 0xff 0xf9 0xff 0xff 0xfd \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xff 0xfe 0xf9 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf9 0xff 0xf7 0xff 0xff 0xfd 0xff \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xff 0xfd 0xff 0xfd 0xfa 0xff \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xf8 0xff 0xff 0xfd 0xf9 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xff 0xff 0xf9 0xff 0xf9 0xf9 \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xf8 0xff 0xfc 0xff 0xff 0xfa \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xff 0xff 0xf4 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfa 0xff 0xff 0xf9 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xfc 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xf8 0xfd 0xfe 0xfe 0xff 0xf7 0xfc \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf9 0xff 0xfc 0xff 0xff 0xff 0xfd \\\n    ' + ffs + ' \\\n    0xfc 0xfd 0xfd 0xfd 0xff 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xff 0xfe 0xff 0xfa 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xf9 0xff 0xff 0xfc 0xff 0xfc 0xfd 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfe 0xff 0xff 0xfd \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xff 0xf8 0xff 0xfd 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xfd 0xff 0xff 0x0 0x7 0x0 \\\n    0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 \\\n    0x1 0x0 0x1 0x0 0xff 0xfd 0xff 0xfd \\\n    0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 \\\n    0x0 0x0 0x0 0x0 0x2 0x3 0x0 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xfd 0xff 0xff 0x0 0x3 0x0 \\\n    0x0 0x0 0x5 0x0 0x1 0x0 0x1 0x1 \\\n    0x0 0x2 0x0 0x0 0xff 0xff 0xfd 0xff \\\n    0x0 0x0 0x4 0x0 0x0 0x3 0x0 0x0 \\\n    0x0 0x1 0x0 0x4 0x0 0x0 0x0 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xff 0xfb 0xf8 0x4c 0x0 0x4 \\\n    0x5b 0x87 0x80 0x84 0x81 0x85 0x87 0x81 \\\n    0x84 0x80 0x83 0x87 0xfc 0xff 0xff 0xff \\\n    0x4d 0x6 0x0 0x5c 0x83 0x7b 0x84 0x87 \\\n    0x85 0x81 0x7f 0x83 0x85 0x82 0x83 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xf9 0xff 0xff 0xf6 0x2a 0x0 \\\n    0x17 0xde 0xfe 0xff 0xff 0xf8 0xff 0xfb \\\n    0xff 0xfc 0xff 0xff 0xfe 0xfe 0xff 0xfa \\\n    0xf5 0x2e 0x5 0x16 0xdd 0xff 0xff 0xfd \\\n    0xfc 0xff 0xfe 0xfa 0xff 0xff 0xfe 0xfc \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfa 0xff 0xfe 0xff 0xf8 0xff 0xea 0x22 \\\n    0x7 0x22 0xe6 0xfc 0xff 0xff 0xfe 0xff \\\n    0xfc 0xfc 0xff 0xff 0xfd 0xfe 0xff 0xff \\\n    0xff 0xe6 0x20 0x0 0x27 0xe5 0xfe 0xff \\\n    0xfc 0xff 0xfa 0xff 0xfe 0xfd 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xff 0xff 0xfd 0xfd 0xff 0xd1 \\\n    0xa 0x0 0x2f 0xec 0xff 0xff 0xfa 0xff \\\n    0xff 0xff 0xff 0xfa 0xff 0xff 0xfe 0xff \\\n    0xff 0xff 0xda 0x8 0x5 0x2a 0xec 0xff \\\n    0xff 0xfc 0xfb 0xff 0xfe 0xff 0xff 0xfa \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfa 0xfe 0xff 0xfa 0xfd 0xff 0xfa 0xff \\\n    0xbe 0xf 0x0 0x3a 0xf2 0xff 0xff 0xfc \\\n    0xfe 0xff 0xff 0xfe 0xff 0xff 0xff 0xff \\\n    0xfe 0xf7 0xff 0xc2 0x0 0x0 0x3c 0xf2 \\\n    0xfd 0xfa 0xff 0xff 0xf9 0xfc 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfd 0xfc 0xff 0xff \\\n    0xfc 0x9d 0x9 0x0 0x41 0xf8 0xfa 0xff \\\n    0xfe 0xff 0xff 0xff 0xfc 0xfe 0xff 0xff \\\n    0xff 0xff 0xff 0xf7 0xa6 0x4 0x0 0x45 \\\n    0xf4 0xff 0xf7 0xfc 0xff 0xff 0xfa 0xfb \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf8 0xfe 0xfd 0xff 0xff 0xfd 0xff \\\n    0xff 0xff 0x7d 0x0 0x2 0x52 0xfe 0xfe \\\n    0xff 0xff 0xfe 0xfc 0xff 0xff 0xfd 0xff \\\n    0xfd 0xfd 0xfe 0xff 0xff 0x7b 0x3 0x0 \\\n    0x50 0xf9 0xff 0xff 0xfc 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xfa 0xff 0xff 0xfc 0xfe 0xff \\\n    0xff 0xff 0xff 0x63 0x0 0x0 0x62 0xff \\\n    0xfe 0xff 0xfe 0xff 0xfc 0xff 0xff 0xfd \\\n    0xff 0xff 0xfa 0xff 0xff 0xfb 0x5f 0x0 \\\n    0x0 0x65 0xfe 0xff 0xff 0xff 0xfa 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfc 0xfc 0xff 0xff 0xff 0xfd \\\n    0xfd 0xff 0xf5 0xfb 0x40 0x0 0x6 0x86 \\\n    0xfd 0xff 0xff 0xfb 0xff 0xf8 0xff 0xff \\\n    0xfc 0xfe 0xfe 0xff 0xfa 0xff 0xf8 0x44 \\\n    0x1 0x0 0x8a 0xff 0xff 0xfa 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xff 0xff 0xfd 0xfa 0xff 0xfd \\\n    0xfe 0xff 0xff 0xf8 0xf1 0x2a 0x0 0x0 \\\n    0xb8 0xfe 0xfb 0xff 0xff 0xff 0xfe 0xfe \\\n    0xff 0xfc 0xff 0xfa 0xff 0xff 0xff 0xee \\\n    0x2a 0x5 0x0 0xb2 0xff 0xfd 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xfe 0xf8 0xff 0xfc 0xff 0xfd 0xff \\\n    0xff 0xff 0xfa 0xff 0xfd 0xd6 0x8 0x0 \\\n    0x19 0xe8 0xff 0xfe 0xfb 0xff 0xff 0xf9 \\\n    0xf9 0xfe 0xff 0xff 0xf3 0xff 0xfe 0xfa \\\n    0xcd 0x11 0x0 0x15 0xec 0xff 0xf9 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfd 0xff 0xff 0xff \\\n    0xff 0xfa 0xff 0xff 0xfe 0xfb 0xa0 0x1 \\\n    0x0 0x52 0xff 0xff 0xff 0xff 0xf0 0xff \\\n    0xff 0xff 0xf6 0xff 0xff 0xf8 0xff 0xff \\\n    0xff 0x94 0x5 0x0 0x56 0xf8 0xfb 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfa 0xfa 0xff 0xfa 0xff 0xff 0xfe 0xf8 \\\n    0xff 0xfd 0xff 0xf9 0xfe 0xff 0xfd 0x37 \\\n    0x9 0x3 0xc3 0xff 0xfa 0xfc 0xff 0xfe \\\n    0xfe 0xfc 0xff 0xfd 0xff 0xfc 0xfe 0xfb \\\n    0xfe 0xff 0x37 0x0 0x0 0xd3 0xff 0xfa \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xff 0xff 0xfd 0xff 0xf9 0xff \\\n    0xff 0xff 0xfe 0xff 0xff 0xff 0xf7 0xad \\\n    0x0 0x0 0x68 0xff 0xff 0xfc 0xfe 0xff \\\n    0xff 0xfa 0xfd 0xff 0xfe 0xff 0xff 0xfc \\\n    0xff 0xff 0xa4 0x5 0x0 0x5c 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xfb 0xff 0xb7 0xaf 0xb7 0xfe \\\n    0xff 0xff 0xf9 0xff 0xfa 0xff 0xff 0xde \\\n    0x2 0x1 0x27 0xfd 0xfe 0xff 0xff 0xb2 \\\n    0xb0 0xb9 0xfd 0xff 0xff 0xfe 0xfb 0xff \\\n    0xff 0xff 0xe1 0x0 0x3 0x22 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfb 0xfd 0xff 0xff 0xf 0x0 0x4 0xf1 \\\n    0xff 0xff 0xfe 0xff 0xfb 0xff 0xf8 0xfe \\\n    0x1 0x0 0xa 0xff 0xff 0xfc 0xfc 0x15 \\\n    0x0 0x5 0xef 0xfe 0xff 0xff 0xff 0xfe \\\n    0xfe 0xff 0xf8 0x3 0x0 0xe 0xfb 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xfd 0xff 0x37 0x0 0x4 0xb9 \\\n    0xfc 0xff 0xfc 0xf5 0xff 0xff 0xfe 0xd3 \\\n    0x1 0x0 0x10 0xfd 0xfc 0xff 0xff 0x31 \\\n    0x1 0x0 0xbd 0xfc 0xff 0xfe 0xfe 0xff \\\n    0xff 0xff 0xd1 0x1 0x0 0x19 0xfa 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xf9 0xff 0x8b 0x0 0x3 0x44 \\\n    0xff 0xff 0xff 0xff 0xfb 0xf9 0xfd 0x6e \\\n    0x0 0x5 0x4b 0xff 0xfc 0xff 0xff 0x8b \\\n    0x0 0x0 0x4a 0xff 0xf8 0xfe 0xff 0xfc \\\n    0xfd 0xfb 0x74 0x0 0x3 0x47 0xff 0xfb \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xf8 0xf2 0x1c 0x0 0x2 \\\n    0x6e 0xfa 0xfc 0xff 0xfb 0xff 0x9d 0x3 \\\n    0x1 0x3 0x9d 0xff 0xff 0xf8 0xfd 0xf0 \\\n    0x11 0x6 0x0 0x6b 0xff 0xff 0xff 0xff \\\n    0xff 0x9c 0x0 0x1 0x0 0xa4 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xfd 0xfd 0xff 0xfd 0xac 0x6 0x5 \\\n    0x4 0x12 0x61 0x7d 0x7a 0x31 0x0 0x5 \\\n    0x5 0x40 0xff 0xfa 0xfd 0xff 0xff 0xff \\\n    0xb4 0x4 0x0 0x0 0x1a 0x58 0x83 0x70 \\\n    0x2e 0x5 0x1 0x0 0x49 0xff 0xf8 0xfb \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0xff 0xb9 0x5 \\\n    0x0 0x1 0x0 0x0 0x0 0x0 0x2 0x0 \\\n    0x55 0xfa 0xfd 0xff 0xff 0xff 0xf8 0xfe \\\n    0xff 0xb1 0x17 0x4 0x0 0x8 0x0 0x0 \\\n    0x2 0x0 0x2 0x5d 0xf5 0xfa 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf9 0xff 0xfe 0xff 0xf9 0xfe 0xfb \\\n    0x8e 0x3b 0x23 0x4 0x9 0x2d 0x5c 0xc2 \\\n    0xff 0xff 0xfe 0xf8 0xff 0xff 0xfe 0xff \\\n    0xfb 0xff 0xec 0x8b 0x42 0x16 0xd 0x7 \\\n    0x2a 0x68 0xbb 0xfc 0xfe 0xff 0xff 0xfa \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfb 0xff 0xfc 0xff 0xfb 0xfc \\\n    0xfd 0xff 0xfd 0xff 0xff 0xfd 0xff 0xfe \\\n    0xfc 0xfe 0xff 0xff 0xfe 0xff 0xfd 0xfc \\\n    0xff 0xfd 0xff 0xff 0xfe 0xff 0xfa 0xff \\\n    0xfe 0xfc 0xfe 0xff 0xfe 0xff 0xfe 0xff \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' '\n    face23.image = '80 80 1 \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xfe 0xfd 0xff 0xff 0xfc \\\n    ' + ffs + ' \\\n    0xff 0xfc 0xff 0xfb 0xff 0xfd 0xff 0xfd \\\n    0xff 0xfd 0xfc 0xff 0xff 0xfe 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xff 0xfe 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfa 0xff 0xff 0xff 0xff 0xfa 0xfe 0xfb \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xfb 0xff 0xf9 0xff 0xff 0xfd \\\n    0xff 0xfe 0xfd 0xff 0xff 0xff 0xfd 0xf9 \\\n    0xfd 0xfd 0xfc 0xfe 0xff 0xff 0xff 0xf9 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf9 0xff 0xf7 0xff 0xff 0xfd 0xff \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xff 0xfd 0xff 0xfd 0xfa 0xff \\\n    0xfe 0xff 0xff 0xfd 0xfb 0xfe 0xff 0xff \\\n    0xff 0xff 0xff 0xfe 0xfa 0xfc 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xff 0xff 0xf9 0xff 0xf9 0xf9 \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xf8 0xff 0xfc 0xff 0xff 0xfa \\\n    0xff 0xfe 0xfd 0xfe 0xff 0xff 0xfb 0xf7 \\\n    0xfb 0xfc 0xfe 0xff 0xff 0xff 0xfe 0xfc \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfa 0xff 0xff 0xf9 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xfc 0xff 0xff \\\n    0xfe 0xfc 0xfd 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xff 0xfc 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf9 0xff 0xfc 0xff 0xff 0xff 0xfd \\\n    ' + ffs + ' \\\n    0xfc 0xfd 0xfd 0xfd 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xfd 0xfb 0xfd 0xff \\\n    0xff 0xff 0xff 0xff 0xff 0xfe 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xf9 0xff 0xff 0xfc 0xff 0xfc 0xfd 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfe 0xff 0xff 0xfd \\\n    0xfc 0xff 0xff 0xfd 0xfd 0xff 0xff 0xfb \\\n    0xfd 0xff 0xff 0xfc 0xfd 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xfd 0xff 0xff 0x0 0x7 0x0 \\\n    0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 \\\n    0x1 0x0 0x1 0x0 0xff 0xfd 0xff 0xfd \\\n    0xff 0xff 0xd9 0x86 0x35 0xf 0xa 0xe \\\n    0x35 0x85 0xdd 0xff 0xff 0xfc 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xfd 0xff 0xff 0x0 0x3 0x0 \\\n    0x0 0x0 0x5 0x0 0x1 0x0 0x1 0x1 \\\n    0x0 0x8 0x0 0x0 0xff 0xfc 0xfd 0xff \\\n    0xfe 0x7e 0x6 0x3 0x0 0x1 0x2 0x0 \\\n    0x0 0x1 0x9 0x8c 0xff 0xfe 0xff 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xff 0xfb 0xf8 0x4c 0x0 0x4 \\\n    0x5b 0x87 0x80 0x84 0x81 0x85 0x87 0x81 \\\n    0x85 0x7e 0x88 0x83 0xfb 0xff 0xff 0xf7 \\\n    0x6a 0x0 0x2 0x0 0x27 0x70 0x80 0x6c \\\n    0x34 0x0 0x8 0x0 0x7a 0xfd 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xf9 0xff 0xff 0xf6 0x2a 0x0 \\\n    0x17 0xde 0xfe 0xff 0xff 0xf8 0xff 0xfb \\\n    0xff 0xfc 0xff 0xf8 0xff 0xfe 0xfd 0xbc \\\n    0x0 0x4 0x8 0xa4 0xff 0xfc 0xff 0xfa \\\n    0xff 0xa1 0x0 0x3 0x4 0xce 0xfa 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfa 0xff 0xfe 0xff 0xf8 0xff 0xea 0x22 \\\n    0x7 0x22 0xe6 0xfc 0xff 0xff 0xfe 0xff \\\n    0xfa 0xff 0xff 0xff 0xff 0xfd 0xff 0x4d \\\n    0x5 0x0 0x7e 0xfe 0xfc 0xff 0xfd 0xff \\\n    0xfb 0xfe 0x84 0x0 0x3 0x64 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xff 0xff 0xfd 0xfd 0xff 0xd1 \\\n    0xa 0x0 0x2f 0xec 0xff 0xff 0xfa 0xff \\\n    0xff 0xff 0xfe 0xfe 0xff 0xff 0xff 0x12 \\\n    0x0 0x4 0xe8 0xfe 0xff 0xfe 0xff 0xfc \\\n    0xff 0xfc 0xd4 0x1 0x2 0x22 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfa 0xfe 0xff 0xfa 0xfd 0xff 0xfa 0xff \\\n    0xbe 0xf 0x0 0x3a 0xf2 0xff 0xff 0xfc \\\n    0xff 0xfb 0xff 0xff 0xff 0xfd 0xff 0x85 \\\n    0x7b 0x7d 0xf8 0xfc 0xff 0xff 0xff 0xfe \\\n    0xf8 0xff 0xfa 0x2 0x1 0xc 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfd 0xfc 0xff 0xff \\\n    0xfc 0x9d 0x9 0x0 0x41 0xf8 0xfa 0xff \\\n    0xfe 0xff 0xff 0xff 0xff 0xfb 0xfb 0xfe \\\n    0xf8 0xff 0xfa 0xff 0xf9 0xf9 0xff 0xff \\\n    0xff 0xf6 0xed 0x0 0x0 0x22 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf8 0xfe 0xfd 0xff 0xff 0xfd 0xff \\\n    0xff 0xff 0x7d 0x0 0x2 0x52 0xfe 0xfe \\\n    0xff 0xfe 0xff 0xfb 0xfe 0xff 0xfe 0xff \\\n    0xff 0xfa 0xff 0xff 0xfe 0xff 0xfc 0xff \\\n    0xfb 0xff 0xae 0x0 0x6 0x51 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xfa 0xff 0xff 0xfc 0xfe 0xff \\\n    0xff 0xff 0xff 0x63 0x0 0x0 0x62 0xff \\\n    0xff 0xfc 0xff 0xfe 0xfa 0xff 0xff 0xff \\\n    0xff 0xfe 0xff 0xfb 0xfb 0xff 0xfd 0xff \\\n    0xff 0xe8 0x24 0x2 0x0 0xc0 0xff 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfc 0xfc 0xff 0xff 0xff 0xfd \\\n    0xfd 0xff 0xf5 0xfb 0x40 0x0 0x6 0x86 \\\n    0xff 0xf8 0xff 0xf8 0xff 0xff 0xfa 0xff \\\n    0xff 0xf8 0xfe 0xff 0xff 0xff 0xf5 0xd0 \\\n    0x81 0x11 0x0 0x2 0x67 0xff 0xfb 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xff 0xff 0xfd 0xfa 0xff 0xfd \\\n    0xfe 0xff 0xff 0xf8 0xf1 0x2a 0x0 0x0 \\\n    0xaa 0xff 0xfd 0xff 0xfd 0xff 0xff 0xfc \\\n    0xff 0xff 0xff 0x80 0x0 0x0 0x0 0x0 \\\n    0x0 0x5 0x1b 0x97 0xff 0xff 0xf8 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xfe 0xf8 0xff 0xfc 0xff 0xfd 0xff \\\n    0xff 0xff 0xfa 0xff 0xfd 0xd6 0x8 0x0 \\\n    0x21 0xe6 0xff 0xfb 0xff 0xff 0xfd 0xff \\\n    0xfe 0xf9 0xff 0x85 0x3 0x1 0x2 0x6 \\\n    0x3 0x2b 0xe1 0xff 0xfe 0xfd 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfd 0xff 0xff 0xff \\\n    0xff 0xfa 0xff 0xff 0xfe 0xfb 0xa0 0x1 \\\n    0x0 0x4f 0xff 0xff 0xfc 0xfe 0xff 0xf8 \\\n    0xfc 0xff 0xfa 0xbb 0x85 0x83 0x70 0x32 \\\n    0x0 0x0 0x17 0xc1 0xff 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfa 0xfa 0xff 0xfa 0xff 0xff 0xfe 0xf8 \\\n    0xff 0xfd 0xff 0xf9 0xfe 0xff 0xfd 0x37 \\\n    0x2 0x0 0xc8 0xfc 0xff 0xfd 0xfd 0xff \\\n    0xff 0xff 0xff 0xff 0xff 0xfc 0xff 0xff \\\n    0xb2 0x7 0x0 0x14 0xe2 0xff 0xf7 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xff 0xff 0xfd 0xff 0xf9 0xff \\\n    0xff 0xff 0xfe 0xff 0xff 0xff 0xf7 0xad \\\n    0x4 0x0 0x68 0xff 0xfa 0xfc 0xff 0xff \\\n    0xff 0xfa 0xff 0xff 0xff 0xff 0xfc 0xff \\\n    0xfd 0x88 0x4 0x0 0x7d 0xff 0xff 0xf9 \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xfb 0xff 0xb7 0xaf 0xb7 0xfe \\\n    0xff 0xff 0xf9 0xff 0xfa 0xff 0xff 0xde \\\n    0x0 0x6 0x21 0xff 0xff 0xff 0xfd 0xff \\\n    0xff 0xff 0xfc 0xff 0xfe 0xf9 0xff 0xff \\\n    0xff 0xde 0x1 0x5 0x22 0xfb 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfb 0xfd 0xff 0xff 0xf 0x0 0x4 0xf1 \\\n    0xff 0xff 0xfe 0xff 0xfb 0xff 0xf8 0xfe \\\n    0x0 0x0 0x9 0xff 0xfa 0xff 0xfe 0x8e \\\n    0x8e 0x8c 0xfb 0xfd 0xff 0xf8 0xfc 0xff \\\n    0xff 0xfb 0x0 0x2 0x6 0xfe 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xfd 0xff 0x37 0x0 0x4 0xb9 \\\n    0xfc 0xff 0xfc 0xf5 0xff 0xff 0xfe 0xd3 \\\n    0x0 0x0 0x1a 0xff 0xff 0xfb 0xff 0x1b \\\n    0x0 0x0 0xee 0xff 0xf8 0xff 0xff 0xfd \\\n    0xfc 0xf0 0x0 0x3 0x13 0xff 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xf9 0xff 0x8b 0x0 0x3 0x44 \\\n    0xff 0xff 0xff 0xff 0xfb 0xf9 0xfd 0x6e \\\n    0x0 0x0 0x45 0xfe 0xfe 0xff 0xf7 0x4d \\\n    0x7 0x3 0x88 0xfe 0xfd 0xfe 0xff 0xf7 \\\n    0xfd 0xa7 0x0 0x3 0x4a 0xff 0xfc 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xf8 0xf2 0x1c 0x0 0x2 \\\n    0x6e 0xfa 0xfc 0xff 0xfb 0xff 0x9d 0x3 \\\n    0x1 0x0 0xa9 0xfa 0xff 0xff 0xff 0xc0 \\\n    0x0 0x2 0x9 0xb8 0xff 0xfe 0xfe 0xff \\\n    0xdc 0x1f 0x0 0x0 0xa1 0xfe 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xfd 0xfd 0xff 0xfd 0xac 0x6 0x5 \\\n    0x4 0x12 0x61 0x7d 0x7a 0x31 0x0 0x5 \\\n    0x1 0x4c 0xfb 0xff 0xff 0xfd 0xfa 0xfe \\\n    0x70 0x0 0x4 0x0 0x35 0x79 0x7c 0x4d \\\n    0x3 0x6 0x2 0x3f 0xf6 0xff 0xfc 0xfa \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0xff 0xb9 0x5 \\\n    0x0 0x1 0x0 0x0 0x0 0x0 0x2 0x0 \\\n    0x55 0xf0 0xff 0xff 0xf7 0xff 0xff 0xfa \\\n    0xfb 0x72 0x0 0x6 0x0 0x4 0x0 0x4 \\\n    0x3 0x0 0x42 0xe9 0xfd 0xff 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf9 0xff 0xfe 0xff 0xf9 0xfe 0xfb \\\n    0x8e 0x3b 0x23 0x4 0x9 0x2d 0x5c 0xc2 \\\n    0xff 0xf9 0xff 0xfd 0xff 0xff 0xf7 0xff \\\n    0xff 0xfd 0xd2 0x65 0x26 0xc 0xc 0x1c \\\n    0x57 0xb4 0xf8 0xff 0xff 0xfd 0xff 0xfb \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfb 0xff 0xfc 0xff 0xfb 0xfc \\\n    0xfd 0xff 0xfd 0xff 0xff 0xfd 0xff 0xfe \\\n    0xfa 0xff 0xfa 0xff 0xfc 0xfd 0xff 0xfe \\\n    0xfd 0xff 0xff 0xfe 0xff 0xff 0xfa 0xff \\\n    0xfd 0xfb 0xff 0xfa 0xff 0xff 0xf9 0xff \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' '\n    face24.image = '80 80 1 \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xfe 0xfd 0xff 0xff 0xfc \\\n    ' + ffs + ' \\\n    0xff 0xfc 0xff 0xfb 0xff 0xfd 0xff 0xfd \\\n    ' + ffs + ' \\\n    0xfc 0xfd 0xff 0xfb 0xff 0xfe 0xff 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfa 0xff 0xff 0xff 0xff 0xfa 0xfe 0xfb \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xfb 0xff 0xf9 0xff 0xff 0xfd \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xfd 0xfb 0xfa 0xff 0xfb 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf9 0xff 0xf7 0xff 0xff 0xfd 0xff \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xff 0xfd 0xff 0xfd 0xfa 0xff \\\n    ' + ffs + ' \\\n    0xfd 0xfd 0xff 0xff 0xff 0xf7 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xff 0xff 0xf9 0xff 0xf9 0xf9 \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xf8 0xff 0xfc 0xff 0xff 0xfa \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfe 0xfc 0xf9 0xff 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfa 0xff 0xff 0xf9 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xff 0xfc 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xf8 0xff 0xfe 0xff 0xff 0xfa 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf9 0xff 0xfc 0xff 0xff 0xff 0xfd \\\n    ' + ffs + ' \\\n    0xfc 0xfd 0xfd 0xfd 0xff 0xff 0xff 0xff \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfe 0xff 0xfe 0xfc 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xf9 0xff 0xff 0xfc 0xff 0xfc 0xfd 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfe 0xff 0xff 0xfd \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xff 0xf9 0xff 0xff 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xfd 0xff 0xff 0x0 0x7 0x0 \\\n    0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 \\\n    0x1 0x0 0x1 0x0 0xff 0xfd 0xff 0xfd \\\n    ' + ffs + ' \\\n    0xff 0x0 0x4 0x4 0xfc 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xfd 0xff 0xff 0x0 0x3 0x0 \\\n    0x0 0x0 0x5 0x0 0x1 0x0 0x1 0x1 \\\n    0x0 0x0 0x0 0x3 0xff 0xfe 0xfd 0xff \\\n    0xfd 0xff 0xff 0xff 0xff 0xfb 0xff 0xff \\\n    0xfd 0x0 0x0 0x0 0xff 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xff 0xfb 0xf8 0x4c 0x0 0x4 \\\n    0x5b 0x87 0x80 0x84 0x81 0x85 0x87 0x81 \\\n    0x82 0x7f 0x88 0x85 0xf6 0xff 0xff 0xfc \\\n    0xff 0xfc 0xff 0xff 0xfc 0xff 0xfb 0xfd \\\n    0xff 0x3 0x3 0x5 0xff 0xff 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xf9 0xff 0xff 0xf6 0x2a 0x0 \\\n    0x17 0xde 0xfe 0xff 0xff 0xf8 0xff 0xfb \\\n    0xff 0xff 0xff 0xfe 0xff 0xfc 0xff 0xfd \\\n    0xfe 0xff 0xff 0xff 0xfc 0xfd 0xff 0xfe \\\n    0xfa 0x0 0x2 0x0 0xff 0xfc 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfa 0xff 0xfe 0xff 0xf8 0xff 0xea 0x22 \\\n    0x7 0x22 0xe6 0xfc 0xff 0xff 0xfe 0xff \\\n    0xff 0xff 0xf8 0xff 0xfd 0xfe 0xff 0xff \\\n    0xff 0xfb 0xff 0xfb 0xff 0xff 0xff 0xfc \\\n    0xff 0x1 0x6 0x0 0xff 0xfc 0xff 0xfc \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xff 0xff 0xfd 0xfd 0xff 0xd1 \\\n    0xa 0x0 0x2f 0xec 0xff 0xff 0xfa 0xff \\\n    0xff 0xfe 0xff 0xff 0xfb 0xff 0x84 0x80 \\\n    0x83 0x7c 0x8b 0x7e 0x82 0x86 0x78 0x8c \\\n    0x83 0x0 0x0 0x9 0x7a 0x83 0x87 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfa 0xfe 0xff 0xfa 0xfd 0xff 0xfa 0xff \\\n    0xbe 0xf 0x0 0x3a 0xf2 0xff 0xff 0xfc \\\n    0xfc 0xf9 0xff 0xfe 0xff 0xff 0x0 0x3 \\\n    0x1 0x5 0x0 0x3 0x3 0x4 0x0 0x0 \\\n    0x1 0x1 0x1 0x0 0xa 0x1 0x0 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfd 0xfc 0xff 0xff \\\n    0xfc 0x9d 0x9 0x0 0x41 0xf8 0xfa 0xff \\\n    0xff 0xff 0xfe 0xf8 0xff 0xff 0x2e 0x0 \\\n    0x1 0x0 0x3 0x0 0x0 0x0 0x9 0x0 \\\n    0x0 0x3 0x0 0x3 0x0 0x1 0x0 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf8 0xfe 0xfd 0xff 0xff 0xfd 0xff \\\n    0xff 0xff 0x7d 0x0 0x2 0x52 0xfe 0xfe \\\n    0xfe 0xff 0xff 0xff 0xff 0xfd 0xc0 0x4 \\\n    0x0 0x38 0xfa 0xff 0xff 0xff 0xf7 0xff \\\n    0xff 0x0 0x0 0x2 0xfe 0xff 0xff 0xfc \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xfa 0xff 0xff 0xfc 0xfe 0xff \\\n    0xff 0xff 0xff 0x63 0x0 0x0 0x62 0xff \\\n    0xff 0xff 0xf9 0xff 0xfb 0xff 0xfd 0x69 \\\n    0x0 0x0 0x90 0xfc 0xfd 0xff 0xff 0xfd \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfc 0xfc 0xff 0xff 0xff 0xfd \\\n    0xfd 0xff 0xf5 0xfb 0x40 0x0 0x6 0x86 \\\n    0xff 0xfa 0xff 0xfa 0xff 0xfc 0xff 0xf8 \\\n    0x22 0x0 0x7 0xe4 0xff 0xfd 0xf9 0xff \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xff 0xff 0xfd 0xfa 0xff 0xfd \\\n    0xfe 0xff 0xff 0xf8 0xf1 0x2a 0x0 0x0 \\\n    0xb5 0xff 0xff 0xff 0xfa 0xff 0xff 0xf6 \\\n    0xb1 0x3 0x3 0x44 0xfd 0xf8 0xff 0xfb \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xfe 0xf8 0xff 0xfc 0xff 0xfd 0xff \\\n    0xff 0xff 0xfa 0xff 0xfd 0xd6 0x8 0x0 \\\n    0x11 0xec 0xff 0xfb 0xff 0xff 0xf9 0xff \\\n    0xff 0x60 0x0 0x5 0x9e 0xff 0xfb 0xfc \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfd 0xff 0xff 0xff \\\n    0xff 0xfa 0xff 0xff 0xfe 0xfb 0xa0 0x1 \\\n    0x5 0x5b 0xf8 0xff 0xfe 0xff 0xff 0xf7 \\\n    0xfc 0xee 0x1a 0x0 0x10 0xea 0xfc 0xff \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfa 0xfa 0xff 0xfa 0xff 0xff 0xfe 0xf8 \\\n    0xff 0xfd 0xff 0xf9 0xfe 0xff 0xfd 0x37 \\\n    0x2 0x0 0xcb 0xff 0xfd 0xff 0xff 0xfe \\\n    0xff 0xfe 0xa8 0x3 0x2 0x5c 0xfe 0xff \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xff 0xff 0xfd 0xff 0xf9 0xff \\\n    0xff 0xff 0xfe 0xff 0xff 0xff 0xf7 0xad \\\n    0x2 0x0 0x6f 0xfb 0xfb 0xff 0xfb 0xff \\\n    0xfd 0xff 0xf8 0x52 0x0 0x0 0xb9 0xfb \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xfb 0xff 0xb7 0xaf 0xb7 0xfe \\\n    0xff 0xff 0xf9 0xff 0xfa 0xff 0xff 0xde \\\n    0x0 0x2 0x22 0xfd 0xff 0xff 0xfd 0xff \\\n    0xfe 0xff 0xff 0xdd 0x11 0x3 0x17 0xf9 \\\n    0xff 0x0 0x1 0x2 0xff 0xff 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfb 0xfd 0xff 0xff 0xf 0x0 0x4 0xf1 \\\n    0xff 0xff 0xfe 0xff 0xfb 0xff 0xf8 0xfe \\\n    0x1 0x0 0x10 0xf9 0xfc 0xff 0xff 0xff \\\n    0xfc 0xff 0xfb 0xfc 0x9e 0x0 0x0 0x70 \\\n    0xff 0x3 0x0 0x2 0xff 0xff 0xfc 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfa 0xfd 0xff 0x37 0x0 0x4 0xb9 \\\n    0xfc 0xff 0xfc 0xf5 0xff 0xff 0xfe 0xd3 \\\n    0x0 0x0 0x14 0xfa 0xff 0xff 0xfb 0xff \\\n    0xff 0xf5 0xff 0xff 0xfa 0x41 0x0 0x4 \\\n    0xc5 0x0 0x7 0x0 0xff 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xf9 0xff 0x8b 0x0 0x3 0x44 \\\n    0xff 0xff 0xff 0xff 0xfb 0xf9 0xfd 0x6e \\\n    0x0 0x6 0x45 0xff 0xf9 0xff 0xff 0xff \\\n    0xfb 0xff 0xff 0xff 0xff 0xd6 0x5 0x4 \\\n    0x32 0x6 0x0 0x5 0xfa 0xfc 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xf8 0xf2 0x1c 0x0 0x2 \\\n    0x6e 0xfa 0xfc 0xff 0xfb 0xff 0x9d 0x3 \\\n    0x2 0x0 0xa3 0xfd 0xff 0xfa 0xff 0xfe \\\n    0xff 0xfb 0xff 0xfb 0xff 0xff 0x89 0x0 \\\n    0x0 0x0 0x2 0x7 0xff 0xff 0xfa 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xfd 0xfd 0xff 0xfd 0xac 0x6 0x5 \\\n    0x4 0x12 0x61 0x7d 0x7a 0x31 0x0 0x5 \\\n    0x0 0x46 0xff 0xfd 0xfd 0xff 0xfd 0xff \\\n    0xff 0xfa 0xfd 0xff 0xff 0xf8 0xfc 0x36 \\\n    0x3 0x0 0x4 0x2 0xf4 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0xff 0xb9 0x5 \\\n    0x0 0x1 0x0 0x0 0x0 0x0 0x2 0x0 \\\n    0x58 0xf7 0xff 0xfe 0xff 0xf9 0xff 0xff \\\n    0xfb 0xff 0xff 0xf7 0xff 0xfa 0xff 0xcb \\\n    0x3 0x0 0x0 0x2 0xff 0xf8 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xf9 0xff 0xfe 0xff 0xf9 0xfe 0xfb \\\n    0x8e 0x3b 0x23 0x4 0x9 0x2d 0x5c 0xc2 \\\n    0xff 0xfb 0xff 0xff 0xfe 0xff 0xff 0xf9 \\\n    0xfd 0xff 0xf7 0xff 0xff 0xff 0xfd 0xfe \\\n    0x74 0xb 0x0 0x0 0xff 0xff 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfb 0xff 0xfc 0xff 0xfb 0xfc \\\n    0xfd 0xff 0xfd 0xff 0xff 0xfd 0xff 0xfe \\\n    0xff 0xfe 0xff 0xfa 0xff 0xff 0xf9 0xff \\\n    0xff 0xfb 0xff 0xfe 0xff 0xfe 0xff 0xff \\\n    0xff 0xfc 0xff 0xff 0xfe 0xfd 0xff 0xfc \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' '\n    face30.image = '80 80 1 \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfb 0xff 0xff 0xff 0xfe 0xff 0xff 0xff \\\n    0xfe 0xff 0xfd 0xfd 0xfd 0xfe 0xff 0xfc \\\n    ' + ffs + ' \\\n    0xfc 0xfc 0xff 0xff 0xff 0xff 0xfc 0xff \\\n    0xfd 0xff 0xff 0xff 0xfd 0xfe 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xfd 0xfd 0xfd 0xfe 0xfe \\\n    0xff 0xff 0xfc 0xff 0xff 0xfd 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xfb 0xfd 0xff 0xfe 0xfb \\\n    0xff 0xfb 0xfb 0xff 0xff 0xff 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfe 0xff 0xff 0xff 0xff 0xff \\\n    0xfa 0xfe 0xfd 0xff 0xff 0xfc 0xff 0xfe \\\n    ' + ffs + ' \\\n    0xf9 0xff 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xfd 0xfb 0xfb 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xff 0xff 0xff 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xff 0xfe 0xff 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfc 0xff 0xff 0xfe 0xff 0xf9 \\\n    0xfa 0xfe 0xff 0xfd 0xff 0xff 0xff 0xfa \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xfe 0xfc 0xfc 0xfe \\\n    0xfd 0xf8 0xfb 0xff 0xff 0xff 0xfe 0xff \\\n    ' + ffs + ' \\\n    0xff 0xff 0xfd 0xff 0xff 0xfe 0xff 0xff \\\n    0xff 0xff 0xff 0xff 0xfe 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xfd 0xfd 0xff 0xff 0xff \\\n    0xff 0xff 0xff 0xfe 0xfc 0xff 0xfd 0xfa \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xff 0xff 0xff 0xff 0xfa 0xfe \\\n    0xff 0xfd 0xfe 0xff 0xff 0xfd 0xfe 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xfc 0xff 0xff 0xff 0xf9 \\\n    0xfe 0xfc 0xff 0xff 0xfd 0xfe 0xfd 0xff \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xff 0xfa 0xfb 0xff 0xfe 0xff \\\n    0xff 0xff 0xff 0xfe 0xfc 0xfe 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xfc 0xff 0xff 0xf6 0xe8 \\\n    0x7d 0x3a 0xe 0x6 0x11 0x35 0x83 0xde \\\n    ' + ffs + ' \\\n    0xff 0xff 0xf3 0x98 0x3e 0x17 0x2 0x14 \\\n    0x3c 0x94 0xeb 0xff 0xff 0xfe 0xff 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xff 0xfc 0xfe 0xff 0x7d 0x7 \\\n    0x0 0x0 0x6 0x0 0x5 0x0 0x0 0x6 \\\n    0x89 0xff 0xff 0xff 0xfc 0xff 0xfa 0xff \\\n    0xff 0xcf 0x1c 0x0 0x2 0x0 0x1 0x1 \\\n    0x1 0x0 0x1d 0xcf 0xfc 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xfc 0xff 0xfe 0x64 0x0 0x2 \\\n    0x2 0x30 0x69 0x82 0x67 0x27 0xd 0x0 \\\n    0x1 0x7c 0xfa 0xfe 0xff 0xff 0xff 0xfb \\\n    0xdf 0x7 0x0 0x0 0x16 0x64 0x77 0x63 \\\n    0x17 0x0 0x0 0x6 0xdc 0xfe 0xff 0xfb \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xff 0xff 0xff 0xb2 0x7 0x0 0x3 \\\n    0xa6 0xfd 0xff 0xff 0xff 0xff 0xa0 0x1 \\\n    0x0 0x0 0xcd 0xff 0xfb 0xfc 0xfd 0xff \\\n    0x38 0x2 0x6 0x3f 0xea 0xf9 0xff 0xfb \\\n    0xf0 0x44 0x4 0x1 0x3d 0xff 0xf9 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfb 0xff 0x4d 0x0 0x9 0x7d \\\n    0xff 0xf8 0xff 0xfb 0xff 0xfd 0xfd 0x84 \\\n    0x5 0x0 0x68 0xfb 0xff 0xfc 0xff 0xd1 \\\n    0x5 0x0 0x11 0xeb 0xff 0xfe 0xff 0xff \\\n    0xfb 0xf4 0xe 0x0 0x3 0xda 0xf8 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xfe 0xff 0x19 0x5 0x0 0xec \\\n    0xfe 0xff 0xff 0xff 0xff 0xff 0xfc 0xd7 \\\n    0x0 0x0 0x1f 0xff 0xfb 0xff 0xff 0x7d \\\n    0x1 0x2 0x74 0xfb 0xff 0xff 0xf8 0xff \\\n    0xff 0xff 0x6e 0x4 0x0 0x85 0xff 0xfa \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfe 0xff 0xfb 0x7a 0x80 0x7a 0xf7 \\\n    0xfd 0xfc 0xff 0xfd 0xff 0xfc 0xff 0xf7 \\\n    0x4 0x3 0xa 0xfd 0xff 0xff 0xf0 0x59 \\\n    0x0 0x0 0xb3 0xff 0xff 0xfd 0xff 0xfd \\\n    0xfe 0xff 0xb3 0x0 0x0 0x51 0xff 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfd 0xff 0xfa 0xf8 0xff 0xfd 0xff 0xff \\\n    0xff 0xff 0xf6 0xff 0xff 0xff 0xf8 0xf0 \\\n    0x0 0x2 0x1f 0xff 0xfd 0xfc 0xff 0x27 \\\n    0x0 0x2 0xdf 0xfd 0xfd 0xff 0xfa 0xff \\\n    0xff 0xfe 0xdc 0x2 0x5 0x32 0xfa 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xff 0xff 0xfc 0xff 0xfe 0xfd \\\n    0xff 0xf9 0xff 0xfe 0xfd 0xff 0xfd 0xad \\\n    0x0 0x2 0x4e 0xff 0xfc 0xfd 0xff 0x13 \\\n    0x2 0x0 0xf9 0xfd 0xff 0xff 0xfa 0xff \\\n    0xfe 0xff 0xef 0x0 0x0 0x1d 0xfb 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xfd 0xff 0xff 0xfb 0xe6 0x25 \\\n    0x0 0x5 0xc2 0xfc 0xff 0xff 0xf7 0xd \\\n    0x0 0x0 0xff 0xfe 0xff 0xfe 0xfc 0xff \\\n    0xff 0xfe 0xfb 0x0 0x4 0xb 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xfb 0xf8 0xd3 0x85 0x19 0x0 \\\n    0x0 0x65 0xff 0xff 0xf7 0xfb 0xff 0x0 \\\n    0x2 0x0 0xff 0xfe 0xff 0xff 0xfe 0xff \\\n    0xfe 0xff 0xfe 0x1 0x0 0x6 0xfd 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0x86 0x0 0x7 0x0 0x0 0x0 0x0 0x1f \\\n    0x99 0xff 0xff 0xff 0xff 0xff 0xff 0x0 \\\n    0x2 0x3 0xff 0xfe 0xfe 0xff 0xff 0xfe \\\n    0xfd 0xff 0xff 0x1 0x0 0x3 0xfc 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0x84 0x0 0x1 0x2 0x5 0x3 0x2b 0xe3 \\\n    0xfe 0xff 0xff 0xfd 0xff 0xfc 0xfb 0x2 \\\n    0x0 0x3 0xff 0xff 0xfc 0xff 0xff 0xfe \\\n    0xff 0xff 0xff 0x0 0x2 0x4 0xfe 0xfd \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xbb 0x8e 0x7b 0x71 0x31 0x0 0x0 0x12 \\\n    0xc7 0xff 0xff 0xfb 0xfe 0xff 0xfc 0x0 \\\n    0x0 0x5 0xfe 0xff 0xfd 0xff 0xff 0xfe \\\n    0xff 0xfe 0xff 0x0 0x4 0x4 0xff 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xf4 0xff 0xff 0xff 0xaf 0x11 0x0 \\\n    0xf 0xe8 0xfb 0xff 0xff 0xfd 0xfd 0xb \\\n    0x0 0x6 0xfb 0xff 0xfd 0xff 0xff 0xfe \\\n    0xff 0xff 0xfd 0x1 0x1 0x9 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xff 0xf8 0xfc 0xff 0x83 0x0 \\\n    0x0 0x7d 0xff 0xf6 0xfb 0xff 0xff 0xf \\\n    0x0 0x2 0xf3 0xff 0xfd 0xff 0xff 0xff \\\n    0xff 0xff 0xee 0x4 0x0 0x18 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    0xff 0xfc 0xfc 0xff 0xff 0xf8 0xeb 0x0 \\\n    0x0 0x24 0xfc 0xff 0xfd 0xff 0xfc 0x24 \\\n    0x0 0x0 0xea 0xfd 0xfc 0xff 0xff 0xff \\\n    0xff 0xff 0xdd 0x5 0x0 0x28 0xff 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xff 0xfd 0x8c 0x8a 0x8b 0xff \\\n    0xff 0xff 0xfb 0xff 0xfe 0xfe 0xff 0x4 \\\n    0x0 0xa 0xff 0xfb 0xff 0xfd 0xfd 0x4d \\\n    0x0 0x1 0xbc 0xff 0xfc 0xff 0xff 0xff \\\n    0xff 0xff 0xba 0x0 0x0 0x55 0xff 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xff 0xff 0x14 0x6 0x0 0xe1 \\\n    0xfb 0xff 0xff 0xfe 0xfe 0xff 0xe6 0x0 \\\n    0x0 0xf 0xff 0xfc 0xfd 0xff 0xff 0x75 \\\n    0x2 0x0 0x80 0xff 0xff 0xfd 0xff 0xfd \\\n    0xff 0xf9 0x78 0x0 0x3 0x7a 0xfc 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xf8 0xfe 0x5a 0x0 0x0 0x96 \\\n    0xff 0xfe 0xfd 0xfd 0xff 0xfd 0xa9 0x0 \\\n    0x0 0x4d 0xff 0xfe 0xff 0xff 0xfa 0xc9 \\\n    0x0 0x7 0x17 0xf2 0xfc 0xfc 0xff 0xff \\\n    0xff 0xee 0x1a 0x0 0x0 0xd0 0xff 0xfc \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfb 0xff 0xfc 0xbc 0x7 0x0 0x8 \\\n    0xbb 0xfb 0xff 0xfd 0xff 0xd8 0x16 0x4 \\\n    0x4 0x99 0xf3 0xff 0xfa 0xfa 0xff 0xff \\\n    0x35 0x0 0x5 0x47 0xf9 0xff 0xff 0xfa \\\n    0xee 0x4b 0x6 0x0 0x33 0xfc 0xfd 0xfe \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfc 0xff 0xfd 0xff 0xfb 0x6d 0x1 0x2 \\\n    0x0 0x3d 0x79 0x77 0x56 0x9 0x0 0x0 \\\n    0x35 0xfa 0xff 0xff 0xfe 0xff 0xfe 0xfe \\\n    0xcf 0xc 0x3 0x0 0xe 0x65 0x7f 0x60 \\\n    0x13 0x0 0x0 0xe 0xd6 0xff 0xff 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfd 0xfc 0xff 0xfe 0xfb 0x74 0x0 \\\n    0x0 0x0 0x0 0x0 0x0 0x0 0x3 0x45 \\\n    0xed 0xff 0xf4 0xfe 0xff 0xfd 0xfe 0xff \\\n    0xff 0xc7 0x14 0x2 0x7 0x1 0x0 0x5 \\\n    0x1 0x6 0x1c 0xc2 0xff 0xff 0xf7 0xff \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xff 0xfc 0xff 0xff 0xfb 0xff 0xfa 0xd6 \\\n    0x64 0x26 0xf 0x9 0x19 0x56 0xb1 0xff \\\n    0xfc 0xff 0xff 0xfb 0xff 0xff 0xfc 0xff \\\n    0xff 0xff 0xf7 0x8f 0x3a 0x13 0x3 0x12 \\\n    0x3d 0x91 0xec 0xff 0xff 0xf9 0xff 0xfb \\\n    ' + ffs4 + ' \\\n    ' + ffs + ' \\\n    0xfe 0xff 0xfc 0xff 0xfe 0xff 0xfa 0xfe \\\n    0xff 0xfa 0xff 0xfd 0xff 0xfd 0xff 0xfc \\\n    0xff 0xf8 0xff 0xfe 0xfc 0xff 0xfe 0xff \\\n    0xff 0xff 0xf9 0xfe 0xff 0xff 0xff 0xfe \\\n    0xfd 0xff 0xff 0xfc 0xfb 0xff 0xff 0xff \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs64 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs16 + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' \\\n    ' + ffs + ' '\n\n    dist = p04.distanceToLineSegment(p04p00, p04p00p03).Length / 5.0\n    dx = DVU.scale(p04.sub(p03).normalize(), dist)\n    dy = DVU.scale(p01.sub(p01p00p02).normalize(), dist)\n    v0 = p04p00p03.add(Base.Vector(0.0, 0.0, 0.01)).sub(DVU.scale(dy, 3.0))\n    mkarrow(v0, dx, dy, \"arrow00p\")\n    dist = p01.distanceToLineSegment(p01p00, p01p00p02).Length / 5.0\n    dx = DVU.scale(p01.sub(p02).normalize(), dist)\n    dy = DVU.scale(p04.sub(p04p00p03).normalize(), dist)\n    v0 = p01p00p02.add(Base.Vector(0.0, 0.0, 0.01)).sub(DVU.scale(dy, 3.0))\n    mkarrow(v0, dx, dy, \"arrow00m\")\n    dist = p10.distanceToLineSegment(p10p23, p10p23p00).Length / 5.0\n    dx = DVU.scale(p10.sub(p00).normalize(), dist)\n    dy = DVU.scale(p11.sub(p11p01p23).normalize(), dist)\n    v0 = p10p00.add(DVU.scale(p10, 0.01)).add(dy).add(dy).add(dx)\n    mkarrow(v0, dx, dy, \"arrow10p\")\n    dist = p11.distanceToLineSegment(p11p23, p11p23p01).Length / 5.0\n    dx = DVU.scale(p11.sub(p01).normalize(), dist)\n    dy = DVU.scale(p10.sub(p10p00p23).normalize(), dist)\n    v0 = p11p01.add(DVU.scale(p11, 0.01)).add(dy).add(dy).add(dx)\n    mkarrow(v0, dx, dy, \"arrow10m\")\n    dist = p11.distanceToLineSegment(p11p24, p11p24p01).Length / 5.0\n    dx = DVU.scale(p11.sub(p01).normalize(), dist)\n    dy = DVU.scale(p12.sub(p12p02p24).normalize(), dist)\n    v0 = p11p01.add(DVU.scale(p11, 0.01)).add(dy).add(dy).add(dx)\n    mkarrow(v0, dx, dy, \"arrow11p\")\n    dist = p12.distanceToLineSegment(p12p24, p12p24p02).Length / 5.0\n    dx = DVU.scale(p12.sub(p02).normalize(), dist)\n    dy = DVU.scale(p11.sub(p11p01p24).normalize(), dist)\n    v0 = p12p02.add(DVU.scale(p12, 0.01)).add(dy).add(dy).add(dx)\n    mkarrow(v0, dx, dy, \"arrow11m\")\n    fs = \"arrow12p\"\n    dist = p12.distanceToLineSegment(p12p20, p12p20p02).Length / 5.0\n    dx = DVU.scale(p12.sub(p02).normalize(), dist)\n    dy = DVU.scale(p13.sub(p13p03p20).normalize(), dist)\n    v0 = p12p02.add(DVU.scale(p12, 0.01)).add(dy).add(dy).add(dx)\n    mkarrow(v0, dx, dy, \"arrow12p\")\n    dist = p13.distanceToLineSegment(p13p20, p13p20p03).Length / 5.0\n    dx = DVU.scale(p13.sub(p03).normalize(), dist)\n    dy = DVU.scale(p12.sub(p12p02p20).normalize(), dist)\n    v0 = p13p03.add(DVU.scale(p13, 0.01)).add(dy).add(dy).add(dx)\n    mkarrow(v0, dx, dy, \"arrow12m\")\n    dist = p13.distanceToLineSegment(p13p21, p13p21p03).Length / 5.0\n    dx = DVU.scale(p13.sub(p03).normalize(), dist)\n    dy = DVU.scale(p14.sub(p14p04p21).normalize(), dist)\n    v0 = p13p03.add(DVU.scale(p13, 0.01)).add(dy).add(dy).add(dx)\n    mkarrow(v0, dx, dy, \"arrow13p\")\n    dist = p14.distanceToLineSegment(p14p21, p14p21p04).Length / 5.0\n    dx = DVU.scale(p14.sub(p04).normalize(), dist)\n    dy = DVU.scale(p13.sub(p13p03p21).normalize(), dist)\n    v0 = p14p04.add(DVU.scale(p14, 0.01)).add(dy).add(dy).add(dx)\n    mkarrow(v0, dx, dy, \"arrow13m\")\n    dist = p14.distanceToLineSegment(p14p22, p14p22p04).Length / 5.0\n    dx = DVU.scale(p14.sub(p04).normalize(), dist)\n    dy = DVU.scale(p10.sub(p10p00p22).normalize(), dist)\n    v0 = p14p04.add(DVU.scale(p14, 0.01)).add(dy).add(dy).add(dx)\n    mkarrow(v0, dx, dy, \"arrow14p\")\n    dist = p10.distanceToLineSegment(p10p22, p10p22p00).Length / 5.0\n    dx = DVU.scale(p10.sub(p00).normalize(), dist)\n    dy = DVU.scale(p14.sub(p14p04p22).normalize(), dist)\n    v0 = p10p00.add(DVU.scale(p10, 0.01)).add(dy).add(dy).add(dx)\n    mkarrow(v0, dx, dy, \"arrow14m\")\n    dist = (p04.distanceToLineSegment(\n        p04p00, p04p00p03).Length * _get(\"sf\")) / -5.0\n    dx = DVU.scale(p04.sub(p03).normalize(), dist)\n    dy = DVU.scale(p01.sub(p01p00p02).normalize(), dist)\n    v0 = DVU.scale(Base.Vector(\n        - p01p00p02.x, p01p00p02.y, p01p00p02.z), _get(\"sf\"))\n    v0 = v0.add(Base.Vector(\n        _get(\"dd\") * c0, _get(\"dd\") * s0, 0.01).sub(DVU.scale(dy, 3.0)))\n    mkarrow(v0, dx, dy, \"arrow20p\")\n    dist = (p04.distanceToLineSegment(\n        p04p00, p04p00p03).Length * _get(\"sf\")) / -5.0\n    dx = DVU.scale(p01.sub(p02).normalize(), dist)\n    dy = DVU.scale(p04.sub(p04p00p03).normalize(), dist)\n    v0 = DVU.scale(Base.Vector(\n        - p04p00p03.x, p04p00p03.y, p04p00p03.z), _get(\"sf\"))\n    v0 = v0.add(Base.Vector(\n        _get(\"dd\") * c0, _get(\"dd\") * s0, 0.01).sub(DVU.scale(dy, 3.0)))\n    mkarrow(v0, dx, dy, \"arrow20m\")\n    dist = (p04.distanceToLineSegment(\n        p04p00, p04p00p03).Length * _get(\"sf\")) / -5.0\n    dx = DVU.scale(p04.sub(p03).normalize(), dist)\n    dy = DVU.scale(p01.sub(p01p00p02).normalize(), dist)\n    v0 = DVU.scale(Base.Vector(\n        - p01p00p02.x, p01p00p02.y, p01p00p02.z), _get(\"sf\"))\n    v0 = v0.add(Base.Vector(\n        _get(\"dd\") * c1, _get(\"dd\") * s1, 0.01).sub(DVU.scale(dy, 3.0)))\n    mkarrow(v0, dx, dy, \"arrow21p\")\n    dist = (p04.distanceToLineSegment(\n        p04p00, p04p00p03).Length * _get(\"sf\")) / -5.0\n    dx = DVU.scale(p01.sub(p02).normalize(), dist)\n    dy = DVU.scale(p04.sub(p04p00p03).normalize(), dist)\n    v0 = DVU.scale(Base.Vector(\n        - p04p00p03.x, p04p00p03.y, p04p00p03.z), _get(\"sf\"))\n    v0 = v0.add(Base.Vector(\n        _get(\"dd\") * c1, _get(\"dd\") * s1, 0.01).sub(DVU.scale(dy, 3.0)))\n    mkarrow(v0, dx, dy, \"arrow21m\")\n    dist = (p04.distanceToLineSegment(\n        p04p00, p04p00p03).Length * _get(\"sf\")) / -5.0\n    dx = DVU.scale(p04.sub(p03).normalize(), dist)\n    dy = DVU.scale(p01.sub(p01p00p02).normalize(), dist)\n    v0 = DVU.scale(Base.Vector(\n        - p01p00p02.x, p01p00p02.y, p01p00p02.z), _get(\"sf\"))\n    v0 = v0.add(Base.Vector(\n        _get(\"dd\") * c2, _get(\"dd\") * s2, 0.01).sub(DVU.scale(dy, 3.0)))\n    mkarrow(v0, dx, dy, \"arrow22p\")\n    dist = (p04.distanceToLineSegment(\n        p04p00, p04p00p03).Length * _get(\"sf\")) / -5.0\n    dx = DVU.scale(p01.sub(p02).normalize(), dist)\n    dy = DVU.scale(p04.sub(p04p00p03).normalize(), dist)\n    v0 = DVU.scale(Base.Vector(\n        - p04p00p03.x, p04p00p03.y, p04p00p03.z), _get(\"sf\"))\n    v0 = v0.add(Base.Vector(\n        _get(\"dd\") * c2, _get(\"dd\") * s2, 0.01).sub(DVU.scale(dy, 3.0)))\n    mkarrow(v0, dx, dy, \"arrow22m\")\n    dist = (p04.distanceToLineSegment(\n        p04p00, p04p00p03).Length * _get(\"sf\")) / -5.0\n    dx = DVU.scale(p04.sub(p03).normalize(), dist)\n    dy = DVU.scale(p01.sub(p01p00p02).normalize(), dist)\n    v0 = DVU.scale(Base.Vector(\n        - p01p00p02.x, p01p00p02.y, p01p00p02.z), _get(\"sf\"))\n    v0 = v0.add(Base.Vector(\n        _get(\"dd\") * c3, _get(\"dd\") * s3, 0.01).sub(DVU.scale(dy, 3.0)))\n    mkarrow(v0, dx, dy, \"arrow23p\")\n    dist = (p04.distanceToLineSegment(\n        p04p00, p04p00p03).Length * _get(\"sf\")) / -5.0\n    dx = DVU.scale(p01.sub(p02).normalize(), dist)\n    dy = DVU.scale(p04.sub(p04p00p03).normalize(), dist)\n    v0 = DVU.scale(Base.Vector(\n        - p04p00p03.x, p04p00p03.y, p04p00p03.z), _get(\"sf\"))\n    v0 = v0.add(Base.Vector(\n        _get(\"dd\") * c3, _get(\"dd\") * s3, 0.01).sub(DVU.scale(dy, 3.0)))\n    mkarrow(v0, dx, dy, \"arrow23m\")\n    dist = (p04.distanceToLineSegment(\n        p04p00, p04p00p03).Length * _get(\"sf\")) / -5.0\n    dx = DVU.scale(p04.sub(p03).normalize(), dist)\n    dy = DVU.scale(p01.sub(p01p00p02).normalize(), dist)\n    v0 = DVU.scale(Base.Vector(\n        - p01p00p02.x, p01p00p02.y, p01p00p02.z), _get(\"sf\"))\n    v0 = v0.add(Base.Vector(\n        _get(\"dd\") * c4, _get(\"dd\") * s4, 0.01).sub(DVU.scale(dy, 3.0)))\n    mkarrow(v0, dx, dy, \"arrow24p\")\n    dist = (p04.distanceToLineSegment(\n        p04p00, p04p00p03).Length * _get(\"sf\")) / -5.0\n    dx = DVU.scale(p01.sub(p02).normalize(), dist)\n    dy = DVU.scale(p04.sub(p04p00p03).normalize(), dist)\n    v0 = DVU.scale(Base.Vector(\n        - p04p00p03.x, p04p00p03.y, p04p00p03.z), _get(\"sf\"))\n    v0 = v0.add(Base.Vector(\n        _get(\"dd\") * c4, _get(\"dd\") * s4, 0.01).sub(DVU.scale(dy, 3.0)))\n    mkarrow(v0, dx, dy, \"arrow24m\")\n    dist = _get(\"sf\") * p12.distanceToLineSegment(\n        p12p20, p12p20p02).Length / 5.0\n    dx = DVU.scale(p13.sub(p03).normalize(), dist)\n    dx = Base.Vector(- dx.x, dx.y, dx.z)\n    dy = DVU.scale(p13.sub(p13p03p20).normalize(), dist)\n    dy = Base.Vector(- dy.x, - dy.y, dy.z)\n    v0 = Base.Vector(\n        _get(\"dd\") * c0 - p12p02.x * _get(\"sf\"),\n        _get(\"dd\") * s0 - p12p02.y * _get(\"sf\"),\n        p12p02.z * _get(\"sf\") * 1.01).add(dy).add(dy).add(dx)\n    mkarrow(v0, dx, dy, \"arrow30p\")\n    ex = Base.Vector(dx.x * c1 - dx.y * s1, dx.x * s1 + dx.y * c1, dx.z)\n    ey = Base.Vector(dy.x * c1 - dy.y * s1, dy.x * s1 + dy.y * c1, dy.z)\n    v0 = Base.Vector(\n        _get(\"dd\") * c1 - p13p03.x * _get(\"sf\"),\n        _get(\"dd\") * s1 - p13p03.y * _get(\"sf\"),\n        p13p03.z * _get(\"sf\") * 1.01).add(ey).add(ey).add(ex)\n    mkarrow(v0, ex, ey, \"arrow30q\")\n    ex = Base.Vector(dx.x * c2 - dx.y * s2, dx.x * s2 + dx.y * c2, dx.z)\n    ey = Base.Vector(dy.x * c2 - dy.y * s2, dy.x * s2 + dy.y * c2, dy.z)\n    v0 = Base.Vector(\n        _get(\"dd\") * c2 - p14p04.x * _get(\"sf\"),\n        _get(\"dd\") * s2 - p14p04.y * _get(\"sf\"),\n        p14p04.z * _get(\"sf\") * 1.01).add(ey).add(ey).add(ex)\n    mkarrow(v0, ex, ey, \"arrow30r\")\n    ex = Base.Vector(dx.x * c3 - dx.y * s3, dx.x * s3 + dx.y * c2, dx.z)\n    ey = Base.Vector(dy.x * c3 - dy.y * s3, dy.x * s3 + dy.y * c2, dy.z)\n    v0 = Base.Vector(\n        _get(\"dd\") * c3 - p10p00.x * _get(\"sf\"),\n        _get(\"dd\") * s3 - p10p00.y * _get(\"sf\"),\n        p10p00.z * _get(\"sf\") * 1.01).add(ey).add(ey).add(ex)\n    mkarrow(v0, ex, ey, \"arrow30s\")\n    ex = Base.Vector(dx.x * c4 - dx.y * s4, dx.x * s4 + dx.y * c4, dx.z)\n    ey = Base.Vector(dy.x * c4 - dy.y * s4, dy.x * s4 + dy.y * c4, dy.z)\n    v0 = Base.Vector(\n        _get(\"dd\") * c4 - p11p01.x * _get(\"sf\"),\n        _get(\"dd\") * s4 - p11p01.y * _get(\"sf\"),\n        p11p01.z * _get(\"sf\") * 1.01).add(ey).add(ey).add(ex)\n    mkarrow(v0, ex, ey, \"arrow30t\")\n    dist = _get(\"sf\") * p12.distanceToLineSegment(\n        p12p20, p12p20p02).Length / 5.0\n    dx = DVU.scale(p12.sub(p02).normalize(), dist)\n    dx = Base.Vector(- dx.x, dx.y, dx.z)\n    dy = DVU.scale(p13.sub(p13p03p20).normalize(), dist)\n    dy = Base.Vector(- dy.x, dy.y, dy.z)\n    v0 = Base.Vector(\n        _get(\"dd\") * c0 - p13p03.x * _get(\"sf\"),\n        _get(\"dd\") * s0 - p13p03.y * _get(\"sf\"),\n        p13p03.z * _get(\"sf\") * 1.01).add(dy).add(dy).add(dx)\n    mkarrow(v0, dx, dy, \"arrow30m\")\n    ex = Base.Vector(dx.x * c1 - dx.y * s1, dx.x * s1 + dx.y * c1, dx.z)\n    ey = Base.Vector(dy.x * c1 - dy.y * s1, dy.x * s1 + dy.y * c1, dy.z)\n    v0 = Base.Vector(\n        _get(\"dd\") * c1 - p14p04.x * _get(\"sf\"),\n        _get(\"dd\") * s1 - p14p04.y * _get(\"sf\"),\n        p14p04.z * _get(\"sf\") * 1.01).add(ey).add(ey).add(ex)\n    mkarrow(v0, ex, ey, \"arrow30l\")\n    ex = Base.Vector(dx.x * c2 - dx.y * s2, dx.x * s2 + dx.y * c2, dx.z)\n    ey = Base.Vector(dy.x * c2 - dy.y * s2, dy.x * s2 + dy.y * c2, dy.z)\n    v0 = Base.Vector(\n        _get(\"dd\") * c2 - p10p00.x * _get(\"sf\"),\n        _get(\"dd\") * s2 - p10p00.y * _get(\"sf\"),\n        p10p00.z * _get(\"sf\") * 1.01).add(ey).add(ey).add(ex)\n    mkarrow(v0, ex, ey, \"arrow30k\")\n    ex = Base.Vector(dx.x * c3 - dx.y * s3, dx.x * s3 + dx.y * c3, dx.z)\n    ey = Base.Vector(dy.x * c3 - dy.y * s3, dy.x * s3 + dy.y * c3, dy.z)\n    v0 = Base.Vector(\n        _get(\"dd\") * c3 - p11p01.x * _get(\"sf\"),\n        _get(\"dd\") * s3 - p11p01.y * _get(\"sf\"),\n        p11p01.z * _get(\"sf\") * 1.01).add(ey).add(ey).add(ex)\n    mkarrow(v0, ex, ey, \"arrow30j\")\n    ex = Base.Vector(dx.x * c4 - dx.y * s4, dx.x * s4 + dx.y * c4, dx.z)\n    ey = Base.Vector(dy.x * c4 - dy.y * s4, dy.x * s4 + dy.y * c4, dy.z)\n    v0 = Base.Vector(\n        _get(\"dd\") * c4 - p12p02.x * _get(\"sf\"),\n        _get(\"dd\") * s4 - p12p02.y * _get(\"sf\"),\n        p12p02.z * _get(\"sf\") * 1.01).add(ey).add(ey).add(ex)\n    mkarrow(v0, ex, ey, \"arrow30i\")\n    vv = Base.Vector(0.0, 0.0, 0.1)\n    dx = DVU.scale(p03.sub(p23).normalize(), 0.2)\n    dy = DVU.scale(p00.sub(p01).normalize(), 0.2)\n    v0 = DVU.scale(p00.add(p01), 0.5).add(vv)\n    mkarrowx(v0, dx, dy, \"arrow00x\", \"00 and 10\")\n    dx = DVU.scale(p04.sub(p24).normalize(), 0.2)\n    dy = DVU.scale(p01.sub(p02).normalize(), 0.2)\n    v0 = DVU.scale(p01.add(p02), 0.5).add(vv)\n    mkarrowx(v0, dx, dy, \"arrow01x\", \"00 and 11\")\n    dx = DVU.scale(p00.sub(p20).normalize(), 0.2)\n    dy = DVU.scale(p02.sub(p03).normalize(), 0.2)\n    v0 = DVU.scale(p02.add(p03), 0.5).add(vv)\n    mkarrowx(v0, dx, dy, \"arrow02x\", \"00 and 12\")\n    dx = DVU.scale(p01.sub(p21).normalize(), 0.2)\n    dy = DVU.scale(p03.sub(p04).normalize(), 0.2)\n    v0 = DVU.scale(p03.add(p04), 0.5).add(vv)\n    mkarrowx(v0, dx, dy, \"arrow03x\", \"00 and 13\")\n    dx = DVU.scale(p02.sub(p22).normalize(), 0.2)\n    dy = DVU.scale(p04.sub(p00).normalize(), 0.2)\n    v0 = DVU.scale(p04.add(p00), 0.5).add(vv)\n    mkarrowx(v0, dx, dy, \"arrow04x\", \"00 and 14\")\n    dx = DVU.scale(p10.sub(p12).normalize(), 0.2)\n    dy = DVU.scale(p01.sub(p11).normalize(), 0.2)\n    v0 = DVU.scale(p01.add(p11), 0.5).add(vv)\n    mkarrowx(v0, dx, dy, \"arrow10x\", \"10 and 11\")\n    dx = DVU.scale(p11.sub(p13).normalize(), 0.2)\n    dy = DVU.scale(p02.sub(p12).normalize(), 0.2)\n    v0 = DVU.scale(p02.add(p12), 0.5).add(vv)\n    mkarrowx(v0, dx, dy, \"arrow11x\", \"11 and 12\")\n    dx = DVU.scale(p12.sub(p14).normalize(), 0.2)\n    dy = DVU.scale(p03.sub(p13).normalize(), 0.2)\n    v0 = DVU.scale(p03.add(p13), 0.5).add(vv)\n    mkarrowx(v0, dx, dy, \"arrow12x\", \"12 and 13\")\n    dx = DVU.scale(p13.sub(p10).normalize(), 0.2)\n    dy = DVU.scale(p04.sub(p14).normalize(), 0.2)\n    v0 = DVU.scale(p04.add(p14), 0.5).add(vv)\n    mkarrowx(v0, dx, dy, \"arrow13x\", \"13 and 14\")\n    dx = DVU.scale(p14.sub(p11).normalize(), 0.2)\n    dy = DVU.scale(p00.sub(p10).normalize(), 0.2)\n    v0 = DVU.scale(p00.add(p10), 0.5).add(vv)\n    mkarrowx(v0, dx, dy, \"arrow14x\", \"14 and 10\")\n    dx = DVU.scale(p12.sub(p22).normalize(), 0.2)\n    dy = DVU.scale(p03.sub(p01).normalize(), 0.2)\n    v0 = DVU.scale(p00.add(p04), 0.5 * _get(\"sf\")).add(vv)\n    v0 = Base.Vector(_get(\"dd\") * c0, _get(\"dd\") * s0, 0.0).add(\n        Base.Vector(- v0.x, - v0.y, v0.z))\n    mkarrowx(v0, dx, dy, \"arrow20x\", \"20 and 10\")\n    dx = DVU.scale(p13.sub(p23).normalize(), 0.2)\n    dy = DVU.scale(p04.sub(p02).normalize(), 0.2)\n    v0 = DVU.scale(p01.add(p00), 0.5 * _get(\"sf\")).add(vv)\n    v0 = Base.Vector(_get(\"dd\") * c0, _get(\"dd\") * s0, 0.0).add(\n        Base.Vector(- v0.x, - v0.y, v0.z))\n    mkarrowx(v0, dx, dy, \"arrow22y\", \"12 and 22\")\n    dx = DVU.scale(p13.sub(p23).normalize(), 0.2)\n    dy = DVU.scale(p04.sub(p02).normalize(), 0.2)\n    v0 = DVU.scale(p01.add(p00), 0.5 * _get(\"sf\")).add(vv)\n    v0 = Base.Vector(_get(\"dd\") * c1, _get(\"dd\") * s1, 0.0).add(\n        Base.Vector(- v0.x, - v0.y, v0.z))\n    mkarrowx(v0, dx, dy, \"arrow21x\", \"21 and 11\")\n    dx = DVU.scale(p14.sub(p24).normalize(), 0.2)\n    dy = DVU.scale(p00.sub(p03).normalize(), 0.2)\n    v0 = DVU.scale(p02.add(p01), 0.5 * _get(\"sf\")).add(vv)\n    v0 = Base.Vector(_get(\"dd\") * c1, _get(\"dd\") * s1, 0.0).add(\n        Base.Vector(- v0.x, - v0.y, v0.z))\n    mkarrowx(v0, dx, dy, \"arrow23y\", \"21 and 11\")\n    dx = DVU.scale(p14.sub(p24).normalize(), 0.2)\n    dy = DVU.scale(p00.sub(p03).normalize(), 0.2)\n    v0 = DVU.scale(p02.add(p01), 0.5 * _get(\"sf\")).add(vv)\n    v0 = Base.Vector(_get(\"dd\") * c2, _get(\"dd\") * s2, 0.0).add(\n        Base.Vector(- v0.x, - v0.y, v0.z))\n    mkarrowx(v0, dx, dy, \"arrow22x\", \"22 and 12\")\n    dx = DVU.scale(p10.sub(p20).normalize(), 0.2)\n    dy = DVU.scale(p01.sub(p04).normalize(), 0.2)\n    v0 = DVU.scale(p03.add(p02), 0.5 * _get(\"sf\")).add(vv)\n    v0 = Base.Vector(_get(\"dd\") * c2, _get(\"dd\") * s2, 0.0).add(\n        Base.Vector(- v0.x, - v0.y, v0.z))\n    mkarrowx(v0, dx, dy, \"arrow24y\", \"22 and 12\")\n    dx = DVU.scale(p10.sub(p20).normalize(), 0.2)\n    dy = DVU.scale(p01.sub(p04).normalize(), 0.2)\n    v0 = DVU.scale(p03.add(p02), 0.5 * _get(\"sf\")).add(vv)\n    v0 = Base.Vector(_get(\"dd\") * c3, _get(\"dd\") * s3, 0.0).add(\n        Base.Vector(- v0.x, - v0.y, v0.z))\n    mkarrowx(v0, dx, dy, \"arrow23x\", \"23 and 13\")\n    dx = DVU.scale(p11.sub(p21).normalize(), 0.2)\n    dy = DVU.scale(p02.sub(p00).normalize(), 0.2)\n    v0 = DVU.scale(p04.add(p03), 0.5 * _get(\"sf\")).add(vv)\n    v0 = Base.Vector(_get(\"dd\") * c3, _get(\"dd\") * s3, 0.0).add(\n        Base.Vector(- v0.x, - v0.y, v0.z))\n    mkarrowx(v0, dx, dy, \"arrow20y\", \"23 and 13\")\n    dx = DVU.scale(p11.sub(p21).normalize(), 0.2)\n    dy = DVU.scale(p02.sub(p00).normalize(), 0.2)\n    v0 = DVU.scale(p04.add(p03), 0.5 * _get(\"sf\")).add(vv)\n    v0 = Base.Vector(_get(\"dd\") * c4, _get(\"dd\") * s4, 0.0).add(\n        Base.Vector(- v0.x, - v0.y, v0.z))\n    mkarrowx(v0, dx, dy, \"arrow24x\", \"24 and 14\")\n    dx = DVU.scale(p12.sub(p22).normalize(), 0.2)\n    dy = DVU.scale(p03.sub(p01).normalize(), 0.2)\n    v0 = DVU.scale(p00.add(p04), 0.5 * _get(\"sf\")).add(vv)\n    v0 = Base.Vector(_get(\"dd\") * c4, _get(\"dd\") * s4, 0.0).add(\n        Base.Vector(- v0.x, - v0.y, v0.z))\n    mkarrowx(v0, dx, dy, \"arrow21y\", \"24 and 14\")\n\ndef rota(name, steps = None):\n    \"\"\"This function rotates the Megaminx by +72 degrees about the normal to \\\nface 'name'.\\\n\"\"\"\n    d = FreeCAD.Megaminx_Dictionary\n    key = App.ActiveDocument.Name + \"$\" + name\n    if steps == None:\n        steps = _get(\"slowness\")\n    if key in d:\n        d[key].rota(steps)\n    else:\n        print(name + \" is not a face\")\n\ndef rotm(name, steps = None):\n    \"\"\"This function rotates face 'name' by -72 degrees.\"\"\"\n    d = FreeCAD.Megaminx_Dictionary\n    key = App.ActiveDocument.Name + \"$\" + name\n    if steps == None:\n        steps = _get(\"slowness\")\n    if key in d:\n        d[key].rotm(steps)\n    else:\n        print(name + \" is not a face\")\n\ndef rotp(name, steps = None):\n    \"\"\"This function rotates face 'name' by +72 degrees.\"\"\"\n    d = FreeCAD.Megaminx_Dictionary\n    key = App.ActiveDocument.Name + \"$\" + name\n    if steps == None:\n        steps = _get(\"slowness\")\n    if key in d:\n        d[key].rotp(steps)\n    else:\n        print(name + \" is not a face\")\n\ndef roth(name, steps = None):\n    \"\"\"This function rotates the history by +72 degrees about the \\\nnormal to face 'name'.\\\n\"\"\"\n    d = FreeCAD.Megaminx_Dictionary\n    key = App.ActiveDocument.Name + \"$\" + name\n    if key in d:\n        d[key].roth(steps)\n    else:\n        print(name + \" is not a face\")\n\ndef reflect(key):\n    \"\"\" Replace the history by a reflected one.\nThis replaces the history by the equivalent of reflecting the Megaminx\nin a plane through the centre of the Megaminx and the edge between two\nfaces, executing the history, and then reflecting the Megaminx back again.\nThis is the function invoked by clicking on the green double headed arrow\nshown across the two faces. dict is a dictionary specific to the two faces. \nReflecting the history can be useful to align it with a real Megaminx\nbefore doing step_history(), or to compose more complex macros out of\nsimple ones.\\\n\"\"\"\n    history = _get(\"history\")\n    nh = history[:]\n    reset()\n    hs = _get(\"historyslowness\")\n    d = _get(\"reflect\")\n    if key in d:\n        d = d[key]\n        while len(nh) > 0:\n            s = nh.pop(0)\n            sl = len(s) - 1\n            f = \"\"\n            rot = \"\"\n            steps = \"\"\n            if sl >= 13 and s[0:3] == \"rot\" and s[4] == \"(\" \\\n                and (s[5] == '\"' or s[5] == \"'\") \\\n                and s[5] == s[12] and s.endswith(\")\"):\n                f = s[6:12]\n                rot = s[0:4]\n                if s[13] == \",\":\n                    steps = s[14:sl].strip()\n            if steps == \"\":\n                steps = \"0\"\n            if rot in [\"rota\", \"rotm\", \"rotp\"] and f in d \\\n                and steps.isnumeric():\n                fn = d[f]\n                if rot == \"rotp\":\n                    fn._rotm(hs)\n                    history.append(\"rotm('\" + fn.name + \"', \" + steps + \")\")\n                elif rot == \"rotm\":\n                    fn._rotp(hs)\n                    history.append(\"rotp('\" + fn.name + \"', \" + steps + \")\")\n                elif rot == \"rota\":\n                    opp = fn.opposite\n                    opp._rota(hs)\n                    history.append(\"rota('\" + opp.name + \"', \" + steps + \")\")\n            else:\n                print(\"Invalid history entry '\" + s + \"'\")\n        updateMenu()\n    else:\n        print(\"Bad argument '\" + key + \"' to reflect()\")\n\nclass StepWindow(QtGui.QDialog):\n    \"\"\" This class creates the dialog box shown on each step by step_history().\n    \"\"\"\n    def __init__(self):\n        super(StepWindow, self).__init__()\n        # Lay out the interactive elements\n        mw = Gui.getMainWindow()\n        cw = mw.centralWidget()\n        view3DWidget = findView(cw)\n        if view3DWidget != None:\n            self.setParent(view3DWidget)\n            geom = view3DWidget.geometry()\n        else:\n            self.setParent(cws)\n            geom = cw.geometry()\n        self.setAutoFillBackground(True)\n        margin = 10\n        height = margin\n        self.label_1 = QtGui.QLabel(self)\n        self.label_1.setObjectName(\"label_1\")\n        font = self.label_1.font()\n        r2 = QtGui.QFontMetrics(font).boundingRect(\"Doing face00.rotp(steps)\")\n        height = height + r2.height() + margin\n        self.OKbutton = QtGui.QPushButton(self)\n        self.OKbutton.setText(\"OK\")\n        self.OKbutton.clicked.connect(self.accept)\n        self.OKbutton.setDefault(True)\n        font = self.OKbutton.font()\n        r3 =QtGui.QFontMetrics(font).boundingRect(\"  OK  \")\n        self.Quitbutton = QtGui.QPushButton(self)\n        self.Quitbutton.setText(\"Stop\")\n        self.Quitbutton.clicked.connect(self.reject)\n        font = self.Quitbutton.font()\n        r4 =QtGui.QFontMetrics(font).boundingRect(\"  Stop  \")\n        # window title width allowing space for some tool buttons\n        width = r2.width()\n        if  width < 3 * margin + r3.width() + r4.width():\n            width = 3 * margin + r3.width() + r4.width()\n        if width > geom.width():\n            width = geom.width()\n        height = r3.height()\n        if height < r4.height():\n            height = r4.height()\n        height = height + r2.height() + 4 * margin\n        xpos = geom.left() + (geom.width() - width) / 2\n        self.setGeometry(geom.right() - width, 0, width, height)\n        ypos = margin\n        self.label_1.setGeometry(QtCore.QRect(\n            (width - r2.width()) / 2, ypos, r2.width(), r2.height()))\n        ypos = ypos + r2.height() + margin \n        self.OKbutton.setGeometry(QtCore.QRect(\n            margin, ypos, r3.width(), r3.height() + margin))\n        xpos = width - r4.width() - margin\n        self.Quitbutton.setGeometry(QtCore.QRect(\n            xpos, ypos, r4.width(), r4.height() + margin))\n        self.setFocusPolicy(QtCore.Qt.StrongFocus)\n        self.setFocus()\n\ndef step_history():\n    \"\"\" Step through the history.\n    It steps through the history, displaying a dialog box at the top right of\n    the window showing what rotation it is about to do. If the user clicks\n    on OK or types a return, the rotation is done and it moves on to the next\n    step: if the user clicks on Stop or types an escape, step_history() quits\n    without doing anything more.\n    This can be used if you want to play the history onto a real Megaminx.\n    \"\"\"\n    history = _get(\"history\")\n    nh = history[:]\n    reset()\n    Gui.updateGui()\n    stepping = True\n    while len(nh) > 0 and stepping == True:\n        s = nh.pop(0)\n        sl = len(s) - 1\n        f = \"\"\n        rot = \"\"\n        steps = \"\"\n        if sl >= 13 and s[0:3] == \"rot\" and s[4] == \"(\" \\\n            and (s[5] == '\"' or s[5] == \"'\") \\\n            and s[5] == s[12] and s.endswith(\")\"):\n            f = s[6:12]\n            rot = s[0:4]\n            if s[13] == \",\":\n                steps = s[14:sl].strip()\n        if steps == \"\":\n            steps = \"0\"\n        d = FreeCAD.Megaminx_Dictionary\n        key = App.ActiveDocument.Name + \"$\" + f\n        if rot in [\"rota\", \"rotm\", \"rotp\"] and key in d \\\n            and steps.isnumeric():\n            fn = d[key]\n            w = StepWindow()\n            w.setWindowModality(QtCore.Qt.WindowModal)\n            w.label_1.setText(\"Doing \" + s)\n            w.label_1.setAlignment(QtCore.Qt.AlignCenter)\n            stepping = w.exec()\n            if stepping:\n                if rot == \"rota\":\n                    fn._rota(int(steps))\n                    history.append(\"rota('\" + fn.name + \"', \" + steps + \")\")\n                elif rot == \"rotm\":\n                    fn._rotm(int(steps))\n                    history.append(\"rotm('\" + fn.name + \"', \" + steps + \")\")\n                elif rot == \"rotp\":\n                    fn._rotp(int(steps))\n                    history.append(\"rotp('\" + fn.name + \"', \" + steps + \")\")\n        else:\n            print(\"Invalid history entry '\" + s + \"'\")\n    updateMenu()\n\n# Randomise the model by doing 120 random face rotations\ndef randomise():\n    \"\"\" Randomise the model.\nThis gives you a puzzle that you can solve.\\\n\"\"\"\n    global echo\n    QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))\n    saveecho = _get(\"echo\")\n    _set(\"echo\", False)\n    reset()\n    keys = [\"face00\", \"face10\", \"face11\", \"face12\", \"face13\", \"face14\",\n            \"face20\", \"face21\", \"face22\", \"face23\", \"face24\", \"face30\"]\n    random.seed()\n    for x in range(120):\n        n = random.randrange(0, 24)\n        fn = _get(keys[int(n / 2)])\n        if n % 2 == 0:\n            fn.rotp(0)\n        else:\n            fn.rotm(0)\n    _set(\"echo\", saveecho)\n    updateMenu()\n    QtGui.QApplication.restoreOverrideCursor()\n\ndef findView(widget):\n    \"\"\" Find the View3DInventor.\nThis is an internal function used to to find the View3DInventor\nof a widget.\\\n\"\"\"\n    if widget.metaObject().className().__str__() == \"Gui::View3DInventor\":\n        return widget\n    else:\n        result = None\n        for child in widget.children():\n            v = findView(child)\n            if v != None:\n                result = v\n        return result\n\nclass ViewObserver:\n    \"\"\" This class catches mouse actions.\nMouse clicks are checked to see if they are clicks on the rotation or\nreflection arrows. Mouse motion is checked to see if the mouse is now\nover a rotation or reflection arrow: if so we show the tooltip.\\\n\"\"\"\n    def __init__(self):\n        \"\"\" Create the callback.\\\n\"\"\"\n        self.view = FreeCADGui.ActiveDocument.ActiveView\n        self.callback = self.view.addEventCallbackPivy(\n            SoMouseButtonEvent.getClassTypeId(), self.mouseclicked)\n        self.callback = self.view.addEventCallbackPivy(\n            SoLocation2Event.getClassTypeId(), self.mousemoved)\n        self.currenTip = \"\"\n        self.timer = QtCore.QTimer()\n        self.timer.timeout.connect(self.timeout)\n        self.point = QtCore.QPoint()\n    def timeout(self):\n        \"\"\" Internal function called every second when the mouse is over an\narrow. It redisplays the tooltip preventing Qt's own timer from removing it\nbefore you have had time to read it all.\\\n\"\"\"\n        if self.currenTip == \"\":\n            self.timer.stop()\n        else:\n            QtGui.QToolTip.showText(self.point, self.currenTip)\n    def removeTip(self):\n        \"\"\" Internal function called when the mouse is moved and no longer\nover an arrow. It removes the tootip and stops our timer.\\\n\"\"\"\n        self.timer.stop()\n        QtGui.QToolTip.hideText()\n        self.currenTip = \"\"\n    def mouseclicked(self, event_cb):\n        \"\"\" Internal function called when the user clicks in the document\nwindow. Clicks on arrows are caught here, and anything else is passed up.\\\n\"\"\"\n        self.removeTip()\n        event = event_cb.getEvent()\n        pos = event.getPosition().getValue()\n        obInfo = self.view.getObjectInfo((int(pos[0]),int(pos[1])))\n        if obInfo != None:\n            obname = obInfo[\"Object\"]\n            if len(obname) == 8 and obname[:5] == \"arrow\":\n                if event.isButtonPressEvent(\n                    event, SoMouseButtonEvent.BUTTON1):\n                    s = obname[7:8]\n                    if s == \"y\":\n                        obname = obname[0:7] + \"x\"\n                    if obname in _get(\"reflect\"):\n                        reflect(obname)\n                        event_cb.setHandled()\n                    elif s in \"pqrst\":\n                        d = FreeCAD.Megaminx_Dictionary\n                        f = _get(\"face\" + obname[5:7])\n                        if event.wasShiftDown():\n                            getattr(f, \"rota\")()\n                            event_cb.setHandled()\n                        elif event.wasCtrlDown():\n                            getattr(f, \"roth\")()\n                            event_cb.setHandled()\n                        else:\n                            getattr(f, \"rotp\")()\n                            event_cb.setHandled()\n                    elif s in \"ijklm\":\n                        d = FreeCAD.Megaminx_Dictionary\n                        f = _get(\"face\" + obname[5:7])\n                        if event.wasShiftDown():\n                            getattr(f.opposite, \"rota\")()\n                            event_cb.setHandled()\n                        elif event.wasCtrlDown():\n                            getattr(f.opposite, \"roth\")()\n                            event_cb.setHandled()\n                        else:\n                            getattr(f, \"rotm\")()\n                            event_cb.setHandled()\n    def mousemoved(self, event_cb):\n        \"\"\" Internal function called when the user moves the mouse within the\ndocument window. If the mouse is now over an object with a tooltip,\nwe display the tooltip.\\\n\"\"\"\n        event = event_cb.getEvent()\n        pos = event.getPosition().getValue()\n        x0 = int(pos[0])\n        y0 = int(pos[1])\n        obInfo = self.view.getObjectInfo((x0, y0))\n        if obInfo != None:\n            d = FreeCAD.Megaminx_Dictionary\n            key = App.ActiveDocument.Name + \"$\" + \"tooltip\" + obInfo[\"Object\"]\n            if key in d:\n                mw = Gui.getMainWindow()\n                view3DWidget = findView(mw.centralWidget())\n                if view3DWidget != None:\n                    geom = view3DWidget.geometry()\n                    y1 = geom.height() - y0\n                    self.point = view3DWidget.mapToGlobal(\n                                     QtCore.QPoint(x0, y1))\n                    self.currenTip = d[key]\n                    QtGui.QToolTip.showText(self.point, self.currenTip)\n                    self.timer.start(1000)\n            else:\n                self.removeTip()\n        else:\n            self.removeTip()\n\ndef fixLightModel():\n    \"\"\" This internal function disables the default Phong shading.\nThis prevents the face colours appearing to change during rotations.\\\n\"\"\"\n    v = Gui.ActiveDocument.ActiveView.getViewer()\n    sceneGraph = v.getSoEventManager().getSceneGraph()\n    if str(sceneGraph.getChild(0).getName()) != \"LightModel\":\n        lm=coin.SoLightModel()\n        lm.model.setValue(0)\n        lm.setName(\"LightModel\")\n        sceneGraph.insertChild(lm,0)\n\ndef MultiViews(parent, child, i):\n    \"\"\" This internal function creates multiple views of an object.\nIt gets applied to all the facets of the Megaminx but not to the arrows.\\\n\"\"\"\n    sf = _get(\"sf\")\n    dd = _get(\"dd\")\n    theta = _get(\"face00\").normal.getAngle(_get(\"face20\").normal)\n    newchild = coin.SoMultipleCopy()\n    newchild.addChild(child)\n    views = coin.SoMFMatrix()\n    views.setNum(6)\n    mat = coin.SbMatrix()\n    mat.makeIdentity()\n    views.set1Value(0, mat)\n    mat = coin.SbMatrix()\n    mat.setTransform(\n        coin.SbVec3f(dd * c1, dd * s1, 0.0),\n        coin.SbRotation(coin.SbVec3f(c0 - c2, s0 - s2, 0.0), theta),\n        coin.SbVec3f(sf, sf, sf))\n    views.set1Value(1, mat)\n    mat = coin.SbMatrix()\n    mat.setTransform(\n        coin.SbVec3f(dd * c0, dd * s0, 0.0),\n        coin.SbRotation(coin.SbVec3f(c4 - c1, s4 - s1, 0.0), theta),\n        coin.SbVec3f(sf, sf, sf))\n    views.set1Value(2, mat)\n    mat = coin.SbMatrix()\n    mat.setTransform(\n        coin.SbVec3f(dd * c4, dd * s4, 0.0),\n        coin.SbRotation(coin.SbVec3f(c3 - c0, s3 - s0, 0.0), theta),\n        coin.SbVec3f(sf, sf, sf))\n    views.set1Value(3, mat)\n    mat = coin.SbMatrix()\n    mat.setTransform(\n        coin.SbVec3f(dd * c3, dd * s3, 0.0),\n        coin.SbRotation(coin.SbVec3f(c2 - c4, s2 - s4, 0.0), theta),\n        coin.SbVec3f(sf, sf, sf))\n    views.set1Value(4, mat)\n    mat = coin.SbMatrix()\n    mat.setTransform(\n        coin.SbVec3f(dd * c2, dd * s2, 0.0),\n        coin.SbRotation(coin.SbVec3f(c1 - c3, s1 - s3, 0.0), theta),\n        coin.SbVec3f(sf, sf, sf))\n    views.set1Value(5, mat)\n    newchild.matrix = views\n    parent.replaceChild(i, newchild)\n\ndef adjustView():\n    \"\"\" This fixes up our special view.\nWe arrange multiple views from different directions of all the parts of the\nMegaminx, but not the arrows. This enables a user to see all of the faces.\nAlso we set the camera position by hand because FreeCAD's fit view function\ndoes not work well with multiple views.\\\n\"\"\"\n    Gui.activeDocument().activeView().viewTop()\n    camera = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()\n    camera.position.setValue(0.2, 0.0, 5.00)\n    camera.scaleHeight(4.3)\n    sg = FreeCADGui.ActiveDocument.ActiveView.getSceneGraph()\n    if sg.getNumChildren() != 0:\n        for i in range(sg.getNumChildren()):\n            child = sg.getChild(i)\n            type = child.getTypeId().getName().__str__()\n            if child.getTypeId().getName().__str__() == 'Separator':\n                name = child.getName().__str__()[:5]\n                if name != \"arrow\":\n                    MultiViews(sg, child, i)\n            if child.getTypeId().getName().__str__() == 'MultipleCopy':\n                if child.getNumChildren() != 0:\n                    name = child.getChild(0).getName().__str__()\n                    if App.ActiveDocument.getObject(name) == None:\n                        child.removeAllChildren()\n\ndef createMenu():\n    \"\"\" Create the Megaminx menu if needed and add it to the menu bar.\\\n\"\"\"\n    menu = None\n    d = FreeCAD.Megaminx_Dictionary\n    for key in d:\n        if key.endswith(\"menu\"):\n            menu = d[key]\n            _set(\"menu\", menu)\n            break\n    if menu == None:\n        MegaminxMenu = Gui.getMainWindow().menuBar().addMenu(\"Megamin&x\")\n        _set(\"menu\", MegaminxMenu)\n        actionHelp = QtGui.QAction(\"Show &help\", MegaminxMenu)\n        actionHelp.setStatusTip(\"Display some help text\")\n        actionHelp.connect(\n            actionHelp, QtCore.SIGNAL(\"triggered()\"), help_window)\n        MegaminxMenu.addAction(actionHelp)\n        resetAction = QtGui.QAction(\"&Reset\", MegaminxMenu)\n        resetAction.setStatusTip(\n            \"Reset the Megaminx to its initial state and clear the history\")\n        resetAction.connect(resetAction, QtCore.SIGNAL(\"triggered()\"), reset)\n        MegaminxMenu.addAction(resetAction)\n        undoAction = QtGui.QAction(\"&Undo\", MegaminxMenu)\n        undoAction.setStatusTip(\n            \"Undo the last rotation and remove it from the history\")\n        undoAction.connect(undoAction, QtCore.SIGNAL(\"triggered()\"), undo)\n        MegaminxMenu.addAction(undoAction)\n        copyAction = QtGui.QAction(\"&Copy history\", MegaminxMenu)\n        copyAction.setStatusTip(\n            \"Copy the history to the clipboard\")\n        copyAction.connect(\n            copyAction, QtCore.SIGNAL(\"triggered()\"), copy_history)\n        MegaminxMenu.addAction(copyAction)\n        stepAction = QtGui.QAction(\"ste&P history\", MegaminxMenu)\n        stepAction.setStatusTip(\n            \"Step through the history showing a dialog box at each step\")\n        stepAction.connect(\n            stepAction, QtCore.SIGNAL(\"triggered()\"), step_history)\n        MegaminxMenu.addAction(stepAction)\n        actionUndoHistory = QtGui.QAction(\"Undo history\", MegaminxMenu)\n        actionUndoHistory.setStatusTip(\n            \"Replace the history by a new one which reverses it\")\n        actionUndoHistory.connect(\n            actionUndoHistory, QtCore.SIGNAL(\"triggered()\"), undo_history)\n        MegaminxMenu.addAction(actionUndoHistory)\n        action = QtGui.QAction(\"Randomise\", MegaminxMenu)\n        action.setStatusTip(\n            \"Randomise the Megaminx giving you a puzzle to solve\")\n        action.connect(action, QtCore.SIGNAL(\"triggered()\"), randomise)\n        MegaminxMenu.addAction(action)\n        actionEcho = QtGui.QAction(\"&Echo\", MegaminxMenu)\n        actionEcho.setCheckable(True)\n        actionEcho.setChecked(_get(\"echo\"))\n        actionEcho.setStatusTip(\n            \"If checked, rotations are echoed to the Report View\")\n        actionEcho.connect(actionEcho, QtCore.SIGNAL(\"triggered()\"), _set_echo)\n        MegaminxMenu.addAction(actionEcho)\ndef updateMenu():\n    \"\"\" This updates the menu.\nMenu items which act on the history are enabled only if the\nhistory is not empty and disabled otherwise.\\\n\"\"\"\n    enabled = len(_get(\"history\")) > 0\n    d = FreeCAD.Megaminx_Dictionary\n    for key in d:\n        if key.endswith(\"menu\"):\n            menu = d[key]\n            for action in menu.actions():\n                if action.iconText() == \"Reset\":\n                    action.setEnabled(enabled)\n                elif action.iconText() == \"Undo\":\n                    action.setEnabled(enabled)\n                elif action.iconText() == \"Copy history\":\n                    action.setEnabled(enabled)\n                elif action.iconText() == \"steP history\":\n                    action.setEnabled(enabled)\n                elif action.iconText() == \"Undo history\":\n                    action.setEnabled(enabled)\n            break\n\n# Now we've defined all these functions, execute them.\n_set(\"history\", [])\nmake_faces()\nreset()\nsetTextures()\nViewObserver()\nadjustView()\ncreateMenu()\nupdateMenu()\nfixLightModel()\nGui.updateGui()\nQtGui.QApplication.restoreOverrideCursor()\n",
    "url": "https://wiki.freecad.org/Macro_Megaminx",
    "raw_code_url": "https://raw.githubusercontent.com/rparkins999/Megaminx/master/Megaminx.FCMacro",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_Megaminx",
    "version": "00.06",
    "license": "",
    "date": "17/02/2019",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Aleph0",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Megaminx.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/4/43/Macro_Megaminx.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "PropertyMemo",
    "on_wiki": true,
    "on_git": false,
    "desc": "<span style=\"background-color:#ff0000; color:#ffffff;\">New version GUI modifyed for the HD dpi (QGridLayout) run only FC version 0.19 and more (PySide2 Qt5)</span> <br /> <br /> <p>For the precedent version see <a rel=\"nofollow\" class=\"external text\" href=\"https://gist.githubusercontent.com/mario52a/eafcf79703fab64b8da5/raw/51702c17fb4b205da52488bf2a239011bbbc9da5/Macro_FCPropertyMemo.FCMacro\">Macro_FCPropertyMemo.FCMacro</a> and install it manually.<br /><br /> This macro creates an additional Property (memo or other text) for your object (works only with Draft objects).<br /><br />Macro version: 2020-05-17<br />FreeCAD version: 0.19<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/f/f2/PropertyMemo.png\">ToolBar Icon</a><br />Author: Mario52<br /> </p> ",
    "comment": "New version GUI modifyed for the HD dpi (QGridLayout) run only FC version 0.19 and more (PySide2 Qt5) ",
    "code": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\"\"\"\n***************************************************************************\n*   Copyright (c) 2015, 2016, 2017, 2018, 2019, 2020 <mario52>            *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n**                                                                       **\n*   Use at your own risk. The author assumes no liability for data loss.  *\n*              It is advised to backup your data frequently.              *\n*             If you do not trust the software do not use it.             *\n**                                                                       **\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n***************************************************************************\n*           WARNING! All changes in this file will be lost and            *  \n*                  may cause malfunction of the program                   *\n***************************************************************************\n\"\"\"\n#Macro_FCPropertyMemo 28/09/2015, 19/10/2015, 2020/05/17\n#\n#\n#OS: Windows 10 (10.0)\n#Word size of OS: 64-bit\n#Word size of FreeCAD: 64-bit\n#Version: 0.19.20887 (Git)\n#Build type: Release\n#Branch: master\n#Hash: 42c56d9fef82b484448e3730eb7da69c48fe1374\n#Python version: 3.6.8\n#Qt version: 5.12.1\n#Coin version: 4.0.0a\n#OCC version: 7.3.0\n#Locale: French/Mars (fr_MA)\n#\n#\n__title__   = \"Macro_FCPropertyMemo\"\n__author__  = \"Mario52\"\n__url__     = \"https://wiki.freecadweb.org/Macro_PropertyMemo\"\n__urlGist   = \"https://gist.github.com/mario52a/eafcf79703fab64b8da5\"\n__version__ = \"00.03\"\n__date__    = \"2020/05/17\"  #YYYY/MM/DD\n\n#### Test FreeCAD.Version simple ############################################################################################################\nif int(FreeCAD.Version()[1]) < 19:      # Version de FreeCAD\n    FreeCAD.Console.PrintMessage(\"This version \" + __title__ + \" rmu  work with the FreeCAD 0.19 or higher.\" + \"\\n\\n\")\n    FreeCAD.Console.PrintMessage(\"For the precedent version see the page \" + \"\\n\\n\")\n    FreeCAD.Console.PrintMessage(\"https://gist.githubusercontent.com/mario52a/eafcf79703fab64b8da5/raw/51702c17fb4b205da52488bf2a239011bbbc9da5/Macro_FCPropertyMemo.FCMacro\" + \"\\n\\n\")\n\n#### Test FreeCAD.Version simple ############################################################################################################\n\nimport PySide2\nfrom PySide2 import (QtWidgets, QtCore, QtGui)\nfrom PySide2.QtWidgets import (QWidget, QApplication, QSlider, QGraphicsView, QGraphicsScene, QVBoxLayout, QStyle)\nfrom PySide2.QtGui import (QPainter, QColor, QIcon)\nfrom PySide2.QtSvg import *\n#import Draft, Part, FreeCAD, math, PartGui, FreeCADGui, FreeCAD\n\nglobal path\n#path = FreeCAD.ConfigGet(\"AppHomePath\")\npath = FreeCAD.ConfigGet(\"UserAppData\")\n\nglobal title_01 ; title_01  = \"Memo\"    # title of menu\nglobal title_02 ; title_02  = \"\"        # title of propriety\nglobal memo_01  ; memo_01   = \"\"        # memo\nglobal forString; forString = 1         # memo for String or List\nglobal ui       ; ui        = \"\"        # \n\ntry:\n    _fromUtf8 = QtCore.QString.fromUtf8\nexcept AttributeError:\n    def _fromUtf8(s):\n        return s\n\ntry:\n    _encoding = QtGui.QApplication.UnicodeUTF8\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig, _encoding)\nexcept AttributeError:\n    def _translate(context, text, disambig):\n        return QtGui.QApplication.translate(context, text, disambig)\n\nclass Ui_MainWindow(object):\n\n    def setupUi(self, MainWindow):\n        self.window = MainWindow\n        global path\n        global title_01\n        global title_02\n        global memo_01\n\n        ##path###########################################################################\n        #path = FreeCAD.ConfigGet(\"AppHomePath\")\n        #path = FreeCAD.ConfigGet(\"UserAppData\")\n        #path = \"your path\"\n        param = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macro\")# macro path\n        self.path = param.GetString(\"MacroPath\",\"\") + \"/\"                   # macro path\n        self.path = self.path.replace(\"\\\\\",\"/\")\n        #App.Console.PrintMessage(str(\"Path for the icons : \") + self.path + \"\\n\" + __title__ + \" : \" +__version__ + \" \" + __date__ + \"\\n\")\n       # #################################################################################\n\n        MainWindow.setObjectName(_fromUtf8(\"MainWindow\"))\n#        MainWindow.resize(260, 200)\n#        MainWindow.setMinimumSize(QtCore.QSize(254, 163))\n#        MainWindow.setMaximumSize(QtCore.QSize(254, 163))\n\n        ###### Read Configuration begin ####\n        title_01 = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetString(\"LE_Edit_01\")\n        title_02 = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetString(\"LE_Edit_02\")\n        CBString = FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).GetBool(\"CB_String\")\n        ###### Read Configuration end   ####\n\n        self.centralwidget = QtWidgets.QWidget(MainWindow)\n        self.centralwidget.setObjectName(_fromUtf8(\"centralwidget\"))\n\n        self.groupBox = QtWidgets.QGroupBox()\n\n        self.label_00 = QtWidgets.QLabel()\n        self.label_00.setAlignment(QtCore.Qt.AlignCenter)\n        font = QtGui.QFont()\n        font.setPointSize(10)\n        font.setBold(True)\n        font.setUnderline(True)\n        font.setWeight(80)\n        self.label_00.setFont(font)\n\n        self.label_01 = QtWidgets.QLabel()\n\n        self.LE_Edit_01 = QtWidgets.QLineEdit()              # title property\n        self.LE_Edit_01.setText(_fromUtf8(title_01))\n        self.LE_Edit_01.textChanged.connect(self.on_LE_Edit_01_Pressed)\n\n        self.label_02 = QtWidgets.QLabel()\n\n        self.LE_Edit_02 = QtWidgets.QLineEdit()              # title name\n        self.LE_Edit_02.setText(_fromUtf8(title_02))\n        self.LE_Edit_02.textChanged.connect(self.on_LE_Edit_02_Pressed)    #\n\n#        self.label_03 = QtWidgets.QLabel()\n\n#        self.LE_Edit_03 = QtWidgets.QLineEdit()              # memo \n#        self.LE_Edit_03.textChanged.connect(self.on_LE_Edit_03_Pressed)    #\n\n        self.CB_String = QtWidgets.QCheckBox()                      # for String or List\n        self.CB_String.setChecked(CBString)\n        self.CB_String.clicked.connect(self.on_CB_String_clicked)   # connect on def \"on_checkBox_1_clicked\"\n\n        self.PB_Help = QtWidgets.QPushButton()\n        self.PB_Help.setToolTip(_fromUtf8(\"Help on line  \" + __version__ + \"  \" + __date__ + \" rmu\"))\n        self.PB_Help.setIcon(QtGui.QIcon.fromTheme(\"help\",QtGui.QIcon(\":/icons/help-browser.svg\")))\n        self.PB_Help.clicked.connect(self.on_PB_Help)    #\n\n        self.PB_Button_01 = QtWidgets.QPushButton()\n        self.PB_Button_01.setIcon(QtGui.QIcon.fromTheme(\"refresh\",QtGui.QIcon(\":/icons/view-refresh.svg\")))\n        self.PB_Button_01.clicked.connect(self.on_PB_Button_01_clicked)    #\n\n        self.PB_Button_02 = QtWidgets.QPushButton()\n#        self.PB_Button_02.setIcon(QIcon(QApplication.style().standardIcon(QStyle.SP_DialogOkButton))) #\n        self.PB_Button_02.setIcon(QtGui.QIcon.fromTheme(\"execute\",QtGui.QIcon(\":/icons/button_valid.svg\")))\n        self.PB_Button_02.clicked.connect(self.on_PB_Button_02_clicked)    #\n\n        self.PB_Button_03 = QtWidgets.QPushButton()\n        self.PB_Button_03.setIcon(QtGui.QIcon.fromTheme(\"close\",QtGui.QIcon(\":/icons/application-exit.svg\")))\n        self.PB_Button_03.clicked.connect(self.on_PB_Button_03_clicked)    #\n\n        #### Layout debut ########################\n        self.grid0 = QtWidgets.QGridLayout(self.centralwidget)\n        self.grid0.setContentsMargins(10, 10, 10, 10)\n        self.grid0.addWidget(self.groupBox, 0, 0, 1, 1)\n        self.gridLayout = QtWidgets.QGridLayout(self.groupBox)\n        self.gridLayout.addWidget(self.label_00, 1, 0, 1, 4)\n        self.gridLayout.addWidget(self.label_01, 2, 0, 1, 4)\n        self.gridLayout.addWidget(self.LE_Edit_01, 3, 0, 1, 4)\n        self.gridLayout.addWidget(self.label_02, 4, 0, 1, 2)\n        self.gridLayout.addWidget(self.CB_String, 4, 2, 1, 2)\n        self.gridLayout.addWidget(self.LE_Edit_02, 5, 0, 1, 4)\n#        self.gridLayout.addWidget(self.label_03, 6, 0, 1, 4)\n#        self.gridLayout.addWidget(self.LE_Edit_03, 7, 0, 1, 3)\n        self.gridLayout.addWidget(self.PB_Help, 8, 0, 1, 1)\n        self.gridLayout.addWidget(self.PB_Button_01, 8, 1, 1, 1)\n        self.gridLayout.addWidget(self.PB_Button_02, 8, 2, 1, 1)\n        self.gridLayout.addWidget(self.PB_Button_03, 8, 3, 1, 1)\n        #### Layout fin ###########################\n\n        MainWindow.setCentralWidget(self.centralwidget)\n        self.retranslateUi(MainWindow)\n        QtCore.QMetaObject.connectSlotsByName(MainWindow)\n\n    def retranslateUi(self, MainWindow):\n        MainWindow.setWindowFlags(PySide2.QtCore.Qt.WindowStaysOnTopHint)                 # PySide2 cette fonction met la fenetre en avant\n\n        MainWindow.setWindowIcon(QtGui.QIcon(_fromUtf8(self.path + \"PropertyMemo.png\")))  # change l'icone de la fenetre principale\n        _translate = QtCore.QCoreApplication.translate\n        MainWindow.setWindowTitle(_translate(\"MainWindow\", \"FCPropertyMemo\"))\n\n        self.groupBox.setTitle(_translate(\"MainWindow\", \"ver : \" + __version__ + \" : \" + __date__ + \" (rmu)\"))\n        self.label_00.setText(_translate(\"MainWindow\", \"FCProperty Memo\"))\n        self.label_01.setText(_translate(\"MainWindow\", \"Property title\"))\n        self.label_02.setText(_translate(\"MainWindow\", \"Property name\"))\n        self.CB_String.setText(_translate(\"MainWindow\", \"UnCheck for String\"))\n        self.LE_Edit_02.setToolTip(\"Title of property\")\n#        self.label_03.setText(_translate(\"MainWindow\", \"Memo\"))\n#        self.LE_Edit_03.setText(_fromUtf8(\"\"))\n#        self.LE_Edit_03.setToolTip(\"Text memo\")\n        self.PB_Help.setText(_translate(\"MainWindow\", \"Wiki\"))\n        self.PB_Button_01.setText(_translate(\"MainWindow\", \"Reset\"))\n        self.PB_Button_02.setText(_translate(\"MainWindow\", \"Validate\"))\n        self.PB_Button_03.setText(_translate(\"MainWindow\", \"Quit\"))\n        self.CB_String.setToolTip(\"The memo is a string by default\"+\"\\n\"+\n                                  \"If the checkBox is checked the memo is a list in one window\"+\"\\n\"+\n                                  \"Clic the '...' in ComboView > Data\")\n\n    def on_LE_Edit_01_Pressed(self):        # Line edit 01 title\n        global title_01\n\n        title_01 = self.LE_Edit_01.text()\n#        App.Console.PrintMessage(title_01+\"\\n\")\n\n    def on_LE_Edit_02_Pressed(self):        # Line edit 02 title property\n        global title_02\n\n        title_02 = self.LE_Edit_02.text()\n#        App.Console.PrintMessage(title_02+\"\\n\")\n\n#    def on_LE_Edit_03_Pressed(self):        # Line edit 03 memo\n#        global memo_01\n#        memo_01 = self.LE_Edit_03.text()\n#        App.Console.PrintMessage(memo_01+\"\\n\")\n\n    def on_CB_String_clicked(self):         # connection on_checkBox_1_clicked\n        global forString\n\n        if self.CB_String.isChecked():      # if checkbox_01 is checked then ....\n            forString = 1\n            self.CB_String.setText(\"UnCheck for String\")\n        else :\n            forString = 0\n            self.CB_String.setText(\"Check for List\")\n#        App.Console.PrintMessage(\"on_CB_String_clicked \"+str(forString)+\"\\n\")\n\n    def on_PB_Button_01_clicked(self):      # Button Reset\n        global title_01\n        global title_02\n        global memo_01\n        global forString\n\n        self.LE_Edit_01.clear()\n        title_01 = \"Memo\"\n        self.LE_Edit_01.setText(_fromUtf8(title_01))\n        self.LE_Edit_02.clear()\n        title_02 = \"\"\n#        self.LE_Edit_03.clear()\n#        memo_01 = \"\"\n        self.CB_String.setChecked(True)\n        forString = 1\n        self.CB_String.setText(\"UnCheck for String\")\n#        App.Console.PrintMessage(\"on_PB_Button_01_clicked\\n\")\n\n    def on_PB_Button_02_clicked(self):      # Button Validate\n        global ui\n        global title_01\n        global title_02\n        global memo_01\n        global forString\n\n#        try:\n        obj = \"\"\n        obj = FreeCADGui.Selection.getSelection()[0]\n        op  = obj.PropertiesList\n        pas = 0\n        if (title_02 != \"\"):\n            for p in op:\n                if str(p) == title_02:\n                    App.Console.PrintWarning(\"This Property is already present\"+\"\\n\")\n                    pas = 0\n                    break\n                else :\n                    pas = 1\n            if pas == 1:\n                    if forString == 0 :                         # title_02 = sous titre, title_01 = titre\n                        a = obj.addProperty(\"App::PropertyString\",title_02, title_01, \"_Memo\")       # create a memo string\n                        #FreeCAD.ActiveDocument.getObject(obj.Name) = memo_01\n                    else :\n                        a = obj.addProperty(\"App::PropertyStringList\",title_02, title_01, \"_Memo\")   # Create a list in window\n                    Gui.Selection.clearSelection(obj.Name)\n                    Gui.Selection.addSelection(obj)\n                    App.activeDocument().recompute()\n            #ui.on_PB_Button_01_clicked()    # Reset\n        else:\n            App.Console.PrintMessage(\"Field empty\"+\"\\n\")\n\n#        except Exception:\n#                    App.Console.PrintWarning(\"Object not selected or not Draft object\"+\"\\n\")\n                \n        App.Console.PrintMessage(\"on_PB_Button_02_clicked\\n\")\n\n    def on_PB_Button_03_clicked(self):      # Button Quit\n        App.Console.PrintMessage(\"End FCPropertyMemo\"+\"\\n\\n\")\n        ###### Write Configuration begin ####\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetBool(\"CB_String\", self.CB_String.isChecked())# True or False\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"LE_Edit_01\", title_01) # \"\"\n        FreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"LE_Edit_02\", \"\") # title_02\n        ###### Write Configuration end   ####\n        self.window.hide()\n\n    def on_PB_Help(self): # Button Help\n        import WebGui\n        WebGui.openBrowser(__url__)\n        App.Console.PrintMessage(__url__ + \"\\n\")\n\nFreeCAD.ParamGet(\"User parameter:BaseApp/Preferences/Macros/FCMmacros/\" + __title__).SetString(\"Version\",__version__ + \" (\" + __date__ + \")\")# \n\nMainWindow = QtWidgets.QMainWindow()\nui = Ui_MainWindow()\nui.setupUi(MainWindow)\nMainWindow.show()",
    "url": "https://wiki.freecad.org/Macro_PropertyMemo",
    "raw_code_url": "",
    "wiki": "",
    "version": "00.03",
    "license": "",
    "date": "2020/05/17",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Mario52",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\PropertyMemo.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/f/f2/PropertyMemo.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Rubik Cube",
    "on_wiki": true,
    "on_git": false,
    "desc": "Macro to Display a Rubik Cube and interactively do slice rotations.<br /><br />Macro version: 00.05<br />Last modified: 2018-12-15<br />FreeCAD version: &lt;= 0.17<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/7/7c/Macro_Rubik_Cube.png\">ToolBar Icon</a><br />Author: Aleph0<br /> ",
    "comment": "Virtual Rubik Cube",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"\n***************************************************************************\n*                                                                         *\n*   This macro creates a virtual Rubik Cube and enable you to manipulate  *\n*   it.                                                                   *\n*   You can chooose the size (number of small cubes along an edge).       *\n*   It then makes the cube: large sizes can take a while.                 *\n*   It then displays several views of the cube.                           *\n*   The central and largest view is an axonometric projection.            *\n*   This has arrows around it which you can click on to rotate slices.    *\n*   There are some text direction labels near the arrows: clicking on one *\n*   of those rotates the whole cube. You have to click on the actual      *\n*   letter: FreeCAD doesn't see clicks on the text background             *\n*   Another view is an axonometric projection from the other side.        *\n*   Another view combines views towards each face so as to                *\n*   look like a net of the cube's surface unfolded.                       *\n*   \n*   The macro maintains a history of the slice rotations you have done.   *\n*   It puts three buttons at the top of the window.                       *\n*   One undoes the last slice rotation and removes it from the history.   *\n*   One saves the history to the clipboard as a sequence of function      *\n*   calls which can be pasted into a macro which can then be called       *\n*   to replay the same set of rotations. Thus you can save an \"operator\"  *\n*   (a sequence of slice rotation which does something useful).           *\n*   The third button resets the cube to its initial state                 *\n*   and clears the history.                                               *\n*                                                                         *\n*   There are also some functions defined which can be called from the    *\n*   python console window:                                                *\n*   fix_reload() modifies a restored FreeCAD save file to add the extra   *\n*   views and interactive controls that this macro and its functions use; *\n*   ramdomise() randomises the cube;                                      *\n*   reverse_history(), reflectX_history(), reflectY_history(),            *\n*   reflectZ_history(), rotpX_history(), rotmX_history(),                 *\n*   rotpY_history(), rotmY_history(), rotpZ_history(), and                *\n*   rotmZ_history() each replace the history by a version modified in the *\n*   manner indicated - these are useful for creating modified operators.  *\n*   step_history() replays the history, popping a dialog box before each  *\n*   rotation - this is useful if you have developed an operator using the *\n*   model and you want to do the same rotations on a real cube.           *\n*                                                                         *\n***************************************************************************\n*   Copyright \u00a9 2018 Richard P. Parkins, M. A.                            *\n*                                                                         *\n*   This file is a supplement to the FreeCAD CAx development system.      *\n*                                                                         *\n*   This program is free software; you can redistribute it and/or modify  *\n*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n*   as published by the Free Software Foundation; either version 2 of     *\n*   the License, or (at your option) any later version.                   *\n*   for detail see the LICENCE text file.                                 *\n*                                                                         *\n*   This software is distributed in the hope that it will be useful,      *\n*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n*   GNU Library General Public License for more details.                  *\n*                                                                         *\n*   You should have received a copy of the GNU Library General Public     *\n*   License along with this macro; if not, write to the Free Software     *\n*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n*   USA                                                                   *\n*                                                                         *\n***************************************************************************\n\"\"\"\n__title__   = \"Rubik_cube\"\n__author__  = \"Aleph0\"\n__version__ = \"00.05\"\n__date__    = \"15/12/2018\"\n__Comment__ = \"Virtual Rubik Cube\"\n__Wiki__ = \"http://www.freecadweb.org/wiki/index.php?title=Macro_Rubik_Cube\"\n__Help__ = \"see first few lines of macro text\"\n__Status__ = \"stable\"\n__Requires__ = \"freecad 0.16\"\n\n#OS: Ubuntu 14.04.5 LTS\n#Word size of OS: 64-bit\n#Word size of FreeCAD: 64-bit\n#Version: 0.16.6703 (Git)\n#Build type: None\n#Branch: releases/FreeCAD-0-16\n#Hash: 2ce5c8d2e3020d05005ed71f710e09e9aa561f40\n#Python version: 2.7.6\n#Qt version: 4.8.6\n#Coin version: 4.0.0a\n#OCC version: 6.8.0.oce-0.17\n\n# This parameter determines the speed at which slice rotations are animated\n# If you have a faster computer you can increase the value\n# This will make the animation smoother\n# If you have a slow computer you can decrease the value\n# This will make the animation faster but more jerky for large cubes\nslowness = 500\n\nimport FreeCAD\nimport Part\nimport Draft\nimport time\nimport random\nfrom FreeCAD import Base\nfrom FreeCAD import Console\nfrom pivy import coin\nfrom pivy.coin import *\nfrom PySide import *\n\n# This horrible hack is needed because some versions of FreeCAD seem to have\n# been built with a mixture of Qt4 and Qt5. In those versions, the Qt5 version\n# of setOverrideCursor() doesn't work, but the Qt4 version of MainWindow\n# doesn't seem to have a centralWidget(), which we need.\ntry:\n    import PyQt4.QtGui\n    def busyCursor():\n        PyQt4.QtGui.QApplication.setOverrideCursor(\n            PyQt4.QtGui.QCursor(PyQt4.QtCore.Qt.WaitCursor))\n    def restoreCursor():\n        PyQt4.QtGui.QApplication.restoreOverrideCursor()\nexcept Exception:\n    def busyCursor():\n        QtGui.QApplication.setOverrideCursor(\n            QtGui.QCursor(QtCore.Qt.WaitCursor))\n    def restoreCursor():\n        QtGui.QApplication.restoreOverrideCursor()\n\n# If this is the first time this macro has been run in this invocation of\n# FreeCAD, create our dictionary of document-specific data structures\nif not hasattr(FreeCAD, \"Rubik_Cube_executed\"):\n    FreeCAD.Rubik_Cube_executed = 1\n    Dictionary = {}\n\n# Create a new document and make it current\nApp.ActiveDocument = App.newDocument(\"Rubik_Cube\")\nGui.ActiveDocument = Gui.getDocument(str(App.ActiveDocument.Name))\n\n# for debugging\ndef showMessage(s):\n    diag = QtGui.QMessageBox(QtGui.QMessageBox.NoIcon, '', s)\n    diag.setWindowModality(QtCore.Qt.NonModal)\n    diag.exec_()\n\n# This bit of code pops up the dialog to ask for the size and whether to orient\n# inner faces (useful if you are simulating a cube which has non-symmetrical\n# patterns instead of plain colours).\ndefaultSize = 3\nclass AskSizeWindow(QtGui.QDialog):\n    # automagically called when a class instance is created\n    def __init__(self):\n        super(AskSizeWindow, self).__init__()\n        self.initUI()\n    # Lay out the interactive elements\n    def initUI(self):\n        self.setWindowTitle(\"Rubik Cube Size\")\n        geom = Gui.getMainWindow().geometry()\n        width = 300\n        height = 200\n        margin = 10\n        xpos = geom.center().x() - width / 2\n        ypos = geom.center().y() - height / 2\n        self.setGeometry(xpos, ypos, width, height)\n        ypos = margin\n        self.label_1 = QtGui.QLabel(self)\n        self.label_1.setGeometry(QtCore.QRect(width/2 - 100, ypos, 200, 25)) \n        self.label_1.setObjectName(\"label_1\")\n        self.label_1.setText(\"Number of small cubes\")\n        self.label_1.setAlignment(QtCore.Qt.AlignCenter)\n        ypos = ypos + 25\n        self.label_2 = QtGui.QLabel(self)\n        self.label_2.setGeometry(QtCore.QRect(width/2 - 100, ypos, 200, 25)) \n        self.label_2.setObjectName(\"label_1\")\n        self.label_2.setText(\"along an edge\")\n        self.label_2.setAlignment(QtCore.Qt.AlignCenter)\n        ypos = ypos + 25\n        self.spinBox = QtGui.QSpinBox(self)\n        self.spinBox.setGeometry(QtCore.QRect(width/2 - 50, ypos, 100, 30))\n        self.spinBox.setMinimum(2)\n        self.spinBox.setMaximum(100)\n        Dictionary[str(App.ActiveDocument.Name)+\"Size\"] = defaultSize\n        self.spinBox.setValue(defaultSize)\n        self.spinBox.setSingleStep(1)\n        self.spinBox.setObjectName(\"spinBox\")\n        self.spinBox.valueChanged.connect(self.on_spinBox_valueChanged)\n        ypos = ypos + 40\n        self.checkBox = QtGui.QCheckBox(\"Oriented inner faces\", self)\n        self.checkBox.setGeometry(QtCore.QRect(width/2 - 100, ypos, 200, 30))\n        Dictionary[str(App.ActiveDocument.Name)+\"Oriented\"] = QtCore.Qt.Unchecked\n        self.checkBox.setCheckState(QtCore.Qt.Unchecked)\n        self.checkBox.setObjectName(\"checkBox\")\n        self.checkBox.stateChanged.connect(self.on_checkBox_stateChanged)\n        ypos = ypos + 40\n        self.OKbutton = QtGui.QPushButton(self)\n        self.OKbutton.setGeometry(QtCore.QRect(width/2 - 40, ypos, 80, 40))\n        self.OKbutton.setText(\"OK\")\n        self.OKbutton.clicked.connect(self.onOK)\n    def on_spinBox_valueChanged(self, val):\n        Dictionary[str(App.ActiveDocument.Name)+\"Size\"] = val\n    def on_checkBox_stateChanged(self, val):\n        Dictionary[str(App.ActiveDocument.Name)+\"Oriented\"] = val\n    def onOK(self):\n        self.close()\n        self.destroy()\n# now create the class instance which shows the dialog\nAskSizeWindow().exec_()\n\n# Display a wait cursor while we are making the cube\nbusyCursor()\n\n# Dialog box shown on each step by step_history()\nclass StepWindow(QtGui.QDialog):\n    # automagically called when a class instance is created\n    def __init__(self):\n        super(StepWindow, self).__init__()\n        # Lay out the interactive elements\n        mw = Gui.getMainWindow()\n        cw = mw.centralWidget()\n        ww = 220\n        wh = 100\n        margin = 10\n        self.setWindowTitle(\"Next Step\")\n        geom1 = mw.geometry()\n        geom2 = cw.geometry()\n        xpos = geom1.left() + geom2.center().x() - ww / 2\n        buttons = Dictionary[str(App.ActiveDocument.Name)+\"buttons\"]\n        buttonsheight = buttons.geometry().height()\n        # The 25 is a bit magic to get the Dialog box just below the buttons\n        ypos = geom1.top() + geom2.top() + buttonsheight + 25\n        self.setGeometry(xpos, ypos, ww, wh)\n        ypos = margin\n        self.label_1 = QtGui.QLabel(self)\n        self.label_1.setGeometry(QtCore.QRect(ww/2 - 100, ypos, 200, 25)) \n        self.label_1.setObjectName(\"label_1\")\n        ypos = ypos + 40\n        self.OKbutton = QtGui.QPushButton(self)\n        self.OKbutton.setGeometry(QtCore.QRect(margin, ypos, 80, 40))\n        self.OKbutton.setText(\"OK\")\n        self.OKbutton.clicked.connect(self.onOK)\n        self.Quitbutton = QtGui.QPushButton(self)\n        xpos = ww - 80 - margin\n        self.Quitbutton.setGeometry(QtCore.QRect(xpos, ypos, 80, 40))\n        self.Quitbutton.setText(\"Stop\")\n        self.Quitbutton.clicked.connect(self.onQuit)\n    def onOK(self):\n        self.close()\n        self.destroy()\n    def onQuit(self):\n        Dictionary[str(App.ActiveDocument.Name)+\"Stepping\"] = 0\n        self.close()\n        self.destroy()\n\n# This bit of code catches clicks on the rotation arrows\nclass ViewObserver:\n    def __init__(self):\n        self.view = FreeCADGui.ActiveDocument.ActiveView\n        self.callback = self.view.addEventCallbackPivy(SoMouseButtonEvent.getClassTypeId(),self.getpoint)  \n    def getpoint(self,event_cb):\n        event = event_cb.getEvent()\n        if event.getButton() == 1:\n            pos = event.getPosition().getValue()\n            obInfo = self.view.getObjectInfo((int(pos[0]),int(pos[1])))\n            if obInfo != None:\n                obj = App.ActiveDocument.getObject(obInfo[\"Object\"])\n                obname = obj.Label\n                if obname[:5] == \"arrow\":\n                    if event.getState() == 1:\n                        wh = obname[5:7]\n                        i = int(obname[7:])\n                        if wh == \"mX\":\n                            mrotmX(i,i+1)\n                        elif wh == \"pX\":\n                            mrotpX(i,i+1)\n                        elif wh == \"mY\":\n                            mrotmY(i,i+1)\n                        elif wh == \"pY\":\n                            mrotpY(i,i+1)\n                        elif wh == \"mZ\":\n                            mrotmZ(i,i+1)\n                        elif wh == \"pZ\":\n                            mrotpZ(i,i+1)\n                    event_cb.setHandled()\n                elif obname[:5] == \"label\":\n                    if event.getState() == 1:\n                        wh = obname[5:7]\n                        n = Dictionary[str(App.ActiveDocument.Name)+\"Size\"]\n                        if wh == \"mX\":\n                            mrotmX(0,n)\n                        elif wh == \"pX\":\n                            mrotpX(0,n)\n                        elif wh == \"mY\":\n                            mrotmY(0,n)\n                        elif wh == \"pY\":\n                            mrotpY(0,n)\n                        elif wh == \"mZ\":\n                            mrotmZ(0,n)\n                        elif wh == \"pZ\":\n                            mrotpZ(0,n)\n                    event_cb.setHandled()\n\n# Create a ViewObserver and save it in the dictionary so that it does not get\n# garbage-collected\nDictionary[str(App.ActiveDocument.Name)+\"ViewObserver\"] = ViewObserver()\n\n# This bit of code creates the basic cube model\n# It is composed of faces rather than cubes because I haven't found a way of\n# making a cube with different coloured faces\n# Each face has a name and a label\n# The name is persistent regardless of how the face moves about the cube\n# The label changes and tells where the face is now: this is needed for\n# fix_reload()\n# I don't make the interior cubies because you can never see them\nfcd = App.ActiveDocument\nn = Dictionary[str(App.ActiveDocument.Name)+\"Size\"]\n# Make array of 6 faces for each of n x n x n cubies\nfc = [[[[None for j in range(6)] for ix in range(n)]\n        for iy in range(n)] for ix in range(n)]\nDictionary[str(App.ActiveDocument.Name)+\"cubies\"] = fc\noriented = Dictionary[str(App.ActiveDocument.Name)+\"Oriented\"]\nfor ix in range(n):\n    fx = ix - (n - 1) / 2.0\n    for iy in range(n):\n        fy = iy - (n - 1) / 2.0\n        for iz in range(n):\n            if ix != 0 and ix != n-1 and (\n              iy != 0 and iy != n-1 and\n              iz != 0 and iz != n-1):\n                continue\n            fz = iz - (n - 1) / 2.0\n            fs = str(ix)+\"q\"+str(iy)+\"q\"+str(iz)\n            x0y0z0 = Base.Vector(fx-0.5,fy-0.5,fz-0.5)\n            x0y0z1 = Base.Vector(fx-0.5,fy-0.5,fz+0.5)\n            x0y1z0 = Base.Vector(fx-0.5,fy+0.5,fz-0.5)\n            x0y1z1 = Base.Vector(fx-0.5,fy+0.5,fz+0.5)\n            x1y0z0 = Base.Vector(fx+0.5,fy-0.5,fz-0.5)\n            x1y0z1 = Base.Vector(fx+0.5,fy-0.5,fz+0.5)\n            x1y1z0 = Base.Vector(fx+0.5,fy+0.5,fz-0.5)\n            x1y1z1 = Base.Vector(fx+0.5,fy+0.5,fz+0.5)\n            if oriented != QtCore.Qt.Unchecked and (\n              ix == 0 and iy != 0 and iy != n-1 and iz != 0 and iz != n-1):\n                x0y2z1 = Base.Vector(fx-0.5,fy,fz)\n                face = Part.Face(Part.makePolygon(\n                    [x0y0z0,x0y0z1,x0y2z1,x0y1z1,x0y1z0,x0y0z0]))\n            else:\n                face = Part.Face(Part.makePolygon(\n                    [x0y0z0,x0y0z1,x0y1z1,x0y1z0,x0y0z0]))\n            f1 = fcd.addObject(\"Part::Feature\", \"ff\"+fs+\"x0\")\n            f1.Shape = face\n            f1.Label = \"fs\"+fs+\"x0\"\n            if ix == 0:\n                f1.ViewObject.DiffuseColor=[(1.0,1.0,1.0)]\n            else:\n                f1.ViewObject.DiffuseColor=[(0.0,0.0,0.0)]\n            f1.ViewObject.RootNode.setName(coin.SbName(\"ff\"+fs+\"x0\"))\n            if oriented != QtCore.Qt.Unchecked and (\n              ix == n - 1 and iy != 0 and iy != n-1 and iz != 0 and iz != n-1):\n                x1y2z1 = Base.Vector(fx+0.5,fy,fz)\n                face = Part.Face(Part.makePolygon(\n                    [x1y0z0,x1y0z1,x1y2z1,x1y1z1,x1y1z0,x1y0z0]))\n            else:\n                face = Part.Face(Part.makePolygon(\n                    [x1y0z0,x1y0z1,x1y1z1,x1y1z0,x1y0z0]))\n            f2 = fcd.addObject(\"Part::Feature\", \"ff\"+fs+\"x1\")\n            f2.Shape = face\n            f2.Label = \"fs\"+fs+\"x1\"\n            if ix == n - 1:\n                f2.ViewObject.DiffuseColor=[(1.0,0.0,0.0)]\n            else:\n                f2.ViewObject.DiffuseColor=[(0.0,0.0,0.0)]\n            f2.ViewObject.RootNode.setName(coin.SbName(\"ff\"+fs+\"x1\"))\n            if oriented != QtCore.Qt.Unchecked and (\n              ix != 0 and ix != n-1 and iy == 0 and iz != 0 and iz != n-1):\n                x1y0z2 = Base.Vector(fx,fy-0.5,fz)\n                face = Part.Face(Part.makePolygon(\n                    [x0y0z0,x0y0z1,x1y0z1,x1y0z2,x1y0z0,x0y0z0]))\n            else:\n                face = Part.Face(Part.makePolygon(\n                    [x0y0z0,x0y0z1,x1y0z1,x1y0z0,x0y0z0]))\n            f3 = fcd.addObject(\"Part::Feature\", \"ff\"+fs+\"y0\")\n            f3.Shape = face\n            f3.Label = \"fs\"+fs+\"y0\"\n            if iy == 0:\n                f3.ViewObject.DiffuseColor=[(0.0,1.0,0.0)]\n            else:\n                f3.ViewObject.DiffuseColor=[(0.0,0.0,0.0)]\n            f3.ViewObject.RootNode.setName(coin.SbName(\"ff\"+fs+\"y0\"))\n            if oriented != QtCore.Qt.Unchecked and (\n              ix != 0 and ix != n-1 and iy == n - 1 and iz != 0 and iz != n-1):\n                x1y1z2 = Base.Vector(fx,fy+0.5,fz)\n                face = Part.Face(Part.makePolygon(\n                    [x0y1z0,x0y1z1,x1y1z1,x1y1z2,x1y1z0,x0y1z0]))\n            else:\n                face = Part.Face(Part.makePolygon(\n                    [x0y1z0,x0y1z1,x1y1z1,x1y1z0,x0y1z0]))\n            f4 = fcd.addObject(\"Part::Feature\", \"ff\"+fs+\"y1\")\n            f4.Shape = face\n            f4.Label = \"fs\"+fs+\"y1\"\n            if iy == n - 1:\n                f4.ViewObject.DiffuseColor=[(1.0,0.0,1.0)]\n            else:\n                f4.ViewObject.DiffuseColor=[(0.0,0.0,0.0)]\n            f4.ViewObject.RootNode.setName(coin.SbName(\"ff\"+fs+\"y1\"))\n            if oriented != QtCore.Qt.Unchecked and (\n              ix != 0 and ix != n-1 and iy != 0 and iy != n-1 and iz == 0):\n                x2y0z0 = Base.Vector(fx,fy,fz-0.5)\n                face = Part.Face(Part.makePolygon(\n                    [x0y0z0,x0y1z0,x1y1z0,x1y0z0,x2y0z0,x0y0z0]))\n            else:\n                face = Part.Face(Part.makePolygon(\n                    [x0y0z0,x0y1z0,x1y1z0,x1y0z0,x0y0z0]))\n            f5 = fcd.addObject(\"Part::Feature\", \"ff\"+fs+\"z0\")\n            f5.Shape = face\n            f5.Label = \"fs\"+fs+\"z0\"\n            if iz == 0:\n                f5.ViewObject.DiffuseColor=[(1.0,1.0,0.0)]\n            else:\n                f5.ViewObject.DiffuseColor=[(0.0,0.0,0.0)]\n            f5.ViewObject.RootNode.setName(coin.SbName(\"ff\"+fs+\"z0\"))\n            if oriented != QtCore.Qt.Unchecked and (\n              ix != 0 and ix != n-1 and iy != 0 and iy != n-1 and iz == n - 1):\n                x2y0z1 = Base.Vector(fx,fy,fz+0.5)\n                face = Part.Face(Part.makePolygon(\n                    [x0y0z1,x0y1z1,x1y1z1,x1y0z1,x2y0z1,x0y0z1]))\n            else:\n                face = Part.Face(Part.makePolygon(\n                    [x0y0z1,x0y1z1,x1y1z1,x1y0z1,x0y0z1]))\n            f6 = fcd.addObject(\"Part::Feature\", \"ff\"+fs+\"z1\")\n            f6.Shape = face\n            f6.Label = \"fs\"+fs+\"z1\"\n            if iz == n - 1:\n                f6.ViewObject.DiffuseColor=[(0.0,0.0,1.0)]\n            else:\n                f6.ViewObject.DiffuseColor=[(0.0,0.0,0.0)]\n            f6.ViewObject.RootNode.setName(coin.SbName(\"ff\"+fs+\"z1\"))\n            fc[ix][iy][iz]=[f1,f2,f3,f4,f5,f6]\n\n# This bit of code creates the clickable arrows\n# Note we make them not selectable because mouse clicking on them\n# does a slice rotation instead of selecting the arrow.\nfor i in range(n):\n    fx = i - (n - 1) / 2.0\n    fy = -(n / 2.0)\n    fz = -(0.2 + n / 2.0)\n    fs = \"arrowpX\"+str(i)\n    v0 = Base.Vector(fx-0.1,fy,fz)\n    v1 = Base.Vector(fx-0.1,fy,fz-0.5)\n    v2 = Base.Vector(fx-0.2,fy,fz-0.5)\n    v3 = Base.Vector(fx,fy,fz-0.7)\n    v4 = Base.Vector(fx+0.2,fy,fz-0.5)\n    v5 = Base.Vector(fx+0.1,fy,fz-0.5)\n    v6 = Base.Vector(fx+0.1,fy,fz)\n    arrow = fcd.addObject(\"Part::Feature\", fs)\n    arrow.Shape = Part.Face(Part.makePolygon([v0,v1,v2,v3,v4,v5,v6,v0]))\n    arrow.ViewObject.DiffuseColor = [(0.0,0.0,0.0)]\n    arrow.ViewObject.RootNode.setName(coin.SbName(fs))\n    arrow.ViewObject.Selectable = False\n    fy = 0.2 + n / 2.0\n    fz = n / 2.0\n    fs = \"arrowmX\"+str(i)\n    v0 = Base.Vector(fx-0.1,fy,fz)\n    v1 = Base.Vector(fx-0.1,fy+0.5,fz)\n    v2 = Base.Vector(fx-0.2,fy+0.5,fz)\n    v3 = Base.Vector(fx,fy+0.7,fz)\n    v4 = Base.Vector(fx+0.2,fy+0.5,fz)\n    v5 = Base.Vector(fx+0.1,fy+0.5,fz)\n    v6 = Base.Vector(fx+0.1,fy,fz)\n    arrow = fcd.addObject(\"Part::Feature\", fs)\n    arrow.Shape = Part.Face(Part.makePolygon([v0,v1,v2,v3,v4,v5,v6,v0]))\n    arrow.ViewObject.DiffuseColor = [(0.0,0.0,0.0)]\n    arrow.ViewObject.RootNode.setName(coin.SbName(fs))\n    arrow.ViewObject.Selectable = False\n    fx = n / 2.0\n    fy = i - (n - 1) / 2.0\n    fz = -(0.2 + n / 2.0)\n    fs = \"arrowpY\"+str(i)\n    v0 = Base.Vector(fx,fy-0.1,fz)\n    v1 = Base.Vector(fx,fy-0.1,fz-0.5)\n    v2 = Base.Vector(fx,fy-0.2,fz-0.5)\n    v3 = Base.Vector(fx,fy,fz-0.7)\n    v4 = Base.Vector(fx,fy+0.2,fz-0.5)\n    v5 = Base.Vector(fx,fy+0.1,fz-0.5)\n    v6 = Base.Vector(fx,fy+0.1,fz)\n    arrow = fcd.addObject(\"Part::Feature\", fs)\n    arrow.Shape = Part.Face(Part.makePolygon([v0,v1,v2,v3,v4,v5,v6,v0]))\n    arrow.ViewObject.DiffuseColor = [(0.0,0.0,0.0)]\n    arrow.ViewObject.RootNode.setName(coin.SbName(fs))\n    arrow.ViewObject.Selectable = False\n    fx = -(0.2 + n / 2.0)\n    fy = i - (n - 1) / 2.0\n    fz = n / 2.0\n    fs = \"arrowmY\"+str(i)\n    v0 = Base.Vector(fx,fy-0.1,fz)\n    v1 = Base.Vector(fx-0.5,fy-0.1,fz)\n    v2 = Base.Vector(fx-0.5,fy-0.2,fz)\n    v3 = Base.Vector(fx-0.7,fy,fz)\n    v4 = Base.Vector(fx-0.5,fy+0.2,fz)\n    v5 = Base.Vector(fx-0.5,fy+0.1,fz)\n    v6 = Base.Vector(fx,fy+0.1,fz)\n    arrow = fcd.addObject(\"Part::Feature\", fs)\n    arrow.Shape = Part.Face(Part.makePolygon([v0,v1,v2,v3,v4,v5,v6,v0]))\n    arrow.ViewObject.DiffuseColor = [(0.0,0.0,0.0)]\n    arrow.ViewObject.RootNode.setName(coin.SbName(fs))\n    arrow.ViewObject.Selectable = False\n    fx = n / 2.0\n    fy = 0.2 + n / 2.0\n    fz = i - (n - 1) / 2.0\n    fs = \"arrowpZ\"+str(i)\n    v0 = Base.Vector(fx,fy,fz-0.1)\n    v1 = Base.Vector(fx,fy+0.5,fz-0.1)\n    v2 = Base.Vector(fx,fy+0.5,fz-0.2)\n    v3 = Base.Vector(fx,fy+0.7,fz)\n    v4 = Base.Vector(fx,fy+0.5,fz+0.2)\n    v5 = Base.Vector(fx,fy+0.5,fz+0.1)\n    v6 = Base.Vector(fx,fy,fz+0.1)\n    arrow = fcd.addObject(\"Part::Feature\", fs)\n    arrow.Shape = Part.Face(Part.makePolygon([v0,v1,v2,v3,v4,v5,v6,v0]))\n    arrow.ViewObject.DiffuseColor = [(0.0,0.0,0.0)]\n    arrow.ViewObject.RootNode.setName(coin.SbName(fs))\n    arrow.ViewObject.Selectable = False\n    fx = -(0.2 + n / 2.0)\n    fy = -(n / 2.0)\n    fz = i - (n - 1) / 2.0\n    fs = \"arrowmZ\"+str(i)\n    v0 = Base.Vector(fx,fy,fz-0.1)\n    v1 = Base.Vector(fx-0.5,fy,fz-0.1)\n    v2 = Base.Vector(fx-0.5,fy,fz-0.2)\n    v3 = Base.Vector(fx-0.7,fy,fz)\n    v4 = Base.Vector(fx-0.5,fy,fz+0.2)\n    v5 = Base.Vector(fx-0.5,fy,fz+0.1)\n    v6 = Base.Vector(fx,fy,fz+0.1)\n    arrow = fcd.addObject(\"Part::Feature\", fs)\n    arrow.Shape = Part.Face(Part.makePolygon([v0,v1,v2,v3,v4,v5,v6,v0]))\n    arrow.ViewObject.DiffuseColor = [(0.0,0.0,0.0)]\n    arrow.ViewObject.RootNode.setName(coin.SbName(fs))\n    arrow.ViewObject.Selectable = False\n\n# Utility routine for doLabels() to make a single label\ndef makeLabel(text, mat):\n    n = Dictionary[str(App.ActiveDocument.Name)+\"Size\"]\n    tx = Draft.makeText(text)\n    tx.Label = \"label\"+text\n    tx.ViewObject.TextColor = (0.0,0.0,0.0)\n    tx.ViewObject.FontSize = 0.2 * n\n    tx.ViewObject.Justification = 'Center'\n    node = tx.ViewObject.RootNode\n    node.setName(coin.SbName(\"label\"+text))\n    if node.getNumChildren() > 0:\n        child = node.getChild(0)\n        if child.getTypeId().getName().__str__() == \"Transform\":\n            child.setMatrix(mat)\n\n# This bit of code creates some labels for the arrows\n# Clicking on one rotates the whole cube\ndef doLabels():\n    n = Dictionary[str(App.ActiveDocument.Name)+\"Size\"]\n    m = coin.SbMatrix()\n    m.makeIdentity()\n    m.setTransform(\n        coin.SbVec3f(0.0, - n / 2.0, -(1.0 + n * 0.7)),\n        coin.SbRotation(coin.SbVec3f(1.0, 0.0, 0.0), 3.14159 / 2.0),\n        coin.SbVec3f(1.0, 1.0, 1.0))\n    makeLabel(\"pX\", m)\n    m = coin.SbMatrix()\n    m.makeIdentity()\n    m.setTransform(\n        coin.SbVec3f(0.0, 1.1 + n / 2.0, n / 2.0),\n        coin.SbRotation(coin.SbVec3f(0.0, 1.0, 0.0), 0.0),\n        coin.SbVec3f(1.0, 1.0, 1.0))\n    makeLabel(\"mX\", m)\n    m = coin.SbMatrix()\n    m.makeIdentity()\n    m.setTransform(\n        coin.SbVec3f(n / 2.0, 0.0, -(1.0 + n * 0.7)),\n        coin.SbRotation(coin.SbVec3f(0.0, 0.0, 1.0), 3.14159 / 2.0),\n        coin.SbVec3f(1.0, 1.0, 1.0))\n    m1 = coin.SbMatrix()\n    m1.makeIdentity()\n    m1.setTransform(\n        coin.SbVec3f(0.0, 0.0, 0.0),\n        coin.SbRotation(coin.SbVec3f(1.0, 0.0, 0.0), 3.14159 / 2.0),\n        coin.SbVec3f(1.0, 1.0, 1.0))\n    m1.multRight(m)\n    makeLabel(\"pY\", m1)\n    m = coin.SbMatrix()\n    m.makeIdentity()\n    m.setTransform(\n        coin.SbVec3f(-1.1 - n / 2.0, 0.0, n / 2.0),\n        coin.SbRotation(coin.SbVec3f(0.0, 0.0, 1.0), 3.14159 / 2.0),\n        coin.SbVec3f(1.0, 1.0, 1.0))\n    makeLabel(\"mY\", m)\n    m = coin.SbMatrix()\n    m.makeIdentity()\n    m.setTransform(\n        coin.SbVec3f(n / 2.0, 0.7 + n * 0.6, 0.0),\n        coin.SbRotation(coin.SbVec3f(0.0, 1.0, 0.0), 3.14159 / 2.0),\n        coin.SbVec3f(1.0, 1.0, 1.0))\n    makeLabel(\"pZ\", m)\n    m = coin.SbMatrix()\n    m.makeIdentity()\n    m.setTransform(\n        coin.SbVec3f(-1.1 - n / 2.0, - n / 2.0, 0.0),\n        coin.SbRotation(coin.SbVec3f(1.0, 0.0, 0.0), 3.14159 / 2.0),\n        coin.SbVec3f(1.0, 1.0, 1.0))\n    m1 = coin.SbMatrix()\n    m1.makeIdentity()\n    m1.setTransform(\n        coin.SbVec3f(0.0, 0.0, 0.0),\n        coin.SbRotation(coin.SbVec3f(0.0, 0.0, 1.0), 3.14159 / 2.0),\n        coin.SbVec3f(1.0, 1.0, 1.0))\n    m1.multRight(m)\n    makeLabel(\"mZ\", m1)\n\n# now call it to make them\ndoLabels()\n\nGui.ActiveDocument.ActiveView.viewAxonometric()\nGui.SendMsgToActiveView(\"ViewFit\")\n\n# Viewfit doesn't seem to do the right thing with MultiViews\n# so we adjust the camera height manually before creating them\ndef fixCamera(lift):\n    # This gets FreeCAD's top level SceneGraph (including camera node),\n    # not the document's SceneGraph which hangs off of it\n    v = Gui.ActiveDocument.ActiveView.getViewer()\n    sceneGraph = v.getSoEventManager().getSceneGraph()\n    camera = sceneGraph.getChild(2)\n    if camera.getTypeId().getName().__str__() == \"OrthographicCamera\":\n        if lift:\n            camera.height.setValue((2.0 + n / 20.0) * camera.height.getValue())\n        return camera.orientation.getValue()\nrotation = fixCamera(True)\n\n# This bit of code finds the widget corresponding to the View3DInventor\ndef findView(widget):\n    if widget.metaObject().className().__str__() == \"Gui::View3DInventor\":\n        return widget\n    else:\n        result = None\n        for child in widget.children():\n            v = findView(child)\n            if v != None:\n                result = v\n        return result\n\n# This bit of code disables the default Phong shading\n# and avoids the face colours appearing to change during rotation\ndef fixLightModel():\n    v = Gui.ActiveDocument.ActiveView.getViewer()\n    sceneGraph = v.getSoEventManager().getSceneGraph()\n    if str(sceneGraph.getChild(0).getName()) <> \"LightModel\":\n        lm=coin.SoLightModel()\n        lm.model.setValue(0)\n        lm.setName(\"LightModel\")\n        sceneGraph.insertChild(lm,0)\nfixLightModel()\n\n# This bit of code persuades FreeCAD'a renderer to put\n# several views of the cube into the same window\ndef MultiViews(parent, child, i, rotation):\n    n = Dictionary[str(App.ActiveDocument.Name)+\"Size\"]\n    newchild=coin.SoMultipleCopy()\n    newchild.addChild(child)\n    views=coin.SoMFMatrix()\n    views.setNum(8)\n    m1=coin.SbMatrix()\n    m1.makeIdentity()\n    views.set1Value(0,m1)\n    m2=coin.SbMatrix()\n    m2.setTransform(\n        coin.SbVec3f(n * 0.9 + 0.4, n * 0.9 + 0.4, 0.0),\n        coin.SbRotation(coin.SbVec3f(-0.5,0.5,1),3.14159),\n        coin.SbVec3f(0.5,0.5,0.5))\n    views.set1Value(1,m2)\n    m3=coin.SbMatrix()\n    m3.setTransform(\n        coin.SbVec3f(- n * 1.15 - 0.7, - n * 1.15 - 0.7, 0.0),\n        rotation,\n        coin.SbVec3f(0.5,0.5,0.5))\n    views.set1Value(2,m3)\n    m4=coin.SbMatrix()\n    m4.setTransform(\n        coin.SbVec3f(0,n,0),\n        coin.SbRotation(coin.SbVec3f(1,0,0),3.14159*90/180.0),\n        coin.SbVec3f(1,1,1))\n    m4.multRight(m3)\n    views.set1Value(3,m4)\n    m5=coin.SbMatrix()\n    m5.setTransform(\n        coin.SbVec3f(n,0,0),\n        coin.SbRotation(coin.SbVec3f(0,1,0),-3.14159*90/180.0),\n        coin.SbVec3f(1,1,1))\n    m5.multRight(m3)\n    views.set1Value(4,m5)\n    m6=coin.SbMatrix()\n    m6.makeIdentity()\n    m6.setTransform(\n        coin.SbVec3f(-n,0,0),\n        coin.SbRotation(coin.SbVec3f(0,1,0),3.14159*90/180.0),\n        coin.SbVec3f(1,1,1))\n    m6.multRight(m3)\n    views.set1Value(5,m6)\n    m7=coin.SbMatrix()\n    m7.setTransform(\n        coin.SbVec3f(0,-n,0),\n        coin.SbRotation(coin.SbVec3f(-1,0,0),3.14159*90/180.0),\n        coin.SbVec3f(1,1,1))\n    m7.multRight(m3)\n    views.set1Value(6,m7)\n    m8=coin.SbMatrix()\n    m8.setTransform(\n        coin.SbVec3f(0,-n*2,0),\n        coin.SbRotation(coin.SbVec3f(-1,0,0),3.14159),\n        coin.SbVec3f(1,1,1))\n    m8.multRight(m3)\n    views.set1Value(7,m8)\n    newchild.matrix=views\n    parent.replaceChild(i,newchild)\ndef createMultiViews(rotation):\n    sg = FreeCADGui.ActiveDocument.ActiveView.getSceneGraph()\n    if sg.getNumChildren() != 0:\n        for i in range(sg.getNumChildren()):\n            child = sg.getChild(i)\n            type = child.getTypeId().getName().__str__()\n            if child.getTypeId().getName().__str__() == 'Separator':\n                name = child.getName().__str__()[:5]\n                if name != \"arrow\" and name != \"label\":\n                    MultiViews(sg,child,i,rotation)\n            if child.getTypeId().getName().__str__() == 'MultipleCopy':\n                if child.getNumChildren() != 0:\n                    name = child.getChild(0).getName().__str__()\n                    if fcd.getObject(name) == None:\n                        child.removeAllChildren()\ncreateMultiViews(rotation)\n\n# This bit of code animates a slice rotation\ndef rotate(dir, rs, re, steps):\n    n = Dictionary[str(App.ActiveDocument.Name)+\"Size\"]\n    fc = Dictionary[str(App.ActiveDocument.Name)+\"cubies\"]\n    fd = [[[[None for j in range(6)] for ix in range(n)] for iy in range(n)] for ix in range(n)]\n    fp = [[[[Base.Placement() for j in range(6)] for ix in range(n)] for iy in range(n)] for ix in range(n)]\n    xyz = [\"x0\",\"x1\",\"y0\",\"y1\",\"z0\",\"z1\"]\n    if dir.x > 0:\n        # We need an explicit matrix for the final rotation step\n        # to prevent rounding errors accumulating over time\n        ff = Base.Matrix(1,0,0,0,0,0,-1,0,0,1,0,0,0,0,0,1)\n        kk =[0,1,5,4,2,3]\n        for iy in range(n):\n            for iz in range(n):\n                for j in range(rs, re):\n                    if fc[j][iy][iz][0] <> None:\n                        for k in range(6):\n                            c = fc[j][iy][iz][k]\n                            c.Label = c.Name\n                            fd[j][iy][iz][k] = c\n                            fp[j][iy][iz][k] = c.Placement\n        if steps > 0:\n            fm = Base.Matrix()\n            fm.rotateX(1.570795 / steps)\n            for i in range(steps):\n                for iy in range(n):\n                    for iz in range(n):\n                        for j in range(rs, re):\n                            if fc[j][iy][iz][0] <> None:\n                                for k in range(6):\n                                    c = fc[j][iy][iz][k]\n                                    p = c.Placement\n                                    c.Placement = Base.Placement(fm).multiply(p)\n                Gui.updateGui()\n        for iy in range(n):\n            for iz in range(n):\n                for j in range(rs, re):\n                    if fc[j][iy][iz][0] <> None:\n                        for k in range(6):\n                            c = fd[j][iz][n-1-iy][kk[k]]\n                            p = fp[j][iz][n-1-iy][kk[k]]\n                            c.Label = \"fs\"+str(j)+\"q\"+str(iy)+\"q\"+str(iz)+xyz[k]\n                            c.Placement = Base.Placement(ff).multiply(p)\n                            fc[j][iy][iz][k] = c\n    elif dir.x < 0:\n        ff = Base.Matrix(1,0,0,0,0,0,1,0,0,-1,0,0,0,0,0,1)\n        kk =[0,1,4,5,3,2]\n        for iy in range(n):\n            for iz in range(n):\n                for j in range(rs, re):\n                    if fc[j][iy][iz][0] <> None:\n                        for k in range(6):\n                            c = fc[j][iy][iz][k]\n                            c.Label = c.Name\n                            fd[j][iy][iz][k] = c\n                            fp[j][iy][iz][k] = c.Placement\n        if steps > 0:\n            fm = Base.Matrix()\n            fm.rotateX(-1.570795 / steps)\n            for i in range(steps):\n                for iy in range(n):\n                    for iz in range(n):\n                        for j in range(rs, re):\n                            if fc[j][iy][iz][0] <> None:\n                                for k in range(6):\n                                    c = fc[j][iy][iz][k]\n                                    p = c.Placement\n                                    c.Placement = Base.Placement(fm).multiply(p)\n                Gui.updateGui()\n        for iy in range(n):\n            for iz in range(n):\n                for j in range(rs, re):\n                    if fc[j][iy][iz][0] <> None:\n                        for k in range(6):\n                            c = fd[j][n-1-iz][iy][kk[k]]\n                            p = fp[j][n-1-iz][iy][kk[k]]\n                            c.Label = \"fs\"+str(j)+\"q\"+str(iy)+\"q\"+str(iz)+xyz[k]\n                            c.Placement = Base.Placement(ff).multiply(p)\n                            fc[j][iy][iz][k] = c\n    elif dir.y > 0:\n        ff = Base.Matrix(0,0,1,0,0,1,0,0,-1,0,0,0,0,0,0,1)\n        kk =[4,5,2,3,1,0]\n        for ix in range(n):\n            for iz in range(n):\n                for j in range(rs, re):\n                    if fc[ix][j][iz][0] <> None:\n                        for k in range(6):\n                            c = fc[ix][j][iz][k]\n                            c.Label = c.Name\n                            fd[ix][j][iz][k] = c\n                            fp[ix][j][iz][k] = c.Placement\n        if steps > 0:\n            fm = Base.Matrix()\n            fm.rotateY(1.570795 / steps)\n            for i in range(steps):\n                for ix in range(n):\n                    for iz in range(n):\n                        for j in range(rs, re):\n                            if fc[ix][j][iz][0] <> None:\n                                for k in range(6):\n                                    c = fc[ix][j][iz][k]\n                                    p = c.Placement\n                                    c.Placement = Base.Placement(fm).multiply(p)\n                Gui.updateGui()\n        for ix in range(n):\n            for iz in range(n):\n                for j in range(rs, re):\n                    if fc[ix][j][iz][0] <> None:\n                        for k in range(6):\n                            c = fd[n-1-iz][j][ix][kk[k]]\n                            p = fp[n-1-iz][j][ix][kk[k]]\n                            c.Label = \"fs\"+str(ix)+\"q\"+str(j)+\"q\"+str(iz)+xyz[k]\n                            c.Placement = Base.Placement(ff).multiply(p)\n                            fc[ix][j][iz][k] = c\n    elif dir.y < 0:\n        ff = Base.Matrix(0,0,-1,0,0,1,0,0,1,0,0,0,0,0,0,1)\n        kk =[5,4,2,3,0,1]\n        for ix in range(n):\n            for iz in range(n):\n                for j in range(rs, re):\n                    if fc[ix][j][iz][0] <> None:\n                        for k in range(6):\n                            c = fc[ix][j][iz][k]\n                            c.Label = c.Name\n                            fd[ix][j][iz][k] = c\n                            fp[ix][j][iz][k] = c.Placement\n        if steps > 0:\n            fm = Base.Matrix()\n            fm.rotateY(-1.570795 / steps)\n            for i in range(steps):\n                for ix in range(n):\n                    for iz in range(n):\n                        for j in range(rs, re):\n                            if fc[ix][j][iz][0] <> None:\n                                for k in range(6):\n                                    c = fc[ix][j][iz][k]\n                                    p = c.Placement\n                                    c.Placement = Base.Placement(fm).multiply(p)\n                Gui.updateGui()\n        for ix in range(n):\n            for iz in range(n):\n                for j in range(rs, re):\n                    if fc[ix][j][iz][0] <> None:\n                        for k in range(6):\n                            c = fd[iz][j][n-1-ix][kk[k]]\n                            p = fp[iz][j][n-1-ix][kk[k]]\n                            c.Label = \"fs\"+str(ix)+\"q\"+str(j)+\"q\"+str(iz)+xyz[k]\n                            c.Placement = Base.Placement(ff).multiply(p)\n                            fc[ix][j][iz][k] = c\n    elif dir.z > 0:\n        ff = Base.Matrix(0,-1,0,0,1,0,0,0,0,0,1,0,0,0,0,1)\n        kk = [3,2,0,1,4,5]\n        for ix in range(n):\n            for iy in range(n):\n                for j in range(rs, re):\n                    if fc[ix][iy][j][0] <> None:\n                        for k in range(6):\n                            c = fc[ix][iy][j][k]\n                            c.Label = c.Name\n                            fd[ix][iy][j][k] = c\n                            fp[ix][iy][j][k] = c.Placement\n        if steps > 0:\n            fm = Base.Matrix()\n            fm.rotateZ(1.570795 / steps)\n            for i in range(steps):\n                for ix in range(n):\n                    for iy in range(n):\n                        for j in range(rs, re):\n                            if fc[ix][iy][j][0] <> None:\n                                for k in range(6):\n                                    c = fc[ix][iy][j][k]\n                                    p = c.Placement\n                                    c.Placement = Base.Placement(fm).multiply(p)\n                Gui.updateGui()\n        for ix in range(n):\n            for iy in range(n):\n                for j in range(rs, re):\n                    if fc[ix][iy][j][0] <> None:\n                        for k in range(6):\n                            c = fd[iy][n-1-ix][j][kk[k]]\n                            p = fp[iy][n-1-ix][j][kk[k]]\n                            c.Label = \"fs\"+str(ix)+\"q\"+str(iy)+\"q\"+str(j)+xyz[k]\n                            c.Placement = Base.Placement(ff).multiply(p)\n                            fc[ix][iy][j][k] = c\n    elif dir.z < 0:\n        ff = Base.Matrix(0,1,0,0,-1,0,0,0,0,0,1,0,0,0,0,1)\n        kk = [2,3,1,0,5,4]\n        for ix in range(n):\n            for iy in range(n):\n                for j in range(rs, re):\n                    if fc[ix][iy][j][0] <> None:\n                        for k in range(6):\n                            c = fc[ix][iy][j][k]\n                            c.Label = c.Name\n                            fd[ix][iy][j][k] = c\n                            fp[ix][iy][j][k] = c.Placement\n        if steps > 0:\n            fm = Base.Matrix()\n            fm.rotateZ(-1.570795 / steps)\n            for i in range(steps):\n                for ix in range(n):\n                    for iy in range(n):\n                        for j in range(rs, re):\n                          if fc[ix][iy][j][0] <> None:\n                            for k in range(6):\n                                c = fc[ix][iy][j][k]\n                                p = c.Placement\n                                c.Placement = Base.Placement(fm).multiply(p)\n                Gui.updateGui()\n        for ix in range(n):\n            for iy in range(n):\n                for j in range(rs, re):\n                    if fc[ix][iy][j][0] <> None:\n                        for k in range(6):\n                            c = fd[n-1-iy][ix][j][kk[k]]\n                            p = fp[n-1-iy][ix][j][kk[k]]\n                            c.Label = \"fs\"+str(ix)+\"q\"+str(iy)+\"q\"+str(j)+xyz[k]\n                            c.Placement = Base.Placement(ff).multiply(p)\n                            fc[ix][iy][j][k] = c\n\ndef slowrotate(dir, rs, re):\n    n = Dictionary[str(App.ActiveDocument.Name)+\"Size\"]\n    steps = slowness / (n * n)\n    if re > rs:\n        rotate(dir, rs, re, steps / (re - rs))\n        Gui.updateGui()\n\n# Quick rotation for use when randomising or modifying history\ndef fastrotate(dir, rs, re):\n    rotate(dir, rs, re, 0)\n\n# These functions manage the history\n# Once you have created a cube, these functions will be defined and in scope\n# and you can call them from another macro created by saving history\n# or by hand from the python console window\nhistory = []\nDictionary[str(App.ActiveDocument.Name)+\"history\"] = history\ndef mrotpX(i,j):\n    slowrotate(Base.Vector(1,0,0),i,j)\n    Dictionary[str(App.ActiveDocument.Name)+\"history\"].append(\"mrotpX(\"+str(i)+\",\"+str(j)+\")\")\ndef mrotpY(i,j):\n    slowrotate(Base.Vector(0,1,0),i,j)\n    Dictionary[str(App.ActiveDocument.Name)+\"history\"].append(\"mrotpY(\"+str(i)+\",\"+str(j)+\")\")\ndef mrotpZ(i,j):\n    slowrotate(Base.Vector(0,0,1),i,j)\n    Dictionary[str(App.ActiveDocument.Name)+\"history\"].append(\"mrotpZ(\"+str(i)+\",\"+str(j)+\")\")\ndef mrotmX(i,j):\n    slowrotate(Base.Vector(-1,0,0),i,j)\n    Dictionary[str(App.ActiveDocument.Name)+\"history\"].append(\"mrotmX(\"+str(i)+\",\"+str(j)+\")\")\ndef mrotmY(i,j):\n    slowrotate(Base.Vector(0,-1,0),i,j)\n    Dictionary[str(App.ActiveDocument.Name)+\"history\"].append(\"mrotmY(\"+str(i)+\",\"+str(j)+\")\")\ndef mrotmZ(i,j):\n    slowrotate(Base.Vector(0,0,-1),i,j)\n    Dictionary[str(App.ActiveDocument.Name)+\"history\"].append(\"mrotmZ(\"+str(i)+\",\"+str(j)+\")\")\ndef undo():\n    history = Dictionary[str(App.ActiveDocument.Name)+\"history\"]\n    if len(history) > 0:\n        fs = history.pop()\n        wh = fs[:6]\n        p = fs.index(\",\")\n        i = int(fs[7:p])\n        j = int(fs[(p+1):(len(fs)-1)])\n        if wh == \"mrotmX\":\n            slowrotate(Base.Vector(1,0,0),i,j)\n        elif wh == \"mrotpX\":\n            slowrotate(Base.Vector(-1,0,0),i,j)\n        elif wh == \"mrotmY\":\n            slowrotate(Base.Vector(0,1,0),i,j)\n        elif wh == \"mrotpY\":\n            slowrotate(Base.Vector(0,-1,0),i,j)\n        elif wh == \"mrotmZ\":\n            slowrotate(Base.Vector(0,0,1),i,j)\n        elif wh == \"mrotpZ\":\n            slowrotate(Base.Vector(0,0,-1),i,j)\ndef itostring(i, n):\n    if 2 * i == n - 1:\n    \treturn \"n/2\"\n    elif i <= n / 2:\n        return str(i)\n    elif i == n - 1:\n        return \"n-1\"\n    else:\n        return \"n-\" + str(n-i) \ndef jtostring(j, n):\n    if j <= n / 2:\n       return str(j)\n    elif 2 * j == n + 1:\n    \treturn \"n/2+1\"\n    elif j == n:\n        return \"n\"\n    elif j == n - 1:\n        return \"n-1\"\n    else:\n        return \"n-\" + str(n-j) \ndef saveHistory():\n    fcd = App.ActiveDocument\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    if len(history) > 0:\n        # This statement will be needed at the start of any macro\n        # to get the size of the cube in the currently active document\n        # in case we have several documents open at once\n        fs = \"n = Dictionary[str(App.ActiveDocument.Name)+'Size']\\n\"\n        for s in history:\n            p = s.index(\",\")\n            i = int(s[7:p])\n            j = int(s[(p+1):(len(s)-1)])\n            fs = fs + s[:7] + itostring(i, n) + \",\"\n            fs = fs + jtostring(j, n) + \")\\n\"\n        clip = QtCore.QCoreApplication.instance().clipboard()\n        clip.setText(fs)\ndef reset():\n    busyCursor()\n    fcd = App.ActiveDocument\n    Dictionary[str(fcd.Name)+\"history\"] = []\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    fc = Dictionary[str(fcd.Name)+\"cubies\"]\n    for obj in fcd.Objects:\n        fs = obj.Name\n        if fs[0:2] == \"ff\":\n            obj.Label = fs\n    for obj in fcd.Objects:\n        fs = obj.Name\n        if fs[0:2] == \"ff\":\n            obj.Label = \"fs\"+fs[2:]\n            obj.Placement = Base.Placement()\n            l = len(fs)\n            q1 = fs.find(\"q\")\n            q2 = fs.find(\"q\",q1+1)\n            ix = int(fs[2:q1])\n            iy = int(fs[q1+1:q2])\n            iz = int(fs[q2+1:l-2])\n            k = \"x0x1y0y1z0z1\".find(fs[l-2:])/2\n            fc[ix][iy][iz][k] = obj\n    restoreCursor()\n\n# Randomise the cube\ndef randomise():\n    busyCursor()\n    fcd = App.ActiveDocument\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    random.seed()\n    i = random.randrange(0,6)\n    for x in range(n*24):\n        i = (i + 2 - i % 2 + random.randrange(0,4)) % 6\n        j = random.randrange(0,n)\n        if i == 0:\n            fastrotate(Base.Vector(1,0,0),j,j+1)\n            history.append(\"mrotpX(\"+str(j)+\",\"+str(j+1)+\")\")\n        elif i == 1:\n            fastrotate(Base.Vector(-1,0,0),j,j+1)\n            history.append(\"mrotmX(\"+str(j)+\",\"+str(j+1)+\")\")\n        elif i == 2:\n            fastrotate(Base.Vector(0,1,0),j,j+1)\n            history.append(\"mrotpY(\"+str(j)+\",\"+str(j+1)+\")\")\n        elif i == 3:\n            fastrotate(Base.Vector(0,-1,0),j,j+1)\n            history.append(\"mrotmY(\"+str(j)+\",\"+str(j+1)+\")\")\n        elif i == 4:\n            fastrotate(Base.Vector(0,0,1),j,j+1)\n            history.append(\"mrotpZ(\"+str(j)+\",\"+str(j+1)+\")\")\n        elif i == 5:\n            fastrotate(Base.Vector(0,0,-1),j,j+1)\n            history.append(\"mrotmZ(\"+str(j)+\",\"+str(j+1)+\")\")\n    restoreCursor()\n\n# Various macros to modify the history\n# They all read the history and undo it, and then perform some modified version\n# of the history. The modifications can be time-reversal, reflection along an\n# axis (as if the cube were reflected, the history replayed,\n# and the cube reflected back again), or rotation (as if the cube were rotated,\n# the history replayed, and the cube rotated back again).\ndef slow_history():\n    busyCursor()\n    fcd = App.ActiveDocument\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    nh = []\n    while len(history) > 0:\n        nh.append(history.pop())\n    reset()\n    Gui.updateGui()\n    while len(nh) > 0:\n        fs = nh.pop()\n        wh = fs[:6]\n        p = fs.index(\",\")\n        i = int(fs[7:p])\n        j = int(fs[p+1:len(fs)-1])\n        if wh == \"mrotpX\":\n            mrotpX(i,j)\n        elif wh == \"mrotmX\":\n            mrotmX(i,j)\n        elif wh == \"mrotpY\":\n            mrotpY(i,j)\n        elif wh == \"mrotmY\":\n            mrotmY(i,j)\n        elif wh == \"mrotpZ\":\n            mrotpZ(i,j)\n        elif wh == \"mrotmZ\":\n            mrotmZ(i,j)\n    restoreCursor()\ndef step_history():\n    fcd = App.ActiveDocument\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    nh = []\n    while len(history) > 0:\n        nh.append(history.pop())\n    reset()\n    Gui.updateGui()\n    Dictionary[str(fcd.Name)+\"Stepping\"] = 1\n    while len(nh) > 0:\n        fs = nh.pop()\n        wh = fs[:6]\n        p = fs.index(\",\")\n        i = int(fs[7:p])\n        j = int(fs[p+1:len(fs)-1])\n        w = StepWindow()\n        w.label_1.setText(\"Doing \"+wh+\"(\"+str(i)+\",\"+str(j)+\")\")\n        w.label_1.setAlignment(QtCore.Qt.AlignCenter)\n        w.exec_()\n        if Dictionary[str(fcd.Name)+\"Stepping\"] == 0:\n            break\n        if wh == \"mrotpX\":\n            mrotpX(i,j)\n        elif wh == \"mrotmX\":\n            mrotmX(i,j)\n        elif wh == \"mrotpY\":\n            mrotpY(i,j)\n        elif wh == \"mrotmY\":\n            mrotmY(i,j)\n        elif wh == \"mrotpZ\":\n            mrotpZ(i,j)\n        elif wh == \"mrotmZ\":\n            mrotmZ(i,j)\ndef reverse_history():\n    busyCursor()\n    fcd = App.ActiveDocument\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    nh = []\n    while len(history) > 0:\n        nh.append(history.pop())\n    reset()\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    for fs in nh:\n        wh = fs[:6]\n        p = fs.index(\",\")\n        i = int(fs[7:p])\n        j = int(fs[p+1:len(fs)-1])\n        if wh == \"mrotpX\":\n            fastrotate(Base.Vector(1,0,0),i,j)\n            history.append(\"mrotpX(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmX\":\n            fastrotate(Base.Vector(-1,0,0),i,j)\n            history.append(\"mrotmX(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpY\":\n            fastrotate(Base.Vector(0,1,0),i,j)\n            history.append(\"mrotpY(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmY\":\n            fastrotate(Base.Vector(0,-1,0),i,j)\n            history.append(\"mrotmY(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpZ\":\n            fastrotate(Base.Vector(0,0,1),i,j)\n            history.append(\"mrotpZ(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmZ\":\n            fastrotate(Base.Vector(0,0,-1),i,j)\n            history.append(\"mrotmZ(\"+str(i)+\",\"+str(j)+\")\")\n    restoreCursor()\ndef undo_history():\n    busyCursor()\n    fcd = App.ActiveDocument\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    nh = []\n    while len(history) > 0:\n        nh.append(history.pop())\n    reset()\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    for fs in nh:\n        wh = fs[:6]\n        p = fs.index(\",\")\n        i = int(fs[7:p])\n        j = int(fs[p+1:len(fs)-1])\n        if wh == \"mrotpX\":\n            fastrotate(Base.Vector(-1,0,0),i,j)\n            history.append(\"mrotmX(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmX\":\n            fastrotate(Base.Vector(1,0,0),i,j)\n            history.append(\"mrotpX(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpY\":\n            fastrotate(Base.Vector(0,-1,0),i,j)\n            history.append(\"mrotmY(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmY\":\n            fastrotate(Base.Vector(0,1,0),i,j)\n            history.append(\"mrotpY(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpZ\":\n            fastrotate(Base.Vector(0,0,-1),i,j)\n            history.append(\"mrotmZ(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmZ\":\n            fastrotate(Base.Vector(0,0,1),i,j)\n            history.append(\"mrotpZ(\"+str(i)+\",\"+str(j)+\")\")\n    restoreCursor()\ndef reflectX_history():\n    busyCursor()\n    fcd = App.ActiveDocument\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    nh = []\n    while len(history) > 0:\n        nh.append(history.pop())\n    reset()\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    while len(nh) > 0:\n        fs = nh.pop()\n        wh = fs[:6]\n        p = fs.index(\",\")\n        i = int(fs[7:p])\n        j = int(fs[p+1:len(fs)-1])\n        if wh == \"mrotpX\":\n            fastrotate(Base.Vector(1,0,0),n-j,n-i)\n            history.append(\"mrotpX(\"+str(n-j)+\",\"+str(n-i)+\")\")\n        elif wh == \"mrotmX\":\n            fastrotate(Base.Vector(-1,0,0),n-j,n-i)\n            history.append(\"mrotmX(\"+str(n-j)+\",\"+str(n-i)+\")\")\n        elif wh == \"mrotpY\":\n            fastrotate(Base.Vector(0,-1,0),i,j)\n            history.append(\"mrotmY(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmY\":\n            fastrotate(Base.Vector(0,1,0),i,j)\n            history.append(\"mrotpY(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpZ\":\n            fastrotate(Base.Vector(0,0,-1),i,j)\n            history.append(\"mrotmZ(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmZ\":\n            fastrotate(Base.Vector(0,0,1),i,j)\n            history.append(\"mrotpZ(\"+str(i)+\",\"+str(j)+\")\")\n    restoreCursor()\ndef reflectY_history():\n    busyCursor()\n    fcd = App.ActiveDocument\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    nh = []\n    while len(history) > 0:\n        nh.append(history.pop())\n    reset()\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    while len(nh) > 0:\n        fs = nh.pop()\n        wh = fs[:6]\n        p = fs.index(\",\")\n        i = int(fs[7:p])\n        j = int(fs[p+1:len(fs)-1])\n        if wh == \"mrotpX\":\n            fastrotate(Base.Vector(-1,0,0),i,j)\n            history.append(\"mrotmX(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmX\":\n            fastrotate(Base.Vector(1,0,0),i,j)\n            history.append(\"mrotpX(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpY\":\n            fastrotate(Base.Vector(0,1,0),n-j,n-i)\n            history.append(\"mrotpY(\"+str(n-j)+\",\"+str(n-i)+\")\")\n        elif wh == \"mrotmY\":\n            fastrotate(Base.Vector(0,-1,0),n-j,n-i)\n            history.append(\"mrotmY(\"+str(n-j)+\",\"+str(n-i)+\")\")\n        elif wh == \"mrotpZ\":\n            fastrotate(Base.Vector(0,0,-1),i,j)\n            history.append(\"mrotmZ(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmZ\":\n            fastrotate(Base.Vector(0,0,1),i,j)\n            history.append(\"mrotpZ(\"+str(i)+\",\"+str(j)+\")\")\n    restoreCursor()\ndef reflectZ_history():\n    busyCursor()\n    fcd = App.ActiveDocument\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    nh = []\n    while len(history) > 0:\n        nh.append(history.pop())\n    reset()\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    while len(nh) > 0:\n        fs = nh.pop()\n        wh = fs[:6]\n        p = fs.index(\",\")\n        i = int(fs[7:p])\n        j = int(fs[p+1:len(fs)-1])\n        if wh == \"mrotpX\":\n            fastrotate(Base.Vector(-1,0,0),i,j)\n            history.append(\"mrotmX(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmX\":\n            fastrotate(Base.Vector(1,0,0),i,j)\n            history.append(\"mrotpX(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpY\":\n            fastrotate(Base.Vector(0,-1,0),i,j)\n            history.append(\"mrotmY(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmY\":\n            fastrotate(Base.Vector(0,1,0),i,j)\n            history.append(\"mrotpY(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpZ\":\n            fastrotate(Base.Vector(0,0,1),n-j,n-i)\n            history.append(\"mrotpZ(\"+str(n-j)+\",\"+str(n-i)+\")\")\n        elif wh == \"mrotmZ\":\n            fastrotate(Base.Vector(0,0,-1),n-j,n-i)\n            history.append(\"mrotmZ(\"+str(n-j)+\",\"+str(n-i)+\")\")\n    restoreCursor()\ndef rotpX_history():\n    busyCursor()\n    fcd = App.ActiveDocument\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    nh = []\n    while len(history) > 0:\n        nh.append(history.pop())\n    reset()\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    while len(nh) > 0:\n        fs = nh.pop()\n        wh = fs[:6]\n        p = fs.index(\",\")\n        i = int(fs[7:p])\n        j = int(fs[p+1:len(fs)-1])\n        if wh == \"mrotpX\":\n            fastrotate(Base.Vector(1,0,0),i,j)\n            history.append(\"mrotpX(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmX\":\n            fastrotate(Base.Vector(-1,0,0),i,j)\n            history.append(\"mrotmX(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpY\":\n            fastrotate(Base.Vector(0,0,1),i,j)\n            history.append(\"mrotpZ(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmY\":\n            fastrotate(Base.Vector(0,0,-1),i,j)\n            history.append(\"mrotmZ(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpZ\":\n            fastrotate(Base.Vector(0,-1,0),n-j,n-i)\n            history.append(\"mrotmY(\"+str(n-j)+\",\"+str(n-i)+\")\")\n        elif wh == \"mrotmZ\":\n            fastrotate(Base.Vector(0,1,0),n-j,n-i)\n            history.append(\"mrotpY(\"+str(n-j)+\",\"+str(n-i)+\")\")\n    restoreCursor()\ndef rotmX_history():\n    busyCursor()\n    fcd = App.ActiveDocument\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    nh = []\n    while len(history) > 0:\n        nh.append(history.pop())\n    reset()\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    while len(nh) > 0:\n        fs = nh.pop()\n        wh = fs[:6]\n        p = fs.index(\",\")\n        i = int(fs[7:p])\n        j = int(fs[p+1:len(fs)-1])\n        if wh == \"mrotpX\":\n            fastrotate(Base.Vector(1,0,0),i,j)\n            history.append(\"mrotpX(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmX\":\n            fastrotate(Base.Vector(-1,0,0),i,j)\n            history.append(\"mrotmX(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpY\":\n            fastrotate(Base.Vector(0,0,-1),n-j,n-i)\n            history.append(\"mrotmZ(\"+str(n-j)+\",\"+str(n-i)+\")\")\n        elif wh == \"mrotmY\":\n            fastrotate(Base.Vector(0,0,1),n-j,n-i)\n            history.append(\"mrotpZ(\"+str(n-j)+\",\"+str(n-i)+\")\")\n        elif wh == \"mrotpZ\":\n            fastrotate(Base.Vector(0,1,0),i,j)\n            history.append(\"mrotpY(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmZ\":\n            fastrotate(Base.Vector(0,-1,0),i,j)\n            history.append(\"mrotmY(\"+str(i)+\",\"+str(j)+\")\")\n    restoreCursor()\ndef rotpY_history():\n    busyCursor()\n    fcd = App.ActiveDocument\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    nh = []\n    while len(history) > 0:\n        nh.append(history.pop())\n    reset()\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    while len(nh) > 0:\n        fs = nh.pop()\n        wh = fs[:6]\n        p = fs.index(\",\")\n        i = int(fs[7:p])\n        j = int(fs[p+1:len(fs)-1])\n        if wh == \"mrotpX\":\n            fastrotate(Base.Vector(0,0,-1),n-j,n-i)\n            history.append(\"mrotmZ(\"+str(n-j)+\",\"+str(n-i)+\")\")\n        elif wh == \"mrotmX\":\n            fastrotate(Base.Vector(0,0,1),n-j,n-i)\n            history.append(\"mrotpZ(\"+str(n-j)+\",\"+str(n-i)+\")\")\n        elif wh == \"mrotpY\":\n            fastrotate(Base.Vector(0,1,0),i,j)\n            history.append(\"mrotpY(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmY\":\n            fastrotate(Base.Vector(0,-1,0),i,j)\n            history.append(\"mrotmY(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpZ\":\n            fastrotate(Base.Vector(1,0,0),i,j)\n            history.append(\"mrotpX(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmZ\":\n            fastrotate(Base.Vector(-1,0,0),i,j)\n            history.append(\"mrotmX(\"+str(i)+\",\"+str(j)+\")\")\n    restoreCursor()\ndef rotmY_history():\n    busyCursor()\n    fcd = App.ActiveDocument\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    nh = []\n    while len(history) > 0:\n        nh.append(history.pop())\n    reset()\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    while len(nh) > 0:\n        fs = nh.pop()\n        wh = fs[:6]\n        p = fs.index(\",\")\n        i = int(fs[7:p])\n        j = int(fs[p+1:len(fs)-1])\n        if wh == \"mrotpX\":\n            fastrotate(Base.Vector(0,0,1),i,j)\n            history.append(\"mrotpZ(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmX\":\n            fastrotate(Base.Vector(0,0,-1),i,j)\n            history.append(\"mrotmZ(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpY\":\n            fastrotate(Base.Vector(0,1,0),i,j)\n            history.append(\"mrotpY(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmY\":\n            fastrotate(Base.Vector(0,-1,0),i,j)\n            history.append(\"mrotmY(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpZ\":\n            fastrotate(Base.Vector(-1,0,0),n-j,n-i)\n            history.append(\"mrotmX(\"+str(n-j)+\",\"+str(n-i)+\")\")\n        elif wh == \"mrotmZ\":\n            fastrotate(Base.Vector(1,0,0),n-j,n-i)\n            history.append(\"mrotpX(\"+str(n-j)+\",\"+str(n-i)+\")\")\n    restoreCursor()\ndef rotpZ_history():\n    busyCursor()\n    fcd = App.ActiveDocument\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    nh = []\n    while len(history) > 0:\n        nh.append(history.pop())\n    reset()\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    while len(nh) > 0:\n        fs = nh.pop()\n        wh = fs[:6]\n        p = fs.index(\",\")\n        i = int(fs[7:p])\n        j = int(fs[p+1:len(fs)-1])\n        if wh == \"mrotpX\":\n            fastrotate(Base.Vector(0,1,0),i,j)\n            history.append(\"mrotpY(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmX\":\n            fastrotate(Base.Vector(0,-1,0),i,j)\n            history.append(\"mrotmY(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpY\":\n            fastrotate(Base.Vector(-1,0,0),n-j,n-i)\n            history.append(\"mrotmX(\"+str(n-j)+\",\"+str(n-i)+\")\")\n        elif wh == \"mrotmY\":\n            fastrotate(Base.Vector(1,0,0),n-j,n-i)\n            history.append(\"mrotpX(\"+str(n-j)+\",\"+str(n-i)+\")\")\n        elif wh == \"mrotpZ\":\n            fastrotate(Base.Vector(0,0,1),i,j)\n            history.append(\"mrotpZ(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmZ\":\n            fastrotate(Base.Vector(0,0,-1),i,j)\n            history.append(\"mrotmZ(\"+str(i)+\",\"+str(j)+\")\")\n    restoreCursor()\ndef rotmZ_history():\n    busyCursor()\n    fcd = App.ActiveDocument\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    n = Dictionary[str(fcd.Name)+\"Size\"]\n    nh = []\n    while len(history) > 0:\n        nh.append(history.pop())\n    reset()\n    history = Dictionary[str(fcd.Name)+\"history\"]\n    while len(nh) > 0:\n        fs = nh.pop()\n        wh = fs[:6]\n        p = fs.index(\",\")\n        i = int(fs[7:p])\n        j = int(fs[p+1:len(fs)-1])\n        if wh == \"mrotpX\":\n            fastrotate(Base.Vector(0,-1,0),n-j,n-i)\n            history.append(\"mrotmY(\"+str(n-j)+\",\"+str(n-i)+\")\")\n        elif wh == \"mrotmX\":\n            fastrotate(Base.Vector(0,1,0),n-j,n-i)\n            history.append(\"mrotpY(\"+str(n-j)+\",\"+str(n-i)+\")\")\n        elif wh == \"mrotpY\":\n            fastrotate(Base.Vector(1,0,0),i,j)\n            history.append(\"mrotpX(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmY\":\n            fastrotate(Base.Vector(-1,0,0),i,j)\n            history.append(\"mrotmX(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotpZ\":\n            fastrotate(Base.Vector(0,0,1),i,j)\n            history.append(\"mrotpZ(\"+str(i)+\",\"+str(j)+\")\")\n        elif wh == \"mrotmZ\":\n            fastrotate(Base.Vector(0,0,-1),i,j)\n            history.append(\"mrotmZ(\"+str(i)+\",\"+str(j)+\")\")\n    restoreCursor()\n\n# This bit of code creates the buttons at the top of the view window\n# The buttons are in a frameless window to save screen space\nclass ButtonRow(QtGui.QWidget):\n    def __init__(self):\n        super(ButtonRow, self).__init__()\n        mw = Gui.getMainWindow()\n        view3DWidget = findView(mw.centralWidget())\n        if view3DWidget != None:\n            self.setParent(view3DWidget)\n        self.setAutoFillBackground(True)\n        self.undoButton = QtGui.QPushButton(self)\n        self.undoButton.setText(\"Undo\")\n        self.undoButton.clicked.connect(self.onUndo)\n        self.saveButton = QtGui.QPushButton(self)\n        self.saveButton.setText(\"Copy history to clipboard\")\n        self.saveButton.clicked.connect(self.onSave)\n        self.resetButton = QtGui.QPushButton(self)\n        self.resetButton.setText(\"Reset\")\n        self.resetButton.clicked.connect(self.onReset)\n        self.show()\n    def onUndo(self):\n        undo()\n    def onReset(self):\n        reset()\n    def onSave(self):\n        saveHistory()\n    def paintEvent(self, event):\n        # we position the buttons every paint\n        # in case the window size has changed\n        bh = 30\n        bw = 80\n        mw = Gui.getMainWindow()\n        view3DWidget = findView(mw.centralWidget())\n        if view3DWidget != None:\n            geom = view3DWidget.geometry()\n            xpos = 0\n            self.setGeometry(xpos, 0, geom.width(), bh + 10)\n            gap = (geom.width() - 5 * bw) / 4\n            if gap < 0:\n                gap = 0\n            xpos = gap\n            self.undoButton.setGeometry(xpos, 0, bw, bh)\n            xpos = xpos + gap + bw\n            self.saveButton.setGeometry(xpos, 0, 3 * bw, bh)\n            xpos = xpos + 3 * bw + gap\n            self.resetButton.setGeometry(xpos, 0, bw, bh)\n        # now do the paint, which will paint the buttons as well since they\n        # are this widget's children\n        super(ButtonRow, self).paintEvent(event)\nDictionary[str(App.ActiveDocument.Name)+\"buttons\"] = ButtonRow()\n\n# FreeCAD's file save only saves the state of the camera\n# and the shapes, positions, orientations, names, and labels\n# of the objects in the scene \n# This function recreates all the other stuff after reloading a saved file\n# I haven't found a way to make FreeCAD save the history, so it gets reset\ndef fix_reload():\n    busyCursor()\n    fcd = App.ActiveDocument\n    # first we find how big a cube we have\n    n = 0\n    for obj in fcd.Objects:\n        fs = obj.Name\n        if fs[0:2] == \"ff\":\n            i = int(fs[2:fs.index(\"q\")])\n            if i > n:\n                n = i\n        elif fs[0:4] == \"Text\":\n            # get rid of this because it's incorrectly positioned\n            # we'll create a new one later\n            fcd.removeObject(fs)\n        elif fs[0:5] == \"arrow\":\n            obj.ViewObject.RootNode.setName(coin.SbName(fs))\n    n = n + 1\n    fc = [[[[None for j in range(6)] for ix in range(n)] for iy in range(n)] for ix in range(n)]\n    Dictionary[str(fcd.Name)+\"Size\"] = n\n    for obj in fcd.Objects:\n        fs = obj.Label\n        if fs[0:2] == \"fs\":\n            l = len(fs)\n            q1 = fs.find(\"q\")\n            q2 = fs.find(\"q\",q1+1)\n            ix = int(fs[2:q1])\n            iy = int(fs[q1+1:q2])\n            iz = int(fs[q2+1:l-2])\n            k = \"x0x1y0y1z0z1\".find(fs[l-2:])/2\n            fc[ix][iy][iz][k] = obj\n    Dictionary[str(fcd.Name)+\"cubies\"] = fc\n    Dictionary[str(fcd.Name)+\"ViewObserver\"] = ViewObserver()\n    doLabels() # create new labels\n    rotation = fixCamera(False)\n    # create the buttons at the top of the window\n    Dictionary[str(App.ActiveDocument.Name)+\"buttons\"] = ButtonRow()\n    fixLightModel()\n    createMultiViews(rotation)\n    history = [] # according to Henry Ford\n    Dictionary[str(fcd.Name)+\"history\"] = history\n    restoreCursor()\n    FreeCAD.Console.PrintLog(\"fix_reload() done\\n\")\n\nrestoreCursor()\n",
    "url": "https://wiki.freecad.org/Macro_Rubik_Cube",
    "raw_code_url": "",
    "wiki": "http://www.freecadweb.org/wiki/index.php?title=Macro_Rubik_Cube",
    "version": "00.05",
    "license": "",
    "date": "15/12/2018",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Aleph0",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Rubik_Cube.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/7/7c/Macro_Rubik_Cube.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Sheet Metal Unfolder",
    "on_wiki": true,
    "on_git": false,
    "desc": "The macro can unfold simple sheet-metal-parts. The parts must have everywhere the same material thickness as typical for sheet-metal-parts.<br /><br />Macro version: 17.0<br />Last modified: 2018-08-14<br />FreeCAD version: 17.0<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/1/16/Macro_Sheet_Metal_Unfolder.png\">ToolBar Icon</a><br />Author: ulrich1a<br /> ",
    "comment": "The macro can unfold simple sheet-metal-parts. The parts must have everywhere the same material thickness as typical for sheet-metal-parts.",
    "code": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#\n#  sheet_ufo.py\n#  \n#  Copyright 2014, 2018 Ulrich Brammer <ulrich@Pauline>\n#  \n#  This program is free software; you can redistribute it and/or modify\n#  it under the terms of the GNU General Public License as published by\n#  the Free Software Foundation; either version 2 of the License, or\n#  (at your option) any later version.\n#  \n#  This program is distributed in the hope that it will be useful,\n#  but WITHOUT ANY WARRANTY; without even the implied warranty of\n#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n#  GNU General Public License for more details.\n#  \n#  You should have received a copy of the GNU General Public License\n#  along with this program; if not, write to the Free Software\n#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n#  MA 02110-1301, USA.\n#  \n#  \n# sheet_ufo.py git-version\n# July 2018\n# added sortEdgesTolerant: more robust generation of Wires for unbend Faces\n# generate fold lines, to be used in drawings of the unfolded part.\n# fixed calculation of Bend Angle, not working in some cases\n\n\n# sheet_ufo20.py\n# removal of dead code\n\n# sheet_ufo19.py\n# changes from June 2018\n# - found solution for the new unbendFace function.\n# - supports now non orthogonals cut in the bends\n# - seams do not get a face, just do not call makeSeamFace\n#   this avoids internal faces in the unfold under certain cases.\n \n\n# sheet_ufo18.py\n# Changes done in 2016 and June 2018\n# allow more complex bends: not only straight cut side edges\n# tested some code, not published\n\n# sheet_ufo17.py\n# Refactored version December 2015\n# Clear division of tasks between analysis and folding\n\n# To do:\n# change code to handle face indexes in the node instead of faces\n\n\n# sheet_ufo16.py\n# Die Weiterreichung eines schon geschnittenen Seitenfaces macht Probleme.\n# Die Seitenfaces passen hinterher nicht mehr mit den Hauptfl\u00e4chen zusammen.\n\n# Ge\u00e4nderter Ansatz: lasse die Seitenfl\u00e4chen in der Suchliste und \n# schneide jeweils nur den ben\u00f6tigten Teil raus.\n# Ich brauche jetzt eine Suchliste und eine Unfoldliste f\u00fcr die \n# Face-Indices.\n\n# To do: \n# - handle a selected seam\n# - handle not-circle-curves in bends, done\n# - detect features like welded screws\n# - make a view-provider for bends\n# - make the k-factor selectable\n# - upfold or unfold single bends\n \n\n# ideas:\n# during analysis make a mesh-like structure for the bend-node\n# list of edges in the bend-node\n# for each face store a list with edge-indices.\n# the reason is, each edge has to be recalculated at unfolding\n# so the number of calculations could be half, as if for each\n# face all edges are calculated.\n# Edges perpendicular to the sheet may only be moved to the new location?\n# Need to think about it! No only at the end of the bend node.\n# Edges in the middle of the bend node will be sheared, because the \n# neutral line is not in the middle of the sheet-thickness.\n# OK this is more complex, than I thought at the beginning.\n\n# in a bend node all faces and edges are recreated\n# all vertices are translated except those from the parent node.\n# the code looked already at each of them.\n# a good storage structure is needed!\n\n'''\n\ndef main():\n    \n    return 0\n\nif __name__ == '__main__':\n    main()\n\n\n'''\n\n\nimport Part, FreeCADGui\nfrom PySide import QtGui\nfrom FreeCAD import Base\nimport DraftVecUtils, DraftGeomUtils, math, time\n\n# to do: \n# - Put error numbers into the text\n# - Put user help into more texts\nunfold_error = {\n  # error codes for the tree-object\n  1: ('starting: volume unusable, needs a real 3D-sheet-metal with thickness'), \n  2: ('Starting: invalid point for thickness measurement'), \n  3: ('Starting: invalid thickness'), \n  4: ('Starting: invalid shape'), \n  5: ('Starting: Shape has unneeded edges. Please use function refine shape from the Part Workbench before unfolding!'), \n  # error codes for the bend-analysis \n  10: ('Analysis: zero wires in sheet edge analysis'), \n  11: ('Analysis: double bends not implemented'), \n  12: ('Analysis: more than one bend-child actually not supported'), \n  13: ('Analysis: Sheet thickness invalid for this face!'), \n  14: ('Analysis: the code can not handle edges without neighbor faces'), \n  15: ('Analysis: the code needs a face at all sheet edges'), \n  16: ('Analysis: did not find startangle of bend, please post failing sample for analysis'),\n  17: ('Analysis: Type of surface not supported for sheet metal parts'), # <SurfaceOfExtrusion object> fix me?\n  # error codes for the unfolding\n  20: ('Unfold: section wire with less than 4 edges'),\n  21: ('Unfold: Unfold: section wire not closed'),\n  22: ('Unfold: section failed'),\n  23: ('Unfold: CutToolWire not closed'),\n  24: ('Unfold: bend-face without child not implemented'),\n  25: ('Unfold: '),\n  26: ('Unfold: not handled curve type in unbendFace'),\n  27: ('Unfold: could not sort wire'),\n  -1: ('unknown error')} \n\n\n\n\n\ndef equal_vertex(vert1, vert2, p=5):\n  # compares two vertices \n  return (round(vert1.X - vert2.X,p)==0 and round(vert1.Y - vert2.Y,p)==0 and round(vert1.Z - vert2.Z,p)==0)\n\ndef equal_vector(vec1, vec2, p=5):\n  # compares two vectors \n  return (round(vec1.x - vec2.x,p)==0 and round(vec1.y - vec2.y,p)==0 and round(vec1.z - vec2.z,p)==0)\n\ndef radial_vector(point, axis_pnt, axis):\n  chord = axis_pnt.sub(point)\n  norm = axis.cross(chord)\n  perp = axis.cross(norm)\n  # FreeCAD.Console.PrintLog( str(chord) + ' ' + str(norm) + ' ' + str(perp)+'\\n')\n  dist_rv = DraftVecUtils.project(chord,perp)\n  #test_line = Part.makeLine(axis_pnt.add(dist_rv),axis_pnt)\n  # test_line = Part.makeLine(axis_pnt.add(perp),axis_pnt)\n  # test_line = Part.makeLine(point, axis_pnt)\n  # Part.show(test_line)\n  return perp.normalize()\n\ndef equal_angle(ang1, ang2, p=5):\n  # compares two angles\n  result = False\n  if round(ang1 - ang2, p)==0:\n    result = True\n  if round((ang1-2.0*math.pi) - ang2, p)==0:\n    result = True\n  if round(ang1 - (ang2-2.0*math.pi), p)==0:\n    result = True\n  return result\n\ndef equal_edge(edg1, edg2, p=5):\n  result = True\n  if len(edg1.Vertexes) > 1:\n    if not (equal_vertex(edg1.Vertexes[0], edg2.Vertexes[0]) or equal_vertex(edg1.Vertexes[0], edg2.Vertexes[1])):\n      result = False\n    if not (equal_vertex(edg1.Vertexes[1], edg2.Vertexes[0]) or equal_vertex(edg1.Vertexes[1], edg2.Vertexes[1])):\n      result = False\n  else:\n    if not (equal_vertex(edg1.Vertexes[0], edg2.Vertexes[0])):\n      result = False\n    if len(edg2.Vertexes) > 1:\n      result = False\n  return result\n\n\nclass Simple_node(object):\n  ''' This class defines the nodes of a tree, that is the result of\n  the analysis of a sheet-metal-part.\n  Each flat or bend part of the metal-sheet gets a node in the tree.\n  The indexes are the number of the face in the original part.\n  Faces of the edge of the metal-sheet need in cases to be split.\n  These new faces are added to the index list.\n  '''\n  def __init__(self, f_idx=None, Parent_node= None, Parent_edge = None):\n    self.idx = f_idx  # index of the \"top-face\"\n    self.c_face_idx = None # face index to the opposite face of the sheet (counter-face)\n    self.node_type = None  # 'Flat' or 'Bend'\n    self.p_node = Parent_node   # Parent node\n    self.p_edge = Parent_edge # the connecting edge to the parent node\n    self.child_list = [] # List of child-nodes = link to tree structure\n    self.child_idx_lists = [] # List of lists with child_idx and child_edge\n    # need also a list of indices of child faces\n    self.sheet_edges = [] # List of edges without child-face \n    self.axis = None # direction of the axis of the detected cylindrical face\n    self.facePosi = None \n    self.bendCenter = None # Vector of the center of the detected cylindrical face\n    self.distCenter = None # Value used to detect faces at opposite side of the bend\n    self.innerRadius = None # nominal radius of the bend \n    # self.axis for 'Flat'-face: vector pointing from the surface into the metal\n    self.bend_dir = None # bend direction values: \"up\" or \"down\"\n    self.bend_angle = None # angle in radians\n    self.tan_vec = None # direction of translation for Bend nodes\n    self.oppositePoint = None # Point of a vertex on the opposite site, used to align points to the sheet plane\n    self.vertexDict = {} # Vertexes of a bend, original and unbend coordinates, flags p, c, t, o\n    self.edgeDict = {} # unbend edges dictionary, key is a combination of indexes to vertexDict.\n    self.k_Factor = None # k-factor according to DIN 6935\n    self._trans_length = None # length of translation for Bend nodes, k-factor used according to DIN 6935\n    self.analysis_ok = True # indicator if something went wrong with the analysis of the face\n    self.error_code = None # index to unfold_error dictionary\n    # here the new features of the nodes:\n    self.nfIndexes = [] # list of all face-indexes of a node (flat and bend: folded state)\n    self.seam_edges = [] # list with edges to seams\n    # bend faces are needed for movement simulation at single other bends.\n    # otherwise unfolded faces are recreated from self.b_edges\n    self.node_flattened_faces = [] # faces of a flattened bend node.\n    self.unfoldTopList = None # source of identical side edges\n    self.unfoldCounterList = None # source of identical side edges\n    self.actual_angle = None # state of angle in refolded sheet metal part\n    self.p_wire = None # wire common with parent node, used for bend node\n    self.c_wire = None # wire common with child node, used for bend node\n    self.b_edges = [] # list of edges in a bend node, that needs to be recalculated, at unfolding\n    self.foldVertex1 = None # points to attach a text to a bend in a drawing\n    self.foldVertex2 = None # point to attach a text to a bend in a drawing\n    self.bendNumber = None # Number assigned to a bend, used in tables and drawings\n\n  def get_Face_idx(self):\n    # get the face index from the tree-element\n    return self.idx\n\n\n\n\n\nclass SheetTree(object):\n  def __init__(self, TheShape, f_idx, theDocument):\n    self.cFaceTol = 0.002 # tolerance to detect counter-face vertices\n    # this high tolerance was needed for more real parts\n    self.root = None # make_new_face_node adds the root node if parent_node == None\n    self.__Shape = TheShape.copy()\n    self.theDoc = theDocument # the active document, where the handled objects are stored in.\n    self.error_code = None\n    self.failed_face_idx = None\n    self.bendCounter = 0 # Counter to give a bend a number, stored in bendNumber in the tree structure\n    \n    if not self.__Shape.isValid():\n      FreeCAD.Console.PrintLog(\"The shape is not valid!\" + \"\\n\")\n      self.error_code = 4  # Starting: invalid shape\n      self.failed_face_idx = f_idx\n    \n    #Part.show(self.__Shape)\n    \n    # List of indices to the shape.Faces. The list is used a lot for face searches.\n    # Some faces will be cut and the new ones added to the list.\n    # So a list of faces independent of the shape is needed.\n    self.f_list = []  #self.__Shape.Faces.copy() does not work\n    self.index_list =[]\n    self.index_unfold_list = [] # indexes needed for unfolding\n    for i in range(len (self.__Shape.Faces)):\n    #for i in range(len (self.f_list)):\n      # if i<>(f_idx):\n      self.index_list.append(i)\n      self.index_unfold_list.append(i)\n      self.f_list.append(self.__Shape.Faces[i])\n    #print self.index_list\n    self.max_f_idx = len(self.f_list) # need this value to make correct indices to new faces\n    self.unfoldFaces = len(self.f_list) # need the original number of faces for error detection\n    withoutSplitter = self.__Shape.removeSplitter()\n    #if self.unfoldFaces > len(withoutSplitter.Faces): # This is not a good idea! Most sheet metal parts have unneeded edges.\n      #print 'got case which needs a refine shape from the Part workbench!'\n      #self.error_code = 5\n      #self.failed_face_idx = f_idx\n      \n\n    theVol = self.__Shape.Volume\n    if theVol < 0.0001:\n      FreeCAD.Console.PrintLog(\"Shape is not a real 3D-object or to small for a metal-sheet!\" + \"\\n\")\n      self.error_code = 1\n      self.failed_face_idx = f_idx\n\n    else:\n      # Make a first estimate of the thickness\n      estimated_thickness = theVol/(self.__Shape.Area / 2.0)\n      FreeCAD.Console.PrintLog( \"approximate Thickness: \" + str(estimated_thickness) + \"\\n\")\n      # Measure the real thickness of the initial face: Use Orientation and\n      # Axis to make an measurement vector\n      \n    \n      if hasattr(self.__Shape.Faces[f_idx],'Surface'):\n        # Part.show(self.__Shape.Faces[f_idx])\n        # print 'the object is a face! vertices: ', len(self.__Shape.Faces[f_idx].Vertexes)\n        F_type = self.__Shape.Faces[f_idx].Surface\n        # fixme: through an error, if not Plane Object\n        FreeCAD.Console.PrintLog('It is a: ' + str(F_type) + '\\n')\n        FreeCAD.Console.PrintLog('Orientation: ' + str(self.__Shape.Faces[f_idx].Orientation) + '\\n')\n        \n        # Need a point on the surface to measure the thickness.\n        # Sheet edges could be sloping, so there is a danger to measure\n        # right at the edge. \n        # Try with Arithmetic mean of plane vertices\n        m_vec = Base.Vector(0.0,0.0,0.0) # calculating a mean vector\n        for Vvec in self.__Shape.Faces[f_idx].Vertexes:\n            #m_vec = m_vec.add(Base.Vector(Vvec.X, Vvec.Y, Vvec.Z))\n            m_vec = m_vec.add(Vvec.Point)\n        mvec = m_vec.multiply(1.0/len(self.__Shape.Faces[f_idx].Vertexes))\n        FreeCAD.Console.PrintLog(\"mvec: \" + str(mvec) + \"\\n\")\n        \n        #if hasattr(self.__Shape.Faces[f_idx].Surface,'Position'):\n          #s_Posi = self.__Shape.Faces[f_idx].Surface.Position\n          #k = 0\n          # while k < len(self.__Shape.Faces[f_idx].Vertexes):\n          # fixme: what if measurepoint is outside?\n          \n        if self.__Shape.isInside(mvec, 0.00001, True):\n          measure_pos = mvec\n          gotValidMeasurePosition = True\n        else:\n          gotValidMeasurePosition = False\n          for pvert in self.__Shape.Faces[f_idx].OuterWire.Vertexes:\n            #pvert = self.__Shape.Faces[f_idx].Vertexes[k]\n            pvec = Base.Vector(pvert.X, pvert.Y, pvert.Z)\n            shiftvec =  mvec.sub(pvec)\n            shiftvec = shiftvec.normalize()*2.0*estimated_thickness\n            measure_pos = pvec.add(shiftvec)\n            if self.__Shape.isInside(measure_pos, 0.00001, True):\n              gotValidMeasurePosition = True\n              break\n          \n        # Description: Checks if a point is inside a solid with a certain tolerance.\n        # If the 3rd parameter is True a point on a face is considered as inside\n        #if not self.__Shape.isInside(measure_pos, 0.00001, True):\n        if not gotValidMeasurePosition:\n          FreeCAD.Console.PrintLog(\"Starting measure_pos for thickness measurement is outside!\\n\")\n          self.error_code = 2\n          self.failed_face_idx = f_idx\n\n        \n        if hasattr(self.__Shape.Faces[f_idx].Surface,'Axis'):\n          s_Axis =  self.__Shape.Faces[f_idx].Surface.Axis\n          # print 'We have an axis: ', s_Axis\n          if hasattr(self.__Shape.Faces[f_idx].Surface,'Position'):\n            s_Posi = self.__Shape.Faces[f_idx].Surface.Position\n            # print 'We have a position: ', s_Posi\n            s_Ori = self.__Shape.Faces[f_idx].Orientation\n            s_Axismp = Base.Vector(s_Axis.x, s_Axis.y, s_Axis.z).multiply(2.0*estimated_thickness)\n            if s_Ori == 'Forward':\n              Meassure_axis = Part.makeLine(measure_pos,measure_pos.sub(s_Axismp))\n              ext_Vec = Base.Vector(-s_Axis.x, -s_Axis.y, -s_Axis.z)\n              # Meassure_axis = Part.makeLine(measure_pos,measure_pos.sub(s_Axis.multiply(2.0*estimated_thickness)))\n            else:                    \n              # Meassure_axis = Part.makeLine(measure_pos,measure_pos.add(s_Axis.multiply(2.0*estimated_thickness)))\n              Meassure_axis = Part.makeLine(measure_pos,measure_pos.add(s_Axismp))\n              ext_Vec = Base.Vector(s_Axis.x, s_Axis.y, s_Axis.z)\n            # Part.show(Meassure_axis)\n                \n        lostShape = self.__Shape.copy()\n        lLine = Meassure_axis.common(lostShape)\n        lLine = Meassure_axis.common(self.__Shape)\n        FreeCAD.Console.PrintLog(\"lLine number edges: \" + str(len(lLine.Edges)) + \"\\n\")\n        measVert = Part.Vertex(measure_pos)\n        for mEdge in lLine.Edges:\n          if equal_vertex(mEdge.Vertexes[0], measVert) or equal_vertex(mEdge.Vertexes[1], measVert):\n            self.__thickness = mEdge.Length\n        \n        # self.__thickness = lLine.Length\n        if (self.__thickness < estimated_thickness) or (self.__thickness > 1.9 * estimated_thickness):\n          self.error_code = 3\n          self.failed_face_idx = f_idx\n          FreeCAD.Console.PrintLog(\"estimated thickness: \" + str(estimated_thickness) + \" measured thickness: \" + self.__thickness + \"\\n\")\n          Part.show(lLine, 'Measurement_Thickness_trial')\n\n\n  def get_node_faces(self, theNode, wires_e_lists):\n    ''' This function searches for all faces making up the node, except\n    of the top and bottom face, which are already there.\n    wires_e_list is the list of wires lists of the top face without the parent-edge\n    theNode: the actual node to be filled with data.\n    '''\n    \n    # How to begin?\n    # searching for all faces, that have two vertices in common with \n    # an edge from the list should give the sheet edge.\n    # But we also need to look at the sheet edge, in order to not claim\n    # faces from the next node!\n    # Then we have to treat thoses faces, that belongs to more than one\n    # node. Those faces needs to be cut and the face list needs to be updated.\n    # look also at the number of wires of the top face. More wires will\n    # indicate a hole or a feature.\n    #print \" When will this be called\"\n    found_indices = []\n    # A search strategy for faces based on the wires_e_lists is needed.\n    # \n\n    for theWire in wires_e_lists:\n      for theEdge in theWire:\n        analyVert = theEdge.Vertexes[0]\n        search_list = []\n        for x in self.index_list:\n          search_list.append(x)\n        for i in search_list:\n          for lookVert in self.f_list[i].Vertexes:\n            if equal_vertex(lookVert, analyVert):\n              if len(theEdge.Vertexes) == 1: # Edge is a circle\n                if not self.is_sheet_edge_face(theEdge, theNode):\n                  found_indices.append(i) # found a node face\n                  theNode.child_idx_lists.append([i,theEdge])\n                  #self.index_list.remove(i) # remove this face from the index_list\n                  #Part.show(self.f_list[i])\n              else:\n                nextVert = theEdge.Vertexes[1]\n                for looknextVert in self.f_list[i].Vertexes:\n                  if equal_vertex(looknextVert, nextVert):\n                    if not self.is_sheet_edge_face(theEdge, theNode):\n                      found_indices.append(i) # found a node face\n                      theNode.child_idx_lists.append([i,theEdge])\n                      #self.index_list.remove(i) # remove this face from the index_list\n                      #Part.show(self.f_list[i])\n    FreeCAD.Console.PrintLog(\"found_indices: \" + str(found_indices) + \"\\n\")\n                \n\n\n  def is_sheet_edge_face(self, ise_edge, tree_node): # ise_edge: IsSheetEdge_edge\n    # idea: look at properties of neighbor face\n    # look at edges with distance of sheet-thickness.\n    #    if found and surface == cylinder, check if it could be a bend-node.  \n    # look at number of edges:\n    # A face with 3 edges is at the sheet edge Cylinder-face or triangle (oh no!)\n    # need to look also at surface!\n    # A sheet edge face with more as 4 edges, is common to more than 1 node.\n    \n    # get the face which has a common edge with ise_edge\n    the_index = None\n    has_sheet_distance_vertex = False\n    for i in self.index_list:\n      for sf_edge in self.f_list[i].Edges:\n        if sf_edge.isSame(ise_edge):\n          the_index = i\n          #print 'got edge face: Face', str(i+1)\n          break\n      if the_index is not None:\n        break\n          \n    # Simple strategy applied: look if the connecting face has vertexes\n    # with sheet-thickness distance to the top face.\n    # fix me: this will fail with sharpened sheet edges with two faces\n    # between top and bottom.\n    if the_index is not None:\n      distVerts = 0\n      vertList = []\n      F_type = str(self.f_list[tree_node.idx].Surface)\n      # now we need to search for vertexes with sheet_thickness_distance\n      for F_vert in self.f_list[i].Vertexes:\n        #vDist = self.getDistanceToFace(F_vert, tree_node)\n        #if vDist > maxDist: maxDist = vDist\n        #if vDist < minDist: minDist = vDist\n      #maxDist = maxDist- self.__thickness\n      #if (minDist > -self.cFaceTol) and (maxDist < self.cFaceTol) and (maxDist > -self.cFaceTol):\n\n        if self.isVertOpposite(F_vert, tree_node):\n          has_sheet_distance_vertex = True\n          if len(self.f_list[i].Edges)<5:\n            tree_node.nfIndexes.append(i)\n            self.index_list.remove(i)\n            #Part.show(self.f_list[i])\n          else:\n            # need to cut the face at the ends of ise_edge\n            self.divideEdgeFace(i, ise_edge, F_vert, tree_node)\n          break\n\n    else:\n      tree_node.analysis_ok = False \n      tree_node.error_code = 15  # Analysis: the code needs a face at all sheet edges\n      self.error_code = 15\n      self.failed_face_idx = tree_node.idx\n      Part.show(self.f_list[tree_node.idx])\n            \n    return has_sheet_distance_vertex\n\n\n  def isVertOpposite(self, theVert, theNode):\n    F_type = str(self.f_list[theNode.idx].Surface)\n    vF_vert = Base.Vector(theVert.X, theVert.Y, theVert.Z)\n    if F_type == \"<Plane object>\":\n      distFailure = vF_vert.distanceToPlane (theNode.facePosi, theNode.axis) - self.__thickness\n    elif F_type == \"<Cylinder object>\":\n      distFailure = vF_vert.distanceToLine (theNode.bendCenter, theNode.axis) - theNode.distCenter\n    else: \n      distFailure = 100.0\n      theNode.error_code = 17  # Analysis: the code needs a face at all sheet edges\n      self.error_code = 17\n      self.failed_face_idx = theNode.idx\n      #Part.show(self.f_list[theNode.idx], 'SurfaceType_not_supported')\n    # print \"counter face distance: \", dist_v + self.__thickness\n    if (distFailure < self.cFaceTol) and (distFailure > -self.cFaceTol):\n      return True\n    else:\n      return False\n\n  def getDistanceToFace(self, theVert, theNode):\n    F_type = str(self.f_list[theNode.idx].Surface)\n    vF_vert = Base.Vector(theVert.X, theVert.Y, theVert.Z)\n    # a positive distance should go through the sheet metal \n    if F_type == \"<Plane object>\":\n      dist = vF_vert.distanceToPlane (theNode.facePosi, theNode.axis)\n    if F_type == \"<Cylinder object>\":\n      dist = vF_vert.distanceToLine(theNode.bendCenter, theNode.axis) - self.f_list[theNode.idx].Surface.Radius\n      if theNode.bend_dir == \"down\":\n        dist = -dist\n    return dist\n\n\n\n  def divideEdgeFace(self, fIdx, ise_edge, F_vert, tree_node):\n    FreeCAD.Console.PrintLog(\"Sheet edge face has more than 4 edges!\\n\")\n    # first find out where the Sheet edge face has no edge to the opposite side of the sheet\n    # There is a need to cut the face.\n    # make a cut-tool perpendicular to the ise_edge\n    # cut the face and select the good one to add to the node\n    # make another cut, in order to add the residual face(s) to the face list.\n    \n    # Search edges in the face with a vertex common with ise_edge\n    F_type = str(self.f_list[tree_node.idx].Surface)\n    needCut0 = True\n    firstCutFaceIdx = None\n    for sEdge in self.f_list[fIdx].Edges:\n      if equal_vertex(ise_edge.Vertexes[0], sEdge.Vertexes[0]) and \\\n        self.isVertOpposite(sEdge.Vertexes[1], tree_node):\n        needCut0 = False\n        theEdge = sEdge\n      if equal_vertex(ise_edge.Vertexes[0], sEdge.Vertexes[1]) and \\\n        self.isVertOpposite(sEdge.Vertexes[0], tree_node):\n        needCut0 = False\n        theEdge = sEdge\n    if needCut0:\n      #print \"need Cut at 0 with fIdx: \", fIdx\n      nFace = self.cutEdgeFace(0, fIdx, ise_edge, tree_node)\n      \n      tree_node.nfIndexes.append(self.max_f_idx)\n      self.f_list.append(nFace)\n      firstCutFaceIdx = self.max_f_idx\n      self.max_f_idx += 1\n      #self.f_list.append(rFace)\n      #self.index_list.append(self.max_f_idx)\n      #self.max_f_idx += 1\n      #self.index_list.remove(fIdx)\n      #Part.show(nFace)\n    #else:\n    #  Part.show(theEdge)\n        \n    needCut1 = True        \n    for sEdge in self.f_list[fIdx].Edges:\n      if equal_vertex(ise_edge.Vertexes[1], sEdge.Vertexes[0]):\n        if self.isVertOpposite(sEdge.Vertexes[1], tree_node):\n          needCut1 = False\n          theEdge = sEdge\n      if equal_vertex(ise_edge.Vertexes[1], sEdge.Vertexes[1]):\n        if self.isVertOpposite(sEdge.Vertexes[0], tree_node):\n          needCut1 = False\n          theEdge = sEdge\n    if needCut1:\n      if needCut0:\n        fIdx = firstCutFaceIdx\n        tree_node.nfIndexes.remove(fIdx)\n      #print \"need Cut at 1 with fIdx: \", fIdx\n      nFace = self.cutEdgeFace(1, fIdx, ise_edge, tree_node)\n      tree_node.nfIndexes.append(self.max_f_idx)\n      self.f_list.append(nFace)\n      firstCutFaceIdx = self.max_f_idx\n      self.max_f_idx += 1\n      #self.f_list.append(rFace)\n      #self.index_list.append(self.max_f_idx)\n      #self.max_f_idx += 1\n      #if not needCut0:\n      #  self.index_list.remove(fIdx)\n      #Part.show(nFace)\n    #else:\n    #  Part.show(theEdge)\n\n\n    \n  def cutEdgeFace(self, eIdx, fIdx, theEdge, theNode):\n    ''' This function cuts a face in two pieces.\n    one piece is connected to the node. \n    The residual piece is discarded. \n    The function returns the piece that has a common edge with the top face of theNode.\n    '''\n    #print \"now the face cutter: \", fIdx, ' ', eIdx, ' ', theNode.idx\n    #Part.show(theEdge, 'EdgeToCut'+ str(theNode.idx+1)+'_')\n    #Part.show(self.f_list[fIdx], 'FaceToCut'+ str(theNode.idx+1)+'_')\n    \n    if eIdx == 0:\n      otherIdx = 1\n    else:\n      otherIdx = 0\n    \n    origin = theEdge.Vertexes[eIdx].Point\n    \n    F_type = str(self.f_list[theNode.idx].Surface)\n    if F_type == \"<Plane object>\":\n      tan_vec = theEdge.Vertexes[eIdx].Point - theEdge.Vertexes[otherIdx].Point\n      #o_thick = Base.Vector(o_vec.x, o_vec.y, o_vec.z) \n      tan_vec.normalize()\n      #New approach: search for the nearest vertex at the opposite site.\n      # The cut is done between the Vertex indicated by eIdx and the nearest\n      # opposite vertex. This approach should avoid the generation of \n      # additional short edges in the side faces.\n      searchAxis = theNode.axis\n      #else:\n        #searchAxis = radVector\n            \n      maxDistance = 1000\n      oppoPoint = None\n      print 'need to check Face', str(fIdx+1), ' with ', len(self.f_list[fIdx].Vertexes)\n      for theVert in self.f_list[fIdx].Vertexes:\n        # need to check if theVert has \n        if self.isVertOpposite(theVert, theNode):\n          vertDist = theVert.Point.distanceToLine(origin, searchAxis)\n          if vertDist < maxDistance:\n            maxDistance = vertDist\n            oppoPoint = theVert.Point\n            \n      if oppoPoint is None:\n        print ' error need always an opposite point in a side face!'\n        # fix me: need a proper error condition.\n      \n      #vec1 = Base.Vector(theNode.axis.x, theNode.axis.y, theNode.axis.z) # make a copy\n      vec1 = (oppoPoint - origin).normalize()\n\n      crossVec = tan_vec.cross(vec1)\n      crossVec.multiply(3.0*self.__thickness)\n\n      vec1.multiply(self.__thickness)\n      # defining the points of the cutting plane:\n      Spnt1 = origin - vec1 - crossVec\n      Spnt2 = origin - vec1 + crossVec\n      Spnt3 = origin + vec1 +  vec1 + crossVec\n      Spnt4 = origin + vec1 +  vec1 - crossVec\n  \n      \n      \n    if F_type == \"<Cylinder object>\":\n      ePar = theEdge.parameterAt(theEdge.Vertexes[eIdx])\n      FreeCAD.Console.PrintLog(\"Idx: \" + str(eIdx) + \" ePar: \" + str(ePar) + \"\\n\")\n      otherPar = theEdge.parameterAt(theEdge.Vertexes[otherIdx])\n      tan_vec = theEdge.tangentAt(ePar)\n      if ePar < otherPar:\n        tan_vec.multiply(-1.0)\n      \n      #tan_line = Part.makeLine(theEdge.Vertexes[eIdx].Point.add(tan_vec), theEdge.Vertexes[eIdx].Point)\n      #Part.show(tan_line, 'tan_line'+ str(theNode.idx+1)+'_')\n      \n      edge_vec = theEdge.Vertexes[eIdx].copy().Point\n      radVector = radial_vector(edge_vec, theNode.bendCenter, theNode.axis)\n      if theNode.bend_dir == \"down\":\n        radVector.multiply(-1.0)\n  \n      #rad_line = Part.makeLine(theEdge.Vertexes[eIdx].Point.add(radVector), theEdge.Vertexes[eIdx].Point)\n      #Part.show(rad_line, 'rad_line'+ str(theNode.idx+1)+'_')\n      searchAxis = radVector\n            \n      maxDistance = 1000\n      oppoPoint = None\n      print 'need to check Face', str(fIdx+1), ' with ', len(self.f_list[fIdx].Vertexes)\n      for theVert in self.f_list[fIdx].Vertexes:\n        # need to check if theVert has \n        if self.isVertOpposite(theVert, theNode):\n          vertDist = theVert.Point.distanceToLine(origin, searchAxis)\n          if vertDist < maxDistance:\n            maxDistance = vertDist\n            oppoPoint = theVert.Point\n            \n      if oppoPoint is None:\n        print ' error need always an opposite point in a side face!'\n        # fix me: need a proper error condition.\n      #vec1 = Base.Vector(radVector.x, radVector.y, radVector.z) # make a copy\n      vec1 = (oppoPoint - origin).normalize()\n\n      crossVec = tan_vec.cross(vec1)\n      crossVec.multiply(3.0*self.__thickness)\n\n      vec1.multiply(self.__thickness)\n      # defining the points of the cutting plane:\n      Spnt1 = origin - vec1 - crossVec\n      Spnt2 = origin - vec1 + crossVec\n      Spnt3 = origin + vec1 +  vec1 + crossVec\n      Spnt4 = origin + vec1 +  vec1 - crossVec\n    \n    Sedge1 = Part.makeLine(Spnt1,Spnt2)\n    Sedge2 = Part.makeLine(Spnt2,Spnt3)\n    Sedge3 = Part.makeLine(Spnt3,Spnt4)\n    Sedge4 = Part.makeLine(Spnt4,Spnt1)\n        \n    Sw1 = Part.Wire([Sedge1, Sedge2, Sedge3, Sedge4])\n    # Part.show(Sw1, 'cutWire'+ str(theNode.idx+1)+'_')\n    Sf1=Part.Face(Sw1) #\n    #Part.show(Sf1, 'cutFace'+ str(theNode.idx+1)+'_')\n    #cut_solid = Sf1.extrude(tan_vec.multiply(5.0))\n    cut_solid = Sf1.extrude(tan_vec.multiply(self.__thickness))\n    #Part.show(cut_solid, 'cut_solid'+ str(theNode.idx+1)+'_')\n    #cut_opposite = Sf1.extrude(tan_vec.multiply(-5.0))\n    \n    cutFaces_node = self.f_list[fIdx].cut(cut_solid)\n    for cFace in cutFaces_node.Faces:\n      for myVert in cFace.Vertexes:\n        if equal_vertex(theEdge.Vertexes[eIdx], myVert):\n          nodeFace = cFace\n          #print \"The nodeFace Idx: \", fIdx, ' eIdx: ', eIdx \n          #Part.show(nodeFace)\n          break\n\n    return nodeFace #, residueFace\n    \n\n  def getBendAngle(self, newNode, wires_e_lists):\n    ''' Get the bend angle for a node connected to a bend face,\n    Get the k-Factor\n    Get the translation Length\n    '''\n    # newNode = Simple_node(face_idx, P_node, P_edge)\n    P_node = newNode.p_node\n    P_edge = newNode.p_edge\n    face_idx = newNode.idx\n    theFace = self.__Shape.Faces[face_idx]\n    \n    s_Axis = newNode.axis\n    s_Center = newNode.bendCenter\n    \n    #Start to investigate the angles at self.__Shape.Faces[face_idx].ParameterRange[0]\n    angle_0 = theFace.ParameterRange[0]\n    angle_1 = theFace.ParameterRange[1]\n    \n    # idea: identify the angle at edge_vec = P_edge.Vertexes[0].copy().Point\n    # This will be = angle_start\n    # calculate the tan_vec from valueAt\n\n    edge_vec = P_edge.Vertexes[0].copy().Point\n    edgeAngle, edgePar = theFace.Surface.parameter(edge_vec)\n\n    #print 'the angles: ', angle_0, ' ', angle_1, ' ', edgeAngle, ' ', edgeAngle - 2*math.pi\n    \n    if equal_angle(angle_0, edgeAngle):\n      angle_start = angle_0\n      angle_end = angle_1\n    else:\n      angle_start = angle_1\n      angle_end = angle_0\n    len_start = edgePar\n      \n    newNode.bend_angle = angle_end - angle_start\n    angle_tan = angle_start + newNode.bend_angle/6.0 # need to have the angle_tan before correcting the sign\n\n    if newNode.bend_angle < 0.0:\n      newNode.bend_angle = -newNode.bend_angle\n\n    first_vec = radial_vector(edge_vec, s_Center, s_Axis)\n    tanPos = self.__Shape.Faces[face_idx].valueAt(angle_tan,len_start)\n    sec_vec = radial_vector(tanPos, s_Center, s_Axis)\n\n\n    cross_vec = first_vec.cross(sec_vec)\n    triple_prod = cross_vec.dot(s_Axis)\n    if triple_prod < 0:\n      newNode.axis = -newNode.axis\n      s_Axis = -s_Axis\n      \n    #tan_vec = radial_vector(tanPos, s_Center, s_Axis)\n    tan_vec = s_Axis.cross(first_vec)\n    #Part.show(Part.makeLine(tanPos, tanPos + 10 * tan_vec), 'tan_Vec')\n    newNode.tan_vec = tan_vec\n    #make a better tan_vec based on the parent face normal and the parent edge:\n    if P_node.node_type == 'Flat':\n      pVec = P_edge.Vertexes[1].Point - P_edge.Vertexes[0].Point\n      pVec = pVec.normalize()\n      pTanVec = P_node.axis.cross(pVec)\n      if (tan_vec - pTanVec).Length > 1.0:\n        newNode.tan_vec = -pTanVec\n      else:\n        newNode.tan_vec = pTanVec\n\n\n    if newNode.bend_dir == 'up':\n      newNode.k_Factor = 0.65 + 0.5*math.log10(theFace.Surface.Radius/self.__thickness)\n      if newNode.k_Factor < 0:\n        newNode.k_Factor = 0\n        \n      FreeCAD.Console.PrintLog(\"up Face\"+ str(newNode.idx+1)+ \" k-factor: \"+ str(newNode.k_Factor) + \"\\n\")\n      newNode._trans_length = (theFace.Surface.Radius + newNode.k_Factor * self.__thickness/2.0) * newNode.bend_angle\n    else:\n      newNode.k_Factor = 0.65 + 0.5*math.log10((theFace.Surface.Radius - self.__thickness)/self.__thickness)\n      if newNode.k_Factor < 0:\n        newNode.k_Factor = 0\n      FreeCAD.Console.PrintLog(\"down Face\"+ str(newNode.idx+1)+ \" k-factor: \"+ str(newNode.k_Factor) + \"\\n\")\n      newNode._trans_length = (theFace.Surface.Radius - self.__thickness \\\n                                + newNode.k_Factor * self.__thickness/2.0) * newNode.bend_angle\n\n    #print 'newNode._trans_length: ', newNode._trans_length\n    cAngle_0 = self.__Shape.Faces[newNode.c_face_idx].ParameterRange[0]\n    cAngle_1 = self.__Shape.Faces[newNode.c_face_idx].ParameterRange[1]\n    \n    cFaceAngle = cAngle_1 - cAngle_0\n    \n    if newNode.bend_angle > 0:\n      if cFaceAngle > 0:\n        diffAngle = newNode.bend_angle - cFaceAngle\n      else:\n        diffAngle = newNode.bend_angle + cFaceAngle\n    else:\n      if cFaceAngle > 0:\n        diffAngle = cFaceAngle + newNode.bend_angle\n      else:\n        diffAngle = newNode.bend_angle - cFaceAngle\n      \n        \n    #print 'node angles: ', newNode.bend_angle, ' ', diffAngle\n\n\n\n\n\n\n\n  def make_new_face_node(self, face_idx, P_node, P_edge, wires_e_lists):\n    # e_list: list of edges of the top face of a node without the parent-edge (P_edge)\n    # analyze the face and get type of face (\"Flat\" or \"Bend\")\n    # search the counter face, get axis of Face\n    # In case of \"Bend\" get angle, k_factor and trans_length\n    # put the node into the tree\n    newNode = Simple_node(face_idx, P_node, P_edge)\n    F_type = str(self.__Shape.Faces[face_idx].Surface)\n    \n    # This face should be a node in the tree, and is therefore known!\n    # removed from the list of all unknown faces\n    self.index_list.remove(face_idx)\n    # This means, it could also not be found as neighbor face anymore.\n    #newNode.node_faces.append(self.f_list[face_idx].copy())\n    newNode.nfIndexes.append(face_idx)\n    \n    such_list = [] \n    for k in self.index_list:\n      such_list.append(k)\n    \n    if F_type == \"<Plane object>\":\n      newNode.node_type = 'Flat' # fixme\n      FreeCAD.Console.PrintLog(\"Face\"+ str(face_idx+1) + \" Type: \"+ str(newNode.node_type) + \"\\n\")\n\n      s_Posi = self.__Shape.Faces[face_idx].Surface.Position\n      newNode.facePosi = s_Posi\n      s_Ori = self.__Shape.Faces[face_idx].Orientation\n      s_Axis = self.__Shape.Faces[face_idx].Surface.Axis\n      if s_Ori == 'Forward':\n        ext_Vec = Base.Vector(-s_Axis.x, -s_Axis.y, -s_Axis.z)\n      else:                    \n        ext_Vec = Base.Vector(s_Axis.x, s_Axis.y, s_Axis.z)\n\n      newNode.axis = ext_Vec\n      axis_line = Part.makeLine(s_Posi.add(ext_Vec), s_Posi)\n      #Part.show(axis_line, 'axis_line'+str(face_idx+1))\n      \n      # nead a mean point of the face to avoid false counter faces\n      faceMiddle = Base.Vector(0.0,0.0,0.0) # calculating a mean vector\n      for Vvec in self.__Shape.Faces[face_idx].OuterWire.Vertexes:\n          faceMiddle = faceMiddle.add(Vvec.Point)\n      faceMiddle = faceMiddle.multiply(1.0/len(self.__Shape.Faces[face_idx].OuterWire.Vertexes))\n      faceMiddle = faceMiddle.add(self.__thickness * ext_Vec)\n      #Part.show(Part.makeLine(faceMiddle, faceMiddle + 2*ext_Vec), 'faceMiddle'+str(face_idx))\n      \n      counterFaceList = []\n      gotCFace = False\n      # search for the counter face\n      for i in such_list:\n        counter_found = True\n        for F_vert in self.f_list[i].Vertexes:\n          vF_vert = Base.Vector(F_vert.X, F_vert.Y, F_vert.Z)\n          dist_v = vF_vert.distanceToPlane (s_Posi, ext_Vec) - self.__thickness\n          # print \"counter face distance: \", dist_v + self.__thickness\n          #print 'checking Face', str(i+1), ' dist_v: ', dist_v\n          if (dist_v > self.cFaceTol) or (dist_v < -self.cFaceTol):\n              counter_found = False\n  \n        if counter_found:\n          # nead a mean point of the face to avoid false counter faces\n          counterMiddle = Base.Vector(0.0,0.0,0.0) # calculating a mean vector\n          for Vvec in self.__Shape.Faces[i].OuterWire.Vertexes:\n              counterMiddle = counterMiddle.add(Vvec.Point)\n          counterMiddle = counterMiddle.multiply(1.0/len(self.__Shape.Faces[i].OuterWire.Vertexes))\n          \n          distVector = counterMiddle.sub(faceMiddle)\n          counterDistance = distVector.Length\n          \n          if counterDistance < 2*self.__thickness: # small stripes are a risk, fix me!\n            FreeCAD.Console.PrintLog( \"found counter-face\"+ str(i + 1) + \"\\n\")\n            counterFaceList.append([i, counterDistance])\n            gotCFace = True\n          else:\n            counter_found = False\n            FreeCAD.Console.PrintLog(\"faceMiddle: \" + str(faceMiddle) + \" counterMiddle: \"+ str(counterMiddle) + \"\\n\")\n      \n      if gotCFace:\n        newNode.c_face_idx = counterFaceList[0][0]\n        if len(counterFaceList) > 1: # check if more than one counterFace was detected!\n          counterDistance = counterFaceList[0][1]\n          for i in range(1,len(counterFaceList)):\n            if counterDistance > counterFaceList[i][1]:\n              counterDistance = counterFaceList[i][1]\n              newNode.c_face_idx = counterFaceList[i][0]\n        self.index_list.remove(newNode.c_face_idx)\n        newNode.nfIndexes.append(newNode.c_face_idx)\n\n            \n      #if newNode.c_face_idx == None:\n      #  Part.show(axis_line)\n      # if the parent is a bend: check the bend angle and correct it.\n      if newNode.p_node:\n        if newNode.p_node.node_type == 'Bend':\n          if newNode.p_node.p_node.node_type == 'Flat':\n            # calculate the angle on base of ext_Vec\n            ppVec = newNode.p_node.p_node.axis # normal of the flat face\n            myVec = newNode.axis # normal of the flat face\n            theAxis = newNode.p_node.axis # Bend axis\n            angle = math.atan2(ppVec.cross(myVec).dot(theAxis), ppVec.dot(myVec))\n            if angle < -math.pi/8:\n              angle = angle + 2*math.pi\n            #print 'compare angles, bend: ', newNode.p_node.bend_angle, ' ', angle\n            newNode.p_node.bend_angle = angle # This seems to be an improvement!\n            # newNode.p_node.bend_angle = (angle + newNode.p_node.bend_angle) / 2.0 # this is a bad approach\n          \n          # update the newNode.p_node.vertexDict with the Vertex data\n          # from the own vertexes corresponding to the parent edge: P_edge\n          topVertIndexes = range(len(self.__Shape.Faces[face_idx].Vertexes))\n          myFlatVertIndexes = []\n          # for theVert in self.__Shape.Faces[face_idx].Vertexes:\n          for vertIdx in topVertIndexes:\n            theVert = self.__Shape.Faces[face_idx].Vertexes[vertIdx]\n            if equal_vertex(theVert, P_edge.Vertexes[0]):\n              myFlatVertIndexes.append(vertIdx)\n            if equal_vertex(theVert, P_edge.Vertexes[1]):\n              myFlatVertIndexes.append(vertIdx)\n              \n          rotatedFace = self.f_list[face_idx].copy()\n          trans_vec = newNode.p_node.tan_vec * newNode.p_node._trans_length\n          rotatedFace.rotate(self.f_list[newNode.p_node.idx].Surface.Center,newNode.p_node.axis,math.degrees(-newNode.p_node.bend_angle))\n          rotatedFace.translate(trans_vec)\n\n          for vKey in newNode.p_node.vertexDict:\n            flagStr, origVec, unbendVec = newNode.p_node.vertexDict[vKey]\n            #for theVert in myFlatVerts:\n            for vertIdx in myFlatVertIndexes:\n              theVert = self.__Shape.Faces[face_idx].Vertexes[vertIdx]\n              if equal_vector(theVert.Point, origVec):\n                flagStr = flagStr + 'c'\n                newNode.p_node.vertexDict[vKey] = flagStr, origVec, rotatedFace.Vertexes[vertIdx].Point\n\n          # update the newNode.p_node.vertexDict with the Vertex data\n          # from the own vertexes corresponding to the opposite face\n          oppVertIndexes = range(len(self.__Shape.Faces[newNode.c_face_idx].Vertexes))\n          myFlatVertIndexes = []\n          # for theVert in self.__Shape.Faces[face_idx].Vertexes:\n          for vertIdx in oppVertIndexes:\n            theVert = self.__Shape.Faces[newNode.c_face_idx].Vertexes[vertIdx]\n            for cVert in self.__Shape.Faces[newNode.p_node.c_face_idx].Vertexes:\n              if equal_vertex(theVert, cVert):\n                myFlatVertIndexes.append(vertIdx)\n              \n          rotatedFace = self.f_list[newNode.c_face_idx].copy()\n          trans_vec = newNode.p_node.tan_vec * newNode.p_node._trans_length\n          rotatedFace.rotate(self.f_list[newNode.p_node.idx].Surface.Center,newNode.p_node.axis,math.degrees(-newNode.p_node.bend_angle))\n          rotatedFace.translate(trans_vec)\n\n          for vKey in newNode.p_node.vertexDict:\n            flagStr, origVec, unbendVec = newNode.p_node.vertexDict[vKey]\n            #for theVert in myFlatVerts:\n            for vertIdx in myFlatVertIndexes:\n              theVert = self.__Shape.Faces[newNode.c_face_idx].Vertexes[vertIdx]\n              if equal_vector(theVert.Point, origVec):\n                flagStr = flagStr + 'c'\n                newNode.p_node.vertexDict[vKey] = flagStr, origVec, rotatedFace.Vertexes[vertIdx].Point\n\n\n    if F_type == \"<Cylinder object>\":\n      newNode.node_type = 'Bend' # fixme\n      self.bendCounter += 1\n      newNode.bendNumber = self.bendCounter # Assign a number to the bend\n      s_Center = self.__Shape.Faces[face_idx].Surface.Center\n      s_Axis = self.__Shape.Faces[face_idx].Surface.Axis\n      newNode.axis = s_Axis\n      newNode.bendCenter = s_Center\n      edge_vec = P_edge.Vertexes[0].copy().Point\n      FreeCAD.Console.PrintLog(\"edge_vec: \"+ str(edge_vec) + \"\\n\")\n      \n      if P_node.node_type == 'Flat':\n        dist_c = edge_vec.distanceToPlane (s_Center, P_node.axis) # distance to center\n      else:\n        P_face = self.__Shape.Faces[P_node.idx]\n        radVector = radial_vector(edge_vec, P_face.Surface.Center, P_face.Surface.Axis)\n        if P_node.bend_dir == \"down\":\n          dist_c = edge_vec.distanceToPlane (s_Center, radVector.multiply(-1.0))\n        else:\n          dist_c = edge_vec.distanceToPlane (s_Center, radVector)\n          \n      if dist_c < 0.0:\n        newNode.bend_dir = \"down\"\n        thick_test = self.__Shape.Faces[face_idx].Surface.Radius - self.__thickness\n        newNode.innerRadius = thick_test\n        fMiddleFactor = - self.__thickness\n      else:\n        newNode.bend_dir = \"up\"\n        thick_test = self.__Shape.Faces[face_idx].Surface.Radius + self.__thickness\n        newNode.innerRadius = self.__Shape.Faces[face_idx].Surface.Radius\n        fMiddleFactor = self.__thickness\n      newNode.distCenter = thick_test\n      # print \"Face idx: \", face_idx, \" bend_dir: \", newNode.bend_dir\n      FreeCAD.Console.PrintLog(\"Face\" + str(face_idx+1) + \" Type: \" + str(newNode.node_type)+ \" bend_dir: \"+ str(newNode.bend_dir) + \"\\n\")\n\n\n      # calculate mean point of face also for cylindric faces:\n      # nead a mean point of the face to avoid false counter faces\n      faceMiddle = Base.Vector(0.0,0.0,0.0) # calculating a mean vector\n      for Vvec in self.__Shape.Faces[face_idx].OuterWire.Vertexes:\n          thicknessCorrector = fMiddleFactor * radial_vector(Vvec.Point, s_Center, s_Axis)\n          faceMiddle = faceMiddle.add(Vvec.Point + thicknessCorrector)\n      faceMiddle = faceMiddle.multiply(1.0/len(self.__Shape.Faces[face_idx].OuterWire.Vertexes))\n      #Part.show(Part.makeLine(faceMiddle, faceMiddle + 2*ext_Vec), 'faceMiddle'+str(face_idx))\n\n      # Search the face at the opposite site of the sheet:\n      #for i in range(len(such_list)):\n      for i in such_list:\n        counter_found = True\n        for F_vert in self.f_list[i].Vertexes:\n          vF_vert = Base.Vector(F_vert.X, F_vert.Y, F_vert.Z)\n          dist_c = vF_vert.distanceToLine (s_Center, s_Axis) - thick_test\n          if (dist_c > self.cFaceTol) or (dist_c < -self.cFaceTol):\n            counter_found = False\n\n        if counter_found:\n          # calculate mean point of counter face\n          counterMiddle = Base.Vector(0.0,0.0,0.0) # calculating a mean vector\n          for Vvec in self.__Shape.Faces[i].OuterWire.Vertexes:\n              counterMiddle = counterMiddle.add(Vvec.Point)\n          counterMiddle = counterMiddle.multiply(1.0/len(self.__Shape.Faces[i].OuterWire.Vertexes))\n          \n          distVector = counterMiddle.sub(faceMiddle)\n          counterDistance = distVector.Length\n          \n          if counterDistance < 2*self.__thickness: # \n            FreeCAD.Console.PrintLog( \"found counter-face\"+ str(i + 1) + \"\\n\")\n            #print \"found counter Face\", such_list[i]+1\n            newNode.c_face_idx = i\n            self.index_list.remove(i)\n            newNode.nfIndexes.append(i)\n            # Part.show(self.__Shape.Faces[newNode.c_face_idx])\n            break\n          else:\n            counter_found = False\n            FreeCAD.Console.PrintLog(\"faceMiddle: \" + str(faceMiddle) + \" counterMiddle: \"+ str(counterMiddle) + \"\\n\")\n\n\n      if not counter_found:\n        newNode.analysis_ok = False\n        newNode.error_code = 13 # Analysis: counter face not found\n        self.error_code = 13\n        self.failed_face_idx = face_idx\n        FreeCAD.Console.PrintLog(\"No opposite face Debugging Thickness: \"+ str(self.__thickness) + \"\\n\")\n        Part.show(self.__Shape.Faces[face_idx], 'FailedFace'+ str(face_idx + 1) +'_')\n        return newNode\n\n        \n      else:\n        # Need a Vertex from the parent node on the opposite side of the \n        # sheet metal part. This vertex is used to align other vertexes\n        # to the unbended sheet metal plane.\n        # The used vertex should be one of the opposite Face of the parent\n        # node with the closest distance to a line through edge_vec.\n        if P_node.node_type == 'Flat':\n          searchAxis = P_node.axis\n        else:\n          searchAxis = radVector\n              \n        maxDistance = 1000\n        bestPoint = None\n        for theVert in self.__Shape.Faces[P_node.c_face_idx].Vertexes:\n          vertDist = theVert.Point.distanceToLine(edge_vec, searchAxis)\n          if vertDist < maxDistance:\n            maxDistance = vertDist\n            bestPoint = theVert.Point\n             \n        newNode.oppositePoint = bestPoint\n        #Part.show(Part.makeLine(bestPoint, edge_vec), 'bestPoint'+str(face_idx+1)+'_')\n        \n        self.getBendAngle(newNode, wires_e_lists)\n              \n         # As I have learned, that it is necessary to apply corrections to Points / Vertexes,\n        # it will be difficult to have all vertexes of the faces of a bend to fit together.\n        # Therefore a dictionary is introduced, which holds the original coordinates and\n        # the unbend coordinates for the vertexes of the bend. It contains also flags,\n        # indicating if a point is part of the parent node (p) or child node (c), top face (t) or\n        # opposite face (o). All in newNode.vertexDict\n        # Structure: key: Flagstring, Base.Vector(original), Base.Vector(unbend)\n        # The unbend coordinates should be added before processing the top face and the\n        # opposite face in the generateBendShell2 procedure.\n        # Next is to identify for each vertex in the edges the corresponding vertex in \n        # newNode.vertexDict. \n        # Create a dictionary for the unbend edges. The key is a combination of the\n        # vertex indexes. The higher index is shifted 16 bits. simple_node.edgeDict\n        # Next is to unbend the edges, using the points in newNode.vertexDict as\n        # starting and ending vertex.\n        # Store the edge in self.edgeDict and process it to make a wire and a face.\n        #\n        # The side faces uses only the unbend vertexes from newNode.vertexDict,\n        # the edges from self.edgeDict are recycled.\n        # Only new to generate edges may need other vertexes too.\n        vertDictIdx = 0 # Index as key in newNode.vertexDict\n        for theVert in self.__Shape.Faces[face_idx].Vertexes:\n          flagStr = 't'\n          origVec = theVert.Point\n          unbendVec = None\n          if equal_vertex(theVert, P_edge.Vertexes[0]):\n            flagStr = flagStr + 'p0'\n            origVec = P_edge.Vertexes[0].Point\n            unbendVec = origVec\n          else:\n            if equal_vertex(theVert, P_edge.Vertexes[1]):\n              flagStr = flagStr + 'p1'\n              origVec = P_edge.Vertexes[1].Point\n              unbendVec = origVec\n          print 'make vertexDict: ', flagStr, ' ', str(face_idx+1)\n          newNode.vertexDict[vertDictIdx] = flagStr, origVec, unbendVec\n          vertDictIdx += 1\n  \n        for theVert in self.__Shape.Faces[newNode.c_face_idx].Vertexes:\n          flagStr = 'o'\n          origVec = theVert.Point\n          unbendVec = None\n          for pVert in self.__Shape.Faces[P_node.c_face_idx].Vertexes:\n            if equal_vertex(theVert, pVert):\n              flagStr = flagStr + 'p'\n              origVec = pVert.Point\n              unbendVec = origVec\n          print 'make vertexDict: ', flagStr, ' ', str(face_idx+1)\n          newNode.vertexDict[vertDictIdx] = flagStr, origVec, unbendVec\n          vertDictIdx += 1\n      \n    # Part.show(self.__Shape.Faces[newNode.c_face_idx])\n    # Part.show(self.__Shape.Faces[newNode.idx])\n    if newNode.c_face_idx == None:\n      newNode.analysis_ok = False\n      newNode.error_code = 13 # Analysis: counter face not found\n      self.error_code = 13\n      self.failed_face_idx = face_idx\n      FreeCAD.Console.PrintLog(\"No counter-face Debugging Thickness: \"+ str(self.__thickness) + \"\\n\")\n      Part.show(self.__Shape.Faces[face_idx], 'FailedFace'+ str(face_idx + 1) +'_')\n\n\n\n\n    # now we call the new code\n    self.get_node_faces(newNode, wires_e_lists)\n    #for nFace in newNode.nfIndexes:\n    #  Part.show(nFace)\n\n\n    if P_node == None:\n      self.root = newNode\n    else:\n      P_node.child_list.append(newNode)\n    return newNode\n\n\n\n  def Bend_analysis(self, face_idx, parent_node = None, parent_edge = None):\n    # This functions traverses the shape in order to build the bend-tree\n    # For each relevant face a t_node is created and linked into the tree\n    # the linking is done in the call of self.make_new_face_node\n    #print \"Bend_analysis Face\", face_idx +1 ,\n    # analysis_ok = True # not used anymore? \n    # edge_list = []\n    if self.error_code is None:\n      wires_edge_lists = []\n      wire_idx = -1\n      for n_wire in self.f_list[face_idx].Wires:\n        wire_idx += 1\n        wires_edge_lists.append([])\n        #for n_edge in self.__Shape.Faces[face_idx].Edges:\n        for n_edge in n_wire.Edges:\n          if parent_edge:\n            if not parent_edge.isSame(n_edge):\n              #edge_list.append(n_edge)\n              wires_edge_lists[wire_idx].append(n_edge)\n            #\n          else:\n            #edge_list.append(n_edge)\n            wires_edge_lists[wire_idx].append(n_edge)\n      if parent_node:\n        FreeCAD.Console.PrintLog(\" Parent Face\" + str(parent_node.idx + 1) + \"\\n\")\n      FreeCAD.Console.PrintLog(\"The list: \"+ str(self.index_list) + \"\\n\")\n      t_node = self.make_new_face_node(face_idx, parent_node, parent_edge, wires_edge_lists)\n      # Need also the edge_list in the node!\n      FreeCAD.Console.PrintLog(\"The list after make_new_face_node: \" + str(self.index_list) + \"\\n\")\n      \n      # in the new code, only the list of child faces will be analyzed.\n      removalList = []\n      for child_info in t_node.child_idx_lists:\n        if child_info[0] in self.index_list:\n          FreeCAD.Console.PrintLog(\"child in list: \"+ str(child_info[0]) + \"\\n\")\n          self.Bend_analysis(child_info[0], t_node, child_info[1])\n        else:\n          FreeCAD.Console.PrintLog(\"remove child from List: \" + str(child_info[0]) + \"\\n\")\n          t_node.seam_edges.append(child_info[1]) # give Information to the node, that it has a seam.\n          FreeCAD.Console.PrintLog(\"node faces before: \" + str(t_node.nfIndexes) + \"\\n\")\n          # do not make Faces at a detected seam!\n          # self.makeSeamFace(child_info[1], t_node)\n          removalList.append(child_info)\n          FreeCAD.Console.PrintLog(\"node faces with seam: \"+ str(t_node.nfIndexes) + \"\\n\")\n          otherSeamNode = self.searchNode(child_info[0], self.root)\n          FreeCAD.Console.PrintLog(\"counterface on otherSeamNode: Face\" + str(otherSeamNode.c_face_idx+1) + \"\\n\")\n          # do not make Faces at a detected seam!\n          # self.makeSeamFace(child_info[1], otherSeamNode)\n      for seams in removalList:\n        t_node.child_idx_lists.remove(seams)\n    else:\n      FreeCAD.Console.PrintError('got error code: '+ str(self.error_code) + ' at Face'+ str(self.failed_face_idx+1) + \"\\n\")\n      \n\n  \n  \n  def searchNode(self, theIdx, sNode):\n    # search for a Node with theIdx in sNode.idx\n    FreeCAD.Console.PrintLog(\"my Idx: \"+ str(sNode.idx) + \"\\n\")\n\n    if sNode.idx == theIdx:\n      return sNode\n    else:\n      result = None\n      childFaces = []\n      for n_node in sNode.child_list:\n        childFaces.append(n_node.idx)\n      FreeCAD.Console.PrintLog(\"my children: \"+ str(childFaces) + \"\\n\")\n      \n      for n_node in sNode.child_list:\n        nextSearch = self.searchNode(theIdx, n_node)\n        if nextSearch is not None:\n          result = nextSearch\n          break\n    if result<>None:\n      FreeCAD.Console.PrintLog(\"This is the result: \"+ str(result.idx) + \"\\n\")\n    else:\n      FreeCAD.Console.PrintLog(\"This is the result: None\\n\")\n    \n    return result\n    \n    # suche bei mir. wenn ja liefere ab\n    # sonst sind Kinder da?\n    # Wenn Kinder vorhanden, frag solange Kinder bis gefunden\n    # oder kein Kind mehr da.\n\n\n  def rotateVec(self, vec, phi, rAxis):\n    ''' rotate a vector by the angle phi around the axis rAxis'''\n    #https://de.wikipedia.org/wiki/Drehmatrix\n    rVec = rAxis.cross(vec).cross(rAxis).multiply(math.cos(phi)) + rAxis.cross(vec)*math.sin(phi) + rAxis*rAxis.dot(vec) \n    return rVec\n\n\n  def unbendFace(self, fIdx, bend_node, nullVec, mode = 'side'):\n    '''\n    The self.vertexDict requires a further data structure to hold for\n    each edge in a list the point indexes to the vertexes of the bend node.\n    key: Index to myEdgeList, content: List of indexes to the self.vertexDict.\n    '''\n    \n    axis = bend_node.axis\n    cent = bend_node.bendCenter\n    bRad = bend_node.innerRadius\n    kFactor = bend_node.k_Factor\n    thick = self.__thickness\n    transRad = bRad + kFactor * thick/2.0\n    #print 'transRad Face', str(fIdx+1), ' ', bRad, ' ', kFactor, ' ', thick\n    tanVec = bend_node.tan_vec\n    aFace = self.f_list[fIdx]\n    \n    normVec = radial_vector(bend_node.p_edge.Vertexes[0].Point, cent, axis)\n    \n    if mode == 'top':\n      chord = cent.sub(bend_node.p_edge.Vertexes[0].Point)\n      norm = axis.cross(chord)\n      compRadialVec = axis.cross(norm)\n\n\n    if mode == 'counter':\n      chord = cent.sub(bend_node.oppositePoint)\n      norm = axis.cross(chord)\n      compRadialVec = axis.cross(norm)\n\n\n    def unbendPoint(poi):\n      radVec = radial_vector(poi, cent, axis)\n      angle = math.atan2(nullVec.cross(radVec).dot(axis), nullVec.dot(radVec))\n      #print 'point Face', str(fIdx+1), ' ', angle\n      if angle < -math.pi/8:\n        angle = angle + 2*math.pi\n      rotVec = self.rotateVec(poi.sub(cent), -angle, axis)\n      #print 'point if Face', str(fIdx+1), ' ', angle, ' ', transRad*angle\n      if (mode == 'top') or (mode == 'counter'):\n        chord = cent.sub(cent + rotVec)\n        norm = axis.cross(chord)\n        correctionVec = compRadialVec.sub(axis.cross(norm))\n        #correctionVec = axis.cross(norm).sub(compRadialVec)\n        #print 'origVec ', axis.cross(norm), ' compRadialVec ', compRadialVec\n        bPoint = cent + rotVec + correctionVec + tanVec*transRad*angle\n      else:\n        bPoint = cent + rotVec + tanVec*transRad*angle\n      \n      return bPoint\n    \n    divisions = 12 # fix me! need a dependence on something useful.\n    \n    \n    fWireList = aFace.Wires[:]\n    #newWires = []\n    edgeLists = []\n\n    for aWire in fWireList:\n        uEdge = None\n        idxList, closedW = self.sortEdgesTolerant(aWire.Edges, fIdx)\n        print 'Wire', str(fIdx+1), ' has ', len(idxList), ' edges, closed: ', closedW\n        \n        eList = []  # is the list of unbend edges\n        j=0\n        for fEdgeIdx in idxList:\n          fEdge = aWire.Edges[fEdgeIdx]\n          eType = str(fEdge.Curve)\n          vertexCount = len(fEdge.Vertexes)\n          #print \"the type of curve: \", eType\n          vert0 = None\n          vert1 = None\n          flags0 = None\n          flags1 = None\n          uVert0 = None\n          uVert1 = None\n          edgeKey = None\n          vert0Idx = None\n          vert1Idx = None\n          \n          #print 'edge vertexes: ', str(fIdx+1), ' ', mode, ' ', fEdge.Vertexes[0].Point, ' ', fEdge.Vertexes[1].Point\n          for oVertIdx in bend_node.vertexDict:\n            flagStr, origVec, unbendVec = bend_node.vertexDict[oVertIdx]\n            #print 'origVec: ', origVec\n            if equal_vector(fEdge.Vertexes[0].Point, origVec,5):\n              vert0Idx = oVertIdx\n              flags0 = flagStr\n              uVert0 = unbendVec\n            if vertexCount > 1:\n              if equal_vector(fEdge.Vertexes[1].Point, origVec,5):\n                vert1Idx = oVertIdx\n                flags1 = flagStr\n                uVert1 = unbendVec\n            # can we break the for loop at some condition?\n          # Handle cases, where a side face has additional vertexes\n          if mode == 'side':\n            if vert0Idx is None:\n              vert0Idx = len(bend_node.vertexDict)\n              print 'got additional side vertex0: ', vert0Idx, ' ', fEdge.Vertexes[0].Point\n              flags0 = ''\n              origVec = fEdge.Vertexes[0].Point\n              uVert0 = unbendPoint(origVec)\n              bend_node.vertexDict[vert0Idx] = flags0, origVec, uVert0\n            if vertexCount >1:\n              if vert1Idx is None:\n                vert1Idx = len(bend_node.vertexDict)\n                print 'got additional side vertex1: ', vert1Idx, ' ', fEdge.Vertexes[1].Point\n                flags1 = ''\n                origVec = fEdge.Vertexes[1].Point\n                uVert1 = unbendPoint(origVec)\n                bend_node.vertexDict[vert1Idx] = flags1, origVec, uVert1\n\n\n          # make the key for bend_node.edgeDict, shift vert1 and add both.\n          if vert0Idx is None:\n            #print 'catastrophy: ', fEdge.Vertexes[0].Point, ' ', fEdge.Vertexes[1].Point, ' ', eType\n            Part.show(fEdge, 'catastrophyEdge')\n            # fix me, need proper failure mode.\n          if vert1Idx:\n            if vert1Idx < vert0Idx:\n              edgeKey = vert0Idx + (vert1Idx << 8)\n            else:\n              edgeKey = vert1Idx + (vert0Idx << 8)\n            # x << n: x shifted left by n bits = Multiplication\n          else:\n            edgeKey = vert0Idx\n            \n          #print 'edgeKey: ', edgeKey, ' ', str(fIdx+1), ' ', mode, ' ', uVert0, ' ', uVert1\n          \n          urollPts = []\n          \n          if (\"<Ellipse object>\" in eType):\n            minPar, maxPar = fEdge.ParameterRange\n            FreeCAD.Console.PrintLog(\"the Parameterrange: \"+ str(minPar)+ \" to \" + str(maxPar)+ \" Type: \"+str(eType) + \"\\n\")\n            \n            # compare minimal 1/curvature with curve-lenght to decide on division\n            iMulti = (maxPar-minPar)/24\n            maxCurva = 0.0\n            for i in range(24):\n              posi = fEdge.valueAt(minPar + i*iMulti)\n              # print 'testEdge ', i, ' curva: ' , testEdge.Curve.curvature(minPar + i*iMulti)\n              curva = fEdge.Curve.curvature(minPar + i*iMulti)\n              if curva > maxCurva:\n                maxCurva = curva\n            \n            decisionAngle = fEdge.Length * maxCurva\n            # print 'Face', str(fIdx+1), ' EllidecisionAngle: ', decisionAngle\n            # Part.show(fEdge, 'EllideciAng'+str(decisionAngle)+ '_')\n            \n            if decisionAngle < 0.1:\n              eDivisions = 4\n            elif decisionAngle < 0.5:\n              eDivisions = 6\n            else:\n              eDivisions = 12\n            \n            iMulti = (maxPar-minPar)/eDivisions\n            urollPts.append(uVert0)\n            for i in range(1,eDivisions):\n              posi = fEdge.valueAt(minPar + i*iMulti)\n              bPosi = unbendPoint(posi)\n              urollPts.append(bPosi)\n            urollPts.append(uVert1)\n            \n            uCurve = Part.BSplineCurve()\n            uCurve.interpolate(urollPts)\n            uEdge = uCurve.toShape()\n            #Part.show(uEdge, 'Elli'+str(j)+'_')\n     \n          elif \"<Line\" in eType:\n            #print 'j: ',j , ' eType: ', eType, ' fIdx: ', fIdx, ' verts: ', fEdge.Vertexes[0].Point, ' ', fEdge.Vertexes[1].Point\n            #Part.show(fEdge)\n            #print 'unbend Line: ', uVert0, ' ', uVert1\n            uEdge = Part.makeLine(uVert0, uVert1)\n            #Part.show(uEdge, 'Line'+str(j)+'_')\n    \n          elif \"Circle\" in eType:  #fix me! need to check if circle ends are at different radii!\n            FreeCAD.Console.PrintLog('j: '+ str(j) + ' eType: '+ str(eType) + '\\n')\n            parList = fEdge.ParameterRange\n            #print \"the Parameterrange: \", parList[0], \" , \", parList[1], \" Type: \",eType\n            #axis_line = Part.makeLine(cent, cent + axis)\n            #Part.show(axis_line, 'axis_line'+ str(bend_node.idx+1)+'_')\n            #print 'Face', str(bend_node.idx+1), 'bAxis: ', axis, ' cAxis: ', fEdge.Curve.Axis\n            uEdge = Part.makeLine(uVert0, uVert1)\n            #Part.show(uEdge, 'CircleLine'+str(j)+'_')\n    \n          elif (\"<BSplineCurve object>\" in eType) or (\"<BezierCurve object>\" in eType):\n            minPar, maxPar = fEdge.ParameterRange\n            #print \"the Parameterrange: \", minPar, \" - \", maxPar, \" Type: \",eType\n            \n            # compare minimal 1/curvature with curve-lenght to decide on division\n            iMulti = (maxPar-minPar)/24\n            maxCurva = 0.0\n            testPts = []\n            for i in range(24+1):\n              posi = fEdge.valueAt(minPar + i*iMulti)\n              bPosi = unbendPoint(posi)\n              testPts.append(bPosi)\n            testCurve = Part.BSplineCurve()\n            testCurve.interpolate(testPts)\n            testEdge = testCurve.toShape()\n\n            for i in range(24+1):\n              posi = testEdge.valueAt(minPar + i*iMulti)\n              # print 'testEdge ', i, ' curva: ' , testEdge.Curve.curvature(minPar + i*iMulti)\n              curva = testEdge.Curve.curvature(minPar + i*iMulti)\n              if curva > maxCurva:\n                maxCurva = curva\n            \n            decisionAngle = testEdge.Length * maxCurva\n            #print 'Face', str(fIdx+1), ' decisionAngle: ', decisionAngle\n            #Part.show(testEdge, 'deciAng'+str(decisionAngle)+ '_')\n            \n            if decisionAngle > 1000.0:\n              bDivisions = 4\n            else:\n              bDivisions = 12\n\n            iMulti = (maxPar-minPar)/bDivisions\n            if vertexCount > 1:\n              urollPts.append(uVert0)\n              for i in range(1,bDivisions):\n                posi = fEdge.valueAt(minPar + i*iMulti)\n                # curvature is 1/radius\n                #print 'Face', str(fIdx+1), ' 1/Curvature: ', 1/fEdge.Curve.curvature(minPar + i*iMulti), ' ', fEdge.Length\n                bPosi = unbendPoint(posi)\n                urollPts.append(bPosi)\n              urollPts.append(uVert1)\n            else:\n              urollPts.append(uVert0)\n              for i in range(1,bDivisions):\n                posi = fEdge.valueAt(minPar + i*iMulti)\n                bPosi = unbendPoint(posi)\n                urollPts.append(bPosi)\n              urollPts.append(uVert0)\n            #testPoly = Part.makePolygon(urollPts)\n            #Part.show(testPoly, 'testPoly'+ str(fIdx+1) + '_')\n            uCurve = Part.BSplineCurve()\n            try:\n              uCurve.interpolate(urollPts)\n              uEdge = uCurve.toShape()\n              #Part.show(theCurve, 'B_spline')\n            except:\n              #uEdge =  Part.makeLine(urollPts[0], urollPts[-1])\n              if bDivisions == 4:\n                uCurve.interpolate([urollPts[0], urollPts[2], urollPts[-1]])\n              if bDivisions == 12:\n                uCurve.interpolate([urollPts[0],urollPts[3],urollPts[6],urollPts[9], urollPts[-1]])\n              uEdge = uCurve.toShape()\n          else:\n            #print 'unbendFace, curve type not handled: ' + str(eType) + ' in Face' + str(fIdx+1)\n            FreeCAD.Console.PrintLog('unbendFace, curve type not handled: ' + str(eType) + ' in Face' + str(fIdx+1) + '\\n')\n            self.error_code = 26\n            self.failed_face_idx = fIdx\n          \n          # in mode 'side' check, if not the top or counter edge can be used instead.\n          if mode == 'side':\n            if edgeKey in bend_node.edgeDict:\n              uEdge = bend_node.edgeDict[edgeKey]\n              #print 'found key in node.edgeDict: ', edgeKey, ' in mode: ', mode\n          #Part.show(uEdge, 'bendEdge'+str(fIdx+1)+'_')\n          eList.append(uEdge)\n          if not (edgeKey in bend_node.edgeDict):\n            bend_node.edgeDict[edgeKey] = uEdge\n            #print 'added key: ', edgeKey, ' to edgeDict in mode: ', mode\n          j += 1\n        edgeLists.append(eList)\n    # end of for what?\n    \n    # Here we store the unbend top and counter outer edge list in the node data.\n    # These are needed later as edges in the new side faces. \n    if mode == 'top':\n      bend_node.unfoldTopList = edgeLists[0]\n    if mode == 'counter':\n      bend_node.unfoldCounterList = edgeLists[0]\n    \n    \n    if len(edgeLists) == 1:\n      eList = Part.__sortEdges__(edgeLists[0])\n      myWire = Part.Wire(eList)\n      FreeCAD.Console.PrintLog('len eList: '+ str(len(eList)) + '\\n')\n      #Part.show(myWire, 'Wire_Face'+str(fIdx+1)+'_' )\n      if (len(myWire.Vertexes) == 2) and (len(myWire.Edges) == 3):\n        #print 'got sweep condition!'\n        pWire = Part.Wire(myWire.Edges[1])\n        fWire = Part.Wire(myWire.Edges[0]) # first sweep profile\n        lWire = Part.Wire(myWire.Edges[2]) # last sweep profile\n        theFace = pWire.makePipeShell([fWire, lWire], False, True)\n        theFace = theFace.Faces[0]\n        #Part.show(theFace, 'Loch')\n      else:\n        try:\n            #Part.show(myWire, 'myWire'+ str(bend_node.idx+1)+'_')\n            theFace = Part.Face(myWire)\n            #theFace = Part.makeFace(myWire, 'Part::FaceMakerSimple')\n        except:\n            FreeCAD.Console.PrintLog('got exception at Face: '+ str(fIdx+1) +' len eList: '+ str(len(eList)) + '\\n')\n            #for w in eList:\n              #Part.show(w, 'exceptEdge')\n              #print 'exception type: ', str(w.Curve)\n            #Part.show(myWire, 'exceptionWire'+ str(fIdx+1)+'_')\n            secWireList = myWire.Edges[:]\n            thirdWireList = Part.__sortEdges__(secWireList)\n            theFace = Part.makeFilledFace(thirdWireList)\n        #Part.show(theFace, 'theFace'+ str(bend_node.idx+1)+'_')\n    else:\n      FreeCAD.Console.PrintLog('len edgeLists: '+ str(len(edgeLists))+'\\n')\n      faces = []\n      wires = []\n      wireNumber = 0\n      for w in edgeLists:\n        eList = Part.__sortEdges__(w)\n        #print 'eList: ', eList\n        if wireNumber < 0:\n          #myWire = Part.Wire(eList.reverse())\n          reversList = []\n          for e in eList:\n            reversList.insert(0,e)\n          myWire = Part.Wire(reversList)\n        else:\n          myWire = Part.Wire(eList)\n        #Part.show(myWire, 'myWire'+ str(bend_node.idx+1)+'_')\n        nextFace = Part.Face(myWire)\n        faces.append(nextFace)\n        wires.append(myWire)\n        wireNumber += 1\n        #Part.show(Part.Face(myWire))\n      try:\n          #theFace = Part.Face(wires)\n          #print 'make cutted face\\n' \n          theFace = faces[0].copy()\n          for f in faces[1:]:\n            f.translate(-normVec)\n            cutter= f.extrude(2*normVec)\n            theFace = theFace.cut(cutter)\n            theFace = theFace.Faces[0]\n          #Part.show(theFace, 'theFace')\n          #theFace = Part.Face(wires[0], wires[1:])\n          #theFace = Part.makeFace(myWire, 'Part::FaceMakerSimple')\n      except:\n          #theFace = Part.makeFilledFace(wires)\n          theFace = faces[0]\n          print 'got execption'\n          #Part.show(theFace, 'exception')\n    keyList = []\n    for key in bend_node.edgeDict:\n      keyList.append(key)\n    #print 'edgeDict keys: ', keyList\n    #Part.show(theFace, 'unbendFace'+str(fIdx+1))\n    return theFace\n\n  def sortEdgesTolerant(self, myEdgeList, fIdx = None):\n    '''\n    sort edges from an existing wire.\n    returns:\n      a new sorted list of indexes to edges of the original wire\n      flag if wire is closed or not (a wire of a cylinder mantle is not closed!)\n    '''\n    eIndex = 0 \n    newEdgeList = []\n    idxList = range(len(myEdgeList))\n    newIdxList = [eIndex]\n    newEdgeList.append(myEdgeList[eIndex])\n    idxList.remove(eIndex)\n    gotConnection = False\n    closedWire = False\n    \n    startVert  = myEdgeList[eIndex].Vertexes[0]\n    if len(myEdgeList[eIndex].Vertexes) > 1:\n      vert = myEdgeList[eIndex].Vertexes[1]\n    else:\n      vert = myEdgeList[eIndex].Vertexes[0]\n    #Part.show(myEdgeList[0], 'tolEdge'+str(1)+'_')\n    while not gotConnection:\n      foundConnection = False\n      for eIdx in idxList:\n        edge = myEdgeList[eIdx]\n        if equal_vertex(vert, edge.Vertexes[0]):\n          idxList.remove(eIdx)\n          eIndex = eIdx\n          #print 'found eIdx: ', eIdx\n          newIdxList.append(eIdx)\n          if len(edge.Vertexes) > 1:\n            vert = edge.Vertexes[1]\n          foundConnection = True\n          break\n        if len(edge.Vertexes) > 1:\n          if equal_vertex(vert, edge.Vertexes[1]):\n            idxList.remove(eIdx)\n            eIndex = eIdx\n            #print 'found eIdx: ', eIdx\n            newIdxList.append(eIdx)\n            vert = edge.Vertexes[0]\n            foundConnection = True\n            break\n      if (len(idxList) == 0):\n        gotConnection = True \n      else:\n        if not foundConnection:\n          gotConnection = True\n          self.error_code = 27  # Unfold: could not sort Wire\n          self.failed_face_idx = fIdx\n      if equal_vertex(vert, startVert):\n        #print 'got last connection'\n        gotConnection = True\n        closedWire = True\n      #Part.show(myEdgeList[eIdx], 'tolEdge'+str(eIdx+1)+'_')\n    #print 'tolerant wire: ', len(myEdgeList)\n    return newIdxList, closedWire\n    \n\n  def makeFoldLines(self, bend_node, nullVec):\n    axis = bend_node.axis\n    cent = bend_node.bendCenter\n    bRad = bend_node.innerRadius\n    kFactor = bend_node.k_Factor\n    thick = self.__thickness\n    transRad = bRad + kFactor * thick/2.0\n    tanVec = bend_node.tan_vec\n    theFace = self.f_list[bend_node.idx]\n    \n    angle_0 = theFace.ParameterRange[0]\n    angle_1 = theFace.ParameterRange[1]\n    length_0 = theFace.ParameterRange[2]\n    \n    halfAngle = (angle_0 + angle_1) / 2\n    bLinePoint0 = theFace.valueAt(halfAngle,length_0)\n    #bLinePoint1 = theFace.valueAt(halfAngle,length_1)\n    normVec = radial_vector(bLinePoint0, cent, axis)\n    sliceVec = normVec.cross(axis)\n    origin = Base.Vector(0.0,0.0,0.0)\n    distance = origin.distanceToPlane(bLinePoint0, sliceVec)\n    testDist = -bLinePoint0.distanceToPlane(sliceVec * distance, sliceVec)\n    if math.fabs(testDist) > math.fabs(distance):\n      sliceVec = -sliceVec\n    \n    \n    #Part.show(Part.makePolygon([origin,sliceVec * distance]), 'distance') \n    #print 'distance: ', distance, ' testDist: ', testDist\n    wires = []\n    for i in theFace.slice(sliceVec, distance):\n      wires.append(i)\n    #print 'got ', len(wires), ' wires'\n    #Part.show(Part.Compound(wires), 'slice')\n    theComp = Part.Compound(wires)\n    # fix me, what if there are no wires?\n    wireList =[]\n     \n    for fEdge in theComp.Edges:\n      eType = str(fEdge.Curve)\n      #print \"the type of curve: \", eType\n      urollPts = []\n\n      if \"<Line\" in eType:\n        for lVert in fEdge.Vertexes:\n          posi = lVert.Point\n          radVec = radial_vector(posi, cent, axis)\n          angle = math.atan2(nullVec.cross(radVec).dot(axis), nullVec.dot(radVec))\n          if angle < 0:\n            angle = angle + 2*math.pi\n          rotVec = self.rotateVec(posi.sub(cent), -angle, axis)\n          \n          bPosi = cent + rotVec + tanVec*transRad*angle\n          \n          urollPts.append(bPosi)\n        edgeL = Part.makeLine(urollPts[0], urollPts[1])\n        lWire = Part.Wire([edgeL])\n        wireList.append(edgeL)\n        #Part.show(lWire, 'foldLine'+str(bend_node.idx +1)+'_')\n      else:\n        print 'fix me! make errorcondition'\n        \n    bend_node.foldVertex1 = wireList[0].Vertexes[0]\n    bend_node.foldVertex2 = wireList[-1].Vertexes[1]\n    \n    return wireList\n  \n  def unbendVertDict(self, bend_node, cent, axis, nullVec):\n    '''\n    calculate the unbend points in the vertexDict.\n    This is called with the vertexes of the top and the opposite face only.\n    '''\n    def unbendDictPoint(poi, compRadialVec):\n      radVec = radial_vector(poi, cent, axis)\n      angle = math.atan2(nullVec.cross(radVec).dot(axis), nullVec.dot(radVec))\n      #print 'point Face', str(fIdx+1), ' ', angle\n      if angle < -math.pi/8:\n        angle = angle + 2*math.pi\n      rotVec = self.rotateVec(poi.sub(cent), -angle, axis)\n      chord = cent.sub(cent + rotVec)\n      norm = axis.cross(chord)\n      correctionVec = compRadialVec.sub(axis.cross(norm))\n      #print 'origVec ', axis.cross(norm), ' compRadialVec ', compRadialVec\n      bPoint = cent + rotVec + correctionVec + tanVec*transRad*angle\n      return bPoint\n\n    thick = self.__thickness\n    transRad = bend_node.innerRadius + bend_node.k_Factor * thick/2.0\n    tanVec = bend_node.tan_vec\n\n    chord = cent.sub(bend_node.p_edge.Vertexes[0].Point)\n    norm = axis.cross(chord)\n    topCompRadialVec = axis.cross(norm)\n\n    chord = cent.sub(bend_node.oppositePoint)\n    norm = axis.cross(chord)\n    oppCompRadialVec = axis.cross(norm)\n      \n    for i in bend_node.vertexDict:\n      flagStr, origVec, unbendVec = bend_node.vertexDict[i]\n      if (not ('p' in flagStr)) and (not ('c' in flagStr)):\n        if 't' in flagStr:\n          unbendVec = unbendDictPoint(origVec, topCompRadialVec)\n        else:\n          unbendVec = unbendDictPoint(origVec, oppCompRadialVec)\n        #print 'unbendDictPoint for ', flagStr\n        bend_node.vertexDict[i] = flagStr, origVec, unbendVec\n        \n    #for i in bend_node.vertexDict:\n      #flagStr, origVec, unbendVec = bend_node.vertexDict[i]\n      #print 'vDict Face', str(bend_node.idx+1), ' ', i, ' ', flagStr, ' ', origVec, ' ', unbendVec\n          \n  def generateBendShell2(self, bend_node):\n    '''\n    This function takes a cylindrical bend part of sheet metal and \n    returns a flat version of that bend part.\n    '''\n    theCenter = bend_node.bendCenter   # theCyl.Surface.Center\n    theAxis = bend_node.axis           # theCyl.Surface.Axis\n    # theRadius = theCyl.Surface.Radius # need to include the k-Factor\n    \n    zeroVert = bend_node.p_edge.Vertexes[0]\n    nullVec = radial_vector(zeroVert.Point, theCenter, theAxis)\n    #nullVec_line = Part.makeLine(theCenter, theCenter + nullVec*bend_node.innerRadius)\n    #Part.show(nullVec_line, 'nullVec_line'+ str(bend_node.idx+1)+'_')\n    #tanVec_line = Part.makeLine(zeroVert.Point, zeroVert.Point + bend_node.tan_vec*bend_node.innerRadius)\n    #Part.show(tanVec_line, 'tanVec_line'+ str(bend_node.idx+1)+'_')\n    \n    # calculate the unbend points in the bend_ node.vertexDict\n    self.unbendVertDict(bend_node, theCenter, theAxis, nullVec)\n    \n    \n    bendFaceList = bend_node.nfIndexes[:]\n    bendFaceList.remove(bend_node.idx)\n    bendFaceList.remove(bend_node.c_face_idx)\n    \n    flat_shell = []\n    flat_shell.append(self.unbendFace(bend_node.idx, bend_node, nullVec, 'top') )\n    flat_shell.append(self.unbendFace(bend_node.c_face_idx, bend_node, nullVec, 'counter') )\n    \n    \n    for i in bendFaceList:\n      bFace = self.unbendFace(i, bend_node, nullVec)\n      flat_shell.append(bFace)\n      #Part.show(bFace, 'bFace'+str(i +1))\n      #for v in bFace.Vertexes:\n      #  print 'Face'+str(i+1) + ' ' + str(v.X) + ' ' + str(v.Y) + ' ' + str(v.Z)\n\n    foldwires = self.makeFoldLines(bend_node, nullVec)\n    #print 'face idx: ', bend_node.idx +1, ' folds: ', foldwires\n    return flat_shell, foldwires\n\n\n  def makeSeamFace(self, sEdge, theNode):\n    ''' This function creates a face at a seam of the sheet metal.\n    It works currently only at a flat node.\n    '''\n    FreeCAD.Console.PrintLog(\"now make a seam Face\\n\")\n    nextVert = sEdge.Vertexes[1]\n    startVert = sEdge.Vertexes[0]\n    start_idx = 0\n    end_idx = 1\n    \n    search_List = theNode.nfIndexes[:]\n    FreeCAD.Console.PrintLog(\"This is the search_List: \" + str(search_List) + \"\\n\")\n    search_List.remove(theNode.idx)\n    the_index = None\n    next_idx = None\n    for i in search_List:\n      for theEdge in self.f_list[i].Edges:\n        if len(theEdge.Vertexes)>1:\n          if equal_vertex(theEdge.Vertexes[0], nextVert):\n            next_idx = 1\n          if equal_vertex(theEdge.Vertexes[1], nextVert):\n            next_idx = 0\n          if next_idx is not None:\n            if self.isVertOpposite(theEdge.Vertexes[next_idx], theNode):\n              nextEdge = theEdge.copy()\n              search_List.remove(i)\n              the_index = i\n              #Part.show(nextEdge)\n              break\n            else:\n              next_idx = None\n      if the_index is not None:\n        break\n\n    #find the lastEdge\n    last_idx = None\n    FreeCAD.Console.PrintLog(\"This is the search_List: \"+ str(search_List) + \"\\n\")\n    for i in search_List:\n      #Part.show(self.f_list[i])\n      for theEdge in self.f_list[i].Edges:\n        FreeCAD.Console.PrintLog(\"find last Edge in Face: \"+ str(i)+ \" at Edge: \"+ str(theEdge) + \"\\n\")\n        if len(theEdge.Vertexes)>1:\n          if equal_vertex(theEdge.Vertexes[0], startVert):\n            last_idx = 1\n          if equal_vertex(theEdge.Vertexes[1], startVert):\n            last_idx = 0\n          if last_idx is not None:\n            FreeCAD.Console.PrintLog(\"test for the last Edge\\n\")\n            if self.isVertOpposite(theEdge.Vertexes[last_idx], theNode):\n              lastEdge = theEdge.copy()\n              search_List.remove(i)\n              the_index = i\n              #Part.show(lastEdge)\n              break\n            else:\n              last_idx = None\n      if last_idx is not None:\n        break\n        \n    # find the middleEdge\n    mid_idx = None\n    midEdge = None\n    for theEdge in self.f_list[theNode.c_face_idx].Edges:\n      if len(theEdge.Vertexes)>1:\n        if equal_vertex(theEdge.Vertexes[0], nextEdge.Vertexes[next_idx]):\n          mid_idx = 1\n        if equal_vertex(theEdge.Vertexes[1], nextEdge.Vertexes[next_idx]):\n          mid_idx = 0\n        if mid_idx is not None:\n          if equal_vertex(theEdge.Vertexes[mid_idx], lastEdge.Vertexes[last_idx]):\n            midEdge = theEdge.copy()\n            #Part.show(midEdge)\n            break\n          else:\n            mid_idx = None\n      if midEdge:\n        break\n\n    seam_wire = Part.Wire([sEdge, nextEdge, midEdge, lastEdge ])\n    seamFace = Part.Face(seam_wire)\n    self.f_list.append(seamFace)\n    theNode.nfIndexes.append(self.max_f_idx)\n    self.max_f_idx += 1\n\n\n  def showFaces(self):\n    for i in self.index_list:\n      Part.show(self.f_list[i])\n\n\n  def unfold_tree2(self, node):\n    # This function traverses the tree and unfolds the faces \n    # beginning at the outermost nodes.\n    #print \"unfold_tree face\", node.idx + 1\n    theShell = []\n    nodeShell = []\n    theFoldLines = []\n    nodeFoldLines = []\n    drawingVerts = [] # Vertexes to assign bendnumbers in a drawing\n    nodeVerts = []    # new vertexes from this node\n    for n_node in node.child_list:\n      if self.error_code == None:\n        shell, foldLines, verts = self.unfold_tree2(n_node)\n        theShell = theShell + shell\n        theFoldLines = theFoldLines + foldLines\n        drawingVerts = drawingVerts + verts\n    if node.node_type == 'Bend':\n      trans_vec = node.tan_vec * node._trans_length\n      for bFaces in theShell:\n        bFaces.rotate(self.f_list[node.idx].Surface.Center,node.axis,math.degrees(-node.bend_angle))\n        bFaces.translate(trans_vec)\n      for fold in theFoldLines:\n        fold.rotate(self.f_list[node.idx].Surface.Center,node.axis,math.degrees(-node.bend_angle))\n        fold.translate(trans_vec)\n      for dVert in drawingVerts:\n        dVert.rotate(self.f_list[node.idx].Surface.Center,node.axis,math.degrees(-node.bend_angle))\n        dVert.translate(trans_vec)\n      if self.error_code == None:\n        #nodeShell = self.generateBendShell(node)\n        nodeShell, nodeFoldLines = self.generateBendShell2(node)\n        nodeVerts.append(node.foldVertex1)\n        nodeVerts.append(node.foldVertex2)\n    else:\n      if self.error_code == None:\n        # nodeShell = self.generateShell(node)\n        for idx in node.nfIndexes:\n          nodeShell.append(self.f_list[idx].copy())\n        #if len(node.seam_edges)>0:\n        #  for seamEdge in node.seam_edges:\n        #    self.makeSeamFace(seamEdge, node)\n    FreeCAD.Console.PrintLog(\"ufo finish face\" + str(node.idx +1) + \"\\n\")\n    return (theShell + nodeShell, theFoldLines + nodeFoldLines, drawingVerts + nodeVerts)\n\n\n\n  def prepareDrawing(self, folds, ufoShape):\n\n    import Draft, Spreadsheet\n\n    def traversNodeNumbers(node):\n      for n_node in node.child_list:\n        traversNodeNumbers(n_node)\n      if node.node_type == 'Bend':\n        textVert = node.foldVertex1\n        if doRotate:\n          textVert.rotate(self.root.facePosi,theAxis,math.degrees(-angle))\n        textVert.translate(-self.root.facePosi)\n\n        text = Draft.makeText([str(node.bendNumber)],point=textVert.Point)\n        text.Label = 'Bend' + str(node.bendNumber)\n        bNums.addObject(text)\n        text.ViewObject.FontSize = 5\n        text.ViewObject.TextColor = (0.00,1.00,0.00) #green color\n        radiusQuantity = FreeCAD.Units.parseQuantity(str(node.innerRadius)+' mm')\n        radiusUnit = radiusQuantity.UserString.split(' ')[1]\n        mySheet.set('A'+str(node.bendNumber+1), str(node.bendNumber))\n        mySheet.set('B'+str(node.bendNumber+1), str(node.innerRadius)+' mm')\n        mySheet.setDisplayUnit('B'+str(node.bendNumber+1), radiusUnit)\n        mySheet.set('C'+str(node.bendNumber+1), node.bend_dir)\n        mySheet.set('D'+str(node.bendNumber+1), str(node.k_Factor/2.0)) \n\n\n    # calculate the rotation in order to place the drawing data into the xy-plane\n    planeVec = Base.Vector(0.0, 0.0, 1.0) # normal of the xy-plane\n    if (not equal_vector(self.root.axis, planeVec)) and (not equal_vector(self.root.axis, -planeVec)):\n      myVec = self.root.axis # normal of the first face = normal of drawing data\n      theAxis = planeVec.cross(myVec) # rotation axis\n      angle = math.atan2(planeVec.cross(myVec).dot(theAxis), planeVec.dot(myVec))\n      doRotate = True\n    else:\n      theAxis = Base.Vector(1.0, 0.0, 0.0)\n      angle = 0.0\n      doRotate = False\n    # calculate the translation in order to place the drawing data into the xy-plane\n    transVec = self.root.facePosi\n    #print ('Posi '+ str(self.root.facePosi)+ ' Axis '+ str(theAxis)+ ' angle '+ str(angle))\n    \n    if doRotate:\n      #print ('Posi ', self.root.facePosi, ' Axis ', theAxis, ' angle ', angle)\n      folds.rotate(self.root.facePosi,theAxis,math.degrees(-angle))\n    folds.translate(-self.root.facePosi)\n\n\n\n    bLines = Draft.makeVisGroup(name=\"BEND\")\n    Draft.autogroup(bLines)\n    bLines.ViewObject.LineColor = (1.00,0.00,0.00) #red color\n    bLines.Group = []\n    fLineObject = self.theDoc.addObject(\"Part::Feature\")\n    fLineObject.Label = 'Bendlines'\n    fLineObject.Shape = folds\n    bLines.addObject(fLineObject)\n\n    mySheet = self.theDoc.addObject('Spreadsheet::Sheet','Bendtable')\n    mySheet.set('A1', 'Bendlabel')\n    mySheet.set('B1', 'Radius')\n    mySheet.set('C1', 'Direction')\n    mySheet.set('D1', 'k-Factor')\n\n\n    bNums = Draft.makeVisGroup(name=\"Bendlabels\")\n    Draft.autogroup(bLines)\n    traversNodeNumbers(self.root)\n\n    #search for the top face in the ufoShape\n    faceList = []\n    gotFace = False\n    such_list = list(range(len(ufoShape.Faces)))\n    # search for the top face\n    for i in such_list:\n      face_found = True\n      for F_vert in ufoShape.Faces[i].Vertexes:\n        #vF_vert = F_vert.Point\n        dist_v = F_vert.Point.distanceToPlane (self.root.facePosi, self.root.axis)\n        # print \"counter face distance: \", dist_v + self.__thickness\n        #print 'checking Face', str(i+1), ' dist_v: ', dist_v\n        if (dist_v > self.cFaceTol) or (dist_v < -self.cFaceTol):\n            face_found = False\n\n      if face_found:\n          faceList.append(i)\n          gotFace = True\n    \n    if gotFace:\n      if len(faceList) > 1: # check if more than one face was detected!\n        print ('fix me, more than one face found')\n        \n    drawingFace = ufoShape.Faces[faceList[0]].copy()\n    if doRotate:\n      drawingFace.rotate(self.root.facePosi,theAxis,math.degrees(-angle))\n    drawingFace.translate(-self.root.facePosi)\n    #Part.show(drawingFace, 'TheFace')\n    #Part.show(drawingFace.OuterWire, 'TheWire')\n\n    outProf_VG = Draft.makeVisGroup(name=\"OUTER_PROFILE\")\n    Draft.autogroup(outProf_VG)\n    #if FreeCAD.GuiUp:\n    outProf_VG.ViewObject.LineColor = (0.00,0.00,1.00) #blue color\n    outProf_VG.Group = []\n    outProfObj = self.theDoc.addObject(\"Part::Feature\")\n    outProfObj.Label = 'Outer_Profile_Lines'\n    outProfObj.Shape = drawingFace.OuterWire\n    outProf_VG.addObject(outProfObj)\n    \n    \n    if len(drawingFace.Wires) >1:\n      #Part.show(Part.Compound(drawingFace.Wires[1:]), 'TheHoles')\n      intProf_VG = Draft.makeVisGroup(name=\"INTERIOR_PROFILES\")\n      Draft.autogroup(intProf_VG)\n      #if FreeCAD.GuiUp:\n      intProf_VG.ViewObject.LineColor = (0.00,0.00,0.80) # color\n      intProf_VG.Group = []\n      intProfObj = self.theDoc.addObject(\"Part::Feature\")\n      intProfObj.Label = 'Interior_Profile_Lines'\n      intProfObj.Shape = Part.Compound(drawingFace.Wires[1:])\n      intProf_VG.addObject(intProfObj)\n\n\n    #text = Draft.makeText([\"Mist\"],point=FreeCAD.Vector(1.02944242954,-0.749239265919,0.0))\n    ## text has a Placement\n    \n    ## v.Group.append(text) # does not work for Text\n    #v.addObject(text) # This works!\n  \n\n\ndef getUnfold():\n    resPart = None\n    normalVect = None\n    folds = None\n    theName = None\n    drawVerts = None\n    mylist = Gui.Selection.getSelectionEx()\n    # print 'Die Selektion: ',mylist\n    # print 'Zahl der Selektionen: ', mylist.__len__()\n    \n    if mylist.__len__() == 0:\n      mw=FreeCADGui.getMainWindow()\n      QtGui.QMessageBox.information(mw,\"Error\",\"\"\"One flat face needs to be selected!\"\"\")\n    else:\n      if mylist.__len__() > 1:\n        mw=FreeCADGui.getMainWindow()\n        QtGui.QMessageBox.information(mw,\"Error\",\"\"\"Only one flat face has to be selected!\"\"\")\n      else:\n        o = Gui.Selection.getSelectionEx()[0]\n        theName = o.ObjectName\n        if len(o.SubObjects)>1:\n          mw=FreeCADGui.getMainWindow()\n          QtGui.QMessageBox.information(mw,\"SubelementError\",\"\"\"Only one flat face has to be selected!\"\"\")\n        else:\n          subelement = o.SubObjects[0]\n          if hasattr(subelement,'Surface'):\n            s_type = str(subelement.Surface)\n            if s_type == \"<Plane object>\":\n              normalVect = subelement.normalAt(0,0)\n              mw=FreeCADGui.getMainWindow()\n              #QtGui.QMessageBox.information(mw,\"Hurra\",\"\"\"Lets try unfolding!\"\"\")\n              FreeCAD.Console.PrintLog(\"name: \"+ str(subelement) + \"\\n\")\n              f_number = int(o.SubElementNames[0].lstrip('Face'))-1\n              #print f_number\n              startzeit = time.clock()\n              TheTree = SheetTree(o.Object.Shape, f_number, o.Document) # initializes the tree-structure\n              if TheTree.error_code == None:\n                TheTree.Bend_analysis(f_number, None) # traverses the shape and builds the tree-structure\n                endzeit = time.clock()\n                FreeCAD.Console.PrintLog(\"Analytical time: \"+ str(endzeit-startzeit) + \"\\n\")\n                \n                if TheTree.error_code == None:\n                  # TheTree.showFaces()\n                  theFaceList, foldLines, drawVerts = TheTree.unfold_tree2(TheTree.root) # traverses the tree-structure\n                  if TheTree.error_code == None:\n                    unfoldTime = time.clock()\n                    FreeCAD.Console.PrintLog(\"time to run the unfold: \"+ str(unfoldTime - endzeit) + \"\\n\")\n                    folds = Part.Compound(foldLines)\n                    #Part.show(folds, 'Fold_Lines')\n                    \n                    try:\n                        newShell = Part.Shell(theFaceList)\n                    except:\n                        FreeCAD.Console.PrintLog(\"couldn't join some faces, show only single faces!\\n\")\n                        resPart = Part.Compound(theFaceList)\n                        #for newFace in theFaceList:\n                          #Part.show(newFace)\n                    else:\n                      \n                      try:\n                          TheSolid = Part.Solid(newShell)\n                          solidTime = time.clock()\n                          FreeCAD.Console.PrintLog(\"time to make the solid: \"+ str(solidTime - unfoldTime) + \"\\n\")\n                      except:\n                          FreeCAD.Console.PrintLog(\"couldn't make a solid, show only a shell, Faces in List: \"+ str(len(theFaceList)) +\"\\n\")\n                          resPart = newShell\n                          #Part.show(newShell)\n                          showTime = time.clock()\n                          FreeCAD.Console.PrintLog(\"Show time: \"+ str(showTime - unfoldTime) + \"\\n\")\n                      else:\n                        try:\n                          cleanSolid = TheSolid.removeSplitter()\n                          #Part.show(cleanSolid)\n                          resPart = cleanSolid\n                          \n                        except:\n                          #Part.show(TheSolid)\n                          resPart = TheSolid\n                        showTime = time.clock()\n                        FreeCAD.Console.PrintLog(\"Show time: \"+ str(showTime - solidTime) + \" total time: \"+ str(showTime - startzeit) + \"\\n\")\n              \n                    if drawVerts is not None:\n                      TheTree.prepareDrawing(folds, resPart)\n    \n              if TheTree.error_code is not None:\n                FreeCAD.Console.PrintError(\"Error \"+ unfold_error[TheTree.error_code] +\n                     \" at Face\"+ str(TheTree.failed_face_idx+1) + \"\\n\")\n                QtGui.QMessageBox.information(mw,\"Error\",unfold_error[TheTree.error_code])\n              else:\n                FreeCAD.Console.PrintLog(\"unfold successful\\n\")\n    \n                      \n            else:\n              mw=FreeCADGui.getMainWindow()\n              QtGui.QMessageBox.information(mw,\"Selection Error\",\"\"\"Sheet UFO works only with a flat face as starter!\\n Select a flat face.\"\"\")\n          else:\n            mw=FreeCADGui.getMainWindow()\n            QtGui.QMessageBox.information(mw,\"Selection Error\",\"\"\"Sheet UFO works only with a flat face as starter!\\n Select a flat face.\"\"\")\n    return resPart, folds, normalVect, theName\n\nif __name__ == '__main__':\n  theUnfold, foldLines, nVec, shapeName = getUnfold()\n  if theUnfold:\n    Part.show(theUnfold, shapeName+'_unfolded')\n    #Part.show(foldLines, 'Foldlines')\n  \n",
    "url": "https://wiki.freecad.org/Macro_Sheet_Metal_Unfolder",
    "raw_code_url": "https://raw.githubusercontent.com/ulrich1a/sheet_ufo/master/sheet_ufo.py",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2018-08-14",
    "src_filename": "",
    "filename_from_url": "",
    "author": "ulrich1a",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Sheet_Metal_Unfolder.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/1/16/Macro_Sheet_Metal_Unfolder.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Unfold Box",
    "on_wiki": true,
    "on_git": false,
    "desc": "The macro allows to unfold the surfaces of a box of any shape and to draw them on a page.<br /><br />Macro version: 1.1<br />Last modified: 2022-07-28<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/e/e4/Macro_Unfold_Box.png\">ToolBar Icon</a><br />Author: Herv\u00e9 B., heda<br /> ",
    "comment": "Unfolds planar surfaces and draws them on a page.",
    "code": "# -*- coding: utf-8 -*-\n\"\"\"\nFreeCAD Macro unfoldBox.\n\nUnfolding of planar surfaces\n\"\"\"\n##################################################\n# SEE https://wiki.freecadweb.org/Macro_Unfold_Box\n# ***************************************************************************\n# *                                                                         *\n# *   Copyright (c) 2013 - DoNovae/Herve BAILLY <hbl13@donovae.com>         *\n# *   Copyright (c) 2022 - heda <heda@fc-forum>                             *\n# *                                                                         *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU Lesser General Public License (LGPL)    *\n# *   as published by the Free Software Foundation; either version 2 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENCE text file.                                 *\n# *                                                                         *\n# *   This program is distributed in the hope that it will be useful,       *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU Library General Public License for more details.                  *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with this program; if not, write to the Free Software   *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\n__Name__ = 'Unfold Box'\n__Comment__ = 'Unfolds planar surfaces and draws them on a page.'\n__Author__ = 'Herv\u00e9 B., heda'\n__Version__ = '1.1'\n__Date__ = '2022-07-28'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'https://wiki.freecad.org/Macro_Unfold_Box'\n__Wiki__ = 'https://wiki.freecad.org/Macro_Unfold_Box'\n__Icon__ = ''\n__Help__ = ('Select surfaces, Explode them (cf Draft menu Downgrade), '\n            'Select the exploded surfaces, Execute the macro')\n__Status__ = ''\n__Requires__ = ''\n__Communication__ = ''\n__Files__ = ''\n\n__doc__ = \"\"\"\nselect a face, or several and run the macro.\na shell/solid needs to be draft/downgraded to get the faces as separate objects\n\nthe macro is intended to unfold a set of planar faces,\nin current state, most of the times it does not place the faces correctly.\nthus one needs to do the final placement of the clones manually, with Draft/Move & Rotate\nregardless, the macro saves a lot of clicks compared to a fully manual unfold\n\nsettings are not context aware, all settings not applicable are ignored.\nas example, using autoscaling ignores the scale-value in the form\n\nsew is always enabled, thus the drawing\nis always the sewed shape on a single page\n\n\nv1.1   (2022-07-28) py3/qt5 compat, cosmetic code changes,\n       minor code tweaks for evolved fc-api\n       added option to skip drawing, made layout engine with techdraw,\n       the drawing wb layout engine is now called \"legacy\"\nv1.0.1 (2020-03-10) - on wiki\nv1.0   (2013-09-14) - on wiki\n\nnote:\n- unfolding occasionally work as expected, but mostly not\n- anyone is free to improve functionality\n\n\"\"\"\n\nimport os, math\n\nfrom PySide import QtGui, QtCore\n\nimport FreeCAD, FreeCADGui\nimport Draft\n\nVector = FreeCAD.Base.Vector\nUnits = FreeCAD.Units\nPrintMessage = FreeCAD.Console.PrintMessage\nPrintError = FreeCAD.Console.PrintError\n\nfields_l = []\nunroll_l = []\ndwgtpllegacy = 'Mod/Drawing/Templates'\ndwgtpl = 'Mod/TechDraw/Templates'\n\n\n#####################################\n###   Functions\n#####################################\n\n\ndef errorDialog(msg):\n    diag = QtGui.QMessageBox(QtGui.QMessageBox.Critical, 'Error Message', msg)\n    diag.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)\n    diag.exec_()\n\n\ndef proceed():\n    QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)\n\n    PrintMessage('===========================================\\n')\n    PrintMessage('unfoldBox: start.\\n')\n    try:\n        file_name = fields_l[0].text()\n        makedwg = makedwg_check.isChecked()\n        leglay = leglay_check.isChecked()\n        scale = float(fields_l[1].text())\n        scale_auto = scale_check.isChecked()\n        a3 = a3_check.isChecked()\n        cartridge = cartridge_check.isChecked()\n        onedrawing = onedrawing_check.isChecked()\n        sewed = sewed_check.isChecked()\n        PrintMessage('unfoldBox.file_name: {}\\n'.format(file_name))\n        PrintMessage('unfoldBox.makedwg: {}\\n'.format(makedwg))\n        PrintMessage('unfoldBox.leglay: {}\\n'.format(leglay))\n        PrintMessage('unfoldBox.scale: {}\\n'.format(scale))\n        PrintMessage('unfoldBox.scale_check: {}\\n'.format(scale_auto))\n        PrintMessage('unfoldBox.a3_check: {}\\n'.format(a3))\n        PrintMessage('unfoldBox.cartridge: {}\\n'.format(cartridge))\n        PrintMessage('unfoldBox.onedrawing: {}\\n'.format(onedrawing))\n        PrintMessage('unfoldBox.sewed: {}\\n'.format(sewed))\n    except:\n        msg = 'unfoldBox: wrong inputs...\\n'\n        PrintError(msg)\n        errorDialog(msg)\n\n    QtGui.QApplication.restoreOverrideCursor()\n    DialogBox.hide()\n\n    ## Get selection\n    sel = FreeCADGui.Selection.getSelection()\n    if not sel or len(sel) < 2:\n        PrintMessage('unfoldBox: requires at least 2 selected faces, ending.\\n')\n        return\n\n    doc = FreeCAD.ActiveDocument\n\n    objnames_l=[]\n    grp = doc.addObject('App::DocumentObjectGroup', str(file_name))\n    for objid in range(len(sel)):\n        obj = Draft.make_clone(sel[objid])\n        grp.addObject(obj)\n        objnames_l.append([ obj, sel[objid].Name ])\n\n    doc.recompute()\n    unfold = unfoldBox(doc)\n    if sewed:\n        objnames_l = unfold.done(objnames_l)\n        grp.addObject(objnames_l[0][0])\n    else:\n        for objid in range(len(objnames_l)):\n            unfold.moveXY(objnames_l[objid][0])\n\n    if not makedwg:\n        return\n\n    if leglay:\n        idx = 0\n        while len(objnames_l) > 0:\n            draw = Drawing2dLegacy(scale, scale_auto, a3,\n                                   cartridge, onedrawing,\n                                   doc.Name, 'Page'+str(idx))\n            objnames_l = draw.all_(objnames_l)\n            idx += 1\n            PrintMessage('unfoldBox: obj_l= {}\\n'.format(len(objnames_l)))\n    else:\n        draw = Drawing2d(scale, scale_auto, a3, cartridge)\n        draw.drawpage(objnames_l[0], \"{}Page\".format(file_name))\n\n    PrintMessage('unfoldBox: end.\\n')\n    PrintMessage('===========================================\\n')\n\n\ndef close():\n    DialogBox.hide()\n\n\ndef getType(obj):\n    return type(obj).__name__\n\ndef mkmm(l):\n    return Units.Quantity(l, Units.Length)\n\nclass unfoldBox:\n    def __init__(self, doc):\n        PrintMessage('unfoldBox.unfoldBox\\n')\n        self.doc = doc\n        self.LIMIT = 0.0001\n\n    def done(self, objnames_l):\n        tree_l = self.makeTree(objnames_l)\n        for idx in range(len(objnames_l)):\n            face = objnames_l[idx]\n            self.moveXY(face[0])\n        self.sew(objnames_l, tree_l)\n        return self.fusion(objnames_l)\n\n    def getEndPoints(self, edge):\n        return [v.Point for v in edge.Vertexes]\n\n    def makeTree(self, objnames_l):\n        ## Initialisation of tree_l.\n        tree_l = []\n        for k in range(len(objnames_l)):\n            facek = objnames_l[k][0]\n            facekEdges = facek.Shape.Edges\n            facek_l = []\n            for i in range(len(facekEdges)):\n                if False and getType(facekEdges[i].Curve) != 'GeomLineSegment':\n                    ## this is a no-op...\n                    facek_l.append([-1, -1])\n                else:\n                    ## Search face link to the ith edge\n                    #vki0 = facekEdges[i].Curve.StartPoint\n                    #vki1 = facekEdges[i].Curve.EndPoint\n                    vki0, vki1 = self.getEndPoints(facekEdges[i])\n                    found = False\n                    for l in range(k+1, len(objnames_l)):\n                        facel = objnames_l[l][0]\n                        facelEdges = facel.Shape.Edges\n                        for j in range(len(facelEdges)):\n                            #vlj0 = facelEdges[j].Curve.StartPoint\n                            #vlj1 = facelEdges[j].Curve.EndPoint\n                            vlj0, vlj1 = self.getEndPoints(facelEdges[j])\n                            if (vki0.isEqual(vlj0, self.LIMIT)\n                                and vki1.isEqual(vlj1, self.LIMIT)):\n                                arelinked = False\n                                isfacek = isfacel = False\n                                for kk in range(k-1):\n                                    for ii in range(len(tree_l[kk])):\n                                        isfacek = tree_l[kk][ii][0] == k\n                                        isfacel = tree_l[kk][ii][0] == l\n                                    if isfacek and isfacel:\n                                        arelinked = True\n                                        break\n                                if not arelinked:\n                                    facek_l.append([l, j])\n                                    found = True\n                                    break\n                            if found:\n                                break\n                if not found:\n                    facek_l.append([-1, -1])\n            tree_l.append(facek_l)\n        return tree_l\n\n    def sew(self, objnames_l, tree_l):\n        placed_l = []\n        for k in range(len(tree_l)):\n            iskplaced = False\n            for p in range(len(placed_l)):\n                iskplaced = placed_l[p] == k\n            if not iskplaced:\n                placed_l.append(k)\n            facek = tree_l[k]\n            objk = objnames_l[k][0]\n            for i in range(len(facek)):\n                edgeki = facek[i]\n                l, j = edgeki[:2]\n                islplaced = False\n                for p in range(len(placed_l)):\n                    if placed_l[p] == l:\n                        islplaced = True\n                        break\n                if not islplaced:\n                    placed_l.append(l)\n                if l >= 0 and not (islplaced and iskplaced):\n                    iskplaced = True\n                    ## Move facel.edgelj to facek.edgeki.\n                    objl = objnames_l[l][0]\n                    #vki0 = objk.Shape.Edges[i].Curve.StartPoint\n                    #vki1 = objk.Shape.Edges[i].Curve.EndPoint\n                    vki0, vki1 = self.getEndPoints(objk.Shape.Edges[i])\n                    #vlj0 = objl.Shape.Edges[j].Curve.StartPoint\n                    #vlj1 = objl.Shape.Edges[j].Curve.EndPoint\n                    vlj0, vlj1 = self.getEndPoints(objk.Shape.Edges[j])\n                    vk = vki1.sub(vki0)\n                    vl = vlj1.sub(vlj0)\n                    alpk = vk.getAngle(vl) * 180 / math.pi\n                    alpl = vl.getAngle(vk) * 180 / math.pi\n                    self.isPlanZ(objk)\n                    if islplaced:\n                        Draft.move(objk, vlj0.sub(vki0))\n                    else:\n                        Draft.move(objl, vki0.sub(vlj0))\n                    self.isPlanZ(objk)\n\n                    if math.fabs(vk.dot(Vector(-vl.y, vl.x, 0))) > self.LIMIT:\n                        if islplaced:\n                            Draft.rotate(objk, -alpl, vlj0, self.vecto(vl, vk))\n                        else:\n                            Draft.rotate(objl, -alpk, vki0, self.vecto(vk, vl))\n                    elif vk.dot(vl) < 0:\n                        if islplaced:\n                            Draft.rotate(objk, 180, vlj0, self.vecto(vl, Vector(-vl.y, vl.x, 0)))\n                        else:\n                            Draft.rotate(objl, 180, vki0, self.vecto(vk, Vector(-vk.y, vk.x, 0)))\n                    ## Verifications.\n                    #vki0 = objk.Shape.Edges[i].Curve.StartPoint\n                    #vki1 = objk.Shape.Edges[i].Curve.EndPoint\n                    vki0, vki1 = self.getEndPoints(objk.Shape.Edges[i])\n                    #vlj0 = objl.Shape.Edges[j].Curve.StartPoint\n                    #vlj1 = objl.Shape.Edges[j].Curve.EndPoint\n                    vli0, vli1 = self.getEndPoints(objk.Shape.Edges[j])\n                    vk = vki1.sub(vki0)\n                    vl = vlj1.sub(vlj0)\n                    self.isPlanZ(objk)\n\n                    ## Flip or not.\n                    bbl, bbk = objl.Shape.BoundBox, objk.Shape.BoundBox\n                    L = max(bbl.XMax, bbk.XMax) - min(bbl.XMin, bbk.XMin)\n                    W = max(bbl.YMax, bbk.YMax) - min(bbl.YMin, bbk.YMin)\n                    S1 = L * W\n                    if islplaced:\n                        Draft.rotate(objk, 180, vlj0, vl)\n                    else:\n                        Draft.rotate(objl, 180, vki0, vk)\n                    bbl, bbk = objl.Shape.BoundBox, objk.Shape.BoundBox\n                    L = max(bbl.XMax, bbk.XMax) - min(bbl.XMin, bbk.XMin)\n                    W = max(bbl.YMax, bbk.YMax) - min(bbl.YMin, bbk.YMin)\n                    S2 = L * W\n                    if S2 <= S1:\n                        if islplaced:\n                            Draft.rotate(objk, 180, vlj0, vl)\n                        else:\n                            Draft.rotate(objl, 180, vki0, vk)\n                    self.isPlanZ(objk)\n\n    def isPlanZ(self, obj):\n        bb = obj.Shape.BoundBox\n        L = bb.XMax - bb.XMin\n        W = bb.YMax - bb.YMin\n        H = bb.ZMax - bb.ZMin\n        return H < self.LIMIT\n\n\n    def fusion(self, objnames_l):\n        ## Init.\n        obj_l, objna_l =[], []\n        obj0, name = objnames_l[0]\n        objfuse = self.doc.addObject('Part::MultiFuse', 'Unfolding')\n        for k in range(len(objnames_l)):\n            objk = objnames_l[k][0]\n            obj_l.append(objk)\n\n        objfuse.Shapes = obj_l\n        self.doc.recompute()\n        objna_l.append([objfuse, name])\n        return objna_l\n\n    def get2Vectors(self, shape):\n        \"\"\"not used in v1.1\"\"\"\n        v0, v1 = Vector(), Vector()\n\n        edges = shape.Edges\n        for idx in range(len(edges) - 1):\n            e1, e2 = edges[idx], edges[idx + 1]\n            ## .EndPoint errors out...\n            va = e1.Curve.EndPoint.sub(e1.Curve.StartPoint)\n            vb = e2.Curve.EndPoint.sub(e2.Curve.StartPoint)\n            if vb.sub(va).Length > v1.sub(v0).Length:\n                v0, v1 = self.vect_copy(va), self.vect_copy(vb)\n        return [v0, v1]\n\n    def vecto(self, vect1, vect2):\n        '''Function vecto.'''\n        v = Vector()\n        v.x = vect1.y * vect2.z - vect1.z * vect2.y\n        v.y = vect1.z * vect2.x - vect1.x * vect2.z\n        v.z = vect1.x * vect2.y - vect1.y * vect2.x\n        return v\n\n    def vect_copy(self, vect):\n        '''Return a copy of vector.'''\n        return vect.add(Vector())\n\n    def moveXY(self, obj):\n        ## Move to origin\n        bb = obj.Shape.BoundBox\n        Draft.move(obj, Vector(-bb.XMin, -bb.YMin, -bb.ZMin))\n\n        ## Find 2 vectors defining the plan of surface\n        #tab = self.get2Vectors(obj.Shape)\n        #v0, v1 = tab[:2]\n        #norm = self.vecto(v0, v1)\n        #norm.normalize()\n        ## above gives null vector, and errors out...\n\n        ## probably sprung out of some api-change over time\n        ## probably part.line vs part.linesegment...\n        ## a part.line does not have edge.Curve.StartPoint, or .EndPoint any more\n        ## the semantics is to get first & second point from a line,\n        ## so edge.Curve.value(edge.Curve.FirstParameter) should get the sought values\n        ## however easier to just use edge.Vertexes...\n        ## which appears to have same orientation\n\n        norm = obj.Shape.findPlane().Axis ## works for planar surfaces\n        #norm = obj.Shape.Surface.Axis ## gives worse results...\n        norm.normalize()\n\n        ## Rotate.\n        nx, ny, nz = (math.fabs(xyz) for xyz in norm)\n        if nx < self.LIMIT and nz < self.LIMIT:\n            Draft.rotate(obj, 90, Vector(0, 0, 0), Vector(1, 0, 0))\n        elif ny < self.LIMIT and nz < self.LIMIT:\n            Draft.rotate(obj, 90, Vector(0, 0, 0), Vector(0, 1, 0))\n        else:\n            ## Rotate following the angle to the normal direction of the plan.\n            oz = Vector(0, 0, 1)\n            alp = oz.getAngle(norm) * 180 / math.pi\n            vecto = self.vecto(oz, norm)\n            rotv = oz if vecto.isEqual(Vector(), self.LIMIT) else self.vecto(oz, norm)\n            #rotv = norm if vecto.isEqual(Vector(), self.LIMIT) else self.vecto(oz, norm)\n            ## flipping here seems to give worse results as well...\n            Draft.rotate(obj, -alp, Vector(0, 0, 0), rotv)\n\n        ## Move to z = 0.\n        Draft.move(obj, Vector(0, 0, -obj.Shape.BoundBox.ZMin))\n\n\nclass Scale:\n    \"\"\"keeps autoscaling to integers\"\"\"\n    def __init__(self, scale):\n        self.scale = scale if scale >= 1 else 1 / scale\n        self.scale = int(self.scale)\n        self.inverted = scale >= 1\n\n    def get(self):\n        if self.inverted:\n            return self.scale, '{}:1'.format(self.scale)\n        else:\n            return 1/self.scale, '1:{}'.format(self.scale)\n\n\nclass Drawing2d:\n    def __init__(self, scale, scale_auto, a3, cartridge):\n        \"\"\"techdraw based layout for one page only\"\"\"\n        self.scale = scale\n        self.scale_auto = scale_auto\n        self.a3 = a3\n        self.cartridge = cartridge\n        if a3:\n            self.WH = 420, 297\n        else:\n            self.WH = 297, 210\n        self.doc = FreeCAD.ActiveDocument\n\n    def newPage(self, page_name):\n        freecad_dir = os.path.join(FreeCAD.getResourceDir(), dwgtpl)\n        page = self.doc.addObject('TechDraw::DrawPage', page_name)\n        template = self.doc.addObject('TechDraw::DrawSVGTemplate', 'Template')\n        size = 'A3' if self.a3 else 'A4'\n        frame = 'TD' if self.cartridge else '_blank'\n        template.Template = freecad_dir + '/{}_Landscape{}.svg'.format(size, frame)\n        page.Template = template\n\n        return page\n\n    def drawpage(self, objname, page_name):\n        page = self.newPage(page_name)\n        faceset, name = objname\n\n        bb = faceset.Shape.BoundBox\n        ## bb does not auto-update, have to pick up new bb after manipulation\n        if bb.YLength > bb.XLength: ## auto rotate\n            Draft.rotate(faceset, 90)\n            bb = faceset.Shape.BoundBox\n\n        Draft.move(faceset, Vector(-bb.XMin, -bb.YMin, 0))\n        bb = faceset.Shape.BoundBox\n\n        W, H = self.WH\n        xr, yr = W / bb.XLength, H / bb.YLength\n        adjust = 0.7 if self.cartridge else 0.85\n        scale = min(xr, yr) * adjust if self.scale_auto else self.scale\n        scale, scr = Scale(scale).get()\n        bb.scale(scale, scale, 1) ## faceset in xy-plane\n\n\n        TopView = self.doc.addObject('TechDraw::DrawViewPart', 'TopView')\n        page.addView(TopView)\n        TopView.Source = faceset\n        TopView.Direction = (0, 0, 1)\n        TopView.XDirection = (1, 0, 0)\n        TopView.Scale = scale\n\n        Text = self.doc.addObject('TechDraw::DrawViewAnnotation', name)\n        page.addView(Text)\n        Text.Text = name\n        Text.recompute() # for size\n        bb.scale(scale, scale, scale)\n        yt = (H - bb.YLength) / 2 - Text.TextSize.Value * 1.5\n        Text.Y = max(1, yt)\n\n        self.doc.recompute()\n        page.ViewObject.doubleClicked()\n        FreeCADGui.runCommand('TechDraw_ToggleFrame', 0)\n\n\nclass Drawing2dLegacy:\n    def __init__(self, scale, scale_auto, a3, cartridge, onedrawing,\n                 drawing_name, page_name):\n        \"\"\"Function __init__\n\n        - scale\n        - scale_auto\n        - a3\n        - cartridge\n        - onedrawing\n        v1.1 - renamed to legacy, functional wise untouched\n        \"\"\"\n        self.TopX_H = self.TopY_H = 0\n        self.TopX_V = self.TopY_V = 0\n        self.TopX_Hmax = self.TopY_Hmax = 0\n        self.TopX_Vmax = self.TopY_Vmax = 0\n        self.a3 = a3\n        self.scale = scale\n        self.scale_auto = scale_auto\n        self.cartridge = cartridge\n        self.onedrawing = onedrawing\n        self.marge = 6\n        if self.a3:\n            self.L, self.H = 420, 297\n        else:\n            self.L, self.H = 297, 210\n        self.page_name = page_name\n        self.drawing_name = drawing_name\n        self.doc = FreeCAD.ActiveDocument\n\n    def newPage(self):\n        freecad_dir = os.path.join(FreeCAD.getResourceDir(), dwgtpllegacy)\n        page = self.doc.addObject('Drawing::FeaturePage', self.page_name)\n        size = 'A3' if self.a3 else 'A4'\n        frame = '' if self.cartridge else '_plain'\n        page.Template = freecad_dir + '/{}_Landscape{}.svg'.format(size, frame)\n        return page\n\n    def all_(self, objnames_l):\n        obj_l = []\n        for objid in range(len(objnames_l)):\n            if objid == 0 or not self.onedrawing:\n                self.newPage()\n            obj_l.extend(self.done(objid, objnames_l[objid]))\n        return obj_l\n\n    def done(self, id_, objname):\n        ## Init.\n        obj_l = []\n        obj, objname = objname\n        bb = obj.Shape.BoundBox\n        xmax, ymax = bb.XMax - bb.XMin, bb.YMax - bb.YMin\n        if ymax > xmax:\n            Draft.rotate(obj, 90)\n            bb = obj.Shape.BoundBox\n\n        Draft.move(obj, Vector(-bb.XMin, -bb.YMin, 0))\n        bb = obj.Shape.BoundBox ## does not auto-update, have to pick up new obj\n        xmax = bb.XMax - bb.XMin\n        ymax = bb.YMax - bb.YMin\n\n        scale = min((self.L-4*self.marge) / xmax, (self.H-4*self.marge) / ymax)\n\n        if (not self.scale_auto) or (self.onedrawing):\n            scale = self.scale\n\n        if id_ == 0 or not self.onedrawing:\n            ## Init.\n            PrintMessage('Drawing2d: init\\n')\n            self.TopX_H = self.TopY_H = self.marge * 2\n            TopX, TopY = self.TopX_H, self.TopY_H\n            self.TopX_H = self.TopX_H + xmax * scale + self.marge\n            self.TopY_H = self.TopY_H\n            self.TopX_Hmax = max(self.TopX_Hmax, self.TopX_H)\n            self.TopY_Hmax = max(self.TopY_Hmax,\n                                 self.TopY_H + ymax*scale + self.marge)\n            self.TopX_Vmax = max(self.TopX_Vmax, self.TopX_Hmax)\n            self.TopX_V = max(self.TopX_Vmax, self.TopX_V)\n            self.TopY_V = self.marge * 2\n\n        elif self.onedrawing:\n            if self.TopX_H + xmax * scale < self.L:\n                if self.TopY_H + ymax * scale + self.marge*2 < self.H:\n                    ## H Add at right on same horizontal line.\n                    PrintMessage('Drawing2d: horizontal\\n')\n                    TopX, TopY = self.TopX_H, self.TopY_H\n                    self.TopX_H = self.TopX_H + xmax * scale + self.marge\n                    self.TopX_Hmax = max(self.TopX_Hmax, self.TopX_H)\n                    self.TopY_Hmax = max(self.TopY_Hmax,\n                                         self.TopY_H + ymax*scale + self.marge)\n                    self.TopX_Vmax = max(self.TopX_Hmax, self.TopX_Vmax)\n                    self.TopX_Vmax = max(self.TopX_Vmax, self.TopX_Hmax)\n                    self.TopX_V = max(self.TopX_Vmax, self.TopX_V)\n                else:\n                    ## V Add at right on same horizontal line\n                    PrintMessage('Drawing2d: vertival\\n')\n                    if (self.TopX_V + ymax * scale + 2 * self.marge < self.L\n                        and self.TopY_V + xmax * scale + 2*self.marge < self.H):\n                        Draft.rotate(obj, 90)\n                        bb = obj.Shape.BoundBox\n                        Draft.move(obj, Vector(-bb.XMin, -bb.YMin, 0))\n                        self.TopX_V = max(self.TopX_Vmax, self.TopX_V)\n                        TopX, TopY = self.TopX_V, self.TopY_V\n                        self.TopX_V = self.TopX_V + ymax * scale + self.marge\n                        self.TopY_Vmax = max(self.TopY_Vmax,\n                                             self.TopY_V + xmax * scale + self.marge)\n                    else:\n                        obj_l.append([obj, 'name'])\n                        return obj_l\n            else:\n                ## H Carriage return.\n                if (self.TopY_Hmax + ymax * scale + self.marge*2 < self.H):\n                    msg = 'Drawing2d: carriage return: {} > {}\\n'\n                    PrintMessage(msg.format(self.TopY_H + ymax * scale, self.H))\n                    TopX = self.marge*2\n                    TopY = self.TopY_Hmax\n                    self.TopX_H = TopX + xmax * scale + self.marge\n                    self.TopY_H = TopY\n                    self.TopX_Hmax = max(self.TopX_Hmax, self.TopX_H)\n                    self.TopY_Hmax = self.TopY_Hmax + ymax*scale+self.marge\n                    self.TopX_Vmax = max(self.TopX_Vmax, self.TopX_Hmax)\n                    self.TopX_V = max(self.TopX_Vmax, self.TopX_V)\n                else:\n                    ## V Add at right on same horizontal line.\n                    msg = 'Drawing2d: vertical: {}, {}\\n'\n                    PrintMessage(msg.format(self.TopX_V, self.TopX_Vmax))\n                    if (self.TopX_V + ymax * scale + 2*self.marge < self.L\n                        and self.TopY_V + xmax * scale + 2*self.marge < self.H):\n                        Draft.rotate(obj, 90)\n                        bb = obj.Shape.BoundBox\n                        Draft.move(obj, Vector(-bb.XMin, -bb.YMin, 0))\n                        TopX, TopY = self.TopX_V, self.TopY_V\n                        self.TopX_V = self.TopX_V + ymax * scale + self.marge\n                        self.TopY_Vmax = max(self.TopY_Vmax,\n                                             self.TopY_V + xmax * scale + self.marge)\n                    else:\n                        obj_l.append([obj, 'name'])\n                        return obj_l\n\n        page = self.doc.getObject(self.page_name)\n\n        ## Drawing wb (untouched)\n        Text = self.doc.addObject('Drawing::FeatureViewAnnotation', objname + '_txt')\n        Text.Text = objname\n        Text.X = TopX + xmax / 2 * scale\n        Text.Y = TopY + ymax / 2 * scale\n        Text.Scale = 7 if self.a3 else 5\n\n        TopView = self.doc.addObject('Drawing::FeatureViewPart', 'TopView')\n        TopView.Source = obj\n        TopView.Direction = (0.0, 0.0, 1)\n        TopView.Rotation = 0\n        TopView.X = TopX\n        TopView.Y = TopY\n        TopView.ShowHiddenLines = True\n        TopView.Scale = scale\n        page.addObject(TopView)\n        page.addObject(Text)\n\n        self.doc.recompute()\n        page.ViewObject.doubleClicked()\n\n        return obj_l\n\n\n#####################################\n###   Dialog Box\n#####################################\nfields = [['Group Name', 'Unfolding']]\nfields.append(['Scale', '1'])\n\nDialogBox = QtGui.QDialog()\nDialogBox.resize(250, 250)\nDialogBox.setWindowTitle('unfoldBox')\nla = QtGui.QVBoxLayout(DialogBox)\n\n# Input fields.\nfor id_ in range(len(fields)):\n    la.addWidget(QtGui.QLabel(fields[id_][0]))\n    fields_l.append(QtGui.QLineEdit(fields[id_][1]))\n    la.addWidget(fields_l[id_])\n\nmakedwg_check = QtGui.QCheckBox(DialogBox)\nmakedwg_check.setObjectName('checkBox')\nmakedwg_check.setChecked(True)\nla.addWidget(QtGui.QLabel('Make drawing'))\nla.addWidget(makedwg_check)\n\nleglay_check = QtGui.QCheckBox(DialogBox)\nleglay_check.setObjectName('checkBox')\nleglay_check.setChecked(False)\nla.addWidget(QtGui.QLabel('Legacy layout'))\nla.addWidget(leglay_check)\n\nscale_check = QtGui.QCheckBox(DialogBox)\nscale_check.setObjectName('checkBox')\nscale_check.setChecked(True)\nla.addWidget(QtGui.QLabel('Scale auto'))\nla.addWidget(scale_check)\n\na3_check = QtGui.QCheckBox(DialogBox)\na3_check.setObjectName('checkBox')\nla.addWidget(QtGui.QLabel('A3 Format'))\na3_check.setChecked(False)\nla.addWidget(a3_check)\n\ncartridge_check = QtGui.QCheckBox(DialogBox)\ncartridge_check.setObjectName('checkBox')\nla.addWidget(QtGui.QLabel('Cartridge'))\ncartridge_check.setChecked(False)\nla.addWidget(cartridge_check)\n\nonedrawing_check = QtGui.QCheckBox(DialogBox)\nonedrawing_check.setObjectName('checkBox')\nla.addWidget(QtGui.QLabel('Group drawings in page'))\nonedrawing_check.setChecked(True)\nla.addWidget(onedrawing_check)\n\nsewed_check = QtGui.QCheckBox(DialogBox)\nsewed_check.setObjectName('checkBox')\nla.addWidget(QtGui.QLabel('Sewed surfaces'))\nsewed_check.setChecked(True)\nsewed_check.setEnabled(False)\nla.addWidget(sewed_check)\n\nbox = QtGui.QDialogButtonBox(DialogBox)\n\nbox = QtGui.QDialogButtonBox(DialogBox)\nbox.setOrientation(QtCore.Qt.Horizontal)\nbox.setStandardButtons(QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok)\nla.addWidget(box)\n\nQtCore.QObject.connect(box, QtCore.SIGNAL('accepted()'), proceed)\nQtCore.QObject.connect(box, QtCore.SIGNAL('rejected()'), close)\nQtCore.QMetaObject.connectSlotsByName(DialogBox)\nDialogBox.show()\n",
    "url": "https://wiki.freecad.org/Macro_Unfold_Box",
    "raw_code_url": "",
    "wiki": "https://wiki.freecad.org/Macro_Unfold_Box",
    "version": "1.1",
    "license": "",
    "date": "2022-07-28",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Herv\u00e9 B., heda",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Unfold_Box.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/e/e4/Macro_Unfold_Box.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Unroll Ruled Surface",
    "on_wiki": true,
    "on_git": false,
    "desc": "The macro allows to unroll ruled surfaces and to draw them on a page.<br /><br />Macro version: 1.1<br />Last modified: 2022-07-24<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecad.org/images/b/ba/Macro_Unroll_Ruled_Surface.png\">ToolBar Icon</a><br />Author: Herv\u00e9 B., heda<br /> ",
    "comment": "Unroll of a ruled surface and draw it on a page.",
    "code": "# -*- coding: utf-8 -*-\n#***************************************************************************\n#*                                                                         *\n#*   Copyright (c) 2013 - DoNovae/Herve BAILLY <hbl13@donovae.com>         *\n#*   Copyright (c) 2022 - heda <heda@fc-forum>                             *\n#*                                                                         *\n#*   This program is free software; you can redistribute it and/or modify  *\n#*   it under the terms of the GNU Lesser General Public License (LGPL)    *\n#*   as published by the Free Software Foundation; either version 2 of     *\n#*   the License, or (at your option) any later version.                   *\n#*   for detail see the LICENCE text file.                                 *\n#*                                                                         *\n#*   This program is distributed in the hope that it will be useful,       *\n#*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n#*   GNU Library General Public License for more details.                  *\n#*                                                                         *\n#*   You should have received a copy of the GNU Library General Public     *\n#*   License along with this program; if not, write to the Free Software   *\n#*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n#*   USA                                                                   *\n#*                                                                         *\n#***************************************************************************\n__Name__ = 'Unroll Ruled Surface'\n__Comment__ = 'Unroll of a ruled surface and draw it on a page.'\n__Author__ = 'Herv\u00e9 B., heda'\n__Version__ = '1.1'\n__Date__ = '2022-07-24'\n__License__ = 'LGPL-2.0-or-later'\n__Web__ = 'https://wiki.freecad.org/Macro_Unroll_Ruled_Surface'\n__Wiki__ = 'https://wiki.freecad.org/Macro_Unroll_Ruled_Surface'\n__Icon__ = ''\n__Help__ = ('Select ruled surfaces, Explode them (cf Draft menu), '\n            'Select the surfaces, Execute the macro')\n__Status__ = ''\n__Requires__ = ''\n__Communication__ = ''\n__Files__ = ''\n\n__doc__ = \"\"\"\nselect a face, or several and run the macro.\na shell/solid needs to be draft/downgraded to get the faces as separate objects\n\nthe macro is intended to unroll lofted faces,\nfunction beyond that is (in current version) a bonus\n\nsettings are not context aware, all settings not applicable are ignored.\nas example, using autoscaling ignores the scale-value in the form\n\n\nv1.1   (2022-07-24) py3/qt5 compat, cosmetic code changes, minor code tweaks,\n       used gridlayout for form, added option to skip drawing,\n       made new layout engine with techdraw,\n       the drawing wb layout engine is now called \"legacy\"\nv1.0.1 (2019-02-01) - on git\nv1.0   (2013-09-14) - on wiki\n\nnote:\n- unfolding sometimes works and sometimes not\n- not all surfaces are theoretically possible to unroll\n\n\"\"\"\n\nimport os\nfrom PySide import QtGui, QtCore\nimport FreeCAD, FreeCADGui\nimport Part, Draft\n\nVector = FreeCAD.Base.Vector\nPrintMessage = FreeCAD.Console.PrintMessage\nPrintError = FreeCAD.Console.PrintError\n\nsettings = dict()\nunroll_l = []\ndwgtpllegacy = 'Mod/Drawing/Templates'\ndwgtpl = 'Mod/TechDraw/Templates'\n\n\n#####################################\n###   Functions\n#####################################\n\ndef errorDialog(msg):\n    diag = QtGui.QMessageBox(QtGui.QMessageBox.Critical, \"Error Message\", msg)\n    diag.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)\n    diag.exec_()\n\ndef ending():\n    PrintMessage(\"UnrollRuledSurface: end.\\n\")\n    PrintMessage(\"===========================================\\n\")\n    FreeCAD.ActiveDocument.recompute()\n\n\ndef proceed():\n    QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)\n\n    PrintMessage(\"===========================================\\n\")\n    PrintMessage(\"UnrollRuledSurface: start.\\n\")\n    try:\n        sts = lambda s: settings.get(s)\n\n        file_name = sts(\"fname\").text()\n        pts_nbr = float(sts(\"dpts\").text())\n        makedwg = sts(\"mkdwg\").isChecked()\n        leglay = sts(\"legacylayout\").isChecked()\n        scale = float(sts(\"scale\").text()) # ignored if autoscale is set\n        scale_auto = sts(\"autoscale\").isChecked()\n        edge0 = sts(\"edge\").checkedId() == -2\n        a3 = sts(\"papersize\").checkedId() == -3\n        cartridge = sts(\"cartridge\").isChecked()\n        onedrawing = sts(\"groupdwg\").isChecked()\n\n        PrintMessage(\"UnrollRuledSurface.file_name: {}\\n\".format(file_name))\n        PrintMessage(\"UnrollRuledSurface.pts_nbr: {}\\n\".format(pts_nbr))\n        PrintMessage(\"UnrollRuledSurface.edge0: {}\\n\".format(edge0))\n        PrintMessage(\"UnrollRuledSurface.makedwg: {}\\n\".format(makedwg))\n        PrintMessage(\"UnrollRuledSurface.leglay: {}\\n\".format(leglay))\n        PrintMessage(\"UnrollRuledSurface.scale_check: {}\\n\".format(scale_auto))\n        PrintMessage(\"UnrollRuledSurface.scale: {}\\n\".format(scale))\n        PrintMessage(\"UnrollRuledSurface.a3_check: {}\\n\".format(a3))\n        PrintMessage(\"UnrollRuledSurface.cartridge: {}\\n\".format(cartridge))\n        PrintMessage(\"UnrollRuledSurface.onedrawing: {}\\n\".format(onedrawing))\n    except:\n        msg = \"UnrollRuledSurface: wrong inputs...\\n\"\n        PrintError(msg)\n        errorDialog(msg)\n        QtGui.QApplication.restoreOverrideCursor()\n        DialogBox.hide()\n        ending()\n        return\n\n    QtGui.QApplication.restoreOverrideCursor()\n    DialogBox.hide()\n    unrollRS = unrollRuledSurface(file_name, pts_nbr, edge0)\n\n    ## Get selection\n    sel = FreeCADGui.Selection.getSelection()\n    if not sel:\n        PrintMessage(\"UnrollRuledSurface: no selection...\\n\")\n        ending()\n        return\n\n    faceid = 0\n    objnames_l, objnames0_l = [], []\n    grp = FreeCAD.ActiveDocument.addObject(\"App::DocumentObjectGroup\",\n                                           \"{}_objs\".format(file_name))\n\n    for objid, obji in enumerate(sel):\n        shape = obji.Shape\n        faces = shape.Faces\n        for idx in range(len(faces)):\n            msg = \"UnrollRuledSurface.proceed: ObjId = {}, faceId = {}\\n\"\n            PrintMessage(msg.format(objid, faceid))\n            name = obji.Name\n            if len(faces) > 1:\n                name = \"{}.face_{}\".format(name, idx)\n            obj = unrollRS.unroll(faces[idx], name)\n            obj.ViewObject.Visibility = not makedwg\n            grp.addObject(obj)\n\n        objnames_l.append([obj, name])\n        objnames0_l.append([obji, name])\n        faceid += 1\n\n    if not makedwg:\n        ending()\n        return\n\n    if leglay:\n        idx = 0\n        while len(objnames_l) > 0:\n            draw = Drawing2dLegacy(scale, scale_auto, a3,\n                                   cartridge, onedrawing,\n                                   \"{}_page{:02}\".format(file_name, idx))\n            objnames_l = draw.all2d(objnames_l)\n            idx += 1\n            msg = \"UnrollRuledSurface: obj_l = {}\\n\"\n            PrintMessage(msg.format(len(objnames_l)))\n\n    else:\n        draw = Drawing2d(scale, scale_auto, a3, cartridge)\n        n = 4 if onedrawing else 1\n        chunks = [objnames_l[i:i + n] for i in range(0, len(objnames_l), n)]\n        for i, chunk in enumerate(chunks, start=1):\n            draw.drawpage(chunk, \"{}_page{:02}\".format(file_name, i))\n\n    ending()\n\n\ndef close():\n    DialogBox.hide()\n\ndef getType(obj):\n    return type(obj).__name__\n\n\nclass unrollRuledSurface:\n    \"\"\"\n    unroll ruled surfaces\n    :file_name: ouput file\n    :pts_nbr: nbr point of discretization\n    \"\"\"\n    def __init__(self, file_name, pts_nbr, edge0):\n        self.doc = FreeCAD.ActiveDocument\n        self.file_name = file_name\n        self.pts_nbr = int(pts_nbr)\n        self.edge0 = edge0\n        msg = \"UnrollRuledSurface.unroll - file_name: {}, pts_nbr: {}\\n\"\n        PrintMessage(msg.format(file_name, pts_nbr))\n\n\n    def discretize(self, curve):\n        \"\"\"discretize a curve\"\"\"\n        if getType(curve) in ('GeomLineSegment', 'GeomCircle'):\n            sd = curve.discretize(self.pts_nbr)\n        elif getType(curve) == 'GeomBSplineCurve':\n            nodes = curve.getPoles()\n            spline = Part.BSplineCurve()\n            spline.buildFromPoles(nodes)\n            sd = spline.discretize(self.pts_nbr)\n        else:\n            sd = curve.discretize(self.pts_nbr)\n        return sd\n\n    def nbpoles(self, curve):\n        \"\"\"find number of poles for a curve\"\"\"\n        if getType(curve) == 'GeomLineSegment':\n            nbpol=1\n        elif getType(curve) == 'GeomBSplineCurve':\n            nbpol=curve.NbPoles\n        elif getType(curve) == 'GeomCircle':\n            nbpol=2\n        elif getType(curve) == 'GeomBezierCurve':\n            nbpol=4\n        else:\n            nbpol=0\n\n        msg = \"UnrollRulrdSurface.nbpole {:s} = {:d}\\n\"\n        PrintMessage(msg.format(getType(curve), nbpol))\n        return nbpol\n\n    def unroll(self, face, name):\n        \"\"\"unrolls a face composed of 2 to 4 edges\"\"\"\n        nbredges = len(face.Edges)\n        msg = \"UnrollRuledSurface.unroll: Edge Nbr = {}\\n\"\n        PrintMessage(msg.format(nbredges))\n\n        if nbredges == 2:\n            e1, e2 = face.Edges\n            sd1 = e1.Curve.discretize(self.pts_nbr)\n            sd2 = e2.Curve.discretize(self.pts_nbr)\n\n        elif nbredges == 3:\n            e1, _, e2 = face.Edges\n            sd1 = e1.Curve.discretize(self.pts_nbr)\n            sd2 = e2.Curve.discretize(self.pts_nbr)\n\n        else:\n            E0, E1, E2, E3, *_ = face.Edges\n            ## Choose more complexe curve as edge\n            nbpol0 = self.nbpoles(E0.Curve)\n            nbpol1 = self.nbpoles(E1.Curve)\n            nbpol2 = self.nbpoles(E2.Curve)\n            nbpol3 = self.nbpoles(E3.Curve)\n            msg = (\"UnrollRuledSurface.unroll: nbpol0= {:d}, nbpol1= {:d},\"\n                   \" nbpol2= {:d}, nbpol3= {:d}\\n\")\n            PrintMessage(msg.format(nbpol0, nbpol1, nbpol2, nbpol3))\n\n            if self.edge0:\n                e1, e2 = E0, E2\n                v = self.discretize(E1)\n                v0, v1 = v[0], v[self.pts_nbr-1]\n            else:\n                e1, e2 = E1, E3\n                v = self.discretize(E2)\n                v0, v1 = v[0], v[self.pts_nbr-1]\n\n            sd1 = self.discretize(e1)\n            sd2 = self.discretize(e2)\n            ## Reverse if curves cross over\n            if not (sd2[0].__eq__(v0) or not sd2[0].__eq__(v1)):\n                sd2.reverse()\n\n        ## Create a polygon object and set its nodes\n        devlxy_l = self.devlxyz(sd1, sd2)\n        msg = \"UnrollRuledSurface.unroll: size devlxy_l: {}\\n\"\n        PrintMessage(msg.format(len(devlxy_l)))\n        p = self.doc.addObject(\"Part::Polygon\", name)\n        p.Nodes = devlxy_l\n        self.doc.recompute()\n        FreeCADGui.ActiveDocument.ActiveView.fitAll()\n        return p\n\n    def vect_copy(self, vect):\n        \"\"\"returns copy of vector\"\"\"\n        return vect.add(Vector())\n\n    def vect_cos(self, vect1, vect2):\n        \"\"\"returns cosine angle between 2 vectors\"\"\"\n        return vect1.dot(vect2) / vect1.Length / vect2.Length\n\n    def vect_sin(self, vect1, vect2):\n        \"\"\"returns absolute sinus angle between 2 vectors\"\"\"\n        v = Vector()\n        v.x = vect1.y * vect2.z - vect1.z * vect2.y\n        v.y = vect1.z * vect2.x - vect1.x * vect2.z\n        v.z = vect1.x * vect2.y - vect1.y * vect2.x\n        return v.Length / vect1.Length / vect2.Length\n\n    def devlxyz(self, vect1, vect2):\n        \"\"\"\n        unrolls a face composed of 4 edges\n        args: vect1, vect2 --> 2 edges of the shape\n        returns: dvlxy\n        \"\"\"\n        lenv1, lenv2 = len(vect1), len(vect2)\n        if lenv1 != lenv2 or lenv1 != self.pts_nbr or lenv2 != self.pts_nbr:\n            msg = (\"UnrollRuledSurface.devlxyz: incompatility of sizes vect1,\"\n                   \" vect2, pts_nbr: ({}, {}, {})\\n\")\n            PrintError(msg.format(lenv1, lenv2, self.pts_nbr))\n            errorDialog(msg)\n\n        devlxy_l, devl1xy_l, devl2xy_l = [], [], []\n        errormax = 0.0\n        ## Init unroll\n        ## AB\n        a1b1 = vect2[0].sub(vect1[0])\n        oa1 = Vector(0, 0, 0)\n        devl1xy_l.append(oa1) #A1\n        ob1 = Vector(a1b1.Length, 0, 0)\n        devl2xy_l.append(ob1) #B1\n        #self.draw_line(devl1xy_l[0], devl2xy_l[0])\n        #self.draw_line(vect1[0], vect2[0])\n        for j in range(1, self.pts_nbr):\n\n            ## AB\n            ab = vect2[j-1].sub(vect1[j-1])\n            #self.draw_line(vect1[j-1], vect2[j-1])\n\n            ## AC\n            ac = vect1[j].sub(vect1[j-1])\n\n            ## BD\n            bd = vect2[j].sub(vect2[j-1])\n\n            ## CD\n            cd = vect2[j].sub(vect1[j])\n\n            ## A1B1 in unroll plan\n            a1b1 = devl2xy_l[j-1].sub(devl1xy_l[j-1])\n            a1b1n = self.vect_copy(a1b1)\n            a1b1n.normalize()\n            a1b1on = Vector(-a1b1n.y, a1b1n.x, 0)\n\n            ## A1C1\n            cosalp = self.vect_cos(ab, ac)\n            sinalp = self.vect_sin(ab, ac)\n            a1c1 = self.vect_copy(a1b1n)\n            a1c1.multiply(cosalp * ac.Length)\n            v = self.vect_copy(a1b1on)\n            v.multiply(sinalp * ac.Length)\n            a1c1 = a1c1.add(v)\n            oa1 = self.vect_copy(devl1xy_l[j-1])\n            oc1 = oa1.add(a1c1)\n            devl1xy_l.append(oc1)\n\n            ## B1D1\n            cosalp = self.vect_cos(ab, bd)\n            sinalp = self.vect_sin(ab, bd)\n            b1d1 = self.vect_copy(a1b1n)\n            b1d1.multiply(cosalp * bd.Length)\n            v = self.vect_copy(a1b1on)\n            v.multiply(sinalp * bd.Length)\n            b1d1 = b1d1.add(v)\n            ob1 = self.vect_copy(devl2xy_l[j-1])\n            od1 = ob1.add(b1d1)\n            devl2xy_l.append(od1)\n\n            ## Draw generatrice\n            #self.draw_line(devl1xy_l[j], devl2xy_l[j])\n            c1d1 = devl2xy_l[j].sub(devl1xy_l[j])\n            if ab.Length != 0:\n                abl = ab.Length\n                errormax = max(errormax, abs(abl - c1d1.Length) / abl)\n\n        msg = \"UnrollRuledSurface Error cd,c1d1: {:.1f} %\\n\"\n        PrintMessage(msg.format(errormax*100))\n\n        ## Close polygone\n        devlxy_l = devl1xy_l\n        devl2xy_l.reverse()\n        devlxy_l.extend(devl2xy_l)\n        v = Vector()\n        devlxy_l.append(v)\n\n        return devlxy_l\n\n\n    def draw_line(self, vect0, vect1):\n        \"\"\"draws a Part.Line between vect0 & vect1\"\"\"\n        l = Part.LineSegment()\n        l.StartPoint = vect0\n        l.EndPoint = vect1\n        self.doc.addObject(\"Part::Feature\", \"Line\").Shape = l.toShape()\n\n\nclass Scale:\n    \"\"\"keeps autoscaling to integers\"\"\"\n    def __init__(self, scale):\n        self.scale = scale if scale >= 1 else 1 / scale\n        self.scale = int(self.scale)\n        self.inverted = scale >= 1\n\n    def get(self):\n        if self.inverted:\n            return self.scale, '{}:1'.format(self.scale)\n        else:\n            return 1/self.scale, '1:{}'.format(self.scale)\n\n\nclass Drawing2d:\n    \"\"\"\n    TechDraw wb layout engine, diffeent logic compared to drawing wb layout.\n    serves basic purpose...\n    \"\"\"\n    def __init__(self, scale, scale_auto, a3, cartridge):\n\n        self.a3 = a3\n        self.scale = scale\n        self.scale_auto = scale_auto\n        self.cartridge = cartridge\n        if a3:\n            self.WH = 420, 297\n        else:\n            self.WH = 297, 210\n        self.doc = FreeCAD.ActiveDocument\n\n\n    def _mkquadrants(self, nbr):\n        \"\"\"centers of quadrants w/o margin\"\"\"\n        w, h = self.WH\n        w2, h2 = w/2, h/2\n        w4, h4 = w/4, h/4\n\n        q = {1: [[w, h], [[w2, h2]]],\n             2: [[w2, h], [[w2 - w4, h2], [w2 + w4, h2]]],\n             3: [[w2, h2], [[w2 - w4, h2 + h4], [w2 + w4, h2 + h4],\n                            [w2 - w4, h2 - h4]]],\n             4: [[w2, h2], [[w2 - w4, h2 + h4], [w2 + w4, h2 + h4],\n                            [w2 - w4, h2 - h4], [w2 + w4, h2 - h4]]]}\n        return q.get(nbr)\n\n\n    def newPage(self, doc, page_name):\n        freecad_dir = os.path.join(FreeCAD.getResourceDir(), dwgtpl)\n        page = doc.addObject('TechDraw::DrawPage', page_name)\n        template = self.doc.addObject('TechDraw::DrawSVGTemplate', 'Template')\n        size = 'A3' if self.a3 else 'A4'\n        frame = 'TD' if self.cartridge else '_blank'\n        template.Template = freecad_dir + '/{}_Landscape{}.svg'.format(size, frame)\n        page.Template = template\n        return page\n\n    def drawpage(self, faces, page_name):\n        \"\"\"max 4 per page, simple layout with halfs or quadrants\"\"\"\n        page = self.newPage(self.doc, page_name)\n        [W, H], ll = self._mkquadrants(len(faces))\n        for [face, name], [x0, y0] in zip(faces, ll):\n            bb = face.Shape.BoundBox\n            xr, yr = W / bb.XLength, H / bb.YLength\n            adjust = 0.7 if self.cartridge else 0.85\n            scale = min(xr, yr) * adjust if self.scale_auto else self.scale\n            scale, scr = Scale(scale).get()\n            bb.scale(scale, scale, 1) # unrolled faces in xy-plane\n\n            TopView = self.doc.addObject('TechDraw::DrawViewPart', name + ' view')\n            page.addView(TopView)\n            TopView.Source = face\n            TopView.Direction = (0, 0, 1)\n            TopView.XDirection = (1, 0, 0)\n            TopView.Scale = scale\n            TopView.X = x0\n            TopView.Y = y0\n\n            Text = self.doc.addObject('TechDraw::DrawViewAnnotation', name + ' txt')\n            page.addView(Text)\n            Text.Text = '{} [{}]'.format(name, scr)\n            Text.recompute() # for size\n            Text.X = x0\n            yt = y0 - bb.YLength / 2 - Text.TextSize.Value * 1.5\n            Text.Y = max(1, yt)\n\n        self.doc.recompute()\n        page.ViewObject.doubleClicked()\n        FreeCADGui.runCommand('TechDraw_ToggleFrame', 0)\n\n\nclass Drawing2dLegacy:\n    \"\"\"\n    makes 2d drawing with Drawing wb (original layout engine, now legacy)\n    - obj_l: list of objects\n    \"\"\"\n    ## untouched logic in v1.1\n    def __init__(self, scale, scale_auto, a3, cartridge, onedrawing, page_str):\n        self.TopX_H = self.TopY_H = 0\n        self.TopX_V = self.TopY_V = 0\n        self.TopX_Hmax = self.TopY_Hmax = 0\n        self.TopX_Vmax = self.TopY_Vmax = 0\n        self.a3 = a3\n        self.scale = scale\n        self.scale_auto = scale_auto\n        self.cartridge = cartridge\n        self.onedrawing = onedrawing\n        self.marge = 6\n        if self.a3:\n            self.L, self.H = 420, 297\n        else:\n            self.L, self.H = 297, 210\n        self.name = page_str\n\n    def newPage(self):\n        freecad_dir = os.path.join(FreeCAD.getResourceDir(), dwgtpllegacy)\n        doc = FreeCAD.ActiveDocument\n        page = doc.addObject('Drawing::FeaturePage', self.name)\n        size = 'A3' if self.a3 else 'A4'\n        frame = '' if self.cartridge else '_plain'\n        page.Template = freecad_dir + '/{}_Landscape{}.svg'.format(size, frame)\n        return page\n\n\n    def all2d(self, objname_l):\n        obj1_l = []\n        for objid in range(len(objname_l)):\n            if objid == 0 or not self.onedrawing:\n                page = self.newPage()\n            obj1_l.extend(self.done(objid, objname_l[objid]))\n        return obj1_l\n\n    def done(self, idx, objname):\n        obj_l = []\n        obj, objname = objname\n        marge = self.marge\n        bb = obj.Shape.BoundBox\n        xmax = bb.XMax - bb.XMin\n        ymax = bb.YMax - bb.YMin\n\n        if ymax > xmax:\n            Draft.rotate(obj, 90)\n        Draft.move(obj, Vector(-bb.XMin, -bb.YMin, 0))\n        xmax = bb.XMax - bb.XMin\n        ymax = bb.YMax - bb.YMin\n\n        scale = min((self.L-4 * marge) / xmax, (self.H-4 * marge) / ymax)\n\n        if (not self.scale_auto) or self.onedrawing:\n            scale = self.scale\n\n        PrintMessage(\"UnrollRuledSurface.drawing: scale= {:.2f}\\n\".format(scale))\n\n\n        if idx == 0 or not self.onedrawing:\n            PrintMessage(\"Drawing2d: init\\n\")\n            TopX = self.TopX_H = marge * 2\n            TopY = self.TopY_H = marge * 2\n            self.TopX_H = self.TopX_H + xmax * scale + marge\n            self.TopY_H = self.TopY_H\n            self.TopX_Hmax = max(self.TopX_Hmax, self.TopX_H)\n            self.TopY_Hmax = max(self.TopY_Hmax,\n                                 self.TopY_H + ymax * scale + marge)\n            self.TopX_Vmax = max(self.TopX_Vmax, self.TopX_Hmax)\n            self.TopX_V = max(self.TopX_Vmax, self.TopX_V)\n            self.TopY_V = marge * 2\n\n        elif self.onedrawing:\n            if self.TopX_H + xmax * scale < self.L:\n                if self.TopY_H + ymax * scale + marge * 2 < self.H:\n                    ## H Add at right on same horizontal line\n                    PrintMessage(\"Drawing2d: horizontal\\n\")\n                    TopX, TopY = self.TopX_H, self.TopY_H\n                    self.TopX_H = self.TopX_H + xmax * scale + marge\n                    self.TopX_Hmax = max(self.TopX_Hmax, self.TopX_H)\n                    self.TopY_Hmax = max(self.TopY_Hmax,\n                                         self.TopY_H + ymax * scale + marge)\n                    self.TopX_Vmax = max(self.TopX_Hmax, self.TopX_Vmax)\n                    self.TopX_Vmax = max(self.TopX_Vmax, self.TopX_Hmax)\n                    self.TopX_V = max(self.TopX_Vmax, self.TopX_V)\n\n                else:\n                    ## V Add at right on same horizontal line\n                    PrintMessage(\"Drawing2d: vertival\\n\")\n                    if (self.TopX_V + ymax * scale + 2 * marge < self.L\n                        and self.TopY_V + xmax * scale + 2 * marge < self.H):\n                        Draft.rotate(obj, 90)\n                        Draft.move(obj, Vector(-bb.XMin, -bb.YMin, 0))\n                        x0 = xmax; xmax = ymax; ymax = x0\n                        self.TopX_V = max(self.TopX_Vmax, self.TopX_V)\n                        TopX, TopY = self.TopX_V, self.TopY_V\n                        self.TopX_V = self.TopX_V + xmax * scale + marge\n                        self.TopY_Vmax = max(self.TopY_Vmax,\n                                             self.TopY_V + ymax * scale + marge)\n\n                    else:\n                        obj_l.append([obj, self.name])\n                        return obj_l\n\n            else:\n                ## H Carriage return\n                if self.TopY_Hmax + ymax * scale + self.marge*2 < self.H:\n                    msg = \"Drawing2d: carriage return: {} > {}\\n\"\n                    PrintMessage(msg.format(self.TopY_H + ymax * scale, self.H))\n                    TopX = self.marge * 2\n                    TopY = self.TopY_Hmax\n                    self.TopX_H = TopX + xmax * scale + self.marge\n                    self.TopY_H = TopY\n                    self.TopX_Hmax = max(self.TopX_Hmax, self.TopX_H)\n                    self.TopY_Hmax = self.TopY_Hmax + ymax * scale + self.marge\n                    self.TopX_Vmax = max(self.TopX_Vmax, self.TopX_Hmax)\n                    self.TopX_V = max(self.TopX_Vmax, self.TopX_V)\n    \n                else:\n                    ## V Add at right on same horizontal line\n                    msg = \"Drawing2d: vertival: {} , {}\\n\"\n                    PrintMessage(msg.format(self.TopX_V, self.TopX_Vmax))\n                    if (self.TopX_V + ymax * scale + 2 * marge < self.L\n                        and self.TopY_V + xmax * scale + 2 * marge < self.H):\n                        Draft.rotate(obj, 90)\n                        Draft.move(obj, Vector(-bb.XMin, -bb.YMin, 0))\n                        x0 = xmax; xmax = ymax; ymax = x0\n                        TopX, TopY = self.TopX_V, self.TopY_V\n                        self.TopX_V = self.TopX_V + xmax * scale + marge\n                        self.TopY_Vmax = max(self.TopY_Vmax,\n                                             self.TopY_V + ymax * scale + marge)\n    \n                    else:\n                        obj_l.append([obj, objname])\n                        return obj_l\n\n        doc = FreeCAD.ActiveDocument\n        page = doc.getObject(self.name)\n\n        Text = doc.addObject('Drawing::FeatureViewAnnotation', f\"{objname}_txt\")\n        Text.Text = objname\n        Text.X = TopX + xmax * scale / 2\n        Text.Y = TopY + ymax * scale / 2\n        Text.Scale = 2\n\n        TopView = doc.addObject('Drawing::FeatureViewPart', objname)\n        TopView.Source = obj\n        TopView.Direction = (0, 0, 1)\n        TopView.Rotation = 0\n        TopView.X = TopX\n        TopView.Y = TopY\n        TopView.ShowHiddenLines = False\n        TopView.Scale = scale\n        page.addObject(TopView)\n        page.addObject(Text)\n        doc.recompute()\n        page.ViewObject.doubleClicked()\n        return obj_l\n\n\n\n#####################################\n###   Dialog Box\n#####################################\n\nDialogBox = QtGui.QDialog()\nDialogBox.setWindowTitle(\"UnrollRuledSurface\")\nla = QtGui.QGridLayout(DialogBox)\nla.setSpacing(7)\nbuttonGrpEdge = QtGui.QButtonGroup(DialogBox)\nbuttonGrpFormat = QtGui.QButtonGroup(DialogBox)\n\ncols = 4\nla.addWidget(QtGui.QLabel(\"File Name\"), 0, 0, 1, cols)\nfname = QtGui.QLineEdit(\"UnrollSurface\")\nla.addWidget(fname, 1, 0, 1, cols)\n\nla.addWidget(QtGui.QLabel(\"Discretization Points Nbr\"), 2, 0, 1, cols)\ndpts = QtGui.QLineEdit(\"30\")\nla.addWidget(dpts, 3, 0, 1, 2)\n\n###\nla.addWidget(QtGui.QLabel(\"Generatrices from edge:\"), 4, 0, 1, 2)\nedgezero = QtGui.QRadioButton(\"0 to 3\")\nla.addWidget(edgezero, 4, 2)\nedgeone = QtGui.QRadioButton(\"1 to 4\")\nla.addWidget(edgeone, 4, 3)\nbuttonGrpEdge.addButton(edgezero); buttonGrpEdge.addButton(edgeone)\nedgezero.setChecked(True)\n\n###\nmkdwg = QtGui.QCheckBox(\"Make drawing\")\nmkdwg.setChecked(True)\nla.addWidget(mkdwg, 5, 0, 1, 2)\n\nlegacylayout = QtGui.QCheckBox(\"Legacy layout\")\nlegacylayout.setChecked(False)\nla.addWidget(legacylayout, 5, 2, 1, 2)\n\n\n###\nautoscale = QtGui.QCheckBox(\"Auto scale\")\nautoscale.setChecked(True)\nla.addWidget(autoscale, 6, 0, 1, 2)\n\nla.addWidget(QtGui.QLabel(\"Scale\"), 6, 2)\nscale = QtGui.QLineEdit(\"1\")\nla.addWidget(scale, 6, 3)\n\n###\nla.addWidget(QtGui.QLabel(\"Paper size:\"), 7, 0, 1, 2)\nrba4 = QtGui.QRadioButton(\"A4\")\nla.addWidget(rba4, 7, 2)\nrba3 = QtGui.QRadioButton(\"A3\")\nla.addWidget(rba3, 7, 3)\nbuttonGrpFormat.addButton(rba4); buttonGrpFormat.addButton(rba3)\nrba4.setChecked(True)\n\n###\ncartridge = QtGui.QCheckBox(\"Cartridge\")\ncartridge.setChecked(False)\nla.addWidget(cartridge, 8, 0, 1, 2)\n\ngroupdwg = QtGui.QCheckBox(\"Group drawings in page\")\ngroupdwg.setChecked(True)\nla.addWidget(groupdwg, 8, 2, 1, 2)\n\n###\nbox = QtGui.QDialogButtonBox(DialogBox)\nbox.setOrientation(QtCore.Qt.Horizontal)\nbox.setStandardButtons(QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok)\nla.addWidget(box, 9, 0, 1, cols)\n\n###\nsettings.update(dict(fname=fname, dpts=dpts, edge=buttonGrpEdge,\n                     mkdwg=mkdwg, legacylayout=legacylayout,\n                     autoscale=autoscale, scale=scale,\n                     papersize=buttonGrpFormat,\n                     cartridge=cartridge, groupdwg=groupdwg))\n\nQtCore.QObject.connect(box, QtCore.SIGNAL(\"accepted()\"), proceed)\nQtCore.QObject.connect(box, QtCore.SIGNAL(\"rejected()\"), close)\nQtCore.QMetaObject.connectSlotsByName(DialogBox)\nDialogBox.show()\n",
    "url": "https://wiki.freecad.org/Macro_Unroll_Ruled_Surface",
    "raw_code_url": "",
    "wiki": "https://wiki.freecad.org/Macro_Unroll_Ruled_Surface",
    "version": "1.1",
    "license": "",
    "date": "2022-07-24",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Herv\u00e9 B., heda",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Unroll_Ruled_Surface.png",
    "icon_source": "https://wiki.freecad.org/images/b/ba/Macro_Unroll_Ruled_Surface.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Cabinets32",
    "on_wiki": true,
    "on_git": false,
    "desc": "This macro creates Top/Bottom and sidewalls for a cabinet with System32 specification. <p>The defaults in the Macro are for parts of manufacturer Hettich.<br /><br />Macro version: 1.0<br />Last modified: 2015-01-22<br />FreeCAD version: All<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://www.freecadweb.org/wiki/images/6/64/Macro_Cabinets32.png\">ToolBar Icon</a><br />Author: Berner<br /> </p> ",
    "comment": "This macro creates Top/Bottom and sidewalls for a cabinet with System32 specification. The defaults in the Macro are for parts of manufacturer Hettich.",
    "code": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# ***************************************************************************\n# *                                                                         *\n# *   Copyright (c) 2015 Bruno Bueckmann reset12 at gmx.de                  *\n# *                      http://home.bb-24.net                              *\n# *   This program is free software; you can redistribute it and/or modify  *\n# *   it under the terms of the GNU Lesser General Public License (LGPL)    *\n# *   as published by the Free Software Foundation; either version 2 of     *\n# *   the License, or (at your option) any later version.                   *\n# *   for detail see the LICENCE text file.                                 *\n# *                                                                         *\n# *   This program is distributed in the hope that it will be useful,       *\n# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n# *   GNU Library General Public License for more details.                  *\n# *                                                                         *\n# *   You should have received a copy of the GNU Library General Public     *\n# *   License along with this program; if not, write to the Free Software   *\n# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *\n# *   USA                                                                   *\n# *                                                                         *\n# ***************************************************************************\n\n\n# Macro Begin: cabinets32.FCMacro ++++++++++++++++++++++++++++++++++++++++++++++\n# This Macro generates holes and a groove for the side Base cabinet\n# Top and Bottom Wall are OUTSIDE the side base\n# like :\n# -------\n# |     |\n# |     |\n# -------\n\nfrom __future__ import division\n\nimport FreeCAD as App\nimport FreeCADGui as Gui\nfrom PySide import QtGui\n\n# GUI\ndebug = False  # debugging on\nguiok = True  # flag for abort input\n\nwidth, ok = QtGui.QInputDialog.getDouble(\n    QtGui.QWidget(), 'Thickness', 'Thickness of cabinet-side', 19, 0, 50, 2)\nif ok:\n    length, ok = QtGui.QInputDialog.getDouble(\n        QtGui.QWidget(), 'Depth', 'Depth of cabinet-side', 600, 0, 2000, 2)\nelse:\n    guiok = False\n\nif ok and guiok:\n    height, ok = QtGui.QInputDialog.getDouble(\n        QtGui.QWidget(), 'Height', 'Height of cabinet-side', 2000, 0, 3000, 2)\nelse:\n    guiok = False\n\nif ok and guiok:\n    bradius, ok = QtGui.QInputDialog.getDouble(\n        QtGui.QWidget(), 'Bradius', 'Radius of drill holes in cabinet-side',\n        2.5, 0, 50, 2)\nelse:\n    guiok = False\n\nif ok:\n    bdeep, ok = QtGui.QInputDialog.getDouble(\n        QtGui.QWidget(), 'Bdeep', 'Depth of drill holes in cabinet-side',\n        12, 0, 50, 2)\nelse:\n    guiok = False\n\nif ok:\n    fdist, ok = QtGui.QInputDialog.getDouble(\n        QtGui.QWidget(), 'Fdist', 'Distance to Front of cabinet-side',\n        37, 0, 50, 2)\nelse:\n    guiok = False\n\nif ok:\n    hole1, ok = QtGui.QInputDialog.getDouble(\n        QtGui.QWidget(), 'Hole1',\n        'Distance first hole from top or bottom of cabinet-side', 10, 0, 50, 2)\nelse:\n    guiok = False\n\nif ok:\n    holedistance, ok = QtGui.QInputDialog.getDouble(\n        QtGui.QWidget(), 'Holedistance',\n        'Distance from hole to hole (System 32)', 32, 1, 50, 2)\nelse:\n    guiok = False\n\nif ok:\n    groovethickness, ok = QtGui.QInputDialog.getDouble(\n        QtGui.QWidget(), 'Groovethickness', 'Thickness of backpanel',\n        3, 1, 50, 2)\nelse:\n    guiok = False\n\nif ok:\n    groovedeep, ok = QtGui.QInputDialog.getDouble(\n        QtGui.QWidget(), 'Groovedeep',\n        'Overlapping of backpanel in cabinet-side', 12, 1, 50, 2)\nelse:\n    guiok = False\n\nif guiok:\n    # VB 35 / 18 or VB 36 M /19 from Hettich\n    connector, ok = QtGui.QInputDialog.getInt(\n        QtGui.QWidget(), 'Connectortype',\n        'Zerohole(0) Singlehole(1) or Doublehole(2) Connector', 2, 0, 2, 1)\n\nif ok:\n    fillwithholes, ok = QtGui.QInputDialog.getItem(None,\n            \"Fillwithholes\",\n            \"Fill Board with holes?\",\n            [\"no\", \"yes\"],\n            editable=False)\nelse:\n    guiok = False\n\nendhole = 9.5\n\nif ok and guiok:\n    endholes, ok = QtGui.QInputDialog.getItem(None,\n            \"Endholes\",\n            \"Drill Holes on Top/Bottom vertical for Connectors\",\n            ['no', 'yes'],\n            editable=False)\n\nif ok and guiok and endholes == 'yes':\n    endhole, ok = QtGui.QInputDialog.getDouble(\n        QtGui.QWidget(), 'Endhole',\n        'Endhole distance from inner cabinet-side', 9.5, 1, 50, 2)\nif debug:\n    App.Console.PrintMessage(\"ok?: {}\\n\".format(ok))\n    App.Console.PrintMessage(\"width = {}\\n\".format(width))\n    App.Console.PrintMessage(\"length = {}\\n\".format(length))\n    App.Console.PrintMessage(\"bradius = {}\\n\".format(bradius))\n    App.Console.PrintMessage(\"bdeep = {}\\n\".format(bdeep))\n    App.Console.PrintMessage(\"fdist = {}\\n\".format(fdist))\n    App.Console.PrintMessage(\"hole1 = {}\\n\".format(hole1))\n    App.Console.PrintMessage(\"holedistance = {}\\n\".format(holedistance))\n    App.Console.PrintMessage(\"groovethickness = {}\\n\".format(groovethickness))\n    App.Console.PrintMessage(\"groovedeep = {}\\n\".format(groovedeep))\n    App.Console.PrintMessage(\"connector = {}\\n\".format(connector))\n    App.Console.PrintMessage(\"fillwithholes = {}\\n\".format(fillwithholes))\n    App.Console.PrintMessage(\"endholes = {}\\n\".format(endholes))\n    App.Console.PrintMessage(\"endhole = {}\\n\".format(endhole))\n    App.Console.PrintMessage(\"guiok = {}\\n\".format(guiok))\n# End GUI\n\nif guiok:\n    # width= 19\t# thickness of korpus\n    # length= 600\t# width of korpus\n    # height= 2000\t# height of korpus\n    #\n    # bradius = 2.5  \t# Radius drill hole\n    # bdeep = 12     \t# deepness of drill hole\n    # fdist = 37    \t# Distance to Front\n    # hole1 = 9.5\t# Distance first hole from top or bottom of korpus\n    # holedistance = 32  # System 32\n    # groovethickness = 3 # 3 mm backpanel\n    # groovedeep = width-8 # deep of groovedeep\n    if int(width) > 16:\n        # First hole depends on specs for VB36 M / 19 for 19 mm boards from\n        # Hettich.\n        holetop = 9.5  # holedistance for screw of vb36\n        hole1 = 9.5 + 0.5  # distance hole 1 from end of board\n        hole1r = 10  # radius first hole\n        hole1d = 14  # deepness first hole\n        hole2r = 5  # radius 2. hole\n        hole2d = 10.5  # deepness 2. hole\n    else:\n        # First hole depends on specs for VB36 M / 16 for 16 mm boards from\n        # Hettich.\n        holetop = 9.5  # holedistance for screw of vb36\n        hole1 = 9.5 + 0.5  # distance hole 1 from end of board\n        hole1r = 10  # radius first hole\n        hole1d = 12.5  # deepness first hole\n        hole2r = 5  # radius 2. hole\n        hole2d = 10.5  # deepness 2. hole\n\n    if debug:\n        App.Console.PrintMessage(\"hole1d = {}\\n\".format(hole1d))\n\n    # functions\n    def cut(tool):\n        global cutsnr\n        global cuts\n        # cuts objects defined in string cuts\n        if debug:\n            App.Console.PrintMessage(\"cuts = {}, cutsnr = {}\\n\".format(\n                cuts, cutsnr))\n        data = 'App.activeDocument().addObject(\"Part::Cut\",\"' + str(cuts.split(\" \")[cutsnr + 1]) + '\")'\n        if debug:\n            App.Console.PrintMessage(str(data) + \"\\n\")\n        exec(data)\n        data = \"App.activeDocument().\" + str(cuts.split(\" \")[cutsnr + 1])\n        data = data + \".Base = App.activeDocument().\" + str(cuts.split(\" \")[cutsnr])\n        if debug:\n            App.Console.PrintMessage(str(data) + \"\\n\")\n        exec(data)\n        data = \"App.activeDocument().\" + str(cuts.split(\" \")[cutsnr + 1])\n        data = data + \".Tool = App.activeDocument().\" + str(tool)\n        if debug:\n            App.Console.PrintMessage(str(data) + \"\\n\")\n        exec(data)\n        cutsnr = cutsnr + 1\n        cuts = cuts + \" Cut%03d\" % cutsnr\n        return 0\n\n    # end functions\n\n    doc = App.activeDocument()\n\n    # Korpus\n    box = doc.addObject(\"Part::Box\", \"Box\")\n    box.Label = \"Cube\"\n    box.Length = length\n    box.Width = width\n    box.Height = height\n    # Change Color of Object.\n    box.ViewObject.DiffuseColor = (0.67, 0.67, 0.0)\n    if debug:\n        doc.recompute()\n    # Groove\n    groove = doc.addObject(\"Part::Box\", \"Groove\")\n    groove.Label = \"Groove\"\n    groove.Length = groovethickness\n    groove.Width = groovedeep\n    groove.Height = height - (2 * groovedeep)\n    groove.ViewObject.DiffuseColor = (0.67, 0.67, 0.0)\n    groove.Placement = App.Placement(\n        App.Vector(length - groovethickness, 0, groovedeep),\n        App.Rotation())\n    if debug:\n        doc.recompute()\n\n    # make endholes\n    cylinders = \"\"  # labels of cylinders to cut\n    if endholes == 'y':\n        # Bottom holes\n        cylendl = doc.addObject(\"Part::Cylinder\", \"Cylinderendl\")\n        cylendl.Label = \"Cylinderendl001\"\n        cylendl.Radius = bradius\n        cylendl.Height = bdeep\n        cylendl.Angle = 360\n        cylinders = cylinders + \" \" + cylendl.Name\n        cylendl.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        doc.ActiveObject.Placement = App.Placement(\n            App.Vector(fdist, bdeep, holetop),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n        if debug:\n            doc.recompute()\n        cylendr = doc.addObject(\"Part::Cylinder\", \"Cylinderendr\")\n        cylendr.Label = \"Cylinderendr001\"\n        cylendr.Radius = bradius\n        cylendr.Height = bdeep\n        cylendr.Angle = 360\n        cylinders = cylinders + \" \" + cylendr.Name\n        cylendr.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        cylendr.Placement = App.Placement(\n            App.Vector(length - fdist, bdeep, holetop),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n        if debug:\n            doc.recompute()\n\n        # Top holes\n        cylendl = doc.addObject(\"Part::Cylinder\", \"Cylinderendl\")\n        cylendl.Label = \"Cylinderendl002\"\n        cylendl.Radius = bradius\n        cylendl.Height = bdeep\n        cylendl.Angle = 360\n        cylinders = cylinders + \" \" + cylendl.Name\n        cylendl.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        cylendl.Placement = App.Placement(\n            App.Vector(fdist, bdeep, height - holetop),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n        if debug:\n            doc.recompute()\n        cylendr = doc.addObject(\"Part::Cylinder\", \"Cylinderendr\")\n        cylendr.Label = \"Cylinderendr002\"\n        cylendr.Radius = bradius\n        cylendr.Height = bdeep\n        cylendr.Angle = 360\n        cylinders = cylinders + \" \" + cylendr.Name\n        cylendr.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        cylendr.Placement = App.Placement(\n            App.Vector(length - fdist, bdeep, height-holetop),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n        if debug:\n            doc.recompute()\n\n    if fillwithholes == 'no':\n        n = 0\n    else:\n        n = int(height / 2 / holedistance)\n\n    # drill holes from bottom to half height\n    # reduce holes for test to 2 alternative use n\n    # Holes for Hettich VB36\n    # Bohrloecher\n    x = -1  # init value\n    if connector >= 1:\n        x = 0\n        App.Console.PrintMessage(\"x=\"+str(x) + \" \" + \"\\n\")\n        cyll = doc.addObject(\"Part::Cylinder\", \"Cylinderl\")\n        cyll.Label = \"Cylinderl%03d\" % x\n        cyll.Radius = hole1r\n        cyll.Height = hole1d\n        cyll.Angle = 360\n        cylinders = cylinders + \" \" + cyll.Name\n        cyll.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        cyll.Placement = App.Placement(\n            App.Vector(fdist, hole1d, hole1 + x * holedistance),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n        if debug:\n            doc.recompute()\n\n        cylr = doc.addObject(\"Part::Cylinder\", \"Cylinderr\")\n        cylr.Label = \"Cylinderr%03d\" % x\n        cylr.Radius = hole1r\n        cylr.Height = hole1d\n        cylr.Angle = 360\n        cylinders = cylinders + \" \" + cylr.Name\n        cylr.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        cylr.Placement = App.Placement(\n            App.Vector(length - fdist, hole1d, hole1 + x * holedistance),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n\n    if connector == 2:\n        x = 1\n        cyll = doc.addObject(\"Part::Cylinder\", \"Cylinderl\")\n        cyll.Label = \"Cylinderl%03d\" % x\n        cyll.Radius = hole2r\n        cyll.Height = hole2d\n        cyll.Angle = 360\n        cylinders = cylinders + \" \" + cyll.Name\n        cyll.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        cyll.Placement = App.Placement(\n            App.Vector(fdist, hole2d, hole1 + x * holedistance),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n        if debug:\n            doc.recompute()\n\n        cylr = doc.addObject(\"Part::Cylinder\", \"Cylinderr\")\n        cylr.Label = \"Cylinderr%03d\" % x\n        cylr.Radius = hole2r\n        cylr.Height = hole2d\n        cylr.Angle = 360\n        cylinders = cylinders + \" \" + cylr.Name\n        cylr.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        cylr.Placement = App.Placement(\n            App.Vector(length - fdist, hole2d, hole1 + x * holedistance),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n        if debug:\n            doc.recompute()\n\n    xs = x + 1\n    for x in range(xs, n):\n        # Bohrloecher\n        cyll = doc.addObject(\"Part::Cylinder\", \"Cylinderl\")\n        cyll.Label = \"Cylinderl%03d\" % x\n        cyll.Radius = bradius\n        cyll.Height = bdeep\n        cyll.Angle = 360\n        cylinders = cylinders + \" \" + cyll.Name\n        cyll.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        cyll.Placement = App.Placement(\n            App.Vector(fdist, bdeep, hole1 + x * holedistance),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n        if debug:\n            doc.recompute()\n\n        cylr = doc.addObject(\"Part::Cylinder\", \"Cylinderr\")\n        cylr.Label = \"Cylinderr%03d\" % x\n        cylr.Radius = bradius\n        cylr.Height = bdeep\n        cylr.Angle = 360\n        cylinders = cylinders + \" \" + cylr.Name\n        cylr.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        cylr.Placement = App.Placement(\n            App.Vector(length - fdist, bdeep, hole1 + x * holedistance),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n        if debug:\n            doc.recompute()\n\n    # drill holes from Top to half height\n    # # Holes for Hettich VB36\n    x = -1  # init value\n    if connector >= 1:\n        x = 0\n        cyll = doc.addObject(\"Part::Cylinder\", \"Cylinderl\")\n        cyll.Label = \"Cylinderl%03d\" % x\n        cyll.Radius = hole1r\n        cyll.Height = hole1d\n        cyll.Angle = 360\n        cylinders = cylinders + \" \" + cyll.Name\n        cyll.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        cyll.Placement = App.Placement(\n            App.Vector(fdist, hole1d, height - hole1 - x * holedistance),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n        if debug:\n            doc.recompute()\n\n        cylr = doc.addObject(\"Part::Cylinder\", \"Cylinderr\")\n        cylr.Label = \"Cylinderr%03d\" % x\n        cylr.Radius = hole1r\n        cylr.Height = hole1d\n        cylr.Angle = 360\n        cylinders = cylinders + \" \" + cylr.Name\n        cylr.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        cylr.Placement = App.Placement(\n            App.Vector(length - fdist, hole1d, height-hole1 - x * holedistance),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n        if debug:\n            doc.recompute()\n\n    if connector == 2:\n        x = 1\n        cyll = doc.addObject(\"Part::Cylinder\", \"Cylinderl\")\n        cyll.Label = \"Cylinderl%03d\" % x\n        cyll.Radius = hole2r\n        cyll.Height = hole2d\n        cyll.Angle = 360\n        cylinders = cylinders + \" \" + cyll.Name\n        cyll.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        cyll.Placement = App.Placement(\n            App.Vector(fdist, hole2d, height - hole1 - x * holedistance),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n        if debug:\n            doc.recompute()\n\n        cylr = doc.addObject(\"Part::Cylinder\", \"Cylinderr\")\n        cylr.Label = \"Cylinderr%03d\" % x\n        cylr.Radius = hole2r\n        cylr.Height = hole2d\n        cylr.Angle = 360\n        cylinders = cylinders + \" \" + cylr.Name\n        cylr.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        cylr.Placement = App.Placement(\n            App.Vector(\n                length - fdist, hole2d, height - hole1 - x * holedistance),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n        if debug:\n            doc.recompute()\n\n    xs = x + 1\n    for x in range(xs, n):\n        # Drillholes\n        cyll = doc.addObject(\"Part::Cylinder\", \"Cylinderl\")\n        cyll.Label = \"Cylinderl%03d\" % x\n        cyll.Radius = bradius\n        cyll.Height = bdeep\n        cyll.Angle = 360\n        cylinders = cylinders + \" \" + cyll.Name\n        cyll.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        cyll.Placement = App.Placement(\n            App.Vector(fdist, bdeep, height - hole1 - x * holedistance),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n        if debug:\n            doc.recompute()\n\n        cylr = doc.addObject(\"Part::Cylinder\", \"Cylinderr\")\n        cylr.Label = \"Cylinderr%03d\" % x\n        cylr.Radius = bradius\n        cylr.Height = bdeep\n        cylr.Angle = 360\n        cylinders = cylinders + \" \" + cylr.Name\n        cylr.ViewObject.DiffuseColor = (0.0, 0.0, 0.0)\n        cylr.Placement = App.Placement(\n            App.Vector(\n                length - fdist, bdeep, height - hole1 - x * holedistance),\n            App.Rotation(App.Vector(1, 0, 0), 90))\n        if debug:\n            doc.recompute()\n\n    if debug:\n        App.Console.PrintMessage(\"cylinders = \")\n        App.Console.PrintMessage(cylinders + \"\\n\")\n\n    # cut all holes\n    cuts = \"Box Cut\"  # cut labels\n    cutsnr = 0     \t# index number in cuts\n    # cut groove\n    cut(\"Groove\")\n    cyls = cylinders.split()  # number of words\n    if debug:\n        App.Console.PrintMessage(\"n=\" + str(cyls) + \"\\n\")\n    for x in cyls:\n        if debug:\n            App.Console.PrintMessage(\"cylinder(\" + x + \")=\" + str(x) + \"\\n\")\n        cut(str(x))\n    doc.recompute()\n    Gui.SendMsgToActiveView('ViewFit')\n\n# OS: Ubuntu 14.04.1 LTS\n# Word size of OS: 32-bit\n# Word size of FreeCAD: 32-bit\n# Version: 0.15.4410 (Git)\n# Branch: master\n# Hash: 9ee08a97ea81304e2690694f76ee2dc013556a5d\n# Python version: 2.7.6\n# Qt version: 4.8.6\n# Coin version: 4.0.0a\n",
    "url": "https://wiki.freecad.org/Macro_Cabinets32",
    "raw_code_url": "",
    "wiki": "",
    "version": "",
    "license": "",
    "date": "2015-01-22",
    "src_filename": "",
    "filename_from_url": "",
    "author": "Berner",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Cabinets32.png",
    "icon_source": "https://www.freecadweb.org/wiki/images/6/64/Macro_Cabinets32.png",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  },
  {
    "name": "Joint",
    "on_wiki": true,
    "on_git": false,
    "desc": "Make joints of various types, including mortise/tenon, box joints, dovetail joints, and various snap joints<br /><br />Macro version: 0.2022.12.21<br />Last modified: 2022-12-21<br />FreeCAD version: Python 3 versions<br />Download: <a rel=\"nofollow\" class=\"external text\" href=\"https://wiki.freecadweb.org/File:Macro_Joint_Icon.svg\">ToolBar Icon</a><br />Author: TheMarkster<br /> ",
    "comment": "Make joints of various types, including mortise/tenon, box joints, dovetail joints, and various snap joints",
    "code": "# -*- coding: utf-8 -*-\n__version__ = \"0.2022.12.21\"\n#__version__ = \"0.2022.12.21\"\n#__title__ = \"Joint Macro\"\n#__author__ = \"<TheMarkster> 2021\"\n#__license__ = \"LGPL 2.1\"\n#__doc__ = \"Create a mortise/tenon joint, box joint, dovetail joint, ball joint, or split joint.\"\n#__usage__ = '''Select the face and activate the tool, modify properties as desired'''\n#import Part, FreeCADGui, FreeCAD\n#from PySide import QtGui,QtCore\n#import DraftGeomUtils as DGU\n#import math\n#\n#class Joint:\n#    def __init__(self,obj):\n#        jointGroup = \"Joint v.\"+__version__\n##        obj.addProperty(\"App::PropertyString\",\"AddSubType\",jointGroup,\"Additive, Subtractive type when using Part Design pattern tools -- set at time of object creation.\")\n##        obj.setEditorMode(\"AddSubType\",1)#readonly\n#        obj.addProperty(\"App::PropertyFloat\", \"Undercut\",\"Cantilever\",\"Cantilever undercut (readonly) calculated value\")\n#        obj.setEditorMode(\"Undercut\",1) #readonly\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"SplitRadius\",\"Split Joint\",\"Radius of spheres\").SplitRadius = (1,0.01,float(\"inf\"),.1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"SplitSlotWidth\",\"Split Joint\",\"Width of slot in Split Joints\").SplitSlotWidth = (2,0,float(\"inf\"),.1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"SplitSlotFilletRadius\",\"Split Joint\",\"Radius of fillets at base of slot in Split Joints\").SplitSlotFilletRadius = (.5,0.01,float(\"inf\"),.1)\n#        obj.addProperty(\"App::PropertyBool\",\"SplitRounded\",\"Split Joint\", \"Split Joints -- Whether to have a rounded end or a flat end\").SplitRounded = True\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"BallRadius\",\"Ball Joint\",\"Ball joints only -- radius of the ball, in mm\").BallRadius=(5,0,1e13,.1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"BallStemRadius\",\"Ball Joint\", \"Ball joints only -- radius of stem connecting ball to face surface\").BallStemRadius=(2,0,1e13,.1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"BallStemLength\",\"Ball Joint\", \"Ball joints only -- length of stem connecting ball to face surface\").BallStemLength=(2,0,1e13,.1)\n#        obj.addProperty(\"App::PropertyIntegerConstraint\",\"BallSlotCount\",\"Ball Joint\",\"Ball joints only -- count of slots cut from ball\").BallSlotCount = (3,0,1000,1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"BallSlotThickness\",\"Ball Joint\",\"Ball joints only -- size of slot in mm\").BallSlotThickness = (.5,0.0,float(\"inf\"),.1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"BallFilletRadius\",\"Ball Joint\",\"Ball joints only -- radius of fillet (in mm) at stem base and ball base\").BallFilletRadius = (0.5,0,1e13,.1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"BallSlotToolFilletRadius\",\"Ball Joint\",\"Ball joints only -- radius of fillet (in mm) at stem base and ball base\").BallSlotToolFilletRadius = (0.1,0,1e13,.1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"BallSlotToolCoreRadius\",\"Ball Joint\",\"Ball joints only -- radius of slot cutting tool core cylinder\").BallSlotToolCoreRadius = (0.5,0,1e13,.1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"BallSlotToolCoreSphereRadius\",\"Ball Joint\",\"Ball joints only -- radius of slot cutting tool core sphere\").BallSlotToolCoreSphereRadius = (3.5,0,1e13,.1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"BallMateStart\",\"Ball Joint\",\"Ball joints only -- ratio from 0 to 1.0 for start of ball mate relative to ball diameter\").BallMateStart = (0.33,0.01,1,.01)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"BallSlotStart\",\"Ball Joint\",\"Ball joints only -- ratio from 0 to 1.0 for start of ball slot relative to ball diameter\").BallSlotStart = (0.2,0,1,.01)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"RadiusFactor\",\"Cantilever\",\"Radius factor * length = radius of filet at base\").RadiusFactor =(0.6,-float(\"inf\"),float(\"inf\"),.1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"HeadSpaceAdjust\",\"Cantilever\",\"(Cantilever Mate only) adjusts the amount of free space between the hook nose tip and the mate back wall\").HeadSpaceAdjust =(0,-float(\"inf\"),float(\"inf\"),.1)\n#        obj.addProperty(\"App::PropertyFloat\",\"UndercutAngle\",\"Cantilever\",\"(Cantilver only) adjust angle of undercut\")\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"UndercutPositionTweak\",\"Cantilever\",\"(Cantilever only) adjust position of undercut\").UndercutPositionTweak = (0,-float(\"inf\"),float(\"inf\"),.1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"SlotBottom\",\"Annular\",\"Annular Hook only - position of bottom of slot as ratio of overall height, default = 0.25\").SlotBottom = (0.25,0,1,.05)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"SlotToolFilletRadius\",\"Annular\",\"Annular Hook only - radius if fillets applied to slot cutting tool, default = .5\").SlotToolFilletRadius = (.5,0,float(\"inf\"),.1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"Scale\",jointGroup,\"Scale factor, default = 1.0 - be advised: what works at one scale might not work so well at another\").Scale = (1.0,-float(\"inf\"),float(\"inf\"),.1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"SlotAngle\",\"Annular\",\"Annular Hook only - angle of slot cutting tool, e.g. 90 degrees would cut 1/4 of the way around\").SlotAngle = (20,-360,360,1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"DiameterTweak\",\"Annular\",\"Annular types only - tweak diameter of revolved faces\").DiameterTweak = (0,-float(\"inf\"),float(\"inf\"),.1)\n#        obj.addProperty(\"App::PropertyIntegerConstraint\",\"SlotCount\",\"Annular\",\"Annular Hook only - number of slots to cut\").SlotCount = (6,0,100,1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"Taper\",\"Cantilever\",\"(Cantilever Hook) thickness of hook end compared to hook base, as a ratio.  default: 0.3\").Taper = (0.3,0.01,1.0,0.01)\n#        obj.addProperty(\"App::PropertyFloat\",\"NoseAngle\",\"Cantilever\",\"Angle of cantilever hook nose, in degrees\").NoseAngle = 60\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"MaterialDeflection\",\"Cantilever\",\"Permissible deflection of material, default = 2%\").MaterialDeflection = (0.02,-float(\"inf\"),float(\"inf\"),.001)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"CantileverMateClearance\",\"Cantilever\",\"Clearance for hook / mate.  Default 0.5 mm (for FDM), recommended 0.3 mm for other 3D printer types\").CantileverMateClearance = (.5,-float(\"inf\"),float(\"inf\"),.1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"ShapeDeflection\",\"Cantilever\",\"Deflection factor for rectangular cross section cantilevers, default = 1.09\").ShapeDeflection = (1.09,-float(\"inf\"),float(\"inf\"),.01)\n#        obj.addProperty(\"App::PropertyEnumeration\",\"JointType\",jointGroup,\"Type of joint to make\").JointType=[\"Mortise\",\"Tenon\",\"Box Joint\",\"Dovetail Joint\",\"Cantilever Hook\", \"Cantilever Mate\",\"Annular Hook\", \"Annular Mate\",\"Ball Joint\", \"Ball Mate\",\"Split Joint\", \"Split Mate\"]\n#        obj.addProperty(\"App::PropertyFloat\",\"Depth\",\"Dimensions\",\"depth of joint below or above surface\").Depth=5\n#        obj.addProperty(\"App::PropertyBool\",\"Rounded\",jointGroup,\"Mortise/Tenon has rounded ends\").Rounded=True\n#        obj.addProperty(\"App::PropertyVector\",\"Position\",\"Positioning\",\"XYZ position adjustments (internal coordinate system)\")\n#        obj.addProperty(\"App::PropertyFloat\",\"FingerWidth\",\"Dimensions\",\"Width of fingers (for Box Joints / Dovetail Joints only)\").FingerWidth=5\n#        obj.addProperty(\"App::PropertyFloat\",\"FingerAngle\",\"Dimensions\",\"Angle of fingers in degrees (for Box Joints / Dovetail Joints only)\").FingerAngle=30\n#        obj.addProperty(\"App::PropertyFloat\",\"FingerAngle2\",\"Dimensions\",\"Angle of fingers in degrees (for Box Joints / Dovetail Joints only)\").FingerAngle2=30\n#        obj.addProperty(\"App::PropertyFloat\",\"BottomFilletAngle\",\"Cantilever\",\"(Cantilever Hook) angle where fillet meets angled edge of hook\").BottomFilletAngle = 110\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"Width\",\"Dimensions\",\"width of joint\").Width=(5,0.01,10e13,1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"Length\",\"Dimensions\",\"length of joint from tip of arc to tip of arc\").Length=(5,1,10e13,1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"Offset\",\"Dimensions\",\"Clearance offset for adjusting the fit\").Offset=(0,-10e13,10e13,.1)\n#        obj.addProperty(\"App::PropertyLinkSub\",\"Face\",jointGroup,\"Selected face for the joint\")\n#        obj.addProperty(\"App::PropertyBool\",\"EditFace\",jointGroup,\"Trigger, toggle to bring up face editor\").EditFace = False\n#        obj.addProperty(\"App::PropertyBool\",\"Boolean\",jointGroup,\"Whether to fuse with or cut from base feature\").Boolean = True\n#        obj.addProperty(\"App::PropertyBool\",\"Symmetric\",\"Positioning\",\"Symmetric to plane (at depth in both directions)\").Symmetric = True\n#        obj.addProperty(\"App::PropertyBool\",\"Reversed\",\"Positioning\",\"Extrude in oppositie direction if True\").Reversed = False\n#        obj.addProperty(\"App::PropertyBool\",\"UseOdd\",\"Positioning\",\"(Box Joints / Dovetails only) cut odd fingers if True, else cut even fingers\").UseOdd = False\n#        obj.addProperty(\"App::PropertyBool\",\"ShowTool\",\"Positioning\",\"To aid in positioning the cutting tool set this temporarily to True\\nSet back to False after positioning tool to create the joint.\").ShowTool = False\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"Angle\",\"Positioning\",\"Rotation angle (in degrees) about the local Z axis\").Angle = (0,-360,360,1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"AngleX\",\"Positioning\",\"Rotation angle (in degrees) about the local X axis\").AngleX = (0,-360,360,1)\n#        obj.addProperty(\"App::PropertyFloatConstraint\",\"AngleY\",\"Positioning\",\"Rotation angle (in degrees) about the local Y axis\").AngleY = (0,-360,360,1)\n#        if not hasattr(obj,\"Refine\"):\n#            obj.addProperty(\"App::PropertyBool\",\"Refine\", jointGroup, \"refine feature\").Refine = False\n#        obj.addProperty(\"App::PropertyBool\",\"ClaimChildren\",jointGroup,\"whether to claim children in the tree\").ClaimChildren = True\n#        obj.setEditorMode(\"Placement\",2) #hidden\n#        self.editingMode = False\n#        self.fpName = obj.Name\n#        obj.Proxy = self\n#\n#    def recompute(self):\n#        t = QtCore.QTimer()\n#        t.singleShot(50,FreeCAD.ActiveDocument.recompute)\n#\n#    def onBeforeChange(self,fp,prop):\n#        pass\n#\n#    def onChanged(self,fp,prop):\n#        if prop == \"EditFace\" and fp.EditFace == True:\n#            t = QtCore.QTimer()\n#            t.singleShot(50, self.editFace) #avoid warning message about selection changing while committing data\n#            fp.EditFace = False\n#\n#    def editFace(self):\n#        fp = FreeCAD.ActiveDocument.getObject(self.fpName)\n#        if not fp.Face:\n#            return\n#        object = fp.Face[0]\n#        if not object:\n#            return\n#        if not FreeCADGui.Control.activeDialog():\n#            panel = TaskEditLinkSubPanel(fp,\"Face\",\"Face\")\n#            FreeCADGui.Control.showDialog(panel)\n#            self.editingMode = True #tells execute() not to hide the linked object\n#        else:\n#            self.editingMode=False\n#            FreeCAD.Console.PrintError(\"Another task dialog is active.  Close that one and try again.\\n\")\n#\n#    def hideThem(self,fp,proplist,hide=True):\n#        for prop in proplist:\n#            mode = 2 if hide else 0\n#            fp.setEditorMode(prop,mode)\n#\n#    def hideProps(self,fp):\n#        '''hide properties unrelated to this type of joint'''\n#        mortiseTenonOnly = [\"Rounded\"]\n#        splitProps = [\"SplitRadius\",\"SplitSlotWidth\",\"SplitSlotFilletRadius\",\"SplitRounded\"]\n#        fingerProps = [\"FingerAngle\",\"FingerAngle2\",\"FingerWidth\",\"UseOdd\",]\n#        dovetailProps = [\"FingerAngle\",\"FingerAngle2\"]\n#        cantileverProps = [\"Taper\",\"UndercutAngle\",\"UndercutPositionTweak\",\"HeadSpaceAdjust\",\"BottomFilletAngle\",\"CantileverMateClearance\",\"MaterialDeflection\",\"NoseAngle\",\"RadiusFactor\",\"ShapeDeflection\",\"Undercut\"]\n#        notLatchProps = [\"Offset\"]\n#        annularProps = [\"SlotToolFilletRadius\",\"DiameterTweak\",\"SlotAngle\",\"SlotBottom\",\"SlotCount\"]\n#        notAnnularProps = [\"Width\"]\n#        notBallProps = [\"Width\",\"Length\",\"Depth\"]\n#        ballProps = [\"BallSlotToolCoreRadius\",\"BallSlotToolCoreSphereRadius\",\"BallRadius\",\"BallStemRadius\",\"BallStemLength\",\"BallSlotCount\",\"BallSlotThickness\",\"BallFilletRadius\",\"BallSlotToolFilletRadius\",\"BallMateStart\",\"BallSlotStart\"]\n#        if fp.JointType in [\"Mortise\",\"Tenon\"]:\n#            self.hideThem(fp,mortiseTenonOnly,False)\n#            self.hideThem(fp,splitProps, True)\n#            self.hideThem(fp,notBallProps,False)\n#            self.hideThem(fp,ballProps,True)\n#            self.hideThem(fp,notAnnularProps,False)\n#            self.hideThem(fp,annularProps,True)\n#            self.hideThem(fp,fingerProps,True)\n#            self.hideThem(fp,cantileverProps, True)\n#            self.hideThem(fp,notLatchProps,False)\n#        elif \"Split\" in fp.JointType:\n#            self.hideThem(fp,mortiseTenonOnly,True)\n#            self.hideThem(fp,splitProps, False)\n#            self.hideThem(fp,notBallProps,False)\n#            self.hideThem(fp,ballProps,True)\n#            self.hideThem(fp,notAnnularProps,False)\n#            self.hideThem(fp,annularProps,True)\n#            self.hideThem(fp,fingerProps,True)\n#            self.hideThem(fp,dovetailProps,True)\n#            self.hideThem(fp,cantileverProps, True)\n#            self.hideThem(fp,notLatchProps,False)\n#        elif fp.JointType == \"Box Joint\":\n#            self.hideThem(fp,mortiseTenonOnly,True)\n#            self.hideThem(fp,splitProps, True)\n#            self.hideThem(fp,notBallProps,False)\n#            self.hideThem(fp,ballProps,True)\n#            self.hideThem(fp,notAnnularProps,False)\n#            self.hideThem(fp,annularProps,True)\n#            self.hideThem(fp,fingerProps,False)\n#            self.hideThem(fp,dovetailProps,True)\n#            self.hideThem(fp,cantileverProps, True)\n#            self.hideThem(fp,notLatchProps,False)\n#        elif fp.JointType == \"Dovetail Joint\":\n#            self.hideThem(fp,mortiseTenonOnly,True)\n#            self.hideThem(fp,splitProps, True)\n#            self.hideThem(fp,notBallProps,False)\n#            self.hideThem(fp,ballProps,True)\n#            self.hideThem(fp,notAnnularProps,False)\n#            self.hideThem(fp,annularProps,True)\n#            self.hideThem(fp,fingerProps,False)\n#            self.hideThem(fp,dovetailProps,False)\n#            self.hideThem(fp,cantileverProps, True)\n#            self.hideThem(fp,notLatchProps,False)\n#        elif \"Cantilever\" in fp.JointType:\n#            self.hideThem(fp,mortiseTenonOnly,True)\n#            self.hideThem(fp,splitProps, True)\n#            self.hideThem(fp,notBallProps,False)\n#            self.hideThem(fp,ballProps,True)\n#            self.hideThem(fp,notAnnularProps,False)\n#            self.hideThem(fp,annularProps,True)\n#            self.hideThem(fp,fingerProps,True)\n#            self.hideThem(fp,dovetailProps,True)\n#            self.hideThem(fp,cantileverProps, False)\n#            self.hideThem(fp,notLatchProps,True)\n#        elif \"Annular\" in fp.JointType:\n#            self.hideThem(fp,mortiseTenonOnly,True)\n#            self.hideThem(fp,splitProps, True)\n#            self.hideThem(fp,notBallProps,False)\n#            self.hideThem(fp,ballProps,True)\n#            self.hideThem(fp,notAnnularProps,True)\n#            self.hideThem(fp,annularProps,False)\n#            self.hideThem(fp,fingerProps,True)\n#            self.hideThem(fp,dovetailProps,True)\n#            self.hideThem(fp,cantileverProps, False)\n#            self.hideThem(fp,notLatchProps,True)\n#        elif \"Ball\" in fp.JointType:\n#            self.hideThem(fp,mortiseTenonOnly,True)\n#            self.hideThem(fp,splitProps, True)\n#            self.hideThem(fp,notBallProps,True)\n#            self.hideThem(fp,ballProps,False)\n#            self.hideThem(fp,annularProps,True)\n#            self.hideThem(fp,fingerProps,True)\n#            self.hideThem(fp,dovetailProps,True)\n#            self.hideThem(fp,cantileverProps, True)\n#            self.hideThem(fp,notLatchProps,True)\n#\n#    def roundIt(self, x):\n#        return round(x, 12)\n#\n#    def execute(self,fp):\n#        if not fp.Face:\n#            return\n#        self.hideProps(fp)\n#        fp.Label2 = \"(\"+fp.JointType+\")\"\n#        object = fp.Face[0]\n#        if not object:\n#            return\n#        face = object.getSubObject(fp.Face[1][0])\n#        if fp.JointType == \"Mortise\" or fp.JointType == \"Tenon\":\n#            shape = self.makeMortiseTenon(fp)\n#        elif fp.JointType == \"Box Joint\":\n#            shape = self.makeBoxJoint(fp)\n#        elif fp.JointType == \"Dovetail Joint\":\n#            shape = self.makeDovetailJoint(fp)\n#        elif fp.JointType == \"Cantilever Hook\":\n#            shape = self.makeCantileverHook(fp)\n#        elif fp.JointType == \"Cantilever Mate\":\n#            shape = self.makeCantileverMate(fp)\n#        elif fp.JointType == \"Annular Hook\":\n#            shape = self.makeAnnularHook(fp)\n#        elif fp.JointType == \"Annular Mate\":\n#            shape = self.makeAnnularMate(fp)\n#        elif fp.JointType == \"Ball Joint\":\n#            shape = self.makeBallJoint(fp)\n#        elif fp.JointType == \"Ball Mate\":\n#            shape = self.makeBallMate(fp)\n#        elif fp.JointType == \"Split Joint\":\n#            shape = self.makeSplitJoint(fp)\n#        elif fp.JointType == \"Split Mate\":\n#            shape = self.makeSplitJoint(fp,True)\n#        else:\n#            FreeCAD.Console.PrintError(f\"Unsupported joint type: {fp.JointType}\\n\")\n#            return\n#        shape = shape.scale(fp.Scale) if fp.Scale != 1.0 else shape\n#        x,y,z = map(self.roundIt, face.Surface.Axis) #round x,y,z to 12 digits\n##       thanks to openBrain on the FreeCAD forum for this next line of code\n#        shape.Placement = fp.Placement.multiply(FreeCAD.Placement(face.BoundBox.Center, FreeCAD.Rotation(FreeCAD.Vector(0,0,1),FreeCAD.Vector(x,y,z))))\n#        if fp.JointType == \"Tenon\" or fp.ShowTool or fp.JointType == \"Cantilever Hook\" or fp.JointType == \"Annular Hook\" or fp.JointType == \"Ball Joint\" or fp.JointType == \"Split Joint\":\n#            full_shape = object.Shape.fuse(shape) if fp.Boolean else shape\n#        else: #other types all require cuts\n#            full_shape = object.Shape.cut(shape) if fp.Boolean else shape\n#        fp.Shape = full_shape.removeSplitter() if fp.Refine else full_shape\n#        if hasattr(fp,\"BaseFeature\") and hasattr(fp,\"AddSubShape\"):\n#            if fp.BaseFeature and not shape.isNull():\n#                fp.AddSubShape = shape.transformShape(fp.Placement.inverse().toMatrix(),True)\n#            else:\n#                fp.AddSubShape = shape\n#        if not self.editingMode:\n#            object.ViewObject.Visibility = False if shape and fp.Boolean else True\n#\n#    def makeSplitJoint(self,fp,makeMate = False):\n#        ##Length is also the diameter of the rounded nose\n#        width = fp.Width + fp.Offset\n#        length = fp.Length + fp.Offset\n#        depth = fp.Depth + fp.Offset\n#        noseRadius = length/2\n#        splitRadius = fp.SplitRadius + fp.Offset\n#        splitSlotFilletRadius = fp.SplitSlotFilletRadius + fp.Offset\n#        ## points\n#        bottomFrontLeft = FreeCAD.Vector(-width/2, -length/2, 0)\n#        topFrontLeft = FreeCAD.Vector(-width/2, -length/2, depth)\n#        topBackLeft = FreeCAD.Vector(-width/2,length/2, depth)\n#        bottomBackLeft = FreeCAD.Vector(-width/2, length/2, 0)\n#        ballCenterLeft = FreeCAD.Vector(-width/2, 0, depth - noseRadius)\n#        frontArcLeft = FreeCAD.Vector(-width/2, -length/2, depth - noseRadius)\n#        topArcLeft = FreeCAD.Vector(-width/2, 0, depth)\n#        backArcLeft = FreeCAD.Vector(-width/2, length/2, depth - noseRadius)\n#        if fp.SplitRounded:\n#            frontBottomLine = Part.makeLine(bottomFrontLeft, frontArcLeft)\n#            arc = Part.ArcOfCircle(frontArcLeft, topArcLeft, backArcLeft).toShape()\n#            backBottomLine = Part.makeLine(backArcLeft, bottomBackLeft)\n#            bottomLine = Part.makeLine(bottomBackLeft, bottomFrontLeft)\n#            wire = Part.Wire([frontBottomLine, arc, backBottomLine, bottomLine])\n#        else:\n#            frontLine = Part.makeLine(bottomFrontLeft, topFrontLeft)\n#            topLine = Part.makeLine(topFrontLeft, topBackLeft)\n#            backLine = Part.makeLine(topBackLeft, bottomBackLeft)\n#            bottomLine = Part.makeLine(bottomBackLeft, bottomFrontLeft)\n#            wire = Part.Wire([frontLine, topLine, backLine, bottomLine])\n#        face = Part.makeFace(wire, \"Part::FaceMakerCheese\")\n#        extrude = face.extrude(FreeCAD.Vector(1,0,0)*width/2)\n#        if not makeMate and fp.SplitSlotWidth != 0:\n#            extrude = face.extrude(FreeCAD.Vector(1,0,0)*(width/2 - fp.SplitSlotWidth/2))\n#        sphere = Part.makeSphere(splitRadius, ballCenterLeft, FreeCAD.Vector(1,0,0),0,90,360)\n#        sphere.Placement.rotate(ballCenterLeft, FreeCAD.Vector(0,-1,0),180)\n#        extrude = extrude.fuse(sphere)\n#        filletTop = extrude.Vertex2.Point.add(FreeCAD.Vector(0,0,splitSlotFilletRadius))\n#        filletMiddle = extrude.Vertex2.Point.add(FreeCAD.Vector(splitSlotFilletRadius, 0, splitSlotFilletRadius))\n#        filletBottom = extrude.Vertex2.Point.add(FreeCAD.Vector(splitSlotFilletRadius, 0, 0))\n#        filletArc = Part.makeCircle(splitSlotFilletRadius, filletMiddle, FreeCAD.Vector(0,1,0),90,180)\n#        filletBottomLine = Part.makeLine(filletBottom, extrude.Vertex2.Point)\n#        filletLeftLine = Part.makeLine(extrude.Vertex2.Point, filletTop)\n#        filletWire = Part.Wire([filletLeftLine,filletArc,filletBottomLine])\n#        filletFace = Part.makeFace(filletWire,\"Part::FaceMakerCheese\")\n#        fillet = filletFace.extrude(FreeCAD.Vector(0,1,0)*length)\n#        mid = extrude.Edge1.CenterOfMass\n#        if not makeMate and fp.SplitSlotWidth != 0:\n#            fillet = fillet.fuse(fillet.mirror(mid,FreeCAD.Vector(1,0,0)))\n#        else:\n#            fillet = fillet.mirror(mid,FreeCAD.Vector(1,0,0))\n#        extrude = extrude.fuse(fillet)\n#        extrude = extrude.fuse(extrude.mirror(FreeCAD.Vector(0,0,0), FreeCAD.Vector(1,0,0)))\n#        mirror = extrude.mirror(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1))\n#        if fp.Symmetric:\n#            fusion = extrude.fuse(mirror)\n#        elif fp.Reversed:\n#            fusion = mirror\n#        else:\n#            fusion = extrude\n#        cog = FreeCAD.Vector(0,0,0)\n#        fusion.rotate(cog,FreeCAD.Vector(0,0,1),fp.Angle)\n#        fusion = fusion.transformShape(fusion.Placement.toMatrix(),True)\n#        fusion.Placement = FreeCAD.Placement()\n#        fusion.rotate(cog,FreeCAD.Vector(0,1,0),fp.AngleY)\n#        fusion = fusion.transformShape(fusion.Placement.toMatrix(),True)\n#        fusion.Placement = FreeCAD.Placement()\n#        fusion.rotate(cog,FreeCAD.Vector(1,0,0),fp.AngleX)\n#        fusion = fusion.transformShape(fusion.Placement.toMatrix(),True)\n#        fusion.Placement = FreeCAD.Placement()\n#        fusion.Placement.move(fp.Position)\n#        fusion = fusion.transformShape(fusion.Placement.toMatrix(),True)\n#        fusion.Placement = FreeCAD.Placement()\n#        return fusion\n#\n#    def makeBoxJoint(self,fp):\n#        '''make the box joint shape'''\n#        num = fp.Width / (fp.FingerWidth)\n#        num = int(math.ceil(num))\n#        boxes = []\n#        depth = fp.Depth if not fp.Symmetric else fp.Depth*2\n#        for n in range(0,num):\n#            if bool(n % 2 == 0 and fp.UseOdd) or bool(n % 2 == 1 and not fp.UseOdd):\n#                continue\n#            x = -fp.Offset -fp.Width/2 + n * fp.FingerWidth\n#            y = -fp.Offset -fp.Length/2\n#            z = 0 if not fp.Symmetric else -fp.Depth\n#            z = -fp.Depth if fp.Reversed else z\n#            pt = FreeCAD.Vector(x,y,z).add(fp.Position)\n#            boxes.append(Part.makeBox(fp.FingerWidth+fp.Offset*2, fp.Length+fp.Offset, depth+fp.Offset*2,pt-FreeCAD.Vector(0,0,fp.Offset*2)))\n#        fusion = boxes[0].fuse(boxes[1:]) if len(boxes) > 1 else boxes[0]\n#        fusion.rotate(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1),fp.Angle)\n#        fusion = fusion.transformShape(fusion.Placement.toMatrix(),True)\n#        fusion.rotate(FreeCAD.Vector(0,0,-fp.Depth/2),FreeCAD.Vector(0,1,0),fp.AngleY)\n#        fusion = fusion.transformShape(fusion.Placement.toMatrix(),True)\n#        fusion.rotate(FreeCAD.Vector(0,0,-fp.Depth/2),FreeCAD.Vector(1,0,0),fp.AngleX)\n#        fusion = fusion.transformShape(fusion.Placement.toMatrix(),True)\n#        return fusion\n#\n#    def makeWedge(self, fp, wid, length, ht, pt):\n#        '''support 2 angles for compound dovetails'''\n#        tanht = math.tan(math.radians(-fp.FingerAngle/2)) * ht / 2\n#        tanlength = math.tan(math.radians(-fp.FingerAngle2/2)) * length / 2\n#        frontLeftBottom = FreeCAD.Vector(-tanht,0,0)\n#        frontLeftTop = FreeCAD.Vector(tanht,0, ht)\n#        frontLeft = Part.makeLine(frontLeftBottom, frontLeftTop)\n#        topLeftBack = FreeCAD.Vector(tanht + tanlength, length, ht)\n#        topLeft = Part.makeLine(frontLeftTop, topLeftBack)\n#        topLeftDirection = topLeft.Vertex2.Point.sub(topLeft.Vertex1.Point)\n#        backLeftBottom = frontLeftBottom.add(topLeftDirection)\n#        backLeft = Part.makeLine(topLeftBack,backLeftBottom)\n#        bottomLeft = Part.makeLine(frontLeftBottom, backLeftBottom)\n#        leftWire = Part.Wire([bottomLeft,backLeft,topLeft,frontLeft])\n#        leftFace = Part.makeFace(leftWire,\"Part::FaceMakerCheese\")\n#        mirror = leftFace.mirror(FreeCAD.Vector(wid/2+leftFace.CenterOfMass.x,0,0),FreeCAD.Vector(1,0,0))\n#        loft = Part.makeLoft([leftWire,mirror.Wire1],True)\n#        loft.Placement.move(pt)\n#        symmetric_mirror = loft.mirror(pt,FreeCAD.Vector(0,0,1))\n#        if fp.Symmetric:\n#            return loft.fuse(symmetric_mirror)\n#        if not fp.Reversed:\n#            return symmetric_mirror\n#        else:\n#            return loft\n#\n#    def makeDovetailJoint(self,fp):\n#        '''make the dovetial joint shape'''\n#        num = fp.Width / (fp.FingerWidth)\n#        num = int(math.ceil(num))\n#        wedges = []\n#        for n in range(-1,num+1):\n#            if bool(n % 2 == 0 and fp.UseOdd) or bool(n % 2 == 1 and not fp.UseOdd):\n#                continue\n#            x = -fp.Offset -fp.Width/2 + n * fp.FingerWidth\n#            y = -fp.Offset -fp.Length/2\n#            z = 0\n#            pt = FreeCAD.Vector(x,y,z).add(fp.Position)\n#            wedges.append(self.makeWedge(fp, fp.FingerWidth+fp.Offset*2, fp.Length+fp.Offset, fp.Depth+fp.Offset,pt))\n#        fusion = wedges[0].fuse(wedges[1:]) if len(wedges) > 1 else wedges[0]\n#        fusion.rotate(FreeCAD.Vector(0,0,-fp.Depth/2),FreeCAD.Vector(0,0,1),fp.Angle)\n#        fusion = fusion.transformShape(fusion.Placement.toMatrix(),True)\n#        fusion.rotate(FreeCAD.Vector(0,0,-fp.Depth/2),FreeCAD.Vector(0,1,0),fp.AngleY)\n#        fusion = fusion.transformShape(fusion.Placement.toMatrix(),True)\n#        fusion.rotate(FreeCAD.Vector(0,0,-fp.Depth/2),FreeCAD.Vector(1,0,0),fp.AngleX)\n#        fusion = fusion.transformShape(fusion.Placement.toMatrix(),True)\n#        return fusion\n#\n#    def makeCantileverHookFace(self,fp):\n#        length = fp.Length #h in diagram\n#        depth = fp.Depth #length in diagram\n#        angle = fp.NoseAngle\n#        radius = fp.RadiusFactor * length #default = 0.6 * length\n#        undercut = fp.ShapeDeflection * fp.MaterialDeflection * depth * depth / length\n#        fp.Undercut = undercut\n#        upt = fp.UndercutPositionTweak\n#        uat = math.tan(math.radians(fp.UndercutAngle))*undercut #undercut angle tweak\n#        baseline = length + radius + radius #bottom of bottom fillet to top of top fillet\n#        ## Points\n#        filletCenterBottom = FreeCAD.Vector(radius, -baseline/2, 0)\n#        filletCenterTop = FreeCAD.Vector(radius, baseline/2, 0)\n#        baselineBottom = FreeCAD.Vector(0, -baseline/2, 0)\n#        baselineTop = FreeCAD.Vector(0, baseline/2, 0)\n#        undercutBottom = FreeCAD.Vector(uat + upt + radius + depth, length/2, 0)\n#        undercutTop = FreeCAD.Vector(upt + radius + depth, length/2 + undercut, 0)\n#        undercutRight = FreeCAD.Vector(radius + depth + undercut, length/2 + undercut, 0)\n#        noseBottomY = -length/2 + (1-fp.Taper) * length\n#        noseBottom = FreeCAD.Vector(radius + depth + undercut + math.tan(math.radians(angle))*undercut, noseBottomY, 0)\n#        noseTop = FreeCAD.Vector(radius + depth + undercut + math.tan(math.radians(angle))*undercut, length/2, 0)\n#        ## Edges\n#        bottomArc = Part.makeCircle(radius,filletCenterBottom,FreeCAD.Vector(0,0,1),fp.BottomFilletAngle,180)\n#        topArc = Part.makeCircle(radius,filletCenterTop,FreeCAD.Vector(0,0,1),180,270)\n#        hookBottom = Part.makeLine(bottomArc.Vertex1.Point, noseBottom)\n#        hookNoseBottom = Part.makeLine(noseBottom, noseTop)\n#        hookNoseSlant = Part.makeLine(noseTop, undercutRight)\n#        hookNoseTop = Part.makeLine(undercutRight, undercutTop)\n#        hookNoseLeft = Part.makeLine(undercutTop, undercutBottom)\n#        hookTop = Part.makeLine(undercutBottom, topArc.Vertex2.Point)\n#        hookBaseline = Part.makeLine(topArc.Vertex1.Point,bottomArc.Vertex2.Point)\n#        wire = Part.Wire([hookBaseline, topArc, hookTop, hookNoseLeft, hookNoseTop, hookNoseSlant, hookNoseBottom, hookBottom, bottomArc])\n#        face = Part.makeFace(wire,\"Part::FaceMakerCheese\")\n#        return face\n#\n#    def makeBallJoint(self,fp):\n#        ## points\n#        bottomLeft = FreeCAD.Vector(-fp.BallStemRadius - fp.BallFilletRadius, 0, 0)\n#        arcCenter = FreeCAD.Vector(-fp.BallStemRadius - fp.BallFilletRadius, 0, fp.BallFilletRadius)\n#        filletTop = FreeCAD.Vector(-fp.BallStemRadius,0,fp.BallFilletRadius)\n#        sagitta = fp.BallRadius - math.sqrt(fp.BallRadius**2 - fp.BallStemRadius**2)\n#        ballBottomLeft = FreeCAD.Vector(-fp.BallStemRadius, 0, fp.BallStemLength+sagitta)\n#        ballLeft = FreeCAD.Vector(-fp.BallRadius,0,fp.BallStemLength + fp.BallRadius)\n#        ballTop = FreeCAD.Vector(0,0,fp.BallStemLength + fp.BallRadius + fp.BallRadius)\n#        bottomRight = FreeCAD.Vector(0,0,0)\n#\n#       ## edges\n#        bottom = Part.makeLine(bottomRight,bottomLeft)\n#        filletArc = Part.makeCircle(fp.BallFilletRadius, arcCenter, FreeCAD.Vector(0,1,0),0, 90)\n#        stemLeft = Part.makeLine(filletTop, ballBottomLeft)\n#        ball = Part.ArcOfCircle(ballBottomLeft,ballLeft,ballTop)\n#        rightSide = Part.makeLine(ballTop,bottomRight)\n#\n#        wire = Part.Wire([bottom,filletArc,stemLeft,ball.toShape().Edge1,rightSide])\n#        face = Part.makeFace(wire,\"Part::FaceMakerCheese\")\n#        revolve = face.revolve(bottomRight, FreeCAD.Vector(0,0,1),180)\n#        revolve = revolve.makeFillet(fp.BallFilletRadius,[revolve.Edge7])\n#        revolve = revolve.fuse(revolve.mirror(FreeCAD.Vector(0,0,0), FreeCAD.Vector(0,1,0)))\n#        ## cut slots in ball\n#        btPos = fp.BallStemLength + fp.BallSlotStart * (2*fp.BallRadius)\n#        thick = fp.BallSlotThickness\n#        centerEdge = Part.makeLine(FreeCAD.Vector(-fp.BallRadius*2,-thick/2,btPos),FreeCAD.Vector(-fp.BallRadius*2,-thick/2,fp.BallStemLength+3*fp.BallRadius))\n#        topEdge = Part.makeLine(FreeCAD.Vector(-fp.BallRadius*2,-thick/2,fp.BallStemLength+3*fp.BallRadius),FreeCAD.Vector(fp.BallRadius*2,-thick/2,fp.BallStemLength+3*fp.BallRadius))\n#        rightEdge = Part.makeLine(FreeCAD.Vector(fp.BallRadius*2,-thick/2,fp.BallStemLength+3*fp.BallRadius),FreeCAD.Vector(fp.BallRadius*2,-thick/2,btPos))\n#        bottomEdge = Part.makeLine(FreeCAD.Vector(-fp.BallRadius*2,-thick/2,btPos),FreeCAD.Vector(fp.BallRadius*2,-thick/2,btPos))\n#        wire = Part.Wire([centerEdge,topEdge,rightEdge,bottomEdge])\n#        face = Part.makeFace(wire,\"Part::FaceMakerCheese\")\n#        slotTool = face.extrude(FreeCAD.Vector(0,thick,0))\n#        slotTool = slotTool.makeFillet(fp.BallSlotToolFilletRadius,[slotTool.Edge6,slotTool.Edge7,slotTool.Edge11,slotTool.Edge12])\n#        if fp.BallSlotToolCoreSphereRadius >= fp.BallRadius:\n#            FreeCAD.Console.PrintError(\"Ball joint core tool sphere radius must be smaller than ball radius.\\n\")\n#        if not fp.BallSlotToolCoreRadius == 0:\n#            core = Part.makeCylinder(fp.BallSlotToolCoreRadius,fp.BallStemLength+3*fp.BallRadius,FreeCAD.Vector(0,0,btPos-.01))\n#            coreSphere = Part.makeSphere(fp.BallSlotToolCoreSphereRadius,FreeCAD.Vector(0,0,fp.BallStemLength+fp.BallRadius)) if fp.BallSlotToolCoreSphereRadius != 0 else Part.Shape()\n#            toolCopies = core.fuse(coreSphere) if not coreSphere.isNull() else core\n#        else:\n#            toolCopies = Part.Shape()\n#        for ii in range(0,fp.BallSlotCount):\n#            copy = slotTool.copy()\n#            copy.rotate(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1), ii * (180 / fp.BallSlotCount))\n#            if toolCopies.isNull():\n#                toolCopies = copy\n#            else:\n#                toolCopies = toolCopies.fuse(copy)\n#        toolCopies = toolCopies.removeSplitter() if not toolCopies.isNull() else toolCopies\n#        if not toolCopies.isNull():\n#            revolve = revolve.cut(toolCopies)\n#        mirror = revolve.mirror(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1))\n#        if fp.Symmetric:\n#            revolve = revolve.fuse(mirror)\n#        elif fp.Reversed:\n#            revolve = mirror\n#        cog = mirror.Face1.CenterOfGravity\n#        revolve.rotate(cog,FreeCAD.Vector(0,0,1),fp.Angle)\n#        revolve = revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        revolve.rotate(cog,FreeCAD.Vector(0,1,0),fp.AngleY)\n#        revolve = revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        revolve.rotate(cog,FreeCAD.Vector(1,0,0),fp.AngleX)\n#        revolve = revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        revolve.Placement.move(fp.Position)\n#        revolve = revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        return revolve\n#\n#    def makeBallMate(self,fp):\n#        #ballProps = [\"BallRadius\",\"BallStemRadius\",\"BallStemLength\",\\\n#        #\"BallSlotCount\",\"BallSlotThickness\",\"BallFilletRadius\",\"BallSlotToolFilletRadius\",\\\n#        #\"BallMateStart\",\"BallSlotStart\"]\n#        sphere = Part.makeSphere(fp.BallRadius, FreeCAD.Vector(0,0,fp.BallStemLength+fp.BallRadius))\n#        start = fp.BallStemLength + fp.BallMateStart * (fp.BallRadius * 2)\n#        circle = Part.makeCircle(fp.BallRadius, FreeCAD.Vector(0,0,start),FreeCAD.Vector(0,0,1))\n#        face = Part.makeFace(circle, \"Part::FaceMakerCheese\")\n#        extrude = face.extrude(FreeCAD.Vector(0,0,-1))\n#        common = extrude.common(sphere)\n#        r1 = common.Edge1.Curve.Radius\n#        cylinder = Part.makeCylinder(r1,start)\n#        fusion = cylinder.fuse(sphere)\n#        mirror = fusion.mirror(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1))\n#        if fp.Symmetric:\n#            fusion = fusion.fuse(mirror)\n#        elif fp.Reversed:\n#            fusion = mirror\n#        cog = mirror.Face1.CenterOfGravity\n#        fusion.rotate(cog,FreeCAD.Vector(0,0,1),fp.Angle)\n#        fusion = fusion.transformShape(fusion.Placement.toMatrix(),True)\n#        fusion.Placement = FreeCAD.Placement()\n#        fusion.rotate(cog,FreeCAD.Vector(0,1,0),fp.AngleY)\n#        fusion = fusion.transformShape(fusion.Placement.toMatrix(),True)\n#        fusion.Placement = FreeCAD.Placement()\n#        fusion.rotate(cog,FreeCAD.Vector(1,0,0),fp.AngleX)\n#        fusion = fusion.transformShape(fusion.Placement.toMatrix(),True)\n#        fusion.Placement = FreeCAD.Placement()\n#        fusion.Placement.move(fp.Position)\n#        fusion = fusion.transformShape(fusion.Placement.toMatrix(),True)\n#        fusion.Placement = FreeCAD.Placement()\n#        return fusion\n#\n#    def makeAnnularHook(self,fp):\n#        face = self.makeCantileverHookFace(fp)\n#        direction = FreeCAD.Vector(1,0,0)\n#        pt = FreeCAD.Vector(0, face.BoundBox.YMin - fp.DiameterTweak, 0)\n#        revolve = face.revolve(pt,direction,180)\n#        revolve = revolve.fuse(revolve.mirror(pt,FreeCAD.Vector(0,0,1)))\n#        revolve.Placement.move(pt*-1) #centers at pt, axis of rotation\n#        revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        #at this point the object is oriented horizontally and centered on the origin\n#        #will be rotated vertically in a later step\n#        wid = revolve.BoundBox.XLength #overall height, once rotated\n#        ht = revolve.BoundBox.ZLength\n#        length = revolve.BoundBox.YLength\n#        btPos = wid * fp.SlotBottom #bottom position of slots to be cut\n#        #fp.SlotAngle will be angle of slots\n#        #fp.SlotCount will be number of slots to cut\n#        centerEdge = Part.makeLine(FreeCAD.Vector(btPos,0,0),FreeCAD.Vector(btPos,length,0))\n#        topEdge = Part.makeLine(FreeCAD.Vector(btPos,length,0),FreeCAD.Vector(wid,length,0))\n#        rightEdge = Part.makeLine(FreeCAD.Vector(wid,length,0),FreeCAD.Vector(wid,0,0))\n#        bottomEdge = Part.makeLine(FreeCAD.Vector(wid,0,0),FreeCAD.Vector(btPos,0,0))\n#        wire = Part.Wire([centerEdge,topEdge,rightEdge,bottomEdge])\n#        face = Part.makeFace(wire,\"Part::FaceMakerCheese\")\n#        slotTool = face.revolve(centerEdge.Vertex1.Point,FreeCAD.Vector(1,0,0),fp.SlotAngle)\n#        slotTool = slotTool.makeFillet(fp.SlotToolFilletRadius,[slotTool.Edge2,slotTool.Edge3])\n#        toolCopies = Part.Shape()\n#        for ii in range(0,fp.SlotCount):\n#            copy = slotTool.copy()\n#            copy.rotate(centerEdge.Vertex1.Point,FreeCAD.Vector(1,0,0), ii * (360 / fp.SlotCount))\n#            if toolCopies.isNull():\n#                toolCopies = copy\n#            else:\n#                toolCopies = toolCopies.fuse(copy)\n#        if not toolCopies.isNull():\n#            revolve = revolve.cut(toolCopies)\n#        mirror = revolve.mirror(FreeCAD.Vector(0,0,0),FreeCAD.Vector(-1,0,0))\n#        if fp.Symmetric:\n#            revolve = revolve.fuse(mirror)\n#        elif fp.Reversed:\n#            revolve = mirror\n#        cog = mirror.Face1.CenterOfGravity\n#        revolve.Placement.rotate(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,1,0),90)\n#        revolve = revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        revolve.rotate(cog,FreeCAD.Vector(0,0,1),fp.Angle)\n#        revolve = revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        revolve.rotate(cog,FreeCAD.Vector(0,1,0),fp.AngleY)\n#        revolve = revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        revolve.rotate(cog,FreeCAD.Vector(1,0,0),fp.AngleX)\n#        revolve = revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        revolve.Placement.move(fp.Position)\n#        revolve = revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        return revolve\n#\n#    def makeCantileverHook(self,fp):\n#        face = self.makeCantileverHookFace(fp)\n#        face.Placement.move(fp.Position)\n#        direction = FreeCAD.Vector(0,0,1)\n#        extrude = face.extrude(direction*fp.Width)\n#        if fp.Symmetric or fp.Reversed:\n#            mirror = extrude.mirror(FreeCAD.Vector(0,0,0),FreeCAD.Vector(-1,0,0))\n#        if fp.Symmetric:\n#            extrude = extrude.fuse(mirror)\n#        elif fp.Reversed:\n#            extrude = mirror\n#        extrude.Placement.rotate(FreeCAD.Vector(0,0,0),FreeCAD.Vector(-1,-1,-1),120)\n#        extrude.Placement.move(FreeCAD.Vector(0,-fp.Width/2,0))\n#        extrude = extrude.transformShape(extrude.Placement.toMatrix(),True)\n#        extrude.Placement = FreeCAD.Placement()\n#        extrude.Placement.rotate(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1),180)\n#        extrude = extrude.transformShape(extrude.Placement.toMatrix(),True)\n#        extrude.Placement = FreeCAD.Placement()\n#        if not fp.Symmetric:\n#            cog = extrude.Face1.CenterOfGravity\n#        else:\n#            cog = extrude.Vertex2.Point.add(extrude.Vertex9.Point)/2\n#        extrude.rotate(cog,FreeCAD.Vector(0,0,1),fp.Angle)\n#        extrude = extrude.transformShape(extrude.Placement.toMatrix(),True)\n#        extrude.rotate(cog,FreeCAD.Vector(0,1,0),fp.AngleY)\n#        extrude = extrude.transformShape(extrude.Placement.toMatrix(),True)\n#        extrude.rotate(cog,FreeCAD.Vector(1,0,0),fp.AngleX)\n#        extrude = extrude.transformShape(extrude.Placement.toMatrix(),True)\n#        return extrude\n#\n#    def makeAnnularMate(self,fp):\n#        face = self.makeCantileverMateFace(fp,True)\n#        direction = FreeCAD.Vector(1,0,0)\n#        pt = FreeCAD.Vector(0,face.BoundBox.YMin, 0)\n#        revolve = face.revolve(pt,direction,180)\n#        revolve = revolve.fuse(revolve.mirror(pt,FreeCAD.Vector(0,0,1)))\n#        revolve.Placement.move(pt*-1) #centers at pt, axis of rotation\n#        revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        #at this point the object is oriented horizontally and centered on the origin\n#        #will be rotated vertically in a later step\n#        mirror = revolve.mirror(FreeCAD.Vector(0,0,0),FreeCAD.Vector(-1,0,0))\n#        if fp.Symmetric:\n#            revolve = revolve.fuse(mirror)\n#        elif fp.Reversed:\n#            revolve = mirror\n#        cog = mirror.Face1.CenterOfGravity\n#        revolve.Placement.rotate(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,1,0),90)\n#        revolve = revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        revolve.rotate(cog,FreeCAD.Vector(0,0,1),fp.Angle)\n#        revolve = revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        revolve.rotate(cog,FreeCAD.Vector(0,1,0),fp.AngleY)\n#        revolve = revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        revolve.rotate(cog,FreeCAD.Vector(1,0,0),fp.AngleX)\n#        revolve = revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        revolve.Placement.move(fp.Position)\n#        revolve = revolve.transformShape(revolve.Placement.toMatrix(),True)\n#        revolve.Placement = FreeCAD.Placement()\n#        return revolve\n#\n#    def makeCantileverMateFace(self,fp, annular=False):\n#        ##cantilever hook calculations first, then we'll use them as references for the\n#        ##mate cutting tool shape, offset by fp.CantileverMateClearance (default 0.5mm)\n#\n#        length = fp.Length #h in diagram\n#        depth = fp.Depth #length in diagram\n#        angle = fp.NoseAngle\n#        radius = fp.RadiusFactor * length #default = 0.6 * length\n#        undercut = fp.ShapeDeflection * fp.MaterialDeflection * depth * depth / length\n#        fp.Undercut = undercut\n#        baseline = length + radius + radius #bottom of bottom fillet to top of top fillet\n#        upt = fp.UndercutPositionTweak\n#        uat = math.tan(math.radians(fp.UndercutAngle))*undercut #undercut angle tweak\n#        ## Points\n#        filletCenterBottom = FreeCAD.Vector(radius, -baseline/2, 0)\n#        filletCenterTop = FreeCAD.Vector(radius, baseline/2, 0)\n#        baselineBottom = FreeCAD.Vector(0, -baseline/2, 0)\n#        baselineTop = FreeCAD.Vector(0, baseline/2, 0)\n#        undercutBottom = FreeCAD.Vector(upt + uat + radius + depth, length/2, 0)\n#        undercutTop = FreeCAD.Vector(upt + radius + depth, length/2 + undercut, 0)\n#        undercutRight = FreeCAD.Vector(radius + depth + undercut, length/2 + undercut, 0)\n#        noseBottom = FreeCAD.Vector(radius + depth + undercut + math.tan(math.radians(angle))*undercut, 0, 0)\n#        noseTop = FreeCAD.Vector(radius + depth + undercut + math.tan(math.radians(angle))*undercut, length/2, 0)\n#        topArc = Part.makeCircle(radius,filletCenterTop,FreeCAD.Vector(0,0,1),180,270)\n#\n#        ## now for the mate points\n#        offset = fp.CantileverMateClearance\n#        baselineTop2 = baselineTop.add(FreeCAD.Vector(0,offset,0))\n#        topArcPt2 = topArc.Vertex2.Point.add(FreeCAD.Vector(0,offset,0))\n#        undercutBottom2 = undercutBottom.add(FreeCAD.Vector(-offset,offset,0))\n#        undercutTop2 = undercutTop.add(FreeCAD.Vector(-offset,offset,0))\n#        topRight = FreeCAD.Vector(noseTop.x + undercut + fp.HeadSpaceAdjust, undercutTop.y + offset,0)\n#        if not annular:\n#            bottomRight = FreeCAD.Vector(topRight.x, -topRight.y - offset, 0)\n#            baselineBottom2 = FreeCAD.Vector(0, -topRight.y -offset, 0)\n#        else:\n#            bottomRight = FreeCAD.Vector(topRight.x, -topRight.y + length/10 - fp.DiameterTweak, 0)\n#            baselineBottom2 = FreeCAD.Vector(0, -topRight.y + length/10 - fp.DiameterTweak, 0)\n#\n#        ## Edges\n#        baseline2 = Part.makeLine(baselineBottom2, baselineTop2)\n#        leftSlant = Part.makeLine(baselineTop2, topArcPt2)\n#        topLine = Part.makeLine(topArcPt2, undercutBottom2)\n#        undercutLeft2 = Part.makeLine(undercutBottom2, undercutTop2)\n#        topRightLine2 = Part.makeLine(undercutTop2, topRight)\n#        rightLine = Part.makeLine(topRight, bottomRight)\n#        bottomLine2 = Part.makeLine(bottomRight, baselineBottom2)\n#        wire = Part.Wire([baseline2, leftSlant, topLine, undercutLeft2, topRightLine2, rightLine, bottomLine2])\n#        face = Part.makeFace(wire,\"Part::FaceMakerCheese\")\n#        if not annular:\n#            face.Placement.move(FreeCAD.Vector(0,0,-offset))\n#        return face\n#\n#    def makeCantileverMate(self,fp):\n#        face = self.makeCantileverMateFace(fp)\n#        face.Placement.move(fp.Position)\n#        direction = FreeCAD.Vector(0,0,1)\n#        offset = fp.CantileverMateClearance\n#        extrude = face.extrude(direction*(fp.Width + 2*offset))\n#        if fp.Symmetric or fp.Reversed:\n#            mirror = extrude.mirror(FreeCAD.Vector(0,0,0),FreeCAD.Vector(-1,0,0))\n#        if fp.Symmetric:\n#            extrude = extrude.fuse(mirror)\n#        elif fp.Reversed:\n#            extrude = mirror\n#        extrude.Placement.rotate(FreeCAD.Vector(0,0,0),FreeCAD.Vector(-1,-1,-1),120)\n#        extrude.Placement.move(FreeCAD.Vector(0,-fp.Width/2,0))\n#        extrude = extrude.transformShape(extrude.Placement.toMatrix(),True)\n#        extrude.Placement = FreeCAD.Placement()\n#        extrude.Placement.rotate(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1),180)\n#        extrude = extrude.transformShape(extrude.Placement.toMatrix(),True)\n#        extrude.Placement = FreeCAD.Placement()\n#        extrude.rotate(extrude.Face1.CenterOfGravity,FreeCAD.Vector(0,0,1),fp.Angle)\n#        extrude = extrude.transformShape(extrude.Placement.toMatrix(),True)\n#        extrude.rotate(extrude.Face1.CenterOfGravity,FreeCAD.Vector(0,1,0),fp.AngleY)\n#        extrude = extrude.transformShape(extrude.Placement.toMatrix(),True)\n#        extrude.rotate(extrude.Face1.CenterOfGravity,FreeCAD.Vector(1,0,0),fp.AngleX)\n#        extrude = extrude.transformShape(extrude.Placement.toMatrix(),True)\n#        return extrude\n#\n#    def makeMortiseTenon(self,fp):\n#        '''make the shape'''\n#        adjust = fp.Position\n#        topLeft = FreeCAD.Vector(-fp.Width/2,fp.Length/2,0).add(adjust)\n#        topRight = FreeCAD.Vector(fp.Width/2,fp.Length/2,0).add(adjust)\n#        bottomLeft = FreeCAD.Vector(-fp.Width/2,-fp.Length/2,0).add(adjust)\n#        bottomRight = FreeCAD.Vector(fp.Width/2,-fp.Length/2,0).add(adjust)\n#        midLeft = FreeCAD.Vector(-fp.Width/2,0,0).add(adjust)\n#        midRight = FreeCAD.Vector(fp.Width/2,0,0).add(adjust)\n#        top = Part.makeLine(topLeft,topRight)\n#        bottom = Part.makeLine(bottomLeft,bottomRight)\n#        if fp.Rounded:\n#            left = Part.makeCircle(fp.Length/2,midLeft,FreeCAD.Vector(0,0,1),90,270)\n#            right = Part.makeCircle(fp.Length/2,midRight,FreeCAD.Vector(0,0,1),270,90)\n#        else:\n#            left = Part.makeLine(topLeft, bottomLeft)\n#            right = Part.makeLine(topRight, bottomRight)\n#        wire = Part.Wire([top,right,bottom,left])\n#        wire.rotate(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1),fp.Angle)\n#        face = Part.makeFace(wire,\"Part::FaceMakerCheese\")\n#        if fp.Offset != 0:\n#            face = face.makeOffset2D(fp.Offset)\n#        if fp.Reversed:\n#            direction = FreeCAD.Vector(0,0,-1)\n#        else:\n#            direction = FreeCAD.Vector(0,0,1)\n#        if fp.JointType == \"Mortise\":\n#            direction = direction * (-1)\n#        extrude = face.extrude(direction*fp.Depth)\n#        if fp.Symmetric:\n#            extrude2 = face.extrude(direction*-1*fp.Depth)\n#            extrude = extrude.fuse(extrude2)\n#        extrude.rotate(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,1,0),fp.AngleY)\n#        extrude = extrude.transformShape(extrude.Placement.toMatrix(),True)\n#        extrude.rotate(FreeCAD.Vector(0,0,0),FreeCAD.Vector(1,0,0),fp.AngleX)\n#        extrude = extrude.transformShape(extrude.Placement.toMatrix(),True)\n#        return extrude\n#\n#class TaskEditLinkSubPanel: #simple editor for App::PropertyLinkSub\n#    def __init__(self, obj, linkSubName, subNames,):\n#        self.obj = obj\n#        self.subNames = subNames\n#        self.linkSubName = linkSubName #entire LinkSub property\n#        self.linkObj = getattr(self.obj,linkSubName)[0]\n#        self.subObjects = getattr(self.obj,linkSubName)[1]\n#        self.form = QtGui.QWidget()\n#        self.label1 = QtGui.QLabel(\"Select the \"+self.subNames+\" subobjects to use and click OK.\\nThe ones already being utilized have been selected for you.\")\n#        layout=QtGui.QHBoxLayout()\n#        layout.addWidget(self.label1)\n#        self.form.setLayout(layout)\n#        self.form.setWindowTitle('Edit '+self.subNames)\n#        self.obj.ViewObject.Visibility = False\n#        self.linkObj.ViewObject.Visibility = True\n#        FreeCADGui.Selection.clearSelection()\n#        for f in self.subObjects:\n#            FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Name,self.linkObj.Name,f)\n#        self.obj.Proxy.editingMode = True\n#\n#    def reject(self):\n#        FreeCADGui.Control.closeDialog()\n#        fp = self.obj\n#        self.linkObj.ViewObject.Visibility = False\n#        fp.ViewObject.Visibility = True\n#        self.obj.Proxy.editingMode = False #self.obj.Proxy is the Joint class object (self in that class)\n#        FreeCADGui.activeDocument().resetEdit()\n#        FreeCAD.ActiveDocument.recompute()\n#\n#    def accept(self):\n#        FreeCADGui.ActiveDocument.resetEdit()\n#        FreeCADGui.Control.closeDialog()\n#        fp = self.obj\n#        if not fp: #user deleted or closed document perhaps\n#            return\n#        selx = FreeCADGui.Selection.getSelectionEx()\n#        if not selx:\n#            FreeCAD.Console.PrintWarning(\"Nothing selected, leaving \"+self.linkObj.Name+\" unmodified.\")\n#            return\n#        seNames = [sen for sen in selx[0].SubElementNames]\n#        setattr(self.obj,self.linkSubName,(selx[0].Object,seNames)) #allow user to select diffent object\n#        self.linkObj = selx[0].Object\n#        if hasattr(fp,\"_Body\") and fp._Body and self.linkObj not in fp._Body.Group:\n#            fp._Body.Group += [self.linkObj]\n#            if not self.linkObj.isDerivedFrom(\"PartDesign::Feature\"):\n#               fp.ClaimChildren = True\n#        self.linkObj.ViewObject.Visibility = False\n#        fp.ViewObject.Visibility = True\n#        if hasattr(fp.Proxy,\"editingMode\"):\n#            fp.Proxy.editingMode = False\n#        FreeCAD.ActiveDocument.recompute()\n#\n#\n#class JointVP:\n#\n#    def __init__(self, obj):\n#        '''Set this object to the proxy object of the actual view provider'''\n#        obj.Proxy = self\n#\n#    def attach(self, obj):\n#        '''Setup the scene sub-graph of the view provider, this method is mandatory'''\n#        self.Object = obj.Object\n#\n#    def updateData(self, fp, prop):\n#        '''If a property of the handled feature has changed we have the chance to handle this here'''\n#        # fp is the handled feature, prop is the name of the property that has changed\n#        pass\n#\n#    def getDisplayModes(self,obj):\n#        '''Return a list of display modes.'''\n#        modes=[]\n#        modes.append(\"Flat Lines\")\n#        return modes\n#\n#    def setEdit(self,vobj,modNum):\n#        if modNum == 0:\n#            vobj.Object.Proxy.editFace()\n#            return True\n#        elif modNum == 3:\n#            FreeCADGui.runCommand('Part_ColorPerFace',0)\n#            return True\n#\n#    def getDefaultDisplayMode(self):\n#        '''Return the name of the default display mode. It must be defined in getDisplayModes.'''\n#        return \"Flat Lines\"\n \n#    def setDisplayMode(self,mode):\n#        '''Map the display mode defined in attach with those defined in getDisplayModes.\\\n#                Since they have the same names nothing needs to be done. This method is optional'''\n#        return mode\n#\n#    def onChanged(self, vp, prop):\n#        '''Here we can do something when a single property got changed'''\n#        #FreeCAD.Console.PrintMessage(\"Change property: \" + str(prop) + \"\"+chr(10))\n#\n#    def claimChildren(self):\n#        if self.Object.ClaimChildren and self.Object.Face and not self.Object.Shape.isNull() and self.Object.Boolean:\n#            return [self.Object.Face[0]]\n#        else:\n#            return []\n#\n#    def onDelete(self, vobj, subelements):\n#        if vobj.Object.Face:\n#            vobj.Object.Face[0].ViewObject.Visibility = True\n#        if hasattr(vobj.Object,\"_Body\"): #do this only when the object is in a PD body\n#            #need to ensure the next feature in the tree's BaseFeature property points to our BaseFeature\n#            solids = [feat for feat in vobj.Object._Body.Group if feat.isDerivedFrom(\"PartDesign::Feature\") and feat.BaseFeature == vobj.Object]\n#            if len(solids) == 1: #found previous solid feature\n#                solids[0].BaseFeature = vobj.Object.BaseFeature\n#        return True\n#\n#    def getIcon(self):\n#        '''Return the icon in XPM format which will appear in the tree view. This method is\\\n#                optional and if not defined a default icon is shown.'''\n#        return '''\n#/* XPM */\n#static char *_637979355779[] = {\n#/* columns rows colors chars-per-pixel */\n#\"64 64 151 2 \",\n#\"   c #1D1D0E0E3C3C\",\n#\".  c #56160CCD0CCD\",\n#\"X  c #5D370A6C0A6C\",\n#\"o  c #45450D0D1717\",\n#\"O  c #56D714951495\",\n#\"+  c #575718181818\",\n#\"@  c #62620D0D0D0D\",\n#\"#  c #6B150D0D0D0D\",\n#\"$  c #74740D0D0D0D\",\n#\"%  c #79790D0D0D0D\",\n#\"&  c #7D270DB812BD\",\n#\"*  c #77770F0F1F1F\",\n#\"=  c #78780D0D1D1D\",\n#\"-  c #656511111313\",\n#\";  c #717110101212\",\n#\":  c #5E5E0F0F2B2B\",\n#\">  c #4B4B0F0F3BBC\",\n#\",  c #59DA0F0F3C3C\",\n#\"<  c #414111113333\",\n#\"1  c #484810103333\",\n#\"2  c #5D5D10103030\",\n#\"3  c #66660E0E2424\",\n#\"4  c #6BEC0F0F2D2D\",\n#\"5  c #65650F0F3333\",\n#\"6  c #6B6B0D0D3F3F\",\n#\"7  c #73730D0D3636\",\n#\"8  c #5D5D22222222\",\n#\"9  c #63632D2D2D2D\",\n#\"0  c #686835353535\",\n#\"q  c #0C8D0C8D562B\",\n#\"w  c #0AAE0AAE5CF5\",\n#\"e  c #1A1A10105151\",\n#\"r  c #1369136958AE\",\n#\"t  c #37370F0F4D4D\",\n#\"y  c #393911114949\",\n#\"u  c #33330F0F52D3\",\n#\"i  c #31310E0E5858\",\n#\"p  c #398F0DB85C5C\",\n#\"a  c #20A120A15D5D\",\n#\"s  c #0D0D0D0D64A4\",\n#\"d  c #0E0E0E0E6D6D\",\n#\"f  c #0D0D0D0D721C\",\n#\"g  c #0D0D0D0D7CBC\",\n#\"h  c #1C9D0E0E72F3\",\n#\"j  c #15400D637E53\",\n#\"k  c #111110107474\",\n#\"l  c #3A3A0D0D6F6F\",\n#\"z  c #29AA0E0E7777\",\n#\"x  c #37370D0D7373\",\n#\"c  c #2A2A2A2A6262\",\n#\"v  c #36B736B769EA\",\n#\"b  c #46460E0E4F4F\",\n#\"n  c #49090D8E4CCD\",\n#\"m  c #5E5E0D0D4C4C\",\n#\"M  c #49490D0D5F5F\",\n#\"N  c #76F74B4B4B4B\",\n#\"B  c #7F7F58585858\",\n#\"V  c #464646467373\",\n#\"C  c #535353537C7C\",\n#\"Z  c #84B70D740D74\",\n#\"A  c #8CE20D0D0D0D\",\n#\"S  c #947D0CB00CC7\",\n#\"D  c #9B9B0CA60CA6\",\n#\"F  c #81810D0D147B\",\n#\"G  c #90900E0E1515\",\n#\"H  c #9ADA0D0D1192\",\n#\"J  c #949412121212\",\n#\"K  c #A6FC0A430A60\",\n#\"L  c #ACEC0C4C0C4C\",\n#\"P  c #B3D80B300B30\",\n#\"I  c #BD0B0A590A59\",\n#\"U  c #A52513941394\",\n#\"Y  c #A1A11D9E1D9E\",\n#\"T  c #A3A32A2A2A2A\",\n#\"R  c #A4A435353535\",\n#\"E  c #A6A63DBE3DBE\",\n#\"W  c #C1C00A0A0A0A\",\n#\"Q  c #A8A845454545\",\n#\"!  c #AD2D58D958D9\",\n#\"~  c #8A8A69696969\",\n#\"^  c #921274F574F5\",\n#\"/  c #AFAF63636363\",\n#\"(  c #B2B26E6E6E6E\",\n#\")  c #B4B477777777\",\n#\"_  c #B6B67E7E7E7E\",\n#\"`  c #0D8E0D8E85C5\",\n#\"'  c #0D0D0CCD8D78\",\n#\"]  c #16970D8E8686\",\n#\"[  c #13130F0F8888\",\n#\"{  c #0CB70CA6941C\",\n#\"}  c #0C7A0C7A9C2E\",\n#\"|  c #12930D0D9A1A\",\n#\" . c #139413949595\",\n#\".. c #1C9D1C9D9313\",\n#\"X. c #22220D0D8888\",\n#\"o. c #252525259393\",\n#\"O. c #2F2F2F2F9494\",\n#\"+. c #3B3B3B3B9797\",\n#\"@. c #0A0F0A0EA794\",\n#\"#. c #0B200B20A900\",\n#\"$. c #0B0B0B0BB333\",\n#\"%. c #0A0A0A0ABEBE\",\n#\"&. c #29292929A2A2\",\n#\"*. c #4C4C4C4C9D1D\",\n#\"=. c #62E362E38606\",\n#\"-. c #747474749292\",\n#\";. c #5C5C5C5CA323\",\n#\":. c #6B6B6B6BA828\",\n#\">. c #79797979AD2D\",\n#\",. c #68686868B1B1\",\n#\"<. c #0A0A0A0AC1B7\",\n#\"1. c #810181019A1A\",\n#\"2. c #A3A38E8E8E8E\",\n#\"3. c #B9B989898989\",\n#\"4. c #A8A897179717\",\n#\"5. c #BDBD97979797\",\n#\"6. c #92929292A5A5\",\n#\"7. c #9F9F9F9FAEAE\",\n#\"8. c #8A8A8A8AB333\",\n#\"9. c #9A1A9A1AB939\",\n#\"0. c #AEAEA0A0A0A0\",\n#\"q. c #A1A1A1A1AFAF\",\n#\"w. c #BFBFA0A0A0A0\",\n#\"e. c #B5B5AAAAAAAA\",\n#\"r. c #A6A6A6A6BEBE\",\n#\"t. c #BBBBB2B2B2B2\",\n#\"y. c #BFBFB8B8B8B8\",\n#\"u. c #C2C2A7A7A7A7\",\n#\"i. c #C5C5B0B0B0B0\",\n#\"p. c #CACABEBEBEBE\",\n#\"a. c #ACACACACC2C2\",\n#\"s. c #B6B6B6B6C7C7\",\n#\"d. c #BFBFBFBFC6C6\",\n#\"f. c #C81DC51AC8C8\",\n#\"g. c #CFCFC8C8C8C8\",\n#\"h. c #D3D3CECECECE\",\n#\"j. c #C6C6C6C6D0D0\",\n#\"k. c #CDCDCDCDD151\",\n#\"l. c #D4D4D3D3D3D3\",\n#\"z. c #D9D9D7D7D7D7\",\n#\"x. c #D4D4D4D4DA5A\",\n#\"c. c #DADAD9D9DA84\",\n#\"v. c #E0E0DFDFDFDF\",\n#\"b. c #DFDFDFDFE2E2\",\n#\"n. c #E3E3E37CE416\",\n#\"m. c #E8E8E7E7E7E7\",\n#\"M. c #E7E7E7E7E8E8\",\n#\"N. c #ECACECACED2C\",\n#\"B. c #F4BDF4BDF62C\",\n#\"V. c #F426F426FB94\",\n#\"C. c None\",\n#/* pixels */\n#\"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.B.B.V.B.V.B.B.V.V.V.V.\",\n#\"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.B.7.v w w w w w g @.@.@.@.@.\",\n#\"f.B.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.m.1.a w w w q s ' @.@.@.@.@.@.@.\",\n#\"X + B 4.z.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.k.=.r w w s q f { @.@.@.@.@.@.@.@.@.\",\n#\"X X X X X 9 ^ t.B.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.B.r.V w w w w q g @.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"L Z # . X X X X O N 2.l.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.N.6.c w w w w s ` @.@.@.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"W W W I S % @ . X X X X 8 ~ e.m.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.c.-.q w w w q f ' @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W L A # . X X X X . N ^ g.B.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.d.C q w s w q f } @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W I K % @ . @ @ X X + B 0.v.C.C.C.C.C.C.C.C.C.C.C.B.q.v w w w w w g @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W I A $ . X X X X . 0 ^ y.B.C.C.C.C.C.M.1.a w w w q s ' @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W I W W W U Z # . X X X X + N 2.c.k.=.r s w w q d } @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W I S $ X . X X o   q w w w q g @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W L Z e q q w q s ` @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W P #.%.} d { @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W P #.<.<.{ @.@.} @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W } <.<.} #.h 1 @.@.@.@.@.@.@.@.@.@.@.@.@.@.$.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W I [ #.$.' t S 4 @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W D D S ; K K 4 @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W D K K = @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W S L K & @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.$.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W D K K F @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W W W I D K K F @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.@.@.@.@.@.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W I L W W D K K F @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W z b K D K K F @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W X.<.#.y > t h @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W z <.<.| @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W l <.<.@.} @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W x <.<.} @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W x <.<.} @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W x <.<.@.} @.@.@.@.@.@.@.@.@.@.@.$.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W l <.<.@.@.@.u { @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W M <.<.$.j : D ' @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W G * 5 2 % K K ' @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W P S K D ' @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W P S K K j @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W P S K K j @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.$.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W I A K K ] @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W I W W W A K K j @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W 5 , L I A K K j @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W m <.| , - 3 > ' @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W m <.<.%.` @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W 6 <.<.%.' @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W 7 <.<.<.' @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W 7 <.<.<. .@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W 7 <.<.<.' @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W 7 <.<.<.' @.{ j @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.#.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W 7 <.<.<.' h F p @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W H n p p < D K p @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.| ;.j.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W A K K p @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@...>.n.C.C.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W A K K p @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.O.9.B.C.C.C.C.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W A K K b @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.} *.s.B.C.C.C.C.C.C.\",\n#\"W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W A K K b @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@. .:.x.C.C.C.C.C.C.C.C.C.\",\n#\"_ E L W W W I W W W W W W W W W W W W W W W W W W W W W W W W A K K n @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.o.8.m.C.C.C.C.C.C.C.C.C.C.C.\",\n#\"C.C.n.u./ Y I W W W W W W W W W W W W W W W W W W W W U 4 I W S K K n @.@.@.@.@.@.@.@.@.@.@.@.} +.a.V.C.C.C.C.C.C.C.C.C.C.C.C.C.\",\n#\"C.C.C.C.C.C.h.3.Q U W W W W W W W W W W W W W W W W W H <.] 4 A S & i @.@.@.@.@.@.@.@.@.@.} ;.f.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.\",\n#\"C.C.C.C.C.C.C.C.C.B.i.( T P W W W W W W W W W W W W W H <.<.<.k ' @.@.@.@.@.@.@.@.@.@...>.b.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.\",\n#\"C.C.C.C.C.C.C.C.C.C.C.C.C.z.5.! U I W W W W W W W W W H <.<.<.{ @.@.@.@.@.@.@.@.@.O.9.B.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.\",\n#\"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.B.p.) R P W W W W W W K $.<.<.{ @.@.@.@.@.@.} *.s.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.\",\n#\"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.n.w.! J I W W L $.<.<.{ @.@.@.@. .:.x.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.\",\n#\"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.g.3.Q J #.<.<.{ @.@.o.8.m.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.\",\n#\"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.N.a.,.&.` +.a.B.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.\",\n#\"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.v.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.\",\n#\"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.\",\n#\"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.\"\n#};\n\n#'''\n \n#    def __getstate__(self):\n#        '''When saving the document this object gets stored using Python's json module.\\\n#                Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\\\n#                to return a tuple of all serializable objects or None.'''\n#        return None\n \n#    def __setstate__(self,state):\n#        '''When restoring the serialized object from document we have the chance to set some internals here.\\\n#                Since no data were serialized nothing needs to be done here.'''\n#        return None\n\n\n\n############\n#if __name__ == \"__main__\":\n#    FreeCAD.Console.PrintMessage(\"Please run Joint.FCMacro rather than this file.\\n\")\n############\n\n#CODE_ENDS_HERE\n\nBASENAME = 'joint'\n\ndef getBody(feature):\n    doc = FreeCAD.ActiveDocument\n    bodies = [obj for obj in doc.Objects if obj.TypeId == \"PartDesign::Body\"]\n    for bod in bodies:\n        if feature in bod.Group:\n            return bod\n    return None\n\ndef getJointType():\n    '''ask user the joint type to make, return as string'''\n    from PySide import QtCore,QtGui\n    window = QtGui.QApplication.activeWindow()\n    items = [\"Mortise\",\"Tenon\",\"Box Joint\",\"Dovetail Joint\",\"Cantilever Hook\", \"Cantilever Mate\",\"Annular Hook\",\"Annular Mate\",\"Ball Joint\",\"Ball Mate\",\"Split Joint\", \"Split Mate\",\"Cancel\"]\n    caption = \"Select joint type\"\n    item,ok = QtGui.QInputDialog.getItem(window,\"Joint type\",caption,items,False)\n    if ok:\n        return item\n    else:\n        return None\n\ndef makeObject(FP):\n    import DraftGeomUtils as DGU\n    doc = FreeCAD.ActiveDocument\n    body=None\n    selobjs = FreeCADGui.Selection.getSelectionEx()\n    if doc:\n        doc.openTransaction(\"Create Joint\")\n\n        if selobjs:\n            for selobj in selobjs:\n                body = getBody(selobj.Object)\n                jType = getJointType()\n                if not jType:\n                    continue\n                if jType == \"Tenon\" or jType == \"Cantilever Hook\" or jType == \"Annular Hook\" or jType == \"Ball Joint\" or jType == \"Split Joint\":\n                    orientation = \"External\"\n                else:\n                    orientation = \"Internal\"\n                if body:\n                    if orientation == \"External\":\n                        joint = body.newObject(\"PartDesign::FeatureAdditivePython\", \"Joint\")\n                    else:\n                        joint = body.newObject(\"PartDesign::FeatureSubtractivePython\", \"Joint\")\n                else:\n                    joint = doc.addObject(\"Part::FeaturePython\",\"Joint\")\n                FP.Joint(joint)\n                FP.JointVP(joint.ViewObject)\n#                joint.AddSubType = \"Additive\" if bool(jType == \"Tenon\" or jType == \"Cantilever Hook\" or jType == \"Annular Hook\" or jType == \"Ball Joint\" or jType == \"Split Joint\") else \"Subtractive\"\n                joint.Width = joint.Width * 10 if \"Box\" in jType or \"Dovetail\" in jType else joint.Width\n                joint.Depth = 10 if \"Split\" in jType else joint.Depth\n                joint.Proxy.execute(joint)\n                if body:\n                    joint.ClaimChildren = False #do not claim children in Part Design to preserve the linear tree\n                if selobj.HasSubObjects:\n                    faces = [name for name in selobj.SubElementNames if \"Face\" in name]\n                    if faces and len(faces) == 1 and DGU.isPlanar(selobj.Object.getSubObject(faces[0])):\n                        joint.Face = (selobj.Object,faces)\n                    else:\n                        FreeCAD.Console.PrintError(\"Select 1 (planar) face of an object. Using Face1\\n\")\n                        joint.Face = (selobj.Object, [\"Face1\"])\n                else:\n                    joint.Face = (selobj.Object, [\"Face1\"])\n                    FreeCAD.Console.PrintError(\"Select 1 (planar) face of an object.\\n\")\n                joint.JointType = jType\n                if \"Cantilever\" in jType or \"Annular\" in jType:\n                    joint.Depth = 15\n                    joint.Length = 3\n        else:\n            FreeCAD.Console.PrintMessage(\"No face selected to make a joint on.\\n\")\n\n        doc.commitTransaction()\n        doc.recompute()\n\ndef writeFile():\n    with open(py_file,\"w\") as outfile:\n        for line in code.splitlines():\n            if \"#CODE_ENDS_HERE\" in line:\n                break\n            if line.startswith('#'):\n                if line == \"# -*- coding: utf-8 -*-\":\n                    line = \"#\" + line\n                outfile.write(line[1:]+\"\\n\") #skip first character (#)\n\n\nif __name__ == \"__main__\":\n    import os\n    fin = open(__file__, 'r')\n    code = fin.read()\n    fin.close()\n    version = code.splitlines()[1][16:]\n    real_path = os.path.realpath(__file__)\n    dir_path = os.path.dirname(real_path)\n    py_file = real_path.replace(\".FCMacro\",\".py\").replace('Joint','joint')\n    bHasFile = os.path.exists(py_file)\n    noImport = False #user elects not to save import file\n\n    if not bHasFile:\n        from PySide import QtCore,QtGui\n        window = QtGui.QApplication.activeWindow()\n        items = [\"Yes, go ahead and create the file.\", \"No, do not create the file.\",\"Cancel\"]\n        caption = \"In order for \"+BASENAME+\" objects to be parametric after saving and reloading file\\n\\\nwe need to create another file on this computer.  File to be created will be: \\n\\n\"+py_file+\"\\n\\n\\\nThis makes it available to the system upon restarting FreeCAD and loading documents containing the \\n\\\n\"+BASENAME+\" feature python objects.  May we proceed?\\n\\n\"\n        item,ok = QtGui.QInputDialog.getItem(window,\"One time installation\",caption,items)\n        if ok and item == items[0]:\n            writeFile()\n            QtGui.QMessageBox.information(window,\"Success\",\"File successfully created.  Please note: if you uninstall \"+BASENAME+\" macro you need to manually remove this file, too.\\n\")\n        else:\n            new_lines = []\n            for line in code.splitlines():\n                if line.startswith('#'):\n                    if \"CODE_ENDS_HERE\" in line:\n                        break\n                    if line == \"# -*- coding: utf-8 -*-\":\n                        new_lines.append(line+\"\\n\")\n                        continue\n                    new_lines.append(line[1:]+\"\\n\")\n            code = \"\".join(new_lines)\n\n            #credit to Mila Nautikus for his answer to a question on stackoverflow, which I modified here\n            #in this example the filename is bevel.py\n            #https://stackoverflow.com/questions/5362771/how-to-load-a-module-from-code-in-a-string\n\n            ##########\n            import sys, importlib\n            my_name = 'joint' #filename = joint.py, so this must be 'joint'\n            my_spec = importlib.util.spec_from_loader(my_name, loader=None)\n\n            joint = importlib.util.module_from_spec(my_spec)\n\n            exec(code, joint.__dict__)\n            sys.modules['joint'] = joint\n            makeObject(joint)\n            noImport = True\n\n    if not noImport: #don't never use no double negatives\n\n        import joint as FP\n        import addonmanager_utilities as utils\n\n        if FP.__version__ != __version__:\n            writeFile()\n            from PySide import QtCore,QtGui\n            window = QtGui.QApplication.activeWindow()\n            mbox = QtGui.QMessageBox()\n            mbox.setWindowTitle(BASENAME+\" updated\")\n\n            mbox.setText(BASENAME+\".py has been updated to version \"+__version__+\". \\\nYou must restart FreeCAD for the new changes to take effect and to use the macro.\")\n            mbox.setIcon(mbox.Warning)\n            mbox.setStandardButtons(mbox.Ok | mbox.Cancel)\n            mbox.setDefaultButton(mbox.Cancel)\n            okBtn = mbox.button(QtGui.QMessageBox.StandardButton.Ok)\n            cancelBtn = mbox.button(QtGui.QMessageBox.StandardButton.Cancel)\n            okBtn.setText(\"Restart now\")\n            cancelBtn.setText(\"Restart later\")\n            ret = mbox.exec_()\n            if ret == mbox.Ok:\n                QtCore.QTimer.singleShot(1000, utils.restart_freecad)\n        else:\n            makeObject(FP)",
    "url": "https://wiki.freecad.org/Macro_Joint",
    "raw_code_url": "https://gist.github.com/mwganson/09d70aa11183e57b5f5925169b4c70b9/raw/2a3530b44bfbad473647d8d7060b278c95c255e1/Joint.FCMacro",
    "wiki": "",
    "version": "0.2022.12.21",
    "license": "",
    "date": "2022-12-21",
    "src_filename": "",
    "filename_from_url": "",
    "author": "TheMarkster",
    "icon": "C:/Users/FikoYT/AppData/Local/cache\\FreeCAD\\Cache\\AddonManager\\MacroIcons\\Macro_Joint_Icon.svg",
    "icon_source": "https://wiki.freecad.org//images/e/ee/Macro_Joint_Icon.svg",
    "xpm": "",
    "other_files": [
      ""
    ],
    "parsed": true
  }
]