Merge svghmi
authorEdouard Tisserant
Wed, 12 Aug 2020 15:24:02 +0200
branchsvghmi
changeset 3024 0a9f6f29b7dd
parent 3023 407a0205405a (current diff)
parent 3021 49799de67540 (diff)
child 3025 48e7e336c052
Merge
svghmi/gen_index_xhtml.xslt
svghmi/svghmi.js
svghmi/widget_button.ysl2
svghmi/widget_tooglebutton.ysl2
svghmi/widgets_common.ysl2
--- a/svghmi/gen_index_xhtml.xslt	Wed Aug 12 13:36:18 2020 +0200
+++ b/svghmi/gen_index_xhtml.xslt	Wed Aug 12 15:24:02 2020 +0200
@@ -850,7 +850,7 @@
     <xsl:variable name="args">
       <xsl:for-each select="$widget/arg">
         <xsl:text>"</xsl:text>
-        <xsl:value-of select="@value"/>
+        <xsl:value-of select="func:escape_quotes(@value)"/>
         <xsl:text>"</xsl:text>
         <xsl:if test="position()!=last()">
           <xsl:text>,</xsl:text>
@@ -959,6 +959,34 @@
 </xsl:text>
     <xsl:text>
 </xsl:text>
+    <xsl:text>const local_defaults = {
+</xsl:text>
+    <xsl:for-each select="$parsed_widgets/widget[@type = 'VarInit']">
+      <xsl:if test="count(path) != 1">
+        <xsl:message terminate="yes">
+          <xsl:text>VarInit </xsl:text>
+          <xsl:value-of select="@id"/>
+          <xsl:text> must have only one variable given.</xsl:text>
+        </xsl:message>
+      </xsl:if>
+      <xsl:if test="path/@type != 'PAGE_LOCAL' and path/@type != 'HMI_LOCAL'">
+        <xsl:message terminate="yes">
+          <xsl:text>VarInit </xsl:text>
+          <xsl:value-of select="@id"/>
+          <xsl:text> only applies to HMI variable.</xsl:text>
+        </xsl:message>
+      </xsl:if>
+      <xsl:value-of select="arg[0]"/>
+      <xsl:text>:</xsl:text>
+      <xsl:value-of select="path/@value"/>
+      <xsl:if test="position()!=last()">
+        <xsl:text>,</xsl:text>
+      </xsl:if>
+      <xsl:text>
+</xsl:text>
+    </xsl:for-each>
+    <xsl:text>};
+</xsl:text>
     <xsl:text>var cache = hmitree_types.map(_ignored =&gt; undefined);
 </xsl:text>
     <xsl:text>
@@ -975,20 +1003,12 @@
 </xsl:text>
     <xsl:text>        hmi_locals[pagename] = {[varname]:new_index}
 </xsl:text>
-    <xsl:text>        console.log("pagelocalindex insert",varname, pagename, new_index);
-</xsl:text>
     <xsl:text>    } else {
 </xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>        console.log("pagevars",pagevars);
-</xsl:text>
     <xsl:text>        let result = pagevars[varname];
 </xsl:text>
     <xsl:text>        if(result != undefined) {
 </xsl:text>
-    <xsl:text>            console.log("pagelocalindex reuse",varname, pagename, result);
-</xsl:text>
     <xsl:text>            return result;
 </xsl:text>
     <xsl:text>        }
@@ -999,12 +1019,8 @@
 </xsl:text>
     <xsl:text>        pagevars[varname] = new_index;
 </xsl:text>
-    <xsl:text>        console.log("pagelocalindex addwidget",varname, pagename, new_index);
-</xsl:text>
     <xsl:text>    }
 </xsl:text>
-    <xsl:text>    cache[new_index] = "";
-</xsl:text>
     <xsl:text>    return new_index;
 </xsl:text>
     <xsl:text>}
@@ -1030,6 +1046,10 @@
 </xsl:text>
     <xsl:text>
 </xsl:text>
