{
  "information": {
    "Title": "Electrolysis_Virtual_Lab_xAPI",
    "Author": [
      "sithu",
      "lookang",
      "storyboard by sheena"
    ],
    "AuthorLogo": [
      "",
      "",
      ""
    ],
    "Password": "unused",
    "Keywords": "",
    "Abstract": "",
    "Copyright": "",
    "Level": "",
    "Language": "",
    "Logo": [
      "./logoElectolysis.png"
    ],
    "RunAlways": "true",
    "ModelTab": "",
    "ModelTabTitle": "",
    "ModelName": "",
    "FixedNavigationBar": "false",
    "CSSFile": "",
    "DetectedFiles": [
      "./logoElectolysis.png"
    ],
    "AuxiliaryFiles": [
      "",
      "./xapiwrapper.min.js",
      "./xapiwrapper.min.js"
    ],
    "HTMLHead": "<script src=\"xapiwrapper.min.js\"></script>\n\n <script>\n    // Using a namespace to prevent global variable clashes\n    const XAPIUtils = {\n      parameters: null, // Parameters store\n      getParameters: function () {\n        if (!this.parameters) { // Ensure fetch once\n          var urlParams = new URLSearchParams(window.location.search);\n          var endpoint = urlParams.get('endpoint');\n          var auth = urlParams.get('auth');\n          var agent = JSON.parse(urlParams.get('agent'));\n          var stateId = urlParams.get('stateId');\n          var activityId = urlParams.get('activityId');\n\n          ADL.XAPIWrapper.changeConfig({\n            \"endpoint\": endpoint + \"/\",\n            \"auth\": `Basic ${auth}`\n          });\n\n          this.parameters = {\n            agent,\n            stateId,\n            activityId\n          };\n        }\n\n        return this.parameters;\n      }\n    };\n\n    // Immediately invoke getParameters on page load\n    document.addEventListener(\"DOMContentLoaded\", function() {\n      XAPIUtils.getParameters(); // Fetch parameters once on load\n    });\n\n    function sendScore(score) {\n      try {\n        const parameters = XAPIUtils.getParameters(); // Retrieve parameters from store\n        const activityid = parameters.activityId;\n        const stateId = parameters.stateId;\n        const agent = parameters.agent;\n        const registration = null;\n\n        const stateValue = {\n          score: score\n        };\n\n        ADL.XAPIWrapper.sendState(activityid, agent, stateId, registration, stateValue);\n      } catch (err) {\n        console.error(\"An error has occurred!\", err);\n      }\n    }\n</script>\n\n<script \nasync=\"true\" src=\"https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ\"></script>\n<script>\n  window.dataLayer = window.dataLayer || [];\n  function gtag(){dataLayer.push(arguments);}\n  gtag('js', new Date());\n\n  gtag('config', 'G-S9EWRY1CPJ');\n</script>",
    "SaveInXMLFormat": "false",
    "IncludeSource": "true",
    "IncludeLibrary": "true",
    "UglifyJS": "false",
    "PreviewFullModel": "false",
    "UseInterpreter": "true",
    "UseDeltaForODE": "false"
  },
  "description": {
    "pages": []
  },
  "model": {
    "variables": {
      "pages": [
        {
          "Name": "Var Table 1",
          "Active": "true",
          "Internal": "false",
          "Type": "undefined",
          "PageComment": "",
          "Variables": [
            {
              "Name": "numOfNegativeIons",
              "Value": "0",
              "Type": "int",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "posOfNegativeIons",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "stuckStatus",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "anodePos",
              "Value": "{}",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "cathodePos",
              "Value": "{}",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "moleculeRad",
              "Value": "0.05",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "numOfPositiveIons",
              "Value": "0",
              "Type": "int",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "posOfPositiveIons",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "positiveIonsTargetPositions",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "negativeIonsTargetPositions",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "negativeIonLabels",
              "Value": "[]",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "positiveIonLabels",
              "Value": "[]",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            }
          ]
        },
        {
          "Name": "Var Table 2",
          "Active": "true",
          "Internal": "false",
          "Type": "VARIABLE_EDITOR",
          "PageComment": "",
          "Variables": [
            {
              "Name": "positiveIons",
              "Value": "{}",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "negativeIons",
              "Value": "{}",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "negativeIonsVisibility",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "positiveIonsVisibility",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "reactions",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "posOfAnodeProducts",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "anodeProductsLabels",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "anodeProductsVisibility",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "posOfCathodeProducts",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "cathodeProductsLabels",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "cathodeProductsVisibility",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            }
          ]
        },
        {
          "Name": "Var Table 3",
          "Active": "true",
          "Internal": "false",
          "Type": "VARIABLE_EDITOR",
          "PageComment": "",
          "Variables": [
            {
              "Name": "anodeProductTarget",
              "Value": "[-0.6, 0.7]",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "cathodeProductTarget",
              "Value": "[0.6, 0.7]",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "anodeProductsReachedTarget",
              "Value": "[]",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "cathodeProductsReachedTarget",
              "Value": "[]",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "anodeTestTubeLevel",
              "Value": "0",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "cathodeTestTubeLevel",
              "Value": "0",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "positiveIonTypes",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "negativeIonTypes",
              "Value": "[]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "solutionTypes",
              "Value": "{}",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "anodeElectronPositions",
              "Value": "[]",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "anodeElectronVisibility",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "anodeElectronReachedTarget",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "cathodeElectronPositions",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "cathodeElectronVisibility",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "cathodeElectronReachedTarget",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            }
          ]
        },
        {
          "Name": "Var Table 6",
          "Active": "true",
          "Internal": "false",
          "Type": "VARIABLE_EDITOR",
          "PageComment": "",
          "Variables": [
            {
              "Name": "anodeElectronStartPos",
              "Value": "[-0.6, -0.2]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "anodeElectronEndPos",
              "Value": "[-0.6, -1.1]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "cathodeElectronStartPos",
              "Value": "[0.6, -0.9]",
              "Type": "Object",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "cathodeElectronEndPos",
              "Value": "[0.6, -0.2]",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "anodeFormula",
              "Value": "\"\"",
              "Type": "String",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "cathodeFormula",
              "Value": "\"\"",
              "Type": "String",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "overallFormula",
              "Value": "\"\"",
              "Type": "String",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            }
          ]
        },
        {
          "Name": "font",
          "Active": "true",
          "Internal": "false",
          "Type": "VARIABLE_EDITOR",
          "PageComment": "",
          "Variables": [
            {
              "Name": "fontSize",
              "Value": "12",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "font",
              "Value": "\"normal normal \" + fontSize + \"px\"",
              "Type": "String",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "fontSmall",
              "Value": "\"normal normal \" + fontSize/2 + \"px\"",
              "Type": "String",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            }
          ]
        },
        {
          "Name": "xapi",
          "Active": "true",
          "Internal": "false",
          "Type": "VARIABLE_EDITOR",
          "PageComment": "",
          "Variables": [
            {
              "Name": "totalScore",
              "Value": "0",
              "Type": "int",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            }
          ]
        },
        {
          "Name": "lookang",
          "Active": "true",
          "Internal": "false",
          "Type": "VARIABLE_EDITOR",
          "PageComment": "",
          "Variables": [
            {
              "Name": "colorSolution",
              "Value": "\"rgba(0,0,255,0.1)\"",
              "Type": "String",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "font",
              "Value": "\"normal normal large \\\"Times New Roman\\\", Times, serif\"",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "anodeText",
              "Value": "\"4 OH\u207b (aq) \u2192  2 H\u2082O(l) + O\u2082  \u200b(g) + 4 e\u208b\"",
              "Type": "String",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "cathodeText",
              "Value": "\"2 H\u207a (aq)+2 e\u208b  \u2192 H\u2082 (g)\"+\"\\n4 H\u207a (aq)+4 e\u208b  \u2192 2 H\u2082 (g)\"",
              "Type": "String",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "overallText",
              "Value": "\"2 H\u2082O (l) \u2192 2 H\u2082  (g)+O\u2082 \u200b(g)\"",
              "Type": "String",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "diluteSelected",
              "Value": "false",
              "Type": "boolean",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "concentratedSelected",
              "Value": "false",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            }
          ]
        }
      ]
    },
    "initialization": {
      "pages": [
        {
          "Name": "solutionTypes",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "",
          "Code": "solutionTypes = {\n    \"dilute NaCl\": {\n        negativeIonTypes: [\n          {\n            formula: \"OH\u00af\",\n            amount: 4,\n          },\n          {\n            formula: \"Cl\u00af\",\n            amount: 4,\n          },\n        ],\n        positiveIonTypes: [\n          {\n            formula: \"H\u207a\",\n            amount: 4,\n          },\n          {\n            formula: \"Na\u207a\",\n            amount: 4,\n          },\n        ],\n        reactions: [\n          {\n            location: \"anode\", // Where the reaction occurs (\"anode\" or \"cathode\")\n            reactants: [\"OH\u00af\", \"OH\u00af\"], // Array of reactant ion labels\n            product: \"O\u2082\", // Product label\n            electronsTransferred: 4,\n          },\n          {\n            location: \"cathode\",\n            //reactants: [\"H\u207a\", \"H\u207a\"],\n            //product: \"H\u2082\",\n            //electronsTransferred: 2,\n            reactants: [\"H\u207a\", \"H\u207a\", \"H\u207a\", \"H\u207a\"], // Include 4 H\u207a ions to balance the 4 electrons\n                product: \"H\u2082\",\n                electronsTransferred: 4, // Change from 2 to 4\n          },\n          \n        ],\n        anodeFormula: \"4 OH\u207b (aq) \u2192 2 H\u2082O(l) + O\u2082 (g) + 4 e\u207b\",\n        cathodeFormula: \"2 H\u207a (aq) + 2 e\u207b \u2192 H\u2082 (g)\\n4 H\u207a (aq) + 4 e\u207b \u2192 2 H\u2082 (g)\",\n        overallFormula: \"2 H\u2082O (l) \u2192 2 H\u2082 (g) + O\u2082 (g)\"\n    },\n    \"concentrated NaCl\": {\n        negativeIonTypes: [\n          {\n            formula: \"OH\u00af\",\n            amount: 2,\n          },\n          {\n            formula: \"Cl\u00af\",\n            amount: 6,\n          },\n        ],\n        positiveIonTypes: [\n          {\n            formula: \"H\u207a\",\n            amount: 2,\n          },\n          {\n            formula: \"Na\u207a\",\n            amount: 6,\n          },\n        ],\n        reactions: [\n          {\n            location: \"anode\", // Where the reaction occurs (\"anode\" or \"cathode\")\n            reactants: [\"OH\u00af\", \"OH\u00af\"], // Array of reactant ion labels\n            product: \"O\u2082\", // Product label\n            electronsTransferred: 2,\n          },\n          {\n            location: \"cathode\",\n            reactants: [\"H\u207a\", \"H\u207a\"],\n            product: \"H\u2082\",\n            electronsTransferred: 2,\n          },\n        ],\n        anodeFormula: \"2 Cl\u207b (aq) \u2192 Cl\u2082 (g) + 2 e\u207b\",\n        cathodeFormula: \"2 H\u207a (aq) + 2 e\u207b \u2192 H\u2082 (g)\",\n        overallFormula: \"2 H\u2082O (l) + 2 Cl\u207b (aq) \u2192 H\u2082 (g) + Cl\u2082 (g) + 2 OH\u207b (aq)\"\n    }\n}"
        },
        {
          "Name": "init",
          "Active": "true",
          "Internal": "false",
          "Type": "undefined",
          "Comment": "",
          "Code": "// Object positions (Anode and Cathode) - \n// not the actual position of the anode/cathode but the boundary where molecules can stick to\nanodePos = {\n  position: { x: -0.6, y: -0.1 },\n  size: { x: 0.1, y: 1 },\n};\n\ncathodePos = {\n  position: { x: 0.6, y: -0.1 },\n  size: { x: 0.1, y: 1 },\n};\n\nanodeProductTarget = [anodePos.position.x, (anodePos.position.y + anodePos.size.y)];\ncathodeProductTarget = [cathodePos.position.x, (cathodePos.position.y + cathodePos.size.y)];\n\n\n// Ion definitions\ninitSolution(\"dilute NaCl\");\n\n\n"
        },
        {
          "Name": "responsiveFont",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "",
          "Code": "// Get the viewport dimensions\nvar viewportWidth = window.innerWidth || document.documentElement.clientWidth;\nvar viewportHeight = window.innerHeight || document.documentElement.clientHeight;\nvar percent = 0.05\n// Calculate the font size based on viewport width or height\nvar fontSize = Math.min(viewportWidth * percent, viewportHeight * percent); // Adjust the multiplier as needed\n\n// Set the font size\n// Set the font size and font family (Comic Sans)\nfont = \"normal normal \" + fontSize * 0.5 + \"px 'Comic Sans MS', 'Comic Sans', cursive\";\nfontSmall = \"normal normal \" + fontSize * 0.35  + \"px 'Comic Sans MS', 'Comic Sans', cursive\";\n\n// Apply the font size to your elements\n// For example, you can apply it to a specific element with a class\n//document.getElementById(\"yourElementId\").style.font = font;"
        }
      ]
    },
    "evolution": {
      "information": {
        "FPS": "20",
        "SPD": "1",
        "RealTimeVariable": "",
        "Autoplay": "false"
      },
      "pages": [
        {
          "Name": "Evol Page 1",
          "Active": "true",
          "Internal": "false",
          "Type": "EVOLUTION_EDITOR",
          "Comment": "",
          "Code": "updatePositions();\n\n\n"
        }
      ]
    },
    "fixed_relations": {
      "pages": []
    },
    "custom": {
      "pages": [
        {
          "Name": "getRandomPosition",
          "Active": "true",
          "Internal": "false",
          "Type": "undefined",
          "Comment": "",
          "Code": "// Function to generate a random position within the boundary, avoiding exclusion zones\nfunction getRandomPosition() {\n  let position;\n  let validPosition = false;\n  while (!validPosition) {\n    var x = Math.random() * (1.4 * 2) + -1.4;\n    var y = Math.random() * (0.4 * 2) + -0.4;\n    position = [x, y];\n\n    // Check if the position is within exclusion zones\n    if (!isInExclusionZone(position)) {\n      validPosition = true;\n    }\n  }\n  return position;\n}\n\n// Function to check if a position is within an exclusion zone\nfunction isInExclusionZone(position) {\n  const exclusionMargin = 0.2; // Adjust as needed\n  const [x, y] = position;\n\n  // Define rectangles representing exclusion zones around the anode and cathode\n  const anodeExclusion = rectContainsPoint(\n    x,\n    y,\n    anodePos.position.x,\n    anodePos.position.y,\n    anodePos.size.x + exclusionMargin,\n    anodePos.size.y + exclusionMargin\n  );\n\n  const cathodeExclusion = rectContainsPoint(\n    x,\n    y,\n    cathodePos.position.x,\n    cathodePos.position.y,\n    cathodePos.size.x + exclusionMargin,\n    cathodePos.size.y + exclusionMargin\n  );\n\n  return anodeExclusion || cathodeExclusion;\n}\n\n// Function to check if a point is within a rectangle\nfunction rectContainsPoint(pointX, pointY, rectX, rectY, rectWidth, rectHeight) {\n  var rectHalfWidth = rectWidth / 2;\n  var rectHalfHeight = rectHeight / 2;\n\n  var left = rectX - rectHalfWidth;\n  var right = rectX + rectHalfWidth;\n  var top = rectY - rectHalfHeight;\n  var bottom = rectY + rectHalfHeight;\n\n  return pointX >= left && pointX <= right && pointY >= top && pointY <= bottom;\n}\n"
        },
        {
          "Name": "generateIons",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "",
          "Code": "// Generate arrays of ion objects\nfunction generateIons(ionTypes) {\n  let ions = [];\n  ionTypes.forEach((ionType) => {\n    for (let i = 0; i < ionType.amount; i++) {\n      ions.push({\n        position: getRandomPosition(),\n        type: ionType.formula,\n        stuck: false,\n      });\n    }\n  });\n  return ions;\n}"
        },
        {
          "Name": "updatePositions",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "",
          "Code": "function updatePositions() {\n  var allStuck = true; // Flag to check if all elements are stuck\n\n  // Precompute constants\n  const stepSize = 0.02;\n  const reachThreshold = 0.01;\n  const reachThresholdSquared = reachThreshold * reachThreshold;\n  const minDistanceSquared = 0.0001 * 0.0001;\n\n  // Update positions for positive ions\n  for (let i = 0; i < posOfPositiveIons.length; i++) {\n    if (!positiveIonsStuckStatus[i] && positiveIonsVisibility[i]) {\n      allStuck = false; // At least one element is still moving\n\n      // Get current and target positions\n      let pos = posOfPositiveIons[i];\n      let targetPos = positiveIonsTargetPositions[i];\n\n      // Compute vector towards the target position\n      let dx = targetPos[0] - pos[0];\n      let dy = targetPos[1] - pos[1];\n      let distanceSquared = dx * dx + dy * dy;\n\n      if (distanceSquared > minDistanceSquared) {\n        let distance = Math.sqrt(distanceSquared);\n        let invDistance = 1 / distance;\n\n        // Normalize the vector and compute movement\n        let vx = dx * invDistance;\n        let vy = dy * invDistance;\n        let moveDistance = Math.min(stepSize, distance);\n\n        // Update position\n        pos[0] += vx * moveDistance;\n        pos[1] += vy * moveDistance;\n\n        // Check if the ion has reached close enough to the target position\n        if (distanceSquared <= reachThresholdSquared) {\n          pos[0] = targetPos[0];\n          pos[1] = targetPos[1];\n          positiveIonsStuckStatus[i] = true;\n        }\n      } else {\n        // Ion has reached its target position\n        pos[0] = targetPos[0];\n        pos[1] = targetPos[1];\n        positiveIonsStuckStatus[i] = true;\n      }\n    }\n  }\n\n  // Update positions for negative ions\n  for (let i = 0; i < posOfNegativeIons.length; i++) {\n    if (!negativeIonsStuckStatus[i] && negativeIonsVisibility[i]) {\n      allStuck = false; // At least one element is still moving\n\n      // Get current and target positions\n      let pos = posOfNegativeIons[i];\n      let targetPos = negativeIonsTargetPositions[i];\n\n      // Compute vector towards the target position\n      let dx = targetPos[0] - pos[0];\n      let dy = targetPos[1] - pos[1];\n      let distanceSquared = dx * dx + dy * dy;\n\n      if (distanceSquared > minDistanceSquared) {\n        let distance = Math.sqrt(distanceSquared);\n        let invDistance = 1 / distance;\n\n        // Normalize the vector and compute movement\n        let vx = dx * invDistance;\n        let vy = dy * invDistance;\n        let moveDistance = Math.min(stepSize, distance);\n\n        // Update position\n        pos[0] += vx * moveDistance;\n        pos[1] += vy * moveDistance;\n\n        // Check if the ion has reached close enough to the target position\n        if (distanceSquared <= reachThresholdSquared) {\n          pos[0] = targetPos[0];\n          pos[1] = targetPos[1];\n          negativeIonsStuckStatus[i] = true;\n        }\n      } else {\n        // Ion has reached its target position\n        pos[0] = targetPos[0];\n        pos[1] = targetPos[1];\n        negativeIonsStuckStatus[i] = true;\n      }\n    }\n  }\n\n  // After updating positions, check for reactions\n  checkForReactions();\n\n  // Update positions for anode products\n  for (let i = 0; i < posOfAnodeProducts.length; i++) {\n    if (anodeProductsVisibility[i] && !anodeProductsReachedTarget[i]) {\n      allStuck = false; // At least one product is still moving\n\n      let pos = posOfAnodeProducts[i];\n      let dx = anodeProductTarget[0] - pos[0];\n      let dy = anodeProductTarget[1] - pos[1];\n      let distanceSquared = dx * dx + dy * dy;\n\n      if (distanceSquared > minDistanceSquared) {\n        let distance = Math.sqrt(distanceSquared);\n        let invDistance = 1 / distance;\n        let vx = dx * invDistance;\n        let vy = dy * invDistance;\n        let moveDistance = Math.min(stepSize, distance);\n\n        pos[0] += vx * moveDistance;\n        pos[1] += vy * moveDistance ;\n        \n\n       // if (distance <= moveDistance) {\n        if ((distance - anodeTestTubeLevel) <= moveDistance) {\n            pos[0] = anodeProductTarget[0];\n          pos[1] = anodeProductTarget[1];\n         // pos[1] = anodeProductTarget[1] - anodeTestTubeLevel ;\n          anodeProductsReachedTarget[i] = true;\n          anodeProductsVisibility[i] = false; // Product disappears\n          anodeTestTubeLevel += 0.025;\n        }\n      }\n      \n      else {\n        pos[0] = anodeProductTarget[0];\n        pos[1] = anodeProductTarget[1] - anodeTestTubeLevel ;\n        anodeProductsReachedTarget[i] = true;\n        anodeProductsVisibility[i] = false; // Product disappears\n        anodeTestTubeLevel += 0.025;\n      }\n    }\n  }\n\n  // Update positions for cathode products\n  for (let i = 0; i < posOfCathodeProducts.length; i++) {\n    if (cathodeProductsVisibility[i] && !cathodeProductsReachedTarget[i]) {\n      allStuck = false; // At least one product is still moving\n\n      let pos = posOfCathodeProducts[i];\n      let dx = cathodeProductTarget[0] - pos[0];\n      let dy = cathodeProductTarget[1] - pos[1];\n      let distanceSquared = dx * dx + dy * dy;\n\n      if (distanceSquared > minDistanceSquared) {\n        let distance = Math.sqrt(distanceSquared);\n        let invDistance = 1 / distance;\n        let vx = dx * invDistance;\n        let vy = dy * invDistance;\n        let moveDistance = Math.min(stepSize, distance);\n\n        pos[0] += vx * moveDistance;\n        pos[1] += vy * moveDistance;\n\n        //if (distance <= moveDistance) {\n        if ((distance - cathodeTestTubeLevel) <= moveDistance) { // make the bubbles disappear at the airlevel instead of the top of the testtube\n          pos[0] = cathodeProductTarget[0];\n          pos[1] = cathodeProductTarget[1];\n          cathodeProductsReachedTarget[i] = true;\n          cathodeProductsVisibility[i] = false; // Product disappears\n          cathodeTestTubeLevel += 0.025;\n        }\n      } else {\n        pos[0] = cathodeProductTarget[0];\n        pos[1] = cathodeProductTarget[1];\n        cathodeProductsReachedTarget[i] = true;\n        cathodeProductsVisibility[i] = false; // Product disappears\n        cathodeTestTubeLevel += 0.025;\n      }\n    }\n  }\n\n  // Update positions for anode electrons\n  for (let i = 0; i < anodeElectronPositions.length; i++) {\n    if (anodeElectronVisibility[i] && !anodeElectronReachedTarget[i]) {\n      allStuck = false; // At least one element is still moving\n\n      let pos = anodeElectronPositions[i];\n      let dx = anodeElectronEndPos[0] - pos[0];\n      let dy = anodeElectronEndPos[1] - pos[1];\n      let distanceSquared = dx * dx + dy * dy;\n\n      if (distanceSquared > minDistanceSquared) {\n        let distance = Math.sqrt(distanceSquared);\n        let invDistance = 1 / distance;\n        let vx = dx * invDistance;\n        let vy = dy * invDistance;\n        let moveDistance = Math.min(stepSize, distance);\n\n        pos[0] += vx * moveDistance;\n        pos[1] += vy * moveDistance;\n\n        if (distance <= moveDistance) {\n          pos[0] = anodeElectronEndPos[0];\n          pos[1] = anodeElectronEndPos[1];\n          anodeElectronReachedTarget[i] = true;\n          anodeElectronVisibility[i] = false; // Electron disappears\n        }\n      } else {\n        pos[0] = anodeElectronEndPos[0];\n        pos[1] = anodeElectronEndPos[1];\n        anodeElectronReachedTarget[i] = true;\n        anodeElectronVisibility[i] = false; // Electron disappears\n      }\n    }\n  }\n\n  // Update positions for cathode electrons\n  for (let i = 0; i < cathodeElectronPositions.length; i++) {\n    if (cathodeElectronVisibility[i] && !cathodeElectronReachedTarget[i]) {\n      allStuck = false; // At least one element is still moving\n\n      let pos = cathodeElectronPositions[i];\n      let dx = cathodeElectronEndPos[0] - pos[0];\n      let dy = cathodeElectronEndPos[1] - pos[1];\n      let distanceSquared = dx * dx + dy * dy;\n\n      if (distanceSquared > minDistanceSquared) {\n        let distance = Math.sqrt(distanceSquared);\n        let invDistance = 1 / distance;\n        let vx = dx * invDistance;\n        let vy = dy * invDistance;\n        let moveDistance = Math.min(stepSize, distance);\n\n        pos[0] += vx * moveDistance;\n        pos[1] += vy * moveDistance;\n\n        if (distance <= moveDistance) {\n          pos[0] = cathodeElectronEndPos[0];\n          pos[1] = cathodeElectronEndPos[1];\n          cathodeElectronReachedTarget[i] = true;\n          cathodeElectronVisibility[i] = false; // Electron disappears\n        }\n      } else {\n        pos[0] = cathodeElectronEndPos[0];\n        pos[1] = cathodeElectronEndPos[1];\n        cathodeElectronReachedTarget[i] = true;\n        cathodeElectronVisibility[i] = false; // Electron disappears\n      }\n    }\n  }\n\n  // Check if any ions or products are still moving\n  if (\n    positiveIonsVisibility.some((v, i) => !positiveIonsStuckStatus[i] && v) ||\n    negativeIonsVisibility.some((v, i) => !negativeIonsStuckStatus[i] && v) ||\n    anodeProductsVisibility.some((v, i) => !anodeProductsReachedTarget[i] && v) ||\n    cathodeProductsVisibility.some((v, i) => !cathodeProductsReachedTarget[i] && v) ||\n    anodeElectronVisibility.some((v, i) => !anodeElectronReachedTarget[i] && v) ||\n    cathodeElectronVisibility.some((v, i) => !cathodeElectronReachedTarget[i] && v)\n  ) {\n    allStuck = false;\n  }\n\n  if (allStuck) {\n    resetIons();\n  }\n}\n"
        },
        {
          "Name": "checkForReactions",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "",
          "Code": "function checkForReactions() {\n  reactions.forEach((reaction) => {\n    const { reactants, product, location, electronsTransferred } = reaction;\n\n    let ionLabels, ionPositions, ionStuckStatus, ionVisibility;\n    let productsPositions, productsLabels, productsVisibility, productsReachedTarget;\n    let electronPositions, electronVisibility, electronReachedTarget;\n    let electronStartPos;\n\n    if (location === \"anode\") {\n      ionLabels = negativeIonLabels;\n      ionPositions = posOfNegativeIons;\n      ionStuckStatus = negativeIonsStuckStatus;\n      ionVisibility = negativeIonsVisibility;\n\n      productsPositions = posOfAnodeProducts;\n      productsLabels = anodeProductsLabels;\n      productsVisibility = anodeProductsVisibility;\n      productsReachedTarget = anodeProductsReachedTarget;\n\n      electronPositions = anodeElectronPositions;\n      electronVisibility = anodeElectronVisibility;\n      electronReachedTarget = anodeElectronReachedTarget;\n      electronStartPos = anodeElectronStartPos;\n    } else if (location === \"cathode\") {\n      ionLabels = positiveIonLabels;\n      ionPositions = posOfPositiveIons;\n      ionStuckStatus = positiveIonsStuckStatus;\n      ionVisibility = positiveIonsVisibility;\n\n      productsPositions = posOfCathodeProducts;\n      productsLabels = cathodeProductsLabels;\n      productsVisibility = cathodeProductsVisibility;\n      productsReachedTarget = cathodeProductsReachedTarget;\n\n      electronPositions = cathodeElectronPositions;\n      electronVisibility = cathodeElectronVisibility;\n      electronReachedTarget = cathodeElectronReachedTarget;\n      electronStartPos = cathodeElectronStartPos;\n    } else {\n      return; // Invalid location\n    }\n\n    // Build a map of available ions by label\n    const availableIonsMap = new Map();\n    for (let i = 0; i < ionLabels.length; i++) {\n      if (ionStuckStatus[i] && ionVisibility[i]) {\n        const label = ionLabels[i];\n        if (!availableIonsMap.has(label)) {\n          availableIonsMap.set(label, []);\n        }\n        availableIonsMap.get(label).push(i);\n      }\n    }\n\n    // Check if enough ions are available for the reaction\n    const requiredIons = {};\n    for (const label of reactants) {\n      requiredIons[label] = (requiredIons[label] || 0) + 1;\n    }\n\n    let canReact = true;\n    for (const label in requiredIons) {\n      if (!availableIonsMap.has(label) || availableIonsMap.get(label).length < requiredIons[label]) {\n        canReact = false;\n        break;\n      }\n    }\n\n    // Perform the reaction if possible\n    while (canReact) {\n      // Remove the ions used in the reaction\n      const combinationIndices = [];\n      for (const label of reactants) {\n        const index = availableIonsMap.get(label).pop();\n        combinationIndices.push(index);\n        ionVisibility[index] = false;\n      }\n\n      // Calculate average position for the product\n      let avgX = 0;\n      let avgY = 0;\n      for (const index of combinationIndices) {\n        avgX += ionPositions[index][0];\n        avgY += ionPositions[index][1];\n      }\n      avgX /= combinationIndices.length;\n      avgY /= combinationIndices.length;\n\n      // Add the new product\n      productsPositions.push([avgX, avgY]);\n      productsLabels.push(product);\n      productsVisibility.push(true);\n      productsReachedTarget.push(false);\n\n      // Create electron animations\n      for (let i = 0; i < electronsTransferred; i++) {\n        const yOffset = i * (2 * moleculeRad);\n        const position = [electronStartPos[0], electronStartPos[1] - yOffset];\n        electronPositions.push(position);\n        electronVisibility.push(true);\n        electronReachedTarget.push(false);\n      }\n\n      // Check if more reactions can occur\n      canReact = true;\n      for (const label in requiredIons) {\n        if (availableIonsMap.get(label).length < requiredIons[label]) {\n          canReact = false;\n          break;\n        }\n      }\n    }\n  });\n}\n"
        },
        {
          "Name": "assignTargetPositions",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "",
          "Code": "// Function to assign target positions along the object's edge\nfunction assignTargetPositions(positionsArray, object) {\n  var rectHalfHeight = object.size.y / 2;\n  //console.log(\"rectHalfHeight\"+ rectHalfHeight) //lookang\n  var minY = object.position.y - rectHalfHeight + moleculeRad; // Lower starting position\n  var maxY = object.position.y + rectHalfHeight - moleculeRad; // Higher target position\n\n  var availableHeight = maxY - minY;\n  var numElements = positionsArray.length;\n\n  var maxElements = Math.floor(availableHeight / (2 * moleculeRad));\n\n  var actualNumElements = Math.min(numElements, maxElements);\n\n  var spacing = availableHeight / (actualNumElements - 1);\n\n  var targetPositions = [];\n\n  for (var i = 0; i < numElements; i++) {\n    // Calculate yPos for each element\n    var index = i % actualNumElements;\n    var yPos = minY + index * spacing;\n    yPos = clamp(yPos, minY, maxY);\n\n    // For each element, calculate the closest edge based on its starting position\n    var elementPos = positionsArray[i];\n    var dxLeft = Math.abs(elementPos[0] - (object.position.x - object.size.x / 2));\n    var dxRight = Math.abs(elementPos[0] - (object.position.x + object.size.x / 2));\n\n    var targetX;\n    if (dxLeft < dxRight) {\n      // Closest to the left edge\n      targetX = object.position.x - object.size.x / 2 - moleculeRad;\n    } else {\n      // Closest to the right edge\n      targetX = object.position.x + object.size.x / 2 + moleculeRad;\n    }\n\n    var targetPos = [targetX, yPos];\n    targetPositions.push(targetPos);\n  }\n\n  return targetPositions;\n}"
        },
        {
          "Name": "clamp",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "",
          "Code": "// Function to clamp a value between a minimum and maximum\nfunction clamp(value, min, max) {\n  return Math.max(min, Math.min(max, value));\n}"
        },
        {
          "Name": "circleRectCollision",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "",
          "Code": "// Function to detect collision between a circle and a rectangle\nfunction circleRectCollision(circleX, circleY, circleRadius, rectX, rectY, rectWidth, rectHeight) {\n  // Half dimensions of the rectangle\n  var rectHalfWidth = rectWidth / 2;\n  var rectHalfHeight = rectHeight / 2;\n\n  // Closest point from the circle's center to the rectangle\n  var closestX = clamp(circleX, rectX - rectHalfWidth, rectX + rectHalfWidth);\n  var closestY = clamp(circleY, rectY - rectHalfHeight, rectY + rectHalfHeight);\n\n  // Distance between the circle's center and the closest point\n  var distanceX = circleX - closestX;\n  var distanceY = circleY - closestY;\n\n  // Check if the distance is less than the circle's radius\n  var distanceSquared = distanceX * distanceX + distanceY * distanceY;\n  return distanceSquared < circleRadius * circleRadius;\n}"
        },
        {
          "Name": "resetIons",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "",
          "Code": "// Function to generate positions and labels for ions\nfunction resetIons() {\n    \n  // Calculate the total number of negative and positive ions\n  numOfNegativeIons = negativeIonTypes.reduce((total, ion) => total + ion.amount, 0);\n  numOfPositiveIons = positiveIonTypes.reduce((total, ion) => total + ion.amount, 0);\n\n  // Generate positions and labels for positive ions\n  posOfPositiveIons = [];\n  positiveIonLabels = [];\n  positiveIonsVisibility = [];\n  positiveIonsStuckStatus = [];\n\n  positiveIonTypes.forEach((ionType) => {\n    for (let i = 0; i < ionType.amount; i++) {\n      posOfPositiveIons.push(getRandomPosition());\n      positiveIonLabels.push(ionType.formula);\n      positiveIonsVisibility.push(true); // Initially, all ions are visible\n      positiveIonsStuckStatus.push(false); // Initially, not stuck\n    }\n  });\n\n  // Generate positions and labels for negative ions\n  posOfNegativeIons = [];\n  negativeIonLabels = [];\n  negativeIonsVisibility = [];\n  negativeIonsStuckStatus = [];\n\n  negativeIonTypes.forEach((ionType) => {\n    for (let i = 0; i < ionType.amount; i++) {\n      posOfNegativeIons.push(getRandomPosition());\n      negativeIonLabels.push(ionType.formula);\n      negativeIonsVisibility.push(true); // Initially, all ions are visible\n      negativeIonsStuckStatus.push(false); // Initially, not stuck\n    }\n  });\n\n  // Assign target positions during initialization\n  positiveIonsTargetPositions = assignTargetPositions(posOfPositiveIons, cathodePos);\n  negativeIonsTargetPositions = assignTargetPositions(posOfNegativeIons, anodePos);\n  \n  // Arrays to keep track of whether an ion is stuck\n  positiveIonsStuckStatus = new Array(posOfPositiveIons.length).fill(false);\n  negativeIonsStuckStatus = new Array(posOfNegativeIons.length).fill(false);\n  \n  // Clear products arrays\n  posOfAnodeProducts = [];\n  anodeProductsLabels = [];\n  anodeProductsVisibility = [];\n  anodeProductsReachedTarget = [];\n\n  posOfCathodeProducts = [];\n  cathodeProductsLabels = [];\n  cathodeProductsVisibility = [];\n  cathodeProductsReachedTarget = [];\n  \n  // Clear electron elements\n  anodeElectronPositions = [];\n  anodeElectronVisibility = [];\n  anodeElectronReachedTarget = [];\n\n  cathodeElectronPositions = [];\n  cathodeElectronVisibility = [];\n  cathodeElectronReachedTarget = [];\n}"
        },
        {
          "Name": "initSolution",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "",
          "Code": "// initSolution\n\nfunction initSolution(solutionType) {\n  negativeIonTypes = solutionTypes[solutionType].negativeIonTypes;\n  positiveIonTypes = solutionTypes[solutionType].positiveIonTypes;\n  reactions = solutionTypes[solutionType].reactions;\n  \n  //lookang\n//   anodeText = \"4 OH\u207b (aq) \u2192  2 H\u2082O(l) + O\u2082  \u200b(g) + 4 e\u208b\"\n//   cathodeText = \"2 H\u207a (aq)+2 e\u208b  \u2192 H\u2082 (g)\"+\"\\n4 H\u207a (aq)+4 e\u208b  \u2192 2 H\u2082 (g)\"\n//   overallText = \"2 H\u2082O (l) \u2192 2 H\u2082  (g)+O\u2082 \u200b(g)\"\n\n  anodeFormula = solutionTypes[solutionType].anodeFormula;\n  cathodeFormula = solutionTypes[solutionType].cathodeFormula;\n  overallFormula = solutionTypes[solutionType].overallFormula;\n  \n  resetIons();\n  anodeTestTubeLevel = 0;\n  cathodeTestTubeLevel = 0;\n}"
        }
      ]
    },
    "elements": {
      "list": []
    }
  },
  "view": {
    "Tree": [
      {
        "Name": "panel",
        "Type": "Panel",
        "Expanded": "true",
        "Properties": [],
        "Children": [
          {
            "Name": "controlPanel",
            "Type": "Panel",
            "Expanded": "true",
            "Properties": [
              {
                "name": "Width",
                "value": "\"100%\""
              },
              {
                "name": "CSS",
                "value": "{\"display\":\"block\"}"
              },
              {
                "name": "Font",
                "value": "font"
              }
            ],
            "Children": [
              {
                "Name": "label",
                "Type": "Label",
                "Properties": [
                  {
                    "name": "Text",
                    "value": "\"Electrolysis Virtual Lab\""
                  }
                ]
              },
              {
                "Name": "comboBox",
                "Type": "ComboBox",
                "Properties": [
                  {
                    "name": "Options",
                    "value": "Object.keys(solutionTypes)"
                  },
                  {
                    "name": "OnChange",
                    "value": "var opts = _view.comboBox.getProperty(\"SelectedOptions\"); \nvar option = (opts.length > 0) ? opts[0] : \"\"; // selected option \n\ninitSolution(option);"
                  },
                  {
                    "name": "Font",
                    "value": "font"
                  }
                ]
              },
              {
                "Name": "playPauseButton",
                "Type": "TwoStateButton",
                "Properties": [
                  {
                    "name": "TextOn",
                    "value": "\"Play\u25b6\""
                  },
                  {
                    "name": "State",
                    "value": "_isPaused"
                  },
                  {
                    "name": "OnClick",
                    "value": "_play();\n\n//xAPI included ensures no more than 2 scores are sent, even if the user repeatedly selects the same or different valid options.\nvar opts = _view.comboBox.getProperty(\"SelectedOptions\"); \nvar option = (opts.length > 0) ? opts[0] : \"\"; // selected option \n\n// Variables to track if each option has been selected\n//let diluteSelected = false;\n//let concentratedSelected = false;\n\n// Update the selection flags based on the current option\nif (option === \"dilute NaCl\") {\n    diluteSelected = true;\n    sendScore(diluteSelected && concentratedSelected ? 2 : 1); // Check if both are selected\n} else if (option === \"concentrated NaCl\") {\n    concentratedSelected = true;\n    sendScore(diluteSelected && concentratedSelected ? 2 : 1); // Check if both are selected\n}"
                  },
                  {
                    "name": "TextOff",
                    "value": "\"Pause\u275a\u275a\""
                  },
                  {
                    "name": "OffClick",
                    "value": "_pause();"
                  },
                  {
                    "name": "Width",
                    "value": "\"20%\""
                  }
                ]
              },
              {
                "Name": "resetButton",
                "Type": "Button",
                "Properties": [
                  {
                    "name": "Text",
                    "value": "\"Reset\u21bb\""
                  },
                  {
                    "name": "OnClick",
                    "value": "%_reset%"
                  },
                  {
                    "name": "Width",
                    "value": "\"20%\""
                  }
                ]
              },
              {
                "Name": "two",
                "Type": "Button",
                "Properties": [
                  {
                    "name": "Text",
                    "value": "\"+2\""
                  },
                  {
                    "name": "OnPress",
                    "value": "sendScore(2)"
                  },
                  {
                    "name": "Display",
                    "value": "\"none\""
                  }
                ]
              },
              {
                "Name": "five",
                "Type": "Button",
                "Properties": [
                  {
                    "name": "Text",
                    "value": "\"+5\""
                  },
                  {
                    "name": "OnPress",
                    "value": "sendScore(5)"
                  },
                  {
                    "name": "Display",
                    "value": "\"none\""
                  }
                ]
              }
            ]
          },
          {
            "Name": "wrappedPanel",
            "Type": "WrappedPanel",
            "Expanded": "true",
            "Properties": [
              {
                "name": "CSS",
                "value": "{ \"display\":\"block\"}"
              }
            ],
            "Children": [
              {
                "Name": "plottingPanel",
                "Type": "PlottingPanel",
                "Expanded": "true",
                "Properties": [
                  {
                    "name": "MinimumX",
                    "value": "-2"
                  },
                  {
                    "name": "MaximumX",
                    "value": "2"
                  },
                  {
                    "name": "MinimumY",
                    "value": "-1.5"
                  },
                  {
                    "name": "MaximumY",
                    "value": "1.5"
                  },
                  {
                    "name": "Enabled",
                    "value": "true"
                  },
                  {
                    "name": "Width",
                    "value": "\"90%\""
                  },
                  {
                    "name": "SquareAspect",
                    "value": "true"
                  },
                  {
                    "name": "Height",
                    "value": "\"90vh\""
                  },
                  {
                    "name": "Gutters",
                    "value": "[0,0,0,0]"
                  },
                  {
                    "name": "MarginX",
                    "value": "0"
                  },
                  {
                    "name": "MarginY",
                    "value": "20"
                  },
                  {
                    "name": "YFixedTick",
                    "value": "-2"
                  },
                  {
                    "name": "XFixedTick",
                    "value": "-2"
                  },
                  {
                    "name": "YTickStep",
                    "value": "4"
                  },
                  {
                    "name": "XTickStep",
                    "value": "4"
                  },
                  {
                    "name": "XAutoTicks",
                    "value": "false"
                  },
                  {
                    "name": "YAutoTicks",
                    "value": "false"
                  },
                  {
                    "name": "TRMessage",
                    "value": "\"Cathode (Reduction)\\n\"+cathodeFormula"
                  },
                  {
                    "name": "TLMessage",
                    "value": "\"Anode (Oxidation)\\n\"+anodeFormula"
                  },
                  {
                    "name": "BRMessage",
                    "value": "\"Overall\\n\"+overallFormula"
                  }
                ],
                "Children": [
                  {
                    "Name": "container",
                    "Type": "Group2D",
                    "Expanded": "true",
                    "Properties": [],
                    "Children": [
                      {
                        "Name": "containerLeftBorder",
                        "Type": "Shape2D",
                        "Properties": [
                          {
                            "name": "X",
                            "value": "-1.5"
                          },
                          {
                            "name": "SizeX",
                            "value": "0.03"
                          },
                          {
                            "name": "SizeY",
                            "value": "1.35"
                          },
                          {
                            "name": "ShapeType",
                            "value": "\"RECTANGLE\""
                          },
                          {
                            "name": "FillColor",
                            "value": "\"Black\""
                          },
                          {
                            "name": "Y",
                            "value": "0.09"
                          }
                        ]
                      },
                      {
                        "Name": "containerRightBorder",
                        "Type": "Shape2D",
                        "Properties": [
                          {
                            "name": "ShapeType",
                            "value": "\"RECTANGLE\""
                          },
                          {
                            "name": "SizeX",
                            "value": "0.03"
                          },
                          {
                            "name": "SizeY",
                            "value": "1.35"
                          },
                          {
                            "name": "X",
                            "value": "1.5"
                          },
                          {
                            "name": "FillColor",
                            "value": "\"Black\""
                          },
                          {
                            "name": "Y",
                            "value": "0.09"
                          }
                        ]
                      },
                      {
                        "Name": "containerBottomBorder",
                        "Type": "Shape2D",
                        "Properties": [
                          {
                            "name": "ShapeType",
                            "value": "\"RECTANGLE\""
                          },
                          {
                            "name": "FillColor",
                            "value": "\"Black\""
                          },
                          {
                            "name": "SizeY",
                            "value": "0.03"
                          },
                          {
                            "name": "SizeX",
                            "value": "3.03"
                          },
                          {
                            "name": "Y",
                            "value": "-0.6"
                          }
                        ]
                      },
                      {
                        "Name": "containerBackground",
                        "Type": "Shape2D",
                        "Properties": [
                          {
                            "name": "ShapeType",
                            "value": "\"RECTANGLE\""
                          },
                          {
                            "name": "FillColor",
                            "value": "colorSolution"
                          },
                          {
                            "name": "SizeX",
                            "value": "2.965"
                          },
                          {
                            "name": "SizeY",
                            "value": "1.22"
                          },
                          {
                            "name": "Y",
                            "value": "0.02"
                          }
                        ]
                      }
                    ]
                  },
                  {
                    "Name": "battery",
                    "Type": "Group2D",
                    "Expanded": "false",
                    "Properties": [],
                    "Children": [
                      {
                        "Name": "image",
                        "Type": "Image2D",
                        "Properties": [
                          {
                            "name": "ImageUrl",
                            "value": "\"./battery.png\""
                          },
                          {
                            "name": "SizeX",
                            "value": "0.4"
                          },
                          {
                            "name": "SizeY",
                            "value": "0.3"
                          },
                          {
                            "name": "Y",
                            "value": "-1.15"
                          }
                        ]
                      }
                    ]
                  },
                  {
                    "Name": "wires",
                    "Type": "Group2D",
                    "Expanded": "true",
                    "Properties": [],
                    "Children": [
                      {
                        "Name": "wireLeft1",
                        "Type": "Shape2D",
                        "Properties": [
                          {
                            "name": "ShapeType",
                            "value": "\"RECTANGLE\""
                          },
                          {
                            "name": "FillColor",
                            "value": "\"Black\""
                          },
                          {
                            "name": "SizeY",
                            "value": "0.49"
                          },
                          {
                            "name": "SizeX",
                            "value": "0.0135"
                          },
                          {
                            "name": "X",
                            "value": "-0.6"
                          },
                          {
                            "name": "Y",
                            "value": "-0.94"
                          }
                        ]
                      },
                      {
                        "Name": "wireLeft2",
                        "Type": "Shape2D",
                        "Properties": [
                          {
                            "name": "ShapeType",
                            "value": "\"RECTANGLE\""
                          },
                          {
                            "name": "FillColor",
                            "value": "\"Black\""
                          },
                          {
                            "name": "Y",
                            "value": "-1.179"
                          },
                          {
                            "name": "SizeY",
                            "value": "0.0135"
                          },
                          {
                            "name": "X",
                            "value": "-0.4"
                          },
                          {
                            "name": "SizeX",
                            "value": "0.4"
                          }
                        ]
                      },
                      {
                        "Name": "wireRight1",
                        "Type": "Shape2D",
                        "Properties": [
                          {
                            "name": "ShapeType",
                            "value": "\"RECTANGLE\""
                          },
                          {
                            "name": "FillColor",
                            "value": "\"Black\""
                          },
                          {
                            "name": "Y",
                            "value": "-0.94"
                          },
                          {
                            "name": "SizeY",
                            "value": "0.49"
                          },
                          {
                            "name": "X",
                            "value": "0.6"
                          },
                          {
                            "name": "SizeX",
                            "value": "0.0135"
                          }
                        ]
                      },
                      {
                        "Name": "wireRight2",
                        "Type": "Shape2D",
                        "Properties": [
                          {
                            "name": "ShapeType",
                            "value": "\"RECTANGLE\""
                          },
                          {
                            "name": "FillColor",
                            "value": "\"Black\""
                          },
                          {
                            "name": "Y",
                            "value": "-1.179"
                          },
                          {
                            "name": "SizeY",
                            "value": "0.0135"
                          },
                          {
                            "name": "X",
                            "value": "0.4"
                          },
                          {
                            "name": "SizeX",
                            "value": "0.4"
                          }
                        ]
                      }
                    ]
                  },
                  {
                    "Name": "testTubes",
                    "Type": "Group2D",
                    "Expanded": "true",
                    "Properties": [],
                    "Children": [
                      {
                        "Name": "testTubeLeft",
                        "Type": "Tank",
                        "Properties": [
                          {
                            "name": "Rotate",
                            "value": "Math.PI"
                          },
                          {
                            "name": "SizeX",
                            "value": "0.3"
                          },
                          {
                            "name": "SizeY",
                            "value": "1.5"
                          },
                          {
                            "name": "X",
                            "value": "-0.6"
                          },
                          {
                            "name": "Y",
                            "value": "0.2"
                          },
                          {
                            "name": "Level",
                            "value": "Math.min(anodeTestTubeLevel, 1)"
                          },
                          {
                            "name": "LevelColor",
                            "value": "\"Green\""
                          },
                          {
                            "name": "FillColor",
                            "value": "colorSolution"
                          },
                          {
                            "name": "DrawFill",
                            "value": "true"
                          }
                        ]
                      },
                      {
                        "Name": "testTubeRight",
                        "Type": "Tank",
                        "Properties": [
                          {
                            "name": "X",
                            "value": "0.6"
                          },
                          {
                            "name": "SizeX",
                            "value": "0.3"
                          },
                          {
                            "name": "SizeY",
                            "value": "1.5"
                          },
                          {
                            "name": "Rotate",
                            "value": "Math.PI"
                          },
                          {
                            "name": "Y",
                            "value": "0.2"
                          },
                          {
                            "name": "Level",
                            "value": "Math.min(cathodeTestTubeLevel, 1)"
                          },
                          {
                            "name": "LevelColor",
                            "value": "\"Orange\""
                          },
                          {
                            "name": "FillColor",
                            "value": "colorSolution"
                          },
                          {
                            "name": "DrawFill",
                            "value": "true"
                          }
                        ]
                      }
                    ]
                  },
                  {
                    "Name": "electrons",
                    "Type": "Group2D",
                    "Expanded": "true",
                    "Properties": [],
                    "Children": [
                      {
                        "Name": "anodeElectrons",
                        "Type": "ShapeSet2D",
                        "Properties": [
                          {
                            "name": "FillColor",
                            "value": "\"Cyan\""
                          },
                          {
                            "name": "Position",
                            "value": "anodeElectronPositions"
                          },
                          {
                            "name": "Visibility",
                            "value": "anodeElectronVisibility.length ? anodeElectronVisibility : false"
                          }
                        ]
                      },
                      {
                        "Name": "cathodeElectrons",
                        "Type": "ShapeSet2D",
                        "Properties": [
                          {
                            "name": "Position",
                            "value": "cathodeElectronPositions"
                          },
                          {
                            "name": "Visibility",
                            "value": "cathodeElectronVisibility.length ? cathodeElectronVisibility : false"
                          },
                          {
                            "name": "FillColor",
                            "value": "\"Cyan\""
                          }
                        ]
                      },
                      {
                        "Name": "anodeElectronText",
                        "Type": "TextSet2D",
                        "Properties": [
                          {
                            "name": "Text",
                            "value": "\"e\""
                          },
                          {
                            "name": "Position",
                            "value": "anodeElectronPositions"
                          },
                          {
                            "name": "Visibility",
                            "value": "anodeElectronVisibility.length ? anodeElectronVisibility : false"
                          },
                          {
                            "name": "Font",
                            "value": "fontSmall"
                          }
                        ]
                      },
                      {
                        "Name": "cathodeElectronText",
                        "Type": "TextSet2D",
                        "Properties": [
                          {
                            "name": "Text",
                            "value": "\"e\""
                          },
                          {
                            "name": "Position",
                            "value": "cathodeElectronPositions"
                          },
                          {
                            "name": "Visibility",
                            "value": "cathodeElectronVisibility.length ? cathodeElectronVisibility : false"
                          },
                          {
                            "name": "Font",
                            "value": "fontSmall"
                          }
                        ]
                      }
                    ]
                  },
                  {
                    "Name": "anode",
                    "Type": "Group2D",
                    "Expanded": "false",
                    "Properties": [],
                    "Children": [
                      {
                        "Name": "anodeBlock",
                        "Type": "Shape2D",
                        "Properties": [
                          {
                            "name": "ShapeType",
                            "value": "\"RECTANGLE\""
                          },
                          {
                            "name": "FillColor",
                            "value": "\"Yellow\""
                          },
                          {
                            "name": "SizeY",
                            "value": "1"
                          },
                          {
                            "name": "Y",
                            "value": "-0.2"
                          },
                          {
                            "name": "X",
                            "value": "-0.6"
                          },
                          {
                            "name": "SizeX",
                            "value": "0.1"
                          }
                        ]
                      },
                      {
                        "Name": "anodeLabel",
                        "Type": "Text2D",
                        "Properties": [
                          {
                            "name": "Text",
                            "value": "\"anode\""
                          },
                          {
                            "name": "Rotate",
                            "value": "Math.PI/2"
                          },
                          {
                            "name": "X",
                            "value": "-0.6"
                          },
                          {
                            "name": "Y",
                            "value": "-0.2"
                          },
                          {
                            "name": "Font",
                            "value": "font"
                          }
                        ]
                      }
                    ]
                  },
                  {
                    "Name": "cathode",
                    "Type": "Group2D",
                    "Expanded": "true",
                    "Properties": [],
                    "Children": [
                      {
                        "Name": "cathodeBlock",
                        "Type": "Shape2D",
                        "Properties": [
                          {
                            "name": "X",
                            "value": "0.6"
                          },
                          {
                            "name": "Y",
                            "value": "-0.2"
                          },
                          {
                            "name": "SizeY",
                            "value": "1"
                          },
                          {
                            "name": "ShapeType",
                            "value": "\"RECTANGLE\""
                          },
                          {
                            "name": "FillColor",
                            "value": "\"Yellow\""
                          },
                          {
                            "name": "SizeX",
                            "value": "0.1"
                          }
                        ]
                      },
                      {
                        "Name": "cathodeLabel",
                        "Type": "Text2D",
                        "Properties": [
                          {
                            "name": "Text",
                            "value": "\"cathode\""
                          },
                          {
                            "name": "Rotate",
                            "value": "Math.PI/2"
                          },
                          {
                            "name": "X",
                            "value": "0.6"
                          },
                          {
                            "name": "Y",
                            "value": "-0.2"
                          },
                          {
                            "name": "Font",
                            "value": "font"
                          }
                        ]
                      }
                    ]
                  },
                  {
                    "Name": "molecules",
                    "Type": "Group2D",
                    "Expanded": "true",
                    "Properties": [],
                    "Children": [
                      {
                        "Name": "negativeIons",
                        "Type": "ShapeSet2D",
                        "Properties": [
                          {
                            "name": "NumberOfElements",
                            "value": "numOfNegativeIons"
                          },
                          {
                            "name": "Position",
                            "value": "posOfNegativeIons"
                          },
                          {
                            "name": "FillColor",
                            "value": "\"Red\""
                          },
                          {
                            "name": "Visibility",
                            "value": "negativeIonsVisibility"
                          }
                        ]
                      },
                      {
                        "Name": "postiveIons",
                        "Type": "ShapeSet2D",
                        "Properties": [
                          {
                            "name": "NumberOfElements",
                            "value": "numOfPositiveIons"
                          },
                          {
                            "name": "Position",
                            "value": "posOfPositiveIons"
                          },
                          {
                            "name": "FillColor",
                            "value": "\"Magenta\""
                          },
                          {
                            "name": "Visibility",
                            "value": "positiveIonsVisibility"
                          }
                        ]
                      },
                      {
                        "Name": "negativeText",
                        "Type": "TextSet2D",
                        "Properties": [
                          {
                            "name": "Text",
                            "value": "negativeIonLabels"
                          },
                          {
                            "name": "Position",
                            "value": "posOfNegativeIons"
                          },
                          {
                            "name": "NumberOfElements",
                            "value": "numOfNegativeIons"
                          },
                          {
                            "name": "FillColor",
                            "value": "\"White\""
                          },
                          {
                            "name": "Visibility",
                            "value": "negativeIonsVisibility"
                          },
                          {
                            "name": "Font",
                            "value": "fontSmall"
                          }
                        ]
                      },
                      {
                        "Name": "positiveText",
                        "Type": "TextSet2D",
                        "Properties": [
                          {
                            "name": "Text",
                            "value": "positiveIonLabels"
                          },
                          {
                            "name": "Position",
                            "value": "posOfPositiveIons"
                          },
                          {
                            "name": "NumberOfElements",
                            "value": "numOfPositiveIons"
                          },
                          {
                            "name": "FillColor",
                            "value": "\"White\""
                          },
                          {
                            "name": "Visibility",
                            "value": "positiveIonsVisibility"
                          },
                          {
                            "name": "Font",
                            "value": "fontSmall"
                          }
                        ]
                      },
                      {
                        "Name": "anodeProducts",
                        "Type": "ShapeSet2D",
                        "Properties": [
                          {
                            "name": "Position",
                            "value": "posOfAnodeProducts"
                          },
                          {
                            "name": "Visibility",
                            "value": "anodeProductsVisibility.length ? anodeProductsVisibility: false"
                          },
                          {
                            "name": "FillColor",
                            "value": "\"Green\""
                          }
                        ]
                      },
                      {
                        "Name": "anodeProductText",
                        "Type": "TextSet2D",
                        "Properties": [
                          {
                            "name": "Text",
                            "value": "anodeProductsLabels"
                          },
                          {
                            "name": "Position",
                            "value": "posOfAnodeProducts"
                          },
                          {
                            "name": "Visibility",
                            "value": "anodeProductsVisibility.length ? anodeProductsVisibility : false"
                          },
                          {
                            "name": "FillColor",
                            "value": "\"White\""
                          },
                          {
                            "name": "Font",
                            "value": "fontSmall"
                          }
                        ]
                      },
                      {
                        "Name": "cathodeProducts",
                        "Type": "ShapeSet2D",
                        "Properties": [
                          {
                            "name": "Visibility",
                            "value": "cathodeProductsVisibility.length ? cathodeProductsVisibility: false"
                          },
                          {
                            "name": "Position",
                            "value": "posOfCathodeProducts"
                          },
                          {
                            "name": "FillColor",
                            "value": "\"Orange\""
                          }
                        ]
                      },
                      {
                        "Name": "cathodeProductText",
                        "Type": "TextSet2D",
                        "Properties": [
                          {
                            "name": "Text",
                            "value": "cathodeProductsLabels"
                          },
                          {
                            "name": "Position",
                            "value": "posOfCathodeProducts"
                          },
                          {
                            "name": "Visibility",
                            "value": "cathodeProductsVisibility.length ? cathodeProductsVisibility : false"
                          },
                          {
                            "name": "FillColor",
                            "value": "\"White\""
                          },
                          {
                            "name": "Font",
                            "value": "fontSmall"
                          }
                        ]
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      }
    ],
    "RootProperties": []
  },
  "metadata": {
    "APP": "WebEJS",
    "CreatedWith": "WebEJS : The web version of Easy JavaScript Simulations",
    "MoreInfo": "WebEJS 1.1",
    "version": "https://www.um.es/fem/wikis/webejs/"
  }
}