Heat Network Designer

From Heatweb Wiki
Jump to: navigation, search

Introduction

The Heat Network Designer is a piece of JavaScript software that runs in a browser, that asks questions, performs calculations and provides outputs including charts, graphs and PDFs.

The Designer is delivered from Node-RED running on our servers, with the various versions provided below. These can be pasted into any instance of Node-RED.

The software can saved from a browser as an html file, and edited.

The questions and calculations are driven by a JSON file fetched by the Designer page, in this instance from our servers, but the source can be changed - to a local file for example.

The design of the Designer is driven by the goal to perform all possible calculatoins that are required to fully design a heat network to latest standards, and to methods known to work from recorded data in the field.

The 'Heat Network' and the 'Designer' functions are seperate. The Designer is also used to drive literature, instructions, and for any form of PDF generation based on a set of questions and rules.

Questions (inputs) are driven by logic, depending on previous answers. The logis is detailed in the JSON file and is also JavaScript allowing both simple and detailed logic.

Mustache markup is used in logic. This is where values are referenced by double curly brackets, e.g.

{{peakLoad}}


See the sample JSON file below for examples of where and how mustache markup is used, both in logic and in notes shown on screen.

Outputs are also called depending on logic. They are other web pages that are called with the answers to all questions, and provide screen output as well as set values in the parent Designer page that are later used to generate PDF files. In this way, output pages generate the material used in PDF creation.

Outputs can also be pages drawn from a Wiki page or a Wordpress website, allowing PDFs to be generated by material saved on the company website or technical website.

Heat Networks

We have loaded our server with two years of weather data for various degree days, as well as other useful data for calculations. One of the output screen driven by our server is a two year daily load analysis. This uses this data to calculate loads based on degree days at various base temperatures.

Our servers also have access to historic (and current) anonomised HIU data from a number of years. This is typically very high resolution down to second intervals on many values, and provides another data set to compare design loads to real world loads.

Unlike other sizing methodologies that size purely to peaks, then rounding up (decrete boiler, pump, buffer, & pipe sizes) and then adding redundency, the Designer sizes to peaks initially, but then rationalises the oversizing caused by descrete sizing to arrive at a final sizing that meets peak loads (with redundency) and no more.

Link to Online Heat Network Designer

If asked to login use guest/guest as username and password.

Libraries

The following require installatoin on server or externally referencing.

Libraries used can be found below. These should be in same directory as the hndesign package, or html page if saved locally.


Features

  • JSON driven
  • Various types of questions can be asked, providing a range of options (text, selection, spreadsheets)
  • Question selection based on logic
  • Custom logic is JavaScript driven
  • Performs custom calculations
  • Calculation results can be used in further calculations, as question defaults, or in any logic
  • Custom outputs based on seperate pages passed design data
  • Outputs can add data into design
  • PDF output
  • SVG manipulation to create detailed drawings
  • SVG output elements can be selected based on logic and can then add to design data
  • Input values and calculations can be nested objects, including other designs

To Do

Question Data (v1)

{
    "title": "My Form",
    "sections": [
        {
            "title": "General",
            "questions": [
                {
                    "title": "Number of buildings",
                    "question": "How many buildings are fed from the network?",
                    "id": "nBuildings",
                    "if": "true",
                    "required": true,
                    "type": "integer",
                    "notes": "The total number of buildings connected to the heat network. See https://hw7.ddns.net/ui/svgexplode?svg=HeatNetwork6.svg&display=g16444,g11206,bulkhm,g14636,landlordload,g16320,g5006,bufferstore,lowgrade,heatpump2,heatpump2-2,qton1,fbyp,hiu,g68266,singlemainpump,backupmainpump,g130841-3,g14610-0,g14636-2,g14610,finestrainer,cwsvcs,g14124,g14362.",
                    "units": "buildings"
                },
                {
                    "title": "Number of properties",
                    "question": "How many properties are there?",
                    "id": "nProperties",
                    "if": "true",
                    "required": true,
                    "type": "integer",
                    "notes": "The total number of properties connected to the heat network.",
                    "units": "properties"
                },
                {
                    "title": "Total number of people",
                    "question": "How many people are there in total?",
                    "id": "nPeople",
                    "if": "true",
                    "required": false,
                    "type": "integer",
                    "units": "people"
                },
                {
                    "title": "DHW network return temperature",
                    "question": "What is the network return temperature for DHW?",
                    "notes": "The temperature fed back from a property to the network when running peak load domestic hot water.",
                    "id": "tPriRtnDHW",
                    "if": "true",
                    "required": false,
                    "default": 19,
                    "type": "number",
                    "units": "°C"
                },
                {
                    "title": "Central heating output per property",
                    "question": "What is the central heating output per property?",
                    "id": "kwCHPP",
                    "if": "true",
                    "required": false,
                    "type": "number",
                    "units": "kW"
                },
                {
                    "title": "Central heating network return temperature",
                    "question": "What is the network return temperature for central heating?",
                    "notes": "The temperature fed back from a property to the network when running peak load central heating.",
                    "id": "tPriRtnCH",
                    "if": "{{kwCHPP}}",
                    "required": false,
                    "default": 45,
                    "type": "number",
                    "units": "°C"
                },
                {
                    "title": "Central heating diversity",
                    "question": "What diversity is applied to central heating output?",
                    "id": "divCH",
                    "if": "{{kwCHPP}}",
                    "required": false,
                    "default": 70,
                    "type": "number",
                    "units": "%"
                },
                {
                    "title": "Peak network flow temperature",
                    "question": "What is the peak network flow temperature?",
                    "id": "tPeak",
                    "if": "true",
                    "required": true,
                    "default": 80,
                    "type": "number",
                    "units": "°C"
                }
            ]
        }
    ],
    "calculations": [
        {
            "id": "pPP",
            "title": "Average people per property",
            "if": "nPeople, nProperties",
            "function": "{{nPeople}} / {{nProperties}}",
            "units": "people"
        },
        {
            "id": "kwDHWEst",
            "title": "Typical HIU rating for DHW",
            "if": "{{pPP}}",
            "function": "{{pPP}}<3?37.5:({{pPP}}<5?45:60)",
            "units": "kW"
        },
        {
            "id": "peepDS439",
            "title": "People per standard DS439 property",
            "if": "true",
            "function": "2.3",
            "units": "people"
        },
        {
            "id": "eqPropDS439",
            "title": "Equivalent number of DS439 properties",
            "if": "{{peepDS439}}",
            "function": "{{nPeople}}/{{peepDS439}}",
            "units": "properties"
        },
        {
            "id": "kwDS439",
            "title": "Peak DHW Load (DS439)",
            "if": "{{eqPropDS439}}",
            "function": "Math.ceil((1.19* {{eqPropDS439}}) + (18.8* Math.pow({{eqPropDS439}},0.5)) + 17.6)",
            "units": "kW"
        },
        {
            "id": "vPPEST",
            "title": "Volume DHW used per property per day",
            "if": "true",
            "function": "40",
            "units": "litres"
        },
        {
            "id": "vPHEST",
            "title": "Volume DHW used per person per day",
            "if": "true",
            "function": "28",
            "units": "litres"
        },
        {
            "id": "tRiseEST",
            "title": "Average temperature Rise on DHW",
            "if": "true",
            "function": "35",
            "units": "°C"
        },
        {
            "id": "vDHWEST",
            "title": "Volume used per day for DHW",
            "if": "true",
            "function": "({{nProperties}}*{{vPPEST}})+({{nPeople}}*{{vPHEST}})",
            "units": "litres"
        },
        {
            "id": "kwhDHWEST",
            "title": "Energy used per day for DHW",
            "if": "true",
            "function": "({{vDHWEST}} * 4.2 * {{tRiseEST}}) / 3600",
            "units": "kWh"
        },
        {
            "id": "kwCH",
            "title": "Peak central heating load",
            "if": "true",
            "function": "({{kwCHPP}} * {{divCH}} * {{nProperties}}) / 100",
            "units": "kW"
        },
        {
            "id": "kwPeak",
            "title": "Peak load",
            "if": "true",
            "function": "{{kwCH}}+{{kwDS439}}",
            "units": "kW"
        },
        {
            "id": "kwPeak24",
            "title": "Average 24h peak load",
            "if": "true",
            "function": "{{kwCH}}+({{kwhDHWEST}}/24)",
            "units": "kW"
        },
        {
            "id": "m3hDHWPeak",
            "title": "Primary flow rate at peak DHW load",
            "if": "true",
            "function": "3.6 * {{kwDS439}} / (4.2 * ({{tPeak}}-{{tPriRtnDHW}}))",
            "units": "m3/h"
        },
        {
            "id": "m3hCHPeak",
            "title": "Primary flow rate at peak central heating load",
            "if": "true",
            "function": "3.6 * {{kwCH}} / (4.2 * ({{tPeak}}-{{tPriRtnCH}}))",
            "units": "m3/h"
        },
        {
            "id": "m3hPeak",
            "title": "Primary flow rate at peak load",
            "if": "true",
            "function": "{{m3hDHWPeak}}+{{m3hCHPeak}}",
            "units": "m3/h"
        },
        {
            "id": "tPriRtnPeak",
            "title": "Primary return temperature at peak load",
            "if": "true",
            "function": "{{tPeak}} - ({{kwPeak}} / (4.2 * {{m3hPeak}} / 3.6))",
            "units": "°C"
        }
    ]
}

Node-RED Flow

v7

  • PDF output
  • Fetch pages from Wiki site
  • Fetch pages from Wordpress site
  • HTML parsing to PDF
  • Image parsing to PDF
  • Tables (array of arrays)
  • STABLE RELEASE
[{"id":"cce2bfaa.e5748","type":"tab","label":"Flow 4","disabled":false,"info":""},{"id":"6011c636.5e4798","type":"comment","z":"cce2bfaa.e5748","name":"","info":"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\nconsole.log(looseJsonParse(\n   \"{a:(4-1), b:function(){}, c:new Date()}\"\n))","x":220,"y":80,"wires":[]},{"id":"6b0cef90.9473f","type":"change","z":"cce2bfaa.e5748","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"title\":\"My Form\",\"sections\":[{\"title\":\"General\",\"questions\":[{\"title\":\"Number of properties\",\"question\":\"How many properties are there?\",\"id\":\"nProperties\",\"if\":\"true\",\"required\":true,\"type\":\"integer\",\"notes\":\"The total number of properties connected to the heat network.\",\"units\":\"properties\"},{\"title\":\"Number of buildings\",\"question\":\"How many buildings are there?\",\"id\":\"nBuildings\",\"if\":\"true\",\"required\":true,\"type\":\"integer\",\"notes\":\"The total number of buildings connected to the heat network. See https://hw7.ddns.net/ui/svgexplode?svg=HeatNetwork6.svg&display=g16444,g11206,bulkhm,g14636,landlordload,g16320,g5006,bufferstore,lowgrade,heatpump2,heatpump2-2,qton1,fbyp,hiu,g68266,singlemainpump,backupmainpump,g130841-3,g14610-0,g14636-2,g14610,finestrainer,cwsvcs,g14124,g14362.\",\"units\":\"buildings\"},{\"title\":\"Total number of people\",\"question\":\"How many people are there in total?\",\"id\":\"nPeople\",\"if\":\"true\",\"required\":false,\"type\":\"integer\",\"units\":\"people\"},{\"title\":\"Central heating output per property\",\"question\":\"What is the central heating output per property?\",\"id\":\"kwCHPP\",\"if\":\"true\",\"required\":false,\"type\":\"number\",\"units\":\"kW\"},{\"title\":\"Central heating diversity\",\"question\":\"What diversity is applied to central heating output?\",\"id\":\"divCH\",\"if\":\"{{kwCHPP}}\",\"required\":false,\"default\":70,\"type\":\"number\",\"units\":\"%\"}]}],\"calculations\":[{\"id\":\"pPP\",\"title\":\"Average people per property\",\"if\":\"nPeople, nProperties\",\"function\":\"{{nPeople}} / {{nProperties}}\",\"units\":\"people\"},{\"id\":\"kwDHWEst\",\"title\":\"Typical HIU rating for DHW\",\"if\":\"{{pPP}}\",\"function\":\"{{pPP}}<3?37.5:({{pPP}}<5?45:60)\",\"units\":\"kW\"},{\"id\":\"peepDS439\",\"title\":\"People per standard DS439 property\",\"if\":\"true\",\"function\":\"2.3\",\"units\":\"people\"},{\"id\":\"eqPropDS439\",\"title\":\"Equivalent number of DS439 properties\",\"if\":\"{{peepDS439}}\",\"function\":\"{{nPeople}}/{{peepDS439}}\",\"units\":\"properties\"},{\"id\":\"kwDS439\",\"title\":\"Peak DHW Load (DS439)\",\"if\":\"{{eqPropDS439}}\",\"function\":\"Math.ceil((1.19* {{eqPropDS439}}) + (18.8* Math.pow({{eqPropDS439}},0.5)) + 17.6)\",\"units\":\"kW\"},{\"id\":\"vPPEST\",\"title\":\"Volume DHW used per property per day\",\"if\":\"true\",\"function\":\"40\",\"units\":\"litres\"},{\"id\":\"vPHEST\",\"title\":\"Volume DHW used per person per day\",\"if\":\"true\",\"function\":\"28\",\"units\":\"litres\"},{\"id\":\"tRiseEST\",\"title\":\"Average temperature Rise on DHW\",\"if\":\"true\",\"function\":\"35\",\"units\":\"°C\"},{\"id\":\"vDHWEST\",\"title\":\"Volume used per day for DHW\",\"if\":\"true\",\"function\":\"({{nProperties}}*{{vPPEST}})+({{nPeople}}*{{vPHEST}})\",\"units\":\"litres\"},{\"id\":\"kwhDHWEST\",\"title\":\"Energy used per day for DHW\",\"if\":\"true\",\"function\":\"({{vDHWEST}} * 4.2 * {{tRiseEST}}) / 3600\",\"units\":\"kWh\"},{\"id\":\"kwCH\",\"title\":\"Peak central heating load\",\"if\":\"true\",\"function\":\"({{kwCHPP}} * {{divCH}} * {{nProperties}}) / 100\",\"units\":\"kW\"},{\"id\":\"kwPeak\",\"title\":\"Peak load\",\"if\":\"true\",\"function\":\"{{kwCH}}+{{kwDS439}}\",\"units\":\"kW\"},{\"id\":\"kwPeak\",\"title\":\"Average 24h peak load\",\"if\":\"true\",\"function\":\"{{kwCH}}+({{kwhDHWEST}}/24)\",\"units\":\"kW\"}]}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":1680,"y":420,"wires":[[]]},{"id":"45cdd69e.5c2788","type":"template","z":"cce2bfaa.e5748","name":"Heat Network Designer","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js\"></script>\n{{!--https://www.sitepoint.com/basic-jquery-form-validation-tutorial/--}}\n\n<script src=\"https://unpkg.com/mustache@latest\"></script>\n\n<style>\n\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 6px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\nvar a = new Date();\nvar qdata;\nvar calculated = {};\nvar hasFocus;\nvar inputsOut;\nvar inputString;\n\n\t$(document).ready(function(e) {\n    \n        // $(\"form[ajax=true]\").submit(function(e) {\n            \n        //     //alert(\"submit\");\n            \n        //     e.preventDefault();\n        \n             \n            //var urlParams = new URLSearchParams(window.location.search);\n            //if (urlParams.get('display')) { loadstring = \",,\" + urlParams.get('display'); }\n\n            var urlParams = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParams) {\n                \n                calculated[urlParams[upa].split(\"=\")[0]] = urlParams[upa].split(\"=\")[1];\n                \n            }\n            \n            var form_data = {};\n            var form_url = \"/ui/qdata\";\n            var form_target = $(this).attr(\"target\") || \"result\";\n            var ftarget = \"#\" + form_target;\n            var form_method = \"GET\";\n            \n        //     $(\"#loadingimg\").show();\n            \n            $.ajax({\n                url: form_url, \n                type: form_method,      \n                data: form_data,     \n                cache: false,\n                success: function(results){   \n                    \n                    qdata = results;\n                    //qdata = JSON.parse(returnhtml);\n                    console.log(qdata);\n                   \n                    \n                    document.getElementById(\"formName\").innerHTML = qdata.title || \"Unamed Form\"; //JSON.stringify(qdata) ;\n                    \n                    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n                    \n                    validform();\n                                  \n                }           \n            });    \n            \n        // });\n        \n      \n        \n    });\n\t\nfunction parseQuestions(qdata) {\n    \n    console.log(qdata);\n    console.log(calculated);\n    \n    inputsOut = '<table class=\"table\">';\n    \n    inputString = \"\";\n    \n    var oot = \"\";\n    for (var s in qdata[\"sections\"]) {\n        console.log(s);\n        console.log(qdata.sections[s]);\n        oot += \"<div class='section'><h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        \n        hasFocus = null;\n        \n        for (var q in qdata.sections[s].questions) {\n            \n            \n            var qif = qdata.sections[s].questions[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n            var v=\"\";\n            if (calculated[qdata.sections[s].questions[q].id]) { v= calculated[qdata.sections[s].questions[q].id] ; }\n            //else if (qdata.sections[s].questions[q].default) { v= qdata.sections[s].questions[q].default ; }\n            \n            if(goq) {\n            \n                if (v!==\"\") { \n                    inputsOut += \"<tr>\";  \n                    inputsOut += \"<td>\" + (qdata.sections[s].questions[q].title||qdata.sections[s].questions[q].id) + \"</td>\";\n                    inputsOut +=  '<td align=\"right\">' + v + \"</td>\";\n                    inputsOut +=  '<td width=\"20%\">' + (qdata.sections[s].questions[q].units||\"\") + \"</td></tr>\\n\";\n                    \n                    inputString += (inputString!==\"\"?\"&\":\"\") + qdata.sections[s].questions[q].id + \"=\" + v;\n                }\n            \n            \n                if (hasFocus && document.getElementById(\"oneQ\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">'; }\n            \n                else if (v!==\"\") { \n                    \n                    if (document.getElementById(\"hideDone\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">';   }\n                    else {  oot += '<div class=\"question\" style=\"background-color: #d2efd2;\">';  }\n                    \n                } else { oot += '<div class=\"question\">'; if (!hasFocus) { hasFocus = qdata.sections[s].questions[q].id; } }\n                \n                //oot += \"<div class='qtext'>\" + qdata.sections[s].questions[q].title + '</div>';\n                oot += '<label for=\"' + qdata.sections[s].questions[q].id + '\" class=\"qtext\">' + (qdata.sections[s].questions[q].question||qdata.sections[s].questions[q].title) + '</label>';\n                \n                if (qdata.sections[s].questions[q].notes) { oot += '<div class=\"notes\">'  + convertLinks(qdata.sections[s].questions[q].notes) + '</div>'; }\n                oot += '<table width=\"100%\"><tr><td width=\"80%\"><input id=\"' + qdata.sections[s].questions[q].id + '\" name=\"' + qdata.sections[s].questions[q].id + '\" class=\"form-control\" type=\"text\"';\n                \n                if (v!==\"\") { oot += ' value=\"' + v + '\"'; }\n                // if (calculated[qdata.sections[s].questions[q].id]) { oot += ' value=\"' + calculated[qdata.sections[s].questions[q].id] + '\"'; }\n                // else if (qdata.sections[s].questions[q].default) { oot += ' value=\"' + qdata.sections[s].questions[q].default + '\"'; }\n                if (qdata.sections[s].questions[q].default) { oot += ' placeholder=\"' + qdata.sections[s].questions[q].default + \" \" + (qdata.sections[s].questions[q].units||\"\") + ' ... please confirm\"'; }\n                \n                oot += '></td><td valign=\"top\"><span class=\"qunits\">' + (qdata.sections[s].questions[q].units||\"\") + '</span></td></tr></table></div>\\n';\n            }\n        }\n    \n        oot += \"</div>\\n\";\n        \n    }\n    inputsOut +=  \"</table>\\n\";  \n    \n    return oot;\n}\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\n// console.log(looseJsonParse(\n//   \"{a:(4-1), b:function(){}, c:new Date()}\"\n// ))\n\nfunction runCalcs() {\n\n\n    \n    \n    // run through form inputs and store current values into calculated.\n    var cells =  document.getElementsByClassName(\"form-control\");\n\tvar i;\n\tfor (i = 0; i < cells.length; i++) {\n\t\n\t\tcalcsOut += cells[i].value + \"<br>\\n\";\n        \n        if (\"\" + cells[i].value !== \"\") { \n            \n            if (isNaN(cells[i].value)) { \n                \n                calculated[cells[i].id] = (cells[i].value);\n                \n            } else {\n                \n                calculated[cells[i].id] = parseFloat(cells[i].value);\n            }\n        }\n\t}\n    \n    var calcsOut = '<table class=\"table\">';\n    for (var calc in (qdata[\"calculations\"]||[])) {\n        \n        console.log(calc);\n        console.log(qdata.calculations[calc]);\n        var f = qdata.calculations[calc].function;\n        var ft = Mustache.render(f, calculated);\n        \n        calcsOut += \"<tr>\";  //<td>\" + qdata.calculations[calc].id + \"</td>\";\n        calcsOut += \"<td>\" + (qdata.calculations[calc].title||qdata.calculations[calc].id) + \"</td>\";\n        \n        //calcsOut += f + \" = \";\n        if (document.getElementById(\"hideMaths\").checked!==true) {\n            calcsOut += \"<td><small>\" + ft + \"</small></td>\";   //\"<br>\\n\";\n        }\n        \n        var cv = \"\";\n        try {\n          cv = looseJsonParse(ft); //  looseJsonParse(\"{a:(4-1), b:function(){}, c:new Date()}\");\n        }\n        catch(err) {\n          \n        }\n         \n        \n        if (!isNaN(cv)) { cv = parseInt(cv*1000)/1000; }\n        \n        calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n        \n        calcsOut +=  '<td width=\"20%\">' + (qdata.calculations[calc].units||\"\") + \"</td></tr>\\n\";\n        \n        calculated[qdata.calculations[calc].id] = cv;\n        \n    }\n    \n    calcsOut +=  \"</table>\\n\";\n    \n    // for (var calc in calculated) {\n        \n        \n    // }\n    \n    document.getElementById(\"calcs\").innerHTML = calcsOut; //JSON.stringify(qdata) ;\n    \n    // rebuild form\n    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"inputs\").innerHTML = inputsOut; //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"mylink\").innerHTML = '<a href=\"hndesign?' + inputString + '\" target=\"_blank\">'+ inputString + '</a>'; //JSON.stringify(qdata) ;\n    \n    \n    \n    validform();\n                    \n}\n\n\nconst convertLinks = ( input ) => {\n\n  let text = input;\n  const linksFound = text.match( /(?:www|https?)[^\\s]+/g );\n  const aLink = [];\n\n  if ( linksFound != null ) {\n\n    for ( let i=0; i<linksFound.length; i++ ) {\n      let replace = linksFound[i];\n      if ( !( linksFound[i].match( /(http(s?)):\\/\\// ) ) ) { replace = 'http://' + linksFound[i] }\n      let linkText = replace.split( '/' )[2];\n      if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) }\n      if ( linkText.match( /youtu/ ) ) {\n\n        let youtubeID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://www.youtube.com/embed/' + youtubeID + '\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe></div>' )\n      }\n      else if ( linkText.match( /vimeo/ ) ) {\n        let vimeoID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://player.vimeo.com/video/' + vimeoID + '\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' )\n      }\n      else {\n        aLink.push( '<a href=\"' + replace + '\" target=\"_blank\">' + linkText + '</a>' );\n      }\n      text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] );\n    }\n    return text;\n\n  }\n  else {\n    return input;\n  }\n}\n\nfunction validform() {\n    \n    if(hasFocus && document.getElementById(hasFocus)) {\n        document.getElementById(hasFocus).focus();\n    }\n    \n    \n    \n// Initialize form validation on the registration form.\n  // It has the name attribute \"registration\"\n  $(\"form[name='qform']\").validate({\n    // Specify validation rules\n    rules: {\n      // The key name on the left side is the name attribute\n      // of an input field. Validation rules are defined\n      // on the right side\n      nProperties: {\n        required: true,\n        digits: true,\n        min: 1\n      },\n      lastname: \"required\",\n      email: {\n        required: true,\n        // Specify that email should be validated\n        // by the built-in \"email\" rule\n        email: true\n      },\n      password: {\n        required: true,\n        minlength: 5\n      }\n    },\n    // Specify validation error messages\n    messages: {\n      nProperties: \"Please enter a number.\",\n      lastname: \"Please enter your lastname\",\n      password: {\n        required: \"Please provide a password\",\n        minlength: \"Your password must be at least 5 characters long\"\n      },\n      email: \"Please enter a valid email address\"\n    },\n    // Make sure the form is submitted to the destination defined\n    // in the \"action\" attribute of the form when valid\n    submitHandler: function(form) {\n      //form.submit();\n      runCalcs();\n      //alert(\"hello\");\n    }\n  });\n}\n\n</script>\n\n\n<div class='section'>\n    \n    <table width=\"100%\"><tr>\n    <td valign=\"top\" width=\"70%\">\n        <div id=\"formName\" class=\"h1\"></div>\n        <a href=\"https://heatweb.co.uk/w/index.php?title=Heat_Network_Designer\" target=\"_blank\"><small>Wiki Help Page</small></a>\n    </td>\n    <td width=\"30%\">\n        <input type=\"checkbox\" id=\"oneQ\" name=\"oneQ\" checked> <small>One question at a time</small><br>\n        <input type=\"checkbox\" id=\"hideDone\" name=\"hideDone\" checked> <small>Hide completed questions</small><br>\n        <input type=\"checkbox\" id=\"hideMaths\" name=\"hideMaths\" checked> <small>Hide maths equations</small>\n    </td>\n    </tr></table>\n</div>\n\n\n<form action=\"\" name=\"qform\" id=\"qform\">\n<div id=\"section1\"></div>\n\n<div class='section'>\n<button type=\"submit\">Submit</button>\n\n</div>\n\n\n<div class='section'>\n<p><b>Inputs</b></p>\n<div id=\"inputs\" class=\"notes\"></div>\n</div>\n\n<div class='section'>\n<p><b>Numeric Values and Calculations</b></p>\n<div id=\"calcs\" class=\"notes\"></div>\n</div>\n\n\n<div class='section'>\n<p><b>Link</b></p>\n<div id=\"mylink\" class=\"notes\"></div>\n</div>\n</form>","output":"str","x":1710,"y":380,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"60eab69c.f64738","type":"change","z":"cce2bfaa.e5748","name":"Heat Network Design","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"title\":\"Heat Network Designer\",\"links\":[{\"src\":\"https://hw7.ddns.net/ui/hncalc\",\"title\":\"Heat Network Calculator v2\"},{\"src\":\"https://hw7.ddns.net/ui/svgexplode?svg=HeatNetwork6.svg\",\"title\":\"Heat Network Schematic Designer (HeatNetwork6.svg)\"}],\"sections\":[{\"title\":\"General\",\"questions\":[{\"title\":\"Number of buildings\",\"question\":\"How many buildings are fed from the network?\",\"id\":\"nBuildings\",\"if\":\"true\",\"required\":true,\"type\":\"integer\",\"notes\":\"The total number of buildings connected to the heat network. See https://hw7.ddns.net/ui/svgexplode?svg=HeatNetwork6.svg&display=g16444,g11206,bulkhm,g14636,landlordload,g16320,g5006,bufferstore,lowgrade,heatpump2,heatpump2-2,qton1,fbyp,hiu,g68266,singlemainpump,backupmainpump,g130841-3,g14610-0,g14636-2,g14610,finestrainer,cwsvcs,g14124,g14362.\",\"units\":\"buildings\"},{\"title\":\"Number of properties\",\"question\":\"How many properties are there?\",\"id\":\"nProperties\",\"if\":\"true\",\"required\":true,\"type\":\"integer\",\"notes\":\"The total number of properties connected to the heat network.\",\"units\":\"properties\"},{\"title\":\"Total number of people\",\"question\":\"How many people are there in total?\",\"id\":\"nPeople\",\"if\":\"true\",\"required\":false,\"type\":\"integer\",\"units\":\"people\"},{\"title\":\"Peak network flow temperature\",\"question\":\"What is the peak network flow temperature?\",\"id\":\"tPeak\",\"if\":\"true\",\"required\":true,\"default\":80,\"type\":\"number\",\"units\":\"°C\"},{\"title\":\"DHW network return temperature\",\"question\":\"What is the network return temperature for DHW?\",\"notes\":\"The temperature fed back from a property to the network when running peak load domestic hot water.\",\"id\":\"tPriRtnDHW\",\"if\":\"true\",\"required\":false,\"default\":19,\"type\":\"number\",\"units\":\"°C\"},{\"title\":\"Central heating output per property\",\"question\":\"What is the central heating output per property?\",\"id\":\"kwCHPP\",\"if\":\"true\",\"required\":false,\"type\":\"number\",\"units\":\"kW\"},{\"title\":\"Central heating network return temperature\",\"question\":\"What is the network return temperature for central heating?\",\"notes\":\"The temperature fed back from a property to the network when running peak load central heating.\",\"id\":\"tPriRtnCH\",\"if\":\"{{kwCHPP}}\",\"required\":false,\"default\":45,\"type\":\"number\",\"units\":\"°C\"},{\"title\":\"Central heating diversity\",\"question\":\"What diversity is applied to central heating output?\",\"id\":\"divCH\",\"if\":\"{{kwCHPP}}\",\"required\":false,\"default\":70,\"type\":\"number\",\"units\":\"%\"}]},{\"title\":\"Heat Sources\",\"questions\":[{\"title\":\"Boilers\",\"question\":\"Are boilers to be used?\",\"id\":\"goBoilers\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\",\"options\":[true,false]},{\"title\":\"Air Source Heat Pumps\",\"question\":\"Are air source heat pumps to be used?\",\"notes\":\"Not including heat pumps in properties.\",\"id\":\"goASHP\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\",\"options\":[true,false]},{\"title\":\"Water Source Heat Pumps\",\"question\":\"Are water source heat pumps to be used?\",\"notes\":\"This is taking heat from an ambient loop or water source. Not including heat pumps in properties.\",\"id\":\"goWSHP\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\",\"options\":[true,false]},{\"title\":\"Cooling Source Heat Pumps\",\"question\":\"Are water source heat pumps to be used to reclaim cooling?\",\"notes\":\"This is where cooling circuits are driven by moving heat to the main storage.\",\"id\":\"goReclaim\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\",\"options\":[true,false]}]},{\"title\":\"Boilers\",\"questions\":[{\"title\":\"Available boiler outputs\",\"question\":\"What sizes of boiler output are available for selection?\",\"id\":\"listBSizes\",\"if\":\"true\",\"required\":true,\"type\":\"csv\",\"notes\":\"This is a comma-seperated list of outputs in kW. Selection will round up to the nearest available size.\",\"units\":\"kW\",\"value\":\"30,50,75,100,250,500,750,1000\"}]},{\"title\":\"Air Source Heat Pumps\",\"questions\":[{\"title\":\"ASHP refrigerant\",\"question\":\"What refrigerant is used in the heat pump?\",\"id\":\"fridgeASHP\",\"if\":\"{{goASHP}}\",\"required\":true,\"type\":\"select\",\"options\":[\"R744 (CO2)\"]},{\"title\":\"Available heat pump outputs\",\"question\":\"What sizes of heat pump output are available for selection?\",\"id\":\"listASHPSizes\",\"if\":\"{{goASHP}}\",\"required\":true,\"type\":\"csv\",\"notes\":\"This is a comma-seperated list of outputs in kW. Selection will round up to the nearest available size.\",\"units\":\"kW\",\"value\":\"30\"}]}],\"calculations\":[{\"id\":\"pPP\",\"title\":\"Average people per property\",\"if\":\"{{nProperties}}\",\"function\":\"{{nPeople}} / {{nProperties}}\",\"units\":\"people\"},{\"id\":\"kwDHWEst\",\"title\":\"Typical HIU rating for DHW\",\"if\":\"{{pPP}}\",\"function\":\"{{pPP}}<3?37.5:({{pPP}}<5?45:60)\",\"units\":\"kW\"},{\"id\":\"peepDS439\",\"title\":\"People per standard DS439 property\",\"if\":\"true\",\"function\":\"2.3\",\"units\":\"people\"},{\"id\":\"eqPropDS439\",\"title\":\"Equivalent number of DS439 properties\",\"if\":\"{{peepDS439}}\",\"function\":\"{{nPeople}}/{{peepDS439}}\",\"units\":\"properties\"},{\"id\":\"kwDS439\",\"title\":\"Peak DHW Load\",\"if\":\"{{eqPropDS439}}\",\"function\":\"Math.ceil((1.19* {{eqPropDS439}}) + (18.8* Math.pow({{eqPropDS439}},0.5)) + 17.6)\",\"units\":\"kW\"},{\"id\":\"vPPEST\",\"title\":\"Volume DHW used per property per day\",\"if\":\"true\",\"function\":\"40\",\"units\":\"litres\"},{\"id\":\"vPHEST\",\"title\":\"Volume DHW used per person per day\",\"if\":\"true\",\"function\":\"28\",\"units\":\"litres\"},{\"id\":\"tRiseEST\",\"title\":\"Average temperature Rise on DHW\",\"if\":\"true\",\"function\":\"35\",\"units\":\"°C\"},{\"id\":\"vDHWEST\",\"title\":\"Volume used per day for DHW\",\"if\":\"{{nPeople}}\",\"function\":\"({{nProperties}}*{{vPPEST}})+({{nPeople}}*{{vPHEST}})\",\"units\":\"litres\"},{\"id\":\"kwhDHWEST\",\"title\":\"Energy used per day for DHW\",\"if\":\"{{vDHWEST}}\",\"function\":\"({{vDHWEST}} * 4.2 * {{tRiseEST}}) / 3600\",\"units\":\"kWh\"},{\"id\":\"kwCH\",\"title\":\"Peak central heating load\",\"if\":\"{{kwCHPP}}\",\"function\":\"({{kwCHPP}} * {{divCH}} * {{nProperties}}) / 100\",\"units\":\"kW\"},{\"id\":\"kwPeak\",\"title\":\"Peak load\",\"if\":\"true\",\"function\":\"{{kwCH}}+{{kwDS439}}\",\"units\":\"kW\"},{\"id\":\"kwPeak24\",\"title\":\"Average 24h peak load\",\"if\":\"true\",\"function\":\"{{kwCH}}+({{kwhDHWEST}}/24)\",\"units\":\"kW\"},{\"id\":\"m3hDHWPeak\",\"title\":\"Primary flow rate at peak DHW load\",\"if\":\"{{tPriRtnDHW}}\",\"function\":\"3.6 * {{kwDS439}} / (4.2 * ({{tPeak}}-{{tPriRtnDHW}}))\",\"units\":\"m3/h\"},{\"id\":\"m3hCHPeak\",\"title\":\"Primary flow rate at peak central heating load\",\"if\":\"{{tPriRtnCH}}\",\"function\":\"3.6 * {{kwCH}} / (4.2 * ({{tPeak}}-{{tPriRtnCH}}))\",\"units\":\"m3/h\"},{\"id\":\"m3hPeak\",\"title\":\"Primary flow rate at peak load\",\"if\":\"{{m3hDHWPeak}}||{{m3hCHPeak}}\",\"function\":\"{{m3hDHWPeak}}+{{m3hCHPeak}}\",\"units\":\"m3/h\"},{\"id\":\"tPriRtnPeak\",\"title\":\"Primary return temperature at peak load\",\"if\":\"{{m3hPeak}}\",\"function\":\"{{tPeak}} - ({{kwPeak}} / (4.2 * {{m3hPeak}} / 3.6))\",\"units\":\"°C\"},{\"id\":\"test\",\"title\":\"Testing object\",\"if\":\"{{goASHP}}\",\"function\":{\"a\":\"hello\",\"b\":45},\"units\":\"object\"},{\"id\":\"test2\",\"title\":\"Testing object bx2\",\"if\":\"true\",\"function\":\"2 * {{test.b}}\",\"units\":\"object\"}]}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":1740,"y":320,"wires":[[]]},{"id":"61512489.8b5adc","type":"template","z":"cce2bfaa.e5748","name":"Heat Network Designer","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js\"></script>\n{{!--https://www.sitepoint.com/basic-jquery-form-validation-tutorial/--}}\n\n<script src=\"https://unpkg.com/mustache@latest\"></script>\n\n<style>\n\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 6px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\nvar a = new Date();\nvar qdata;\nvar calculated = {};\nvar hasFocus;\nvar inputsOut;\nvar inputString;\n\n\t$(document).ready(function(e) {\n    \n        // $(\"form[ajax=true]\").submit(function(e) {\n            \n        //     //alert(\"submit\");\n            \n        //     e.preventDefault();\n        \n             \n            //var urlParams = new URLSearchParams(window.location.search);\n            //if (urlParams.get('display')) { loadstring = \",,\" + urlParams.get('display'); }\n\n            var urlParams = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParams) {\n                \n                calculated[urlParams[upa].split(\"=\")[0]] = urlParams[upa].split(\"=\")[1];\n                \n            }\n            \n            var form_data = {};\n            var form_url = \"/ui/qdata\";\n            var form_target = $(this).attr(\"target\") || \"result\";\n            var ftarget = \"#\" + form_target;\n            var form_method = \"GET\";\n            \n        //     $(\"#loadingimg\").show();\n            \n            $.ajax({\n                url: form_url, \n                type: form_method,      \n                data: form_data,     \n                cache: false,\n                success: function(results){   \n                    \n                    qdata = results;\n                    //qdata = JSON.parse(returnhtml);\n                    console.log(qdata);\n                   \n                    \n                    document.getElementById(\"formName\").innerHTML = qdata.title || \"Unamed Form\"; //JSON.stringify(qdata) ;\n                    \n                    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n                    \n                    validform();\n                                  \n                }           \n            });    \n            \n        // });\n        \n      \n        \n    });\n\t\nfunction parseQuestions(qdata) {\n    \n    console.log(qdata);\n    console.log(calculated);\n    \n    var linkstxt=\"\";\n    if (qdata.links) {\n        for (var lnk in qdata.links) {\n            linkstxt += (linkstxt!==\"\"?\"<br>\":\"\") + '<a href=\"' + qdata.links[lnk].src + '\" target=\"_blank\">' + (qdata.links[lnk].title||qdata.links[lnk].src) + '</a>';\n        }\n        \n    }\n    document.getElementById(\"links\").innerHTML = linkstxt ; //JSON.stringify(qdata) ;\n    \n    inputsOut = '<table class=\"table\">';\n    \n    inputString = \"\";\n    hasFocus = null;\n    \n    var oot = \"\";\n    for (var s in qdata[\"sections\"]) {\n        console.log(s);\n        console.log(qdata.sections[s]);\n        oot += \"<div class='section'><h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        \n        \n        \n        for (var q in qdata.sections[s].questions) {\n            \n            \n            var qif = qdata.sections[s].questions[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n            var v=\"\";\n            if (calculated[qdata.sections[s].questions[q].id]) { v= calculated[qdata.sections[s].questions[q].id] ; }\n            else if (qdata.sections[s].questions[q].value) { v= qdata.sections[s].questions[q].value ; }\n            \n            if(goq) {\n            \n                if (v!==\"\") { \n                    inputsOut += \"<tr>\";  \n                    inputsOut += \"<td>\" + (qdata.sections[s].questions[q].title||qdata.sections[s].questions[q].id) + \"</td>\";\n                    inputsOut +=  '<td align=\"right\">' + v + \"</td>\";\n                    inputsOut +=  '<td width=\"20%\">' + (qdata.sections[s].questions[q].units||\"\") + \"</td></tr>\\n\";\n                    \n                    inputString += (inputString!==\"\"?\"&\":\"\") + qdata.sections[s].questions[q].id + \"=\" + v;\n                }\n            \n            \n                if (hasFocus && document.getElementById(\"oneQ\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">'; }\n            \n                else if (v!==\"\") { \n                    \n                    if (document.getElementById(\"hideDone\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">';   }\n                    else {  oot += '<div class=\"question\" style=\"background-color: #d2efd2;\">';  }\n                    \n                } else { oot += '<div class=\"question\">'; if (!hasFocus) { hasFocus = qdata.sections[s].questions[q].id; } }\n                \n                //oot += \"<div class='qtext'>\" + qdata.sections[s].questions[q].title + '</div>';\n                oot += '<label for=\"' + qdata.sections[s].questions[q].id + '\" class=\"qtext\">' + (qdata.sections[s].questions[q].question||qdata.sections[s].questions[q].title) + '</label>';\n                \n                if (qdata.sections[s].questions[q].notes) { oot += '<div class=\"notes\">'  + convertLinks(qdata.sections[s].questions[q].notes) + '</div>'; }\n                oot += '<table width=\"100%\"><tr><td width=\"80%\">';\n                \n                if (qdata.sections[s].questions[q].type==\"boolean\") {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                      if (v==\"true\") { oot += '<option value=\"false\">No</option><option value=\"true\" selected>Yes</option>'; }\n                      else if (v==\"false\")  { oot += '<option value=\"false\" selected>No</option><option value=\"true\">Yes</option>'; }\n                      else  { oot += '<option value=\"\"></option><option value=\"false\">No</option><option value=\"true\">Yes</option>'; }\n                    oot += '</select>';\n                    \n                } else if (qdata.sections[s].questions[q].options) {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    if (v==\"\") { oot += '<option value=\"\"></option>'; }\n                    for (var opt in qdata.sections[s].questions[q].options) {\n                    \n                      var optobj = qdata.sections[s].questions[q].options[opt];\n                      \n                      if (v==optobj) { oot += '<option selected value=\"' + optobj + '\">' + optobj + '</option>'; }\n                      else  { oot += '<option value=\"' + optobj + '\">' + optobj + '</option>'; }\n                      \n                    }  \n                    oot += '</select>';\n                    \n                } else {\n                \n                    oot += '<input id=\"' + qdata.sections[s].questions[q].id + '\" name=\"' + qdata.sections[s].questions[q].id + '\" class=\"form-control\" type=\"text\"';\n                    if (v!==\"\") { oot += ' value=\"' + v + '\"'; }\n                    if (qdata.sections[s].questions[q].default) { oot += ' placeholder=\"' + qdata.sections[s].questions[q].default + \" \" + (qdata.sections[s].questions[q].units||\"\") + ' ... please confirm\"'; }\n                    oot += '>';\n                }\n                \n                oot += '</td><td valign=\"top\"><span class=\"qunits\">' + (qdata.sections[s].questions[q].units||\"\") + '</span></td></tr></table></div>\\n';\n            }\n        }\n    \n        oot += \"</div>\\n\";\n        \n    }\n    inputsOut +=  \"</table>\\n\";  \n    \n    return oot;\n}\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\n// console.log(looseJsonParse(\n//   \"{a:(4-1), b:function(){}, c:new Date()}\"\n// ))\n\nfunction runCalcs() {\n\n\n    \n    \n    // run through form inputs and store current values into calculated.\n    var cells =  document.getElementsByClassName(\"form-control\");\n\tvar i;\n\tfor (i = 0; i < cells.length; i++) {\n\t\n\t\tcalcsOut += cells[i].value + \"<br>\\n\";\n        \n        if (\"\" + cells[i].value !== \"\") { \n            \n            if (isNaN(cells[i].value)) { \n                \n                calculated[cells[i].id] = (cells[i].value);\n                \n            } else {\n                \n                calculated[cells[i].id] = parseFloat(cells[i].value);\n            }\n        }\n\t}\n    \n    var calcsOut = '<table class=\"table\">';\n    for (var calc in (qdata[\"calculations\"]||[])) {\n        \n        console.log(calc);\n        console.log(qdata.calculations[calc]);\n        \n        \n        var cif = qdata.calculations[calc].if || true;\n        var cift = Mustache.render(cif, calculated);\n        var goc = true;\n        try {\n          goc = looseJsonParse(cift); \n        }\n        catch(err) {\n          goc = false;\n        }\n        \n        if (goc) {\n        \n            var f = qdata.calculations[calc].function;\n            var ft;\n            var cv = \"\";\n            \n            calcsOut += \"<tr>\"; \n            calcsOut += \"<td>\" + (qdata.calculations[calc].title||qdata.calculations[calc].id) + \"</td>\";\n            \n            try {\n                \n                ft = Mustache.render(f, calculated);  // error trap incase object\n                cv = looseJsonParse(ft); \n                if (!isNaN(cv)) { cv = parseInt(cv*1000)/1000; }\n                if (document.getElementById(\"hideMaths\").checked!==true) {\n                    calcsOut += \"<td><small>\" + ft + \"</small></td>\";   //\"<br>\\n\";\n                }\n                calcsOut +=  '<td align=\"right\">' + cv + \"</td>\"; \n                 \n            }\n            catch(err) {   // is an object returned\n                \n                ft = f; \n                cv = f; \n                var obst = \"\";\n                try { obst = JSON.stringify(cv); } catch { obst = \"error\"; }\n                //if (document.getElementById(\"hideMaths\").checked!==true) { calcsOut += \"<td> </td>\";  }\n                calcsOut += '<td ';\n                if (document.getElementById(\"hideMaths\").checked!==true) { calcsOut += 'colspan=\"2\" ';  }\n                calcsOut += 'align=\"right\"><small>' + obst + \"</small></td>\";\n                \n            }\n            \n            calculated[qdata.calculations[calc].id] = cv;\n            \n            calcsOut +=  '<td width=\"20%\">' + (qdata.calculations[calc].units||\"\") + \"</td></tr>\\n\";\n            \n            \n            \n        }\n        \n    }\n    \n    calcsOut +=  \"</table>\\n\";\n    \n    // for (var calc in calculated) {\n        \n        \n    // }\n    \n    document.getElementById(\"calcs\").innerHTML = calcsOut; //JSON.stringify(qdata) ;\n    \n    // rebuild form\n    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"inputs\").innerHTML = inputsOut; //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"mylink\").innerHTML = '<a href=\"hndesign?' + inputString + '\" target=\"_blank\">Click/Copy this link to open design...</a>'; //JSON.stringify(qdata) ;\n    \n    \n    \n    validform();\n                    \n}\n\n\nconst convertLinks = ( input ) => {\n\n  let text = input;\n  const linksFound = text.match( /(?:www|https?)[^\\s]+/g );\n  const aLink = [];\n\n  if ( linksFound != null ) {\n\n    for ( let i=0; i<linksFound.length; i++ ) {\n      let replace = linksFound[i];\n      if ( !( linksFound[i].match( /(http(s?)):\\/\\// ) ) ) { replace = 'http://' + linksFound[i] }\n      let linkText = replace.split( '/' )[2];\n      if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) }\n      if ( linkText.match( /youtu/ ) ) {\n\n        let youtubeID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://www.youtube.com/embed/' + youtubeID + '\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe></div>' )\n      }\n      else if ( linkText.match( /vimeo/ ) ) {\n        let vimeoID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://player.vimeo.com/video/' + vimeoID + '\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' )\n      }\n      else {\n        aLink.push( '<a href=\"' + replace + '\" target=\"_blank\">' + linkText + '</a>' );\n      }\n      text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] );\n    }\n    return text;\n\n  }\n  else {\n    return input;\n  }\n}\n\nfunction validform() {\n    \n    if(hasFocus && document.getElementById(hasFocus)) {\n        document.getElementById(hasFocus).focus();\n    }\n    \n    \n    \n// Initialize form validation on the registration form.\n  // It has the name attribute \"registration\"\n  $(\"form[name='qform']\").validate({\n    // Specify validation rules\n    rules: {\n      // The key name on the left side is the name attribute\n      // of an input field. Validation rules are defined\n      // on the right side\n      nProperties: {\n        required: true,\n        digits: true,\n        min: 1\n      },\n      lastname: \"required\",\n      email: {\n        required: true,\n        // Specify that email should be validated\n        // by the built-in \"email\" rule\n        email: true\n      },\n      password: {\n        required: true,\n        minlength: 5\n      }\n    },\n    // Specify validation error messages\n    messages: {\n      nProperties: \"Please enter a number.\",\n      lastname: \"Please enter your lastname\",\n      password: {\n        required: \"Please provide a password\",\n        minlength: \"Your password must be at least 5 characters long\"\n      },\n      email: \"Please enter a valid email address\"\n    },\n    // Make sure the form is submitted to the destination defined\n    // in the \"action\" attribute of the form when valid\n    submitHandler: function(form) {\n      //form.submit();\n      runCalcs();\n      //alert(\"hello\");\n    }\n  });\n}\n\n</script>\n\n\n<div class='section'>\n    \n    <table width=\"100%\"><tr>\n    <td valign=\"top\" width=\"70%\">\n        <div id=\"formName\" class=\"h1\"></div>\n        <a href=\"https://heatweb.co.uk/w/index.php?title=Heat_Network_Designer\" target=\"_blank\"><small>Wiki Help Page</small></a>\n    </td>\n    <td width=\"30%\">\n        <input type=\"checkbox\" id=\"oneQ\" name=\"oneQ\" checked> <small>One question at a time</small><br>\n        <input type=\"checkbox\" id=\"hideDone\" name=\"hideDone\" checked> <small>Hide completed questions</small><br>\n        <input type=\"checkbox\" id=\"hideMaths\" name=\"hideMaths\" checked> <small>Hide maths equations</small>\n    </td>\n    </tr></table>\n</div>\n\n\n<form action=\"\" name=\"qform\" id=\"qform\">\n<div id=\"section1\"></div>\n\n<div class='section'>\n<button type=\"submit\">Submit</button>\n\n</div>\n\n\n<div class='section'>\n<p><b>Inputs</b></p>\n<div id=\"inputs\" class=\"notes\"></div>\n</div>\n\n<div class='section'>\n<p><b>Numeric Values and Calculations</b></p>\n<div id=\"calcs\" class=\"notes\"></div>\n</div>\n\n\n<div class='section'>\n<p><b>Links</b></p>\n<div id=\"mylink\" class=\"notes\"></div>\n<div id=\"links\" class=\"notes\"></div>\n</div>\n</form>","output":"str","x":1750,"y":280,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"7bcbccf5.64f074","type":"change","z":"cce2bfaa.e5748","name":"Heat Network Design JSON","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"title\":\"Heat Network Designer\",\"links\":[{\"src\":\"http://www.systemdesigner.co.uk/heatnetwork.php\",\"title\":\"Heat Network Calculator v1\"},{\"src\":\"https://hw3.ddns.net/index.php?page=3D&&startp=heatnetcalc\",\"title\":\"3D Model for Calculator v1\"},{\"src\":\"https://hw7.ddns.net/ui/hncalc\",\"title\":\"Heat Network Calculator v2\"},{\"src\":\"https://hw7.ddns.net/ui/svgexplode?svg=HeatNetwork6.svg\",\"title\":\"Heat Network Schematic Designer (HeatNetwork6.svg)\"}],\"sections\":[{\"title\":\"Loads\",\"questions\":[{\"title\":\"Schedule of loads\",\"question\":\"List the loads on the network\",\"id\":\"loadSchedule\",\"if\":\"true\",\"required\":true,\"type\":\"sheet\",\"notes\":\"Add, edit and copy down lines as with a normal spreadsheet. Right click for further actions including deleting lines.\",\"units\":\"\",\"Xcalculator\":\"hndesignfunctions\",\"XcalculatorStyle\":\"width:100%;height:300px\",\"default\":[[\"Flat\",1,2,3,130],[\"Duplex\",2,4,5.5,20],[\"Office\",0,2,5,1]],\"columns\":[{\"type\":\"text\",\"name\":\"propertyType\",\"title\":\"Property Type\",\"width\":120},{\"type\":\"numeric\",\"name\":\"bedrooms\",\"title\":\"Bedrooms\",\"width\":120,\"decimal\":\".\"},{\"type\":\"numeric\",\"name\":\"occupants\",\"title\":\"Occupants\",\"width\":120,\"decimal\":\".\"},{\"type\":\"numeric\",\"name\":\"kwCH\",\"title\":\"Heating Load kW\",\"width\":120,\"decimal\":\".\"},{\"type\":\"numeric\",\"name\":\"qty\",\"title\":\"Quantity\",\"width\":100,\"decimal\":\".\"}]}]},{\"title\":\"General\",\"questions\":[{\"title\":\"Number of buildings\",\"question\":\"How many buildings are fed from the network?\",\"id\":\"nBuildings\",\"if\":\"true\",\"required\":true,\"type\":\"integer\",\"notes\":\"The total number of buildings connected to the heat network. See https://hw7.ddns.net/ui/svgexplode?svg=HeatNetwork6.svg&display=g16444,g11206,bulkhm,g14636,landlordload,g16320,g5006,bufferstore,lowgrade,heatpump2,heatpump2-2,qton1,fbyp,hiu,g68266,singlemainpump,backupmainpump,g130841-3,g14610-0,g14636-2,g14610,finestrainer,cwsvcs,g14124,g14362.\",\"units\":\"buildings\"},{\"title\":\"Number of properties\",\"question\":\"How many properties are there?\",\"id\":\"nProperties\",\"if\":\"false\",\"required\":true,\"type\":\"integer\",\"notes\":\"The total number of properties connected to the heat network.\",\"units\":\"properties\"},{\"title\":\"Total number of people\",\"question\":\"How many people are there in total?\",\"id\":\"nPeople\",\"if\":\"false\",\"required\":false,\"type\":\"integer\",\"units\":\"people\"},{\"title\":\"Peak network flow temperature\",\"question\":\"What is the peak network flow temperature?\",\"id\":\"tPeak\",\"if\":\"true\",\"required\":true,\"default\":80,\"type\":\"number\",\"units\":\"°C\"}]},{\"title\":\"Domestic Hot Water\",\"questions\":[{\"title\":\"DHW network return temperature\",\"question\":\"What is the network return temperature for DHW?\",\"notes\":\"The temperature fed back from a property to the network when running peak load domestic hot water.\",\"id\":\"tPriRtnDHW\",\"if\":\"true\",\"required\":false,\"default\":19,\"type\":\"number\",\"units\":\"°C\"},{\"title\":\"DHW load profile\",\"question\":\"What hourly DHW load profie to use?\",\"id\":\"profileDHW\",\"if\":\"true\",\"required\":true,\"type\":\"select\",\"options\":[{\"title\":\"EST Data\",\"value\":\"EST\"}]}]},{\"title\":\"Central Heating\",\"questions\":[{\"title\":\"Central heating emitter\",\"question\":\"What types of central heating emitter are used?\",\"id\":\"typeEmitter\",\"if\":\"{{kwCHMax}}\",\"required\":true,\"type\":\"select\",\"options\":[{\"title\":\"Radiators\",\"value\":\"radiator\"},{\"title\":\"Underfloor heating (piped)\",\"value\":\"underfloor\"},{\"title\":\"Fan convectors\",\"value\":\"fan\"}]},{\"title\":\"Central heating connection\",\"question\":\"What types of central heating connection is used?\",\"id\":\"connectionCH\",\"if\":\"{{kwCHMax}}\",\"required\":true,\"type\":\"select\",\"options\":[{\"title\":\"Direct\",\"value\":\"direct\"},{\"title\":\"Indirect\",\"value\":\"indirect\"},{\"title\":\"Mixed\",\"value\":\"mixed\"}]},{\"title\":\"Radiator flow control\",\"question\":\"What types of TRVs are used?\",\"id\":\"typeTRV\",\"if\":\"'{{typeEmitter}}'=='radiator'\",\"required\":true,\"type\":\"select\",\"options\":[{\"title\":\"Basic TRV, with no presetting\",\"value\":\"basic TRV\"},{\"title\":\"Pre-settable TRV\",\"value\":\"presettable TRV\"},{\"title\":\"Pressure-independent pre-settable TRV\",\"value\":\"PICV TRV\"},{\"title\":\"None, isolation only\",\"value\":\"isolation\"}]},{\"title\":\"Radiator return control\",\"question\":\"Are return temperature limit valves fitted to radiators?\",\"id\":\"typeRTL\",\"if\":\"'{{typeEmitter}}'=='radiator'\",\"required\":true,\"type\":\"select\",\"options\":[{\"title\":\"Return temperature control\",\"value\":\"RTL\"},{\"title\":\"None, isolation only\",\"value\":\"isolation\"}]},{\"title\":\"External temperature at peak load\",\"question\":\"What is the outside temperature used for the peak central heating?\",\"notes\":\"Typically -5C. This is the temperatures used to derive figures in the load schedule.\",\"id\":\"tXPeak\",\"if\":\"{{kwCHMax}}\",\"required\":true,\"default\":-5,\"value\":-5,\"type\":\"number\",\"units\":\"°C\"},{\"title\":\"Central heating network return temperature\",\"question\":\"What is the network return temperature for central heating?\",\"notes\":\"The temperature fed back from a property to the network when running peak load central heating.\",\"id\":\"tPriRtnCH\",\"if\":\"{{kwCHMax}}\",\"required\":false,\"default\":45,\"type\":\"number\",\"units\":\"°C\"},{\"title\":\"Central heating diversity\",\"question\":\"What diversity is applied to central heating output?\",\"id\":\"divCH\",\"if\":\"{{kwCHMax}}\",\"required\":false,\"default\":70,\"type\":\"number\",\"units\":\"%\"},{\"title\":\"Base temperature\",\"question\":\"What base temperature is used for heating calculations?\",\"notes\":\"The <i>base temperature</i> is the external temperature below which central heating comes on. 16C to 18C is a typical range. Visit https://www.degreedays.net/base-temperature for further information.\",\"id\":\"baseTemp\",\"if\":\"{{kwCHMax}}\",\"required\":true,\"type\":\"select\",\"default\":\"18\",\"options\":[{\"title\":\"16.0\",\"value\":\"16\"},{\"title\":\"16.5\",\"value\":\"16.5\"},{\"title\":\"17.0\",\"value\":\"17\"},{\"title\":\"17.5\",\"value\":\"17.5\"},{\"title\":\"18.0\",\"value\":\"18\"},{\"title\":\"18.5\",\"value\":\"18.5\"},{\"title\":\"19.0\",\"value\":\"19\"},{\"title\":\"19.5\",\"value\":\"19.5\"},{\"title\":\"20.0\",\"value\":\"20\"},{\"title\":\"20.5\",\"value\":\"20.5\"},{\"title\":\"21.0\",\"value\":\"21\"},{\"title\":\"21.5\",\"value\":\"21.5\"},{\"title\":\"22.0\",\"value\":\"22\"}]},{\"title\":\"Central heating degree-days\",\"question\":\"What degree-days are used to estimate annual central heating loads (16C to 22C base temp)?\",\"notes\":\"Degree days represent the amount of heating required in a location, based on historic weather data. Visit https://www.degreedays.net/ for further information and to obtain values.\",\"id\":\"degDaysAvg\",\"if\":\"{{kwCHMax}}\",\"required\":true,\"type\":\"csv\",\"value\":\"1749.5,1884.5,2023.9,2167.9,2316.2,2467.9,2623.5,2782.4,2944.3,3108.6,3275.4,3444.9,3615.7\",\"units\":\"°days\"},{\"title\":\"Central heating degree-days at base temperature\",\"question\":\"What degree-days are used to estimate annual central heating loads?\",\"notes\":\"Degree days represent the amount of heating required in a location, based on historic weather data. Visit https://www.degreedays.net/ for further information and to obtain values.\",\"id\":\"degDays\",\"if\":\"{{baseTemp}}\",\"required\":true,\"default\":\"{{dDaysCalc}}\",\"type\":\"number\",\"Xcalculator\":\"https://www.degreedays.net/\",\"units\":\"°days\",\"calculatorStyle\":\"width:100%;height:600px\"}]},{\"title\":\"Heat Sources\",\"questions\":[{\"title\":\"Boilers\",\"question\":\"Are boilers to be used?\",\"id\":\"goBoilers\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\"},{\"title\":\"Air Source Heat Pumps\",\"question\":\"Are air source heat pumps to be used?\",\"notes\":\"Not including heat pumps in properties.\",\"id\":\"goASHP\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\"},{\"title\":\"External Heat Network Supply\",\"question\":\"Is the network fed from another heat network?\",\"notes\":\"\",\"id\":\"goHN\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\"},{\"title\":\"Water Source Heat Pumps\",\"question\":\"Are water source heat pumps to be used?\",\"notes\":\"This is taking heat from an ambient loop or water source. Not including heat pumps in properties.\",\"id\":\"goWSHP\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\"},{\"title\":\"Cooling Source Heat Pumps\",\"question\":\"Are water source heat pumps to be used to reclaim cooling?\",\"notes\":\"This is where cooling circuits are driven by moving heat to the main storage.\",\"id\":\"goReclaim\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\"},{\"title\":\"Combined Heat & Power\",\"question\":\"Is CHP (Combined Heat & Power) to be used?\",\"id\":\"goCHP\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\"},{\"title\":\"Solar Thermal\",\"question\":\"Are solar panels (thermal) to be used?\",\"id\":\"goSolar\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\"}]},{\"title\":\"Boilers\",\"questions\":[{\"title\":\"Boiler fuel type\",\"question\":\"What is the fuel source?\",\"id\":\"boilerFuel\",\"if\":\"{{goBoilers}}\",\"required\":true,\"type\":\"select\",\"options\":[{\"title\":\"Mains Gas\",\"value\":\"gas\"},{\"title\":\"LPG\",\"value\":\"lpg\"},{\"title\":\"Biogas\",\"value\":\"biogas\"},{\"title\":\"Biomass\",\"value\":\"biomass\"},{\"title\":\"Hydrogen\",\"value\":\"hydrogen\"},{\"title\":\"Fuel Oil\",\"value\":\"oil\"},{\"title\":\"Electric\",\"value\":\"electric\"}]},{\"title\":\"Boiler Emissions\",\"question\":\"The following CO2 emissions will be used.\",\"id\":\"boilerEmissions\",\"if\":\"{{goBoilers}}\",\"required\":true,\"type\":\"number\",\"notes\":\"\",\"units\":\"kgCO2/kWh\",\"default\":\"0.216\"},{\"title\":\"Available boiler outputs\",\"question\":\"What sizes of boiler output are available for selection?\",\"id\":\"listBSizes\",\"if\":\"{{goBoilers}}\",\"required\":true,\"type\":\"csv\",\"notes\":\"This is a comma-seperated list of outputs in kW. Selection will round up to the nearest available size.\",\"units\":\"kW\",\"value\":\"30,50,75,100,250,500,750,1000\"},{\"title\":\"Boiler selection\",\"question\":\"Please confirm boiler selection\",\"id\":\"selectBoilers\",\"if\":\"{{goBoilers}}\",\"required\":true,\"type\":\"object\",\"units\":\"n x kW\",\"calculator\":\"hndesignfunctions\",\"calculatorStyle\":\"width:100%;height:75px\"}]},{\"title\":\"Electrical Supplies for Heat Pumps\",\"questions\":[{\"title\":\"Electrical Tariff\",\"question\":\"What Electrical Tariff is used to drive heat pumps?\",\"id\":\"tariffHP\",\"notes\":\"Are electricity supplied provided at a flat rate charge or do prices vary, for example by the time of day.\",\"if\":\"{{goASHP}}\",\"required\":true,\"type\":\"select\",\"options\":[{\"value\":\"flat\",\"title\":\"Flat rate\"},{\"value\":\"mixed\",\"title\":\"Peak+Economy rates\"}]},{\"title\":\"Electrical Supply Emissions\",\"question\":\"The following CO2 emissions will be used for grid supplied electricity.\",\"id\":\"elecEmissions\",\"if\":\"{{goASHP}}\",\"required\":true,\"type\":\"number\",\"notes\":\"Source: https://www.buildenergy.co.uk/tips-and-insight/sap-technicals-fuel-factors/\",\"units\":\"kgCO2/kWh\",\"default\":\"0.519\"}]},{\"title\":\"Air Source Heat Pumps\",\"questions\":[{\"title\":\"ASHP refrigerant\",\"question\":\"What refrigerant is used in the heat pump?\",\"id\":\"fridgeASHP\",\"if\":\"{{goASHP}}\",\"required\":true,\"type\":\"select\",\"options\":[{\"value\":\"R744\",\"title\":\"R744 (CO2)\"}]},{\"title\":\"Available heat pump outputs\",\"question\":\"What sizes of heat pump output are available for selection?\",\"id\":\"listASHPSizes\",\"if\":\"{{goASHP}}\",\"required\":true,\"type\":\"csv\",\"notes\":\"This is a comma-seperated list of outputs in kW. Selection will round up to the nearest available size.\",\"units\":\"kW\",\"value\":\"30\"},{\"title\":\"ASHP selection\",\"question\":\"Please confirm air source heat pump selection\",\"id\":\"selectASHP\",\"if\":\"{{goASHP}}\",\"required\":true,\"type\":\"object\",\"units\":\"n x kW\",\"calculator\":\"hndesignfunctions\",\"calculatorStyle\":\"width:100%;height:75px\"}]},{\"title\":\"Buffer Storage\",\"questions\":[{\"title\":\"Buffer volume\",\"question\":\"What volume of buffer storage is to be provided?\",\"notes\":\"A volume of {{vBuffer9}} litres or more is advised. This is based on storing the heaviest hour of hot water use. A minimum of 500 litres would ne normal for low load functions.\",\"id\":\"vBuffer\",\"if\":\"true\",\"required\":true,\"type\":\"number\",\"units\":\"litres\",\"default\":\"{{vBuffer9}}\"}],\"outputs\":[{\"title\":\"Daily Hot Water Patterns\",\"id\":\"est24\",\"if\":\"{{kWInPeak}}\",\"type\":\"iframe\",\"url\":\"hnoutputs/peakload\",\"style\":\"width:100%;height:425px\",\"buttons\":[{\"onClick\":\"jpegDownload('est24')\",\"text\":\"JPEG\"}]},{\"title\":\"Buffer Charging\",\"id\":\"bufferUse\",\"if\":\"{{kWInPeak}}\",\"type\":\"iframe\",\"url\":\"hnoutputs/buffer\",\"style\":\"width:100%;height:425px\"},{\"title\":\"Historical Load Modelling\",\"id\":\"yearly\",\"if\":\"{{kWInPeak}}\",\"type\":\"iframe\",\"url\":\"hnoutputs/yearly\",\"style\":\"width:100%;height:700px\",\"buttons\":[{\"onClick\":\"jpegDownload('loads2020')\",\"text\":\"JPEG 2020\"},{\"onClick\":\"jpegDownload('loads2021')\",\"text\":\"JPEG 2021\"}]},{\"title\":\"Topology\",\"id\":\"topology\",\"if\":\"{{kWInPeak}}\",\"type\":\"iframe\",\"url\":\"https://hw7.ddns.net/ui/svgexplode?svg=hnio.svg&nozoom=1\",\"style\":\"width:100%;height:450px\",\"buttons\":[{\"onClick\":\"tosvg('mysvg')\",\"text\":\"SVG\"},{\"onClick\":\"topdf('mysvg')\",\"text\":\"PDF\"}]}]},{\"title\":\"Save\",\"questions\":[{\"title\":\"Save design\",\"question\":\"Save design?\",\"id\":\"goSave\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\"},{\"title\":\"Network name\",\"question\":\"What is the name of the Network?\",\"id\":\"networkName\",\"if\":\"{{goSave}}\",\"required\":false,\"type\":\"text\",\"units\":\"\"},{\"title\":\"Email address\",\"question\":\"Email address?\",\"id\":\"email\",\"if\":\"{{goSave}}\",\"required\":true,\"type\":\"email\",\"notes\":\"The design will be saved against your email, and a link will be emailed to you providing access.\"}],\"outputs\":[{\"title\":\"Save Design\",\"id\":\"save\",\"if\":\"{{goSave}}\",\"type\":\"iframe\",\"url\":\"hnoutputs/save\",\"style\":\"width:100%;height:125px\"}]}],\"calculations\":[{\"id\":\"pPP\",\"title\":\"Average people per property\",\"if\":\"{{nProperties}}\",\"function\":\"{{nPeople}} / {{nProperties}}\",\"units\":\"people\"},{\"id\":\"density\",\"title\":\"Average people per building (density)\",\"if\":\"{{nBuildings}}\",\"function\":\"{{nPeople}} / {{nBuildings}}\",\"units\":\"people\"},{\"id\":\"kwDHWEst\",\"title\":\"Typical HIU rating for DHW\",\"if\":\"{{pPP}}\",\"function\":\"{{pPP}}<3?37.5:({{pPP}}<5?45:60)\",\"units\":\"kW\"},{\"id\":\"peepDS439\",\"title\":\"People per standard DS439 property\",\"if\":\"true\",\"function\":\"2.3\",\"units\":\"people\"},{\"id\":\"eqPropDS439\",\"title\":\"Equivalent number of DS439 properties\",\"if\":\"{{peepDS439}}\",\"function\":\"{{nPeople}}/{{peepDS439}}\",\"units\":\"properties\"},{\"id\":\"kwDS439\",\"title\":\"Peak DHW Load\",\"if\":\"{{eqPropDS439}}\",\"function\":\"Math.ceil((1.19* {{eqPropDS439}}) + (18.8* Math.pow({{eqPropDS439}},0.5)) + 17.6)\",\"units\":\"kW\"},{\"id\":\"vPPEST\",\"title\":\"Volume DHW used per property per day\",\"if\":\"true\",\"function\":\"40\",\"units\":\"litres\"},{\"id\":\"vPHEST\",\"title\":\"Volume DHW used per person per day\",\"if\":\"true\",\"function\":\"28\",\"units\":\"litres\"},{\"id\":\"tRiseEST\",\"title\":\"Average temperature Rise on DHW\",\"if\":\"true\",\"function\":\"35\",\"units\":\"°C\"},{\"id\":\"vDHWEST\",\"title\":\"Volume drawn per day for DHW (tap)\",\"if\":\"{{nPeople}}\",\"function\":\"({{nProperties}}*{{vPPEST}})+({{nPeople}}*{{vPHEST}})\",\"units\":\"litres\"},{\"id\":\"kwhDHWEST\",\"title\":\"Energy used per day for DHW\",\"if\":\"{{vDHWEST}}\",\"function\":\"({{vDHWEST}} * 4.2 * {{tRiseEST}}) / 3600\",\"units\":\"kWh\"},{\"id\":\"vPDHW\",\"title\":\"Volume used per day for DHW (primary)\",\"if\":\"{{vDHWEST}}\",\"function\":\"({{vDHWEST}} * {{tRiseEST}}) / (({{tPeak}}-{{tPriRtnDHW}}))\",\"units\":\"litres\"},{\"id\":\"vBuffer9\",\"title\":\"Buffer Storage for DHW (based on 9%)\",\"if\":\"{{vPDHW}}\",\"function\":\"{{vPDHW}} * 0.09\",\"units\":\"litres\"},{\"id\":\"kwCH\",\"title\":\"Peak diversified (steady state) central heating load\",\"if\":\"{{kwCHMax}} &&  {{divCH}}\",\"function\":\"({{kwCHMax}} * {{divCH}}) / 100\",\"units\":\"kW\"},{\"id\":\"kwhCH\",\"title\":\"Energy used per day for CH\",\"if\":\"{{kwCH}}\",\"function\":\"{{kwCH}} * 24\",\"units\":\"kWh\"},{\"id\":\"vPCH\",\"title\":\"Volume used on peak load day for CH (primary)\",\"if\":\"{{kwCH}}\",\"function\":\"({{kwhCH}} * 3600) / (4.2 * ({{tPeak}}-{{tPriRtnCH}}))\",\"units\":\"litres\"},{\"id\":\"kwhP24\",\"title\":\"Peak energy used per day\",\"if\":\"true\",\"function\":\"{{kwhCH}}+{{kwhDHWEST}}\",\"units\":\"kWh\"},{\"id\":\"vP24\",\"title\":\"Peak volume used per day (primary)\",\"if\":\"true\",\"function\":\"{{vPCH}}+{{vPDHW}}\",\"units\":\"litres\"},{\"id\":\"kwPeak\",\"title\":\"Peak load\",\"if\":\"true\",\"function\":\"{{kwCH}}+{{kwDS439}}\",\"units\":\"kW\"},{\"id\":\"kwP24\",\"title\":\"Average 24h peak load\",\"if\":\"true\",\"function\":\"{{kwCH}}+({{kwhDHWEST}}/24)\",\"units\":\"kW\"},{\"id\":\"m3hDHWPeak\",\"title\":\"Primary flow rate at peak DHW load\",\"if\":\"{{tPriRtnDHW}}\",\"function\":\"3.6 * {{kwDS439}} / (4.2 * ({{tPeak}}-{{tPriRtnDHW}}))\",\"units\":\"m3/h\"},{\"id\":\"m3hCHPeak\",\"title\":\"Primary flow rate at peak central heating load\",\"if\":\"{{tPriRtnCH}}\",\"function\":\"3.6 * {{kwCH}} / (4.2 * ({{tPeak}}-{{tPriRtnCH}}))\",\"units\":\"m3/h\"},{\"id\":\"m3hPeak\",\"title\":\"Primary flow rate at peak load\",\"if\":\"{{m3hDHWPeak}}||{{m3hCHPeak}}\",\"function\":\"{{m3hDHWPeak}}+{{m3hCHPeak}}\",\"units\":\"m3/h\"},{\"id\":\"tPriRtnPeak\",\"title\":\"Primary return temperature at peak load\",\"if\":\"{{m3hPeak}}\",\"function\":\"{{tPeak}} - ({{kwPeak}} / (4.2 * {{m3hPeak}} / 3.6))\",\"units\":\"°C\"},{\"id\":\"tVWART24\",\"title\":\"Weighted primary return temperature on peak load day\",\"if\":\"{{m3hPeak}}\",\"function\":\"( ({{tPriRtnCH}} * {{vPCH}}) + ({{tPriRtnDHW}} * {{vPDHW}}) ) / ({{vPCH}} + {{vPDHW}})\",\"units\":\"°C\"},{\"id\":\"bufferkWh\",\"title\":\"Buffer storage peak energy content\",\"if\":\"{{vBuffer}}\",\"function\":\"({{vBuffer}} * 4.2 * ({{tPeak}} - {{tPriRtnPeak}})) / 3600\",\"units\":\"kWh\"},{\"id\":\"boilerQty\",\"title\":\"Boiler quantity\",\"if\":\"'{{selectBoilers}}'!==''\",\"function\":\"('{{selectBoilers}}').split('x')[0].trim()\",\"units\":\"boilers\"},{\"id\":\"boilerkW\",\"title\":\"Boiler unit power\",\"if\":\"'{{selectBoilers}}'!==''\",\"function\":\"('{{selectBoilers}}').split('x')[1].trim()\",\"units\":\"kW\"},{\"id\":\"boilerkWPeak\",\"title\":\"Boiler peak power (n)\",\"if\":\"'{{selectBoilers}}'!==''\",\"function\":\"{{boilerkW}}*{{boilerQty}}\",\"units\":\"kW\"},{\"id\":\"boilerkWxN1\",\"title\":\"Boiler power (n-1)\",\"if\":\"'{{selectBoilers}}'!==''\",\"function\":\"{{boilerkW}}*({{boilerQty}}-1)\",\"units\":\"kW\"},{\"id\":\"ASHPQty\",\"title\":\"ASHP quantity\",\"if\":\"'{{selectASHP}}'!==''\",\"function\":\"('{{selectASHP}}').split('x')[0].trim()\",\"units\":\"ASHPs\"},{\"id\":\"ASHPkW\",\"title\":\"ASHP unit power\",\"if\":\"'{{selectASHP}}'!==''\",\"function\":\"('{{selectASHP}}').split('x')[1].trim()\",\"units\":\"kW\"},{\"id\":\"ASHPkWPeak\",\"title\":\"ASHP peak power (n)\",\"if\":\"'{{selectASHP}}'!==''\",\"function\":\"{{ASHPkW}}*{{ASHPQty}}\",\"units\":\"kW\"},{\"id\":\"ASHPkWxN1\",\"title\":\"ASHP power (n-1)\",\"if\":\"'{{selectASHP}}'!==''\",\"function\":\"{{ASHPkW}}*({{ASHPQty}}-1)\",\"units\":\"kW\"},{\"id\":\"kWInPeak\",\"title\":\"Peak power available from all sources\",\"if\":\"true\",\"function\":\"parseFloat('{{boilerkWPeak}}'||0)+parseFloat('{{ASHPkWPeak}}'||0)\",\"units\":\"kW\"},{\"id\":\"kWxN1\",\"title\":\"Peak power available from (n-1) sources\",\"if\":\"true\",\"function\":\"{{boilerkWPeak}}+{{ASHPkWPeak}}-Math.max(parseFloat('{{boilerkW}}'||0),parseFloat('{{ASHPkW}}'||0))\",\"units\":\"kW\"},{\"id\":\"sparekW\",\"title\":\"Excess power availiable (n)\",\"if\":\"{{kwP24}}\",\"function\":\"({{kWInPeak}}-{{kwP24}})\",\"units\":\"kW\"},{\"id\":\"ovsersizing\",\"title\":\"Oversizing (n)\",\"if\":\"{{kwP24}}\",\"function\":\"100*({{kWInPeak}}-{{kwP24}})/{{kwP24}}\",\"units\":\"%\"},{\"id\":\"ovsersizingxN1\",\"title\":\"Oversizing (n-1)\",\"if\":\"{{kwP24}}\",\"function\":\"100*({{kWxN1}}-{{kwP24}})/{{kwP24}}\",\"units\":\"%\"},{\"id\":\"dDaysCalc\",\"title\":\"Calculated degree days per year\",\"if\":\"{{baseTemp}}\",\"function\":\"('{{degDaysAvg}}').split(',')[({{baseTemp}}-16)*2]\",\"units\":\"°days\"},{\"id\":\"dDaysPeak\",\"title\":\"Peak load day degree days\",\"if\":\"('{{tXPeak}}'!=='') && ('{{baseTemp}}'!=='')\",\"function\":\"{{baseTemp}} - {{tXPeak}}\",\"units\":\"°days\"},{\"id\":\"dDaysPeak\",\"title\":\"Annual days of full load heating\",\"if\":\"{{dDaysPeak}}\",\"function\":\"{{dDaysCalc}} / {{dDaysPeak}}\",\"units\":\"days\"},{\"id\":\"kwhCH365\",\"title\":\"Annual energy for central heating\",\"if\":\"{{dDaysPeak}}\",\"function\":\"parseInt({{dDaysPeak}} * {{kwhCH}})\",\"units\":\"kWh\"},{\"id\":\"kwhDHW365\",\"title\":\"Annual energy for domestic hot water\",\"if\":\"{{kwhDHWEST}}\",\"function\":\"parseInt({{kwhDHWEST}} * 365)\",\"units\":\"kWh\"},{\"id\":\"kwhUsed365\",\"title\":\"Annual energy utilised\",\"if\":\"{{kwhDHWEST}}\",\"function\":\"parseInt({{kwhCH365}} + {{kwhDHW365}})\",\"units\":\"kWh\"},{\"id\":\"kwhDistLoss365\",\"title\":\"Annual distribution heat losses (est at 20%)\",\"if\":\"{{kwhUsed365}}\",\"function\":\"parseInt({{kwhUsed365}} * 0.2)\",\"units\":\"kWh\"},{\"id\":\"kwh365\",\"title\":\"Annual energy required\",\"if\":\"{{kwhCH365}}\",\"function\":\"parseInt('{{kwhCH365}}'||0) + parseInt('{{kwhDHW365}}'||0) + parseInt('{{kwhDistLoss365}}'||0)\",\"units\":\"kWh\"}]}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":720,"y":340,"wires":[["d2c83715.bc4ad8"]]},{"id":"a0339f75.b2c11","type":"http in","z":"cce2bfaa.e5748","name":"","url":"/ui/hndesign","method":"get","upload":false,"swaggerDoc":"","x":220,"y":220,"wires":[["8dc13cac.e444b"]]},{"id":"8dc13cac.e444b","type":"template","z":"cce2bfaa.e5748","name":"Form Generator","field":"payload.body","fieldType":"msg","format":"html","syntax":"plain","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js\"></script>\n<!--https://www.sitepoint.com/basic-jquery-form-validation-tutorial/-->\n\n<script src=\"https://unpkg.com/mustache@latest\"></script>\n\n\n\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n\n<script src=\"https://cdn.ckeditor.com/ckeditor5/34.0.0/inline/ckeditor.js\"></script>\n\n<!--These need to be installed locally-->\n<script src=\"pdfkit.standalone.js\"></script>\n<script src=\"blob-stream.js\"></script>\n<script src=\"svg-to-pdfkit.js\"></script>\n\n\n<style>\n    \n  \n    .jexcel_content {\n        font-size: 14px;\n    }\n    \n    .jexcel {\n        white-space: normal;\n    }\n\n/*for wiki*/\nli.gallerybox {\n    \n    display: inline-block;\n}\n\n.mybutt {\n    padding-left: 6px;\n    padding-right: 6px;\n    padding-top: 4px;\n    padding-bottom: 4px;\n    margin-right: 3px;\n    font-size: 14px;\n    border-radius: 4px;\n    cursor: pointer;\n    background-color: #a4eba4;\n    border-color: #4aa55a;\n    border: solid;\n    border-width: 1px;\n    box-shadow: 2px 2px 3px 1px rgb(0 0 0 / 28%);\n}\n.mybutt:hover {\n  background-color: #dcffdc;\n}\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\ntextarea.form-control {\n    font-size: 0.9rem;\n}\n\n.outputbox {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #ffffff;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n    font-size: 16px;\n}\n\n.cframe {\n    border-radius: 0.25rem;\n    margin: 0px 0px 20px 0px;\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 3px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\nvar a = new Date();\nvar qdata;\nvar calculated = {};  calculated.objects = {};\nvar hasFocus;\nvar currentSection;\nvar inputsOut;\nvar inputString;\nvar calcsString;\nvar tableArrays=[];\ntableArrays[\"calcsArray\"] = [];\n\nvar objects={}; \nvar sheets = {};\nvar sheetdata = {};\nvar initsheets;\n\n\t$(document).ready(function(e) {\n    \n        // $(\"form[ajax=true]\").submit(function(e) {\n            \n        //     //alert(\"submit\");\n            \n        //     e.preventDefault();\n        \n             \n            //var urlParams = new URLSearchParams(window.location.search);\n            //if (urlParams.get('display')) { loadstring = \",,\" + urlParams.get('display'); }\n\n            calculated[\"jsonQ\"] = \"hndesign\";\n\n            var urlParams = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParams) {\n                \n                calculated[urlParams[upa].split(\"=\")[0]] = decodeURIComponent(urlParams[upa].split(\"=\")[1]);\n                \n            }\n            \n            \n            \n            var form_data = {};\n            var form_url = \"/ui/qdata/\" + calculated[\"jsonQ\"];\n            var form_target = $(this).attr(\"target\") || \"result\";\n            var ftarget = \"#\" + form_target;\n            var form_method = \"GET\";\n            \n        //     $(\"#loadingimg\").show();\n            \n            $.ajax({\n                url: form_url, \n                type: form_method,      \n                data: form_data,     \n                cache: false,\n                success: function(results){   \n                    \n                    qdata = results;\n                    //qdata = JSON.parse(returnhtml);\n                    console.log(qdata);\n                   \n                    //if(urlParams['nBuildings']) { runCalcs(); runCalcs();  }\n                    runCalcs(); \n                    runCalcs();\n                    \n                    document.getElementById(\"formName\").innerHTML = qdata.title || \"Unamed Form\"; //JSON.stringify(qdata) ;\n                    \n                    // document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n                    \n                    // for (var sht in initsheets) {  initSheet(initsheets[sht]);   }\n                    \n                    // validform();\n                                  \n                }           \n            });    \n            \n        // });\n        \n      \n        \n    });\n\n\n    \nfunction tosvg(obid) {\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.svg\";\n    if (nn.indexOf(\".svg\")<0) { nn = nn + \".svg\"; }\n    \n    download( objects[obid].value, nn, \"image/svg+xml\")\n}\n  \n function jpegDownload(obid){\n\t    \n\t    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n        if (nn===null) { return(null); }\n        nn = nn || \"download.jpeg\";\n        if (nn.indexOf(\".jpeg\")<0) { nn = nn + \".jpeg\"; }\n        \n        var byteString = atob(objects[obid].value.split(',')[1]);\n        var mimeString = objects[obid].value.split(',')[0].split(':')[1].split(';')[0]\n\n        \n        // write the bytes of the string to an ArrayBuffer\n          var ab = new ArrayBuffer(byteString.length);\n        \n          // create a view into the buffer\n          var ia = new Uint8Array(ab);\n        \n          // set the bytes of the buffer to the correct values\n          for (var i = 0; i < byteString.length; i++) {\n              ia[i] = byteString.charCodeAt(i);\n          }\n        \n        download( ia , nn, mimeString)\n\t}\n\t\nfunction topdf(obid) {\n    \n    if (!objects[obid]) { return null; }\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.pdf\";\n    if (nn.indexOf(\".pdf\")<0) { nn = nn + \".pdf\"; }\n    \n    var headed = document.getElementById(\"headed\").innerHTML;\n    headed = headed.substr(headed.indexOf(\"<g\"));\n    headed = headed.substr(0,headed.lastIndexOf(\"</g>\")+4);\n    \n    var svgoot = objects[obid].value;\n    svgoot = svgoot.substr(svgoot.indexOf(\"<svg\"));\n    \n    var lg = svgoot.indexOf(\"<g\");\n    svgoot = svgoot.substr(0,lg) + '<g transform=\"translate(0,40)\">' + svgoot.substr(lg);\n    \n    lg = svgoot.lastIndexOf(\"</g>\")+4;\n    svgoot = svgoot.substr(0,lg) + \"</g>\" + headed + svgoot.substr(lg);\n    \n    var tits = {\"title\":\"Heatweb Heat Network Designer\",\"subtitle\":obid,\"pn\":\"1\",\"pc\":\"1\"}\n    svgoot = Mustache.render(svgoot, tits);\n    \n    //alert(svgoot);\n            $(\"#svgtext\").val(svgoot);\n            $(\"#svgfile\").val(nn);  //  + (new Date().getTime()) +\n            \n            $(\"#nextform\").submit(); \n            \n         \n}\n\nfunction topdf2(obid) {\n    \n    // without headed notepaper\n    \n    if (!objects[obid]) { return null; }\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.pdf\";\n    if (nn.indexOf(\".pdf\")<0) { nn = nn + \".pdf\"; }\n    \n    var svgoot = objects[obid].value;\n    svgoot = svgoot.substr(svgoot.indexOf(\"<svg\"));\n    \n    \n    \n    \n    //alert(svgoot);\n            $(\"#svgtext\").val(svgoot);\n            $(\"#svgfile\").val(nn);  //  + (new Date().getTime()) +\n            \n            $(\"#nextform\").submit(); \n            \n         \n}\n\n\n\n\n\nfunction initSheet(id) {\n\n    console.log(\"initSheet \" + id);\n    console.log(sheetdata);\n    \n    var shid = 'sheet-' + id;\n    var sdata = sheetdata[id];\n    \n    \n\n    try {\n    \n        document.getElementById(shid).innerHTML = \"\";\n        \n        sheets[id] = jspreadsheet(document.getElementById(shid), {\n            data: sdata.data,\n            columns: sdata.columns,\n            onchange: function(instance, cell, x, y, value) {\n                \n                console.log(value);\n                getSheetData(id);\n            },\n            updateTable:function(instance, cell, col, row, val, label, cellName) {\n               \n                //console.log(instance);\n                //console.log(val);\n                \n            },\n            columnSorting:false\n        });\n\n    } catch {}\n}\n\nfunction getSheetData(id) {\n    \n    \n    //alert(id);\n    \n    //console.log(sheets[id].getData());\n    \n    sheetdata[id].data = sheets[id].getData();\n    console.log(sheetdata);\n    \n    var oots = \"\";\n    for (var row in sheetdata[id].data) {\n       for (var c in sheetdata[id].data[row]) {\n           \n           var val = \"\" + (sheetdata[id].data[row][c] || \"\");\n           val = val.replace(/ /g,\"_\")\n           oots += val + \",\";\n        } \n        oots += \" \";\n    }\n    \n    oots = oots.substr(0, oots.length - 2);\n    console.log(oots);\n    \n    returncalc(id,oots)\n    \n    \n}\n\n\nfunction getObject(id) {\n    \n  \n    return (objects[id]||null);\n    \n}\n\n\nfunction setObject(id,value) {\n    \n\n    try { objects[id] = value; }\n    catch {}\n}\n\t\nfunction returncalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).value = value; }\n    catch {\n        \n        try { calculated[id] = value; }\n        catch {}\n    }\n    \n}\n\nfunction suggestcalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).placeholder = value + \" ... please confirm\"; }\n    catch {}\n}\n\t\nfunction parseQuestions(qdata) {\n    \n    console.log(qdata);\n    console.log(calculated);\n    \n    tableArrays[\"qArray\"] = [[\"Key\",\"Description\",\"Value\",\"Units\"]];\n    \n    var linkstxt=\"\";\n    if (qdata.links) {\n        for (var lnk in qdata.links) {\n            linkstxt += (linkstxt!==\"\"?\"<br>\":\"\") + '<a href=\"' + qdata.links[lnk].src + '\" target=\"_blank\">' + (qdata.links[lnk].title||qdata.links[lnk].src) + '</a>';\n        }\n        \n    }\n    document.getElementById(\"links\").innerHTML = linkstxt ; //JSON.stringify(qdata) ;\n    \n    \n    inputsOut = '<input id=\"jsonQ\" name=\"jsonQ\" value=\"' + calculated[\"jsonQ\"] + '\" class=\"form-control\" type=\"hidden\">';\n                    \n    \n    inputsOut += '<table class=\"table\">';\n    \n    inputString = \"jsonQ=\" + calculated[\"jsonQ\"];  // data source for form is fixed\n    \n    hasFocus = null;\n    currentSection = null;\n    initsheets = [];\n    \n    var ootoot = \"\";\n    for (var s in qdata[\"sections\"]) {\n        console.log(s);\n        console.log(qdata.sections[s]);\n        \n        var oot = \"\";\n        var ootcount=0;\n        \n        //oot += \"<div class='section'><h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        oot += \"<h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        \n        \n        \n        for (var q in qdata.sections[s].questions) {\n            \n            \n            var qif = qdata.sections[s].questions[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n            var v=\"\";\n            if (calculated[qdata.sections[s].questions[q].id]) { v= calculated[qdata.sections[s].questions[q].id] ; }\n            else if (qdata.sections[s].questions[q].value) { v= qdata.sections[s].questions[q].value ; }\n            \n            if (v!==\"\") { qdata.sections[s].questions[q].value = v; }    // save answers back into json.\n            \n            \n            if(goq) {\n                \n                var calcfr = \"\";\n                if (qdata.sections[s].questions[q].calculator) { calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].questions[q].calculator + '?field=' + qdata.sections[s].questions[q].id + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].questions[q].calculatorStyle ? qdata.sections[s].questions[q].calculatorStyle:'width:100%; height:300px;') + '\"></iframe>'}\n            \n            \n                if (v!==\"\") { \n                    inputsOut += \"<tr>\";  \n                    \n                    var cOs1 = \"\";  var cOs2 = \"\";\n            \n                    if (document.getElementById(\"hideID\").checked!==true) {\n                        cOs2 = \" <small>[<i>\" + qdata.sections[s].questions[q].id + \"</i>]</small>\";  \n                    }\n                    \n                    inputsOut += '<td width=\"40%\">' + (qdata.sections[s].questions[q].title||qdata.sections[s].questions[q].id) + cOs2 + \"</td>\";\n                    \n                    var vs1=\"\"; var vs2=\"\";\n                    if((\"\"+v).indexOf(\",\") > -1) { vs1=\"<small>\"; vs2=\"</small>\"; }\n                    if((\"\"+v).indexOf(\"&\") > -1) { vs1=\"<small style='width:400px; word-wrap:break-word; display:inline-block;'>\"; vs2=\"</small>\"; }\n                    \n                    \n                    inputsOut +=  ('<td align=\"right\">' + vs1 + v + vs2 + \"</td>\").replace(/\\, /g,\"<br>\").replace(/\\,/g,\", \");\n                    inputsOut +=  '<td width=\"14%\">' + (qdata.sections[s].questions[q].units||\"\") + \"</td></tr>\\n\";\n                    \n                    inputString += (inputString!==\"\"?\"&\":\"\") + qdata.sections[s].questions[q].id + \"=\" + encodeURIComponent(v);\n                }\n            \n                var isDisplayed = false;\n            \n                if (hasFocus && document.getElementById(\"oneQ\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">'; }\n            \n                else if (v!==\"\") { \n                    \n                    if (document.getElementById(\"hideDone\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">';   }\n                    else {  oot += '<div class=\"question\" style=\"background-color: #d2efd2;\">'; ootcount++; isDisplayed=true; }\n                    \n                } else { oot += '<div class=\"question\">'; ootcount++; isDisplayed=true; if (!hasFocus) { hasFocus = qdata.sections[s].questions[q].id;  currentSection = qdata.sections[s].title;  } }\n                \n                \n                //oot += \"<div class='qtext'>\" + qdata.sections[s].questions[q].title + '</div>';\n                oot += '<label for=\"' + qdata.sections[s].questions[q].id + '\" class=\"qtext\">' + (qdata.sections[s].questions[q].question||qdata.sections[s].questions[q].title) + '</label>';\n                \n                if (calcfr!==\"\") { oot += \"\\n\" + calcfr + \"\\n\"; }\n                \n                if (qdata.sections[s].questions[q].notes) { oot += '<div class=\"notes\">'  + convertLinks(Mustache.render(qdata.sections[s].questions[q].notes, calculated)) + '</div>'; }\n                \n                if (qdata.sections[s].questions[q].type == \"sheet\") {\n                    \n                    oot += '<br><div id=\"sheet-' + qdata.sections[s].questions[q].id + '\">';\n                \n                    oot += '<span onclick=\"initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ')\"><small class=\"mybutt\">Load Sheet</small></span> ';\n                    \n                    oot += '</div><br><br>';\n                    \n                    //oot += '<script>initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ');</scrip' + 't> ';\n                    //var myTimeout = setTimeout(initSheet(qdata.sections[s].questions[q].id), 1000);\n                    if (isDisplayed) { initsheets.push(qdata.sections[s].questions[q].id); }\n                \n                    var shob = {};\n                    shob['columns'] = qdata.sections[s].questions[q].columns;\n                    shob['data'] = qdata.sections[s].questions[q].default;\n                    \n                    if((\"\"+v)!==\"\") {\n                        \n                        shob['data']=[];\n                        var vv = v.replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                        var lns = vv.split(\", \");\n                        for (var lnsv in lns) {\n                            shob['data'].push(lns[lnsv].split(\",\"));\n                        }\n                    }\n                    \n                    sheetdata[qdata.sections[s].questions[q].id] = shob;\n                    \n                }\n                \n                \n                \n                if (qdata.sections[s].questions[q].type==\"html\") {\n                    \n                    oot += '<br><br><div class=\"form-control htmlinput\" style=\"height:fit-content\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    oot += decodeURIComponent('' + v + '')\n                    oot += '</div>';\n                \n                }\n                \n                \n                oot += '<table width=\"100%\"><tr><td width=\"80%\">';\n                \n                if (qdata.sections[s].questions[q].jsonQ) {\n                    \n                    \n                    oot += '<textarea class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    //oot += ('' + v + '').replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                    oot += decodeURIComponent('' + v + '')\n                    oot += '</textarea>';\n                    \n                } \n                \n                else if (qdata.sections[s].questions[q].type==\"html\") {\n                    \n                    oot += '';\n                    \n                   \n                \n                }\n                    \n                else if (qdata.sections[s].questions[q].type==\"boolean\") {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                      if (v==\"true\") { oot += '<option value=\"false\">No</option><option value=\"true\" selected>Yes</option>'; }\n                      else if (v==\"false\")  { oot += '<option value=\"false\" selected>No</option><option value=\"true\">Yes</option>'; }\n                      else  { oot += '<option value=\"\"></option><option value=\"false\">No</option><option value=\"true\">Yes</option>'; }\n                    oot += '</select>';\n                    \n                } else if (qdata.sections[s].questions[q].options) {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    if (v==\"\") { oot += '<option value=\"\"></option>'; }\n                    for (var opt in qdata.sections[s].questions[q].options) {\n                    \n                      var optobj = qdata.sections[s].questions[q].options[opt];\n                      \n                      \n                      if (v==optobj.value) { oot += '<option selected value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      else  { oot += '<option value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      \n                    }  \n                    oot += '</select>';\n                    \n                }  else {\n                \n                    oot += '<input id=\"' + qdata.sections[s].questions[q].id + '\" name=\"' + qdata.sections[s].questions[q].id + '\" class=\"form-control\" type=\"text\"';\n                    if (v!==\"\") { oot += (' value=\"' + v + '\"').replace(/\\%20/g,\" \").replace(/_/g,\" \"); }\n                    if (qdata.sections[s].questions[q].default) { \n                        \n                        oot += ' placeholder=\"' + Mustache.render(\"\"+qdata.sections[s].questions[q].default, calculated)  + \" \" + (qdata.sections[s].questions[q].units||\"\") + ' ... please confirm\"'; \n                        \n                    }\n                    oot += '>';\n                }\n                \n                oot += '</td><td valign=\"top\"><span class=\"qunits\">' + (qdata.sections[s].questions[q].units||\"\") + '</span></td></tr></table>';\n                \n                \n                \n                oot += '</div>\\n';\n                \n                \n                tableArrays.qArray.push([qdata.sections[s].questions[q].id,qdata.sections[s].questions[q].title||\"\".id,(\"\"+v).replace(/\\,/g,\", \"),qdata.sections[s].questions[q].units||\"\"]);\n       \n            }\n        }\n    \n        oot += '<table width=\"100%\"><tr><td width=\"100%\" align=\"right\"><button class=\"mybutt\" type=\"submit\">Submit</button></td></tr></table>';\n\n        oot += \"</div>\\n\";\n       \n        \n        var outhtml = \"\";   \n        for (var q in qdata.sections[s].outputs) {\n            \n            var qif = qdata.sections[s].outputs[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n\n            if(goq && (calcsString||\"\")!==\"\") {\n                \n                var calcfr = \"\";\n                //if (!objects[qdata.sections[s].outputs[q].id]) { objects[qdata.sections[s].outputs[q].id] = {}; }\n                \n                if (qdata.sections[s].outputs[q].type==\"wiki\") { \n                    \n                    var oid = 'output'+qdata.sections[s].outputs[q].id;\n                    \n                    //qdata.sections[s].outputs[q].url\n                    //http://heatweb.co.uk/w/index.php?title=The_DATA_HIU#Description\n                    \n                    qdata.sections[s].outputs[q].url = qdata.sections[s].outputs[q].url.replace(\"http://heatweb.co.uk/w/index.php?title=\",\"\").replace(\"https://heatweb.co.uk/w/index.php?title=\",\"\")\n                    \n                    var tit = qdata.sections[s].outputs[q].url;\n                    if (tit.indexOf(\"#\")>-1) { tit = qdata.sections[s].outputs[q].url.split(\"#\")[0]; }\n                    \n                    var wikilocal = \"hnoutputs/wiki?id=\" + qdata.sections[s].outputs[q].id + \"&des=\" + qdata.sections[s].outputs[q].title.replace(/ /g,\"_\") + \"&title=\" + tit;\n                    if(qdata.sections[s].outputs[q].url.split(\"#\")[1]) { wikilocal += \"&section=\" + qdata.sections[s].outputs[q].url.split(\"#\")[1]; }\n                \n                    \n                    outhtml += prepWebPage(qdata.sections[s].outputs[q],wikilocal);\n                    \n                    \n                    \n                }\n                else if (qdata.sections[s].outputs[q].type==\"heatwebcouk\") { \n                    \n                    var oid = 'output'+qdata.sections[s].outputs[q].id;\n                    \n                    //qdata.sections[s].outputs[q].url\n                    //https://www.heatweb.co.uk/district-heating-substations/heating-substations/\n                    \n                    //qdata.sections[s].outputs[q].url = qdata.sections[s].outputs[q].url.replace(\"https://www.heatweb.co.uk/w/index.php?title=\",\"\").replace(\"https://heatweb.co.uk/w/index.php?title=\",\"\")\n                    \n                    var sec = \"\";\n                    var tit = qdata.sections[s].outputs[q].url.replace(\"https://www.heatweb.co.uk/\",\"\").replace(\"https://heatweb.co.uk/\",\"\");\n                    if (tit.indexOf(\"/\")>-1) { tit = qdata.sections[s].outputs[q].url.split(\"/\")[0]; sec = qdata.sections[s].outputs[q].url.split(\"/\")[1]; }\n                    \n                    var wikilocal = \"hnoutputs/wiki?id=\" + qdata.sections[s].outputs[q].id + \"&des=\" + qdata.sections[s].outputs[q].title.replace(/ /g,\"_\") + \"&title=\" + tit;\n                    if(sec) { wikilocal += \"&section=\" + sec; }\n                \n                    wikilocal += \"&type=\" + qdata.sections[s].outputs[q].type;\n                    wikilocal += \"&url=\" + encodeURIComponent(qdata.sections[s].outputs[q].url);\n                    outhtml += prepWebPage(qdata.sections[s].outputs[q],wikilocal);\n                    \n                    \n                    \n                }\n                else if (qdata.sections[s].outputs[q].url) { \n                    \n                    calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].outputs[q].url + (qdata.sections[s].outputs[q].url.indexOf(\"?\")>0?'':'?') + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].outputs[q].style ? qdata.sections[s].outputs[q].style:'width:100%; height:300px;') + '\"></iframe>'\n                    \n                    outhtml += '<div class=\"outputbox\">';\n                    outhtml += \"<table width='100%'><tr><td><b>\" + qdata.sections[s].outputs[q].title + \"</b></td>\\n\";\n                    \n                    if (qdata.sections[s].outputs[q].buttons) { \n                        \n                        outhtml += '<td align=\"right\">';\n                        for (var btn in qdata.sections[s].outputs[q].buttons) {\n                            \n                            outhtml += '<span class=\"mybutt\" onclick=\"' + qdata.sections[s].outputs[q].buttons[btn].onClick + '\">' + qdata.sections[s].outputs[q].buttons[btn].text + '</span> ';\n                        }\n                        outhtml += '</td>';\n                    }\n                    \n                    outhtml += '</tr></table><br>';\n                    \n                    outhtml += calcfr ; \n                    \n                    \n                    \n                    outhtml += \"</div>\\n\";\n                }\n            \n            }\n        }\n        \n        if (outhtml!==\"\") {\n            \n            //oot += '<div class=\"outputbox\">';\n            oot += outhtml;\n            //oot += \"</div>\\n\";\n        }\n        \n        \n        \n        \n        \n        if (document.getElementById(\"oneS\").checked==true && (currentSection != qdata.sections[s].title)) {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n        else if (ootcount>0) {  ootoot += \"<div class='section'>\" + oot; }\n        \n        else {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n    }\n    inputsOut +=  \"</table>\\n\";  \n    \n    return ootoot;\n}\n\nfunction prepWebPage(qd,url) {\n                    \n    var nn = \"\"+ qd.id;\n    var des = \"\" + qd.title;\n    if (qd[\"maxImageHeight\"]) { var maxImageHeight = qd[\"maxImageHeight\"]; }\n    \n    var outhtml='';\n    \n    $.ajax({\n        url: url, \n        type: \"GET\",      \n        data: {},     \n        cache: false,\n        success: function(results){   \n            \n            \n            var obid = results.split('obid=\"')[1].split('\"')[0];\n            var des = results.split('title=\"')[1].split('\"')[0];\n            \n            console.log('#'+obid);\n            console.log(results);\n            var opb = document.querySelector('#output'+obid);\n            opb.innerHTML = results || \"No Data\"; //JSON.stringify(qdata) ;\n            //document.getElementById(\"output\"+qd.id).innerHTML = results || \"No Data\"; //JSON.stringify(qdata) \n            \n            feImages(results);\n            \n            var myob = {};\n            myob.id = obid;\n            myob.filename = obid + \".html\";\n            myob.page = des;\n            myob.type = \"text/html\";\n            if (maxImageHeight) { myob[\"maxImageHeight\"]=maxImageHeight; }\n            myob.value = \"\" + results;\n            try { setObject(obid, myob); } catch {}\n            myob = null;\n            \n            \n            \n        }           \n    });    \n    \n    \n    //calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qd.url + (qd.url.indexOf(\"?\")>0?'':'?') + (calcsString||\"\") + '\" style=\"' + (qd.style ? qd.style:'width:100%; height:300px;') + '\"></iframe>'\n    var calcfr = '<div id=\"output'+qd.id + '\">waiting... ' + qd.id + '</div>'\n    \n    outhtml += '<div class=\"outputbox\">';\n    outhtml += \"<table width='100%'><tr><td><b>WIKI: \" + qd.title + \"</b></td>\\n\";\n    \n    if (qd.buttons) { \n        \n        outhtml += '<td align=\"right\">';\n        for (var btn in qd.buttons) {\n            \n            outhtml += '<span class=\"mybutt\" onclick=\"' + qd.buttons[btn].onClick + '\">' + qd.buttons[btn].text + '</span> ';\n        }\n        outhtml += '</td>';\n    }\n    \n    outhtml += '</tr></table><br>';\n    \n    outhtml += calcfr ; \n    \n    \n    \n    outhtml += \"</div>\\n\";\n    \n    return (outhtml);\n    \n}\n\n\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\n// console.log(looseJsonParse(\n//   \"{a:(4-1), b:function(){}, c:new Date()}\"\n// ))\n\nfunction runCalcs() {\n\n\n    calcsString = \"\";\n    tableArrays.calcsArray = [[\"key\",\"Description\",\"Value\",\"Units\"]];\n    \n    // run through form inputs and store current values into calculated.\n    var cells =  document.getElementsByClassName(\"form-control\");\n\tvar i;\n\tfor (i = 0; i < cells.length; i++) {\n\t\n\t    \n\t    \n\t\n\t\tcalcsOut += cells[i].value + \"<br>\\n\";\n        \n        if (\"\" + cells[i].value !== \"\") { \n            \n            if (isNaN(cells[i].value)) { \n                \n                if ((cells[i].classList+\" \").indexOf(\"htmlinput\")>-1) {     // && cells[i].classList.indexOf(\"ck\")>-1\n                    \n                    calculated[cells[i].id] = cells[i].innerHTML;\n                }\n                else {\n                    \n                    calculated[cells[i].id] = (cells[i].value);\n                \n                    if ((calculated[cells[i].id]+\" \").substr(0,1)==\"{\" || (calculated[cells[i].id]+\" \").substr(0,1)==\"[\") {    // detect objects in textboxes\n                        \n                        try  { calculated.objects[cells[i].id] = JSON.parse(calculated[cells[i].id]) } catch {  }\n                    }\n                \n                }\n               \n                \n            } else {\n                \n                calculated[cells[i].id] = parseFloat(cells[i].value);\n            }\n            \n            calcsString += \"&\" + cells[i].id + \"=\" + cells[i].value;\n        }\n\t}\n\t\n    var calcsOut = '<table class=\"table\">';\n    \n    //calculated.objects = objects;\n    \n    // ================== Sheet Custom Calculations\n    \n    \n    if (calculated['loadSchedule']) {\n        \n        console.log(\"Load Schedule = \" + calculated['loadSchedule']);\n        \n        \n            \n            var cv1 = calculated['loadSchedule'];\n            var cv = 0;\n            var np = 0;\n            var kwCHMax = 0;\n            \n            var ldata=[];\n            \n            if((\"\"+cv1)!==\"\") {\n                \n                var vv = (\"\"+cv1).replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                var lns = vv.split(\", \");\n                for (var lnsv in lns) {\n                    ldata.push(lns[lnsv].split(\",\"));\n                    \n                    cv = cv + parseFloat(lns[lnsv].split(\",\")[4])\n                    \n                    np = np + (parseFloat(lns[lnsv].split(\",\")[2]) * parseFloat(lns[lnsv].split(\",\")[4]));\n                    \n                    kwCHMax = kwCHMax + (parseFloat(lns[lnsv].split(\",\")[3]) * parseFloat(lns[lnsv].split(\",\")[4]));\n                    \n                    \n                }\n            }\n            \n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total Properties</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">properties</td></tr>\\n';\n            \n            calculated['nProperties'] = cv;\n            calcsString += \"&nProperties=\" + cv;\n            \n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total People</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + np + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">people</td></tr>\\n';\n            \n            calculated['nPeople'] = np;\n            calcsString += \"&nPeople=\" + np;\n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total of central heating outputs</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + kwCHMax + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">kW</td></tr>\\n';\n            \n            calculated['kwCHMax'] = kwCHMax;\n            calcsString += \"&kwCHMax=\" + kwCHMax;\n            \n        \n        \n    }\n    \n    \n    // ================================\n    \n    \n    for (var calc in (qdata[\"calculations\"]||[])) {\n        \n        console.log(calc);\n        console.log(qdata.calculations[calc]);\n        \n        var cif = qdata.calculations[calc].if || true;\n        var cift = Mustache.render(cif, calculated);\n        var goc = true;\n        try {\n          goc = looseJsonParse(cift); \n        }\n        catch(err) {\n          goc = false;\n        }\n        \n        if (goc) {\n            \n            var f = qdata.calculations[calc].function;\n            var ft = Mustache.render(f, calculated);\n            \n            calcsOut += \"<tr>\";  //<td>\" + qdata.calculations[calc].id + \"</td>\";\n            calcsOut += \"<td>\";\n            \n            var cOs1 = \"\";  var cOs2 = \"\";\n            \n            if (document.getElementById(\"hideID\").checked!==true) {\n                cOs2 = \" <small>[<i>\" + qdata.calculations[calc].id + \"</i>]</small>\";  \n            }\n            \n            calcsOut += cOs1 + (qdata.calculations[calc].title||qdata.calculations[calc].id) + cOs2 + \"</td>\";\n            \n            //calcsOut += f + \" = \";\n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small>\" + ft.replace(/\\,/g,\", \") + \"</small></td>\";   //\"<br>\\n\";\n            }\n            \n            var cv = \"\";\n            try {\n              cv = looseJsonParse(ft); //  looseJsonParse(\"{a:(4-1), b:function(){}, c:new Date()}\");\n            }\n            catch(err) {\n              \n            }\n             \n            \n            if (!isNaN(cv)) { cv = parseInt(cv*1000)/1000; }\n            \n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            \n            calcsOut +=  '<td width=\"14%\">' + (qdata.calculations[calc].units||\"\") + \"</td></tr>\\n\";\n            \n            calculated[qdata.calculations[calc].id] = cv;\n            calcsString += \"&\" + qdata.calculations[calc].id + \"=\" + cv;\n            \n            tableArrays.calcsArray.push([qdata.calculations[calc].id,qdata.calculations[calc].title||\"\".id,cv,qdata.calculations[calc].units]);\n        }\n        \n    }\n    \n    calcsOut +=  \"</table>\\n\";\n    \n    // for (var calc in calculated) {\n        \n        \n    // }\n    \n    document.getElementById(\"calcs\").innerHTML = calcsOut; //JSON.stringify(qdata) ;\n    \n    // rebuild form\n    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"inputs\").innerHTML = inputsOut; //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"mylink\").innerHTML = '<a href=\"hndesign?' + inputString + '\" target=\"_blank\">Open/share design...</a>'; //JSON.stringify(qdata) ;\n    \n    if(document.getElementById(\"description\")) {  // work in progress - need to link to all\n        InlineEditor\n                .create( document.querySelector( '#description' ) )\n                .catch( error => {\n                    console.error( error );\n                } );\n        \n        for (var sht in initsheets) {  initSheet(initsheets[sht]);   }\n    }\n    \n    validform();\n                    \n}\n\n\nconst convertLinks = ( input ) => {\n\n  let text = input;\n  const linksFound = text.match( /(?:www|https?)[^\\s]+/g );\n  const aLink = [];\n\n  if ( linksFound != null ) {\n\n    for ( let i=0; i<linksFound.length; i++ ) {\n      let replace = linksFound[i];\n      if ( !( linksFound[i].match( /(http(s?)):\\/\\// ) ) ) { replace = 'http://' + linksFound[i] }\n      let linkText = replace.split( '/' )[2];\n      if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) }\n      if ( linkText.match( /youtu/ ) ) {\n\n        let youtubeID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://www.youtube.com/embed/' + youtubeID + '\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe></div>' )\n      }\n      else if ( linkText.match( /vimeo/ ) ) {\n        let vimeoID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://player.vimeo.com/video/' + vimeoID + '\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' )\n      }\n      else {\n        aLink.push( '<a href=\"' + replace + '\" target=\"_blank\">' + linkText + '</a>' );\n      }\n      text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] );\n    }\n    return text;\n\n  }\n  else {\n    return input;\n  }\n}\n\nfunction validform() {\n    \n    if(hasFocus && document.getElementById(hasFocus)) {\n        document.getElementById(hasFocus).focus();\n    }\n    \n    \n    \n// Initialize form validation on the registration form.\n  // It has the name attribute \"registration\"\n  $(\"form[name='qform']\").validate({\n    // Specify validation rules\n    rules: {\n      // The key name on the left side is the name attribute\n      // of an input field. Validation rules are defined\n      // on the right side\n    //   nProperties: {\n    //     required: true,\n    //     digits: true,\n    //     min: 1\n    //   },\n      lastname: \"required\",\n      email: {\n        required: true,\n        // Specify that email should be validated\n        // by the built-in \"email\" rule\n        email: true\n      },\n      password: {\n        required: true,\n        minlength: 5\n      }\n    },\n    // Specify validation error messages\n    messages: {\n      nProperties: \"Please enter a number.\",\n      lastname: \"Please enter your lastname\",\n      password: {\n        required: \"Please provide a password\",\n        minlength: \"Your password must be at least 5 characters long\"\n      },\n      email: \"Please enter a valid email address\"\n    },\n    // Make sure the form is submitted to the destination defined\n    // in the \"action\" attribute of the form when valid\n    submitHandler: function(form) {\n      //form.submit();\n      runCalcs();\n      //alert(\"hello\");\n    }\n  });\n}\n\n</script>\n\n\n<div class='section'>\n    \n    <table width=\"100%\"><tr>\n    <td valign=\"top\" width=\"70%\">\n        <div id=\"formName\" class=\"h1\"></div>\n        <a href=\"https://heatweb.co.uk/w/index.php?title=Heat_Network_Designer\" target=\"_blank\"><small>Wiki Help Page</small></a>\n    </td>\n    <td width=\"30%\">\n        <input type=\"checkbox\" id=\"oneS\" name=\"oneS\" checked> <small>One section at a time</small><br>\n        <input type=\"checkbox\" id=\"oneQ\" name=\"oneQ\" checked> <small>One question at a time</small><br>\n        <input type=\"checkbox\" id=\"hideDone\" name=\"hideDone\" checked> <small>Hide completed questions</small><br>\n        <input type=\"checkbox\" id=\"hideMaths\" name=\"hideMaths\" checked> <small>Hide maths equations</small><br>\n        <input type=\"checkbox\" id=\"hideID\" name=\"hideID\" checked> <small>Hide IDs</small>\n    </td>\n    </tr></table>\n</div>\n\n<form action=\"\" name=\"qform\" id=\"qform\">\n\n<div class='section'>\n\n<table width=\"100%\"><tr><td><span class=\"mybutt\" onclick=\"onDownload()\">Download JSON</span> <span class=\"mybutt\" onclick=\"copyData()\">Copy Data</span> <span class=\"mybutt\" onclick=\"copylink()\">Copy Link</span> <span class=\"mybutt\" onclick=\"openlink()\">Open in New</span> <span class=\"mybutt\" onclick=\"shareTwitter()\">Tweet Design</span> <span  class=\"mybutt\"  onclick=\"showPDF()\">Generate PDF</span> <span class=\"mybutt\" onclick=\"downloadp()\">Download PDF</span> </td><td align=\"right\"><button class=\"mybutt\" type=\"submit\">Submit</button></td></tr></table>\n\n\n\n\n</div>\n\n\n    \n\n<div id=\"pdfframebox\" class='outputbox' style='padding: 0px; display:none;'>\n\n    <iframe  id=\"pdfframe\" width=\"100%\" height=\"1200px\"></iframe>\n\n</div>\n\n\n\n\n<div id=\"section1\"></div>\n\n<script>\n\n\n    \n\n   function download(content, fileName, contentType) {\n       \n       if(!contentType) contentType = 'application/octet-stream';\n\t\t  const a = document.createElement(\"a\");\n\t\t  const file = new Blob([content], { type: contentType });\n\t\t  a.href = URL.createObjectURL(file);\n\t\t  a.download = fileName;\n\t\t  a.click();\n\t}\n\n\tfunction onDownload(){\n\t    \n\t    var jsonData = { \"url\": (window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString),\"calculated\": calculated, \"qdata\": qdata, \"objects\": objects };\n\t\tdownload(JSON.stringify(jsonData), \"hndesign.json\", \"text/plain\");\n\t}\n    \n   \n    \n    function copyData(){\n\t    \n\t    var jsonData = calculated ;\n\t\tnavigator.clipboard.writeText(JSON.stringify(jsonData));\n\t\talert(\"Data Copied to Clipboard\");\n\t}\n    \n    \n    function copylink() {\n        \n        //alert(window.location.href.split(\".svg\")[0]+\".svg&display=\"+displayed);\n        \n        navigator.clipboard.writeText(window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\"));  //\n        alert(\"Link Copied to Clipboard\");\n         \n    \n    }\n    \n    function openlink() {\n        \n        //alert(window.location.href.split(\".svg\")[0]+\".svg&display=\"+displayed);\n        \n        window.open(window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\"));  //\n        \n         \n    \n    }\n    \n    function shareTwitter() {       \n        \n        var text = \"My latest heat network design.\";\n        var url = window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\");\n        window.open('http://twitter.com/share?url='+encodeURIComponent(url)+'&text='+encodeURIComponent(text), '', 'left=0,top=0,width=550,height=450,personalbar=0,toolbar=0,scrollbars=0,resizable=0');\n\n    } \n\n</script>\n\n\n<div class='section'>\n<p><b>Inputs</b></p>\n<div id=\"inputs\" class=\"notes\"></div>\n</div>\n\n<div class='section'>\n<p><b>Numeric Values and Calculations</b></p>\n<div id=\"calcs\" class=\"notes\"></div>\n</div>\n\n\n<div class='section'>\n<p><b>Links</b><img style=\"padding:25px\" src=\"/files/images/heatwebsl.png\" width=\"200px\" align=\"right\"></p>\n<div id=\"mylink\" class=\"notes\"></div>\n<div id=\"links\" class=\"notes\"></div>\n\n\n\n</div>\n</form>\n\n\n\n\n <form id=\"nextform\" name=\"nextform\" method=\"post\" action=\"/api/print\" ajax=\"true\" target=\"result1\">\n    <input type=\"hidden\" id=\"svgtext\" name=\"svgtext\" value=\"\">\n    <input type=\"hidden\" id=\"svgfile\" name=\"svgfile\" value=\"\">\n    <input type=\"hidden\" id=\"show\" name=\"show\" value=\"\">\n    </form>\n <iframe width=\"100%\" frameborder=\"0\" id=\"result1\" name=\"result1\" style=\"display:none\"></iframe>\n\n<div id=\"headed\" style=\"display:none\">\n    <svg\n   xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n   xmlns:cc=\"http://creativecommons.org/ns#\"\n   xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n   xmlns:svg=\"http://www.w3.org/2000/svg\"\n   xmlns=\"http://www.w3.org/2000/svg\"\n   xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n   id=\"svg1156\"\n   version=\"1.1\"\n   viewBox=\"0 0 210 297\"\n   height=\"297mm\"\n   width=\"210mm\">\n  <defs\n     id=\"defs1150\" />\n  <metadata\n     id=\"metadata1153\">\n    <rdf:RDF>\n      <cc:Work\n         rdf:about=\"\">\n        <dc:format>image/svg+xml</dc:format>\n        <dc:type\n           rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\n        <dc:title></dc:title>\n      </cc:Work>\n    </rdf:RDF>\n  </metadata>\n  <g\n     id=\"layer1\">\n    <path\n       id=\"path973\"\n       d=\"M 4.7230732,285.08269 H 204.21415\"\n       style=\"opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1\" />\n    <image\n       width=\"33.573963\"\n       height=\"10.040811\"\n       preserveAspectRatio=\"none\"\n       xlink:href=\"data:image/png;base64,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 PAAAAABJRU5ErkJggg== \"\n       id=\"image970\"\n       x=\"6.2852573\"\n       y=\"5.9025064\" />\n    <path\n       id=\"path973-9\"\n       d=\"M 4.7230731,18.88226 H 204.21415\"\n       style=\"opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1\" />\n    <text\n       id=\"text1007\"\n       y=\"289.65405\"\n       x=\"108.3\"\n       style=\"font-style:normal;font-weight:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:2.82222223px;text-align:center;text-anchor:middle;stroke-width:0.26458332\"\n         y=\"289.65405\"\n         x=\"108.3\"\n         id=\"tspan1005\">Page {{pn}} of {{pc}}</tspan></text>\n    <text\n       id=\"text1007-5\"\n       y=\"9.4398441\"\n       x=\"203.11298\"\n       style=\"font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:4.23333311px;text-align:end;text-anchor:end;stroke-width:0.26458332\"\n         y=\"9.4398441\"\n         x=\"203.11298\"\n         id=\"tspan1005-2\">{{title}}</tspan></text>\n    <text\n       id=\"text1007-5-0\"\n       y=\"14.542536\"\n       x=\"203.11298\"\n       style=\"font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:3.17499995px;text-align:end;text-anchor:end;stroke-width:0.26458332\"\n         y=\"14.542536\"\n         x=\"203.11298\"\n         id=\"tspan1005-2-7\">{{subtitle}}</tspan></text>\n  </g>\n</svg>\n</div>\n\n\n\n<script>\n    \n\nvar filesLoaded = 0;\n\nvar files = {\n  img1: {\n    url: \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  },\n  img2: {\n    url: \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  },\n  img3: {\n    url:\n      \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  }\n};\n\nvar fonts = {\n  f1: {\n    url: \"https://hw7.ddns.net/ui/fonts/Roboto-Regular.ttf\"\n  },\n  f2: {\n    url: \"https://hw7.ddns.net/ui/fonts/Roboto-Bold.ttf\"\n  },\n  f3: {\n    url:\n      \"https://hw7.ddns.net/ui/fonts/Roboto-Italic.ttf\"\n  },\n  f4: {\n    url:\n      \"https://hw7.ddns.net/ui/fonts/Roboto-BoldItalic.ttf\"\n  }\n};\n\nvar doc;\n\n\nfunction loadedFile(xhr) {\n  for (var file in files) {\n    if (files[file].url === xhr.responseURL) {\n      files[file].data = xhr.response;\n    }\n  }\n  filesLoaded += 1;\n  \n  console.log(xhr);\n  \n  if (filesLoaded == Object.keys(files).length) {\n    // showPDF();\n  }\n}\n\n\n\nfor (var file in files) {\n  files[file].xhr = new XMLHttpRequest();\n  files[file].xhr.onreadystatechange = function() {\n    if (this.readyState == 4 && this.status == 200) {\n      loadedFile(this);\n    }\n  };\n  files[file].xhr.responseType = \"arraybuffer\";\n  files[file].xhr.open(\"GET\", files[file].url);\n  files[file].xhr.send(null);\n}\n\nfor (var font in fonts) {\n  fonts[font].xhr = new XMLHttpRequest();\n  fonts[font].xhr.onreadystatechange = function() {\n    if (this.readyState == 4 && this.status == 200) {\n      //loadedFile(this);\n      console.log(\"font...\");\n      console.log(fonts[font].xhr)\n    }\n  };\n  fonts[font].xhr.responseType = \"arraybuffer\";\n  fonts[font].xhr.open(\"GET\", fonts[font].url);\n  fonts[font].xhr.send(null);\n}\n\n\n\nfunction prepImage (imid, imurl) {\n    \n       files[imid] = {};\n       files[imid][\"url\"] = imurl;\n    \n    //for (var file in files) {\n      files[imid].xhr = new XMLHttpRequest();\n      files[imid].xhr.onreadystatechange = function() {\n        if (this.readyState == 4 && this.status == 200) {\n          loadedFile(this);\n          console.log(files);\n        }\n      };\n      files[imid].xhr.responseType = \"arraybuffer\";\n      files[imid].xhr.open(\"GET\", files[imid].url);\n      files[imid].xhr.send(null);\n    //}\n   \n}\n\nfunction feImages(htmlt) {\n    \n    var bits = htmlt.split('src=\"');\n    //var hoot = \"\";\n    \n    var ic=0;\n    for (var i in bits) {\n        \n        ic++;\n        \n        if (ic>1) {  \n            \n            try {\n            \n                var src = bits[i].split('\"')[0];\n                \n                // bits[i] = bits[i].substr(bits[i].indexOf('\"'));\n                \n                var fn = src.substr(src.lastIndexOf(\"/\")+1);\n                fn = fn.replace(/ /g,\"_\").replace(/\\./g,\"_\").toLowerCase();\n                \n                console.log(fn + \" ... \" + src);\n                \n                prepImage (fn, src);\n                \n                //src = \"/ui/w/images/\" + src;\n                \n                // bits[i] = 'src=\"' + src + bits[i]; \n                \n                \n            } catch {}\n            \n            \n        }\n        \n        \n        //hoot += bits[i];\n    }\n\n}\n\n// =============================================== PDF\n\nvar layoutP = {\n      layout: \"portrait\",\n      size: 'A4',\n      margins: {\n        top: 60,\n        bottom: 60,\n        left: 60,\n        right: 60\n      }\n    };\n\nvar docL = layoutP.margins.left;\nvar docW = 595 - layoutP.margins.left - layoutP.margins.right;\nvar curSec = \"\";\nvar tableCount = 0;\n\nvar stdFontSize = 11.5;\n\n    \nfunction showPDF() {\n    \n    if (qdata && qdata.pdfOptions && qdata.pdfOptions[\"fontSize\"]) { stdFontSize = parseFloat(qdata.pdfOptions[\"fontSize\"]) ; }\n\n    \n    tableCount=0;\n    \n    \n     doc = new PDFDocument(layoutP);\n       \n    var stream = doc.pipe(blobStream());\n\n    stream.on(\"finish\", function() {\n       // get a blob you can do whatever you like with\n      blob = stream.toBlob(\"application/pdf\");\n    \n      const url = stream.toBlobURL('application/pdf');\n      const iframe = document.querySelector('#pdfframe')\n      iframe.src = url;\n      \n      document.getElementById(\"pdfframebox\").style.display = 'block';\n      \n    });   \n   \n   \n   //doc.registerFont('Standard', fonts.f1.xrh.response, \"object\");\n   \n   var pc = 0;\n   var posy = 100;\n   var lastpage = \"-1\";\n   \n   // doc.on('pageAdded', () => standardStuff(curSec,false););\n\n   standardStuff(\"Inputs\",true);\n   pdftable(tableArrays.qArray, {\"widths\":[100,210,110,60],\"align\":[\"left\",\"left\",\"right\",\"left\"], \"title\":\"Inputs\", \"fontSize\":9});\n   \n   doc.addPage(layoutP);\n  \n   if (tableArrays.calcsArray && tableArrays.calcsArray.length>1) {\n       standardStuff(\"Calculations\",true);\n       pdftable(tableArrays.calcsArray, {\"widths\":[100,240,80,60],\"align\":[\"left\",\"left\",\"right\",\"left\"], \"title\":\"Calculations\", \"fontSize\":9});\n       doc.addPage(layoutP);\n   }\n    \n\n       \n   for (var oo in objects) {\n       \n       \n       if(posy>600 || objects[oo].page!==lastpage) {  \n           \n            pc++;\n            posy = 100;\n           \n            if (lastpage!==\"-1\") { doc.addPage(layoutP);  }\n        \n            standardStuff(objects[oo].page||objects[oo].id,true);\n        }\n       \n        lastpage = objects[oo].page;\n       \n        doc.fontSize(12);\n        doc.moveDown();\n       \n        if (objects[oo].text) {\n        \n            //doc.moveDown();\n            doc.fontSize(stdFontSize);\n            doc.fillColor(\"black\");\n            doc.font(\"Helvetica\");\n            doc.text(objects[oo].text, {\n              width: docW,\n              align: 'justify',\n              lineGap: 4\n            }\n            );\n        \n        }\n        \n        if (objects[oo].type==\"image/jpeg\") {\n            \n            //doc.image(objects[oo].value, 50, posy, { fit: [500, 300] });\n            \n            \n            doc.moveDown();\n            \n            \n            doc.image(objects[oo].value, { width: docW });\n            \n            \n            posy = posy + 300;\n        }\n        else if (objects[oo].type==\"image/svg+xml\") {\n           \n            SVGtoPDF(doc,  objects[oo].value,docL-15,150,{\"width\":docW+40, \"preserveAspectRatio\":\"xMinYMin\"});\n            \n            posy = 9999;\n            \n        }\n        \n        else if (objects[oo].type==\"text/html\") {\n           \n            var secs = objects[oo].value.split(\"\\n\");\n            var inlist = false;\n            var lilist = [];\n            \n            var intable = false;\n            var intabledata = [];\n            var tabletext = \"\";\n            \n            var galleryW = (docW / 2) - 10;\n            var galleryH = (docW / 2) - 10;\n            var ingallery = false;\n            var nextX = 1 * docL;\n            var nextY = 100;\n            var lastX = 1 * docL;\n            \n            console.log(secs);\n            \n            doc.moveUp();  // to counter first moveDown\n            \n            var secscnt = 0;\n            \n            for (var sss in secs) { \n             \n                \n                \n                var txt = secs[sss].replace(/(<([^>]+)>)/gi, \"\");\n                txt = txt.replace(/&/g, \"&\");\n                txt = txt.replace(/ /g, \" \");\n             \n                console.log(txt);\n                console.log(secs[sss]);\n                \n                \n                if (txt.trim()!==\"\" && secs[sss].indexOf(\"<p>\")>-1)    {\n                    \n                    secscnt++;\n                    doc.moveDown();\n                    doc.fontSize(stdFontSize);\n                    doc.fillColor(\"black\");\n                    doc.font(\"Helvetica\");\n                    \n                    if (ingallery) { \n                        \n                        doc.fontSize(9);\n                        doc.fillColor(\"black\");\n                        doc.font(\"Helvetica-BoldOblique\");\n                            \n                        doc.text(txt, lastX, doc.y, {\n                          width: 250,\n                          align: 'center'\n                        } );\n                        \n                    } else { \n                            \n                        doc.text(txt, docL, doc.y, {\n                          width: docW,\n                          align: 'justify',\n                          lineGap: 4\n                        } );\n                    }\n                    \n                    \n                }\n                else if (txt.trim()!==\"\" && secs[sss].indexOf(\"<h2\")>-1)    {\n                    \n                    \n                    ingallery=false;\n                    \n                    if((secscnt>1) || (objects[oo].page||objects[oo].id)!==txt) {   // dont repeat section title\n                        \n                        secscnt++;\n                        \n                        if(secscnt>1) { doc.moveDown(2); }\n                        \n                        if (doc.y > 700) {\n                            doc.addPage(layoutP);\n                            standardStuff(curSec,false);\n                            doc.moveDown();\n                            secscnt=1;\n                        }\n                        \n                        \n                        \n                        doc.fontSize(16);\n                        doc.fillColor(\"black\");\n                        doc.font(\"Helvetica-Bold\");\n                        doc.text(txt, docL, doc.y, {\n                          width: docW,\n                          align: 'justify'\n                        }\n                        );\n                    }\n                    \n                    \n                } else if (txt.trim()!==\"\" && secs[sss].indexOf(\"<h3\")>-1)    {\n                    \n                    \n                    \n                    ingallery=false;\n                    \n                    if((secscnt>1) || (objects[oo].page||objects[oo].id)!==txt) {   // dont repeat section title\n                        \n                        secscnt++;\n                        \n                        if(secscnt>1) { doc.moveDown(2);  }\n                        \n                        if (doc.y > 700) {\n                            doc.addPage(layoutP);\n                            standardStuff(curSec,false);\n                            doc.moveDown();\n                            secscnt=1;\n                        }\n                        \n                        \n                        \n                        doc.fontSize(14);\n                        doc.fillColor(\"black\");\n                        doc.font(\"Helvetica-Bold\");\n                        doc.text(txt,  docL, doc.y, {\n                          width: docW,\n                          align: 'justify'\n                        }\n                        );\n                    }\n                }\n                else if (txt.trim()!==\"\" && secs[sss].substr(0,3)==\"<ul\")    {\n                    \n                    \n                    \n                    console.log(\"<ul>\");\n                    inlist = true;\n                    ingallery=false;\n                    lilist.push(txt);\n                    \n                } else if (txt.trim()!==\"\" && secs[sss].indexOf(\"<li>\")>-1)    {\n                    \n                    console.log(\"<li>\");\n                    inlist = true\n                    lilist.push(txt);\n                    \n                } \n                \n                \n                \n                if (secs[sss].indexOf(\"</ul>\")>-1)    {\n                    \n                    inlist = false;\n                    ingallery=false;\n                    \n                    if(lilist.length>1 || (lilist[0] && lilist[0].length>1)) {\n                    \n                        console.log(lilist);\n                        secscnt++;\n                        doc.moveDown();\n                        \n                        doc.fontSize(stdFontSize);\n                        doc.fillColor(\"black\");\n                        doc.font(\"Helvetica\");\n                        doc.list(lilist,  docL, doc.y, {\n                          width: docW,\n                          align: 'justify',\n                          paragraphGap: 5,\n                          lineGap: 2\n                        }\n                        );\n                    \n                    }\n                    \n                    lilist=[];\n                }\n                \n                if (secs[sss].indexOf(\"<table\")>-1)    {\n                    \n                    console.log(\"<table>\");\n                    intable = true;\n                    tabletext = \"\";\n                    tabletext += secs[sss].substr(secs[sss].indexOf(\"<table\")).trim();\n                    \n                    \n                } \n                else if (secs[sss].indexOf(\"</table>\")>-1)    {\n                    \n                    intable = false;\n                    ingallery = false;\n                    \n                    tabletext += secs[sss].substr(0, secs[sss].indexOf(\"</table>\")+8).trim();\n                    \n                    if(1==1) {\n                    \n                        console.log(tabletext);\n                        \n                        intabledata = tabletext.split(\"<tr\");\n                        intabledata.shift();\n                        for (var ttr in intabledata) {\n                            \n                            intabledata[ttr] = intabledata[ttr].split(\"<td\");\n                            intabledata[ttr].shift();\n                            for (var ttd in intabledata[ttr]) {\n                            \n                                intabledata[ttr][ttd] = (\"<td\"+intabledata[ttr][ttd]).replace(/\\<br/g, \"\\n<br\").replace(/(<([^>]+)>)/gi, \"\");\n                            }\n                        }\n                        \n                        \n                        //var tdout = tabletext.replace(/(<([^>]+)>)/gi, \"\");\n                        \n                        doc.moveDown();\n                        \n                        //doc.text(tdout, docL, doc.y, {\"align\":\"left\", \"width\": docW});\n                        \n                        //NEXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxT\n                        secscnt++;\n                        pdftable(intabledata, {\"title\":\"Table\", \"fontSize\":9});\n   \n                    }\n                    \n                    tabletext = \"\";\n                    \n                } else if (intable) {\n                    \n                    tabletext += secs[sss].trim();\n                }\n                \n                if (secs[sss].indexOf('class=\"gallery')>-1 || secs[sss].indexOf('<table')>-1)    {\n                    \n                    if (!ingallery) {\n                        ingallery=true; \n                        nextY=nextY+20;\n                    }\n                }\n                \n                if (secs[sss].indexOf('<img ')>-1)    {\n                    \n                    var imgbits  = secs[sss].split('<img ')[1];\n                    var src = imgbits.split('src=\"')[1].split('\"')[0];\n                    \n                    imgbits = imgbits.replace(/max\\-width/g,\"max-w\");\n                    \n                    console.log(\"imgbits... \" + imgbits);\n                    \n                    if (imgbits.indexOf('width')>-1) {\n                        \n                        var fn = src.substr(src.lastIndexOf(\"/\")+1);\n                        fn = fn.replace(/ /g,\"_\").replace(/\\./g,\"_\").toLowerCase();\n                    \n                        if (files[fn].xhr.response) {\n                            \n                            var imgh = 780;  \n                            \n                            \n                            if (imgbits.indexOf('height=\"')>-1) { imgh = (imgbits.split('height=\"')[1].split('\"')[0]); }\n                            else if (imgbits.indexOf('height: ')>-1) { imgh = (imgbits.split('height: ')[1].split('px')[0].split('\"')[0]); }\n                            \n                            var imgw = docW;  \n                            if (imgbits.indexOf('width=\"')>-1) { imgw = (imgbits.split('width=\"')[1].split('\"')[0]); }\n                            else if (imgbits.indexOf('width: ')>-1) { imgw = (imgbits.split('width: ')[1].split('px')[0].split('\"')[0]); }\n                            \n                            console.log(\"WxH before... \" + imgw + \" x \" + imgh);\n                            \n                            if(isNaN(imgh)) { imgh = 780; }\n                            if(isNaN(imgw)) { imgw = docW; }\n                            \n                            imgw = parseInt(imgw);\n                            imgh = parseInt(imgh);\n                            \n                            if (imgw<40) { continue; }\n                            \n                            if (ingallery) { \n                                imgh = galleryH; \n                                imgw = galleryW; \n                                \n                            }\n                            \n                            \n                            if (imgw > docW) { imgw = docW; }\n                            \n                            if (ingallery) {\n                            \n                                if (nextY + imgh > 1000) {  \n                                    doc.addPage(layoutP);  \n                                    nextX = 1*docL; nextY = 100; \n                                    doc.text(\" \", docL, 100, {\"align\":\"left\", \"width\": 410});\n                                }\n                                \n                                if (nextY + imgh > 750) { imgh = parseInt(750 - nextY); }\n                            \n                            } else {\n                                \n                                if (doc.y + imgh > 1000) {  \n                                \n                                    doc.addPage(layoutP);  \n                                    nextX = 1*docL; nextY = 100; \n                                    doc.text(\" \", docL, 100, {\"align\":\"left\", \"width\": 410});\n                                }\n                                \n                                if (doc.y + imgh > 750) { imgh = parseInt(750 - doc.y); }\n                            }   \n                            \n                            \n                            if (objects[oo].maxImageHeight>0) { \n                                imgh = Math.min(objects[oo].maxImageHeight,imgh);\n                            } \n                            \n                            console.log(\"WxH after... \" + imgw + \" x \" + imgh);\n                        \n                            if (ingallery) {\n                                \n                                lastX = 1 * nextX;\n                                doc.image(files[fn].xhr.response, nextX, nextY, { \"fit\": [imgw, imgh], align: 'center', valign: 'center' });\n                                nextX = nextX + imgw + 10;\n                                \n                                doc.text(\" \", docL, nextY + imgh - 15, {\"align\":\"left\", \"width\": 410});\n                                \n                                if ((nextX + galleryW)>550) {  // new gallery line\n                                    \n                                    nextX = 1*docL;\n                                    nextY = nextY + galleryH + 25;\n                                    //doc.text(\"\", 40, nextY, {\"align\":\"left\", \"width\": 410});\n                                }\n                                \n                                //doc.moveTo(30, nextY + imgh + 25);  // prepare for next non-gallery item\n                                //\n                                \n                            } else {\n                                \n                                doc.moveDown();\n                                \n                                \n                                \n                                doc.image(files[fn].xhr.response, docL, doc.y, { \"fit\": [imgw, imgh], align: 'center', valign: 'top' });\n                            \n                                posy = posy + 300;\n                            }\n                            \n                        }\n                    }\n                }\n                \n                if (!ingallery) { nextX = doc.x;  nextY = doc.y;  }\n                \n            }\n            \n            posy = 9999;\n            \n        }\n        \n   }\n   \n    \n\n  doc.end();\n}\n\nfunction standardStuff (txt1, showHead) {\n    \n       curSec = \"\"+txt1;\n       \n            doc.image(files.img1.data, 30, 25, { fit: [60, 120] });\n       \n            \n            doc.fontSize(9);\n            doc.font(\"Helvetica\");\n            doc.fillColor(\"black\").text(\"Heatweb Heat Network Designer\", 100, 25, {\"align\":\"right\", \"width\": 455});\n            \n            doc.fontSize(11);\n            doc.font(\"Helvetica-BoldOblique\");\n            doc.fillColor(\"black\").text(txt1, 100, 40, {\"align\":\"right\", \"width\": 455});\n           \n           doc\n           \n            .lineWidth(1)\n            .moveTo(0, 65)\n            .lineTo(600, 65)\n            .stroke();\n            \n            doc\n            .moveTo(0, 805)\n            .lineTo(600, 805)\n            .stroke();\n            \n            doc.fontSize(9);\n            doc.font(\"Helvetica\");\n            doc.fillColor(\"black\").text(\"Thermal Integration Ltd. (Heatweb)   Tel. 0345 2411441   Email: newenquiries@heatweb.com   Website: https://heatweb.co.uk\", 50, 815, {\"align\":\"center\", \"lineBreak\": false });\n            \n            \n            \n            if (showHead===true) {\n                doc.fontSize(20);\n                doc.font(\"Helvetica-Bold\"); \n                //#000077\n                doc.fillColor(\"black\").text(txt1, docL, 100, {\"align\":\"justify\", \"width\": 410});\n                doc.moveDown();\n                //doc.text(\"\", docL, doc.y, {\"align\":\"left\", \"width\": 410});  // position\n            \n                \n            } else {\n                \n                doc.text(\"\", docL, 90, {\"align\":\"left\", \"width\": 410});  // position\n            }\n}   \n\nfunction pdftable(tdata,toptions) {\n    \n    tableCount++;\n    \n    var tdaw = parseInt(docW / (tdata[0].length || tdata[1].length));\n    if (isNaN(tdaw)) { tdaw = docW / 2; }\n    \n    var thead = \"Table \" + tableCount + (toptions.title?(\": \" + toptions.title):\"\");\n    var twidths = toptions.widths || [tdaw,tdaw,tdaw,tdaw,tdaw,tdaw,tdaw,tdaw,tdaw,tdaw,tdaw,tdaw];\n    var tfs = toptions[\"fontSize\"] || 11.5;\n    var aligns = toptions.align || [];\n    \n   \n    \n    doc.fillColor(\"black\");\n    \n    doc.font(\"Helvetica-Oblique\");\n    doc.fontSize(10);\n    \n    \n    doc.text(thead, docL, doc.y, {\"align\":\"left\", \"width\": 400, lineGap: 2});\n    doc.font(\"Helvetica\");\n    doc.fontSize(tfs);\n    \n    var tx1 = 1*doc.x;\n    var ty1 = 1*doc.y;\n    var ty = 1*ty1;\n    var tx = 1*tx1;\n    var trow = -1;\n    var tcol = -1;\n    \n    var tdh = 14;\n    var cellhmax = 0;\n    doc.lineWidth(0.5);\n    \n    for (var tr in tdata) {\n        \n        if (ty>750) {\n            \n            doc.addPage(layoutP);\n            standardStuff((toptions.title?toptions.title:\"\"),false);\n            doc.fontSize(tfs);\n            doc.fillColor(\"black\");\n            doc.font(\"Helvetica\");\n            ty = 100;\n            trow = -1;\n            \n            doc.font(\"Helvetica-Oblique\");\n            doc.fontSize(10);\n            doc.text(thead + \" (continued)\", doc.x, 100, {\"align\":\"left\", \"width\": 400, lineGap: 2});\n            doc.font(\"Helvetica\");\n            doc.fontSize(tfs);\n            doc.lineWidth(0.5);\n            ty = doc.y;\n            ty1 = 1*doc.y;\n            ty = 1*ty1;\n            \n        }\n        \n        trow++;\n        tcol=-1;\n        cellhmax = 0;\n\n        tx = 1*tx1;\n        for (var td in tdata[tr]) {\n            tcol++;\n            var tdw = 1 * (twidths[td] || tdaw);\n            var tdal = aligns[td] || \"left\";\n            \n            var tdval = \"\" + tdata[tr][td];\n            if (tdval.substr(0,1)==\"{\") { tdval = \"{object}\"; }  // dont display objects\n            \n            console.log(\"tdval.. \" + tdval + \"...\" + tdw + \"...\" + tdaw  + \"...\" + twidths[td]);\n            doc.text(tdval, tx+5, ty+5, {\"align\":tdal, \"width\": tdw-10, lineGap: 2});\n            \n            var cellh = doc.y - (ty+5) + 3;\n            cellhmax = Math.max(cellhmax,cellh);\n            \n            tx = tx + tdw;\n        }\n        \n        tcol=-1;\n        tx = 1*tx1;\n        for (var td in tdata[tr]) {\n            tcol++;\n            var tdw = 1 * (twidths[td] || tdaw);\n            \n            doc.rect(tx, ty, tdw, cellhmax).stroke();\n            \n            tx = tx + tdw;\n        }\n        \n        ty = ty + cellhmax;  // end of row move down\n        \n        \n        \n    }\n    \n}\n\n\nconst ppp = document.createElement(\"a\");\ndocument.body.appendChild(ppp);\nppp.style = \"display: none\";\n\nlet blob;\n\nfunction downloadp() {\n  if (!blob) return;\n  var url = window.URL.createObjectURL(blob);\n  ppp.href = url;\n  ppp.download = 'test.pdf';\n  ppp.click();\n  window.URL.revokeObjectURL(url);\n}\n\n\n\n</script>\n\n\n","output":"str","x":460,"y":280,"wires":[["efd4be68.d8373","ff5ca928.7571d8"]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"5671eaf7.b04df4","type":"inject","z":"cce2bfaa.e5748","name":"","topic":"","payload":"{\"title\":\"Heat Network Designer\",\"body\":\"\"}","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":250,"y":280,"wires":[["8dc13cac.e444b"]]},{"id":"efd4be68.d8373","type":"change","z":"cce2bfaa.e5748","name":"","rules":[{"t":"set","p":"sections.hndesign","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":800,"y":280,"wires":[[]]},{"id":"b6ba981e.886638","type":"template","z":"cce2bfaa.e5748","name":"","field":"heads","fieldType":"msg","format":"handlebars","syntax":"plain","template":"<!doctype html>\n<html lang=\"en\">\n  <head>\n    <!-- Required meta tags -->\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n\n    <!-- Bootstrap CSS -->\n    <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css\" integrity=\"sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2\" crossorigin=\"anonymous\">\n\n   \n    <script src=\"https://kit.fontawesome.com/c6b21b7a8f.js\" crossorigin=\"anonymous\"></script>\n\n \n    <title>Thermal Integration Heatweb Node</title>\n\n\n  <script src=\"https://code.jquery.com/jquery-3.5.1.js\"></script>\n  <script src=\"https://cdn.datatables.net/1.10.22/js/jquery.dataTables.min.js\" type=\"text/javascript\"></script>\n  <link rel=\"stylesheet\" href=\"https://cdn.datatables.net/1.10.22/css/jquery.dataTables.min.css\">\n\n\n  \n    <style>\n    \n    body, textarea, input, select {\n    font-size: 18px;\n}\n\nsection  {\n    /*border-bottom: 1px solid rgb(255, 255, 255);*/\n    padding: 20px 50px;\n    /* height: 100vh; */\n    scroll-snap-align: start;\n    /* text-align: center; */\n    position: relative;\n    /*background: #ffffff;*/\n    font-size: 18px;\n    }\n\nsection .table {\n            font-size: 16px;\n        }\n\ntable.dataTable.compact tbody td {\n    \n    padding: 2px;\n}   \n\nsection .jstree-node {\n    font-size: 16px;\n}\n\n.nowrap {\n    white-space: nowrap;\n}\n\n@media (max-width: 1480px) {\n\n    section {\n        \n        padding: 20px 20px;\n        \n        }\n\n}\n\n@media (max-width:480px) {\n\n    section {\n        \n        padding: 10px 8px;\n        \n        }\n\n}\n\n    \n        .maxsiz {\n\n        width: 100%; \n        height: 100vh;\n\n        }\n\n        .maxsiz2 {\n\n        width: 100%; \n        height: calc(100vh - 70px);\n\n        }\n\n        .dot {\n            height: 13px;\n            width: 13px;\n            background-color: rgb(52, 58, 52);\n            border-radius: 20%;\n            border: 2px;\n            border-color: rgb(5, 5, 20);\n            display: inline-block;\n        }\n\n        .thindot {\n            height: 13px;\n            width: 6px;\n            background-color: rgb(52, 58, 52);\n            border-radius: 20%;\n            border: 2px;\n            border-color: rgb(5, 5, 20);\n            display: inline-block;\n        }\n\n        .dotspacer {\n            height: 13px;\n            width: 2px;\n            display: inline-block;\n        }\n\n        .navReadings  {\n            /* border-bottom: 1px solid rgb(32, 28, 28); */\n            padding: 20px 50px 0px 50px;\n            /* background: #6d6d70; */\n            font-size: 80%;   \n            /* font-weight: bold; */\n            text-align: left;\n            color: #212529;   \n        }\n\n        .navReadings a {\n            color: #212529;         \n        }\n\n        \n\n           \n    </style>\n    \n</head>\n","output":"str","x":660,"y":100,"wires":[["ee42376e.6a38c8"]]},{"id":"ee42376e.6a38c8","type":"function","z":"cce2bfaa.e5748","name":"","func":"msg.payload = msg.heads + \"<body><section>\" +  msg.payload.body + \"</section></body></html>\"\n\nreturn msg;","outputs":1,"noerr":0,"x":850,"y":100,"wires":[["b64da5dd.b40028"]]},{"id":"b64da5dd.b40028","type":"http response","z":"cce2bfaa.e5748","name":"","statusCode":"","headers":{},"x":1030,"y":100,"wires":[]},{"id":"d2c83715.bc4ad8","type":"http response","z":"cce2bfaa.e5748","name":"","statusCode":"","headers":{"content-type":"application/json"},"x":1030,"y":360,"wires":[]},{"id":"2969e69c.af225a","type":"template","z":"cce2bfaa.e5748","name":"Heat Network Designer","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js\"></script>\n{{!--https://www.sitepoint.com/basic-jquery-form-validation-tutorial/--}}\n\n<script src=\"https://unpkg.com/mustache@latest\"></script>\n\n<style>\n\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 6px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\nvar a = new Date();\nvar qdata;\nvar calculated = {};\nvar hasFocus;\nvar inputsOut;\nvar inputString;\n\n\t$(document).ready(function(e) {\n    \n        // $(\"form[ajax=true]\").submit(function(e) {\n            \n        //     //alert(\"submit\");\n            \n        //     e.preventDefault();\n        \n             \n            //var urlParams = new URLSearchParams(window.location.search);\n            //if (urlParams.get('display')) { loadstring = \",,\" + urlParams.get('display'); }\n\n            var urlParams = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParams) {\n                \n                calculated[urlParams[upa].split(\"=\")[0]] = urlParams[upa].split(\"=\")[1];\n                \n            }\n            \n            var form_data = {};\n            var form_url = \"/ui/qdata\";\n            var form_target = $(this).attr(\"target\") || \"result\";\n            var ftarget = \"#\" + form_target;\n            var form_method = \"GET\";\n            \n        //     $(\"#loadingimg\").show();\n            \n            $.ajax({\n                url: form_url, \n                type: form_method,      \n                data: form_data,     \n                cache: false,\n                success: function(results){   \n                    \n                    qdata = results;\n                    //qdata = JSON.parse(returnhtml);\n                    console.log(qdata);\n                   \n                    \n                    document.getElementById(\"formName\").innerHTML = qdata.title || \"Unamed Form\"; //JSON.stringify(qdata) ;\n                    \n                    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n                    \n                    validform();\n                                  \n                }           \n            });    \n            \n        // });\n        \n      \n        \n    });\n\t\nfunction parseQuestions(qdata) {\n    \n    console.log(qdata);\n    console.log(calculated);\n    \n    var linkstxt=\"\";\n    if (qdata.links) {\n        for (var lnk in qdata.links) {\n            linkstxt += (linkstxt!==\"\"?\"<br>\":\"\") + '<a href=\"' + qdata.links[lnk].src + '\" target=\"_blank\">' + (qdata.links[lnk].title||qdata.links[lnk].src) + '</a>';\n        }\n        \n    }\n    document.getElementById(\"links\").innerHTML = linkstxt ; //JSON.stringify(qdata) ;\n    \n    inputsOut = '<table class=\"table\">';\n    \n    inputString = \"\";\n    hasFocus = null;\n    \n    var ootoot = \"\";\n    for (var s in qdata[\"sections\"]) {\n        console.log(s);\n        console.log(qdata.sections[s]);\n        \n        var oot = \"\";\n        var ootcount=0;\n        \n        //oot += \"<div class='section'><h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        oot += \"<h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        \n        \n        \n        for (var q in qdata.sections[s].questions) {\n            \n            \n            var qif = qdata.sections[s].questions[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n            var v=\"\";\n            if (calculated[qdata.sections[s].questions[q].id]) { v= calculated[qdata.sections[s].questions[q].id] ; }\n            else if (qdata.sections[s].questions[q].value) { v= qdata.sections[s].questions[q].value ; }\n            \n            if(goq) {\n                \n                \n            \n                if (v!==\"\") { \n                    inputsOut += \"<tr>\";  \n                    inputsOut += \"<td>\" + (qdata.sections[s].questions[q].title||qdata.sections[s].questions[q].id) + \"</td>\";\n                    inputsOut +=  '<td align=\"right\">' + v + \"</td>\";\n                    inputsOut +=  '<td width=\"14%\">' + (qdata.sections[s].questions[q].units||\"\") + \"</td></tr>\\n\";\n                    \n                    inputString += (inputString!==\"\"?\"&\":\"\") + qdata.sections[s].questions[q].id + \"=\" + v;\n                }\n            \n            \n                if (hasFocus && document.getElementById(\"oneQ\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">'; }\n            \n                else if (v!==\"\") { \n                    \n                    if (document.getElementById(\"hideDone\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">';   }\n                    else {  oot += '<div class=\"question\" style=\"background-color: #d2efd2;\">'; ootcount++; }\n                    \n                } else { oot += '<div class=\"question\">'; ootcount++; if (!hasFocus) { hasFocus = qdata.sections[s].questions[q].id; } }\n                \n                //oot += \"<div class='qtext'>\" + qdata.sections[s].questions[q].title + '</div>';\n                oot += '<label for=\"' + qdata.sections[s].questions[q].id + '\" class=\"qtext\">' + (qdata.sections[s].questions[q].question||qdata.sections[s].questions[q].title) + '</label>';\n                \n                if (qdata.sections[s].questions[q].notes) { oot += '<div class=\"notes\">'  + convertLinks(qdata.sections[s].questions[q].notes) + '</div>'; }\n                oot += '<table width=\"100%\"><tr><td width=\"80%\">';\n                \n                if (qdata.sections[s].questions[q].type==\"boolean\") {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                      if (v==\"true\") { oot += '<option value=\"false\">No</option><option value=\"true\" selected>Yes</option>'; }\n                      else if (v==\"false\")  { oot += '<option value=\"false\" selected>No</option><option value=\"true\">Yes</option>'; }\n                      else  { oot += '<option value=\"\"></option><option value=\"false\">No</option><option value=\"true\">Yes</option>'; }\n                    oot += '</select>';\n                    \n                } else if (qdata.sections[s].questions[q].options) {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    if (v==\"\") { oot += '<option value=\"\"></option>'; }\n                    for (var opt in qdata.sections[s].questions[q].options) {\n                    \n                      var optobj = qdata.sections[s].questions[q].options[opt];\n                      \n                      \n                      if (v==optobj.value) { oot += '<option selected value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      else  { oot += '<option value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      \n                    }  \n                    oot += '</select>';\n                    \n                } else {\n                \n                    oot += '<input id=\"' + qdata.sections[s].questions[q].id + '\" name=\"' + qdata.sections[s].questions[q].id + '\" class=\"form-control\" type=\"text\"';\n                    if (v!==\"\") { oot += ' value=\"' + v + '\"'; }\n                    if (qdata.sections[s].questions[q].default) { oot += ' placeholder=\"' + qdata.sections[s].questions[q].default + \" \" + (qdata.sections[s].questions[q].units||\"\") + ' ... please confirm\"'; }\n                    oot += '>';\n                }\n                \n                oot += '</td><td valign=\"top\"><span class=\"qunits\">' + (qdata.sections[s].questions[q].units||\"\") + '</span></td></tr></table></div>\\n';\n            }\n        }\n    \n        oot += \"</div>\\n\";\n        \n        if(ootcount>0) {  ootoot += \"<div class='section'>\" + oot; }\n        \n        else {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n    }\n    inputsOut +=  \"</table>\\n\";  \n    \n    return ootoot;\n}\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\n// console.log(looseJsonParse(\n//   \"{a:(4-1), b:function(){}, c:new Date()}\"\n// ))\n\nfunction runCalcs() {\n\n\n    \n    \n    // run through form inputs and store current values into calculated.\n    var cells =  document.getElementsByClassName(\"form-control\");\n\tvar i;\n\tfor (i = 0; i < cells.length; i++) {\n\t\n\t\tcalcsOut += cells[i].value + \"<br>\\n\";\n        \n        if (\"\" + cells[i].value !== \"\") { \n            \n            if (isNaN(cells[i].value)) { \n                \n                calculated[cells[i].id] = (cells[i].value);\n                \n            } else {\n                \n                calculated[cells[i].id] = parseFloat(cells[i].value);\n            }\n        }\n\t}\n    \n    var calcsOut = '<table class=\"table\">';\n    for (var calc in (qdata[\"calculations\"]||[])) {\n        \n        console.log(calc);\n        console.log(qdata.calculations[calc]);\n        \n        \n        var cif = qdata.calculations[calc].if || true;\n        var cift = Mustache.render(cif, calculated);\n        var goc = true;\n        try {\n          goc = looseJsonParse(cift); \n        }\n        catch(err) {\n          goc = false;\n        }\n        \n        if (goc) {\n        \n            var f = qdata.calculations[calc].function;\n            var ft;\n            var cv = \"\";\n            \n            calcsOut += \"<tr>\"; \n            calcsOut += \"<td>\" + (qdata.calculations[calc].title||qdata.calculations[calc].id) + \"</td>\";\n            \n            try {\n                \n                ft = Mustache.render(f, calculated);  // error trap incase object\n                cv = looseJsonParse(ft); \n                if (!isNaN(cv)) { cv = parseInt(cv*1000)/1000; }\n                if (document.getElementById(\"hideMaths\").checked!==true) {\n                    calcsOut += \"<td><small>\" + ft + \"</small></td>\";   //\"<br>\\n\";\n                }\n                calcsOut +=  '<td align=\"right\">' + cv + \"</td>\"; \n                 \n            }\n            catch(err) {   // is an object returned\n                \n                ft = f; \n                cv = f; \n                var obst = \"\";\n                try { obst = JSON.stringify(cv); } catch { obst = \"error\"; }\n                //if (document.getElementById(\"hideMaths\").checked!==true) { calcsOut += \"<td> </td>\";  }\n                calcsOut += '<td ';\n                if (document.getElementById(\"hideMaths\").checked!==true) { calcsOut += 'colspan=\"2\" ';  }\n                if (obst.length>29) { obst = obst.substr(0,20) + \" ... \" + obst.substr(-10); } // truncate if long\n                calcsOut += 'align=\"right\"><small>' + obst + \"</small></td>\";\n                \n            }\n            \n            calculated[qdata.calculations[calc].id] = cv;\n            \n            calcsOut +=  '<td width=\"14%\">' + (qdata.calculations[calc].units||\"\") + \"</td></tr>\\n\";\n            \n            \n            \n        }\n        \n    }\n    \n    calcsOut +=  \"</table>\\n\";\n    \n    // for (var calc in calculated) {\n        \n        \n    // }\n    \n    document.getElementById(\"calcs\").innerHTML = calcsOut; //JSON.stringify(qdata) ;\n    \n    // rebuild form\n    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"inputs\").innerHTML = inputsOut; //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"mylink\").innerHTML = '<a href=\"hndesign?' + inputString + '\" target=\"_blank\">Click/Copy this link to open design...</a>'; //JSON.stringify(qdata) ;\n    \n    \n    \n    validform();\n                    \n}\n\n\nconst convertLinks = ( input ) => {\n\n  let text = input;\n  const linksFound = text.match( /(?:www|https?)[^\\s]+/g );\n  const aLink = [];\n\n  if ( linksFound != null ) {\n\n    for ( let i=0; i<linksFound.length; i++ ) {\n      let replace = linksFound[i];\n      if ( !( linksFound[i].match( /(http(s?)):\\/\\// ) ) ) { replace = 'http://' + linksFound[i] }\n      let linkText = replace.split( '/' )[2];\n      if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) }\n      if ( linkText.match( /youtu/ ) ) {\n\n        let youtubeID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://www.youtube.com/embed/' + youtubeID + '\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe></div>' )\n      }\n      else if ( linkText.match( /vimeo/ ) ) {\n        let vimeoID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://player.vimeo.com/video/' + vimeoID + '\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' )\n      }\n      else {\n        aLink.push( '<a href=\"' + replace + '\" target=\"_blank\">' + linkText + '</a>' );\n      }\n      text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] );\n    }\n    return text;\n\n  }\n  else {\n    return input;\n  }\n}\n\nfunction validform() {\n    \n    if(hasFocus && document.getElementById(hasFocus)) {\n        document.getElementById(hasFocus).focus();\n    }\n    \n    \n    \n// Initialize form validation on the registration form.\n  // It has the name attribute \"registration\"\n  $(\"form[name='qform']\").validate({\n    // Specify validation rules\n    rules: {\n      // The key name on the left side is the name attribute\n      // of an input field. Validation rules are defined\n      // on the right side\n      nProperties: {\n        required: true,\n        digits: true,\n        min: 1\n      },\n      lastname: \"required\",\n      email: {\n        required: true,\n        // Specify that email should be validated\n        // by the built-in \"email\" rule\n        email: true\n      },\n      password: {\n        required: true,\n        minlength: 5\n      }\n    },\n    // Specify validation error messages\n    messages: {\n      nProperties: \"Please enter a number.\",\n      lastname: \"Please enter your lastname\",\n      password: {\n        required: \"Please provide a password\",\n        minlength: \"Your password must be at least 5 characters long\"\n      },\n      email: \"Please enter a valid email address\"\n    },\n    // Make sure the form is submitted to the destination defined\n    // in the \"action\" attribute of the form when valid\n    submitHandler: function(form) {\n      //form.submit();\n      runCalcs();\n      //alert(\"hello\");\n    }\n  });\n}\n\n</script>\n\n\n<div class='section'>\n    \n    <table width=\"100%\"><tr>\n    <td valign=\"top\" width=\"70%\">\n        <div id=\"formName\" class=\"h1\"></div>\n        <a href=\"https://heatweb.co.uk/w/index.php?title=Heat_Network_Designer\" target=\"_blank\"><small>Wiki Help Page</small></a>\n    </td>\n    <td width=\"30%\">\n        <input type=\"checkbox\" id=\"oneQ\" name=\"oneQ\" checked> <small>One question at a time</small><br>\n        <input type=\"checkbox\" id=\"hideDone\" name=\"hideDone\" checked> <small>Hide completed questions</small><br>\n        <input type=\"checkbox\" id=\"hideMaths\" name=\"hideMaths\" checked> <small>Hide maths equations</small>\n    </td>\n    </tr></table>\n</div>\n\n\n<form action=\"\" name=\"qform\" id=\"qform\">\n<div id=\"section1\"></div>\n\n<div class='section'>\n<button type=\"submit\">Submit</button>\n\n</div>\n\n\n<div class='section'>\n<p><b>Inputs</b></p>\n<div id=\"inputs\" class=\"notes\"></div>\n</div>\n\n<div class='section'>\n<p><b>Numeric Values and Calculations</b></p>\n<div id=\"calcs\" class=\"notes\"></div>\n</div>\n\n\n<div class='section'>\n<p><b>Links</b></p>\n<div id=\"mylink\" class=\"notes\"></div>\n<div id=\"links\" class=\"notes\"></div>\n</div>\n</form>","output":"str","x":1470,"y":200,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"f7df0a19.056d88","type":"template","z":"cce2bfaa.e5748","name":"Heat Network Designer","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js\"></script>\n{{!--https://www.sitepoint.com/basic-jquery-form-validation-tutorial/--}}\n\n<script src=\"https://unpkg.com/mustache@latest\"></script>\n\n<style>\n\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 6px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\nvar a = new Date();\nvar qdata;\nvar calculated = {};\nvar hasFocus;\nvar inputsOut;\nvar inputString;\n\n\t$(document).ready(function(e) {\n    \n        // $(\"form[ajax=true]\").submit(function(e) {\n            \n        //     //alert(\"submit\");\n            \n        //     e.preventDefault();\n        \n             \n            //var urlParams = new URLSearchParams(window.location.search);\n            //if (urlParams.get('display')) { loadstring = \",,\" + urlParams.get('display'); }\n\n            var urlParams = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParams) {\n                \n                calculated[urlParams[upa].split(\"=\")[0]] = urlParams[upa].split(\"=\")[1];\n                \n            }\n            \n            var form_data = {};\n            var form_url = \"/ui/qdata\";\n            var form_target = $(this).attr(\"target\") || \"result\";\n            var ftarget = \"#\" + form_target;\n            var form_method = \"GET\";\n            \n        //     $(\"#loadingimg\").show();\n            \n            $.ajax({\n                url: form_url, \n                type: form_method,      \n                data: form_data,     \n                cache: false,\n                success: function(results){   \n                    \n                    qdata = results;\n                    //qdata = JSON.parse(returnhtml);\n                    console.log(qdata);\n                   \n                    \n                    document.getElementById(\"formName\").innerHTML = qdata.title || \"Unamed Form\"; //JSON.stringify(qdata) ;\n                    \n                    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n                    \n                    validform();\n                                  \n                }           \n            });    \n            \n        // });\n        \n      \n        \n    });\n\t\nfunction parseQuestions(qdata) {\n    \n    console.log(qdata);\n    console.log(calculated);\n    \n    var linkstxt=\"\";\n    if (qdata.links) {\n        for (var lnk in qdata.links) {\n            linkstxt += (linkstxt!==\"\"?\"<br>\":\"\") + '<a href=\"' + qdata.links[lnk].src + '\" target=\"_blank\">' + (qdata.links[lnk].title||qdata.links[lnk].src) + '</a>';\n        }\n        \n    }\n    document.getElementById(\"links\").innerHTML = linkstxt ; //JSON.stringify(qdata) ;\n    \n    inputsOut = '<table class=\"table\">';\n    \n    inputString = \"\";\n    hasFocus = null;\n    \n    var oot = \"\";\n    for (var s in qdata[\"sections\"]) {\n        console.log(s);\n        console.log(qdata.sections[s]);\n        oot += \"<div class='section'><h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        \n        \n        \n        for (var q in qdata.sections[s].questions) {\n            \n            \n            var qif = qdata.sections[s].questions[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n            var v=\"\";\n            if (calculated[qdata.sections[s].questions[q].id]) { v= calculated[qdata.sections[s].questions[q].id] ; }\n            else if (qdata.sections[s].questions[q].value) { v= qdata.sections[s].questions[q].value ; }\n            \n            if(goq) {\n            \n                if (v!==\"\") { \n                    inputsOut += \"<tr>\";  \n                    inputsOut += \"<td>\" + (qdata.sections[s].questions[q].title||qdata.sections[s].questions[q].id) + \"</td>\";\n                    inputsOut +=  '<td align=\"right\">' + v + \"</td>\";\n                    inputsOut +=  '<td width=\"20%\">' + (qdata.sections[s].questions[q].units||\"\") + \"</td></tr>\\n\";\n                    \n                    inputString += (inputString!==\"\"?\"&\":\"\") + qdata.sections[s].questions[q].id + \"=\" + v;\n                }\n            \n            \n                if (hasFocus && document.getElementById(\"oneQ\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">'; }\n            \n                else if (v!==\"\") { \n                    \n                    if (document.getElementById(\"hideDone\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">';   }\n                    else {  oot += '<div class=\"question\" style=\"background-color: #d2efd2;\">';  }\n                    \n                } else { oot += '<div class=\"question\">'; if (!hasFocus) { hasFocus = qdata.sections[s].questions[q].id; } }\n                \n                //oot += \"<div class='qtext'>\" + qdata.sections[s].questions[q].title + '</div>';\n                oot += '<label for=\"' + qdata.sections[s].questions[q].id + '\" class=\"qtext\">' + (qdata.sections[s].questions[q].question||qdata.sections[s].questions[q].title) + '</label>';\n                \n                if (qdata.sections[s].questions[q].notes) { oot += '<div class=\"notes\">'  + convertLinks(qdata.sections[s].questions[q].notes) + '</div>'; }\n                oot += '<table width=\"100%\"><tr><td width=\"80%\">';\n                \n                if (qdata.sections[s].questions[q].type==\"boolean\") {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                      if (v==\"true\") { oot += '<option value=\"false\">No</option><option value=\"true\" selected>Yes</option>'; }\n                      else if (v==\"false\")  { oot += '<option value=\"false\" selected>No</option><option value=\"true\">Yes</option>'; }\n                      else  { oot += '<option value=\"\"></option><option value=\"false\">No</option><option value=\"true\">Yes</option>'; }\n                    oot += '</select>';\n                    \n                } else if (qdata.sections[s].questions[q].options) {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    if (v==\"\") { oot += '<option value=\"\"></option>'; }\n                    for (var opt in qdata.sections[s].questions[q].options) {\n                    \n                      var optobj = qdata.sections[s].questions[q].options[opt];\n                      \n                      if (v==optobj) { oot += '<option selected value=\"' + optobj + '\">' + optobj + '</option>'; }\n                      else  { oot += '<option value=\"' + optobj + '\">' + optobj + '</option>'; }\n                      \n                    }  \n                    oot += '</select>';\n                    \n                } else {\n                \n                    oot += '<input id=\"' + qdata.sections[s].questions[q].id + '\" name=\"' + qdata.sections[s].questions[q].id + '\" class=\"form-control\" type=\"text\"';\n                    if (v!==\"\") { oot += ' value=\"' + v + '\"'; }\n                    if (qdata.sections[s].questions[q].default) { oot += ' placeholder=\"' + qdata.sections[s].questions[q].default + \" \" + (qdata.sections[s].questions[q].units||\"\") + ' ... please confirm\"'; }\n                    oot += '>';\n                }\n                \n                oot += '</td><td valign=\"top\"><span class=\"qunits\">' + (qdata.sections[s].questions[q].units||\"\") + '</span></td></tr></table></div>\\n';\n            }\n        }\n    \n        oot += \"</div>\\n\";\n        \n    }\n    inputsOut +=  \"</table>\\n\";  \n    \n    return oot;\n}\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\n// console.log(looseJsonParse(\n//   \"{a:(4-1), b:function(){}, c:new Date()}\"\n// ))\n\nfunction runCalcs() {\n\n\n    \n    \n    // run through form inputs and store current values into calculated.\n    var cells =  document.getElementsByClassName(\"form-control\");\n\tvar i;\n\tfor (i = 0; i < cells.length; i++) {\n\t\n\t\tcalcsOut += cells[i].value + \"<br>\\n\";\n        \n        if (\"\" + cells[i].value !== \"\") { \n            \n            if (isNaN(cells[i].value)) { \n                \n                calculated[cells[i].id] = (cells[i].value);\n                \n            } else {\n                \n                calculated[cells[i].id] = parseFloat(cells[i].value);\n            }\n        }\n\t}\n    \n    var calcsOut = '<table class=\"table\">';\n    for (var calc in (qdata[\"calculations\"]||[])) {\n        \n        console.log(calc);\n        console.log(qdata.calculations[calc]);\n        var f = qdata.calculations[calc].function;\n        var ft = Mustache.render(f, calculated);\n        \n        calcsOut += \"<tr>\";  //<td>\" + qdata.calculations[calc].id + \"</td>\";\n        calcsOut += \"<td>\" + (qdata.calculations[calc].title||qdata.calculations[calc].id) + \"</td>\";\n        \n        //calcsOut += f + \" = \";\n        if (document.getElementById(\"hideMaths\").checked!==true) {\n            calcsOut += \"<td><small>\" + ft + \"</small></td>\";   //\"<br>\\n\";\n        }\n        \n        var cv = \"\";\n        try {\n          cv = looseJsonParse(ft); //  looseJsonParse(\"{a:(4-1), b:function(){}, c:new Date()}\");\n        }\n        catch(err) {\n          \n        }\n         \n        \n        if (!isNaN(cv)) { cv = parseInt(cv*1000)/1000; }\n        \n        calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n        \n        calcsOut +=  '<td width=\"20%\">' + (qdata.calculations[calc].units||\"\") + \"</td></tr>\\n\";\n        \n        calculated[qdata.calculations[calc].id] = cv;\n        \n    }\n    \n    calcsOut +=  \"</table>\\n\";\n    \n    // for (var calc in calculated) {\n        \n        \n    // }\n    \n    document.getElementById(\"calcs\").innerHTML = calcsOut; //JSON.stringify(qdata) ;\n    \n    // rebuild form\n    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"inputs\").innerHTML = inputsOut; //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"mylink\").innerHTML = '<a href=\"hndesign?' + inputString + '\" target=\"_blank\">'+ inputString + '</a>'; //JSON.stringify(qdata) ;\n    \n    \n    \n    validform();\n                    \n}\n\n\nconst convertLinks = ( input ) => {\n\n  let text = input;\n  const linksFound = text.match( /(?:www|https?)[^\\s]+/g );\n  const aLink = [];\n\n  if ( linksFound != null ) {\n\n    for ( let i=0; i<linksFound.length; i++ ) {\n      let replace = linksFound[i];\n      if ( !( linksFound[i].match( /(http(s?)):\\/\\// ) ) ) { replace = 'http://' + linksFound[i] }\n      let linkText = replace.split( '/' )[2];\n      if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) }\n      if ( linkText.match( /youtu/ ) ) {\n\n        let youtubeID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://www.youtube.com/embed/' + youtubeID + '\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe></div>' )\n      }\n      else if ( linkText.match( /vimeo/ ) ) {\n        let vimeoID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://player.vimeo.com/video/' + vimeoID + '\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' )\n      }\n      else {\n        aLink.push( '<a href=\"' + replace + '\" target=\"_blank\">' + linkText + '</a>' );\n      }\n      text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] );\n    }\n    return text;\n\n  }\n  else {\n    return input;\n  }\n}\n\nfunction validform() {\n    \n    if(hasFocus && document.getElementById(hasFocus)) {\n        document.getElementById(hasFocus).focus();\n    }\n    \n    \n    \n// Initialize form validation on the registration form.\n  // It has the name attribute \"registration\"\n  $(\"form[name='qform']\").validate({\n    // Specify validation rules\n    rules: {\n      // The key name on the left side is the name attribute\n      // of an input field. Validation rules are defined\n      // on the right side\n      nProperties: {\n        required: true,\n        digits: true,\n        min: 1\n      },\n      lastname: \"required\",\n      email: {\n        required: true,\n        // Specify that email should be validated\n        // by the built-in \"email\" rule\n        email: true\n      },\n      password: {\n        required: true,\n        minlength: 5\n      }\n    },\n    // Specify validation error messages\n    messages: {\n      nProperties: \"Please enter a number.\",\n      lastname: \"Please enter your lastname\",\n      password: {\n        required: \"Please provide a password\",\n        minlength: \"Your password must be at least 5 characters long\"\n      },\n      email: \"Please enter a valid email address\"\n    },\n    // Make sure the form is submitted to the destination defined\n    // in the \"action\" attribute of the form when valid\n    submitHandler: function(form) {\n      //form.submit();\n      runCalcs();\n      //alert(\"hello\");\n    }\n  });\n}\n\n</script>\n\n\n<div class='section'>\n    \n    <table width=\"100%\"><tr>\n    <td valign=\"top\" width=\"70%\">\n        <div id=\"formName\" class=\"h1\"></div>\n        <a href=\"https://heatweb.co.uk/w/index.php?title=Heat_Network_Designer\" target=\"_blank\"><small>Wiki Help Page</small></a>\n    </td>\n    <td width=\"30%\">\n        <input type=\"checkbox\" id=\"oneQ\" name=\"oneQ\" checked> <small>One question at a time</small><br>\n        <input type=\"checkbox\" id=\"hideDone\" name=\"hideDone\" checked> <small>Hide completed questions</small><br>\n        <input type=\"checkbox\" id=\"hideMaths\" name=\"hideMaths\" checked> <small>Hide maths equations</small>\n    </td>\n    </tr></table>\n</div>\n\n\n<form action=\"\" name=\"qform\" id=\"qform\">\n<div id=\"section1\"></div>\n\n<div class='section'>\n<button type=\"submit\">Submit</button>\n\n</div>\n\n\n<div class='section'>\n<p><b>Inputs</b></p>\n<div id=\"inputs\" class=\"notes\"></div>\n</div>\n\n<div class='section'>\n<p><b>Numeric Values and Calculations</b></p>\n<div id=\"calcs\" class=\"notes\"></div>\n</div>\n\n\n<div class='section'>\n<p><b>Links</b></p>\n<div id=\"mylink\" class=\"notes\"></div>\n<div id=\"links\" class=\"notes\"></div>\n</div>\n</form>","output":"str","x":1730,"y":160,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"b323bab.fe3e548","type":"change","z":"cce2bfaa.e5748","name":"Heat Network Design","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"title\":\"Heat Network Designer\",\"links\":[{\"src\":\"https://hw7.ddns.net/ui/hncalc\",\"title\":\"Heat Network Calculator v2\"},{\"src\":\"https://hw7.ddns.net/ui/svgexplode?svg=HeatNetwork6.svg\",\"title\":\"Heat Network Schematic Designer (HeatNetwork6.svg)\"}],\"sections\":[{\"title\":\"General\",\"questions\":[{\"title\":\"Number of buildings\",\"question\":\"How many buildings are fed from the network?\",\"id\":\"nBuildings\",\"if\":\"true\",\"required\":true,\"type\":\"integer\",\"notes\":\"The total number of buildings connected to the heat network. See https://hw7.ddns.net/ui/svgexplode?svg=HeatNetwork6.svg&display=g16444,g11206,bulkhm,g14636,landlordload,g16320,g5006,bufferstore,lowgrade,heatpump2,heatpump2-2,qton1,fbyp,hiu,g68266,singlemainpump,backupmainpump,g130841-3,g14610-0,g14636-2,g14610,finestrainer,cwsvcs,g14124,g14362.\",\"units\":\"buildings\"},{\"title\":\"Number of properties\",\"question\":\"How many properties are there?\",\"id\":\"nProperties\",\"if\":\"true\",\"required\":true,\"type\":\"integer\",\"notes\":\"The total number of properties connected to the heat network.\",\"units\":\"properties\"},{\"title\":\"Total number of people\",\"question\":\"How many people are there in total?\",\"id\":\"nPeople\",\"if\":\"true\",\"required\":false,\"type\":\"integer\",\"units\":\"people\"},{\"title\":\"Peak network flow temperature\",\"question\":\"What is the peak network flow temperature?\",\"id\":\"tPeak\",\"if\":\"true\",\"required\":true,\"default\":80,\"type\":\"number\",\"units\":\"°C\"},{\"title\":\"DHW network return temperature\",\"question\":\"What is the network return temperature for DHW?\",\"notes\":\"The temperature fed back from a property to the network when running peak load domestic hot water.\",\"id\":\"tPriRtnDHW\",\"if\":\"true\",\"required\":false,\"default\":19,\"type\":\"number\",\"units\":\"°C\"},{\"title\":\"Central heating output per property\",\"question\":\"What is the central heating output per property?\",\"id\":\"kwCHPP\",\"if\":\"true\",\"required\":false,\"type\":\"number\",\"units\":\"kW\"},{\"title\":\"Central heating network return temperature\",\"question\":\"What is the network return temperature for central heating?\",\"notes\":\"The temperature fed back from a property to the network when running peak load central heating.\",\"id\":\"tPriRtnCH\",\"if\":\"{{kwCHPP}}\",\"required\":false,\"default\":45,\"type\":\"number\",\"units\":\"°C\"},{\"title\":\"Central heating diversity\",\"question\":\"What diversity is applied to central heating output?\",\"id\":\"divCH\",\"if\":\"{{kwCHPP}}\",\"required\":false,\"default\":70,\"type\":\"number\",\"units\":\"%\"}]},{\"title\":\"Heat Sources\",\"questions\":[{\"title\":\"Boilers\",\"question\":\"Are boilers to be used?\",\"id\":\"goBoilers\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\",\"options\":[true,false]},{\"title\":\"Air Source Heat Pumps\",\"question\":\"Are air source heat pumps to be used?\",\"notes\":\"Not including heat pumps in properties.\",\"id\":\"goASHP\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\",\"options\":[true,false]},{\"title\":\"Water Source Heat Pumps\",\"question\":\"Are water source heat pumps to be used?\",\"notes\":\"This is taking heat from an ambient loop or water source. Not including heat pumps in properties.\",\"id\":\"goWSHP\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\",\"options\":[true,false]},{\"title\":\"Cooling Source Heat Pumps\",\"question\":\"Are water source heat pumps to be used to reclaim cooling?\",\"notes\":\"This is where cooling circuits are driven by moving heat to the main storage.\",\"id\":\"goReclaim\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\",\"options\":[true,false]}]},{\"title\":\"Boilers\",\"questions\":[{\"title\":\"Available boiler outputs\",\"question\":\"What sizes of boiler output are available for selection?\",\"id\":\"listBSizes\",\"if\":\"true\",\"required\":true,\"type\":\"csv\",\"notes\":\"This is a comma-seperated list of outputs in kW. Selection will round up to the nearest available size.\",\"units\":\"kW\",\"value\":\"30,50,75,100,250,500,750,1000\"}]},{\"title\":\"Air Source Heat Pumps\",\"questions\":[{\"title\":\"ASHP refrigerant\",\"question\":\"What refrigerant is used in the heat pump?\",\"id\":\"fridgeASHP\",\"if\":\"{{goASHP}}\",\"required\":true,\"type\":\"select\",\"options\":[\"R744 (CO2)\"]},{\"title\":\"Available heat pump outputs\",\"question\":\"What sizes of heat pump output are available for selection?\",\"id\":\"listASHPSizes\",\"if\":\"{{goASHP}}\",\"required\":true,\"type\":\"csv\",\"notes\":\"This is a comma-seperated list of outputs in kW. Selection will round up to the nearest available size.\",\"units\":\"kW\",\"value\":\"30\"}]}],\"calculations\":[{\"id\":\"pPP\",\"title\":\"Average people per property\",\"if\":\"{{nProperties}}\",\"function\":\"{{nPeople}} / {{nProperties}}\",\"units\":\"people\"},{\"id\":\"kwDHWEst\",\"title\":\"Typical HIU rating for DHW\",\"if\":\"{{pPP}}\",\"function\":\"{{pPP}}<3?37.5:({{pPP}}<5?45:60)\",\"units\":\"kW\"},{\"id\":\"peepDS439\",\"title\":\"People per standard DS439 property\",\"if\":\"true\",\"function\":\"2.3\",\"units\":\"people\"},{\"id\":\"eqPropDS439\",\"title\":\"Equivalent number of DS439 properties\",\"if\":\"{{peepDS439}}\",\"function\":\"{{nPeople}}/{{peepDS439}}\",\"units\":\"properties\"},{\"id\":\"kwDS439\",\"title\":\"Peak DHW Load\",\"if\":\"{{eqPropDS439}}\",\"function\":\"Math.ceil((1.19* {{eqPropDS439}}) + (18.8* Math.pow({{eqPropDS439}},0.5)) + 17.6)\",\"units\":\"kW\"},{\"id\":\"vPPEST\",\"title\":\"Volume DHW used per property per day\",\"if\":\"true\",\"function\":\"40\",\"units\":\"litres\"},{\"id\":\"vPHEST\",\"title\":\"Volume DHW used per person per day\",\"if\":\"true\",\"function\":\"28\",\"units\":\"litres\"},{\"id\":\"tRiseEST\",\"title\":\"Average temperature Rise on DHW\",\"if\":\"true\",\"function\":\"35\",\"units\":\"°C\"},{\"id\":\"vDHWEST\",\"title\":\"Volume used per day for DHW\",\"if\":\"{{nPeople}}\",\"function\":\"({{nProperties}}*{{vPPEST}})+({{nPeople}}*{{vPHEST}})\",\"units\":\"litres\"},{\"id\":\"kwhDHWEST\",\"title\":\"Energy used per day for DHW\",\"if\":\"{{vDHWEST}}\",\"function\":\"({{vDHWEST}} * 4.2 * {{tRiseEST}}) / 3600\",\"units\":\"kWh\"},{\"id\":\"kwCH\",\"title\":\"Peak central heating load\",\"if\":\"{{kwCHPP}}\",\"function\":\"({{kwCHPP}} * {{divCH}} * {{nProperties}}) / 100\",\"units\":\"kW\"},{\"id\":\"kwPeak\",\"title\":\"Peak load\",\"if\":\"true\",\"function\":\"{{kwCH}}+{{kwDS439}}\",\"units\":\"kW\"},{\"id\":\"kwPeak24\",\"title\":\"Average 24h peak load\",\"if\":\"true\",\"function\":\"{{kwCH}}+({{kwhDHWEST}}/24)\",\"units\":\"kW\"},{\"id\":\"m3hDHWPeak\",\"title\":\"Primary flow rate at peak DHW load\",\"if\":\"{{tPriRtnDHW}}\",\"function\":\"3.6 * {{kwDS439}} / (4.2 * ({{tPeak}}-{{tPriRtnDHW}}))\",\"units\":\"m3/h\"},{\"id\":\"m3hCHPeak\",\"title\":\"Primary flow rate at peak central heating load\",\"if\":\"{{tPriRtnCH}}\",\"function\":\"3.6 * {{kwCH}} / (4.2 * ({{tPeak}}-{{tPriRtnCH}}))\",\"units\":\"m3/h\"},{\"id\":\"m3hPeak\",\"title\":\"Primary flow rate at peak load\",\"if\":\"{{m3hDHWPeak}}||{{m3hCHPeak}}\",\"function\":\"{{m3hDHWPeak}}+{{m3hCHPeak}}\",\"units\":\"m3/h\"},{\"id\":\"tPriRtnPeak\",\"title\":\"Primary return temperature at peak load\",\"if\":\"{{m3hPeak}}\",\"function\":\"{{tPeak}} - ({{kwPeak}} / (4.2 * {{m3hPeak}} / 3.6))\",\"units\":\"°C\"},{\"id\":\"test\",\"title\":\"Testing object\",\"if\":\"{{goASHP}}\",\"function\":{\"a\":\"hello\",\"b\":45},\"units\":\"object\"},{\"id\":\"test2\",\"title\":\"Testing object bx2\",\"if\":\"true\",\"function\":\"2 * {{test.b}}\",\"units\":\"object\"}]}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":1720,"y":200,"wires":[[]]},{"id":"57266758.3f2ab8","type":"http in","z":"cce2bfaa.e5748","name":"","url":"/ui/qdata/:qd","method":"get","upload":false,"swaggerDoc":"","x":240,"y":360,"wires":[["dd7405b4.c165a8"]]},{"id":"5a6a160d.a25fb8","type":"template","z":"cce2bfaa.e5748","name":"Heat Network Designer","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js\"></script>\n{{!--https://www.sitepoint.com/basic-jquery-form-validation-tutorial/--}}\n\n<script src=\"https://unpkg.com/mustache@latest\"></script>\n\n<style>\n\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 6px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\nvar a = new Date();\nvar qdata;\nvar calculated = {};\nvar hasFocus;\nvar inputsOut;\nvar inputString;\n\n\t$(document).ready(function(e) {\n    \n        // $(\"form[ajax=true]\").submit(function(e) {\n            \n        //     //alert(\"submit\");\n            \n        //     e.preventDefault();\n        \n             \n            //var urlParams = new URLSearchParams(window.location.search);\n            //if (urlParams.get('display')) { loadstring = \",,\" + urlParams.get('display'); }\n\n            var urlParams = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParams) {\n                \n                calculated[urlParams[upa].split(\"=\")[0]] = urlParams[upa].split(\"=\")[1];\n                \n            }\n            \n            var form_data = {};\n            var form_url = \"/ui/qdata\";\n            var form_target = $(this).attr(\"target\") || \"result\";\n            var ftarget = \"#\" + form_target;\n            var form_method = \"GET\";\n            \n        //     $(\"#loadingimg\").show();\n            \n            $.ajax({\n                url: form_url, \n                type: form_method,      \n                data: form_data,     \n                cache: false,\n                success: function(results){   \n                    \n                    qdata = results;\n                    //qdata = JSON.parse(returnhtml);\n                    console.log(qdata);\n                   \n                    \n                    document.getElementById(\"formName\").innerHTML = qdata.title || \"Unamed Form\"; //JSON.stringify(qdata) ;\n                    \n                    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n                    \n                    validform();\n                                  \n                }           \n            });    \n            \n        // });\n        \n      \n        \n    });\n\t\nfunction parseQuestions(qdata) {\n    \n    console.log(qdata);\n    console.log(calculated);\n    \n    var linkstxt=\"\";\n    if (qdata.links) {\n        for (var lnk in qdata.links) {\n            linkstxt += (linkstxt!==\"\"?\"<br>\":\"\") + '<a href=\"' + qdata.links[lnk].src + '\" target=\"_blank\">' + (qdata.links[lnk].title||qdata.links[lnk].src) + '</a>';\n        }\n        \n    }\n    document.getElementById(\"links\").innerHTML = linkstxt ; //JSON.stringify(qdata) ;\n    \n    inputsOut = '<table class=\"table\">';\n    \n    inputString = \"\";\n    hasFocus = null;\n    \n    var oot = \"\";\n    for (var s in qdata[\"sections\"]) {\n        console.log(s);\n        console.log(qdata.sections[s]);\n        oot += \"<div class='section'><h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        \n        \n        \n        for (var q in qdata.sections[s].questions) {\n            \n            \n            var qif = qdata.sections[s].questions[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n            var v=\"\";\n            if (calculated[qdata.sections[s].questions[q].id]) { v= calculated[qdata.sections[s].questions[q].id] ; }\n            else if (qdata.sections[s].questions[q].value) { v= qdata.sections[s].questions[q].value ; }\n            \n            if(goq) {\n            \n                if (v!==\"\") { \n                    inputsOut += \"<tr>\";  \n                    inputsOut += \"<td>\" + (qdata.sections[s].questions[q].title||qdata.sections[s].questions[q].id) + \"</td>\";\n                    inputsOut +=  '<td align=\"right\">' + v + \"</td>\";\n                    inputsOut +=  '<td width=\"20%\">' + (qdata.sections[s].questions[q].units||\"\") + \"</td></tr>\\n\";\n                    \n                    inputString += (inputString!==\"\"?\"&\":\"\") + qdata.sections[s].questions[q].id + \"=\" + v;\n                }\n            \n            \n                if (hasFocus && document.getElementById(\"oneQ\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">'; }\n            \n                else if (v!==\"\") { \n                    \n                    if (document.getElementById(\"hideDone\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">';   }\n                    else {  oot += '<div class=\"question\" style=\"background-color: #d2efd2;\">';  }\n                    \n                } else { oot += '<div class=\"question\">'; if (!hasFocus) { hasFocus = qdata.sections[s].questions[q].id; } }\n                \n                //oot += \"<div class='qtext'>\" + qdata.sections[s].questions[q].title + '</div>';\n                oot += '<label for=\"' + qdata.sections[s].questions[q].id + '\" class=\"qtext\">' + (qdata.sections[s].questions[q].question||qdata.sections[s].questions[q].title) + '</label>';\n                \n                if (qdata.sections[s].questions[q].notes) { oot += '<div class=\"notes\">'  + convertLinks(qdata.sections[s].questions[q].notes) + '</div>'; }\n                oot += '<table width=\"100%\"><tr><td width=\"80%\">';\n                \n                if (qdata.sections[s].questions[q].type==\"boolean\") {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                      if (v==\"true\") { oot += '<option value=\"false\">No</option><option value=\"true\" selected>Yes</option>'; }\n                      else if (v==\"false\")  { oot += '<option value=\"false\" selected>No</option><option value=\"true\">Yes</option>'; }\n                      else  { oot += '<option value=\"\"></option><option value=\"false\">No</option><option value=\"true\">Yes</option>'; }\n                    oot += '</select>';\n                    \n                } else if (qdata.sections[s].questions[q].options) {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    if (v==\"\") { oot += '<option value=\"\"></option>'; }\n                    for (var opt in qdata.sections[s].questions[q].options) {\n                    \n                      var optobj = qdata.sections[s].questions[q].options[opt];\n                      \n                      if (v==optobj) { oot += '<option selected value=\"' + optobj + '\">' + optobj + '</option>'; }\n                      else  { oot += '<option value=\"' + optobj + '\">' + optobj + '</option>'; }\n                      \n                    }  \n                    oot += '</select>';\n                    \n                } else {\n                \n                    oot += '<input id=\"' + qdata.sections[s].questions[q].id + '\" name=\"' + qdata.sections[s].questions[q].id + '\" class=\"form-control\" type=\"text\"';\n                    if (v!==\"\") { oot += ' value=\"' + v + '\"'; }\n                    if (qdata.sections[s].questions[q].default) { oot += ' placeholder=\"' + qdata.sections[s].questions[q].default + \" \" + (qdata.sections[s].questions[q].units||\"\") + ' ... please confirm\"'; }\n                    oot += '>';\n                }\n                \n                oot += '</td><td valign=\"top\"><span class=\"qunits\">' + (qdata.sections[s].questions[q].units||\"\") + '</span></td></tr></table></div>\\n';\n            }\n        }\n    \n        oot += \"</div>\\n\";\n        \n    }\n    inputsOut +=  \"</table>\\n\";  \n    \n    return oot;\n}\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\n// console.log(looseJsonParse(\n//   \"{a:(4-1), b:function(){}, c:new Date()}\"\n// ))\n\nfunction runCalcs() {\n\n\n    \n    \n    // run through form inputs and store current values into calculated.\n    var cells =  document.getElementsByClassName(\"form-control\");\n\tvar i;\n\tfor (i = 0; i < cells.length; i++) {\n\t\n\t\tcalcsOut += cells[i].value + \"<br>\\n\";\n        \n        if (\"\" + cells[i].value !== \"\") { \n            \n            if (isNaN(cells[i].value)) { \n                \n                calculated[cells[i].id] = (cells[i].value);\n                \n            } else {\n                \n                calculated[cells[i].id] = parseFloat(cells[i].value);\n            }\n        }\n\t}\n    \n    var calcsOut = '<table class=\"table\">';\n    for (var calc in (qdata[\"calculations\"]||[])) {\n        \n        console.log(calc);\n        console.log(qdata.calculations[calc]);\n        \n        \n        var cif = qdata.calculations[calc].if || true;\n        var cift = Mustache.render(cif, calculated);\n        var goc = true;\n        try {\n          goc = looseJsonParse(cift); \n        }\n        catch(err) {\n          goc = false;\n        }\n        \n        if (goc) {\n        \n            var f = qdata.calculations[calc].function;\n            var ft;\n            var cv = \"\";\n            \n            calcsOut += \"<tr>\"; \n            calcsOut += \"<td>\" + (qdata.calculations[calc].title||qdata.calculations[calc].id) + \"</td>\";\n            \n            try {\n                \n                ft = Mustache.render(f, calculated);  // error trap incase object\n                cv = looseJsonParse(ft); \n                if (!isNaN(cv)) { cv = parseInt(cv*1000)/1000; }\n                if (document.getElementById(\"hideMaths\").checked!==true) {\n                    calcsOut += \"<td><small>\" + ft + \"</small></td>\";   //\"<br>\\n\";\n                }\n                calcsOut +=  '<td align=\"right\">' + cv + \"</td>\"; \n                 \n            }\n            catch(err) {   // is an object returned\n                \n                ft = f; \n                cv = f; \n                var obst = \"\";\n                try { obst = JSON.stringify(cv); } catch { obst = \"error\"; }\n                //if (document.getElementById(\"hideMaths\").checked!==true) { calcsOut += \"<td> </td>\";  }\n                calcsOut += '<td ';\n                if (document.getElementById(\"hideMaths\").checked!==true) { calcsOut += 'colspan=\"2\" ';  }\n                calcsOut += 'align=\"right\"><small>' + obst + \"</small></td>\";\n                \n            }\n            \n            calculated[qdata.calculations[calc].id] = cv;\n            \n            calcsOut +=  '<td width=\"20%\">' + (qdata.calculations[calc].units||\"\") + \"</td></tr>\\n\";\n            \n            \n            \n        }\n        \n    }\n    \n    calcsOut +=  \"</table>\\n\";\n    \n    // for (var calc in calculated) {\n        \n        \n    // }\n    \n    document.getElementById(\"calcs\").innerHTML = calcsOut; //JSON.stringify(qdata) ;\n    \n    // rebuild form\n    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"inputs\").innerHTML = inputsOut; //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"mylink\").innerHTML = '<a href=\"hndesign?' + inputString + '\" target=\"_blank\">Click/Copy this link to open design...</a>'; //JSON.stringify(qdata) ;\n    \n    \n    \n    validform();\n                    \n}\n\n\nconst convertLinks = ( input ) => {\n\n  let text = input;\n  const linksFound = text.match( /(?:www|https?)[^\\s]+/g );\n  const aLink = [];\n\n  if ( linksFound != null ) {\n\n    for ( let i=0; i<linksFound.length; i++ ) {\n      let replace = linksFound[i];\n      if ( !( linksFound[i].match( /(http(s?)):\\/\\// ) ) ) { replace = 'http://' + linksFound[i] }\n      let linkText = replace.split( '/' )[2];\n      if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) }\n      if ( linkText.match( /youtu/ ) ) {\n\n        let youtubeID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://www.youtube.com/embed/' + youtubeID + '\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe></div>' )\n      }\n      else if ( linkText.match( /vimeo/ ) ) {\n        let vimeoID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://player.vimeo.com/video/' + vimeoID + '\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' )\n      }\n      else {\n        aLink.push( '<a href=\"' + replace + '\" target=\"_blank\">' + linkText + '</a>' );\n      }\n      text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] );\n    }\n    return text;\n\n  }\n  else {\n    return input;\n  }\n}\n\nfunction validform() {\n    \n    if(hasFocus && document.getElementById(hasFocus)) {\n        document.getElementById(hasFocus).focus();\n    }\n    \n    \n    \n// Initialize form validation on the registration form.\n  // It has the name attribute \"registration\"\n  $(\"form[name='qform']\").validate({\n    // Specify validation rules\n    rules: {\n      // The key name on the left side is the name attribute\n      // of an input field. Validation rules are defined\n      // on the right side\n      nProperties: {\n        required: true,\n        digits: true,\n        min: 1\n      },\n      lastname: \"required\",\n      email: {\n        required: true,\n        // Specify that email should be validated\n        // by the built-in \"email\" rule\n        email: true\n      },\n      password: {\n        required: true,\n        minlength: 5\n      }\n    },\n    // Specify validation error messages\n    messages: {\n      nProperties: \"Please enter a number.\",\n      lastname: \"Please enter your lastname\",\n      password: {\n        required: \"Please provide a password\",\n        minlength: \"Your password must be at least 5 characters long\"\n      },\n      email: \"Please enter a valid email address\"\n    },\n    // Make sure the form is submitted to the destination defined\n    // in the \"action\" attribute of the form when valid\n    submitHandler: function(form) {\n      //form.submit();\n      runCalcs();\n      //alert(\"hello\");\n    }\n  });\n}\n\n</script>\n\n\n<div class='section'>\n    \n    <table width=\"100%\"><tr>\n    <td valign=\"top\" width=\"70%\">\n        <div id=\"formName\" class=\"h1\"></div>\n        <a href=\"https://heatweb.co.uk/w/index.php?title=Heat_Network_Designer\" target=\"_blank\"><small>Wiki Help Page</small></a>\n    </td>\n    <td width=\"30%\">\n        <input type=\"checkbox\" id=\"oneQ\" name=\"oneQ\" checked> <small>One question at a time</small><br>\n        <input type=\"checkbox\" id=\"hideDone\" name=\"hideDone\" checked> <small>Hide completed questions</small><br>\n        <input type=\"checkbox\" id=\"hideMaths\" name=\"hideMaths\" checked> <small>Hide maths equations</small>\n    </td>\n    </tr></table>\n</div>\n\n\n<form action=\"\" name=\"qform\" id=\"qform\">\n<div id=\"section1\"></div>\n\n<div class='section'>\n<button type=\"submit\">Submit</button>\n\n</div>\n\n\n<div class='section'>\n<p><b>Inputs</b></p>\n<div id=\"inputs\" class=\"notes\"></div>\n</div>\n\n<div class='section'>\n<p><b>Numeric Values and Calculations</b></p>\n<div id=\"calcs\" class=\"notes\"></div>\n</div>\n\n\n<div class='section'>\n<p><b>Links</b></p>\n<div id=\"mylink\" class=\"notes\"></div>\n<div id=\"links\" class=\"notes\"></div>\n</div>\n</form>","output":"str","x":1490,"y":160,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"ded643a7.55925","type":"http in","z":"cce2bfaa.e5748","name":"","url":"/ui/hndesignfunctions","method":"get","upload":false,"swaggerDoc":"","x":230,"y":520,"wires":[["b2a81672.0b7388","c835eae.f6c4818"]]},{"id":"40987f89.08381","type":"template","z":"cce2bfaa.e5748","name":"hndesign1","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n<style>\n\nbody {\n    background-color: transparent;\n}\n\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 6px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\n\nvar inputs = {};\nvar oot = \"\";\nvar oots=[];\n\n\t$(document).ready(function(e) {\n    \n            var urlParams = new URLSearchParams(window.location.search);\n            //var listBSizes = urlParams.get('listBSizes');\n\n            var urlParamsL = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParamsL) {\n                \n                inputs[urlParamsL[upa].split(\"=\")[0]] = urlParamsL[upa].split(\"=\")[1];\n                oot += urlParamsL[upa].split(\"=\")[0] + \"=\" + urlParamsL[upa].split(\"=\")[1] + \" \";\n            }\n            \n            //document.getElementById(\"section1\").innerHTML = oot; //window.location.search;\n            \n            oot=\"\";\n            \n            if (inputs[\"field\"]==\"selectBoilers\") {\n                \n                \n                var breq = parseFloat(inputs[\"kwP24\"]);\n                var boot = \"\";\n                \n                var brun = runsize(breq);\n                \n                oot = brun.qty + \" x \" + brun.size; // + \"kW\";\n                oots.push(oot);\n                boot += '<button onclick=\"returncalc(0)\">' + oot + 'kW (min)</button> ';\n                \n                oot = (brun.qty+1) + \" x \" + brun.size; // + \"kW\";\n                oots.push(oot);\n                boot += '  <button onclick=\"returncalc(1)\">' + oot + 'kW (N+1)</button> ';\n                \n                suggestcalc(1);\n                \n                if (inputs[\"kwPeak\"]) {    \n                    var brun = runsize(parseFloat(inputs[\"kwPeak\"]));\n                    \n                    oot = brun.qty + \" x \" + brun.size; // + \"kW\";\n                    oots.push(oot);\n                    boot += '  <button onclick=\"returncalc(2)\">' + oot + 'kW (max)</button> ';\n                }\n                \n                \n            }\n            document.getElementById(\"section1\").innerHTML = boot;\n\t});\n\nfunction runsize(breq) {\n    \n    var blist = (inputs[\"listBSizes\"] || \"30,50,75,100,150,250,400,500,750,1000\").split(\",\");\n    var nplus = (inputs[\"nplus\"] || 0);\n    var bsel = 0;\n    \n    \n    for (var diver = 3; diver<100; diver++) {\n        for (var sz in blist) {\n            \n            if ((diver*parseFloat(blist[sz]))>breq) { bsel = blist[sz]; break; }\n        }\n        if (bsel>0) { break; }\n    }\n    \n    diver = diver + nplus;\n    return({\"qty\":diver,\"size\":bsel});\n                \n}\n\n\n\nfunction returncalc(v) {\n    \n    try { parent.returncalc(inputs[\"field\"],oots[v]); } catch { }\n}\nfunction suggestcalc(v) {\n    \n    try { parent.suggestcalc(inputs[\"field\"],oots[v]); } catch { }\n}\n\n</script>\n\n\n<small><div id=\"section1\"></div></small>\n\n\n","output":"str","x":750,"y":520,"wires":[["a5d17239.59f16"]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"46f26691.159bd8","type":"link in","z":"cce2bfaa.e5748","name":"","links":["ff5ca928.7571d8","a5d17239.59f16","3641b220.fd838e","ff07a724.4bee18","2a501ff2.83e55","257acec1.1b5382"],"x":535,"y":100,"wires":[["b6ba981e.886638"]]},{"id":"ff5ca928.7571d8","type":"link out","z":"cce2bfaa.e5748","name":"","links":["46f26691.159bd8"],"x":655,"y":220,"wires":[]},{"id":"a5d17239.59f16","type":"link out","z":"cce2bfaa.e5748","name":"","links":["46f26691.159bd8"],"x":975,"y":520,"wires":[]},{"id":"b56afcbd.d0d9","type":"template","z":"cce2bfaa.e5748","name":"hndesign1","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n<style>\n\nbody {\n    background-color: transparent;\n}\n\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 6px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\n\nvar inputs = {};\nvar oot = \"\";\n\n\t$(document).ready(function(e) {\n    \n            var urlParams = new URLSearchParams(window.location.search);\n            //var listBSizes = urlParams.get('listBSizes');\n\n            var urlParamsL = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParamsL) {\n                \n                inputs[urlParamsL[upa].split(\"=\")[0]] = urlParamsL[upa].split(\"=\")[1];\n                oot += urlParamsL[upa].split(\"=\")[0] + \"=\" + urlParamsL[upa].split(\"=\")[1] + \" \";\n            }\n            \n            document.getElementById(\"section1\").innerHTML = oot; //window.location.search;\n            \n            if (inputs[\"listBSizes\"]) {\n                \n                document.getElementById(\"section1\").innerHTML = inputs[\"listBSizes\"];\n                suggestcalc(inputs[\"listBSizes\"]);\n            }\n            \n\t});\n\nfunction returncalc(v) {\n    \n    try { parent.returncalc(inputs[\"field\"],v); } catch { }\n}\nfunction suggestcalc(v) {\n    \n    try { parent.suggestcalc(inputs[\"field\"],v); } catch { }\n}\n\n</script>\n\n\n<small><div id=\"section1\"></div></small>\n\n<button onclick=\"returncalc(123)\">OK</button>\n","output":"str","x":1550,"y":1040,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"b2a81672.0b7388","type":"debug","z":"cce2bfaa.e5748","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":360,"y":580,"wires":[]},{"id":"c835eae.f6c4818","type":"switch","z":"cce2bfaa.e5748","name":"","property":"payload.field","propertyType":"msg","rules":[{"t":"eq","v":"selectBoilers","vt":"str"},{"t":"eq","v":"selectASHP","vt":"str"}],"checkall":"false","repair":false,"outputs":2,"x":510,"y":520,"wires":[["40987f89.08381"],["e391cd6a.513e7"]]},{"id":"e391cd6a.513e7","type":"template","z":"cce2bfaa.e5748","name":"hndesign1","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n<style>\n\nbody {\n    background-color: transparent;\n}\n\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 6px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\n\nvar inputs = {};\nvar oot = \"\";\nvar oots=[];\n\n\t$(document).ready(function(e) {\n    \n            var urlParams = new URLSearchParams(window.location.search);\n            //var listBSizes = urlParams.get('listBSizes');\n\n            var urlParamsL = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParamsL) {\n                \n                inputs[urlParamsL[upa].split(\"=\")[0]] = urlParamsL[upa].split(\"=\")[1];\n                oot += urlParamsL[upa].split(\"=\")[0] + \"=\" + urlParamsL[upa].split(\"=\")[1] + \" \";\n            }\n            \n            //document.getElementById(\"section1\").innerHTML = oot; //window.location.search;\n            \n            oot=\"\";\n            \n            if (inputs[\"field\"]==\"selectASHP\") {\n                \n                \n                var breq = parseFloat(inputs[\"kwP24\"]);\n                var boot = \"\";\n                \n                var brun = runsize(breq);\n                \n                oot = brun.qty + \" x \" + brun.size; // + \"kW\";\n                oots.push(oot);\n                boot += '<button onclick=\"returncalc(0)\">' + oot + 'kW (min)</button> ';\n                \n                oot = (brun.qty+1) + \" x \" + brun.size; // + \"kW\";\n                oots.push(oot);\n                boot += '  <button onclick=\"returncalc(1)\">' + oot + 'kW (N+1)</button> ';\n                \n                suggestcalc(1);\n                \n                if (inputs[\"kwPeak\"]) {    \n                    var brun = runsize(parseFloat(inputs[\"kwPeak\"]));\n                    \n                    oot = brun.qty + \" x \" + brun.size; // + \"kW\";\n                    oots.push(oot);\n                    boot += '  <button onclick=\"returncalc(2)\">' + oot + 'kW (max)</button> ';\n                }\n                \n                \n            }\n            document.getElementById(\"section1\").innerHTML = boot;\n\t});\n\nfunction runsize(breq) {\n    \n    var blist = (inputs[\"listASHPSizes\"] || \"30,50,75,100,150,250,400,500,750,1000\").split(\",\");\n    var nplus = (inputs[\"nplus\"] || 0);\n    var bsel = 0;\n    \n    \n    for (var diver = 3; diver<100; diver++) {\n        for (var sz in blist) {\n            \n            if ((diver*parseFloat(blist[sz]))>breq) { bsel = blist[sz]; break; }\n        }\n        if (bsel>0) { break; }\n    }\n    \n    diver = diver + nplus;\n    return({\"qty\":diver,\"size\":bsel});\n                \n}\n\n\n\nfunction returncalc(v) {\n    \n    try { parent.returncalc(inputs[\"field\"],oots[v]); } catch { }\n}\nfunction suggestcalc(v) {\n    \n    try { parent.suggestcalc(inputs[\"field\"],oots[v]); } catch { }\n}\n\n</script>\n\n\n<small><div id=\"section1\"></div></small>\n\n\n","output":"str","x":750,"y":560,"wires":[["a5d17239.59f16"]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"ba08a660.a2af08","type":"template","z":"cce2bfaa.e5748","name":"editor","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n\n\n<style>\n    \n    body {\n        background-color: transparent;\n    }\n\n    .jexcel_content {\n        font-size: 12px;\n    }\n    \n    .jexcel {\n        white-space: normal;\n    }\n</style>\n\n \n<div id=\"spreadsheet1\"></div>\n\n\n<script>\n\n \n\nvar columns1 = [\n        {\n            type: 'text',\n            name: 'propertyType',\n            title:'Property Type',\n            width:90\n        },\n        {\n            type: 'numeric',\n            name: 'bedrooms',\n            title:'Bedrooms',\n            width:80,\n            decimal:'.'\n        },\n        {\n            type: 'numeric',\n            name: 'occupants',\n            title:'Occupants',\n            width:80,\n            decimal:'.'\n        },\n        {\n            type: 'numeric',\n            name: 'kwCH',\n            title:'Heating Load kW',\n            width:80,\n            decimal:'.'\n        },\n        {\n            type: 'numeric',\n            name: 'tHoCH',\n            title:'Primary CH Return Temp C',\n            width:80,\n            decimal:'.'\n        },\n        {\n            type: 'numeric',\n            name: 'kwDHW',\n            title:'DHW Peak kW',\n            width:80,\n            decimal:'.'\n        },\n        {\n            type: 'numeric',\n            name: 'tHoDHW',\n            title:'Primary DHW Return Temp C',\n            width:80,\n            decimal:'.'\n        },\n        {\n            type: 'numeric',\n            name: 'qty',\n            title:'Quantity',\n            width:80,\n            decimal:'.'\n        }\n     ];\n\n\nvar data1 = [\n    ['Flat', 1, 2,  3, 35,  37.5,28,  130],\n    ['Duplex', 2, 4, 5.5, 35, 45,28, 20],\n];\n\nvar myspreadsheet1 = jspreadsheet(document.getElementById('spreadsheet1'), {\n    data:data1,\n    columns: columns1\n});\n\n</script>","output":"str","x":1430,"y":1000,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"5bbd9898.b60428","type":"template","z":"cce2bfaa.e5748","name":"editor","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n \n<p>This is a calculator for sizing and equipment selection on heat networks.</p>\n<p>Right click or press <i>Enter</i> in a cell to add new rows.</p>\n<br>\n\n<style>\n    .jexcel_content {\n        font-size: 15px;\n    }\n    \n    .jexcel {\n        white-space: normal;\n    }\n</style>\n\n \n<div id=\"spreadsheet1\"></div>\n<br>\n<table cellpadding=\"6\">\n  <tr><td>Central Heating Diversity:</td><td><input type=\"text\" id=\"chdiv\" name=\"chdiv\" value=\"70\" placeholder=\"% Peak\"> % </td></tr>\n  \n <tr><td>Peak Flow Temperature:</td><td><input type=\"text\" id=\"tHPeak\" name=\"tHPeak\" value=\"75\" placeholder=\"Input C\"> C</td></tr>\n \n</table>\n\n\n<br>\nHot Water Hourly Profile (default values from EST study):<br>\n<div id=\"profilesheet\"></div>\n<br>\n<input type=\"button\" onClick=\"runprofile()\" value=\"Level to 100%\"> <input type=\"button\" onClick=\"resetprofile()\" value=\"Reset to EST volumes\">\n<br>\n<br>\n<input type=\"button\" onClick=\"calc(1)\" value=\"Run Calculation\">\n<br><br>\n<div id=\"spreadsheet1results\"></div>\n\n<br>\n<div id=\"spreadsheet3\"></div>\n<br><br>\n<p>Heat input is initially set to the minimum, resulting in maximum storage sizes. Increase the heat input to reduce storage sizes.</p>\n<p>Network DHW Priority requires networked HIUs that can respond to signals from planroom to limit central heating loads for short periods to enable load prioritisation, and thereby limit the instantaneous demand on the system as required.  This allows peak heat input to be safely sized to average hourly loads and may avoid the need for storage.</p>\n<table cellpadding=\"6\">\n    <tr><td>Heat Input (kW):</td><td><input type=\"text\" id=\"boilerkw\" name=\"boilerkw\" value=\"\" placeholder=\"Input kW\"></td></tr>\n \n <tr><td>Network DHW Priority:</td><td><input type=\"checkbox\" id=\"dhwPriority\" name=\"dhwPriority\"></td></tr>\n</table>\n<br><input type=\"button\" onClick=\"runstore()\" value=\"Run Storage Calcs\">\n<br><br>\n<div id=\"spreadsheet2results\"></div>\n<br><br>\n<table>\n    <tr>\n        <td><div id=\"spreadsheet2\"></div></td>\n        <td width=\"100\"> </td>\n        <td valign=\"top\"></td>\n    </tr>\n</table>\n\n<br><br>\n\n\n<br><br>\n<div id=\"spreadsheet\"></div>\n\n \n<br><br>\n\n<script>\n\nvar calcs = {};\n\n    function calc(n) {\n        \n        \n        console.log(myspreadsheet1.getJson());\n        \n        calcs[\"totalCH\"] = 0;\n        calcs[\"totalDHW\"] = 0;\n        calcs[\"kwhDHW\"] = 0;\n        calcs[\"weighCH\"] = 0;\n        calcs[\"vHCH\"] = 0;\n        calcs[\"vHDHW\"] = 0;\n        \n        calcs[\"tHPeak\"] = parseFloat(document.getElementById(\"tHPeak\").value || 75);\n        calcs[\"divCH\"] = parseFloat(document.getElementById(\"chdiv\").value || 100) / 100;\n        \n        var dat = myspreadsheet1.getJson();\n        for (var line in dat) {\n            \n            if (dat[line][\"enabled\"]==true) {\n                calcs[\"totalCH\"]  = calcs[\"totalCH\"] + (calcs[\"divCH\"] * parseFloat(dat[line][\"kwCH\"]) * parseFloat(dat[line][\"qty\"]));\n                calcs[\"totalDHW\"]  = calcs[\"totalDHW\"] + (parseFloat(dat[line][\"kwDHW\"]) * parseFloat(dat[line][\"qty\"]));\n                \n                var kwhdhw =  parseFloat(dat[line][\"qty\"]) * 4200 * parseFloat(dat[line][\"deltatDHW\"])  * (parseFloat(dat[line][\"vPropDHW\"]) +  (parseFloat(dat[line][\"vPersonDHW\"]) * parseFloat(dat[line][\"occupants\"])));\n                kwhdhw = kwhdhw / (1000*3600);\n                \n                calcs[\"kwhDHW\"]  = calcs[\"kwhDHW\"] + kwhdhw;\n                \n                var myvCH = (parseFloat(dat[line][\"qty\"]) * 24 * 3600 * calcs[\"divCH\"] * parseFloat(dat[line][\"kwCH\"]) / (4.200 * (calcs[\"tHPeak\"] - parseFloat(dat[line][\"tHoCH\"]))) );\n                calcs[\"vHCH\"] = calcs[\"vHCH\"] + myvCH;\n                \n                var myvDHW =  (3600 * kwhdhw / (4.200 * (calcs[\"tHPeak\"] - parseFloat(dat[line][\"tHoDHW\"]))) );\n                \n                calcs[\"vHDHW\"] = calcs[\"vHDHW\"] + myvDHW;\n                calcs[\"weighCH\"]  = calcs[\"weighCH\"] + (parseFloat(dat[line][\"tHoCH\"]) *  myvCH)  + (parseFloat(dat[line][\"tHoDHW\"]) *  myvDHW);\n               \n                \n                \n            }\n        }\n        calcs[\"ds439number\"] = Math.ceil(calcs[\"totalDHW\"] / 37.5);\n        \n        calcs[\"ds439load\"]  = Math.ceil((1.19* calcs[\"ds439number\"]) + (18.8* Math.pow(calcs[\"ds439number\"],0.5)) + 17.6);\n        \n        calcs[\"kwAvgDHW\"] = Math.ceil(10*(calcs[\"kwhDHW\"] / 24)) /10;\n        \n        calcs[\"kwAvg\"] = Math.ceil(10*(calcs[\"kwAvgDHW\"] + calcs[\"totalCH\"])) /10;\n        \n        //if (calcs[\"totalCH\"]) {\n            calcs[\"tHoPeak\"] =  Math.ceil(10*(  calcs[\"weighCH\"] / (calcs[\"vHCH\"] + calcs[\"vHDHW\"])  )) /10;\n        //}\n        \n        var result1 = \"Total CH: \" + (Math.ceil(10*(calcs[\"totalCH\"]))/10) + \"kW\";\n        \n        result1 += \"<br>Total DHW: \" +  (Math.ceil(10*(calcs[\"kwhDHW\"]))/10) + \"kWh\";\n        result1 += \"<br>Averaged DHW: \" + calcs[\"kwAvgDHW\"] + \"kW\";\n        \n        result1 += \"<br>Diversified DHW: \" + calcs[\"ds439load\"] + \"kW (\" + calcs[\"ds439number\"] +\" equivalent 37.5kW properties)\";\n        result1 += \"<br>Minimum Averaged Input: \" + calcs[\"kwAvg\"] + \"kW\";\n        \n        \n        result1 += \"<br>Daily Volume CH: \" +  (Math.ceil(10*(calcs[\"vHCH\"]))/10) + \" litres\";\n        result1 += \"<br>Daily Volume DHW: \" +  (Math.ceil(10*(calcs[\"vHDHW\"]))/10) + \" litres\";\n        \n        result1 += \"<br>Volume Weighed Average Return Temperature: \" + calcs[\"tHoPeak\"] + \"C\";\n        \n        document.getElementById(\"spreadsheet1results\").innerHTML = result1;\n        \n        var holdp = document.getElementById(\"dhwPriority\").checked;\n        ssets = [];\n        runstorearray();\n        \n        document.getElementById(\"dhwPriority\").checked = holdp;\n        document.getElementById(\"boilerkw\").value =  calcs[\"kwAvg\"];\n        \n        runstore();\n    }\n    \n    \n    function runstore() {\n        \n        \n        //var estVolumes = [1.8,1.2,1,0.8,1.3,1.7,4.5,8.7,7.6,6.1,5.4,4.8,4.2,3.6,3.1,3.2,3.7,5.3,7.7,7.3,6.1,4.9,3.7,2.4];\n        var estVolumes = dhwprofilesheet.getRowData(0);\n        \n        calcs[\"tHPeak\"] = parseFloat(document.getElementById(\"tHPeak\").value || 75);\n        \n        columns2 = [\n            {\n                type: 'numeric',\n                name: 'hour',\n                title:'Hour',\n                width:90,\n                decimal:'.'\n            },\n            {\n                type: 'numeric',\n                name: 'percent',\n                title:'EST Volume %',\n                width:80,\n                decimal:'.'\n            },\n            {\n                type: 'numeric',\n                name: 'dhwload',\n                title:'DHW Energy kWh',\n                width:80,\n                decimal:'.'\n            },\n            {\n                type: 'numeric',\n                name: 'dischargetime',\n                title:'Discharge Time h',\n                width:80,\n                decimal:'.'\n            },\n            {\n                type: 'numeric',\n                name: 'dischargestorage',\n                title:'Discharge Storage kWh',\n                width:80,\n                decimal:'.'\n            },\n            {\n                type: 'numeric',\n                name: 'energy',\n                title:'Balance kWh',\n                width:80,\n                decimal:'.'\n            },\n            {\n                type: 'numeric',\n                name: 'dischargebalance',\n                title:'Discharge Balance kWh',\n                width:80,\n                decimal:'.'\n            }\n        ];\n        \n        \n        var runload = 0;\n        var runinput = 0;\n        var mine = 999999;\n        var maxe = -999999;\n        var maxh = -999999;\n        var hr = 0;\n        volumecalcs = [];\n        var lastbalance = 0;\n        \n        if (parseFloat(document.getElementById(\"boilerkw\").value)  < calcs[\"kwAvg\"]) {\n            \n            alert(\"Not enough heat input, adjusting to minimum.\");\n            document.getElementById(\"boilerkw\").value = calcs[\"kwAvg\"];\n        }\n        \n        calcs[\"boilerkw\"] =parseFloat(document.getElementById(\"boilerkw\").value);\n         \n        var bin = calcs[\"boilerkw\"] - calcs[\"totalCH\"];\n        console.log(\"bin=\"+bin);\n        \n        calcs[\"dhwPriority\"] = document.getElementById(\"dhwPriority\").checked;\n        console.log(\"dhwPriority=\"+calcs[\"dhwPriority\"]);\n        \n        \n        \n        for (var h in estVolumes) {\n            \n            hr++;\n            \n            var houroff = hr + 5;  // start with first hour where output exceeds min input - where store would be full.\n            if (houroff>23) { houroff = houroff - 24; }\n            var ob = {};\n            ob[\"hour\"] = houroff; //hr;\n            ob[\"percent\"] = estVolumes[houroff];\n            ob[\"dhwload\"] = parseInt(estVolumes[houroff] * calcs[\"kwhDHW\"]) / 100;\n            \n            \n             ob[\"dischargetime\"] = Math.ceil(1000*(ob[\"dhwload\"] / calcs[\"ds439load\"]))/1000;\n             \n            if (calcs[\"dhwPriority\"]==true) {\n                \n                var dhwneeded = calcs[\"ds439load\"] - calcs[\"totalCH\"];\n                \n                ob[\"dischargestorage\"] = Math.ceil(10*(ob[\"dhwload\"] - (ob[\"dischargetime\"] * calcs[\"boilerkw\"]))) / 10;\n                \n            } else {\n                \n                ob[\"dischargestorage\"] = Math.ceil(10*(ob[\"dhwload\"] - (ob[\"dischargetime\"] * bin))) / 10;\n            }\n            \n            \n            if (ob[\"dischargestorage\"] < 0) { ob[\"dischargestorage\"] =0; }\n            \n            \n            ob[\"dischargebalance\"] = Math.ceil(10*(lastbalance - ob[\"dischargestorage\"]))/10;\n            \n            runload = runload + ob[\"dhwload\"];\n            runinput = runinput + bin;\n            \n            ob[\"energy\"] = parseInt(100*(runinput - runload))/100;\n            \n            if (ob[\"energy\"]>0) { // removed input beyond store capacity\n                \n                runinput = runinput - ob[\"energy\"];   \n                ob[\"energy\"] = 0; \n                \n            }\n            \n            if (ob[\"energy\"] < mine) { mine = ob[\"energy\"]; }\n            if (ob[\"energy\"] > maxe) { maxe = ob[\"energy\"]; }\n            //if (ob[\"dischargestorage\"] > maxh) { maxh = ob[\"dischargestorage\"]; }\n            \n            if ((0-ob[\"dischargebalance\"]) > maxh) { maxh = 0-ob[\"dischargebalance\"]; }\n            \n            lastbalance = ob[\"energy\"];\n            \n            volumecalcs.push(ob);\n            \n        }\n        calcs[\"khwStorage\"] = Math.ceil(Math.max(maxe - mine, maxh));\n        \n        \n        calcs[\"litreStorage\"] = Math.ceil(calcs[\"khwStorage\"] * 3600000 / (4200 * (calcs[\"tHPeak\"] - calcs[\"tHoPeak\"])));\n        \n        \n        document.getElementById('spreadsheet2').innerHTML=\"\";\n        var myspreadsheet2 = jspreadsheet(document.getElementById('spreadsheet2'), {\n            data: volumecalcs,\n            columns: columns2\n        });\n        \n        \n        var result2 = \"Minimum Averaged Storage: \" + calcs[\"khwStorage\"] + \"kWh\";\n        result2 += \" = \" + calcs[\"litreStorage\"] + \" litres\";\n        \n        document.getElementById(\"spreadsheet2results\").innerHTML = result2;\n        \n    }\n    \n    \n    var ssets = [];\n    \n    function runstorearray() {\n        \n        \n        \n        brun = [calcs[\"kwAvg\"]];\n        var b30 = 30* Math.ceil(calcs[\"kwAvg\"] / 30);\n        brun.push( b30 );\n        \n        if(calcs[\"kwAvg\"]>70) { brun.push( b30 + 30 ); }\n        if(calcs[\"kwAvg\"]>100) { brun.push( b30 + 60 ); }\n        \n        brun.push( calcs[\"ds439load\"] + calcs[\"totalCH\"] );\n        \n        for (var k in brun) {\n            \n            var ob2 =  {\"boilerkw\":brun[k] };\n            document.getElementById(\"boilerkw\").value = brun[k];\n            document.getElementById(\"dhwPriority\").checked = false;\n            runstore();\n            ob2[\"vStore\"] = calcs[\"litreStorage\"];\n            \n            document.getElementById(\"boilerkw\").value = brun[k];\n            document.getElementById(\"dhwPriority\").checked = true;\n            runstore();\n            ob2[\"vStorePriority\"] = calcs[\"litreStorage\"];\n            \n            ssets.push( ob2 )\n        }\n        \n        document.getElementById('spreadsheet3').innerHTML=\"\";\n        var myspreadsheet3 = jspreadsheet(document.getElementById('spreadsheet3'), {\n            data: ssets,\n            columns: [\n            {\n                type: 'numeric',\n                name: 'boilerkw',\n                title:'kW Input',\n                width:150,\n                decimal:'.'\n            },\n            {\n                type: 'numeric',\n                name: 'vStore',\n                title:'Storage Volume litres',\n                width:150,\n                decimal:'.'\n            },\n            {\n                type: 'numeric',\n                name: 'vStorePriority',\n                title:'Storage Volume (With Priority) litres',\n                width:150,\n                decimal:'.'\n            }],\n            updateTable:function(instance, cell, col, row, val, label, cellName) {\n               \n                if (row==2) {\n                        cell.style.backgroundColor = '#aaffaa';\n                    \n                }\n            },\n            columnSorting:false\n        });\n        \n    }\n    \n    \n    \n    function but() {\n        \n        \n        console.log(myspreadsheet.getJson());\n        console.log(myspreadsheet.getConfig());\n        \n    }\n    function fullscreen(mode) {\n    \n        myspreadsheet.fullscreen(mode);\n        \n    }\n\n\n\nvar columns1 = [\n        {\n            type: 'text',\n            name: 'propertyType',\n            title:'Property Type',\n            width:90\n        },\n        {\n            type: 'numeric',\n            name: 'bedrooms',\n            title:'Bedrooms',\n            width:80,\n            decimal:'.'\n        },\n        {\n            type: 'numeric',\n            name: 'occupants',\n            title:'Occupants',\n            width:80,\n            decimal:'.'\n        },\n        {\n            type: 'dropdown',\n            name: 'connectionTypeCH',\n            title:'Heating Connection',\n            width:120,\n            source:[\n                \"direct\",\n                \"indirect\",\n                \"none\",\n                // (...)\n              ]\n        },\n        {\n            type: 'dropdown',\n            name: 'emitterTypeCH',\n            title:'Heating Type',\n            width:120,\n            source:[\n                \"radiators\",\n                \"underfloor\",\n                \"none\",\n                // (...)\n              ]\n        },\n        {\n            type: 'numeric',\n            name: 'kwCH',\n            title:'Heating Load kW',\n            width:80,\n            decimal:'.'\n        },\n        {\n            type: 'numeric',\n            name: 'tHoCH',\n            title:'Primary CH Return Temp C',\n            width:80,\n            decimal:'.'\n        },\n        {\n            type: 'dropdown',\n            name: 'connectionTypeDHW',\n            title:'DHW Type',\n            width:120,\n            source:[\n                \"instantaneous\",\n                \"phe+coil+store\",\n                \"phe+store\",\n                \"coil+store\",\n                \"none\",\n                // (...)\n              ]\n        },\n        {\n            type: 'numeric',\n            name: 'kwDHW',\n            title:'DHW Peak kW',\n            width:80,\n            decimal:'.'\n        },\n        {\n            type: 'numeric',\n            name: 'vPropDHW',\n            title:'DHW Litres (property)',\n            width:80,\n            decimal:'.'\n        },\n        {\n            type: 'numeric',\n            name: 'vPersonDHW',\n            title:'DHW Litres (person)',\n            width:80,\n            decimal:'.'\n        },\n        {\n            type: 'numeric',\n            name: 'deltatDHW',\n            title:'DHW Temp Rise',\n            width:80,\n            decimal:'.'\n        },\n        {\n            type: 'numeric',\n            name: 'tHoDHW',\n            title:'Primary DHW Return Temp C',\n            width:80,\n            decimal:'.'\n        },\n        {\n            type: 'image',\n            name: 'graphic',\n            title:'Photo',\n            width:120\n        },\n        {\n            type: 'checkbox',\n            name: 'enabled',\n            title:'Enable',\n            width:80\n        },\n        {\n            type: 'numeric',\n            name: 'qty',\n            title:'Quantity',\n            width:80,\n            decimal:'.'\n        }\n     ];\n\nvar icon = \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAOFQTFRFAAAAAIlARERARERAAYhARERARERABoNAiaRmh6FlAIlAX5h6Xpd6AYhAXpZ5rK2srK2tX5l7XpV4qqqq0NHR19jYsLGx4uPj4+Tk2NnZ6uvrX5h7BIVAqqurXZR3AodAtYVY6erq29zcz9DQgpyP09TUqXpSqHpS4eLi4OHhg56RoaKjnXBLnHBLmG5Ko6SlkGZE9cdoj2ZEjGREi2REimFAhl9A3N3dg109gFw9f1w91tfX1dbWflA4HHY8G3Y8GXk8gVE4iaRmkbRfjrBeh6FlaGlpa2tkampjZ2ho////c2A5CgAAAAp0Uk5TAGsBBGwJBXGho317A2MAAAABYktHREoeDLXGAAAACXBIWXMAAABIAAAASABGyWs+AAAAu0lEQVQY002O1xKCMBAAE7HGriAxVrChorGCih2U+P8/5BHGGfcl2Z27TBCSYEIw+gOTfKGI/71UrlTlTCL2Wl3VGlFJKD/XaRNKMpX+OWNQWu2MEu1Lh6J1uj2MSL6s6v0Iwxx0qgSh4UhnY2BiTU1tBm/OYd627cVyahmUQ+CwvlpvtjvLYEwGSul+7ziODhcZXNc9HE/HA5wuh59yzztfrrf7wwO4grJP3w+CwI955dA7DIUQYYwQny8RbRx9zgBJtwAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxOC0wNS0wNlQxNzo1NDoyNS0wNTowMMd7TXIAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTgtMDUtMDZUMTc6NTQ6MjUtMDU6MDC2JvXOAAAAAElFTkSuQmCC\";\n\nvar data1 = [\n    ['Flat', 1, 2, 'indirect', 'radiators', 3, 35, 'instantaneous', 37.5,40,28,35, 25, icon ,true, 130],\n    ['Duplex', 2, 4, 'indirect', 'underfloor', 5.5, 35, 'instantaneous', 45,40,28,35, 25, icon ,true, 20],\n];\n\nvar myspreadsheet1 = jspreadsheet(document.getElementById('spreadsheet1'), {\n    data:data1,\n    columns: columns1\n});\n\nvar rprof;\nvar dhwprofilesheet = jspreadsheet(document.getElementById('profilesheet'), {\n            data: [[1.8,1.2,1,0.8,1.3,1.7,4.5,8.7,7.6,6.1,5.4,4.8,4.2,3.6,3.1,3.2,3.7,5.3,7.7,7.3,6.1,4.9,3.7,2.4]],\n            columns: [\n            {\n                title:'0'\n            },\n            {\n                title:'1'\n            },\n            {\n                title:'2'\n            },\n            {\n                title:'3'\n            },\n            {\n                title:'4'\n            },\n            {\n                title:'5'\n            },\n            {\n                title:'6'\n            },\n            {\n                title:'7'\n            },\n            {\n                title:'8'\n            },\n            {\n                title:'9'\n            },\n            {\n                title:'10'\n            },\n            {\n                title:'11'\n            },\n            {\n                title:'12'\n            },\n            {\n                title:'13'\n            },\n            {\n                title:'14'\n            },\n            {\n                title:'15'\n            },\n            {\n                title:'16'\n            },\n            {\n                title:'17'\n            },\n            {\n                title:'18'\n            },\n            {\n                title:'19'\n            },\n            {\n                title:'20'\n            },\n            {\n                title:'21'\n            },\n            {\n                title:'22'\n            },\n            {\n                title:'23'\n            }],\n            columnSorting:false,\n            allowInsertColumn: false,\n            allowInsertRow: false,\n            allowDeleteColumn: false,\n            allowDeleteRow: false\n        });\n\nfunction runprofile() {\n    \n    if (dhwprofilesheet) {\n        \n        var prof = dhwprofilesheet.getRowData(0);\n        var tot = 0;\n        for (var h in prof) {\n            tot = tot + parseFloat(prof[h]);\n        }\n        if (tot>0) {\n            for (var h in prof) {\n                prof[h] = parseInt(100 * (100/tot) * parseFloat(prof[h])) / 100;\n            }\n        }\n        dhwprofilesheet.setRowData(0, prof);\n    }\n}\n\nfunction resetprofile() {\n    \n    if (dhwprofilesheet) {\n        \n        dhwprofilesheet.setRowData(0, [1.8,1.2,1,0.8,1.3,1.7,4.5,8.7,7.6,6.1,5.4,4.8,4.2,3.6,3.1,3.2,3.7,5.3,7.7,7.3,6.1,4.9,3.7,2.4]);\n    }\n}\n</script>","output":"str","x":1410,"y":1040,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"57995e7e.0e8f4","type":"template","z":"cce2bfaa.e5748","name":"Form Generator","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js\"></script>\n{{!--https://www.sitepoint.com/basic-jquery-form-validation-tutorial/--}}\n\n<script src=\"https://unpkg.com/mustache@latest\"></script>\n\n<style>\n\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.cframe {\n    border-radius: 0.25rem;\n    margin: 0px 0px 20px 0px;\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 6px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\nvar a = new Date();\nvar qdata;\nvar calculated = {};\nvar hasFocus;\nvar currentSection;\nvar inputsOut;\nvar inputString;\nvar calcsString;\nvar objects={};\n\n\n\t$(document).ready(function(e) {\n    \n        // $(\"form[ajax=true]\").submit(function(e) {\n            \n        //     //alert(\"submit\");\n            \n        //     e.preventDefault();\n        \n             \n            //var urlParams = new URLSearchParams(window.location.search);\n            //if (urlParams.get('display')) { loadstring = \",,\" + urlParams.get('display'); }\n\n            var urlParams = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParams) {\n                \n                calculated[urlParams[upa].split(\"=\")[0]] = urlParams[upa].split(\"=\")[1];\n                \n            }\n            \n            var form_data = {};\n            var form_url = \"/ui/qdata\";\n            var form_target = $(this).attr(\"target\") || \"result\";\n            var ftarget = \"#\" + form_target;\n            var form_method = \"GET\";\n            \n        //     $(\"#loadingimg\").show();\n            \n            $.ajax({\n                url: form_url, \n                type: form_method,      \n                data: form_data,     \n                cache: false,\n                success: function(results){   \n                    \n                    qdata = results;\n                    //qdata = JSON.parse(returnhtml);\n                    console.log(qdata);\n                   \n                    \n                    document.getElementById(\"formName\").innerHTML = qdata.title || \"Unamed Form\"; //JSON.stringify(qdata) ;\n                    \n                    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n                    \n                    validform();\n                                  \n                }           \n            });    \n            \n        // });\n        \n      \n        \n    });\n\n\n\t\nfunction getObject(id) {\n    \n  \n    return (objects[id]||null);\n    \n}\n\n\nfunction setObject(id,value) {\n    \n\n    try { objects[id] = value; }\n    catch {}\n}\n\t\nfunction returncalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).value = value; }\n    catch {\n        \n        try { calculated[id] = value; }\n        catch {}\n    }\n    \n}\n\nfunction suggestcalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).placeholder = value + \" ... please confirm\"; }\n    catch {}\n}\n\t\nfunction parseQuestions(qdata) {\n    \n    console.log(qdata);\n    console.log(calculated);\n    \n    var linkstxt=\"\";\n    if (qdata.links) {\n        for (var lnk in qdata.links) {\n            linkstxt += (linkstxt!==\"\"?\"<br>\":\"\") + '<a href=\"' + qdata.links[lnk].src + '\" target=\"_blank\">' + (qdata.links[lnk].title||qdata.links[lnk].src) + '</a>';\n        }\n        \n    }\n    document.getElementById(\"links\").innerHTML = linkstxt ; //JSON.stringify(qdata) ;\n    \n    inputsOut = '<table class=\"table\">';\n    \n    inputString = \"\";\n    hasFocus = null;\n    currentSection = null;\n    \n    var ootoot = \"\";\n    for (var s in qdata[\"sections\"]) {\n        console.log(s);\n        console.log(qdata.sections[s]);\n        \n        var oot = \"\";\n        var ootcount=0;\n        \n        //oot += \"<div class='section'><h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        oot += \"<h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        \n        \n        \n        for (var q in qdata.sections[s].questions) {\n            \n            \n            var qif = qdata.sections[s].questions[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n            var v=\"\";\n            if (calculated[qdata.sections[s].questions[q].id]) { v= calculated[qdata.sections[s].questions[q].id] ; }\n            else if (qdata.sections[s].questions[q].value) { v= qdata.sections[s].questions[q].value ; }\n            \n                \n            \n            \n            if(goq) {\n                \n                var calcfr = \"\";\n                if (qdata.sections[s].questions[q].calculator) { calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].questions[q].calculator + '?field=' + qdata.sections[s].questions[q].id + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].questions[q].calculatorStyle ? qdata.sections[s].questions[q].calculatorStyle:'width:100%; height:300px;') + '\"></iframe>'}\n            \n            \n                if (v!==\"\") { \n                    inputsOut += \"<tr>\";  \n                    inputsOut += \"<td>\" + (qdata.sections[s].questions[q].title||qdata.sections[s].questions[q].id) + \"</td>\";\n                    inputsOut +=  '<td align=\"right\">' + v + \"</td>\";\n                    inputsOut +=  '<td width=\"14%\">' + (qdata.sections[s].questions[q].units||\"\") + \"</td></tr>\\n\";\n                    \n                    inputString += (inputString!==\"\"?\"&\":\"\") + qdata.sections[s].questions[q].id + \"=\" + v;\n                }\n            \n            \n                if (hasFocus && document.getElementById(\"oneQ\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">'; }\n            \n                else if (v!==\"\") { \n                    \n                    if (document.getElementById(\"hideDone\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">';   }\n                    else {  oot += '<div class=\"question\" style=\"background-color: #d2efd2;\">'; ootcount++; }\n                    \n                } else { oot += '<div class=\"question\">'; ootcount++; if (!hasFocus) { hasFocus = qdata.sections[s].questions[q].id;  currentSection = qdata.sections[s].title;  } }\n                \n                \n                //oot += \"<div class='qtext'>\" + qdata.sections[s].questions[q].title + '</div>';\n                oot += '<label for=\"' + qdata.sections[s].questions[q].id + '\" class=\"qtext\">' + (qdata.sections[s].questions[q].question||qdata.sections[s].questions[q].title) + '</label>';\n                \n                if (calcfr!==\"\") { oot += \"\\n\" + calcfr + \"\\n\"; }\n                \n                if (qdata.sections[s].questions[q].notes) { oot += '<div class=\"notes\">'  + convertLinks(qdata.sections[s].questions[q].notes) + '</div>'; }\n                oot += '<table width=\"100%\"><tr><td width=\"80%\">';\n                \n                if (qdata.sections[s].questions[q].type==\"boolean\") {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                      if (v==\"true\") { oot += '<option value=\"false\">No</option><option value=\"true\" selected>Yes</option>'; }\n                      else if (v==\"false\")  { oot += '<option value=\"false\" selected>No</option><option value=\"true\">Yes</option>'; }\n                      else  { oot += '<option value=\"\"></option><option value=\"false\">No</option><option value=\"true\">Yes</option>'; }\n                    oot += '</select>';\n                    \n                } else if (qdata.sections[s].questions[q].options) {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    if (v==\"\") { oot += '<option value=\"\"></option>'; }\n                    for (var opt in qdata.sections[s].questions[q].options) {\n                    \n                      var optobj = qdata.sections[s].questions[q].options[opt];\n                      \n                      \n                      if (v==optobj.value) { oot += '<option selected value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      else  { oot += '<option value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      \n                    }  \n                    oot += '</select>';\n                    \n                } else {\n                \n                    oot += '<input id=\"' + qdata.sections[s].questions[q].id + '\" name=\"' + qdata.sections[s].questions[q].id + '\" class=\"form-control\" type=\"text\"';\n                    if (v!==\"\") { oot += ' value=\"' + v + '\"'; }\n                    if (qdata.sections[s].questions[q].default) { oot += ' placeholder=\"' + qdata.sections[s].questions[q].default + \" \" + (qdata.sections[s].questions[q].units||\"\") + ' ... please confirm\"'; }\n                    oot += '>';\n                }\n                \n                oot += '</td><td valign=\"top\"><span class=\"qunits\">' + (qdata.sections[s].questions[q].units||\"\") + '</span></td></tr></table>';\n                \n                \n                oot += '</div>\\n';\n            }\n        }\n    \n        oot += \"</div>\\n\";\n        \n        \n        \n        if (document.getElementById(\"oneS\").checked==true && (currentSection != qdata.sections[s].title)) {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n        else if (ootcount>0) {  ootoot += \"<div class='section'>\" + oot; }\n        \n        else {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n    }\n    inputsOut +=  \"</table>\\n\";  \n    \n    return ootoot;\n}\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\n// console.log(looseJsonParse(\n//   \"{a:(4-1), b:function(){}, c:new Date()}\"\n// ))\n\nfunction runCalcs() {\n\n\n    calcsString = \"\";\n    \n    // run through form inputs and store current values into calculated.\n    var cells =  document.getElementsByClassName(\"form-control\");\n\tvar i;\n\tfor (i = 0; i < cells.length; i++) {\n\t\n\t\tcalcsOut += cells[i].value + \"<br>\\n\";\n        \n        if (\"\" + cells[i].value !== \"\") { \n            \n            if (isNaN(cells[i].value)) { \n                \n                calculated[cells[i].id] = (cells[i].value);\n                \n            } else {\n                \n                calculated[cells[i].id] = parseFloat(cells[i].value);\n            }\n            \n            calcsString += \"&\" + cells[i].id + \"=\" + cells[i].value;\n        }\n\t}\n    \n    var calcsOut = '<table class=\"table\">';\n    for (var calc in (qdata[\"calculations\"]||[])) {\n        \n        console.log(calc);\n        console.log(qdata.calculations[calc]);\n        \n        var cif = qdata.calculations[calc].if || true;\n        var cift = Mustache.render(cif, calculated);\n        var goc = true;\n        try {\n          goc = looseJsonParse(cift); \n        }\n        catch(err) {\n          goc = false;\n        }\n        \n        if (goc) {\n            \n            var f = qdata.calculations[calc].function;\n            var ft = Mustache.render(f, calculated);\n            \n            calcsOut += \"<tr>\";  //<td>\" + qdata.calculations[calc].id + \"</td>\";\n            calcsOut += \"<td>\" + (qdata.calculations[calc].title||qdata.calculations[calc].id) + \"</td>\";\n            \n            //calcsOut += f + \" = \";\n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small>\" + ft + \"</small></td>\";   //\"<br>\\n\";\n            }\n            \n            var cv = \"\";\n            try {\n              cv = looseJsonParse(ft); //  looseJsonParse(\"{a:(4-1), b:function(){}, c:new Date()}\");\n            }\n            catch(err) {\n              \n            }\n             \n            \n            if (!isNaN(cv)) { cv = parseInt(cv*1000)/1000; }\n            \n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            \n            calcsOut +=  '<td width=\"14%\">' + (qdata.calculations[calc].units||\"\") + \"</td></tr>\\n\";\n            \n            calculated[qdata.calculations[calc].id] = cv;\n            calcsString += \"&\" + qdata.calculations[calc].id + \"=\" + cv;\n        }\n        \n    }\n    \n    calcsOut +=  \"</table>\\n\";\n    \n    // for (var calc in calculated) {\n        \n        \n    // }\n    \n    document.getElementById(\"calcs\").innerHTML = calcsOut; //JSON.stringify(qdata) ;\n    \n    // rebuild form\n    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"inputs\").innerHTML = inputsOut; //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"mylink\").innerHTML = '<a href=\"hndesign?' + inputString + '\" target=\"_blank\">Open/share design...</a>'; //JSON.stringify(qdata) ;\n    \n    \n    \n    validform();\n                    \n}\n\n\nconst convertLinks = ( input ) => {\n\n  let text = input;\n  const linksFound = text.match( /(?:www|https?)[^\\s]+/g );\n  const aLink = [];\n\n  if ( linksFound != null ) {\n\n    for ( let i=0; i<linksFound.length; i++ ) {\n      let replace = linksFound[i];\n      if ( !( linksFound[i].match( /(http(s?)):\\/\\// ) ) ) { replace = 'http://' + linksFound[i] }\n      let linkText = replace.split( '/' )[2];\n      if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) }\n      if ( linkText.match( /youtu/ ) ) {\n\n        let youtubeID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://www.youtube.com/embed/' + youtubeID + '\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe></div>' )\n      }\n      else if ( linkText.match( /vimeo/ ) ) {\n        let vimeoID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://player.vimeo.com/video/' + vimeoID + '\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' )\n      }\n      else {\n        aLink.push( '<a href=\"' + replace + '\" target=\"_blank\">' + linkText + '</a>' );\n      }\n      text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] );\n    }\n    return text;\n\n  }\n  else {\n    return input;\n  }\n}\n\nfunction validform() {\n    \n    if(hasFocus && document.getElementById(hasFocus)) {\n        document.getElementById(hasFocus).focus();\n    }\n    \n    \n    \n// Initialize form validation on the registration form.\n  // It has the name attribute \"registration\"\n  $(\"form[name='qform']\").validate({\n    // Specify validation rules\n    rules: {\n      // The key name on the left side is the name attribute\n      // of an input field. Validation rules are defined\n      // on the right side\n      nProperties: {\n        required: true,\n        digits: true,\n        min: 1\n      },\n      lastname: \"required\",\n      email: {\n        required: true,\n        // Specify that email should be validated\n        // by the built-in \"email\" rule\n        email: true\n      },\n      password: {\n        required: true,\n        minlength: 5\n      }\n    },\n    // Specify validation error messages\n    messages: {\n      nProperties: \"Please enter a number.\",\n      lastname: \"Please enter your lastname\",\n      password: {\n        required: \"Please provide a password\",\n        minlength: \"Your password must be at least 5 characters long\"\n      },\n      email: \"Please enter a valid email address\"\n    },\n    // Make sure the form is submitted to the destination defined\n    // in the \"action\" attribute of the form when valid\n    submitHandler: function(form) {\n      //form.submit();\n      runCalcs();\n      //alert(\"hello\");\n    }\n  });\n}\n\n</script>\n\n\n<div class='section'>\n    \n    <table width=\"100%\"><tr>\n    <td valign=\"top\" width=\"70%\">\n        <div id=\"formName\" class=\"h1\"></div>\n        <a href=\"https://heatweb.co.uk/w/index.php?title=Heat_Network_Designer\" target=\"_blank\"><small>Wiki Help Page</small></a>\n    </td>\n    <td width=\"30%\">\n        <input type=\"checkbox\" id=\"oneS\" name=\"oneS\" checked> <small>One section at a time</small><br>\n        <input type=\"checkbox\" id=\"oneQ\" name=\"oneQ\"> <small>One question at a time</small><br>\n        <input type=\"checkbox\" id=\"hideDone\" name=\"hideDone\"> <small>Hide completed questions</small><br>\n        <input type=\"checkbox\" id=\"hideMaths\" name=\"hideMaths\" checked> <small>Hide maths equations</small>\n    </td>\n    </tr></table>\n</div>\n\n\n<form action=\"\" name=\"qform\" id=\"qform\">\n<div id=\"section1\"></div>\n\n<div class='section'>\n<button type=\"submit\">Submit</button>\n\n</div>\n\n\n<div class='section'>\n<p><b>Inputs</b></p>\n<div id=\"inputs\" class=\"notes\"></div>\n</div>\n\n<div class='section'>\n<p><b>Numeric Values and Calculations</b></p>\n<div id=\"calcs\" class=\"notes\"></div>\n</div>\n\n\n<div class='section'>\n<p><b>Links</b><img style=\"padding:25px\" src=\"/files/images/heatwebsl.png\" width=\"200px\" align=\"right\"></p>\n<div id=\"mylink\" class=\"notes\"></div>\n<div id=\"links\" class=\"notes\"></div>\n</div>\n</form>","output":"str","x":1500,"y":280,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"6caac8e6.e0da98","type":"template","z":"cce2bfaa.e5748","name":"Form Generator","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js\"></script>\n{{!--https://www.sitepoint.com/basic-jquery-form-validation-tutorial/--}}\n\n<script src=\"https://unpkg.com/mustache@latest\"></script>\n\n\n\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n\n\n<style>\n    \n  \n    .jexcel_content {\n        font-size: 12px;\n    }\n    \n    .jexcel {\n        white-space: normal;\n    }\n\n\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.cframe {\n    border-radius: 0.25rem;\n    margin: 0px 0px 20px 0px;\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 6px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\nvar a = new Date();\nvar qdata;\nvar calculated = {};\nvar hasFocus;\nvar currentSection;\nvar inputsOut;\nvar inputString;\nvar calcsString;\nvar objects={};\n\n\n\t$(document).ready(function(e) {\n    \n        // $(\"form[ajax=true]\").submit(function(e) {\n            \n        //     //alert(\"submit\");\n            \n        //     e.preventDefault();\n        \n             \n            //var urlParams = new URLSearchParams(window.location.search);\n            //if (urlParams.get('display')) { loadstring = \",,\" + urlParams.get('display'); }\n\n            var urlParams = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParams) {\n                \n                calculated[urlParams[upa].split(\"=\")[0]] = urlParams[upa].split(\"=\")[1];\n                \n            }\n            \n            var form_data = {};\n            var form_url = \"/ui/qdata\";\n            var form_target = $(this).attr(\"target\") || \"result\";\n            var ftarget = \"#\" + form_target;\n            var form_method = \"GET\";\n            \n        //     $(\"#loadingimg\").show();\n            \n            $.ajax({\n                url: form_url, \n                type: form_method,      \n                data: form_data,     \n                cache: false,\n                success: function(results){   \n                    \n                    qdata = results;\n                    //qdata = JSON.parse(returnhtml);\n                    console.log(qdata);\n                   \n                    \n                    document.getElementById(\"formName\").innerHTML = qdata.title || \"Unamed Form\"; //JSON.stringify(qdata) ;\n                    \n                    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n                    \n                    validform();\n                                  \n                }           \n            });    \n            \n        // });\n        \n      \n        \n    });\n\n\n\t\nfunction getObject(id) {\n    \n  \n    return (objects[id]||null);\n    \n}\n\n\nfunction setObject(id,value) {\n    \n\n    try { objects[id] = value; }\n    catch {}\n}\n\t\nfunction returncalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).value = value; }\n    catch {\n        \n        try { calculated[id] = value; }\n        catch {}\n    }\n    \n}\n\nfunction suggestcalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).placeholder = value + \" ... please confirm\"; }\n    catch {}\n}\n\t\nfunction parseQuestions(qdata) {\n    \n    console.log(qdata);\n    console.log(calculated);\n    \n    var linkstxt=\"\";\n    if (qdata.links) {\n        for (var lnk in qdata.links) {\n            linkstxt += (linkstxt!==\"\"?\"<br>\":\"\") + '<a href=\"' + qdata.links[lnk].src + '\" target=\"_blank\">' + (qdata.links[lnk].title||qdata.links[lnk].src) + '</a>';\n        }\n        \n    }\n    document.getElementById(\"links\").innerHTML = linkstxt ; //JSON.stringify(qdata) ;\n    \n    inputsOut = '<table class=\"table\">';\n    \n    inputString = \"\";\n    hasFocus = null;\n    currentSection = null;\n    \n    var ootoot = \"\";\n    for (var s in qdata[\"sections\"]) {\n        console.log(s);\n        console.log(qdata.sections[s]);\n        \n        var oot = \"\";\n        var ootcount=0;\n        \n        //oot += \"<div class='section'><h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        oot += \"<h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        \n        \n        \n        for (var q in qdata.sections[s].questions) {\n            \n            \n            var qif = qdata.sections[s].questions[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n            var v=\"\";\n            if (calculated[qdata.sections[s].questions[q].id]) { v= calculated[qdata.sections[s].questions[q].id] ; }\n            else if (qdata.sections[s].questions[q].value) { v= qdata.sections[s].questions[q].value ; }\n            \n                \n            \n            \n            if(goq) {\n                \n                var calcfr = \"\";\n                if (qdata.sections[s].questions[q].calculator) { calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].questions[q].calculator + '?field=' + qdata.sections[s].questions[q].id + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].questions[q].calculatorStyle ? qdata.sections[s].questions[q].calculatorStyle:'width:100%; height:300px;') + '\"></iframe>'}\n            \n            \n                if (v!==\"\") { \n                    inputsOut += \"<tr>\";  \n                    inputsOut += \"<td>\" + (qdata.sections[s].questions[q].title||qdata.sections[s].questions[q].id) + \"</td>\";\n                    inputsOut +=  '<td align=\"right\">' + v + \"</td>\";\n                    inputsOut +=  '<td width=\"14%\">' + (qdata.sections[s].questions[q].units||\"\") + \"</td></tr>\\n\";\n                    \n                    inputString += (inputString!==\"\"?\"&\":\"\") + qdata.sections[s].questions[q].id + \"=\" + v;\n                }\n            \n            \n                if (hasFocus && document.getElementById(\"oneQ\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">'; }\n            \n                else if (v!==\"\") { \n                    \n                    if (document.getElementById(\"hideDone\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">';   }\n                    else {  oot += '<div class=\"question\" style=\"background-color: #d2efd2;\">'; ootcount++; }\n                    \n                } else { oot += '<div class=\"question\">'; ootcount++; if (!hasFocus) { hasFocus = qdata.sections[s].questions[q].id;  currentSection = qdata.sections[s].title;  } }\n                \n                \n                //oot += \"<div class='qtext'>\" + qdata.sections[s].questions[q].title + '</div>';\n                oot += '<label for=\"' + qdata.sections[s].questions[q].id + '\" class=\"qtext\">' + (qdata.sections[s].questions[q].question||qdata.sections[s].questions[q].title) + '</label>';\n                \n                if (calcfr!==\"\") { oot += \"\\n\" + calcfr + \"\\n\"; }\n                \n                if (qdata.sections[s].questions[q].notes) { oot += '<div class=\"notes\">'  + convertLinks(qdata.sections[s].questions[q].notes) + '</div>'; }\n                \n                if (qdata.sections[s].questions[q].type == \"csv\") {\n                    \n                    oot += '<div id=\"sheet-' + qdata.sections[s].questions[q].id + '\"></div>';\n                }\n                \n                oot += '<table width=\"100%\"><tr><td width=\"80%\">';\n                \n                if (qdata.sections[s].questions[q].type==\"boolean\") {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                      if (v==\"true\") { oot += '<option value=\"false\">No</option><option value=\"true\" selected>Yes</option>'; }\n                      else if (v==\"false\")  { oot += '<option value=\"false\" selected>No</option><option value=\"true\">Yes</option>'; }\n                      else  { oot += '<option value=\"\"></option><option value=\"false\">No</option><option value=\"true\">Yes</option>'; }\n                    oot += '</select>';\n                    \n                } else if (qdata.sections[s].questions[q].options) {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    if (v==\"\") { oot += '<option value=\"\"></option>'; }\n                    for (var opt in qdata.sections[s].questions[q].options) {\n                    \n                      var optobj = qdata.sections[s].questions[q].options[opt];\n                      \n                      \n                      if (v==optobj.value) { oot += '<option selected value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      else  { oot += '<option value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      \n                    }  \n                    oot += '</select>';\n                    \n                }  else {\n                \n                    oot += '<input id=\"' + qdata.sections[s].questions[q].id + '\" name=\"' + qdata.sections[s].questions[q].id + '\" class=\"form-control\" type=\"text\"';\n                    if (v!==\"\") { oot += ' value=\"' + v + '\"'; }\n                    if (qdata.sections[s].questions[q].default) { oot += ' placeholder=\"' + qdata.sections[s].questions[q].default + \" \" + (qdata.sections[s].questions[q].units||\"\") + ' ... please confirm\"'; }\n                    oot += '>';\n                }\n                \n                oot += '</td><td valign=\"top\"><span class=\"qunits\">' + (qdata.sections[s].questions[q].units||\"\") + '</span></td></tr></table>';\n                \n                \n                oot += '</div>\\n';\n            }\n        }\n    \n        oot += \"</div>\\n\";\n        \n        \n        \n        if (document.getElementById(\"oneS\").checked==true && (currentSection != qdata.sections[s].title)) {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n        else if (ootcount>0) {  ootoot += \"<div class='section'>\" + oot; }\n        \n        else {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n    }\n    inputsOut +=  \"</table>\\n\";  \n    \n    return ootoot;\n}\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\n// console.log(looseJsonParse(\n//   \"{a:(4-1), b:function(){}, c:new Date()}\"\n// ))\n\nfunction runCalcs() {\n\n\n    calcsString = \"\";\n    \n    // run through form inputs and store current values into calculated.\n    var cells =  document.getElementsByClassName(\"form-control\");\n\tvar i;\n\tfor (i = 0; i < cells.length; i++) {\n\t\n\t\tcalcsOut += cells[i].value + \"<br>\\n\";\n        \n        if (\"\" + cells[i].value !== \"\") { \n            \n            if (isNaN(cells[i].value)) { \n                \n                calculated[cells[i].id] = (cells[i].value);\n                \n            } else {\n                \n                calculated[cells[i].id] = parseFloat(cells[i].value);\n            }\n            \n            calcsString += \"&\" + cells[i].id + \"=\" + cells[i].value;\n        }\n\t}\n    \n    var calcsOut = '<table class=\"table\">';\n    for (var calc in (qdata[\"calculations\"]||[])) {\n        \n        console.log(calc);\n        console.log(qdata.calculations[calc]);\n        \n        var cif = qdata.calculations[calc].if || true;\n        var cift = Mustache.render(cif, calculated);\n        var goc = true;\n        try {\n          goc = looseJsonParse(cift); \n        }\n        catch(err) {\n          goc = false;\n        }\n        \n        if (goc) {\n            \n            var f = qdata.calculations[calc].function;\n            var ft = Mustache.render(f, calculated);\n            \n            calcsOut += \"<tr>\";  //<td>\" + qdata.calculations[calc].id + \"</td>\";\n            calcsOut += \"<td>\" + (qdata.calculations[calc].title||qdata.calculations[calc].id) + \"</td>\";\n            \n            //calcsOut += f + \" = \";\n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small>\" + ft + \"</small></td>\";   //\"<br>\\n\";\n            }\n            \n            var cv = \"\";\n            try {\n              cv = looseJsonParse(ft); //  looseJsonParse(\"{a:(4-1), b:function(){}, c:new Date()}\");\n            }\n            catch(err) {\n              \n            }\n             \n            \n            if (!isNaN(cv)) { cv = parseInt(cv*1000)/1000; }\n            \n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            \n            calcsOut +=  '<td width=\"14%\">' + (qdata.calculations[calc].units||\"\") + \"</td></tr>\\n\";\n            \n            calculated[qdata.calculations[calc].id] = cv;\n            calcsString += \"&\" + qdata.calculations[calc].id + \"=\" + cv;\n        }\n        \n    }\n    \n    calcsOut +=  \"</table>\\n\";\n    \n    // for (var calc in calculated) {\n        \n        \n    // }\n    \n    document.getElementById(\"calcs\").innerHTML = calcsOut; //JSON.stringify(qdata) ;\n    \n    // rebuild form\n    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"inputs\").innerHTML = inputsOut; //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"mylink\").innerHTML = '<a href=\"hndesign?' + inputString + '\" target=\"_blank\">Open/share design...</a>'; //JSON.stringify(qdata) ;\n    \n    \n    \n    validform();\n                    \n}\n\n\nconst convertLinks = ( input ) => {\n\n  let text = input;\n  const linksFound = text.match( /(?:www|https?)[^\\s]+/g );\n  const aLink = [];\n\n  if ( linksFound != null ) {\n\n    for ( let i=0; i<linksFound.length; i++ ) {\n      let replace = linksFound[i];\n      if ( !( linksFound[i].match( /(http(s?)):\\/\\// ) ) ) { replace = 'http://' + linksFound[i] }\n      let linkText = replace.split( '/' )[2];\n      if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) }\n      if ( linkText.match( /youtu/ ) ) {\n\n        let youtubeID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://www.youtube.com/embed/' + youtubeID + '\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe></div>' )\n      }\n      else if ( linkText.match( /vimeo/ ) ) {\n        let vimeoID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://player.vimeo.com/video/' + vimeoID + '\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' )\n      }\n      else {\n        aLink.push( '<a href=\"' + replace + '\" target=\"_blank\">' + linkText + '</a>' );\n      }\n      text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] );\n    }\n    return text;\n\n  }\n  else {\n    return input;\n  }\n}\n\nfunction validform() {\n    \n    if(hasFocus && document.getElementById(hasFocus)) {\n        document.getElementById(hasFocus).focus();\n    }\n    \n    \n    \n// Initialize form validation on the registration form.\n  // It has the name attribute \"registration\"\n  $(\"form[name='qform']\").validate({\n    // Specify validation rules\n    rules: {\n      // The key name on the left side is the name attribute\n      // of an input field. Validation rules are defined\n      // on the right side\n      nProperties: {\n        required: true,\n        digits: true,\n        min: 1\n      },\n      lastname: \"required\",\n      email: {\n        required: true,\n        // Specify that email should be validated\n        // by the built-in \"email\" rule\n        email: true\n      },\n      password: {\n        required: true,\n        minlength: 5\n      }\n    },\n    // Specify validation error messages\n    messages: {\n      nProperties: \"Please enter a number.\",\n      lastname: \"Please enter your lastname\",\n      password: {\n        required: \"Please provide a password\",\n        minlength: \"Your password must be at least 5 characters long\"\n      },\n      email: \"Please enter a valid email address\"\n    },\n    // Make sure the form is submitted to the destination defined\n    // in the \"action\" attribute of the form when valid\n    submitHandler: function(form) {\n      //form.submit();\n      runCalcs();\n      //alert(\"hello\");\n    }\n  });\n}\n\n</script>\n\n\n<div class='section'>\n    \n    <table width=\"100%\"><tr>\n    <td valign=\"top\" width=\"70%\">\n        <div id=\"formName\" class=\"h1\"></div>\n        <a href=\"https://heatweb.co.uk/w/index.php?title=Heat_Network_Designer\" target=\"_blank\"><small>Wiki Help Page</small></a>\n    </td>\n    <td width=\"30%\">\n        <input type=\"checkbox\" id=\"oneS\" name=\"oneS\" checked> <small>One section at a time</small><br>\n        <input type=\"checkbox\" id=\"oneQ\" name=\"oneQ\"> <small>One question at a time</small><br>\n        <input type=\"checkbox\" id=\"hideDone\" name=\"hideDone\"> <small>Hide completed questions</small><br>\n        <input type=\"checkbox\" id=\"hideMaths\" name=\"hideMaths\" checked> <small>Hide maths equations</small>\n    </td>\n    </tr></table>\n</div>\n\n\n<form action=\"\" name=\"qform\" id=\"qform\">\n<div id=\"section1\"></div>\n\n<div class='section'>\n<button type=\"submit\">Submit</button>\n\n</div>\n\n\n<div class='section'>\n<p><b>Inputs</b></p>\n<div id=\"inputs\" class=\"notes\"></div>\n</div>\n\n<div class='section'>\n<p><b>Numeric Values and Calculations</b></p>\n<div id=\"calcs\" class=\"notes\"></div>\n</div>\n\n\n<div class='section'>\n<p><b>Links</b><img style=\"padding:25px\" src=\"/files/images/heatwebsl.png\" width=\"200px\" align=\"right\"></p>\n<div id=\"mylink\" class=\"notes\"></div>\n<div id=\"links\" class=\"notes\"></div>\n</div>\n</form>","output":"str","x":1480,"y":320,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"83e28194.2812f","type":"http in","z":"cce2bfaa.e5748","name":"","url":"/ui/hnoutputs/:op","method":"get","upload":false,"swaggerDoc":"","x":220,"y":760,"wires":[["f7343cc9.a6d5d","3fe6d5fd.e6904a"]]},{"id":"3641b220.fd838e","type":"link out","z":"cce2bfaa.e5748","name":"","links":["46f26691.159bd8"],"x":1155,"y":860,"wires":[]},{"id":"f7343cc9.a6d5d","type":"debug","z":"cce2bfaa.e5748","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":230,"y":840,"wires":[]},{"id":"3fe6d5fd.e6904a","type":"switch","z":"cce2bfaa.e5748","name":"","property":"req.params.op","propertyType":"msg","rules":[{"t":"eq","v":"save","vt":"str"},{"t":"eq","v":"peakload","vt":"str"},{"t":"eq","v":"buffer","vt":"str"},{"t":"eq","v":"yearly","vt":"str"},{"t":"eq","v":"graph","vt":"str"},{"t":"eq","v":"wiki","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":7,"x":470,"y":880,"wires":[["613ec873.99c508"],["ea750aba.beb938"],["60e3a4b0.15fb4c"],["3d915fb2.148b4"],["be3da149.3d54c"],["1dcecb6e.9e9885"],["3000bdf2.746082"]]},{"id":"3000bdf2.746082","type":"template","z":"cce2bfaa.e5748","name":"sorry","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"Sorry.","output":"str","x":650,"y":1040,"wires":[["2a501ff2.83e55"]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"f8575e83.2b736","type":"template","z":"cce2bfaa.e5748","name":"google charts from HIUs","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n\n    <script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>\n    <script type=\"text/javascript\">\n      google.charts.load('current', {'packages':['corechart','gauge','bar','table']});\n      google.charts.setOnLoadCallback(drawChart3);\n\n      \n      function drawChart3() {\n      var data = google.visualization.arrayToDataTable([\n        ['Hour', '{{series1name}}'],\n        ['0', {{hourload.h0}}],\n        ['1', {{hourload.h1}}],\n        ['2', {{hourload.h2}}],\n        ['3', {{hourload.h3}}],\n        ['4', {{hourload.h4}}],\n        ['5', {{hourload.h5}}],\n        ['6', {{hourload.h6}}],\n        ['7', {{hourload.h7}}],\n        ['8', {{hourload.h8}}],\n        ['9', {{hourload.h9}}],\n        ['10', {{hourload.h10}}],\n        ['11', {{hourload.h11}}],\n        ['12', {{hourload.h12}}],\n        ['13', {{hourload.h13}}],\n        ['14', {{hourload.h14}}],\n        ['15', {{hourload.h15}}],\n        ['16', {{hourload.h16}}],\n        ['17', {{hourload.h17}}],\n        ['18', {{hourload.h18}}],\n        ['19', {{hourload.h19}}],\n        ['20', {{hourload.h20}}],\n        ['21', {{hourload.h21}}],\n        ['22', {{hourload.h22}}],\n        ['23', {{hourload.h23}}]\n      ]);\n\n      \n\n      var options = {\n        title: '{{title}}',\n        chartArea: {width: '91%'},\n        legend: {\n          position: 'none'\n          },\n        annotations: {\n          alwaysOutside: true,\n          textStyle: {\n            fontSize: 12,\n            auraColor: 'none',\n            color: '#555'\n          },\n          boxStyle: {\n            stroke: '#ccc',\n            strokeWidth: 1,\n            gradient: {\n              color1: '#f3e5f5',\n              color2: '#f3e5f5',\n              x1: '0%', y1: '0%',\n              x2: '100%', y2: '100%'\n            }\n          }\n        },\n        hAxis: {\n          title: 'Hour of Day',\n          minValue: 0,\n        },\n        vAxis: {\n          title: '{{yaxis}}',\n          minValue: 0,\n        }\n      };\n      var chart = new google.visualization.ColumnChart(document.getElementById('hourload'));\n      chart.draw(data, options);\n    }\n      \n      \n    \n      \n    </script>\n    \n    <link rel=\"stylesheet\"\n          href=\"https://fonts.googleapis.com/css?family=Hind+Siliguri|Poppins|Questrial|Kosugi+Maru|Nanum+Gothic+Coding\">\n    <style>\n      body {\n        font-family: 'Poppins', serif;\n        font-size: 36px;\n      }\n    </style>\n    \n  </head>\n  <body>\n    <p>\n    {{intro}} \n    </p>  \n    \n    <div id=\"hourload\" style=\"width: 800px; height: 300px;\"></div>\n    \n    \n","output":"str","x":1570,"y":820,"wires":[[]]},{"id":"2d10be67.f71a42","type":"function","z":"cce2bfaa.e5748","name":"","func":"msg.est = [1.8,1.2,1,0.8,1.3,1.7,4.5,8.7,7.6,6.1,5.4,4.8,4.2,3.6,3.1,3.2,3.7,5.3,7.7,7.3,6.1,4.9,3.7,2.4];\n\nmsg.hourload = {};\n\n\nfor (let i = 0; i < 24; i++) {\n    \n    msg.hourload[\"h\" + i] = parseFloat(msg.payload.kwhDHWEST) * msg.est[i] / 100;\n}\n\nmsg.intro = \"The chart below shows the hourly energy use for domestic hot water, based on EST profile.\"\nmsg.title = \"Hourly DHW Energy Use\";\nmsg.yaxis = \"kWh\";\nmsg.series1name = \"Primary Volume\";\n\nreturn msg;","outputs":1,"noerr":0,"x":1370,"y":820,"wires":[["f8575e83.2b736"]]},{"id":"8771a830.495098","type":"template","z":"cce2bfaa.e5748","name":"google charts from HIUs","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n\n    <script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>\n    <script type=\"text/javascript\">\n      google.charts.load('current', {'packages':['corechart','gauge','bar','table']});\n      google.charts.setOnLoadCallback(drawChart3);\n\n      \n      function drawChart3() {\n      var data = google.visualization.arrayToDataTable([\n        ['Hour', 'Primary Volume'],\n        ['0', {{hourload.h0}}],\n        ['1', {{hourload.h1}}],\n        ['2', {{hourload.h2}}],\n        ['3', {{hourload.h3}}],\n        ['4', {{hourload.h4}}],\n        ['5', {{hourload.h5}}],\n        ['6', {{hourload.h6}}],\n        ['7', {{hourload.h7}}],\n        ['8', {{hourload.h8}}],\n        ['9', {{hourload.h9}}],\n        ['10', {{hourload.h10}}],\n        ['11', {{hourload.h11}}],\n        ['12', {{hourload.h12}}],\n        ['13', {{hourload.h13}}],\n        ['14', {{hourload.h14}}],\n        ['15', {{hourload.h15}}],\n        ['16', {{hourload.h16}}],\n        ['17', {{hourload.h17}}],\n        ['18', {{hourload.h18}}],\n        ['19', {{hourload.h19}}],\n        ['20', {{hourload.h20}}],\n        ['21', {{hourload.h21}}],\n        ['22', {{hourload.h22}}],\n        ['23', {{hourload.h23}}]\n      ]);\n\n      \n\n      var options = {\n        title: '{{title}}',\n        chartArea: {width: '91%'},\n        legend: {\n          position: 'none'\n          },\n        annotations: {\n          alwaysOutside: true,\n          textStyle: {\n            fontSize: 12,\n            auraColor: 'none',\n            color: '#555'\n          },\n          boxStyle: {\n            stroke: '#ccc',\n            strokeWidth: 1,\n            gradient: {\n              color1: '#f3e5f5',\n              color2: '#f3e5f5',\n              x1: '0%', y1: '0%',\n              x2: '100%', y2: '100%'\n            }\n          }\n        },\n        hAxis: {\n          title: 'Hour of Day',\n          minValue: 0,\n        },\n        vAxis: {\n          title: '{{yaxis}}'\n        }\n      };\n      var chart = new google.visualization.ColumnChart(document.getElementById('hourload'));\n      chart.draw(data, options);\n    }\n      \n      \n    \n      \n    </script>\n    \n    <link rel=\"stylesheet\"\n          href=\"https://fonts.googleapis.com/css?family=Hind+Siliguri|Poppins|Questrial|Kosugi+Maru|Nanum+Gothic+Coding\">\n    <style>\n      body {\n        font-family: 'Poppins', serif;\n        font-size: 36px;\n      }\n    </style>\n    \n  </head>\n  <body>\n    <p>\n    {{intro}} \n    </p>  \n    \n    <div id=\"hourload\" style=\"width: 800px; height: 300px;\"></div>\n    \n    \n","output":"str","x":1490,"y":960,"wires":[[]]},{"id":"60e3a4b0.15fb4c","type":"function","z":"cce2bfaa.e5748","name":"","func":"msg.est = [1.8,1.2,1,0.8,1.3,1.7,4.5,8.7,7.6,6.1,5.4,4.8,4.2,3.6,3.1,3.2,3.7,5.3,7.7,7.3,6.1,4.9,3.7,2.4];\n\nmsg.hourload = {};\n\nvar bn,bout;\nvar primHSource=\"\";\nvar hout=0;\n\nif (msg.payload.selectASHP) {\n//  bn = parseFloat(msg.payload.selectASHP.split(\"x\")[0].trim()) ;\n//  if (bn>1) { bn = bn -1; }\n//  bout = parseFloat(msg.payload.selectASHP.split(\"x\")[1].trim()) ;\n primHSource = \"heat pump\";\n//  hout = hout + (bn * bout);\n}\nif (msg.payload.selectBoilers) {\n//  bn = parseFloat(msg.payload.selectBoilers.split(\"x\")[0].trim()) ;\n//  bout = parseFloat(msg.payload.selectBoilers.split(\"x\")[1].trim()) ;\n primHSource += (primHSource===\"\"?\"\":\" + \") +  \"boiler\";\n//  hout = hout + (bn * bout);\n}\n\nmsg.notes=\"\";\n\n\n\nmsg.x1 = [];\n\nmsg.y1 = [];\nmsg.y2 = [];\n\n\n\nvar running = 0;\n\nvar check1 = \"ok\";\nvar check2 = \"ok\";\n\nfor (let i = 0; i < 24; i++) {\n    \n    msg.x1.push(i+1);\n    running = running + parseFloat(msg.payload.kWxN1) - ((parseFloat(msg.payload.kwhDHWEST) * msg.est[i] / 100) + (parseFloat(msg.payload.kwCH))) ;\n    \n    if (running > parseFloat(msg.payload.bufferkWh)) { running = parseFloat(msg.payload.bufferkWh); }\n    \n    if (running>0) {\n        \n        msg.y1.push(running);\n        msg.y2.push(0);\n        \n        // msg.hourload[\"h\" + i] = running;\n        // msg.hourload[\"s2h\" + i] = 0;\n        \n    } else {\n        \n        check1 = \"failed\"; // negative storage = not enough input\n        // msg.hourload[\"h\" + i] = 0;\n        // msg.hourload[\"s2h\" + i] = running;\n        \n        msg.y1.push(0);\n        msg.y2.push(running);\n        \n    }\n}\n\n\nmsg.x1 = JSON.stringify(msg.x1);\nmsg.y1 = JSON.stringify(msg.y1);\n\nmsg.y2 = JSON.stringify(msg.y2);\n\nif(running<0) { check2 = \"failed\"; }  // less at end than start = not enough input\n\nif (check2!==\"ok\") { msg.notes=\" <b>Warning, Please increase the number or power of heat sources.</b>\"; }\nelse if (check1!==\"ok\") { msg.notes=\" <b>Warning, Please increase buffer storage capacity.</b>\"; }\n\n\nmsg.intro = \"The chart below shows the buffer charge over a peak load day, with one \" + primHSource + \" unavailable (in failure), starting from empty. Values should remain positive.\"\n\nmsg.title = \"Hourly Energy Balance\";\nmsg.yaxis = \"kWh\";\n\nmsg.series1name = \"Positive kWh\";\nmsg.series2name = \"Negative kWh\";\n\nreturn msg;","outputs":1,"noerr":0,"x":690,"y":780,"wires":[["31a05810.26d4f8"]]},{"id":"87871e9c.23dd2","type":"template","z":"cce2bfaa.e5748","name":"google charts from HIUs","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n\n    <script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>\n    <script type=\"text/javascript\">\n      google.charts.load('current', {'packages':['corechart','gauge','bar','table']});\n      google.charts.setOnLoadCallback(drawChart3);\n\n      \n      function drawChart3() {\n      var data = google.visualization.arrayToDataTable([\n        ['Hour', '{{series1name}}', '{{series2name}}'],\n        ['0', {{hourload.h0}}, {{hourload.s2h0}}],\n        ['1', {{hourload.h1}}, {{hourload.s2h1}}],\n        ['2', {{hourload.h2}}, {{hourload.s2h2}}],\n        ['3', {{hourload.h3}}, {{hourload.s2h3}}],\n        ['4', {{hourload.h4}}, {{hourload.s2h4}}],\n        ['5', {{hourload.h5}}, {{hourload.s2h5}}],\n        ['6', {{hourload.h6}}, {{hourload.s2h6}}],\n        ['7', {{hourload.h7}}, {{hourload.s2h7}}],\n        ['8', {{hourload.h8}}, {{hourload.s2h8}}],\n        ['9', {{hourload.h9}}, {{hourload.s2h9}}],\n        ['10', {{hourload.h10}}, {{hourload.s2h10}}],\n        ['11', {{hourload.h11}}, {{hourload.s2h11}}],\n        ['12', {{hourload.h12}}, {{hourload.s2h12}}],\n        ['13', {{hourload.h13}}, {{hourload.s2h13}}],\n        ['14', {{hourload.h14}}, {{hourload.s2h14}}],\n        ['15', {{hourload.h15}}, {{hourload.s2h15}}],\n        ['16', {{hourload.h16}}, {{hourload.s2h16}}],\n        ['17', {{hourload.h17}}, {{hourload.s2h17}}],\n        ['18', {{hourload.h18}}, {{hourload.s2h18}}],\n        ['19', {{hourload.h19}}, {{hourload.s2h19}}],\n        ['20', {{hourload.h20}}, {{hourload.s2h20}}],\n        ['21', {{hourload.h21}}, {{hourload.s2h21}}],\n        ['22', {{hourload.h22}}, {{hourload.s2h22}}],\n        ['23', {{hourload.h23}}, {{hourload.s2h23}}]\n      ]);\n\n      \n\n      var options = {\n        title: '{{title}}',\n        isStacked: true,\n        chartArea: {width: '85%'},\n        legend: {\n          position: 'none'\n          },\n        annotations: {\n          alwaysOutside: true,\n          textStyle: {\n            fontSize: 12,\n            auraColor: 'none',\n            color: '#555'\n          },\n          boxStyle: {\n            stroke: '#ccc',\n            strokeWidth: 1,\n            gradient: {\n              color1: '#f3e5f5',\n              color2: '#f3e5f5',\n              x1: '0%', y1: '0%',\n              x2: '100%', y2: '100%'\n            }\n          }\n        },\n        hAxis: {\n          title: 'Hour of Day',\n          minValue: 0,\n        },\n        vAxis: {\n          title: '{{yaxis}}',\n          minValue: 0,\n        }\n      };\n      var chart = new google.visualization.ColumnChart(document.getElementById('hourload'));\n      chart.draw(data, options);\n    }\n      \n      \n    \n      \n    </script>\n    \n    <link rel=\"stylesheet\"\n          href=\"https://fonts.googleapis.com/css?family=Hind+Siliguri|Poppins|Questrial|Kosugi+Maru|Nanum+Gothic+Coding\">\n    <style>\n      body {\n        font-family: 'Poppins', serif;\n        font-size: 36px;\n      }\n    </style>\n    \n  </head>\n  <body>\n    <p>\n    {{{intro}}} {{{notes}}}\n    </p>  \n    \n    <div id=\"hourload\" style=\"width: 800px; height: 300px;\"></div>\n    \n     \n    \n","output":"str","x":1430,"y":740,"wires":[[]]},{"id":"1a8e6828.5d3148","type":"template","z":"cce2bfaa.e5748","name":"google charts from HIUs","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n\n    \n    <link rel=\"stylesheet\"\n          href=\"https://fonts.googleapis.com/css?family=Hind+Siliguri|Poppins|Questrial|Kosugi+Maru|Nanum+Gothic+Coding\">\n    <style>\n      body {\n        font-family: 'Poppins', serif;\n        font-size: 36px;\n      }\n    </style>\n    \n \n    <p>\n    {{fn}} \n    </p>  \n    \n   \n    \n    \n","output":"str","x":962,"y":654,"wires":[["ff07a724.4bee18"]]},{"id":"613ec873.99c508","type":"function","z":"cce2bfaa.e5748","name":"","func":"\n\nmsg.intro = \" \"\nmsg.title = \" \";\n\nmsg.fn = \"No action taken.\";\n\nmsg2={};\n\nif (msg.payload.email && msg.payload.networkName) {\n    \n    \n    msg2.filename = msg.payload.email + \"/\" + msg.payload.networkName;\n    msg2.filename = msg2.filename.replace(/ /g,\"_\").replace(/\\%20/g,\"_\").replace(/\\@/g,\"_\").replace(/\\./g,\"_\").replace(/\\,/g,\"_\")  + \".json\";\n    \n    msg.fn = \"Saved to hw7 server as \" + msg2.filename;\n    \n    msg2.filename = global.get(\"localDirectory\") + \"/hndesigns/\" + msg2.filename;\n    \n    msg2.payload = JSON.stringify(msg.payload);\n    \n    return [msg,msg2];\n}\n\n\n\nreturn [msg,null];\n\n","outputs":2,"noerr":0,"x":570,"y":660,"wires":[["1a8e6828.5d3148","edc8af2c.096f7"],["3a41594b.05b1d6"]]},{"id":"edc8af2c.096f7","type":"debug","z":"cce2bfaa.e5748","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":770,"y":620,"wires":[]},{"id":"3a41594b.05b1d6","type":"file","z":"cce2bfaa.e5748","name":"","filename":"","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":710,"y":700,"wires":[[]]},{"id":"a948f1d4.48e0e","type":"template","z":"cce2bfaa.e5748","name":"3 years degree days","field":"payload","fieldType":"msg","format":"handlebars","syntax":"plain","template":"Description:,\"Celsius-based heating degree days with base temperatures at and around 19 C\"\nSource:,\"www.degreedays.net\"\nAccuracy:,\"Estimates were made to account for missing data: the \"\"% Estimated\"\" column shows how much each figure was affected (0% is best, 100% is worst)\"\nStation:,\"London St James Park, -, GB (0.13W,51.50N)\"\nStation ID:,=\"03770\"\n,(Column titles show the base temperature in Celsius)\nDate,HDD 16,HDD 16.5,HDD 17,HDD 17.5,HDD 18,HDD 18.5,HDD 19,HDD 19.5,HDD 20,HDD 20.5,HDD 21,HDD 21.5,HDD 22,% Estimated\n2019-04-01,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,1\n2019-04-02,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,0\n2019-04-03,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,1\n2019-04-04,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,1\n2019-04-05,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,1\n2019-04-06,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,1\n2019-04-07,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,0\n2019-04-08,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,0\n2019-04-09,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,0\n2019-04-10,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,0\n2019-04-11,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,0\n2019-04-12,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,0\n2019-04-13,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,0\n2019-04-14,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,0\n2019-04-15,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,0\n2019-04-16,4.3,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,0\n2019-04-17,3.7,4,4.4,4.8,5.2,5.7,6.1,6.6,7.1,7.6,8.1,8.6,9.1,0\n2019-04-18,2.8,3.1,3.4,3.7,4.1,4.4,4.8,5.2,5.7,6.1,6.6,7.1,7.6,0\n2019-04-19,1.9,2.2,2.5,2.8,3.1,3.4,3.7,4.1,4.4,4.8,5.1,5.5,5.9,0\n2019-04-20,1.7,1.9,2.2,2.5,2.8,3.1,3.4,3.7,4,4.4,4.7,5.1,5.5,0\n2019-04-21,1.9,2.1,2.4,2.7,3,3.3,3.7,4,4.4,4.7,5.1,5.5,5.9,0\n2019-04-22,1.9,2.1,2.4,2.7,3,3.3,3.6,3.9,4.2,4.6,4.9,5.3,5.7,0\n2019-04-23,1.1,1.4,1.8,2.1,2.5,2.9,3.3,3.7,4.2,4.7,5.2,5.7,6.2,0\n2019-04-24,2.3,2.6,3.1,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,0\n2019-04-25,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,0\n2019-04-26,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,0\n2019-04-27,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,1\n2019-04-28,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,1\n2019-04-29,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,0\n2019-04-30,4.1,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,0\n2019-05-01,3.7,4.1,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,1\n2019-05-02,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,1\n2019-05-03,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,0\n2019-05-04,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,0\n2019-05-05,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,0\n2019-05-06,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,0\n2019-05-07,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,0\n2019-05-08,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,0\n2019-05-09,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,0\n2019-05-10,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,0\n2019-05-11,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,0\n2019-05-12,4.5,5,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,0\n2019-05-13,4.4,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,0\n2019-05-14,3.4,3.8,4.2,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,1\n2019-05-15,3.2,3.6,3.9,4.3,4.7,5.1,5.5,6,6.5,7,7.5,8,8.5,0\n2019-05-16,3.2,3.6,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,0\n2019-05-17,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,0\n2019-05-18,2.8,3.2,3.7,4.1,4.6,5,5.5,6,6.5,7,7.5,8,8.5,0\n2019-05-19,2.1,2.5,2.9,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,0\n2019-05-20,1.1,1.3,1.6,1.9,2.2,2.5,2.9,3.4,3.9,4.4,4.9,5.4,5.9,0\n2019-05-21,1.3,1.5,1.8,2.1,2.4,2.7,3,3.4,3.8,4.3,4.8,5.3,5.8,0\n2019-05-22,1.2,1.5,1.8,2.1,2.4,2.7,3,3.4,3.8,4.2,4.7,5.2,5.7,0\n2019-05-23,1.4,1.7,1.9,2.1,2.4,2.7,2.9,3.2,3.6,3.9,4.2,4.6,4.9,0\n2019-05-24,0.9,1.2,1.4,1.7,1.9,2.2,2.5,2.9,3.2,3.6,4,4.5,5,0\n2019-05-25,0.4,0.6,0.8,1,1.2,1.4,1.7,1.9,2.2,2.5,2.9,3.3,3.6,0\n2019-05-26,0.2,0.4,0.5,0.7,1,1.2,1.6,2,2.4,2.9,3.4,3.9,4.4,0\n2019-05-27,2.1,2.4,2.7,3.1,3.5,4,4.5,5,5.5,6,6.5,7,7.5,0\n2019-05-28,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,1\n2019-05-29,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,0\n2019-05-30,0.2,0.4,0.6,0.7,0.9,1.2,1.4,1.7,2,2.3,2.6,3,3.4,0\n2019-05-31,0.2,0.4,0.7,0.9,1.2,1.5,1.8,2.3,2.8,3.3,3.8,4.3,4.8,0\n2019-06-01,1,1.2,1.4,1.6,1.8,1.9,2.2,2.4,2.6,2.8,3,3.3,3.6,0\n2019-06-02,0,0,0,0.1,0.2,0.3,0.5,0.7,0.9,1.2,1.4,1.7,2,0\n2019-06-03,1.2,1.4,1.7,2,2.4,2.7,3.1,3.6,4.1,4.6,5.1,5.6,6.1,1\n2019-06-04,1.6,2,2.5,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,0\n2019-06-05,1.2,1.5,1.9,2.3,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,0\n2019-06-06,2,2.4,2.7,3.1,3.5,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,0\n2019-06-07,1.5,1.9,2.4,2.9,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,0\n2019-06-08,1.8,2.1,2.5,2.8,3.2,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,0\n2019-06-09,2,2.3,2.6,3,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,0\n2019-06-10,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,0\n2019-06-11,2.4,2.8,3.2,3.7,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,1\n2019-06-12,3.1,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,0\n2019-06-13,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,0\n2019-06-14,1.2,1.6,2,2.4,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,1\n2019-06-15,1.3,1.6,1.9,2.3,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,1\n2019-06-16,1.5,1.8,2.1,2.4,2.7,3.1,3.5,3.9,4.4,4.9,5.4,5.9,6.4,0\n2019-06-17,0.8,1,1.2,1.5,1.8,2.1,2.4,2.8,3.1,3.6,4,4.5,5,0\n2019-06-18,0.8,1,1.3,1.6,2,2.5,2.9,3.4,3.9,4.4,4.9,5.4,5.9,0\n2019-06-19,0.5,0.7,1,1.3,1.6,2,2.4,2.9,3.4,3.9,4.4,4.9,5.4,1\n2019-06-20,0.6,0.8,1.1,1.4,1.8,2.3,2.8,3.3,3.8,4.3,4.8,5.3,5.8,1\n2019-06-21,1.5,1.7,1.9,2.2,2.4,2.7,3,3.4,3.9,4.4,4.9,5.4,5.9,0\n2019-06-22,1.1,1.3,1.6,1.8,2.1,2.4,2.7,3,3.3,3.7,4.1,4.6,5.1,0\n2019-06-23,0.6,0.8,1,1.1,1.3,1.5,1.7,1.9,2.2,2.4,2.8,3.1,3.5,0\n2019-06-24,0,0,0,0,0.1,0.2,0.3,0.4,0.6,0.8,1,1.2,1.4,0\n2019-06-25,0,0,0,0,0,0.1,0.3,0.5,0.8,1.1,1.4,1.8,2.2,1\n2019-06-26,0.1,0.2,0.5,0.8,1.1,1.5,1.8,2.2,2.6,3,3.5,4,4.5,0\n2019-06-27,0.7,0.9,1.2,1.5,1.8,2.1,2.4,2.7,3,3.4,3.8,4.1,4.6,1\n2019-06-28,0.5,0.7,0.9,1.2,1.4,1.7,2,2.3,2.7,3.1,3.4,3.9,4.3,0\n2019-06-29,0.2,0.3,0.5,0.6,0.8,1,1.1,1.3,1.5,1.7,1.9,2.1,2.2,1\n2019-06-30,0,0,0.1,0.2,0.3,0.4,0.6,0.8,1,1.2,1.5,1.8,2.1,1\n2019-07-01,0.3,0.5,0.6,0.8,1,1.3,1.5,1.8,2.1,2.5,2.9,3.3,3.8,0\n2019-07-02,0.8,0.9,1.1,1.3,1.6,1.8,2.1,2.4,2.7,3.1,3.5,4,4.5,0\n2019-07-03,0.5,0.7,0.9,1.1,1.4,1.6,1.9,2.2,2.5,2.9,3.3,3.6,4.1,0\n2019-07-04,0.6,0.8,1,1.2,1.4,1.6,1.8,2,2.2,2.4,2.7,2.9,3.2,0\n2019-07-05,0,0,0,0,0,0.1,0.2,0.3,0.5,0.6,0.8,1,1.3,0\n2019-07-06,0,0,0,0.1,0.2,0.4,0.5,0.8,1,1.3,1.6,1.9,2.3,0\n2019-07-07,0.3,0.5,0.8,1.1,1.4,1.7,2.1,2.5,2.9,3.3,3.7,4.2,4.7,0\n2019-07-08,0.2,0.4,0.5,0.7,1,1.3,1.6,1.9,2.3,2.6,3,3.5,3.9,0\n2019-07-09,0.1,0.3,0.4,0.6,0.8,1,1.3,1.5,1.8,2.1,2.4,2.8,3.2,0\n2019-07-10,0,0,0,0,0.1,0.2,0.4,0.6,0.8,1,1.2,1.5,1.7,0\n2019-07-11,0,0,0,0,0.1,0.3,0.4,0.6,0.8,1,1.2,1.5,1.8,0\n2019-07-12,0,0,0,0,0,0.1,0.2,0.4,0.6,0.8,1,1.3,1.6,1\n2019-07-13,0,0.1,0.1,0.2,0.4,0.5,0.7,1,1.2,1.5,1.9,2.3,2.7,1\n2019-07-14,0.2,0.4,0.6,0.8,1.1,1.4,1.8,2.1,2.5,3,3.4,3.9,4.4,0\n2019-07-15,0.7,0.9,1.2,1.5,1.8,2.1,2.4,2.8,3.2,3.6,4,4.5,4.9,0\n2019-07-16,0.7,0.8,1,1.2,1.4,1.6,1.8,2,2.2,2.5,2.7,3,3.3,1\n2019-07-17,0.2,0.3,0.4,0.6,0.7,0.9,1.1,1.3,1.5,1.7,1.9,2.2,2.5,0\n2019-07-18,0,0,0.1,0.2,0.4,0.6,0.9,1.2,1.5,1.8,2.2,2.5,2.9,0\n2019-07-19,0.4,0.6,0.8,1.1,1.4,1.7,2.1,2.6,3.1,3.6,4.1,4.6,5.1,1\n2019-07-20,0,0,0.1,0.2,0.4,0.6,0.8,1,1.3,1.6,1.9,2.2,2.6,0\n2019-07-21,0.4,0.5,0.7,0.9,1.1,1.3,1.5,1.8,2,2.3,2.6,3,3.4,0\n2019-07-22,0,0,0,0.1,0.2,0.3,0.5,0.7,0.8,1,1.2,1.5,1.7,0\n2019-07-23,0,0,0,0.1,0.2,0.3,0.4,0.5,0.7,0.8,1,1.2,1.3,0\n2019-07-24,0,0,0,0,0,0,0,0,0,0,0,0,0,1\n2019-07-25,0,0,0,0,0,0,0,0,0,0,0,0.1,0.1,0\n2019-07-26,0,0,0,0,0,0,0,0,0,0.1,0.2,0.4,0.7,0\n2019-07-27,0,0.1,0.2,0.3,0.5,0.8,1.1,1.4,1.9,2.3,2.8,3.3,3.8,0\n2019-07-28,0,0,0.2,0.4,0.6,0.8,1.1,1.4,1.8,2.1,2.5,2.8,3.2,0\n2019-07-29,0.4,0.5,0.7,0.8,1,1.2,1.4,1.6,1.8,2,2.2,2.4,2.7,0\n2019-07-30,0,0,0,0,0.1,0.3,0.6,1,1.5,2,2.5,3,3.5,0\n2019-07-31,0,0,0,0.2,0.4,0.6,0.8,1,1.3,1.6,2,2.4,2.9,1\n2019-08-01,0,0.1,0.3,0.4,0.5,0.7,0.9,1.1,1.3,1.6,1.8,2.1,2.4,0\n2019-08-02,0,0,0.1,0.1,0.2,0.4,0.6,0.8,1.1,1.4,1.6,1.9,2.3,0\n2019-08-03,0,0,0,0.1,0.3,0.4,0.6,0.8,1,1.3,1.6,1.9,2.2,0\n2019-08-04,0,0,0,0.1,0.2,0.3,0.5,0.7,0.9,1.1,1.4,1.7,2,0\n2019-08-05,0,0,0,0.1,0.3,0.5,0.8,1.1,1.4,1.7,2,2.3,2.6,1\n2019-08-06,0,0.1,0.2,0.4,0.6,0.8,1.1,1.3,1.6,1.9,2.2,2.6,2.9,0\n2019-08-07,0.1,0.3,0.4,0.6,0.8,1,1.3,1.5,1.8,2.1,2.5,3,3.4,0\n2019-08-08,0.3,0.4,0.6,0.8,0.9,1.1,1.3,1.5,1.7,2,2.2,2.5,2.8,1\n2019-08-09,0,0,0,0,0,0.1,0.2,0.3,0.5,0.8,1.1,1.4,1.7,0\n2019-08-10,0,0,0,0.1,0.4,0.6,0.9,1.2,1.6,1.9,2.3,2.7,3.2,0\n2019-08-11,0.1,0.3,0.5,0.7,0.9,1.2,1.4,1.7,2,2.3,2.7,3.1,3.6,0\n2019-08-12,1.1,1.5,1.9,2.4,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,0\n2019-08-13,1.4,1.7,1.9,2.2,2.5,2.8,3.1,3.4,3.8,4.1,4.6,5,5.5,1\n2019-08-14,0.5,0.8,1.2,1.6,2.1,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,1\n2019-08-15,0.1,0.2,0.3,0.5,0.7,1,1.3,1.6,1.9,2.2,2.6,3.1,3.5,0\n2019-08-16,0.5,0.7,0.9,1.2,1.6,2.1,2.6,3.1,3.6,4.1,4.6,5.1,5.6,0\n2019-08-17,0,0,0.1,0.3,0.5,0.8,1.1,1.4,1.8,2.2,2.6,3,3.4,0\n2019-08-18,0.3,0.5,0.8,1.2,1.5,1.9,2.2,2.6,3,3.4,3.9,4.4,4.9,1\n2019-08-19,0.9,1.1,1.4,1.7,2,2.3,2.6,3,3.5,4,4.5,5,5.5,0\n2019-08-20,1.4,1.7,1.9,2.2,2.6,2.9,3.3,3.6,4,4.5,5,5.5,6,0\n2019-08-21,1.2,1.5,1.7,2,2.2,2.5,2.8,3.1,3.5,3.8,4.2,4.6,5.1,0\n2019-08-22,0.8,1,1.1,1.3,1.5,1.8,2,2.3,2.5,2.9,3.2,3.5,3.9,1\n2019-08-23,0.3,0.5,0.6,0.8,1,1.2,1.4,1.6,1.8,2.1,2.3,2.6,2.9,1\n2019-08-24,0.3,0.4,0.5,0.6,0.8,1,1.1,1.3,1.5,1.8,2,2.2,2.5,1\n2019-08-25,0,0,0,0,0.1,0.2,0.4,0.6,0.8,1,1.1,1.4,1.6,0\n2019-08-26,0,0,0,0.1,0.1,0.2,0.3,0.4,0.6,0.7,0.9,1.1,1.3,1\n2019-08-27,0,0,0,0,0,0.1,0.2,0.4,0.5,0.7,0.8,1,1.2,0\n2019-08-28,0,0,0,0,0,0,0,0.2,0.4,0.6,0.9,1.2,1.5,0\n2019-08-29,0.4,0.6,0.8,1,1.3,1.6,1.8,2.1,2.5,2.8,3.1,3.5,3.9,0\n2019-08-30,0.3,0.5,0.7,0.9,1.2,1.4,1.7,2,2.3,2.6,2.9,3.3,3.6,1\n2019-08-31,0.6,0.8,1,1.2,1.5,1.9,2.3,2.6,3,3.4,3.9,4.3,4.7,0\n2019-09-01,1.1,1.4,1.7,2,2.3,2.7,3.1,3.5,4,4.5,5,5.5,6,0\n2019-09-02,1.8,2,2.3,2.5,2.8,3.1,3.4,3.8,4.2,4.6,5.1,5.6,6.1,0\n2019-09-03,0.1,0.2,0.4,0.7,0.9,1.2,1.5,1.9,2.3,2.8,3.2,3.7,4.2,0\n2019-09-04,0.3,0.5,0.7,1,1.3,1.6,2,2.4,2.8,3.3,3.8,4.3,4.8,0\n2019-09-05,1.7,2,2.4,2.8,3.2,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,1\n2019-09-06,2.2,2.5,2.9,3.4,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,0\n2019-09-07,1.7,2,2.4,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,0\n2019-09-08,3,3.4,3.8,4.2,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,0\n2019-09-09,1.9,2.4,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,0\n2019-09-10,1.2,1.5,1.8,2.1,2.4,2.8,3.2,3.7,4.2,4.7,5.2,5.7,6.2,0\n2019-09-11,0.6,0.8,1,1.3,1.5,1.8,2.1,2.5,2.8,3.3,3.7,4.2,4.7,1\n2019-09-12,0.4,0.6,0.8,1,1.2,1.4,1.7,2,2.3,2.6,3,3.4,3.7,0\n2019-09-13,0.4,0.5,0.8,1,1.3,1.6,1.9,2.3,2.7,3.1,3.5,4,4.4,0\n2019-09-14,1.7,2,2.2,2.6,2.9,3.2,3.5,3.9,4.2,4.6,5,5.4,5.8,0\n2019-09-15,1.5,1.7,1.9,2.1,2.3,2.6,2.8,3.1,3.4,3.7,4,4.3,4.6,1\n2019-09-16,0,0,0.1,0.4,0.8,1.2,1.6,2,2.5,3,3.5,4,4.5,0\n2019-09-17,1.6,1.9,2.3,2.6,3,3.4,3.9,4.3,4.8,5.3,5.8,6.3,6.8,0\n2019-09-18,2.5,2.8,3.2,3.5,3.9,4.3,4.7,5.1,5.6,6.1,6.6,7.1,7.6,1\n2019-09-19,2.5,2.8,3.1,3.4,3.8,4.1,4.5,4.9,5.3,5.7,6.1,6.6,7.1,1\n2019-09-20,1.4,1.7,2.1,2.4,2.8,3.1,3.5,3.9,4.3,4.8,5.3,5.8,6.3,1\n2019-09-21,0.6,0.8,1,1.3,1.5,1.8,2.1,2.4,2.8,3.1,3.5,3.9,4.3,3\n2019-09-22,0,0.1,0.2,0.3,0.4,0.7,1.1,1.5,2,2.4,2.9,3.4,3.8,0\n2019-09-23,0.4,0.7,1,1.4,1.8,2.2,2.6,3,3.5,4,4.5,5,5.5,0\n2019-09-24,0.1,0.2,0.5,0.9,1.3,1.7,2.2,2.7,3.2,3.7,4.2,4.7,5.2,1\n2019-09-25,0.3,0.5,0.8,1.1,1.4,1.7,2.1,2.5,3,3.4,3.9,4.4,4.9,1\n2019-09-26,0.1,0.3,0.5,0.9,1.3,1.7,2.1,2.6,3,3.5,4,4.5,5,0\n2019-09-27,1.1,1.4,1.8,2.2,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,0\n2019-09-28,1.3,1.6,2,2.3,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,0\n2019-09-29,0.5,0.8,1.1,1.5,1.9,2.3,2.8,3.3,3.8,4.3,4.8,5.3,5.8,0\n2019-09-30,2,2.3,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,0\n2019-10-01,0.9,1.2,1.6,2,2.5,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,1\n2019-10-02,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,0\n2019-10-03,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2019-10-04,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,1\n2019-10-05,2.1,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,0\n2019-10-06,1.6,2,2.5,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,0\n2019-10-07,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,1\n2019-10-08,2.2,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,0\n2019-10-09,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,1\n2019-10-10,3,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,0\n2019-10-11,0.7,1,1.5,2,2.5,3,3.5,4,4.5,5,5.5,6,6.5,1\n2019-10-12,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,1\n2019-10-13,2.4,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,0\n2019-10-14,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,0\n2019-10-15,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,1\n2019-10-16,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,0\n2019-10-17,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,0\n2019-10-18,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,1\n2019-10-19,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,0\n2019-10-20,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,0\n2019-10-21,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,0\n2019-10-22,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,0\n2019-10-23,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,1\n2019-10-24,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,0\n2019-10-25,2.7,3.1,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,0\n2019-10-26,2.1,2.5,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,0\n2019-10-27,8.3,8.8,9.3,9.8,10.4,10.9,11.4,11.9,12.4,13,13.5,14,14.5,0\n2019-10-28,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,0\n2019-10-29,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,0\n2019-10-30,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,0\n2019-10-31,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,0\n2019-11-01,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,0\n2019-11-02,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,0\n2019-11-03,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,0\n2019-11-04,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,0\n2019-11-05,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,0\n2019-11-06,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,0\n2019-11-07,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,0\n2019-11-08,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,0\n2019-11-09,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,0\n2019-11-10,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,0\n2019-11-11,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,0\n2019-11-12,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,0\n2019-11-13,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,0\n2019-11-14,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,0\n2019-11-15,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,0\n2019-11-16,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,0\n2019-11-17,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,0\n2019-11-18,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,0\n2019-11-19,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,16.8,17.3,17.8,18.3,0\n2019-11-20,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,0\n2019-11-21,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,0\n2019-11-22,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,0\n2019-11-23,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2019-11-24,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,0\n2019-11-25,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,0\n2019-11-26,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,0\n2019-11-27,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,0\n2019-11-28,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,0\n2019-11-29,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,0\n2019-11-30,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,16.8,17.3,0\n2019-12-01,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,1\n2019-12-02,12.6,13.1,13.6,14.1,14.6,15.1,15.6,16.1,16.6,17.1,17.6,18.1,18.6,0\n2019-12-03,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,0\n2019-12-04,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5,18,1\n2019-12-05,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,0\n2019-12-06,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,0\n2019-12-07,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2019-12-08,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,0\n2019-12-09,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,1\n2019-12-10,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,1\n2019-12-11,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,1\n2019-12-12,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,0\n2019-12-13,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,0\n2019-12-14,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,0\n2019-12-15,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,0\n2019-12-16,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,0\n2019-12-17,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,0\n2019-12-18,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,0\n2019-12-19,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,0\n2019-12-20,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,0\n2019-12-21,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,0\n2019-12-22,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,0\n2019-12-23,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,0\n2019-12-24,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,0\n2019-12-25,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,0\n2019-12-26,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,0\n2019-12-27,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,0\n2019-12-28,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,0\n2019-12-29,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,1\n2019-12-30,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,0\n2019-12-31,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,0\n2020-01-01,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,0\n2020-01-02,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,0\n2020-01-03,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,0\n2020-01-04,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,0\n2020-01-05,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,0\n2020-01-06,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,0\n2020-01-07,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,0\n2020-01-08,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,0\n2020-01-09,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,0\n2020-01-10,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,0\n2020-01-11,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2020-01-12,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2020-01-13,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,0\n2020-01-14,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,1\n2020-01-15,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,1\n2020-01-16,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,0\n2020-01-17,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,0\n2020-01-18,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5,0\n2020-01-19,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,17.2,17.7,0\n2020-01-20,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,16.9,17.4,17.9,18.4,0\n2020-01-21,13.3,13.8,14.3,14.8,15.3,15.8,16.3,16.8,17.3,17.8,18.3,18.8,19.3,0\n2020-01-22,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,0\n2020-01-23,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,0\n2020-01-24,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,0\n2020-01-25,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,0\n2020-01-26,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,0\n2020-01-27,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,0\n2020-01-28,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,16.1,16.6,17.1,0\n2020-01-29,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,1\n2020-01-30,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,0\n2020-01-31,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,0\n2020-02-01,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,0\n2020-02-02,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,1\n2020-02-03,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,0\n2020-02-04,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,0\n2020-02-05,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,16.1,0\n2020-02-06,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,0\n2020-02-07,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,0\n2020-02-08,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,0\n2020-02-09,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,0\n2020-02-10,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,0\n2020-02-11,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,0\n2020-02-12,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,0\n2020-02-13,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,0\n2020-02-14,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,0\n2020-02-15,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,0\n2020-02-16,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,1\n2020-02-17,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,0\n2020-02-18,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,0\n2020-02-19,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,1\n2020-02-20,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,1\n2020-02-21,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,0\n2020-02-22,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,0\n2020-02-23,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,0\n2020-02-24,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2020-02-25,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,0\n2020-02-26,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,0\n2020-02-27,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,17.2,0\n2020-02-28,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,1\n2020-02-29,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,0\n2020-03-01,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,0\n2020-03-02,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,0\n2020-03-03,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,0\n2020-03-04,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,16.1,16.6,0\n2020-03-05,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,0\n2020-03-06,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,0\n2020-03-07,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,1\n2020-03-08,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,1\n2020-03-09,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,0\n2020-03-10,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,0\n2020-03-11,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,2\n2020-03-12,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,0\n2020-03-13,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,1\n2020-03-14,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,3\n2020-03-15,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,0\n2020-03-16,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,0\n2020-03-17,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2020-03-18,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,0\n2020-03-19,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,0\n2020-03-20,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,0\n2020-03-21,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,0\n2020-03-22,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,0\n2020-03-23,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,0\n2020-03-24,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,0\n2020-03-25,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,0\n2020-03-26,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,0\n2020-03-27,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,0\n2020-03-28,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,0\n2020-03-29,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,1\n2020-03-30,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,0\n2020-03-31,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,0\n2020-04-01,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,1\n2020-04-02,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,0\n2020-04-03,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,1\n2020-04-04,5.8,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,0\n2020-04-05,2.8,3,3.3,3.6,3.9,4.2,4.6,5,5.3,5.8,6.2,6.7,7.2,1\n2020-04-06,2.2,2.6,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,0\n2020-04-07,3.8,4.2,4.5,4.9,5.3,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,1\n2020-04-08,2.1,2.4,2.7,3,3.3,3.7,4,4.4,4.9,5.4,5.9,6.4,6.9,0\n2020-04-09,2.4,2.7,3.1,3.4,3.7,4.1,4.4,4.8,5.2,5.6,6,6.5,7,0\n2020-04-10,2.7,3,3.3,3.7,4,4.4,4.7,5.1,5.5,5.9,6.3,6.8,7.2,1\n2020-04-11,2.2,2.4,2.7,2.9,3.2,3.5,3.8,4.1,4.4,4.8,5.1,5.4,5.8,0\n2020-04-12,1.6,1.9,2.1,2.4,2.6,2.9,3.2,3.5,3.9,4.2,4.5,4.9,5.3,0\n2020-04-13,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,1\n2020-04-14,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,0\n2020-04-15,5.7,6.1,6.5,7,7.5,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,0\n2020-04-16,3.9,4.2,4.6,5,5.4,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,1\n2020-04-17,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,1\n2020-04-18,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,1\n2020-04-19,4.2,4.6,5,5.5,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,0\n2020-04-20,3.8,4.2,4.6,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,0\n2020-04-21,2.7,3.1,3.5,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,0\n2020-04-22,2.7,3,3.3,3.7,4,4.4,4.7,5.1,5.6,6,6.5,7,7.5,1\n2020-04-23,2.8,3.1,3.4,3.7,4,4.4,4.7,5.1,5.4,5.8,6.2,6.6,7,0\n2020-04-24,2.7,3,3.3,3.6,3.9,4.2,4.6,4.9,5.3,5.7,6.1,6.6,7.1,0\n2020-04-25,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,1\n2020-04-26,4.1,4.5,4.8,5.1,5.5,5.9,6.2,6.6,7.1,7.6,8.1,8.6,9.1,0\n2020-04-27,3.3,3.6,4,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,1\n2020-04-28,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,1\n2020-04-29,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,0\n2020-04-30,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,1\n2020-05-01,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,0\n2020-05-02,4,4.5,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,1\n2020-05-03,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,0\n2020-05-04,3.1,3.6,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,0\n2020-05-05,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,1\n2020-05-06,4.4,4.8,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,1\n2020-05-07,2.7,2.9,3.2,3.5,3.8,4.1,4.4,4.7,5,5.4,5.8,6.2,6.6,0\n2020-05-08,1.5,1.7,1.9,2.2,2.4,2.6,2.9,3.2,3.5,3.8,4.2,4.5,4.9,1\n2020-05-09,1.3,1.5,1.7,1.9,2.2,2.4,2.7,2.9,3.2,3.5,3.9,4.2,4.6,0\n2020-05-10,3.2,3.6,4.1,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,1\n2020-05-11,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,0\n2020-05-12,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,1\n2020-05-13,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,1\n2020-05-14,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,0\n2020-05-15,4.3,4.7,5,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,1\n2020-05-16,3,3.5,3.9,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,0\n2020-05-17,2.5,2.8,3.1,3.4,3.8,4.1,4.5,5,5.4,5.9,6.4,6.9,7.4,0\n2020-05-18,1.5,1.7,1.9,2.2,2.5,2.8,3.1,3.4,3.7,4,4.4,4.7,5.1,0\n2020-05-19,0.8,1,1.2,1.4,1.7,1.9,2.1,2.4,2.7,3,3.2,3.6,3.9,1\n2020-05-20,0.5,0.6,0.8,0.9,1.1,1.3,1.5,1.7,1.9,2.1,2.4,2.6,2.9,0\n2020-05-21,0.2,0.3,0.4,0.5,0.6,0.8,0.9,1.1,1.3,1.5,1.7,2,2.2,0\n2020-05-22,0.1,0.2,0.3,0.4,0.5,0.7,0.9,1.1,1.4,1.8,2.2,2.6,3.1,1\n2020-05-23,1.7,2.1,2.5,2.9,3.3,3.8,4.2,4.7,5.2,5.7,6.2,6.7,7.2,0\n2020-05-24,1.4,1.7,1.9,2.2,2.5,2.8,3.1,3.4,3.8,4.2,4.6,5,5.5,0\n2020-05-25,1.1,1.3,1.5,1.7,1.9,2.1,2.3,2.6,2.8,3.1,3.4,3.7,4,1\n2020-05-26,0.7,0.9,1.1,1.2,1.4,1.6,1.8,2.1,2.3,2.5,2.7,3,3.2,1\n2020-05-27,0.3,0.5,0.7,1,1.2,1.4,1.7,1.9,2.2,2.4,2.7,3,3.3,0\n2020-05-28,1.2,1.4,1.7,2,2.3,2.6,3,3.3,3.7,4.1,4.6,5.1,5.6,0\n2020-05-29,1.3,1.5,1.8,2.1,2.3,2.6,3,3.3,3.6,3.9,4.3,4.7,5.1,0\n2020-05-30,1.5,1.7,1.9,2.1,2.4,2.6,2.9,3.2,3.5,3.8,4.1,4.4,4.8,1\n2020-05-31,0.6,0.8,1,1.2,1.5,1.8,2,2.3,2.6,2.9,3.2,3.6,3.9,0\n2020-06-01,0.9,1.1,1.3,1.5,1.7,1.9,2.2,2.4,2.7,3,3.3,3.6,3.9,0\n2020-06-02,0.5,0.7,0.8,1,1.3,1.5,1.7,2,2.3,2.5,2.8,3.1,3.4,0\n2020-06-03,0.4,0.7,0.9,1.2,1.6,2,2.4,2.9,3.4,3.9,4.4,4.9,5.4,1\n2020-06-04,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,1\n2020-06-05,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,0\n2020-06-06,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,0\n2020-06-07,3.5,3.9,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,0\n2020-06-08,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,0\n2020-06-09,2.1,2.4,2.7,3.1,3.5,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,0\n2020-06-10,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,0\n2020-06-11,1.7,2,2.4,2.8,3.2,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,0\n2020-06-12,0.5,0.7,0.9,1.2,1.5,1.8,2.2,2.7,3.2,3.7,4.2,4.7,5.2,0\n2020-06-13,0.6,0.7,0.9,1.1,1.3,1.6,1.8,2.1,2.4,2.7,3.1,3.4,3.7,1\n2020-06-14,0.4,0.5,0.7,0.9,1.1,1.3,1.6,1.8,2.1,2.5,2.8,3.2,3.7,0\n2020-06-15,0.7,0.9,1.1,1.4,1.6,1.9,2.1,2.4,2.7,3,3.4,3.7,4.1,1\n2020-06-16,0.4,0.5,0.7,0.9,1.1,1.3,1.6,1.8,2.1,2.3,2.6,3,3.3,1\n2020-06-17,0.5,0.7,1,1.3,1.6,1.9,2.2,2.6,3,3.4,3.9,4.4,4.9,0\n2020-06-18,0.6,0.9,1.3,1.7,2.1,2.5,2.9,3.4,3.9,4.4,4.9,5.4,5.9,0\n2020-06-19,0.5,0.7,1,1.4,1.9,2.3,2.8,3.3,3.8,4.3,4.8,5.3,5.8,1\n2020-06-20,0.7,0.9,1.1,1.3,1.6,1.9,2.2,2.6,3,3.4,3.8,4.2,4.7,0\n2020-06-21,0.1,0.3,0.5,0.8,1,1.3,1.6,1.9,2.2,2.6,3,3.4,3.9,1\n2020-06-22,1.1,1.2,1.5,1.7,1.9,2.2,2.5,2.8,3.1,3.4,3.8,4.2,4.6,0\n2020-06-23,0.5,0.7,0.8,1,1.2,1.3,1.5,1.7,1.9,2.1,2.3,2.6,2.8,0\n2020-06-24,0,0,0,0.1,0.1,0.2,0.3,0.5,0.6,0.8,1,1.2,1.4,1\n2020-06-25,0,0,0,0,0,0,0.1,0.1,0.2,0.4,0.5,0.7,0.8,0\n2020-06-26,0,0,0,0,0,0.1,0.1,0.2,0.3,0.5,0.7,0.9,1.2,1\n2020-06-27,0,0.1,0.3,0.5,0.9,1.2,1.6,2,2.5,3,3.5,4,4.5,0\n2020-06-28,1.1,1.4,1.7,2,2.4,2.7,3.2,3.6,4.1,4.6,5.1,5.6,6.1,0\n2020-06-29,1.2,1.4,1.7,2.1,2.5,2.9,3.3,3.8,4.3,4.8,5.3,5.8,6.3,1\n2020-06-30,0.7,0.9,1.2,1.5,1.9,2.4,2.9,3.4,3.9,4.4,4.9,5.4,5.9,0\n2020-07-01,0.2,0.3,0.5,0.7,1,1.3,1.7,2.1,2.5,3,3.5,4,4.5,0\n2020-07-02,0.8,1.1,1.4,1.8,2.2,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,1\n2020-07-03,1,1.3,1.5,1.8,2.2,2.5,2.9,3.3,3.8,4.2,4.7,5.2,5.7,1\n2020-07-04,0.1,0.2,0.3,0.5,0.7,0.9,1.3,1.7,2.1,2.6,3.1,3.6,4.1,0\n2020-07-05,0.2,0.2,0.3,0.5,0.8,1,1.3,1.7,2,2.4,2.9,3.4,3.9,0\n2020-07-06,1,1.3,1.5,1.8,2.1,2.5,2.9,3.4,3.9,4.4,4.9,5.4,5.9,0\n2020-07-07,1.4,1.6,1.9,2.2,2.5,2.8,3.2,3.6,4.1,4.6,5.1,5.6,6.1,1\n2020-07-08,0.5,0.7,0.9,1.1,1.4,1.8,2.2,2.7,3.2,3.7,4.2,4.7,5.2,0\n2020-07-09,0,0.1,0.3,0.5,0.8,1.1,1.5,2,2.5,3,3.5,4,4.5,0\n2020-07-10,0.9,1.1,1.4,1.8,2.2,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,0\n2020-07-11,1.5,1.7,2,2.3,2.6,2.9,3.3,3.7,4.1,4.6,5.1,5.6,6.1,0\n2020-07-12,1.3,1.5,1.7,1.9,2.1,2.4,2.6,2.9,3.2,3.5,3.8,4.1,4.5,0\n2020-07-13,0.4,0.6,0.8,0.9,1.1,1.3,1.5,1.8,2,2.3,2.5,2.8,3.2,0\n2020-07-14,0,0.2,0.3,0.5,0.7,1,1.3,1.6,1.9,2.3,2.8,3.3,3.8,0\n2020-07-15,0.4,0.6,0.8,1,1.4,1.8,2.3,2.8,3.3,3.8,4.3,4.8,5.3,0\n2020-07-16,0,0,0.2,0.4,0.6,0.8,1.1,1.3,1.6,1.9,2.3,2.6,3,0\n2020-07-17,0,0,0,0,0,0.1,0.2,0.3,0.5,0.7,0.9,1.1,1.4,1\n2020-07-18,0,0.1,0.2,0.3,0.5,0.7,0.9,1.1,1.4,1.6,1.9,2.2,2.5,0\n2020-07-19,0.1,0.2,0.4,0.6,0.9,1.2,1.6,2,2.4,2.9,3.4,3.9,4.4,1\n2020-07-20,0.8,1,1.2,1.5,1.7,2,2.3,2.6,3,3.3,3.7,4.1,4.5,0\n2020-07-21,0.6,0.8,0.9,1.2,1.4,1.7,2,2.3,2.6,3,3.4,3.8,4.3,0\n2020-07-22,0,0.1,0.3,0.4,0.6,0.8,1,1.3,1.5,1.8,2.1,2.4,2.7,1\n2020-07-23,0.2,0.3,0.5,0.7,0.8,1,1.2,1.5,1.7,2,2.3,2.6,2.9,0\n2020-07-24,0,0,0,0.1,0.2,0.3,0.5,0.8,1,1.3,1.6,1.9,2.2,0\n2020-07-25,0.1,0.1,0.2,0.3,0.4,0.7,1.1,1.5,1.9,2.4,2.8,3.3,3.8,0\n2020-07-26,0.8,1,1.2,1.4,1.7,1.9,2.2,2.6,3,3.4,3.9,4.3,4.8,0\n2020-07-27,0,0,0.2,0.4,0.7,0.9,1.2,1.6,2.1,2.5,3,3.5,4,0\n2020-07-28,0.6,0.9,1.1,1.4,1.7,2,2.3,2.7,3.1,3.5,4,4.5,5,0\n2020-07-29,1.5,1.7,1.8,2,2.2,2.4,2.7,2.9,3.2,3.5,3.8,4.2,4.6,0\n2020-07-30,0.4,0.5,0.7,0.8,1,1.2,1.4,1.6,1.7,1.9,2.1,2.4,2.6,0\n2020-07-31,0,0,0,0,0,0.1,0.2,0.3,0.4,0.6,0.8,0.9,1.1,0\n2020-08-01,0,0,0,0,0.1,0.1,0.2,0.3,0.5,0.6,0.8,1.1,1.4,0\n2020-08-02,0.4,0.5,0.7,0.8,1,1.2,1.5,1.7,2,2.3,2.7,3,3.4,0\n2020-08-03,0.1,0.1,0.3,0.4,0.6,0.8,1.1,1.4,1.7,2,2.4,2.8,3.2,0\n2020-08-04,0.7,0.9,1,1.3,1.5,1.7,2,2.3,2.6,2.9,3.2,3.6,4,0\n2020-08-05,0,0.1,0.2,0.4,0.5,0.7,0.9,1.1,1.3,1.5,1.8,2,2.3,0\n2020-08-06,0,0,0,0,0,0,0,0.1,0.2,0.4,0.6,0.9,1.2,0\n2020-08-07,0,0.1,0.2,0.3,0.4,0.5,0.6,0.8,0.9,1.1,1.3,1.5,1.6,0\n2020-08-08,0,0,0,0,0,0,0,0,0,0,0,0.1,0.1,0\n2020-08-09,0,0,0,0,0,0.1,0.2,0.4,0.6,0.8,1,1.2,1.4,0\n2020-08-10,0,0,0,0,0,0,0,0,0,0,0.1,0.2,0.3,0\n2020-08-11,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n2020-08-12,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n2020-08-13,0,0,0,0,0,0,0,0,0,0,0.1,0.2,0.3,0\n2020-08-14,0,0,0,0,0,0.1,0.3,0.6,1.1,1.6,2.1,2.6,3.1,0\n2020-08-15,0,0,0,0,0.1,0.3,0.5,0.8,1.2,1.7,2.2,2.7,3.2,0\n2020-08-16,0,0,0,0,0,0.1,0.2,0.3,0.6,0.9,1.2,1.5,1.8,0\n2020-08-17,0.1,0.2,0.4,0.5,0.7,0.9,1.1,1.4,1.6,2,2.3,2.7,3.2,0\n2020-08-18,0,0,0,0.1,0.2,0.4,0.6,0.8,1.1,1.3,1.6,1.9,2.3,1\n2020-08-19,0,0,0.1,0.2,0.4,0.5,0.7,1.1,1.5,2,2.5,3,3.5,1\n2020-08-20,0,0,0,0,0.1,0.2,0.2,0.4,0.6,0.8,1,1.3,1.7,1\n2020-08-21,0,0,0,0,0,0,0,0.1,0.3,0.5,0.8,1.2,1.5,1\n2020-08-22,0,0,0,0.1,0.3,0.5,0.8,1.1,1.5,1.8,2.2,2.6,3.1,1\n2020-08-23,0.1,0.2,0.4,0.6,0.9,1.2,1.5,1.8,2.2,2.6,3,3.5,4,0\n2020-08-24,0.5,0.8,1,1.3,1.6,2,2.3,2.7,3.1,3.5,3.9,4.4,4.9,1\n2020-08-25,0,0.1,0.3,0.5,0.8,1.2,1.5,1.9,2.2,2.6,3.1,3.6,4.1,1\n2020-08-26,0,0.1,0.2,0.4,0.7,1,1.3,1.6,2,2.3,2.7,3.2,3.7,1\n2020-08-27,0.8,1.2,1.6,1.9,2.4,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,2\n2020-08-28,1.3,1.7,2.1,2.5,2.9,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,1\n2020-08-29,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,0\n2020-08-30,1.8,2.3,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,0\n2020-08-31,3,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,0\n2020-09-01,2.8,3.1,3.4,3.6,4,4.3,4.7,5.1,5.6,6.1,6.6,7.1,7.6,0\n2020-09-02,1.8,2.1,2.4,2.7,3.1,3.5,3.9,4.3,4.7,5.2,5.7,6.2,6.7,1\n2020-09-03,0,0,0.1,0.2,0.4,0.7,1,1.3,1.7,2,2.4,2.9,3.3,1\n2020-09-04,0.9,1.2,1.4,1.7,2.1,2.5,3,3.5,4,4.5,5,5.5,6,1\n2020-09-05,2.2,2.6,3,3.4,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,0\n2020-09-06,2.2,2.5,2.8,3.2,3.5,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,0\n2020-09-07,1.6,1.8,2,2.3,2.6,2.9,3.3,3.7,4.1,4.6,5.1,5.6,6.1,0\n2020-09-08,0,0,0.1,0.2,0.4,0.6,0.8,1.1,1.3,1.6,1.9,2.3,2.6,0\n2020-09-09,0.1,0.2,0.4,0.6,0.8,1,1.3,1.6,2,2.3,2.7,3.2,3.6,0\n2020-09-10,1.4,1.7,2,2.4,2.8,3.2,3.6,4.1,4.6,5.1,5.6,6.1,6.6,0\n2020-09-11,2.2,2.5,2.9,3.2,3.6,4,4.4,4.9,5.4,5.9,6.4,6.9,7.4,0\n2020-09-12,0.9,1.1,1.4,1.6,1.9,2.3,2.6,3,3.4,3.7,4.2,4.6,5.1,0\n2020-09-13,0.7,0.9,1.1,1.3,1.6,1.8,2.1,2.4,2.7,3,3.3,3.7,4,0\n2020-09-14,1.1,1.3,1.5,1.7,1.9,2.2,2.4,2.7,2.9,3.2,3.5,3.8,4.1,1\n2020-09-15,0,0,0.1,0.2,0.4,0.6,0.7,0.9,1.1,1.3,1.6,1.8,2,1\n2020-09-16,0,0,0,0,0.1,0.1,0.2,0.2,0.4,0.6,0.8,1.1,1.5,1\n2020-09-17,0.7,1,1.3,1.7,2,2.3,2.7,3,3.4,3.8,4.2,4.7,5.2,0\n2020-09-18,1.3,1.6,1.9,2.2,2.5,2.8,3.2,3.5,3.9,4.3,4.7,5.2,5.7,1\n2020-09-19,0.5,0.7,0.9,1.2,1.4,1.7,2,2.3,2.6,2.9,3.2,3.6,3.9,1\n2020-09-20,0.4,0.6,0.8,1.1,1.3,1.6,1.8,2.1,2.5,2.8,3.1,3.5,3.8,0\n2020-09-21,0.7,1,1.3,1.6,2,2.3,2.7,3.1,3.5,3.9,4.3,4.7,5.1,1\n2020-09-22,0.9,1.1,1.3,1.5,1.7,2,2.3,2.6,2.9,3.3,3.6,4,4.3,1\n2020-09-23,0.6,0.8,1.1,1.5,1.9,2.4,2.9,3.4,3.9,4.4,4.9,5.4,5.9,1\n2020-09-24,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,0\n2020-09-25,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,1\n2020-09-26,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,0\n2020-09-27,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,1\n2020-09-28,2.6,3,3.4,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,1\n2020-09-29,0.8,1.1,1.5,1.9,2.4,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,1\n2020-09-30,2,2.4,2.9,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,1\n2020-10-01,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,0\n2020-10-02,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,0\n2020-10-03,2.2,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,0\n2020-10-04,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,0\n2020-10-05,3.4,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,0\n2020-10-06,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,0\n2020-10-07,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,0\n2020-10-08,1.5,1.9,2.3,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,0\n2020-10-09,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2020-10-10,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,0\n2020-10-11,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,0\n2020-10-12,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,0\n2020-10-13,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2020-10-14,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,0\n2020-10-15,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,0\n2020-10-16,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,1\n2020-10-17,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,1\n2020-10-18,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,1\n2020-10-19,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,1\n2020-10-20,1.1,1.5,1.8,2.2,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,1\n2020-10-21,1.3,1.8,2.3,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,1\n2020-10-22,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,0\n2020-10-23,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,1\n2020-10-24,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,0\n2020-10-25,6.1,6.6,7.1,7.6,8.1,8.7,9.2,9.7,10.2,10.7,11.3,11.8,12.3,0\n2020-10-26,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,0\n2020-10-27,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,0\n2020-10-28,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,1\n2020-10-29,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,0\n2020-10-30,0.8,1.2,1.7,2.2,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,0\n2020-10-31,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,0\n2020-11-01,1.5,1.8,2.1,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,1\n2020-11-02,2.5,2.8,3.2,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,0\n2020-11-03,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,0\n2020-11-04,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,0\n2020-11-05,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,0\n2020-11-06,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,0\n2020-11-07,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2020-11-08,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,0\n2020-11-09,2.4,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,0\n2020-11-10,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,0\n2020-11-11,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,0\n2020-11-12,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,0\n2020-11-13,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,0\n2020-11-14,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,0\n2020-11-15,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,1\n2020-11-16,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,0\n2020-11-17,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,0\n2020-11-18,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,1\n2020-11-19,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,0\n2020-11-20,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,1\n2020-11-21,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,0\n2020-11-22,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,0\n2020-11-23,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,0\n2020-11-24,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,0\n2020-11-25,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,0\n2020-11-26,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,1\n2020-11-27,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,17.2,1\n2020-11-28,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,0\n2020-11-29,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,0\n2020-11-30,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,0\n2020-12-01,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,0\n2020-12-02,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,0\n2020-12-03,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,0\n2020-12-04,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,16.8,17.3,0\n2020-12-05,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,0\n2020-12-06,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5,18,0\n2020-12-07,13.6,14.1,14.6,15.1,15.6,16.1,16.6,17.1,17.6,18.1,18.6,19.1,19.6,0\n2020-12-08,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,16.9,17.4,17.9,18.4,18.9,0\n2020-12-09,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,0\n2020-12-10,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,0\n2020-12-11,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,0\n2020-12-12,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,0\n2020-12-13,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,0\n2020-12-14,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,0\n2020-12-15,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,0\n2020-12-16,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,0\n2020-12-17,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,0\n2020-12-18,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,0\n2020-12-19,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,0\n2020-12-20,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,0\n2020-12-21,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,0\n2020-12-22,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,0\n2020-12-23,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,0\n2020-12-24,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,0\n2020-12-25,13.3,13.8,14.3,14.8,15.3,15.8,16.3,16.8,17.3,17.8,18.3,18.8,19.3,0\n2020-12-26,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,0\n2020-12-27,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,0\n2020-12-28,13.6,14.1,14.6,15.1,15.6,16.1,16.6,17.1,17.6,18.1,18.6,19.1,19.6,0\n2020-12-29,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5,18,18.5,19,0\n2020-12-30,13.9,14.4,14.9,15.4,15.9,16.4,16.9,17.4,17.9,18.4,18.9,19.4,19.9,0\n2020-12-31,15.2,15.7,16.2,16.7,17.2,17.7,18.2,18.7,19.2,19.7,20.2,20.7,21.2,0\n2021-01-01,13.9,14.4,14.9,15.4,15.9,16.4,16.9,17.4,17.9,18.4,18.9,19.4,19.9,0\n2021-01-02,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,16.8,17.3,17.8,18.3,0\n2021-01-03,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,16.1,16.6,17.1,17.6,18.1,0\n2021-01-04,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,16.8,17.3,17.8,0\n2021-01-05,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,16.8,17.3,17.8,18.3,0\n2021-01-06,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,16.1,16.6,17.1,17.6,18.1,0\n2021-01-07,15,15.5,16,16.5,17,17.5,18,18.5,19,19.5,20,20.5,21,0\n2021-01-08,15.4,15.9,16.4,16.9,17.4,17.9,18.4,18.9,19.4,19.9,20.4,20.9,21.4,2\n2021-01-09,14.9,15.4,15.9,16.4,16.9,17.4,17.9,18.4,18.9,19.4,19.9,20.4,20.9,0\n2021-01-10,14.9,15.4,15.9,16.4,16.9,17.4,17.9,18.4,18.9,19.4,19.9,20.4,20.9,0\n2021-01-11,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,0\n2021-01-12,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,1\n2021-01-13,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,1\n2021-01-14,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,17.2,0\n2021-01-15,13.6,14.1,14.6,15.1,15.6,16.1,16.6,17.1,17.6,18.1,18.6,19.1,19.6,0\n2021-01-16,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,0\n2021-01-17,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,0\n2021-01-18,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,0\n2021-01-19,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,0\n2021-01-20,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,2\n2021-01-21,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,0\n2021-01-22,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5,18,0\n2021-01-23,14,14.5,15,15.5,16,16.5,17,17.5,18,18.5,19,19.5,20,0\n2021-01-24,15.4,15.9,16.4,16.9,17.4,17.9,18.4,18.9,19.4,19.9,20.4,20.9,21.4,0\n2021-01-25,14.3,14.8,15.3,15.8,16.3,16.8,17.3,17.8,18.3,18.8,19.3,19.8,20.3,1\n2021-01-26,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,16.9,17.4,17.9,18.4,18.9,0\n2021-01-27,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,0\n2021-01-28,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,0\n2021-01-29,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,0\n2021-01-30,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,16.8,0\n2021-01-31,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,16.9,17.4,17.9,18.4,18.9,0\n2021-02-01,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,16.9,17.4,17.9,0\n2021-02-02,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,0\n2021-02-03,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,0\n2021-02-04,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,0\n2021-02-05,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,0\n2021-02-06,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,0\n2021-02-07,14.3,14.8,15.3,15.8,16.3,16.8,17.3,17.8,18.3,18.8,19.3,19.8,20.3,0\n2021-02-08,16.9,17.4,17.9,18.4,18.9,19.4,19.9,20.4,20.9,21.4,21.9,22.4,22.9,0\n2021-02-09,16.1,16.6,17.1,17.6,18.1,18.6,19.1,19.6,20.1,20.6,21.1,21.6,22.1,0\n2021-02-10,15.5,16,16.5,17,17.5,18,18.5,19,19.5,20,20.5,21,21.5,0\n2021-02-11,16.3,16.8,17.3,17.8,18.3,18.8,19.3,19.8,20.3,20.8,21.3,21.8,22.3,0\n2021-02-12,16.2,16.7,17.2,17.7,18.2,18.7,19.2,19.7,20.2,20.7,21.2,21.7,22.2,0\n2021-02-13,16.6,17.1,17.6,18.1,18.6,19.1,19.6,20.1,20.6,21.1,21.6,22.1,22.6,0\n2021-02-14,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5,18,18.5,19,0\n2021-02-15,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,0\n2021-02-16,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,0\n2021-02-17,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,0\n2021-02-18,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,0\n2021-02-19,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,0\n2021-02-20,2.4,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,0\n2021-02-21,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,0\n2021-02-22,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,0\n2021-02-23,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,0\n2021-02-24,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,0\n2021-02-25,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,0\n2021-02-26,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,0\n2021-02-27,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,0\n2021-02-28,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,0\n2021-03-01,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,0\n2021-03-02,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,0\n2021-03-03,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,16.1,0\n2021-03-04,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,16.1,16.6,0\n2021-03-05,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,17.2,0\n2021-03-06,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5,0\n2021-03-07,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,16.1,16.6,17.1,17.6,18.1,0\n2021-03-08,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,16.1,16.6,0\n2021-03-09,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,0\n2021-03-10,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,0\n2021-03-11,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,0\n2021-03-12,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,0\n2021-03-13,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,0\n2021-03-14,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,0\n2021-03-15,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,0\n2021-03-16,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,0\n2021-03-17,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,0\n2021-03-18,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,0\n2021-03-19,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,0\n2021-03-20,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,0\n2021-03-21,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,0\n2021-03-22,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,0\n2021-03-23,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,0\n2021-03-24,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,0\n2021-03-25,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,0\n2021-03-26,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,0\n2021-03-27,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,0\n2021-03-28,5,5.5,6,6.5,7,7.4,7.9,8.4,8.9,9.4,9.8,10.3,10.8,0\n2021-03-29,3.7,4.1,4.5,4.9,5.3,5.7,6.2,6.6,7.1,7.6,8.1,8.6,9.1,0\n2021-03-30,4.4,4.7,5.1,5.4,5.7,6,6.4,6.7,7.1,7.4,7.8,8.2,8.6,0\n2021-03-31,2.8,3.1,3.3,3.7,4,4.3,4.7,5,5.4,5.9,6.4,6.9,7.4,0\n2021-04-01,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,1\n2021-04-02,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,0\n2021-04-03,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,0\n2021-04-04,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,0\n2021-04-05,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,1\n2021-04-06,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5,18,0\n2021-04-07,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,16.8,17.3,17.8,18.3,0\n2021-04-08,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,0\n2021-04-09,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,0\n2021-04-10,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,0\n2021-04-11,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,16.9,0\n2021-04-12,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,16.9,0\n2021-04-13,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,1\n2021-04-14,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,0\n2021-04-15,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,0\n2021-04-16,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,0\n2021-04-17,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,0\n2021-04-18,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,0\n2021-04-19,5.5,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,0\n2021-04-20,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,0\n2021-04-21,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,0\n2021-04-22,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,0\n2021-04-23,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,0\n2021-04-24,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,0\n2021-04-25,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,0\n2021-04-26,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,0\n2021-04-27,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,0\n2021-04-28,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,0\n2021-04-29,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,0\n2021-04-30,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,0\n2021-05-01,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,0\n2021-05-02,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,0\n2021-05-03,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,0\n2021-05-04,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,0\n2021-05-05,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,0\n2021-05-06,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,0\n2021-05-07,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,0\n2021-05-08,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,1\n2021-05-09,1,1.2,1.5,1.8,2.1,2.4,2.8,3.3,3.7,4.2,4.7,5.2,5.7,0\n2021-05-10,2.5,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,0\n2021-05-11,3.3,3.7,4.2,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,0\n2021-05-12,3,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,0\n2021-05-13,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,1\n2021-05-14,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,70\n2021-05-15,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,100\n2021-05-16,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,74\n2021-05-17,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,1\n2021-05-18,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,0\n2021-05-19,3.8,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,0\n2021-05-20,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,0\n2021-05-21,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,0\n2021-05-22,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,0\n2021-05-23,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,0\n2021-05-24,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,0\n2021-05-25,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,0\n2021-05-26,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,0\n2021-05-27,2.6,2.9,3.2,3.5,3.9,4.2,4.6,5,5.5,6,6.5,7,7.5,0\n2021-05-28,1.8,2.2,2.5,2.9,3.2,3.6,4.1,4.5,5,5.5,6,6.5,7,0\n2021-05-29,1.3,1.5,1.8,2.1,2.4,2.8,3.1,3.5,3.9,4.3,4.8,5.3,5.8,0\n2021-05-30,3.4,3.7,4.1,4.5,4.9,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,0\n2021-05-31,2.2,2.5,2.7,3,3.3,3.6,4,4.3,4.6,5,5.3,5.7,6.1,0\n2021-06-01,0.9,1.1,1.3,1.5,1.7,1.9,2.1,2.4,2.6,2.9,3.2,3.5,3.8,0\n2021-06-02,0.5,0.7,0.8,1,1.2,1.4,1.5,1.7,1.9,2.2,2.4,2.7,3,0\n2021-06-03,0,0,0,0,0,0.1,0.3,0.5,0.8,1.1,1.4,1.8,2.1,0\n2021-06-04,0.8,1.3,1.7,2.2,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,0\n2021-06-05,0.7,0.9,1.1,1.3,1.6,1.8,2.1,2.4,2.7,3,3.4,3.7,4.1,0\n2021-06-06,0.5,0.7,0.8,1,1.2,1.5,1.7,2,2.2,2.5,2.9,3.2,3.6,0\n2021-06-07,0.1,0.2,0.4,0.5,0.7,1,1.2,1.5,1.7,2.1,2.4,2.7,3.1,0\n2021-06-08,0.5,0.7,0.8,1,1.2,1.4,1.7,1.9,2.1,2.4,2.7,3,3.4,0\n2021-06-09,0.6,0.7,0.9,1.1,1.3,1.5,1.7,1.9,2.1,2.3,2.6,2.9,3.1,0\n2021-06-10,0,0.1,0.2,0.3,0.4,0.6,0.8,1.1,1.3,1.6,1.9,2.3,2.6,0\n2021-06-11,0,0,0,0.1,0.3,0.5,0.7,0.9,1.2,1.4,1.8,2.1,2.4,0\n2021-06-12,0.1,0.2,0.3,0.4,0.6,0.8,1,1.2,1.4,1.7,2,2.3,2.7,0\n2021-06-13,0.1,0.2,0.3,0.4,0.6,0.8,0.9,1.1,1.3,1.5,1.8,2,2.2,0\n2021-06-14,0,0,0.1,0.2,0.3,0.5,0.6,0.8,1,1.1,1.3,1.5,1.7,0\n2021-06-15,0,0.1,0.3,0.4,0.5,0.7,0.9,1.2,1.4,1.7,2,2.3,2.6,0\n2021-06-16,0.1,0.1,0.2,0.3,0.4,0.6,0.8,0.9,1.1,1.4,1.6,1.8,2.1,0\n2021-06-17,0,0,0,0.1,0.1,0.2,0.3,0.6,1,1.4,1.8,2.3,2.8,0\n2021-06-18,1.2,1.7,2.2,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,0\n2021-06-19,1.9,2.4,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,0\n2021-06-20,1.2,1.6,2,2.4,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,0\n2021-06-21,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,0\n2021-06-22,1.9,2.4,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,0\n2021-06-23,2,2.2,2.5,2.8,3.1,3.4,3.7,4.1,4.5,4.9,5.4,5.8,6.3,0\n2021-06-24,1.6,1.8,2,2.2,2.4,2.6,2.9,3.2,3.6,4,4.4,4.9,5.4,1\n2021-06-25,0.3,0.5,0.7,1,1.3,1.6,1.9,2.2,2.6,2.9,3.4,3.8,4.3,0\n2021-06-26,0.2,0.4,0.6,0.8,1.1,1.3,1.6,1.9,2.3,2.6,3.1,3.5,4,0\n2021-06-27,0,0.2,0.4,0.6,0.9,1.2,1.5,1.9,2.3,2.8,3.3,3.8,4.3,0\n2021-06-28,0,0.2,0.5,0.7,1.1,1.4,1.8,2.2,2.6,3.1,3.6,4.1,4.6,0\n2021-06-29,0.2,0.5,0.9,1.4,1.8,2.3,2.8,3.3,3.8,4.3,4.8,5.3,5.8,0\n2021-06-30,0.7,1.1,1.5,1.9,2.4,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,0\n2021-07-01,0.5,0.7,0.9,1.1,1.3,1.6,1.9,2.2,2.5,2.9,3.4,3.8,4.3,0\n2021-07-02,0.1,0.2,0.3,0.4,0.6,0.8,1.1,1.3,1.5,1.8,2.1,2.4,2.7,0\n2021-07-03,0,0,0,0.1,0.3,0.5,0.8,1.1,1.5,1.9,2.4,2.9,3.4,0\n2021-07-04,0.1,0.2,0.4,0.7,1,1.3,1.6,2,2.4,2.9,3.4,3.9,4.4,0\n2021-07-05,0.6,0.9,1.2,1.5,1.8,2.1,2.5,2.9,3.4,3.8,4.3,4.8,5.3,0\n2021-07-06,0.9,1.3,1.7,2.2,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,0\n2021-07-07,0.6,0.8,1.1,1.3,1.6,1.9,2.3,2.7,3.2,3.7,4.2,4.7,5.2,0\n2021-07-08,0.3,0.4,0.6,0.8,1,1.2,1.5,1.8,2.2,2.6,3.1,3.6,4.1,0\n2021-07-09,0,0.1,0.2,0.4,0.6,0.8,1.1,1.4,1.7,2,2.3,2.7,3.1,0\n2021-07-10,0.5,0.8,1,1.4,1.7,2.2,2.7,3.2,3.7,4.2,4.7,5.2,5.7,0\n2021-07-11,0.8,1,1.2,1.5,1.8,2.1,2.4,2.8,3.2,3.6,4,4.5,5,0\n2021-07-12,0.5,0.7,1,1.3,1.7,2.1,2.5,2.9,3.3,3.7,4.2,4.7,5.2,0\n2021-07-13,0,0,0.1,0.3,0.5,0.8,1,1.3,1.7,2,2.4,2.7,3.1,0\n2021-07-14,0.1,0.2,0.3,0.4,0.6,0.8,1.1,1.3,1.6,1.9,2.1,2.5,2.8,0\n2021-07-15,0.1,0.1,0.3,0.4,0.6,0.9,1.1,1.4,1.6,2,2.4,2.9,3.4,0\n2021-07-16,0.9,1,1.2,1.4,1.6,1.8,2,2.2,2.5,2.7,2.9,3.2,3.5,0\n2021-07-17,0,0,0,0.1,0.2,0.3,0.4,0.6,0.7,1,1.2,1.4,1.7,0\n2021-07-18,0,0.1,0.2,0.3,0.4,0.5,0.6,0.8,0.9,1.1,1.2,1.4,1.6,0\n2021-07-19,0,0,0,0,0,0,0,0,0.1,0.2,0.3,0.5,0.7,0\n2021-07-20,0,0,0,0,0,0,0.1,0.2,0.3,0.5,0.7,0.9,1.1,0\n2021-07-21,0,0,0,0,0,0,0,0.1,0.2,0.4,0.5,0.7,0.9,0\n2021-07-22,0,0,0,0,0,0,0.1,0.2,0.3,0.5,0.7,0.9,1.1,0\n2021-07-23,0,0,0,0.1,0.3,0.5,0.8,1.1,1.4,1.7,2.1,2.4,2.8,0\n2021-07-24,0,0,0.1,0.3,0.5,0.7,1,1.3,1.6,2,2.4,2.8,3.2,0\n2021-07-25,0,0,0,0,0.2,0.5,0.9,1.3,1.7,2.2,2.6,3.1,3.6,0\n2021-07-26,0,0,0,0.2,0.4,0.5,0.8,1,1.2,1.5,1.8,2.1,2.4,0\n2021-07-27,0,0,0,0,0.1,0.3,0.5,0.8,1.1,1.5,2,2.4,2.9,0\n2021-07-28,0.3,0.5,0.7,1,1.4,1.8,2.2,2.7,3.2,3.7,4.2,4.7,5.2,0\n2021-07-29,0.9,1.1,1.3,1.5,1.8,2.1,2.4,2.8,3.1,3.5,3.9,4.4,4.9,0\n2021-07-30,0.2,0.4,0.7,1.1,1.5,2,2.5,3,3.5,4,4.5,5,5.5,0\n2021-07-31,0.6,0.8,1.1,1.4,1.7,2,2.4,2.9,3.4,3.9,4.4,4.9,5.4,0\n2021-08-01,0.4,0.6,0.8,1.1,1.4,1.8,2.1,2.5,2.9,3.4,3.9,4.4,4.9,0\n2021-08-02,0.6,0.9,1.1,1.4,1.7,2.1,2.5,3,3.5,4,4.5,5,5.5,0\n2021-08-03,0.8,1,1.3,1.5,1.8,2.1,2.5,2.9,3.3,3.7,4.2,4.7,5.2,0\n2021-08-04,0.8,0.9,1.1,1.3,1.6,1.8,2.1,2.4,2.7,3.1,3.5,3.9,4.4,0\n2021-08-05,0.5,0.7,0.9,1.2,1.5,1.9,2.2,2.6,3,3.5,4,4.5,5,0\n2021-08-06,0.1,0.2,0.4,0.7,1,1.4,1.8,2.2,2.7,3.1,3.6,4,4.5,0\n2021-08-07,0.7,1,1.4,1.7,2.1,2.5,2.9,3.4,3.8,4.3,4.8,5.3,5.8,0\n2021-08-08,0.7,1,1.4,1.7,2.1,2.5,3,3.4,3.9,4.4,4.9,5.4,5.9,0\n2021-08-09,0.8,1.1,1.5,1.8,2.2,2.6,3,3.4,3.9,4.3,4.8,5.3,5.8,0\n2021-08-10,0.7,0.9,1.1,1.4,1.6,1.9,2.1,2.4,2.7,3,3.4,3.8,4.2,0\n2021-08-11,0.5,0.7,0.9,1.1,1.3,1.6,1.8,2.1,2.4,2.7,3.1,3.4,3.8,0\n2021-08-12,0,0,0.1,0.2,0.4,0.6,0.9,1.1,1.4,1.8,2.2,2.6,3.1,0\n2021-08-13,0.3,0.5,0.7,0.9,1.1,1.4,1.7,2,2.3,2.7,3.1,3.5,4,0\n2021-08-14,0.1,0.2,0.4,0.6,0.7,0.9,1.2,1.4,1.7,2,2.3,2.6,3,0\n2021-08-15,0.1,0.2,0.3,0.5,0.7,0.9,1.2,1.5,1.9,2.2,2.6,3,3.4,0\n2021-08-16,0.6,0.8,1.1,1.4,1.8,2.3,2.8,3.3,3.8,4.3,4.8,5.3,5.8,0\n2021-08-17,1.2,1.4,1.6,1.9,2.3,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,0\n2021-08-18,0,0.2,0.4,0.6,0.8,1.1,1.4,1.7,2,2.3,2.7,3.1,3.6,0\n2021-08-19,0.3,0.5,0.8,1,1.2,1.5,1.8,2.2,2.5,2.9,3.4,3.9,4.4,0\n2021-08-20,0.1,0.2,0.3,0.5,0.7,1,1.3,1.7,2.1,2.5,3,3.5,4,0\n2021-08-21,0,0,0.1,0.3,0.5,0.8,1.1,1.5,1.9,2.4,2.9,3.4,3.9,0\n2021-08-22,0,0.1,0.2,0.4,0.7,1,1.3,1.7,2.1,2.5,2.9,3.4,3.9,0\n2021-08-23,0,0.1,0.3,0.5,0.8,1.1,1.5,1.9,2.3,2.8,3.3,3.8,4.3,0\n2021-08-24,0.7,0.9,1.2,1.5,1.7,2.1,2.4,2.7,3.1,3.4,3.8,4.2,4.6,0\n2021-08-25,0.4,0.5,0.7,1,1.3,1.6,2,2.3,2.7,3.1,3.5,3.9,4.4,0\n2021-08-26,0,0.2,0.4,0.7,1.1,1.6,2.1,2.6,3.1,3.6,4.1,4.6,5.1,0\n2021-08-27,1,1.3,1.6,1.9,2.2,2.6,3,3.5,4,4.5,5,5.5,6,0\n2021-08-28,1,1.3,1.5,1.8,2.1,2.4,2.8,3.2,3.7,4.2,4.7,5.2,5.7,0\n2021-08-29,1.3,1.6,1.9,2.2,2.6,3,3.5,4,4.5,5,5.5,6,6.5,0\n2021-08-30,0.4,0.7,1.2,1.7,2.2,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,0\n2021-08-31,0.6,0.9,1.2,1.6,2,2.5,3,3.5,4,4.5,5,5.5,6,0\n2021-09-01,0.3,0.6,0.9,1.3,1.7,2.1,2.6,3.1,3.6,4.1,4.6,5.1,5.6,0\n2021-09-02,0.2,0.4,0.6,0.9,1.2,1.6,2,2.5,3,3.5,4,4.5,5,0\n2021-09-03,0.2,0.4,0.6,0.9,1.1,1.5,1.8,2.1,2.5,2.9,3.3,3.8,4.3,0\n2021-09-04,0.4,0.6,0.9,1.1,1.4,1.8,2.3,2.7,3.2,3.7,4.2,4.7,5.2,0\n2021-09-05,0.4,0.6,0.7,1,1.2,1.4,1.7,2,2.3,2.6,2.9,3.3,3.6,0\n2021-09-06,0.2,0.4,0.5,0.7,0.9,1.1,1.3,1.5,1.8,2,2.3,2.6,3,0\n2021-09-07,0,0,0.1,0.3,0.4,0.6,0.8,1,1.2,1.4,1.7,1.9,2.2,0\n2021-09-08,0,0,0,0.1,0.2,0.4,0.6,0.8,1,1.2,1.5,1.8,2,0\n2021-09-09,0,0,0,0.2,0.3,0.5,0.8,1.1,1.4,1.8,2.1,2.5,3,0\n2021-09-10,0,0,0,0,0.1,0.3,0.6,0.9,1.3,1.7,2.1,2.5,3,0\n2021-09-11,0,0.1,0.2,0.2,0.4,0.7,1,1.4,1.7,2,2.4,2.8,3.2,0\n2021-09-12,1,1.2,1.4,1.6,1.9,2.2,2.5,2.9,3.2,3.7,4.1,4.6,5.1,0\n2021-09-13,0.3,0.4,0.7,1,1.3,1.6,2,2.4,2.8,3.3,3.8,4.3,4.8,0\n2021-09-14,0,0,0.2,0.4,0.8,1.2,1.6,2.1,2.6,3.1,3.6,4.1,4.6,0\n2021-09-15,0.2,0.4,0.6,0.9,1.3,1.7,2.1,2.5,3,3.5,4,4.5,5,0\n2021-09-16,1.3,1.5,1.8,2,2.3,2.6,2.9,3.2,3.6,3.9,4.3,4.6,5,0\n2021-09-17,0.7,1,1.3,1.6,1.9,2.2,2.5,2.9,3.2,3.6,4,4.5,5,0\n2021-09-18,0.3,0.4,0.6,0.8,1,1.2,1.5,1.8,2.1,2.5,2.8,3.1,3.5,1\n2021-09-19,0,0.1,0.3,0.5,0.9,1.3,1.8,2.2,2.7,3.2,3.7,4.2,4.7,0\n2021-09-20,0.8,1.1,1.4,1.7,2.1,2.5,2.9,3.4,3.9,4.4,4.9,5.4,5.9,0\n2021-09-21,1.6,1.9,2.2,2.6,2.9,3.3,3.6,4,4.5,4.9,5.3,5.8,6.3,0\n2021-09-22,1.7,1.9,2.2,2.5,2.8,3.1,3.5,3.8,4.2,4.6,5,5.4,5.9,0\n2021-09-23,1.2,1.5,1.8,2.1,2.4,2.7,3.1,3.5,3.9,4.3,4.8,5.3,5.8,0\n2021-09-24,0.7,1,1.2,1.5,1.7,2,2.3,2.7,3,3.4,3.8,4.2,4.6,0\n2021-09-25,0.2,0.4,0.6,0.9,1.3,1.8,2.3,2.8,3.3,3.8,4.3,4.8,5.3,0\n2021-09-26,0.5,0.7,0.9,1.2,1.5,1.8,2.1,2.5,2.9,3.2,3.7,4.1,4.6,0\n2021-09-27,0.6,0.8,1,1.4,1.8,2.3,2.8,3.3,3.8,4.3,4.8,5.3,5.8,1\n2021-09-28,2.1,2.5,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,0\n2021-09-29,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,0\n2021-09-30,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,0\n2021-10-01,1.5,1.9,2.3,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,0\n2021-10-02,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,0\n2021-10-03,3,3.5,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,0\n2021-10-04,2.9,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,0\n2021-10-05,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,0\n2021-10-06,3.4,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,0\n2021-10-07,1.1,1.4,1.7,2.1,2.5,3,3.5,4,4.5,5,5.5,6,6.5,0\n2021-10-08,0.6,0.9,1.2,1.6,2.1,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,0\n2021-10-09,2.9,3.3,3.7,4.1,4.5,5,5.4,5.9,6.4,6.9,7.4,7.9,8.4,0\n2021-10-10,2.7,3.1,3.5,4,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,0\n2021-10-11,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,0\n2021-10-12,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,0\n2021-10-13,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,1\n2021-10-14,2.5,2.9,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,0\n2021-10-15,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,1\n2021-10-16,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,0\n2021-10-17,3,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,0\n2021-10-18,2.4,2.8,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,0\n2021-10-19,0,0,0,0.1,0.3,0.6,1,1.4,1.9,2.4,2.9,3.4,3.9,0\n2021-10-20,0.8,1.1,1.5,1.9,2.4,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,0\n2021-10-21,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,0\n2021-10-22,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,0\n2021-10-23,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,0\n2021-10-24,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,0\n2021-10-25,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,0\n2021-10-26,2.8,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,0\n2021-10-27,0.7,1.1,1.6,2.1,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,0\n2021-10-28,2.1,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,0\n2021-10-29,2.5,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,1\n2021-10-30,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,0\n2021-10-31,4.3,4.8,5.3,5.9,6.4,6.9,7.4,8,8.5,9,9.5,10,10.6,0\n2021-11-01,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,0\n2021-11-02,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,0\n2021-11-03,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,0\n2021-11-04,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,0\n2021-11-05,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,0\n2021-11-06,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,0\n2021-11-07,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,0\n2021-11-08,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,0\n2021-11-09,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,0\n2021-11-10,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,0\n2021-11-11,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,0\n2021-11-12,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,0\n2021-11-13,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,0\n2021-11-14,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,0\n2021-11-15,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,0\n2021-11-16,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2021-11-17,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,0\n2021-11-18,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,0\n2021-11-19,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,0\n2021-11-20,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,0\n2021-11-21,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,0\n2021-11-22,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,0\n2021-11-23,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,0\n2021-11-24,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,16.1,0\n2021-11-25,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,0\n2021-11-26,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,0\n2021-11-27,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,16.9,17.4,17.9,0\n2021-11-28,13.8,14.3,14.8,15.3,15.8,16.3,16.8,17.3,17.8,18.3,18.8,19.3,19.8,0\n2021-11-29,14.7,15.2,15.7,16.2,16.7,17.2,17.7,18.2,18.7,19.2,19.7,20.2,20.7,0\n2021-11-30,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,0\n2021-12-01,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,0\n2021-12-02,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,16.9,17.4,17.9,18.4,18.9,0\n2021-12-03,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,0\n2021-12-04,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,0\n2021-12-05,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,0\n2021-12-06,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,16.8,17.3,0\n2021-12-07,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,16.1,16.6,17.1,0\n2021-12-08,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,0\n2021-12-09,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,0\n2021-12-10,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,0\n2021-12-11,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,0\n2021-12-12,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,0\n2021-12-13,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,0\n2021-12-14,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,0\n2021-12-15,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,0\n2021-12-16,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,0\n2021-12-17,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,0\n2021-12-18,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,0\n2021-12-19,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,16.1,16.6,0\n2021-12-20,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,0\n2021-12-21,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,16.9,0\n2021-12-22,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,17.2,17.7,18.2,18.7,0\n2021-12-23,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,0\n2021-12-24,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,0\n2021-12-25,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,0\n2021-12-26,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,0\n2021-12-27,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,0\n2021-12-28,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,0\n2021-12-29,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,0\n2021-12-30,1.7,2.2,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,0\n2021-12-31,2.1,2.6,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,0\n2022-01-01,2.2,2.7,3.2,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,0\n2022-01-02,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,0\n2022-01-03,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,0\n2022-01-04,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,0\n2022-01-05,12.6,13.1,13.6,14.1,14.6,15.1,15.6,16.1,16.6,17.1,17.6,18.1,18.6,0\n2022-01-06,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,16.8,17.3,17.8,18.3,18.8,0\n2022-01-07,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,17.2,17.7,0\n2022-01-08,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,0\n2022-01-09,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,16.9,17.4,0\n2022-01-10,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,0\n2022-01-11,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,0\n2022-01-12,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,0\n2022-01-13,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,16.8,17.3,17.8,18.3,0\n2022-01-14,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,16.9,17.4,17.9,18.4,0\n2022-01-15,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,16.8,17.3,17.8,0\n2022-01-16,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,0\n2022-01-17,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,17.2,17.7,18.2,0\n2022-01-18,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,16.8,17.3,17.8,18.3,18.8,0\n2022-01-19,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,0\n2022-01-20,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,17.2,17.7,0\n2022-01-21,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,17.2,17.7,18.2,18.7,19.2,0\n2022-01-22,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,0\n2022-01-23,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,0\n2022-01-24,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,16.9,17.4,0\n2022-01-25,13.1,13.6,14.1,14.6,15.1,15.6,16.1,16.6,17.1,17.6,18.1,18.6,19.1,0\n2022-01-26,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,0\n2022-01-27,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,0\n2022-01-28,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,0\n2022-01-29,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,0\n2022-01-30,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,0\n2022-01-31,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,0\n2022-02-01,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,0\n2022-02-02,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,0\n2022-02-03,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,0\n2022-02-04,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,0\n2022-02-05,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,0\n2022-02-06,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,0\n2022-02-07,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,0\n2022-02-08,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,0\n2022-02-09,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,0\n2022-02-10,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,0\n2022-02-11,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,0\n2022-02-12,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,0\n2022-02-13,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,0\n2022-02-14,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,0\n2022-02-15,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,0\n2022-02-16,3.1,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,0\n2022-02-17,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,0\n2022-02-18,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,0\n2022-02-19,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,0\n2022-02-20,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,0\n2022-02-21,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,0\n2022-02-22,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,0\n2022-02-23,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,0\n2022-02-24,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,0\n2022-02-25,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,0\n2022-02-26,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,0\n2022-02-27,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,0\n2022-02-28,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2022-03-01,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,0\n2022-03-02,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,0\n2022-03-03,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,0\n2022-03-04,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,0\n2022-03-05,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,0\n2022-03-06,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,14.3,14.8,15.3,15.8,16.3,0\n2022-03-07,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,0\n2022-03-08,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,0\n2022-03-09,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,0\n2022-03-10,3.7,4.2,4.7,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,0\n2022-03-11,5.4,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,0\n2022-03-12,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,0\n2022-03-13,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2022-03-14,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,0\n2022-03-15,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,0\n2022-03-16,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2022-03-17,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,0\n2022-03-18,5.9,6.4,6.9,7.4,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,0\n2022-03-19,5.7,6.2,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,0\n2022-03-20,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,12.8,13.3,13.8,0\n2022-03-21,6.6,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,0\n2022-03-22,3.2,3.5,3.9,4.3,4.6,5,5.4,5.9,6.3,6.8,7.3,7.8,8.3,0\n2022-03-23,4,4.3,4.6,5,5.4,5.8,6.2,6.7,7.2,7.7,8.2,8.7,9.2,0\n2022-03-24,4.6,4.9,5.3,5.7,6.1,6.6,7,7.5,8,8.5,9,9.5,10,0\n2022-03-25,4.3,4.7,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,10.1,0\n2022-03-26,4.1,4.5,4.9,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,0\n2022-03-27,6.5,7,7.5,7.9,8.4,8.9,9.4,9.9,10.3,10.8,11.3,11.8,12.3,0\n2022-03-28,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2022-03-29,6.7,7.2,7.7,8.2,8.7,9.2,9.7,10.2,10.7,11.2,11.7,12.2,12.7,0\n2022-03-30,7.9,8.4,8.9,9.4,9.9,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,0\n2022-03-31,11.6,12.1,12.6,13.1,13.6,14.1,14.6,15.1,15.6,16.1,16.6,17.1,17.6,0\n2022-04-01,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,17.2,0\n2022-04-02,11.2,11.7,12.2,12.7,13.2,13.7,14.2,14.7,15.2,15.7,16.2,16.7,17.2,0\n2022-04-03,10.4,10.9,11.4,11.9,12.4,12.9,13.4,13.9,14.4,14.9,15.4,15.9,16.4,0\n2022-04-04,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,10.8,11.3,11.8,12.3,0\n2022-04-05,3.6,4.1,4.6,5.1,5.6,6.1,6.6,7.1,7.6,8.1,8.6,9.1,9.6,0\n2022-04-06,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,0\n2022-04-07,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,0\n2022-04-08,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,14.6,0\n2022-04-09,8.1,8.6,9.1,9.6,10.1,10.6,11.1,11.6,12.1,12.6,13.1,13.6,14.1,0\n2022-04-10,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,0\n2022-04-11,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3,9.8,10.3,0\n2022-04-12,2.4,2.8,3.2,3.6,4,4.5,5,5.5,6,6.5,7,7.5,8,0\n2022-04-13,2.2,2.6,2.9,3.4,3.9,4.4,4.9,5.4,5.9,6.4,6.9,7.4,7.9,0\n2022-04-14,2.6,2.9,3.2,3.6,3.9,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,0\n2022-04-15,2.3,2.6,2.9,3.2,3.5,3.9,4.2,4.6,5,5.4,5.8,6.2,6.7,0\n2022-04-16,3.2,3.6,3.9,4.3,4.8,5.2,5.7,6.2,6.7,7.2,7.7,8.2,8.7,0\n","output":"str","x":580,"y":1120,"wires":[["3183442d.ff591c"]]},{"id":"7d2a4a21.2e7654","type":"http in","z":"cce2bfaa.e5748","name":"","url":"/ui/wdata","method":"get","upload":false,"swaggerDoc":"","x":350,"y":1120,"wires":[["a948f1d4.48e0e"]]},{"id":"c3306aac.c157f8","type":"http response","z":"cce2bfaa.e5748","name":"","statusCode":"","headers":{"content-type":"application/json"},"x":1210,"y":1120,"wires":[]},{"id":"3183442d.ff591c","type":"function","z":"cce2bfaa.e5748","name":"","func":"msg.payload = msg.payload.substr(msg.payload.indexOf(\"Date,\"));\n\nreturn msg;","outputs":1,"noerr":0,"x":750,"y":1120,"wires":[["dda06847.729758"]]},{"id":"dda06847.729758","type":"csv","z":"cce2bfaa.e5748","name":"","sep":",","hdrin":true,"hdrout":"","multi":"mult","ret":"\\n","temp":"","skip":"0","strings":true,"x":870,"y":1120,"wires":[["26f27f7b.2f949","cd73d882.ce7c18","911c1c00.6090f8"]]},{"id":"26f27f7b.2f949","type":"json","z":"cce2bfaa.e5748","name":"","property":"payload","action":"str","pretty":false,"x":1030,"y":1120,"wires":[["c3306aac.c157f8","cd73d882.ce7c18"]]},{"id":"cd73d882.ce7c18","type":"debug","z":"cce2bfaa.e5748","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1070,"y":1180,"wires":[]},{"id":"49459489.ba8e1c","type":"function","z":"cce2bfaa.e5748","name":"","func":"msg.est = [1.8,1.2,1,0.8,1.3,1.7,4.5,8.7,7.6,6.1,5.4,4.8,4.2,3.6,3.1,3.2,3.7,5.3,7.7,7.3,6.1,4.9,3.7,2.4];\n\nmsg.hourload = {};\n\nvar bn,bout;\nvar primHSource=\"\";\nvar hout=0;\n\nmsg.notes=\"\";\n\n\nvar running = -1;\n\nvar check1 = \"ok\";\nvar check2 = \"ok\";\n\nvar ddays = flow.get(\"ddays\");\n\nvar oot = [];\nvar oot2 = [];\n\nvar ootoot = ['Day', 'DHW', 'CHGreen', 'CHRed'];\noot.push(ootoot);\noot2.push(ootoot);\n\nfor (var dd in ddays) {\n    \n   if(running<0 && ddays[dd][\"Date\"].indexOf(\"-01-01\")>-1)  { running = 0; }\n       \n    if (running>-1) {\n    \n        var dhw = parseFloat(msg.payload.kwhDHWEST);\n        var ch2 = ddays[dd][\"HDD \"+msg.payload.baseTemp] * parseFloat(msg.payload.kwhCH) / parseFloat(msg.payload.dDaysPeak);\n        var ch1 = 0;\n        \n        if (msg.payload.ASHPkWPeak) { \n            \n            var ASHPkWh = 24 * parseFloat(msg.payload.ASHPkWPeak);\n            \n            ch1 = Math.min(ASHPkWh - dhw, ch2);\n            \n            ch2 = Math.max(0, (ch2 - ch1)); \n            \n        }\n        \n        if (running>364) { \n            \n            ootoot = [running-364, dhw,ch1,ch2];\n            oot2.push(ootoot); \n            \n        }\n        else { \n            \n            ootoot = [running, dhw,ch1,ch2];\n            oot.push(ootoot); \n            \n            \n        }\n       \n        running++;\n        if (running>728) { break; }\n        \n     } \n     \n    \n}\n\n\nmsg.arrayarray = JSON.stringify(oot);\nmsg.arrayarray2 = JSON.stringify(oot2);\n\n\nmsg.intro = \"The chart below shows the hot water and central heating demands over 2020 and 2021.\"\n\nmsg.title = \"2020 Load Analysis\";\nmsg.title2 = \"2021 Load Analysis\";\n\nmsg.yaxis = \"kWh\";\n\nmsg.series1name = \"Degree Days\";\nmsg.series2name = \"Negative Energy\";\n\nreturn msg;","outputs":1,"noerr":0,"x":1370,"y":880,"wires":[["f2d212e8.ced2c"]]},{"id":"27a16e86.e6fdd2","type":"inject","z":"cce2bfaa.e5748","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"20","x":370,"y":1060,"wires":[["a948f1d4.48e0e"]]},{"id":"911c1c00.6090f8","type":"function","z":"cce2bfaa.e5748","name":"ddays","func":"flow.set(\"ddays\",msg.payload);\nreturn msg;","outputs":1,"noerr":0,"x":1030,"y":1080,"wires":[[]]},{"id":"f2d212e8.ced2c","type":"template","z":"cce2bfaa.e5748","name":"Annaul report","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n\n    <script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>\n    <script type=\"text/javascript\">\n      google.charts.load('current', {'packages':['corechart','gauge','bar','table']});\n      google.charts.setOnLoadCallback(drawChart3);\n      google.charts.setOnLoadCallback(drawChart2);\n\n      \n      function drawChart2() {\n      var data = google.visualization.arrayToDataTable({{{arrayarray2}}});\n\n      \n\n      var options = {\n        title: '{{title2}}',\n        isStacked: true,\n        chartArea: {width: '85%'},\n        legend: {\n          position: 'none', maxLines: 3\n          },\n        annotations: {\n          alwaysOutside: true,\n          textStyle: {\n            fontSize: 12,\n            auraColor: 'none',\n            color: '#555'\n          },\n          boxStyle: {\n            stroke: '#ccc',\n            strokeWidth: 1,\n            gradient: {\n              color1: '#f3e5f5',\n              color2: '#f3e5f5',\n              x1: '0%', y1: '0%',\n              x2: '100%', y2: '100%'\n            }\n          }\n        },\n        hAxis: {\n          title: 'Day of Year',\n          minValue: 0,\n        },\n        vAxis: {\n          title: '{{yaxis}}',\n          minValue: 0,\n        }\n      };\n      var chart2 = new google.visualization.ColumnChart(document.getElementById('hourload2'));\n      chart2.draw(data, options);\n    }\n      \n      \n    function drawChart3() {\n      var data = google.visualization.arrayToDataTable({{{arrayarray}}});\n\n      \n\n      var options = {\n        title: '{{title}}',\n        isStacked: true,\n        chartArea: {width: '85%'},\n        legend: {\n          position: 'none'\n          },\n        annotations: {\n          alwaysOutside: true,\n          textStyle: {\n            fontSize: 12,\n            auraColor: 'none',\n            color: '#555'\n          },\n          boxStyle: {\n            stroke: '#ccc',\n            strokeWidth: 1,\n            gradient: {\n              color1: '#f3e5f5',\n              color2: '#f3e5f5',\n              x1: '0%', y1: '0%',\n              x2: '100%', y2: '100%'\n            }\n          }\n        },\n        hAxis: {\n          title: 'Day of Year',\n          minValue: 0,\n        },\n        vAxis: {\n          title: '{{yaxis}}',\n          minValue: 0,\n        }\n      };\n      var chart = new google.visualization.ColumnChart(document.getElementById('hourload'));\n      chart.draw(data, options);\n    }\n        \n    \n      \n    </script>\n    \n    <link rel=\"stylesheet\"\n          href=\"https://fonts.googleapis.com/css?family=Hind+Siliguri|Poppins|Questrial|Kosugi+Maru|Nanum+Gothic+Coding\">\n    <style>\n      body {\n        font-family: 'Poppins', serif;\n        font-size: 36px;\n      }\n    </style>\n    \n  </head>\n  <body>\n    <p>\n    {{{intro}}} \n    </p>  \n    \n    <div id=\"hourload\" style=\"width: 800px; height: 300px;\"></div>\n    \n    <div id=\"hourload2\" style=\"width: 800px; height: 300px;\"></div>\n    \n    {{{notes}}} \n    \n","output":"str","x":1600,"y":880,"wires":[[]]},{"id":"dd7405b4.c165a8","type":"switch","z":"cce2bfaa.e5748","name":"","property":"req.params.qd","propertyType":"msg","rules":[{"t":"eq","v":"hndesign","vt":"str"},{"t":"empty"},{"t":"eq","v":"hncompile","vt":"str"},{"t":"eq","v":"products","vt":"str"},{"t":"eq","v":"hiu-install","vt":"str"}],"checkall":"false","repair":false,"outputs":5,"x":410,"y":360,"wires":[["7bcbccf5.64f074"],["7bcbccf5.64f074"],["9ebd1382.8a089"],["3f340f5c.797b9"],["36daa724.841bb8"]]},{"id":"9ebd1382.8a089","type":"change","z":"cce2bfaa.e5748","name":"Heat Network Compile JSON","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"title\":\"Heat Network Compiler\",\"links\":[{\"src\":\"http://www.systemdesigner.co.uk/heatnetwork.php\",\"title\":\"Heat Network Calculator v1\"},{\"src\":\"https://hw3.ddns.net/index.php?page=3D&&startp=heatnetcalc\",\"title\":\"3D Model for Calculator v1\"},{\"src\":\"https://hw7.ddns.net/ui/hncalc\",\"title\":\"Heat Network Calculator v2\"},{\"src\":\"https://hw7.ddns.net/ui/svgexplode?svg=HeatNetwork6.svg\",\"title\":\"Heat Network Schematic Designer (HeatNetwork6.svg)\"}],\"sections\":[{\"title\":\"Blocks\",\"questions\":[{\"title\":\"Schedule of blocks\",\"question\":\"List the components of the network\",\"id\":\"loadSchedule\",\"if\":\"true\",\"required\":true,\"type\":\"sheet\",\"notes\":\"Add, edit and copy down lines as with a normal spreadsheet. Right click for further actions including deleting lines.\",\"units\":\"\",\"default\":[[\"Block 1\",222,663,70]],\"columns\":[{\"type\":\"text\",\"name\":\"blockName\",\"title\":\"Block Name\",\"width\":120},{\"type\":\"numeric\",\"name\":\"occupants\",\"title\":\"Occupants\",\"width\":120,\"decimal\":\".\"},{\"type\":\"numeric\",\"name\":\"kwCH\",\"title\":\"Heating Load kW\",\"width\":120,\"decimal\":\".\"},{\"type\":\"numeric\",\"name\":\"diversityCH\",\"title\":\"Heating Diversity\",\"width\":120,\"decimal\":\".\"}]},{\"title\":\"Description\",\"question\":\"Please describe the network.\",\"id\":\"description\",\"if\":\"true\",\"required\":true,\"type\":\"html\",\"notes\":\"\"},{\"title\":\"Block 1\",\"question\":\"Answer questions for Block 1\",\"id\":\"block1\",\"if\":\"true\",\"required\":true,\"type\":\"object\",\"notes\":\"\",\"units\":\"\",\"jsonQ\":\"hndesign\"},{\"title\":\"Number of blocks\",\"question\":\"Number of blocks?\",\"id\":\"nBlocks\",\"if\":\"true\",\"required\":true,\"type\":\"number\",\"notes\":\"\",\"units\":\"\"},{\"title\":\"Block 1\",\"question\":\"Answer questions for all blocks\",\"id\":\"blocks\",\"count\":\"{{nBlocks}}\",\"array\":\"blocks\",\"if\":\"{{nBlocks}}\",\"required\":true,\"type\":\"array\",\"notes\":\"\",\"units\":\"\",\"jsonQ\":\"hndesign\"},{\"title\":\"Wiki\",\"question\":\"Pick a wiki section\",\"id\":\"wiki1\",\"if\":\"true\",\"required\":true,\"type\":\"wiki\",\"notes\":\"\",\"units\":\"\"}],\"outputs\":[{\"title\":\"The DATA HIU\",\"id\":\"wiki\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"http://heatweb.co.uk/w/index.php?title=The_DATA_HIU#Description\",\"style\":\"width:100%;height:425px\"},{\"title\":\"Substations\",\"id\":\"heatweb1\",\"if\":\"true\",\"type\":\"heatwebcouk\",\"url\":\"https://www.heatweb.co.uk/district-heating-substations/heating-substations/\",\"style\":\"width:100%;height:425px\",\"maxImageHeight\":450},{\"title\":\"The DATA-SPLIT HIU\",\"id\":\"heatweb2\",\"if\":\"true\",\"type\":\"heatwebcouk\",\"url\":\"https://www.heatweb.co.uk/heat-interface-units/the-data-split/\",\"style\":\"width:100%;height:425px\",\"maxImageHeight\":250},{\"title\":\"Schematic\",\"id\":\"wiki2\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"https://heatweb.co.uk/w/index.php?title=The_DATA_HIU#Schematic\",\"style\":\"width:100%;height:425px\"},{\"title\":\"Flushing Bypass\",\"id\":\"wiki3\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"https://heatweb.co.uk/w/index.php?title=The_DATA_HIU#Flushing_Bypass\",\"style\":\"width:100%;height:425px\"},{\"title\":\"EC Declaration\",\"id\":\"wiki4\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"https://www.heatweb.co.uk/w/index.php?title=DATA_EC_Declaration\",\"style\":\"width:100%;height:425px\"},{\"title\":\"EC Declaration\",\"id\":\"wiki5\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"https://www.heatweb.co.uk/w/index.php?title=Installation_Instructions_for_the_Data_HIU#Wilo_Pump_Settings\",\"style\":\"width:100%;height:425px\",\"maxImageHeight\":250},{\"title\":\"BEMS\",\"id\":\"wiki6\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"http://www.heatweb.co.uk/w/index.php?title=Heatweb_BEMS_Controller#Custom_Values_.26_Metadata\",\"style\":\"width:100%;height:425px\"},{\"title\":\"Wiki\",\"id\":\"graph\",\"if\":\"true\",\"type\":\"iframe\",\"url\":\"hnoutputs/graph?wiki=wiki1\",\"style\":\"width:100%;height:725px\",\"buttons\":[{\"onClick\":\"jpegDownload('mygraph')\",\"text\":\"JPEG\"}]}]}],\"calculations\":[{\"id\":\"parsedBlock\",\"title\":\"parsedBlock\",\"if\":\"{{objects.blocks.tPeak}}\",\"function\":\"{{objects.blocks.tPeak}}\",\"units\":\"\"}]}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":720,"y":380,"wires":[["d2c83715.bc4ad8"]]},{"id":"28066280.7df54e","type":"http in","z":"cce2bfaa.e5748","name":"","url":"/ui/hnio.svg","method":"get","upload":false,"swaggerDoc":"","x":440,"y":1240,"wires":[["a758fa69.6e9ee8"]]},{"id":"bbd42a24.08f6e8","type":"http response","z":"cce2bfaa.e5748","name":"","statusCode":"","headers":{},"x":1050,"y":1320,"wires":[]},{"id":"a758fa69.6e9ee8","type":"file in","z":"cce2bfaa.e5748","name":"","filename":"/home/servicedeptuk/.node-red/node_modules/node-red-contrib-heatweb/public/files/svg/hnio.svg","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":700,"y":1280,"wires":[["bbd42a24.08f6e8"]]},{"id":"90c2f76f.e737f8","type":"template","z":"cce2bfaa.e5748","name":"Form Generator","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js\"></script>\n{{!--https://www.sitepoint.com/basic-jquery-form-validation-tutorial/--}}\n\n<script src=\"https://unpkg.com/mustache@latest\"></script>\n\n\n\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n\n\n<style>\n    \n  \n    .jexcel_content {\n        font-size: 14px;\n    }\n    \n    .jexcel {\n        white-space: normal;\n    }\n\n\n.mybutt {\n    padding-left: 6px;\n    padding-right: 6px;\n    padding-top: 4px;\n    padding-bottom: 4px;\n    margin-right: 3px;\n    font-size: 14px;\n    border-radius: 4px;\n    cursor: pointer;\n    background-color: #a4eba4;\n    border-color: #4aa55a;\n    border: solid;\n    border-width: 1px;\n    box-shadow: 2px 2px 3px 1px rgb(0 0 0 / 28%);\n}\n.mybutt:hover {\n  background-color: #dcffdc;\n}\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n\n.outputbox {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #ffffff;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.cframe {\n    border-radius: 0.25rem;\n    margin: 0px 0px 20px 0px;\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 3px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\nvar a = new Date();\nvar qdata;\nvar calculated = {};\nvar hasFocus;\nvar currentSection;\nvar inputsOut;\nvar inputString;\nvar calcsString;\nvar objects={}; // not used yet\nvar sheets = {};\nvar sheetdata = {};\nvar initsheets;\n\n\t$(document).ready(function(e) {\n    \n        // $(\"form[ajax=true]\").submit(function(e) {\n            \n        //     //alert(\"submit\");\n            \n        //     e.preventDefault();\n        \n             \n            //var urlParams = new URLSearchParams(window.location.search);\n            //if (urlParams.get('display')) { loadstring = \",,\" + urlParams.get('display'); }\n\n            calculated[\"jsonQ\"] = \"hndesign\";\n\n            var urlParams = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParams) {\n                \n                calculated[urlParams[upa].split(\"=\")[0]] = urlParams[upa].split(\"=\")[1];\n                \n            }\n            \n            \n            \n            var form_data = {};\n            var form_url = \"/ui/qdata/\" + calculated[\"jsonQ\"];\n            var form_target = $(this).attr(\"target\") || \"result\";\n            var ftarget = \"#\" + form_target;\n            var form_method = \"GET\";\n            \n        //     $(\"#loadingimg\").show();\n            \n            $.ajax({\n                url: form_url, \n                type: form_method,      \n                data: form_data,     \n                cache: false,\n                success: function(results){   \n                    \n                    qdata = results;\n                    //qdata = JSON.parse(returnhtml);\n                    console.log(qdata);\n                   \n                    //if(urlParams['nBuildings']) { runCalcs(); runCalcs();  }\n                    runCalcs(); \n                    runCalcs();\n                    \n                    document.getElementById(\"formName\").innerHTML = qdata.title || \"Unamed Form\"; //JSON.stringify(qdata) ;\n                    \n                    // document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n                    \n                    // for (var sht in initsheets) {  initSheet(initsheets[sht]);   }\n                    \n                    // validform();\n                                  \n                }           \n            });    \n            \n        // });\n        \n      \n        \n    });\n\n\nfunction initSheet(id) {\n\n    console.log(\"initSheet \" + id);\n    console.log(sheetdata);\n    \n    var shid = 'sheet-' + id;\n    var sdata = sheetdata[id];\n    \n    \n\n    try {\n    \n        document.getElementById(shid).innerHTML = \"\";\n        \n        sheets[id] = jspreadsheet(document.getElementById(shid), {\n            data: sdata.data,\n            columns: sdata.columns,\n            onchange: function(instance, cell, x, y, value) {\n                \n                console.log(value);\n                getSheetData(id);\n            },\n            updateTable:function(instance, cell, col, row, val, label, cellName) {\n               \n                //console.log(instance);\n                //console.log(val);\n                \n            },\n            columnSorting:false\n        });\n\n    } catch {}\n}\n\nfunction getSheetData(id) {\n    \n    \n    //alert(id);\n    \n    //console.log(sheets[id].getData());\n    \n    sheetdata[id].data = sheets[id].getData();\n    console.log(sheetdata);\n    \n    var oots = \"\";\n    for (var row in sheetdata[id].data) {\n       for (var c in sheetdata[id].data[row]) {\n           \n           var val = \"\" + (sheetdata[id].data[row][c] || \"\");\n           val = val.replace(/ /g,\"_\")\n           oots += val + \",\";\n        } \n        oots += \" \";\n    }\n    \n    oots = oots.substr(0, oots.length - 2);\n    console.log(oots);\n    \n    returncalc(id,oots)\n    \n    \n}\n\n\nfunction getObject(id) {\n    \n  \n    return (objects[id]||null);\n    \n}\n\n\nfunction setObject(id,value) {\n    \n\n    try { objects[id] = value; }\n    catch {}\n}\n\t\nfunction returncalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).value = value; }\n    catch {\n        \n        try { calculated[id] = value; }\n        catch {}\n    }\n    \n}\n\nfunction suggestcalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).placeholder = value + \" ... please confirm\"; }\n    catch {}\n}\n\t\nfunction parseQuestions(qdata) {\n    \n    console.log(qdata);\n    console.log(calculated);\n    \n    var linkstxt=\"\";\n    if (qdata.links) {\n        for (var lnk in qdata.links) {\n            linkstxt += (linkstxt!==\"\"?\"<br>\":\"\") + '<a href=\"' + qdata.links[lnk].src + '\" target=\"_blank\">' + (qdata.links[lnk].title||qdata.links[lnk].src) + '</a>';\n        }\n        \n    }\n    document.getElementById(\"links\").innerHTML = linkstxt ; //JSON.stringify(qdata) ;\n    \n    \n    inputsOut = '<input id=\"jsonQ\" name=\"jsonQ\" value=\"' + calculated[\"jsonQ\"] + '\" class=\"form-control\" type=\"hidden\">';\n                    \n    \n    inputsOut += '<table class=\"table\">';\n    \n    inputString = \"jsonQ=\" + calculated[\"jsonQ\"];  // data source for form is fixed\n    \n    hasFocus = null;\n    currentSection = null;\n    initsheets = [];\n    \n    var ootoot = \"\";\n    for (var s in qdata[\"sections\"]) {\n        console.log(s);\n        console.log(qdata.sections[s]);\n        \n        var oot = \"\";\n        var ootcount=0;\n        \n        //oot += \"<div class='section'><h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        oot += \"<h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        \n        \n        \n        for (var q in qdata.sections[s].questions) {\n            \n            \n            var qif = qdata.sections[s].questions[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n            var v=\"\";\n            if (calculated[qdata.sections[s].questions[q].id]) { v= calculated[qdata.sections[s].questions[q].id] ; }\n            else if (qdata.sections[s].questions[q].value) { v= qdata.sections[s].questions[q].value ; }\n            \n                \n            \n            \n            if(goq) {\n                \n                var calcfr = \"\";\n                if (qdata.sections[s].questions[q].calculator) { calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].questions[q].calculator + '?field=' + qdata.sections[s].questions[q].id + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].questions[q].calculatorStyle ? qdata.sections[s].questions[q].calculatorStyle:'width:100%; height:300px;') + '\"></iframe>'}\n            \n            \n                if (v!==\"\") { \n                    inputsOut += \"<tr>\";  \n                    \n                    var cOs1 = \"\";  var cOs2 = \"\";\n            \n                    if (document.getElementById(\"hideID\").checked!==true) {\n                        cOs2 = \" <small>[<i>\" + qdata.sections[s].questions[q].id + \"</i>]</small>\";  \n                    }\n                    \n                    inputsOut += '<td width=\"40%\">' + (qdata.sections[s].questions[q].title||qdata.sections[s].questions[q].id) + cOs2 + \"</td>\";\n                    \n                    var vs1=\"\"; var vs2=\"\";\n                    if((\"\"+v).indexOf(\",\") > -1) { vs1=\"<small>\"; vs2=\"</small>\"; }\n                    \n                    inputsOut +=  ('<td align=\"right\">' + vs1 + v + vs2 + \"</td>\").replace(/\\, /g,\"<br>\").replace(/\\,/g,\", \");\n                    inputsOut +=  '<td width=\"14%\">' + (qdata.sections[s].questions[q].units||\"\") + \"</td></tr>\\n\";\n                    \n                    inputString += (inputString!==\"\"?\"&\":\"\") + qdata.sections[s].questions[q].id + \"=\" + v;\n                }\n            \n                var isDisplayed = false;\n            \n                if (hasFocus && document.getElementById(\"oneQ\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">'; }\n            \n                else if (v!==\"\") { \n                    \n                    if (document.getElementById(\"hideDone\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">';   }\n                    else {  oot += '<div class=\"question\" style=\"background-color: #d2efd2;\">'; ootcount++; isDisplayed=true; }\n                    \n                } else { oot += '<div class=\"question\">'; ootcount++; isDisplayed=true; if (!hasFocus) { hasFocus = qdata.sections[s].questions[q].id;  currentSection = qdata.sections[s].title;  } }\n                \n                \n                //oot += \"<div class='qtext'>\" + qdata.sections[s].questions[q].title + '</div>';\n                oot += '<label for=\"' + qdata.sections[s].questions[q].id + '\" class=\"qtext\">' + (qdata.sections[s].questions[q].question||qdata.sections[s].questions[q].title) + '</label>';\n                \n                if (calcfr!==\"\") { oot += \"\\n\" + calcfr + \"\\n\"; }\n                \n                if (qdata.sections[s].questions[q].notes) { oot += '<div class=\"notes\">'  + convertLinks(Mustache.render(qdata.sections[s].questions[q].notes, calculated)) + '</div>'; }\n                \n                if (qdata.sections[s].questions[q].type == \"sheet\") {\n                    \n                    oot += '<br><br><div id=\"sheet-' + qdata.sections[s].questions[q].id + '\">';\n                \n                    oot += '<span onclick=\"initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ')\"><small>Load Sheet</small></span> ';\n                    \n                    oot += '</div><br><br>';\n                    \n                    //oot += '<script>initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ');</scrip' + 't> ';\n                    //var myTimeout = setTimeout(initSheet(qdata.sections[s].questions[q].id), 1000);\n                    if (isDisplayed) { initsheets.push(qdata.sections[s].questions[q].id); }\n                \n                    var shob = {};\n                    shob['columns'] = qdata.sections[s].questions[q].columns;\n                    shob['data'] = qdata.sections[s].questions[q].default;\n                    \n                    if((\"\"+v)!==\"\") {\n                        \n                        shob['data']=[];\n                        var vv = v.replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                        var lns = vv.split(\", \");\n                        for (var lnsv in lns) {\n                            shob['data'].push(lns[lnsv].split(\",\"));\n                        }\n                    }\n                    \n                    sheetdata[qdata.sections[s].questions[q].id] = shob;\n                    \n                }\n                \n                oot += '<table width=\"100%\"><tr><td width=\"80%\">';\n                \n                if (qdata.sections[s].questions[q].type==\"boolean\") {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                      if (v==\"true\") { oot += '<option value=\"false\">No</option><option value=\"true\" selected>Yes</option>'; }\n                      else if (v==\"false\")  { oot += '<option value=\"false\" selected>No</option><option value=\"true\">Yes</option>'; }\n                      else  { oot += '<option value=\"\"></option><option value=\"false\">No</option><option value=\"true\">Yes</option>'; }\n                    oot += '</select>';\n                    \n                } else if (qdata.sections[s].questions[q].options) {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    if (v==\"\") { oot += '<option value=\"\"></option>'; }\n                    for (var opt in qdata.sections[s].questions[q].options) {\n                    \n                      var optobj = qdata.sections[s].questions[q].options[opt];\n                      \n                      \n                      if (v==optobj.value) { oot += '<option selected value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      else  { oot += '<option value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      \n                    }  \n                    oot += '</select>';\n                    \n                }  else {\n                \n                    oot += '<input id=\"' + qdata.sections[s].questions[q].id + '\" name=\"' + qdata.sections[s].questions[q].id + '\" class=\"form-control\" type=\"text\"';\n                    if (v!==\"\") { oot += (' value=\"' + v + '\"').replace(/\\%20/g,\" \").replace(/_/g,\" \"); }\n                    if (qdata.sections[s].questions[q].default) { \n                        \n                        oot += ' placeholder=\"' + Mustache.render(\"\"+qdata.sections[s].questions[q].default, calculated)  + \" \" + (qdata.sections[s].questions[q].units||\"\") + ' ... please confirm\"'; \n                        \n                    }\n                    oot += '>';\n                }\n                \n                oot += '</td><td valign=\"top\"><span class=\"qunits\">' + (qdata.sections[s].questions[q].units||\"\") + '</span></td></tr></table>';\n                \n                \n                oot += '</div>\\n';\n            }\n        }\n    \n        oot += '<table width=\"100%\"><tr><td width=\"100%\" align=\"right\"><button class=\"mybutt\" type=\"submit\">Submit</button></td></tr></table>';\n\n        oot += \"</div>\\n\";\n       \n        \n        var outhtml = \"\";   \n        for (var q in qdata.sections[s].outputs) {\n            \n            var qif = qdata.sections[s].outputs[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n\n            if(goq && (calcsString||\"\")!==\"\") {\n                \n                var calcfr = \"\";\n                if (qdata.sections[s].outputs[q].url) { \n                    \n                    calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].outputs[q].url + (qdata.sections[s].outputs[q].url.indexOf(\"?\")>0?'':'?') + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].outputs[q].style ? qdata.sections[s].outputs[q].style:'width:100%; height:300px;') + '\"></iframe>'\n                    \n                    outhtml += '<div class=\"outputbox\">';\n                    outhtml += \"<b>\" + qdata.sections[s].outputs[q].title + \"</b><br><br>\\n\";\n                    outhtml += calcfr ; \n                    outhtml += \"</div>\\n\";\n                }\n            \n            }\n        }\n        \n        if (outhtml!==\"\") {\n            \n            //oot += '<div class=\"outputbox\">';\n            oot += outhtml;\n            //oot += \"</div>\\n\";\n        }\n        \n        \n        \n        \n        \n        if (document.getElementById(\"oneS\").checked==true && (currentSection != qdata.sections[s].title)) {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n        else if (ootcount>0) {  ootoot += \"<div class='section'>\" + oot; }\n        \n        else {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n    }\n    inputsOut +=  \"</table>\\n\";  \n    \n    return ootoot;\n}\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\n// console.log(looseJsonParse(\n//   \"{a:(4-1), b:function(){}, c:new Date()}\"\n// ))\n\nfunction runCalcs() {\n\n\n    calcsString = \"\";\n    \n    // run through form inputs and store current values into calculated.\n    var cells =  document.getElementsByClassName(\"form-control\");\n\tvar i;\n\tfor (i = 0; i < cells.length; i++) {\n\t\n\t\tcalcsOut += cells[i].value + \"<br>\\n\";\n        \n        if (\"\" + cells[i].value !== \"\") { \n            \n            if (isNaN(cells[i].value)) { \n                \n                calculated[cells[i].id] = (cells[i].value);\n                \n            } else {\n                \n                calculated[cells[i].id] = parseFloat(cells[i].value);\n            }\n            \n            calcsString += \"&\" + cells[i].id + \"=\" + cells[i].value;\n        }\n\t}\n\t\n    var calcsOut = '<table class=\"table\">';\n    \n    \n    // ================== Sheet Custom Calculations\n    \n    \n    if (calculated['loadSchedule']) {\n        \n        console.log(\"Load Schedule = \" + calculated['loadSchedule']);\n        \n        \n            \n            var cv1 = calculated['loadSchedule'];\n            var cv = 0;\n            var np = 0;\n            var kwCHMax = 0;\n            \n            var ldata=[];\n            \n            if((\"\"+cv1)!==\"\") {\n                \n                var vv = (\"\"+cv1).replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                var lns = vv.split(\", \");\n                for (var lnsv in lns) {\n                    ldata.push(lns[lnsv].split(\",\"));\n                    \n                    cv = cv + parseFloat(lns[lnsv].split(\",\")[4])\n                    \n                    np = np + (parseFloat(lns[lnsv].split(\",\")[2]) * parseFloat(lns[lnsv].split(\",\")[4]));\n                    \n                    kwCHMax = kwCHMax + (parseFloat(lns[lnsv].split(\",\")[3]) * parseFloat(lns[lnsv].split(\",\")[4]));\n                    \n                    \n                }\n            }\n            \n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total Properties</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">properties</td></tr>\\n';\n            \n            calculated['nProperties'] = cv;\n            calcsString += \"&nProperties=\" + cv;\n            \n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total People</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + np + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">people</td></tr>\\n';\n            \n            calculated['nPeople'] = np;\n            calcsString += \"&nPeople=\" + np;\n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total of central heating outputs</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + kwCHMax + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">kW</td></tr>\\n';\n            \n            calculated['kwCHMax'] = kwCHMax;\n            calcsString += \"&kwCHMax=\" + kwCHMax;\n            \n        \n        \n    }\n    \n    \n    // ================================\n    \n    \n    for (var calc in (qdata[\"calculations\"]||[])) {\n        \n        console.log(calc);\n        console.log(qdata.calculations[calc]);\n        \n        var cif = qdata.calculations[calc].if || true;\n        var cift = Mustache.render(cif, calculated);\n        var goc = true;\n        try {\n          goc = looseJsonParse(cift); \n        }\n        catch(err) {\n          goc = false;\n        }\n        \n        if (goc) {\n            \n            var f = qdata.calculations[calc].function;\n            var ft = Mustache.render(f, calculated);\n            \n            calcsOut += \"<tr>\";  //<td>\" + qdata.calculations[calc].id + \"</td>\";\n            calcsOut += \"<td>\";\n            \n            var cOs1 = \"\";  var cOs2 = \"\";\n            \n            if (document.getElementById(\"hideID\").checked!==true) {\n                cOs2 = \" <small>[<i>\" + qdata.calculations[calc].id + \"</i>]</small>\";  \n            }\n            \n            calcsOut += cOs1 + (qdata.calculations[calc].title||qdata.calculations[calc].id) + cOs2 + \"</td>\";\n            \n            //calcsOut += f + \" = \";\n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small>\" + ft.replace(/\\,/g,\", \") + \"</small></td>\";   //\"<br>\\n\";\n            }\n            \n            var cv = \"\";\n            try {\n              cv = looseJsonParse(ft); //  looseJsonParse(\"{a:(4-1), b:function(){}, c:new Date()}\");\n            }\n            catch(err) {\n              \n            }\n             \n            \n            if (!isNaN(cv)) { cv = parseInt(cv*1000)/1000; }\n            \n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            \n            calcsOut +=  '<td width=\"14%\">' + (qdata.calculations[calc].units||\"\") + \"</td></tr>\\n\";\n            \n            calculated[qdata.calculations[calc].id] = cv;\n            calcsString += \"&\" + qdata.calculations[calc].id + \"=\" + cv;\n        }\n        \n    }\n    \n    calcsOut +=  \"</table>\\n\";\n    \n    // for (var calc in calculated) {\n        \n        \n    // }\n    \n    document.getElementById(\"calcs\").innerHTML = calcsOut; //JSON.stringify(qdata) ;\n    \n    // rebuild form\n    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"inputs\").innerHTML = inputsOut; //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"mylink\").innerHTML = '<a href=\"hndesign?' + inputString + '\" target=\"_blank\">Open/share design...</a>'; //JSON.stringify(qdata) ;\n    \n    \n    for (var sht in initsheets) {  initSheet(initsheets[sht]);   }\n    \n    validform();\n                    \n}\n\n\nconst convertLinks = ( input ) => {\n\n  let text = input;\n  const linksFound = text.match( /(?:www|https?)[^\\s]+/g );\n  const aLink = [];\n\n  if ( linksFound != null ) {\n\n    for ( let i=0; i<linksFound.length; i++ ) {\n      let replace = linksFound[i];\n      if ( !( linksFound[i].match( /(http(s?)):\\/\\// ) ) ) { replace = 'http://' + linksFound[i] }\n      let linkText = replace.split( '/' )[2];\n      if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) }\n      if ( linkText.match( /youtu/ ) ) {\n\n        let youtubeID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://www.youtube.com/embed/' + youtubeID + '\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe></div>' )\n      }\n      else if ( linkText.match( /vimeo/ ) ) {\n        let vimeoID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://player.vimeo.com/video/' + vimeoID + '\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' )\n      }\n      else {\n        aLink.push( '<a href=\"' + replace + '\" target=\"_blank\">' + linkText + '</a>' );\n      }\n      text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] );\n    }\n    return text;\n\n  }\n  else {\n    return input;\n  }\n}\n\nfunction validform() {\n    \n    if(hasFocus && document.getElementById(hasFocus)) {\n        document.getElementById(hasFocus).focus();\n    }\n    \n    \n    \n// Initialize form validation on the registration form.\n  // It has the name attribute \"registration\"\n  $(\"form[name='qform']\").validate({\n    // Specify validation rules\n    rules: {\n      // The key name on the left side is the name attribute\n      // of an input field. Validation rules are defined\n      // on the right side\n    //   nProperties: {\n    //     required: true,\n    //     digits: true,\n    //     min: 1\n    //   },\n      lastname: \"required\",\n      email: {\n        required: true,\n        // Specify that email should be validated\n        // by the built-in \"email\" rule\n        email: true\n      },\n      password: {\n        required: true,\n        minlength: 5\n      }\n    },\n    // Specify validation error messages\n    messages: {\n      nProperties: \"Please enter a number.\",\n      lastname: \"Please enter your lastname\",\n      password: {\n        required: \"Please provide a password\",\n        minlength: \"Your password must be at least 5 characters long\"\n      },\n      email: \"Please enter a valid email address\"\n    },\n    // Make sure the form is submitted to the destination defined\n    // in the \"action\" attribute of the form when valid\n    submitHandler: function(form) {\n      //form.submit();\n      runCalcs();\n      //alert(\"hello\");\n    }\n  });\n}\n\n</script>\n\n\n<div class='section'>\n    \n    <table width=\"100%\"><tr>\n    <td valign=\"top\" width=\"70%\">\n        <div id=\"formName\" class=\"h1\"></div>\n        <a href=\"https://heatweb.co.uk/w/index.php?title=Heat_Network_Designer\" target=\"_blank\"><small>Wiki Help Page</small></a>\n    </td>\n    <td width=\"30%\">\n        <input type=\"checkbox\" id=\"oneS\" name=\"oneS\" checked> <small>One section at a time</small><br>\n        <input type=\"checkbox\" id=\"oneQ\" name=\"oneQ\" checked> <small>One question at a time</small><br>\n        <input type=\"checkbox\" id=\"hideDone\" name=\"hideDone\" checked> <small>Hide completed questions</small><br>\n        <input type=\"checkbox\" id=\"hideMaths\" name=\"hideMaths\" checked> <small>Hide maths equations</small><br>\n        <input type=\"checkbox\" id=\"hideID\" name=\"hideID\" checked> <small>Hide IDs</small>\n    </td>\n    </tr></table>\n</div>\n\n\n<form action=\"\" name=\"qform\" id=\"qform\">\n<div id=\"section1\"></div>\n\n<div class='section'>\n\n<table width=\"100%\"><tr><td width=\"50%\"><span class=\"mybutt\" onclick=\"onDownload()\">Download JSON</span> <span class=\"mybutt\" onclick=\"copyData()\">Copy Data</span> <span class=\"mybutt\" onclick=\"copylink()\">Copy Link</span> <span class=\"mybutt\" onclick=\"shareTwitter()\">Tweet Design</span></td><td width=\"50%\" align=\"right\"><button class=\"mybutt\" type=\"submit\">Submit</button></td></tr></table>\n\n\n\n\n</div>\n\n<script>\n    \n   function download(content, fileName, contentType) {\n\t\t  const a = document.createElement(\"a\");\n\t\t  const file = new Blob([content], { type: contentType });\n\t\t  a.href = URL.createObjectURL(file);\n\t\t  a.download = fileName;\n\t\t  a.click();\n\t}\n\n\tfunction onDownload(){\n\t    \n\t    var jsonData = { \"url\": (window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\")),\"calculated\": calculated, \"qdata\": qdata };\n\t\tdownload(JSON.stringify(jsonData), \"hndesign.json\", \"text/plain\");\n\t}\n    \n    function copyData(){\n\t    \n\t    var jsonData = { \"url\": (window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\")),\"calculated\": calculated };\n\t\tnavigator.clipboard.writeText(JSON.stringify(jsonData));\n\t\talert(\"Data Copied to Clipboard\");\n\t}\n    \n    \n    function copylink() {\n        \n        //alert(window.location.href.split(\".svg\")[0]+\".svg&display=\"+displayed);\n        \n        navigator.clipboard.writeText(window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\"));  //\n        alert(\"Link Copied to Clipboard\");\n         \n    \n    }\n    \n    function shareTwitter() {       \n        \n        var text = \"My latest heat network design.\";\n        var url = window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\");\n        window.open('http://twitter.com/share?url='+encodeURIComponent(url)+'&text='+encodeURIComponent(text), '', 'left=0,top=0,width=550,height=450,personalbar=0,toolbar=0,scrollbars=0,resizable=0');\n\n    } \n\n</script>\n\n\n<div class='section'>\n<p><b>Inputs</b></p>\n<div id=\"inputs\" class=\"notes\"></div>\n</div>\n\n<div class='section'>\n<p><b>Numeric Values and Calculations</b></p>\n<div id=\"calcs\" class=\"notes\"></div>\n</div>\n\n\n<div class='section'>\n<p><b>Links</b><img style=\"padding:25px\" src=\"/files/images/heatwebsl.png\" width=\"200px\" align=\"right\"></p>\n<div id=\"mylink\" class=\"notes\"></div>\n<div id=\"links\" class=\"notes\"></div>\n</div>\n</form>","output":"str","x":1460,"y":360,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"2d80cb17.8a0d54","type":"function","z":"cce2bfaa.e5748","name":"","func":"\nmsg.section = msg.payload.section || null;\nmsg.title = msg.payload.title ||  null;\nmsg.obid = msg.payload.id ;\nmsg.type = msg.payload.type || \"wiki\"\n\nmsg.title = msg.title.replace(\"http://www.heatweb.co.uk/w/index.php?title=\",\"\");\nmsg.title = msg.title.replace(\"https://www.heatweb.co.uk/w/index.php?title=\",\"\");\n\nif (msg.payload.des) { msg.des = msg.payload.des.replace(/\\_/g,\" \"); }\nelse { msg.des = msg.title.replace(/\\_/g,\" \") + \" - \" + msg.section.replace(/\\_/g,\" \"); }\n\nif (msg.payload.type == \"heatwebcouk\") { \n    \n        \n    msg.url = decodeURIComponent(msg.payload.url); // \"https://heatweb.co.uk/\" + msg.title.replace(/ /g,\"-\") ;\n    //if (msg.section) msg.url += \"/\" + msg.section.replace(/ /g,\"-\") ;\n\n} else {\n    \n    msg.url = \"https://heatweb.co.uk/w/index.php?title=\" + msg.title.replace(/ /g,\"_\") + \"&printable=yes\";\n    if (msg.section) msg.url += \"#\" + msg.section.replace(/ /g,\"_\") ;\n\n}\n\n//<h2><span class=\"mw-headline\" id=\"Setting_up_MQTT_Broker_Permissions\"></span>Setting up MQTT Broker Permissions</h2>\n\nreturn msg;","outputs":1,"noerr":0,"x":490,"y":1780,"wires":[["c3728c16.faaeb"]]},{"id":"ff07a724.4bee18","type":"link out","z":"cce2bfaa.e5748","name":"","links":["46f26691.159bd8"],"x":1155,"y":660,"wires":[]},{"id":"2a501ff2.83e55","type":"link out","z":"cce2bfaa.e5748","name":"","links":["46f26691.159bd8"],"x":815,"y":1040,"wires":[]},{"id":"6e12432d.294abc","type":"http in","z":"cce2bfaa.e5748","name":"","url":"/ui/postdata","method":"post","upload":false,"swaggerDoc":"","x":330,"y":1420,"wires":[["a1b2721e.ba6b7","896da634.2b8468"]]},{"id":"dd2aeb53.8b4978","type":"http response","z":"cce2bfaa.e5748","name":"","statusCode":"","headers":{},"x":670,"y":1420,"wires":[]},{"id":"a1b2721e.ba6b7","type":"template","z":"cce2bfaa.e5748","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"This is the payload: {{payload}} !","output":"str","x":520,"y":1420,"wires":[["dd2aeb53.8b4978"]]},{"id":"896da634.2b8468","type":"debug","z":"cce2bfaa.e5748","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":510,"y":1360,"wires":[]},{"id":"be3da149.3d54c","type":"function","z":"cce2bfaa.e5748","name":"","func":"\nreturn msg;","outputs":1,"noerr":0,"x":690,"y":900,"wires":[["4f4d172d.8c1ee8"]]},{"id":"4f4d172d.8c1ee8","type":"template","z":"cce2bfaa.e5748","name":"graph","field":"payload.body","fieldType":"msg","format":"html","syntax":"mustache","template":"<script src=\"https://cdn.plot.ly/plotly-latest.min.js\"></script>\n     \n<script>\n\nfunction saveG() { \n            \n            //clearTimeout(myTimeout);\n            //alert(\"ok\");\n            \n            // var imgh = \"1200px\"; // ($(\"#graph-id\").css(\"height\")) || 500;\n            // var imgw = \"2300px\"; // ($(\"#graph-id\").css(\"width\")) || 1300;\n            var imgh = ($(\"#graph-id\").css(\"height\")) || 500;\n            var imgw = ($(\"#graph-id\").css(\"width\")) || 1300;\n            \n            imgh = 2 * parseInt(imgh.replace(\"px\",\"\"));\n            imgw = 2 * parseInt(imgw.replace(\"px\",\"\"));\n            \n            //var img_svg = Plotly.d3.select('#svg-export');\n            Plotly.toImage('graph-id',{format:'jpeg',height:imgh,width:imgw})\n                 .then(\n                         function(url)\n                     {\n                        \n                        // url = decodeURIComponent(url); //data:image/svg\n                        // url = url.substr(url.indexOf(\"<svg\"));\n                        \n                        console.log(url);\n                        \n                        var nn=\"mygraph\";\n\n                        var myob = {};\n                        myob.value = url;\n                        myob.id = nn;\n                        myob.filename = nn + \".jpeg\";\n                        //myob.type = \"image/svg+xml\";\n                        myob.type = \"image/jpeg\";\n                        \n                        try { parent.setObject(nn, myob); } catch {}\n                        \n                        \n                        \n                        myob = null;\n\n                        // $(\"#svgtext\").val(url);\n                        // $(\"#svgfile\").val(\"/files/graphs/graph_\" + (new Date().getTime()) + \".svg\");\n\n                        // var tit = document.getElementsByClassName(\"gtitle\")[0];\n                        // if (tit) {\n                        //     var tittxt = tit.innerHTML;\n                        //     if (tittxt !==\"\") { $(\"#svgfile\").val(\"/files/graphs/\" + tittxt.replace(/ /g,\"_\") + \"_\" + (new Date().getTime()) + \".svg\");}\n                        // }\n\n                       \n                        \n                        // $(\"#nextform\").submit(); \n                         \n                         \n                     }\n                 )\n            \n           \n           \n            \n        } \n\n\n    var jsonUrl = \"/api/graphdata?show=local.phex1.dat.tH\";  // \"/parts/test.json\"; //\n\n\n\njsonUrl = \"/api/graphdata?show=KkkCpGTv///dat/tF&title=hello,legend\";\n\n\n    Plotly.d3.json(jsonUrl, function(err, fig) {\n        // assuming json is formatted as { \"data\": [/* */], \"layout\": {/* */} }\n       var config = {responsive: true, editable: true}\n        Plotly.plot('graph-id', fig.data, fig.layout, config);\n      });\n     \n       \n      </script>\n  \n  <!--<div id=\"graph-id\" class=\"gstyle\"></div>-->\n   <div id=\"graph-id\" style=\"width:100%; height:calc(100vh - 50px);\"></div> \n\n<!--<button onClick=\"saveG()\">save</button>-->\n\n<script>\nconst myTimeout = setTimeout(saveG, 3000);\n\n</script>","output":"str","x":950,"y":900,"wires":[["3641b220.fd838e"]]},{"id":"7b31c66b.458618","type":"comment","z":"cce2bfaa.e5748","name":"PDF stuff","info":"https://codepen.io/blikblum/pen/YboVNq?editors=1010\n\nhttps://www.youtube.com/watch?v=MsFgGNa-HMg","x":1140,"y":1520,"wires":[]},{"id":"773e33e1.ed2c6c","type":"http in","z":"cce2bfaa.e5748","name":"","url":"/ui/pdf","method":"post","upload":false,"swaggerDoc":"","x":470,"y":1560,"wires":[["2e7fd0f4.5356f","79de0785.17cb38"]]},{"id":"2e6117d8.6cd5f8","type":"http response","z":"cce2bfaa.e5748","name":"","statusCode":"","headers":{},"x":830,"y":1560,"wires":[]},{"id":"79de0785.17cb38","type":"template","z":"cce2bfaa.e5748","name":"","field":"payload","fieldType":"msg","format":"html","syntax":"mustache","template":"<script src=\"pdfkit.standalone.js\"></script>\n    <script src=\"blob-stream.js\"></script>\n    <script src=\"svg-to-pdfkit.js\"></script>\n\n<div>PDF Output <button onclick=\"download()\">Download</button></div>\n<iframe width=\"100%\" height=\"800px\"></iframe>\n\n<script>\n    \n\nvar filesLoaded = 0;\n\nvar files = {\n  img1: {\n    url: \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  },\n  img2: {\n    url: \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  },\n  img3: {\n    url:\n      \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  }\n};\n\nvar doc = new PDFDocument({\n  layout: \"landscape\",\n  size: [311.83, 595.28],\n  margins: {\n    top: 0,\n    bottom: 0,\n    left: 0,\n    right: 0\n  }\n});\nvar stream = doc.pipe(blobStream());\n\nfunction loadedFile(xhr) {\n  for (var file in files) {\n    if (files[file].url === xhr.responseURL) {\n      files[file].data = xhr.response;\n    }\n  }\n  filesLoaded += 1;\n  if (filesLoaded == Object.keys(files).length) {\n    showPDF();\n  }\n}\n\nfor (var file in files) {\n  files[file].xhr = new XMLHttpRequest();\n  files[file].xhr.onreadystatechange = function() {\n    if (this.readyState == 4 && this.status == 200) {\n      loadedFile(this);\n    }\n  };\n  files[file].xhr.responseType = \"arraybuffer\";\n  files[file].xhr.open(\"GET\", files[file].url);\n  files[file].xhr.send(null);\n}\n\nfunction showPDF() {\n    \n    svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 540 320\">\n <defs>\n  <path id=\"Triangle\" d=\"M120 20 L 220 193.205 L 20 193.205 Z\" stroke=\"red\" fill=\"url(#radial)\"/>\n  <path id=\"Maths\" d=\"M250,50C380,50 350,150 480,150\" stroke=\"green\" fill=\"none\"/>\n  <path id=\"Chemistry\" transform=\"translate(-200,0) scale(1.5)\" d=\"M250,50C380,50 350,150 480,150\" stroke=\"blue\" fill=\"none\"/>\n  <path id=\"Path\" d=\"M20,240 C40,280 60,280 200,230 A100 100 0 0 1 300,260 L 330,280 Q 400,320 500,200\" stroke=\"orange\" fill=\"none\"/>\n  <linearGradient id=\"linear\" x1=\"0\" x2=\"1\" gradientUnits=\"objectBoundingBox\">\n    <stop stop-color=\"green\" offset=\"0\"/>\n    <stop stop-color=\"red\" offset=\"1\"/>\n  </linearGradient>\n  <radialGradient id=\"radial\" cx=\"0.5\" cy=\"0.6667\" r=\"0.6\" gradientUnits=\"objectBoundingBox\">\n    <stop stop-color=\"orange\" offset=\"0.2\"/>\n    <stop stop-color=\"yellow\" offset=\"1\"/>\n  </radialGradient>\n  <pattern id=\"pattern\" width=\"4\" height=\"4\" patternUnits=\"userSpaceOnUse\">\n    <rect width=\"4\" height=\"4\"/>\n    <rect width=\"2\" height=\"2\" fill=\"red\"/>\n    <rect x=\"2\" y=\"2\" width=\"2\" height=\"2\" fill=\"red\"/>\n  </pattern>\n </defs>\n <rect x=\"2%\" y=\"2%\" width=\"96%\" height=\"96%\" fill=\"url(#linear)\" fill-opacity=\"0.3\" stroke=\"orange\" stroke-width=\"2\" stroke-dasharray=\"5 2 2 2 5 5\"/>\n <use xlink:href=\"#Triangle\"/>\n <use xlink:href=\"#Maths\"/>\n <use xlink:href=\"#Chemistry\"/>\n <use xlink:href=\"#Path\"/>\n <text textLength=\"600px\" lengthAdjust=\"spacingAndGlyphs\" fill=\"url(#pattern)\">\n  <textPath xlink:href=\"#Triangle\" font-size=\"20\" font-family=\"serif\" font-weight=\"bold\" textLength=\"600px\" lengthAdjust=\"spacingAndGlyphs\">Text adjusted around a triangle</textPath>\n </text>\n <text font-family=\"sans-serif\">\n  <textPath xlink:href=\"#Maths\" font-size=\"30\" fill=\"blue\" text-anchor=\"middle\" startOffset=\"50%\">Maths x<tspan font-size=\"20\" baseline-shift=\"super\">2</tspan> + y<tspan font-size=\"20\" baseline-shift=\"super\">2</tspan> = z<tspan font-size=\"20\" baseline-shift=\"super\">2</tspan>!</textPath>\n  <textPath xlink:href=\"#Chemistry\" font-size=\"30\" fill=\"green\" text-anchor=\"middle\" startOffset=\"50%\">Chemistry 2H<tspan font-size=\"20\" baseline-shift=\"sub\">2</tspan> + O<tspan font-size=\"20\" baseline-shift=\"sub\">2</tspan> -> 2H<tspan font-size=\"20\" baseline-shift=\"sub\">2</tspan>O</textPath>\n  <textPath xlink:href=\"#Path\" font-size=\"30\" fill=\"purple\" dominant-baseline=\"middle\" text-anchor=\"middle\" startOffset=\"50%\">Text centered on a complex path</textPath>\n </text>\n</svg>`;\n\nSVGtoPDF(doc, svg,0,0);\n    \n    \n    \n  doc.rect(10, 10, 430, 20).fill(\"#000000\");\n  doc.rect(450, 10, 135, 20).fill(\"#000000\");\n\n  doc\n    .moveTo(10, 180)\n    .lineTo(430, 180)\n    .stroke();\n  doc\n    .moveTo(10, 240)\n    .lineTo(310, 240)\n    .stroke();\n  doc\n    .moveTo(10, 280)\n    .lineTo(310, 280)\n    .stroke();\n  doc\n    .moveTo(445, 10)\n    .lineTo(445, 300)\n    .dash(5)\n    .stroke();\n\n  // pass loaded ArrayBuffer data instead of a path to image\n  doc.image(files.img1.data, 455, 80, { fit: [80, 80] });\n  doc.image(files.img2.data, 455, 200, { fit: [80, 80] });\n  doc.image(files.img3.data, 350, 200, { fit: [80, 80] });\n\n  doc.fontSize(17);\n  doc.fillColor(\"white\").text(\"TEST1\", 12, 13);\n  doc.fillColor(\"white\").text(\"TEST2\", 452, 13);\n\n  doc.end();\n}\n\nconst a = document.createElement(\"a\");\ndocument.body.appendChild(a);\na.style = \"display: none\";\n\nlet blob;\n\nfunction download() {\n  if (!blob) return;\n  var url = window.URL.createObjectURL(blob);\n  a.href = url;\n  a.download = 'test.pdf';\n  a.click();\n  window.URL.revokeObjectURL(url);\n}\n\nstream.on(\"finish\", function() {\n   // get a blob you can do whatever you like with\n  blob = stream.toBlob(\"application/pdf\");\n\n  const url = stream.toBlobURL('application/pdf');\n  const iframe = document.querySelector('iframe')\n  iframe.src = url;\n});\n\n</script>","output":"str","x":680,"y":1560,"wires":[["2e6117d8.6cd5f8"]]},{"id":"2e7fd0f4.5356f","type":"debug","z":"cce2bfaa.e5748","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":670,"y":1500,"wires":[]},{"id":"914a6004.bed52","type":"http in","z":"cce2bfaa.e5748","name":"","url":"/ui/pdf","method":"get","upload":false,"swaggerDoc":"","x":460,"y":1600,"wires":[["79de0785.17cb38"]]},{"id":"f7a10b50.21f588","type":"template","z":"cce2bfaa.e5748","name":"","field":"payload","fieldType":"msg","format":"html","syntax":"mustache","template":"<script src=\"pdfkit.standalone.js\"></script>\n    <script src=\"blob-stream.js\"></script>\n\n<div>PDF Output <button onclick=\"download()\">Download</button></div>\n<iframe width=\"100%\" height=\"800px\"></iframe>\n\n<script>\n    \n\nvar filesLoaded = 0;\n\nvar files = {\n  img1: {\n    url: \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  },\n  img2: {\n    url: \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  },\n  img3: {\n    url:\n      \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  }\n};\n\nvar doc = new PDFDocument({\n  layout: \"landscape\",\n  size: [311.83, 595.28],\n  margins: {\n    top: 0,\n    bottom: 0,\n    left: 0,\n    right: 0\n  }\n});\nvar stream = doc.pipe(blobStream());\n\nfunction loadedFile(xhr) {\n  for (var file in files) {\n    if (files[file].url === xhr.responseURL) {\n      files[file].data = xhr.response;\n    }\n  }\n  filesLoaded += 1;\n  if (filesLoaded == Object.keys(files).length) {\n    showPDF();\n  }\n}\n\nfor (var file in files) {\n  files[file].xhr = new XMLHttpRequest();\n  files[file].xhr.onreadystatechange = function() {\n    if (this.readyState == 4 && this.status == 200) {\n      loadedFile(this);\n    }\n  };\n  files[file].xhr.responseType = \"arraybuffer\";\n  files[file].xhr.open(\"GET\", files[file].url);\n  files[file].xhr.send(null);\n}\n\nfunction showPDF() {\n  doc.rect(10, 10, 430, 20).fill(\"#000000\");\n  doc.rect(450, 10, 135, 20).fill(\"#000000\");\n\n  doc\n    .moveTo(10, 180)\n    .lineTo(430, 180)\n    .stroke();\n  doc\n    .moveTo(10, 240)\n    .lineTo(310, 240)\n    .stroke();\n  doc\n    .moveTo(10, 280)\n    .lineTo(310, 280)\n    .stroke();\n  doc\n    .moveTo(445, 10)\n    .lineTo(445, 300)\n    .dash(5)\n    .stroke();\n\n  // pass loaded ArrayBuffer data instead of a path to image\n  doc.image(files.img1.data, 455, 80, { fit: [80, 80] });\n  doc.image(files.img2.data, 455, 200, { fit: [80, 80] });\n  doc.image(files.img3.data, 350, 200, { fit: [80, 80] });\n\n  doc.fontSize(17);\n  doc.fillColor(\"white\").text(\"TEST1\", 12, 13);\n  doc.fillColor(\"white\").text(\"TEST2\", 452, 13);\n\n  doc.end();\n}\n\nconst a = document.createElement(\"a\");\ndocument.body.appendChild(a);\na.style = \"display: none\";\n\nlet blob;\n\nfunction download() {\n  if (!blob) return;\n  var url = window.URL.createObjectURL(blob);\n  a.href = url;\n  a.download = 'test.pdf';\n  a.click();\n  window.URL.revokeObjectURL(url);\n}\n\nstream.on(\"finish\", function() {\n   // get a blob you can do whatever you like with\n  blob = stream.toBlob(\"application/pdf\");\n\n  const url = stream.toBlobURL('application/pdf');\n  const iframe = document.querySelector('iframe')\n  iframe.src = url;\n});\n\n</script>","output":"str","x":1140,"y":1560,"wires":[[]]},{"id":"a7a26a08.eb6a98","type":"comment","z":"cce2bfaa.e5748","name":"Blob from Data URL","info":"https://stackoverflow.com/questions/12168909/blob-from-dataurl\n\nfunction dataURItoBlob(dataURI) {\n  // convert base64 to raw binary data held in a string\n  // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this\n  var byteString = atob(dataURI.split(',')[1]);\n\n  // separate out the mime component\n  var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]\n\n  // write the bytes of the string to an ArrayBuffer\n  var ab = new ArrayBuffer(byteString.length);\n\n  // create a view into the buffer\n  var ia = new Uint8Array(ab);\n\n  // set the bytes of the buffer to the correct values\n  for (var i = 0; i < byteString.length; i++) {\n      ia[i] = byteString.charCodeAt(i);\n  }\n\n  // write the ArrayBuffer to a blob, and you're done\n  var blob = new Blob([ab], {type: mimeString});\n  return blob;\n\n}","x":1170,"y":1460,"wires":[]},{"id":"14619c1f.51d384","type":"template","z":"cce2bfaa.e5748","name":"EST Profile","field":"payload.body","fieldType":"msg","format":"html","syntax":"mustache","template":"<div id=\"graph-id\" style=\"width:100%; height:calc(100vh - 50px);\"></div> \n\n<script src=\"https://cdn.plot.ly/plotly-latest.min.js\"></script>\n     \n<script>\n\nfunction saveG() { \n            \n            //clearTimeout(myTimeout);\n            //alert(\"ok\");\n            \n            // var imgh = \"1200px\"; // ($(\"#graph-id\").css(\"height\")) || 500;\n            // var imgw = \"2300px\"; // ($(\"#graph-id\").css(\"width\")) || 1300;\n            var imgh = ($(\"#graph-id\").css(\"height\")) || 500;\n            var imgw = ($(\"#graph-id\").css(\"width\")) || 1300;\n            \n            imgh = 1.2 * parseInt(imgh.replace(\"px\",\"\"));\n            imgw = 1.2 * parseInt(imgw.replace(\"px\",\"\"));\n            \n            //var img_svg = Plotly.d3.select('#svg-export');\n            Plotly.toImage('graph-id',{format:'jpeg',height:imgh,width:imgw})\n                 .then(\n                         function(url)\n                     {\n                        \n                        // url = decodeURIComponent(url); //data:image/svg\n                        // url = url.substr(url.indexOf(\"<svg\"));\n                        \n                        console.log(url);\n                        \n                        var nn=\"est24\";\n\n                        var myob = {};\n                        myob.value = url;\n                        myob.id = nn;\n                        myob.filename = nn + \".jpeg\";\n                        //myob.type = \"image/svg+xml\";\n                        myob.type = \"image/jpeg\";\n                        myob.page = \"DHW Loads\";\n                        myob.text = \"The following graph shown the energy used for domestic hot water, for each hour of the day. This is the standard profile for domestic properties from the EST.\";\n                        \n                        try { parent.setObject(nn, myob); } catch {}\n                        \n                        \n                        \n                        myob = null;\n\n                        // $(\"#svgtext\").val(url);\n                        // $(\"#svgfile\").val(\"/files/graphs/graph_\" + (new Date().getTime()) + \".svg\");\n\n                        // var tit = document.getElementsByClassName(\"gtitle\")[0];\n                        // if (tit) {\n                        //     var tittxt = tit.innerHTML;\n                        //     if (tittxt !==\"\") { $(\"#svgfile\").val(\"/files/graphs/\" + tittxt.replace(/ /g,\"_\") + \"_\" + (new Date().getTime()) + \".svg\");}\n                        // }\n\n                       \n                        \n                        // $(\"#nextform\").submit(); \n                         \n                         \n                     }\n                 )\n            \n           \n           \n            \n        } \n\n\n    var jsonUrl = \"/api/graphdata?show=local.phex1.dat.tH\";  // \"/parts/test.json\"; //\n\n\n\njsonUrl = \"/api/graphdata?show=KkkCpGTv///dat/tF&title=hello,legend\";\n\n\n    // Plotly.d3.json(jsonUrl, function(err, fig) {\n    //     // assuming json is formatted as { \"data\": [/* */], \"layout\": {/* */} }\n    //   var config = {responsive: true, editable: true}\n    //     Plotly.plot('graph-id', fig.data, fig.layout, config);\n    //   });\n     \nvar trace1 = {\n  x: {{{x1}}},\n  y: {{{y1}}},\n  name: '{{{series1name}}}',\n  type: 'bar'\n};\n\nvar trace2 = {\n  x: ['giraffes', 'orangutans', 'monkeys'],\n  y: [12, 18, 29],\n  name: 'LA Zoo',\n  type: 'bar'\n};\n\n//var data = [trace1, trace2];\nvar data = [trace1];\n\nvar layout = {barmode: 'stack',\"margin\":{\"b\":60,\"l\":60,\"r\":20,\"t\":25},\"autosize\":true,\"showlegend\": true,  \"legend\": {\"orientation\": \"h\"}};\n\nPlotly.newPlot('graph-id', data, layout);\n      </script>\n  \n  <!--<div id=\"graph-id\" class=\"gstyle\"></div>-->\n   \n\n<!--<button onClick=\"saveG()\">save</button>-->\n\n<script>\nconst myTimeout = setTimeout(saveG, 2000);\n\n</script>","output":"str","x":930,"y":740,"wires":[["3641b220.fd838e","b771422c.aa078"]]},{"id":"ea750aba.beb938","type":"function","z":"cce2bfaa.e5748","name":"","func":"msg.est = [1.8,1.2,1,0.8,1.3,1.7,4.5,8.7,7.6,6.1,5.4,4.8,4.2,3.6,3.1,3.2,3.7,5.3,7.7,7.3,6.1,4.9,3.7,2.4];\n\nmsg.x1 = [];\n\nmsg.y1 = [];\n\n\nfor (let i = 0; i < 24; i++) {\n    \n    msg.x1.push(i+1);\n    msg.y1.push(parseFloat(msg.payload.kwhDHWEST) * msg.est[i] / 100);\n}\n\nmsg.x1 = JSON.stringify(msg.x1);\nmsg.y1 = JSON.stringify(msg.y1);\nmsg.intro = \"The chart below shows the hourly energy use for domestic hot water, based on EST profile.\"\nmsg.title = \"Hourly DHW Energy Use\";\nmsg.yaxis = \"kWh\";\nmsg.series1name = \"Primary kWh\";\n\nreturn msg;","outputs":1,"noerr":0,"x":690,"y":740,"wires":[["14619c1f.51d384"]]},{"id":"b771422c.aa078","type":"debug","z":"cce2bfaa.e5748","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.body","targetType":"msg","x":1170,"y":720,"wires":[]},{"id":"34ad924.442d56e","type":"template","z":"cce2bfaa.e5748","name":"Historical Modelling","field":"payload.body","fieldType":"msg","format":"html","syntax":"mustache","template":"<div id=\"graph-id\" style=\"width:100%; height:calc(50vh - 20px);\"></div> \n<div id=\"graph-id2\" style=\"width:100%; height:calc(50vh - 20px);\"></div> \n\n\n<script src=\"https://cdn.plot.ly/plotly-latest.min.js\"></script>\n     \n<script>\n\nfunction saveG() { \n            \n            //clearTimeout(myTimeout);\n            //alert(\"ok\");\n            \n            // var imgh = \"1200px\"; // ($(\"#graph-id\").css(\"height\")) || 500;\n            // var imgw = \"2300px\"; // ($(\"#graph-id\").css(\"width\")) || 1300;\n            var imgh = ($(\"#graph-id\").css(\"height\")) || 500;\n            var imgw = ($(\"#graph-id\").css(\"width\")) || 1300;\n            \n            imgh = 1.5 * parseInt(imgh.replace(\"px\",\"\"));\n            imgw = 1.5 * parseInt(imgw.replace(\"px\",\"\"));\n            \n            //var img_svg = Plotly.d3.select('#svg-export');\n            Plotly.toImage('graph-id',{format:'jpeg',height:imgh,width:imgw})\n                 .then(\n                         function(url)\n                     {\n                       \n                        \n                        console.log(url);\n                        \n                        var nn=\"loads2020\";\n\n                        var myob = {};\n                        myob.value = url;\n                        myob.id = nn;\n                        myob.filename = nn + \".jpeg\";\n                        myob.page = \"Historical Modelling\";\n                        //myob.type = \"image/svg+xml\";\n                        myob.type = \"image/jpeg\";\n                        myob.text = \"The following chart shows the estimated loads for 2020 using historical degree day data.\";\n                        \n                        try { parent.setObject(nn, myob); } catch {}\n                        \n                        myob = null;\n                         \n                     }\n                 )\n            \n            Plotly.toImage('graph-id2',{format:'jpeg',height:imgh,width:imgw})\n                 .then(\n                         function(url)\n                     {\n                       \n                        \n                        console.log(url);\n                        \n                        var nn=\"loads2021\";\n\n                        var myob = {};\n                        myob.value = url;\n                        myob.id = nn;\n                        myob.filename = nn + \".jpeg\";\n                        myob.page = \"Historical Modelling\";\n                        //myob.type = \"image/svg+xml\";\n                        myob.type = \"image/jpeg\";\n                        myob.text = \"The following chart shows the estimated loads for 2021 using historical degree day data.\";\n                        \n                        try { parent.setObject(nn, myob); } catch {}\n                        \n                        myob = null;\n                         \n                     }\n                 )\n            \n           \n           \n            \n        } \n\n\n\n\n//var data = [trace1, trace2];\nvar data = {{{data}}};\n\nvar layout = {\"barmode\": 'stack',\"margin\":{\"b\":60,\"l\":60,\"r\":20,\"t\":25},\"autosize\":true,\"bargap\":0,\"showlegend\": true,  \"legend\": {\"orientation\": \"h\"}};\n\nPlotly.newPlot('graph-id', data, layout);\n    \n \nvar data2 = {{{data2}}};\n\n\nPlotly.newPlot('graph-id2', data2, layout);\n   \nconst myTimeout = setTimeout(saveG, 4000);\n\n</script>","output":"str","x":910,"y":840,"wires":[["3641b220.fd838e"]]},{"id":"3d915fb2.148b4","type":"function","z":"cce2bfaa.e5748","name":"","func":"msg.est = [1.8,1.2,1,0.8,1.3,1.7,4.5,8.7,7.6,6.1,5.4,4.8,4.2,3.6,3.1,3.2,3.7,5.3,7.7,7.3,6.1,4.9,3.7,2.4];\n\nmsg.hourload = {};\n\nvar bn,bout;\nvar primHSource=\"\";\nvar hout=0;\n\nmsg.notes=\"\";\n\n\nvar running = -1;\n\nvar check1 = \"ok\";\nvar check2 = \"ok\";\n\nvar ddays = flow.get(\"ddays\");\n\n\nvar x1 = [];\nvar y1dhw = [];\nvar y1ch1 = [];\nvar y1ch2 = [];\n\nvar y2dhw = [];\nvar y2ch1 = [];\nvar y2ch2 = [];\n\nvar oot = [];\nvar oot2 = [];\n\nvar ootoot = ['Day', 'DHW', 'CHGreen', 'CHRed'];\noot.push(ootoot);\noot2.push(ootoot);\n\nfor (var dd in ddays) {\n    \n   if(running<0 && ddays[dd][\"Date\"].indexOf(\"-01-01\")>-1)  { running = 0; }\n       \n    if (running>-1) {\n    \n        x1.push(running);\n    \n        var dhw = parseFloat(msg.payload.kwhDHWEST);\n        var ch2 = ddays[dd][\"HDD \"+msg.payload.baseTemp] * parseFloat(msg.payload.kwhCH) / parseFloat(msg.payload.dDaysPeak);\n        var ch1 = 0;\n        \n        if (msg.payload.ASHPkWPeak) { \n            \n            var ASHPkWh = 24 * parseFloat(msg.payload.ASHPkWPeak);\n            \n            ch1 = Math.min(ASHPkWh - dhw, ch2);\n            \n            ch2 = Math.max(0, (ch2 - ch1)); \n            \n        }\n        \n        if (running>364) { \n            \n            // ootoot = [running-364, dhw,ch1,ch2];\n            // oot2.push(ootoot); \n            \n            y1dhw.push(dhw);\n            y1ch1.push(ch1);\n            y1ch2.push(ch2);\n            \n        }\n        else { \n            \n            // ootoot = [running, dhw,ch1,ch2];\n            // oot.push(ootoot); \n            \n            \n            y2dhw.push(dhw);\n            y2ch1.push(ch1);\n            y2ch2.push(ch2);\n            \n            \n        }\n       \n        running++;\n        if (running>728) { break; }\n        \n     } \n     \n    \n}\n\n\nmsg.arrayarray = JSON.stringify(oot);\nmsg.arrayarray2 = JSON.stringify(oot2);\n\n\nmsg.intro = \"The chart below shows the hot water and central heating demands over 2020 and 2021.\"\n\nmsg.title = \"2020 Load Analysis\";\nmsg.title2 = \"2021 Load Analysis\";\n\nmsg.yaxis = \"kWh\";\n\nmsg.series1name = \"Degree Days\";\nmsg.series2name = \"Negative Energy\";\n\n     \nvar trace1 = {\n  x: x1,\n  y: y1dhw,\n  name: 'DHW',\n  type: 'bar'\n};\n\nvar trace2 = {\n  x: x1,\n  y: y1ch1,\n  name: 'CH1',\n  type: 'bar'\n};\n\nvar trace3 = {\n  x: x1,\n  y: y1ch2,\n  name: 'CH2',\n  type: 'bar'\n};\n\n\nvar data = [trace1,trace2,trace3];\nmsg.data = JSON.stringify(data);\n\n     \nvar trace4 = {\n  x: x1,\n  y: y2dhw,\n  name: 'DHW',\n  type: 'bar'\n};\n\nvar trace5 = {\n  x: x1,\n  y: y2ch1,\n  name: 'CH1',\n  type: 'bar'\n};\n\nvar trace6 = {\n  x: x1,\n  y: y2ch2,\n  name: 'CH2',\n  type: 'bar'\n};\n\nvar data2 = [trace4,trace5,trace6];\nmsg.data2 = JSON.stringify(data2);\n\n\nreturn msg;","outputs":1,"noerr":0,"x":690,"y":840,"wires":[["34ad924.442d56e"]]},{"id":"e15a2b7e.19b6f8","type":"template","z":"cce2bfaa.e5748","name":"Form Generator","field":"payload.body","fieldType":"msg","format":"html","syntax":"plain","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js\"></script>\n<!--https://www.sitepoint.com/basic-jquery-form-validation-tutorial/-->\n\n<script src=\"https://unpkg.com/mustache@latest\"></script>\n\n\n\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n\n<script src=\"https://cdn.ckeditor.com/ckeditor5/34.0.0/inline/ckeditor.js\"></script>\n\n\n<style>\n    \n  \n    .jexcel_content {\n        font-size: 14px;\n    }\n    \n    .jexcel {\n        white-space: normal;\n    }\n\n\n.mybutt {\n    padding-left: 6px;\n    padding-right: 6px;\n    padding-top: 4px;\n    padding-bottom: 4px;\n    margin-right: 3px;\n    font-size: 14px;\n    border-radius: 4px;\n    cursor: pointer;\n    background-color: #a4eba4;\n    border-color: #4aa55a;\n    border: solid;\n    border-width: 1px;\n    box-shadow: 2px 2px 3px 1px rgb(0 0 0 / 28%);\n}\n.mybutt:hover {\n  background-color: #dcffdc;\n}\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\ntextarea.form-control {\n    font-size: 0.9rem;\n}\n\n.outputbox {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #ffffff;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.cframe {\n    border-radius: 0.25rem;\n    margin: 0px 0px 20px 0px;\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 3px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\nvar a = new Date();\nvar qdata;\nvar calculated = {};  calculated.objects = {};\nvar hasFocus;\nvar currentSection;\nvar inputsOut;\nvar inputString;\nvar calcsString;\nvar objects={}; \nvar sheets = {};\nvar sheetdata = {};\nvar initsheets;\n\n\t$(document).ready(function(e) {\n    \n        // $(\"form[ajax=true]\").submit(function(e) {\n            \n        //     //alert(\"submit\");\n            \n        //     e.preventDefault();\n        \n             \n            //var urlParams = new URLSearchParams(window.location.search);\n            //if (urlParams.get('display')) { loadstring = \",,\" + urlParams.get('display'); }\n\n            calculated[\"jsonQ\"] = \"hndesign\";\n\n            var urlParams = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParams) {\n                \n                calculated[urlParams[upa].split(\"=\")[0]] = decodeURIComponent(urlParams[upa].split(\"=\")[1]);\n                \n            }\n            \n            \n            \n            var form_data = {};\n            var form_url = \"/ui/qdata/\" + calculated[\"jsonQ\"];\n            var form_target = $(this).attr(\"target\") || \"result\";\n            var ftarget = \"#\" + form_target;\n            var form_method = \"GET\";\n            \n        //     $(\"#loadingimg\").show();\n            \n            $.ajax({\n                url: form_url, \n                type: form_method,      \n                data: form_data,     \n                cache: false,\n                success: function(results){   \n                    \n                    qdata = results;\n                    //qdata = JSON.parse(returnhtml);\n                    console.log(qdata);\n                   \n                    //if(urlParams['nBuildings']) { runCalcs(); runCalcs();  }\n                    runCalcs(); \n                    runCalcs();\n                    \n                    document.getElementById(\"formName\").innerHTML = qdata.title || \"Unamed Form\"; //JSON.stringify(qdata) ;\n                    \n                    // document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n                    \n                    // for (var sht in initsheets) {  initSheet(initsheets[sht]);   }\n                    \n                    // validform();\n                                  \n                }           \n            });    \n            \n        // });\n        \n      \n        \n    });\n\n\n    \nfunction tosvg(obid) {\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.svg\";\n    if (nn.indexOf(\".svg\")<0) { nn = nn + \".svg\"; }\n    \n    download( objects[obid].value, nn, \"image/svg+xml\")\n}\n  \n function jpegDownload(obid){\n\t    \n\t    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n        if (nn===null) { return(null); }\n        nn = nn || \"download.jpeg\";\n        if (nn.indexOf(\".jpeg\")<0) { nn = nn + \".jpeg\"; }\n        \n        var byteString = atob(objects[obid].value.split(',')[1]);\n        var mimeString = objects[obid].value.split(',')[0].split(':')[1].split(';')[0]\n\n        \n        // write the bytes of the string to an ArrayBuffer\n          var ab = new ArrayBuffer(byteString.length);\n        \n          // create a view into the buffer\n          var ia = new Uint8Array(ab);\n        \n          // set the bytes of the buffer to the correct values\n          for (var i = 0; i < byteString.length; i++) {\n              ia[i] = byteString.charCodeAt(i);\n          }\n        \n        download( ia , nn, mimeString)\n\t}\n\t\nfunction topdf(obid) {\n    \n    if (!objects[obid]) { return null; }\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.pdf\";\n    if (nn.indexOf(\".pdf\")<0) { nn = nn + \".pdf\"; }\n    \n    var headed = document.getElementById(\"headed\").innerHTML;\n    headed = headed.substr(headed.indexOf(\"<g\"));\n    headed = headed.substr(0,headed.lastIndexOf(\"</g>\")+4);\n    \n    var svgoot = objects[obid].value;\n    svgoot = svgoot.substr(svgoot.indexOf(\"<svg\"));\n    \n    var lg = svgoot.indexOf(\"<g\");\n    svgoot = svgoot.substr(0,lg) + '<g transform=\"translate(0,40)\">' + svgoot.substr(lg);\n    \n    lg = svgoot.lastIndexOf(\"</g>\")+4;\n    svgoot = svgoot.substr(0,lg) + \"</g>\" + headed + svgoot.substr(lg);\n    \n    var tits = {\"title\":\"Heatweb Heat Network Designer\",\"subtitle\":obid,\"pn\":\"1\",\"pc\":\"1\"}\n    svgoot = Mustache.render(svgoot, tits);\n    \n    //alert(svgoot);\n            $(\"#svgtext\").val(svgoot);\n            $(\"#svgfile\").val(nn);  //  + (new Date().getTime()) +\n            \n            $(\"#nextform\").submit(); \n            \n         \n}\n\nfunction topdf2(obid) {\n    \n    // without headed notepaper\n    \n    if (!objects[obid]) { return null; }\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.pdf\";\n    if (nn.indexOf(\".pdf\")<0) { nn = nn + \".pdf\"; }\n    \n    var svgoot = objects[obid].value;\n    svgoot = svgoot.substr(svgoot.indexOf(\"<svg\"));\n    \n    \n    \n    \n    //alert(svgoot);\n            $(\"#svgtext\").val(svgoot);\n            $(\"#svgfile\").val(nn);  //  + (new Date().getTime()) +\n            \n            $(\"#nextform\").submit(); \n            \n         \n}\n\n\n\n\n\nfunction initSheet(id) {\n\n    console.log(\"initSheet \" + id);\n    console.log(sheetdata);\n    \n    var shid = 'sheet-' + id;\n    var sdata = sheetdata[id];\n    \n    \n\n    try {\n    \n        document.getElementById(shid).innerHTML = \"\";\n        \n        sheets[id] = jspreadsheet(document.getElementById(shid), {\n            data: sdata.data,\n            columns: sdata.columns,\n            onchange: function(instance, cell, x, y, value) {\n                \n                console.log(value);\n                getSheetData(id);\n            },\n            updateTable:function(instance, cell, col, row, val, label, cellName) {\n               \n                //console.log(instance);\n                //console.log(val);\n                \n            },\n            columnSorting:false\n        });\n\n    } catch {}\n}\n\nfunction getSheetData(id) {\n    \n    \n    //alert(id);\n    \n    //console.log(sheets[id].getData());\n    \n    sheetdata[id].data = sheets[id].getData();\n    console.log(sheetdata);\n    \n    var oots = \"\";\n    for (var row in sheetdata[id].data) {\n       for (var c in sheetdata[id].data[row]) {\n           \n           var val = \"\" + (sheetdata[id].data[row][c] || \"\");\n           val = val.replace(/ /g,\"_\")\n           oots += val + \",\";\n        } \n        oots += \" \";\n    }\n    \n    oots = oots.substr(0, oots.length - 2);\n    console.log(oots);\n    \n    returncalc(id,oots)\n    \n    \n}\n\n\nfunction getObject(id) {\n    \n  \n    return (objects[id]||null);\n    \n}\n\n\nfunction setObject(id,value) {\n    \n\n    try { objects[id] = value; }\n    catch {}\n}\n\t\nfunction returncalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).value = value; }\n    catch {\n        \n        try { calculated[id] = value; }\n        catch {}\n    }\n    \n}\n\nfunction suggestcalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).placeholder = value + \" ... please confirm\"; }\n    catch {}\n}\n\t\nfunction parseQuestions(qdata) {\n    \n    console.log(qdata);\n    console.log(calculated);\n    \n    var linkstxt=\"\";\n    if (qdata.links) {\n        for (var lnk in qdata.links) {\n            linkstxt += (linkstxt!==\"\"?\"<br>\":\"\") + '<a href=\"' + qdata.links[lnk].src + '\" target=\"_blank\">' + (qdata.links[lnk].title||qdata.links[lnk].src) + '</a>';\n        }\n        \n    }\n    document.getElementById(\"links\").innerHTML = linkstxt ; //JSON.stringify(qdata) ;\n    \n    \n    inputsOut = '<input id=\"jsonQ\" name=\"jsonQ\" value=\"' + calculated[\"jsonQ\"] + '\" class=\"form-control\" type=\"hidden\">';\n                    \n    \n    inputsOut += '<table class=\"table\">';\n    \n    inputString = \"jsonQ=\" + calculated[\"jsonQ\"];  // data source for form is fixed\n    \n    hasFocus = null;\n    currentSection = null;\n    initsheets = [];\n    \n    var ootoot = \"\";\n    for (var s in qdata[\"sections\"]) {\n        console.log(s);\n        console.log(qdata.sections[s]);\n        \n        var oot = \"\";\n        var ootcount=0;\n        \n        //oot += \"<div class='section'><h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        oot += \"<h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        \n        \n        \n        for (var q in qdata.sections[s].questions) {\n            \n            \n            var qif = qdata.sections[s].questions[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n            var v=\"\";\n            if (calculated[qdata.sections[s].questions[q].id]) { v= calculated[qdata.sections[s].questions[q].id] ; }\n            else if (qdata.sections[s].questions[q].value) { v= qdata.sections[s].questions[q].value ; }\n            \n            if (v!==\"\") { qdata.sections[s].questions[q].value = v; }    // save answers back into json.\n            \n            \n            if(goq) {\n                \n                var calcfr = \"\";\n                if (qdata.sections[s].questions[q].calculator) { calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].questions[q].calculator + '?field=' + qdata.sections[s].questions[q].id + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].questions[q].calculatorStyle ? qdata.sections[s].questions[q].calculatorStyle:'width:100%; height:300px;') + '\"></iframe>'}\n            \n            \n                if (v!==\"\") { \n                    inputsOut += \"<tr>\";  \n                    \n                    var cOs1 = \"\";  var cOs2 = \"\";\n            \n                    if (document.getElementById(\"hideID\").checked!==true) {\n                        cOs2 = \" <small>[<i>\" + qdata.sections[s].questions[q].id + \"</i>]</small>\";  \n                    }\n                    \n                    inputsOut += '<td width=\"40%\">' + (qdata.sections[s].questions[q].title||qdata.sections[s].questions[q].id) + cOs2 + \"</td>\";\n                    \n                    var vs1=\"\"; var vs2=\"\";\n                    if((\"\"+v).indexOf(\",\") > -1) { vs1=\"<small>\"; vs2=\"</small>\"; }\n                    if((\"\"+v).indexOf(\"&\") > -1) { vs1=\"<small style='width:400px; word-wrap:break-word; display:inline-block;'>\"; vs2=\"</small>\"; }\n                    \n                    \n                    inputsOut +=  ('<td align=\"right\">' + vs1 + v + vs2 + \"</td>\").replace(/\\, /g,\"<br>\").replace(/\\,/g,\", \");\n                    inputsOut +=  '<td width=\"14%\">' + (qdata.sections[s].questions[q].units||\"\") + \"</td></tr>\\n\";\n                    \n                    inputString += (inputString!==\"\"?\"&\":\"\") + qdata.sections[s].questions[q].id + \"=\" + encodeURIComponent(v);\n                }\n            \n                var isDisplayed = false;\n            \n                if (hasFocus && document.getElementById(\"oneQ\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">'; }\n            \n                else if (v!==\"\") { \n                    \n                    if (document.getElementById(\"hideDone\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">';   }\n                    else {  oot += '<div class=\"question\" style=\"background-color: #d2efd2;\">'; ootcount++; isDisplayed=true; }\n                    \n                } else { oot += '<div class=\"question\">'; ootcount++; isDisplayed=true; if (!hasFocus) { hasFocus = qdata.sections[s].questions[q].id;  currentSection = qdata.sections[s].title;  } }\n                \n                \n                //oot += \"<div class='qtext'>\" + qdata.sections[s].questions[q].title + '</div>';\n                oot += '<label for=\"' + qdata.sections[s].questions[q].id + '\" class=\"qtext\">' + (qdata.sections[s].questions[q].question||qdata.sections[s].questions[q].title) + '</label>';\n                \n                if (calcfr!==\"\") { oot += \"\\n\" + calcfr + \"\\n\"; }\n                \n                if (qdata.sections[s].questions[q].notes) { oot += '<div class=\"notes\">'  + convertLinks(Mustache.render(qdata.sections[s].questions[q].notes, calculated)) + '</div>'; }\n                \n                if (qdata.sections[s].questions[q].type == \"sheet\") {\n                    \n                    oot += '<br><div id=\"sheet-' + qdata.sections[s].questions[q].id + '\">';\n                \n                    oot += '<span onclick=\"initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ')\"><small>Load Sheet</small></span> ';\n                    \n                    oot += '</div><br><br>';\n                    \n                    //oot += '<script>initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ');</scrip' + 't> ';\n                    //var myTimeout = setTimeout(initSheet(qdata.sections[s].questions[q].id), 1000);\n                    if (isDisplayed) { initsheets.push(qdata.sections[s].questions[q].id); }\n                \n                    var shob = {};\n                    shob['columns'] = qdata.sections[s].questions[q].columns;\n                    shob['data'] = qdata.sections[s].questions[q].default;\n                    \n                    if((\"\"+v)!==\"\") {\n                        \n                        shob['data']=[];\n                        var vv = v.replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                        var lns = vv.split(\", \");\n                        for (var lnsv in lns) {\n                            shob['data'].push(lns[lnsv].split(\",\"));\n                        }\n                    }\n                    \n                    sheetdata[qdata.sections[s].questions[q].id] = shob;\n                    \n                }\n                \n                \n                \n                if (qdata.sections[s].questions[q].type==\"html\") {\n                    \n                    oot += '<br><br><div class=\"form-control htmlinput\" style=\"height:fit-content\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    oot += decodeURIComponent('' + v + '')\n                    oot += '</div>';\n                \n                }\n                \n                \n                oot += '<table width=\"100%\"><tr><td width=\"80%\">';\n                \n                if (qdata.sections[s].questions[q].jsonQ) {\n                    \n                    \n                    oot += '<textarea class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    //oot += ('' + v + '').replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                    oot += decodeURIComponent('' + v + '')\n                    oot += '</textarea>';\n                    \n                } \n                \n                else if (qdata.sections[s].questions[q].type==\"html\") {\n                    \n                    oot += '';\n                    \n                   \n                \n                }\n                    \n                else if (qdata.sections[s].questions[q].type==\"boolean\") {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                      if (v==\"true\") { oot += '<option value=\"false\">No</option><option value=\"true\" selected>Yes</option>'; }\n                      else if (v==\"false\")  { oot += '<option value=\"false\" selected>No</option><option value=\"true\">Yes</option>'; }\n                      else  { oot += '<option value=\"\"></option><option value=\"false\">No</option><option value=\"true\">Yes</option>'; }\n                    oot += '</select>';\n                    \n                } else if (qdata.sections[s].questions[q].options) {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    if (v==\"\") { oot += '<option value=\"\"></option>'; }\n                    for (var opt in qdata.sections[s].questions[q].options) {\n                    \n                      var optobj = qdata.sections[s].questions[q].options[opt];\n                      \n                      \n                      if (v==optobj.value) { oot += '<option selected value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      else  { oot += '<option value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      \n                    }  \n                    oot += '</select>';\n                    \n                }  else {\n                \n                    oot += '<input id=\"' + qdata.sections[s].questions[q].id + '\" name=\"' + qdata.sections[s].questions[q].id + '\" class=\"form-control\" type=\"text\"';\n                    if (v!==\"\") { oot += (' value=\"' + v + '\"').replace(/\\%20/g,\" \").replace(/_/g,\" \"); }\n                    if (qdata.sections[s].questions[q].default) { \n                        \n                        oot += ' placeholder=\"' + Mustache.render(\"\"+qdata.sections[s].questions[q].default, calculated)  + \" \" + (qdata.sections[s].questions[q].units||\"\") + ' ... please confirm\"'; \n                        \n                    }\n                    oot += '>';\n                }\n                \n                oot += '</td><td valign=\"top\"><span class=\"qunits\">' + (qdata.sections[s].questions[q].units||\"\") + '</span></td></tr></table>';\n                \n                \n                \n                oot += '</div>\\n';\n            }\n        }\n    \n        oot += '<table width=\"100%\"><tr><td width=\"100%\" align=\"right\"><button class=\"mybutt\" type=\"submit\">Submit</button></td></tr></table>';\n\n        oot += \"</div>\\n\";\n       \n        \n        var outhtml = \"\";   \n        for (var q in qdata.sections[s].outputs) {\n            \n            var qif = qdata.sections[s].outputs[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n\n            if(goq && (calcsString||\"\")!==\"\") {\n                \n                var calcfr = \"\";\n                if (qdata.sections[s].outputs[q].url) { \n                    \n                    calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].outputs[q].url + (qdata.sections[s].outputs[q].url.indexOf(\"?\")>0?'':'?') + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].outputs[q].style ? qdata.sections[s].outputs[q].style:'width:100%; height:300px;') + '\"></iframe>'\n                    \n                    outhtml += '<div class=\"outputbox\">';\n                    outhtml += \"<table width='100%'><tr><td><b>\" + qdata.sections[s].outputs[q].title + \"</b></td>\\n\";\n                    \n                    if (qdata.sections[s].outputs[q].buttons) { \n                        \n                        outhtml += '<td align=\"right\">';\n                        for (var btn in qdata.sections[s].outputs[q].buttons) {\n                            \n                            outhtml += '<span class=\"mybutt\" onclick=\"' + qdata.sections[s].outputs[q].buttons[btn].onClick + '\">' + qdata.sections[s].outputs[q].buttons[btn].text + '</span> ';\n                        }\n                        outhtml += '</td>';\n                    }\n                    \n                    outhtml += '</tr></table><br>';\n                    \n                    outhtml += calcfr ; \n                    \n                    \n                    \n                    outhtml += \"</div>\\n\";\n                }\n            \n            }\n        }\n        \n        if (outhtml!==\"\") {\n            \n            //oot += '<div class=\"outputbox\">';\n            oot += outhtml;\n            //oot += \"</div>\\n\";\n        }\n        \n        \n        \n        \n        \n        if (document.getElementById(\"oneS\").checked==true && (currentSection != qdata.sections[s].title)) {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n        else if (ootcount>0) {  ootoot += \"<div class='section'>\" + oot; }\n        \n        else {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n    }\n    inputsOut +=  \"</table>\\n\";  \n    \n    return ootoot;\n}\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\n// console.log(looseJsonParse(\n//   \"{a:(4-1), b:function(){}, c:new Date()}\"\n// ))\n\nfunction runCalcs() {\n\n\n    calcsString = \"\";\n    \n    // run through form inputs and store current values into calculated.\n    var cells =  document.getElementsByClassName(\"form-control\");\n\tvar i;\n\tfor (i = 0; i < cells.length; i++) {\n\t\n\t    \n\t    \n\t\n\t\tcalcsOut += cells[i].value + \"<br>\\n\";\n        \n        if (\"\" + cells[i].value !== \"\") { \n            \n            if (isNaN(cells[i].value)) { \n                \n                if ((cells[i].classList+\" \").indexOf(\"htmlinput\")>-1) {     // && cells[i].classList.indexOf(\"ck\")>-1\n                    \n                    calculated[cells[i].id] = cells[i].innerHTML;\n                }\n                else {\n                    \n                    calculated[cells[i].id] = (cells[i].value);\n                \n                    if ((calculated[cells[i].id]+\" \").substr(0,1)==\"{\" || (calculated[cells[i].id]+\" \").substr(0,1)==\"[\") {    // detect objects in textboxes\n                        \n                        try  { calculated.objects[cells[i].id] = JSON.parse(calculated[cells[i].id]) } catch {  }\n                    }\n                \n                }\n               \n                \n            } else {\n                \n                calculated[cells[i].id] = parseFloat(cells[i].value);\n            }\n            \n            calcsString += \"&\" + cells[i].id + \"=\" + cells[i].value;\n        }\n\t}\n\t\n    var calcsOut = '<table class=\"table\">';\n    \n    //calculated.objects = objects;\n    \n    // ================== Sheet Custom Calculations\n    \n    \n    if (calculated['loadSchedule']) {\n        \n        console.log(\"Load Schedule = \" + calculated['loadSchedule']);\n        \n        \n            \n            var cv1 = calculated['loadSchedule'];\n            var cv = 0;\n            var np = 0;\n            var kwCHMax = 0;\n            \n            var ldata=[];\n            \n            if((\"\"+cv1)!==\"\") {\n                \n                var vv = (\"\"+cv1).replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                var lns = vv.split(\", \");\n                for (var lnsv in lns) {\n                    ldata.push(lns[lnsv].split(\",\"));\n                    \n                    cv = cv + parseFloat(lns[lnsv].split(\",\")[4])\n                    \n                    np = np + (parseFloat(lns[lnsv].split(\",\")[2]) * parseFloat(lns[lnsv].split(\",\")[4]));\n                    \n                    kwCHMax = kwCHMax + (parseFloat(lns[lnsv].split(\",\")[3]) * parseFloat(lns[lnsv].split(\",\")[4]));\n                    \n                    \n                }\n            }\n            \n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total Properties</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">properties</td></tr>\\n';\n            \n            calculated['nProperties'] = cv;\n            calcsString += \"&nProperties=\" + cv;\n            \n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total People</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + np + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">people</td></tr>\\n';\n            \n            calculated['nPeople'] = np;\n            calcsString += \"&nPeople=\" + np;\n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total of central heating outputs</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + kwCHMax + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">kW</td></tr>\\n';\n            \n            calculated['kwCHMax'] = kwCHMax;\n            calcsString += \"&kwCHMax=\" + kwCHMax;\n            \n        \n        \n    }\n    \n    \n    // ================================\n    \n    \n    for (var calc in (qdata[\"calculations\"]||[])) {\n        \n        console.log(calc);\n        console.log(qdata.calculations[calc]);\n        \n        var cif = qdata.calculations[calc].if || true;\n        var cift = Mustache.render(cif, calculated);\n        var goc = true;\n        try {\n          goc = looseJsonParse(cift); \n        }\n        catch(err) {\n          goc = false;\n        }\n        \n        if (goc) {\n            \n            var f = qdata.calculations[calc].function;\n            var ft = Mustache.render(f, calculated);\n            \n            calcsOut += \"<tr>\";  //<td>\" + qdata.calculations[calc].id + \"</td>\";\n            calcsOut += \"<td>\";\n            \n            var cOs1 = \"\";  var cOs2 = \"\";\n            \n            if (document.getElementById(\"hideID\").checked!==true) {\n                cOs2 = \" <small>[<i>\" + qdata.calculations[calc].id + \"</i>]</small>\";  \n            }\n            \n            calcsOut += cOs1 + (qdata.calculations[calc].title||qdata.calculations[calc].id) + cOs2 + \"</td>\";\n            \n            //calcsOut += f + \" = \";\n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small>\" + ft.replace(/\\,/g,\", \") + \"</small></td>\";   //\"<br>\\n\";\n            }\n            \n            var cv = \"\";\n            try {\n              cv = looseJsonParse(ft); //  looseJsonParse(\"{a:(4-1), b:function(){}, c:new Date()}\");\n            }\n            catch(err) {\n              \n            }\n             \n            \n            if (!isNaN(cv)) { cv = parseInt(cv*1000)/1000; }\n            \n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            \n            calcsOut +=  '<td width=\"14%\">' + (qdata.calculations[calc].units||\"\") + \"</td></tr>\\n\";\n            \n            calculated[qdata.calculations[calc].id] = cv;\n            calcsString += \"&\" + qdata.calculations[calc].id + \"=\" + cv;\n        }\n        \n    }\n    \n    calcsOut +=  \"</table>\\n\";\n    \n    // for (var calc in calculated) {\n        \n        \n    // }\n    \n    document.getElementById(\"calcs\").innerHTML = calcsOut; //JSON.stringify(qdata) ;\n    \n    // rebuild form\n    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"inputs\").innerHTML = inputsOut; //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"mylink\").innerHTML = '<a href=\"hndesign?' + inputString + '\" target=\"_blank\">Open/share design...</a>'; //JSON.stringify(qdata) ;\n    \n    if(document.getElementById(\"description\")) {  // work in progress - need to link to all\n        InlineEditor\n                .create( document.querySelector( '#description' ) )\n                .catch( error => {\n                    console.error( error );\n                } );\n        \n        for (var sht in initsheets) {  initSheet(initsheets[sht]);   }\n    }\n    \n    validform();\n                    \n}\n\n\nconst convertLinks = ( input ) => {\n\n  let text = input;\n  const linksFound = text.match( /(?:www|https?)[^\\s]+/g );\n  const aLink = [];\n\n  if ( linksFound != null ) {\n\n    for ( let i=0; i<linksFound.length; i++ ) {\n      let replace = linksFound[i];\n      if ( !( linksFound[i].match( /(http(s?)):\\/\\// ) ) ) { replace = 'http://' + linksFound[i] }\n      let linkText = replace.split( '/' )[2];\n      if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) }\n      if ( linkText.match( /youtu/ ) ) {\n\n        let youtubeID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://www.youtube.com/embed/' + youtubeID + '\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe></div>' )\n      }\n      else if ( linkText.match( /vimeo/ ) ) {\n        let vimeoID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://player.vimeo.com/video/' + vimeoID + '\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' )\n      }\n      else {\n        aLink.push( '<a href=\"' + replace + '\" target=\"_blank\">' + linkText + '</a>' );\n      }\n      text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] );\n    }\n    return text;\n\n  }\n  else {\n    return input;\n  }\n}\n\nfunction validform() {\n    \n    if(hasFocus && document.getElementById(hasFocus)) {\n        document.getElementById(hasFocus).focus();\n    }\n    \n    \n    \n// Initialize form validation on the registration form.\n  // It has the name attribute \"registration\"\n  $(\"form[name='qform']\").validate({\n    // Specify validation rules\n    rules: {\n      // The key name on the left side is the name attribute\n      // of an input field. Validation rules are defined\n      // on the right side\n    //   nProperties: {\n    //     required: true,\n    //     digits: true,\n    //     min: 1\n    //   },\n      lastname: \"required\",\n      email: {\n        required: true,\n        // Specify that email should be validated\n        // by the built-in \"email\" rule\n        email: true\n      },\n      password: {\n        required: true,\n        minlength: 5\n      }\n    },\n    // Specify validation error messages\n    messages: {\n      nProperties: \"Please enter a number.\",\n      lastname: \"Please enter your lastname\",\n      password: {\n        required: \"Please provide a password\",\n        minlength: \"Your password must be at least 5 characters long\"\n      },\n      email: \"Please enter a valid email address\"\n    },\n    // Make sure the form is submitted to the destination defined\n    // in the \"action\" attribute of the form when valid\n    submitHandler: function(form) {\n      //form.submit();\n      runCalcs();\n      //alert(\"hello\");\n    }\n  });\n}\n\n</script>\n\n\n<div class='section'>\n    \n    <table width=\"100%\"><tr>\n    <td valign=\"top\" width=\"70%\">\n        <div id=\"formName\" class=\"h1\"></div>\n        <a href=\"https://heatweb.co.uk/w/index.php?title=Heat_Network_Designer\" target=\"_blank\"><small>Wiki Help Page</small></a>\n    </td>\n    <td width=\"30%\">\n        <input type=\"checkbox\" id=\"oneS\" name=\"oneS\" checked> <small>One section at a time</small><br>\n        <input type=\"checkbox\" id=\"oneQ\" name=\"oneQ\" checked> <small>One question at a time</small><br>\n        <input type=\"checkbox\" id=\"hideDone\" name=\"hideDone\" checked> <small>Hide completed questions</small><br>\n        <input type=\"checkbox\" id=\"hideMaths\" name=\"hideMaths\" checked> <small>Hide maths equations</small><br>\n        <input type=\"checkbox\" id=\"hideID\" name=\"hideID\" checked> <small>Hide IDs</small>\n    </td>\n    </tr></table>\n</div>\n\n\n<form action=\"\" name=\"qform\" id=\"qform\">\n<div id=\"section1\"></div>\n\n<div class='section'>\n\n<table width=\"100%\"><tr><td><span class=\"mybutt\" onclick=\"onDownload()\">Download JSON</span> <span class=\"mybutt\" onclick=\"copyData()\">Copy Data</span> <span class=\"mybutt\" onclick=\"copylink()\">Copy Link</span> <span class=\"mybutt\" onclick=\"openlink()\">Open in New</span> <span class=\"mybutt\" onclick=\"shareTwitter()\">Tweet Design</span> <span class=\"mybutt\" onclick=\"tosvg('mysvg')\">SVG</span> <span class=\"mybutt\" onclick=\"topdf('mysvg')\">PDF</span></td><td align=\"right\"><button class=\"mybutt\" type=\"submit\">Submit</button></td></tr></table>\n\n\n\n\n</div>\n\n<script>\n\n\n    \n\n   function download(content, fileName, contentType) {\n       \n       if(!contentType) contentType = 'application/octet-stream';\n\t\t  const a = document.createElement(\"a\");\n\t\t  const file = new Blob([content], { type: contentType });\n\t\t  a.href = URL.createObjectURL(file);\n\t\t  a.download = fileName;\n\t\t  a.click();\n\t}\n\n\tfunction onDownload(){\n\t    \n\t    var jsonData = { \"url\": (window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString),\"calculated\": calculated, \"qdata\": qdata, \"objects\": objects };\n\t\tdownload(JSON.stringify(jsonData), \"hndesign.json\", \"text/plain\");\n\t}\n    \n   \n    \n    function copyData(){\n\t    \n\t    var jsonData = calculated ;\n\t\tnavigator.clipboard.writeText(JSON.stringify(jsonData));\n\t\talert(\"Data Copied to Clipboard\");\n\t}\n    \n    \n    function copylink() {\n        \n        //alert(window.location.href.split(\".svg\")[0]+\".svg&display=\"+displayed);\n        \n        navigator.clipboard.writeText(window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\"));  //\n        alert(\"Link Copied to Clipboard\");\n         \n    \n    }\n    \n    function openlink() {\n        \n        //alert(window.location.href.split(\".svg\")[0]+\".svg&display=\"+displayed);\n        \n        window.open(window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\"));  //\n        \n         \n    \n    }\n    \n    function shareTwitter() {       \n        \n        var text = \"My latest heat network design.\";\n        var url = window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\");\n        window.open('http://twitter.com/share?url='+encodeURIComponent(url)+'&text='+encodeURIComponent(text), '', 'left=0,top=0,width=550,height=450,personalbar=0,toolbar=0,scrollbars=0,resizable=0');\n\n    } \n\n</script>\n\n\n<div class='section'>\n<p><b>Inputs</b></p>\n<div id=\"inputs\" class=\"notes\"></div>\n</div>\n\n<div class='section'>\n<p><b>Numeric Values and Calculations</b></p>\n<div id=\"calcs\" class=\"notes\"></div>\n</div>\n\n\n<div class='section'>\n<p><b>Links</b><img style=\"padding:25px\" src=\"/files/images/heatwebsl.png\" width=\"200px\" align=\"right\"></p>\n<div id=\"mylink\" class=\"notes\"></div>\n<div id=\"links\" class=\"notes\"></div>\n\n\n\n</div>\n</form>\n\n\n\n\n <form id=\"nextform\" name=\"nextform\" method=\"post\" action=\"/api/print\" ajax=\"true\" target=\"result1\">\n    <input type=\"hidden\" id=\"svgtext\" name=\"svgtext\" value=\"\">\n    <input type=\"hidden\" id=\"svgfile\" name=\"svgfile\" value=\"\">\n    <input type=\"hidden\" id=\"show\" name=\"show\" value=\"\">\n    </form>\n <iframe width=\"100%\" frameborder=\"0\" id=\"result1\" name=\"result1\" style=\"display:none\"></iframe>\n\n<div id=\"headed\" style=\"display:none\">\n    <svg\n   xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n   xmlns:cc=\"http://creativecommons.org/ns#\"\n   xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n   xmlns:svg=\"http://www.w3.org/2000/svg\"\n   xmlns=\"http://www.w3.org/2000/svg\"\n   xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n   id=\"svg1156\"\n   version=\"1.1\"\n   viewBox=\"0 0 210 297\"\n   height=\"297mm\"\n   width=\"210mm\">\n  <defs\n     id=\"defs1150\" />\n  <metadata\n     id=\"metadata1153\">\n    <rdf:RDF>\n      <cc:Work\n         rdf:about=\"\">\n        <dc:format>image/svg+xml</dc:format>\n        <dc:type\n           rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\n        <dc:title></dc:title>\n      </cc:Work>\n    </rdf:RDF>\n  </metadata>\n  <g\n     id=\"layer1\">\n    <path\n       id=\"path973\"\n       d=\"M 4.7230732,285.08269 H 204.21415\"\n       style=\"opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1\" />\n    <image\n       width=\"33.573963\"\n       height=\"10.040811\"\n       preserveAspectRatio=\"none\"\n       xlink:href=\"data:image/png;base64,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 PAAAAABJRU5ErkJggg== \"\n       id=\"image970\"\n       x=\"6.2852573\"\n       y=\"5.9025064\" />\n    <path\n       id=\"path973-9\"\n       d=\"M 4.7230731,18.88226 H 204.21415\"\n       style=\"opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1\" />\n    <text\n       id=\"text1007\"\n       y=\"289.65405\"\n       x=\"108.3\"\n       style=\"font-style:normal;font-weight:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:2.82222223px;text-align:center;text-anchor:middle;stroke-width:0.26458332\"\n         y=\"289.65405\"\n         x=\"108.3\"\n         id=\"tspan1005\">Page {{pn}} of {{pc}}</tspan></text>\n    <text\n       id=\"text1007-5\"\n       y=\"9.4398441\"\n       x=\"203.11298\"\n       style=\"font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:4.23333311px;text-align:end;text-anchor:end;stroke-width:0.26458332\"\n         y=\"9.4398441\"\n         x=\"203.11298\"\n         id=\"tspan1005-2\">{{title}}</tspan></text>\n    <text\n       id=\"text1007-5-0\"\n       y=\"14.542536\"\n       x=\"203.11298\"\n       style=\"font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:3.17499995px;text-align:end;text-anchor:end;stroke-width:0.26458332\"\n         y=\"14.542536\"\n         x=\"203.11298\"\n         id=\"tspan1005-2-7\">{{subtitle}}</tspan></text>\n  </g>\n</svg>\n</div>\n","output":"str","x":1440,"y":400,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"31a05810.26d4f8","type":"template","z":"cce2bfaa.e5748","name":"buffer24","field":"payload.body","fieldType":"msg","format":"html","syntax":"mustache","template":"<div id=\"graph-id\" style=\"width:100%; height:calc(100vh - 50px);\"></div> \n\n<script src=\"https://cdn.plot.ly/plotly-latest.min.js\"></script>\n     \n<script>\n\nfunction saveG() { \n            \n            //clearTimeout(myTimeout);\n            //alert(\"ok\");\n            \n            // var imgh = \"1200px\"; // ($(\"#graph-id\").css(\"height\")) || 500;\n            // var imgw = \"2300px\"; // ($(\"#graph-id\").css(\"width\")) || 1300;\n            var imgh = ($(\"#graph-id\").css(\"height\")) || 500;\n            var imgw = ($(\"#graph-id\").css(\"width\")) || 1300;\n            \n            imgh = 1.2 * parseInt(imgh.replace(\"px\",\"\"));\n            imgw = 1.2 * parseInt(imgw.replace(\"px\",\"\"));\n            \n            //var img_svg = Plotly.d3.select('#svg-export');\n            Plotly.toImage('graph-id',{format:'jpeg',height:imgh,width:imgw})\n                 .then(\n                         function(url)\n                     {\n                        \n                        // url = decodeURIComponent(url); //data:image/svg\n                        // url = url.substr(url.indexOf(\"<svg\"));\n                        \n                        console.log(url);\n                        \n                        var nn=\"buffer24\";\n\n                        var myob = {};\n                        myob.value = url;\n                        myob.id = nn;\n                        myob.filename = nn + \".jpeg\";\n                        //myob.type = \"image/svg+xml\";\n                        myob.type = \"image/jpeg\";\n                        myob.page = \"DHW Loads\";\n                        myob.text = \"The following chart shows the energy stored in the buffer at the end of each hour, starting with an empty buffer. The storage must remain positive throughout the day.\";\n                        \n                        try { parent.setObject(nn, myob); } catch {}\n                        \n                        \n                        \n                        myob = null;\n\n                        // $(\"#svgtext\").val(url);\n                        // $(\"#svgfile\").val(\"/files/graphs/graph_\" + (new Date().getTime()) + \".svg\");\n\n                        // var tit = document.getElementsByClassName(\"gtitle\")[0];\n                        // if (tit) {\n                        //     var tittxt = tit.innerHTML;\n                        //     if (tittxt !==\"\") { $(\"#svgfile\").val(\"/files/graphs/\" + tittxt.replace(/ /g,\"_\") + \"_\" + (new Date().getTime()) + \".svg\");}\n                        // }\n\n                       \n                        \n                        // $(\"#nextform\").submit(); \n                         \n                         \n                     }\n                 )\n            \n           \n           \n            \n        } \n\n\n     \nvar trace1 = {\n  x: {{{x1}}},\n  y: {{{y1}}},\n  name: '{{{series1name}}}',\n  type: 'bar'\n};\n\nvar trace2 = {\n  x: {{{x1}}},\n  y: {{{y2}}},\n  name: '{{{series2name}}}',\n  type: 'bar'\n};\n\n//var data = [trace1, trace2];\nvar data = [trace1,trace2];\n\nvar layout = {barmode: 'stack',\"margin\":{\"b\":60,\"l\":60,\"r\":20,\"t\":25},\"autosize\":true,\"showlegend\": true,  \"legend\": {\"orientation\": \"h\"}};\n\nPlotly.newPlot('graph-id', data, layout);\n      </script>\n  \n  <!--<div id=\"graph-id\" class=\"gstyle\"></div>-->\n   \n\n<!--<button onClick=\"saveG()\">save</button>-->\n\n<script>\nconst myTimeout = setTimeout(saveG, 3000);\n\n</script>","output":"str","x":940,"y":780,"wires":[["3641b220.fd838e"]]},{"id":"b2b32b34.eac598","type":"template","z":"cce2bfaa.e5748","name":"Form Generator","field":"payload.body","fieldType":"msg","format":"html","syntax":"plain","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js\"></script>\n<!--https://www.sitepoint.com/basic-jquery-form-validation-tutorial/-->\n\n<script src=\"https://unpkg.com/mustache@latest\"></script>\n\n\n\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n\n<script src=\"https://cdn.ckeditor.com/ckeditor5/34.0.0/inline/ckeditor.js\"></script>\n\n<!--These need to be installed locally-->\n<script src=\"pdfkit.standalone.js\"></script>\n<script src=\"blob-stream.js\"></script>\n<script src=\"svg-to-pdfkit.js\"></script>\n\n\n<style>\n    \n  \n    .jexcel_content {\n        font-size: 14px;\n    }\n    \n    .jexcel {\n        white-space: normal;\n    }\n\n\n.mybutt {\n    padding-left: 6px;\n    padding-right: 6px;\n    padding-top: 4px;\n    padding-bottom: 4px;\n    margin-right: 3px;\n    font-size: 14px;\n    border-radius: 4px;\n    cursor: pointer;\n    background-color: #a4eba4;\n    border-color: #4aa55a;\n    border: solid;\n    border-width: 1px;\n    box-shadow: 2px 2px 3px 1px rgb(0 0 0 / 28%);\n}\n.mybutt:hover {\n  background-color: #dcffdc;\n}\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\ntextarea.form-control {\n    font-size: 0.9rem;\n}\n\n.outputbox {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #ffffff;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.cframe {\n    border-radius: 0.25rem;\n    margin: 0px 0px 20px 0px;\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 3px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\nvar a = new Date();\nvar qdata;\nvar calculated = {};  calculated.objects = {};\nvar hasFocus;\nvar currentSection;\nvar inputsOut;\nvar inputString;\nvar calcsString;\nvar objects={}; \nvar sheets = {};\nvar sheetdata = {};\nvar initsheets;\n\n\t$(document).ready(function(e) {\n    \n        // $(\"form[ajax=true]\").submit(function(e) {\n            \n        //     //alert(\"submit\");\n            \n        //     e.preventDefault();\n        \n             \n            //var urlParams = new URLSearchParams(window.location.search);\n            //if (urlParams.get('display')) { loadstring = \",,\" + urlParams.get('display'); }\n\n            calculated[\"jsonQ\"] = \"hndesign\";\n\n            var urlParams = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParams) {\n                \n                calculated[urlParams[upa].split(\"=\")[0]] = decodeURIComponent(urlParams[upa].split(\"=\")[1]);\n                \n            }\n            \n            \n            \n            var form_data = {};\n            var form_url = \"/ui/qdata/\" + calculated[\"jsonQ\"];\n            var form_target = $(this).attr(\"target\") || \"result\";\n            var ftarget = \"#\" + form_target;\n            var form_method = \"GET\";\n            \n        //     $(\"#loadingimg\").show();\n            \n            $.ajax({\n                url: form_url, \n                type: form_method,      \n                data: form_data,     \n                cache: false,\n                success: function(results){   \n                    \n                    qdata = results;\n                    //qdata = JSON.parse(returnhtml);\n                    console.log(qdata);\n                   \n                    //if(urlParams['nBuildings']) { runCalcs(); runCalcs();  }\n                    runCalcs(); \n                    runCalcs();\n                    \n                    document.getElementById(\"formName\").innerHTML = qdata.title || \"Unamed Form\"; //JSON.stringify(qdata) ;\n                    \n                    // document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n                    \n                    // for (var sht in initsheets) {  initSheet(initsheets[sht]);   }\n                    \n                    // validform();\n                                  \n                }           \n            });    \n            \n        // });\n        \n      \n        \n    });\n\n\n    \nfunction tosvg(obid) {\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.svg\";\n    if (nn.indexOf(\".svg\")<0) { nn = nn + \".svg\"; }\n    \n    download( objects[obid].value, nn, \"image/svg+xml\")\n}\n  \n function jpegDownload(obid){\n\t    \n\t    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n        if (nn===null) { return(null); }\n        nn = nn || \"download.jpeg\";\n        if (nn.indexOf(\".jpeg\")<0) { nn = nn + \".jpeg\"; }\n        \n        var byteString = atob(objects[obid].value.split(',')[1]);\n        var mimeString = objects[obid].value.split(',')[0].split(':')[1].split(';')[0]\n\n        \n        // write the bytes of the string to an ArrayBuffer\n          var ab = new ArrayBuffer(byteString.length);\n        \n          // create a view into the buffer\n          var ia = new Uint8Array(ab);\n        \n          // set the bytes of the buffer to the correct values\n          for (var i = 0; i < byteString.length; i++) {\n              ia[i] = byteString.charCodeAt(i);\n          }\n        \n        download( ia , nn, mimeString)\n\t}\n\t\nfunction topdf(obid) {\n    \n    if (!objects[obid]) { return null; }\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.pdf\";\n    if (nn.indexOf(\".pdf\")<0) { nn = nn + \".pdf\"; }\n    \n    var headed = document.getElementById(\"headed\").innerHTML;\n    headed = headed.substr(headed.indexOf(\"<g\"));\n    headed = headed.substr(0,headed.lastIndexOf(\"</g>\")+4);\n    \n    var svgoot = objects[obid].value;\n    svgoot = svgoot.substr(svgoot.indexOf(\"<svg\"));\n    \n    var lg = svgoot.indexOf(\"<g\");\n    svgoot = svgoot.substr(0,lg) + '<g transform=\"translate(0,40)\">' + svgoot.substr(lg);\n    \n    lg = svgoot.lastIndexOf(\"</g>\")+4;\n    svgoot = svgoot.substr(0,lg) + \"</g>\" + headed + svgoot.substr(lg);\n    \n    var tits = {\"title\":\"Heatweb Heat Network Designer\",\"subtitle\":obid,\"pn\":\"1\",\"pc\":\"1\"}\n    svgoot = Mustache.render(svgoot, tits);\n    \n    //alert(svgoot);\n            $(\"#svgtext\").val(svgoot);\n            $(\"#svgfile\").val(nn);  //  + (new Date().getTime()) +\n            \n            $(\"#nextform\").submit(); \n            \n         \n}\n\nfunction topdf2(obid) {\n    \n    // without headed notepaper\n    \n    if (!objects[obid]) { return null; }\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.pdf\";\n    if (nn.indexOf(\".pdf\")<0) { nn = nn + \".pdf\"; }\n    \n    var svgoot = objects[obid].value;\n    svgoot = svgoot.substr(svgoot.indexOf(\"<svg\"));\n    \n    \n    \n    \n    //alert(svgoot);\n            $(\"#svgtext\").val(svgoot);\n            $(\"#svgfile\").val(nn);  //  + (new Date().getTime()) +\n            \n            $(\"#nextform\").submit(); \n            \n         \n}\n\n\n\n\n\nfunction initSheet(id) {\n\n    console.log(\"initSheet \" + id);\n    console.log(sheetdata);\n    \n    var shid = 'sheet-' + id;\n    var sdata = sheetdata[id];\n    \n    \n\n    try {\n    \n        document.getElementById(shid).innerHTML = \"\";\n        \n        sheets[id] = jspreadsheet(document.getElementById(shid), {\n            data: sdata.data,\n            columns: sdata.columns,\n            onchange: function(instance, cell, x, y, value) {\n                \n                console.log(value);\n                getSheetData(id);\n            },\n            updateTable:function(instance, cell, col, row, val, label, cellName) {\n               \n                //console.log(instance);\n                //console.log(val);\n                \n            },\n            columnSorting:false\n        });\n\n    } catch {}\n}\n\nfunction getSheetData(id) {\n    \n    \n    //alert(id);\n    \n    //console.log(sheets[id].getData());\n    \n    sheetdata[id].data = sheets[id].getData();\n    console.log(sheetdata);\n    \n    var oots = \"\";\n    for (var row in sheetdata[id].data) {\n       for (var c in sheetdata[id].data[row]) {\n           \n           var val = \"\" + (sheetdata[id].data[row][c] || \"\");\n           val = val.replace(/ /g,\"_\")\n           oots += val + \",\";\n        } \n        oots += \" \";\n    }\n    \n    oots = oots.substr(0, oots.length - 2);\n    console.log(oots);\n    \n    returncalc(id,oots)\n    \n    \n}\n\n\nfunction getObject(id) {\n    \n  \n    return (objects[id]||null);\n    \n}\n\n\nfunction setObject(id,value) {\n    \n\n    try { objects[id] = value; }\n    catch {}\n}\n\t\nfunction returncalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).value = value; }\n    catch {\n        \n        try { calculated[id] = value; }\n        catch {}\n    }\n    \n}\n\nfunction suggestcalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).placeholder = value + \" ... please confirm\"; }\n    catch {}\n}\n\t\nfunction parseQuestions(qdata) {\n    \n    console.log(qdata);\n    console.log(calculated);\n    \n    var linkstxt=\"\";\n    if (qdata.links) {\n        for (var lnk in qdata.links) {\n            linkstxt += (linkstxt!==\"\"?\"<br>\":\"\") + '<a href=\"' + qdata.links[lnk].src + '\" target=\"_blank\">' + (qdata.links[lnk].title||qdata.links[lnk].src) + '</a>';\n        }\n        \n    }\n    document.getElementById(\"links\").innerHTML = linkstxt ; //JSON.stringify(qdata) ;\n    \n    \n    inputsOut = '<input id=\"jsonQ\" name=\"jsonQ\" value=\"' + calculated[\"jsonQ\"] + '\" class=\"form-control\" type=\"hidden\">';\n                    \n    \n    inputsOut += '<table class=\"table\">';\n    \n    inputString = \"jsonQ=\" + calculated[\"jsonQ\"];  // data source for form is fixed\n    \n    hasFocus = null;\n    currentSection = null;\n    initsheets = [];\n    \n    var ootoot = \"\";\n    for (var s in qdata[\"sections\"]) {\n        console.log(s);\n        console.log(qdata.sections[s]);\n        \n        var oot = \"\";\n        var ootcount=0;\n        \n        //oot += \"<div class='section'><h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        oot += \"<h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        \n        \n        \n        for (var q in qdata.sections[s].questions) {\n            \n            \n            var qif = qdata.sections[s].questions[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n            var v=\"\";\n            if (calculated[qdata.sections[s].questions[q].id]) { v= calculated[qdata.sections[s].questions[q].id] ; }\n            else if (qdata.sections[s].questions[q].value) { v= qdata.sections[s].questions[q].value ; }\n            \n            if (v!==\"\") { qdata.sections[s].questions[q].value = v; }    // save answers back into json.\n            \n            \n            if(goq) {\n                \n                var calcfr = \"\";\n                if (qdata.sections[s].questions[q].calculator) { calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].questions[q].calculator + '?field=' + qdata.sections[s].questions[q].id + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].questions[q].calculatorStyle ? qdata.sections[s].questions[q].calculatorStyle:'width:100%; height:300px;') + '\"></iframe>'}\n            \n            \n                if (v!==\"\") { \n                    inputsOut += \"<tr>\";  \n                    \n                    var cOs1 = \"\";  var cOs2 = \"\";\n            \n                    if (document.getElementById(\"hideID\").checked!==true) {\n                        cOs2 = \" <small>[<i>\" + qdata.sections[s].questions[q].id + \"</i>]</small>\";  \n                    }\n                    \n                    inputsOut += '<td width=\"40%\">' + (qdata.sections[s].questions[q].title||qdata.sections[s].questions[q].id) + cOs2 + \"</td>\";\n                    \n                    var vs1=\"\"; var vs2=\"\";\n                    if((\"\"+v).indexOf(\",\") > -1) { vs1=\"<small>\"; vs2=\"</small>\"; }\n                    if((\"\"+v).indexOf(\"&\") > -1) { vs1=\"<small style='width:400px; word-wrap:break-word; display:inline-block;'>\"; vs2=\"</small>\"; }\n                    \n                    \n                    inputsOut +=  ('<td align=\"right\">' + vs1 + v + vs2 + \"</td>\").replace(/\\, /g,\"<br>\").replace(/\\,/g,\", \");\n                    inputsOut +=  '<td width=\"14%\">' + (qdata.sections[s].questions[q].units||\"\") + \"</td></tr>\\n\";\n                    \n                    inputString += (inputString!==\"\"?\"&\":\"\") + qdata.sections[s].questions[q].id + \"=\" + encodeURIComponent(v);\n                }\n            \n                var isDisplayed = false;\n            \n                if (hasFocus && document.getElementById(\"oneQ\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">'; }\n            \n                else if (v!==\"\") { \n                    \n                    if (document.getElementById(\"hideDone\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">';   }\n                    else {  oot += '<div class=\"question\" style=\"background-color: #d2efd2;\">'; ootcount++; isDisplayed=true; }\n                    \n                } else { oot += '<div class=\"question\">'; ootcount++; isDisplayed=true; if (!hasFocus) { hasFocus = qdata.sections[s].questions[q].id;  currentSection = qdata.sections[s].title;  } }\n                \n                \n                //oot += \"<div class='qtext'>\" + qdata.sections[s].questions[q].title + '</div>';\n                oot += '<label for=\"' + qdata.sections[s].questions[q].id + '\" class=\"qtext\">' + (qdata.sections[s].questions[q].question||qdata.sections[s].questions[q].title) + '</label>';\n                \n                if (calcfr!==\"\") { oot += \"\\n\" + calcfr + \"\\n\"; }\n                \n                if (qdata.sections[s].questions[q].notes) { oot += '<div class=\"notes\">'  + convertLinks(Mustache.render(qdata.sections[s].questions[q].notes, calculated)) + '</div>'; }\n                \n                if (qdata.sections[s].questions[q].type == \"sheet\") {\n                    \n                    oot += '<br><div id=\"sheet-' + qdata.sections[s].questions[q].id + '\">';\n                \n                    oot += '<span onclick=\"initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ')\"><small>Load Sheet</small></span> ';\n                    \n                    oot += '</div><br><br>';\n                    \n                    //oot += '<script>initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ');</scrip' + 't> ';\n                    //var myTimeout = setTimeout(initSheet(qdata.sections[s].questions[q].id), 1000);\n                    if (isDisplayed) { initsheets.push(qdata.sections[s].questions[q].id); }\n                \n                    var shob = {};\n                    shob['columns'] = qdata.sections[s].questions[q].columns;\n                    shob['data'] = qdata.sections[s].questions[q].default;\n                    \n                    if((\"\"+v)!==\"\") {\n                        \n                        shob['data']=[];\n                        var vv = v.replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                        var lns = vv.split(\", \");\n                        for (var lnsv in lns) {\n                            shob['data'].push(lns[lnsv].split(\",\"));\n                        }\n                    }\n                    \n                    sheetdata[qdata.sections[s].questions[q].id] = shob;\n                    \n                }\n                \n                \n                \n                if (qdata.sections[s].questions[q].type==\"html\") {\n                    \n                    oot += '<br><br><div class=\"form-control htmlinput\" style=\"height:fit-content\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    oot += decodeURIComponent('' + v + '')\n                    oot += '</div>';\n                \n                }\n                \n                \n                oot += '<table width=\"100%\"><tr><td width=\"80%\">';\n                \n                if (qdata.sections[s].questions[q].jsonQ) {\n                    \n                    \n                    oot += '<textarea class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    //oot += ('' + v + '').replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                    oot += decodeURIComponent('' + v + '')\n                    oot += '</textarea>';\n                    \n                } \n                \n                else if (qdata.sections[s].questions[q].type==\"html\") {\n                    \n                    oot += '';\n                    \n                   \n                \n                }\n                    \n                else if (qdata.sections[s].questions[q].type==\"boolean\") {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                      if (v==\"true\") { oot += '<option value=\"false\">No</option><option value=\"true\" selected>Yes</option>'; }\n                      else if (v==\"false\")  { oot += '<option value=\"false\" selected>No</option><option value=\"true\">Yes</option>'; }\n                      else  { oot += '<option value=\"\"></option><option value=\"false\">No</option><option value=\"true\">Yes</option>'; }\n                    oot += '</select>';\n                    \n                } else if (qdata.sections[s].questions[q].options) {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    if (v==\"\") { oot += '<option value=\"\"></option>'; }\n                    for (var opt in qdata.sections[s].questions[q].options) {\n                    \n                      var optobj = qdata.sections[s].questions[q].options[opt];\n                      \n                      \n                      if (v==optobj.value) { oot += '<option selected value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      else  { oot += '<option value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      \n                    }  \n                    oot += '</select>';\n                    \n                }  else {\n                \n                    oot += '<input id=\"' + qdata.sections[s].questions[q].id + '\" name=\"' + qdata.sections[s].questions[q].id + '\" class=\"form-control\" type=\"text\"';\n                    if (v!==\"\") { oot += (' value=\"' + v + '\"').replace(/\\%20/g,\" \").replace(/_/g,\" \"); }\n                    if (qdata.sections[s].questions[q].default) { \n                        \n                        oot += ' placeholder=\"' + Mustache.render(\"\"+qdata.sections[s].questions[q].default, calculated)  + \" \" + (qdata.sections[s].questions[q].units||\"\") + ' ... please confirm\"'; \n                        \n                    }\n                    oot += '>';\n                }\n                \n                oot += '</td><td valign=\"top\"><span class=\"qunits\">' + (qdata.sections[s].questions[q].units||\"\") + '</span></td></tr></table>';\n                \n                \n                \n                oot += '</div>\\n';\n            }\n        }\n    \n        oot += '<table width=\"100%\"><tr><td width=\"100%\" align=\"right\"><button class=\"mybutt\" type=\"submit\">Submit</button></td></tr></table>';\n\n        oot += \"</div>\\n\";\n       \n        \n        var outhtml = \"\";   \n        for (var q in qdata.sections[s].outputs) {\n            \n            var qif = qdata.sections[s].outputs[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n\n            if(goq && (calcsString||\"\")!==\"\") {\n                \n                var calcfr = \"\";\n                if (qdata.sections[s].outputs[q].url) { \n                    \n                    calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].outputs[q].url + (qdata.sections[s].outputs[q].url.indexOf(\"?\")>0?'':'?') + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].outputs[q].style ? qdata.sections[s].outputs[q].style:'width:100%; height:300px;') + '\"></iframe>'\n                    \n                    outhtml += '<div class=\"outputbox\">';\n                    outhtml += \"<table width='100%'><tr><td><b>\" + qdata.sections[s].outputs[q].title + \"</b></td>\\n\";\n                    \n                    if (qdata.sections[s].outputs[q].buttons) { \n                        \n                        outhtml += '<td align=\"right\">';\n                        for (var btn in qdata.sections[s].outputs[q].buttons) {\n                            \n                            outhtml += '<span class=\"mybutt\" onclick=\"' + qdata.sections[s].outputs[q].buttons[btn].onClick + '\">' + qdata.sections[s].outputs[q].buttons[btn].text + '</span> ';\n                        }\n                        outhtml += '</td>';\n                    }\n                    \n                    outhtml += '</tr></table><br>';\n                    \n                    outhtml += calcfr ; \n                    \n                    \n                    \n                    outhtml += \"</div>\\n\";\n                }\n            \n            }\n        }\n        \n        if (outhtml!==\"\") {\n            \n            //oot += '<div class=\"outputbox\">';\n            oot += outhtml;\n            //oot += \"</div>\\n\";\n        }\n        \n        \n        \n        \n        \n        if (document.getElementById(\"oneS\").checked==true && (currentSection != qdata.sections[s].title)) {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n        else if (ootcount>0) {  ootoot += \"<div class='section'>\" + oot; }\n        \n        else {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n    }\n    inputsOut +=  \"</table>\\n\";  \n    \n    return ootoot;\n}\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\n// console.log(looseJsonParse(\n//   \"{a:(4-1), b:function(){}, c:new Date()}\"\n// ))\n\nfunction runCalcs() {\n\n\n    calcsString = \"\";\n    \n    // run through form inputs and store current values into calculated.\n    var cells =  document.getElementsByClassName(\"form-control\");\n\tvar i;\n\tfor (i = 0; i < cells.length; i++) {\n\t\n\t    \n\t    \n\t\n\t\tcalcsOut += cells[i].value + \"<br>\\n\";\n        \n        if (\"\" + cells[i].value !== \"\") { \n            \n            if (isNaN(cells[i].value)) { \n                \n                if ((cells[i].classList+\" \").indexOf(\"htmlinput\")>-1) {     // && cells[i].classList.indexOf(\"ck\")>-1\n                    \n                    calculated[cells[i].id] = cells[i].innerHTML;\n                }\n                else {\n                    \n                    calculated[cells[i].id] = (cells[i].value);\n                \n                    if ((calculated[cells[i].id]+\" \").substr(0,1)==\"{\" || (calculated[cells[i].id]+\" \").substr(0,1)==\"[\") {    // detect objects in textboxes\n                        \n                        try  { calculated.objects[cells[i].id] = JSON.parse(calculated[cells[i].id]) } catch {  }\n                    }\n                \n                }\n               \n                \n            } else {\n                \n                calculated[cells[i].id] = parseFloat(cells[i].value);\n            }\n            \n            calcsString += \"&\" + cells[i].id + \"=\" + cells[i].value;\n        }\n\t}\n\t\n    var calcsOut = '<table class=\"table\">';\n    \n    //calculated.objects = objects;\n    \n    // ================== Sheet Custom Calculations\n    \n    \n    if (calculated['loadSchedule']) {\n        \n        console.log(\"Load Schedule = \" + calculated['loadSchedule']);\n        \n        \n            \n            var cv1 = calculated['loadSchedule'];\n            var cv = 0;\n            var np = 0;\n            var kwCHMax = 0;\n            \n            var ldata=[];\n            \n            if((\"\"+cv1)!==\"\") {\n                \n                var vv = (\"\"+cv1).replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                var lns = vv.split(\", \");\n                for (var lnsv in lns) {\n                    ldata.push(lns[lnsv].split(\",\"));\n                    \n                    cv = cv + parseFloat(lns[lnsv].split(\",\")[4])\n                    \n                    np = np + (parseFloat(lns[lnsv].split(\",\")[2]) * parseFloat(lns[lnsv].split(\",\")[4]));\n                    \n                    kwCHMax = kwCHMax + (parseFloat(lns[lnsv].split(\",\")[3]) * parseFloat(lns[lnsv].split(\",\")[4]));\n                    \n                    \n                }\n            }\n            \n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total Properties</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">properties</td></tr>\\n';\n            \n            calculated['nProperties'] = cv;\n            calcsString += \"&nProperties=\" + cv;\n            \n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total People</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + np + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">people</td></tr>\\n';\n            \n            calculated['nPeople'] = np;\n            calcsString += \"&nPeople=\" + np;\n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total of central heating outputs</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + kwCHMax + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">kW</td></tr>\\n';\n            \n            calculated['kwCHMax'] = kwCHMax;\n            calcsString += \"&kwCHMax=\" + kwCHMax;\n            \n        \n        \n    }\n    \n    \n    // ================================\n    \n    \n    for (var calc in (qdata[\"calculations\"]||[])) {\n        \n        console.log(calc);\n        console.log(qdata.calculations[calc]);\n        \n        var cif = qdata.calculations[calc].if || true;\n        var cift = Mustache.render(cif, calculated);\n        var goc = true;\n        try {\n          goc = looseJsonParse(cift); \n        }\n        catch(err) {\n          goc = false;\n        }\n        \n        if (goc) {\n            \n            var f = qdata.calculations[calc].function;\n            var ft = Mustache.render(f, calculated);\n            \n            calcsOut += \"<tr>\";  //<td>\" + qdata.calculations[calc].id + \"</td>\";\n            calcsOut += \"<td>\";\n            \n            var cOs1 = \"\";  var cOs2 = \"\";\n            \n            if (document.getElementById(\"hideID\").checked!==true) {\n                cOs2 = \" <small>[<i>\" + qdata.calculations[calc].id + \"</i>]</small>\";  \n            }\n            \n            calcsOut += cOs1 + (qdata.calculations[calc].title||qdata.calculations[calc].id) + cOs2 + \"</td>\";\n            \n            //calcsOut += f + \" = \";\n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small>\" + ft.replace(/\\,/g,\", \") + \"</small></td>\";   //\"<br>\\n\";\n            }\n            \n            var cv = \"\";\n            try {\n              cv = looseJsonParse(ft); //  looseJsonParse(\"{a:(4-1), b:function(){}, c:new Date()}\");\n            }\n            catch(err) {\n              \n            }\n             \n            \n            if (!isNaN(cv)) { cv = parseInt(cv*1000)/1000; }\n            \n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            \n            calcsOut +=  '<td width=\"14%\">' + (qdata.calculations[calc].units||\"\") + \"</td></tr>\\n\";\n            \n            calculated[qdata.calculations[calc].id] = cv;\n            calcsString += \"&\" + qdata.calculations[calc].id + \"=\" + cv;\n        }\n        \n    }\n    \n    calcsOut +=  \"</table>\\n\";\n    \n    // for (var calc in calculated) {\n        \n        \n    // }\n    \n    document.getElementById(\"calcs\").innerHTML = calcsOut; //JSON.stringify(qdata) ;\n    \n    // rebuild form\n    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"inputs\").innerHTML = inputsOut; //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"mylink\").innerHTML = '<a href=\"hndesign?' + inputString + '\" target=\"_blank\">Open/share design...</a>'; //JSON.stringify(qdata) ;\n    \n    if(document.getElementById(\"description\")) {  // work in progress - need to link to all\n        InlineEditor\n                .create( document.querySelector( '#description' ) )\n                .catch( error => {\n                    console.error( error );\n                } );\n        \n        for (var sht in initsheets) {  initSheet(initsheets[sht]);   }\n    }\n    \n    validform();\n                    \n}\n\n\nconst convertLinks = ( input ) => {\n\n  let text = input;\n  const linksFound = text.match( /(?:www|https?)[^\\s]+/g );\n  const aLink = [];\n\n  if ( linksFound != null ) {\n\n    for ( let i=0; i<linksFound.length; i++ ) {\n      let replace = linksFound[i];\n      if ( !( linksFound[i].match( /(http(s?)):\\/\\// ) ) ) { replace = 'http://' + linksFound[i] }\n      let linkText = replace.split( '/' )[2];\n      if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) }\n      if ( linkText.match( /youtu/ ) ) {\n\n        let youtubeID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://www.youtube.com/embed/' + youtubeID + '\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe></div>' )\n      }\n      else if ( linkText.match( /vimeo/ ) ) {\n        let vimeoID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://player.vimeo.com/video/' + vimeoID + '\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' )\n      }\n      else {\n        aLink.push( '<a href=\"' + replace + '\" target=\"_blank\">' + linkText + '</a>' );\n      }\n      text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] );\n    }\n    return text;\n\n  }\n  else {\n    return input;\n  }\n}\n\nfunction validform() {\n    \n    if(hasFocus && document.getElementById(hasFocus)) {\n        document.getElementById(hasFocus).focus();\n    }\n    \n    \n    \n// Initialize form validation on the registration form.\n  // It has the name attribute \"registration\"\n  $(\"form[name='qform']\").validate({\n    // Specify validation rules\n    rules: {\n      // The key name on the left side is the name attribute\n      // of an input field. Validation rules are defined\n      // on the right side\n    //   nProperties: {\n    //     required: true,\n    //     digits: true,\n    //     min: 1\n    //   },\n      lastname: \"required\",\n      email: {\n        required: true,\n        // Specify that email should be validated\n        // by the built-in \"email\" rule\n        email: true\n      },\n      password: {\n        required: true,\n        minlength: 5\n      }\n    },\n    // Specify validation error messages\n    messages: {\n      nProperties: \"Please enter a number.\",\n      lastname: \"Please enter your lastname\",\n      password: {\n        required: \"Please provide a password\",\n        minlength: \"Your password must be at least 5 characters long\"\n      },\n      email: \"Please enter a valid email address\"\n    },\n    // Make sure the form is submitted to the destination defined\n    // in the \"action\" attribute of the form when valid\n    submitHandler: function(form) {\n      //form.submit();\n      runCalcs();\n      //alert(\"hello\");\n    }\n  });\n}\n\n</script>\n\n\n<div class='section'>\n    \n    <table width=\"100%\"><tr>\n    <td valign=\"top\" width=\"70%\">\n        <div id=\"formName\" class=\"h1\"></div>\n        <a href=\"https://heatweb.co.uk/w/index.php?title=Heat_Network_Designer\" target=\"_blank\"><small>Wiki Help Page</small></a>\n    </td>\n    <td width=\"30%\">\n        <input type=\"checkbox\" id=\"oneS\" name=\"oneS\" checked> <small>One section at a time</small><br>\n        <input type=\"checkbox\" id=\"oneQ\" name=\"oneQ\" checked> <small>One question at a time</small><br>\n        <input type=\"checkbox\" id=\"hideDone\" name=\"hideDone\" checked> <small>Hide completed questions</small><br>\n        <input type=\"checkbox\" id=\"hideMaths\" name=\"hideMaths\" checked> <small>Hide maths equations</small><br>\n        <input type=\"checkbox\" id=\"hideID\" name=\"hideID\" checked> <small>Hide IDs</small>\n    </td>\n    </tr></table>\n</div>\n\n\n<form action=\"\" name=\"qform\" id=\"qform\">\n<div id=\"section1\"></div>\n\n<div class='section'>\n\n<table width=\"100%\"><tr><td><span class=\"mybutt\" onclick=\"onDownload()\">Download JSON</span> <span class=\"mybutt\" onclick=\"copyData()\">Copy Data</span> <span class=\"mybutt\" onclick=\"copylink()\">Copy Link</span> <span class=\"mybutt\" onclick=\"openlink()\">Open in New</span> <span class=\"mybutt\" onclick=\"shareTwitter()\">Tweet Design</span> <span class=\"mybutt\" onclick=\"tosvg('mysvg')\">SVG</span> <span class=\"mybutt\" onclick=\"topdf('mysvg')\">PDF</span></td><td align=\"right\"><button class=\"mybutt\" type=\"submit\">Submit</button></td></tr></table>\n\n\n\n\n</div>\n\n<script>\n\n\n    \n\n   function download(content, fileName, contentType) {\n       \n       if(!contentType) contentType = 'application/octet-stream';\n\t\t  const a = document.createElement(\"a\");\n\t\t  const file = new Blob([content], { type: contentType });\n\t\t  a.href = URL.createObjectURL(file);\n\t\t  a.download = fileName;\n\t\t  a.click();\n\t}\n\n\tfunction onDownload(){\n\t    \n\t    var jsonData = { \"url\": (window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString),\"calculated\": calculated, \"qdata\": qdata, \"objects\": objects };\n\t\tdownload(JSON.stringify(jsonData), \"hndesign.json\", \"text/plain\");\n\t}\n    \n   \n    \n    function copyData(){\n\t    \n\t    var jsonData = calculated ;\n\t\tnavigator.clipboard.writeText(JSON.stringify(jsonData));\n\t\talert(\"Data Copied to Clipboard\");\n\t}\n    \n    \n    function copylink() {\n        \n        //alert(window.location.href.split(\".svg\")[0]+\".svg&display=\"+displayed);\n        \n        navigator.clipboard.writeText(window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\"));  //\n        alert(\"Link Copied to Clipboard\");\n         \n    \n    }\n    \n    function openlink() {\n        \n        //alert(window.location.href.split(\".svg\")[0]+\".svg&display=\"+displayed);\n        \n        window.open(window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\"));  //\n        \n         \n    \n    }\n    \n    function shareTwitter() {       \n        \n        var text = \"My latest heat network design.\";\n        var url = window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\");\n        window.open('http://twitter.com/share?url='+encodeURIComponent(url)+'&text='+encodeURIComponent(text), '', 'left=0,top=0,width=550,height=450,personalbar=0,toolbar=0,scrollbars=0,resizable=0');\n\n    } \n\n</script>\n\n\n<div class='section'>\n<p><b>Inputs</b></p>\n<div id=\"inputs\" class=\"notes\"></div>\n</div>\n\n<div class='section'>\n<p><b>Numeric Values and Calculations</b></p>\n<div id=\"calcs\" class=\"notes\"></div>\n</div>\n\n\n<div class='section'>\n<p><b>Links</b><img style=\"padding:25px\" src=\"/files/images/heatwebsl.png\" width=\"200px\" align=\"right\"></p>\n<div id=\"mylink\" class=\"notes\"></div>\n<div id=\"links\" class=\"notes\"></div>\n\n\n\n</div>\n</form>\n\n\n\n\n <form id=\"nextform\" name=\"nextform\" method=\"post\" action=\"/api/print\" ajax=\"true\" target=\"result1\">\n    <input type=\"hidden\" id=\"svgtext\" name=\"svgtext\" value=\"\">\n    <input type=\"hidden\" id=\"svgfile\" name=\"svgfile\" value=\"\">\n    <input type=\"hidden\" id=\"show\" name=\"show\" value=\"\">\n    </form>\n <iframe width=\"100%\" frameborder=\"0\" id=\"result1\" name=\"result1\" style=\"display:none\"></iframe>\n\n<div id=\"headed\" style=\"display:none\">\n    <svg\n   xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n   xmlns:cc=\"http://creativecommons.org/ns#\"\n   xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n   xmlns:svg=\"http://www.w3.org/2000/svg\"\n   xmlns=\"http://www.w3.org/2000/svg\"\n   xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n   id=\"svg1156\"\n   version=\"1.1\"\n   viewBox=\"0 0 210 297\"\n   height=\"297mm\"\n   width=\"210mm\">\n  <defs\n     id=\"defs1150\" />\n  <metadata\n     id=\"metadata1153\">\n    <rdf:RDF>\n      <cc:Work\n         rdf:about=\"\">\n        <dc:format>image/svg+xml</dc:format>\n        <dc:type\n           rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\n        <dc:title></dc:title>\n      </cc:Work>\n    </rdf:RDF>\n  </metadata>\n  <g\n     id=\"layer1\">\n    <path\n       id=\"path973\"\n       d=\"M 4.7230732,285.08269 H 204.21415\"\n       style=\"opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1\" />\n    <image\n       width=\"33.573963\"\n       height=\"10.040811\"\n       preserveAspectRatio=\"none\"\n       xlink:href=\"data:image/png;base64,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 PAAAAABJRU5ErkJggg== \"\n       id=\"image970\"\n       x=\"6.2852573\"\n       y=\"5.9025064\" />\n    <path\n       id=\"path973-9\"\n       d=\"M 4.7230731,18.88226 H 204.21415\"\n       style=\"opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1\" />\n    <text\n       id=\"text1007\"\n       y=\"289.65405\"\n       x=\"108.3\"\n       style=\"font-style:normal;font-weight:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:2.82222223px;text-align:center;text-anchor:middle;stroke-width:0.26458332\"\n         y=\"289.65405\"\n         x=\"108.3\"\n         id=\"tspan1005\">Page {{pn}} of {{pc}}</tspan></text>\n    <text\n       id=\"text1007-5\"\n       y=\"9.4398441\"\n       x=\"203.11298\"\n       style=\"font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:4.23333311px;text-align:end;text-anchor:end;stroke-width:0.26458332\"\n         y=\"9.4398441\"\n         x=\"203.11298\"\n         id=\"tspan1005-2\">{{title}}</tspan></text>\n    <text\n       id=\"text1007-5-0\"\n       y=\"14.542536\"\n       x=\"203.11298\"\n       style=\"font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:3.17499995px;text-align:end;text-anchor:end;stroke-width:0.26458332\"\n         y=\"14.542536\"\n         x=\"203.11298\"\n         id=\"tspan1005-2-7\">{{subtitle}}</tspan></text>\n  </g>\n</svg>\n</div>\n\n<div class='section'>\n\n<div><button class=\"mybutt\" onclick=\"downloadp()\">Download</button> <button  class=\"mybutt\"  onclick=\"showPDF()\">Generate</button></div>\n\n\n<iframe id=\"pdfframe\" width=\"100%\" height=\"800px\"></iframe>\n\n</div>\n\n<script>\n    \n\nvar filesLoaded = 0;\n\nvar files = {\n  img1: {\n    url: \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  },\n  img2: {\n    url: \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  },\n  img3: {\n    url:\n      \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  }\n};\n\nvar doc;\n\n\nfunction loadedFile(xhr) {\n  for (var file in files) {\n    if (files[file].url === xhr.responseURL) {\n      files[file].data = xhr.response;\n    }\n  }\n  filesLoaded += 1;\n  if (filesLoaded == Object.keys(files).length) {\n    // showPDF();\n  }\n}\n\nfor (var file in files) {\n  files[file].xhr = new XMLHttpRequest();\n  files[file].xhr.onreadystatechange = function() {\n    if (this.readyState == 4 && this.status == 200) {\n      loadedFile(this);\n    }\n  };\n  files[file].xhr.responseType = \"arraybuffer\";\n  files[file].xhr.open(\"GET\", files[file].url);\n  files[file].xhr.send(null);\n}\n\nfunction showPDF() {\n    \n     doc = new PDFDocument({\n      layout: \"portrait\",\n      size: 'A4',\n      margins: {\n        top: 0,\n        bottom: 0,\n        left: 0,\n        right: 0\n      }\n    });\n       \n    var stream = doc.pipe(blobStream());\n\n    stream.on(\"finish\", function() {\n       // get a blob you can do whatever you like with\n      blob = stream.toBlob(\"application/pdf\");\n    \n      const url = stream.toBlobURL('application/pdf');\n      const iframe = document.querySelector('#pdfframe')\n      iframe.src = url;\n    });   \n   \n   var pc = 0;\n   var posy = 100;\n   var lastpage = \"-1\";\n   \n   for (var oo in objects) {\n       \n       \n       if(posy>600 || objects[oo].page!==lastpage) {  \n           \n            pc++;\n            posy = 100;\n           \n            if (lastpage!==\"-1\") { doc.addPage({size: 'A4'});  }\n           \n            doc.image(files.img1.data, 30, 20, { fit: [60, 120] });\n       \n            \n            doc.fontSize(14);\n            doc.fillColor(\"black\").text(\"Heatweb Heat Network Designer\", 330, 22);\n            \n            doc.fontSize(9);\n            doc.fillColor(\"black\").text(\"My Page\", 500, 30);\n           \n           doc\n            .moveTo(30, 50)\n            .lineTo(560, 50)\n            .dash(5)\n            .stroke();\n       }\n       \n       lastpage = objects[oo].page;\n       \n       \n            // doc.moveDown();\n            // doc.text(\"Heatweb Heat Network Designer\", {\n            //   width: 450,\n            //   align: 'right'\n            // }\n            // );\n        \n        if (objects[oo].type==\"image/jpeg\") {\n            \n            doc.image(objects[oo].value, 50, posy, { fit: [500, 300] });\n            \n            posy = posy + 300;\n        }\n        else if (objects[oo].type==\"image/svg+xml\") {\n           \n            SVGtoPDF(doc,  objects[oo].value,5,posy);\n            \n            posy = 9999;\n            \n        }\n        \n   }\n   \n \n\n  doc.end();\n}\n\nconst ppp = document.createElement(\"a\");\ndocument.body.appendChild(ppp);\nppp.style = \"display: none\";\n\nlet blob;\n\nfunction downloadp() {\n  if (!blob) return;\n  var url = window.URL.createObjectURL(blob);\n  ppp.href = url;\n  ppp.download = 'test.pdf';\n  ppp.click();\n  window.URL.revokeObjectURL(url);\n}\n\n\n\n</script>\n\n\n","output":"str","x":1300,"y":280,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"3ea3fd01.3c5b52","type":"template","z":"cce2bfaa.e5748","name":"post data","field":"payload.body","fieldType":"msg","format":"html","syntax":"mustache","template":"\n<script type=\"text/javascript\">\n\n// Example POST method implementation:\nasync function postData(url = '', data = {}) {\n  // Default options are marked with *\n  const response = await fetch(url, {\n    method: 'POST', // *GET, POST, PUT, DELETE, etc.\n    mode: 'no-cors', // no-cors, *cors, same-origin\n    cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached      // credentials: 'same-origin', // include, *same-origin, omit\n    headers: {\n      'Content-Type': 'application/json'\n      // 'Content-Type': 'application/x-www-form-urlencoded',\n    },\n    redirect: 'follow', // manual, *follow, error\n    referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url\n    body: JSON.stringify(data) // body data type must match \"Content-Type\" header\n  });\n  return response.text(); //.json(); // parses JSON response into native JavaScript objects\n}\n\npostData('/ui/postdata', { answer: 42 })\n  .then(data => {\n    console.log(data); // JSON data parsed by `data.json()` call\n  });\n  \n  </script>\n  \n  <div id=\"wikip\"></div>","output":"str","x":1400,"y":920,"wires":[[]]},{"id":"c3728c16.faaeb","type":"http request","z":"cce2bfaa.e5748","name":"","method":"GET","ret":"txt","paytoqs":false,"url":"","persist":false,"authType":"","x":645,"y":1780,"wires":[["eb9800ad.2de54","227e25db.92cd3a"]]},{"id":"eb9800ad.2de54","type":"function","z":"cce2bfaa.e5748","name":"","func":"//msg.payload = \"hello\";\n//<h2><span class=\"mw-headline\" id=\"Setting_up_MQTT_Subscriptions\"></span>Setting up MQTT Subscriptions</h2>\nvar stt;\n\nif (msg.type==\"heatwebcouk\") {\n\n    stt= '<main class=\"wp_content\">';\n    msg.divid = 'xxx' +msg.obid;\n}\nelse if (msg.section) {\n    stt= '<span class=\"mw-headline\" id=\"' + msg.section.replace(/ /g,\"_\") + '\"></span>';\n    msg.divid = 'xxx' + msg.section.replace(/ /g,\"_\");\n    \n} else {\n    \n    \n    \n   stt=\"<!-- start content -->\";\n   if (msg.payload.indexOf(stt)<0) { stt='<div id=\"content\">'; }\n   \n   if (msg.payload.indexOf(stt)<0) { stt='</head>'; }\n   \n   \n   msg.divid = 'xx' + msg.title.replace(/ /g,\"_\");\n   \n}\n\n\n\n\n\n\nif (msg.payload.indexOf(stt)>-1) {\n    \n    msg.payload = msg.payload.split(stt)[1];\n    \n    var he = \"\";\n    \n    if (msg.section && msg.section.length>1) {\n    \n        he = msg.payload.split(\">\")[0].split(\"/\")[1]\n        var hn = parseInt(he.replace(\"h\",\"\"));\n        \n        msg.payload = msg.payload.split(\"<\" + he + \">\")[0]; \n        msg.payload = msg.payload.split(\"<h\" + (hn-1) + \">\")[0];\n    \n        he = \"<\" + he + \">\";\n    }\n    \n    msg.payload = msg.payload.split(\"<!--\")[0]; // if last section wiki\n    msg.payload = msg.payload.split(\"</main\")[0]; // if last section heatewb\n    \n    msg.payload =  '<div obid=\"' + msg.obid + '\"  title=\"' + msg.des + '\" id=\"' + msg.divid + '\">' +  he + stt +  msg.payload + \"</div>\"\n}\nelse { \n    \n    msg.payload =  '<div obid=\"' + msg.obid + '\"  title=\"' + msg.des + '\" id=\"' + msg.divid + '\">' +   msg.payload + \"</div>\"\n}\n\n\n\nmsg.payload = msg.payload.replace(/<img /g,'<img style=\"max-width: 800px; height: auto\" ')\n\nmsg.payload = msg.payload.replace(/\\\"\\/w\\//g,'\"https://heatweb.co.uk/w/')\n\n// ============\n\nif (msg.payload.indexOf('<div id=\"toc\" class=\"toc\">')>-1) {\n\n    var rsst = msg.payload.substr(msg.payload.indexOf('<div id=\"toc\" class=\"toc\">'));\n    msg.payload = msg.payload.substr(0,msg.payload.indexOf('<div id=\"mw-content-text\"')) + rsst.substr(rsst.indexOf('</ul>')+5);\n\n}\n\n\n\n\n// ==================  Fpr wordpress need to remove downsampled images.\n\n// https://www.heatweb.co.uk/wp-content/uploads/2021/05/Estimated-weight-and-dims-768x561.jpg\n\n\n    \n    var bits = msg.payload.split('src=\"');\n    var oot = \"\";\n    \n    var ic=0;\n    for (var i in bits) {\n        \n        ic++;\n        \n        if (ic>1) {  \n            \n            var src = bits[i].split('\"')[0];\n            \n            bits[i] = bits[i].substr(bits[i].indexOf('\"'));\n            \n            if (msg.type==\"heatwebcouk\") {\n            \n                if (src.indexOf(\"-\")>-1 && src.substr(src.lastIndexOf(\"-\")).indexOf(\"x\")>-1) {\n                    \n                    src = src.substr(0,src.lastIndexOf(\"-\")) + src.substr(src.lastIndexOf(\".\"));\n                    //src = \"/ui/w/images/\" + src;\n                }\n            \n            }\n            else {\n            \n                if (src.indexOf(\"thumb/\")>-1) {\n                    \n                    //http://heatweb.co.uk/w/images/thumb/7/7d/Zenner_C5_Heat_Meter.jpg/300px-Zenner_C5_Heat_Meter.jpg\n                    //http://heatweb.co.uk/w/images/7/7d/Zenner_C5_Heat_Meter.jpg\n                    \n                    src = src.replace(\"thumb\\/\",\"\");\n                    src = src.substr(0,src.lastIndexOf(\"/\"));\n                    //src = \"/ui/w/images/\" + src;\n                }\n            \n            }\n            \n            bits[i] = 'src=\"' + src + bits[i]; \n            \n        }\n        \n        \n        //if (ic>1 && imgs.indexOf(imglist[i])<0) { imgs.push(imglist[i]); }\n        \n        oot += bits[i];\n    }\n    \n    msg.payload = oot;\n\n\n\n\n\n\n\nreturn msg;","outputs":1,"noerr":0,"x":805,"y":1780,"wires":[["bbd2f4d5.08d388","e8fd6ddd.bb96e"]]},{"id":"227e25db.92cd3a","type":"debug","z":"cce2bfaa.e5748","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":790,"y":1720,"wires":[]},{"id":"ac800d6a.65d7e","type":"http response","z":"cce2bfaa.e5748","name":"","statusCode":"","headers":{},"x":1450,"y":1780,"wires":[]},{"id":"bbd2f4d5.08d388","type":"delay","z":"cce2bfaa.e5748","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":990,"y":1780,"wires":[["28945f86.eca83","befb04ec.38b268"]]},{"id":"1dcecb6e.9e9885","type":"link out","z":"cce2bfaa.e5748","name":"","links":["4e4efa93.6f22d4"],"x":615,"y":940,"wires":[]},{"id":"4e4efa93.6f22d4","type":"link in","z":"cce2bfaa.e5748","name":"","links":["1dcecb6e.9e9885"],"x":375,"y":1780,"wires":[["2d80cb17.8a0d54","f0baf666.6b8c98"]]},{"id":"e8fd6ddd.bb96e","type":"function","z":"cce2bfaa.e5748","name":"","func":"\nvar imgs = [];\n\nvar imglist = msg.payload.split('src=\"');\n\nvar ic=0;\nfor (var i in imglist) {\n    \n    ic++;\n    imglist[i] = imglist[i].split('\"')[0];\n    \n    if (ic>1 && imgs.indexOf(imglist[i])<0) { imgs.push(imglist[i]); }\n}\n\nmsg.payload = imgs;\n\nreturn msg;","outputs":1,"noerr":0,"x":870,"y":1860,"wires":[["7689d5ad.bfd97c","32d59153.32aa5e"]]},{"id":"7689d5ad.bfd97c","type":"debug","z":"cce2bfaa.e5748","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1070,"y":1860,"wires":[]},{"id":"32d59153.32aa5e","type":"split","z":"cce2bfaa.e5748","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":890,"y":1940,"wires":[["678c5662.317258"]]},{"id":"678c5662.317258","type":"function","z":"cce2bfaa.e5748","name":"","func":"msg.url = msg.payload;\n\n msg.fn = msg.url.substr(msg.url.lastIndexOf(\"/\")+1);\n\n\n// msg.filename = \"/home/servicedeptuk/w/images/\" + fn;\n// msg.filename2 = \"/var/www/html/ihiu/w/images/\" + fn;\n\n\n\n// msg.cmd = \"sudo mv \" + msg.filename + \" \" + msg.filename2;\n\nmsg.payload = \"ls /var/www/html/ihiu/ui/w/images/\" + msg.fn;\n\n\nreturn msg;","outputs":1,"noerr":0,"x":1010,"y":1940,"wires":[["865d1065.1c03a"]]},{"id":"865d1065.1c03a","type":"exec","z":"cce2bfaa.e5748","command":"","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":1170,"y":1940,"wires":[["8fbf7bbe.f6ed38"],[],[]]},{"id":"8fbf7bbe.f6ed38","type":"function","z":"cce2bfaa.e5748","name":"","func":"\nif (msg.payload.indexOf(msg.fn)>-1) { return null; }\n\n//msg.url = msg.payload;\n\n// var fn = msg.url.substr(msg.url.lastIndexOf(\"/\")+1);\n\n\n// msg.filename = \"/home/servicedeptuk/w/images/\" + fn;\n// msg.filename2 = \"/var/www/html/ihiu/w/images/\" + fn;\n\n\n\n// msg.cmd = \"sudo mv \" + msg.filename + \" \" + msg.filename2;\n\nmsg.payload = \"cd /var/www/html/ihiu/ui/w/images && sudo wget \" + msg.url;\n\n\nreturn msg;","outputs":1,"noerr":0,"x":1350,"y":1920,"wires":[["9d1f1013.70d0f"]]},{"id":"9d1f1013.70d0f","type":"exec","z":"cce2bfaa.e5748","command":"","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":1510,"y":1920,"wires":[[],[],[]]},{"id":"befb04ec.38b268","type":"function","z":"cce2bfaa.e5748","name":"src","func":"\n\nvar bits = msg.payload.split('src=\"');\nvar oot = \"\";\n\nvar ic=0;\nfor (var i in bits) {\n    \n    ic++;\n    \n    if (ic>1) {  \n        \n        var src = bits[i].split('\"')[0];\n        \n        bits[i] = bits[i].substr(bits[i].indexOf('\"'));\n        \n        src = src.substr(src.lastIndexOf(\"/\")+1);\n        src = \"/ui/w/images/\" + src;\n        \n        bits[i] = 'src=\"' + src + bits[i]; \n        \n    }\n    \n    \n    //if (ic>1 && imgs.indexOf(imglist[i])<0) { imgs.push(imglist[i]); }\n    \n    oot += bits[i];\n}\n\nmsg.payload = oot;\n\n// if (msg.obid) { msg.payload += \"\\n\" + msg.pscript; }\n\nreturn msg;","outputs":1,"noerr":0,"x":1270,"y":1780,"wires":[["ac800d6a.65d7e"]]},{"id":"f0baf666.6b8c98","type":"debug","z":"cce2bfaa.e5748","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":500,"y":1840,"wires":[]},{"id":"28945f86.eca83","type":"debug","z":"cce2bfaa.e5748","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1150,"y":1720,"wires":[]},{"id":"ad5a5fbb.cfd1f","type":"template","z":"cce2bfaa.e5748","name":"Form Generator","field":"payload.body","fieldType":"msg","format":"html","syntax":"plain","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js\"></script>\n<!--https://www.sitepoint.com/basic-jquery-form-validation-tutorial/-->\n\n<script src=\"https://unpkg.com/mustache@latest\"></script>\n\n\n\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n\n<script src=\"https://cdn.ckeditor.com/ckeditor5/34.0.0/inline/ckeditor.js\"></script>\n\n<!--These need to be installed locally-->\n<script src=\"pdfkit.standalone.js\"></script>\n<script src=\"blob-stream.js\"></script>\n<script src=\"svg-to-pdfkit.js\"></script>\n\n\n<style>\n    \n  \n    .jexcel_content {\n        font-size: 14px;\n    }\n    \n    .jexcel {\n        white-space: normal;\n    }\n\n/*for wiki*/\nli.gallerybox {\n    \n    display: inline-block;\n}\n\n.mybutt {\n    padding-left: 6px;\n    padding-right: 6px;\n    padding-top: 4px;\n    padding-bottom: 4px;\n    margin-right: 3px;\n    font-size: 14px;\n    border-radius: 4px;\n    cursor: pointer;\n    background-color: #a4eba4;\n    border-color: #4aa55a;\n    border: solid;\n    border-width: 1px;\n    box-shadow: 2px 2px 3px 1px rgb(0 0 0 / 28%);\n}\n.mybutt:hover {\n  background-color: #dcffdc;\n}\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\ntextarea.form-control {\n    font-size: 0.9rem;\n}\n\n.outputbox {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #ffffff;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n    font-size: 16px;\n}\n\n.cframe {\n    border-radius: 0.25rem;\n    margin: 0px 0px 20px 0px;\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 3px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\nvar a = new Date();\nvar qdata;\nvar calculated = {};  calculated.objects = {};\nvar hasFocus;\nvar currentSection;\nvar inputsOut;\nvar inputString;\nvar calcsString;\nvar objects={}; \nvar sheets = {};\nvar sheetdata = {};\nvar initsheets;\n\n\t$(document).ready(function(e) {\n    \n        // $(\"form[ajax=true]\").submit(function(e) {\n            \n        //     //alert(\"submit\");\n            \n        //     e.preventDefault();\n        \n             \n            //var urlParams = new URLSearchParams(window.location.search);\n            //if (urlParams.get('display')) { loadstring = \",,\" + urlParams.get('display'); }\n\n            calculated[\"jsonQ\"] = \"hndesign\";\n\n            var urlParams = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParams) {\n                \n                calculated[urlParams[upa].split(\"=\")[0]] = decodeURIComponent(urlParams[upa].split(\"=\")[1]);\n                \n            }\n            \n            \n            \n            var form_data = {};\n            var form_url = \"/ui/qdata/\" + calculated[\"jsonQ\"];\n            var form_target = $(this).attr(\"target\") || \"result\";\n            var ftarget = \"#\" + form_target;\n            var form_method = \"GET\";\n            \n        //     $(\"#loadingimg\").show();\n            \n            $.ajax({\n                url: form_url, \n                type: form_method,      \n                data: form_data,     \n                cache: false,\n                success: function(results){   \n                    \n                    qdata = results;\n                    //qdata = JSON.parse(returnhtml);\n                    console.log(qdata);\n                   \n                    //if(urlParams['nBuildings']) { runCalcs(); runCalcs();  }\n                    runCalcs(); \n                    runCalcs();\n                    \n                    document.getElementById(\"formName\").innerHTML = qdata.title || \"Unamed Form\"; //JSON.stringify(qdata) ;\n                    \n                    // document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n                    \n                    // for (var sht in initsheets) {  initSheet(initsheets[sht]);   }\n                    \n                    // validform();\n                                  \n                }           \n            });    \n            \n        // });\n        \n      \n        \n    });\n\n\n    \nfunction tosvg(obid) {\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.svg\";\n    if (nn.indexOf(\".svg\")<0) { nn = nn + \".svg\"; }\n    \n    download( objects[obid].value, nn, \"image/svg+xml\")\n}\n  \n function jpegDownload(obid){\n\t    \n\t    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n        if (nn===null) { return(null); }\n        nn = nn || \"download.jpeg\";\n        if (nn.indexOf(\".jpeg\")<0) { nn = nn + \".jpeg\"; }\n        \n        var byteString = atob(objects[obid].value.split(',')[1]);\n        var mimeString = objects[obid].value.split(',')[0].split(':')[1].split(';')[0]\n\n        \n        // write the bytes of the string to an ArrayBuffer\n          var ab = new ArrayBuffer(byteString.length);\n        \n          // create a view into the buffer\n          var ia = new Uint8Array(ab);\n        \n          // set the bytes of the buffer to the correct values\n          for (var i = 0; i < byteString.length; i++) {\n              ia[i] = byteString.charCodeAt(i);\n          }\n        \n        download( ia , nn, mimeString)\n\t}\n\t\nfunction topdf(obid) {\n    \n    if (!objects[obid]) { return null; }\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.pdf\";\n    if (nn.indexOf(\".pdf\")<0) { nn = nn + \".pdf\"; }\n    \n    var headed = document.getElementById(\"headed\").innerHTML;\n    headed = headed.substr(headed.indexOf(\"<g\"));\n    headed = headed.substr(0,headed.lastIndexOf(\"</g>\")+4);\n    \n    var svgoot = objects[obid].value;\n    svgoot = svgoot.substr(svgoot.indexOf(\"<svg\"));\n    \n    var lg = svgoot.indexOf(\"<g\");\n    svgoot = svgoot.substr(0,lg) + '<g transform=\"translate(0,40)\">' + svgoot.substr(lg);\n    \n    lg = svgoot.lastIndexOf(\"</g>\")+4;\n    svgoot = svgoot.substr(0,lg) + \"</g>\" + headed + svgoot.substr(lg);\n    \n    var tits = {\"title\":\"Heatweb Heat Network Designer\",\"subtitle\":obid,\"pn\":\"1\",\"pc\":\"1\"}\n    svgoot = Mustache.render(svgoot, tits);\n    \n    //alert(svgoot);\n            $(\"#svgtext\").val(svgoot);\n            $(\"#svgfile\").val(nn);  //  + (new Date().getTime()) +\n            \n            $(\"#nextform\").submit(); \n            \n         \n}\n\nfunction topdf2(obid) {\n    \n    // without headed notepaper\n    \n    if (!objects[obid]) { return null; }\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.pdf\";\n    if (nn.indexOf(\".pdf\")<0) { nn = nn + \".pdf\"; }\n    \n    var svgoot = objects[obid].value;\n    svgoot = svgoot.substr(svgoot.indexOf(\"<svg\"));\n    \n    \n    \n    \n    //alert(svgoot);\n            $(\"#svgtext\").val(svgoot);\n            $(\"#svgfile\").val(nn);  //  + (new Date().getTime()) +\n            \n            $(\"#nextform\").submit(); \n            \n         \n}\n\n\n\n\n\nfunction initSheet(id) {\n\n    console.log(\"initSheet \" + id);\n    console.log(sheetdata);\n    \n    var shid = 'sheet-' + id;\n    var sdata = sheetdata[id];\n    \n    \n\n    try {\n    \n        document.getElementById(shid).innerHTML = \"\";\n        \n        sheets[id] = jspreadsheet(document.getElementById(shid), {\n            data: sdata.data,\n            columns: sdata.columns,\n            onchange: function(instance, cell, x, y, value) {\n                \n                console.log(value);\n                getSheetData(id);\n            },\n            updateTable:function(instance, cell, col, row, val, label, cellName) {\n               \n                //console.log(instance);\n                //console.log(val);\n                \n            },\n            columnSorting:false\n        });\n\n    } catch {}\n}\n\nfunction getSheetData(id) {\n    \n    \n    //alert(id);\n    \n    //console.log(sheets[id].getData());\n    \n    sheetdata[id].data = sheets[id].getData();\n    console.log(sheetdata);\n    \n    var oots = \"\";\n    for (var row in sheetdata[id].data) {\n       for (var c in sheetdata[id].data[row]) {\n           \n           var val = \"\" + (sheetdata[id].data[row][c] || \"\");\n           val = val.replace(/ /g,\"_\")\n           oots += val + \",\";\n        } \n        oots += \" \";\n    }\n    \n    oots = oots.substr(0, oots.length - 2);\n    console.log(oots);\n    \n    returncalc(id,oots)\n    \n    \n}\n\n\nfunction getObject(id) {\n    \n  \n    return (objects[id]||null);\n    \n}\n\n\nfunction setObject(id,value) {\n    \n\n    try { objects[id] = value; }\n    catch {}\n}\n\t\nfunction returncalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).value = value; }\n    catch {\n        \n        try { calculated[id] = value; }\n        catch {}\n    }\n    \n}\n\nfunction suggestcalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).placeholder = value + \" ... please confirm\"; }\n    catch {}\n}\n\t\nfunction parseQuestions(qdata) {\n    \n    console.log(qdata);\n    console.log(calculated);\n    \n    var linkstxt=\"\";\n    if (qdata.links) {\n        for (var lnk in qdata.links) {\n            linkstxt += (linkstxt!==\"\"?\"<br>\":\"\") + '<a href=\"' + qdata.links[lnk].src + '\" target=\"_blank\">' + (qdata.links[lnk].title||qdata.links[lnk].src) + '</a>';\n        }\n        \n    }\n    document.getElementById(\"links\").innerHTML = linkstxt ; //JSON.stringify(qdata) ;\n    \n    \n    inputsOut = '<input id=\"jsonQ\" name=\"jsonQ\" value=\"' + calculated[\"jsonQ\"] + '\" class=\"form-control\" type=\"hidden\">';\n                    \n    \n    inputsOut += '<table class=\"table\">';\n    \n    inputString = \"jsonQ=\" + calculated[\"jsonQ\"];  // data source for form is fixed\n    \n    hasFocus = null;\n    currentSection = null;\n    initsheets = [];\n    \n    var ootoot = \"\";\n    for (var s in qdata[\"sections\"]) {\n        console.log(s);\n        console.log(qdata.sections[s]);\n        \n        var oot = \"\";\n        var ootcount=0;\n        \n        //oot += \"<div class='section'><h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        oot += \"<h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        \n        \n        \n        for (var q in qdata.sections[s].questions) {\n            \n            \n            var qif = qdata.sections[s].questions[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n            var v=\"\";\n            if (calculated[qdata.sections[s].questions[q].id]) { v= calculated[qdata.sections[s].questions[q].id] ; }\n            else if (qdata.sections[s].questions[q].value) { v= qdata.sections[s].questions[q].value ; }\n            \n            if (v!==\"\") { qdata.sections[s].questions[q].value = v; }    // save answers back into json.\n            \n            \n            if(goq) {\n                \n                var calcfr = \"\";\n                if (qdata.sections[s].questions[q].calculator) { calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].questions[q].calculator + '?field=' + qdata.sections[s].questions[q].id + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].questions[q].calculatorStyle ? qdata.sections[s].questions[q].calculatorStyle:'width:100%; height:300px;') + '\"></iframe>'}\n            \n            \n                if (v!==\"\") { \n                    inputsOut += \"<tr>\";  \n                    \n                    var cOs1 = \"\";  var cOs2 = \"\";\n            \n                    if (document.getElementById(\"hideID\").checked!==true) {\n                        cOs2 = \" <small>[<i>\" + qdata.sections[s].questions[q].id + \"</i>]</small>\";  \n                    }\n                    \n                    inputsOut += '<td width=\"40%\">' + (qdata.sections[s].questions[q].title||qdata.sections[s].questions[q].id) + cOs2 + \"</td>\";\n                    \n                    var vs1=\"\"; var vs2=\"\";\n                    if((\"\"+v).indexOf(\",\") > -1) { vs1=\"<small>\"; vs2=\"</small>\"; }\n                    if((\"\"+v).indexOf(\"&\") > -1) { vs1=\"<small style='width:400px; word-wrap:break-word; display:inline-block;'>\"; vs2=\"</small>\"; }\n                    \n                    \n                    inputsOut +=  ('<td align=\"right\">' + vs1 + v + vs2 + \"</td>\").replace(/\\, /g,\"<br>\").replace(/\\,/g,\", \");\n                    inputsOut +=  '<td width=\"14%\">' + (qdata.sections[s].questions[q].units||\"\") + \"</td></tr>\\n\";\n                    \n                    inputString += (inputString!==\"\"?\"&\":\"\") + qdata.sections[s].questions[q].id + \"=\" + encodeURIComponent(v);\n                }\n            \n                var isDisplayed = false;\n            \n                if (hasFocus && document.getElementById(\"oneQ\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">'; }\n            \n                else if (v!==\"\") { \n                    \n                    if (document.getElementById(\"hideDone\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">';   }\n                    else {  oot += '<div class=\"question\" style=\"background-color: #d2efd2;\">'; ootcount++; isDisplayed=true; }\n                    \n                } else { oot += '<div class=\"question\">'; ootcount++; isDisplayed=true; if (!hasFocus) { hasFocus = qdata.sections[s].questions[q].id;  currentSection = qdata.sections[s].title;  } }\n                \n                \n                //oot += \"<div class='qtext'>\" + qdata.sections[s].questions[q].title + '</div>';\n                oot += '<label for=\"' + qdata.sections[s].questions[q].id + '\" class=\"qtext\">' + (qdata.sections[s].questions[q].question||qdata.sections[s].questions[q].title) + '</label>';\n                \n                if (calcfr!==\"\") { oot += \"\\n\" + calcfr + \"\\n\"; }\n                \n                if (qdata.sections[s].questions[q].notes) { oot += '<div class=\"notes\">'  + convertLinks(Mustache.render(qdata.sections[s].questions[q].notes, calculated)) + '</div>'; }\n                \n                if (qdata.sections[s].questions[q].type == \"sheet\") {\n                    \n                    oot += '<br><div id=\"sheet-' + qdata.sections[s].questions[q].id + '\">';\n                \n                    oot += '<span onclick=\"initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ')\"><small>Load Sheet</small></span> ';\n                    \n                    oot += '</div><br><br>';\n                    \n                    //oot += '<script>initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ');</scrip' + 't> ';\n                    //var myTimeout = setTimeout(initSheet(qdata.sections[s].questions[q].id), 1000);\n                    if (isDisplayed) { initsheets.push(qdata.sections[s].questions[q].id); }\n                \n                    var shob = {};\n                    shob['columns'] = qdata.sections[s].questions[q].columns;\n                    shob['data'] = qdata.sections[s].questions[q].default;\n                    \n                    if((\"\"+v)!==\"\") {\n                        \n                        shob['data']=[];\n                        var vv = v.replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                        var lns = vv.split(\", \");\n                        for (var lnsv in lns) {\n                            shob['data'].push(lns[lnsv].split(\",\"));\n                        }\n                    }\n                    \n                    sheetdata[qdata.sections[s].questions[q].id] = shob;\n                    \n                }\n                \n                \n                \n                if (qdata.sections[s].questions[q].type==\"html\") {\n                    \n                    oot += '<br><br><div class=\"form-control htmlinput\" style=\"height:fit-content\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    oot += decodeURIComponent('' + v + '')\n                    oot += '</div>';\n                \n                }\n                \n                \n                oot += '<table width=\"100%\"><tr><td width=\"80%\">';\n                \n                if (qdata.sections[s].questions[q].jsonQ) {\n                    \n                    \n                    oot += '<textarea class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    //oot += ('' + v + '').replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                    oot += decodeURIComponent('' + v + '')\n                    oot += '</textarea>';\n                    \n                } \n                \n                else if (qdata.sections[s].questions[q].type==\"html\") {\n                    \n                    oot += '';\n                    \n                   \n                \n                }\n                    \n                else if (qdata.sections[s].questions[q].type==\"boolean\") {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                      if (v==\"true\") { oot += '<option value=\"false\">No</option><option value=\"true\" selected>Yes</option>'; }\n                      else if (v==\"false\")  { oot += '<option value=\"false\" selected>No</option><option value=\"true\">Yes</option>'; }\n                      else  { oot += '<option value=\"\"></option><option value=\"false\">No</option><option value=\"true\">Yes</option>'; }\n                    oot += '</select>';\n                    \n                } else if (qdata.sections[s].questions[q].options) {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    if (v==\"\") { oot += '<option value=\"\"></option>'; }\n                    for (var opt in qdata.sections[s].questions[q].options) {\n                    \n                      var optobj = qdata.sections[s].questions[q].options[opt];\n                      \n                      \n                      if (v==optobj.value) { oot += '<option selected value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      else  { oot += '<option value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      \n                    }  \n                    oot += '</select>';\n                    \n                }  else {\n                \n                    oot += '<input id=\"' + qdata.sections[s].questions[q].id + '\" name=\"' + qdata.sections[s].questions[q].id + '\" class=\"form-control\" type=\"text\"';\n                    if (v!==\"\") { oot += (' value=\"' + v + '\"').replace(/\\%20/g,\" \").replace(/_/g,\" \"); }\n                    if (qdata.sections[s].questions[q].default) { \n                        \n                        oot += ' placeholder=\"' + Mustache.render(\"\"+qdata.sections[s].questions[q].default, calculated)  + \" \" + (qdata.sections[s].questions[q].units||\"\") + ' ... please confirm\"'; \n                        \n                    }\n                    oot += '>';\n                }\n                \n                oot += '</td><td valign=\"top\"><span class=\"qunits\">' + (qdata.sections[s].questions[q].units||\"\") + '</span></td></tr></table>';\n                \n                \n                \n                oot += '</div>\\n';\n            }\n        }\n    \n        oot += '<table width=\"100%\"><tr><td width=\"100%\" align=\"right\"><button class=\"mybutt\" type=\"submit\">Submit</button></td></tr></table>';\n\n        oot += \"</div>\\n\";\n       \n        \n        var outhtml = \"\";   \n        for (var q in qdata.sections[s].outputs) {\n            \n            var qif = qdata.sections[s].outputs[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n\n            if(goq && (calcsString||\"\")!==\"\") {\n                \n                var calcfr = \"\";\n                //if (!objects[qdata.sections[s].outputs[q].id]) { objects[qdata.sections[s].outputs[q].id] = {}; }\n                \n                if (qdata.sections[s].outputs[q].type==\"wiki\") { \n                    \n                    var oid = 'output'+qdata.sections[s].outputs[q].id;\n                    \n                    //qdata.sections[s].outputs[q].url\n                    //http://heatweb.co.uk/w/index.php?title=The_DATA_HIU#Description\n                    \n                    qdata.sections[s].outputs[q].url = qdata.sections[s].outputs[q].url.replace(\"http://heatweb.co.uk/w/index.php?title=\",\"\").replace(\"https://heatweb.co.uk/w/index.php?title=\",\"\")\n                    \n                    var wikilocal = \"hnoutputs/wiki?id=\" + qdata.sections[s].outputs[q].id + \"&des=\" + qdata.sections[s].outputs[q].title.replace(/ /g,\"_\") + \"&title=\" + qdata.sections[s].outputs[q].url.split(\"#\")[0];\n                    if(qdata.sections[s].outputs[q].url.split(\"#\")[1]) { wikilocal += \"&section=\" + qdata.sections[s].outputs[q].url.split(\"#\")[1]; }\n                    \n                    var nn = \"\"+ qdata.sections[s].outputs[q].id;\n                    var des = \"\" + qdata.sections[s].outputs[q].title;\n                    \n                    \n                    \n                    $.ajax({\n                        url: wikilocal, \n                        type: \"GET\",      \n                        data: {},     \n                        cache: false,\n                        success: function(results){   \n                            \n                            \n                            var obid = results.split('obid=\"')[1].split('\"')[0];\n                            var des = results.split('title=\"')[1].split('\"')[0];\n                            \n                            console.log('#'+obid);\n                            console.log(results);\n                            var opb = document.querySelector('#output'+obid);\n                            opb.innerHTML = results || \"No Data\"; //JSON.stringify(qdata) ;\n                            //document.getElementById(\"output\"+qdata.sections[s].outputs[q].id).innerHTML = results || \"No Data\"; //JSON.stringify(qdata) \n                            \n                            feImages(results);\n                            \n                            var myob = {};\n                            myob.id = obid;\n                            myob.filename = obid + \".html\";\n                            myob.page = des;\n                            myob.type = \"text/html\";\n                            myob.value = \"\" + results;\n                            try { setObject(obid, myob); } catch {}\n                            myob = null;\n                            \n                            \n                            \n                        }           \n                    });    \n                    \n                    \n                    //calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].outputs[q].url + (qdata.sections[s].outputs[q].url.indexOf(\"?\")>0?'':'?') + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].outputs[q].style ? qdata.sections[s].outputs[q].style:'width:100%; height:300px;') + '\"></iframe>'\n                    calcfr = '<div id=\"output'+qdata.sections[s].outputs[q].id + '\">waiting... ' + qdata.sections[s].outputs[q].id + '</div>'\n                    \n                    outhtml += '<div class=\"outputbox\">';\n                    outhtml += \"<table width='100%'><tr><td><b>WIKI: \" + qdata.sections[s].outputs[q].title + \"</b></td>\\n\";\n                    \n                    if (qdata.sections[s].outputs[q].buttons) { \n                        \n                        outhtml += '<td align=\"right\">';\n                        for (var btn in qdata.sections[s].outputs[q].buttons) {\n                            \n                            outhtml += '<span class=\"mybutt\" onclick=\"' + qdata.sections[s].outputs[q].buttons[btn].onClick + '\">' + qdata.sections[s].outputs[q].buttons[btn].text + '</span> ';\n                        }\n                        outhtml += '</td>';\n                    }\n                    \n                    outhtml += '</tr></table><br>';\n                    \n                    outhtml += calcfr ; \n                    \n                    \n                    \n                    outhtml += \"</div>\\n\";\n                }\n                else if (qdata.sections[s].outputs[q].url) { \n                    \n                    calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].outputs[q].url + (qdata.sections[s].outputs[q].url.indexOf(\"?\")>0?'':'?') + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].outputs[q].style ? qdata.sections[s].outputs[q].style:'width:100%; height:300px;') + '\"></iframe>'\n                    \n                    outhtml += '<div class=\"outputbox\">';\n                    outhtml += \"<table width='100%'><tr><td><b>\" + qdata.sections[s].outputs[q].title + \"</b></td>\\n\";\n                    \n                    if (qdata.sections[s].outputs[q].buttons) { \n                        \n                        outhtml += '<td align=\"right\">';\n                        for (var btn in qdata.sections[s].outputs[q].buttons) {\n                            \n                            outhtml += '<span class=\"mybutt\" onclick=\"' + qdata.sections[s].outputs[q].buttons[btn].onClick + '\">' + qdata.sections[s].outputs[q].buttons[btn].text + '</span> ';\n                        }\n                        outhtml += '</td>';\n                    }\n                    \n                    outhtml += '</tr></table><br>';\n                    \n                    outhtml += calcfr ; \n                    \n                    \n                    \n                    outhtml += \"</div>\\n\";\n                }\n            \n            }\n        }\n        \n        if (outhtml!==\"\") {\n            \n            //oot += '<div class=\"outputbox\">';\n            oot += outhtml;\n            //oot += \"</div>\\n\";\n        }\n        \n        \n        \n        \n        \n        if (document.getElementById(\"oneS\").checked==true && (currentSection != qdata.sections[s].title)) {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n        else if (ootcount>0) {  ootoot += \"<div class='section'>\" + oot; }\n        \n        else {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n    }\n    inputsOut +=  \"</table>\\n\";  \n    \n    return ootoot;\n}\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\n// console.log(looseJsonParse(\n//   \"{a:(4-1), b:function(){}, c:new Date()}\"\n// ))\n\nfunction runCalcs() {\n\n\n    calcsString = \"\";\n    \n    // run through form inputs and store current values into calculated.\n    var cells =  document.getElementsByClassName(\"form-control\");\n\tvar i;\n\tfor (i = 0; i < cells.length; i++) {\n\t\n\t    \n\t    \n\t\n\t\tcalcsOut += cells[i].value + \"<br>\\n\";\n        \n        if (\"\" + cells[i].value !== \"\") { \n            \n            if (isNaN(cells[i].value)) { \n                \n                if ((cells[i].classList+\" \").indexOf(\"htmlinput\")>-1) {     // && cells[i].classList.indexOf(\"ck\")>-1\n                    \n                    calculated[cells[i].id] = cells[i].innerHTML;\n                }\n                else {\n                    \n                    calculated[cells[i].id] = (cells[i].value);\n                \n                    if ((calculated[cells[i].id]+\" \").substr(0,1)==\"{\" || (calculated[cells[i].id]+\" \").substr(0,1)==\"[\") {    // detect objects in textboxes\n                        \n                        try  { calculated.objects[cells[i].id] = JSON.parse(calculated[cells[i].id]) } catch {  }\n                    }\n                \n                }\n               \n                \n            } else {\n                \n                calculated[cells[i].id] = parseFloat(cells[i].value);\n            }\n            \n            calcsString += \"&\" + cells[i].id + \"=\" + cells[i].value;\n        }\n\t}\n\t\n    var calcsOut = '<table class=\"table\">';\n    \n    //calculated.objects = objects;\n    \n    // ================== Sheet Custom Calculations\n    \n    \n    if (calculated['loadSchedule']) {\n        \n        console.log(\"Load Schedule = \" + calculated['loadSchedule']);\n        \n        \n            \n            var cv1 = calculated['loadSchedule'];\n            var cv = 0;\n            var np = 0;\n            var kwCHMax = 0;\n            \n            var ldata=[];\n            \n            if((\"\"+cv1)!==\"\") {\n                \n                var vv = (\"\"+cv1).replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                var lns = vv.split(\", \");\n                for (var lnsv in lns) {\n                    ldata.push(lns[lnsv].split(\",\"));\n                    \n                    cv = cv + parseFloat(lns[lnsv].split(\",\")[4])\n                    \n                    np = np + (parseFloat(lns[lnsv].split(\",\")[2]) * parseFloat(lns[lnsv].split(\",\")[4]));\n                    \n                    kwCHMax = kwCHMax + (parseFloat(lns[lnsv].split(\",\")[3]) * parseFloat(lns[lnsv].split(\",\")[4]));\n                    \n                    \n                }\n            }\n            \n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total Properties</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">properties</td></tr>\\n';\n            \n            calculated['nProperties'] = cv;\n            calcsString += \"&nProperties=\" + cv;\n            \n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total People</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + np + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">people</td></tr>\\n';\n            \n            calculated['nPeople'] = np;\n            calcsString += \"&nPeople=\" + np;\n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total of central heating outputs</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + kwCHMax + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">kW</td></tr>\\n';\n            \n            calculated['kwCHMax'] = kwCHMax;\n            calcsString += \"&kwCHMax=\" + kwCHMax;\n            \n        \n        \n    }\n    \n    \n    // ================================\n    \n    \n    for (var calc in (qdata[\"calculations\"]||[])) {\n        \n        console.log(calc);\n        console.log(qdata.calculations[calc]);\n        \n        var cif = qdata.calculations[calc].if || true;\n        var cift = Mustache.render(cif, calculated);\n        var goc = true;\n        try {\n          goc = looseJsonParse(cift); \n        }\n        catch(err) {\n          goc = false;\n        }\n        \n        if (goc) {\n            \n            var f = qdata.calculations[calc].function;\n            var ft = Mustache.render(f, calculated);\n            \n            calcsOut += \"<tr>\";  //<td>\" + qdata.calculations[calc].id + \"</td>\";\n            calcsOut += \"<td>\";\n            \n            var cOs1 = \"\";  var cOs2 = \"\";\n            \n            if (document.getElementById(\"hideID\").checked!==true) {\n                cOs2 = \" <small>[<i>\" + qdata.calculations[calc].id + \"</i>]</small>\";  \n            }\n            \n            calcsOut += cOs1 + (qdata.calculations[calc].title||qdata.calculations[calc].id) + cOs2 + \"</td>\";\n            \n            //calcsOut += f + \" = \";\n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small>\" + ft.replace(/\\,/g,\", \") + \"</small></td>\";   //\"<br>\\n\";\n            }\n            \n            var cv = \"\";\n            try {\n              cv = looseJsonParse(ft); //  looseJsonParse(\"{a:(4-1), b:function(){}, c:new Date()}\");\n            }\n            catch(err) {\n              \n            }\n             \n            \n            if (!isNaN(cv)) { cv = parseInt(cv*1000)/1000; }\n            \n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            \n            calcsOut +=  '<td width=\"14%\">' + (qdata.calculations[calc].units||\"\") + \"</td></tr>\\n\";\n            \n            calculated[qdata.calculations[calc].id] = cv;\n            calcsString += \"&\" + qdata.calculations[calc].id + \"=\" + cv;\n        }\n        \n    }\n    \n    calcsOut +=  \"</table>\\n\";\n    \n    // for (var calc in calculated) {\n        \n        \n    // }\n    \n    document.getElementById(\"calcs\").innerHTML = calcsOut; //JSON.stringify(qdata) ;\n    \n    // rebuild form\n    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"inputs\").innerHTML = inputsOut; //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"mylink\").innerHTML = '<a href=\"hndesign?' + inputString + '\" target=\"_blank\">Open/share design...</a>'; //JSON.stringify(qdata) ;\n    \n    if(document.getElementById(\"description\")) {  // work in progress - need to link to all\n        InlineEditor\n                .create( document.querySelector( '#description' ) )\n                .catch( error => {\n                    console.error( error );\n                } );\n        \n        for (var sht in initsheets) {  initSheet(initsheets[sht]);   }\n    }\n    \n    validform();\n                    \n}\n\n\nconst convertLinks = ( input ) => {\n\n  let text = input;\n  const linksFound = text.match( /(?:www|https?)[^\\s]+/g );\n  const aLink = [];\n\n  if ( linksFound != null ) {\n\n    for ( let i=0; i<linksFound.length; i++ ) {\n      let replace = linksFound[i];\n      if ( !( linksFound[i].match( /(http(s?)):\\/\\// ) ) ) { replace = 'http://' + linksFound[i] }\n      let linkText = replace.split( '/' )[2];\n      if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) }\n      if ( linkText.match( /youtu/ ) ) {\n\n        let youtubeID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://www.youtube.com/embed/' + youtubeID + '\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe></div>' )\n      }\n      else if ( linkText.match( /vimeo/ ) ) {\n        let vimeoID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://player.vimeo.com/video/' + vimeoID + '\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' )\n      }\n      else {\n        aLink.push( '<a href=\"' + replace + '\" target=\"_blank\">' + linkText + '</a>' );\n      }\n      text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] );\n    }\n    return text;\n\n  }\n  else {\n    return input;\n  }\n}\n\nfunction validform() {\n    \n    if(hasFocus && document.getElementById(hasFocus)) {\n        document.getElementById(hasFocus).focus();\n    }\n    \n    \n    \n// Initialize form validation on the registration form.\n  // It has the name attribute \"registration\"\n  $(\"form[name='qform']\").validate({\n    // Specify validation rules\n    rules: {\n      // The key name on the left side is the name attribute\n      // of an input field. Validation rules are defined\n      // on the right side\n    //   nProperties: {\n    //     required: true,\n    //     digits: true,\n    //     min: 1\n    //   },\n      lastname: \"required\",\n      email: {\n        required: true,\n        // Specify that email should be validated\n        // by the built-in \"email\" rule\n        email: true\n      },\n      password: {\n        required: true,\n        minlength: 5\n      }\n    },\n    // Specify validation error messages\n    messages: {\n      nProperties: \"Please enter a number.\",\n      lastname: \"Please enter your lastname\",\n      password: {\n        required: \"Please provide a password\",\n        minlength: \"Your password must be at least 5 characters long\"\n      },\n      email: \"Please enter a valid email address\"\n    },\n    // Make sure the form is submitted to the destination defined\n    // in the \"action\" attribute of the form when valid\n    submitHandler: function(form) {\n      //form.submit();\n      runCalcs();\n      //alert(\"hello\");\n    }\n  });\n}\n\n</script>\n\n\n<div class='section'>\n    \n    <table width=\"100%\"><tr>\n    <td valign=\"top\" width=\"70%\">\n        <div id=\"formName\" class=\"h1\"></div>\n        <a href=\"https://heatweb.co.uk/w/index.php?title=Heat_Network_Designer\" target=\"_blank\"><small>Wiki Help Page</small></a>\n    </td>\n    <td width=\"30%\">\n        <input type=\"checkbox\" id=\"oneS\" name=\"oneS\" checked> <small>One section at a time</small><br>\n        <input type=\"checkbox\" id=\"oneQ\" name=\"oneQ\" checked> <small>One question at a time</small><br>\n        <input type=\"checkbox\" id=\"hideDone\" name=\"hideDone\" checked> <small>Hide completed questions</small><br>\n        <input type=\"checkbox\" id=\"hideMaths\" name=\"hideMaths\" checked> <small>Hide maths equations</small><br>\n        <input type=\"checkbox\" id=\"hideID\" name=\"hideID\" checked> <small>Hide IDs</small>\n    </td>\n    </tr></table>\n</div>\n\n\n<form action=\"\" name=\"qform\" id=\"qform\">\n<div id=\"section1\"></div>\n\n<div class='section'>\n\n<table width=\"100%\"><tr><td><span class=\"mybutt\" onclick=\"onDownload()\">Download JSON</span> <span class=\"mybutt\" onclick=\"copyData()\">Copy Data</span> <span class=\"mybutt\" onclick=\"copylink()\">Copy Link</span> <span class=\"mybutt\" onclick=\"openlink()\">Open in New</span> <span class=\"mybutt\" onclick=\"shareTwitter()\">Tweet Design</span> <span  class=\"mybutt\"  onclick=\"showPDF()\">Generate PDF</span> <span class=\"mybutt\" onclick=\"downloadp()\">Download PDF</span> </td><td align=\"right\"><button class=\"mybutt\" type=\"submit\">Submit</button></td></tr></table>\n\n\n\n\n</div>\n\n\n    \n\n<div id=\"pdfframebox\" class='outputbox' style='padding: 0px; display:none;'>\n\n    <iframe  id=\"pdfframe\" width=\"100%\" height=\"1200px\"></iframe>\n\n</div>\n\n<script>\n\n\n    \n\n   function download(content, fileName, contentType) {\n       \n       if(!contentType) contentType = 'application/octet-stream';\n\t\t  const a = document.createElement(\"a\");\n\t\t  const file = new Blob([content], { type: contentType });\n\t\t  a.href = URL.createObjectURL(file);\n\t\t  a.download = fileName;\n\t\t  a.click();\n\t}\n\n\tfunction onDownload(){\n\t    \n\t    var jsonData = { \"url\": (window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString),\"calculated\": calculated, \"qdata\": qdata, \"objects\": objects };\n\t\tdownload(JSON.stringify(jsonData), \"hndesign.json\", \"text/plain\");\n\t}\n    \n   \n    \n    function copyData(){\n\t    \n\t    var jsonData = calculated ;\n\t\tnavigator.clipboard.writeText(JSON.stringify(jsonData));\n\t\talert(\"Data Copied to Clipboard\");\n\t}\n    \n    \n    function copylink() {\n        \n        //alert(window.location.href.split(\".svg\")[0]+\".svg&display=\"+displayed);\n        \n        navigator.clipboard.writeText(window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\"));  //\n        alert(\"Link Copied to Clipboard\");\n         \n    \n    }\n    \n    function openlink() {\n        \n        //alert(window.location.href.split(\".svg\")[0]+\".svg&display=\"+displayed);\n        \n        window.open(window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\"));  //\n        \n         \n    \n    }\n    \n    function shareTwitter() {       \n        \n        var text = \"My latest heat network design.\";\n        var url = window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\");\n        window.open('http://twitter.com/share?url='+encodeURIComponent(url)+'&text='+encodeURIComponent(text), '', 'left=0,top=0,width=550,height=450,personalbar=0,toolbar=0,scrollbars=0,resizable=0');\n\n    } \n\n</script>\n\n\n<div class='section'>\n<p><b>Inputs</b></p>\n<div id=\"inputs\" class=\"notes\"></div>\n</div>\n\n<div class='section'>\n<p><b>Numeric Values and Calculations</b></p>\n<div id=\"calcs\" class=\"notes\"></div>\n</div>\n\n\n<div class='section'>\n<p><b>Links</b><img style=\"padding:25px\" src=\"/files/images/heatwebsl.png\" width=\"200px\" align=\"right\"></p>\n<div id=\"mylink\" class=\"notes\"></div>\n<div id=\"links\" class=\"notes\"></div>\n\n\n\n</div>\n</form>\n\n\n\n\n <form id=\"nextform\" name=\"nextform\" method=\"post\" action=\"/api/print\" ajax=\"true\" target=\"result1\">\n    <input type=\"hidden\" id=\"svgtext\" name=\"svgtext\" value=\"\">\n    <input type=\"hidden\" id=\"svgfile\" name=\"svgfile\" value=\"\">\n    <input type=\"hidden\" id=\"show\" name=\"show\" value=\"\">\n    </form>\n <iframe width=\"100%\" frameborder=\"0\" id=\"result1\" name=\"result1\" style=\"display:none\"></iframe>\n\n<div id=\"headed\" style=\"display:none\">\n    <svg\n   xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n   xmlns:cc=\"http://creativecommons.org/ns#\"\n   xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n   xmlns:svg=\"http://www.w3.org/2000/svg\"\n   xmlns=\"http://www.w3.org/2000/svg\"\n   xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n   id=\"svg1156\"\n   version=\"1.1\"\n   viewBox=\"0 0 210 297\"\n   height=\"297mm\"\n   width=\"210mm\">\n  <defs\n     id=\"defs1150\" />\n  <metadata\n     id=\"metadata1153\">\n    <rdf:RDF>\n      <cc:Work\n         rdf:about=\"\">\n        <dc:format>image/svg+xml</dc:format>\n        <dc:type\n           rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\n        <dc:title></dc:title>\n      </cc:Work>\n    </rdf:RDF>\n  </metadata>\n  <g\n     id=\"layer1\">\n    <path\n       id=\"path973\"\n       d=\"M 4.7230732,285.08269 H 204.21415\"\n       style=\"opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1\" />\n    <image\n       width=\"33.573963\"\n       height=\"10.040811\"\n       preserveAspectRatio=\"none\"\n       xlink:href=\"data:image/png;base64,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 PAAAAABJRU5ErkJggg== \"\n       id=\"image970\"\n       x=\"6.2852573\"\n       y=\"5.9025064\" />\n    <path\n       id=\"path973-9\"\n       d=\"M 4.7230731,18.88226 H 204.21415\"\n       style=\"opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1\" />\n    <text\n       id=\"text1007\"\n       y=\"289.65405\"\n       x=\"108.3\"\n       style=\"font-style:normal;font-weight:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:2.82222223px;text-align:center;text-anchor:middle;stroke-width:0.26458332\"\n         y=\"289.65405\"\n         x=\"108.3\"\n         id=\"tspan1005\">Page {{pn}} of {{pc}}</tspan></text>\n    <text\n       id=\"text1007-5\"\n       y=\"9.4398441\"\n       x=\"203.11298\"\n       style=\"font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:4.23333311px;text-align:end;text-anchor:end;stroke-width:0.26458332\"\n         y=\"9.4398441\"\n         x=\"203.11298\"\n         id=\"tspan1005-2\">{{title}}</tspan></text>\n    <text\n       id=\"text1007-5-0\"\n       y=\"14.542536\"\n       x=\"203.11298\"\n       style=\"font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:3.17499995px;text-align:end;text-anchor:end;stroke-width:0.26458332\"\n         y=\"14.542536\"\n         x=\"203.11298\"\n         id=\"tspan1005-2-7\">{{subtitle}}</tspan></text>\n  </g>\n</svg>\n</div>\n\n\n\n<script>\n    \n\nvar filesLoaded = 0;\n\nvar files = {\n  img1: {\n    url: \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  },\n  img2: {\n    url: \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  },\n  img3: {\n    url:\n      \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  }\n};\n\nvar doc;\n\n\nfunction loadedFile(xhr) {\n  for (var file in files) {\n    if (files[file].url === xhr.responseURL) {\n      files[file].data = xhr.response;\n    }\n  }\n  filesLoaded += 1;\n  \n  console.log(xhr);\n  \n  if (filesLoaded == Object.keys(files).length) {\n    // showPDF();\n  }\n}\n\nfor (var file in files) {\n  files[file].xhr = new XMLHttpRequest();\n  files[file].xhr.onreadystatechange = function() {\n    if (this.readyState == 4 && this.status == 200) {\n      loadedFile(this);\n    }\n  };\n  files[file].xhr.responseType = \"arraybuffer\";\n  files[file].xhr.open(\"GET\", files[file].url);\n  files[file].xhr.send(null);\n}\n\nfunction prepImage (imid, imurl) {\n    \n       files[imid] = {};\n       files[imid][\"url\"] = imurl;\n    \n    //for (var file in files) {\n      files[imid].xhr = new XMLHttpRequest();\n      files[imid].xhr.onreadystatechange = function() {\n        if (this.readyState == 4 && this.status == 200) {\n          loadedFile(this);\n          console.log(files);\n        }\n      };\n      files[imid].xhr.responseType = \"arraybuffer\";\n      files[imid].xhr.open(\"GET\", files[imid].url);\n      files[imid].xhr.send(null);\n    //}\n   \n}\n\nfunction feImages(htmlt) {\n    \n    var bits = htmlt.split('src=\"');\n    //var hoot = \"\";\n    \n    var ic=0;\n    for (var i in bits) {\n        \n        ic++;\n        \n        if (ic>1) {  \n            \n            try {\n            \n                var src = bits[i].split('\"')[0];\n                \n                // bits[i] = bits[i].substr(bits[i].indexOf('\"'));\n                \n                var fn = src.substr(src.lastIndexOf(\"/\")+1);\n                fn = fn.replace(/ /g,\"_\").replace(/\\./g,\"_\").toLowerCase();\n                \n                console.log(fn + \" ... \" + src);\n                \n                prepImage (fn, src);\n                \n                //src = \"/ui/w/images/\" + src;\n                \n                // bits[i] = 'src=\"' + src + bits[i]; \n                \n                \n            } catch {}\n            \n            \n        }\n        \n        \n        //hoot += bits[i];\n    }\n\n}\n\n\nfunction showPDF() {\n    \n    var layoutP = {\n      layout: \"portrait\",\n      size: 'A4',\n      margins: {\n        top: 60,\n        bottom: 50,\n        left: 40,\n        right: 40\n      }\n    };\n    \n     doc = new PDFDocument(layoutP);\n       \n    var stream = doc.pipe(blobStream());\n\n    stream.on(\"finish\", function() {\n       // get a blob you can do whatever you like with\n      blob = stream.toBlob(\"application/pdf\");\n    \n      const url = stream.toBlobURL('application/pdf');\n      const iframe = document.querySelector('#pdfframe')\n      iframe.src = url;\n      \n      document.getElementById(\"pdfframebox\").style.display = 'block';\n      \n    });   \n   \n   var pc = 0;\n   var posy = 100;\n   var lastpage = \"-1\";\n   \n    //   doc.on('pageAdded', () => doc.fontSize(9).fillColor(\"black\").text(\"Page x of x\", 80, 750, {\"align\":\"left\", \"lineBreak\": false }).moveTo(30, 80));\n   \n   for (var oo in objects) {\n       \n       \n       if(posy>600 || objects[oo].page!==lastpage) {  \n           \n            pc++;\n            posy = 100;\n           \n            if (lastpage!==\"-1\") { doc.addPage(layoutP);  }\n           \n            doc.image(files.img1.data, 30, 30, { fit: [60, 120] });\n       \n            \n            doc.fontSize(9);\n            doc.font(\"Helvetica\");\n            doc.fillColor(\"black\").text(\"Heatweb Heat Network Designer\", 110, 30, {\"align\":\"right\"});\n            \n            doc.fontSize(11);\n            doc.font(\"Helvetica-BoldOblique\");\n            doc.fillColor(\"black\").text(objects[oo].page||objects[oo].id, 350, 44, {\"align\":\"right\"});\n           \n           doc\n            .moveTo(30, 65)\n            .lineTo(560, 65)\n            .stroke();\n            \n            doc\n            .moveTo(30, 805)\n            .lineTo(560, 805)\n            .stroke();\n            \n            doc.fontSize(9);\n            doc.font(\"Helvetica\");\n            doc.fillColor(\"black\").text(\"Thermal Integration Ltd. (Heatweb)   Tel. 0345 2411441   Email: newenquiries@heatweb.com   Website: heatweb.co.uk\", 30, 815, {\"align\":\"center\", \"lineBreak\": false });\n            \n            \n            doc.fontSize(18);\n            doc.font(\"Courier-Bold\"); \n            //#000077\n            doc.fillColor(\"black\").text(objects[oo].page||objects[oo].id, 40, 90, {\"align\":\"justify\", \"width\": 410});\n        }\n       \n        lastpage = objects[oo].page;\n       \n        doc.fontSize(12);\n        doc.moveDown();\n       \n        if (objects[oo].text) {\n        \n            doc.moveDown();\n            doc.fontSize(12);\n            doc.fillColor(\"black\");\n            doc.font(\"Helvetica\");\n            doc.text(objects[oo].text, {\n              width: 510,\n              align: 'justify'\n            }\n            );\n        \n        }\n        \n        if (objects[oo].type==\"image/jpeg\") {\n            \n            //doc.image(objects[oo].value, 50, posy, { fit: [500, 300] });\n            \n            \n             doc.moveDown();\n            doc.image(objects[oo].value, { width: 510 });\n            \n            posy = posy + 300;\n        }\n        else if (objects[oo].type==\"image/svg+xml\") {\n           \n            SVGtoPDF(doc,  objects[oo].value,5,150);\n            \n            posy = 9999;\n            \n        }\n        \n        else if (objects[oo].type==\"text/html\") {\n           \n            var secs = objects[oo].value.split(\"\\n\");\n            var inlist = false;\n            var lilist = [];\n            \n            var galleryW = 250;\n            var galleryH = 250;\n            var ingallery = false;\n            var nextX = 30;\n            var nextY = 100;\n            \n            console.log(secs);\n            \n            for (var sss in secs) { \n             \n                var txt = secs[sss].replace(/(<([^>]+)>)/gi, \"\");\n                txt = txt.replace(/&/g, \"&\");\n             \n                console.log(txt);\n                console.log(secs[sss]);\n                \n                if (secs[sss].substr(0,3)==\"<p>\")    {\n                    \n                    \n                    ingallery=false;\n                    \n                    doc.moveDown();\n                    doc.fontSize(12);\n                    doc.fillColor(\"black\");\n                    doc.font(\"Helvetica\");\n                    doc.text(txt, {\n                      width: 510,\n                      align: 'justify'\n                    }\n                    );\n                }\n                else if (secs[sss].indexOf(\"<h2\")>-1)    {\n                    \n                   \n                    ingallery=false;\n                    \n                    doc.moveDown();\n                    doc.moveDown();\n                    \n                    doc.fontSize(16);\n                    doc.fillColor(\"black\");\n                    doc.font(\"Helvetica-Bold\");\n                    doc.text(txt, {\n                      width: 510,\n                      align: 'justify'\n                    }\n                    );\n                    \n                } else if (secs[sss].indexOf(\"<h3\")>-1)    {\n                    \n                    \n                    ingallery=false;\n                    \n                    doc.moveDown();\n                    doc.moveDown();\n                    \n                    doc.fontSize(14);\n                    doc.fillColor(\"black\");\n                    doc.font(\"Helvetica-Bold\");\n                    doc.text(txt, {\n                      width: 510,\n                      align: 'justify'\n                    }\n                    );\n                }\n                else if (secs[sss].substr(0,3)==\"<ul\")    {\n                    \n                    \n                    \n                    console.log(\"<ul>\");\n                    inlist = true;\n                    ingallery=false;\n                    lilist.push(txt);\n                    \n                } else if (secs[sss].indexOf(\"<li>\")>-1)    {\n                    \n                    console.log(\"<li>\");\n                    inlist = true\n                    lilist.push(txt);\n                    \n                } \n                \n                if (secs[sss].indexOf(\"</ul>\")>-1)    {\n                    \n                    inlist = false;\n                    \n                    if(lilist.length>1 || lilist[0].length>1) {\n                    \n                        console.log(lilist);\n                        \n                        doc.moveDown();\n                        \n                        doc.fontSize(12);\n                        doc.fillColor(\"black\");\n                        doc.font(\"Helvetica\");\n                        doc.list(lilist, {\n                          width: 510,\n                          align: 'left',\n                          paragraphGap: 10\n                        }\n                        );\n                    \n                    }\n                    \n                    lilist=[];\n                }\n                \n                if (secs[sss].indexOf('src=\"')>-1)    {\n                    \n                    var imgbits  = secs[sss].split('src=\"')[1];\n                    var src = imgbits.split('\"')[0];\n                    \n                    console.log(\"imgbits... \" + imgbits);\n                    \n                    if (imgbits.indexOf('width=\"')>-1) {\n                        \n                        var fn = src.substr(src.lastIndexOf(\"/\")+1);\n                        fn = fn.replace(/ /g,\"_\").replace(/\\./g,\"_\").toLowerCase();\n                    \n                        if (files[fn].xhr.response) {\n                            \n                            var imgh = 510;  if (imgbits.indexOf('height=\"')>-1) { imgh = parseInt(imgbits.split('height=\"')[1].split('\"')[0]); }\n                            var imgw = 700;  if (imgbits.indexOf('width=\"')>-1) { imgw = parseInt(imgbits.split('width=\"')[1].split('\"')[0]); }\n                            \n                            console.log(\"WxH before... \" + imgw + \" x \" + imgh);\n                            \n                            //if (imgw > 250 && imgw < 700) { imgh = Math.max(350, imgh * 250/imgw); imgw = 250; ingallery=true; }\n                            if (imgw > 250 && imgw < 700) { imgh = galleryH; imgw = galleryW; ingallery=true; }\n                            \n                            if (imgw > 400) { imgw = 510; }\n                            if (imgh > 800) { imgh = 800; }\n                            \n                            console.log(\"WxH after... \" + imgw + \" x \" + imgh);\n                        \n                            if (ingallery) {\n                                \n                                doc.image(files[fn].xhr.response, nextX, nextY, { \"fit\": [imgw, imgh] });\n                                nextX = nextX + galleryW + 25;\n                                \n                            } else {\n                                \n                                doc.moveDown();\n                                doc.image(files[fn].xhr.response, { \"fit\": [imgw, imgh] });\n                            \n                                posy = posy + 300;\n                            }\n                            \n                        }\n                    }\n                }\n                \n                if (!ingallery) { nextX = doc.x;  nextY = doc.y;  }\n                \n            }\n            \n            posy = 9999;\n            \n        }\n        \n   }\n   \n \n\n  doc.end();\n}\n\nconst ppp = document.createElement(\"a\");\ndocument.body.appendChild(ppp);\nppp.style = \"display: none\";\n\nlet blob;\n\nfunction downloadp() {\n  if (!blob) return;\n  var url = window.URL.createObjectURL(blob);\n  ppp.href = url;\n  ppp.download = 'test.pdf';\n  ppp.click();\n  window.URL.revokeObjectURL(url);\n}\n\n\n\n</script>\n\n\n","output":"str","x":1240,"y":320,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"bbffb07b.30402","type":"template","z":"cce2bfaa.e5748","name":"Form Generator","field":"payload.body","fieldType":"msg","format":"html","syntax":"plain","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js\"></script>\n<!--https://www.sitepoint.com/basic-jquery-form-validation-tutorial/-->\n\n<script src=\"https://unpkg.com/mustache@latest\"></script>\n\n\n\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n\n<script src=\"https://cdn.ckeditor.com/ckeditor5/34.0.0/inline/ckeditor.js\"></script>\n\n<!--These need to be installed locally-->\n<script src=\"pdfkit.standalone.js\"></script>\n<script src=\"blob-stream.js\"></script>\n<script src=\"svg-to-pdfkit.js\"></script>\n\n\n<style>\n    \n  \n    .jexcel_content {\n        font-size: 14px;\n    }\n    \n    .jexcel {\n        white-space: normal;\n    }\n\n/*for wiki*/\nli.gallerybox {\n    \n    display: inline-block;\n}\n\n.mybutt {\n    padding-left: 6px;\n    padding-right: 6px;\n    padding-top: 4px;\n    padding-bottom: 4px;\n    margin-right: 3px;\n    font-size: 14px;\n    border-radius: 4px;\n    cursor: pointer;\n    background-color: #a4eba4;\n    border-color: #4aa55a;\n    border: solid;\n    border-width: 1px;\n    box-shadow: 2px 2px 3px 1px rgb(0 0 0 / 28%);\n}\n.mybutt:hover {\n  background-color: #dcffdc;\n}\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\ntextarea.form-control {\n    font-size: 0.9rem;\n}\n\n.outputbox {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #ffffff;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n    font-size: 16px;\n}\n\n.cframe {\n    border-radius: 0.25rem;\n    margin: 0px 0px 20px 0px;\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 3px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\nvar a = new Date();\nvar qdata;\nvar calculated = {};  calculated.objects = {};\nvar hasFocus;\nvar currentSection;\nvar inputsOut;\nvar inputString;\nvar calcsString;\nvar objects={}; \nvar sheets = {};\nvar sheetdata = {};\nvar initsheets;\n\n\t$(document).ready(function(e) {\n    \n        // $(\"form[ajax=true]\").submit(function(e) {\n            \n        //     //alert(\"submit\");\n            \n        //     e.preventDefault();\n        \n             \n            //var urlParams = new URLSearchParams(window.location.search);\n            //if (urlParams.get('display')) { loadstring = \",,\" + urlParams.get('display'); }\n\n            calculated[\"jsonQ\"] = \"hndesign\";\n\n            var urlParams = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParams) {\n                \n                calculated[urlParams[upa].split(\"=\")[0]] = decodeURIComponent(urlParams[upa].split(\"=\")[1]);\n                \n            }\n            \n            \n            \n            var form_data = {};\n            var form_url = \"/ui/qdata/\" + calculated[\"jsonQ\"];\n            var form_target = $(this).attr(\"target\") || \"result\";\n            var ftarget = \"#\" + form_target;\n            var form_method = \"GET\";\n            \n        //     $(\"#loadingimg\").show();\n            \n            $.ajax({\n                url: form_url, \n                type: form_method,      \n                data: form_data,     \n                cache: false,\n                success: function(results){   \n                    \n                    qdata = results;\n                    //qdata = JSON.parse(returnhtml);\n                    console.log(qdata);\n                   \n                    //if(urlParams['nBuildings']) { runCalcs(); runCalcs();  }\n                    runCalcs(); \n                    runCalcs();\n                    \n                    document.getElementById(\"formName\").innerHTML = qdata.title || \"Unamed Form\"; //JSON.stringify(qdata) ;\n                    \n                    // document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n                    \n                    // for (var sht in initsheets) {  initSheet(initsheets[sht]);   }\n                    \n                    // validform();\n                                  \n                }           \n            });    \n            \n        // });\n        \n      \n        \n    });\n\n\n    \nfunction tosvg(obid) {\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.svg\";\n    if (nn.indexOf(\".svg\")<0) { nn = nn + \".svg\"; }\n    \n    download( objects[obid].value, nn, \"image/svg+xml\")\n}\n  \n function jpegDownload(obid){\n\t    \n\t    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n        if (nn===null) { return(null); }\n        nn = nn || \"download.jpeg\";\n        if (nn.indexOf(\".jpeg\")<0) { nn = nn + \".jpeg\"; }\n        \n        var byteString = atob(objects[obid].value.split(',')[1]);\n        var mimeString = objects[obid].value.split(',')[0].split(':')[1].split(';')[0]\n\n        \n        // write the bytes of the string to an ArrayBuffer\n          var ab = new ArrayBuffer(byteString.length);\n        \n          // create a view into the buffer\n          var ia = new Uint8Array(ab);\n        \n          // set the bytes of the buffer to the correct values\n          for (var i = 0; i < byteString.length; i++) {\n              ia[i] = byteString.charCodeAt(i);\n          }\n        \n        download( ia , nn, mimeString)\n\t}\n\t\nfunction topdf(obid) {\n    \n    if (!objects[obid]) { return null; }\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.pdf\";\n    if (nn.indexOf(\".pdf\")<0) { nn = nn + \".pdf\"; }\n    \n    var headed = document.getElementById(\"headed\").innerHTML;\n    headed = headed.substr(headed.indexOf(\"<g\"));\n    headed = headed.substr(0,headed.lastIndexOf(\"</g>\")+4);\n    \n    var svgoot = objects[obid].value;\n    svgoot = svgoot.substr(svgoot.indexOf(\"<svg\"));\n    \n    var lg = svgoot.indexOf(\"<g\");\n    svgoot = svgoot.substr(0,lg) + '<g transform=\"translate(0,40)\">' + svgoot.substr(lg);\n    \n    lg = svgoot.lastIndexOf(\"</g>\")+4;\n    svgoot = svgoot.substr(0,lg) + \"</g>\" + headed + svgoot.substr(lg);\n    \n    var tits = {\"title\":\"Heatweb Heat Network Designer\",\"subtitle\":obid,\"pn\":\"1\",\"pc\":\"1\"}\n    svgoot = Mustache.render(svgoot, tits);\n    \n    //alert(svgoot);\n            $(\"#svgtext\").val(svgoot);\n            $(\"#svgfile\").val(nn);  //  + (new Date().getTime()) +\n            \n            $(\"#nextform\").submit(); \n            \n         \n}\n\nfunction topdf2(obid) {\n    \n    // without headed notepaper\n    \n    if (!objects[obid]) { return null; }\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.pdf\";\n    if (nn.indexOf(\".pdf\")<0) { nn = nn + \".pdf\"; }\n    \n    var svgoot = objects[obid].value;\n    svgoot = svgoot.substr(svgoot.indexOf(\"<svg\"));\n    \n    \n    \n    \n    //alert(svgoot);\n            $(\"#svgtext\").val(svgoot);\n            $(\"#svgfile\").val(nn);  //  + (new Date().getTime()) +\n            \n            $(\"#nextform\").submit(); \n            \n         \n}\n\n\n\n\n\nfunction initSheet(id) {\n\n    console.log(\"initSheet \" + id);\n    console.log(sheetdata);\n    \n    var shid = 'sheet-' + id;\n    var sdata = sheetdata[id];\n    \n    \n\n    try {\n    \n        document.getElementById(shid).innerHTML = \"\";\n        \n        sheets[id] = jspreadsheet(document.getElementById(shid), {\n            data: sdata.data,\n            columns: sdata.columns,\n            onchange: function(instance, cell, x, y, value) {\n                \n                console.log(value);\n                getSheetData(id);\n            },\n            updateTable:function(instance, cell, col, row, val, label, cellName) {\n               \n                //console.log(instance);\n                //console.log(val);\n                \n            },\n            columnSorting:false\n        });\n\n    } catch {}\n}\n\nfunction getSheetData(id) {\n    \n    \n    //alert(id);\n    \n    //console.log(sheets[id].getData());\n    \n    sheetdata[id].data = sheets[id].getData();\n    console.log(sheetdata);\n    \n    var oots = \"\";\n    for (var row in sheetdata[id].data) {\n       for (var c in sheetdata[id].data[row]) {\n           \n           var val = \"\" + (sheetdata[id].data[row][c] || \"\");\n           val = val.replace(/ /g,\"_\")\n           oots += val + \",\";\n        } \n        oots += \" \";\n    }\n    \n    oots = oots.substr(0, oots.length - 2);\n    console.log(oots);\n    \n    returncalc(id,oots)\n    \n    \n}\n\n\nfunction getObject(id) {\n    \n  \n    return (objects[id]||null);\n    \n}\n\n\nfunction setObject(id,value) {\n    \n\n    try { objects[id] = value; }\n    catch {}\n}\n\t\nfunction returncalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).value = value; }\n    catch {\n        \n        try { calculated[id] = value; }\n        catch {}\n    }\n    \n}\n\nfunction suggestcalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).placeholder = value + \" ... please confirm\"; }\n    catch {}\n}\n\t\nfunction parseQuestions(qdata) {\n    \n    console.log(qdata);\n    console.log(calculated);\n    \n    var linkstxt=\"\";\n    if (qdata.links) {\n        for (var lnk in qdata.links) {\n            linkstxt += (linkstxt!==\"\"?\"<br>\":\"\") + '<a href=\"' + qdata.links[lnk].src + '\" target=\"_blank\">' + (qdata.links[lnk].title||qdata.links[lnk].src) + '</a>';\n        }\n        \n    }\n    document.getElementById(\"links\").innerHTML = linkstxt ; //JSON.stringify(qdata) ;\n    \n    \n    inputsOut = '<input id=\"jsonQ\" name=\"jsonQ\" value=\"' + calculated[\"jsonQ\"] + '\" class=\"form-control\" type=\"hidden\">';\n                    \n    \n    inputsOut += '<table class=\"table\">';\n    \n    inputString = \"jsonQ=\" + calculated[\"jsonQ\"];  // data source for form is fixed\n    \n    hasFocus = null;\n    currentSection = null;\n    initsheets = [];\n    \n    var ootoot = \"\";\n    for (var s in qdata[\"sections\"]) {\n        console.log(s);\n        console.log(qdata.sections[s]);\n        \n        var oot = \"\";\n        var ootcount=0;\n        \n        //oot += \"<div class='section'><h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        oot += \"<h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        \n        \n        \n        for (var q in qdata.sections[s].questions) {\n            \n            \n            var qif = qdata.sections[s].questions[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n            var v=\"\";\n            if (calculated[qdata.sections[s].questions[q].id]) { v= calculated[qdata.sections[s].questions[q].id] ; }\n            else if (qdata.sections[s].questions[q].value) { v= qdata.sections[s].questions[q].value ; }\n            \n            if (v!==\"\") { qdata.sections[s].questions[q].value = v; }    // save answers back into json.\n            \n            \n            if(goq) {\n                \n                var calcfr = \"\";\n                if (qdata.sections[s].questions[q].calculator) { calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].questions[q].calculator + '?field=' + qdata.sections[s].questions[q].id + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].questions[q].calculatorStyle ? qdata.sections[s].questions[q].calculatorStyle:'width:100%; height:300px;') + '\"></iframe>'}\n            \n            \n                if (v!==\"\") { \n                    inputsOut += \"<tr>\";  \n                    \n                    var cOs1 = \"\";  var cOs2 = \"\";\n            \n                    if (document.getElementById(\"hideID\").checked!==true) {\n                        cOs2 = \" <small>[<i>\" + qdata.sections[s].questions[q].id + \"</i>]</small>\";  \n                    }\n                    \n                    inputsOut += '<td width=\"40%\">' + (qdata.sections[s].questions[q].title||qdata.sections[s].questions[q].id) + cOs2 + \"</td>\";\n                    \n                    var vs1=\"\"; var vs2=\"\";\n                    if((\"\"+v).indexOf(\",\") > -1) { vs1=\"<small>\"; vs2=\"</small>\"; }\n                    if((\"\"+v).indexOf(\"&\") > -1) { vs1=\"<small style='width:400px; word-wrap:break-word; display:inline-block;'>\"; vs2=\"</small>\"; }\n                    \n                    \n                    inputsOut +=  ('<td align=\"right\">' + vs1 + v + vs2 + \"</td>\").replace(/\\, /g,\"<br>\").replace(/\\,/g,\", \");\n                    inputsOut +=  '<td width=\"14%\">' + (qdata.sections[s].questions[q].units||\"\") + \"</td></tr>\\n\";\n                    \n                    inputString += (inputString!==\"\"?\"&\":\"\") + qdata.sections[s].questions[q].id + \"=\" + encodeURIComponent(v);\n                }\n            \n                var isDisplayed = false;\n            \n                if (hasFocus && document.getElementById(\"oneQ\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">'; }\n            \n                else if (v!==\"\") { \n                    \n                    if (document.getElementById(\"hideDone\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">';   }\n                    else {  oot += '<div class=\"question\" style=\"background-color: #d2efd2;\">'; ootcount++; isDisplayed=true; }\n                    \n                } else { oot += '<div class=\"question\">'; ootcount++; isDisplayed=true; if (!hasFocus) { hasFocus = qdata.sections[s].questions[q].id;  currentSection = qdata.sections[s].title;  } }\n                \n                \n                //oot += \"<div class='qtext'>\" + qdata.sections[s].questions[q].title + '</div>';\n                oot += '<label for=\"' + qdata.sections[s].questions[q].id + '\" class=\"qtext\">' + (qdata.sections[s].questions[q].question||qdata.sections[s].questions[q].title) + '</label>';\n                \n                if (calcfr!==\"\") { oot += \"\\n\" + calcfr + \"\\n\"; }\n                \n                if (qdata.sections[s].questions[q].notes) { oot += '<div class=\"notes\">'  + convertLinks(Mustache.render(qdata.sections[s].questions[q].notes, calculated)) + '</div>'; }\n                \n                if (qdata.sections[s].questions[q].type == \"sheet\") {\n                    \n                    oot += '<br><div id=\"sheet-' + qdata.sections[s].questions[q].id + '\">';\n                \n                    oot += '<span onclick=\"initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ')\"><small class=\"mybutt\">Load Sheet</small></span> ';\n                    \n                    oot += '</div><br><br>';\n                    \n                    //oot += '<script>initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ');</scrip' + 't> ';\n                    //var myTimeout = setTimeout(initSheet(qdata.sections[s].questions[q].id), 1000);\n                    if (isDisplayed) { initsheets.push(qdata.sections[s].questions[q].id); }\n                \n                    var shob = {};\n                    shob['columns'] = qdata.sections[s].questions[q].columns;\n                    shob['data'] = qdata.sections[s].questions[q].default;\n                    \n                    if((\"\"+v)!==\"\") {\n                        \n                        shob['data']=[];\n                        var vv = v.replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                        var lns = vv.split(\", \");\n                        for (var lnsv in lns) {\n                            shob['data'].push(lns[lnsv].split(\",\"));\n                        }\n                    }\n                    \n                    sheetdata[qdata.sections[s].questions[q].id] = shob;\n                    \n                }\n                \n                \n                \n                if (qdata.sections[s].questions[q].type==\"html\") {\n                    \n                    oot += '<br><br><div class=\"form-control htmlinput\" style=\"height:fit-content\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    oot += decodeURIComponent('' + v + '')\n                    oot += '</div>';\n                \n                }\n                \n                \n                oot += '<table width=\"100%\"><tr><td width=\"80%\">';\n                \n                if (qdata.sections[s].questions[q].jsonQ) {\n                    \n                    \n                    oot += '<textarea class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    //oot += ('' + v + '').replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                    oot += decodeURIComponent('' + v + '')\n                    oot += '</textarea>';\n                    \n                } \n                \n                else if (qdata.sections[s].questions[q].type==\"html\") {\n                    \n                    oot += '';\n                    \n                   \n                \n                }\n                    \n                else if (qdata.sections[s].questions[q].type==\"boolean\") {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                      if (v==\"true\") { oot += '<option value=\"false\">No</option><option value=\"true\" selected>Yes</option>'; }\n                      else if (v==\"false\")  { oot += '<option value=\"false\" selected>No</option><option value=\"true\">Yes</option>'; }\n                      else  { oot += '<option value=\"\"></option><option value=\"false\">No</option><option value=\"true\">Yes</option>'; }\n                    oot += '</select>';\n                    \n                } else if (qdata.sections[s].questions[q].options) {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    if (v==\"\") { oot += '<option value=\"\"></option>'; }\n                    for (var opt in qdata.sections[s].questions[q].options) {\n                    \n                      var optobj = qdata.sections[s].questions[q].options[opt];\n                      \n                      \n                      if (v==optobj.value) { oot += '<option selected value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      else  { oot += '<option value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      \n                    }  \n                    oot += '</select>';\n                    \n                }  else {\n                \n                    oot += '<input id=\"' + qdata.sections[s].questions[q].id + '\" name=\"' + qdata.sections[s].questions[q].id + '\" class=\"form-control\" type=\"text\"';\n                    if (v!==\"\") { oot += (' value=\"' + v + '\"').replace(/\\%20/g,\" \").replace(/_/g,\" \"); }\n                    if (qdata.sections[s].questions[q].default) { \n                        \n                        oot += ' placeholder=\"' + Mustache.render(\"\"+qdata.sections[s].questions[q].default, calculated)  + \" \" + (qdata.sections[s].questions[q].units||\"\") + ' ... please confirm\"'; \n                        \n                    }\n                    oot += '>';\n                }\n                \n                oot += '</td><td valign=\"top\"><span class=\"qunits\">' + (qdata.sections[s].questions[q].units||\"\") + '</span></td></tr></table>';\n                \n                \n                \n                oot += '</div>\\n';\n            }\n        }\n    \n        oot += '<table width=\"100%\"><tr><td width=\"100%\" align=\"right\"><button class=\"mybutt\" type=\"submit\">Submit</button></td></tr></table>';\n\n        oot += \"</div>\\n\";\n       \n        \n        var outhtml = \"\";   \n        for (var q in qdata.sections[s].outputs) {\n            \n            var qif = qdata.sections[s].outputs[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n\n            if(goq && (calcsString||\"\")!==\"\") {\n                \n                var calcfr = \"\";\n                //if (!objects[qdata.sections[s].outputs[q].id]) { objects[qdata.sections[s].outputs[q].id] = {}; }\n                \n                if (qdata.sections[s].outputs[q].type==\"wiki\") { \n                    \n                    var oid = 'output'+qdata.sections[s].outputs[q].id;\n                    \n                    //qdata.sections[s].outputs[q].url\n                    //http://heatweb.co.uk/w/index.php?title=The_DATA_HIU#Description\n                    \n                    qdata.sections[s].outputs[q].url = qdata.sections[s].outputs[q].url.replace(\"http://heatweb.co.uk/w/index.php?title=\",\"\").replace(\"https://heatweb.co.uk/w/index.php?title=\",\"\")\n                    \n                    var wikilocal = \"hnoutputs/wiki?id=\" + qdata.sections[s].outputs[q].id + \"&des=\" + qdata.sections[s].outputs[q].title.replace(/ /g,\"_\") + \"&title=\" + qdata.sections[s].outputs[q].url.split(\"#\")[0];\n                    if(qdata.sections[s].outputs[q].url.split(\"#\")[1]) { wikilocal += \"&section=\" + qdata.sections[s].outputs[q].url.split(\"#\")[1]; }\n                    \n                    var nn = \"\"+ qdata.sections[s].outputs[q].id;\n                    var des = \"\" + qdata.sections[s].outputs[q].title;\n                    \n                    \n                    \n                    $.ajax({\n                        url: wikilocal, \n                        type: \"GET\",      \n                        data: {},     \n                        cache: false,\n                        success: function(results){   \n                            \n                            \n                            var obid = results.split('obid=\"')[1].split('\"')[0];\n                            var des = results.split('title=\"')[1].split('\"')[0];\n                            \n                            console.log('#'+obid);\n                            console.log(results);\n                            var opb = document.querySelector('#output'+obid);\n                            opb.innerHTML = results || \"No Data\"; //JSON.stringify(qdata) ;\n                            //document.getElementById(\"output\"+qdata.sections[s].outputs[q].id).innerHTML = results || \"No Data\"; //JSON.stringify(qdata) \n                            \n                            feImages(results);\n                            \n                            var myob = {};\n                            myob.id = obid;\n                            myob.filename = obid + \".html\";\n                            myob.page = des;\n                            myob.type = \"text/html\";\n                            myob.value = \"\" + results;\n                            try { setObject(obid, myob); } catch {}\n                            myob = null;\n                            \n                            \n                            \n                        }           \n                    });    \n                    \n                    \n                    //calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].outputs[q].url + (qdata.sections[s].outputs[q].url.indexOf(\"?\")>0?'':'?') + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].outputs[q].style ? qdata.sections[s].outputs[q].style:'width:100%; height:300px;') + '\"></iframe>'\n                    calcfr = '<div id=\"output'+qdata.sections[s].outputs[q].id + '\">waiting... ' + qdata.sections[s].outputs[q].id + '</div>'\n                    \n                    outhtml += '<div class=\"outputbox\">';\n                    outhtml += \"<table width='100%'><tr><td><b>WIKI: \" + qdata.sections[s].outputs[q].title + \"</b></td>\\n\";\n                    \n                    if (qdata.sections[s].outputs[q].buttons) { \n                        \n                        outhtml += '<td align=\"right\">';\n                        for (var btn in qdata.sections[s].outputs[q].buttons) {\n                            \n                            outhtml += '<span class=\"mybutt\" onclick=\"' + qdata.sections[s].outputs[q].buttons[btn].onClick + '\">' + qdata.sections[s].outputs[q].buttons[btn].text + '</span> ';\n                        }\n                        outhtml += '</td>';\n                    }\n                    \n                    outhtml += '</tr></table><br>';\n                    \n                    outhtml += calcfr ; \n                    \n                    \n                    \n                    outhtml += \"</div>\\n\";\n                }\n                else if (qdata.sections[s].outputs[q].url) { \n                    \n                    calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].outputs[q].url + (qdata.sections[s].outputs[q].url.indexOf(\"?\")>0?'':'?') + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].outputs[q].style ? qdata.sections[s].outputs[q].style:'width:100%; height:300px;') + '\"></iframe>'\n                    \n                    outhtml += '<div class=\"outputbox\">';\n                    outhtml += \"<table width='100%'><tr><td><b>\" + qdata.sections[s].outputs[q].title + \"</b></td>\\n\";\n                    \n                    if (qdata.sections[s].outputs[q].buttons) { \n                        \n                        outhtml += '<td align=\"right\">';\n                        for (var btn in qdata.sections[s].outputs[q].buttons) {\n                            \n                            outhtml += '<span class=\"mybutt\" onclick=\"' + qdata.sections[s].outputs[q].buttons[btn].onClick + '\">' + qdata.sections[s].outputs[q].buttons[btn].text + '</span> ';\n                        }\n                        outhtml += '</td>';\n                    }\n                    \n                    outhtml += '</tr></table><br>';\n                    \n                    outhtml += calcfr ; \n                    \n                    \n                    \n                    outhtml += \"</div>\\n\";\n                }\n            \n            }\n        }\n        \n        if (outhtml!==\"\") {\n            \n            //oot += '<div class=\"outputbox\">';\n            oot += outhtml;\n            //oot += \"</div>\\n\";\n        }\n        \n        \n        \n        \n        \n        if (document.getElementById(\"oneS\").checked==true && (currentSection != qdata.sections[s].title)) {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n        else if (ootcount>0) {  ootoot += \"<div class='section'>\" + oot; }\n        \n        else {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n    }\n    inputsOut +=  \"</table>\\n\";  \n    \n    return ootoot;\n}\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\n// console.log(looseJsonParse(\n//   \"{a:(4-1), b:function(){}, c:new Date()}\"\n// ))\n\nfunction runCalcs() {\n\n\n    calcsString = \"\";\n    \n    // run through form inputs and store current values into calculated.\n    var cells =  document.getElementsByClassName(\"form-control\");\n\tvar i;\n\tfor (i = 0; i < cells.length; i++) {\n\t\n\t    \n\t    \n\t\n\t\tcalcsOut += cells[i].value + \"<br>\\n\";\n        \n        if (\"\" + cells[i].value !== \"\") { \n            \n            if (isNaN(cells[i].value)) { \n                \n                if ((cells[i].classList+\" \").indexOf(\"htmlinput\")>-1) {     // && cells[i].classList.indexOf(\"ck\")>-1\n                    \n                    calculated[cells[i].id] = cells[i].innerHTML;\n                }\n                else {\n                    \n                    calculated[cells[i].id] = (cells[i].value);\n                \n                    if ((calculated[cells[i].id]+\" \").substr(0,1)==\"{\" || (calculated[cells[i].id]+\" \").substr(0,1)==\"[\") {    // detect objects in textboxes\n                        \n                        try  { calculated.objects[cells[i].id] = JSON.parse(calculated[cells[i].id]) } catch {  }\n                    }\n                \n                }\n               \n                \n            } else {\n                \n                calculated[cells[i].id] = parseFloat(cells[i].value);\n            }\n            \n            calcsString += \"&\" + cells[i].id + \"=\" + cells[i].value;\n        }\n\t}\n\t\n    var calcsOut = '<table class=\"table\">';\n    \n    //calculated.objects = objects;\n    \n    // ================== Sheet Custom Calculations\n    \n    \n    if (calculated['loadSchedule']) {\n        \n        console.log(\"Load Schedule = \" + calculated['loadSchedule']);\n        \n        \n            \n            var cv1 = calculated['loadSchedule'];\n            var cv = 0;\n            var np = 0;\n            var kwCHMax = 0;\n            \n            var ldata=[];\n            \n            if((\"\"+cv1)!==\"\") {\n                \n                var vv = (\"\"+cv1).replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                var lns = vv.split(\", \");\n                for (var lnsv in lns) {\n                    ldata.push(lns[lnsv].split(\",\"));\n                    \n                    cv = cv + parseFloat(lns[lnsv].split(\",\")[4])\n                    \n                    np = np + (parseFloat(lns[lnsv].split(\",\")[2]) * parseFloat(lns[lnsv].split(\",\")[4]));\n                    \n                    kwCHMax = kwCHMax + (parseFloat(lns[lnsv].split(\",\")[3]) * parseFloat(lns[lnsv].split(\",\")[4]));\n                    \n                    \n                }\n            }\n            \n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total Properties</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">properties</td></tr>\\n';\n            \n            calculated['nProperties'] = cv;\n            calcsString += \"&nProperties=\" + cv;\n            \n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total People</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + np + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">people</td></tr>\\n';\n            \n            calculated['nPeople'] = np;\n            calcsString += \"&nPeople=\" + np;\n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total of central heating outputs</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + kwCHMax + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">kW</td></tr>\\n';\n            \n            calculated['kwCHMax'] = kwCHMax;\n            calcsString += \"&kwCHMax=\" + kwCHMax;\n            \n        \n        \n    }\n    \n    \n    // ================================\n    \n    \n    for (var calc in (qdata[\"calculations\"]||[])) {\n        \n        console.log(calc);\n        console.log(qdata.calculations[calc]);\n        \n        var cif = qdata.calculations[calc].if || true;\n        var cift = Mustache.render(cif, calculated);\n        var goc = true;\n        try {\n          goc = looseJsonParse(cift); \n        }\n        catch(err) {\n          goc = false;\n        }\n        \n        if (goc) {\n            \n            var f = qdata.calculations[calc].function;\n            var ft = Mustache.render(f, calculated);\n            \n            calcsOut += \"<tr>\";  //<td>\" + qdata.calculations[calc].id + \"</td>\";\n            calcsOut += \"<td>\";\n            \n            var cOs1 = \"\";  var cOs2 = \"\";\n            \n            if (document.getElementById(\"hideID\").checked!==true) {\n                cOs2 = \" <small>[<i>\" + qdata.calculations[calc].id + \"</i>]</small>\";  \n            }\n            \n            calcsOut += cOs1 + (qdata.calculations[calc].title||qdata.calculations[calc].id) + cOs2 + \"</td>\";\n            \n            //calcsOut += f + \" = \";\n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small>\" + ft.replace(/\\,/g,\", \") + \"</small></td>\";   //\"<br>\\n\";\n            }\n            \n            var cv = \"\";\n            try {\n              cv = looseJsonParse(ft); //  looseJsonParse(\"{a:(4-1), b:function(){}, c:new Date()}\");\n            }\n            catch(err) {\n              \n            }\n             \n            \n            if (!isNaN(cv)) { cv = parseInt(cv*1000)/1000; }\n            \n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            \n            calcsOut +=  '<td width=\"14%\">' + (qdata.calculations[calc].units||\"\") + \"</td></tr>\\n\";\n            \n            calculated[qdata.calculations[calc].id] = cv;\n            calcsString += \"&\" + qdata.calculations[calc].id + \"=\" + cv;\n        }\n        \n    }\n    \n    calcsOut +=  \"</table>\\n\";\n    \n    // for (var calc in calculated) {\n        \n        \n    // }\n    \n    document.getElementById(\"calcs\").innerHTML = calcsOut; //JSON.stringify(qdata) ;\n    \n    // rebuild form\n    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"inputs\").innerHTML = inputsOut; //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"mylink\").innerHTML = '<a href=\"hndesign?' + inputString + '\" target=\"_blank\">Open/share design...</a>'; //JSON.stringify(qdata) ;\n    \n    if(document.getElementById(\"description\")) {  // work in progress - need to link to all\n        InlineEditor\n                .create( document.querySelector( '#description' ) )\n                .catch( error => {\n                    console.error( error );\n                } );\n        \n        for (var sht in initsheets) {  initSheet(initsheets[sht]);   }\n    }\n    \n    validform();\n                    \n}\n\n\nconst convertLinks = ( input ) => {\n\n  let text = input;\n  const linksFound = text.match( /(?:www|https?)[^\\s]+/g );\n  const aLink = [];\n\n  if ( linksFound != null ) {\n\n    for ( let i=0; i<linksFound.length; i++ ) {\n      let replace = linksFound[i];\n      if ( !( linksFound[i].match( /(http(s?)):\\/\\// ) ) ) { replace = 'http://' + linksFound[i] }\n      let linkText = replace.split( '/' )[2];\n      if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) }\n      if ( linkText.match( /youtu/ ) ) {\n\n        let youtubeID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://www.youtube.com/embed/' + youtubeID + '\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe></div>' )\n      }\n      else if ( linkText.match( /vimeo/ ) ) {\n        let vimeoID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://player.vimeo.com/video/' + vimeoID + '\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' )\n      }\n      else {\n        aLink.push( '<a href=\"' + replace + '\" target=\"_blank\">' + linkText + '</a>' );\n      }\n      text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] );\n    }\n    return text;\n\n  }\n  else {\n    return input;\n  }\n}\n\nfunction validform() {\n    \n    if(hasFocus && document.getElementById(hasFocus)) {\n        document.getElementById(hasFocus).focus();\n    }\n    \n    \n    \n// Initialize form validation on the registration form.\n  // It has the name attribute \"registration\"\n  $(\"form[name='qform']\").validate({\n    // Specify validation rules\n    rules: {\n      // The key name on the left side is the name attribute\n      // of an input field. Validation rules are defined\n      // on the right side\n    //   nProperties: {\n    //     required: true,\n    //     digits: true,\n    //     min: 1\n    //   },\n      lastname: \"required\",\n      email: {\n        required: true,\n        // Specify that email should be validated\n        // by the built-in \"email\" rule\n        email: true\n      },\n      password: {\n        required: true,\n        minlength: 5\n      }\n    },\n    // Specify validation error messages\n    messages: {\n      nProperties: \"Please enter a number.\",\n      lastname: \"Please enter your lastname\",\n      password: {\n        required: \"Please provide a password\",\n        minlength: \"Your password must be at least 5 characters long\"\n      },\n      email: \"Please enter a valid email address\"\n    },\n    // Make sure the form is submitted to the destination defined\n    // in the \"action\" attribute of the form when valid\n    submitHandler: function(form) {\n      //form.submit();\n      runCalcs();\n      //alert(\"hello\");\n    }\n  });\n}\n\n</script>\n\n\n<div class='section'>\n    \n    <table width=\"100%\"><tr>\n    <td valign=\"top\" width=\"70%\">\n        <div id=\"formName\" class=\"h1\"></div>\n        <a href=\"https://heatweb.co.uk/w/index.php?title=Heat_Network_Designer\" target=\"_blank\"><small>Wiki Help Page</small></a>\n    </td>\n    <td width=\"30%\">\n        <input type=\"checkbox\" id=\"oneS\" name=\"oneS\" checked> <small>One section at a time</small><br>\n        <input type=\"checkbox\" id=\"oneQ\" name=\"oneQ\" checked> <small>One question at a time</small><br>\n        <input type=\"checkbox\" id=\"hideDone\" name=\"hideDone\" checked> <small>Hide completed questions</small><br>\n        <input type=\"checkbox\" id=\"hideMaths\" name=\"hideMaths\" checked> <small>Hide maths equations</small><br>\n        <input type=\"checkbox\" id=\"hideID\" name=\"hideID\" checked> <small>Hide IDs</small>\n    </td>\n    </tr></table>\n</div>\n\n\n<form action=\"\" name=\"qform\" id=\"qform\">\n<div id=\"section1\"></div>\n\n<div class='section'>\n\n<table width=\"100%\"><tr><td><span class=\"mybutt\" onclick=\"onDownload()\">Download JSON</span> <span class=\"mybutt\" onclick=\"copyData()\">Copy Data</span> <span class=\"mybutt\" onclick=\"copylink()\">Copy Link</span> <span class=\"mybutt\" onclick=\"openlink()\">Open in New</span> <span class=\"mybutt\" onclick=\"shareTwitter()\">Tweet Design</span> <span  class=\"mybutt\"  onclick=\"showPDF()\">Generate PDF</span> <span class=\"mybutt\" onclick=\"downloadp()\">Download PDF</span> </td><td align=\"right\"><button class=\"mybutt\" type=\"submit\">Submit</button></td></tr></table>\n\n\n\n\n</div>\n\n\n    \n\n<div id=\"pdfframebox\" class='outputbox' style='padding: 0px; display:none;'>\n\n    <iframe  id=\"pdfframe\" width=\"100%\" height=\"1200px\"></iframe>\n\n</div>\n\n<script>\n\n\n    \n\n   function download(content, fileName, contentType) {\n       \n       if(!contentType) contentType = 'application/octet-stream';\n\t\t  const a = document.createElement(\"a\");\n\t\t  const file = new Blob([content], { type: contentType });\n\t\t  a.href = URL.createObjectURL(file);\n\t\t  a.download = fileName;\n\t\t  a.click();\n\t}\n\n\tfunction onDownload(){\n\t    \n\t    var jsonData = { \"url\": (window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString),\"calculated\": calculated, \"qdata\": qdata, \"objects\": objects };\n\t\tdownload(JSON.stringify(jsonData), \"hndesign.json\", \"text/plain\");\n\t}\n    \n   \n    \n    function copyData(){\n\t    \n\t    var jsonData = calculated ;\n\t\tnavigator.clipboard.writeText(JSON.stringify(jsonData));\n\t\talert(\"Data Copied to Clipboard\");\n\t}\n    \n    \n    function copylink() {\n        \n        //alert(window.location.href.split(\".svg\")[0]+\".svg&display=\"+displayed);\n        \n        navigator.clipboard.writeText(window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\"));  //\n        alert(\"Link Copied to Clipboard\");\n         \n    \n    }\n    \n    function openlink() {\n        \n        //alert(window.location.href.split(\".svg\")[0]+\".svg&display=\"+displayed);\n        \n        window.open(window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\"));  //\n        \n         \n    \n    }\n    \n    function shareTwitter() {       \n        \n        var text = \"My latest heat network design.\";\n        var url = window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\");\n        window.open('http://twitter.com/share?url='+encodeURIComponent(url)+'&text='+encodeURIComponent(text), '', 'left=0,top=0,width=550,height=450,personalbar=0,toolbar=0,scrollbars=0,resizable=0');\n\n    } \n\n</script>\n\n\n<div class='section'>\n<p><b>Inputs</b></p>\n<div id=\"inputs\" class=\"notes\"></div>\n</div>\n\n<div class='section'>\n<p><b>Numeric Values and Calculations</b></p>\n<div id=\"calcs\" class=\"notes\"></div>\n</div>\n\n\n<div class='section'>\n<p><b>Links</b><img style=\"padding:25px\" src=\"/files/images/heatwebsl.png\" width=\"200px\" align=\"right\"></p>\n<div id=\"mylink\" class=\"notes\"></div>\n<div id=\"links\" class=\"notes\"></div>\n\n\n\n</div>\n</form>\n\n\n\n\n <form id=\"nextform\" name=\"nextform\" method=\"post\" action=\"/api/print\" ajax=\"true\" target=\"result1\">\n    <input type=\"hidden\" id=\"svgtext\" name=\"svgtext\" value=\"\">\n    <input type=\"hidden\" id=\"svgfile\" name=\"svgfile\" value=\"\">\n    <input type=\"hidden\" id=\"show\" name=\"show\" value=\"\">\n    </form>\n <iframe width=\"100%\" frameborder=\"0\" id=\"result1\" name=\"result1\" style=\"display:none\"></iframe>\n\n<div id=\"headed\" style=\"display:none\">\n    <svg\n   xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n   xmlns:cc=\"http://creativecommons.org/ns#\"\n   xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n   xmlns:svg=\"http://www.w3.org/2000/svg\"\n   xmlns=\"http://www.w3.org/2000/svg\"\n   xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n   id=\"svg1156\"\n   version=\"1.1\"\n   viewBox=\"0 0 210 297\"\n   height=\"297mm\"\n   width=\"210mm\">\n  <defs\n     id=\"defs1150\" />\n  <metadata\n     id=\"metadata1153\">\n    <rdf:RDF>\n      <cc:Work\n         rdf:about=\"\">\n        <dc:format>image/svg+xml</dc:format>\n        <dc:type\n           rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\n        <dc:title></dc:title>\n      </cc:Work>\n    </rdf:RDF>\n  </metadata>\n  <g\n     id=\"layer1\">\n    <path\n       id=\"path973\"\n       d=\"M 4.7230732,285.08269 H 204.21415\"\n       style=\"opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1\" />\n    <image\n       width=\"33.573963\"\n       height=\"10.040811\"\n       preserveAspectRatio=\"none\"\n       xlink:href=\"data:image/png;base64,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 PAAAAABJRU5ErkJggg== \"\n       id=\"image970\"\n       x=\"6.2852573\"\n       y=\"5.9025064\" />\n    <path\n       id=\"path973-9\"\n       d=\"M 4.7230731,18.88226 H 204.21415\"\n       style=\"opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1\" />\n    <text\n       id=\"text1007\"\n       y=\"289.65405\"\n       x=\"108.3\"\n       style=\"font-style:normal;font-weight:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:2.82222223px;text-align:center;text-anchor:middle;stroke-width:0.26458332\"\n         y=\"289.65405\"\n         x=\"108.3\"\n         id=\"tspan1005\">Page {{pn}} of {{pc}}</tspan></text>\n    <text\n       id=\"text1007-5\"\n       y=\"9.4398441\"\n       x=\"203.11298\"\n       style=\"font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:4.23333311px;text-align:end;text-anchor:end;stroke-width:0.26458332\"\n         y=\"9.4398441\"\n         x=\"203.11298\"\n         id=\"tspan1005-2\">{{title}}</tspan></text>\n    <text\n       id=\"text1007-5-0\"\n       y=\"14.542536\"\n       x=\"203.11298\"\n       style=\"font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:3.17499995px;text-align:end;text-anchor:end;stroke-width:0.26458332\"\n         y=\"14.542536\"\n         x=\"203.11298\"\n         id=\"tspan1005-2-7\">{{subtitle}}</tspan></text>\n  </g>\n</svg>\n</div>\n\n\n\n<script>\n    \n\nvar filesLoaded = 0;\n\nvar files = {\n  img1: {\n    url: \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  },\n  img2: {\n    url: \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  },\n  img3: {\n    url:\n      \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  }\n};\n\nvar doc;\n\n\nfunction loadedFile(xhr) {\n  for (var file in files) {\n    if (files[file].url === xhr.responseURL) {\n      files[file].data = xhr.response;\n    }\n  }\n  filesLoaded += 1;\n  \n  console.log(xhr);\n  \n  if (filesLoaded == Object.keys(files).length) {\n    // showPDF();\n  }\n}\n\nfor (var file in files) {\n  files[file].xhr = new XMLHttpRequest();\n  files[file].xhr.onreadystatechange = function() {\n    if (this.readyState == 4 && this.status == 200) {\n      loadedFile(this);\n    }\n  };\n  files[file].xhr.responseType = \"arraybuffer\";\n  files[file].xhr.open(\"GET\", files[file].url);\n  files[file].xhr.send(null);\n}\n\nfunction prepImage (imid, imurl) {\n    \n       files[imid] = {};\n       files[imid][\"url\"] = imurl;\n    \n    //for (var file in files) {\n      files[imid].xhr = new XMLHttpRequest();\n      files[imid].xhr.onreadystatechange = function() {\n        if (this.readyState == 4 && this.status == 200) {\n          loadedFile(this);\n          console.log(files);\n        }\n      };\n      files[imid].xhr.responseType = \"arraybuffer\";\n      files[imid].xhr.open(\"GET\", files[imid].url);\n      files[imid].xhr.send(null);\n    //}\n   \n}\n\nfunction feImages(htmlt) {\n    \n    var bits = htmlt.split('src=\"');\n    //var hoot = \"\";\n    \n    var ic=0;\n    for (var i in bits) {\n        \n        ic++;\n        \n        if (ic>1) {  \n            \n            try {\n            \n                var src = bits[i].split('\"')[0];\n                \n                // bits[i] = bits[i].substr(bits[i].indexOf('\"'));\n                \n                var fn = src.substr(src.lastIndexOf(\"/\")+1);\n                fn = fn.replace(/ /g,\"_\").replace(/\\./g,\"_\").toLowerCase();\n                \n                console.log(fn + \" ... \" + src);\n                \n                prepImage (fn, src);\n                \n                //src = \"/ui/w/images/\" + src;\n                \n                // bits[i] = 'src=\"' + src + bits[i]; \n                \n                \n            } catch {}\n            \n            \n        }\n        \n        \n        //hoot += bits[i];\n    }\n\n}\n\n\nfunction showPDF() {\n    \n    var layoutP = {\n      layout: \"portrait\",\n      size: 'A4',\n      margins: {\n        top: 60,\n        bottom: 60,\n        left: 40,\n        right: 40\n      }\n    };\n    \n     doc = new PDFDocument(layoutP);\n       \n    var stream = doc.pipe(blobStream());\n\n    stream.on(\"finish\", function() {\n       // get a blob you can do whatever you like with\n      blob = stream.toBlob(\"application/pdf\");\n    \n      const url = stream.toBlobURL('application/pdf');\n      const iframe = document.querySelector('#pdfframe')\n      iframe.src = url;\n      \n      document.getElementById(\"pdfframebox\").style.display = 'block';\n      \n    });   \n   \n   var pc = 0;\n   var posy = 100;\n   var lastpage = \"-1\";\n   \n    //   doc.on('pageAdded', () => doc.fontSize(9).fillColor(\"black\").text(\"Page x of x\", 80, 750, {\"align\":\"left\", \"lineBreak\": false }).moveTo(30, 80));\n   \n   for (var oo in objects) {\n       \n       \n       if(posy>600 || objects[oo].page!==lastpage) {  \n           \n            pc++;\n            posy = 100;\n           \n            if (lastpage!==\"-1\") { doc.addPage(layoutP);  }\n           \n            doc.image(files.img1.data, 30, 30, { fit: [60, 120] });\n       \n            \n            doc.fontSize(9);\n            doc.font(\"Helvetica\");\n            doc.fillColor(\"black\").text(\"Heatweb Heat Network Designer\", 110, 30, {\"align\":\"right\"});\n            \n            doc.fontSize(11);\n            doc.font(\"Helvetica-BoldOblique\");\n            doc.fillColor(\"black\").text(objects[oo].page||objects[oo].id, 350, 44, {\"align\":\"right\"});\n           \n           doc\n            .moveTo(30, 65)\n            .lineTo(560, 65)\n            .stroke();\n            \n            doc\n            .moveTo(30, 805)\n            .lineTo(560, 805)\n            .stroke();\n            \n            doc.fontSize(9);\n            doc.font(\"Helvetica\");\n            doc.fillColor(\"black\").text(\"Thermal Integration Ltd. (Heatweb)   Tel. 0345 2411441   Email: newenquiries@heatweb.com   Website: heatweb.co.uk\", 30, 815, {\"align\":\"center\", \"lineBreak\": false });\n            \n            \n            doc.fontSize(18);\n            doc.font(\"Courier-Bold\"); \n            //#000077\n            doc.fillColor(\"black\").text(objects[oo].page||objects[oo].id, 40, 90, {\"align\":\"justify\", \"width\": 410});\n        }\n       \n        lastpage = objects[oo].page;\n       \n        doc.fontSize(12);\n        doc.moveDown();\n       \n        if (objects[oo].text) {\n        \n            doc.moveDown();\n            doc.fontSize(12);\n            doc.fillColor(\"black\");\n            doc.font(\"Helvetica\");\n            doc.text(objects[oo].text, {\n              width: 510,\n              align: 'justify'\n            }\n            );\n        \n        }\n        \n        if (objects[oo].type==\"image/jpeg\") {\n            \n            //doc.image(objects[oo].value, 50, posy, { fit: [500, 300] });\n            \n            \n             doc.moveDown();\n            doc.image(objects[oo].value, { width: 510 });\n            \n            posy = posy + 300;\n        }\n        else if (objects[oo].type==\"image/svg+xml\") {\n           \n            SVGtoPDF(doc,  objects[oo].value,5,150);\n            \n            posy = 9999;\n            \n        }\n        \n        else if (objects[oo].type==\"text/html\") {\n           \n            var secs = objects[oo].value.split(\"\\n\");\n            var inlist = false;\n            var lilist = [];\n            \n            var galleryW = 250;\n            var galleryH = 250;\n            var ingallery = false;\n            var nextX = 30;\n            var nextY = 100;\n            \n            console.log(secs);\n            \n            doc.moveUp();  // to counter first moveDown\n            \n            for (var sss in secs) { \n             \n                var txt = secs[sss].replace(/(<([^>]+)>)/gi, \"\");\n                txt = txt.replace(/&/g, \"&\");\n             \n                console.log(txt);\n                console.log(secs[sss]);\n                \n                if (secs[sss].substr(0,3)==\"<p>\")    {\n                    \n                    \n                    ingallery=false;\n                    \n                    doc.moveDown();\n                    doc.fontSize(12);\n                    doc.fillColor(\"black\");\n                    doc.font(\"Helvetica\");\n                    doc.text(txt, {\n                      width: 510,\n                      align: 'justify'\n                    }\n                    );\n                }\n                else if (secs[sss].indexOf(\"<h2\")>-1)    {\n                    \n                   \n                    ingallery=false;\n                    \n                    doc.moveDown();\n                    doc.moveDown();\n                    \n                    doc.fontSize(16);\n                    doc.fillColor(\"black\");\n                    doc.font(\"Helvetica-Bold\");\n                    doc.text(txt, {\n                      width: 510,\n                      align: 'justify'\n                    }\n                    );\n                    \n                } else if (secs[sss].indexOf(\"<h3\")>-1)    {\n                    \n                    \n                    ingallery=false;\n                    \n                    doc.moveDown();\n                    doc.moveDown();\n                    \n                    doc.fontSize(14);\n                    doc.fillColor(\"black\");\n                    doc.font(\"Helvetica-Bold\");\n                    doc.text(txt, {\n                      width: 510,\n                      align: 'justify'\n                    }\n                    );\n                }\n                else if (secs[sss].substr(0,3)==\"<ul\")    {\n                    \n                    \n                    \n                    console.log(\"<ul>\");\n                    inlist = true;\n                    ingallery=false;\n                    lilist.push(txt);\n                    \n                } else if (secs[sss].indexOf(\"<li>\")>-1)    {\n                    \n                    console.log(\"<li>\");\n                    inlist = true\n                    lilist.push(txt);\n                    \n                } \n                \n                if (secs[sss].indexOf(\"</ul>\")>-1)    {\n                    \n                    inlist = false;\n                    \n                    if(lilist.length>1 || lilist[0].length>1) {\n                    \n                        console.log(lilist);\n                        \n                        doc.moveDown();\n                        \n                        doc.fontSize(12);\n                        doc.fillColor(\"black\");\n                        doc.font(\"Helvetica\");\n                        doc.list(lilist, {\n                          width: 510,\n                          align: 'left',\n                          paragraphGap: 10\n                        }\n                        );\n                    \n                    }\n                    \n                    lilist=[];\n                }\n                \n                if (secs[sss].indexOf('src=\"')>-1)    {\n                    \n                    var imgbits  = secs[sss].split('src=\"')[1];\n                    var src = imgbits.split('\"')[0];\n                    \n                    console.log(\"imgbits... \" + imgbits);\n                    \n                    if (imgbits.indexOf('width=\"')>-1) {\n                        \n                        var fn = src.substr(src.lastIndexOf(\"/\")+1);\n                        fn = fn.replace(/ /g,\"_\").replace(/\\./g,\"_\").toLowerCase();\n                    \n                        if (files[fn].xhr.response) {\n                            \n                            var imgh = 510;  if (imgbits.indexOf('height=\"')>-1) { imgh = parseInt(imgbits.split('height=\"')[1].split('\"')[0]); }\n                            var imgw = 700;  if (imgbits.indexOf('width=\"')>-1) { imgw = parseInt(imgbits.split('width=\"')[1].split('\"')[0]); }\n                            \n                            console.log(\"WxH before... \" + imgw + \" x \" + imgh);\n                            \n                            //if (imgw > 250 && imgw < 700) { imgh = Math.max(350, imgh * 250/imgw); imgw = 250; ingallery=true; }\n                            if (imgw > 250 && imgw < 700) { \n                                imgh = galleryH; \n                                imgw = galleryW; \n                                if (!ingallery) {\n                                    ingallery=true; \n                                    nextY=nextY+20;\n                                }\n                            }\n                            \n                            if (imgw > 400) { imgw = 510; }\n                            if (imgh > 800) { imgh = 800; }\n                            \n                            console.log(\"WxH after... \" + imgw + \" x \" + imgh);\n                        \n                            if (ingallery) {\n                                \n                                doc.image(files[fn].xhr.response, nextX, nextY, { \"fit\": [imgw, imgh], align: 'center', valign: 'center' });\n                                nextX = nextX + galleryW + 25;\n                                \n                                //doc.moveTo(30, nextY + imgh + 25);  // prepare for next non-gallery item\n                                doc.text(\" \", 40, nextY + imgh - 15, {\"align\":\"left\", \"width\": 410});\n                                \n                            } else {\n                                \n                                doc.moveDown();\n                                doc.image(files[fn].xhr.response, { \"fit\": [imgw, imgh] });\n                            \n                                posy = posy + 300;\n                            }\n                            \n                        }\n                    }\n                }\n                \n                if (!ingallery) { nextX = doc.x;  nextY = doc.y;  }\n                \n            }\n            \n            posy = 9999;\n            \n        }\n        \n   }\n   \n \n\n  doc.end();\n}\n\nconst ppp = document.createElement(\"a\");\ndocument.body.appendChild(ppp);\nppp.style = \"display: none\";\n\nlet blob;\n\nfunction downloadp() {\n  if (!blob) return;\n  var url = window.URL.createObjectURL(blob);\n  ppp.href = url;\n  ppp.download = 'test.pdf';\n  ppp.click();\n  window.URL.revokeObjectURL(url);\n}\n\n\n\n</script>\n\n\n","output":"str","x":1220,"y":360,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"},{"id":"3f340f5c.797b9","type":"change","z":"cce2bfaa.e5748","name":"Products JSON","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"title\":\"Product Information\",\"links\":[{\"src\":\"https://www.heatweb.co.uk\",\"title\":\"Company Website\"}],\"sections\":[{\"title\":\"General\",\"questions\":[{\"title\":\"Number of properties\",\"question\":\"Number of properties?\",\"id\":\"nProperty\",\"if\":\"true\",\"required\":true,\"type\":\"number\",\"notes\":\"\",\"units\":\"\"},{\"title\":\"Heat sources\",\"question\":\"Where does heat come from?\",\"id\":\"heatFrom\",\"if\":\"true\",\"required\":true,\"type\":\"select\",\"options\":[{\"title\":\"individual System(s)\",\"value\":\"local\"},{\"title\":\"Heat Network\",\"value\":\"network\"}]}],\"outputs\":[{\"title\":\"The DATA HIU\",\"id\":\"wiki\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"http://heatweb.co.uk/w/index.php?title=The_DATA_HIU#Description\",\"style\":\"width:100%;height:425px\"},{\"title\":\"Schematic\",\"id\":\"wiki2\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"https://heatweb.co.uk/w/index.php?title=The_DATA_HIU#Schematic\",\"style\":\"width:100%;height:425px\"}]}],\"calculations\":[]}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":680,"y":420,"wires":[["d2c83715.bc4ad8"]]},{"id":"36daa724.841bb8","type":"change","z":"cce2bfaa.e5748","name":"HIU Instructions JSON","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"title\":\"HIU Instructions\",\"pdfOptions\":{\"fontSize\":10},\"links\":[{\"src\":\"http://www.systemdesigner.co.uk/heatnetwork.php\",\"title\":\"Heat Network Calculator v1\"},{\"src\":\"https://hw3.ddns.net/index.php?page=3D&&startp=heatnetcalc\",\"title\":\"3D Model for Calculator v1\"},{\"src\":\"https://hw7.ddns.net/ui/hncalc\",\"title\":\"Heat Network Calculator v2\"},{\"src\":\"https://hw7.ddns.net/ui/svgexplode?svg=HeatNetwork6.svg\",\"title\":\"Heat Network Schematic Designer (HeatNetwork6.svg)\"}],\"sections\":[{\"title\":\"General\",\"questions\":[{\"title\":\"HIU Model\",\"question\":\"What model of HIU?\",\"id\":\"modelHIU\",\"if\":\"true\",\"required\":true,\"type\":\"select\",\"options\":[{\"title\":\"DATA\",\"value\":\"DATA\"},{\"title\":\"DATA SPLIT\",\"value\":\"DATA-SPLIT\"},{\"title\":\"SLIM\",\"value\":\"SLIM\"}]},{\"title\":\"Heat Meter Model\",\"question\":\"What model of Heat Meter is fitted?\",\"id\":\"modelHMeter\",\"if\":\"true\",\"required\":true,\"type\":\"select\",\"options\":[{\"title\":\"None\",\"value\":\"none\"},{\"title\":\"Zenner C5\",\"value\":\"ZennerC5\"},{\"title\":\"Kamstrup Multical\",\"value\":\"KamstrupMultical\"},{\"title\":\"Danfoss Sonometer\",\"value\":\"DanfossSonometer\"}]}],\"outputs\":[{\"title\":\"About Thermal Integration Limited\",\"id\":\"wiki1\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"https://www.heatweb.co.uk/w/index.php?title=About_Thermal_Integration_Limited\",\"style\":\"width:100%;height:425px\"},{\"title\":\"Explanation of symbols and abbreviations\",\"id\":\"symbols\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"https://www.heatweb.co.uk/w/index.php?title=Installation_Instructions_for_the_Data_HIU#Explanation_of_symbols_and_abbreviations\",\"style\":\"width:100%;height:425px\"},{\"title\":\"Introduction\",\"id\":\"intro\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"https://www.heatweb.co.uk/w/index.php?title=Installation_Instructions_for_the_Data_HIU#Introduction\",\"style\":\"width:100%;height:425px\",\"maxImageHeight\":370},{\"title\":\"Available Options\",\"id\":\"availopt\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"https://www.heatweb.co.uk/w/index.php?title=Installation_Instructions_for_the_Data_HIU#Available_Options\",\"style\":\"width:100%;height:425px\",\"maxImageHeight\":400},{\"title\":\"Schematic\",\"id\":\"dataschem\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"https://heatweb.co.uk/w/index.php?title=The_DATA_HIU#Schematic\",\"style\":\"width:100%;height:425px\"},{\"title\":\"Flushing Bypass\",\"id\":\"flushbyp\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"https://heatweb.co.uk/w/index.php?title=The_DATA_HIU#Flushing_Bypass\",\"style\":\"width:100%;height:425px\"},{\"title\":\"EC Declaration\",\"id\":\"ecdec\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"https://www.heatweb.co.uk/w/index.php?title=DATA_EC_Declaration\",\"style\":\"width:100%;height:425px\"},{\"title\":\"Pump Settings (WILO)\",\"id\":\"wiki8\",\"if\":\"true\",\"type\":\"wiki\",\"url\":\"https://www.heatweb.co.uk/w/index.php?title=Installation_Instructions_for_the_Data_HIU#Wilo_Pump_Settings\",\"style\":\"width:100%;height:425px\",\"maxImageHeight\":200},{\"title\":\"Heat Meter\",\"id\":\"hmeter\",\"if\":\"'{{modelHMeter}}'=='ZennerC5'\",\"type\":\"wiki\",\"url\":\"http://heatweb.co.uk/w/index.php?title=Zenner_C5_Heat_Meter\",\"style\":\"width:100%;height:425px\",\"maxImageHeight\":350}]}],\"calculations\":[]}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":460,"wires":[["d2c83715.bc4ad8"]]},{"id":"123bc6a4.a74f29","type":"template","z":"cce2bfaa.e5748","name":"Form Generator","field":"payload.body","fieldType":"msg","format":"html","syntax":"plain","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js\"></script>\n<!--https://www.sitepoint.com/basic-jquery-form-validation-tutorial/-->\n\n<script src=\"https://unpkg.com/mustache@latest\"></script>\n\n\n\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n\n<script src=\"https://cdn.ckeditor.com/ckeditor5/34.0.0/inline/ckeditor.js\"></script>\n\n<!--These need to be installed locally-->\n<script src=\"pdfkit.standalone.js\"></script>\n<script src=\"blob-stream.js\"></script>\n<script src=\"svg-to-pdfkit.js\"></script>\n\n\n<style>\n    \n  \n    .jexcel_content {\n        font-size: 14px;\n    }\n    \n    .jexcel {\n        white-space: normal;\n    }\n\n/*for wiki*/\nli.gallerybox {\n    \n    display: inline-block;\n}\n\n.mybutt {\n    padding-left: 6px;\n    padding-right: 6px;\n    padding-top: 4px;\n    padding-bottom: 4px;\n    margin-right: 3px;\n    font-size: 14px;\n    border-radius: 4px;\n    cursor: pointer;\n    background-color: #a4eba4;\n    border-color: #4aa55a;\n    border: solid;\n    border-width: 1px;\n    box-shadow: 2px 2px 3px 1px rgb(0 0 0 / 28%);\n}\n.mybutt:hover {\n  background-color: #dcffdc;\n}\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\ntextarea.form-control {\n    font-size: 0.9rem;\n}\n\n.outputbox {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #ffffff;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n    font-size: 16px;\n}\n\n.cframe {\n    border-radius: 0.25rem;\n    margin: 0px 0px 20px 0px;\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 3px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\nvar a = new Date();\nvar qdata;\nvar calculated = {};  calculated.objects = {};\nvar hasFocus;\nvar currentSection;\nvar inputsOut;\nvar inputString;\nvar calcsString;\nvar tableArrays=[];\ntableArrays[\"calcsArray\"] = [];\n\nvar objects={}; \nvar sheets = {};\nvar sheetdata = {};\nvar initsheets;\n\n\t$(document).ready(function(e) {\n    \n        // $(\"form[ajax=true]\").submit(function(e) {\n            \n        //     //alert(\"submit\");\n            \n        //     e.preventDefault();\n        \n             \n            //var urlParams = new URLSearchParams(window.location.search);\n            //if (urlParams.get('display')) { loadstring = \",,\" + urlParams.get('display'); }\n\n            calculated[\"jsonQ\"] = \"hndesign\";\n\n            var urlParams = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParams) {\n                \n                calculated[urlParams[upa].split(\"=\")[0]] = decodeURIComponent(urlParams[upa].split(\"=\")[1]);\n                \n            }\n            \n            \n            \n            var form_data = {};\n            var form_url = \"/ui/qdata/\" + calculated[\"jsonQ\"];\n            var form_target = $(this).attr(\"target\") || \"result\";\n            var ftarget = \"#\" + form_target;\n            var form_method = \"GET\";\n            \n        //     $(\"#loadingimg\").show();\n            \n            $.ajax({\n                url: form_url, \n                type: form_method,      \n                data: form_data,     \n                cache: false,\n                success: function(results){   \n                    \n                    qdata = results;\n                    //qdata = JSON.parse(returnhtml);\n                    console.log(qdata);\n                   \n                    //if(urlParams['nBuildings']) { runCalcs(); runCalcs();  }\n                    runCalcs(); \n                    runCalcs();\n                    \n                    document.getElementById(\"formName\").innerHTML = qdata.title || \"Unamed Form\"; //JSON.stringify(qdata) ;\n                    \n                    // document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n                    \n                    // for (var sht in initsheets) {  initSheet(initsheets[sht]);   }\n                    \n                    // validform();\n                                  \n                }           \n            });    \n            \n        // });\n        \n      \n        \n    });\n\n\n    \nfunction tosvg(obid) {\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.svg\";\n    if (nn.indexOf(\".svg\")<0) { nn = nn + \".svg\"; }\n    \n    download( objects[obid].value, nn, \"image/svg+xml\")\n}\n  \n function jpegDownload(obid){\n\t    \n\t    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n        if (nn===null) { return(null); }\n        nn = nn || \"download.jpeg\";\n        if (nn.indexOf(\".jpeg\")<0) { nn = nn + \".jpeg\"; }\n        \n        var byteString = atob(objects[obid].value.split(',')[1]);\n        var mimeString = objects[obid].value.split(',')[0].split(':')[1].split(';')[0]\n\n        \n        // write the bytes of the string to an ArrayBuffer\n          var ab = new ArrayBuffer(byteString.length);\n        \n          // create a view into the buffer\n          var ia = new Uint8Array(ab);\n        \n          // set the bytes of the buffer to the correct values\n          for (var i = 0; i < byteString.length; i++) {\n              ia[i] = byteString.charCodeAt(i);\n          }\n        \n        download( ia , nn, mimeString)\n\t}\n\t\nfunction topdf(obid) {\n    \n    if (!objects[obid]) { return null; }\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.pdf\";\n    if (nn.indexOf(\".pdf\")<0) { nn = nn + \".pdf\"; }\n    \n    var headed = document.getElementById(\"headed\").innerHTML;\n    headed = headed.substr(headed.indexOf(\"<g\"));\n    headed = headed.substr(0,headed.lastIndexOf(\"</g>\")+4);\n    \n    var svgoot = objects[obid].value;\n    svgoot = svgoot.substr(svgoot.indexOf(\"<svg\"));\n    \n    var lg = svgoot.indexOf(\"<g\");\n    svgoot = svgoot.substr(0,lg) + '<g transform=\"translate(0,40)\">' + svgoot.substr(lg);\n    \n    lg = svgoot.lastIndexOf(\"</g>\")+4;\n    svgoot = svgoot.substr(0,lg) + \"</g>\" + headed + svgoot.substr(lg);\n    \n    var tits = {\"title\":\"Heatweb Heat Network Designer\",\"subtitle\":obid,\"pn\":\"1\",\"pc\":\"1\"}\n    svgoot = Mustache.render(svgoot, tits);\n    \n    //alert(svgoot);\n            $(\"#svgtext\").val(svgoot);\n            $(\"#svgfile\").val(nn);  //  + (new Date().getTime()) +\n            \n            $(\"#nextform\").submit(); \n            \n         \n}\n\nfunction topdf2(obid) {\n    \n    // without headed notepaper\n    \n    if (!objects[obid]) { return null; }\n    \n    var nn = prompt(\"Fileame\", objects[obid].id  || obid);\n    if (nn===null) { return(null); }\n    nn = nn || \"download.pdf\";\n    if (nn.indexOf(\".pdf\")<0) { nn = nn + \".pdf\"; }\n    \n    var svgoot = objects[obid].value;\n    svgoot = svgoot.substr(svgoot.indexOf(\"<svg\"));\n    \n    \n    \n    \n    //alert(svgoot);\n            $(\"#svgtext\").val(svgoot);\n            $(\"#svgfile\").val(nn);  //  + (new Date().getTime()) +\n            \n            $(\"#nextform\").submit(); \n            \n         \n}\n\n\n\n\n\nfunction initSheet(id) {\n\n    console.log(\"initSheet \" + id);\n    console.log(sheetdata);\n    \n    var shid = 'sheet-' + id;\n    var sdata = sheetdata[id];\n    \n    \n\n    try {\n    \n        document.getElementById(shid).innerHTML = \"\";\n        \n        sheets[id] = jspreadsheet(document.getElementById(shid), {\n            data: sdata.data,\n            columns: sdata.columns,\n            onchange: function(instance, cell, x, y, value) {\n                \n                console.log(value);\n                getSheetData(id);\n            },\n            updateTable:function(instance, cell, col, row, val, label, cellName) {\n               \n                //console.log(instance);\n                //console.log(val);\n                \n            },\n            columnSorting:false\n        });\n\n    } catch {}\n}\n\nfunction getSheetData(id) {\n    \n    \n    //alert(id);\n    \n    //console.log(sheets[id].getData());\n    \n    sheetdata[id].data = sheets[id].getData();\n    console.log(sheetdata);\n    \n    var oots = \"\";\n    for (var row in sheetdata[id].data) {\n       for (var c in sheetdata[id].data[row]) {\n           \n           var val = \"\" + (sheetdata[id].data[row][c] || \"\");\n           val = val.replace(/ /g,\"_\")\n           oots += val + \",\";\n        } \n        oots += \" \";\n    }\n    \n    oots = oots.substr(0, oots.length - 2);\n    console.log(oots);\n    \n    returncalc(id,oots)\n    \n    \n}\n\n\nfunction getObject(id) {\n    \n  \n    return (objects[id]||null);\n    \n}\n\n\nfunction setObject(id,value) {\n    \n\n    try { objects[id] = value; }\n    catch {}\n}\n\t\nfunction returncalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).value = value; }\n    catch {\n        \n        try { calculated[id] = value; }\n        catch {}\n    }\n    \n}\n\nfunction suggestcalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).placeholder = value + \" ... please confirm\"; }\n    catch {}\n}\n\t\nfunction parseQuestions(qdata) {\n    \n    console.log(qdata);\n    console.log(calculated);\n    \n    tableArrays[\"qArray\"] = [[\"Key\",\"Description\",\"Value\",\"Units\"]];\n    \n    var linkstxt=\"\";\n    if (qdata.links) {\n        for (var lnk in qdata.links) {\n            linkstxt += (linkstxt!==\"\"?\"<br>\":\"\") + '<a href=\"' + qdata.links[lnk].src + '\" target=\"_blank\">' + (qdata.links[lnk].title||qdata.links[lnk].src) + '</a>';\n        }\n        \n    }\n    document.getElementById(\"links\").innerHTML = linkstxt ; //JSON.stringify(qdata) ;\n    \n    \n    inputsOut = '<input id=\"jsonQ\" name=\"jsonQ\" value=\"' + calculated[\"jsonQ\"] + '\" class=\"form-control\" type=\"hidden\">';\n                    \n    \n    inputsOut += '<table class=\"table\">';\n    \n    inputString = \"jsonQ=\" + calculated[\"jsonQ\"];  // data source for form is fixed\n    \n    hasFocus = null;\n    currentSection = null;\n    initsheets = [];\n    \n    var ootoot = \"\";\n    for (var s in qdata[\"sections\"]) {\n        console.log(s);\n        console.log(qdata.sections[s]);\n        \n        var oot = \"\";\n        var ootcount=0;\n        \n        //oot += \"<div class='section'><h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        oot += \"<h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        \n        \n        \n        for (var q in qdata.sections[s].questions) {\n            \n            \n            var qif = qdata.sections[s].questions[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n            var v=\"\";\n            if (calculated[qdata.sections[s].questions[q].id]) { v= calculated[qdata.sections[s].questions[q].id] ; }\n            else if (qdata.sections[s].questions[q].value) { v= qdata.sections[s].questions[q].value ; }\n            \n            if (v!==\"\") { qdata.sections[s].questions[q].value = v; }    // save answers back into json.\n            \n            \n            if(goq) {\n                \n                var calcfr = \"\";\n                if (qdata.sections[s].questions[q].calculator) { calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].questions[q].calculator + '?field=' + qdata.sections[s].questions[q].id + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].questions[q].calculatorStyle ? qdata.sections[s].questions[q].calculatorStyle:'width:100%; height:300px;') + '\"></iframe>'}\n            \n            \n                if (v!==\"\") { \n                    inputsOut += \"<tr>\";  \n                    \n                    var cOs1 = \"\";  var cOs2 = \"\";\n            \n                    if (document.getElementById(\"hideID\").checked!==true) {\n                        cOs2 = \" <small>[<i>\" + qdata.sections[s].questions[q].id + \"</i>]</small>\";  \n                    }\n                    \n                    inputsOut += '<td width=\"40%\">' + (qdata.sections[s].questions[q].title||qdata.sections[s].questions[q].id) + cOs2 + \"</td>\";\n                    \n                    var vs1=\"\"; var vs2=\"\";\n                    if((\"\"+v).indexOf(\",\") > -1) { vs1=\"<small>\"; vs2=\"</small>\"; }\n                    if((\"\"+v).indexOf(\"&\") > -1) { vs1=\"<small style='width:400px; word-wrap:break-word; display:inline-block;'>\"; vs2=\"</small>\"; }\n                    \n                    \n                    inputsOut +=  ('<td align=\"right\">' + vs1 + v + vs2 + \"</td>\").replace(/\\, /g,\"<br>\").replace(/\\,/g,\", \");\n                    inputsOut +=  '<td width=\"14%\">' + (qdata.sections[s].questions[q].units||\"\") + \"</td></tr>\\n\";\n                    \n                    inputString += (inputString!==\"\"?\"&\":\"\") + qdata.sections[s].questions[q].id + \"=\" + encodeURIComponent(v);\n                }\n            \n                var isDisplayed = false;\n            \n                if (hasFocus && document.getElementById(\"oneQ\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">'; }\n            \n                else if (v!==\"\") { \n                    \n                    if (document.getElementById(\"hideDone\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">';   }\n                    else {  oot += '<div class=\"question\" style=\"background-color: #d2efd2;\">'; ootcount++; isDisplayed=true; }\n                    \n                } else { oot += '<div class=\"question\">'; ootcount++; isDisplayed=true; if (!hasFocus) { hasFocus = qdata.sections[s].questions[q].id;  currentSection = qdata.sections[s].title;  } }\n                \n                \n                //oot += \"<div class='qtext'>\" + qdata.sections[s].questions[q].title + '</div>';\n                oot += '<label for=\"' + qdata.sections[s].questions[q].id + '\" class=\"qtext\">' + (qdata.sections[s].questions[q].question||qdata.sections[s].questions[q].title) + '</label>';\n                \n                if (calcfr!==\"\") { oot += \"\\n\" + calcfr + \"\\n\"; }\n                \n                if (qdata.sections[s].questions[q].notes) { oot += '<div class=\"notes\">'  + convertLinks(Mustache.render(qdata.sections[s].questions[q].notes, calculated)) + '</div>'; }\n                \n                if (qdata.sections[s].questions[q].type == \"sheet\") {\n                    \n                    oot += '<br><div id=\"sheet-' + qdata.sections[s].questions[q].id + '\">';\n                \n                    oot += '<span onclick=\"initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ')\"><small class=\"mybutt\">Load Sheet</small></span> ';\n                    \n                    oot += '</div><br><br>';\n                    \n                    //oot += '<script>initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ');</scrip' + 't> ';\n                    //var myTimeout = setTimeout(initSheet(qdata.sections[s].questions[q].id), 1000);\n                    if (isDisplayed) { initsheets.push(qdata.sections[s].questions[q].id); }\n                \n                    var shob = {};\n                    shob['columns'] = qdata.sections[s].questions[q].columns;\n                    shob['data'] = qdata.sections[s].questions[q].default;\n                    \n                    if((\"\"+v)!==\"\") {\n                        \n                        shob['data']=[];\n                        var vv = v.replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                        var lns = vv.split(\", \");\n                        for (var lnsv in lns) {\n                            shob['data'].push(lns[lnsv].split(\",\"));\n                        }\n                    }\n                    \n                    sheetdata[qdata.sections[s].questions[q].id] = shob;\n                    \n                }\n                \n                \n                \n                if (qdata.sections[s].questions[q].type==\"html\") {\n                    \n                    oot += '<br><br><div class=\"form-control htmlinput\" style=\"height:fit-content\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    oot += decodeURIComponent('' + v + '')\n                    oot += '</div>';\n                \n                }\n                \n                \n                oot += '<table width=\"100%\"><tr><td width=\"80%\">';\n                \n                if (qdata.sections[s].questions[q].jsonQ) {\n                    \n                    \n                    oot += '<textarea class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    //oot += ('' + v + '').replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                    oot += decodeURIComponent('' + v + '')\n                    oot += '</textarea>';\n                    \n                } \n                \n                else if (qdata.sections[s].questions[q].type==\"html\") {\n                    \n                    oot += '';\n                    \n                   \n                \n                }\n                    \n                else if (qdata.sections[s].questions[q].type==\"boolean\") {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                      if (v==\"true\") { oot += '<option value=\"false\">No</option><option value=\"true\" selected>Yes</option>'; }\n                      else if (v==\"false\")  { oot += '<option value=\"false\" selected>No</option><option value=\"true\">Yes</option>'; }\n                      else  { oot += '<option value=\"\"></option><option value=\"false\">No</option><option value=\"true\">Yes</option>'; }\n                    oot += '</select>';\n                    \n                } else if (qdata.sections[s].questions[q].options) {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    if (v==\"\") { oot += '<option value=\"\"></option>'; }\n                    for (var opt in qdata.sections[s].questions[q].options) {\n                    \n                      var optobj = qdata.sections[s].questions[q].options[opt];\n                      \n                      \n                      if (v==optobj.value) { oot += '<option selected value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      else  { oot += '<option value=\"' + optobj.value + '\">' + optobj.title + '</option>'; }\n                      \n                    }  \n                    oot += '</select>';\n                    \n                }  else {\n                \n                    oot += '<input id=\"' + qdata.sections[s].questions[q].id + '\" name=\"' + qdata.sections[s].questions[q].id + '\" class=\"form-control\" type=\"text\"';\n                    if (v!==\"\") { oot += (' value=\"' + v + '\"').replace(/\\%20/g,\" \").replace(/_/g,\" \"); }\n                    if (qdata.sections[s].questions[q].default) { \n                        \n                        oot += ' placeholder=\"' + Mustache.render(\"\"+qdata.sections[s].questions[q].default, calculated)  + \" \" + (qdata.sections[s].questions[q].units||\"\") + ' ... please confirm\"'; \n                        \n                    }\n                    oot += '>';\n                }\n                \n                oot += '</td><td valign=\"top\"><span class=\"qunits\">' + (qdata.sections[s].questions[q].units||\"\") + '</span></td></tr></table>';\n                \n                \n                \n                oot += '</div>\\n';\n                \n                \n                tableArrays.qArray.push([qdata.sections[s].questions[q].id,qdata.sections[s].questions[q].title||\"\".id,(\"\"+v).replace(/\\,/g,\", \"),qdata.sections[s].questions[q].units||\"\"]);\n       \n            }\n        }\n    \n        oot += '<table width=\"100%\"><tr><td width=\"100%\" align=\"right\"><button class=\"mybutt\" type=\"submit\">Submit</button></td></tr></table>';\n\n        oot += \"</div>\\n\";\n       \n        \n        var outhtml = \"\";   \n        for (var q in qdata.sections[s].outputs) {\n            \n            var qif = qdata.sections[s].outputs[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n\n            if(goq && (calcsString||\"\")!==\"\") {\n                \n                var calcfr = \"\";\n                //if (!objects[qdata.sections[s].outputs[q].id]) { objects[qdata.sections[s].outputs[q].id] = {}; }\n                \n                if (qdata.sections[s].outputs[q].type==\"wiki\") { \n                    \n                    var oid = 'output'+qdata.sections[s].outputs[q].id;\n                    \n                    //qdata.sections[s].outputs[q].url\n                    //http://heatweb.co.uk/w/index.php?title=The_DATA_HIU#Description\n                    \n                    qdata.sections[s].outputs[q].url = qdata.sections[s].outputs[q].url.replace(\"http://heatweb.co.uk/w/index.php?title=\",\"\").replace(\"https://heatweb.co.uk/w/index.php?title=\",\"\")\n                    \n                    var tit = qdata.sections[s].outputs[q].url;\n                    if (tit.indexOf(\"#\")>-1) { tit = qdata.sections[s].outputs[q].url.split(\"#\")[0]; }\n                    \n                    var wikilocal = \"hnoutputs/wiki?id=\" + qdata.sections[s].outputs[q].id + \"&des=\" + qdata.sections[s].outputs[q].title.replace(/ /g,\"_\") + \"&title=\" + tit;\n                    if(qdata.sections[s].outputs[q].url.split(\"#\")[1]) { wikilocal += \"&section=\" + qdata.sections[s].outputs[q].url.split(\"#\")[1]; }\n                \n                    \n                    outhtml += prepWebPage(qdata.sections[s].outputs[q],wikilocal);\n                    \n                    \n                    \n                }\n                else if (qdata.sections[s].outputs[q].type==\"heatwebcouk\") { \n                    \n                    var oid = 'output'+qdata.sections[s].outputs[q].id;\n                    \n                    //qdata.sections[s].outputs[q].url\n                    //https://www.heatweb.co.uk/district-heating-substations/heating-substations/\n                    \n                    //qdata.sections[s].outputs[q].url = qdata.sections[s].outputs[q].url.replace(\"https://www.heatweb.co.uk/w/index.php?title=\",\"\").replace(\"https://heatweb.co.uk/w/index.php?title=\",\"\")\n                    \n                    var sec = \"\";\n                    var tit = qdata.sections[s].outputs[q].url.replace(\"https://www.heatweb.co.uk/\",\"\").replace(\"https://heatweb.co.uk/\",\"\");\n                    if (tit.indexOf(\"/\")>-1) { tit = qdata.sections[s].outputs[q].url.split(\"/\")[0]; sec = qdata.sections[s].outputs[q].url.split(\"/\")[1]; }\n                    \n                    var wikilocal = \"hnoutputs/wiki?id=\" + qdata.sections[s].outputs[q].id + \"&des=\" + qdata.sections[s].outputs[q].title.replace(/ /g,\"_\") + \"&title=\" + tit;\n                    if(sec) { wikilocal += \"&section=\" + sec; }\n                \n                    wikilocal += \"&type=\" + qdata.sections[s].outputs[q].type;\n                    wikilocal += \"&url=\" + encodeURIComponent(qdata.sections[s].outputs[q].url);\n                    outhtml += prepWebPage(qdata.sections[s].outputs[q],wikilocal);\n                    \n                    \n                    \n                }\n                else if (qdata.sections[s].outputs[q].url) { \n                    \n                    calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].outputs[q].url + (qdata.sections[s].outputs[q].url.indexOf(\"?\")>0?'':'?') + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].outputs[q].style ? qdata.sections[s].outputs[q].style:'width:100%; height:300px;') + '\"></iframe>'\n                    \n                    outhtml += '<div class=\"outputbox\">';\n                    outhtml += \"<table width='100%'><tr><td><b>\" + qdata.sections[s].outputs[q].title + \"</b></td>\\n\";\n                    \n                    if (qdata.sections[s].outputs[q].buttons) { \n                        \n                        outhtml += '<td align=\"right\">';\n                        for (var btn in qdata.sections[s].outputs[q].buttons) {\n                            \n                            outhtml += '<span class=\"mybutt\" onclick=\"' + qdata.sections[s].outputs[q].buttons[btn].onClick + '\">' + qdata.sections[s].outputs[q].buttons[btn].text + '</span> ';\n                        }\n                        outhtml += '</td>';\n                    }\n                    \n                    outhtml += '</tr></table><br>';\n                    \n                    outhtml += calcfr ; \n                    \n                    \n                    \n                    outhtml += \"</div>\\n\";\n                }\n            \n            }\n        }\n        \n        if (outhtml!==\"\") {\n            \n            //oot += '<div class=\"outputbox\">';\n            oot += outhtml;\n            //oot += \"</div>\\n\";\n        }\n        \n        \n        \n        \n        \n        if (document.getElementById(\"oneS\").checked==true && (currentSection != qdata.sections[s].title)) {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n        else if (ootcount>0) {  ootoot += \"<div class='section'>\" + oot; }\n        \n        else {  ootoot += '<div class=\"section\" style=\"display:none\">' + oot; }\n        \n    }\n    inputsOut +=  \"</table>\\n\";  \n    \n    return ootoot;\n}\n\nfunction prepWebPage(qd,url) {\n                    \n    var nn = \"\"+ qd.id;\n    var des = \"\" + qd.title;\n    \n    var outhtml='';\n    \n    $.ajax({\n        url: url, \n        type: \"GET\",      \n        data: {},     \n        cache: false,\n        success: function(results){   \n            \n            \n            var obid = results.split('obid=\"')[1].split('\"')[0];\n            var des = results.split('title=\"')[1].split('\"')[0];\n            \n            console.log('#'+obid);\n            console.log(results);\n            var opb = document.querySelector('#output'+obid);\n            opb.innerHTML = results || \"No Data\"; //JSON.stringify(qdata) ;\n            //document.getElementById(\"output\"+qd.id).innerHTML = results || \"No Data\"; //JSON.stringify(qdata) \n            \n            feImages(results);\n            \n            var myob = {};\n            myob.id = obid;\n            myob.filename = obid + \".html\";\n            myob.page = des;\n            myob.type = \"text/html\";\n            myob.value = \"\" + results;\n            try { setObject(obid, myob); } catch {}\n            myob = null;\n            \n            \n            \n        }           \n    });    \n    \n    \n    //calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qd.url + (qd.url.indexOf(\"?\")>0?'':'?') + (calcsString||\"\") + '\" style=\"' + (qd.style ? qd.style:'width:100%; height:300px;') + '\"></iframe>'\n    var calcfr = '<div id=\"output'+qd.id + '\">waiting... ' + qd.id + '</div>'\n    \n    outhtml += '<div class=\"outputbox\">';\n    outhtml += \"<table width='100%'><tr><td><b>WIKI: \" + qd.title + \"</b></td>\\n\";\n    \n    if (qd.buttons) { \n        \n        outhtml += '<td align=\"right\">';\n        for (var btn in qd.buttons) {\n            \n            outhtml += '<span class=\"mybutt\" onclick=\"' + qd.buttons[btn].onClick + '\">' + qd.buttons[btn].text + '</span> ';\n        }\n        outhtml += '</td>';\n    }\n    \n    outhtml += '</tr></table><br>';\n    \n    outhtml += calcfr ; \n    \n    \n    \n    outhtml += \"</div>\\n\";\n    \n    return (outhtml);\n    \n}\n\n\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\n// console.log(looseJsonParse(\n//   \"{a:(4-1), b:function(){}, c:new Date()}\"\n// ))\n\nfunction runCalcs() {\n\n\n    calcsString = \"\";\n    tableArrays.calcsArray = [[\"key\",\"Description\",\"Value\",\"Units\"]];\n    \n    // run through form inputs and store current values into calculated.\n    var cells =  document.getElementsByClassName(\"form-control\");\n\tvar i;\n\tfor (i = 0; i < cells.length; i++) {\n\t\n\t    \n\t    \n\t\n\t\tcalcsOut += cells[i].value + \"<br>\\n\";\n        \n        if (\"\" + cells[i].value !== \"\") { \n            \n            if (isNaN(cells[i].value)) { \n                \n                if ((cells[i].classList+\" \").indexOf(\"htmlinput\")>-1) {     // && cells[i].classList.indexOf(\"ck\")>-1\n                    \n                    calculated[cells[i].id] = cells[i].innerHTML;\n                }\n                else {\n                    \n                    calculated[cells[i].id] = (cells[i].value);\n                \n                    if ((calculated[cells[i].id]+\" \").substr(0,1)==\"{\" || (calculated[cells[i].id]+\" \").substr(0,1)==\"[\") {    // detect objects in textboxes\n                        \n                        try  { calculated.objects[cells[i].id] = JSON.parse(calculated[cells[i].id]) } catch {  }\n                    }\n                \n                }\n               \n                \n            } else {\n                \n                calculated[cells[i].id] = parseFloat(cells[i].value);\n            }\n            \n            calcsString += \"&\" + cells[i].id + \"=\" + cells[i].value;\n        }\n\t}\n\t\n    var calcsOut = '<table class=\"table\">';\n    \n    //calculated.objects = objects;\n    \n    // ================== Sheet Custom Calculations\n    \n    \n    if (calculated['loadSchedule']) {\n        \n        console.log(\"Load Schedule = \" + calculated['loadSchedule']);\n        \n        \n            \n            var cv1 = calculated['loadSchedule'];\n            var cv = 0;\n            var np = 0;\n            var kwCHMax = 0;\n            \n            var ldata=[];\n            \n            if((\"\"+cv1)!==\"\") {\n                \n                var vv = (\"\"+cv1).replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                var lns = vv.split(\", \");\n                for (var lnsv in lns) {\n                    ldata.push(lns[lnsv].split(\",\"));\n                    \n                    cv = cv + parseFloat(lns[lnsv].split(\",\")[4])\n                    \n                    np = np + (parseFloat(lns[lnsv].split(\",\")[2]) * parseFloat(lns[lnsv].split(\",\")[4]));\n                    \n                    kwCHMax = kwCHMax + (parseFloat(lns[lnsv].split(\",\")[3]) * parseFloat(lns[lnsv].split(\",\")[4]));\n                    \n                    \n                }\n            }\n            \n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total Properties</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">properties</td></tr>\\n';\n            \n            calculated['nProperties'] = cv;\n            calcsString += \"&nProperties=\" + cv;\n            \n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total People</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + np + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">people</td></tr>\\n';\n            \n            calculated['nPeople'] = np;\n            calcsString += \"&nPeople=\" + np;\n            \n            \n            calcsOut += \"<tr>\";  \n            calcsOut += \"<td>Total of central heating outputs</td>\";\n            \n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small></small></td>\";   //\"<br>\\n\";\n            }\n            calcsOut +=  '<td align=\"right\">' + kwCHMax + \"</td>\";\n            calcsOut +=  '<td width=\"14%\">kW</td></tr>\\n';\n            \n            calculated['kwCHMax'] = kwCHMax;\n            calcsString += \"&kwCHMax=\" + kwCHMax;\n            \n        \n        \n    }\n    \n    \n    // ================================\n    \n    \n    for (var calc in (qdata[\"calculations\"]||[])) {\n        \n        console.log(calc);\n        console.log(qdata.calculations[calc]);\n        \n        var cif = qdata.calculations[calc].if || true;\n        var cift = Mustache.render(cif, calculated);\n        var goc = true;\n        try {\n          goc = looseJsonParse(cift); \n        }\n        catch(err) {\n          goc = false;\n        }\n        \n        if (goc) {\n            \n            var f = qdata.calculations[calc].function;\n            var ft = Mustache.render(f, calculated);\n            \n            calcsOut += \"<tr>\";  //<td>\" + qdata.calculations[calc].id + \"</td>\";\n            calcsOut += \"<td>\";\n            \n            var cOs1 = \"\";  var cOs2 = \"\";\n            \n            if (document.getElementById(\"hideID\").checked!==true) {\n                cOs2 = \" <small>[<i>\" + qdata.calculations[calc].id + \"</i>]</small>\";  \n            }\n            \n            calcsOut += cOs1 + (qdata.calculations[calc].title||qdata.calculations[calc].id) + cOs2 + \"</td>\";\n            \n            //calcsOut += f + \" = \";\n            if (document.getElementById(\"hideMaths\").checked!==true) {\n                calcsOut += \"<td><small>\" + ft.replace(/\\,/g,\", \") + \"</small></td>\";   //\"<br>\\n\";\n            }\n            \n            var cv = \"\";\n            try {\n              cv = looseJsonParse(ft); //  looseJsonParse(\"{a:(4-1), b:function(){}, c:new Date()}\");\n            }\n            catch(err) {\n              \n            }\n             \n            \n            if (!isNaN(cv)) { cv = parseInt(cv*1000)/1000; }\n            \n            calcsOut +=  '<td align=\"right\">' + cv + \"</td>\";\n            \n            calcsOut +=  '<td width=\"14%\">' + (qdata.calculations[calc].units||\"\") + \"</td></tr>\\n\";\n            \n            calculated[qdata.calculations[calc].id] = cv;\n            calcsString += \"&\" + qdata.calculations[calc].id + \"=\" + cv;\n            \n            tableArrays.calcsArray.push([qdata.calculations[calc].id,qdata.calculations[calc].title||\"\".id,cv,qdata.calculations[calc].units]);\n        }\n        \n    }\n    \n    calcsOut +=  \"</table>\\n\";\n    \n    // for (var calc in calculated) {\n        \n        \n    // }\n    \n    document.getElementById(\"calcs\").innerHTML = calcsOut; //JSON.stringify(qdata) ;\n    \n    // rebuild form\n    document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"inputs\").innerHTML = inputsOut; //JSON.stringify(qdata) ;\n    \n    document.getElementById(\"mylink\").innerHTML = '<a href=\"hndesign?' + inputString + '\" target=\"_blank\">Open/share design...</a>'; //JSON.stringify(qdata) ;\n    \n    if(document.getElementById(\"description\")) {  // work in progress - need to link to all\n        InlineEditor\n                .create( document.querySelector( '#description' ) )\n                .catch( error => {\n                    console.error( error );\n                } );\n        \n        for (var sht in initsheets) {  initSheet(initsheets[sht]);   }\n    }\n    \n    validform();\n                    \n}\n\n\nconst convertLinks = ( input ) => {\n\n  let text = input;\n  const linksFound = text.match( /(?:www|https?)[^\\s]+/g );\n  const aLink = [];\n\n  if ( linksFound != null ) {\n\n    for ( let i=0; i<linksFound.length; i++ ) {\n      let replace = linksFound[i];\n      if ( !( linksFound[i].match( /(http(s?)):\\/\\// ) ) ) { replace = 'http://' + linksFound[i] }\n      let linkText = replace.split( '/' )[2];\n      if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) }\n      if ( linkText.match( /youtu/ ) ) {\n\n        let youtubeID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://www.youtube.com/embed/' + youtubeID + '\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe></div>' )\n      }\n      else if ( linkText.match( /vimeo/ ) ) {\n        let vimeoID = replace.split( '/' ).slice(-1)[0];\n        aLink.push( '<div class=\"video-wrapper\"><iframe src=\"https://player.vimeo.com/video/' + vimeoID + '\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' )\n      }\n      else {\n        aLink.push( '<a href=\"' + replace + '\" target=\"_blank\">' + linkText + '</a>' );\n      }\n      text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] );\n    }\n    return text;\n\n  }\n  else {\n    return input;\n  }\n}\n\nfunction validform() {\n    \n    if(hasFocus && document.getElementById(hasFocus)) {\n        document.getElementById(hasFocus).focus();\n    }\n    \n    \n    \n// Initialize form validation on the registration form.\n  // It has the name attribute \"registration\"\n  $(\"form[name='qform']\").validate({\n    // Specify validation rules\n    rules: {\n      // The key name on the left side is the name attribute\n      // of an input field. Validation rules are defined\n      // on the right side\n    //   nProperties: {\n    //     required: true,\n    //     digits: true,\n    //     min: 1\n    //   },\n      lastname: \"required\",\n      email: {\n        required: true,\n        // Specify that email should be validated\n        // by the built-in \"email\" rule\n        email: true\n      },\n      password: {\n        required: true,\n        minlength: 5\n      }\n    },\n    // Specify validation error messages\n    messages: {\n      nProperties: \"Please enter a number.\",\n      lastname: \"Please enter your lastname\",\n      password: {\n        required: \"Please provide a password\",\n        minlength: \"Your password must be at least 5 characters long\"\n      },\n      email: \"Please enter a valid email address\"\n    },\n    // Make sure the form is submitted to the destination defined\n    // in the \"action\" attribute of the form when valid\n    submitHandler: function(form) {\n      //form.submit();\n      runCalcs();\n      //alert(\"hello\");\n    }\n  });\n}\n\n</script>\n\n\n<div class='section'>\n    \n    <table width=\"100%\"><tr>\n    <td valign=\"top\" width=\"70%\">\n        <div id=\"formName\" class=\"h1\"></div>\n        <a href=\"https://heatweb.co.uk/w/index.php?title=Heat_Network_Designer\" target=\"_blank\"><small>Wiki Help Page</small></a>\n    </td>\n    <td width=\"30%\">\n        <input type=\"checkbox\" id=\"oneS\" name=\"oneS\" checked> <small>One section at a time</small><br>\n        <input type=\"checkbox\" id=\"oneQ\" name=\"oneQ\" checked> <small>One question at a time</small><br>\n        <input type=\"checkbox\" id=\"hideDone\" name=\"hideDone\" checked> <small>Hide completed questions</small><br>\n        <input type=\"checkbox\" id=\"hideMaths\" name=\"hideMaths\" checked> <small>Hide maths equations</small><br>\n        <input type=\"checkbox\" id=\"hideID\" name=\"hideID\" checked> <small>Hide IDs</small>\n    </td>\n    </tr></table>\n</div>\n\n\n<form action=\"\" name=\"qform\" id=\"qform\">\n<div id=\"section1\"></div>\n\n<div class='section'>\n\n<table width=\"100%\"><tr><td><span class=\"mybutt\" onclick=\"onDownload()\">Download JSON</span> <span class=\"mybutt\" onclick=\"copyData()\">Copy Data</span> <span class=\"mybutt\" onclick=\"copylink()\">Copy Link</span> <span class=\"mybutt\" onclick=\"openlink()\">Open in New</span> <span class=\"mybutt\" onclick=\"shareTwitter()\">Tweet Design</span> <span  class=\"mybutt\"  onclick=\"showPDF()\">Generate PDF</span> <span class=\"mybutt\" onclick=\"downloadp()\">Download PDF</span> </td><td align=\"right\"><button class=\"mybutt\" type=\"submit\">Submit</button></td></tr></table>\n\n\n\n\n</div>\n\n\n    \n\n<div id=\"pdfframebox\" class='outputbox' style='padding: 0px; display:none;'>\n\n    <iframe  id=\"pdfframe\" width=\"100%\" height=\"1200px\"></iframe>\n\n</div>\n\n<script>\n\n\n    \n\n   function download(content, fileName, contentType) {\n       \n       if(!contentType) contentType = 'application/octet-stream';\n\t\t  const a = document.createElement(\"a\");\n\t\t  const file = new Blob([content], { type: contentType });\n\t\t  a.href = URL.createObjectURL(file);\n\t\t  a.download = fileName;\n\t\t  a.click();\n\t}\n\n\tfunction onDownload(){\n\t    \n\t    var jsonData = { \"url\": (window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString),\"calculated\": calculated, \"qdata\": qdata, \"objects\": objects };\n\t\tdownload(JSON.stringify(jsonData), \"hndesign.json\", \"text/plain\");\n\t}\n    \n   \n    \n    function copyData(){\n\t    \n\t    var jsonData = calculated ;\n\t\tnavigator.clipboard.writeText(JSON.stringify(jsonData));\n\t\talert(\"Data Copied to Clipboard\");\n\t}\n    \n    \n    function copylink() {\n        \n        //alert(window.location.href.split(\".svg\")[0]+\".svg&display=\"+displayed);\n        \n        navigator.clipboard.writeText(window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\"));  //\n        alert(\"Link Copied to Clipboard\");\n         \n    \n    }\n    \n    function openlink() {\n        \n        //alert(window.location.href.split(\".svg\")[0]+\".svg&display=\"+displayed);\n        \n        window.open(window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\"));  //\n        \n         \n    \n    }\n    \n    function shareTwitter() {       \n        \n        var text = \"My latest heat network design.\";\n        var url = window.location.href.split(\"hndesign\")[0]+ 'hndesign?' + inputString.replace(/ /g,\"%20\");\n        window.open('http://twitter.com/share?url='+encodeURIComponent(url)+'&text='+encodeURIComponent(text), '', 'left=0,top=0,width=550,height=450,personalbar=0,toolbar=0,scrollbars=0,resizable=0');\n\n    } \n\n</script>\n\n\n<div class='section'>\n<p><b>Inputs</b></p>\n<div id=\"inputs\" class=\"notes\"></div>\n</div>\n\n<div class='section'>\n<p><b>Numeric Values and Calculations</b></p>\n<div id=\"calcs\" class=\"notes\"></div>\n</div>\n\n\n<div class='section'>\n<p><b>Links</b><img style=\"padding:25px\" src=\"/files/images/heatwebsl.png\" width=\"200px\" align=\"right\"></p>\n<div id=\"mylink\" class=\"notes\"></div>\n<div id=\"links\" class=\"notes\"></div>\n\n\n\n</div>\n</form>\n\n\n\n\n <form id=\"nextform\" name=\"nextform\" method=\"post\" action=\"/api/print\" ajax=\"true\" target=\"result1\">\n    <input type=\"hidden\" id=\"svgtext\" name=\"svgtext\" value=\"\">\n    <input type=\"hidden\" id=\"svgfile\" name=\"svgfile\" value=\"\">\n    <input type=\"hidden\" id=\"show\" name=\"show\" value=\"\">\n    </form>\n <iframe width=\"100%\" frameborder=\"0\" id=\"result1\" name=\"result1\" style=\"display:none\"></iframe>\n\n<div id=\"headed\" style=\"display:none\">\n    <svg\n   xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n   xmlns:cc=\"http://creativecommons.org/ns#\"\n   xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n   xmlns:svg=\"http://www.w3.org/2000/svg\"\n   xmlns=\"http://www.w3.org/2000/svg\"\n   xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n   id=\"svg1156\"\n   version=\"1.1\"\n   viewBox=\"0 0 210 297\"\n   height=\"297mm\"\n   width=\"210mm\">\n  <defs\n     id=\"defs1150\" />\n  <metadata\n     id=\"metadata1153\">\n    <rdf:RDF>\n      <cc:Work\n         rdf:about=\"\">\n        <dc:format>image/svg+xml</dc:format>\n        <dc:type\n           rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\n        <dc:title></dc:title>\n      </cc:Work>\n    </rdf:RDF>\n  </metadata>\n  <g\n     id=\"layer1\">\n    <path\n       id=\"path973\"\n       d=\"M 4.7230732,285.08269 H 204.21415\"\n       style=\"opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1\" />\n    <image\n       width=\"33.573963\"\n       height=\"10.040811\"\n       preserveAspectRatio=\"none\"\n       xlink:href=\"data:image/png;base64,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 PAAAAABJRU5ErkJggg== \"\n       id=\"image970\"\n       x=\"6.2852573\"\n       y=\"5.9025064\" />\n    <path\n       id=\"path973-9\"\n       d=\"M 4.7230731,18.88226 H 204.21415\"\n       style=\"opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1\" />\n    <text\n       id=\"text1007\"\n       y=\"289.65405\"\n       x=\"108.3\"\n       style=\"font-style:normal;font-weight:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:2.82222223px;text-align:center;text-anchor:middle;stroke-width:0.26458332\"\n         y=\"289.65405\"\n         x=\"108.3\"\n         id=\"tspan1005\">Page {{pn}} of {{pc}}</tspan></text>\n    <text\n       id=\"text1007-5\"\n       y=\"9.4398441\"\n       x=\"203.11298\"\n       style=\"font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:4.23333311px;text-align:end;text-anchor:end;stroke-width:0.26458332\"\n         y=\"9.4398441\"\n         x=\"203.11298\"\n         id=\"tspan1005-2\">{{title}}</tspan></text>\n    <text\n       id=\"text1007-5-0\"\n       y=\"14.542536\"\n       x=\"203.11298\"\n       style=\"font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332\"\n       xml:space=\"preserve\"><tspan\n         style=\"font-size:3.17499995px;text-align:end;text-anchor:end;stroke-width:0.26458332\"\n         y=\"14.542536\"\n         x=\"203.11298\"\n         id=\"tspan1005-2-7\">{{subtitle}}</tspan></text>\n  </g>\n</svg>\n</div>\n\n\n\n<script>\n    \n\nvar filesLoaded = 0;\n\nvar files = {\n  img1: {\n    url: \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  },\n  img2: {\n    url: \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  },\n  img3: {\n    url:\n      \"https://hw7.ddns.net/files/images/heatwebsl.png\"\n  }\n};\n\nvar fonts = {\n  f1: {\n    url: \"https://hw7.ddns.net/ui/fonts/Roboto-Regular.ttf\"\n  },\n  f2: {\n    url: \"https://hw7.ddns.net/ui/fonts/Roboto-Bold.ttf\"\n  },\n  f3: {\n    url:\n      \"https://hw7.ddns.net/ui/fonts/Roboto-Italic.ttf\"\n  },\n  f4: {\n    url:\n      \"https://hw7.ddns.net/ui/fonts/Roboto-BoldItalic.ttf\"\n  }\n};\n\nvar doc;\n\n\nfunction loadedFile(xhr) {\n  for (var file in files) {\n    if (files[file].url === xhr.responseURL) {\n      files[file].data = xhr.response;\n    }\n  }\n  filesLoaded += 1;\n  \n  console.log(xhr);\n  \n  if (filesLoaded == Object.keys(files).length) {\n    // showPDF();\n  }\n}\n\n\n\nfor (var file in files) {\n  files[file].xhr = new XMLHttpRequest();\n  files[file].xhr.onreadystatechange = function() {\n    if (this.readyState == 4 && this.status == 200) {\n      loadedFile(this);\n    }\n  };\n  files[file].xhr.responseType = \"arraybuffer\";\n  files[file].xhr.open(\"GET\", files[file].url);\n  files[file].xhr.send(null);\n}\n\nfor (var font in fonts) {\n  fonts[font].xhr = new XMLHttpRequest();\n  fonts[font].xhr.onreadystatechange = function() {\n    if (this.readyState == 4 && this.status == 200) {\n      //loadedFile(this);\n      console.log(\"font...\");\n      console.log(fonts[font].xhr)\n    }\n  };\n  fonts[font].xhr.responseType = \"arraybuffer\";\n  fonts[font].xhr.open(\"GET\", fonts[font].url);\n  fonts[font].xhr.send(null);\n}\n\n\n\nfunction prepImage (imid, imurl) {\n    \n       files[imid] = {};\n       files[imid][\"url\"] = imurl;\n    \n    //for (var file in files) {\n      files[imid].xhr = new XMLHttpRequest();\n      files[imid].xhr.onreadystatechange = function() {\n        if (this.readyState == 4 && this.status == 200) {\n          loadedFile(this);\n          console.log(files);\n        }\n      };\n      files[imid].xhr.responseType = \"arraybuffer\";\n      files[imid].xhr.open(\"GET\", files[imid].url);\n      files[imid].xhr.send(null);\n    //}\n   \n}\n\nfunction feImages(htmlt) {\n    \n    var bits = htmlt.split('src=\"');\n    //var hoot = \"\";\n    \n    var ic=0;\n    for (var i in bits) {\n        \n        ic++;\n        \n        if (ic>1) {  \n            \n            try {\n            \n                var src = bits[i].split('\"')[0];\n                \n                // bits[i] = bits[i].substr(bits[i].indexOf('\"'));\n                \n                var fn = src.substr(src.lastIndexOf(\"/\")+1);\n                fn = fn.replace(/ /g,\"_\").replace(/\\./g,\"_\").toLowerCase();\n                \n                console.log(fn + \" ... \" + src);\n                \n                prepImage (fn, src);\n                \n                //src = \"/ui/w/images/\" + src;\n                \n                // bits[i] = 'src=\"' + src + bits[i]; \n                \n                \n            } catch {}\n            \n            \n        }\n        \n        \n        //hoot += bits[i];\n    }\n\n}\n\n// =============================================== PDF\n\nvar layoutP = {\n      layout: \"portrait\",\n      size: 'A4',\n      margins: {\n        top: 60,\n        bottom: 60,\n        left: 60,\n        right: 60\n      }\n    };\n\nvar docL = layoutP.margins.left;\nvar docW = 595 - layoutP.margins.left - layoutP.margins.right;\nvar curSec = \"\";\nvar tableCount = 0;\n\nvar stdFontSize = 11.5;\n\n    \nfunction showPDF() {\n    \n    if (qdata && qdata.pdfOptions && qdata.pdfOptions[\"fontSize\"]) { stdFontSize = parseFloat(qdata.pdfOptions[\"fontSize\"]) ; }\n\n    \n    tableCount=0;\n    \n    \n     doc = new PDFDocument(layoutP);\n       \n    var stream = doc.pipe(blobStream());\n\n    stream.on(\"finish\", function() {\n       // get a blob you can do whatever you like with\n      blob = stream.toBlob(\"application/pdf\");\n    \n      const url = stream.toBlobURL('application/pdf');\n      const iframe = document.querySelector('#pdfframe')\n      iframe.src = url;\n      \n      document.getElementById(\"pdfframebox\").style.display = 'block';\n      \n    });   \n   \n   \n   //doc.registerFont('Standard', fonts.f1.xrh.response, \"object\");\n   \n   var pc = 0;\n   var posy = 100;\n   var lastpage = \"-1\";\n   \n   // doc.on('pageAdded', () => standardStuff(curSec,false););\n\n   standardStuff(\"Inputs\",true);\n   pdftable(tableArrays.qArray, {\"widths\":[100,210,110,60],\"align\":[\"left\",\"left\",\"right\",\"left\"], \"title\":\"Inputs\", \"fontSize\":9});\n   \n   doc.addPage(layoutP);\n  \n   standardStuff(\"Calculations\",true);\n   pdftable(tableArrays.calcsArray, {\"widths\":[100,240,80,60],\"align\":[\"left\",\"left\",\"right\",\"left\"], \"title\":\"Calculations\", \"fontSize\":9});\n   \n   doc.addPage(layoutP);\n   \n    \n   \n   for (var oo in objects) {\n       \n       \n       if(posy>600 || objects[oo].page!==lastpage) {  \n           \n            pc++;\n            posy = 100;\n           \n            if (lastpage!==\"-1\") { doc.addPage(layoutP);  }\n        \n            standardStuff(objects[oo].page||objects[oo].id,true);\n        }\n       \n        lastpage = objects[oo].page;\n       \n        doc.fontSize(12);\n        doc.moveDown();\n       \n        if (objects[oo].text) {\n        \n            //doc.moveDown();\n            doc.fontSize(stdFontSize);\n            doc.fillColor(\"black\");\n            doc.font(\"Helvetica\");\n            doc.text(objects[oo].text, {\n              width: docW,\n              align: 'justify',\n              lineGap: 4\n            }\n            );\n        \n        }\n        \n        if (objects[oo].type==\"image/jpeg\") {\n            \n            //doc.image(objects[oo].value, 50, posy, { fit: [500, 300] });\n            \n            \n            doc.moveDown();\n            doc.image(objects[oo].value, { width: docW });\n            \n            posy = posy + 300;\n        }\n        else if (objects[oo].type==\"image/svg+xml\") {\n           \n            SVGtoPDF(doc,  objects[oo].value,docL-15,150,{\"width\":docW+40, \"preserveAspectRatio\":\"xMinYMin\"});\n            \n            posy = 9999;\n            \n        }\n        \n        else if (objects[oo].type==\"text/html\") {\n           \n            var secs = objects[oo].value.split(\"\\n\");\n            var inlist = false;\n            var lilist = [];\n            \n            var galleryW = (docW / 2) - 10;\n            var galleryH = (docW / 2) - 10;\n            var ingallery = false;\n            var nextX = 1 * docL;\n            var nextY = 100;\n            var lastX = 1 * docL;\n            \n            console.log(secs);\n            \n            doc.moveUp();  // to counter first moveDown\n            \n            var secscnt = 0;\n            \n            for (var sss in secs) { \n             \n                \n                \n                var txt = secs[sss].replace(/(<([^>]+)>)/gi, \"\");\n                txt = txt.replace(/&/g, \"&\");\n                txt = txt.replace(/ /g, \" \");\n             \n                console.log(txt);\n                console.log(secs[sss]);\n                \n                \n                if (txt.trim()!==\"\" && secs[sss].indexOf(\"<p>\")>-1)    {\n                    \n                    doc.moveDown();\n                    doc.fontSize(stdFontSize);\n                    doc.fillColor(\"black\");\n                    doc.font(\"Helvetica\");\n                    \n                    if (ingallery) { \n                        \n                        doc.fontSize(9);\n                        doc.fillColor(\"black\");\n                        doc.font(\"Helvetica-BoldOblique\");\n                            \n                        doc.text(txt, lastX, doc.y, {\n                          width: 250,\n                          align: 'center'\n                        } );\n                        \n                    } else { \n                            \n                        doc.text(txt, docL, doc.y, {\n                          width: docW,\n                          align: 'justify',\n                          lineGap: 4\n                        } );\n                    }\n                    \n                    \n                }\n                else if (txt.trim()!==\"\" && secs[sss].indexOf(\"<h2\")>-1)    {\n                    \n                    secscnt++;\n                    ingallery=false;\n                    \n                    if((secscnt>1) || (objects[oo].page||objects[oo].id)!==txt) {   // dont repeat section title\n                        \n                        \n                        if(secscnt>1) { doc.moveDown(); }\n                        \n                        doc.fontSize(16);\n                        doc.fillColor(\"black\");\n                        doc.font(\"Helvetica-Bold\");\n                        doc.text(txt, docL, doc.y, {\n                          width: docW,\n                          align: 'justify'\n                        }\n                        );\n                    }\n                    \n                    \n                } else if (txt.trim()!==\"\" && secs[sss].indexOf(\"<h3\")>-1)    {\n                    \n                    \n                    secscnt++;\n                    ingallery=false;\n                    \n                    if((secscnt>1) || (objects[oo].page||objects[oo].id)!==txt) {   // dont repeat section title\n                       \n                        if(secscnt>1) { doc.moveDown(); }\n                        \n                        doc.moveDown();\n                        \n                        doc.fontSize(14);\n                        doc.fillColor(\"black\");\n                        doc.font(\"Helvetica-Bold\");\n                        doc.text(txt,  docL, doc.y, {\n                          width: docW,\n                          align: 'justify'\n                        }\n                        );\n                    }\n                }\n                else if (txt.trim()!==\"\" && secs[sss].substr(0,3)==\"<ul\")    {\n                    \n                    \n                    \n                    console.log(\"<ul>\");\n                    inlist = true;\n                    ingallery=false;\n                    lilist.push(txt);\n                    \n                } else if (txt.trim()!==\"\" && secs[sss].indexOf(\"<li>\")>-1)    {\n                    \n                    console.log(\"<li>\");\n                    inlist = true\n                    lilist.push(txt);\n                    \n                } \n                \n                if (secs[sss].indexOf(\"</ul>\")>-1)    {\n                    \n                    inlist = false;\n                    ingallery=false;\n                    \n                    if(lilist.length>1 || (lilist[0] && lilist[0].length>1)) {\n                    \n                        console.log(lilist);\n                        \n                        doc.moveDown();\n                        \n                        doc.fontSize(stdFontSize);\n                        doc.fillColor(\"black\");\n                        doc.font(\"Helvetica\");\n                        doc.list(lilist,  docL, doc.y, {\n                          width: docW,\n                          align: 'justify',\n                          paragraphGap: 5,\n                          lineGap: 2\n                        }\n                        );\n                    \n                    }\n                    \n                    lilist=[];\n                }\n                \n                if (secs[sss].indexOf('class=\"gallery')>-1 || secs[sss].indexOf('<table')>-1)    {\n                    \n                    if (!ingallery) {\n                        ingallery=true; \n                        nextY=nextY+20;\n                    }\n                }\n                \n                if (secs[sss].indexOf('<img ')>-1)    {\n                    \n                    var imgbits  = secs[sss].split('<img ')[1];\n                    var src = imgbits.split('src=\"')[1].split('\"')[0];\n                    \n                    imgbits = imgbits.replace(/max\\-width/g,\"max-w\");\n                    \n                    console.log(\"imgbits... \" + imgbits);\n                    \n                    if (imgbits.indexOf('width')>-1) {\n                        \n                        var fn = src.substr(src.lastIndexOf(\"/\")+1);\n                        fn = fn.replace(/ /g,\"_\").replace(/\\./g,\"_\").toLowerCase();\n                    \n                        if (files[fn].xhr.response) {\n                            \n                            var imgh = 780;  \n                            \n                            \n                            if (imgbits.indexOf('height=\"')>-1) { imgh = (imgbits.split('height=\"')[1].split('\"')[0]); }\n                            else if (imgbits.indexOf('height: ')>-1) { imgh = (imgbits.split('height: ')[1].split('px')[0].split('\"')[0]); }\n                            \n                            var imgw = docW;  \n                            if (imgbits.indexOf('width=\"')>-1) { imgw = (imgbits.split('width=\"')[1].split('\"')[0]); }\n                            else if (imgbits.indexOf('width: ')>-1) { imgw = (imgbits.split('width: ')[1].split('px')[0].split('\"')[0]); }\n                            \n                            console.log(\"WxH before... \" + imgw + \" x \" + imgh);\n                            \n                            if(isNaN(imgh)) { imgh = 780; }\n                            if(isNaN(imgw)) { imgw = docW; }\n                            \n                            imgw = parseInt(imgw);\n                            imgh = parseInt(imgh);\n                            \n                            if (imgw<40) { continue; }\n                            \n                            if (ingallery) { \n                                imgh = galleryH; \n                                imgw = galleryW; \n                                \n                            }\n                            \n                            \n                            if (imgw > docW) { imgw = docW; }\n                            \n                            if (ingallery) {\n                            \n                                if (nextY + imgh > 1000) {  \n                                    doc.addPage(layoutP);  \n                                    nextX = 1*docL; nextY = 100; \n                                    doc.text(\" \", docL, 100, {\"align\":\"left\", \"width\": 410});\n                                }\n                                \n                                if (nextY + imgh > 750) { imgh = parseInt(750 - nextY); }\n                            \n                            } else {\n                                \n                                if (doc.y + imgh > 1000) {  \n                                \n                                    doc.addPage(layoutP);  \n                                    nextX = 1*docL; nextY = 100; \n                                    doc.text(\" \", docL, 100, {\"align\":\"left\", \"width\": 410});\n                                }\n                                \n                                if (doc.y + imgh > 750) { imgh = parseInt(750 - doc.y); }\n                            }   \n                            \n                            \n                            \n                            \n                            console.log(\"WxH after... \" + imgw + \" x \" + imgh);\n                        \n                            if (ingallery) {\n                                \n                                lastX = 1 * nextX;\n                                doc.image(files[fn].xhr.response, nextX, nextY, { \"fit\": [imgw, imgh], align: 'center', valign: 'center' });\n                                nextX = nextX + imgw + 10;\n                                \n                                doc.text(\" \", docL, nextY + imgh - 15, {\"align\":\"left\", \"width\": 410});\n                                \n                                if ((nextX + galleryW)>550) {  // new gallery line\n                                    \n                                    nextX = 1*docL;\n                                    nextY = nextY + galleryH + 25;\n                                    //doc.text(\"\", 40, nextY, {\"align\":\"left\", \"width\": 410});\n                                }\n                                \n                                //doc.moveTo(30, nextY + imgh + 25);  // prepare for next non-gallery item\n                                //\n                                \n                            } else {\n                                \n                                doc.moveDown();\n                                doc.image(files[fn].xhr.response, docL, doc.y, { \"fit\": [imgw, imgh], align: 'center', valign: 'top' });\n                            \n                                posy = posy + 300;\n                            }\n                            \n                        }\n                    }\n                }\n                \n                if (!ingallery) { nextX = doc.x;  nextY = doc.y;  }\n                \n            }\n            \n            posy = 9999;\n            \n        }\n        \n   }\n   \n    \n\n  doc.end();\n}\n\nfunction standardStuff (txt1, showHead) {\n    \n       curSec = \"\"+txt1;\n       \n            doc.image(files.img1.data, 30, 25, { fit: [60, 120] });\n       \n            \n            doc.fontSize(9);\n            doc.font(\"Helvetica\");\n            doc.fillColor(\"black\").text(\"Heatweb Heat Network Designer\", 100, 25, {\"align\":\"right\", \"width\": 455});\n            \n            doc.fontSize(11);\n            doc.font(\"Helvetica-BoldOblique\");\n            doc.fillColor(\"black\").text(txt1, 100, 40, {\"align\":\"right\", \"width\": 455});\n           \n           doc\n           \n            .lineWidth(1)\n            .moveTo(0, 65)\n            .lineTo(600, 65)\n            .stroke();\n            \n            doc\n            .moveTo(0, 805)\n            .lineTo(600, 805)\n            .stroke();\n            \n            doc.fontSize(9);\n            doc.font(\"Helvetica\");\n            doc.fillColor(\"black\").text(\"Thermal Integration Ltd. (Heatweb)   Tel. 0345 2411441   Email: newenquiries@heatweb.com   Website: https://heatweb.co.uk\", 50, 815, {\"align\":\"center\", \"lineBreak\": false });\n            \n            \n            \n            if (showHead===true) {\n                doc.fontSize(20);\n                doc.font(\"Helvetica-Bold\"); \n                //#000077\n                doc.fillColor(\"black\").text(txt1, docL, 100, {\"align\":\"justify\", \"width\": 410});\n                doc.moveDown();\n                //doc.text(\"\", docL, doc.y, {\"align\":\"left\", \"width\": 410});  // position\n            \n                \n            } else {\n                \n                doc.text(\"\", docL, 90, {\"align\":\"left\", \"width\": 410});  // position\n            }\n}   \n\nfunction pdftable(tdata,toptions) {\n    \n    tableCount++;\n    \n    var tdaw = parseInt(470 / (tdata[0].length));\n    var thead = \"Table \" + tableCount + (toptions.title?(\": \" + toptions.title):\"\");\n    var twidths = toptions.widths || [tdaw,tdaw,tdaw,tdaw,tdaw,tdaw,tdaw,tdaw,tdaw,tdaw,tdaw,tdaw];\n    var tfs = toptions[\"fontSize\"] || 11.5;\n    var aligns = toptions.align || [];\n    \n    \n    doc.fillColor(\"black\");\n    \n    doc.font(\"Helvetica-Oblique\");\n    doc.fontSize(10);\n    doc.text(thead, doc.x, doc.y, {\"align\":\"left\", \"width\": 400, lineGap: 2});\n    doc.font(\"Helvetica\");\n    doc.fontSize(tfs);\n    \n    var tx1 = 1*doc.x;\n    var ty1 = 1*doc.y;\n    var ty = 1*ty1;\n    var tx = 1*tx1;\n    var trow = -1;\n    var tcol = -1;\n    \n    var tdh = 14;\n    var cellhmax = 0;\n    doc.lineWidth(0.5);\n    \n    for (var tr in tdata) {\n        \n        if (ty>750) {\n            \n            doc.addPage(layoutP);\n            standardStuff((toptions.title?toptions.title:\"\"),false);\n            doc.fontSize(tfs);\n            doc.fillColor(\"black\");\n            doc.font(\"Helvetica\");\n            ty = 100;\n            trow = -1;\n            \n            doc.font(\"Helvetica-Oblique\");\n            doc.fontSize(10);\n            doc.text(thead + \" (continued)\", doc.x, 100, {\"align\":\"left\", \"width\": 400, lineGap: 2});\n            doc.font(\"Helvetica\");\n            doc.fontSize(tfs);\n            doc.lineWidth(0.5);\n            ty = doc.y;\n            ty1 = 1*doc.y;\n            ty = 1*ty1;\n            \n        }\n        \n        trow++;\n        tcol=-1;\n        cellhmax = 0;\n\n        tx = 1*tx1;\n        for (var td in tdata[tr]) {\n            tcol++;\n            var tdw = 1 * (twidths[td] || tdaw);\n            var tdal = aligns[td] || \"left\";\n            \n            var tdval = \"\" + tdata[tr][td];\n            if (tdval.substr(0,1)==\"{\") { tdval = \"{object}\"; }  // dont display objects\n            \n            doc.text(tdval, tx+5, ty+5, {\"align\":tdal, \"width\": tdw-10, lineGap: 2});\n            \n            var cellh = doc.y - (ty+5) + 3;\n            cellhmax = Math.max(cellhmax,cellh);\n            \n            tx = tx + tdw;\n        }\n        \n        tcol=-1;\n        tx = 1*tx1;\n        for (var td in tdata[tr]) {\n            tcol++;\n            var tdw = 1 * (twidths[td] || tdaw);\n            \n            doc.rect(tx, ty, tdw, cellhmax).stroke();\n            \n            tx = tx + tdw;\n        }\n        \n        ty = ty + cellhmax;  // end of row move down\n        \n        \n        \n    }\n    \n}\n\n\nconst ppp = document.createElement(\"a\");\ndocument.body.appendChild(ppp);\nppp.style = \"display: none\";\n\nlet blob;\n\nfunction downloadp() {\n  if (!blob) return;\n  var url = window.URL.createObjectURL(blob);\n  ppp.href = url;\n  ppp.download = 'test.pdf';\n  ppp.click();\n  window.URL.revokeObjectURL(url);\n}\n\n\n\n</script>\n\n\n","output":"str","x":1140,"y":240,"wires":[[]],"info":"https://bossanova.uk/jspreadsheet/v4/"}]

v6

  • weekly and yearly load calculations
  • STABLE RELEASE
[{"id":"6011c636.5e4798","type":"comment","z":"cce2bfaa.e5748","name":"","info":"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval\n\nfunction looseJsonParse(obj) {\n    return Function('\"use strict\";return (' + obj + ')')();\n}\nconsole.log(looseJsonParse(\n   \"{a:(4-1), b:function(){}, c:new Date()}\"\n))","x":220,"y":80,"wires":[]},{"id":"7bcbccf5.64f074","type":"change","z":"cce2bfaa.e5748","name":"Heat Network Design JSON","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"title\":\"Heat Network Designer\",\"links\":[{\"src\":\"http://www.systemdesigner.co.uk/heatnetwork.php\",\"title\":\"Heat Network Calculator v1\"},{\"src\":\"https://hw3.ddns.net/index.php?page=3D&&startp=heatnetcalc\",\"title\":\"3D Model for Calculator v1\"},{\"src\":\"https://hw7.ddns.net/ui/hncalc\",\"title\":\"Heat Network Calculator v2\"},{\"src\":\"https://hw7.ddns.net/ui/svgexplode?svg=HeatNetwork6.svg\",\"title\":\"Heat Network Schematic Designer (HeatNetwork6.svg)\"}],\"sections\":[{\"title\":\"Loads\",\"questions\":[{\"title\":\"Schedule of loads\",\"question\":\"List the loads on the network\",\"id\":\"loadSchedule\",\"if\":\"true\",\"required\":true,\"type\":\"sheet\",\"notes\":\"Add, edit and copy down lines as with a normal spreadsheet. Right click for further actions including deleting lines.\",\"units\":\"\",\"Xcalculator\":\"hndesignfunctions\",\"XcalculatorStyle\":\"width:100%;height:300px\",\"default\":[[\"Flat\",1,2,3,130],[\"Duplex\",2,4,5.5,20],[\"Office\",0,2,5,1]],\"columns\":[{\"type\":\"text\",\"name\":\"propertyType\",\"title\":\"Property Type\",\"width\":120},{\"type\":\"numeric\",\"name\":\"bedrooms\",\"title\":\"Bedrooms\",\"width\":120,\"decimal\":\".\"},{\"type\":\"numeric\",\"name\":\"occupants\",\"title\":\"Occupants\",\"width\":120,\"decimal\":\".\"},{\"type\":\"numeric\",\"name\":\"kwCH\",\"title\":\"Heating Load kW\",\"width\":120,\"decimal\":\".\"},{\"type\":\"numeric\",\"name\":\"qty\",\"title\":\"Quantity\",\"width\":100,\"decimal\":\".\"}]}]},{\"title\":\"General\",\"questions\":[{\"title\":\"Number of buildings\",\"question\":\"How many buildings are fed from the network?\",\"id\":\"nBuildings\",\"if\":\"true\",\"required\":true,\"type\":\"integer\",\"notes\":\"The total number of buildings connected to the heat network. See https://hw7.ddns.net/ui/svgexplode?svg=HeatNetwork6.svg&display=g16444,g11206,bulkhm,g14636,landlordload,g16320,g5006,bufferstore,lowgrade,heatpump2,heatpump2-2,qton1,fbyp,hiu,g68266,singlemainpump,backupmainpump,g130841-3,g14610-0,g14636-2,g14610,finestrainer,cwsvcs,g14124,g14362.\",\"units\":\"buildings\"},{\"title\":\"Number of properties\",\"question\":\"How many properties are there?\",\"id\":\"nProperties\",\"if\":\"false\",\"required\":true,\"type\":\"integer\",\"notes\":\"The total number of properties connected to the heat network.\",\"units\":\"properties\"},{\"title\":\"Total number of people\",\"question\":\"How many people are there in total?\",\"id\":\"nPeople\",\"if\":\"false\",\"required\":false,\"type\":\"integer\",\"units\":\"people\"},{\"title\":\"Peak network flow temperature\",\"question\":\"What is the peak network flow temperature?\",\"id\":\"tPeak\",\"if\":\"true\",\"required\":true,\"default\":80,\"type\":\"number\",\"units\":\"°C\"}]},{\"title\":\"Domestic Hot Water\",\"questions\":[{\"title\":\"DHW network return temperature\",\"question\":\"What is the network return temperature for DHW?\",\"notes\":\"The temperature fed back from a property to the network when running peak load domestic hot water.\",\"id\":\"tPriRtnDHW\",\"if\":\"true\",\"required\":false,\"default\":19,\"type\":\"number\",\"units\":\"°C\"},{\"title\":\"DHW load profile\",\"question\":\"What hourly DHW load profie to use?\",\"id\":\"profileDHW\",\"if\":\"true\",\"required\":true,\"type\":\"select\",\"options\":[{\"title\":\"EST Data\",\"value\":\"EST\"}]}]},{\"title\":\"Central Heating\",\"questions\":[{\"title\":\"Central heating emitter\",\"question\":\"What types of central heating emitter are used?\",\"id\":\"typeEmitter\",\"if\":\"{{kwCHMax}}\",\"required\":true,\"type\":\"select\",\"options\":[{\"title\":\"Radiators\",\"value\":\"radiator\"},{\"title\":\"Underfloor heating (piped)\",\"value\":\"underfloor\"},{\"title\":\"Fan convectors\",\"value\":\"fan\"}]},{\"title\":\"Central heating connection\",\"question\":\"What types of central heating connection is used?\",\"id\":\"connectionCH\",\"if\":\"{{kwCHMax}}\",\"required\":true,\"type\":\"select\",\"options\":[{\"title\":\"Direct\",\"value\":\"direct\"},{\"title\":\"Indirect\",\"value\":\"indirect\"},{\"title\":\"Mixed\",\"value\":\"mixed\"}]},{\"title\":\"Radiator flow control\",\"question\":\"What types of TRVs are used?\",\"id\":\"typeTRV\",\"if\":\"'{{typeEmitter}}'=='radiator'\",\"required\":true,\"type\":\"select\",\"options\":[{\"title\":\"Basic TRV, with no presetting\",\"value\":\"basic TRV\"},{\"title\":\"Pre-settable TRV\",\"value\":\"presettable TRV\"},{\"title\":\"Pressure-independent pre-settable TRV\",\"value\":\"PICV TRV\"},{\"title\":\"None, isolation only\",\"value\":\"isolation\"}]},{\"title\":\"Radiator return control\",\"question\":\"Are return temperature limit valves fitted to radiators?\",\"id\":\"typeRTL\",\"if\":\"'{{typeEmitter}}'=='radiator'\",\"required\":true,\"type\":\"select\",\"options\":[{\"title\":\"Return temperature control\",\"value\":\"RTL\"},{\"title\":\"None, isolation only\",\"value\":\"isolation\"}]},{\"title\":\"External temperature at peak load\",\"question\":\"What is the outside temperature used for the peak central heating?\",\"notes\":\"Typically -5C. This is the temperatures used to derive figures in the load schedule.\",\"id\":\"tXPeak\",\"if\":\"{{kwCHMax}}\",\"required\":true,\"default\":-5,\"value\":-5,\"type\":\"number\",\"units\":\"°C\"},{\"title\":\"Central heating network return temperature\",\"question\":\"What is the network return temperature for central heating?\",\"notes\":\"The temperature fed back from a property to the network when running peak load central heating.\",\"id\":\"tPriRtnCH\",\"if\":\"{{kwCHMax}}\",\"required\":false,\"default\":45,\"type\":\"number\",\"units\":\"°C\"},{\"title\":\"Central heating diversity\",\"question\":\"What diversity is applied to central heating output?\",\"id\":\"divCH\",\"if\":\"{{kwCHMax}}\",\"required\":false,\"default\":70,\"type\":\"number\",\"units\":\"%\"},{\"title\":\"Base temperature\",\"question\":\"What base temperature is used for heating calculations?\",\"notes\":\"The <i>base temperature</i> is the external temperature below which central heating comes on. 16C to 18C is a typical range. Visit https://www.degreedays.net/base-temperature for further information.\",\"id\":\"baseTemp\",\"if\":\"{{kwCHMax}}\",\"required\":true,\"type\":\"select\",\"default\":\"18\",\"options\":[{\"title\":\"16.0\",\"value\":\"16\"},{\"title\":\"16.5\",\"value\":\"16.5\"},{\"title\":\"17.0\",\"value\":\"17\"},{\"title\":\"17.5\",\"value\":\"17.5\"},{\"title\":\"18.0\",\"value\":\"18\"},{\"title\":\"18.5\",\"value\":\"18.5\"},{\"title\":\"19.0\",\"value\":\"19\"},{\"title\":\"19.5\",\"value\":\"19.5\"},{\"title\":\"20.0\",\"value\":\"20\"},{\"title\":\"20.5\",\"value\":\"20.5\"},{\"title\":\"21.0\",\"value\":\"21\"},{\"title\":\"21.5\",\"value\":\"21.5\"},{\"title\":\"22.0\",\"value\":\"22\"}]},{\"title\":\"Central heating degree-days\",\"question\":\"What degree-days are used to estimate annual central heating loads (16C to 22C base temp)?\",\"notes\":\"Degree days represent the amount of heating required in a location, based on historic weather data. Visit https://www.degreedays.net/ for further information and to obtain values.\",\"id\":\"degDaysAvg\",\"if\":\"{{kwCHMax}}\",\"required\":true,\"type\":\"csv\",\"value\":\"1749.5,1884.5,2023.9,2167.9,2316.2,2467.9,2623.5,2782.4,2944.3,3108.6,3275.4,3444.9,3615.7\",\"units\":\"°days\"},{\"title\":\"Central heating degree-days at base temperature\",\"question\":\"What degree-days are used to estimate annual central heating loads?\",\"notes\":\"Degree days represent the amount of heating required in a location, based on historic weather data. Visit https://www.degreedays.net/ for further information and to obtain values.\",\"id\":\"degDays\",\"if\":\"{{baseTemp}}\",\"required\":true,\"default\":\"{{dDaysCalc}}\",\"type\":\"number\",\"Xcalculator\":\"https://www.degreedays.net/\",\"units\":\"°days\",\"calculatorStyle\":\"width:100%;height:600px\"}]},{\"title\":\"Heat Sources\",\"questions\":[{\"title\":\"Boilers\",\"question\":\"Are boilers to be used?\",\"id\":\"goBoilers\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\"},{\"title\":\"Air Source Heat Pumps\",\"question\":\"Are air source heat pumps to be used?\",\"notes\":\"Not including heat pumps in properties.\",\"id\":\"goASHP\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\"},{\"title\":\"Water Source Heat Pumps\",\"question\":\"Are water source heat pumps to be used?\",\"notes\":\"This is taking heat from an ambient loop or water source. Not including heat pumps in properties.\",\"id\":\"goWSHP\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\"},{\"title\":\"Cooling Source Heat Pumps\",\"question\":\"Are water source heat pumps to be used to reclaim cooling?\",\"notes\":\"This is where cooling circuits are driven by moving heat to the main storage.\",\"id\":\"goReclaim\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\"},{\"title\":\"Combined Heat & Power\",\"question\":\"Is CHP (Combined Heat & Power) to be used?\",\"id\":\"goCHP\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\"},{\"title\":\"Solar Thermal\",\"question\":\"Are solar panels (thermal) to be used?\",\"id\":\"goSolar\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\"}]},{\"title\":\"Boilers\",\"questions\":[{\"title\":\"Boiler fuel type\",\"question\":\"What is the fuel source?\",\"id\":\"boilerFuel\",\"if\":\"{{goBoilers}}\",\"required\":true,\"type\":\"select\",\"options\":[{\"title\":\"Mains Gas\",\"value\":\"gas\"},{\"title\":\"LPG\",\"value\":\"lpg\"},{\"title\":\"Biogas\",\"value\":\"biogas\"},{\"title\":\"Biomass\",\"value\":\"biomass\"},{\"title\":\"Hydrogen\",\"value\":\"hydrogen\"},{\"title\":\"Fuel Oil\",\"value\":\"oil\"},{\"title\":\"Electric\",\"value\":\"electric\"}]},{\"title\":\"Boiler Emissions\",\"question\":\"The following CO2 emissions will be used.\",\"id\":\"boilerEmissions\",\"if\":\"{{goBoilers}}\",\"required\":true,\"type\":\"number\",\"notes\":\"\",\"units\":\"kgCO2/kWh\",\"default\":\"0.216\"},{\"title\":\"Available boiler outputs\",\"question\":\"What sizes of boiler output are available for selection?\",\"id\":\"listBSizes\",\"if\":\"{{goBoilers}}\",\"required\":true,\"type\":\"csv\",\"notes\":\"This is a comma-seperated list of outputs in kW. Selection will round up to the nearest available size.\",\"units\":\"kW\",\"value\":\"30,50,75,100,250,500,750,1000\"},{\"title\":\"Boiler selection\",\"question\":\"Please confirm boiler selection\",\"id\":\"selectBoilers\",\"if\":\"{{goBoilers}}\",\"required\":true,\"type\":\"object\",\"units\":\"n x kW\",\"calculator\":\"hndesignfunctions\",\"calculatorStyle\":\"width:100%;height:75px\"}]},{\"title\":\"Electrical Supplies for Heat Pumps\",\"questions\":[{\"title\":\"Electrical Tariff\",\"question\":\"What Electrical Tariff is used to drive heat pumps?\",\"id\":\"tariffHP\",\"notes\":\"Are electricity supplied provided at a flat rate charge or do prices vary, for example by the time of day.\",\"if\":\"{{goASHP}}\",\"required\":true,\"type\":\"select\",\"options\":[{\"value\":\"flat\",\"title\":\"Flat rate\"},{\"value\":\"mixed\",\"title\":\"Peak+Economy rates\"}]},{\"title\":\"Electrical Supply Emissions\",\"question\":\"The following CO2 emissions will be used for grid supplied electricity.\",\"id\":\"elecEmissions\",\"if\":\"{{goASHP}}\",\"required\":true,\"type\":\"number\",\"notes\":\"Source: https://www.buildenergy.co.uk/tips-and-insight/sap-technicals-fuel-factors/\",\"units\":\"kgCO2/kWh\",\"default\":\"0.519\"}]},{\"title\":\"Air Source Heat Pumps\",\"questions\":[{\"title\":\"ASHP refrigerant\",\"question\":\"What refrigerant is used in the heat pump?\",\"id\":\"fridgeASHP\",\"if\":\"{{goASHP}}\",\"required\":true,\"type\":\"select\",\"options\":[{\"value\":\"R744\",\"title\":\"R744 (CO2)\"}]},{\"title\":\"Available heat pump outputs\",\"question\":\"What sizes of heat pump output are available for selection?\",\"id\":\"listASHPSizes\",\"if\":\"{{goASHP}}\",\"required\":true,\"type\":\"csv\",\"notes\":\"This is a comma-seperated list of outputs in kW. Selection will round up to the nearest available size.\",\"units\":\"kW\",\"value\":\"30\"},{\"title\":\"ASHP selection\",\"question\":\"Please confirm air source heat pump selection\",\"id\":\"selectASHP\",\"if\":\"{{goASHP}}\",\"required\":true,\"type\":\"object\",\"units\":\"n x kW\",\"calculator\":\"hndesignfunctions\",\"calculatorStyle\":\"width:100%;height:75px\"}]},{\"title\":\"Buffer Storage\",\"questions\":[{\"title\":\"Buffer volume\",\"question\":\"What volume of buffer storage is to be provided?\",\"notes\":\"A volume of {{vBuffer9}} litres or more is advised. This is based on storing the heaviest hour of hot water use. A minimum of 500 litres would ne normal for low load functions.\",\"id\":\"vBuffer\",\"if\":\"true\",\"required\":true,\"type\":\"number\",\"units\":\"litres\",\"default\":\"{{vBuffer9}}\"}],\"outputs\":[{\"title\":\"Daily Hot Water Patterns\",\"id\":\"est24\",\"if\":\"{{vBuffer}}\",\"type\":\"iframe\",\"url\":\"hnoutputs/peakload\",\"style\":\"width:100%;height:425px\"},{\"title\":\"Buffer Charging\",\"id\":\"bufferUse\",\"if\":\"{{vBuffer}}\",\"type\":\"iframe\",\"url\":\"hnoutputs/buffer\",\"style\":\"width:100%;height:425px\"},{\"title\":\"Historical Load Modelling\",\"id\":\"yearly\",\"if\":\"{{vBuffer}}\",\"type\":\"iframe\",\"url\":\"hnoutputs/yearly\",\"style\":\"width:100%;height:700px\"}]},{\"title\":\"Save\",\"questions\":[{\"title\":\"Save design\",\"question\":\"Save design?\",\"id\":\"goSave\",\"if\":\"true\",\"required\":true,\"type\":\"boolean\"},{\"title\":\"Network name\",\"question\":\"What is the name of the Network?\",\"id\":\"networkName\",\"if\":\"{{goSave}}\",\"required\":false,\"type\":\"text\",\"units\":\"\"},{\"title\":\"Email address\",\"question\":\"Email address?\",\"id\":\"email\",\"if\":\"{{goSave}}\",\"required\":true,\"type\":\"email\",\"notes\":\"The design will be saved against your email, and a link will be emailed to you providing access.\"}],\"outputs\":[{\"title\":\"Save Design\",\"id\":\"save\",\"if\":\"{{goSave}}\",\"type\":\"iframe\",\"url\":\"hnoutputs/save\",\"style\":\"width:100%;height:110px\"}]}],\"calculations\":[{\"id\":\"pPP\",\"title\":\"Average people per property\",\"if\":\"{{nProperties}}\",\"function\":\"{{nPeople}} / {{nProperties}}\",\"units\":\"people\"},{\"id\":\"density\",\"title\":\"Average people per building (density)\",\"if\":\"{{nBuildings}}\",\"function\":\"{{nPeople}} / {{nBuildings}}\",\"units\":\"people\"},{\"id\":\"kwDHWEst\",\"title\":\"Typical HIU rating for DHW\",\"if\":\"{{pPP}}\",\"function\":\"{{pPP}}<3?37.5:({{pPP}}<5?45:60)\",\"units\":\"kW\"},{\"id\":\"peepDS439\",\"title\":\"People per standard DS439 property\",\"if\":\"true\",\"function\":\"2.3\",\"units\":\"people\"},{\"id\":\"eqPropDS439\",\"title\":\"Equivalent number of DS439 properties\",\"if\":\"{{peepDS439}}\",\"function\":\"{{nPeople}}/{{peepDS439}}\",\"units\":\"properties\"},{\"id\":\"kwDS439\",\"title\":\"Peak DHW Load\",\"if\":\"{{eqPropDS439}}\",\"function\":\"Math.ceil((1.19* {{eqPropDS439}}) + (18.8* Math.pow({{eqPropDS439}},0.5)) + 17.6)\",\"units\":\"kW\"},{\"id\":\"vPPEST\",\"title\":\"Volume DHW used per property per day\",\"if\":\"true\",\"function\":\"40\",\"units\":\"litres\"},{\"id\":\"vPHEST\",\"title\":\"Volume DHW used per person per day\",\"if\":\"true\",\"function\":\"28\",\"units\":\"litres\"},{\"id\":\"tRiseEST\",\"title\":\"Average temperature Rise on DHW\",\"if\":\"true\",\"function\":\"35\",\"units\":\"°C\"},{\"id\":\"vDHWEST\",\"title\":\"Volume drawn per day for DHW (tap)\",\"if\":\"{{nPeople}}\",\"function\":\"({{nProperties}}*{{vPPEST}})+({{nPeople}}*{{vPHEST}})\",\"units\":\"litres\"},{\"id\":\"kwhDHWEST\",\"title\":\"Energy used per day for DHW\",\"if\":\"{{vDHWEST}}\",\"function\":\"({{vDHWEST}} * 4.2 * {{tRiseEST}}) / 3600\",\"units\":\"kWh\"},{\"id\":\"vPDHW\",\"title\":\"Volume used per day for DHW (primary)\",\"if\":\"{{vDHWEST}}\",\"function\":\"({{vDHWEST}} * {{tRiseEST}}) / (({{tPeak}}-{{tPriRtnDHW}}))\",\"units\":\"litres\"},{\"id\":\"vBuffer9\",\"title\":\"Buffer Storage for DHW (based on 9%)\",\"if\":\"{{vPDHW}}\",\"function\":\"{{vPDHW}} * 0.09\",\"units\":\"litres\"},{\"id\":\"kwCH\",\"title\":\"Peak diversified (steady state) central heating load\",\"if\":\"{{kwCHMax}} &&  {{divCH}}\",\"function\":\"({{kwCHMax}} * {{divCH}}) / 100\",\"units\":\"kW\"},{\"id\":\"kwhCH\",\"title\":\"Energy used per day for CH\",\"if\":\"{{kwCH}}\",\"function\":\"{{kwCH}} * 24\",\"units\":\"kWh\"},{\"id\":\"vPCH\",\"title\":\"Volume used on peak load day for CH (primary)\",\"if\":\"{{kwCH}}\",\"function\":\"({{kwhCH}} * 3600) / (4.2 * ({{tPeak}}-{{tPriRtnCH}}))\",\"units\":\"litres\"},{\"id\":\"kwhP24\",\"title\":\"Peak energy used per day\",\"if\":\"true\",\"function\":\"{{kwhCH}}+{{kwhDHWEST}}\",\"units\":\"kWh\"},{\"id\":\"vPCH\",\"title\":\"Peak volume used per day (primary)\",\"if\":\"true\",\"function\":\"{{vPCH}}+{{vPDHW}}\",\"units\":\"litres\"},{\"id\":\"kwPeak\",\"title\":\"Peak load\",\"if\":\"true\",\"function\":\"{{kwCH}}+{{kwDS439}}\",\"units\":\"kW\"},{\"id\":\"kwP24\",\"title\":\"Average 24h peak load\",\"if\":\"true\",\"function\":\"{{kwCH}}+({{kwhDHWEST}}/24)\",\"units\":\"kW\"},{\"id\":\"m3hDHWPeak\",\"title\":\"Primary flow rate at peak DHW load\",\"if\":\"{{tPriRtnDHW}}\",\"function\":\"3.6 * {{kwDS439}} / (4.2 * ({{tPeak}}-{{tPriRtnDHW}}))\",\"units\":\"m3/h\"},{\"id\":\"m3hCHPeak\",\"title\":\"Primary flow rate at peak central heating load\",\"if\":\"{{tPriRtnCH}}\",\"function\":\"3.6 * {{kwCH}} / (4.2 * ({{tPeak}}-{{tPriRtnCH}}))\",\"units\":\"m3/h\"},{\"id\":\"m3hPeak\",\"title\":\"Primary flow rate at peak load\",\"if\":\"{{m3hDHWPeak}}||{{m3hCHPeak}}\",\"function\":\"{{m3hDHWPeak}}+{{m3hCHPeak}}\",\"units\":\"m3/h\"},{\"id\":\"tPriRtnPeak\",\"title\":\"Primary return temperature at peak load\",\"if\":\"{{m3hPeak}}\",\"function\":\"{{tPeak}} - ({{kwPeak}} / (4.2 * {{m3hPeak}} / 3.6))\",\"units\":\"°C\"},{\"id\":\"tVWART24\",\"title\":\"Weighted primary return temperature on peak load day\",\"if\":\"{{m3hPeak}}\",\"function\":\"( ({{tPriRtnCH}} * {{vPCH}}) + ({{tPriRtnDHW}} * {{vPDHW}}) ) / ({{vPCH}} + {{vPDHW}})\",\"units\":\"°C\"},{\"id\":\"bufferkWh\",\"title\":\"Buffer storage peak energy content\",\"if\":\"{{vBuffer}}\",\"function\":\"({{vBuffer}} * 4.2 * ({{tPeak}} - {{tPriRtnPeak}})) / 3600\",\"units\":\"kWh\"},{\"id\":\"boilerQty\",\"title\":\"Boiler quantity\",\"if\":\"'{{selectBoilers}}'!==''\",\"function\":\"('{{selectBoilers}}').split('x')[0].trim()\",\"units\":\"boilers\"},{\"id\":\"boilerkW\",\"title\":\"Boiler unit power\",\"if\":\"'{{selectBoilers}}'!==''\",\"function\":\"('{{selectBoilers}}').split('x')[1].trim()\",\"units\":\"kW\"},{\"id\":\"boilerkWPeak\",\"title\":\"Boiler peak power (n)\",\"if\":\"'{{selectBoilers}}'!==''\",\"function\":\"{{boilerkW}}*{{boilerQty}}\",\"units\":\"kW\"},{\"id\":\"boilerkWxN1\",\"title\":\"Boiler power (n-1)\",\"if\":\"'{{selectBoilers}}'!==''\",\"function\":\"{{boilerkW}}*({{boilerQty}}-1)\",\"units\":\"kW\"},{\"id\":\"ASHPQty\",\"title\":\"ASHP quantity\",\"if\":\"'{{selectASHP}}'!==''\",\"function\":\"('{{selectASHP}}').split('x')[0].trim()\",\"units\":\"ASHPs\"},{\"id\":\"ASHPkW\",\"title\":\"ASHP unit power\",\"if\":\"'{{selectASHP}}'!==''\",\"function\":\"('{{selectASHP}}').split('x')[1].trim()\",\"units\":\"kW\"},{\"id\":\"ASHPkWPeak\",\"title\":\"ASHP peak power (n)\",\"if\":\"'{{selectASHP}}'!==''\",\"function\":\"{{ASHPkW}}*{{ASHPQty}}\",\"units\":\"kW\"},{\"id\":\"ASHPkWxN1\",\"title\":\"ASHP power (n-1)\",\"if\":\"'{{selectASHP}}'!==''\",\"function\":\"{{ASHPkW}}*({{ASHPQty}}-1)\",\"units\":\"kW\"},{\"id\":\"kWInPeak\",\"title\":\"Peak power available from all sources\",\"if\":\"true\",\"function\":\"parseFloat('{{boilerkWPeak}}'||0)+parseFloat('{{ASHPkWPeak}}'||0)\",\"units\":\"kW\"},{\"id\":\"kWxN1\",\"title\":\"Peak power available from (n-1) sources\",\"if\":\"true\",\"function\":\"{{boilerkWPeak}}+{{ASHPkWPeak}}-Math.max(parseFloat('{{boilerkW}}'||0),parseFloat('{{ASHPkW}}'||0))\",\"units\":\"kW\"},{\"id\":\"sparekW\",\"title\":\"Excess power availiable (n)\",\"if\":\"{{kwP24}}\",\"function\":\"({{kWInPeak}}-{{kwP24}})\",\"units\":\"kW\"},{\"id\":\"ovsersizing\",\"title\":\"Oversizing (n)\",\"if\":\"{{kwP24}}\",\"function\":\"100*({{kWInPeak}}-{{kwP24}})/{{kwP24}}\",\"units\":\"%\"},{\"id\":\"ovsersizingxN1\",\"title\":\"Oversizing (n-1)\",\"if\":\"{{kwP24}}\",\"function\":\"100*({{kWxN1}}-{{kwP24}})/{{kwP24}}\",\"units\":\"%\"},{\"id\":\"dDaysCalc\",\"title\":\"Calculated degree days per year\",\"if\":\"{{baseTemp}}\",\"function\":\"('{{degDaysAvg}}').split(',')[({{baseTemp}}-16)*2]\",\"units\":\"°days\"},{\"id\":\"dDaysPeak\",\"title\":\"Peak load day degree days\",\"if\":\"('{{tXPeak}}'!=='') && ('{{baseTemp}}'!=='')\",\"function\":\"{{baseTemp}} - {{tXPeak}}\",\"units\":\"°days\"},{\"id\":\"dDaysPeak\",\"title\":\"Annual days of full load heating\",\"if\":\"{{dDaysPeak}}\",\"function\":\"{{dDaysCalc}} / {{dDaysPeak}}\",\"units\":\"days\"},{\"id\":\"kwhCH365\",\"title\":\"Annual energy for central heating\",\"if\":\"{{dDaysPeak}}\",\"function\":\"parseInt({{dDaysPeak}} * {{kwhCH}})\",\"units\":\"kWh\"},{\"id\":\"kwhDHW365\",\"title\":\"Annual energy for domestic hot water\",\"if\":\"{{kwhDHWEST}}\",\"function\":\"parseInt({{kwhDHWEST}} * 365)\",\"units\":\"kWh\"},{\"id\":\"kwhUsed365\",\"title\":\"Annual energy utilised\",\"if\":\"{{kwhDHWEST}}\",\"function\":\"parseInt({{kwhCH365}} + {{kwhDHW365}})\",\"units\":\"kWh\"},{\"id\":\"kwhDistLoss365\",\"title\":\"Annual distribution heat losses (est at 20%)\",\"if\":\"{{kwhUsed365}}\",\"function\":\"parseInt({{kwhUsed365}} * 0.2)\",\"units\":\"kWh\"},{\"id\":\"kwh365\",\"title\":\"Annual energy required\",\"if\":\"{{kwhCH365}}\",\"function\":\"parseInt('{{kwhCH365}}'||0) + parseInt('{{kwhDHW365}}'||0) + parseInt('{{kwhDistLoss365}}'||0)\",\"units\":\"kWh\"}]}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":740,"y":380,"wires":[["d2c83715.bc4ad8"]]},{"id":"a0339f75.b2c11","type":"http in","z":"cce2bfaa.e5748","name":"","url":"/ui/hndesign","method":"get","upload":false,"swaggerDoc":"","x":220,"y":220,"wires":[["8dc13cac.e444b"]]},{"id":"8dc13cac.e444b","type":"template","z":"cce2bfaa.e5748","name":"Form Generator","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js\"></script>\n{{!--https://www.sitepoint.com/basic-jquery-form-validation-tutorial/--}}\n\n<script src=\"https://unpkg.com/mustache@latest\"></script>\n\n\n\n<script src=\"https://bossanova.uk/jspreadsheet/v4/jexcel.js\"></script>\n<link rel=\"stylesheet\" href=\"https://bossanova.uk/jspreadsheet/v4/jexcel.css\" type=\"text/css\" />\n \n<script src=\"https://jsuites.net/v4/jsuites.js\"></script>\n<link rel=\"stylesheet\" href=\"https://jsuites.net/v4/jsuites.css\" type=\"text/css\" />\n\n\n\n<style>\n    \n  \n    .jexcel_content {\n        font-size: 14px;\n    }\n    \n    .jexcel {\n        white-space: normal;\n    }\n\n\n.mybutt {\n    padding-left: 6px;\n    padding-right: 6px;\n    padding-top: 4px;\n    padding-bottom: 4px;\n    margin-right: 3px;\n    font-size: 14px;\n    border-radius: 4px;\n    cursor: pointer;\n    background-color: #a4eba4;\n    border-color: #4aa55a;\n    border: solid;\n    border-width: 1px;\n    box-shadow: 2px 2px 3px 1px rgb(0 0 0 / 28%);\n}\n.mybutt:hover {\n  background-color: #dcffdc;\n}\n.section {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.question {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #a8e5a8;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n\n.outputbox {\n    margin: auto;\n    min-height: 20px;\n    max-width: 900px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #ffffff;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    box-shadow: inset 0 1px 1px rgb(0 0 0 / 5%);\n}\n\n.cframe {\n    border-radius: 0.25rem;\n    margin: 0px 0px 20px 0px;\n}\n\n.h2, h2 {\n    font-size: 24px;\n}\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    margin-bottom: 20px;\n    font-weight: 500;\n    line-height: 1.2;\n}\n\n\n.qtext {\n    \n    padding: 6px 0px 12px;\n    font-size: 18px;\n    font-weight: bold;\n}\n.notes {\n    \n    padding: 0px 0px 12px;\n    font-size: 16px;\n}\n.qunits {\n    \n    padding: 10px 10px 0px;\n    line-height: 2;\n}\n\n.video-wrapper {\n\tposition: relative;\n\tpadding-bottom: 56.25%; /* 16:9 */\n\tpadding-top: 15px;\n\theight: 0;\n\tmargin: 10px 0;\n}\n.video-wrapper iframe {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n\nform .error {\n  color: #ff0000;\n  font-size: 16px;\n}\n\n::-webkit-input-placeholder { /* Edge */\n  color: yellow;\n}\n\n:-ms-input-placeholder { /* Internet Explorer 10-11 */\n  color: yellow;\n}\n\n::placeholder {\n  color: yellow;\n}\n\n.table td, .table th {\n    padding: 3px;\n}\n\n</style>\n<script type=\"text/javascript\">\n\nvar a = new Date();\nvar qdata;\nvar calculated = {};\nvar hasFocus;\nvar currentSection;\nvar inputsOut;\nvar inputString;\nvar calcsString;\nvar objects={}; // not used yet\nvar sheets = {};\nvar sheetdata = {};\nvar initsheets;\n\n\t$(document).ready(function(e) {\n    \n        // $(\"form[ajax=true]\").submit(function(e) {\n            \n        //     //alert(\"submit\");\n            \n        //     e.preventDefault();\n        \n             \n            //var urlParams = new URLSearchParams(window.location.search);\n            //if (urlParams.get('display')) { loadstring = \",,\" + urlParams.get('display'); }\n\n            calculated[\"jsonQ\"] = \"hndesign\";\n\n            var urlParams = window.location.search.replace(\"?\",\"\").split(\"&\");\n            for(var upa in urlParams) {\n                \n                calculated[urlParams[upa].split(\"=\")[0]] = urlParams[upa].split(\"=\")[1];\n                \n            }\n            \n            \n            \n            var form_data = {};\n            var form_url = \"/ui/qdata/\" + calculated[\"jsonQ\"];\n            var form_target = $(this).attr(\"target\") || \"result\";\n            var ftarget = \"#\" + form_target;\n            var form_method = \"GET\";\n            \n        //     $(\"#loadingimg\").show();\n            \n            $.ajax({\n                url: form_url, \n                type: form_method,      \n                data: form_data,     \n                cache: false,\n                success: function(results){   \n                    \n                    qdata = results;\n                    //qdata = JSON.parse(returnhtml);\n                    console.log(qdata);\n                   \n                    //if(urlParams['nBuildings']) { runCalcs(); runCalcs();  }\n                    runCalcs(); \n                    runCalcs();\n                    \n                    document.getElementById(\"formName\").innerHTML = qdata.title || \"Unamed Form\"; //JSON.stringify(qdata) ;\n                    \n                    // document.getElementById(\"section1\").innerHTML = parseQuestions(qdata); //JSON.stringify(qdata) ;\n                    \n                    // for (var sht in initsheets) {  initSheet(initsheets[sht]);   }\n                    \n                    // validform();\n                                  \n                }           \n            });    \n            \n        // });\n        \n      \n        \n    });\n\n\nfunction initSheet(id) {\n\n    console.log(\"initSheet \" + id);\n    console.log(sheetdata);\n    \n    var shid = 'sheet-' + id;\n    var sdata = sheetdata[id];\n    \n    \n\n    try {\n    \n        document.getElementById(shid).innerHTML = \"\";\n        \n        sheets[id] = jspreadsheet(document.getElementById(shid), {\n            data: sdata.data,\n            columns: sdata.columns,\n            onchange: function(instance, cell, x, y, value) {\n                \n                console.log(value);\n                getSheetData(id);\n            },\n            updateTable:function(instance, cell, col, row, val, label, cellName) {\n               \n                //console.log(instance);\n                //console.log(val);\n                \n            },\n            columnSorting:false\n        });\n\n    } catch {}\n}\n\nfunction getSheetData(id) {\n    \n    \n    //alert(id);\n    \n    //console.log(sheets[id].getData());\n    \n    sheetdata[id].data = sheets[id].getData();\n    console.log(sheetdata);\n    \n    var oots = \"\";\n    for (var row in sheetdata[id].data) {\n       for (var c in sheetdata[id].data[row]) {\n           \n           var val = \"\" + (sheetdata[id].data[row][c] || \"\");\n           val = val.replace(/ /g,\"_\")\n           oots += val + \",\";\n        } \n        oots += \" \";\n    }\n    \n    oots = oots.substr(0, oots.length - 2);\n    console.log(oots);\n    \n    returncalc(id,oots)\n    \n    \n}\n\n\nfunction getObject(id) {\n    \n  \n    return (objects[id]||null);\n    \n}\n\n\nfunction setObject(id,value) {\n    \n\n    try { objects[id] = value; }\n    catch {}\n}\n\t\nfunction returncalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).value = value; }\n    catch {\n        \n        try { calculated[id] = value; }\n        catch {}\n    }\n    \n}\n\nfunction suggestcalc(id,value) {\n    \n    //alert(id + \" = \" + value);\n    \n    try { document.getElementById(id).placeholder = value + \" ... please confirm\"; }\n    catch {}\n}\n\t\nfunction parseQuestions(qdata) {\n    \n    console.log(qdata);\n    console.log(calculated);\n    \n    var linkstxt=\"\";\n    if (qdata.links) {\n        for (var lnk in qdata.links) {\n            linkstxt += (linkstxt!==\"\"?\"<br>\":\"\") + '<a href=\"' + qdata.links[lnk].src + '\" target=\"_blank\">' + (qdata.links[lnk].title||qdata.links[lnk].src) + '</a>';\n        }\n        \n    }\n    document.getElementById(\"links\").innerHTML = linkstxt ; //JSON.stringify(qdata) ;\n    \n    \n    inputsOut = '<input id=\"jsonQ\" name=\"jsonQ\" value=\"' + calculated[\"jsonQ\"] + '\" class=\"form-control\" type=\"hidden\">';\n                    \n    \n    inputsOut += '<table class=\"table\">';\n    \n    inputString = \"jsonQ=\" + calculated[\"jsonQ\"];  // data source for form is fixed\n    \n    hasFocus = null;\n    currentSection = null;\n    initsheets = [];\n    \n    var ootoot = \"\";\n    for (var s in qdata[\"sections\"]) {\n        console.log(s);\n        console.log(qdata.sections[s]);\n        \n        var oot = \"\";\n        var ootcount=0;\n        \n        //oot += \"<div class='section'><h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        oot += \"<h2>\" + qdata.sections[s].title + \"</h2>\\n\";\n        \n        \n        \n        for (var q in qdata.sections[s].questions) {\n            \n            \n            var qif = qdata.sections[s].questions[q].if || true;\n            var qift = Mustache.render(qif, calculated);\n            \n            var goq = true;\n            try {\n              goq = looseJsonParse(qift); \n            }\n            catch(err) {\n              goq = false;\n            }\n            \n            var v=\"\";\n            if (calculated[qdata.sections[s].questions[q].id]) { v= calculated[qdata.sections[s].questions[q].id] ; }\n            else if (qdata.sections[s].questions[q].value) { v= qdata.sections[s].questions[q].value ; }\n            \n                \n            \n            \n            if(goq) {\n                \n                var calcfr = \"\";\n                if (qdata.sections[s].questions[q].calculator) { calcfr = '<iframe class=\"cframe\" frameBorder=\"0\" src=\"' +qdata.sections[s].questions[q].calculator + '?field=' + qdata.sections[s].questions[q].id + (calcsString||\"\") + '\" style=\"' + (qdata.sections[s].questions[q].calculatorStyle ? qdata.sections[s].questions[q].calculatorStyle:'width:100%; height:300px;') + '\"></iframe>'}\n            \n            \n                if (v!==\"\") { \n                    inputsOut += \"<tr>\";  \n                    \n                    var cOs1 = \"\";  var cOs2 = \"\";\n            \n                    if (document.getElementById(\"hideID\").checked!==true) {\n                        cOs2 = \" <small>[<i>\" + qdata.sections[s].questions[q].id + \"</i>]</small>\";  \n                    }\n                    \n                    inputsOut += '<td width=\"40%\">' + (qdata.sections[s].questions[q].title||qdata.sections[s].questions[q].id) + cOs2 + \"</td>\";\n                    \n                    var vs1=\"\"; var vs2=\"\";\n                    if((\"\"+v).indexOf(\",\") > -1) { vs1=\"<small>\"; vs2=\"</small>\"; }\n                    \n                    inputsOut +=  ('<td align=\"right\">' + vs1 + v + vs2 + \"</td>\").replace(/\\, /g,\"<br>\").replace(/\\,/g,\", \");\n                    inputsOut +=  '<td width=\"14%\">' + (qdata.sections[s].questions[q].units||\"\") + \"</td></tr>\\n\";\n                    \n                    inputString += (inputString!==\"\"?\"&\":\"\") + qdata.sections[s].questions[q].id + \"=\" + v;\n                }\n            \n                var isDisplayed = false;\n            \n                if (hasFocus && document.getElementById(\"oneQ\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">'; }\n            \n                else if (v!==\"\") { \n                    \n                    if (document.getElementById(\"hideDone\").checked==true) {  oot += '<div class=\"question\" style=\"display:none\">';   }\n                    else {  oot += '<div class=\"question\" style=\"background-color: #d2efd2;\">'; ootcount++; isDisplayed=true; }\n                    \n                } else { oot += '<div class=\"question\">'; ootcount++; isDisplayed=true; if (!hasFocus) { hasFocus = qdata.sections[s].questions[q].id;  currentSection = qdata.sections[s].title;  } }\n                \n                \n                //oot += \"<div class='qtext'>\" + qdata.sections[s].questions[q].title + '</div>';\n                oot += '<label for=\"' + qdata.sections[s].questions[q].id + '\" class=\"qtext\">' + (qdata.sections[s].questions[q].question||qdata.sections[s].questions[q].title) + '</label>';\n                \n                if (calcfr!==\"\") { oot += \"\\n\" + calcfr + \"\\n\"; }\n                \n                if (qdata.sections[s].questions[q].notes) { oot += '<div class=\"notes\">'  + convertLinks(Mustache.render(qdata.sections[s].questions[q].notes, calculated)) + '</div>'; }\n                \n                if (qdata.sections[s].questions[q].type == \"sheet\") {\n                    \n                    oot += '<br><br><div id=\"sheet-' + qdata.sections[s].questions[q].id + '\">';\n                \n                    oot += '<span onclick=\"initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ')\"><small>Load Sheet</small></span> ';\n                    \n                    oot += '</div><br><br>';\n                    \n                    //oot += '<script>initSheet(' + \"'\" + qdata.sections[s].questions[q].id + \"'\"  + ');</scrip' + 't> ';\n                    //var myTimeout = setTimeout(initSheet(qdata.sections[s].questions[q].id), 1000);\n                    if (isDisplayed) { initsheets.push(qdata.sections[s].questions[q].id); }\n                \n                    var shob = {};\n                    shob['columns'] = qdata.sections[s].questions[q].columns;\n                    shob['data'] = qdata.sections[s].questions[q].default;\n                    \n                    if((\"\"+v)!==\"\") {\n                        \n                        shob['data']=[];\n                        var vv = v.replace(/\\%20/g,\" \").replace(/_/g,\" \");\n                        var lns = vv.split(\", \");\n                        for (var lnsv in lns) {\n                            shob['data'].push(lns[lnsv].split(\",\"));\n                        }\n                    }\n                    \n                    sheetdata[qdata.sections[s].questions[q].id] = shob;\n                    \n                }\n                \n                oot += '<table width=\"100%\"><tr><td width=\"80%\">';\n                \n                if (qdata.sections[s].questions[q].type==\"boolean\") {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                      if (v==\"true\") { oot += '<option value=\"false\">No</option><option value=\"true\" selected>Yes</option>'; }\n                      else if (v==\"false\")  { oot += '<option value=\"false\" selected>No</option><option value=\"true\">Yes</option>'; }\n                      else  { oot += '<option value=\"\"></option><option value=\"false\">No</option><option value=\"true\">Yes</option>'; }\n                    oot += '</select>';\n                    \n                } else if (qdata.sections[s].questions[q].options) {\n                    \n                    oot += '<select class=\"form-control\" name=\"' + qdata.sections[s].questions[q].id + '\" id=\"' + qdata.sections[s].questions[q].id + '\">';\n                    if (v==\"\") { oot += '<option value=\&qu