+    <xsl:text>var pending_widget_animates = [];
+</xsl:text>
+    <xsl:text>
+</xsl:text>
     <xsl:text>class Widget {
 </xsl:text>
     <xsl:text>    offset = 0;
@@ -1038,6 +1058,10 @@
 </xsl:text>
     <xsl:text>    unsubscribable = false;
 </xsl:text>
+    <xsl:text>    pending_animate = false;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
     <xsl:text>    constructor(elt_id,args,indexes,members){
 </xsl:text>
     <xsl:text>        this.element_id = elt_id;
@@ -1108,11 +1132,11 @@
 </xsl:text>
     <xsl:text>    apply_cache() {
 </xsl:text>
-    <xsl:text>        if(!this.unsubscribable) for(let i = 0; i &lt; this.indexes.length; i++) {
+    <xsl:text>        if(!this.unsubscribable) for(let index of this.indexes){
 </xsl:text>
     <xsl:text>            /* dispatch current cache in newly opened page widgets */
 </xsl:text>
-    <xsl:text>            let realindex = this.get_variable_index(i);
+    <xsl:text>            let realindex = this.get_variable_index(index);
 </xsl:text>
     <xsl:text>            let cached_val = cache[realindex];
 </xsl:text>
@@ -1166,7 +1190,7 @@
 </xsl:text>
     <xsl:text>    new_hmi_value(index, value, oldval) {
 </xsl:text>
-    <xsl:text>    /*  try {*/
+    <xsl:text>        try {
 </xsl:text>
     <xsl:text>            // TODO avoid searching, store index at sub()
 </xsl:text>
@@ -1206,11 +1230,39 @@
 </xsl:text>
     <xsl:text>            }
 </xsl:text>
-    <xsl:text>    /*    } catch(err) {
+    <xsl:text>        } catch(err) {
 </xsl:text>
     <xsl:text>            console.log(err);
 </xsl:text>
-    <xsl:text>        }*/
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>    
+</xsl:text>
+    <xsl:text>    _animate(){
+</xsl:text>
+    <xsl:text>        this.animate();
+</xsl:text>
+    <xsl:text>        this.pending_animate = false;
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    request_animate(){
+</xsl:text>
+    <xsl:text>        if(!this.pending_animate){
+</xsl:text>
+    <xsl:text>            pending_widget_animates.push(this);
+</xsl:text>
+    <xsl:text>            this.pending_animate = true;
+</xsl:text>
+    <xsl:text>            requestHMIAnimation();
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>
 </xsl:text>
     <xsl:text>    }
 </xsl:text>
@@ -1246,8 +1298,8 @@
     <xsl:text>}
 </xsl:text>
   </xsl:template>
-  <xsl:variable name="excluded_types" select="str:split('Page Lang')"/>
-  <xsl:variable name="excluded_ids" select="$parsed_widgets/widget[not(@type = $excluded_types)]/@id"/>
+  <xsl:variable name="excluded_types" select="str:split('Page Lang VarInit')"/>
+  <xsl:variable name="included_ids" select="$parsed_widgets/widget[not(@type = $excluded_types)]/@id"/>
   <declarations:hmi-elements/>
   <xsl:template match="declarations:hmi-elements">
     <xsl:text>
@@ -1260,7 +1312,7 @@
 </xsl:text>
     <xsl:text>var hmi_widgets = {
 </xsl:text>
-    <xsl:apply-templates mode="hmi_widgets" select="$hmi_elements[@id = $excluded_ids]"/>
+    <xsl:apply-templates mode="hmi_widgets" select="$hmi_elements[@id = $included_ids]"/>
     <xsl:text>}
 </xsl:text>
     <xsl:text>
@@ -1343,11 +1395,9 @@
   </xsl:template>
   <func:function name="func:escape_quotes">
     <xsl:param name="txt"/>
-    <xsl:variable name="frst" select="substring-before($txt,'&quot;')"/>
-    <xsl:variable name="frstln" select="string-length($frst)"/>
     <xsl:choose>
-      <xsl:when test="$frstln &gt; 0 and string-length($txt) &gt; $frstln">
-        <func:result select="concat($frst,'\&quot;',func:escape_quotes(substring-after($txt,'&quot;')))"/>
+      <xsl:when test="contains($txt,'&quot;')">
+        <func:result select="concat(substring-before($txt,'&quot;'),'\&quot;',func:escape_quotes(substring-after($txt,'&quot;')))"/>
       </xsl:when>
       <xsl:otherwise>
         <func:result select="$txt"/>
@@ -1380,6 +1430,78 @@
     <xsl:text>}
 </xsl:text>
   </xsl:template>
+  <xsl:template mode="widget_class" match="widget[@type='Button']">
+    <xsl:text>class ButtonWidget extends Widget{
+</xsl:text>
+    <xsl:text>    frequency = 5;
+</xsl:text>
+    <xsl:text>    state = 0;
+</xsl:text>
+    <xsl:text>    active_style = undefined;
+</xsl:text>
+    <xsl:text>    inactive_style = undefined;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     on_mouse_down(evt) {
+</xsl:text>
+    <xsl:text>         if (this.active_style &amp;&amp; this.inactive_style) {
+</xsl:text>
+    <xsl:text>             this.active_elt.setAttribute("style", this.active_style);
+</xsl:text>
+    <xsl:text>             this.inactive_elt.setAttribute("style", "display:none");
+</xsl:text>
+    <xsl:text>         }
+</xsl:text>
+    <xsl:text>         this.apply_hmi_value(0, 1);
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     on_mouse_up(evt) {
+</xsl:text>
+    <xsl:text>         if (this.active_style &amp;&amp; this.inactive_style) {
+</xsl:text>
+    <xsl:text>             this.active_elt.setAttribute("style", "display:none");
+</xsl:text>
+    <xsl:text>             this.inactive_elt.setAttribute("style", this.inactive_style);
+</xsl:text>
+    <xsl:text>         }
+</xsl:text>
+    <xsl:text>         this.apply_hmi_value(0, 0);
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     init() {
+</xsl:text>
+    <xsl:text>        this.active_style = this.active_elt ? this.active_elt.style.cssText : undefined;
+</xsl:text>
+    <xsl:text>        this.inactive_style = this.inactive_elt ? this.inactive_elt.style.cssText : undefined;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        if (this.active_style &amp;&amp; this.inactive_style) {
+</xsl:text>
+    <xsl:text>            this.active_elt.setAttribute("style", "display:none");
+</xsl:text>
+    <xsl:text>            this.inactive_elt.setAttribute("style", this.inactive_style);
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        this.element.setAttribute("onmousedown", "hmi_widgets["+this.element_id+"].on_mouse_down(evt)");
+</xsl:text>
+    <xsl:text>        this.element.setAttribute("onmouseup", "hmi_widgets["+this.element_id+"].on_mouse_up(evt)");
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>}
+</xsl:text>
+  </xsl:template>
   <xsl:template mode="widget_defs" match="widget[@type='Button']">
     <xsl:param name="hmi_element"/>
     <xsl:call-template name="defs_by_labels">
@@ -1389,63 +1511,7 @@
       </xsl:with-param>
       <xsl:with-param name="mandatory" select="'no'"/>
     </xsl:call-template>
-    <xsl:text>frequency: 5,
-</xsl:text>
-    <xsl:text>on_mouse_down: function(evt) {
-</xsl:text>
-    <xsl:text>    if (this.active_style &amp;&amp; this.inactive_style) {
-</xsl:text>
-    <xsl:text>        this.active_elt.setAttribute("style", this.active_style);
-</xsl:text>
-    <xsl:text>        this.inactive_elt.setAttribute("style", "display:none");
-</xsl:text>
-    <xsl:text>    }
-</xsl:text>
-    <xsl:text>    this.apply_hmi_value(0, 1);
-</xsl:text>
-    <xsl:text>},
-</xsl:text>
-    <xsl:text>on_mouse_up: function(evt) {
-</xsl:text>
-    <xsl:text>    if (this.active_style &amp;&amp; this.inactive_style) {
-</xsl:text>
-    <xsl:text>        this.active_elt.setAttribute("style", "display:none");
-</xsl:text>
-    <xsl:text>        this.inactive_elt.setAttribute("style", this.inactive_style);
-</xsl:text>
-    <xsl:text>    }
-</xsl:text>
-    <xsl:text>    this.apply_hmi_value(0, 0);
-</xsl:text>
-    <xsl:text>},
-</xsl:text>
-    <xsl:text>active_style: undefined,
-</xsl:text>
-    <xsl:text>inactive_style: undefined,
-</xsl:text>
-    <xsl:text>init: function() {
-</xsl:text>
-    <xsl:text>  this.active_style = this.active_elt ? this.active_elt.style.cssText : undefined;
-</xsl:text>
-    <xsl:text>  this.inactive_style = this.inactive_elt ? this.inactive_elt.style.cssText : undefined;
-</xsl:text>
-    <xsl:text>  if (this.active_style &amp;&amp; this.inactive_style) {
-</xsl:text>
-    <xsl:text>      this.active_elt.setAttribute("style", "display:none");
-</xsl:text>
-    <xsl:text>      this.inactive_elt.setAttribute("style", this.inactive_style);
-</xsl:text>
-    <xsl:text>  }
-</xsl:text>
-    <xsl:text>  this.element.setAttribute("onmousedown", "hmi_widgets['</xsl:text>
-    <xsl:value-of select="$hmi_element/@id"/>
-    <xsl:text>'].on_mouse_down(evt)");
-</xsl:text>
-    <xsl:text>  this.element.setAttribute("onmouseup", "hmi_widgets['</xsl:text>
-    <xsl:value-of select="$hmi_element/@id"/>
-    <xsl:text>'].on_mouse_up(evt)");
-</xsl:text>
-    <xsl:text>},
+    <xsl:text>
 </xsl:text>
   </xsl:template>
   <xsl:template mode="widget_defs" match="widget[@type='CircularBar']">
@@ -1544,6 +1610,320 @@
     <xsl:text>},
 </xsl:text>
   </xsl:template>
+  <xsl:template mode="widget_class" match="widget[@type='CircularSlider']">
+    <xsl:text>class CircularSliderWidget extends Widget{
+</xsl:text>
+    <xsl:text>    frequency = 5;
+</xsl:text>
+    <xsl:text>    range = undefined;
+</xsl:text>
+    <xsl:text>    circle = undefined;
+</xsl:text>
+    <xsl:text>    handle_pos = undefined;
+</xsl:text>
+    <xsl:text>    drag = false;
+</xsl:text>
+    <xsl:text>    enTimer = false;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    dispatch(value) {
+</xsl:text>
+    <xsl:text>        if(!this.drag){
+</xsl:text>
+    <xsl:text>            if(this.value_elt)
+</xsl:text>
+    <xsl:text>                this.value_elt.textContent = String(value);
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>            this.handle_position(value);
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    handle_position(value){
+</xsl:text>
+    <xsl:text>        let [min,max,totalDistance] = this.range;
+</xsl:text>
+    <xsl:text>        let length = Math.max(0,Math.min((totalDistance),(Number(value)-min)/(max-min)*(totalDistance)));
+</xsl:text>
+    <xsl:text>        let tip = this.range_elt.getPointAtLength(length);
+</xsl:text>
+    <xsl:text>        this.handle_elt.setAttribute('transform',"translate("+(tip.x-this.handle_pos.x)+","+(tip.y-this.handle_pos.y)+")");
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    on_release(evt) {
+</xsl:text>
+    <xsl:text>        if(this.drag){
+</xsl:text>
+    <xsl:text>            this.drag = false;
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    update_position(evt){
+</xsl:text>
+    <xsl:text>        if(this.drag &amp;&amp; this.enTimer){
+</xsl:text>
+    <xsl:text>            var svg_dist = 0;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>            //calculate center of widget in html
+</xsl:text>
+    <xsl:text>            // --TODO maybe it would be better to bind this part to window change size event ???
+</xsl:text>
+    <xsl:text>            let [xdest,ydest,svgWidth,svgHeight] = page_desc[current_visible_page].bbox;
+</xsl:text>
+    <xsl:text>            let [cX, cY,fiStart,fiEnd,minMax,x1,y1,width,height] = this.circle;
+</xsl:text>
+    <xsl:text>            let htmlCirc = this.range_elt.getBoundingClientRect();
+</xsl:text>
+    <xsl:text>            let cxHtml = ((htmlCirc.right-htmlCirc.left)/(width)*(cX-x1))+htmlCirc.left;
+</xsl:text>
+    <xsl:text>            let cyHtml = ((htmlCirc.bottom-htmlCirc.top)/(height)*(cY-y1))+htmlCirc.top;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>            //get mouse coordinates
+</xsl:text>
+    <xsl:text>            let mouseX = undefined;
+</xsl:text>
+    <xsl:text>            let mouseY = undefined;
+</xsl:text>
+    <xsl:text>            if (evt.type.startsWith("touch")){
+</xsl:text>
+    <xsl:text>                mouseX = Math.ceil(evt.touches[0].clientX);
+</xsl:text>
+    <xsl:text>                mouseY = Math.ceil(evt.touches[0].clientY);
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>            else{
+</xsl:text>
+    <xsl:text>                mouseX = evt.pageX;
+</xsl:text>
+    <xsl:text>                mouseY = evt.pageY;
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>            //calculate angle
+</xsl:text>
+    <xsl:text>            let fi = Math.atan2(cyHtml-mouseY, mouseX-cxHtml);
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>            // transform from 0 to 2PI
+</xsl:text>
+    <xsl:text>            if (fi &gt; 0){
+</xsl:text>
+    <xsl:text>                fi = 2*Math.PI-fi;
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>            else{
+</xsl:text>
+    <xsl:text>                fi = -fi;
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>            //offset it to 0
+</xsl:text>
+    <xsl:text>            fi = fi - fiStart;
+</xsl:text>
+    <xsl:text>            if (fi &lt; 0){
+</xsl:text>
+    <xsl:text>                fi = fi + 2*Math.PI;
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>            //get handle distance from mouse position
+</xsl:text>
+    <xsl:text>            if(fi&lt;fiEnd){
+</xsl:text>
+    <xsl:text>                svg_dist=(fi)/(fiEnd)*(this.range[1]-this.range[0]);
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>            else if(fiEnd&lt;fi &amp;&amp; fi&lt;fiEnd+minMax){
+</xsl:text>
+    <xsl:text>                svg_dist = this.range[1];
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>            else{
+</xsl:text>
+    <xsl:text>                svg_dist = this.range[0];
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>            //redraw handle --TODO is it fast enough if I just call change_hmi_value???
+</xsl:text>
+    <xsl:text>            this.handle_position(svg_dist);
+</xsl:text>
+    <xsl:text>            if(this.value_elt)
+</xsl:text>
+    <xsl:text>                this.value_elt.textContent = String(Math.ceil(svg_dist));
+</xsl:text>
+    <xsl:text>            this.apply_hmi_value(0, Math.ceil(svg_dist));
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>            //reset timer
+</xsl:text>
+    <xsl:text>            this.enTimer = false;
+</xsl:text>
+    <xsl:text>            setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100);
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    on_select(evt){
+</xsl:text>
+    <xsl:text>        this.drag = true;
+</xsl:text>
+    <xsl:text>        this.enTimer = true;
+</xsl:text>
+    <xsl:text>        this.update_position(evt);
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    init() {
+</xsl:text>
+    <xsl:text>        //get min max
+</xsl:text>
+    <xsl:text>        let min = this.min_elt ?
+</xsl:text>
+    <xsl:text>                    Number(this.min_elt.textContent) :
+</xsl:text>
+    <xsl:text>                    this.args.length &gt;= 1 ? this.args[0] : 0;
+</xsl:text>
+    <xsl:text>        let max = this.max_elt ?
+</xsl:text>
+    <xsl:text>                    Number(this.max_elt.textContent) :
+</xsl:text>
+    <xsl:text>                    this.args.length &gt;= 2 ? this.args[1] : 100;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        //fiStart ==&gt; offset
+</xsl:text>
+    <xsl:text>        let fiStart = Number(this.range_elt.getAttribute('sodipodi:start'));
+</xsl:text>
+    <xsl:text>        let fiEnd = Number(this.range_elt.getAttribute('sodipodi:end'));
+</xsl:text>
+    <xsl:text>        fiEnd = fiEnd - fiStart;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        //fiEnd ==&gt; size of angle
+</xsl:text>
+    <xsl:text>        if (fiEnd &lt; 0){
+</xsl:text>
+    <xsl:text>            fiEnd = 2*Math.PI + fiEnd;
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        //min max barrier angle
+</xsl:text>
+    <xsl:text>        let minMax = (2*Math.PI - fiEnd)/2;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        //get parameters from svg
+</xsl:text>
+    <xsl:text>        let cX = Number(this.range_elt.getAttribute('sodipodi:cx'));
+</xsl:text>
+    <xsl:text>        let cY = Number(this.range_elt.getAttribute('sodipodi:cy'));
+</xsl:text>
+    <xsl:text>        this.range_elt.style.strokeMiterlimit="0"; //eliminates some weird border around html object
+</xsl:text>
+    <xsl:text>        this.range = [min, max,this.range_elt.getTotalLength()];
+</xsl:text>
+    <xsl:text>        let cPos = this.range_elt.getBBox();
+</xsl:text>
+    <xsl:text>        this.handle_pos = this.range_elt.getPointAtLength(0);
+</xsl:text>
+    <xsl:text>        this.circle = [cX, cY,fiStart,fiEnd,minMax,cPos.x,cPos.y,cPos.width,cPos.height];
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        //init events
+</xsl:text>
+    <xsl:text>        this.handle_elt.addEventListener("touchstart", hmi_widgets[this.element_id].on_select.bind(this));
+</xsl:text>
+    <xsl:text>        this.handle_elt.addEventListener("mousedown", hmi_widgets[this.element_id].on_select.bind(this));
+</xsl:text>
+    <xsl:text>        this.element.addEventListener("mousedown", hmi_widgets[this.element_id].on_select.bind(this));
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        window.addEventListener("touchmove", hmi_widgets[this.element_id].update_position.bind(this));
+</xsl:text>
+    <xsl:text>        window.addEventListener("mousemove", hmi_widgets[this.element_id].update_position.bind(this));
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        window.addEventListener("mouseup", hmi_widgets[this.element_id].on_release.bind(this))
+</xsl:text>
+    <xsl:text>        window.addEventListener("touchend", hmi_widgets[this.element_id].on_release.bind(this));
+</xsl:text>
+    <xsl:text>        window.addEventListener("touchcancel", hmi_widgets[this.element_id].on_release.bind(this));
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>}
+</xsl:text>
+  </xsl:template>
+  <xsl:template mode="widget_defs" match="widget[@type='CircularSlider']">
+    <xsl:param name="hmi_element"/>
+    <xsl:call-template name="defs_by_labels">
+      <xsl:with-param name="hmi_element" select="$hmi_element"/>
+      <xsl:with-param name="labels">
+        <xsl:text>handle range</xsl:text>
+      </xsl:with-param>
+    </xsl:call-template>
+    <xsl:call-template name="defs_by_labels">
+      <xsl:with-param name="hmi_element" select="$hmi_element"/>
+      <xsl:with-param name="labels">
+        <xsl:text>value min max</xsl:text>
+      </xsl:with-param>
+      <xsl:with-param name="mandatory" select="'no'"/>
+    </xsl:call-template>
+    <xsl:text>
+</xsl:text>
+  </xsl:template>
   <xsl:template mode="widget_class" match="widget[@type='Display']">
     <xsl:text>class DisplayWidget extends Widget{
 </xsl:text>
@@ -2833,6 +3213,13 @@
   </xsl:template>
   <xsl:template mode="widget_defs" match="widget[@type='Input']">
     <xsl:param name="hmi_element"/>
+    <xsl:call-template name="defs_by_labels">
+      <xsl:with-param name="hmi_element" select="$hmi_element"/>
+      <xsl:with-param name="labels">
+        <xsl:text>key_pos</xsl:text>
+      </xsl:with-param>
+      <xsl:with-param name="mandatory" select="'no'"/>
+    </xsl:call-template>
     <xsl:variable name="value_elt">
       <xsl:call-template name="defs_by_labels">
         <xsl:with-param name="hmi_element" select="$hmi_element"/>
@@ -2891,11 +3278,13 @@
 </xsl:text>
     <xsl:text>    on_edit_click: function(opstr) {
 </xsl:text>
+    <xsl:text>        var size = (typeof this.key_pos_elt !== 'undefined') ?  this.key_pos_elt.getBBox() : undefined
+</xsl:text>
     <xsl:text>        edit_value("</xsl:text>
     <xsl:value-of select="path/@value"/>
     <xsl:text>", "</xsl:text>
     <xsl:value-of select="path/@type"/>
-    <xsl:text>", this, this.last_val);
+    <xsl:text>", this, this.last_val,size);
 </xsl:text>
     <xsl:text>    },
 </xsl:text>
@@ -3310,6 +3699,298 @@
     <xsl:text>
 </xsl:text>
   </xsl:template>
+  <xsl:template mode="widget_class" match="widget[@type='Keypad']">
+    <xsl:text>class KeypadWidget extends Widget{
+</xsl:text>
+    <xsl:text>     moving = undefined;
+</xsl:text>
+    <xsl:text>     enTimer = undefined;
+</xsl:text>
+    <xsl:text>     offset = undefined;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     on_position_click(evt) {
+</xsl:text>
+    <xsl:text>         this.moving = true;
+</xsl:text>
+    <xsl:text>         this.enTimer = true;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>         // get click position offset from widget x,y and save it to variable
+</xsl:text>
+    <xsl:text>         var keypad_borders = this.position_elt.getBoundingClientRect();
+</xsl:text>
+    <xsl:text>         var clickX = undefined;
+</xsl:text>
+    <xsl:text>         var clickY = undefined;
+</xsl:text>
+    <xsl:text>         if (evt.type == "touchstart"){
+</xsl:text>
+    <xsl:text>             clickX = Math.ceil(evt.touches[0].clientX);
+</xsl:text>
+    <xsl:text>             clickY = Math.ceil(evt.touches[0].clientY);
+</xsl:text>
+    <xsl:text>         }
+</xsl:text>
+    <xsl:text>         else{
+</xsl:text>
+    <xsl:text>             clickX = evt.pageX;
+</xsl:text>
+    <xsl:text>             clickY = evt.pageY;
+</xsl:text>
+    <xsl:text>         }
+</xsl:text>
+    <xsl:text>         this.offset=[clickX-keypad_borders.left,clickY-keypad_borders.top]
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     off_position_click(evt) {
+</xsl:text>
+    <xsl:text>        if(this.moving)
+</xsl:text>
+    <xsl:text>            this.moving = false;
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     on_move(evt) {
+</xsl:text>
+    <xsl:text>         if(this.moving &amp;&amp; this.enTimer){
+</xsl:text>
+    <xsl:text>             //get keyboard pos in html
+</xsl:text>
+    <xsl:text>             let [eltid, tmpgrp] = current_modal;
+</xsl:text>
+    <xsl:text>             let [xcoord,ycoord] = this.coordinates;
+</xsl:text>
+    <xsl:text>             let [xdest,ydest,svgWidth,svgHeight] = page_desc[current_visible_page].bbox;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>             //get mouse coordinates
+</xsl:text>
+    <xsl:text>             var clickX = undefined;
+</xsl:text>
+    <xsl:text>             var clickY = undefined;
+</xsl:text>
+    <xsl:text>             if (evt.type == "touchmove"){
+</xsl:text>
+    <xsl:text>                 clickX = Math.ceil(evt.touches[0].clientX);
+</xsl:text>
+    <xsl:text>                 clickY = Math.ceil(evt.touches[0].clientY);
+</xsl:text>
+    <xsl:text>             }
+</xsl:text>
+    <xsl:text>             else{
+</xsl:text>
+    <xsl:text>                 clickX = evt.pageX;
+</xsl:text>
+    <xsl:text>                 clickY = evt.pageY;
+</xsl:text>
+    <xsl:text>             }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>             //translate keyboard position
+</xsl:text>
+    <xsl:text>             let mouseX = ((clickX-this.offset[0])/window.innerWidth)*svgWidth;
+</xsl:text>
+    <xsl:text>             let mouseY = ((clickY-this.offset[1])/window.innerHeight)*svgHeight;
+</xsl:text>
+    <xsl:text>             tmpgrp.setAttribute("transform","translate("+String(xdest-xcoord+mouseX)+","+String(ydest-ycoord+mouseY)+")");
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>             //reset timer
+</xsl:text>
+    <xsl:text>             this.enTimer = false;
+</xsl:text>
+    <xsl:text>             setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100);
+</xsl:text>
+    <xsl:text>         }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     on_key_click(symbols) {
+</xsl:text>
+    <xsl:text>         var syms = symbols.split(" ");
+</xsl:text>
+    <xsl:text>         this.shift |= this.caps;
+</xsl:text>
+    <xsl:text>         this.editstr += syms[this.shift?syms.length-1:0];
+</xsl:text>
+    <xsl:text>         this.shift = false;
+</xsl:text>
+    <xsl:text>         this.update();
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     on_Esc_click() {
+</xsl:text>
+    <xsl:text>         end_modal.call(this);
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     on_Enter_click() {
+</xsl:text>
+    <xsl:text>         end_modal.call(this);
+</xsl:text>
+    <xsl:text>         let callback_obj = this.result_callback_obj;
+</xsl:text>
+    <xsl:text>         callback_obj.edit_callback(this.editstr);
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     on_BackSpace_click() {
+</xsl:text>
+    <xsl:text>         this.editstr = this.editstr.slice(0,this.editstr.length-1);
+</xsl:text>
+    <xsl:text>         this.update();
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     on_Sign_click() {
+</xsl:text>
+    <xsl:text>         if(this.editstr[0] == "-")
+</xsl:text>
+    <xsl:text>             this.editstr = this.editstr.slice(1,this.editstr.length);
+</xsl:text>
+    <xsl:text>         else
+</xsl:text>
+    <xsl:text>             this.editstr = "-" + this.editstr;
+</xsl:text>
+    <xsl:text>         this.update();
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     on_NumDot_click() {
+</xsl:text>
+    <xsl:text>         if(this.editstr.indexOf(".") == "-1"){
+</xsl:text>
+    <xsl:text>             this.editstr += ".";
+</xsl:text>
+    <xsl:text>             this.update();
+</xsl:text>
+    <xsl:text>         }
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     on_Space_click() {
+</xsl:text>
+    <xsl:text>         this.editstr += " ";
+</xsl:text>
+    <xsl:text>         this.update();
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     caps = false;
+</xsl:text>
+    <xsl:text>     _caps = undefined;
+</xsl:text>
+    <xsl:text>     on_CapsLock_click() {
+</xsl:text>
+    <xsl:text>         this.caps = !this.caps;
+</xsl:text>
+    <xsl:text>         this.update();
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     shift = false;
+</xsl:text>
+    <xsl:text>     _shift = undefined;
+</xsl:text>
+    <xsl:text>     on_Shift_click() {
+</xsl:text>
+    <xsl:text>         this.shift = !this.shift;
+</xsl:text>
+    <xsl:text>         this.caps = false;
+</xsl:text>
+    <xsl:text>         this.update();
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>     editstr = "";
+</xsl:text>
+    <xsl:text>     _editstr = undefined;
+</xsl:text>
+    <xsl:text>     result_callback_obj = undefined;
+</xsl:text>
+    <xsl:text>     start_edit(info, valuetype, callback_obj, initial,size) {
+</xsl:text>
+    <xsl:text>         show_modal.call(this,size);
+</xsl:text>
+    <xsl:text>         this.editstr = initial;
+</xsl:text>
+    <xsl:text>         this.result_callback_obj = callback_obj;
+</xsl:text>
+    <xsl:text>         this.Info_elt.textContent = info;
+</xsl:text>
+    <xsl:text>         this.shift = false;
+</xsl:text>
+    <xsl:text>         this.caps = false;
+</xsl:text>
+    <xsl:text>         this.update();
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>     update() {
+</xsl:text>
+    <xsl:text>         if(this.editstr != this._editstr){
+</xsl:text>
+    <xsl:text>             this._editstr = this.editstr;
+</xsl:text>
+    <xsl:text>             this.Value_elt.textContent = this.editstr;
+</xsl:text>
+    <xsl:text>         }
+</xsl:text>
+    <xsl:text>         if(this.shift != this._shift){
+</xsl:text>
+    <xsl:text>             this._shift = this.shift;
+</xsl:text>
+    <xsl:text>             (this.shift?widget_active_activable:widget_inactive_activable)(this.Shift_sub);
+</xsl:text>
+    <xsl:text>         }
+</xsl:text>
+    <xsl:text>         if(this.caps != this._caps){
+</xsl:text>
+    <xsl:text>             this._caps = this.caps;
+</xsl:text>
+    <xsl:text>             (this.caps?widget_active_activable:widget_inactive_activable)(this.CapsLock_sub);
+</xsl:text>
+    <xsl:text>         }
+</xsl:text>
+    <xsl:text>     }
+</xsl:text>
+    <xsl:text>}
+</xsl:text>
+  </xsl:template>
   <xsl:template mode="widget_defs" match="widget[@type='Keypad']">
     <xsl:param name="hmi_element"/>
     <xsl:call-template name="defs_by_labels">
@@ -3321,7 +4002,7 @@
     <xsl:call-template name="defs_by_labels">
       <xsl:with-param name="hmi_element" select="$hmi_element"/>
       <xsl:with-param name="labels">
-        <xsl:text>Sign Space NumDot</xsl:text>
+        <xsl:text>Sign Space NumDot position</xsl:text>
       </xsl:with-param>
       <xsl:with-param name="mandatory" select="'no'"/>
     </xsl:call-template>
@@ -3359,105 +4040,27 @@
       <xsl:text>_click()");
 </xsl:text>
     </xsl:for-each>
+    <xsl:text>        if(this.position_elt){
+</xsl:text>
+    <xsl:text>           this.position_elt.setAttribute("onmousedown", "hmi_widgets['"+this.element_id+"'].on_position_click(evt)");
+</xsl:text>
+    <xsl:text>           this.position_elt.setAttribute("ontouchstart", "hmi_widgets['"+this.element_id+"'].on_position_click(evt)");
+</xsl:text>
+    <xsl:text>           window.addEventListener("mouseup", hmi_widgets[this.element_id].off_position_click.bind(this));
+</xsl:text>
+    <xsl:text>           window.addEventListener("touchend", hmi_widgets[this.element_id].off_position_click.bind(this));
+</xsl:text>
+    <xsl:text>           window.addEventListener("touchcancel", hmi_widgets[this.element_id].off_position_click.bind(this));
+</xsl:text>
+    <xsl:text>           window.addEventListener("mousemove", hmi_widgets[this.element_id].on_move.bind(this));
+</xsl:text>
+    <xsl:text>           window.addEventListener("touchmove", hmi_widgets[this.element_id].on_move.bind(this));
+</xsl:text>
+    <xsl:text>       }
+</xsl:text>
     <xsl:text>    },
 </xsl:text>
-    <xsl:text>    on_key_click: function(symbols) {
-</xsl:text>
-    <xsl:text>        var syms = symbols.split(" ");
-</xsl:text>
-    <xsl:text>        this.shift |= this.caps;
-</xsl:text>
-    <xsl:text>        this.editstr += syms[this.shift?syms.length-1:0];
-</xsl:text>
-    <xsl:text>        this.shift = false;
-</xsl:text>
-    <xsl:text>        this.update();
-</xsl:text>
-    <xsl:text>    },
-</xsl:text>
-    <xsl:text>    on_Esc_click: function() {
-</xsl:text>
-    <xsl:text>        end_modal.call(this);
-</xsl:text>
-    <xsl:text>    },
-</xsl:text>
-    <xsl:text>    on_Enter_click: function() {
-</xsl:text>
-    <xsl:text>        end_modal.call(this);
-</xsl:text>
-    <xsl:text>        callback_obj = this.result_callback_obj;
-</xsl:text>
-    <xsl:text>        callback_obj.edit_callback(this.editstr);
-</xsl:text>
-    <xsl:text>    },
-</xsl:text>
-    <xsl:text>    on_BackSpace_click: function() {
-</xsl:text>
-    <xsl:text>        this.editstr = this.editstr.slice(0,this.editstr.length-1);
-</xsl:text>
-    <xsl:text>        this.update();
-</xsl:text>
-    <xsl:text>    },
-</xsl:text>
-    <xsl:text>    on_Sign_click: function() {
-</xsl:text>
-    <xsl:text>        if(this.editstr[0] == "-")
-</xsl:text>
-    <xsl:text>            this.editstr = this.editstr.slice(1,this.editstr.length);
-</xsl:text>
-    <xsl:text>        else
-</xsl:text>
-    <xsl:text>            this.editstr = "-" + this.editstr;
-</xsl:text>
-    <xsl:text>        this.update();
-</xsl:text>
-    <xsl:text>    },
-</xsl:text>
-    <xsl:text>    on_NumDot_click: function() {
-</xsl:text>
-    <xsl:text>        if(this.editstr.indexOf(".") == "-1"){
-</xsl:text>
-    <xsl:text>            this.editstr += ".";
-</xsl:text>
-    <xsl:text>            this.update();
-</xsl:text>
-    <xsl:text>        }
-</xsl:text>
-    <xsl:text>    },
-</xsl:text>
-    <xsl:text>    on_Space_click: function() {
-</xsl:text>
-    <xsl:text>        this.editstr += " ";
-</xsl:text>
-    <xsl:text>        this.update();
-</xsl:text>
-    <xsl:text>    },
-</xsl:text>
-    <xsl:text>    caps: false,
-</xsl:text>
-    <xsl:text>    _caps: undefined,
-</xsl:text>
-    <xsl:text>    on_CapsLock_click: function() {
-</xsl:text>
-    <xsl:text>        this.caps = !this.caps;
-</xsl:text>
-    <xsl:text>        this.update();
-</xsl:text>
-    <xsl:text>    },
-</xsl:text>
-    <xsl:text>    shift: false,
-</xsl:text>
-    <xsl:text>    _shift: undefined,
-</xsl:text>
-    <xsl:text>    on_Shift_click: function() {
-</xsl:text>
-    <xsl:text>        this.shift = !this.shift;
-</xsl:text>
-    <xsl:text>        this.caps = false;
-</xsl:text>
-    <xsl:text>        this.update();
-</xsl:text>
-    <xsl:text>    },
+    <xsl:text>
 </xsl:text>
     <xsl:variable name="g" select="$geometry[@Id = $hmi_element/@id]"/>
     <xsl:text>    coordinates: [</xsl:text>
@@ -3466,58 +4069,6 @@
     <xsl:value-of select="$g/@y"/>
     <xsl:text>],
 </xsl:text>
-    <xsl:text>    editstr: "",
-</xsl:text>
-    <xsl:text>    _editstr: undefined,
-</xsl:text>
-    <xsl:text>    result_callback_obj: undefined,
-</xsl:text>
-    <xsl:text>    start_edit: function(info, valuetype, callback_obj, initial) {
-</xsl:text>
-    <xsl:text>        show_modal.call(this);
-</xsl:text>
-    <xsl:text>        this.editstr = initial;
-</xsl:text>
-    <xsl:text>        this.result_callback_obj = callback_obj;
-</xsl:text>
-    <xsl:text>        this.Info_elt.textContent = info;
-</xsl:text>
-    <xsl:text>        this.shift = false;
-</xsl:text>
-    <xsl:text>        this.caps = false;
-</xsl:text>
-    <xsl:text>        this.update();
-</xsl:text>
-    <xsl:text>    },
-</xsl:text>
-    <xsl:text>    update: function() {
-</xsl:text>
-    <xsl:text>        if(this.editstr != this._editstr){
-</xsl:text>
-    <xsl:text>            this._editstr = this.editstr;
-</xsl:text>
-    <xsl:text>            this.Value_elt.textContent = this.editstr;
-</xsl:text>
-    <xsl:text>        }
-</xsl:text>
-    <xsl:text>        if(this.shift != this._shift){
-</xsl:text>
-    <xsl:text>            this._shift = this.shift;
-</xsl:text>
-    <xsl:text>            (this.shift?widget_active_activable:widget_inactive_activable)(this.Shift_sub);
-</xsl:text>
-    <xsl:text>        }
-</xsl:text>
-    <xsl:text>        if(this.caps != this._caps){
-</xsl:text>
-    <xsl:text>            this._caps = this.caps;
-</xsl:text>
-    <xsl:text>            (this.caps?widget_active_activable:widget_inactive_activable)(this.CapsLock_sub);
-</xsl:text>
-    <xsl:text>        }
-</xsl:text>
-    <xsl:text>    },
-</xsl:text>
   </xsl:template>
   <xsl:template mode="widget_defs" match="widget[@type='List']">
     <xsl:param name="hmi_element"/>
@@ -3592,16 +4143,20 @@
     <xsl:text>    },
 </xsl:text>
   </xsl:template>
-  <xsl:template mode="widget_class" match="widget[@type='Switch']">
-    <xsl:text>class SwitchWidget extends Widget{
+  <xsl:template mode="widget_class" match="widget[@type='MultiState']">
+    <xsl:text>class MultiStateWidget extends Widget{
 </xsl:text>
     <xsl:text>    frequency = 5;
 </xsl:text>
+    <xsl:text>    state = 0;
+</xsl:text>
     <xsl:text>    dispatch(value) {
 </xsl:text>
+    <xsl:text>        this.state = value;
+</xsl:text>
     <xsl:text>        for(let choice of this.choices){
 </xsl:text>
-    <xsl:text>            if(value != choice.value){
+    <xsl:text>            if(this.state != choice.value){
 </xsl:text>
     <xsl:text>                choice.elt.setAttribute("style", "display:none");
 </xsl:text>
@@ -3615,10 +4170,62 @@
 </xsl:text>
     <xsl:text>    }
 </xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    on_click(evt) {
+</xsl:text>
+    <xsl:text>        //get current selected value
+</xsl:text>
+    <xsl:text>        let next_ind;
+</xsl:text>
+    <xsl:text>        for(next_ind=0; next_ind&lt;this.choices.length; next_ind++){
+</xsl:text>
+    <xsl:text>            if(this.state == this.choices[next_ind].value){
+</xsl:text>
+    <xsl:text>               next_ind = next_ind + 1;
+</xsl:text>
+    <xsl:text>               break;
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        //get next selected value
+</xsl:text>
+    <xsl:text>        if(this.choices.length &gt; next_ind){
+</xsl:text>
+    <xsl:text>            this.state = this.choices[next_ind].value;
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>        else{
+</xsl:text>
+    <xsl:text>            this.state = this.choices[0].value;
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        //post value to plc
+</xsl:text>
+    <xsl:text>        this.apply_hmi_value(0, this.state);
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    init() {
+</xsl:text>
+    <xsl:text>        this.element.setAttribute("onclick", "hmi_widgets['"+this.element_id+"'].on_click(evt)");
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
     <xsl:text>}
 </xsl:text>
   </xsl:template>
-  <xsl:template mode="widget_defs" match="widget[@type='Switch']">
+  <xsl:template mode="widget_defs" match="widget[@type='MultiState']">
     <xsl:param name="hmi_element"/>
     <xsl:text>    choices: [
 </xsl:text>
@@ -3649,6 +4256,457 @@
     <xsl:text>    ],
 </xsl:text>
   </xsl:template>
+  <xsl:template mode="widget_class" match="widget[@type='Slider']">
+    <xsl:text>class SliderWidget extends Widget{
+</xsl:text>
+    <xsl:text>    frequency = 5;
+</xsl:text>
+    <xsl:text>    range = undefined;
+</xsl:text>
+    <xsl:text>    fi = undefined;
+</xsl:text>
+    <xsl:text>    drag = false;
+</xsl:text>
+    <xsl:text>    enTimer = false;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    dispatch(value) {
+</xsl:text>
+    <xsl:text>        if(this.value_elt)
+</xsl:text>
+    <xsl:text>            this.value_elt.textContent = String(value);
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        this.update_DOM(value, this.handle_elt);
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    last_drag = false;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    update_DOM(value, elt){
+</xsl:text>
+    <xsl:text>        let [min,max,start,totallength] = this.range;
+</xsl:text>
+    <xsl:text>        let length = Math.max(0,Math.min(totallength,(Number(value)-min)*totallength/(max-min)));
+</xsl:text>
+    <xsl:text>        let tip = this.range_elt.getPointAtLength(length);
+</xsl:text>
+    <xsl:text>        elt.setAttribute('transform',"translate("+(tip.x-start.x)+","+(tip.y-start.y)+")");
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        if(this.setpoint_elt != undefined){
+</xsl:text>
+    <xsl:text>            if(this.last_drag!= this.drag){
+</xsl:text>
+    <xsl:text>                if(this.drag){
+</xsl:text>
+    <xsl:text>                    this.setpoint_elt.setAttribute("style", this.setpoint_style);
+</xsl:text>
+    <xsl:text>                }else{
+</xsl:text>
+    <xsl:text>                    this.setpoint_elt.setAttribute("style", "display:none");
+</xsl:text>
+    <xsl:text>                }
+</xsl:text>
+    <xsl:text>                this.last_drag = this.drag;
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    on_release(evt) {
+</xsl:text>
+    <xsl:text>        window.removeEventListener("touchmove", this.on_bound_drag, true);
+</xsl:text>
+    <xsl:text>        window.removeEventListener("mousemove", this.on_bound_drag, true);
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        window.removeEventListener("mouseup", this.bound_on_release, true)
+</xsl:text>
+    <xsl:text>        window.removeEventListener("touchend", this.bound_on_release, true);
+</xsl:text>
+    <xsl:text>        window.removeEventListener("touchcancel", this.bound_on_release, true);
+</xsl:text>
+    <xsl:text>        if(this.drag){
+</xsl:text>
+    <xsl:text>            this.drag = false;
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>        this.update_position(evt);
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    on_drag(evt){
+</xsl:text>
+    <xsl:text>        if(this.enTimer &amp;&amp; this.drag){
+</xsl:text>
+    <xsl:text>            this.update_position(evt);
+</xsl:text>
+    <xsl:text>            //reset timer
+</xsl:text>
+    <xsl:text>            this.enTimer = false;
+</xsl:text>
+    <xsl:text>            setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100);
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    update_position(evt){
+</xsl:text>
+    <xsl:text>        var html_dist = 0;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        //calculate size of widget in html
+</xsl:text>
+    <xsl:text>        var range_borders = this.range_elt.getBoundingClientRect();
+</xsl:text>
+    <xsl:text>        var range_length = Math.sqrt( range_borders.height*range_borders.height + range_borders.width*range_borders.width );
+</xsl:text>
+    <xsl:text>        var [minX,minY,maxX,maxY] = [range_borders.left,range_borders.bottom,range_borders.right,range_borders.top];
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        //get range and mouse coordinates
+</xsl:text>
+    <xsl:text>        var mouseX = undefined;
+</xsl:text>
+    <xsl:text>        var mouseY = undefined;
+</xsl:text>
+    <xsl:text>        if (evt.type.startsWith("touch")){
+</xsl:text>
+    <xsl:text>            mouseX = Math.ceil(evt.touches[0].clientX);
+</xsl:text>
+    <xsl:text>            mouseY = Math.ceil(evt.touches[0].clientY);
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>        else{
+</xsl:text>
+    <xsl:text>            mouseX = evt.pageX;
+</xsl:text>
+    <xsl:text>            mouseY = evt.pageY;
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        //get handle distance from mouse position
+</xsl:text>
+    <xsl:text>        if (minX &gt; mouseX &amp;&amp; minY &lt; mouseY){
+</xsl:text>
+    <xsl:text>            html_dist = 0;
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>        else if (maxX &lt; mouseX &amp;&amp; maxY &gt; mouseY){
+</xsl:text>
+    <xsl:text>            html_dist = range_length;
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>        else{
+</xsl:text>
+    <xsl:text>            // calculate distace
+</xsl:text>
+    <xsl:text>            if(this.fi &gt; 0.7){
+</xsl:text>
+    <xsl:text>                html_dist = (minY - mouseY)/Math.sin(this.fi);
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>            else{
+</xsl:text>
+    <xsl:text>                html_dist = (mouseX - minX)/Math.cos(this.fi);
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>            //check if in range
+</xsl:text>
+    <xsl:text>            if (html_dist &gt; range_length){
+</xsl:text>
+    <xsl:text>                html_dist = range_length;
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>            else if (html_dist &lt; 0){
+</xsl:text>
+    <xsl:text>                html_dist = 0;
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        this.svg_dist=Math.ceil((html_dist/range_length)*this.range[1]);
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        this.apply_hmi_value(0, this.svg_dist);
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        // update ghost cursor
+</xsl:text>
+    <xsl:text>        if(this.setpoint_elt != undefined){
+</xsl:text>
+    <xsl:text>            this.request_animate();
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    animate(){
+</xsl:text>
+    <xsl:text>        this.update_DOM(this.svg_dist, this.setpoint_elt);
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    on_select(evt){
+</xsl:text>
+    <xsl:text>        this.drag = true;
+</xsl:text>
+    <xsl:text>        this.enTimer = true;
+</xsl:text>
+    <xsl:text>        window.addEventListener("touchmove", this.on_bound_drag, true);
+</xsl:text>
+    <xsl:text>        window.addEventListener("mousemove", this.on_bound_drag, true);
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        window.addEventListener("mouseup", this.bound_on_release, true)
+</xsl:text>
+    <xsl:text>        window.addEventListener("touchend", this.bound_on_release, true);
+</xsl:text>
+    <xsl:text>        window.addEventListener("touchcancel", this.bound_on_release, true);
+</xsl:text>
+    <xsl:text>        this.update_position(evt);
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    init() {
+</xsl:text>
+    <xsl:text>        let min = this.min_elt ?
+</xsl:text>
+    <xsl:text>                    Number(this.min_elt.textContent) :
+</xsl:text>
+    <xsl:text>                    this.args.length &gt;= 1 ? this.args[0] : 0;
+</xsl:text>
+    <xsl:text>        let max = this.max_elt ?
+</xsl:text>
+    <xsl:text>                    Number(this.max_elt.textContent) :
+</xsl:text>
+    <xsl:text>                    this.args.length &gt;= 2 ? this.args[1] : 100;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        this.range = [min, max, this.range_elt.getPointAtLength(0),this.range_elt.getTotalLength()];
+</xsl:text>
+    <xsl:text>        let start = this.range_elt.getPointAtLength(0);
+</xsl:text>
+    <xsl:text>        let end = this.range_elt.getPointAtLength(this.range_elt.getTotalLength());
+</xsl:text>
+    <xsl:text>        this.fi = Math.atan2(start.y-end.y, end.x-start.x);
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        this.bound_on_select = this.on_select.bind(this);
+</xsl:text>
+    <xsl:text>        this.bound_on_release = this.on_release.bind(this);
+</xsl:text>
+    <xsl:text>        this.on_bound_drag = this.on_drag.bind(this);
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        this.element.addEventListener("mousedown", this.bound_on_select);
+</xsl:text>
+    <xsl:text>        this.element.addEventListener("touchstart", this.bound_on_select);
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>        if(this.setpoint_elt != undefined){
+</xsl:text>
+    <xsl:text>            this.setpoint_style = this.setpoint_elt.getAttribute("style");
+</xsl:text>
+    <xsl:text>            this.setpoint_elt.setAttribute("style", "display:none");
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>}
+</xsl:text>
+  </xsl:template>
+  <xsl:template mode="widget_defs" match="widget[@type='Slider']">
+    <xsl:param name="hmi_element"/>
+    <xsl:call-template name="defs_by_labels">
+      <xsl:with-param name="hmi_element" select="$hmi_element"/>
+      <xsl:with-param name="labels">
+        <xsl:text>handle range</xsl:text>
+      </xsl:with-param>
+    </xsl:call-template>
+    <xsl:call-template name="defs_by_labels">
+      <xsl:with-param name="hmi_element" select="$hmi_element"/>
+      <xsl:with-param name="labels">
+        <xsl:text>value min max setpoint</xsl:text>
+      </xsl:with-param>
+      <xsl:with-param name="mandatory" select="'no'"/>
+    </xsl:call-template>
+    <xsl:text>
+</xsl:text>
+  </xsl:template>
+  <xsl:template mode="widget_class" match="widget[@type='Switch']">
+    <xsl:text>class SwitchWidget extends Widget{
+</xsl:text>
+    <xsl:text>    frequency = 5;
+</xsl:text>
+    <xsl:text>    dispatch(value) {
+</xsl:text>
+    <xsl:text>        for(let choice of this.choices){
+</xsl:text>
+    <xsl:text>            if(value != choice.value){
+</xsl:text>
+    <xsl:text>                choice.elt.setAttribute("style", "display:none");
+</xsl:text>
+    <xsl:text>            } else {
+</xsl:text>
+    <xsl:text>                choice.elt.setAttribute("style", choice.style);
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>}
+</xsl:text>
+  </xsl:template>
+  <xsl:template mode="widget_defs" match="widget[@type='Switch']">
+    <xsl:param name="hmi_element"/>
+    <xsl:text>    choices: [
+</xsl:text>
+    <xsl:variable name="regex" select="'^(&quot;[^&quot;].*&quot;|\-?[0-9]+|false|true)(#.*)?$'"/>
+    <xsl:for-each select="$result_svg_ns//*[@id = $hmi_element/@id]//*[regexp:test(@inkscape:label,$regex)]">
+      <xsl:variable name="literal" select="regexp:match(@inkscape:label,$regex)[2]"/>
+      <xsl:text>        {
+</xsl:text>
+      <xsl:text>            elt:id("</xsl:text>
+      <xsl:value-of select="@id"/>
+      <xsl:text>"),
+</xsl:text>
+      <xsl:text>            style:"</xsl:text>
+      <xsl:value-of select="@style"/>
+      <xsl:text>",
+</xsl:text>
+      <xsl:text>            value:</xsl:text>
+      <xsl:value-of select="$literal"/>
+      <xsl:text>
+</xsl:text>
+      <xsl:text>        }</xsl:text>
+      <xsl:if test="position()!=last()">
+        <xsl:text>,</xsl:text>
+      </xsl:if>
+      <xsl:text>
+</xsl:text>
+    </xsl:for-each>
+    <xsl:text>    ],
+</xsl:text>
+  </xsl:template>
+  <xsl:template mode="widget_class" match="widget[@type='ToggleButton']">
+    <xsl:text>class ToggleButtonWidget extends Widget{
+</xsl:text>
+    <xsl:text>    frequency = 5;
+</xsl:text>
+    <xsl:text>    state = 0;
+</xsl:text>
+    <xsl:text>    active_style = undefined;
+</xsl:text>
+    <xsl:text>    inactive_style = undefined;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    dispatch(value) {
+</xsl:text>
+    <xsl:text>        this.state = value;
+</xsl:text>
+    <xsl:text>        if (this.state) {
+</xsl:text>
+    <xsl:text>            this.active_elt.setAttribute("style", this.active_style);
+</xsl:text>
+    <xsl:text>            this.inactive_elt.setAttribute("style", "display:none");
+</xsl:text>
+    <xsl:text>            this.state = 0;
+</xsl:text>
+    <xsl:text>        } else {
+</xsl:text>
+    <xsl:text>            this.inactive_elt.setAttribute("style", this.inactive_style);
+</xsl:text>
+    <xsl:text>            this.active_elt.setAttribute("style", "display:none");
+</xsl:text>
+    <xsl:text>            this.state = 1;
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    on_click(evt) {
+</xsl:text>
+    <xsl:text>        this.apply_hmi_value(0, this.state);
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    init() {
+</xsl:text>
+    <xsl:text>        this.active_style = this.active_elt.style.cssText;
+</xsl:text>
+    <xsl:text>        this.inactive_style = this.inactive_elt.style.cssText;
+</xsl:text>
+    <xsl:text>        this.element.setAttribute("onclick", "hmi_widgets['"+this.element_id+"'].on_click(evt)");
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>}
+</xsl:text>
+  </xsl:template>
   <xsl:template mode="widget_defs" match="widget[@type='ToggleButton']">
     <xsl:param name="hmi_element"/>
     <xsl:call-template name="defs_by_labels">
@@ -3657,55 +4715,7 @@
         <xsl:text>active inactive</xsl:text>
       </xsl:with-param>
     </xsl:call-template>
-    <xsl:text>    frequency: 5,
-</xsl:text>
-    <xsl:text>    state: 0,
-</xsl:text>
-    <xsl:text>    dispatch: function(value) {
-</xsl:text>
-    <xsl:text>        this.state = value;
-</xsl:text>
-    <xsl:text>        if (this.state) {
-</xsl:text>
-    <xsl:text>            this.active_elt.setAttribute("style", this.active_style);
-</xsl:text>
-    <xsl:text>            this.inactive_elt.setAttribute("style", "display:none");
-</xsl:text>
-    <xsl:text>            this.state = 0;
-</xsl:text>
-    <xsl:text>        } else {
-</xsl:text>
-    <xsl:text>            this.inactive_elt.setAttribute("style", this.inactive_style);
-</xsl:text>
-    <xsl:text>            this.active_elt.setAttribute("style", "display:none");
-</xsl:text>
-    <xsl:text>            this.state = 1;
-</xsl:text>
-    <xsl:text>        }
-</xsl:text>
-    <xsl:text>    },
-</xsl:text>
-    <xsl:text>    on_click: function(evt) {
-</xsl:text>
-    <xsl:text>        this.apply_hmi_value(0, this.state);
-</xsl:text>
-    <xsl:text>    },
-</xsl:text>
-    <xsl:text>    active_style: undefined,
-</xsl:text>
-    <xsl:text>    inactive_style: undefined,
-</xsl:text>
-    <xsl:text>    init: function() {
-</xsl:text>
-    <xsl:text>        this.active_style = this.active_elt.style.cssText;
-</xsl:text>
-    <xsl:text>        this.inactive_style = this.inactive_elt.style.cssText;
-</xsl:text>
-    <xsl:text>        this.element.setAttribute("onclick", "hmi_widgets['</xsl:text>
-    <xsl:value-of select="$hmi_element/@id"/>
-    <xsl:text>'].on_click(evt)");
-</xsl:text>
-    <xsl:text>    },
+    <xsl:text>
 </xsl:text>
   </xsl:template>
   <xsl:template match="/">
@@ -3866,8 +4876,6 @@
 </xsl:text>
           <xsl:text>        // -&gt; pass Number(index) instead
 </xsl:text>
-          <xsl:text>        console.log("apply updated local variable ",index, updates[index]);
-</xsl:text>
           <xsl:text>        dispatch_value(Number(index), updates[index]);
 </xsl:text>
           <xsl:text>        delete updates[index];
@@ -3908,6 +4916,14 @@
 </xsl:text>
           <xsl:text>    apply_updates();
 </xsl:text>
+          <xsl:text>
+</xsl:text>
+          <xsl:text>    pending_widget_animates.forEach(widget =&gt; widget._animate());
+</xsl:text>
+          <xsl:text>    pending_widget_animates = [];
+</xsl:text>
+          <xsl:text>
+</xsl:text>
           <xsl:text>    requestAnimationFrameID = null;
 </xsl:text>
           <xsl:text>}
@@ -4576,7 +5592,7 @@
 </xsl:text>
           <xsl:text>var edit_callback;
 </xsl:text>
-          <xsl:text>function edit_value(path, valuetype, callback, initial) {
+          <xsl:text>function edit_value(path, valuetype, callback, initial, size) {
 </xsl:text>
           <xsl:text>
 </xsl:text>
@@ -4588,7 +5604,7 @@
 </xsl:text>
           <xsl:text>    let widget = hmi_widgets[keypadid];
 </xsl:text>
-          <xsl:text>    widget.start_edit(path, valuetype, callback, initial);
+          <xsl:text>    widget.start_edit(path, valuetype, callback, initial, size);
 </xsl:text>
           <xsl:text>};
 </xsl:text>
@@ -4598,7 +5614,7 @@
 </xsl:text>
           <xsl:text>
 </xsl:text>
-          <xsl:text>function show_modal() {
+          <xsl:text>function show_modal(size) {
 </xsl:text>
           <xsl:text>    let [element, parent] = detachable_elements[this.element.id];
 </xsl:text>
@@ -4608,13 +5624,23 @@
 </xsl:text>
           <xsl:text>    tmpgrpattr = document.createAttribute("transform");
 </xsl:text>
-          <xsl:text>
-</xsl:text>
           <xsl:text>    let [xcoord,ycoord] = this.coordinates;
 </xsl:text>
           <xsl:text>    let [xdest,ydest] = page_desc[current_visible_page].bbox;
 </xsl:text>
-          <xsl:text>    tmpgrpattr.value = "translate("+String(xdest-xcoord)+","+String(ydest-ycoord)+")";
+          <xsl:text>    if (typeof size === 'undefined'){
+</xsl:text>
+          <xsl:text>        tmpgrpattr.value = "translate("+String(xdest-xcoord)+","+String(ydest-ycoord)+")";
+</xsl:text>
+          <xsl:text>    }
+</xsl:text>
+          <xsl:text>    else{
+</xsl:text>
+          <xsl:text>        tmpgrpattr.value = "translate("+String(xdest-xcoord+size.x)+","+String(ydest-ycoord+size.y)+")";
+</xsl:text>
+          <xsl:text>    }
+</xsl:text>
+          <xsl:text>
 </xsl:text>
           <xsl:text>    tmpgrp.setAttributeNode(tmpgrpattr);
 </xsl:text>
--- a/svghmi/svghmi.js	Wed Aug 12 13:36:18 2020 +0200
+++ b/svghmi/svghmi.js	Wed Aug 12 15:24:02 2020 +0200
@@ -75,6 +75,10 @@
     if(jumps_need_update) update_jumps();
 
     apply_updates();
+
+    pending_widget_animates.forEach(widget => widget._animate());
+    pending_widget_animates = [];
+
     requestAnimationFrameID = null;
 }
 
@@ -409,26 +413,31 @@
 
 var xmlns = "http://www.w3.org/2000/svg";
 var edit_callback;
-function edit_value(path, valuetype, callback, initial) {
+function edit_value(path, valuetype, callback, initial, size) {
 
     let [keypadid, xcoord, ycoord] = keypads[valuetype];
     console.log('XXX TODO : Edit value', path, valuetype, callback, initial, keypadid);
     edit_callback = callback;
     let widget = hmi_widgets[keypadid];
-    widget.start_edit(path, valuetype, callback, initial);
+    widget.start_edit(path, valuetype, callback, initial, size);
 };
 
 var current_modal; /* TODO stack ?*/
 
-function show_modal() {
+function show_modal(size) {
     let [element, parent] = detachable_elements[this.element.id];
 
     tmpgrp = document.createElementNS(xmlns,"g");
     tmpgrpattr = document.createAttribute("transform");
-
     let [xcoord,ycoord] = this.coordinates;
     let [xdest,ydest] = page_desc[current_visible_page].bbox;
-    tmpgrpattr.value = "translate("+String(xdest-xcoord)+","+String(ydest-ycoord)+")";
+    if (typeof size === 'undefined'){
+        tmpgrpattr.value = "translate("+String(xdest-xcoord)+","+String(ydest-ycoord)+")";
+    }
+    else{
+        tmpgrpattr.value = "translate("+String(xdest-xcoord+size.x)+","+String(ydest-ycoord+size.y)+")";
+    }
+
     tmpgrp.setAttributeNode(tmpgrpattr);
 
     tmpgrp.appendChild(element);
--- a/svghmi/widget_button.ysl2	Wed Aug 12 13:36:18 2020 +0200
+++ b/svghmi/widget_button.ysl2	Wed Aug 12 15:24:02 2020 +0200
@@ -1,33 +1,48 @@
 // widget_button.ysl2
 
+template "widget[@type='Button']", mode="widget_class"{
+    ||
+    class ButtonWidget extends Widget{
+        frequency = 5;
+        state = 0;
+        active_style = undefined;
+        inactive_style = undefined;
+
+         on_mouse_down(evt) {
+             if (this.active_style && this.inactive_style) {
+                 this.active_elt.setAttribute("style", this.active_style);
+                 this.inactive_elt.setAttribute("style", "display:none");
+             }
+             this.apply_hmi_value(0, 1);
+         }
+
+         on_mouse_up(evt) {
+             if (this.active_style && this.inactive_style) {
+                 this.active_elt.setAttribute("style", "display:none");
+                 this.inactive_elt.setAttribute("style", this.inactive_style);
+             }
+             this.apply_hmi_value(0, 0);
+         }
+
+         init() {
+            this.active_style = this.active_elt ? this.active_elt.style.cssText : undefined;
+            this.inactive_style = this.inactive_elt ? this.inactive_elt.style.cssText : undefined;
+
+            if (this.active_style && this.inactive_style) {
+                this.active_elt.setAttribute("style", "display:none");
+                this.inactive_elt.setAttribute("style", this.inactive_style);
+            }
+
+            this.element.setAttribute("onmousedown", "hmi_widgets["+this.element_id+"].on_mouse_down(evt)");
+            this.element.setAttribute("onmouseup", "hmi_widgets["+this.element_id+"].on_mouse_up(evt)");
+         }
+    }
+    ||
+}
+
+
 template "widget[@type='Button']", mode="widget_defs" {
     param "hmi_element";
     optional_labels("active inactive");
-    | frequency: 5,
-    | on_mouse_down: function(evt) {
-    |     if (this.active_style && this.inactive_style) {
-    |         this.active_elt.setAttribute("style", this.active_style);
-    |         this.inactive_elt.setAttribute("style", "display:none");
-    |     }
-    |     this.apply_hmi_value(0, 1);
-    | },
-    | on_mouse_up: function(evt) {
-    |     if (this.active_style && this.inactive_style) {
-    |         this.active_elt.setAttribute("style", "display:none");
-    |         this.inactive_elt.setAttribute("style", this.inactive_style);
-    |     }
-    |     this.apply_hmi_value(0, 0);
-    | },
-    | active_style: undefined,
-    | inactive_style: undefined,
-    | init: function() {
-    |   this.active_style = this.active_elt ? this.active_elt.style.cssText : undefined;
-    |   this.inactive_style = this.inactive_elt ? this.inactive_elt.style.cssText : undefined;
-    |   if (this.active_style && this.inactive_style) {
-    |       this.active_elt.setAttribute("style", "display:none");
-    |       this.inactive_elt.setAttribute("style", this.inactive_style);
-    |   }
-    |   this.element.setAttribute("onmousedown", "hmi_widgets['«$hmi_element/@id»'].on_mouse_down(evt)");
-    |   this.element.setAttribute("onmouseup", "hmi_widgets['«$hmi_element/@id»'].on_mouse_up(evt)");
-    | },
+    |,
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/svghmi/widget_circularslider.ysl2	Wed Aug 12 15:24:02 2020 +0200
@@ -0,0 +1,159 @@
+// widget_circuralslider.ysl2
+
+template "widget[@type='CircularSlider']", mode="widget_class"
+    ||
+    class CircularSliderWidget extends Widget{
+        frequency = 5;
+        range = undefined;
+        circle = undefined;
+        handle_pos = undefined;
+        drag = false;
+        enTimer = false;
+
+        dispatch(value) {
+            if(!this.drag){
+                if(this.value_elt)
+                    this.value_elt.textContent = String(value);
+
+                this.handle_position(value);
+            }
+        }
+
+        handle_position(value){
+            let [min,max,totalDistance] = this.range;
+            let length = Math.max(0,Math.min((totalDistance),(Number(value)-min)/(max-min)*(totalDistance)));
+            let tip = this.range_elt.getPointAtLength(length);
+            this.handle_elt.setAttribute('transform',"translate("+(tip.x-this.handle_pos.x)+","+(tip.y-this.handle_pos.y)+")");
+        }
+
+        on_release(evt) {
+            if(this.drag){
+                this.drag = false;
+            }
+        }
+
+        update_position(evt){
+            if(this.drag && this.enTimer){
+                var svg_dist = 0;
+
+                //calculate center of widget in html
+                // --TODO maybe it would be better to bind this part to window change size event ???
+                let [xdest,ydest,svgWidth,svgHeight] = page_desc[current_visible_page].bbox;
+                let [cX, cY,fiStart,fiEnd,minMax,x1,y1,width,height] = this.circle;
+                let htmlCirc = this.range_elt.getBoundingClientRect();
+                let cxHtml = ((htmlCirc.right-htmlCirc.left)/(width)*(cX-x1))+htmlCirc.left;
+                let cyHtml = ((htmlCirc.bottom-htmlCirc.top)/(height)*(cY-y1))+htmlCirc.top;
+
+
+                //get mouse coordinates
+                let mouseX = undefined;
+                let mouseY = undefined;
+                if (evt.type.startsWith("touch")){
+                    mouseX = Math.ceil(evt.touches[0].clientX);
+                    mouseY = Math.ceil(evt.touches[0].clientY);
+                }
+                else{
+                    mouseX = evt.pageX;
+                    mouseY = evt.pageY;
+                }
+
+                //calculate angle
+                let fi = Math.atan2(cyHtml-mouseY, mouseX-cxHtml);
+
+                // transform from 0 to 2PI
+                if (fi > 0){
+                    fi = 2*Math.PI-fi;
+                }
+                else{
+                    fi = -fi;
+                }
+
+                //offset it to 0
+                fi = fi - fiStart;
+                if (fi < 0){
+                    fi = fi + 2*Math.PI;
+                }
+
+                //get handle distance from mouse position
+                if(fi<fiEnd){
+                    svg_dist=(fi)/(fiEnd)*(this.range[1]-this.range[0]);
+                }
+                else if(fiEnd<fi && fi<fiEnd+minMax){
+                    svg_dist = this.range[1];
+                }
+                else{
+                    svg_dist = this.range[0];
+                }
+
+                //redraw handle --TODO is it fast enough if I just call change_hmi_value???
+                this.handle_position(svg_dist);
+                if(this.value_elt)
+                    this.value_elt.textContent = String(Math.ceil(svg_dist));
+                this.apply_hmi_value(0, Math.ceil(svg_dist));
+
+                //reset timer
+                this.enTimer = false;
+                setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100);
+            }
+
+        }
+
+        on_select(evt){
+            this.drag = true;
+            this.enTimer = true;
+            this.update_position(evt);
+        }
+
+        init() {
+            //get min max
+            let min = this.min_elt ?
+                        Number(this.min_elt.textContent) :
+                        this.args.length >= 1 ? this.args[0] : 0;
+            let max = this.max_elt ?
+                        Number(this.max_elt.textContent) :
+                        this.args.length >= 2 ? this.args[1] : 100;
+
+            //fiStart ==> offset
+            let fiStart = Number(this.range_elt.getAttribute('sodipodi:start'));
+            let fiEnd = Number(this.range_elt.getAttribute('sodipodi:end'));
+            fiEnd = fiEnd - fiStart;
+
+            //fiEnd ==> size of angle
+            if (fiEnd < 0){
+                fiEnd = 2*Math.PI + fiEnd;
+            }
+
+            //min max barrier angle
+            let minMax = (2*Math.PI - fiEnd)/2;
+
+            //get parameters from svg
+            let cX = Number(this.range_elt.getAttribute('sodipodi:cx'));
+            let cY = Number(this.range_elt.getAttribute('sodipodi:cy'));
+            this.range_elt.style.strokeMiterlimit="0"; //eliminates some weird border around html object
+            this.range = [min, max,this.range_elt.getTotalLength()];
+            let cPos = this.range_elt.getBBox();
+            this.handle_pos = this.range_elt.getPointAtLength(0);
+            this.circle = [cX, cY,fiStart,fiEnd,minMax,cPos.x,cPos.y,cPos.width,cPos.height];
+
+            //init events
+            this.handle_elt.addEventListener("touchstart", hmi_widgets[this.element_id].on_select.bind(this));
+            this.handle_elt.addEventListener("mousedown", hmi_widgets[this.element_id].on_select.bind(this));
+            this.element.addEventListener("mousedown", hmi_widgets[this.element_id].on_select.bind(this));
+
+            window.addEventListener("touchmove", hmi_widgets[this.element_id].update_position.bind(this));
+            window.addEventListener("mousemove", hmi_widgets[this.element_id].update_position.bind(this));
+
+            window.addEventListener("mouseup", hmi_widgets[this.element_id].on_release.bind(this))
+            window.addEventListener("touchend", hmi_widgets[this.element_id].on_release.bind(this));
+            window.addEventListener("touchcancel", hmi_widgets[this.element_id].on_release.bind(this));
+
+        }
+    }
+    ||
+
+template "widget[@type='CircularSlider']", mode="widget_defs" {
+    param "hmi_element";
+    labels("handle range");
+    optional_labels("value min max");
+    |,
+}
--- a/svghmi/widget_input.ysl2	Wed Aug 12 13:36:18 2020 +0200
+++ b/svghmi/widget_input.ysl2	Wed Aug 12 15:24:02 2020 +0200
@@ -2,6 +2,7 @@
 
 template "widget[@type='Input']", mode="widget_defs" {
     param "hmi_element";
+    optional_labels("key_pos");
     const "value_elt" {
         optional_labels("value");
     }
@@ -33,7 +34,8 @@
     //     }
     |     },
     |     on_edit_click: function(opstr) {
-    |         edit_value("«path/@value»", "«path/@type»", this, this.last_val);
+    |         var size = (typeof this.key_pos_elt !== 'undefined') ?  this.key_pos_elt.getBBox() : undefined
+    |         edit_value("«path/@value»", "«path/@type»", this, this.last_val,size);
     |     },
 
     |     edit_callback: function(new_val) {
--- a/svghmi/widget_keypad.ysl2	Wed Aug 12 13:36:18 2020 +0200
+++ b/svghmi/widget_keypad.ysl2	Wed Aug 12 15:24:02 2020 +0200
@@ -13,10 +13,159 @@
     | }
 }
 
+template "widget[@type='Keypad']", mode="widget_class"
+    ||
+    class KeypadWidget extends Widget{
+         moving = undefined;
+         enTimer = undefined;
+         offset = undefined;
+
+         on_position_click(evt) {
+             this.moving = true;
+             this.enTimer = true;
+
+             // get click position offset from widget x,y and save it to variable
+             var keypad_borders = this.position_elt.getBoundingClientRect();
+             var clickX = undefined;
+             var clickY = undefined;
+             if (evt.type == "touchstart"){
+                 clickX = Math.ceil(evt.touches[0].clientX);
+                 clickY = Math.ceil(evt.touches[0].clientY);
+             }
+             else{
+                 clickX = evt.pageX;
+                 clickY = evt.pageY;
+             }
+             this.offset=[clickX-keypad_borders.left,clickY-keypad_borders.top]
+         }
+
+         off_position_click(evt) {
+            if(this.moving)
+                this.moving = false;
+         }
+
+         on_move(evt) {
+             if(this.moving && this.enTimer){
+                 //get keyboard pos in html
+                 let [eltid, tmpgrp] = current_modal;
+                 let [xcoord,ycoord] = this.coordinates;
+                 let [xdest,ydest,svgWidth,svgHeight] = page_desc[current_visible_page].bbox;
+
+                 //get mouse coordinates
+                 var clickX = undefined;
+                 var clickY = undefined;
+                 if (evt.type == "touchmove"){
+                     clickX = Math.ceil(evt.touches[0].clientX);
+                     clickY = Math.ceil(evt.touches[0].clientY);
+                 }
+                 else{
+                     clickX = evt.pageX;
+                     clickY = evt.pageY;
+                 }
+
+                 //translate keyboard position
+                 let mouseX = ((clickX-this.offset[0])/window.innerWidth)*svgWidth;
+                 let mouseY = ((clickY-this.offset[1])/window.innerHeight)*svgHeight;
+                 tmpgrp.setAttribute("transform","translate("+String(xdest-xcoord+mouseX)+","+String(ydest-ycoord+mouseY)+")");
+
+                 //reset timer
+                 this.enTimer = false;
+                 setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100);
+             }
+
+         }
+
+         on_key_click(symbols) {
+             var syms = symbols.split(" ");
+             this.shift |= this.caps;
+             this.editstr += syms[this.shift?syms.length-1:0];
+             this.shift = false;
+             this.update();
+         }
+
+         on_Esc_click() {
+             end_modal.call(this);
+         }
+
+         on_Enter_click() {
+             end_modal.call(this);
+             let callback_obj = this.result_callback_obj;
+             callback_obj.edit_callback(this.editstr);
+         }
+
+         on_BackSpace_click() {
+             this.editstr = this.editstr.slice(0,this.editstr.length-1);
+             this.update();
+         }
+
+         on_Sign_click() {
+             if(this.editstr[0] == "-")
+                 this.editstr = this.editstr.slice(1,this.editstr.length);
+             else
+                 this.editstr = "-" + this.editstr;
+             this.update();
+         }
+
+         on_NumDot_click() {
+             if(this.editstr.indexOf(".") == "-1"){
+                 this.editstr += ".";
+                 this.update();
+             }
+         }
+
+         on_Space_click() {
+             this.editstr += " ";
+             this.update();
+         }
+
+         caps = false;
+         _caps = undefined;
+         on_CapsLock_click() {
+             this.caps = !this.caps;
+             this.update();
+         }
+
+         shift = false;
+         _shift = undefined;
+         on_Shift_click() {
+             this.shift = !this.shift;
+             this.caps = false;
+             this.update();
+         }
+         editstr = "";
+         _editstr = undefined;
+         result_callback_obj = undefined;
+         start_edit(info, valuetype, callback_obj, initial,size) {
+             show_modal.call(this,size);
+             this.editstr = initial;
+             this.result_callback_obj = callback_obj;
+             this.Info_elt.textContent = info;
+             this.shift = false;
+             this.caps = false;
+             this.update();
+         }
+
+         update() {
+             if(this.editstr != this._editstr){
+                 this._editstr = this.editstr;
+                 this.Value_elt.textContent = this.editstr;
+             }
+             if(this.shift != this._shift){
+                 this._shift = this.shift;
+                 (this.shift?widget_active_activable:widget_inactive_activable)(this.Shift_sub);
+             }
+             if(this.caps != this._caps){
+                 this._caps = this.caps;
+                 (this.caps?widget_active_activable:widget_inactive_activable)(this.CapsLock_sub);
+             }
+         }
+    }
+    ||
+
 template "widget[@type='Keypad']", mode="widget_defs" {
     param "hmi_element";
     labels("Esc Enter BackSpace Keys Info Value");
-    optional_labels("Sign Space NumDot");
+    optional_labels("Sign Space NumDot position");
     activable_labels("CapsLock Shift");
     |     init: function() {
     foreach "$hmi_element/*[@inkscape:label = 'Keys']/*" {
@@ -26,82 +175,19 @@
     |         if(this.«.»_elt)
     |             this.«.»_elt.setAttribute("onclick", "hmi_widgets['«$hmi_element/@id»'].on_«.»_click()");
     }
+    |         if(this.position_elt){
+    |            this.position_elt.setAttribute("onmousedown", "hmi_widgets['"+this.element_id+"'].on_position_click(evt)");
+    |            this.position_elt.setAttribute("ontouchstart", "hmi_widgets['"+this.element_id+"'].on_position_click(evt)");
+
+    |            window.addEventListener("mouseup", hmi_widgets[this.element_id].off_position_click.bind(this));
+    |            window.addEventListener("touchend", hmi_widgets[this.element_id].off_position_click.bind(this));
+    |            window.addEventListener("touchcancel", hmi_widgets[this.element_id].off_position_click.bind(this));
+
+    |            window.addEventListener("mousemove", hmi_widgets[this.element_id].on_move.bind(this));
+    |            window.addEventListener("touchmove", hmi_widgets[this.element_id].on_move.bind(this));
+    |        }
     |     },
-    |     on_key_click: function(symbols) {
-    |         var syms = symbols.split(" ");
-    |         this.shift |= this.caps;
-    |         this.editstr += syms[this.shift?syms.length-1:0];
-    |         this.shift = false;
-    |         this.update();
-    |     },
-    |     on_Esc_click: function() {
-    |         end_modal.call(this);
-    |     },
-    |     on_Enter_click: function() {
-    |         end_modal.call(this);
-    |         callback_obj = this.result_callback_obj;
-    |         callback_obj.edit_callback(this.editstr);
-    |     },
-    |     on_BackSpace_click: function() {
-    |         this.editstr = this.editstr.slice(0,this.editstr.length-1);
-    |         this.update();
-    |     },
-    |     on_Sign_click: function() {
-    |         if(this.editstr[0] == "-")
-    |             this.editstr = this.editstr.slice(1,this.editstr.length);
-    |         else
-    |             this.editstr = "-" + this.editstr;
-    |         this.update();
-    |     },
-    |     on_NumDot_click: function() {
-    |         if(this.editstr.indexOf(".") == "-1"){
-    |             this.editstr += ".";
-    |             this.update();
-    |         }
-    |     },
-    |     on_Space_click: function() {
-    |         this.editstr += " ";
-    |         this.update();
-    |     },
-    |     caps: false,
-    |     _caps: undefined,
-    |     on_CapsLock_click: function() {
-    |         this.caps = !this.caps;
-    |         this.update();
-    |     },
-    |     shift: false,
-    |     _shift: undefined,
-    |     on_Shift_click: function() {
-    |         this.shift = !this.shift;
-    |         this.caps = false;
-    |         this.update();
-    |     },
+    |
     const "g", "$geometry[@Id = $hmi_element/@id]"; 
     |     coordinates: [«$g/@x», «$g/@y»],
-    |     editstr: "",
-    |     _editstr: undefined,
-    |     result_callback_obj: undefined,
-    |     start_edit: function(info, valuetype, callback_obj, initial) {
-    |         show_modal.call(this);
-    |         this.editstr = initial;
-    |         this.result_callback_obj = callback_obj;
-    |         this.Info_elt.textContent = info;
-    |         this.shift = false;
-    |         this.caps = false;
-    |         this.update();
-    |     },
-    |     update: function() {
-    |         if(this.editstr != this._editstr){
-    |             this._editstr = this.editstr;
-    |             this.Value_elt.textContent = this.editstr;
-    |         }
-    |         if(this.shift != this._shift){
-    |             this._shift = this.shift;
-    |             (this.shift?widget_active_activable:widget_inactive_activable)(this.Shift_sub);
-    |         }
-    |         if(this.caps != this._caps){
-    |             this._caps = this.caps;
-    |             (this.caps?widget_active_activable:widget_inactive_activable)(this.CapsLock_sub);
-    |         }
-    |     },
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/svghmi/widget_multistate.ysl2	Wed Aug 12 15:24:02 2020 +0200
@@ -0,0 +1,60 @@
+// widget_multistate.ysl2
+
+template "widget[@type='MultiState']", mode="widget_class"
+    ||
+    class MultiStateWidget extends Widget{
+        frequency = 5;
+        state = 0;
+        dispatch(value) {
+            this.state = value;
+            for(let choice of this.choices){
+                if(this.state != choice.value){
+                    choice.elt.setAttribute("style", "display:none");
+                } else {
+                    choice.elt.setAttribute("style", choice.style);
+                }
+            }
+        }
+
+        on_click(evt) {
+            //get current selected value
+            let next_ind;
+            for(next_ind=0; next_ind<this.choices.length; next_ind++){
+                if(this.state == this.choices[next_ind].value){
+                   next_ind = next_ind + 1;
+                   break;
+                }
+            }
+
+            //get next selected value
+            if(this.choices.length > next_ind){
+                this.state = this.choices[next_ind].value;
+            }
+            else{
+                this.state = this.choices[0].value;
+            }
+
+            //post value to plc
+            this.apply_hmi_value(0, this.state);
+        }
+
+        init() {
+            this.element.setAttribute("onclick", "hmi_widgets['"+this.element_id+"'].on_click(evt)");
+        }
+    }
+    ||
+
+template "widget[@type='MultiState']", mode="widget_defs" {
+    param "hmi_element";
+    |     choices: [
+    const "regex",!"'^(\"[^\"].*\"|\-?[0-9]+|false|true)(#.*)?$'"!;
+    foreach "$result_svg_ns//*[@id = $hmi_element/@id]//*[regexp:test(@inkscape:label,$regex)]" {
+        const "literal", "regexp:match(@inkscape:label,$regex)[2]";
+    |         {
+    |             elt:id("«@id»"),
+    |             style:"«@style»",
+    |             value:«$literal»
+    |         }`if "position()!=last()" > ,`
+    }
+    |     ],
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/svghmi/widget_slider.ysl2	Wed Aug 12 15:24:02 2020 +0200
@@ -0,0 +1,169 @@
+// widget_slider.ysl2
+
+template "widget[@type='Slider']", mode="widget_class"
+    ||
+    class SliderWidget extends Widget{
+        frequency = 5;
+        range = undefined;
+        fi = undefined;
+        drag = false;
+        enTimer = false;
+
+        dispatch(value) {
+            if(this.value_elt)
+                this.value_elt.textContent = String(value);
+
+            this.update_DOM(value, this.handle_elt);
+
+        }
+
+        last_drag = false;
+
+        update_DOM(value, elt){
+            let [min,max,start,totallength] = this.range;
+            let length = Math.max(0,Math.min(totallength,(Number(value)-min)*totallength/(max-min)));
+            let tip = this.range_elt.getPointAtLength(length);
+            elt.setAttribute('transform',"translate("+(tip.x-start.x)+","+(tip.y-start.y)+")");
+
+            if(this.setpoint_elt != undefined){
+                if(this.last_drag!= this.drag){
+                    if(this.drag){
+                        this.setpoint_elt.setAttribute("style", this.setpoint_style);
+                    }else{
+                        this.setpoint_elt.setAttribute("style", "display:none");
+                    }
+                    this.last_drag = this.drag;
+                }
+            }
+        }
+
+        on_release(evt) {
+            window.removeEventListener("touchmove", this.on_bound_drag, true);
+            window.removeEventListener("mousemove", this.on_bound_drag, true);
+
+            window.removeEventListener("mouseup", this.bound_on_release, true)
+            window.removeEventListener("touchend", this.bound_on_release, true);
+            window.removeEventListener("touchcancel", this.bound_on_release, true);
+            if(this.drag){
+                this.drag = false;
+            }
+            this.update_position(evt);
+        }
+
+
+        on_drag(evt){
+            if(this.enTimer && this.drag){
+                this.update_position(evt);
+                //reset timer
+                this.enTimer = false;
+                setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100);
+            }
+        }
+
+        update_position(evt){
+            var html_dist = 0;
+
+            //calculate size of widget in html
+            var range_borders = this.range_elt.getBoundingClientRect();
+            var range_length = Math.sqrt( range_borders.height*range_borders.height + range_borders.width*range_borders.width );
+            var [minX,minY,maxX,maxY] = [range_borders.left,range_borders.bottom,range_borders.right,range_borders.top];
+
+            //get range and mouse coordinates
+            var mouseX = undefined;
+            var mouseY = undefined;
+            if (evt.type.startsWith("touch")){
+                mouseX = Math.ceil(evt.touches[0].clientX);
+                mouseY = Math.ceil(evt.touches[0].clientY);
+            }
+            else{
+                mouseX = evt.pageX;
+                mouseY = evt.pageY;
+            }
+
+            //get handle distance from mouse position
+            if (minX > mouseX && minY < mouseY){
+                html_dist = 0;
+            }
+            else if (maxX < mouseX && maxY > mouseY){
+                html_dist = range_length;
+            }
+            else{
+                // calculate distace
+                if(this.fi > 0.7){
+                    html_dist = (minY - mouseY)/Math.sin(this.fi);
+                }
+                else{
+                    html_dist = (mouseX - minX)/Math.cos(this.fi);
+                }
+
+                //check if in range
+                if (html_dist > range_length){
+                    html_dist = range_length;
+                }
+                else if (html_dist < 0){
+                    html_dist = 0;
+                }
+
+            }
+
+            this.svg_dist=Math.ceil((html_dist/range_length)*this.range[1]);
+
+            this.apply_hmi_value(0, this.svg_dist);
+
+            // update ghost cursor
+            if(this.setpoint_elt != undefined){
+                this.request_animate();
+            }
+        }
+
+        animate(){
+            this.update_DOM(this.svg_dist, this.setpoint_elt);
+        }
+
+        on_select(evt){
+            this.drag = true;
+            this.enTimer = true;
+            window.addEventListener("touchmove", this.on_bound_drag, true);
+            window.addEventListener("mousemove", this.on_bound_drag, true);
+
+            window.addEventListener("mouseup", this.bound_on_release, true)
+            window.addEventListener("touchend", this.bound_on_release, true);
+            window.addEventListener("touchcancel", this.bound_on_release, true);
+            this.update_position(evt);
+        }
+
+        init() {
+            let min = this.min_elt ?
+                        Number(this.min_elt.textContent) :
+                        this.args.length >= 1 ? this.args[0] : 0;
+            let max = this.max_elt ?
+                        Number(this.max_elt.textContent) :
+                        this.args.length >= 2 ? this.args[1] : 100;
+
+            this.range = [min, max, this.range_elt.getPointAtLength(0),this.range_elt.getTotalLength()];
+            let start = this.range_elt.getPointAtLength(0);
+            let end = this.range_elt.getPointAtLength(this.range_elt.getTotalLength());
+            this.fi = Math.atan2(start.y-end.y, end.x-start.x);
+
+            this.bound_on_select = this.on_select.bind(this);
+            this.bound_on_release = this.on_release.bind(this);
+            this.on_bound_drag = this.on_drag.bind(this);
+
+            this.element.addEventListener("mousedown", this.bound_on_select);
+            this.element.addEventListener("touchstart", this.bound_on_select);
+
+            if(this.setpoint_elt != undefined){
+                this.setpoint_style = this.setpoint_elt.getAttribute("style");
+                this.setpoint_elt.setAttribute("style", "display:none");
+            }
+
+        }
+    }
+    ||
+
+template "widget[@type='Slider']", mode="widget_defs" {
+    param "hmi_element";
+    labels("handle range");
+    optional_labels("value min max setpoint");
+    |,
+}
--- a/svghmi/widget_tooglebutton.ysl2	Wed Aug 12 13:36:18 2020 +0200
+++ b/svghmi/widget_tooglebutton.ysl2	Wed Aug 12 15:24:02 2020 +0200
@@ -1,30 +1,42 @@
 // widget_tooglebutton.ysl2
 
+
+template "widget[@type='ToggleButton']", mode="widget_class"{
+    ||
+    class ToggleButtonWidget extends Widget{
+        frequency = 5;
+        state = 0;
+        active_style = undefined;
+        inactive_style = undefined;
+
+        dispatch(value) {
+            this.state = value;
+            if (this.state) {
+                this.active_elt.setAttribute("style", this.active_style);
+                this.inactive_elt.setAttribute("style", "display:none");
+                this.state = 0;
+            } else {
+                this.inactive_elt.setAttribute("style", this.inactive_style);
+                this.active_elt.setAttribute("style", "display:none");
+                this.state = 1;
+            }
+        }
+
+        on_click(evt) {
+            this.apply_hmi_value(0, this.state);
+        }
+
+        init() {
+            this.active_style = this.active_elt.style.cssText;
+            this.inactive_style = this.inactive_elt.style.cssText;
+            this.element.setAttribute("onclick", "hmi_widgets['"+this.element_id+"'].on_click(evt)");
+        }
+    }
+    ||
+}
+
 template "widget[@type='ToggleButton']", mode="widget_defs" {
     param "hmi_element";
     labels("active inactive");
-    |     frequency: 5,
-    |     state: 0,
-    |     dispatch: function(value) {
-    |         this.state = value;
-    |         if (this.state) {
-    |             this.active_elt.setAttribute("style", this.active_style);
-    |             this.inactive_elt.setAttribute("style", "display:none");
-    |             this.state = 0;
-    |         } else {
-    |             this.inactive_elt.setAttribute("style", this.inactive_style);
-    |             this.active_elt.setAttribute("style", "display:none");
-    |             this.state = 1;
-    |         }
-    |     },
-    |     on_click: function(evt) {
-    |         this.apply_hmi_value(0, this.state);
-    |     },
-    |     active_style: undefined,
-    |     inactive_style: undefined,
-    |     init: function() {
-    |         this.active_style = this.active_elt.style.cssText;
-    |         this.inactive_style = this.inactive_elt.style.cssText;
-    |         this.element.setAttribute("onclick", "hmi_widgets['«$hmi_element/@id»'].on_click(evt)");
-    |     },
+    |,
 }
--- a/svghmi/widgets_common.ysl2	Wed Aug 12 13:36:18 2020 +0200
+++ b/svghmi/widgets_common.ysl2	Wed Aug 12 15:24:02 2020 +0200
@@ -24,7 +24,7 @@
 template "svg:*", mode="hmi_widgets" {
     const "widget", "func:widget(@id)";
     const "eltid","@id";
-    const "args" foreach "$widget/arg" > "«@value»"`if "position()!=last()" > ,`
+    const "args" foreach "$widget/arg" > "«func:escape_quotes(@value)»"`if "position()!=last()" > ,`
     const "indexes" foreach "$widget/path" {
         choose {
             when "not(@index)" {
@@ -92,7 +92,6 @@
             new_index = next_available_index++;
             pagevars[varname] = new_index;
         }
-        cache[new_index] = "";
         return new_index;
     }
 
@@ -104,10 +103,14 @@
 
 emit "preamble:widget-base-class" {
     ||
+    var pending_widget_animates = [];
+
     class Widget {
         offset = 0;
         frequency = 10; /* FIXME arbitrary default max freq. Obtain from config ? */
         unsubscribable = false;
+        pending_animate = false;
+
         constructor(elt_id,args,indexes,members){
             this.element_id = elt_id;
             this.element = id(elt_id);
@@ -143,9 +146,9 @@
         }
 
         apply_cache() {
-            if(!this.unsubscribable) for(let i = 0; i < this.indexes.length; i++) {
+            if(!this.unsubscribable) for(let index of this.indexes){
                 /* dispatch current cache in newly opened page widgets */
-                let realindex = this.get_variable_index(i);
+                let realindex = this.get_variable_index(index);
                 let cached_val = cache[realindex];
                 if(cached_val != undefined)
                     this.new_hmi_value(realindex, cached_val, cached_val);
@@ -196,6 +199,20 @@
                 console.log(err);
             }
         }
+        
+        _animate(){
+            this.animate();
+            this.pending_animate = false;
+        }
+
+        request_animate(){
+            if(!this.pending_animate){
+                pending_widget_animates.push(this);
+                this.pending_animate = true;
+                requestHMIAnimation();
+            }
+
+        }
     }
     ||
 }
@@ -212,12 +229,12 @@
 }
 ||
 
-const "excluded_types", "str:split('Page Lang')";
-const "excluded_ids","$parsed_widgets/widget[not(@type = $excluded_types)]/@id";
+const "excluded_types", "str:split('Page Lang VarInit')";
+const "included_ids","$parsed_widgets/widget[not(@type = $excluded_types)]/@id";
 
 emit "declarations:hmi-elements" {
     | var hmi_widgets = {
-    apply  "$hmi_elements[@id = $excluded_ids]", mode="hmi_widgets";
+    apply "$hmi_elements[@id = $included_ids]", mode="hmi_widgets";
     | }
 }
 
@@ -266,11 +283,10 @@
 def "func:escape_quotes" {
     param "txt";
     // have to use a python string to enter escaped quote
-    const "frst", !"substring-before($txt,'\"')"!;
-    const "frstln", "string-length($frst)";
+    // const "frstln", "string-length($frst)";
     choose {
-        when "$frstln > 0 and string-length($txt) > $frstln" {
-            result !"concat($frst,'\\\"',func:escape_quotes(substring-after($txt,'\"')))"!;
+        when !"contains($txt,'\"')"! {
+            result !"concat(substring-before($txt,'\"'),'\\\"',func:escape_quotes(substring-after($txt,'\"')))"!;
         }
         otherwise {
             result "$txt";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/svghmi_v2/beremiz.xml	Wed Aug 12 15:24:02 2020 +0200
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding='utf-8'?>
+<BeremizRoot xmlns:xsd="http://www.w3.org/2001/XMLSchema" URI_location="PYRO://127.0.0.1:61284">
+  <TargetType/>
+  <Libraries Enable_SVGHMI_Library="true"/>
+</BeremizRoot>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/svghmi_v2/plc.xml	Wed Aug 12 15:24:02 2020 +0200
@@ -0,0 +1,578 @@
+<?xml version='1.0' encoding='utf-8'?>
+<project xmlns:ns1="http://www.plcopen.org/xml/tc6_0201" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.plcopen.org/xml/tc6_0201">
+  <fileHeader companyName="Unknown" productName="Unnamed" productVersion="1" creationDateTime="2019-08-06T14:23:42"/>
+  <contentHeader name="Unnamed" modificationDateTime="2020-07-30T12:04:22">
+    <coordinateInfo>
+      <fbd>
+        <scaling x="5" y="5"/>
+      </fbd>
+      <ld>
+        <scaling x="0" y="0"/>
+      </ld>
+      <sfc>
+        <scaling x="0" y="0"/>
+      </sfc>
+    </coordinateInfo>
+  </contentHeader>
+  <types>
+    <dataTypes/>
+    <pous>
+      <pou name="MainStuff" pouType="program">
+        <interface>
+          <localVars>
+            <variable name="TargetPressure">
+              <type>
+                <derived name="HMI_INT"/>
+              </type>
+            </variable>
+            <variable name="selection">
+              <type>
+                <derived name="HMI_INT"/>
+              </type>
+            </variable>
+            <variable name="Pump0">
+              <type>
+                <derived name="PumpControl"/>
+              </type>
+            </variable>
+            <variable name="TestButton">
+              <type>
+                <derived name="HMI_BOOL"/>
+              </type>
+            </variable>
+            <variable name="TestLocal">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="Multistate">
+              <type>
+                <derived name="HMI_INT"/>
+              </type>
+            </variable>
+            <variable name="Radiostate">
+              <type>
+                <derived name="HMI_INT"/>
+              </type>
+            </variable>
+            <variable name="MultistateExt">
+              <type>
+                <INT/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <FBD>
+            <block localId="4" typeName="PumpControl" instanceName="Pump0" executionOrderId="0" height="40" width="127">
+              <position x="595" y="50"/>
+              <inputVariables>
+                <variable formalParameter="TargetPressure">
+                  <connectionPointIn>
+                    <relPosition x="0" y="30"/>
+                    <connection refLocalId="5">
+                      <position x="595" y="80"/>
+                      <position x="570" y="80"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+              </inputVariables>
+              <inOutVariables/>
+              <outputVariables/>
+            </block>
+            <inVariable localId="5" executionOrderId="0" height="30" width="125" negated="false">
+              <position x="445" y="65"/>
+              <connectionPointOut>
+                <relPosition x="125" y="15"/>
+              </connectionPointOut>
+              <expression>TargetPressure</expression>
+            </inVariable>
+            <inVariable localId="6" executionOrderId="0" height="25" width="90" negated="false">
+              <position x="155" y="220"/>
+              <connectionPointOut>
+                <relPosition x="90" y="10"/>
+              </connectionPointOut>
+              <expression>TestButton</expression>
+            </inVariable>
+            <outVariable localId="7" executionOrderId="0" height="25" width="85" negated="false">
+              <position x="495" y="220"/>
+              <connectionPointIn>
+                <relPosition x="0" y="10"/>
+                <connection refLocalId="6">
+                  <position x="495" y="230"/>
+                  <position x="245" y="230"/>
+                </connection>
+              </connectionPointIn>
+              <expression>TestLocal</expression>
+            </outVariable>
+            <inVariable localId="1" executionOrderId="0" height="25" width="115" negated="false">
+              <position x="175" y="355"/>
+              <connectionPointOut>
+                <relPosition x="115" y="10"/>
+              </connectionPointOut>
+              <expression>Multistate</expression>
+            </inVariable>
+            <outVariable localId="8" executionOrderId="0" height="25" width="115" negated="false">
+              <position x="495" y="355"/>
+              <connectionPointIn>
+                <relPosition x="0" y="10"/>
+                <connection refLocalId="1">
+                  <position x="495" y="365"/>
+                  <position x="290" y="365"/>
+                </connection>
+              </connectionPointIn>
+              <expression>MultistateExt</expression>
+            </outVariable>
+          </FBD>
+        </body>
+      </pou>
+      <pou name="PumpControl" pouType="functionBlock">
+        <interface>
+          <localVars>
+            <variable name="Pump">
+              <type>
+                <derived name="HMI_NODE"/>
+              </type>
+            </variable>
+            <variable name="Pressure">
+              <type>
+                <derived name="HMI_INT"/>
+              </type>
+            </variable>
+          </localVars>
+          <inputVars>
+            <variable name="TargetPressure">
+              <type>
+                <INT/>
+              </type>
+            </variable>
+          </inputVars>
+          <localVars>
+            <variable name="Sloth">
+              <type>
+                <derived name="HMI_INT"/>
+              </type>
+            </variable>
+            <variable name="boolout">
+              <type>
+                <derived name="HMI_BOOL"/>
+              </type>
+            </variable>
+            <variable name="boolin">
+              <type>
+                <derived name="HMI_BOOL"/>
+              </type>
+              <initialValue>
+                <simpleValue value="True"/>
+              </initialValue>
+            </variable>
+            <variable name="strout">
+              <type>
+                <derived name="HMI_STRING"/>
+              </type>
+            </variable>
+            <variable name="strin">
+              <type>
+                <derived name="HMI_STRING"/>
+              </type>
+              <initialValue>
+                <simpleValue value="blup"/>
+              </initialValue>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <FBD>
+            <inVariable localId="5" executionOrderId="0" height="30" width="125" negated="false">
+              <position x="150" y="100"/>
+              <connectionPointOut>
+                <relPosition x="125" y="15"/>
+              </connectionPointOut>
+              <expression>TargetPressure</expression>
+            </inVariable>
+            <inOutVariable localId="4" executionOrderId="0" height="30" width="60" negatedOut="false" negatedIn="false">
+              <position x="510" y="80"/>
+              <connectionPointIn>
+                <relPosition x="0" y="15"/>
+                <connection refLocalId="6" formalParameter="OUT">
+                  <position x="510" y="95"/>
+                  <position x="470" y="95"/>
+                </connection>
+              </connectionPointIn>
+              <connectionPointOut>
+                <relPosition x="60" y="15"/>
+              </connectionPointOut>
+              <expression>Sloth</expression>
+            </inOutVariable>
+            <block localId="6" typeName="ADD" executionOrderId="0" height="60" width="65">
+              <position x="405" y="65"/>
+              <inputVariables>
+                <variable formalParameter="IN1">
+                  <connectionPointIn>
+                    <relPosition x="0" y="30"/>
+                    <connection refLocalId="4">
+                      <position x="405" y="95"/>
+                      <position x="385" y="95"/>
+                      <position x="385" y="50"/>
+                      <position x="580" y="50"/>
+                      <position x="580" y="95"/>
+                      <position x="570" y="95"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+                <variable formalParameter="IN2">
+                  <connectionPointIn>
+                    <relPosition x="0" y="50"/>
+                    <connection refLocalId="7" formalParameter="OUT">
+                      <position x="405" y="115"/>
+                      <position x="360" y="115"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+              </inputVariables>
+              <inOutVariables/>
+              <outputVariables>
+                <variable formalParameter="OUT">
+                  <connectionPointOut>
+                    <relPosition x="65" y="30"/>
+                  </connectionPointOut>
+                </variable>
+              </outputVariables>
+            </block>
+            <inVariable localId="1" executionOrderId="0" height="30" width="75" negated="false">
+              <position x="150" y="135"/>
+              <connectionPointOut>
+                <relPosition x="75" y="15"/>
+              </connectionPointOut>
+              <expression>Pressure</expression>
+            </inVariable>
+            <block localId="7" typeName="SUB" executionOrderId="0" height="60" width="65">
+              <position x="295" y="85"/>
+              <inputVariables>
+                <variable formalParameter="IN1">
+                  <connectionPointIn>
+                    <relPosition x="0" y="30"/>
+                    <connection refLocalId="5">
+                      <position x="295" y="115"/>
+                      <position x="275" y="115"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+                <variable formalParameter="IN2">
+                  <connectionPointIn>
+                    <relPosition x="0" y="50"/>
+                    <connection refLocalId="1">
+                      <position x="295" y="135"/>
+                      <position x="285" y="135"/>
+                      <position x="285" y="150"/>
+                      <position x="225" y="150"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+              </inputVariables>
+              <inOutVariables/>
+              <outputVariables>
+                <variable formalParameter="OUT">
+                  <connectionPointOut>
+                    <relPosition x="65" y="30"/>
+                  </connectionPointOut>
+                </variable>
+              </outputVariables>
+            </block>
+            <inVariable localId="2" executionOrderId="0" height="30" width="60" negated="false">
+              <position x="240" y="190"/>
+              <connectionPointOut>
+                <relPosition x="60" y="15"/>
+              </connectionPointOut>
+              <expression>Sloth</expression>
+            </inVariable>
+            <outVariable localId="3" executionOrderId="0" height="30" width="75" negated="false">
+              <position x="435" y="205"/>
+              <connectionPointIn>
+                <relPosition x="0" y="15"/>
+                <connection refLocalId="8" formalParameter="OUT">
+                  <position x="435" y="220"/>
+                  <position x="410" y="220"/>
+                </connection>
+              </connectionPointIn>
+              <expression>Pressure</expression>
+            </outVariable>
+            <block localId="8" typeName="DIV" executionOrderId="0" height="60" width="65">
+              <position x="345" y="190"/>
+              <inputVariables>
+                <variable formalParameter="IN1">
+                  <connectionPointIn>
+                    <relPosition x="0" y="30"/>
+                    <connection refLocalId="2">
+                      <position x="345" y="220"/>
+                      <position x="335" y="220"/>
+                      <position x="335" y="205"/>
+                      <position x="300" y="205"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+                <variable formalParameter="IN2">
+                  <connectionPointIn>
+                    <relPosition x="0" y="50"/>
+                    <connection refLocalId="9">
+                      <position x="345" y="240"/>
+                      <position x="300" y="240"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+              </inputVariables>
+              <inOutVariables/>
+              <outputVariables>
+                <variable formalParameter="OUT">
+                  <connectionPointOut>
+                    <relPosition x="65" y="30"/>
+                  </connectionPointOut>
+                </variable>
+              </outputVariables>
+            </block>
+            <inVariable localId="9" executionOrderId="0" height="30" width="60" negated="false">
+              <position x="240" y="225"/>
+              <connectionPointOut>
+                <relPosition x="60" y="15"/>
+              </connectionPointOut>
+              <expression>100</expression>
+            </inVariable>
+            <block localId="10" typeName="CONCAT" executionOrderId="0" height="60" width="65">
+              <position x="360" y="345"/>
+              <inputVariables>
+                <variable formalParameter="IN1">
+                  <connectionPointIn>
+                    <relPosition x="0" y="30"/>
+                    <connection refLocalId="13" formalParameter="OUT">
+                      <position x="360" y="375"/>
+                      <position x="330" y="375"/>
+                      <position x="330" y="332"/>
+                      <position x="440" y="332"/>
+                      <position x="440" y="300"/>
+                      <position x="430" y="300"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+                <variable formalParameter="IN2">
+                  <connectionPointIn>
+                    <relPosition x="0" y="50"/>
+                    <connection refLocalId="14">
+                      <position x="360" y="395"/>
+                      <position x="322" y="395"/>
+                      <position x="322" y="400"/>
+                      <position x="285" y="400"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+              </inputVariables>
+              <inOutVariables/>
+              <outputVariables>
+                <variable formalParameter="OUT">
+                  <connectionPointOut>
+                    <relPosition x="65" y="30"/>
+                  </connectionPointOut>
+                </variable>
+              </outputVariables>
+            </block>
+            <outVariable localId="11" executionOrderId="0" height="30" width="58" negated="false">
+              <position x="495" y="355"/>
+              <connectionPointIn>
+                <relPosition x="0" y="15"/>
+                <connection refLocalId="10" formalParameter="OUT">
+                  <position x="495" y="370"/>
+                  <position x="450" y="370"/>
+                  <position x="450" y="375"/>
+                  <position x="425" y="375"/>
+                </connection>
+              </connectionPointIn>
+              <expression>strout</expression>
+            </outVariable>
+            <inVariable localId="12" executionOrderId="0" height="30" width="125" negated="false">
+              <position x="145" y="285"/>
+              <connectionPointOut>
+                <relPosition x="125" y="15"/>
+              </connectionPointOut>
+              <expression>TargetPressure</expression>
+            </inVariable>
+            <block localId="13" typeName="INT_TO_STRING" executionOrderId="0" height="40" width="115">
+              <position x="315" y="270"/>
+              <inputVariables>
+                <variable formalParameter="IN">
+                  <connectionPointIn>
+                    <relPosition x="0" y="30"/>
+                    <connection refLocalId="12">
+                      <position x="315" y="300"/>
+                      <position x="270" y="300"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+              </inputVariables>
+              <inOutVariables/>
+              <outputVariables>
+                <variable formalParameter="OUT">
+                  <connectionPointOut>
+                    <relPosition x="115" y="30"/>
+                  </connectionPointOut>
+                </variable>
+              </outputVariables>
+            </block>
+            <inVariable localId="14" executionOrderId="0" height="30" width="50" negated="false">
+              <position x="235" y="385"/>
+              <connectionPointOut>
+                <relPosition x="50" y="15"/>
+              </connectionPointOut>
+              <expression>strin</expression>
+            </inVariable>
+            <inVariable localId="15" executionOrderId="0" height="30" width="60" negated="false">
+              <position x="690" y="210"/>
+              <connectionPointOut>
+                <relPosition x="60" y="15"/>
+              </connectionPointOut>
+              <expression>boolin</expression>
+            </inVariable>
+            <outVariable localId="16" executionOrderId="0" height="30" width="70" negated="false">
+              <position x="915" y="240"/>
+              <connectionPointIn>
+                <relPosition x="0" y="15"/>
+                <connection refLocalId="17" formalParameter="OUT">
+                  <position x="915" y="255"/>
+                  <position x="880" y="255"/>
+                </connection>
+              </connectionPointIn>
+              <expression>boolout</expression>
+            </outVariable>
+            <block localId="17" typeName="AND" executionOrderId="0" height="60" width="65">
+              <position x="815" y="225"/>
+              <inputVariables>
+                <variable formalParameter="IN1">
+                  <connectionPointIn>
+                    <relPosition x="0" y="30"/>
+                    <connection refLocalId="15">
+                      <position x="815" y="255"/>
+                      <position x="762" y="255"/>
+                      <position x="762" y="225"/>
+                      <position x="750" y="225"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+                <variable formalParameter="IN2">
+                  <connectionPointIn>
+                    <relPosition x="0" y="50"/>
+                    <connection refLocalId="21" formalParameter="OUT">
+                      <position x="815" y="275"/>
+                      <position x="750" y="275"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+              </inputVariables>
+              <inOutVariables/>
+              <outputVariables>
+                <variable formalParameter="OUT">
+                  <connectionPointOut>
+                    <relPosition x="65" y="30"/>
+                  </connectionPointOut>
+                </variable>
+              </outputVariables>
+            </block>
+            <inVariable localId="18" executionOrderId="0" height="30" width="75" negated="false">
+              <position x="455" y="260"/>
+              <connectionPointOut>
+                <relPosition x="75" y="15"/>
+              </connectionPointOut>
+              <expression>Pressure</expression>
+            </inVariable>
+            <block localId="19" typeName="MOD" executionOrderId="0" height="60" width="65">
+              <position x="585" y="245"/>
+              <inputVariables>
+                <variable formalParameter="IN1">
+                  <connectionPointIn>
+                    <relPosition x="0" y="30"/>
+                    <connection refLocalId="18">
+                      <position x="585" y="275"/>
+                      <position x="530" y="275"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+                <variable formalParameter="IN2">
+                  <connectionPointIn>
+                    <relPosition x="0" y="50"/>
+                    <connection refLocalId="20">
+                      <position x="585" y="295"/>
+                      <position x="555" y="295"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+              </inputVariables>
+              <inOutVariables/>
+              <outputVariables>
+                <variable formalParameter="OUT">
+                  <connectionPointOut>
+                    <relPosition x="65" y="30"/>
+                  </connectionPointOut>
+                </variable>
+              </outputVariables>
+            </block>
+            <inVariable localId="20" executionOrderId="0" height="30" width="20" negated="false">
+              <position x="535" y="280"/>
+              <connectionPointOut>
+                <relPosition x="20" y="15"/>
+              </connectionPointOut>
+              <expression>2</expression>
+            </inVariable>
+            <block localId="21" typeName="EQ" executionOrderId="0" height="60" width="65">
+              <position x="685" y="245"/>
+              <inputVariables>
+                <variable formalParameter="IN1">
+                  <connectionPointIn>
+                    <relPosition x="0" y="30"/>
+                    <connection refLocalId="19" formalParameter="OUT">
+                      <position x="685" y="275"/>
+                      <position x="650" y="275"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+                <variable formalParameter="IN2">
+                  <connectionPointIn>
+                    <relPosition x="0" y="50"/>
+                    <connection refLocalId="22">
+                      <position x="685" y="295"/>
+                      <position x="670" y="295"/>
+                      <position x="670" y="330"/>
+                      <position x="650" y="330"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+              </inputVariables>
+              <inOutVariables/>
+              <outputVariables>
+                <variable formalParameter="OUT">
+                  <connectionPointOut>
+                    <relPosition x="65" y="30"/>
+                  </connectionPointOut>
+                </variable>
+              </outputVariables>
+            </block>
+            <inVariable localId="22" executionOrderId="0" height="30" width="20" negated="false">
+              <position x="630" y="315"/>
+              <connectionPointOut>
+                <relPosition x="20" y="15"/>
+              </connectionPointOut>
+              <expression>0</expression>
+            </inVariable>
+          </FBD>
+        </body>
+      </pou>
+    </pous>
+  </types>
+  <instances>
+    <configurations>
+      <configuration name="config">
+        <resource name="resource1">
+          <task name="task0" priority="0" interval="T#20ms">
+            <pouInstance name="instance0" typeName="MainStuff"/>
+          </task>
+        </resource>
+      </configuration>
+    </configurations>
+  </instances>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/svghmi_v2/py_ext_0@py_ext/baseconfnode.xml	Wed Aug 12 15:24:02 2020 +0200
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='utf-8'?>
+<BaseParams xmlns:xsd="http://www.w3.org/2001/XMLSchema" IEC_Channel="1" Name="py_ext_0"/>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/svghmi_v2/py_ext_0@py_ext/pyfile.xml	Wed Aug 12 15:24:02 2020 +0200
@@ -0,0 +1,30 @@
+<?xml version='1.0' encoding='utf-8'?>
+<PyFile xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+  <variables>
+    <variable name="SomePLCglobal" type="HMI_STRING" initial="'blaf'" onchange="MyOnChangeFunc"/>
+  </variables>
+  <globals>
+    <xhtml:p><![CDATA[
+
+def MyOnChangeFunc(changed_var_name):
+    print changed_var_name + ": " + getattr(PLCGlobals, changed_var_name)
+
+]]></xhtml:p>
+  </globals>
+  <init>
+    <xhtml:p><![CDATA[
+]]></xhtml:p>
+  </init>
+  <cleanup>
+    <xhtml:p><![CDATA[
+]]></xhtml:p>
+  </cleanup>
+  <start>
+    <xhtml:p><![CDATA[
+]]></xhtml:p>
+  </start>
+  <stop>
+    <xhtml:p><![CDATA[
+]]></xhtml:p>
+  </stop>
+</PyFile>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/svghmi_v2/svghmi_0@svghmi/baseconfnode.xml	Wed Aug 12 15:24:02 2020 +0200
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='utf-8'?>
+<BaseParams xmlns:xsd="http://www.w3.org/2001/XMLSchema" IEC_Channel="0" Name="svghmi_0"/>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/svghmi_v2/svghmi_0@svghmi/confnode.xml	Wed Aug 12 15:24:02 2020 +0200
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SVGHMI xmlns:xsd="http://www.w3.org/2001/XMLSchema" OnWatchdog="echo Watchdog for {name} !" OnStart="xdg-open http://127.0.0.1:{port}/{name}" OnStop="echo Closing {name}" WatchdogInitial="10" WatchdogInterval="5"/>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/svghmi_v2/svghmi_0@svghmi/svghmi.svg	Wed Aug 12 15:24:02 2020 +0200
@@ -0,0 +1,1525 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="1280"
+   height="720"
+   viewBox="0 0 1280 720"
+   version="1.1"
+   id="hmi0"
+   sodipodi:docname="svghmi.svg"
+   inkscape:version="0.92.3 (2405546, 2018-03-11)"
+   inkscape:label="Layer">
+  <metadata
+     id="metadata4542">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs2">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="-688.56326 : 510.71991 : 1"
+       inkscape:vp_y="0 : 1306.0642 : 0"
+       inkscape:vp_z="662.62627 : 323.72015 : 1"
+       inkscape:persp3d-origin="147.31778 : 353.99223 : 1"
+       id="perspective258" />
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="-457.78124 : 416.79285 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="576.76945 : 273.61475 : 1"
+       inkscape:persp3d-origin="182.21876 : 296.79285 : 1"
+       id="perspective503" />
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="-104 : 357 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="1272 : 385 : 1"
+       inkscape:persp3d-origin="536 : 237 : 1"
+       id="perspective445" />
+    <inkscape:tag
+       id="Set 1"
+       inkscape:label="HMI:AccessList@Admin"
+       inkscape:expanded="true">
+      <inkscape:tagref
+         xlink:href="#text995"
+         id="tagref192" />
+      <inkscape:tagref
+         xlink:href="#g991"
+         id="tagref194" />
+    </inkscape:tag>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient962">
+      <stop
+         style="stop-color:#ff3000;stop-opacity:1;"
+         offset="0"
+         id="stop958" />
+      <stop
+         style="stop-color:#0022ff;stop-opacity:1"
+         offset="1"
+         id="stop960" />
+    </linearGradient>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker926"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#ff3000;fill-opacity:1;fill-rule:evenodd;stroke:#ff3000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path924"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <inkscape:tag
+       id="Set 3"
+       inkscape:expanded="true"
+       inkscape:label="HMI:Translate">
+      <inkscape:tagref
+         xlink:href="#text831"
+         id="tagref1085" />
+      <inkscape:tagref
+         xlink:href="#text827"
+         id="tagref1087" />
+      <inkscape:tagref
+         xlink:href="#text4497"
+         id="tagref1089" />
+      <inkscape:tagref
+         xlink:href="#home_jmp"
+         id="tagref1091" />
+      <inkscape:tagref
+         xlink:href="#setting_jmp"
+         id="tagref1093" />
+    </inkscape:tag>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient962"
+       id="linearGradient1407"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.5,0,0,0.03945396,73.07865,3.7693345)"
+       x1="113.38908"
+       y1="-62.210247"
+       x2="113.38908"
+       y2="4.0725975" />
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="-173.06414 : 591.30354 : 1"
+       inkscape:vp_y="0 : 1319.7648 : 0"
+       inkscape:vp_z="1192.2994 : 402.34211 : 1"
+       inkscape:persp3d-origin="671.58536 : 432.93175 : 1"
+       id="perspective503-6" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:document-units="px"
+     inkscape:current-layer="g110-0-9"
+     showgrid="false"
+     units="px"
+     inkscape:zoom="1.4142136"
+     inkscape:cx="437.24009"
+     inkscape:cy="177.36896"
+     inkscape:window-width="1800"
+     inkscape:window-height="836"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     showguides="true"
+     inkscape:guide-bbox="true" />
+  <rect
+     style="color:#000000;fill:#4d4d4d"
+     id="page0"
+     width="1280"
+     height="720"
+     x="0"
+     y="0"
+     inkscape:label="HMI:Page:Home"
+     sodipodi:insensitive="true" />
+  <g
+     inkscape:label="HMI:Slider@/PUMP0/SLOTH"
+     transform="matrix(7.5590552,0,0,7.5590552,-710.78539,551.61779)"
+     id="g110-0">
+    <path
+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ff0000;stroke-width:0.52916664;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="M 113.38908,2.2017068 V -62.210247"
+       id="path90-9"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc"
+       inkscape:label="range" />
+    <path
+       inkscape:label="handle"
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path92-3"
+       d="m 113.32293,4.2048893 v -5.230241"
+       style="fill:none;fill-rule:evenodd;stroke:url(#linearGradient1407);stroke-width:5.28146696;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:29.63333321;stroke-opacity:1" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:5.29166651px;line-height:125%;font-family:sans-serif;text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#ff6600;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="115.07632"
+       y="9.3424692"
+       id="text96-6"
+       inkscape:label="min"><tspan
+         sodipodi:role="line"
+         id="tspan94-0"
+         x="115.07632"
+         y="9.3424692"
+         style="text-align:end;text-anchor:end;fill:#ff6600;stroke-width:0.26458332px">0</tspan></text>
+    <text
+       id="text100-6"
+       y="-64.195457"
+       x="113.27539"
+       style="font-style:normal;font-weight:normal;font-size:5.29166651px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ff6600;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       inkscape:label="max"><tspan
+         style="text-align:center;text-anchor:middle;fill:#ff6600;stroke-width:0.26458332px"
+         y="-64.195457"
+         x="113.27539"
+         sodipodi:role="line"
+         id="tspan1409">100</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ff6600;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="-24.72547"
+       y="-121.97556"
+       id="text104-6"
+       inkscape:label="value"
+       transform="rotate(90)"><tspan
+         sodipodi:role="line"
+         x="-24.72547"
+         y="-121.97556"
+         style="text-align:center;text-anchor:middle;fill:#ff6600;stroke-width:0.26458332px"
+         id="tspan102-1">000</tspan></text>
+  </g>
+  <g
+     id="g4557"
+     inkscape:label="HMI:Input@/SOMEPLCGLOBAL">
+    <text
+       inkscape:label="value"
+       transform="scale(1.1201068,0.89277203)"
+       id="text2398"
+       y="446.98395"
+       x="347.5253"
+       style="font-style:normal;font-weight:normal;font-size:124.08008575px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:3.10200214px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         style="stroke-width:3.10200214px"
+         y="446.98395"
+         x="347.5253"
+         id="tspan2396"
+         sodipodi:role="line">Test</tspan></text>
+    <rect
+       style="opacity:0.18600003;fill:#de2cc9;fill-opacity:1;stroke:none;stroke-width:1.11699021"
+       id="rect4559"
+       width="323.85489"
+       height="132.93608"
+       x="369.10974"
+       y="299.97858"
+       inkscape:label="edit" />
+    <rect
+       style="opacity:0;fill:#de2cc9;fill-opacity:1;stroke:none;stroke-width:3.45667744"
+       id="rect4561"
+       width="580.42413"
+       height="339.91623"
+       x="699.57587"
+       y="380.08374"
+       inkscape:label="key_pos" />
+  </g>
+  <g
+     transform="matrix(1.5213157,0,0,1.4848913,-82.472173,789.79964)"
+     style="fill-rule:evenodd;stroke-width:0.47631353"
+     id="g4278"
+     inkscape:label="HMI:Keypad:HMI_STRING">
+    <path
+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.16776976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="M 54.211084,1.2654702 H 435.7388 V 230.18209 H 54.211084 Z"
+       id="rect1006-3"
+       inkscape:connector-curvature="0"
+       inkscape:label="Background"
+       sodipodi:nodetypes="ccccc" />
+    <path
+       style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path185"
+       d="m 162,197 h -11 c -2,0 -3,1 -3,3 v 18 c 0,2 1,3 3,3 h 11 168 18 c 0,0 1,-1 1,-3 v -18 c 0,-2 -1,-3 -1,-3 h -18 z"
+       inkscape:connector-curvature="0"
+       inkscape:label="Space" />
+    <g
+       id="g4380"
+       inkscape:label="Keys"
+       style="stroke-width:0.47631353"
+       transform="translate(0,-19.076386)">
+      <g
+         id="g4283"
+         inkscape:label="q Q"
+         style="stroke-width:0.47631353"
+         transform="translate(0,-9.5381931)">
+        <path
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="path41"
+           d="m 95,121 h 19 c 2,0 3,1 3,3 v 18 c 0,1 -1,3 -3,3 H 95 c -1,0 -3,-2 -3,-3 v -18 c 0,-2 2,-3 3,-3 z"
+           inkscape:connector-curvature="0" />
+        <text
+           x="99.378708"
+           y="138.28395"
+           id="text203"
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           transform="scale(1.0007154,0.99928514)">Q</text>
+      </g>
+      <g
+         id="g4337"
+         inkscape:label="w W"
+         style="stroke-width:0.47631353"
+         transform="translate(0,-9.5381931)">
+        <path
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="path43"
+           d="m 124,121 h 20 c 2,0 3,1 3,3 v 18 c 0,1 -1,3 -3,3 h -20 c -1,0 -3,-2 -3,-3 v -18 c 0,-2 2,-3 3,-3 z"
+           inkscape:connector-curvature="0" />
+        <text
+           x="127.0709"
+           y="138.28395"
+           id="text207"
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           transform="scale(1.0007154,0.99928514)">W</text>
+      </g>
+      <g
+         id="g4332"
+         inkscape:label="e E"
+         style="stroke-width:0.47631353"
+         transform="translate(0,-9.5381931)">
+        <path
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="path45"
+           d="m 154,121 h 20 c 2,0 3,1 3,3 v 18 c 0,1 -1,3 -3,3 h -20 c -1,0 -3,-2 -3,-3 v -18 c 0,-2 2,-3 3,-3 z"
+           inkscape:connector-curvature="0" />
+        <text
+           x="159.70854"
+           y="138.28395"
+           id="text211"
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           transform="scale(1.0007154,0.99928514)">E</text>
+      </g>
+      <g
+         id="g4326"
+         inkscape:label="r R"
+         style="stroke-width:0.47631353"
+         transform="translate(0,-9.5381931)">
+        <path
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="path47"
+           d="m 184,121 h 19 c 2,0 3,1 3,3 v 18 c 0,1 -1,3 -3,3 h -19 c -1,0 -3,-2 -3,-3 v -18 c 0,-2 2,-3 3,-3 z"
+           inkscape:connector-curvature="0" />
+        <text
+           x="188.39003"
+           y="138.28395"
+           id="text215"
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           transform="scale(1.0007154,0.99928514)">R</text>
+      </g>
+      <g
+         id="g4321"
+         inkscape:label="t T"
+         style="stroke-width:0.47631353"
+         transform="translate(0,-9.5381931)">
+        <path
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="path49"
+           d="m 213,121 h 20 c 2,0 3,1 3,3 v 18 c 0,1 -1,3 -3,3 h -20 c -1,0 -2,-2 -2,-3 v -18 c 0,-2 1,-3 2,-3 z"
+           inkscape:connector-curvature="0" />
+        <text
+           x="219.04961"
+           y="138.28395"
+           id="text219"
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           transform="scale(1.0007154,0.99928514)">T</text>
+      </g>
+      <g
+         id="g4316"
+         inkscape:label="y Y"
+         style="stroke-width:0.47631353"
+         transform="translate(0,-9.5381931)">
+        <path
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="path51"
+           d="m 243,121 h 20 c 2,0 3,1 3,3 v 18 c 0,1 -1,3 -3,3 h -20 c -1,0 -2,-2 -2,-3 v -18 c 0,-2 1,-3 2,-3 z"
+           inkscape:connector-curvature="0" />
+        <text
+           x="248.72017"
+           y="138.28395"
+           id="text223"
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           transform="scale(1.0007154,0.99928514)">Y</text>
+      </g>
+      <g
+         id="g4311"
+         inkscape:label="u U"
+         style="stroke-width:0.47631353"
+         transform="translate(0,-9.5381931)">
+        <path
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="path53"
+           d="m 273,121 h 20 c 2,0 3,1 3,3 v 18 c 0,1 -1,3 -3,3 h -20 c -1,0 -2,-2 -2,-3 v -18 c 0,-2 1,-3 2,-3 z"
+           inkscape:connector-curvature="0" />
+        <text
+           x="278.39075"
+           y="138.28395"
+           id="text227"
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           transform="scale(1.0007154,0.99928514)">U</text>
+      </g>
+      <g
+         id="g4306"
+         inkscape:label="i I"
+         style="stroke-width:0.47631353"
+         transform="translate(0,-9.5381931)">
+        <path
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="path55"
+           d="m 302,121 h 20 c 2,0 3,1 3,3 v 18 c 0,1 -1,3 -3,3 h -20 c -1,0 -2,-2 -2,-3 v -18 c 0,-2 1,-3 2,-3 z"
+           inkscape:connector-curvature="0" />
+        <text
+           x="311.02859"
+           y="138.28395"
+           id="text231"
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           transform="scale(1.0007154,0.99928514)">I</text>
+      </g>
+      <g
+         id="g4301"
+         inkscape:label="o O"
+         style="stroke-width:0.47631353"
+         transform="translate(0,-9.5381931)">
+        <path
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="path57"
+           d="m 332,121 h 20 c 2,0 3,1 3,3 v 18 c 0,1 -1,3 -3,3 h -20 c -1,0 -2,-2 -2,-3 v -18 c 0,-2 1,-3 2,-3 z"
+           inkscape:connector-curvature="0" />
+        <text
+           x="336.74319"
+           y="138.28395"
+           id="text235"
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           transform="scale(1.0007154,0.99928514)">O</text>
+      </g>
+      <g
+         id="g4296"
+         inkscape:label="p P"
+         style="stroke-width:0.47631353"
+         transform="translate(0,-9.5381931)">
+        <path
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="path59"
+           d="m 362,121 h 20 c 2,0 3,1 3,3 v 18 c 0,1 -1,3 -3,3 h -20 c -1,0 -2,-2 -2,-3 v -18 c 0,-2 1,-3 2,-3 z"
+           inkscape:connector-curvature="0" />
+        <text
+           x="367.40256"
+           y="138.28395"
+           id="text239"
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           transform="scale(1.0007154,0.99928514)">P</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4511"
+         inkscape:label="a A">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 103,147 h 19 c 1,0 3,1 3,2 v 19 c 0,1 -2,2 -3,2 h -19 c -2,0 -3,-1 -3,-2 v -19 c 0,-1 1,-2 3,-2 z"
+           id="path65"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text243"
+           y="163.99854"
+           x="107.29005"
+           transform="scale(1.0007154,0.99928514)">A</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4516"
+         inkscape:label="s S">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 132,147 h 20 c 1,0 3,1 3,2 v 19 c 0,1 -2,2 -3,2 h -20 c -2,0 -3,-1 -3,-2 v -19 c 0,-1 1,-2 3,-2 z"
+           id="path67"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text247"
+           y="163.99854"
+           x="137.95012"
+           transform="scale(1.0007154,0.99928514)">S</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4521"
+         inkscape:label="d D">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 162,147 h 20 c 2,0 3,1 3,2 v 19 c 0,1 -1,2 -3,2 h -20 c -2,0 -3,-1 -3,-2 v -19 c 0,-1 1,-2 3,-2 z"
+           id="path69"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text251"
+           y="163.99854"
+           x="166.63159"
+           transform="scale(1.0007154,0.99928514)">D</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4526"
+         inkscape:label="f F">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 192,147 h 19 c 2,0 3,1 3,2 v 19 c 0,1 -1,2 -3,2 h -19 c -2,0 -3,-1 -3,-2 v -19 c 0,-1 1,-2 3,-2 z"
+           id="path71"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text255"
+           y="163.99854"
+           x="197.29166"
+           transform="scale(1.0007154,0.99928514)">F</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4531"
+         inkscape:label="g G">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 221,147 h 20 c 2,0 3,1 3,2 v 19 c 0,1 -1,2 -3,2 h -20 c -2,0 -3,-1 -3,-2 v -19 c 0,-1 1,-2 3,-2 z"
+           id="path73"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text259"
+           y="163.99854"
+           x="225.97284"
+           transform="scale(1.0007154,0.99928514)">G</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4536"
+         inkscape:label="h H">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 251,147 h 20 c 2,0 3,1 3,2 v 19 c 0,1 -1,2 -3,2 h -20 c -1,0 -3,-1 -3,-2 v -19 c 0,-1 2,-2 3,-2 z"
+           id="path75"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text263"
+           y="163.99854"
+           x="255.64342"
+           transform="scale(1.0007154,0.99928514)">H</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4541"
+         inkscape:label="j J">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 281,147 h 19 c 2,0 3,1 3,2 v 19 c 0,1 -1,2 -3,2 h -19 c -1,0 -3,-1 -3,-2 v -19 c 0,-1 2,-2 3,-2 z"
+           id="path77"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text267"
+           y="163.99854"
+           x="287.29208"
+           transform="scale(1.0007154,0.99928514)">J</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4546"
+         inkscape:label="k K">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 310,147 h 20 c 2,0 3,1 3,2 v 19 c 0,1 -1,2 -3,2 h -20 c -1,0 -3,-1 -3,-2 v -19 c 0,-1 2,-2 3,-2 z"
+           id="path79"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text271"
+           y="163.99854"
+           x="314.98465"
+           transform="scale(1.0007154,0.99928514)">K</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4551"
+         inkscape:label="l L">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 340,147 h 20 c 2,0 3,1 3,2 v 19 c 0,1 -1,2 -3,2 h -20 c -1,0 -3,-1 -3,-2 v -19 c 0,-1 2,-2 3,-2 z"
+           id="path81"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text275"
+           y="163.99854"
+           x="345.64444"
+           transform="scale(1.0007154,0.99928514)">L</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4586"
+         inkscape:label="z Z"
+         transform="translate(0,9.5381929)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 113,172 h 21 c 1,0 2,2 2,3 v 17 c 0,2 -1,3 -2,3 h -21 c -1,0 -2,-1 -2,-3 v -17 c 0,-1 1,-3 2,-3 z"
+           id="path87-3"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text279"
+           y="188.72411"
+           x="119.15855"
+           transform="scale(1.0007154,0.99928514)">Z</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4581"
+         inkscape:label="x X"
+         transform="translate(0,9.5381929)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 143,172 h 21 c 1,0 2,2 2,3 v 17 c 0,2 -1,3 -2,3 h -21 c -1,0 -2,-1 -2,-3 v -17 c 0,-1 1,-3 2,-3 z"
+           id="path89-6"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text283"
+           y="188.72411"
+           x="148.82933"
+           transform="scale(1.0007154,0.99928514)">X</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4576"
+         inkscape:label="c C"
+         transform="translate(0,9.5381929)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 173,172 h 21 c 1,0 2,2 2,3 v 17 c 0,2 -1,3 -2,3 h -21 c -1,0 -2,-1 -2,-3 v -17 c 0,-1 1,-3 2,-3 z"
+           id="path91-7"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text287"
+           y="188.72411"
+           x="178.50011"
+           transform="scale(1.0007154,0.99928514)">C</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4571"
+         inkscape:label="v V"
+         transform="translate(0,9.5381929)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 202,172 h 21 c 1,0 2,2 2,3 v 17 c 0,2 -1,3 -2,3 h -21 c 0,0 -1,-1 -1,-3 v -17 c 0,-1 1,-3 1,-3 z"
+           id="path195"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text291"
+           y="188.72411"
+           x="208.16988"
+           transform="scale(1.0007154,0.99928514)">V</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4566"
+         inkscape:label="b B"
+         transform="translate(0,9.5381929)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 233,172 h 20 c 1,0 2,2 2,3 v 17 c 0,2 -1,3 -2,3 h -20 c -2,0 -3,-1 -3,-3 v -17 c 0,-1 1,-3 3,-3 z"
+           id="path93"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text295"
+           y="188.72411"
+           x="237.84096"
+           transform="scale(1.0007154,0.99928514)">B</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4561"
+         inkscape:label="n N"
+         transform="translate(0,9.5381929)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 263,172 h 20 c 1,0 2,2 2,3 v 17 c 0,2 -1,3 -2,3 h -20 c -2,0 -3,-1 -3,-3 v -17 c 0,-1 1,-3 3,-3 z"
+           id="path95"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text299"
+           y="188.72411"
+           x="267.51193"
+           transform="scale(1.0007154,0.99928514)">N</text>
+      </g>
+      <g
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4556"
+         inkscape:label="m M"
+         transform="translate(0,9.5381929)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 293,172 h 19 c 1,0 2,2 2,3 v 17 c 0,2 -1,3 -2,3 h -19 c -2,0 -3,-1 -3,-3 v -17 c 0,-1 1,-3 3,-3 z"
+           id="path97"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text303"
+           y="188.72411"
+           x="296.1933"
+           transform="scale(1.0007154,0.99928514)">M</text>
+      </g>
+      <g
+         id="g4818"
+         inkscape:label=". :"
+         style="stroke-width:0.47631353"
+         transform="translate(0,9.5381929)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 352,172 h 20 c 1,0 2,2 2,3 v 17 c 0,2 -1,3 -2,3 h -20 c -2,0 -3,-1 -3,-3 v -17 c 0,-1 1,-3 3,-3 z"
+           id="path101"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           transform="scale(1.0007154,0.99928513)"
+           style="font-weight:normal;font-size:9.28803921px;font-family:Arial;fill:#2b2828;fill-rule:evenodd;stroke-width:0.36866826"
+           id="text719"
+           y="189.66107"
+           x="359.58276">.</text>
+        <text
+           x="359.58276"
+           y="181.64532"
+           id="text4834"
+           style="font-weight:normal;font-size:9.28803921px;font-family:Arial;fill:#2b2828;fill-rule:evenodd;stroke-width:0.36866826"
+           transform="scale(1.0007154,0.99928512)">:</text>
+      </g>
+      <g
+         id="g4813"
+         inkscape:label=", ;"
+         style="stroke-width:0.47631353"
+         transform="translate(0,9.5381929)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 322,172 h 20 c 1,0 2,2 2,3 v 17 c 0,2 -1,3 -2,3 h -20 c -2,0 -3,-1 -3,-3 v -17 c 0,-1 1,-3 3,-3 z"
+           id="path99"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:9.28803921px;font-family:Arial;fill:#2b2828;fill-rule:evenodd;stroke-width:0.36866826"
+           id="text727"
+           y="181.64532"
+           x="330.00806"
+           transform="scale(1.0007154,0.99928512)">;</text>
+        <text
+           style="font-weight:normal;font-size:9.28803921px;font-family:Arial;fill:#2b2828;fill-rule:evenodd;stroke-width:0.36866826"
+           y="189.66107"
+           x="330.00806"
+           transform="scale(1.0007154,0.99928512)"
+           id="text4826">,</text>
+      </g>
+      <g
+         style="stroke-width:0.47631353"
+         inkscape:label="1"
+         id="g2845"
+         transform="translate(-13.353469,-45.783327)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 95,121 h 19 c 2,0 3,1 3,3 v 18 c 0,1 -1,3 -3,3 H 95 c -1,0 -3,-2 -3,-3 v -18 c 0,-2 2,-3 3,-3 z"
+           id="path2839"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text2841"
+           y="138.28395"
+           x="101.07153"
+           transform="scale(1.0007154,0.99928513)">1</text>
+      </g>
+      <g
+         style="stroke-width:0.47631353"
+         inkscape:label="2"
+         id="g2853"
+         transform="translate(-13.353469,-45.783327)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 124,121 h 20 c 2,0 3,1 3,3 v 18 c 0,1 -1,3 -3,3 h -20 c -1,0 -3,-2 -3,-3 v -18 c 0,-2 2,-3 3,-3 z"
+           id="path2847"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text2849"
+           y="138.28395"
+           x="130.18704"
+           transform="scale(1.0007154,0.99928513)">2</text>
+      </g>
+      <g
+         inkscape:label="3"
+         id="g2861"
+         style="stroke-width:0.47631353"
+         transform="translate(-13.353469,-45.783327)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 154,121 h 20 c 2,0 3,1 3,3 v 18 c 0,1 -1,3 -3,3 h -20 c -1,0 -3,-2 -3,-3 v -18 c 0,-2 2,-3 3,-3 z"
+           id="path2855"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text2857"
+           y="138.28395"
+           x="159.70854"
+           transform="scale(1.0007154,0.99928514)">3</text>
+      </g>
+      <g
+         id="g2957"
+         inkscape:label="4"
+         transform="translate(0,-19.076386)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 170.64653,94.293059 h 19 c 2,0 3,1 3,3 v 18.000001 c 0,1 -1,3 -3,3 h -19 c -1,0 -3,-2 -3,-3 V 97.293059 c 0,-2 2,-3 3,-3 z"
+           id="path2865"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text2867"
+           y="111.55791"
+           x="176.39188"
+           transform="scale(1.0007154,0.99928514)">4</text>
+      </g>
+      <g
+         id="g2962"
+         inkscape:label="5"
+         transform="translate(0,-19.076386)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 199.64653,94.293059 h 20 c 2,0 3,1 3,3 v 18.000001 c 0,1 -1,3 -3,3 h -20 c -1,0 -2,-2 -2,-3 V 97.293059 c 0,-2 1,-3 2,-3 z"
+           id="path2873"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text2875"
+           y="111.55791"
+           x="205.70567"
+           transform="scale(1.0007154,0.99928514)">5</text>
+      </g>
+      <g
+         id="g2967"
+         inkscape:label="6"
+         transform="translate(0,-19.076386)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 229.64653,94.293059 h 20 c 2,0 3,1 3,3 v 18.000001 c 0,1 -1,3 -3,3 h -20 c -1,0 -2,-2 -2,-3 V 97.293059 c 0,-2 1,-3 2,-3 z"
+           id="path2881"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text2883"
+           y="111.55791"
+           x="236.15851"
+           transform="scale(1.0007154,0.99928514)">6</text>
+      </g>
+      <g
+         id="g2972"
+         inkscape:label="7"
+         transform="translate(0,-19.076386)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 259.64653,94.293059 h 20 c 2,0 3,1 3,3 v 18.000001 c 0,1 -1,3 -3,3 h -20 c -1,0 -2,-2 -2,-3 V 97.293059 c 0,-2 1,-3 2,-3 z"
+           id="path2889"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text2891"
+           y="111.55791"
+           x="266.06564"
+           transform="scale(1.0007154,0.99928514)">7</text>
+      </g>
+      <g
+         id="g2977"
+         inkscape:label="8"
+         transform="translate(0,-19.076386)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 288.64653,94.293059 h 20 c 2,0 3,1 3,3 v 18.000001 c 0,1 -1,3 -3,3 h -20 c -1,0 -2,-2 -2,-3 V 97.293059 c 0,-2 1,-3 2,-3 z"
+           id="path2897"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text2899"
+           y="111.55791"
+           x="295.08231"
+           transform="scale(1.0007154,0.99928514)">8</text>
+      </g>
+      <g
+         id="g2982"
+         inkscape:label="9 -"
+         transform="translate(0,-19.076386)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 318.64653,94.293059 h 20 c 2,0 3,1 3,3 v 18.000001 c 0,1 -1,3 -3,3 h -20 c -1,0 -2,-2 -2,-3 V 97.293059 c 0,-2 1,-3 2,-3 z"
+           id="path2905"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text2907"
+           y="111.55791"
+           x="325.05408"
+           transform="scale(1.0007154,0.99928514)">9</text>
+        <text
+           transform="scale(1.0007154,0.99928511)"
+           x="335.72681"
+           y="102.42173"
+           id="text806"
+           style="font-weight:normal;font-size:9.28803921px;font-family:Arial;fill:#2b2828;fill-rule:evenodd;stroke-width:0.36866826">-</text>
+      </g>
+      <g
+         id="g2987"
+         inkscape:label="0 +"
+         transform="translate(0,-19.076386)">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 348.64653,94.293059 h 20 c 2,0 3,1 3,3 v 18.000001 c 0,1 -1,3 -3,3 h -20 c -1,0 -2,-2 -2,-3 V 97.293059 c 0,-2 1,-3 2,-3 z"
+           id="path2913"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+        <text
+           style="font-weight:normal;font-size:13.93205929px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text2915"
+           y="111.55791"
+           x="355.05984"
+           transform="scale(1.0007154,0.99928514)">0</text>
+        <text
+           transform="scale(1.0007154,0.99928511)"
+           style="font-weight:normal;font-size:9.28803921px;font-family:Arial;fill:#2b2828;fill-rule:evenodd;stroke-width:0.36866826"
+           id="text804"
+           y="102.42173"
+           x="365.30151">+</text>
+      </g>
+    </g>
+    <g
+       transform="translate(335.89988,-58.934803)"
+       id="g3544"
+       inkscape:label="Esc"
+       style="stroke-width:0.47631353">
+      <path
+         style="opacity:1;vector-effect:none;fill:#4f4c4d;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.16824313;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+         id="path105"
+         d="m 47.948645,115.07509 h 39.076386 c 1,0 3,1 3,3 v 18 c 0,1 -2,3 -3,3 H 47.948645 c -2,0 -3,-2 -3,-3 v -18 c 0,-2 1,-3 3,-3 z"
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="sssssssss" />
+      <text
+         transform="scale(1.0007154,0.99928512)"
+         style="font-weight:normal;font-size:9.37966251px;font-family:Arial;fill:#ffffff;fill-rule:evenodd;stroke-width:0.36866826"
+         id="text469"
+         y="130.02028"
+         x="59.288635">Esc</text>
+    </g>
+    <g
+       inkscape:label="Enter"
+       id="g4291"
+       style="stroke-width:0.47631353"
+       transform="translate(0,-19.076386)">
+      <path
+         sodipodi:nodetypes="sssssssss"
+         style="opacity:1;vector-effect:none;fill:#4f4c4d;fill-opacity:1;stroke:none;stroke-width:0.16824313;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+         id="path3616"
+         d="m 368.68274,170 c -1,0 -2,-1 -2,-3 v -17 c 0,-1 1,-3 2,-3 h 54.24217 c 2,0 3,2 3,3 v 17 c 0,2 -1,3 -3,3 z"
+         inkscape:connector-curvature="0" />
+      <path
+         style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         d="m -260.23633,1080.8125 v 15.7949 h -38.68555 v -3 l -6.91992,4 6.91992,4 v -3.0019 h 40.6836 v -17.793 z"
+         transform="matrix(0.47690966,0,0,0.47690966,531.12074,-361.18588)"
+         id="path6545"
+         inkscape:connector-curvature="0" />
+    </g>
+    <g
+       inkscape:label="BackSpace"
+       id="g4287"
+       style="fill-rule:evenodd;stroke-width:0.47631353"
+       transform="translate(2.3648311e-6,-28.614579)">
+      <path
+         sodipodi:nodetypes="sssssssss"
+         style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+         id="path3624"
+         d="m 391.97749,144 c -1,0 -2,-1 -2,-3 v -17 c 0,-1 1,-3 2,-3 h 30.94742 c 2,0 3,2 3,3 v 17 c 0,2 -1,3 -3,3 z"
+         inkscape:connector-curvature="0" />
+      <path
+         style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#2b2828;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         d="m -268.72656,1011.1777 -6.91992,4 6.91992,4 v -3.0019 h 29.18945 v -1.9981 h -29.18945 z"
+         transform="matrix(0.47690966,0,0,0.47690966,531.12074,-351.64769)"
+         id="path11623-1-0"
+         inkscape:connector-curvature="0" />
+    </g>
+    <g
+       id="g934"
+       inkscape:label="CapsLock">
+      <g
+         inkscape:label="inactive"
+         id="g942"
+         style="display:inline;fill-rule:evenodd;stroke-width:0.47631353"
+         transform="translate(0,-19.076386)">
+        <path
+           sodipodi:nodetypes="sssssssss"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="path936-3"
+           d="m 67.025031,170 c -1,0 -3,-1 -3,-2 v -19 c 0,-1 2,-2 3,-2 H 92 c 2,0 4,1 4,2 v 19 c 0,1 -2,2 -4,2 z"
+           inkscape:connector-curvature="0" />
+        <text
+           x="69.789322"
+           y="156.71973"
+           id="text938-5"
+           style="font-weight:normal;font-size:8.66233635px;font-family:Arial;fill:#2b2828;stroke-width:0.36866823"
+           transform="scale(1.0007154,0.99928515)">Caps</text>
+        <text
+           x="69.789322"
+           y="166.5585"
+           id="text940"
+           style="font-weight:normal;font-size:8.66233635px;font-family:Arial;fill:#2b2828;stroke-width:0.36866823"
+           transform="scale(1.0007154,0.99928515)">Lock</text>
+      </g>
+      <g
+         transform="translate(0,-19.076386)"
+         style="fill-rule:evenodd;stroke-width:0.47631353"
+         id="g4429"
+         inkscape:label="active">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 67.025031,170 c -1,0 -3,-1 -3,-2 v -19 c 0,-1 2,-2 3,-2 H 92 c 2,0 4,1 4,2 v 19 c 0,1 -2,2 -4,2 z"
+           id="path199"
+           style="opacity:1;vector-effect:none;fill:#4f4c4d;fill-opacity:1;stroke:none;stroke-width:0.16824313;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           sodipodi:nodetypes="sssssssss" />
+        <text
+           transform="scale(1.0007154,0.99928515)"
+           style="font-weight:normal;font-size:8.66233635px;font-family:Arial;fill:#ffffff;stroke-width:0.36866823"
+           id="text647"
+           y="156.71973"
+           x="69.789322">Caps</text>
+        <text
+           transform="scale(1.0007154,0.99928515)"
+           style="font-weight:normal;font-size:8.66233635px;font-family:Arial;fill:#ffffff;stroke-width:0.36866823"
+           id="text651"
+           y="166.5585"
+           x="69.789322">Lock</text>
+      </g>
+    </g>
+    <rect
+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#fffff5;fill-opacity:1;fill-rule:nonzero;stroke:#202326;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       id="rect2130"
+       width="361.89996"
+       height="30.150299"
+       x="64.024956"
+       y="15.771065"
+       rx="3.8152773"
+       ry="3.8152773"
+       inkscape:label="Field" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:19.0763855px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.47690967px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="72.50132"
+       y="38.296417"
+       id="text1309"
+       inkscape:label="Value"><tspan
+         sodipodi:role="line"
+         id="tspan1307"
+         x="72.50132"
+         y="38.296417"
+         style="text-align:start;text-anchor:start;stroke-width:0.47690967px">text</tspan></text>
+    <g
+       id="g437"
+       inkscape:label="Shift">
+      <g
+         id="g421"
+         inkscape:label="inactive">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 379.96247,185.46181 c -1,0 -2,-1 -2,-3 v -17 c 0,-1 1,-3 2,-3 h 42.96244 c 2,0 3,2 3,3 v 17 c 0,2 -1,3 -3,3 z"
+           id="path910"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           sodipodi:nodetypes="sssssssss" />
+        <text
+           style="font-weight:normal;font-size:8.92098808px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text912"
+           y="177.90059"
+           x="392.55679"
+           transform="scale(1.0007154,0.99928513)">Shift</text>
+        <path
+           sodipodi:nodetypes="sssssssss"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="path856"
+           d="m 67.025031,185.46181 c -1,0 -3,-1 -3,-3 v -17 c 0,-1 2,-3 3,-3 H 104 c 1,0 2,2 2,3 v 17 c 0,2 -1,3 -2,3 z"
+           inkscape:connector-curvature="0" />
+        <text
+           x="75.85218"
+           y="177.90059"
+           id="text858"
+           style="font-weight:normal;font-size:8.92098808px;font-family:Arial;fill:#2b2828;fill-rule:evenodd;stroke-width:0.36866826"
+           transform="scale(1.0007154,0.99928513)">Shift</text>
+      </g>
+      <g
+         id="g413"
+         inkscape:label="active">
+        <path
+           sodipodi:nodetypes="sssssssss"
+           style="opacity:1;vector-effect:none;fill:#4f4c4d;fill-opacity:1;stroke:none;stroke-width:0.16824313;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="path551"
+           d="m 379.96247,185.46181 c -1,0 -2,-1 -2,-3 v -17 c 0,-1 1,-3 2,-3 h 42.96244 c 2,0 3,2 3,3 v 17 c 0,2 -1,3 -3,3 z"
+           inkscape:connector-curvature="0" />
+        <text
+           transform="scale(1.0007154,0.99928513)"
+           x="392.55679"
+           y="177.90059"
+           id="text629"
+           style="font-weight:normal;font-size:8.92098808px;font-family:Arial;fill:#ffffff;stroke-width:0.36866826">Shift</text>
+        <path
+           inkscape:connector-curvature="0"
+           d="m 67.025031,185.46181 c -1,0 -3,-1 -3,-3 v -17 c 0,-1 2,-3 3,-3 H 104 c 1,0 2,2 2,3 v 17 c 0,2 -1,3 -2,3 z"
+           id="path879"
+           style="opacity:1;vector-effect:none;fill:#4f4c4d;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.16824313;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           sodipodi:nodetypes="sssssssss" />
+        <text
+           transform="scale(1.0007154,0.99928513)"
+           style="font-weight:normal;font-size:8.92098808px;font-family:Arial;fill:#ffffff;fill-rule:evenodd;stroke-width:0.36866826"
+           id="text881"
+           y="177.90059"
+           x="75.85218">Shift</text>
+      </g>
+    </g>
+    <text
+       transform="scale(0.96824588,1.0327955)"
+       id="text471"
+       y="12.333657"
+       x="252.9579"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.31375408px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.30784383px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       inkscape:label="Info"><tspan
+         style="stroke-width:0.30784383px"
+         y="12.333657"
+         x="252.9579"
+         id="tspan469"
+         sodipodi:role="line">information</tspan></text>
+    <rect
+       style="opacity:0.18600003;fill:#de2cc9;fill-opacity:1;stroke:none;stroke-width:0.31677353"
+       id="rect4563"
+       width="381.45959"
+       height="14.110301"
+       x="54.211086"
+       y="1.2654642"
+       inkscape:label="position" />
+  </g>
+  <g
+     inkscape:label="HMI:Slider@/PUMP0/SLOTH"
+     transform="matrix(7.5590552,0,0,7.5590552,-248.554,584.0829)"
+     id="g110-0-9">
+    <g
+       inkscape:label="setpoint"
+       style="opacity:0.5;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.76565915"
+       inkscape:corner7="-0.15304809 : -0.15652183 : 0.051043755 : 1"
+       inkscape:corner0="-0.13109479 : -0.13697746 : 0 : 1"
+       inkscape:perspectiveID="#perspective258"
+       id="g256"
+       sodipodi:type="inkscape:box3d">
+      <path
+         style="fill:#353564;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+         points="69.054145,5.4029493 71.910946,3.7246414 71.910946,0.053890203 69.054145,1.5165601 "
+         d="M 69.054145,1.5165601 V 5.4029493 L 71.910946,3.7246414 V 0.0538902 Z"
+         inkscape:box3dsidetype="6"
+         id="path244"
+         sodipodi:type="inkscape:box3dside" />
+      <path
+         style="fill:#afafde;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+         points="72.352867,6.8282124 75.092002,5.0278603 71.910946,3.7246414 69.054145,5.4029493 "
+         d="M 69.054145,5.4029493 72.352867,6.8282124 75.092002,5.0278603 71.910946,3.7246414 Z"
+         inkscape:box3dsidetype="13"
+         id="path246"
+         sodipodi:type="inkscape:box3dside" />
+      <path
+         style="fill:#e9e9ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+         points="75.092002,1.2673703 75.092002,5.0278603 71.910946,3.7246414 71.910946,0.053890203 "
+         d="m 71.910946,0.0538902 3.181056,1.2134801 v 3.76049 L 71.910946,3.7246414 Z"
+         inkscape:box3dsidetype="11"
+         id="path248"
+         sodipodi:type="inkscape:box3dside" />
+      <path
+         style="fill:#4d4d9f;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+         points="72.352867,2.8410867 75.092002,1.2673703 71.910946,0.053890203 69.054145,1.5165601 "
+         d="M 69.054145,1.5165601 72.352867,2.8410867 75.092002,1.2673703 71.910946,0.0538902 Z"
+         inkscape:box3dsidetype="5"
+         id="path250"
+         sodipodi:type="inkscape:box3dside" />
+      <path
+         style="fill:#d7d7ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+         points="72.352867,6.8282124 75.092002,5.0278603 75.092002,1.2673703 72.352867,2.8410867 "
+         d="m 72.352867,2.8410867 v 3.9871257 l 2.739135,-1.8003521 v -3.76049 z"
+         inkscape:box3dsidetype="14"
+         id="path252"
+         sodipodi:type="inkscape:box3dside" />
+      <path
+         style="fill:#8686bf;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+         points="72.352867,2.8410867 72.352867,6.8282124 69.054145,5.4029493 69.054145,1.5165601 "
+         d="m 69.054145,1.5165601 3.298722,1.3245266 V 6.8282124 L 69.054145,5.4029493 Z"
+         inkscape:box3dsidetype="3"
+         id="path254"
+         sodipodi:type="inkscape:box3dside" />
+    </g>
+    <path
+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ff0000;stroke-width:0.52375954;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="m 71.94894,3.6581855 79.3256,0.040092"
+       id="path90-9-3"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc"
+       inkscape:label="range" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:5.29166651px;line-height:125%;font-family:sans-serif;text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#ff6600;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="68.771873"
+       y="5.501111"
+       id="text96-6-0"
+       inkscape:label="min"><tspan
+         sodipodi:role="line"
+         id="tspan94-0-62"
+         x="68.771873"
+         y="5.501111"
+         style="text-align:end;text-anchor:end;fill:#ff6600;stroke-width:0.26458332px">0</tspan></text>
+    <text
+       id="text100-6-6"
+       y="5.501111"
+       x="159.67337"
+       style="font-style:normal;font-weight:normal;font-size:5.29166651px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ff6600;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       inkscape:label="max"><tspan
+         style="text-align:center;text-anchor:middle;fill:#ff6600;stroke-width:0.26458332px"
+         y="5.501111"
+         x="159.67337"
+         sodipodi:role="line"
+         id="tspan1409-1">100</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:7.78479624px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ff6600;fill-opacity:1;stroke:none;stroke-width:0.19461991px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="-115.32294"
+       y="-9.0188799"
+       id="text104-6-8"
+       inkscape:label="value"
+       transform="scale(-1)"><tspan
+         sodipodi:role="line"
+         x="-115.32294"
+         y="-9.0188799"
+         style="text-align:center;text-anchor:middle;fill:#ff6600;stroke-width:0.19461991px"
+         id="tspan102-1-7">000</tspan></text>
+    <g
+       sodipodi:type="inkscape:box3d"
+       id="g930"
+       inkscape:perspectiveID="#perspective503"
+       inkscape:corner0="-0.13109479 : -0.13697746 : 0 : 1"
+       inkscape:corner7="-0.15304809 : -0.15652183 : 0.051043755 : 1"
+       style="fill:#ff0000;fill-opacity:1;stroke:none"
+       inkscape:label="handle"
+       transform="translate(0.01,0.01)">
+      <path
+         sodipodi:type="inkscape:box3dside"
+         id="path932"
+         inkscape:box3dsidetype="6"
+         d="M 69.751604,1.9575481 V 4.9331975 L 71.93894,3.6481857 V 0.8376415 Z"
+         points="69.751604,4.9331975 71.93894,3.6481857 71.93894,0.8376415 69.751604,1.9575481 "
+         style="fill:#353564;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
+      <path
+         sodipodi:type="inkscape:box3dside"
+         id="path940"
+         inkscape:box3dsidetype="13"
+         d="M 69.751604,4.9331975 72.2773,6.0244633 74.374544,4.6460073 71.93894,3.6481857 Z"
+         points="72.2773,6.0244633 74.374544,4.6460073 71.93894,3.6481857 69.751604,4.9331975 "
+         style="fill:#afafde;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
+      <path
+         sodipodi:type="inkscape:box3dside"
+         id="path942"
+         inkscape:box3dsidetype="11"
+         d="m 71.93894,0.8376415 2.435604,0.9291122 V 4.6460073 L 71.93894,3.6481857 Z"
+         points="74.374544,1.7667537 74.374544,4.6460073 71.93894,3.6481857 71.93894,0.8376415 "
+         style="fill:#e9e9ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
+      <path
+         sodipodi:type="inkscape:box3dside"
+         id="path934"
+         inkscape:box3dsidetype="5"
+         d="M 69.751604,1.9575481 72.2773,2.971684 74.374544,1.7667537 71.93894,0.8376415 Z"
+         points="72.2773,2.971684 74.374544,1.7667537 71.93894,0.8376415 69.751604,1.9575481 "
+         style="fill:#4d4d9f;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
+      <path
+         sodipodi:type="inkscape:box3dside"
+         id="path938"
+         inkscape:box3dsidetype="14"
+         d="m 72.2773,2.971684 v 3.0527793 l 2.097244,-1.378456 V 1.7667537 Z"
+         points="72.2773,6.0244633 74.374544,4.6460073 74.374544,1.7667537 72.2773,2.971684 "
+         style="fill:#d7d7ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
+      <path
+         sodipodi:type="inkscape:box3dside"
+         id="path936"
+         inkscape:box3dsidetype="3"
+         d="M 69.751604,1.9575481 72.2773,2.971684 V 6.0244633 L 69.751604,4.9331975 Z"
+         points="72.2773,2.971684 72.2773,6.0244633 69.751604,4.9331975 69.751604,1.9575481 "
+         style="fill:#8686bf;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
+    </g>
+  </g>
+  <g
+     id="g1292-3"
+     inkscape:label="HMI:Input@/RADIOSTATE"
+     transform="matrix(0.94144976,0,0,1.7212489,176.35468,-2117.077)">
+    <g
+       id="g2530"
+       inkscape:label="=3">
+      <rect
+         style="display:inline;fill:#0009ff;fill-opacity:1;stroke:none;stroke-width:0.24259248"
+         id="rect1273-6-3"
+         width="57.391823"
+         height="24.148804"
+         x="230.03636"
+         y="1238.2637"
+         inkscape:label="3" />
+      <g
+         transform="translate(-213.152,55.750293)"
+         id="g2520-5"
+         inkscape:label="HMI:Switch@/RADIOSTATE"
+         style="fill:#0009ff;fill-opacity:1">
+        <rect
+           inkscape:label="3"
+           y="1206.6622"
+           x="443.18835"
+           height="24.148754"
+           width="57.39183"
+           id="rect1273-6-9-9-9"
+           style="display:inline;fill:#0009ff;fill-opacity:1;stroke:none;stroke-width:0.24259226" />
+      </g>
+    </g>
+    <g
+       id="g2527"
+       inkscape:label="=2">
+      <rect
+         style="display:inline;fill:#00ffed;fill-opacity:1;stroke:none;stroke-width:0.24259254"
+         id="rect1273-6-56"
+         width="57.391857"
+         height="24.148804"
+         x="313.84549"
+         y="1238.2637"
+         inkscape:label="2" />
+      <g
+         transform="translate(-303.62283,32.70105)"
+         id="g2520-2"
+         inkscape:label="HMI:Switch@/RADIOSTATE">
+        <rect
+           inkscape:label="2"
+           y="1229.7114"
+           x="617.46832"
+           height="24.148754"
+           width="57.39183"
+           id="rect1273-6-9-9-0"
+           style="display:inline;fill:#00ffed;fill-opacity:1;stroke:none;stroke-width:0.24259226" />
+      </g>
+    </g>
+    <g
+       id="g2524"
+       inkscape:label="=1">
+      <rect
+         style="display:inline;fill:#3eff00;fill-opacity:1;stroke:none;stroke-width:0.24182089"
+         id="rect1273-6-2"
+         width="57.027344"
+         height="24.148796"
+         x="146.22725"
+         y="1238.2637"
+         inkscape:label="1" />
+      <g
+         transform="translate(-213.152,55.750293)"
+         id="g2520-23"
+         inkscape:label="HMI:Switch@/RADIOSTATE">
+        <rect
+           inkscape:label="1"
+           y="1206.6622"
+           x="359.37924"
+           height="24.148754"
+           width="57.39183"
+           id="rect1273-6-9-9-7"
+           style="display:inline;fill:#3eff00;fill-opacity:1;stroke:none;stroke-width:0.24259226" />
+      </g>
+    </g>
+    <g
+       id="g2501"
+       inkscape:label="=0"
+       transform="translate(-260.62575)">
+      <rect
+         inkscape:label="0"
+         y="1238.2637"
+         x="323.04385"
+         height="24.148754"
+         width="57.39183"
+         id="rect1273-6-9"
+         style="display:inline;fill:#ffea00;fill-opacity:1;stroke:none;stroke-width:0.24259225" />
+      <g
+         id="g2520"
+         inkscape:label="HMI:Switch@/RADIOSTATE">
+        <rect
+           inkscape:label="0"
+           y="1262.4125"
+           x="323.04385"
+           height="24.148754"
+           width="57.39183"
+           id="rect1273-6-9-9"
+           style="display:inline;fill:#ffea00;fill-opacity:1;stroke:none;stroke-width:0.24259226" />
+      </g>
+    </g>
+  </g>
+  <g
+     id="g1047"
+     inkscape:label="HMI:CircularBar@/PUMP0/SLOTH"
+     transform="matrix(0.39840034,0,0,0.35920948,224.04409,96.134885)">
+    <path
+       inkscape:label="range"
+       sodipodi:open="true"
+       d="M 1079.626,411.60913 A 184.25998,167.44942 0 0 1 874.51345,308.78336 184.25998,167.44942 0 0 1 946.20137,106.11681 184.25998,167.44942 0 0 1 1178.8257,131.16507"
+       sodipodi:end="5.5191826"
+       sodipodi:start="1.3860423"
+       sodipodi:ry="167.44942"
+       sodipodi:rx="184.25998"
+       sodipodi:cy="247.00946"
+       sodipodi:cx="1045.7766"
+       sodipodi:type="arc"
+       id="path1044"
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#fe00dc;stroke-width:22.07197189;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:90.1384964px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff00ca;fill-opacity:1;stroke:none;stroke-width:2.25346255px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1046.8701"
+       y="258.16129"
+       id="text1051"
+       transform="scale(0.91814752,1.0891496)"
+       inkscape:label="value"><tspan
+         sodipodi:role="line"
+         id="tspan1049"
+         x="1046.8701"
+         y="258.16129"
+         style="fill:#ff00ca;fill-opacity:1;stroke:none;stroke-width:2.25346255px;stroke-opacity:1">000</tspan></text>
+    <path
+       inkscape:label="path"
+       sodipodi:open="true"
+       d="M 1083.68,410.87778 A 184.25998,167.44942 0 0 1 875.42544,310.83196 184.25998,167.44942 0 0 1 945.58759,106.47662 184.25998,167.44942 0 0 1 1179.4956,131.8038"
+       sodipodi:end="5.524452"
+       sodipodi:start="1.3636114"
+       sodipodi:ry="167.44942"
+       sodipodi:rx="184.25998"
+       sodipodi:cy="247.00946"
+       sodipodi:cx="1045.7766"
+       sodipodi:type="arc"
+       id="path1044-3"
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#00fff1;stroke-width:40;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  </g>
+  <g
+     id="g1047-6"
+     inkscape:label="HMI:CircularSlider@/PUMP0/SLOTH"
+     transform="matrix(0.45707797,0,0,0.45707797,330.74411,340.99474)">
+    <path
+       inkscape:label="range"
+       d="M 970.29569,399.76446 A 184.25998,167.44942 0 0 1 866.26395,284.77467 184.25998,167.44942 0 0 1 904.10823,139.93753"
+       sodipodi:end="3.8353474"
+       sodipodi:start="1.9928597"
+       sodipodi:ry="167.44942"
+       sodipodi:rx="184.25998"
+       sodipodi:cy="247.00946"
+       sodipodi:cx="1045.7766"
+       sodipodi:type="arc"
+       id="path1044-7"
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#fe00dc;stroke-width:22.07197189;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       sodipodi:open="true" />
+    <g
+       sodipodi:type="inkscape:box3d"
+       id="g930-2"
+       inkscape:perspectiveID="#perspective503-6"
+       inkscape:corner0="-0.086129988 : -0.14445971 : 0 : 1"
+       inkscape:corner7="-0.10808329 : -0.16400408 : 0.051043755 : 1"
+       style="fill:#ff0000;fill-opacity:1;stroke:none"
+       inkscape:label="handle"
+       inkscape:transform-center-x="8"
+       inkscape:transform-center-y="98">
+      <path
+         sodipodi:type="inkscape:box3dside"
+         id="path932-9"
+         inkscape:box3dsidetype="6"
+         d="m 919.8592,371.09874 v 61.75093 l 51.05152,-25.59855 V 348.7668 Z"
+         points="919.8592,432.84967 970.91072,407.25112 970.91072,348.7668 919.8592,371.09874 "
+         style="fill:#353564;fill-rule:evenodd;stroke:none;stroke-width:21.82598114px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
+      <path
+         sodipodi:type="inkscape:box3dside"
+         id="path940-1"
+         inkscape:box3dsidetype="13"
+         d="m 919.8592,432.84967 49.77111,22.08625 49.54589,-27.39008 -48.26548,-20.29472 z"
+         points="969.63031,454.93592 1019.1762,427.54584 970.91072,407.25112 919.8592,432.84967 "
+         style="fill:#afafde;fill-rule:evenodd;stroke:none;stroke-width:21.82598114px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
+      <path
+         sodipodi:type="inkscape:box3dside"
+         id="path942-2"
+         inkscape:box3dsidetype="11"
+         d="m 970.91072,348.7668 48.26548,18.93314 v 59.8459 l -48.26548,-20.29472 z"
+         points="1019.1762,367.69994 1019.1762,427.54584 970.91072,407.25112 970.91072,348.7668 "
+         style="fill:#e9e9ff;fill-rule:evenodd;stroke:none;stroke-width:21.82598114px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
+      <path
+         sodipodi:type="inkscape:box3dside"
+         id="path934-7"
+         inkscape:box3dsidetype="5"
+         d="m 919.8592,371.09874 49.77111,20.56633 49.54589,-23.96513 -48.26548,-18.93314 z"
+         points="969.63031,391.66507 1019.1762,367.69994 970.91072,348.7668 919.8592,371.09874 "
+         style="fill:#4d4d9f;fill-rule:evenodd;stroke:none;stroke-width:21.82598114px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
+      <path
+         sodipodi:type="inkscape:box3dside"
+         id="path938-0"
+         inkscape:box3dsidetype="14"
+         d="m 969.63031,391.66507 v 63.27085 l 49.54589,-27.39008 v -59.8459 z"
+         points="969.63031,454.93592 1019.1762,427.54584 1019.1762,367.69994 969.63031,391.66507 "
+         style="fill:#d7d7ff;fill-rule:evenodd;stroke:none;stroke-width:21.82598114px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
+      <path
+         sodipodi:type="inkscape:box3dside"
+         id="path936-9"
+         inkscape:box3dsidetype="3"
+         d="m 919.8592,371.09874 49.77111,20.56633 v 63.27085 L 919.8592,432.84967 Z"
+         points="969.63031,391.66507 969.63031,454.93592 919.8592,432.84967 919.8592,371.09874 "
+         style="fill:#8686bf;fill-rule:evenodd;stroke:none;stroke-width:21.82598114px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:90.1384964px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff00ca;fill-opacity:1;stroke:none;stroke-width:2.25346255px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1046.8701"
+       y="258.16129"
+       id="text1051-5"
+       transform="scale(0.91814752,1.0891496)"
+       inkscape:label="value"><tspan
+         sodipodi:role="line"
+         id="tspan1049-3"
+         x="1046.8701"
+         y="258.16129"
+         style="fill:#ff00ca;fill-opacity:1;stroke:none;stroke-width:2.25346255px;stroke-opacity:1">000</tspan></text>
+  </g>
+</svg>