Mercurial > hg > camir-aes2014
diff toolboxes/graph_visualisation/lib/lefty/dotty.lefty @ 0:e9a9cd732c1e tip
first hg version after svn
author | wolffd |
---|---|
date | Tue, 10 Feb 2015 15:05:51 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolboxes/graph_visualisation/lib/lefty/dotty.lefty Tue Feb 10 15:05:51 2015 +0000 @@ -0,0 +1,735 @@ +# +# DOTTY +# +dotty = [ + 'keys' = [ + 'nid' = 'nid'; + 'eid' = 'eid'; + 'gid' = 'gid'; + 'name' = 'name'; + 'attr' = 'attr'; + 'gattr' = 'graphattr'; + 'eattr' = 'edgeattr'; + 'nattr' = 'nodeattr'; + 'edges' = 'edges'; + 'tail' = 'tail'; + 'tport' = 'tport'; + 'head' = 'head'; + 'hport' = 'hport'; + 'pos' = 'pos'; + 'size' = 'size'; + 'rect' = 'rect'; + 'fname' = 'fontname'; + 'fsize' = 'fontsize'; + 'fcolor' = 'fontcolor'; + 'dcolor' = 'drawcolor'; + 'bcolor' = 'fillcolor'; + ]; + 'maps' = [ + 'X11' = [ + 'fontmap' = [ + 'Times-Roman' = '-*-times-medium-r-*--%d-*-*-*-*-*-*-1'; + 'Times-Italic' = '-*-times-medium-i-*--%d-*-*-*-*-*-*-1'; + 'Times-Bold' = '-*-times-bold-r-*--%d-*-*-*-*-*-*-1'; + 'Courier' = '-*-courier-bold-r-*--%d-*-*-*-*-*-*-1'; + 'Courier-Bold' = '-*-courier-bold-r-*--%d-*-*-*-*-*-*-1'; + 'Helvetica' = ( + '-*-helvetica-medium-r-normal--%d-*-*-*-p-*-iso8859-1' + ); + 'Helvetica-Bold' = ( + '-*-helvetica-bold-r-normal--%d-*-*-*-p-*-iso8859-1' + ); + ]; + 'psfontmap' = [ + 'Times-Roman' = 'Times-Roman'; + 'Times-Italic' = 'Times-Italic'; + 'Times-Bold' = 'Times-Bold'; + 'Courier' = 'Courier'; + 'Courier-Bold' = 'Courier-Bold'; + 'Helvetica' = 'Helvetica'; + 'Helvetica-Bold' = 'Helvetica-Bold'; + ]; + ]; + 'mswin' = [ + 'fontmap' = [ + 'Times-Roman' = 'Times New Roman'; + 'Times-Italic' = 'Times New Roman Italic'; + 'Times-Bold' = 'Times New Roman Bold'; + 'Courier' = 'Courier New'; + 'Courier-Bold' = 'Courier New Bold'; + 'Helvetica' = 'Arial'; + 'Helvetica-Bold' = 'Arial Bold'; + ]; + 'psfontmap' = [ + 'Times-Roman' = 'Times New Roman'; + 'Times-Italic' = 'Times New Roman Italic'; + 'Times-Bold' = 'Times New Roman Bold'; + 'Courier' = 'Courier New'; + 'Courier-Bold' = 'Courier New Bold'; + 'Helvetica' = 'Arial'; + 'Helvetica-Bold' = 'Arial Bold'; + ]; + ]; + ]; + 'protogt' = [ + 'graph' = [ + 'graphattr' = [ + 'fontsize' = '14'; + 'fontname' = 'Times-Roman'; + 'fontcolor' = 'black'; + ]; + 'nodeattr' = [ + 'shape' = 'ellipse'; + 'fontsize' = '14'; + 'fontname' = 'Times-Roman'; + 'fontcolor' = 'black'; + 'style' = 'solid'; + ]; + 'edgeattr' = [ + 'fontsize' = '14'; + 'fontname' = 'Times-Roman'; + 'fontcolor' = 'black'; + 'style' = 'solid'; + ]; + 'graphdict' = []; + 'nodedict' = []; + 'graphs' = []; + 'nodes' = []; + 'edges' = []; + 'maxgid' = 0; + 'maxnid' = 0; + 'maxeid' = 0; + 'type' = 'digraph'; + ]; + 'layoutmode' = 'sync'; + 'lserver' = 'dot'; + 'edgehandles' = 1; + 'noundo' = 0; + ]; + 'lservers' = []; + 'mlevel' = 0; + 'graphs' = []; + 'views' = []; + 'protovt' = [ + 'normal' = [ + 'name' = 'DOTTY'; + 'orig' = ['x' = 1; 'y' = 1;]; + 'size' = ['x' = 420; 'y' = 520;]; + 'wrect' = [ + 0 = ['x' = 0; 'y' = 0;]; + 1 = ['x' = 400; 'y' = 500;]; + ]; + 'vsize' = ['x' = 400; 'y' = 500;]; + 'w2v' = 1; + ]; + 'birdseye' = [ + 'type' = 'birdseye'; + 'name' = 'DOTTY birdseye view'; + 'orig' = ['x' = 1; 'y' = 1;]; + 'size' = ['x' = 220; 'y' = 260;]; + 'wrect' = [ + 0 = ['x' = 0; 'y' = 0;]; + 1 = ['x' = 200; 'y' = 250;]; + ]; + 'vsize' = ['x' = 200; 'y' = 250;]; + 'w2v' = 1; + ]; + ]; + 'pagesizes' = [ + '8.5x11' = ['x' = 8; 'y' = 10.5;]; + '11x17' = ['x' = 10.5; 'y' = 16.5;]; + '36x50' = ['x' = 35.5; 'y' = 49.5;]; + ]; +]; +load ('dotty_draw.lefty'); +load ('dotty_edit.lefty'); +load ('dotty_layout.lefty'); +load ('dotty_ui.lefty'); +# +# initialization functions +# +dotty.init = function () { + dotty.fontmap = dotty.maps[getenv ('LEFTYWINSYS')].fontmap; + dotty.clipgt = dotty.protogt.creategraph (['noundo' = 1;]); + dotty.inited = 1; +}; +dotty.simple = function (file) { + if (dotty.inited ~= 1) + dotty.init (); + dotty.createviewandgraph (file, 'file', null, null); + txtview ('off'); +}; +# +# main operations +# +dotty.protogt.creategraph = function (protogt) { + local gt, id, gtid; + + if (~protogt) + protogt = dotty.protogt; + for (gtid = 0; dotty.graphs[gtid]; gtid = gtid + 1) + ; + gt = (dotty.graphs[gtid] = []); + if (protogt.mode ~= 'replace') { + for (id in dotty.protogt) + gt[id] = copy (dotty.protogt[id]); + } + for (id in protogt) + gt[id] = copy (protogt[id]); + gt.gtid = gtid; + gt.views = []; + gt.undoarray = ['level' = 0; 'entries' = [];]; + gt.busy = 0; + return gt; +}; +dotty.protogt.copygraph = function (ogt) { + local gt, gtid, id; + + for (gtid = 0; dotty.graphs[gtid]; gtid = gtid + 1) + ; + gt = (dotty.graphs[gtid] = []); + for (id in ogt) + gt[id] = copy (ogt[id]); + gt.gtid = gtid; + gt.views = []; + gt.undoarray = ['level' = 0; 'entries' = [];]; + gt.busy = 0; + return gt; +}; +dotty.protogt.destroygraph = function (gt) { + local vid, vlist; + + if (gt.layoutpending > 0) + gt.cancellayout (gt); + for (vid in gt.views) + vlist[vid] = gt.views[vid]; + for (vid in gt.views) + gt.destroyview (gt, vlist[vid]); + remove (gt.gtid, dotty.graphs); +}; +dotty.protogt.loadgraph = function (gt, name, type, protograph, layoutflag) { + local fd, vid, vt, graph, nid, eid, gid; + + if (gt.layoutpending > 0) + gt.cancellayout (gt); + if (~name) + if (~(name = ask ('file name:', 'file', ''))) + return; + dotty.pushbusy (gt, gt.views); + dotty.message (1, 'loading'); + if (~protograph) + protograph = dotty.protogt.graph; + if ( + ~((fd = dotty.openio (name, type, 'r')) >= 0) | + ~(graph = readgraph (fd, protograph)) + ) { + dotty.message (0, 'cannot load graph'); + dotty.popbusy (gt, gt.views); + return; + } + for (vid in gt.views) { + vt = gt.views[vid]; + vt.colors = []; + vt.colorn = 2; + } + gt.graph = graph; + gt.name = name; + gt.type = type; + gt.undoarray = ['level' = 0; 'entries' = [];]; + if (~(type == 'file' & name == '-')) + closeio (fd); + graph.maxgid = tablesize (graph.graphs); + graph.maxnid = tablesize (graph.nodes); + graph.maxeid = tablesize (graph.edges); + for (nid in graph.nodes) + graph.nodes[nid][dotty.keys.nid] = nid; + for (eid in graph.edges) + graph.edges[eid][dotty.keys.eid] = eid; + for (gid in graph.graphs) + graph.graphs[gid][dotty.keys.gid] = gid; + gt.unpackattr (gt); + if (layoutflag) { + dotty.message (1, 'generating layout'); + gt.layoutgraph (gt); + } + dotty.popbusy (gt, gt.views); + return gt.graph; +}; +dotty.protogt.savegraph = function (gt, name, type) { + local fd; + + if (~name) + if (~(name = ask ('file name:', 'file', ''))) + return; + if ( + ~((fd = dotty.openio (name, type, 'w')) >= 0) | + ~writegraph (fd, gt.graph, 0) + ) { + dotty.message (0, 'cannot save graph'); + return; + } + if (~(type == 'file' & name == '-')) + closeio (fd); +}; +dotty.protogt.setgraph = function (gt, graph) { + local vid, vt, nid, eid, gid; + + if (gt.layoutpending > 0) + gt.cancellayout (gt); + for (vid in gt.views) { + vt = gt.views[vid]; + vt.colors = []; + vt.colorn = 2; + } + gt.graph = copy (graph); + gt.undoarray = ['level' = 0; 'entries' = [];]; + gt.unpackattr (gt); + gt.graph.maxgid = tablesize (graph.graphs); + gt.graph.maxnid = tablesize (graph.nodes); + gt.graph.maxeid = tablesize (graph.edges); + for (nid in gt.graph.nodes) + gt.graph.nodes[nid][dotty.keys.nid] = nid; + for (eid in gt.graph.edges) + gt.graph.edges[eid][dotty.keys.eid] = eid; + for (gid in gt.graph.graphs) + gt.graph.graphs[gid][dotty.keys.gid] = gid; + gt.unpackattr (gt); + dotty.message (1, 'generating layout'); + gt.layoutgraph (gt); + return gt.graph; +}; +dotty.protogt.erasegraph = function (gt, protogt, protovt) { + local vid, vt; + + if (gt.layoutpending > 0) + gt.cancellayout (gt); + for (vid in gt.views) { + vt = gt.views[vid]; + vt.colors = []; + vt.colorn = 2; + clear (vt.canvas); + } + if (~protogt) + protogt = dotty.protogt; + gt.graph = copy (protogt.graph); + gt.undoarray = ['level' = 0; 'entries' = [];]; +}; +dotty.protogt.layoutgraph = function (gt) { + if (gt.graph.graphattr.xdotversion) { + gt.unpacklayout (gt, gt.graph); + gt.setviewsize (gt.views, gt.graph.rect); + gt.redrawgraph (gt, gt.views); + return; + } + if (gt.layoutmode == 'async') { + if (~gt.haveinput) { + gt.startlayout (gt); + return; + } + if (~gt.finishlayout (gt)) + return; + gt.setviewsize (gt.views, gt.graph.rect); + gt.redrawgraph (gt, gt.views); + } else { + if (~gt.startlayout (gt)) + return; + else + while (~gt.finishlayout (gt)) + ; + gt.setviewsize (gt.views, gt.graph.rect); + gt.redrawgraph (gt, gt.views); + } +}; +dotty.protogt.createview = function (gt, protovt) { + local vt, ovt, id, t; + + vt = []; + vt.colors = []; + vt.colorn = 2; + if (~protovt) + protovt = dotty.protovt.normal; + if (protovt.mode ~= 'replace') { + for (id in dotty.protovt[protovt.type]) + vt[id] = copy (dotty.protovt[protovt.type][id]); + } + for (id in protovt) + vt[id] = copy (protovt[id]); + if (~(vt.parent >= 0)) { + vt.view = createwidget (-1, [ + 'type' = 'view'; + 'name' = vt.name; + 'origin' = vt.orig; + 'size' = vt.size; + ]); + vt.scroll = createwidget (vt.view, ['type' = 'scroll';]); + } else { + vt.view = -1; + vt.scroll = createwidget (vt.parent, [ + 'type' = 'scroll'; + 'size' = vt.size; + ]); + } + vt.canvas = createwidget (vt.scroll, [ + 'type' = 'canvas'; + 'color' = [0 = protovt.bgcolor; 1 = protovt.fgcolor;]; + ]); + setwidgetattr (vt.canvas, [ + 'window' = vt.wrect; + 'viewport' = vt.vsize; + ]); + clear (vt.canvas); + dotty.views[vt.canvas] = vt; + vt.vtid = vt.canvas; + vt.gtid = gt.gtid; + gt.views[vt.vtid] = vt; + dotty.views[vt.scroll] = vt; + if (vt.view ~= -1) + dotty.views[vt.view] = vt; + if (protovt.colors & tablesize (protovt.colors) > 0) { + for (id in protovt.colors) + if (id == '_bgcolor_') + setwidgetattr (vt.canvas, [ + 'color' = [0 = protovt.colors[id];]; + ]); + else if (setwidgetattr (vt.canvas, ['color' = [ + protovt.colors[id] = id; + ];]) ~= 1) { + t = split (id, ' '); + if (tablesize (t) ~= 3 | setwidgetattr (vt.canvas, [ + 'color' = [protovt.colors[id] = [ + 'h' = ston (t[0]); 's' = ston (t[1]); 'v' = ston (t[2]); + ];]; + ]) ~= 1) { + dotty.message ( + 0, concat ('unknown color ', id, ' using #1') + ); + } + } + vt.colors = copy (protovt.colors); + vt.colorn = protovt.colorn; + } else if (tablesize (gt.views) > 1) { + for (id in gt.views) + if (gt.views[id] ~= vt) + break; + ovt = gt.views[id]; + for (id in ovt.colors) + if (id == '_bgcolor_') + setwidgetattr (vt.canvas, ['color' = [0 = ovt.colors[id];];]); + else if (setwidgetattr (vt.canvas, ['color' = [ + ovt.colors[id] = id; + ];]) ~= 1) { + t = split (id, ' '); + if (tablesize (t) ~= 3 | setwidgetattr (vt.canvas, [ + 'color' = [ovt.colors[id] = [ + 'h' = ston (t[0]); 's' = ston (t[1]); 'v' = ston (t[2]); + ];]; + ]) ~= 1) { + dotty.message ( + 0, concat ('unknown color ', id, ' using #1') + ); + } + } + vt.colors = copy (ovt.colors); + vt.colorn = ovt.colorn; + } + if (gt.graph.rect) + gt.setviewsize ([vt.vtid = vt;], gt.graph.rect); + gt.drawgraph (gt, [vt.vtid = vt;]); + for (id in vt.uifuncs) + if (id == 'closeview') + widgets[vt.view][id] = vt.uifuncs[id]; + else + widgets[vt.canvas][id] = vt.uifuncs[id]; + return vt; +}; +dotty.protogt.destroyview = function (gt, vt) { + destroywidget (vt.canvas); + destroywidget (vt.scroll); + if (vt.view ~= -1) { + destroywidget (vt.view); + remove (vt.view, dotty.views); + } + remove (vt.scroll, dotty.views); + remove (vt.canvas, dotty.views); + if (vt.gtid >= 0) + remove (vt.vtid, gt.views); + if (tablesize (dotty.views) == 0) + exit (); +}; +dotty.protogt.zoom = function (gt, vt, factor, pos) { + gt.setviewscale ([vt.vtid = vt;], factor); + if (pos) + gt.setviewcenter ([vt.vtid = vt;], pos); + gt.redrawgraph (gt, [vt.vtid = vt;]); +}; +dotty.protogt.findnode = function (gt, vt) { + local key, node, node1, nid; + + if (~(key = ask ('give node name or label'))) + return; + if (gt.graph.nodedict[key] >= 0) + node = gt.graph.nodes[gt.graph.nodedict[key]]; + else if (gt.graph.nodedict[ston (key)] >= 0) + node = gt.graph.nodes[gt.graph.nodedict[ston (key)]]; + else { + for (nid in gt.graph.nodes) { + node1 = gt.graph.nodes[nid]; + if (node1.attr.label == key | node1.attr.label == ston (key)) { + node = node1; + break; + } + } + } + if (~node) { + dotty.message (0, concat ('cannot find node: ', key)); + return; + } + gt.setviewcenter ([vt.vtid = vt;], node.pos); +}; +dotty.protogt.setattr = function (gt, obj) { + local kv, t, attr, value; + + if (~(kv = ask ('give attr/value, eg. color=blue'))) + return; + t = split (kv, '='); + attr = t[0]; + value = t[1]; + if ( + obj.attr == gt.graph.graphattr | + obj.attr == gt.graph.edgeattr | + obj.attr == gt.graph.nodeattr + ) { + obj.attr[attr] = value; + return; + } + if (obj.nid >= 0) { + gt.undrawnode (gt, gt.views, obj); + obj.attr[attr] = value; + gt.unpacknodeattr (gt, obj); + gt.drawnode (gt, gt.views, obj); + } else if (obj.eid >= 0) { + gt.undrawedge (gt, gt.views, obj); + obj.attr[attr] = value; + gt.unpackedgeattr (gt, obj); + gt.drawedge (gt, gt.views, obj); + } +}; +dotty.protogt.getattr = function (gt, node) { + local kv; + + if (~(kv.key = ask ('give attr name'))) + return null; + if ((kv.val = node.attr[kv.key])) + return kv; + return null; +}; +# +# utilities +# +dotty.createviewandgraph = function (name, type, protogt, protovt) { + local vt, gt; + + if (~protogt) + protogt = dotty.protogt; + if (protogt.creategraph) + gt = protogt.creategraph (protogt); + else + gt = dotty.protogt.creategraph (protogt); + vt = gt.createview (gt, protovt); + if (~protogt.graph) + protogt.graph = copy (dotty.protogt.graph); + if (name) + gt.loadgraph (gt, name, type, protogt.graph, 1); + return ['gt' = gt; 'vt' = vt;]; +}; +dotty.openio = function (name, type, mode) { + local fd; + + if (~name) + return null; + if (type == 'file') { + if (name == '-') { + if (mode == 'r' | mode == 'r+') + fd = 0; + else + fd = 1; + } else if (~((fd = openio ('file', name, mode)) >= 0)) { + dotty.message (0, concat ('cannot open file: ', name)); + return null; + } + } else if (type == 'pipe') { + if (~((fd = openio ( + 'pipe', 'ksh', mode, concat ("%e ", name) + )) >= 0)) { + dotty.message (0, concat ('cannot run command: ', name)); + return null; + } + } else + return null; + return fd; +}; +dotty.pushbusy = function (gt, views) { + local vid; + + if (gt.busy == 0) + for (vid in gt.views) + setwidgetattr (vid, ['cursor' = 'watch';]); + gt.busy = gt.busy + 1; +}; +dotty.popbusy = function (gt, views) { + local vid; + + gt.busy = gt.busy - 1; + if (gt.busy == 0) + for (vid in gt.views) + setwidgetattr (vid, ['cursor' = 'default';]); +}; +dotty.message = function (level, text) { + if (level <= dotty.mlevel) + echo ('dotty.lefty: ', text); +}; +# +# printing or saving to file +# +dotty.protogt.printorsave = function (gt, vt, otype, name, mode, ptype) { + local pr, wrect, vsize, xy, psize, canvas, pscanvas, cid, cname, t; + local graph, edgehandles, fontmap, eid, edge, nid, node, gid, sgraph; + local did, draw, i; + + if (~otype) + if (~(otype = ask ('print to', 'choice', 'file|printer'))) + return; + if (otype == 'printer') { + if (~getenv ('TMPDIR')) + name = concat (getenv ('HOME'), '/.dottyout.ps'); + else + name = concat (getenv ('TMPDIR'), '/.dottyout.ps', random (10000)); + if (getenv ('LEFTYWINSYS') ~= 'mswin' & ~pr) + if (~(pr = ask ('printer command', 'string', 'lpr'))) + return; + } + if (~name) + if (~(name = ask ('postscript file', 'file', 'out.ps'))) + return; + if (~ptype) + if (~(ptype = ask ('page size', 'choice', '8.5x11|11x17|36x50'))) + return; + if (~mode) + if (~(mode = ask ('mode', 'choice', 'portrait|landscape|best fit'))) + return; + wrect = copy (vt.wrect); + wrect[0].x = wrect[0].x - 1; + wrect[1].x = wrect[1].x + 1; + wrect[0].y = wrect[0].y - 1; + wrect[1].y = wrect[1].y + 1; + vsize = copy (vt.vsize); + if (vsize.x == 0) + vsize.x = 1; + if (vsize.y == 0) + vsize.y = 1; + xy = vsize.x / vsize.y; + if (mode == 'best fit') { + if (xy < 1) + mode = 'portrait'; + else + mode = 'landscape'; + } + psize = dotty.pagesizes[ptype]; + if (mode == 'portrait') { + if (xy < psize.x / psize.y) { + vsize.y = psize.y * 300; + vsize.x = vsize.y * xy; + } else { + vsize.x = psize.x * 300; + vsize.y = vsize.x / xy; + } + } else { + if (xy < psize.y / psize.x) { + vsize.y = psize.x * 300; + vsize.x = vsize.y * xy; + } else { + vsize.x = psize.y * 300; + vsize.y = vsize.x / xy; + } + } + if (~((pscanvas = createwidget (-1, [ + 'type' = 'ps'; + 'origin' = ['x' = 0; 'y' = 0;]; + 'size' = vsize; + 'mode' = mode; + 'name' = name; + ])) >= 0)) { + dotty.message (0, 'cannot open printer device'); + return; + } + for (cname in vt.colors) { + cid = vt.colors[cname]; + if (cname == '_bgcolor_') + setwidgetattr (pscanvas, ['color' = [0 = cid;];]); + else if (setwidgetattr (pscanvas, ['color' = [cid = cname;];]) ~= 1) { + t = split (cname, ' '); + if (tablesize (t) ~= 3 | setwidgetattr (pscanvas, [ + 'color' = [cid = [ + 'h' = ston (t[0]); 's' = ston (t[1]); 'v' = ston (t[2]); + ];]; + ]) ~= 1) { + dotty.message ( + 0, concat ('unknown color ', cname, ' using #1') + ); + } + } + } + setwidgetattr (pscanvas, ['window' = wrect;]); + graph = copy (gt.graph); + canvas = vt.canvas; + vt.canvas = pscanvas; + edgehandles = gt.edgehandles; + gt.edgehandles = 0; + fontmap = dotty.maps[getenv ('LEFTYWINSYS')].psfontmap; + for (eid in graph.edges) { + edge = graph.edges[eid]; + edge.fontname = fontmap[edge.attr.fontname]; + for (did in edge.draws) { + if (did == 'ep') + continue; + draw = edge.draws[did]; + for (i = 0; draw[i]; i = i + 1) + if (draw[i].type == 'F') + draw[i].fn = fontmap[draw[i].ofn]; + } + gt.drawedge (gt, [0 = vt;], edge); + } + for (nid in graph.nodes) { + node = graph.nodes[nid]; + node.fontname = fontmap[node.attr.fontname]; + for (did in node.draws) { + if (did == 'ep') + continue; + draw = node.draws[did]; + for (i = 0; draw[i]; i = i + 1) + if (draw[i].type == 'F') + draw[i].fn = fontmap[draw[i].ofn]; + } + gt.drawnode (gt, [0 = vt;], node); + } + for (gid in graph.graphs) { + sgraph = graph.graphs[gid]; + sgraph.fontname = fontmap[sgraph.graphattr.fontname]; + for (did in sgraph.draws) { + if (did == 'ep') + continue; + draw = sgraph.draws[did]; + for (i = 0; draw[i]; i = i + 1) + if (draw[i].type == 'F') + draw[i].fn = fontmap[draw[i].ofn]; + } + gt.drawsgraph (gt, [0 = vt;], sgraph); + } + graph.fontname = fontmap[graph.graphattr.fontname]; + gt.drawsgraph (gt, [0 = vt;], graph); + gt.edgehandles = edgehandles; + vt.canvas = canvas; + destroywidget (pscanvas); + if (otype == 'printer' & getenv ('LEFTYWINSYS') ~= 'mswin') + system (concat (pr, ' ', name, '; rm ',name)); +};